[
  {
    "path": ".circleci/config.yml",
    "content": "version: 2.1\n\norbs:\n  win: circleci/windows@4.1.1\n\ncommands:\n  ulimit:\n    parameters:\n      n: { type: integer }\n    steps:\n    - run:\n        command: \"echo 'ulimit -n <<parameters.n>>' >> $BASH_ENV\"\n\n  concat_files:\n    description: Concatenate file contents\n    parameters:\n      glob: { type: string }\n      to: { type: string }\n    steps:\n    - run:\n        name: Concatenate file contents\n        command: \"cat -s <<parameters.glob>> > <<parameters.to>>\"\n        shell: bash\n\n  codecov:\n    description: Upload a code coverage report file to Codecov.io\n    parameters:\n      file: { type: string }\n    steps:\n    - restore_cache:\n        keys:\n        - \"v1-codecov\"\n    - run:\n        name: Upload a code coverage report file to Codecov.io\n        shell: bash\n        command: |\n          set -evx\n          case \"$OSTYPE\" in\n            darwin*) plat=macos;;\n            msys*)   plat=windows; suffix=.exe;;\n            cygwin*) plat=windows; suffix=.exe;;\n            *)       plat=linux;;\n          esac\n          mkdir -p _codecov_uploader/$plat/\n          pushd _codecov_uploader/$plat/\n          if [[ ! -f \"codecov$suffix\" ]]; then\n            curl -OL \"https://uploader.codecov.io/latest/$plat/codecov$suffix\"\n          fi\n          chmod +x \"codecov$suffix\"\n          popd\n          \"_codecov_uploader/$plat/codecov$suffix\" \\\n            -K \\\n            -f '<<parameters.file>>' \\\n            -n \"$CIRCLE_BUILD_NUM\"\n        when: always\n    - save_cache:\n        key: \"v1-codecov\"\n        paths:\n        - _codecov_uploader/\n        when: always\n\n  netcore_build_base:\n    parameters:\n      collect_tests_to:\n        type: string\n        default: .tests.txt\n      collect_tests_filter:\n        type: string\n        default: \"\"\n    steps:\n    - checkout\n    - concat_files:\n        glob: \"{src,test,tools,sdk/*}/*/*.csproj\"\n        to: .combined-package-files.txt\n    - restore_cache:\n        keys:\n        - v1-deps-{{ arch }}-{{ checksum \".combined-package-files.txt\" }}\n        - v1-deps-{{ arch }}\n    - run:\n        name: Install .NET 8.0 SDK for Libplanet-SDK\n        shell: bash\n        command: |\n          curl -sSL https://dot.net/v1/dotnet-install.sh | \\\n          bash /dev/stdin --channel 8.0 --install-dir /usr/share/dotnet\n    - run: dotnet restore\n    - save_cache:\n        key: v1-deps-{{ arch }}-{{ checksum \".combined-package-files.txt\" }}\n        paths:\n        - ~/.nuget/packages\n    - run: dotnet build --no-restore -c Release -p:SkipSonar=true\n    - run:\n        name: Collect tests\n        shell: bash\n        command: |\n          set -evx\n          if ! command -v dotnet > /dev/null && \\\n             [[ -d /usr/local/share/dotnet ]]; then\n            export PATH=\"/usr/local/share/dotnet:$PATH\"\n          fi\n          dotnet test --no-restore --no-build -c Release --list-tests --filter \"<<parameters.collect_tests_filter>>\" \\\n          > .dotnet-list-tests.txt\n          grep '    ' .dotnet-list-tests.txt \\\n          | sed 's/    /\\n    /g' \\\n          | sed '/^$/d' \\\n          | grep '^    ' \\\n          | sed -E 's/^    |\\(.*?\\)$//g' \\\n          | uniq \\\n          | /usr/bin/sort -R --random-source=CHANGES.md \\\n          > \"<<parameters.collect_tests_to>>\"\n    - persist_to_workspace:\n        root: .\n        paths:\n        - <<parameters.collect_tests_to>>\n        - \"src/*/bin/\"\n        - \"src/*/obj/\"\n        - \"test/*/bin/\"\n        - \"test/*/obj/\"\n        - \"tools/*/bin/\"\n        - \"tools/*/obj/\"\n        - \"sdk/node/*/bin/\"\n        - \"sdk/node/*/obj/\"\n\n  netcore_test_base:\n    parameters:\n      collect_tests_from:\n        type: string\n        default: .tests.txt\n      locale:\n        type: string\n        default: en_US.UTF-8\n      code_coverage:\n        type: boolean\n        default: true\n    steps:\n    - when:\n        condition: \"<<parameters.code_coverage>>\"\n        steps:\n        - restore_cache:\n            keys:\n            - v1-dotcover-{{ arch }}\n        - run:\n            name: Install JetBrains dotCover\n            command: >-\n              dotnet tool install\n              --global\n              JetBrains.dotCover.GlobalTool\n              --version 2021.2.2\n        - save_cache:\n            key: v1-dotcover-{{ arch }}\n            paths:\n            - ~/.nuget/packages\n    - checkout\n    - attach_workspace:\n        at: .\n    - run:\n        name: Distribute tests\n        shell: bash\n        command: |\n          set -evx\n          tests_collection=\"<<parameters.collect_tests_from>>\"\n          total=\"$(wc -l \"$tests_collection\" | awk '{ print $1 }')\"\n          part=\"$(( (total + CIRCLE_NODE_TOTAL - 1) / CIRCLE_NODE_TOTAL ))\"\n          tail -n +$((CIRCLE_NODE_INDEX * part + 1)) \"$tests_collection\" \\\n          > .head_tests.txt\n          if [[ \"$part\" = \"0\" ]]; then\n            cp .head_tests.txt .current_tests.txt\n          else\n            head -n $part .head_tests.txt > .current_tests.txt\n          fi\n          cat .current_tests.txt\n          first=1\n          while read test; do\n            if [[ \"$first\" = \"1\" ]]; then\n              echo \"FullyQualifiedName=$test\"\n              first=0\n            else\n              echo \"| FullyQualifiedName=$test\"\n            fi\n          done < .current_tests.txt > .test-filter.txt\n    - when:\n        condition: \"<<parameters.code_coverage>>\"\n        steps:\n        - run:\n            name: Run tests (using dotCover)\n            command: >-\n              ~/.dotnet/tools/dotnet-dotcover test\n              --no-restore\n              --no-build\n              -c Release\n              -l \"junit;FailureBodyFormat=Verbose;LogFilePath=/tmp/junit/{assembly}.xml\"\n              --filter \"$(cat .test-filter.txt)\"\n              --dcDisableDefaultFilters\n              --dcReportType=DetailedXML\n              --dcFilters=\"+:Libplanet;+:Libplanet.*;-:Libplanet.Tests;-:Libplanet.*.Tests;-:Libplanet.*.UnitTests;-:Libplanet.Benchmarks;-:Libplanet.Explorer\"\n            no_output_timeout: 360s\n            environment:\n              LC_ALL: \"<<parameters.locale>>\"\n              LANG: \"<<parameters.locale>>\"\n              LANGUAGE: \"<<parameters.locale>>\"\n        - store_test_results:\n            path: /tmp/junit\n        - codecov:\n            file: dotCover.Output.xml\n    - unless:\n        condition: \"<<parameters.code_coverage>>\"\n        steps:\n        - run:\n            name: Display tests\n            command: >-\n              dotnet test\n              --no-restore\n              --no-build\n              -c Release\n              -l \"junit;FailureBodyFormat=Verbose;LogFilePath=/tmp/junit/{assembly}.xml\"\n              --filter \"$(cat .test-filter.txt)\"\n              --list-tests | grep -E \"    .+\"\n            environment:\n              LC_ALL: \"<<parameters.locale>>\"\n              LANG: \"<<parameters.locale>>\"\n              LANGUAGE: \"<<parameters.locale>>\"\n        - run:\n            name: Run tests\n            command: >-\n              dotnet test\n              --no-restore\n              --no-build\n              -c Release\n              -l \"junit;FailureBodyFormat=Verbose;LogFilePath=/tmp/junit/{assembly}.xml\"\n              --filter \"$(cat .test-filter.txt)\"\n            no_output_timeout: 360s\n            environment:\n              LC_ALL: \"<<parameters.locale>>\"\n              LANG: \"<<parameters.locale>>\"\n              LANGUAGE: \"<<parameters.locale>>\"\n        - store_test_results:\n            path: /tmp/junit\n\n  linux_netcore_test_base:\n    parameters:\n      collect_tests_from:\n        type: string\n        default: .tests.txt\n      locale:\n        type: string\n        default: en_US.UTF-8\n      code_coverage:\n        type: boolean\n        default: true\n    steps:\n      - run:\n          name: Install lib6c-dev (for RocksDBSharp)\n          shell: bash\n          command: apt update -y && apt install -y libc6-dev liblz4-dev zlib1g-dev libsnappy-dev libzstd-dev\n      - run:\n          name: Install .NET 8.0 SDK for Libplanet-SDK\n          shell: bash\n          command: |\n            curl -sSL https://dot.net/v1/dotnet-install.sh | \\\n            bash /dev/stdin --channel 8.0 --install-dir /usr/share/dotnet\n      - netcore_test_base:\n          collect_tests_from: \"<<parameters.collect_tests_from>>\"\n          locale: \"<<parameters.locale>>\"\n          code_coverage: \"<<parameters.code_coverage>>\"\n\n  macos_netcore_test_base:\n    parameters:\n      collect_tests_from:\n        type: string\n        default: .tests.txt\n      locale:\n        type: string\n        default: en_US.UTF-8\n      code_coverage:\n        type: boolean\n        default: true\n    steps:\n    - ulimit: { n: 10240 }\n    - restore_cache:\n        keys:\n        - v1-macos-dotnet-sdk-6.0\n    - run:\n        name: Export PATH & DOTNET_ROOT\n        shell: bash\n        command: |\n          {\n            echo export PATH=\"$HOME/.dotnet:$PATH\"\n            echo export DOTNET_ROOT=\"$HOME/.dotnet\"\n          } >> $BASH_ENV\n    - run:\n        name: Install .NET 6.0 SDK\n        shell: bash\n        command: |\n          curl -sSL https://dot.net/v1/dotnet-install.sh | bash /dev/stdin --channel 6.0\n    - run:\n        name: Install .NET 8.0 SDK for Libplanet-SDK\n        shell: bash\n        command: |\n          curl -sSL https://dot.net/v1/dotnet-install.sh | bash /dev/stdin --channel 8.0\n    - save_cache:\n        key: v1-macos-dotnet-sdk-6.0\n        paths:\n        - ~/.dotnet/\n    - netcore_test_base:\n        collect_tests_from: \"<<parameters.collect_tests_from>>\"\n        locale: \"<<parameters.locale>>\"\n        code_coverage: \"<<parameters.code_coverage>>\"\n\n  unity_test_base:\n    parameters:\n      runner_target:\n        type: string\n        default: StandaloneLinux64\n      runner_version:\n        type: string\n        default: 0.5.0\n    steps:\n    - checkout\n    - attach_workspace:\n        at: .\n    - run:\n        name: Run tests (using xunit-unity-runner <<parameters.runner_version>>)\n        shell: bash\n        command: |\n          set -evx\n          url=\"https://github.com/planetarium/xunit-unity-runner/releases/download/<<parameters.runner_version>>/xunit-unity-runner-<<parameters.runner_version>>-<<parameters.runner_target>>.tar.bz2\"\n          mkdir -p /tmp/xur/\n          curl -o \"/tmp/xur.tar.bz2\" -L \"$url\"\n          pushd /tmp/xur/\n          bzip2 -d ../xur.tar.bz2\n          tar xvf ../xur.tar\n          popd\n          if [[ \"<<parameters.runner_target>>\" = \"StandaloneOSX\" ]]; then\n            xur_path=/tmp/xur/StandaloneOSX.app/Contents/MacOS/unity-xunit\n          else\n            xur_path=/tmp/xur/<<parameters.runner_target>>\n          fi\n          excluded_classes=(\n            Libplanet.Tests.Blockchain.Renderers.AnonymousActionRendererTest\n            Libplanet.Tests.Blockchain.Renderers.AnonymousRendererTest\n            Libplanet.Tests.Blockchain.Renderers.DelayedActionRendererTest\n            Libplanet.Tests.Blockchain.Renderers.DelayedRendererTest\n            Libplanet.Tests.Blockchain.Renderers.LoggedActionRendererTest\n            Libplanet.Tests.Blockchain.Renderers.LoggedRendererTest\n            Libplanet.Tests.Blockchain.Renderers.NonblockRendererTest\n            Libplanet.Tests.Store.MemoryStoreTest\n            Libplanet.Tests.Blockchain.DefaultStoreBlockChainTest\n            Libplanet.Tests.Blockchain.BlockChainTest\n            Libplanet.Tests.Blockchain.Policies.BlockPolicyTest\n            Libplanet.Tests.Blockchain.Policies.VolatileStagePolicyTest\n            Libplanet.Tests.Store.BlockSetTest\n            Libplanet.Tests.Store.StoreTrackerTest\n            Libplanet.Tests.Blocks.PreEvaluationBlockTest\n            Libplanet.Tests.Blocks.PreEvaluationBlockHeaderTest\n            Libplanet.Tests.Blocks.BlockContentTest\n            Libplanet.Tests.Blocks.BlockMetadataExtensionsTest\n            Libplanet.Tests.Blocks.BlockMetadataTest\n          )\n          excluded_methods=(\n          )\n          args=(\n            \"--hang-seconds=60\"\n            \"--parallel=1\"\n            \"--report-xml-path=$PWD/.xur.xml\"\n          )\n          if [[ \"$CIRCLE_NODE_TOTAL\" != \"\" ]]; then\n            args+=(\n              \"--distributed=$CIRCLE_NODE_INDEX/$CIRCLE_NODE_TOTAL\"\n              \"--distributed-seed=$CIRCLE_BUILD_NUM\"\n            )\n          fi\n          for c in \"${excluded_classes[@]}\"; do\n            args+=(\"--exclude-class=$c\")\n          done\n          for c in \"${excluded_methods[@]}\"; do\n            args+=(\"--exclude-method=$c\")\n          done\n          for project in *.Tests; do\n            if [[\n              $project == Libplanet.Analyzers.Tests\n              || $project == Libplanet.Tests\n            ]]\n            then\n              args+=(\"$PWD/$project/bin/Release/net47/$project.dll\")\n            fi\n          done\n          \"$xur_path\" \"${args[@]}\"\n        no_output_timeout: 65s\n    - run:\n        name: Transform xUnit.net report XML to JUnit report XML\n        shell: bash\n        command: |\n          set -evx\n          mkdir -p _junit\n          xsltproc -o _junit/xur.xml .circleci/xunit-junit.xslt .xur.xml\n          cat _junit/xur.xml\n        when: always\n    - store_test_results:\n        path: _junit\n\njobs:\n  linux-netcore-build:\n    parameters:\n      collect_tests_filter:\n        type: string\n        default: \"\"\n    docker:\n    - image: mcr.microsoft.com/dotnet/sdk:6.0\n    resource_class: large\n    working_directory: /mnt/ramdisk\n    steps:\n    - netcore_build_base:\n        collect_tests_filter: \"<<parameters.collect_tests_filter>>\"\n\n  linux-netcore-test-netmq:\n    parameters:\n      parallelism:\n        type: integer\n        default: 4\n    docker:\n    - image: mcr.microsoft.com/dotnet/sdk:6.0\n    environment:\n      TRANSPORT_TYPE: netmq\n    resource_class: large\n    working_directory: /mnt/ramdisk\n    parallelism: <<parameters.parallelism>>\n    steps:\n    - linux_netcore_test_base:\n        code_coverage: false\n\n  linux-netcore-test-ar-SA:\n    docker:\n    - image: mcr.microsoft.com/dotnet/sdk:6.0\n    resource_class: large\n    working_directory: /mnt/ramdisk\n    parallelism: 4\n    steps:\n    - linux_netcore_test_base:\n        locale: ar_SA.UTF-8\n        code_coverage: false\n\n  linux-netcore-test-fr-FR:\n    docker:\n    - image: mcr.microsoft.com/dotnet/sdk:6.0\n    resource_class: large\n    working_directory: /mnt/ramdisk\n    parallelism: 4\n    steps:\n    - linux_netcore_test_base:\n        locale: fr_FR.UTF-8\n        code_coverage: false\n\n  macos-netcore-test:\n    parameters:\n      parallelism:\n        type: integer\n        default: 4\n    macos:\n      xcode: 14.3.1\n    resource_class: macos.m1.medium.gen1\n    parallelism: <<parameters.parallelism>>\n    steps:\n    - macos_netcore_test_base: { code_coverage: false }\n\n  windows-netcore-test:\n    parameters:\n      parallelism:\n        type: integer\n        default: 6\n    executor:\n      name: win/server-2022\n      size: large\n    parallelism: <<parameters.parallelism>>\n    steps:\n    - netcore_test_base: { code_coverage: false }\n\nworkflows:\n  Libplanet:\n    jobs:\n    - linux-netcore-build:\n        collect_tests_filter: \"FullyQualifiedName!~Libplanet.Net.Tests & CircleCI!=Skip\"\n    - linux-netcore-test-netmq:\n        requires: [linux-netcore-build]\n    - linux-netcore-test-ar-SA:\n        filters:\n          branches:\n            only:\n              - main\n        requires: [linux-netcore-build]\n    - linux-netcore-test-fr-FR:\n        filters:\n          branches:\n            only:\n              - main\n        requires: [linux-netcore-build]\n    - macos-netcore-test:\n        filters:\n          branches:\n            only:\n              - main\n        requires: [linux-netcore-build]\n    - windows-netcore-test:\n        filters:\n          branches:\n            only:\n              - main\n        requires: [linux-netcore-build]\n  Libplanet.Net:\n    jobs:\n    - linux-netcore-build:\n        name: linux-netcore-build-net\n        collect_tests_filter: \"FullyQualifiedName~Libplanet.Net.Tests\"\n    - linux-netcore-test-netmq:\n        name: linux-netcore-test-netmq-net\n        requires: [linux-netcore-build-net]\n        parallelism: 1\n    - windows-netcore-test:\n        filters:\n          branches:\n            only:\n              - main\n        name: windows-netcore-test-net\n        requires: [linux-netcore-build-net]\n        parallelism: 1\n\n"
  },
  {
    "path": ".circleci/xunit-junit.xslt",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n<!-- Original: https://github.com/gabrielweyer/xunit-to-junit -->\n<xsl:stylesheet version=\"1.0\" xmlns:xsl=\"http://www.w3.org/1999/XSL/Transform\">\n  <xsl:output\n    method=\"xml\"\n    encoding=\"UTF-8\"\n    byte-order-mark=\"no\"\n    indent=\"yes\"\n    omit-xml-declaration=\"no\"\n    cdata-section-elements=\"skipped failure \"/>\n  <xsl:template match=\"/\">\n    <testsuites>\n      <xsl:for-each select=\"//assembly\">\n        <testsuite>\n          <xsl:attribute name=\"name\">\n            <xsl:value-of select=\"@name\"/>\n          </xsl:attribute>\n          <xsl:attribute name=\"tests\">\n            <xsl:value-of select=\"@total\"/>\n          </xsl:attribute>\n          <xsl:attribute name=\"failures\">\n            <xsl:value-of select=\"@failed\"/>\n          </xsl:attribute>\n          <xsl:attribute name=\"skipped\">\n            <xsl:value-of select=\"@skipped\"/>\n          </xsl:attribute>\n          <xsl:attribute name=\"errors\">\n            <xsl:value-of select=\"@errors\"/>\n          </xsl:attribute>\n          <xsl:attribute name=\"time\">\n            <xsl:value-of select=\"@time\"/>\n          </xsl:attribute>\n          <xsl:attribute name=\"timestamp\">\n            <xsl:value-of\n              select=\"@run-date\"\n            />T<xsl:value-of select=\"@run-time\"/>\n          </xsl:attribute>\n          <xsl:for-each select=\"collection/test\">\n            <testcase>\n              <xsl:attribute name=\"name\">\n                <xsl:value-of select=\"@name\"/>\n              </xsl:attribute>\n              <xsl:attribute name=\"classname\">\n                <xsl:value-of select=\"@type\"/>\n              </xsl:attribute>\n              <xsl:attribute name=\"time\">\n                <xsl:value-of select=\"@time\"/>\n              </xsl:attribute>\n              <xsl:if test=\"@result='Skip'\">\n                <skipped><xsl:value-of select=\"reason\"/></skipped>\n              </xsl:if>\n              <xsl:if test=\"@result='Fail'\">\n                <failure>\n                  <xsl:attribute name=\"type\">\n                    <xsl:value-of select=\"failure/@exception-type\"/>\n                  </xsl:attribute>\n                  <xsl:attribute name=\"message\">\n                    <xsl:value-of select=\"failure/message\"/>\n                  </xsl:attribute>\n                  <xsl:value-of select=\"failure/stack-trace\"/>\n                </failure>\n              </xsl:if>\n            </testcase>\n          </xsl:for-each>\n        </testsuite>\n      </xsl:for-each>\n    </testsuites>\n  </xsl:template>\n</xsl:stylesheet>\n"
  },
  {
    "path": ".config/dotnet-tools.json",
    "content": "{\n  \"version\": 1,\n  \"isRoot\": true,\n  \"tools\": {\n    \"docfx\": {\n      \"version\": \"2.60.2\",\n      \"commands\": [\n        \"docfx\"\n      ]\n    }\n  }\n}\n"
  },
  {
    "path": ".devcontainer/Dockerfile",
    "content": "# See here for image contents: https://github.com/microsoft/vscode-dev-containers/tree/v0.209.6/containers/dotnet/.devcontainer/base.Dockerfile\n\n# [Choice] .NET version: 6.0, 5.0, 3.1, 6.0-bullseye, 5.0-bullseye, 3.1-bullseye, 6.0-focal, 5.0-focal, 3.1-focal\nARG VARIANT=\"6.0-bullseye-slim\"\nFROM mcr.microsoft.com/vscode/devcontainers/dotnet:0-${VARIANT}\n\nRUN apt-get update && export DEBIAN_FRONTEND=noninteractive \\\n    && apt-get -y install bash-completion xz-utils\n\nRUN curl -fsSL https://deb.nodesource.com/setup_lts.x | bash - && \\\n    apt-get install -y nodejs\n"
  },
  {
    "path": ".devcontainer/devcontainer.json",
    "content": "// For format details, see https://aka.ms/devcontainer.json. For config options, see the README at:\n// https://github.com/microsoft/vscode-dev-containers/tree/v0.209.6/containers/dotnet\n{\n  \"name\": \"C# (.NET)\",\n  \"build\": {\n    \"dockerfile\": \"Dockerfile\",\n    \"args\": {\n      // Update 'VARIANT' to pick a .NET Core version: 3.1, 5.0, 6.0\n      // Append -bullseye or -focal to pin to an OS version.\n      \"VARIANT\": \"6.0\"\n    }\n  },\n\n  // Set *default* container specific settings.json values on container create.\n  \"settings\": {},\n\n  // Add the IDs of extensions you want installed when the container is created.\n  \"extensions\": [\n    \"editorconfig.editorconfig\",\n    \"ms-dotnettools.csharp\",\n    \"formulahendry.dotnet-test-explorer\",\n    \"ms-vscode.powershell\",\n    \"ms-vsliveshare.vsliveshare\",\n    \"streetsidesoftware.code-spell-checker\",\n    \"GitHub.vscode-pull-request-github\"\n  ],\n\n  // Use 'postCreateCommand' to run commands after the container is created.\n  \"postCreateCommand\": \"dotnet build\",\n\n  // Comment out connect as root instead. More info: https://aka.ms/vscode-remote/containers/non-root.\n  \"remoteUser\": \"vscode\",\n  \"features\": {\n    \"git\": \"os-provided\",\n    \"powershell\": \"latest\"\n  }\n}\n"
  },
  {
    "path": ".dockerignore",
    "content": "Dockerfile\n.git\n.github\nhooks\n.vs\n*.ps1\n"
  },
  {
    "path": ".editorconfig",
    "content": "# https://editorconfig.org/\nroot = true\n\n[*]\ncharset = utf-8\nend_of_line = lf\ninsert_final_newline = true\ntab_width = 8\ntrim_trailing_whitespace = true\nmax_line_length = 80\nindent_style = space\ncontinuation_indent_size = 4\nindent_size = 4\n\n[*.{json,ps1,sh,yaml,yml}]\nindent_size = 2\ncontinuation_indent_size = 2\n\n[*.{csproj,xml}]\nindent_size = 2\nquote_type = double\n\n[*.cs]\nmax_line_length = 100\ncurly_bracket_next_line = true\nspaces_around_operators = true\nindent_brace_style = Allman\ndotnet_naming_rule.public_members_must_be_capitalized.symbols = public_symbols\ndotnet_naming_symbols.public_symbols.applicable_kinds = property,method,field,event,delegate\ndotnet_naming_symbols.public_symbols.applicable_accessibilities = public\ndotnet_naming_rule.public_members_must_be_capitalized.style = first_word_upper_case_style\ndotnet_naming_style.first_word_upper_case_style.capitalization = first_word_upper\ndotnet_naming_rule.public_members_must_be_capitalized.severity = warning\n\n[*.csproj]\nquote_type = double\n\n[*.sln]\nindent_style = tab\nindent_size = 2\n\n[hooks/*]\nindent_size = 2\ncontinuation_indent_size = 2\n\n[stylecop.json]\nmax_line_length =\n"
  },
  {
    "path": ".gitallowed",
    "content": "# For Web3Account.test.ts\nda63b632d3e48de4099e32e3664741fa60880547ab8740854abb77a8c5183638\n5ea19f4c94faa5c698dbbcdd55390f72dac8b6383b2c1010328dfc9248eac2fc\ndd8a1132cf57db67c038c6763afe2cbe6ea1949a86abc5843f8ca656ebbb1ea2\n25710c2ccd7c610b24d068af83b959b7a0e5f40641f0c82daeb1345766191034\n337aeb86505d2d0bb620effe57f18381377d67d76dac1090626aa5cd20886a7c\n99b480642f6406a10c67429168fb36ba35da7743965e10390eda649ec6da2ae8\n7856d88908c72f0af78457ccd085696ad6193f7d2bda525723862f450ce060fa\n2af8da24b177f6723d8b99762b416fc3050289b572b8819ebbb0a6b143b1d55d\n7a28b5ba57c53603b0b07b56bba752f7784bf506fa95edc395f5cf6c7514fe9d\n00000000000000000000000000000000000000000000000000000000000000aa\nb56fe718d3f29d5f111d3e975abe0ac57595f1717183793540a8065dd5ba34fd\ne8b612d1126989e1b85b0b94e511bfca5eff4866bb646fc7a42275759bc2d529\ndebd6928cf96f23e3cd5580aebd911c8ea4eb7c29d4db10c251ce8f29c2f32f6\n\n# For account-web3-secret-storage/test/fixtures\n902352dd97b4d73f9efcaf60b94a7ce204ba6cb8b92d669d29e99850ad61a00e\n264020c7d11f2470316db06623390f488453df251b0731a4f33c7b8e2178afec\nfd7c9047651a97713678cceeb19a23d8260c7bd77f384bc850ce4a1206d2d9bd\nf3b18df2a2c391a3d1b1071470b4c81ce22f76ce582525a3f81b3a42c8d58613\nc7925c8fa327a114ac5b24560c0c7c4dc4715353976b858f7ee20fcde375f7fd\ne665d78dc1796544aea4605230f4f25ad2994aa2ebdc5b63ab803d6c9cbefa39\n99b480642f6406a10c67429168fb36ba35da7743965e10390eda649ec6da2ae8\n7856d88908c72f0af78457ccd085696ad6193f7d2bda525723862f450ce060fa\n\n# For Message.test.ts\n2c26b46b68ffc68ff99b453c1d30413413422d706483bfa0f98a5e886266e7ae\nfcde2b2edba56bf408601fb721fe9b5c338d10ee429ea04fae5511b68fbf8fb9\n5760ea321bdd7ac302469e192aa527b6458e3a1e0ddf6c76d9618aca6f653b4d\n\n# For fixtures.ts\n9bf4664ba09a89faeb684b94e69ffde01d26ae14b556204d3f6ab58f61f78418\nfcf30b333d04ccfeb562f000a32df488e7154949d31ddcac3cf9278acb5786c7\n\n# For signed.test.ts\n49a645bb80fa96757009615ec33bc15a2e90e9121877de9f14de35b7d657a118\n\n# For TxResultTypeTest.cs\n45bcaa4c0b00f4f31eb61577e595ea58fb69c7df3ee612aa6eea945bbb0ce39d\n\n# For StateQueryTest.cs\n01ba4719c80b6fe911b091a7c05124b64eeece964e09c058ef8f9805daca546b\n\n# For MessageIdTest.cs\n45a22187e2d8850bb357886958bc3e8560929ccc886958bc3e8560929ccc9ccc\n\n# For MessageTest.cs\ndf91283da7f6bace4ec5ff7c4990594e9725f534665bb52fd40b17b337b86d07\n\n# For Broadcast.cs\n8568eb6f287afedece2c7b918471183db0451e1a61535bb0381cfdf95b85df20\nc34f7498befcc39a14f03b37833f6c7bb78310f1243616524eda70e078b8313c\n941bc2edfab840d79914d80fe3b30840628ac37a5d812d7f922b5d2405a223d3\n\n# For ProtectedPrivateKeyTest.cs\n3eeaaf35da70928387cae1ead31ed782b1135d7578a89d95e30cc914010ba2ed\n535bab75c112fe327dc2e293f80297ff339e1e3cb76749615313cdc2aaa3b37a\nd86ab9eff23f28210dc0102a236498e5c96888be6b5cd6f30981aa896be842d1\n45a5b80fd3ea8f4f0db824b9b56b42be2c1e3759e77c0197cfa3a136f18d5957\n445c0bbc6c310d1fcabf7d7456fd3c558e504c4d308ddb83eddb0b2b8f66f834\n7870dff71e174af3cdc3e9dd47ecfd2dbeca665cd133fb0f87dd9359f3279e0b\nc3f7e2be00e7f6c3377121bc7fe2967c22d627c3289be1b8ace3a6b3c4a54dad\n75de082f96f1c780e460b8400166d411482bff402444b869125e7559315ea892\n\n# For PreEvaluationBlockHeaderTest.cs\n9c999d048603c32369bcd982ac2488f8d2782f339f0296ad537d4f039984dc47\nd1cc52736d25293415eb276a245db7cd1ad4c90c14c22516f3eeccdbc206ff8d\ndfd589064f9127a1b0c99f792776de1006a0a5c89cea00b3c72c635ca56d3b55\n68a92bf6032b87cd42e5b21d8845aa73e727866037eb61de20546885f7801510\nfecb4bff71ac372a3a14080af55d63c4d8058458206267b41d9e7f98f962b907\n54f7572223e4d642ca8772378528120392a9997655860a6ec108f3e4d8c1cc14\n5e63ed240742d7dac4b7f290f5a7afc51e2d410b13d2ad9690e56ac66486b23d\n1ff0ca42037e91a07db6b42a2f0aadc7fc1249900033718d783334a90a333892\ne6b3803208416556db8de50670aaf0b642e13c90afd77d24da8f642dc3e8f320\n\n# For PrivateKeyTest.cs\ne07107ca4b0d19147fa1152a0f2c7884705d59cbb6318e2f901bd28dd9ff78e3\n82fc9947e878fc7ed01c6c310688603f0a41c8e8704e5b990e8388343b0fd465\n5f706787ac72c1080275c1f398640fb07e9da0b124ae9734b28b8d0f01eda586\n91cd3ac5b0ee0642dc5f3c64061d8b87d6a7a1f9bfd3c4159068ebffa229bebb\na1b9932496f358b26a4e3611abf1e46cd39d3d8da5b2a1bd082535470306a0b2\ndbee28545e490ff2b1311a0545a7498eb1bae9156207ee732f1ee59ec1b18bb4\n7bdce857e2476eb4988e52263f9b51fdb3ceabb546e00cd4ffb52540637131ff\n341e8f360597d5bc45ab96aabc5f1b0608063f30af7bd4153556c9536a07693a\n\n# For ScryptTest.cs\n3ada4bad7033fdaa65684ecf93dab3186e48d3f80965070d5fc9aac07811dc8f\n\n# For BlockContentFixture.cs\n2d5c20079bc4b2e6eab9ecbb405da8ba6590c436edfb07b7d4466563d7dac096\n105341c78dfb0dd313b961081630444c2586a1f01fb0c625368ffdc9136cfa30\n654698d34b6d9a55b0c93e4ffb2639278324868c91965bc5f96cb3071d6903a0\n\n# For TestUtils.cs\n042b81bef7d4bca6e01f5975ce9ac7ed9f75248903d08836bed6566488c8089d\n2a15e7deaac09ce631e1faa184efadb175b6b90989cf1faed9dfc321ad1db5ac\ncf36ecf9e47c879a0dbf46b2ecd83fd276182ade0265825e3b8c6ba214467b76\n91d61834be824c952754510fcf545180eca38e036d3d9b66564f0667b30d5b93\nb17c919b07320edfb3e6da2f1cfed75910322de2e49377d6d4d226505afca550\n91602d7091c5c7837ac8e71a8d6b1ed1355cfe311914d9a76107899add0ad56a\ne5792a1518d9c7f7ecc35cd352899211a05164c9dde059c9811e0654860549ef\n\n# For MessageIntegrityTest.cs\nae0633cd58ba097a1167c6d2cc4e236db52256a40d565f11edf76c02d13db93c\n\n# For UserNameTest.cs\nae0633cd58ba097a1167c6d2cc4e236db52256a40d565f11edf76c02d13db93c\n\n# For TxMetadataTest.cs\n83915317ebdbf870c567b263dd2e61ec9dca7fb381c592d80993291b6ffe5ad5\n\n# For TxInvoiceTest.cs\n92854cf0a62a7103b9c610fd588ad45254e64b74ceeeb209090ba572a41bf265\n\n# For UnsignedTxTest.cs\n51fb8c2eb261ed761429c297dd1f8952c8ce327d2ec2ec5bcc7728e3362627c2\n\n# For TransactionTest.cs\nd1475d7f4c84444a0522989876aa0a1aa5d9ba8fdbf84ea5a33c60bd83cbbe7f\nd4e3e4db802ef1b19c4bc74dd8fae5da60108414a6772b060752825034cb7f1b\neff61a6ee0faa2705b3dbd23abefbf18b4c864fa6b344c4fc3846cbb71a0e294\n\n# For MerkleTrieTest.cs\n4783d18dfc8a2d4d98f722a935e45bd7fc1d0197fb4d33e62f734bfde968af39\n1dabec2c0fea02af0182e9fee6c7ce7ad1a9d9bcfaa2cd80c2971bbce5272655\n586ba0ba5dfe07433b01fbf7611f95832bde07b8dc5669540ef8866f465bbb85\nf29820df65c1d1a66b69a59b9fe3e21911bbd2d97a9f298853c529804bf84a26\n77d13e9d97033400ad31fcb0441819285b9165f6ea6ae599d85e7d7e24428feb\n88d6375097fd03e6c30a129eb0030d938caeaa796643971ca938fbd27ff5e057\nad9fb53a8f643bd308d7afea57a5d1796d6031b1df95bdd415fa69b44177d155\n56e5a39a726acba1f7631a6520ae92e20bb93ca3992a7b7d3542c6daee68e56d\nabb5759141f7af1c40f1b0993ba60073cf4227900617be9641373e5a097eaa3c\nab1359a2497453110a9c658dd3db45f282404fe68d8c8aca30856f395572284c\n4458796f4092b5ebfc1ffb3989e72edee228501e438080a12dea45591dc66d58\n16fc25f43edd0c2d2cb6e3cc3827576e57f4b9e04f8dc3a062c7fe59041f77bd\n1b16b1df538ba12dc3f97edbb85caa7050d46c148134290feba80f8236c83db9\n\n# For BlockContentTest.cs\nea0493b0ed67fc97b2e5e85a1d145adea294112f09df15398cb10f2ed5ad1a83\n2ed05de0b35d93e4ae801ae40c8bb4257a771ff67c1e5d1754562e4191953710\n76942b42f99c28da02ed916ebd2fadb189415e8288a4bd87f9ae3594127b79e6\n\n# For BlockFixture.cs\ne2e938f9d8af0a20d16d1c233fc4e8f39157145d003565807e4055ce6b5a0121\naaeda4f1a6a4aee7fc9a29014cff005109176e83a8e5d28876f2d889680e6421\n6a648da9e91c21aa22bdae4e35c338406392aad0db4a0f998c01a7d7973cb8aa\n\n# For ByteUtilTest.cs\n8ec2f5285c8fc2f5285c8fc2f5285c8fc2f5285c8fc2f5285c8fc2f5285c8f00\ne94a399c4fd6d508f022bbee8781a9c44754408bb92ca5b509fa824b00000000\na85f4662e531e44d161346dcaa256af7923c87291b5408b109fa820000000000\n\n# For BlockMetadataTest.cs\n3d8e87977b1142863435b9385657e69557df8951a0698e9719f7d06c5fb8db1f\nd6c03233c2fbe96c57c823c5edc679810f1714dceef7a466a3f7a6659af9fe17\n9ae70453c854c69c03e9841e117d269b97615dcf4f580fb99577d981d3f61ebf\n\n# For BlockHashTest.cs\n2831d4c24ae5d1931a16de0a066e233e0eed1d3fdf6d572ad58d1c3705c8cbfc\n"
  },
  {
    "path": ".gitattributes",
    "content": "/.yarn/**            linguist-vendored\n/.yarn/releases/*    binary\n/.yarn/plugins/**/*  binary\n/.pnp.*              binary linguist-generated\n/yarn.lock           binary linguist-generated\n"
  },
  {
    "path": ".github/auto_assign.yml",
    "content": "addReviewers: false\naddAssignees: author\n"
  },
  {
    "path": ".github/bin/bundle.sh",
    "content": "#!/bin/bash\n# Make \"bundle\" archives, include all referenced assemblies, for each\n# supported target platform.\n# Note that this script is intended to be run by GitHub Actions.\nset -e\n\n# shellcheck source=constants.sh\n. \"$(dirname \"$0\")/constants.sh\"\n\nif [[ \"$1\" = \"\" ]]; then\n  echo No the first argument.  Needs a nupkg path. > /dev/stderr\n  exit 1\nelif [[ \"$2\" = \"\" ]]; then\n  echo No the second argument.  Needs an output directory. > /dev/stderr\n  exit 1\nelif [[ \"$3\" = \"\" ]]; then\n  echo No the third argument.  Needs a target framework. > /dev/stderr\n  exit 1\nfi\n\nnupkg=\"$(realpath \"$1\")\"\noutdir=\"$(realpath \"$2\")\"\ntarget=\"$3\"\n\nif ! [[ \"$(basename \"$nupkg\")\" =~ \\.([0-9]+\\.[0-9]+\\.[0-9]+.*)\\.nupkg$ ]]; then\n  echo No version information in the filename: \"$nupkg\" > /dev/stderr\n  exit 1\nfi\n\nversion=\"${BASH_REMATCH[1]}\"\npackage=\"$(basename \"$nupkg\" | sed -E 's/(\\.[0-9]{1,}){3}.*?\\.nupkg$//')\"\nworkdir=\"$(mktemp -d)\"\n\nif printf '%s\\n' \"${executables[@]}\" | grep -q -P \"^$package$\"; then\n  echo \"Since $package is an executable project, its bundle won't be made.\" \\\n    > /dev/stderr\n  exit 0\nfi\n\npushd \"$workdir\"\n  # Prepare a local NuGet repository\n  mkdir repo/\n  nuget add \"$nupkg\" -Source ./repo\n  nuget sources add \\\n    -NonInteractive \\\n    -Name \"$workdir/repo\" \\\n    -Source \"$workdir/repo\"\n\n  if ! nuget sources list | grep -i nuget.org > /dev/null; then\n    nuget sources add \\\n      -NonInteractive \\\n      -Name nuget.org \\\n      -Source https://api.nuget.org/v3/index.json\n  fi\n\n  # Create a skeleton app to bundle assemblies\n  app=\"BundleApp$(head -c 1024 /dev/urandom | md5sum | head -c 10)\"\n  dotnet new console -o \"$app\" -n \"$app\"\n  pushd \"$app/\"\n    sed \\\n      -E \"s|(<TargetFramework>)[^<]*(</TargetFramework>)|\\1$target\\2|\" \\\n      \"$app.csproj\" \\\n      > \"$app.csproj_\"\n    mv \"$app.csproj_\" \"$app.csproj\"\n\n    dotnet add package \"$package\" --version \"$version\" --source \"$workdir/repo\"\n\n    if [[ \"$target\" =~ ^net[0-9][0-9][0-9]$ ]]; then\n      msbuild /r \"/p:Configuration=$configuration\"\n    else\n      dotnet build -c \"$configuration\"\n    fi\n\n    # All referenced assemblies would go inside the bin/ directory:\n    pushd \"bin/Release/$target/\"\n      # Remove unnecessary assemblies\n      find . -name \"$app*\" -exec rm {} +\n\n      # Archive everything in the directory using tarball + xz\n      mkdir -p \"$outdir\"\n      tar cvfJ \"$outdir/$package-$version-$target.tar.xz\" .\n    popd\n  popd\npopd\n"
  },
  {
    "path": ".github/bin/constants.sh",
    "content": "#!/bin/bash\n\n# shellcheck disable=SC2034\nsolution=\"Libplanet\"\nprojects=(\n  \"sdk/node/Libplanet.Node\"\n  \"sdk/node/Libplanet.Node.Executable\"\n  \"sdk/node/Libplanet.Node.Extensions\"\n  \"src/Libplanet\"\n  \"src/Libplanet.Action\"\n  \"src/Libplanet.Common\"\n  \"src/Libplanet.Crypto\"\n  \"src/Libplanet.Crypto.Secp256k1\"\n  \"src/Libplanet.Net\"\n  \"src/Libplanet.Store\"\n  \"src/Libplanet.Store.Remote\"\n  \"src/Libplanet.Stun\"\n  \"src/Libplanet.Types\"\n  \"src/Libplanet.RocksDBStore\"\n  \"test/Libplanet.Mocks\"\n  \"tools/Libplanet.Analyzers\"\n  \"tools/Libplanet.Tools\"\n  \"tools/Libplanet.Explorer\"\n  \"tools/Libplanet.Explorer.Executable\"\n  \"tools/Libplanet.Explorer.Cocona\"\n  \"tools/Libplanet.Extensions.Cocona\"\n)\nconfiguration=Release\nexecutables=(\n  \"tools/Libplanet.Tools\"\n)\nnpm_packages=(\n  \"@planetarium/cli\"\n  \"@planetarium/tx\"\n  \"@planetarium/account\"\n  \"@planetarium/account-aws-kms\"\n  \"@planetarium/account-web3-secret-storage\"\n)\n\n# https://docs.microsoft.com/en-us/dotnet/core/rid-catalog\nrids=(linux-x64 osx-x64 osx-arm64 win-x64)\n\n# Publish a package only if the repository is upstream (planetarium/libplanet)\n# and the branch is for releases (main or *-maintenance or 9c-*).\n# shellcheck disable=SC2235\nif [ \"$GITHUB_REPOSITORY\" = \"planetarium/libplanet\" ] && [[ \\\n    \"$GITHUB_REF\" = refs/tags/* || \\\n    \"$GITHUB_REF\" = refs/heads/main || \\\n    \"$GITHUB_REF\" = refs/heads/*-maintenance || \\\n    \"$GITHUB_REF\" = refs/heads/ci-* || \\\n    \"$GITHUB_REF\" = refs/heads/9c-* \\\n  ]]; then\n  publish_package=true\nfi\n"
  },
  {
    "path": ".github/bin/dist-github-release.sh",
    "content": "#!/bin/bash\n# Extract a release note from the given changelog file.\n# Note that this script is intended to be run by GitHub Actions.\n# shellcheck disable=SC2169\nset -e\n\n# shellcheck source=constants.sh\n. \"$(dirname \"$0\")/constants.sh\"\n\nif [ \"$GITHUB_REPOSITORY\" = \"\" ] | [ \"$GITHUB_REF\" = \"\" ]; then\n  echo \"This script is intended to be run by GitHub Actions.\" > /dev/stderr\n  exit 1\nelif [ ! -f obj/package_version.txt ]; then\n  {\n    echo \"obj/package_version.txt file is missing.\"\n    echo \"dist:version action must be run first.\"\n  } > /dev/stderr\n  exit 1\nelif [ \"${GITHUB_REF:0:10}\" != \"refs/tags/\" ]; then\n  echo \"This script is run for only tag push; being skipped...\" > /dev/stderr\n  exit 0  # If it exits with non-zero other actions become cancelled\nfi\n\ntag=\"${GITHUB_REF#refs/*/}\"\nif [ \"$tag\" != \"$(cat obj/package_version.txt)\" ]; then\n  {\n    echo -n \"Git tag ($tag) does not match to obj/package_version.txt (\"\n    cat obj/package_version.txt\n    echo \").\"\n  } > /dev/stderr\n  exit 1\nelif [ ! -f obj/release_note.txt ]; then\n  {\n    echo \"obj/release_note.txt file is missing.\"\n    echo \"dist:release-note action must be run first.\"\n  } > /dev/stderr\n  exit 1\nfi\n\nfor project in \"${projects[@]}\"; do\n  name=$(echo $project | sed -E 's/^.+\\///')\n  nupkg_path=\"./$project/bin/$configuration/$name.$tag.nupkg\"\n  if [ ! -f \"$nupkg_path\" ]; then\n    {\n      echo \"$nupkg_path is missing.\"\n      echo \"dist:pack action must be run first.\"\n    } > /dev/stderr\n    exit 1\n  fi\ndone\n\nif command -v apk; then\n  apk add --no-cache ca-certificates\n  update-ca-certificates\nfi\n\n# Fill the description on GitHub releases with the release note\ngithub_user=\"${GITHUB_REPOSITORY%/*}\"\ngithub_repo=\"${GITHUB_REPOSITORY#*/}\"\n\ntrial=0\nwhile ! \"$(dirname \"$0\")/github-release.sh\" info \\\n          --user \"$github_user\" \\\n          --repo \"$github_repo\" \\\n          --tag \"$tag\"; do\n  \"$(dirname \"$0\")/github-release.sh\" release \\\n    --user \"$github_user\" \\\n    --repo \"$github_repo\" \\\n    --tag \"$tag\" \\\n    --name \"$solution $tag\" \\\n    --description - < obj/release_note.txt || true\n  trial=$(( trial + 1 ))\n  if [[ \"$trial\" -gt 5 ]]; then break; fi\ndone\n\nfor project in \"${projects[@]}\"; do\n  name=$(echo $project | sed -E 's/^.+\\///')\n  nupkg_path=\"./$project/bin/$configuration/$name.$tag.nupkg\"\n  \"$(dirname \"$0\")/github-release.sh\" upload \\\n    --user \"$github_user\" \\\n    --repo \"$github_repo\" \\\n    --tag \"$tag\" \\\n    --name \"$(basename \"$nupkg_path\")\" \\\n    --file \"$nupkg_path\"\ndone\n\nfor project in \"${executables[@]}\"; do\n  for rid in \"${rids[@]}\"; do\n    for exec_path in \"./$project/bin/$configuration\"/*-\"$tag-$rid\".*\n    do\n      \"$(dirname \"$0\")/github-release.sh\" upload \\\n        --user \"$github_user\" \\\n        --repo \"$github_repo\" \\\n        --tag \"$tag\" \\\n        --name \"$(basename \"$exec_path\")\" \\\n        --file \"$exec_path\"\n    done\n  done\ndone\n\nfor npmpkg in \"${npm_packages[@]}\"; do\n  for tgz in \"./$npmpkg\"/*.tgz; do\n    \"$(dirname \"$0\")/github-release.sh\" upload \\\n      --user \"$github_user\" \\\n      --repo \"$github_repo\" \\\n      --tag \"$tag\" \\\n      --name \"$(basename \"$tgz\")\" \\\n      --file \"$tgz\"\n  done\ndone\n"
  },
  {
    "path": ".github/bin/dist-npm.sh",
    "content": "#!/bin/bash\n# Submit npm packages to npmjs.org.\n# Note that this script is intended to be run by GitHub Actions.\nset -e\n\n# shellcheck source=constants.sh\n. \"$(dirname \"$0\")/constants.sh\"\n\nif [ \"$NODE_AUTH_TOKEN\" = \"\" ]; then\n  echo \"This script requires NODE_AUTH_TOKEN environment variable.\" \\\n    > /dev/stderr\n  exit 1\nfi\n\nif [ \"$publish_package\" = \"\" ]; then\n  dry_run=--dry-run\nelse\n  dry_run=\nfi\n\nversion_type=\"$(cat \"$(dirname \"$0\")/../../obj/version_type.txt\")\"\nif [[ \"$version_type\" = stable ]]; then\n  tag=latest\nelse\n  tag=\"$version_type\"\nfi\n\nfor npmpkg in \"${npm_packages[@]}\"; do\n  for tgz in \"./$npmpkg\"/*.tgz; do\n    # shellcheck disable=SC2086\n    npm publish --access=public --tag=\"$tag\" $dry_run \"$tgz\"\n  done\ndone\n"
  },
  {
    "path": ".github/bin/dist-nuget.sh",
    "content": "#!/bin/bash\n# Submit .nupkg files to NuGet.\n# Note that this script is intended to be run by GitHub Actions.\nset -e\n\n# shellcheck source=constants.sh\n. \"$(dirname \"$0\")/constants.sh\"\n\nif [ ! -f obj/package_version.txt ]; then\n  {\n    echo \"obj/package_version.txt file is missing.\"\n    echo \"dist:version action must be run first.\"\n  } > /dev/stderr\n  exit 1\nfi\n\nif [ \"$NUGET_API_KEY\" = \"\" ]; then\n  echo \"This script requires NUGET_API_KEY envrionment variable.\" > /dev/stderr\n  exit 1\nfi\n\nif [ \"$publish_package\" = \"\" ]; then\n  function dotnet-nuget {\n    echo \"DRY-RUN: dotnet nuget\" \"$@\"\n  }\nelse\n  function dotnet-nuget {\n    dotnet nuget \"$@\"\n  }\nfi\n\npackage_version=\"$(cat obj/package_version.txt)\"\n\nfor project in \"${projects[@]}\"; do\n  name=$(echo $project | sed -E 's/^.+\\///')\n  dotnet-nuget push \\\n    \"./$project/bin/$configuration/$name.$package_version.nupkg\" \\\n    --skip-duplicate \\\n    --api-key \"$NUGET_API_KEY\" \\\n    --source https://api.nuget.org/v3/index.json\ndone\n"
  },
  {
    "path": ".github/bin/dist-pack.sh",
    "content": "#!/bin/bash\n# Build a .nupkg file.\n# Note that this script is intended to be run by GitHub Actions.\nset -e\n\n# shellcheck source=constants.sh\n. \"$(dirname \"$0\")/constants.sh\"\n\nif ! (env | grep '^GITHUB_'); then\n  echo \"This script is intended to be run by GitHub Actions.\" > /dev/stderr\n  exit 1\nfi\n\nversion=\"$(cat obj/package_version.txt)\"       # e.g. 0.50.0-dev.20230221015836\nversion_prefix=\"$(cat obj/version_prefix.txt)\" # e.g. 0.50.0\nif [[ -f obj/version_suffix.txt ]]; then       # e.g. dev.20230221015836+35a2dbc\n  version_suffix=\"$(cat obj/version_suffix.txt)\"\nfi\nrepository_url=\"$(cat obj/repository_url.txt)\"\n\nfor project in \"${executables[@]}\"; do\n  for rid in \"${rids[@]}\"; do\n    output_dir=\"./$project/bin/$configuration/$rid/\"\n    mkdir -p \"$output_dir\"\n    dotnet publish \\\n      --runtime \"$rid\" \\\n      -p:PublishSingleFile=true \\\n      --self-contained \\\n      -p:Version=\"$version\" \\\n      --configuration \"$configuration\" \\\n      --output \"$output_dir\" \\\n      \"$project\" || \\\n        if [[ \"$?\" = \"139\" ]]; then\n          # On GitHub Actions, `dotnet` command occasionally fails due to\n          # segfault.\n          dotnet publish \\\n            --runtime \"$rid\" \\\n            -p:PublishSingleFile=true \\\n            --self-contained \\\n            -p:Version=\"$version\" \\\n            --configuration \"$configuration\" \\\n            --output \"$output_dir\" \\\n            \"$project\"\n        else\n          exit 1\n        fi\n    bin_name=\"$(find \"$output_dir\" -type f -perm /o+x -exec basename {} \\;)\"\n    pushd \"$output_dir\"\n    if [[ \"$rid\" = win-* ]]; then\n      zip -r9 \"../${bin_name%.exe}-$version-$rid.zip\" ./*\n    else\n      tar cvfJ \"../$bin_name-$version-$rid.tar.xz\" ./*\n    fi\n    popd\n    rm -rf \"$output_dir\"\n  done\ndone\n\nfor project in \"${projects[@]}\"; do\n  if [[ \"$version_suffix\" = \"\" ]]; then\n    dotnet_args=\"-p:Version=$version\"\n  else\n    dotnet_args=\"-p:VersionPrefix=$version_prefix\"\n    dotnet_args=\"$dotnet_args --version-suffix=$version_suffix\"\n    dotnet_args=\"$dotnet_args -p:NoPackageAnalysis=true\"\n  fi\n\n  if [[ \"$repository_url\" != \"\" ]]; then\n    dotnet_args=\"$dotnet_args -p:RepositoryUrl=$repository_url\"\n  fi\n\n  dotnet_args=\"$dotnet_args -p:_IsPacking=true\"\n  # shellcheck disable=SC2086\n  dotnet build -c \"$configuration\" $dotnet_args || \\\n    if [[ \"$?\" = \"139\" ]]; then\n      # On GitHub Actions, `dotnet` command occasionally fails due to segfault.\n      dotnet build -c \"$configuration\" $dotnet_args\n    else\n      exit 1\n    fi\n  # shellcheck disable=SC2086\n  dotnet pack \"$project\" -c \"$configuration\" $dotnet_args || \\\n    if [[ \"$?\" = \"139\" ]]; then\n      # On GitHub Actions, `dotnet` command occasionally fails due to segfault.\n      dotnet pack \"$project\" -c \"$configuration\" $dotnet_args\n    else\n      exit 1\n    fi\n\n  ls -al \"./$project/bin/$configuration/\"\n  if [ \"$version\" != \"$version_prefix\" ]; then\n    rm -f \"./$project/bin/$configuration/$project.$version_prefix.nupkg\"\n  fi\ndone\n\nfor npmpkg in \"${npm_packages[@]}\"; do\n  if [[ -f \"./$npmpkg/package.json\" ]]; then\n    pushd \"./$npmpkg/\"\n    jq --arg v \"$version\" 'del(.private) | .version = $v' package.json \\\n      > .package.json.tmp\n    mv .package.json.tmp package.json\n    popd\n  fi\ndone\n\n# Loop twice to make sure that all packages are versioned\nfor npmpkg in \"${npm_packages[@]}\"; do\n  if [[ -f \"./$npmpkg/package.json\" ]]; then\n    pushd \"./$npmpkg/\"\n    yarn\n    yarn pack --out \"${npmpkg//\\//-}-$version.tgz\"\n    popd\n  fi\ndone\n"
  },
  {
    "path": ".github/bin/dist-release-note.sh",
    "content": "#!/bin/bash\n# Extract a release note from the given changelog file.\n# Note that this script is intended to be run by GitHub Actions.\nset -e\n\nif [ \"$1\" = \"\" ]; then\n  echo \"A changelog file path is missing.\" > /dev/stderr\n  exit 1\nelif [ \"$2\" = \"\" ]; then\n  echo \"An output path is missing.\" > /dev/stderr\n  exit 1\nelif [ ! -f obj/package_version.txt ]; then\n  {\n    echo \"obj/package_version.txt file is missing.\"\n    echo \"dist:version action must be run first.\"\n  } > /dev/stderr\n  exit 1\nfi\n\nversion_prefix=\"$(cat obj/version_prefix.txt)\"\npackage_version=\"$(cat obj/package_version.txt)\"\n\nwget -O /tmp/submark \\\n  https://github.com/dahlia/submark/releases/download/0.2.0/submark-linux-x86_64\nchmod +x /tmp/submark\n/tmp/submark \\\n  -o \"$2\" \\\n  -iO \\\n  --h2 \"Version $version_prefix\" \\\n  \"$1\"\nrm /tmp/submark\n\nif ! grep -E '\\S' \"$2\" > /dev/null; then\n  echo \"There is no section for the version $version_prefix.\" > /dev/stderr\n  exit 1\nelif [ \"$version_prefix\" = \"$package_version\" ] && \\\n     grep -i \"to be released\" \"$2\"; then\n  echo 'Release date should be shown on the release note.' > /dev/stderr\n  exit 1\nfi\n"
  },
  {
    "path": ".github/bin/github-release.sh",
    "content": "#!/bin/bash\n# Invoke github-release <https://github.com/github-release/github-release>.\nset -e\n\nif [[ ! -f /tmp/github-release ]]; then\n  wget -O /tmp/github-release.bz2 \\\n    https://github.com/github-release/github-release/releases/download/v0.10.0/linux-amd64-github-release.bz2\n  bzip2 -d /tmp/github-release.bz2\n  chmod +x /tmp/github-release\nfi\n\n/tmp/github-release \"$@\"\n"
  },
  {
    "path": ".github/stale.yml",
    "content": "# Settings only applied to pull requests\npulls:\n  # Number of days of inactivity before an issue becomes stale\n  daysUntilStale: 14\n  # Number of days of inactivity before a stale issue is closed\n  daysUntilClose: 7\n  # Issues with these labels will never be considered stale\n  exemptLabels: []\n  # Label to use when marking an issue as stale\n  staleLabel: stale\n  # Comment to post when marking an issue as stale. Set to `false` to disable\n  markComment: >\n    This pull request has been automatically marked as stale because it has not had\n    recent activity. It will be closed if no further activity occurs. Thank you\n    for your contributions.\n  # Comment to post when closing a stale issue. Set to `false` to disable\n  closeComment: >\n    This pull request has been automatically closed because it has not had recent\n    activity. Thank you for your contributions.\n\n# Settings only applied to issues\nissues:\n  # Number of days of inactivity before an issue becomes stale\n  daysUntilStale: 60\n    # Number of days of inactivity before a stale issue is closed\n  daysUntilClose: false\n  # Issues with these labels will never be considered stale\n  exemptLabels: []\n  # Label to use when marking an issue as stale\n  staleLabel: stale\n  # Comment to post when marking an issue as stale. Set to `false` to disable\n  markComment: >\n    This issue has been automatically marked as stale because it has not had\n    recent activity. Thank you for your contributions.\n"
  },
  {
    "path": ".github/workflows/benchmarks-merged.yml",
    "content": "# yaml-language-server: $schema=https://json.schemastore.org/github-workflow.json\nname: Libplanet benchmark (for merge commits)\non:\n  push:\n    branches-ignore:\n      - \"gh-pages\"\n\npermissions:\n  contents: write\n  deployments: write\n\njobs:\n  benchmark:\n    name: Run Benchmark.Net benchmarks\n    continue-on-error: true\n    strategy:\n      matrix:\n        os:\n        - [macOS, self-hosted, ARM64]\n        - linux-8cores\n        - windows-8cores\n    runs-on: ${{ matrix.os }}\n    steps:\n    - uses: actions/checkout@v3\n    - uses: actions/setup-dotnet@v3\n      with:\n        dotnet-version: 8.0.x\n    - name: Run benchmark\n      run: dotnet run --project tools/Libplanet.Benchmarks -c Release -- --exporters json --filter '*'\n\n    - name: Store benchmark result\n      uses: planetarium/github-action-benchmark@v1\n      with:\n        name: Benchmark.Net Benchmark\n        tool: 'benchmarkdotnet'\n        output-file-path: BenchmarkDotNet.Artifacts/results/Combined.Benchmarks.json\n        github-token: ${{ secrets.GITHUB_TOKEN }}\n        benchmark-data-dir-path: dev/bench/${{ github.ref_name }}/${{ matrix.os }}\n        auto-push: true\n"
  },
  {
    "path": ".github/workflows/benchmarks-pr.yml",
    "content": "# yaml-language-server: $schema=https://json.schemastore.org/github-workflow.json\nname: Libplanet benchmark (for pull requests)\non:\n  pull_request: {}\n\npermissions:\n  contents: write\n  deployments: write\n\njobs:\n  benchmark:\n    name: Run Benchmark.Net benchmarks\n    continue-on-error: true\n    strategy:\n      matrix:\n        os:\n        - [macOS, self-hosted, ARM64]\n        - linux-8cores\n        - windows-8cores\n    runs-on: ${{ matrix.os }}\n    steps:\n    - uses: actions/checkout@v3\n      with:\n        ref: ${{ github.pull_request.head.sha }}\n    - uses: actions/setup-dotnet@v3\n      with:\n        dotnet-version: 8.0.x\n    - name: Run benchmark\n      run: dotnet run --project tools/Libplanet.Benchmarks -c Release -- --exporters json --filter '*'\n\n    - name: Compare benchmark result\n      uses: planetarium/github-action-benchmark@v1\n      with:\n        name: Benchmark.Net Benchmark\n        tool: 'benchmarkdotnet'\n        output-file-path: BenchmarkDotNet.Artifacts/results/Combined.Benchmarks.json\n        github-token: ${{ secrets.GITHUB_TOKEN }}\n        benchmark-data-dir-path: dev/bench/${{ github.base_ref }}/${{ matrix.os }}\n        save-data-file: false\n        alert-threshold: '200%'\n        comment-on-alert: true\n        fail-on-alert: true\n        alert-comment-cc-users: '@libplanet'\n"
  },
  {
    "path": ".github/workflows/build.yaml",
    "content": "# yaml-language-server: $schema=https://json.schemastore.org/github-workflow.json\non:\n  push:\n    branches:\n      - \"main\"\n    tags:\n      - \"*\"\nname: Build artifact and push\n\njobs:\n  build:\n    name: build\n    runs-on: ubuntu-latest\n    steps:\n    - uses: actions/checkout@main\n    - if: github.ref_type == 'tag'\n      run: |\n        set -evx\n        pushd /tmp\n        wget $WEB_FLOW_KEY_URL\n        popd\n        gpg --import /tmp/web-flow.gpg\n        if ! git verify-commit \"$GITHUB_REF_NAME\" && \\\n           [[ \"$( git cat-file -p \"$GITHUB_REF_NAME\" \\\n                | grep -Ei '^parent\\s+[0-9a-f]{40}$' | wc -l )\" -lt 2 ]]; then\n          echo \"::error title=Invalid tag commit::Tags must refer to a merge\" \\\n               \"commit or a commit signed by GitHub @web-flow\" \\\n               \"($WEB_FLOW_KEY_URL).  The tag $GITHUB_REF_NAME refers to \" \\\n               \"a commit $(git rev-parse $GITHUB_REF_NAME) which is neither\" \\\n               \"a merge commit nor signed by GitHub @web-flow.\"\n          exit 1\n        fi\n      env:\n        WEB_FLOW_KEY_URL: https://github.com/web-flow.gpg\n    - uses: actions/setup-dotnet@v3\n      with:\n        dotnet-version: 8.0.x\n    - uses: actions/setup-node@v3\n      with:\n        registry-url: 'https://registry.npmjs.org'\n        scope: '@planetarium'\n        node-version: 'lts/*'\n    - id: determine-version\n      run: node scripts/determine-version.js\n    - shell: bash\n      run: |\n        mkdir -p obj\n        echo \"$VERSION_PREFIX\" > obj/version_prefix.txt\n        if [[ \"$VERSION_SUFFIX\" != \"\" ]]; then\n          echo \"$VERSION_SUFFIX\" > obj/version_suffix.txt\n        fi\n        echo \"$PACKAGE_VERSION\" > obj/package_version.txt\n        echo \"$VERSION_TYPE\" > obj/version_type.txt\n      env:\n        VERSION_PREFIX: ${{ steps.determine-version.outputs.version-prefix }}\n        VERSION_SUFFIX: ${{ steps.determine-version.outputs.version-suffix }}\n        PACKAGE_VERSION: ${{ steps.determine-version.outputs.package-version }}\n        VERSION_TYPE: ${{ steps.determine-version.outputs.version-type }}\n    - run: echo \"$GITHUB_SERVER_URL/$GITHUB_REPOSITORY/tree/$GITHUB_SHA\" > obj/repository_url.txt\n    - run: .github/bin/dist-release-note.sh CHANGES.md obj/release_note.txt\n    - uses: actions/upload-artifact@main\n      with:\n        name: dist-obj\n        path: obj/\n    - run: .github/bin/dist-pack.sh\n    - run: |\n        . .github/bin/constants.sh\n        mkdir -p /tmp/dist-bin/\n        for project in \"${projects[@]}\"; do\n          cp -r \"$project/bin/$configuration\"/* /tmp/dist-bin/\n        done\n        for npmpkg in \"${npm_packages[@]}\"; do\n          cp \"$npmpkg\"/*.tgz /tmp/dist-bin/\n        done\n    - uses: actions/upload-artifact@main\n      with:\n        name: dist-bin\n        path: /tmp/dist-bin/\n    - if: startsWith(github.ref, 'refs/tags/')\n      run: .github/bin/dist-github-release.sh\n      env:\n        GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}\n    - if: env.NUGET_API_KEY != ''\n      run: .github/bin/dist-nuget.sh\n      env:\n        NUGET_API_KEY: ${{ secrets.NUGET_API_KEY }}\n    - if: env.NODE_AUTH_TOKEN != ''\n      run: .github/bin/dist-npm.sh\n      env:\n        NODE_AUTH_TOKEN: ${{ secrets.NPM_ACCESS_TOKEN }}\n"
  },
  {
    "path": ".github/workflows/check-build.yaml",
    "content": "# yaml-language-server: $schema=https://json.schemastore.org/github-workflow.json\n# This workflow checks if the build (compilation) succeeds without any errors.\n# Although the build is done in CircleCI as well, to speed up the build time\n# some checks are turned off in CircleCI.  To conduct the complete checks\n# there should be this separated workflow.\n# See also the below issues:\n# - https://github.com/planetarium/libplanet/pull/979\n# - https://github.com/planetarium/libplanet/pull/977\n# - https://github.com/planetarium/libplanet/issues/976\non:\n  push: null\n  pull_request: null\nname: check-build\n\njobs:\n  build:\n    name: check-build\n    runs-on: ubuntu-latest\n    steps:\n    - uses: actions/checkout@main\n      if: github.event_name != 'pull_request'\n    - uses: actions/checkout@main\n      if: github.event_name == 'pull_request'\n      with:\n        ref: ${{ github.pull_request.head.sha }}\n    - uses: actions/setup-dotnet@v3\n      with:\n        dotnet-version: 8.0.x\n    - run: 'hooks/pre-commit'\n    - run: 'dotnet pack -p:SkipSonar=false -p:_IsPacking=true'\n"
  },
  {
    "path": ".github/workflows/check-changelog.yml",
    "content": "name: check-changelog\non:\n  pull_request:\n    types: [assigned, opened, synchronize, reopened, labeled, unlabeled]\n    branches:\n      - main\n      - '*-maintenance'\njobs:\n  check-changelog:\n    runs-on: ubuntu-latest\n    steps:\n      - uses: tarides/changelog-check-action@v2\n        with:\n          changelog: CHANGES.md\n"
  },
  {
    "path": ".github/workflows/delete-old-artifacts.yml",
    "content": "# yaml-language-server: $schema=https://json.schemastore.org/github-workflow.json\nname: 'Delete old artifacts'\non:\n  schedule:\n    - cron: '0 15 * * *' # every day\n\njobs:\n  delete-artifacts:\n    runs-on: ubuntu-latest\n    steps:\n      - uses: kolpav/purge-artifacts-action@v1\n        with:\n          token: ${{ secrets.GITHUB_TOKEN }}\n          expire-in: 7days\n"
  },
  {
    "path": ".github/workflows/docs.yml",
    "content": "# yaml-language-server: $schema=https://json.schemastore.org/github-workflow.json\non:\n  push:\n    branches-ignore:\n      - gh-pages\n    tags:\n      - \"*\"\n  schedule:\n    - cron: 59 14 * * *\n  pull_request: null\nname: update docs\n\njobs:\n  docs:\n    if: github.event_name != 'schedule' || github.repository == 'planetarium/libplanet'\n    name: docs\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions/checkout@main\n        if: github.event_name != 'pull_request'\n      - uses: actions/checkout@main\n        if: github.event_name == 'pull_request'\n        with:\n          ref: ${{ github.pull_request.head.sha }}\n      - run: git fetch --depth=1 origin +refs/tags/*:refs/tags/*\n      - uses: actions/setup-dotnet@v3\n        with:\n          dotnet-version: 8.0.x\n      - run: dotnet build -p:SkipSonar=true\n      - run: mkdir -p Docs/obj/\n      - run: Docs/build.ps1\n        shell: pwsh\n      - uses: actions/upload-artifact@main\n        with:\n          name: docs\n          path: Docs/_site/\n      - run: Docs/publish.sh\n        env:\n          GHPAGES_SSH_KEY: ${{ secrets.GHPAGES_SSH_KEY }}\n        if: github.event_name != 'pull_request'\n      - id: docs-url\n        run: 'echo ::set-output name=url::\"$(cat Docs/obj/url.txt)\"'\n        if: github.event_name != 'pull_request'\n      - uses: Sibz/github-status-action@v1.1.6\n        with:\n          authToken: ${{ secrets.GITHUB_TOKEN }}\n          context: docs\n          description: Libplanet docs generated by DocFX\n          state: 'success'\n          target_url: ${{ steps.docs-url.outputs.url }}\n        if: github.event_name != 'pull_request'\n"
  },
  {
    "path": ".github/workflows/lint.yml",
    "content": "name: lint\non: [pull_request, push]\n\njobs:\n  typos:\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions/checkout@v2\n\n      - name: Check spelling\n        uses: crate-ci/typos@v1.15.5\n"
  },
  {
    "path": ".github/workflows/push-docker-image.yml",
    "content": "# yaml-language-server: $schema=https://json.schemastore.org/github-workflow.json\non: push\nname: push docker image\njobs:\n  build_and_push:\n    if: github.repository == 'planetarium/libplanet'\n    runs-on: ubuntu-20.04\n    env:\n      DOCKER_USERNAME: ${{ secrets.DOCKER_USERNAME  }}\n    steps:\n      - name: checkout\n        uses: actions/checkout@v3\n      - name: login\n        run: |\n          docker login \\\n            --username \"${{ secrets.DOCKER_USERNAME }}\" \\\n            --password \"${{ secrets.DOCKER_HUB_ACCESS_TOKEN }}\"\n      - name: build\n        run: |\n          docker build \\\n            -f Dockerfile.explorer \\\n            -t planetariumhq/libplanet-explorer:git-${{ github.sha }} \\\n            .\n      - name: push (publish)\n        run: docker push planetariumhq/libplanet-explorer:git-${{ github.sha }}\n"
  },
  {
    "path": ".github/workflows/rebase.yml",
    "content": "# yaml-language-server: $schema=https://json.schemastore.org/github-workflow.json\non:\n  issue_comment:\n    types: [created]\nname: Automatic Rebase\njobs:\n  rebase:\n    name: Rebase\n    if: github.event.issue.pull_request != '' && contains(github.event.comment.body, '/rebase')\n    runs-on: ubuntu-latest\n    steps:\n    - uses: actions/checkout@v3\n      with:\n        fetch-depth: 0\n        token: ${{ secrets.AUTO_REBASE_TOKEN }}\n    - name: Automatic Rebase\n      uses: cirrus-actions/rebase@1.4\n      env:\n        GITHUB_TOKEN: ${{ secrets.AUTO_REBASE_TOKEN }}\n  # https://github.community/t5/GitHub-Actions/Workflow-is-failing-if-no-job-can-be-ran-due-to-condition/m-p/38186#M3250\n  always_job:\n    name: Always run job\n    runs-on: ubuntu-latest\n    steps:\n      - name: Always run\n        run: echo \"This job is used to prevent the workflow to fail when all other jobs are skipped.\"\n"
  },
  {
    "path": ".github/workflows/yarn.yaml",
    "content": "# yaml-language-server: $schema=https://json.schemastore.org/github-workflow.json\nname: yarn\non:\n  push:\n    branches: [\"*\"]\n    tags: [\"*\"]\n  pull_request: null\n\njobs:\n  build:\n    strategy:\n      matrix:\n        node-version: ['lts/*']\n    runs-on: ubuntu-22.04\n    steps:\n    - uses: actions/checkout@v3\n    - uses: actions/setup-node@v3\n      with:\n        node-version: ${{ matrix.node-version }}\n        cache: yarn\n    - run: yarn install --immutable  # TODO: cache and apply --immutable-cache --check-cache\n    - run: yarn build\n    - id: account-aws-kms-changes\n      uses: step-security/changed-files@v45\n      with:\n        files: \"@planetarium/account-aws-kms\"\n    - name: Run yarn test w/o AWS cred for PR unrelated to account-aws-kms\n      if: |\n        github.event_name == 'pull_request' &&\n        steps.account-aws-kms-changes.outputs.any_changed != 'true'\n      run: yarn test\n    - name: Run yarn test w/ AWS cred for push and PR related to account-aws-kms\n      if: |\n        github.event_name != 'pull_request' ||\n        steps.account-aws-kms-changes.outputs.any_changed == 'true'\n      run: yarn test\n      env:\n        AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}\n        AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}\n        AWS_REGION: ${{ secrets.AWS_REGION }}\n    - run: yarn pack-all\n\n  libplanet-tools-npm-install-test:\n    name: \"@planetarium/cli installation test\"\n    strategy:\n      matrix:\n        os:\n        - macos-latest\n        - ubuntu-latest\n        - windows-latest\n    runs-on: ${{ matrix.os }}\n    steps:\n    - uses: actions/checkout@v3\n      with:\n        fetch-depth: 0  # Required for the latest-tag action\n    - id: latest-tag\n      name: Get the latest tag\n      uses: WyriHaximus/github-action-get-previous-tag@v1\n      with:\n        fallback: 1.0.0\n    - if: runner.os != 'Windows'\n      run: |\n        set -ev\n        cd tools/Libplanet.Tools/\n        bin/npm-test.sh \"$LATEST_VERSION\"\n      env:\n        LATEST_VERSION: ${{ steps.latest-tag.outputs.tag }}\n    - if: runner.os == 'Windows'\n      shell: pwsh\n      run: |\n        $ErrorActionPreference = \"Stop\"\n        cd tools\\Libplanet.Tools\\\n        pwsh `\n          -ExecutionPolicy Bypass `\n          -File bin\\npm-test.ps1 `\n          -Version $env:LATEST_VERSION\n      env:\n        LATEST_VERSION: ${{ steps.latest-tag.outputs.tag }}\n"
  },
  {
    "path": ".gitignore",
    "content": "# Common IntelliJ Platform excludes\n\n# User specific\n**/.idea/**/workspace.xml\n**/.idea/**/tasks.xml\n**/.idea/shelf/*\n**/.idea/dictionaries\n\n# Sensitive or high-churn files\n**/.idea/**/dataSources/\n**/.idea/**/dataSources.ids\n**/.idea/**/dataSources.xml\n**/.idea/**/dataSources.local.xml\n**/.idea/**/sqlDataSources.xml\n**/.idea/**/dynamic.xml\n\n# Rider\n# Rider auto-generates .iml files, contentModel.xml, projectSettingsUpdater.xml, and indexLayout.xml\n**/.idea/**/*.iml\n**/.idea/**/contentModel.xml\n**/.idea/**/modules.xml\n**/.idea/**/projectSettingsUpdater.xml\n**/.idea/**/indexLayout.xml\n\n# dotCover\ndotCover.Output.*\ndotCover.Output/\n\n# .NET\n*.suo\n*.user\n.vs/\n[Bb]in/\n[Oo]bj/\n!.github/bin/\n_UpgradeReport_Files/\n[Pp]ackages/\nmono_crash.*.json\nFodyWeavers.xsd\nBenchmarkDotNet.Artifacts\nxunit.runner.console.*/\n\n# typescript\n.pnp.*\n.yarn/*\n!.yarn/patches\n!.yarn/plugins\n!.yarn/releases\n!.yarn/sdks\n!.yarn/versions\n\nyarn-debug.log*\nyarn-error.log*\n\n# macOS & Windows\nThumbs.db\nDesktop.ini\n.DS_Store\n\n# sdk\n.db\n"
  },
  {
    "path": ".idea/.idea.Libplanet/.idea/.name",
    "content": "Libplanet"
  },
  {
    "path": ".idea/.idea.Libplanet/.idea/vcs.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project version=\"4\">\n  <component name=\"CommitMessageInspectionProfile\">\n    <profile version=\"1.0\">\n      <inspection_tool class=\"BodyLimit\" enabled=\"true\" level=\"WARNING\" enabled_by_default=\"true\" />\n      <inspection_tool class=\"SubjectBodySeparation\" enabled=\"true\" level=\"WARNING\" enabled_by_default=\"true\" />\n      <inspection_tool class=\"SubjectLimit\" enabled=\"true\" level=\"WARNING\" enabled_by_default=\"true\" />\n    </profile>\n  </component>\n  <component name=\"VcsDirectoryMappings\">\n    <mapping directory=\"$PROJECT_DIR$\" vcs=\"Git\" />\n  </component>\n</project>"
  },
  {
    "path": ".vscode/extensions.json",
    "content": "{\n  \"recommendations\": [\n    \"editorconfig.editorconfig\",\n    \"ms-dotnettools.csharp\",\n    \"formulahendry.dotnet-test-explorer\",\n    \"ms-vscode.powershell\",\n    \"streetsidesoftware.code-spell-checker\",\n    \"GitHub.vscode-pull-request-github\",\n    \"arcanis.vscode-zipfs\",\n    \"rome.rome\",\n    \"redhat.vscode-yaml\"\n  ]\n}\n"
  },
  {
    "path": ".vscode/launch.json",
    "content": "{\n    // Use IntelliSense to learn about possible attributes.\n    // Hover to view descriptions of existing attributes.\n    // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387\n    \"version\": \"0.2.0\",\n    \"configurations\": [\n        {\n            \"name\": \"C#: Libplanet Node\",\n            \"type\": \"coreclr\",\n            \"request\": \"launch\",\n            \"program\": \"${workspaceFolder}/sdk/node/Libplanet.Node.Executable/bin/Debug/net8.0/Libplanet.Node.Executable.dll\",\n            \"console\": \"integratedTerminal\",\n            \"args\": [\n            ],\n            \"env\": {\n                \"ASPNETCORE_ENVIRONMENT\": \"Development\",\n            },\n            \"cwd\": \"${workspaceFolder}/sdk/node/Libplanet.Node.Executable\"\n        },\n    ]\n}\n"
  },
  {
    "path": ".vscode/settings.json",
    "content": "{\n  \"editor.rulers\": [\n    80,\n    100\n  ],\n  \"search.exclude\": {\n    \"**/.yarn\": true,\n    \"**/.pnp.*\": true,\n    \"**/bin\": true,\n    \"**/obj\": true\n  },\n  \"files.exclude\": {\n    \"**/obj\": true,\n    \"**/.git\": true,\n    \"**/.svn\": true,\n    \"**/.hg\": true,\n    \"**/CVS\": true,\n    \"**/.DS_Store\": true,\n    \"**/Thumbs.db\": true\n  },\n  \"csharp.semanticHighlighting.enabled\": true,\n  \"cSpell.words\": [\n    \"bencoded\",\n    \"Bencodex\",\n    \"Bitcoin\",\n    \"Ethereum\",\n    \"Kademlia\",\n    \"Libplanet\",\n    \"Libplanet's\",\n    \"PRNG\",\n    \"Unstage\",\n    \"blockchain\",\n    \"branchpoint\",\n    \"broadcasted\",\n    \"changeset\",\n    \"ciphertext\",\n    \"indeterministic\",\n    \"marshaler\",\n    \"nonces\",\n    \"outdate\",\n    \"parameterless\",\n    \"preload\",\n    \"roadmap\",\n    \"ruleset\",\n    \"runtimes\",\n    \"secp256k1\",\n    \"struct\",\n    \"txid\",\n    \"unmarshal\",\n    \"unmarshaling\",\n    \"unstage\",\n    \"unstaged\",\n    \"unrender\",\n    \"unrendered\",\n    \"unrenderer\",\n    \"unrendering\",\n    \"unrenders\",\n    \"upstream's\"\n  ],\n  \"cSpell.enabled\": false,\n  \"dotnet-test-explorer.autoExpandTree\": true,\n  \"dotnet-test-explorer.testProjectPath\": \"**/*Tests.@(csproj|vbproj|fsproj)\",\n  \"typescript.tsdk\": \".yarn/sdks/typescript/lib\",\n  \"typescript.enablePromptUseWorkspaceTsdk\": true,\n  \"eslint.nodePath\": \".yarn/sdks\",\n  \"[typescript]\": {\n    \"editor.defaultFormatter\": \"esbenp.prettier-vscode\",\n    \"editor.formatOnSave\": true,\n    \"editor.codeActionsOnSave\": {\n      \"source.organizeImports.rome\": \"explicit\"\n    }\n  },\n  \"[javascript]\": {\n    \"editor.defaultFormatter\": \"rome.rome\",\n    \"editor.formatOnSave\": true,\n    \"editor.codeActionsOnSave\": {\n      \"source.organizeImports.rome\": \"explicit\"\n    }\n  }\n}\n"
  },
  {
    "path": ".vscode/tasks.json",
    "content": "{\n  \"version\": \"2.0.0\",\n  \"tasks\": [\n    {\n      \"label\": \"Build\",\n      \"type\": \"shell\",\n      \"command\": \"dotnet\",\n      \"args\": [\n        \"build\"\n      ],\n      \"group\": {\n        \"kind\": \"build\",\n        \"isDefault\": true\n      },\n      \"presentation\": {\n        \"reveal\": \"silent\"\n      },\n      \"problemMatcher\": \"$msCompile\"\n    },\n    {\n      \"label\": \"Test\",\n      \"type\": \"shell\",\n      \"command\": \"dotnet\",\n      \"args\": [\n        \"test\"\n      ],\n      \"group\": \"test\",\n      \"presentation\": {\n        \"reveal\": \"always\",\n        \"panel\": \"new\"\n      },\n      \"problemMatcher\": \"$msCompile\"\n    }\n  ]\n}\n"
  },
  {
    "path": ".yarn/releases/yarn-4.0.1.cjs",
    "content": "#!/usr/bin/env node\n/* eslint-disable */\n//prettier-ignore\n(()=>{var n_e=Object.create;var OR=Object.defineProperty;var i_e=Object.getOwnPropertyDescriptor;var s_e=Object.getOwnPropertyNames;var o_e=Object.getPrototypeOf,a_e=Object.prototype.hasOwnProperty;var Be=(t=>typeof require<\"u\"?require:typeof Proxy<\"u\"?new Proxy(t,{get:(e,r)=>(typeof require<\"u\"?require:e)[r]}):t)(function(t){if(typeof require<\"u\")return require.apply(this,arguments);throw new Error('Dynamic require of \"'+t+'\" is not supported')});var Et=(t,e)=>()=>(t&&(e=t(t=0)),e);var _=(t,e)=>()=>(e||t((e={exports:{}}).exports,e),e.exports),Vt=(t,e)=>{for(var r in e)OR(t,r,{get:e[r],enumerable:!0})},l_e=(t,e,r,o)=>{if(e&&typeof e==\"object\"||typeof e==\"function\")for(let a of s_e(e))!a_e.call(t,a)&&a!==r&&OR(t,a,{get:()=>e[a],enumerable:!(o=i_e(e,a))||o.enumerable});return t};var $e=(t,e,r)=>(r=t!=null?n_e(o_e(t)):{},l_e(e||!t||!t.__esModule?OR(r,\"default\",{value:t,enumerable:!0}):r,t));var vi={};Vt(vi,{SAFE_TIME:()=>R7,S_IFDIR:()=>wD,S_IFLNK:()=>ID,S_IFMT:()=>Ou,S_IFREG:()=>_w});var Ou,wD,_w,ID,R7,T7=Et(()=>{Ou=61440,wD=16384,_w=32768,ID=40960,R7=456789e3});var ar={};Vt(ar,{EBADF:()=>Io,EBUSY:()=>c_e,EEXIST:()=>g_e,EINVAL:()=>A_e,EISDIR:()=>h_e,ENOENT:()=>f_e,ENOSYS:()=>u_e,ENOTDIR:()=>p_e,ENOTEMPTY:()=>m_e,EOPNOTSUPP:()=>y_e,EROFS:()=>d_e,ERR_DIR_CLOSED:()=>MR});function Tl(t,e){return Object.assign(new Error(`${t}: ${e}`),{code:t})}function c_e(t){return Tl(\"EBUSY\",t)}function u_e(t,e){return Tl(\"ENOSYS\",`${t}, ${e}`)}function A_e(t){return Tl(\"EINVAL\",`invalid argument, ${t}`)}function Io(t){return Tl(\"EBADF\",`bad file descriptor, ${t}`)}function f_e(t){return Tl(\"ENOENT\",`no such file or directory, ${t}`)}function p_e(t){return Tl(\"ENOTDIR\",`not a directory, ${t}`)}function h_e(t){return Tl(\"EISDIR\",`illegal operation on a directory, ${t}`)}function g_e(t){return Tl(\"EEXIST\",`file already exists, ${t}`)}function d_e(t){return Tl(\"EROFS\",`read-only filesystem, ${t}`)}function m_e(t){return Tl(\"ENOTEMPTY\",`directory not empty, ${t}`)}function y_e(t){return Tl(\"EOPNOTSUPP\",`operation not supported, ${t}`)}function MR(){return Tl(\"ERR_DIR_CLOSED\",\"Directory handle was closed\")}var BD=Et(()=>{});var Ea={};Vt(Ea,{BigIntStatsEntry:()=>$m,DEFAULT_MODE:()=>HR,DirEntry:()=>UR,StatEntry:()=>Zm,areStatsEqual:()=>jR,clearStats:()=>vD,convertToBigIntStats:()=>C_e,makeDefaultStats:()=>N7,makeEmptyStats:()=>E_e});function N7(){return new Zm}function E_e(){return vD(N7())}function vD(t){for(let e in t)if(Object.hasOwn(t,e)){let r=t[e];typeof r==\"number\"?t[e]=0:typeof r==\"bigint\"?t[e]=BigInt(0):_R.types.isDate(r)&&(t[e]=new Date(0))}return t}function C_e(t){let e=new $m;for(let r in t)if(Object.hasOwn(t,r)){let o=t[r];typeof o==\"number\"?e[r]=BigInt(o):_R.types.isDate(o)&&(e[r]=new Date(o))}return e.atimeNs=e.atimeMs*BigInt(1e6),e.mtimeNs=e.mtimeMs*BigInt(1e6),e.ctimeNs=e.ctimeMs*BigInt(1e6),e.birthtimeNs=e.birthtimeMs*BigInt(1e6),e}function jR(t,e){if(t.atimeMs!==e.atimeMs||t.birthtimeMs!==e.birthtimeMs||t.blksize!==e.blksize||t.blocks!==e.blocks||t.ctimeMs!==e.ctimeMs||t.dev!==e.dev||t.gid!==e.gid||t.ino!==e.ino||t.isBlockDevice()!==e.isBlockDevice()||t.isCharacterDevice()!==e.isCharacterDevice()||t.isDirectory()!==e.isDirectory()||t.isFIFO()!==e.isFIFO()||t.isFile()!==e.isFile()||t.isSocket()!==e.isSocket()||t.isSymbolicLink()!==e.isSymbolicLink()||t.mode!==e.mode||t.mtimeMs!==e.mtimeMs||t.nlink!==e.nlink||t.rdev!==e.rdev||t.size!==e.size||t.uid!==e.uid)return!1;let r=t,o=e;return!(r.atimeNs!==o.atimeNs||r.mtimeNs!==o.mtimeNs||r.ctimeNs!==o.ctimeNs||r.birthtimeNs!==o.birthtimeNs)}var _R,HR,UR,Zm,$m,qR=Et(()=>{_R=$e(Be(\"util\")),HR=33188,UR=class{constructor(){this.name=\"\";this.path=\"\";this.mode=0}isBlockDevice(){return!1}isCharacterDevice(){return!1}isDirectory(){return(this.mode&61440)===16384}isFIFO(){return!1}isFile(){return(this.mode&61440)===32768}isSocket(){return!1}isSymbolicLink(){return(this.mode&61440)===40960}},Zm=class{constructor(){this.uid=0;this.gid=0;this.size=0;this.blksize=0;this.atimeMs=0;this.mtimeMs=0;this.ctimeMs=0;this.birthtimeMs=0;this.atime=new Date(0);this.mtime=new Date(0);this.ctime=new Date(0);this.birthtime=new Date(0);this.dev=0;this.ino=0;this.mode=HR;this.nlink=1;this.rdev=0;this.blocks=1}isBlockDevice(){return!1}isCharacterDevice(){return!1}isDirectory(){return(this.mode&61440)===16384}isFIFO(){return!1}isFile(){return(this.mode&61440)===32768}isSocket(){return!1}isSymbolicLink(){return(this.mode&61440)===40960}},$m=class{constructor(){this.uid=BigInt(0);this.gid=BigInt(0);this.size=BigInt(0);this.blksize=BigInt(0);this.atimeMs=BigInt(0);this.mtimeMs=BigInt(0);this.ctimeMs=BigInt(0);this.birthtimeMs=BigInt(0);this.atimeNs=BigInt(0);this.mtimeNs=BigInt(0);this.ctimeNs=BigInt(0);this.birthtimeNs=BigInt(0);this.atime=new Date(0);this.mtime=new Date(0);this.ctime=new Date(0);this.birthtime=new Date(0);this.dev=BigInt(0);this.ino=BigInt(0);this.mode=BigInt(HR);this.nlink=BigInt(1);this.rdev=BigInt(0);this.blocks=BigInt(1)}isBlockDevice(){return!1}isCharacterDevice(){return!1}isDirectory(){return(this.mode&BigInt(61440))===BigInt(16384)}isFIFO(){return!1}isFile(){return(this.mode&BigInt(61440))===BigInt(32768)}isSocket(){return!1}isSymbolicLink(){return(this.mode&BigInt(61440))===BigInt(40960)}}});function D_e(t){let e,r;if(e=t.match(B_e))t=e[1];else if(r=t.match(v_e))t=`\\\\\\\\${r[1]?\".\\\\\":\"\"}${r[2]}`;else return t;return t.replace(/\\//g,\"\\\\\")}function P_e(t){t=t.replace(/\\\\/g,\"/\");let e,r;return(e=t.match(w_e))?t=`/${e[1]}`:(r=t.match(I_e))&&(t=`/unc/${r[1]?\".dot/\":\"\"}${r[2]}`),t}function DD(t,e){return t===ue?O7(e):GR(e)}var Hw,Bt,dr,ue,V,L7,w_e,I_e,B_e,v_e,GR,O7,Ca=Et(()=>{Hw=$e(Be(\"path\")),Bt={root:\"/\",dot:\".\",parent:\"..\"},dr={home:\"~\",nodeModules:\"node_modules\",manifest:\"package.json\",lockfile:\"yarn.lock\",virtual:\"__virtual__\",pnpJs:\".pnp.js\",pnpCjs:\".pnp.cjs\",pnpData:\".pnp.data.json\",pnpEsmLoader:\".pnp.loader.mjs\",rc:\".yarnrc.yml\",env:\".env\"},ue=Object.create(Hw.default),V=Object.create(Hw.default.posix);ue.cwd=()=>process.cwd();V.cwd=process.platform===\"win32\"?()=>GR(process.cwd()):process.cwd;process.platform===\"win32\"&&(V.resolve=(...t)=>t.length>0&&V.isAbsolute(t[0])?Hw.default.posix.resolve(...t):Hw.default.posix.resolve(V.cwd(),...t));L7=function(t,e,r){return e=t.normalize(e),r=t.normalize(r),e===r?\".\":(e.endsWith(t.sep)||(e=e+t.sep),r.startsWith(e)?r.slice(e.length):null)};ue.contains=(t,e)=>L7(ue,t,e);V.contains=(t,e)=>L7(V,t,e);w_e=/^([a-zA-Z]:.*)$/,I_e=/^\\/\\/(\\.\\/)?(.*)$/,B_e=/^\\/([a-zA-Z]:.*)$/,v_e=/^\\/unc\\/(\\.dot\\/)?(.*)$/;GR=process.platform===\"win32\"?P_e:t=>t,O7=process.platform===\"win32\"?D_e:t=>t;ue.fromPortablePath=O7;ue.toPortablePath=GR});async function PD(t,e){let r=\"0123456789abcdef\";await t.mkdirPromise(e.indexPath,{recursive:!0});let o=[];for(let a of r)for(let n of r)o.push(t.mkdirPromise(t.pathUtils.join(e.indexPath,`${a}${n}`),{recursive:!0}));return await Promise.all(o),e.indexPath}async function M7(t,e,r,o,a){let n=t.pathUtils.normalize(e),u=r.pathUtils.normalize(o),A=[],p=[],{atime:h,mtime:C}=a.stableTime?{atime:Ng,mtime:Ng}:await r.lstatPromise(u);await t.mkdirpPromise(t.pathUtils.dirname(e),{utimes:[h,C]}),await YR(A,p,t,n,r,u,{...a,didParentExist:!0});for(let I of A)await I();await Promise.all(p.map(I=>I()))}async function YR(t,e,r,o,a,n,u){let A=u.didParentExist?await U7(r,o):null,p=await a.lstatPromise(n),{atime:h,mtime:C}=u.stableTime?{atime:Ng,mtime:Ng}:p,I;switch(!0){case p.isDirectory():I=await b_e(t,e,r,o,A,a,n,p,u);break;case p.isFile():I=await Q_e(t,e,r,o,A,a,n,p,u);break;case p.isSymbolicLink():I=await F_e(t,e,r,o,A,a,n,p,u);break;default:throw new Error(`Unsupported file type (${p.mode})`)}return(u.linkStrategy?.type!==\"HardlinkFromIndex\"||!p.isFile())&&((I||A?.mtime?.getTime()!==C.getTime()||A?.atime?.getTime()!==h.getTime())&&(e.push(()=>r.lutimesPromise(o,h,C)),I=!0),(A===null||(A.mode&511)!==(p.mode&511))&&(e.push(()=>r.chmodPromise(o,p.mode&511)),I=!0)),I}async function U7(t,e){try{return await t.lstatPromise(e)}catch{return null}}async function b_e(t,e,r,o,a,n,u,A,p){if(a!==null&&!a.isDirectory())if(p.overwrite)t.push(async()=>r.removePromise(o)),a=null;else return!1;let h=!1;a===null&&(t.push(async()=>{try{await r.mkdirPromise(o,{mode:A.mode})}catch(v){if(v.code!==\"EEXIST\")throw v}}),h=!0);let C=await n.readdirPromise(u),I=p.didParentExist&&!a?{...p,didParentExist:!1}:p;if(p.stableSort)for(let v of C.sort())await YR(t,e,r,r.pathUtils.join(o,v),n,n.pathUtils.join(u,v),I)&&(h=!0);else(await Promise.all(C.map(async x=>{await YR(t,e,r,r.pathUtils.join(o,x),n,n.pathUtils.join(u,x),I)}))).some(x=>x)&&(h=!0);return h}async function x_e(t,e,r,o,a,n,u,A,p,h){let C=await n.checksumFilePromise(u,{algorithm:\"sha1\"}),I=r.pathUtils.join(h.indexPath,C.slice(0,2),`${C}.dat`),v;(te=>(te[te.Lock=0]=\"Lock\",te[te.Rename=1]=\"Rename\"))(v||={});let x=1,E=await U7(r,I);if(a){let U=E&&a.dev===E.dev&&a.ino===E.ino,z=E?.mtimeMs!==S_e;if(U&&z&&h.autoRepair&&(x=0,E=null),!U)if(p.overwrite)t.push(async()=>r.removePromise(o)),a=null;else return!1}let R=!E&&x===1?`${I}.${Math.floor(Math.random()*4294967296).toString(16).padStart(8,\"0\")}`:null,L=!1;return t.push(async()=>{if(!E&&(x===0&&await r.lockPromise(I,async()=>{let U=await n.readFilePromise(u);await r.writeFilePromise(I,U)}),x===1&&R)){let U=await n.readFilePromise(u);await r.writeFilePromise(R,U);try{await r.linkPromise(R,I)}catch(z){if(z.code===\"EEXIST\")L=!0,await r.unlinkPromise(R);else throw z}}a||await r.linkPromise(I,o)}),e.push(async()=>{E||await r.lutimesPromise(I,Ng,Ng),R&&!L&&await r.unlinkPromise(R)}),!1}async function k_e(t,e,r,o,a,n,u,A,p){if(a!==null)if(p.overwrite)t.push(async()=>r.removePromise(o)),a=null;else return!1;return t.push(async()=>{let h=await n.readFilePromise(u);await r.writeFilePromise(o,h)}),!0}async function Q_e(t,e,r,o,a,n,u,A,p){return p.linkStrategy?.type===\"HardlinkFromIndex\"?x_e(t,e,r,o,a,n,u,A,p,p.linkStrategy):k_e(t,e,r,o,a,n,u,A,p)}async function F_e(t,e,r,o,a,n,u,A,p){if(a!==null)if(p.overwrite)t.push(async()=>r.removePromise(o)),a=null;else return!1;return t.push(async()=>{await r.symlinkPromise(DD(r.pathUtils,await n.readlinkPromise(u)),o)}),!0}var Ng,S_e,WR=Et(()=>{Ca();Ng=new Date(456789e3*1e3),S_e=Ng.getTime()});function SD(t,e,r,o){let a=()=>{let n=r.shift();if(typeof n>\"u\")return null;let u=t.pathUtils.join(e,n);return Object.assign(t.statSync(u),{name:n,path:void 0})};return new jw(e,a,o)}var jw,_7=Et(()=>{BD();jw=class{constructor(e,r,o={}){this.path=e;this.nextDirent=r;this.opts=o;this.closed=!1}throwIfClosed(){if(this.closed)throw MR()}async*[Symbol.asyncIterator](){try{let e;for(;(e=await this.read())!==null;)yield e}finally{await this.close()}}read(e){let r=this.readSync();return typeof e<\"u\"?e(null,r):Promise.resolve(r)}readSync(){return this.throwIfClosed(),this.nextDirent()}close(e){return this.closeSync(),typeof e<\"u\"?e(null):Promise.resolve()}closeSync(){this.throwIfClosed(),this.opts.onClose?.(),this.closed=!0}}});function H7(t,e){if(t!==e)throw new Error(`Invalid StatWatcher status: expected '${e}', got '${t}'`)}var j7,ey,q7=Et(()=>{j7=Be(\"events\");qR();ey=class extends j7.EventEmitter{constructor(r,o,{bigint:a=!1}={}){super();this.status=\"ready\";this.changeListeners=new Map;this.startTimeout=null;this.fakeFs=r,this.path=o,this.bigint=a,this.lastStats=this.stat()}static create(r,o,a){let n=new ey(r,o,a);return n.start(),n}start(){H7(this.status,\"ready\"),this.status=\"running\",this.startTimeout=setTimeout(()=>{this.startTimeout=null,this.fakeFs.existsSync(this.path)||this.emit(\"change\",this.lastStats,this.lastStats)},3)}stop(){H7(this.status,\"running\"),this.status=\"stopped\",this.startTimeout!==null&&(clearTimeout(this.startTimeout),this.startTimeout=null),this.emit(\"stop\")}stat(){try{return this.fakeFs.statSync(this.path,{bigint:this.bigint})}catch{let o=this.bigint?new $m:new Zm;return vD(o)}}makeInterval(r){let o=setInterval(()=>{let a=this.stat(),n=this.lastStats;jR(a,n)||(this.lastStats=a,this.emit(\"change\",a,n))},r.interval);return r.persistent?o:o.unref()}registerChangeListener(r,o){this.addListener(\"change\",r),this.changeListeners.set(r,this.makeInterval(o))}unregisterChangeListener(r){this.removeListener(\"change\",r);let o=this.changeListeners.get(r);typeof o<\"u\"&&clearInterval(o),this.changeListeners.delete(r)}unregisterAllChangeListeners(){for(let r of this.changeListeners.keys())this.unregisterChangeListener(r)}hasChangeListeners(){return this.changeListeners.size>0}ref(){for(let r of this.changeListeners.values())r.ref();return this}unref(){for(let r of this.changeListeners.values())r.unref();return this}}});function ty(t,e,r,o){let a,n,u,A;switch(typeof r){case\"function\":a=!1,n=!0,u=5007,A=r;break;default:({bigint:a=!1,persistent:n=!0,interval:u=5007}=r),A=o;break}let p=bD.get(t);typeof p>\"u\"&&bD.set(t,p=new Map);let h=p.get(e);return typeof h>\"u\"&&(h=ey.create(t,e,{bigint:a}),p.set(e,h)),h.registerChangeListener(A,{persistent:n,interval:u}),h}function Lg(t,e,r){let o=bD.get(t);if(typeof o>\"u\")return;let a=o.get(e);typeof a>\"u\"||(typeof r>\"u\"?a.unregisterAllChangeListeners():a.unregisterChangeListener(r),a.hasChangeListeners()||(a.stop(),o.delete(e)))}function Og(t){let e=bD.get(t);if(!(typeof e>\"u\"))for(let r of e.keys())Lg(t,r)}var bD,KR=Et(()=>{q7();bD=new WeakMap});function R_e(t){let e=t.match(/\\r?\\n/g);if(e===null)return Y7.EOL;let r=e.filter(a=>a===`\\r\n`).length,o=e.length-r;return r>o?`\\r\n`:`\n`}function Mg(t,e){return e.replace(/\\r?\\n/g,R_e(t))}var G7,Y7,hf,Mu,Ug=Et(()=>{G7=Be(\"crypto\"),Y7=Be(\"os\");WR();Ca();hf=class{constructor(e){this.pathUtils=e}async*genTraversePromise(e,{stableSort:r=!1}={}){let o=[e];for(;o.length>0;){let a=o.shift();if((await this.lstatPromise(a)).isDirectory()){let u=await this.readdirPromise(a);if(r)for(let A of u.sort())o.push(this.pathUtils.join(a,A));else throw new Error(\"Not supported\")}else yield a}}async checksumFilePromise(e,{algorithm:r=\"sha512\"}={}){let o=await this.openPromise(e,\"r\");try{let n=Buffer.allocUnsafeSlow(65536),u=(0,G7.createHash)(r),A=0;for(;(A=await this.readPromise(o,n,0,65536))!==0;)u.update(A===65536?n:n.slice(0,A));return u.digest(\"hex\")}finally{await this.closePromise(o)}}async removePromise(e,{recursive:r=!0,maxRetries:o=5}={}){let a;try{a=await this.lstatPromise(e)}catch(n){if(n.code===\"ENOENT\")return;throw n}if(a.isDirectory()){if(r){let n=await this.readdirPromise(e);await Promise.all(n.map(u=>this.removePromise(this.pathUtils.resolve(e,u))))}for(let n=0;n<=o;n++)try{await this.rmdirPromise(e);break}catch(u){if(u.code!==\"EBUSY\"&&u.code!==\"ENOTEMPTY\")throw u;n<o&&await new Promise(A=>setTimeout(A,n*100))}}else await this.unlinkPromise(e)}removeSync(e,{recursive:r=!0}={}){let o;try{o=this.lstatSync(e)}catch(a){if(a.code===\"ENOENT\")return;throw a}if(o.isDirectory()){if(r)for(let a of this.readdirSync(e))this.removeSync(this.pathUtils.resolve(e,a));this.rmdirSync(e)}else this.unlinkSync(e)}async mkdirpPromise(e,{chmod:r,utimes:o}={}){if(e=this.resolve(e),e===this.pathUtils.dirname(e))return;let a=e.split(this.pathUtils.sep),n;for(let u=2;u<=a.length;++u){let A=a.slice(0,u).join(this.pathUtils.sep);if(!this.existsSync(A)){try{await this.mkdirPromise(A)}catch(p){if(p.code===\"EEXIST\")continue;throw p}if(n??=A,r!=null&&await this.chmodPromise(A,r),o!=null)await this.utimesPromise(A,o[0],o[1]);else{let p=await this.statPromise(this.pathUtils.dirname(A));await this.utimesPromise(A,p.atime,p.mtime)}}}return n}mkdirpSync(e,{chmod:r,utimes:o}={}){if(e=this.resolve(e),e===this.pathUtils.dirname(e))return;let a=e.split(this.pathUtils.sep),n;for(let u=2;u<=a.length;++u){let A=a.slice(0,u).join(this.pathUtils.sep);if(!this.existsSync(A)){try{this.mkdirSync(A)}catch(p){if(p.code===\"EEXIST\")continue;throw p}if(n??=A,r!=null&&this.chmodSync(A,r),o!=null)this.utimesSync(A,o[0],o[1]);else{let p=this.statSync(this.pathUtils.dirname(A));this.utimesSync(A,p.atime,p.mtime)}}}return n}async copyPromise(e,r,{baseFs:o=this,overwrite:a=!0,stableSort:n=!1,stableTime:u=!1,linkStrategy:A=null}={}){return await M7(this,e,o,r,{overwrite:a,stableSort:n,stableTime:u,linkStrategy:A})}copySync(e,r,{baseFs:o=this,overwrite:a=!0}={}){let n=o.lstatSync(r),u=this.existsSync(e);if(n.isDirectory()){this.mkdirpSync(e);let p=o.readdirSync(r);for(let h of p)this.copySync(this.pathUtils.join(e,h),o.pathUtils.join(r,h),{baseFs:o,overwrite:a})}else if(n.isFile()){if(!u||a){u&&this.removeSync(e);let p=o.readFileSync(r);this.writeFileSync(e,p)}}else if(n.isSymbolicLink()){if(!u||a){u&&this.removeSync(e);let p=o.readlinkSync(r);this.symlinkSync(DD(this.pathUtils,p),e)}}else throw new Error(`Unsupported file type (file: ${r}, mode: 0o${n.mode.toString(8).padStart(6,\"0\")})`);let A=n.mode&511;this.chmodSync(e,A)}async changeFilePromise(e,r,o={}){return Buffer.isBuffer(r)?this.changeFileBufferPromise(e,r,o):this.changeFileTextPromise(e,r,o)}async changeFileBufferPromise(e,r,{mode:o}={}){let a=Buffer.alloc(0);try{a=await this.readFilePromise(e)}catch{}Buffer.compare(a,r)!==0&&await this.writeFilePromise(e,r,{mode:o})}async changeFileTextPromise(e,r,{automaticNewlines:o,mode:a}={}){let n=\"\";try{n=await this.readFilePromise(e,\"utf8\")}catch{}let u=o?Mg(n,r):r;n!==u&&await this.writeFilePromise(e,u,{mode:a})}changeFileSync(e,r,o={}){return Buffer.isBuffer(r)?this.changeFileBufferSync(e,r,o):this.changeFileTextSync(e,r,o)}changeFileBufferSync(e,r,{mode:o}={}){let a=Buffer.alloc(0);try{a=this.readFileSync(e)}catch{}Buffer.compare(a,r)!==0&&this.writeFileSync(e,r,{mode:o})}changeFileTextSync(e,r,{automaticNewlines:o=!1,mode:a}={}){let n=\"\";try{n=this.readFileSync(e,\"utf8\")}catch{}let u=o?Mg(n,r):r;n!==u&&this.writeFileSync(e,u,{mode:a})}async movePromise(e,r){try{await this.renamePromise(e,r)}catch(o){if(o.code===\"EXDEV\")await this.copyPromise(r,e),await this.removePromise(e);else throw o}}moveSync(e,r){try{this.renameSync(e,r)}catch(o){if(o.code===\"EXDEV\")this.copySync(r,e),this.removeSync(e);else throw o}}async lockPromise(e,r){let o=`${e}.flock`,a=1e3/60,n=Date.now(),u=null,A=async()=>{let p;try{[p]=await this.readJsonPromise(o)}catch{return Date.now()-n<500}try{return process.kill(p,0),!0}catch{return!1}};for(;u===null;)try{u=await this.openPromise(o,\"wx\")}catch(p){if(p.code===\"EEXIST\"){if(!await A())try{await this.unlinkPromise(o);continue}catch{}if(Date.now()-n<60*1e3)await new Promise(h=>setTimeout(h,a));else throw new Error(`Couldn't acquire a lock in a reasonable time (via ${o})`)}else throw p}await this.writePromise(u,JSON.stringify([process.pid]));try{return await r()}finally{try{await this.closePromise(u),await this.unlinkPromise(o)}catch{}}}async readJsonPromise(e){let r=await this.readFilePromise(e,\"utf8\");try{return JSON.parse(r)}catch(o){throw o.message+=` (in ${e})`,o}}readJsonSync(e){let r=this.readFileSync(e,\"utf8\");try{return JSON.parse(r)}catch(o){throw o.message+=` (in ${e})`,o}}async writeJsonPromise(e,r,{compact:o=!1}={}){let a=o?0:2;return await this.writeFilePromise(e,`${JSON.stringify(r,null,a)}\n`)}writeJsonSync(e,r,{compact:o=!1}={}){let a=o?0:2;return this.writeFileSync(e,`${JSON.stringify(r,null,a)}\n`)}async preserveTimePromise(e,r){let o=await this.lstatPromise(e),a=await r();typeof a<\"u\"&&(e=a),await this.lutimesPromise(e,o.atime,o.mtime)}async preserveTimeSync(e,r){let o=this.lstatSync(e),a=r();typeof a<\"u\"&&(e=a),this.lutimesSync(e,o.atime,o.mtime)}},Mu=class extends hf{constructor(){super(V)}}});var Ps,gf=Et(()=>{Ug();Ps=class extends hf{getExtractHint(e){return this.baseFs.getExtractHint(e)}resolve(e){return this.mapFromBase(this.baseFs.resolve(this.mapToBase(e)))}getRealPath(){return this.mapFromBase(this.baseFs.getRealPath())}async openPromise(e,r,o){return this.baseFs.openPromise(this.mapToBase(e),r,o)}openSync(e,r,o){return this.baseFs.openSync(this.mapToBase(e),r,o)}async opendirPromise(e,r){return Object.assign(await this.baseFs.opendirPromise(this.mapToBase(e),r),{path:e})}opendirSync(e,r){return Object.assign(this.baseFs.opendirSync(this.mapToBase(e),r),{path:e})}async readPromise(e,r,o,a,n){return await this.baseFs.readPromise(e,r,o,a,n)}readSync(e,r,o,a,n){return this.baseFs.readSync(e,r,o,a,n)}async writePromise(e,r,o,a,n){return typeof r==\"string\"?await this.baseFs.writePromise(e,r,o):await this.baseFs.writePromise(e,r,o,a,n)}writeSync(e,r,o,a,n){return typeof r==\"string\"?this.baseFs.writeSync(e,r,o):this.baseFs.writeSync(e,r,o,a,n)}async closePromise(e){return this.baseFs.closePromise(e)}closeSync(e){this.baseFs.closeSync(e)}createReadStream(e,r){return this.baseFs.createReadStream(e!==null?this.mapToBase(e):e,r)}createWriteStream(e,r){return this.baseFs.createWriteStream(e!==null?this.mapToBase(e):e,r)}async realpathPromise(e){return this.mapFromBase(await this.baseFs.realpathPromise(this.mapToBase(e)))}realpathSync(e){return this.mapFromBase(this.baseFs.realpathSync(this.mapToBase(e)))}async existsPromise(e){return this.baseFs.existsPromise(this.mapToBase(e))}existsSync(e){return this.baseFs.existsSync(this.mapToBase(e))}accessSync(e,r){return this.baseFs.accessSync(this.mapToBase(e),r)}async accessPromise(e,r){return this.baseFs.accessPromise(this.mapToBase(e),r)}async statPromise(e,r){return this.baseFs.statPromise(this.mapToBase(e),r)}statSync(e,r){return this.baseFs.statSync(this.mapToBase(e),r)}async fstatPromise(e,r){return this.baseFs.fstatPromise(e,r)}fstatSync(e,r){return this.baseFs.fstatSync(e,r)}lstatPromise(e,r){return this.baseFs.lstatPromise(this.mapToBase(e),r)}lstatSync(e,r){return this.baseFs.lstatSync(this.mapToBase(e),r)}async fchmodPromise(e,r){return this.baseFs.fchmodPromise(e,r)}fchmodSync(e,r){return this.baseFs.fchmodSync(e,r)}async chmodPromise(e,r){return this.baseFs.chmodPromise(this.mapToBase(e),r)}chmodSync(e,r){return this.baseFs.chmodSync(this.mapToBase(e),r)}async fchownPromise(e,r,o){return this.baseFs.fchownPromise(e,r,o)}fchownSync(e,r,o){return this.baseFs.fchownSync(e,r,o)}async chownPromise(e,r,o){return this.baseFs.chownPromise(this.mapToBase(e),r,o)}chownSync(e,r,o){return this.baseFs.chownSync(this.mapToBase(e),r,o)}async renamePromise(e,r){return this.baseFs.renamePromise(this.mapToBase(e),this.mapToBase(r))}renameSync(e,r){return this.baseFs.renameSync(this.mapToBase(e),this.mapToBase(r))}async copyFilePromise(e,r,o=0){return this.baseFs.copyFilePromise(this.mapToBase(e),this.mapToBase(r),o)}copyFileSync(e,r,o=0){return this.baseFs.copyFileSync(this.mapToBase(e),this.mapToBase(r),o)}async appendFilePromise(e,r,o){return this.baseFs.appendFilePromise(this.fsMapToBase(e),r,o)}appendFileSync(e,r,o){return this.baseFs.appendFileSync(this.fsMapToBase(e),r,o)}async writeFilePromise(e,r,o){return this.baseFs.writeFilePromise(this.fsMapToBase(e),r,o)}writeFileSync(e,r,o){return this.baseFs.writeFileSync(this.fsMapToBase(e),r,o)}async unlinkPromise(e){return this.baseFs.unlinkPromise(this.mapToBase(e))}unlinkSync(e){return this.baseFs.unlinkSync(this.mapToBase(e))}async utimesPromise(e,r,o){return this.baseFs.utimesPromise(this.mapToBase(e),r,o)}utimesSync(e,r,o){return this.baseFs.utimesSync(this.mapToBase(e),r,o)}async lutimesPromise(e,r,o){return this.baseFs.lutimesPromise(this.mapToBase(e),r,o)}lutimesSync(e,r,o){return this.baseFs.lutimesSync(this.mapToBase(e),r,o)}async mkdirPromise(e,r){return this.baseFs.mkdirPromise(this.mapToBase(e),r)}mkdirSync(e,r){return this.baseFs.mkdirSync(this.mapToBase(e),r)}async rmdirPromise(e,r){return this.baseFs.rmdirPromise(this.mapToBase(e),r)}rmdirSync(e,r){return this.baseFs.rmdirSync(this.mapToBase(e),r)}async linkPromise(e,r){return this.baseFs.linkPromise(this.mapToBase(e),this.mapToBase(r))}linkSync(e,r){return this.baseFs.linkSync(this.mapToBase(e),this.mapToBase(r))}async symlinkPromise(e,r,o){let a=this.mapToBase(r);if(this.pathUtils.isAbsolute(e))return this.baseFs.symlinkPromise(this.mapToBase(e),a,o);let n=this.mapToBase(this.pathUtils.join(this.pathUtils.dirname(r),e)),u=this.baseFs.pathUtils.relative(this.baseFs.pathUtils.dirname(a),n);return this.baseFs.symlinkPromise(u,a,o)}symlinkSync(e,r,o){let a=this.mapToBase(r);if(this.pathUtils.isAbsolute(e))return this.baseFs.symlinkSync(this.mapToBase(e),a,o);let n=this.mapToBase(this.pathUtils.join(this.pathUtils.dirname(r),e)),u=this.baseFs.pathUtils.relative(this.baseFs.pathUtils.dirname(a),n);return this.baseFs.symlinkSync(u,a,o)}async readFilePromise(e,r){return this.baseFs.readFilePromise(this.fsMapToBase(e),r)}readFileSync(e,r){return this.baseFs.readFileSync(this.fsMapToBase(e),r)}readdirPromise(e,r){return this.baseFs.readdirPromise(this.mapToBase(e),r)}readdirSync(e,r){return this.baseFs.readdirSync(this.mapToBase(e),r)}async readlinkPromise(e){return this.mapFromBase(await this.baseFs.readlinkPromise(this.mapToBase(e)))}readlinkSync(e){return this.mapFromBase(this.baseFs.readlinkSync(this.mapToBase(e)))}async truncatePromise(e,r){return this.baseFs.truncatePromise(this.mapToBase(e),r)}truncateSync(e,r){return this.baseFs.truncateSync(this.mapToBase(e),r)}async ftruncatePromise(e,r){return this.baseFs.ftruncatePromise(e,r)}ftruncateSync(e,r){return this.baseFs.ftruncateSync(e,r)}watch(e,r,o){return this.baseFs.watch(this.mapToBase(e),r,o)}watchFile(e,r,o){return this.baseFs.watchFile(this.mapToBase(e),r,o)}unwatchFile(e,r){return this.baseFs.unwatchFile(this.mapToBase(e),r)}fsMapToBase(e){return typeof e==\"number\"?e:this.mapToBase(e)}}});var Uu,W7=Et(()=>{gf();Uu=class extends Ps{constructor(r,{baseFs:o,pathUtils:a}){super(a);this.target=r,this.baseFs=o}getRealPath(){return this.target}getBaseFs(){return this.baseFs}mapFromBase(r){return r}mapToBase(r){return r}}});function K7(t){let e=t;return typeof t.path==\"string\"&&(e.path=ue.toPortablePath(t.path)),e}var V7,Tn,_g=Et(()=>{V7=$e(Be(\"fs\"));Ug();Ca();Tn=class extends Mu{constructor(r=V7.default){super();this.realFs=r}getExtractHint(){return!1}getRealPath(){return Bt.root}resolve(r){return V.resolve(r)}async openPromise(r,o,a){return await new Promise((n,u)=>{this.realFs.open(ue.fromPortablePath(r),o,a,this.makeCallback(n,u))})}openSync(r,o,a){return this.realFs.openSync(ue.fromPortablePath(r),o,a)}async opendirPromise(r,o){return await new Promise((a,n)=>{typeof o<\"u\"?this.realFs.opendir(ue.fromPortablePath(r),o,this.makeCallback(a,n)):this.realFs.opendir(ue.fromPortablePath(r),this.makeCallback(a,n))}).then(a=>{let n=a;return Object.defineProperty(n,\"path\",{value:r,configurable:!0,writable:!0}),n})}opendirSync(r,o){let n=typeof o<\"u\"?this.realFs.opendirSync(ue.fromPortablePath(r),o):this.realFs.opendirSync(ue.fromPortablePath(r));return Object.defineProperty(n,\"path\",{value:r,configurable:!0,writable:!0}),n}async readPromise(r,o,a=0,n=0,u=-1){return await new Promise((A,p)=>{this.realFs.read(r,o,a,n,u,(h,C)=>{h?p(h):A(C)})})}readSync(r,o,a,n,u){return this.realFs.readSync(r,o,a,n,u)}async writePromise(r,o,a,n,u){return await new Promise((A,p)=>typeof o==\"string\"?this.realFs.write(r,o,a,this.makeCallback(A,p)):this.realFs.write(r,o,a,n,u,this.makeCallback(A,p)))}writeSync(r,o,a,n,u){return typeof o==\"string\"?this.realFs.writeSync(r,o,a):this.realFs.writeSync(r,o,a,n,u)}async closePromise(r){await new Promise((o,a)=>{this.realFs.close(r,this.makeCallback(o,a))})}closeSync(r){this.realFs.closeSync(r)}createReadStream(r,o){let a=r!==null?ue.fromPortablePath(r):r;return this.realFs.createReadStream(a,o)}createWriteStream(r,o){let a=r!==null?ue.fromPortablePath(r):r;return this.realFs.createWriteStream(a,o)}async realpathPromise(r){return await new Promise((o,a)=>{this.realFs.realpath(ue.fromPortablePath(r),{},this.makeCallback(o,a))}).then(o=>ue.toPortablePath(o))}realpathSync(r){return ue.toPortablePath(this.realFs.realpathSync(ue.fromPortablePath(r),{}))}async existsPromise(r){return await new Promise(o=>{this.realFs.exists(ue.fromPortablePath(r),o)})}accessSync(r,o){return this.realFs.accessSync(ue.fromPortablePath(r),o)}async accessPromise(r,o){return await new Promise((a,n)=>{this.realFs.access(ue.fromPortablePath(r),o,this.makeCallback(a,n))})}existsSync(r){return this.realFs.existsSync(ue.fromPortablePath(r))}async statPromise(r,o){return await new Promise((a,n)=>{o?this.realFs.stat(ue.fromPortablePath(r),o,this.makeCallback(a,n)):this.realFs.stat(ue.fromPortablePath(r),this.makeCallback(a,n))})}statSync(r,o){return o?this.realFs.statSync(ue.fromPortablePath(r),o):this.realFs.statSync(ue.fromPortablePath(r))}async fstatPromise(r,o){return await new Promise((a,n)=>{o?this.realFs.fstat(r,o,this.makeCallback(a,n)):this.realFs.fstat(r,this.makeCallback(a,n))})}fstatSync(r,o){return o?this.realFs.fstatSync(r,o):this.realFs.fstatSync(r)}async lstatPromise(r,o){return await new Promise((a,n)=>{o?this.realFs.lstat(ue.fromPortablePath(r),o,this.makeCallback(a,n)):this.realFs.lstat(ue.fromPortablePath(r),this.makeCallback(a,n))})}lstatSync(r,o){return o?this.realFs.lstatSync(ue.fromPortablePath(r),o):this.realFs.lstatSync(ue.fromPortablePath(r))}async fchmodPromise(r,o){return await new Promise((a,n)=>{this.realFs.fchmod(r,o,this.makeCallback(a,n))})}fchmodSync(r,o){return this.realFs.fchmodSync(r,o)}async chmodPromise(r,o){return await new Promise((a,n)=>{this.realFs.chmod(ue.fromPortablePath(r),o,this.makeCallback(a,n))})}chmodSync(r,o){return this.realFs.chmodSync(ue.fromPortablePath(r),o)}async fchownPromise(r,o,a){return await new Promise((n,u)=>{this.realFs.fchown(r,o,a,this.makeCallback(n,u))})}fchownSync(r,o,a){return this.realFs.fchownSync(r,o,a)}async chownPromise(r,o,a){return await new Promise((n,u)=>{this.realFs.chown(ue.fromPortablePath(r),o,a,this.makeCallback(n,u))})}chownSync(r,o,a){return this.realFs.chownSync(ue.fromPortablePath(r),o,a)}async renamePromise(r,o){return await new Promise((a,n)=>{this.realFs.rename(ue.fromPortablePath(r),ue.fromPortablePath(o),this.makeCallback(a,n))})}renameSync(r,o){return this.realFs.renameSync(ue.fromPortablePath(r),ue.fromPortablePath(o))}async copyFilePromise(r,o,a=0){return await new Promise((n,u)=>{this.realFs.copyFile(ue.fromPortablePath(r),ue.fromPortablePath(o),a,this.makeCallback(n,u))})}copyFileSync(r,o,a=0){return this.realFs.copyFileSync(ue.fromPortablePath(r),ue.fromPortablePath(o),a)}async appendFilePromise(r,o,a){return await new Promise((n,u)=>{let A=typeof r==\"string\"?ue.fromPortablePath(r):r;a?this.realFs.appendFile(A,o,a,this.makeCallback(n,u)):this.realFs.appendFile(A,o,this.makeCallback(n,u))})}appendFileSync(r,o,a){let n=typeof r==\"string\"?ue.fromPortablePath(r):r;a?this.realFs.appendFileSync(n,o,a):this.realFs.appendFileSync(n,o)}async writeFilePromise(r,o,a){return await new Promise((n,u)=>{let A=typeof r==\"string\"?ue.fromPortablePath(r):r;a?this.realFs.writeFile(A,o,a,this.makeCallback(n,u)):this.realFs.writeFile(A,o,this.makeCallback(n,u))})}writeFileSync(r,o,a){let n=typeof r==\"string\"?ue.fromPortablePath(r):r;a?this.realFs.writeFileSync(n,o,a):this.realFs.writeFileSync(n,o)}async unlinkPromise(r){return await new Promise((o,a)=>{this.realFs.unlink(ue.fromPortablePath(r),this.makeCallback(o,a))})}unlinkSync(r){return this.realFs.unlinkSync(ue.fromPortablePath(r))}async utimesPromise(r,o,a){return await new Promise((n,u)=>{this.realFs.utimes(ue.fromPortablePath(r),o,a,this.makeCallback(n,u))})}utimesSync(r,o,a){this.realFs.utimesSync(ue.fromPortablePath(r),o,a)}async lutimesPromise(r,o,a){return await new Promise((n,u)=>{this.realFs.lutimes(ue.fromPortablePath(r),o,a,this.makeCallback(n,u))})}lutimesSync(r,o,a){this.realFs.lutimesSync(ue.fromPortablePath(r),o,a)}async mkdirPromise(r,o){return await new Promise((a,n)=>{this.realFs.mkdir(ue.fromPortablePath(r),o,this.makeCallback(a,n))})}mkdirSync(r,o){return this.realFs.mkdirSync(ue.fromPortablePath(r),o)}async rmdirPromise(r,o){return await new Promise((a,n)=>{o?this.realFs.rmdir(ue.fromPortablePath(r),o,this.makeCallback(a,n)):this.realFs.rmdir(ue.fromPortablePath(r),this.makeCallback(a,n))})}rmdirSync(r,o){return this.realFs.rmdirSync(ue.fromPortablePath(r),o)}async linkPromise(r,o){return await new Promise((a,n)=>{this.realFs.link(ue.fromPortablePath(r),ue.fromPortablePath(o),this.makeCallback(a,n))})}linkSync(r,o){return this.realFs.linkSync(ue.fromPortablePath(r),ue.fromPortablePath(o))}async symlinkPromise(r,o,a){return await new Promise((n,u)=>{this.realFs.symlink(ue.fromPortablePath(r.replace(/\\/+$/,\"\")),ue.fromPortablePath(o),a,this.makeCallback(n,u))})}symlinkSync(r,o,a){return this.realFs.symlinkSync(ue.fromPortablePath(r.replace(/\\/+$/,\"\")),ue.fromPortablePath(o),a)}async readFilePromise(r,o){return await new Promise((a,n)=>{let u=typeof r==\"string\"?ue.fromPortablePath(r):r;this.realFs.readFile(u,o,this.makeCallback(a,n))})}readFileSync(r,o){let a=typeof r==\"string\"?ue.fromPortablePath(r):r;return this.realFs.readFileSync(a,o)}async readdirPromise(r,o){return await new Promise((a,n)=>{o?o.recursive&&process.platform===\"win32\"?o.withFileTypes?this.realFs.readdir(ue.fromPortablePath(r),o,this.makeCallback(u=>a(u.map(K7)),n)):this.realFs.readdir(ue.fromPortablePath(r),o,this.makeCallback(u=>a(u.map(ue.toPortablePath)),n)):this.realFs.readdir(ue.fromPortablePath(r),o,this.makeCallback(a,n)):this.realFs.readdir(ue.fromPortablePath(r),this.makeCallback(a,n))})}readdirSync(r,o){return o?o.recursive&&process.platform===\"win32\"?o.withFileTypes?this.realFs.readdirSync(ue.fromPortablePath(r),o).map(K7):this.realFs.readdirSync(ue.fromPortablePath(r),o).map(ue.toPortablePath):this.realFs.readdirSync(ue.fromPortablePath(r),o):this.realFs.readdirSync(ue.fromPortablePath(r))}async readlinkPromise(r){return await new Promise((o,a)=>{this.realFs.readlink(ue.fromPortablePath(r),this.makeCallback(o,a))}).then(o=>ue.toPortablePath(o))}readlinkSync(r){return ue.toPortablePath(this.realFs.readlinkSync(ue.fromPortablePath(r)))}async truncatePromise(r,o){return await new Promise((a,n)=>{this.realFs.truncate(ue.fromPortablePath(r),o,this.makeCallback(a,n))})}truncateSync(r,o){return this.realFs.truncateSync(ue.fromPortablePath(r),o)}async ftruncatePromise(r,o){return await new Promise((a,n)=>{this.realFs.ftruncate(r,o,this.makeCallback(a,n))})}ftruncateSync(r,o){return this.realFs.ftruncateSync(r,o)}watch(r,o,a){return this.realFs.watch(ue.fromPortablePath(r),o,a)}watchFile(r,o,a){return this.realFs.watchFile(ue.fromPortablePath(r),o,a)}unwatchFile(r,o){return this.realFs.unwatchFile(ue.fromPortablePath(r),o)}makeCallback(r,o){return(a,n)=>{a?o(a):r(n)}}}});var gn,z7=Et(()=>{_g();gf();Ca();gn=class extends Ps{constructor(r,{baseFs:o=new Tn}={}){super(V);this.target=this.pathUtils.normalize(r),this.baseFs=o}getRealPath(){return this.pathUtils.resolve(this.baseFs.getRealPath(),this.target)}resolve(r){return this.pathUtils.isAbsolute(r)?V.normalize(r):this.baseFs.resolve(V.join(this.target,r))}mapFromBase(r){return r}mapToBase(r){return this.pathUtils.isAbsolute(r)?r:this.pathUtils.join(this.target,r)}}});var J7,_u,X7=Et(()=>{_g();gf();Ca();J7=Bt.root,_u=class extends Ps{constructor(r,{baseFs:o=new Tn}={}){super(V);this.target=this.pathUtils.resolve(Bt.root,r),this.baseFs=o}getRealPath(){return this.pathUtils.resolve(this.baseFs.getRealPath(),this.pathUtils.relative(Bt.root,this.target))}getTarget(){return this.target}getBaseFs(){return this.baseFs}mapToBase(r){let o=this.pathUtils.normalize(r);if(this.pathUtils.isAbsolute(r))return this.pathUtils.resolve(this.target,this.pathUtils.relative(J7,r));if(o.match(/^\\.\\.\\/?/))throw new Error(`Resolving this path (${r}) would escape the jail`);return this.pathUtils.resolve(this.target,r)}mapFromBase(r){return this.pathUtils.resolve(J7,this.pathUtils.relative(this.target,r))}}});var ry,Z7=Et(()=>{gf();ry=class extends Ps{constructor(r,o){super(o);this.instance=null;this.factory=r}get baseFs(){return this.instance||(this.instance=this.factory()),this.instance}set baseFs(r){this.instance=r}mapFromBase(r){return r}mapToBase(r){return r}}});var Hg,wa,Up,$7=Et(()=>{Hg=Be(\"fs\");Ug();_g();KR();BD();Ca();wa=4278190080,Up=class extends Mu{constructor({baseFs:r=new Tn,filter:o=null,magicByte:a=42,maxOpenFiles:n=1/0,useCache:u=!0,maxAge:A=5e3,typeCheck:p=Hg.constants.S_IFREG,getMountPoint:h,factoryPromise:C,factorySync:I}){if(Math.floor(a)!==a||!(a>1&&a<=127))throw new Error(\"The magic byte must be set to a round value between 1 and 127 included\");super();this.fdMap=new Map;this.nextFd=3;this.isMount=new Set;this.notMount=new Set;this.realPaths=new Map;this.limitOpenFilesTimeout=null;this.baseFs=r,this.mountInstances=u?new Map:null,this.factoryPromise=C,this.factorySync=I,this.filter=o,this.getMountPoint=h,this.magic=a<<24,this.maxAge=A,this.maxOpenFiles=n,this.typeCheck=p}getExtractHint(r){return this.baseFs.getExtractHint(r)}getRealPath(){return this.baseFs.getRealPath()}saveAndClose(){if(Og(this),this.mountInstances)for(let[r,{childFs:o}]of this.mountInstances.entries())o.saveAndClose?.(),this.mountInstances.delete(r)}discardAndClose(){if(Og(this),this.mountInstances)for(let[r,{childFs:o}]of this.mountInstances.entries())o.discardAndClose?.(),this.mountInstances.delete(r)}resolve(r){return this.baseFs.resolve(r)}remapFd(r,o){let a=this.nextFd++|this.magic;return this.fdMap.set(a,[r,o]),a}async openPromise(r,o,a){return await this.makeCallPromise(r,async()=>await this.baseFs.openPromise(r,o,a),async(n,{subPath:u})=>this.remapFd(n,await n.openPromise(u,o,a)))}openSync(r,o,a){return this.makeCallSync(r,()=>this.baseFs.openSync(r,o,a),(n,{subPath:u})=>this.remapFd(n,n.openSync(u,o,a)))}async opendirPromise(r,o){return await this.makeCallPromise(r,async()=>await this.baseFs.opendirPromise(r,o),async(a,{subPath:n})=>await a.opendirPromise(n,o),{requireSubpath:!1})}opendirSync(r,o){return this.makeCallSync(r,()=>this.baseFs.opendirSync(r,o),(a,{subPath:n})=>a.opendirSync(n,o),{requireSubpath:!1})}async readPromise(r,o,a,n,u){if((r&wa)!==this.magic)return await this.baseFs.readPromise(r,o,a,n,u);let A=this.fdMap.get(r);if(typeof A>\"u\")throw Io(\"read\");let[p,h]=A;return await p.readPromise(h,o,a,n,u)}readSync(r,o,a,n,u){if((r&wa)!==this.magic)return this.baseFs.readSync(r,o,a,n,u);let A=this.fdMap.get(r);if(typeof A>\"u\")throw Io(\"readSync\");let[p,h]=A;return p.readSync(h,o,a,n,u)}async writePromise(r,o,a,n,u){if((r&wa)!==this.magic)return typeof o==\"string\"?await this.baseFs.writePromise(r,o,a):await this.baseFs.writePromise(r,o,a,n,u);let A=this.fdMap.get(r);if(typeof A>\"u\")throw Io(\"write\");let[p,h]=A;return typeof o==\"string\"?await p.writePromise(h,o,a):await p.writePromise(h,o,a,n,u)}writeSync(r,o,a,n,u){if((r&wa)!==this.magic)return typeof o==\"string\"?this.baseFs.writeSync(r,o,a):this.baseFs.writeSync(r,o,a,n,u);let A=this.fdMap.get(r);if(typeof A>\"u\")throw Io(\"writeSync\");let[p,h]=A;return typeof o==\"string\"?p.writeSync(h,o,a):p.writeSync(h,o,a,n,u)}async closePromise(r){if((r&wa)!==this.magic)return await this.baseFs.closePromise(r);let o=this.fdMap.get(r);if(typeof o>\"u\")throw Io(\"close\");this.fdMap.delete(r);let[a,n]=o;return await a.closePromise(n)}closeSync(r){if((r&wa)!==this.magic)return this.baseFs.closeSync(r);let o=this.fdMap.get(r);if(typeof o>\"u\")throw Io(\"closeSync\");this.fdMap.delete(r);let[a,n]=o;return a.closeSync(n)}createReadStream(r,o){return r===null?this.baseFs.createReadStream(r,o):this.makeCallSync(r,()=>this.baseFs.createReadStream(r,o),(a,{archivePath:n,subPath:u})=>{let A=a.createReadStream(u,o);return A.path=ue.fromPortablePath(this.pathUtils.join(n,u)),A})}createWriteStream(r,o){return r===null?this.baseFs.createWriteStream(r,o):this.makeCallSync(r,()=>this.baseFs.createWriteStream(r,o),(a,{subPath:n})=>a.createWriteStream(n,o))}async realpathPromise(r){return await this.makeCallPromise(r,async()=>await this.baseFs.realpathPromise(r),async(o,{archivePath:a,subPath:n})=>{let u=this.realPaths.get(a);return typeof u>\"u\"&&(u=await this.baseFs.realpathPromise(a),this.realPaths.set(a,u)),this.pathUtils.join(u,this.pathUtils.relative(Bt.root,await o.realpathPromise(n)))})}realpathSync(r){return this.makeCallSync(r,()=>this.baseFs.realpathSync(r),(o,{archivePath:a,subPath:n})=>{let u=this.realPaths.get(a);return typeof u>\"u\"&&(u=this.baseFs.realpathSync(a),this.realPaths.set(a,u)),this.pathUtils.join(u,this.pathUtils.relative(Bt.root,o.realpathSync(n)))})}async existsPromise(r){return await this.makeCallPromise(r,async()=>await this.baseFs.existsPromise(r),async(o,{subPath:a})=>await o.existsPromise(a))}existsSync(r){return this.makeCallSync(r,()=>this.baseFs.existsSync(r),(o,{subPath:a})=>o.existsSync(a))}async accessPromise(r,o){return await this.makeCallPromise(r,async()=>await this.baseFs.accessPromise(r,o),async(a,{subPath:n})=>await a.accessPromise(n,o))}accessSync(r,o){return this.makeCallSync(r,()=>this.baseFs.accessSync(r,o),(a,{subPath:n})=>a.accessSync(n,o))}async statPromise(r,o){return await this.makeCallPromise(r,async()=>await this.baseFs.statPromise(r,o),async(a,{subPath:n})=>await a.statPromise(n,o))}statSync(r,o){return this.makeCallSync(r,()=>this.baseFs.statSync(r,o),(a,{subPath:n})=>a.statSync(n,o))}async fstatPromise(r,o){if((r&wa)!==this.magic)return this.baseFs.fstatPromise(r,o);let a=this.fdMap.get(r);if(typeof a>\"u\")throw Io(\"fstat\");let[n,u]=a;return n.fstatPromise(u,o)}fstatSync(r,o){if((r&wa)!==this.magic)return this.baseFs.fstatSync(r,o);let a=this.fdMap.get(r);if(typeof a>\"u\")throw Io(\"fstatSync\");let[n,u]=a;return n.fstatSync(u,o)}async lstatPromise(r,o){return await this.makeCallPromise(r,async()=>await this.baseFs.lstatPromise(r,o),async(a,{subPath:n})=>await a.lstatPromise(n,o))}lstatSync(r,o){return this.makeCallSync(r,()=>this.baseFs.lstatSync(r,o),(a,{subPath:n})=>a.lstatSync(n,o))}async fchmodPromise(r,o){if((r&wa)!==this.magic)return this.baseFs.fchmodPromise(r,o);let a=this.fdMap.get(r);if(typeof a>\"u\")throw Io(\"fchmod\");let[n,u]=a;return n.fchmodPromise(u,o)}fchmodSync(r,o){if((r&wa)!==this.magic)return this.baseFs.fchmodSync(r,o);let a=this.fdMap.get(r);if(typeof a>\"u\")throw Io(\"fchmodSync\");let[n,u]=a;return n.fchmodSync(u,o)}async chmodPromise(r,o){return await this.makeCallPromise(r,async()=>await this.baseFs.chmodPromise(r,o),async(a,{subPath:n})=>await a.chmodPromise(n,o))}chmodSync(r,o){return this.makeCallSync(r,()=>this.baseFs.chmodSync(r,o),(a,{subPath:n})=>a.chmodSync(n,o))}async fchownPromise(r,o,a){if((r&wa)!==this.magic)return this.baseFs.fchownPromise(r,o,a);let n=this.fdMap.get(r);if(typeof n>\"u\")throw Io(\"fchown\");let[u,A]=n;return u.fchownPromise(A,o,a)}fchownSync(r,o,a){if((r&wa)!==this.magic)return this.baseFs.fchownSync(r,o,a);let n=this.fdMap.get(r);if(typeof n>\"u\")throw Io(\"fchownSync\");let[u,A]=n;return u.fchownSync(A,o,a)}async chownPromise(r,o,a){return await this.makeCallPromise(r,async()=>await this.baseFs.chownPromise(r,o,a),async(n,{subPath:u})=>await n.chownPromise(u,o,a))}chownSync(r,o,a){return this.makeCallSync(r,()=>this.baseFs.chownSync(r,o,a),(n,{subPath:u})=>n.chownSync(u,o,a))}async renamePromise(r,o){return await this.makeCallPromise(r,async()=>await this.makeCallPromise(o,async()=>await this.baseFs.renamePromise(r,o),async()=>{throw Object.assign(new Error(\"EEXDEV: cross-device link not permitted\"),{code:\"EEXDEV\"})}),async(a,{subPath:n})=>await this.makeCallPromise(o,async()=>{throw Object.assign(new Error(\"EEXDEV: cross-device link not permitted\"),{code:\"EEXDEV\"})},async(u,{subPath:A})=>{if(a!==u)throw Object.assign(new Error(\"EEXDEV: cross-device link not permitted\"),{code:\"EEXDEV\"});return await a.renamePromise(n,A)}))}renameSync(r,o){return this.makeCallSync(r,()=>this.makeCallSync(o,()=>this.baseFs.renameSync(r,o),()=>{throw Object.assign(new Error(\"EEXDEV: cross-device link not permitted\"),{code:\"EEXDEV\"})}),(a,{subPath:n})=>this.makeCallSync(o,()=>{throw Object.assign(new Error(\"EEXDEV: cross-device link not permitted\"),{code:\"EEXDEV\"})},(u,{subPath:A})=>{if(a!==u)throw Object.assign(new Error(\"EEXDEV: cross-device link not permitted\"),{code:\"EEXDEV\"});return a.renameSync(n,A)}))}async copyFilePromise(r,o,a=0){let n=async(u,A,p,h)=>{if((a&Hg.constants.COPYFILE_FICLONE_FORCE)!==0)throw Object.assign(new Error(`EXDEV: cross-device clone not permitted, copyfile '${A}' -> ${h}'`),{code:\"EXDEV\"});if(a&Hg.constants.COPYFILE_EXCL&&await this.existsPromise(A))throw Object.assign(new Error(`EEXIST: file already exists, copyfile '${A}' -> '${h}'`),{code:\"EEXIST\"});let C;try{C=await u.readFilePromise(A)}catch{throw Object.assign(new Error(`EINVAL: invalid argument, copyfile '${A}' -> '${h}'`),{code:\"EINVAL\"})}await p.writeFilePromise(h,C)};return await this.makeCallPromise(r,async()=>await this.makeCallPromise(o,async()=>await this.baseFs.copyFilePromise(r,o,a),async(u,{subPath:A})=>await n(this.baseFs,r,u,A)),async(u,{subPath:A})=>await this.makeCallPromise(o,async()=>await n(u,A,this.baseFs,o),async(p,{subPath:h})=>u!==p?await n(u,A,p,h):await u.copyFilePromise(A,h,a)))}copyFileSync(r,o,a=0){let n=(u,A,p,h)=>{if((a&Hg.constants.COPYFILE_FICLONE_FORCE)!==0)throw Object.assign(new Error(`EXDEV: cross-device clone not permitted, copyfile '${A}' -> ${h}'`),{code:\"EXDEV\"});if(a&Hg.constants.COPYFILE_EXCL&&this.existsSync(A))throw Object.assign(new Error(`EEXIST: file already exists, copyfile '${A}' -> '${h}'`),{code:\"EEXIST\"});let C;try{C=u.readFileSync(A)}catch{throw Object.assign(new Error(`EINVAL: invalid argument, copyfile '${A}' -> '${h}'`),{code:\"EINVAL\"})}p.writeFileSync(h,C)};return this.makeCallSync(r,()=>this.makeCallSync(o,()=>this.baseFs.copyFileSync(r,o,a),(u,{subPath:A})=>n(this.baseFs,r,u,A)),(u,{subPath:A})=>this.makeCallSync(o,()=>n(u,A,this.baseFs,o),(p,{subPath:h})=>u!==p?n(u,A,p,h):u.copyFileSync(A,h,a)))}async appendFilePromise(r,o,a){return await this.makeCallPromise(r,async()=>await this.baseFs.appendFilePromise(r,o,a),async(n,{subPath:u})=>await n.appendFilePromise(u,o,a))}appendFileSync(r,o,a){return this.makeCallSync(r,()=>this.baseFs.appendFileSync(r,o,a),(n,{subPath:u})=>n.appendFileSync(u,o,a))}async writeFilePromise(r,o,a){return await this.makeCallPromise(r,async()=>await this.baseFs.writeFilePromise(r,o,a),async(n,{subPath:u})=>await n.writeFilePromise(u,o,a))}writeFileSync(r,o,a){return this.makeCallSync(r,()=>this.baseFs.writeFileSync(r,o,a),(n,{subPath:u})=>n.writeFileSync(u,o,a))}async unlinkPromise(r){return await this.makeCallPromise(r,async()=>await this.baseFs.unlinkPromise(r),async(o,{subPath:a})=>await o.unlinkPromise(a))}unlinkSync(r){return this.makeCallSync(r,()=>this.baseFs.unlinkSync(r),(o,{subPath:a})=>o.unlinkSync(a))}async utimesPromise(r,o,a){return await this.makeCallPromise(r,async()=>await this.baseFs.utimesPromise(r,o,a),async(n,{subPath:u})=>await n.utimesPromise(u,o,a))}utimesSync(r,o,a){return this.makeCallSync(r,()=>this.baseFs.utimesSync(r,o,a),(n,{subPath:u})=>n.utimesSync(u,o,a))}async lutimesPromise(r,o,a){return await this.makeCallPromise(r,async()=>await this.baseFs.lutimesPromise(r,o,a),async(n,{subPath:u})=>await n.lutimesPromise(u,o,a))}lutimesSync(r,o,a){return this.makeCallSync(r,()=>this.baseFs.lutimesSync(r,o,a),(n,{subPath:u})=>n.lutimesSync(u,o,a))}async mkdirPromise(r,o){return await this.makeCallPromise(r,async()=>await this.baseFs.mkdirPromise(r,o),async(a,{subPath:n})=>await a.mkdirPromise(n,o))}mkdirSync(r,o){return this.makeCallSync(r,()=>this.baseFs.mkdirSync(r,o),(a,{subPath:n})=>a.mkdirSync(n,o))}async rmdirPromise(r,o){return await this.makeCallPromise(r,async()=>await this.baseFs.rmdirPromise(r,o),async(a,{subPath:n})=>await a.rmdirPromise(n,o))}rmdirSync(r,o){return this.makeCallSync(r,()=>this.baseFs.rmdirSync(r,o),(a,{subPath:n})=>a.rmdirSync(n,o))}async linkPromise(r,o){return await this.makeCallPromise(o,async()=>await this.baseFs.linkPromise(r,o),async(a,{subPath:n})=>await a.linkPromise(r,n))}linkSync(r,o){return this.makeCallSync(o,()=>this.baseFs.linkSync(r,o),(a,{subPath:n})=>a.linkSync(r,n))}async symlinkPromise(r,o,a){return await this.makeCallPromise(o,async()=>await this.baseFs.symlinkPromise(r,o,a),async(n,{subPath:u})=>await n.symlinkPromise(r,u))}symlinkSync(r,o,a){return this.makeCallSync(o,()=>this.baseFs.symlinkSync(r,o,a),(n,{subPath:u})=>n.symlinkSync(r,u))}async readFilePromise(r,o){return this.makeCallPromise(r,async()=>await this.baseFs.readFilePromise(r,o),async(a,{subPath:n})=>await a.readFilePromise(n,o))}readFileSync(r,o){return this.makeCallSync(r,()=>this.baseFs.readFileSync(r,o),(a,{subPath:n})=>a.readFileSync(n,o))}async readdirPromise(r,o){return await this.makeCallPromise(r,async()=>await this.baseFs.readdirPromise(r,o),async(a,{subPath:n})=>await a.readdirPromise(n,o),{requireSubpath:!1})}readdirSync(r,o){return this.makeCallSync(r,()=>this.baseFs.readdirSync(r,o),(a,{subPath:n})=>a.readdirSync(n,o),{requireSubpath:!1})}async readlinkPromise(r){return await this.makeCallPromise(r,async()=>await this.baseFs.readlinkPromise(r),async(o,{subPath:a})=>await o.readlinkPromise(a))}readlinkSync(r){return this.makeCallSync(r,()=>this.baseFs.readlinkSync(r),(o,{subPath:a})=>o.readlinkSync(a))}async truncatePromise(r,o){return await this.makeCallPromise(r,async()=>await this.baseFs.truncatePromise(r,o),async(a,{subPath:n})=>await a.truncatePromise(n,o))}truncateSync(r,o){return this.makeCallSync(r,()=>this.baseFs.truncateSync(r,o),(a,{subPath:n})=>a.truncateSync(n,o))}async ftruncatePromise(r,o){if((r&wa)!==this.magic)return this.baseFs.ftruncatePromise(r,o);let a=this.fdMap.get(r);if(typeof a>\"u\")throw Io(\"ftruncate\");let[n,u]=a;return n.ftruncatePromise(u,o)}ftruncateSync(r,o){if((r&wa)!==this.magic)return this.baseFs.ftruncateSync(r,o);let a=this.fdMap.get(r);if(typeof a>\"u\")throw Io(\"ftruncateSync\");let[n,u]=a;return n.ftruncateSync(u,o)}watch(r,o,a){return this.makeCallSync(r,()=>this.baseFs.watch(r,o,a),(n,{subPath:u})=>n.watch(u,o,a))}watchFile(r,o,a){return this.makeCallSync(r,()=>this.baseFs.watchFile(r,o,a),()=>ty(this,r,o,a))}unwatchFile(r,o){return this.makeCallSync(r,()=>this.baseFs.unwatchFile(r,o),()=>Lg(this,r,o))}async makeCallPromise(r,o,a,{requireSubpath:n=!0}={}){if(typeof r!=\"string\")return await o();let u=this.resolve(r),A=this.findMount(u);return A?n&&A.subPath===\"/\"?await o():await this.getMountPromise(A.archivePath,async p=>await a(p,A)):await o()}makeCallSync(r,o,a,{requireSubpath:n=!0}={}){if(typeof r!=\"string\")return o();let u=this.resolve(r),A=this.findMount(u);return!A||n&&A.subPath===\"/\"?o():this.getMountSync(A.archivePath,p=>a(p,A))}findMount(r){if(this.filter&&!this.filter.test(r))return null;let o=\"\";for(;;){let a=r.substring(o.length),n=this.getMountPoint(a,o);if(!n)return null;if(o=this.pathUtils.join(o,n),!this.isMount.has(o)){if(this.notMount.has(o))continue;try{if(this.typeCheck!==null&&(this.baseFs.lstatSync(o).mode&Hg.constants.S_IFMT)!==this.typeCheck){this.notMount.add(o);continue}}catch{return null}this.isMount.add(o)}return{archivePath:o,subPath:this.pathUtils.join(Bt.root,r.substring(o.length))}}}limitOpenFiles(r){if(this.mountInstances===null)return;let o=Date.now(),a=o+this.maxAge,n=r===null?0:this.mountInstances.size-r;for(let[u,{childFs:A,expiresAt:p,refCount:h}]of this.mountInstances.entries())if(!(h!==0||A.hasOpenFileHandles?.())){if(o>=p){A.saveAndClose?.(),this.mountInstances.delete(u),n-=1;continue}else if(r===null||n<=0){a=p;break}A.saveAndClose?.(),this.mountInstances.delete(u),n-=1}this.limitOpenFilesTimeout===null&&(r===null&&this.mountInstances.size>0||r!==null)&&isFinite(a)&&(this.limitOpenFilesTimeout=setTimeout(()=>{this.limitOpenFilesTimeout=null,this.limitOpenFiles(null)},a-o).unref())}async getMountPromise(r,o){if(this.mountInstances){let a=this.mountInstances.get(r);if(!a){let n=await this.factoryPromise(this.baseFs,r);a=this.mountInstances.get(r),a||(a={childFs:n(),expiresAt:0,refCount:0})}this.mountInstances.delete(r),this.limitOpenFiles(this.maxOpenFiles-1),this.mountInstances.set(r,a),a.expiresAt=Date.now()+this.maxAge,a.refCount+=1;try{return await o(a.childFs)}finally{a.refCount-=1}}else{let a=(await this.factoryPromise(this.baseFs,r))();try{return await o(a)}finally{a.saveAndClose?.()}}}getMountSync(r,o){if(this.mountInstances){let a=this.mountInstances.get(r);return a||(a={childFs:this.factorySync(this.baseFs,r),expiresAt:0,refCount:0}),this.mountInstances.delete(r),this.limitOpenFiles(this.maxOpenFiles-1),this.mountInstances.set(r,a),a.expiresAt=Date.now()+this.maxAge,o(a.childFs)}else{let a=this.factorySync(this.baseFs,r);try{return o(a)}finally{a.saveAndClose?.()}}}}});var Zt,VR,qw,eY=Et(()=>{Ug();Ca();Zt=()=>Object.assign(new Error(\"ENOSYS: unsupported filesystem access\"),{code:\"ENOSYS\"}),VR=class extends hf{constructor(){super(V)}getExtractHint(){throw Zt()}getRealPath(){throw Zt()}resolve(){throw Zt()}async openPromise(){throw Zt()}openSync(){throw Zt()}async opendirPromise(){throw Zt()}opendirSync(){throw Zt()}async readPromise(){throw Zt()}readSync(){throw Zt()}async writePromise(){throw Zt()}writeSync(){throw Zt()}async closePromise(){throw Zt()}closeSync(){throw Zt()}createWriteStream(){throw Zt()}createReadStream(){throw Zt()}async realpathPromise(){throw Zt()}realpathSync(){throw Zt()}async readdirPromise(){throw Zt()}readdirSync(){throw Zt()}async existsPromise(e){throw Zt()}existsSync(e){throw Zt()}async accessPromise(){throw Zt()}accessSync(){throw Zt()}async statPromise(){throw Zt()}statSync(){throw Zt()}async fstatPromise(e){throw Zt()}fstatSync(e){throw Zt()}async lstatPromise(e){throw Zt()}lstatSync(e){throw Zt()}async fchmodPromise(){throw Zt()}fchmodSync(){throw Zt()}async chmodPromise(){throw Zt()}chmodSync(){throw Zt()}async fchownPromise(){throw Zt()}fchownSync(){throw Zt()}async chownPromise(){throw Zt()}chownSync(){throw Zt()}async mkdirPromise(){throw Zt()}mkdirSync(){throw Zt()}async rmdirPromise(){throw Zt()}rmdirSync(){throw Zt()}async linkPromise(){throw Zt()}linkSync(){throw Zt()}async symlinkPromise(){throw Zt()}symlinkSync(){throw Zt()}async renamePromise(){throw Zt()}renameSync(){throw Zt()}async copyFilePromise(){throw Zt()}copyFileSync(){throw Zt()}async appendFilePromise(){throw Zt()}appendFileSync(){throw Zt()}async writeFilePromise(){throw Zt()}writeFileSync(){throw Zt()}async unlinkPromise(){throw Zt()}unlinkSync(){throw Zt()}async utimesPromise(){throw Zt()}utimesSync(){throw Zt()}async lutimesPromise(){throw Zt()}lutimesSync(){throw Zt()}async readFilePromise(){throw Zt()}readFileSync(){throw Zt()}async readlinkPromise(){throw Zt()}readlinkSync(){throw Zt()}async truncatePromise(){throw Zt()}truncateSync(){throw Zt()}async ftruncatePromise(e,r){throw Zt()}ftruncateSync(e,r){throw Zt()}watch(){throw Zt()}watchFile(){throw Zt()}unwatchFile(){throw Zt()}},qw=VR;qw.instance=new VR});var _p,tY=Et(()=>{gf();Ca();_p=class extends Ps{constructor(r){super(ue);this.baseFs=r}mapFromBase(r){return ue.fromPortablePath(r)}mapToBase(r){return ue.toPortablePath(r)}}});var T_e,zR,N_e,mi,rY=Et(()=>{_g();gf();Ca();T_e=/^[0-9]+$/,zR=/^(\\/(?:[^/]+\\/)*?(?:\\$\\$virtual|__virtual__))((?:\\/((?:[^/]+-)?[a-f0-9]+)(?:\\/([^/]+))?)?((?:\\/.*)?))$/,N_e=/^([^/]+-)?[a-f0-9]+$/,mi=class extends Ps{constructor({baseFs:r=new Tn}={}){super(V);this.baseFs=r}static makeVirtualPath(r,o,a){if(V.basename(r)!==\"__virtual__\")throw new Error('Assertion failed: Virtual folders must be named \"__virtual__\"');if(!V.basename(o).match(N_e))throw new Error(\"Assertion failed: Virtual components must be ended by an hexadecimal hash\");let u=V.relative(V.dirname(r),a).split(\"/\"),A=0;for(;A<u.length&&u[A]===\"..\";)A+=1;let p=u.slice(A);return V.join(r,o,String(A),...p)}static resolveVirtual(r){let o=r.match(zR);if(!o||!o[3]&&o[5])return r;let a=V.dirname(o[1]);if(!o[3]||!o[4])return a;if(!T_e.test(o[4]))return r;let u=Number(o[4]),A=\"../\".repeat(u),p=o[5]||\".\";return mi.resolveVirtual(V.join(a,A,p))}getExtractHint(r){return this.baseFs.getExtractHint(r)}getRealPath(){return this.baseFs.getRealPath()}realpathSync(r){let o=r.match(zR);if(!o)return this.baseFs.realpathSync(r);if(!o[5])return r;let a=this.baseFs.realpathSync(this.mapToBase(r));return mi.makeVirtualPath(o[1],o[3],a)}async realpathPromise(r){let o=r.match(zR);if(!o)return await this.baseFs.realpathPromise(r);if(!o[5])return r;let a=await this.baseFs.realpathPromise(this.mapToBase(r));return mi.makeVirtualPath(o[1],o[3],a)}mapToBase(r){if(r===\"\")return r;if(this.pathUtils.isAbsolute(r))return mi.resolveVirtual(r);let o=mi.resolveVirtual(this.baseFs.resolve(Bt.dot)),a=mi.resolveVirtual(this.baseFs.resolve(r));return V.relative(o,a)||Bt.dot}mapFromBase(r){return r}}});function L_e(t,e){return typeof JR.default.isUtf8<\"u\"?JR.default.isUtf8(t):Buffer.byteLength(e)===t.byteLength}var JR,kD,nY,xD,iY=Et(()=>{JR=$e(Be(\"buffer\")),kD=Be(\"url\"),nY=Be(\"util\");gf();Ca();xD=class extends Ps{constructor(r){super(ue);this.baseFs=r}mapFromBase(r){return r}mapToBase(r){if(typeof r==\"string\")return r;if(r instanceof kD.URL)return(0,kD.fileURLToPath)(r);if(Buffer.isBuffer(r)){let o=r.toString();if(!L_e(r,o))throw new Error(\"Non-utf8 buffers are not supported at the moment. Please upvote the following issue if you encounter this error: https://github.com/yarnpkg/berry/issues/4942\");return o}throw new Error(`Unsupported path type: ${(0,nY.inspect)(r)}`)}}});var sY,Bo,df,Hp,QD,FD,ny,Tc,Nc,O_e,M_e,U_e,__e,Gw,oY=Et(()=>{sY=Be(\"readline\"),Bo=Symbol(\"kBaseFs\"),df=Symbol(\"kFd\"),Hp=Symbol(\"kClosePromise\"),QD=Symbol(\"kCloseResolve\"),FD=Symbol(\"kCloseReject\"),ny=Symbol(\"kRefs\"),Tc=Symbol(\"kRef\"),Nc=Symbol(\"kUnref\"),Gw=class{constructor(e,r){this[O_e]=1;this[M_e]=void 0;this[U_e]=void 0;this[__e]=void 0;this[Bo]=r,this[df]=e}get fd(){return this[df]}async appendFile(e,r){try{this[Tc](this.appendFile);let o=(typeof r==\"string\"?r:r?.encoding)??void 0;return await this[Bo].appendFilePromise(this.fd,e,o?{encoding:o}:void 0)}finally{this[Nc]()}}async chown(e,r){try{return this[Tc](this.chown),await this[Bo].fchownPromise(this.fd,e,r)}finally{this[Nc]()}}async chmod(e){try{return this[Tc](this.chmod),await this[Bo].fchmodPromise(this.fd,e)}finally{this[Nc]()}}createReadStream(e){return this[Bo].createReadStream(null,{...e,fd:this.fd})}createWriteStream(e){return this[Bo].createWriteStream(null,{...e,fd:this.fd})}datasync(){throw new Error(\"Method not implemented.\")}sync(){throw new Error(\"Method not implemented.\")}async read(e,r,o,a){try{this[Tc](this.read);let n;return Buffer.isBuffer(e)?n=e:(e??={},n=e.buffer??Buffer.alloc(16384),r=e.offset||0,o=e.length??n.byteLength,a=e.position??null),r??=0,o??=0,o===0?{bytesRead:o,buffer:n}:{bytesRead:await this[Bo].readPromise(this.fd,n,r,o,a),buffer:n}}finally{this[Nc]()}}async readFile(e){try{this[Tc](this.readFile);let r=(typeof e==\"string\"?e:e?.encoding)??void 0;return await this[Bo].readFilePromise(this.fd,r)}finally{this[Nc]()}}readLines(e){return(0,sY.createInterface)({input:this.createReadStream(e),crlfDelay:1/0})}async stat(e){try{return this[Tc](this.stat),await this[Bo].fstatPromise(this.fd,e)}finally{this[Nc]()}}async truncate(e){try{return this[Tc](this.truncate),await this[Bo].ftruncatePromise(this.fd,e)}finally{this[Nc]()}}utimes(e,r){throw new Error(\"Method not implemented.\")}async writeFile(e,r){try{this[Tc](this.writeFile);let o=(typeof r==\"string\"?r:r?.encoding)??void 0;await this[Bo].writeFilePromise(this.fd,e,o)}finally{this[Nc]()}}async write(...e){try{if(this[Tc](this.write),ArrayBuffer.isView(e[0])){let[r,o,a,n]=e;return{bytesWritten:await this[Bo].writePromise(this.fd,r,o??void 0,a??void 0,n??void 0),buffer:r}}else{let[r,o,a]=e;return{bytesWritten:await this[Bo].writePromise(this.fd,r,o,a),buffer:r}}}finally{this[Nc]()}}async writev(e,r){try{this[Tc](this.writev);let o=0;if(typeof r<\"u\")for(let a of e){let n=await this.write(a,void 0,void 0,r);o+=n.bytesWritten,r+=n.bytesWritten}else for(let a of e){let n=await this.write(a);o+=n.bytesWritten}return{buffers:e,bytesWritten:o}}finally{this[Nc]()}}readv(e,r){throw new Error(\"Method not implemented.\")}close(){if(this[df]===-1)return Promise.resolve();if(this[Hp])return this[Hp];if(this[ny]--,this[ny]===0){let e=this[df];this[df]=-1,this[Hp]=this[Bo].closePromise(e).finally(()=>{this[Hp]=void 0})}else this[Hp]=new Promise((e,r)=>{this[QD]=e,this[FD]=r}).finally(()=>{this[Hp]=void 0,this[FD]=void 0,this[QD]=void 0});return this[Hp]}[(Bo,df,O_e=ny,M_e=Hp,U_e=QD,__e=FD,Tc)](e){if(this[df]===-1){let r=new Error(\"file closed\");throw r.code=\"EBADF\",r.syscall=e.name,r}this[ny]++}[Nc](){if(this[ny]--,this[ny]===0){let e=this[df];this[df]=-1,this[Bo].closePromise(e).then(this[QD],this[FD])}}}});function Yw(t,e){e=new xD(e);let r=(o,a,n)=>{let u=o[a];o[a]=n,typeof u?.[iy.promisify.custom]<\"u\"&&(n[iy.promisify.custom]=u[iy.promisify.custom])};{r(t,\"exists\",(o,...a)=>{let u=typeof a[a.length-1]==\"function\"?a.pop():()=>{};process.nextTick(()=>{e.existsPromise(o).then(A=>{u(A)},()=>{u(!1)})})}),r(t,\"read\",(...o)=>{let[a,n,u,A,p,h]=o;if(o.length<=3){let C={};o.length<3?h=o[1]:(C=o[1],h=o[2]),{buffer:n=Buffer.alloc(16384),offset:u=0,length:A=n.byteLength,position:p}=C}if(u==null&&(u=0),A|=0,A===0){process.nextTick(()=>{h(null,0,n)});return}p==null&&(p=-1),process.nextTick(()=>{e.readPromise(a,n,u,A,p).then(C=>{h(null,C,n)},C=>{h(C,0,n)})})});for(let o of aY){let a=o.replace(/Promise$/,\"\");if(typeof t[a]>\"u\")continue;let n=e[o];if(typeof n>\"u\")continue;r(t,a,(...A)=>{let h=typeof A[A.length-1]==\"function\"?A.pop():()=>{};process.nextTick(()=>{n.apply(e,A).then(C=>{h(null,C)},C=>{h(C)})})})}t.realpath.native=t.realpath}{r(t,\"existsSync\",o=>{try{return e.existsSync(o)}catch{return!1}}),r(t,\"readSync\",(...o)=>{let[a,n,u,A,p]=o;return o.length<=3&&({offset:u=0,length:A=n.byteLength,position:p}=o[2]||{}),u==null&&(u=0),A|=0,A===0?0:(p==null&&(p=-1),e.readSync(a,n,u,A,p))});for(let o of H_e){let a=o;if(typeof t[a]>\"u\")continue;let n=e[o];typeof n>\"u\"||r(t,a,n.bind(e))}t.realpathSync.native=t.realpathSync}{let o=t.promises;for(let a of aY){let n=a.replace(/Promise$/,\"\");if(typeof o[n]>\"u\")continue;let u=e[a];typeof u>\"u\"||a!==\"open\"&&r(o,n,(A,...p)=>A instanceof Gw?A[n].apply(A,p):u.call(e,A,...p))}r(o,\"open\",async(...a)=>{let n=await e.openPromise(...a);return new Gw(n,e)})}t.read[iy.promisify.custom]=async(o,a,...n)=>({bytesRead:await e.readPromise(o,a,...n),buffer:a}),t.write[iy.promisify.custom]=async(o,a,...n)=>({bytesWritten:await e.writePromise(o,a,...n),buffer:a})}function RD(t,e){let r=Object.create(t);return Yw(r,e),r}var iy,H_e,aY,lY=Et(()=>{iy=Be(\"util\");iY();oY();H_e=new Set([\"accessSync\",\"appendFileSync\",\"createReadStream\",\"createWriteStream\",\"chmodSync\",\"fchmodSync\",\"chownSync\",\"fchownSync\",\"closeSync\",\"copyFileSync\",\"linkSync\",\"lstatSync\",\"fstatSync\",\"lutimesSync\",\"mkdirSync\",\"openSync\",\"opendirSync\",\"readlinkSync\",\"readFileSync\",\"readdirSync\",\"readlinkSync\",\"realpathSync\",\"renameSync\",\"rmdirSync\",\"statSync\",\"symlinkSync\",\"truncateSync\",\"ftruncateSync\",\"unlinkSync\",\"unwatchFile\",\"utimesSync\",\"watch\",\"watchFile\",\"writeFileSync\",\"writeSync\"]),aY=new Set([\"accessPromise\",\"appendFilePromise\",\"fchmodPromise\",\"chmodPromise\",\"fchownPromise\",\"chownPromise\",\"closePromise\",\"copyFilePromise\",\"linkPromise\",\"fstatPromise\",\"lstatPromise\",\"lutimesPromise\",\"mkdirPromise\",\"openPromise\",\"opendirPromise\",\"readdirPromise\",\"realpathPromise\",\"readFilePromise\",\"readdirPromise\",\"readlinkPromise\",\"renamePromise\",\"rmdirPromise\",\"statPromise\",\"symlinkPromise\",\"truncatePromise\",\"ftruncatePromise\",\"unlinkPromise\",\"utimesPromise\",\"writeFilePromise\",\"writeSync\"])});function cY(t){let e=Math.ceil(Math.random()*4294967296).toString(16).padStart(8,\"0\");return`${t}${e}`}function uY(){if(XR)return XR;let t=ue.toPortablePath(AY.default.tmpdir()),e=oe.realpathSync(t);return process.once(\"exit\",()=>{oe.rmtempSync()}),XR={tmpdir:t,realTmpdir:e}}var AY,Lc,XR,oe,fY=Et(()=>{AY=$e(Be(\"os\"));_g();Ca();Lc=new Set,XR=null;oe=Object.assign(new Tn,{detachTemp(t){Lc.delete(t)},mktempSync(t){let{tmpdir:e,realTmpdir:r}=uY();for(;;){let o=cY(\"xfs-\");try{this.mkdirSync(V.join(e,o))}catch(n){if(n.code===\"EEXIST\")continue;throw n}let a=V.join(r,o);if(Lc.add(a),typeof t>\"u\")return a;try{return t(a)}finally{if(Lc.has(a)){Lc.delete(a);try{this.removeSync(a)}catch{}}}}},async mktempPromise(t){let{tmpdir:e,realTmpdir:r}=uY();for(;;){let o=cY(\"xfs-\");try{await this.mkdirPromise(V.join(e,o))}catch(n){if(n.code===\"EEXIST\")continue;throw n}let a=V.join(r,o);if(Lc.add(a),typeof t>\"u\")return a;try{return await t(a)}finally{if(Lc.has(a)){Lc.delete(a);try{await this.removePromise(a)}catch{}}}}},async rmtempPromise(){await Promise.all(Array.from(Lc.values()).map(async t=>{try{await oe.removePromise(t,{maxRetries:0}),Lc.delete(t)}catch{}}))},rmtempSync(){for(let t of Lc)try{oe.removeSync(t),Lc.delete(t)}catch{}}})});var Ww={};Vt(Ww,{AliasFS:()=>Uu,BasePortableFakeFS:()=>Mu,CustomDir:()=>jw,CwdFS:()=>gn,FakeFS:()=>hf,Filename:()=>dr,JailFS:()=>_u,LazyFS:()=>ry,MountFS:()=>Up,NoFS:()=>qw,NodeFS:()=>Tn,PortablePath:()=>Bt,PosixFS:()=>_p,ProxiedFS:()=>Ps,VirtualFS:()=>mi,constants:()=>vi,errors:()=>ar,extendFs:()=>RD,normalizeLineEndings:()=>Mg,npath:()=>ue,opendir:()=>SD,patchFs:()=>Yw,ppath:()=>V,setupCopyIndex:()=>PD,statUtils:()=>Ea,unwatchAllFiles:()=>Og,unwatchFile:()=>Lg,watchFile:()=>ty,xfs:()=>oe});var Pt=Et(()=>{T7();BD();qR();WR();_7();KR();Ug();Ca();Ca();W7();Ug();z7();X7();Z7();$7();eY();_g();tY();gf();rY();lY();fY()});var mY=_((sbt,dY)=>{dY.exports=gY;gY.sync=q_e;var pY=Be(\"fs\");function j_e(t,e){var r=e.pathExt!==void 0?e.pathExt:process.env.PATHEXT;if(!r||(r=r.split(\";\"),r.indexOf(\"\")!==-1))return!0;for(var o=0;o<r.length;o++){var a=r[o].toLowerCase();if(a&&t.substr(-a.length).toLowerCase()===a)return!0}return!1}function hY(t,e,r){return!t.isSymbolicLink()&&!t.isFile()?!1:j_e(e,r)}function gY(t,e,r){pY.stat(t,function(o,a){r(o,o?!1:hY(a,t,e))})}function q_e(t,e){return hY(pY.statSync(t),t,e)}});var IY=_((obt,wY)=>{wY.exports=EY;EY.sync=G_e;var yY=Be(\"fs\");function EY(t,e,r){yY.stat(t,function(o,a){r(o,o?!1:CY(a,e))})}function G_e(t,e){return CY(yY.statSync(t),e)}function CY(t,e){return t.isFile()&&Y_e(t,e)}function Y_e(t,e){var r=t.mode,o=t.uid,a=t.gid,n=e.uid!==void 0?e.uid:process.getuid&&process.getuid(),u=e.gid!==void 0?e.gid:process.getgid&&process.getgid(),A=parseInt(\"100\",8),p=parseInt(\"010\",8),h=parseInt(\"001\",8),C=A|p,I=r&h||r&p&&a===u||r&A&&o===n||r&C&&n===0;return I}});var vY=_((lbt,BY)=>{var abt=Be(\"fs\"),TD;process.platform===\"win32\"||global.TESTING_WINDOWS?TD=mY():TD=IY();BY.exports=ZR;ZR.sync=W_e;function ZR(t,e,r){if(typeof e==\"function\"&&(r=e,e={}),!r){if(typeof Promise!=\"function\")throw new TypeError(\"callback not provided\");return new Promise(function(o,a){ZR(t,e||{},function(n,u){n?a(n):o(u)})})}TD(t,e||{},function(o,a){o&&(o.code===\"EACCES\"||e&&e.ignoreErrors)&&(o=null,a=!1),r(o,a)})}function W_e(t,e){try{return TD.sync(t,e||{})}catch(r){if(e&&e.ignoreErrors||r.code===\"EACCES\")return!1;throw r}}});var QY=_((cbt,kY)=>{var sy=process.platform===\"win32\"||process.env.OSTYPE===\"cygwin\"||process.env.OSTYPE===\"msys\",DY=Be(\"path\"),K_e=sy?\";\":\":\",PY=vY(),SY=t=>Object.assign(new Error(`not found: ${t}`),{code:\"ENOENT\"}),bY=(t,e)=>{let r=e.colon||K_e,o=t.match(/\\//)||sy&&t.match(/\\\\/)?[\"\"]:[...sy?[process.cwd()]:[],...(e.path||process.env.PATH||\"\").split(r)],a=sy?e.pathExt||process.env.PATHEXT||\".EXE;.CMD;.BAT;.COM\":\"\",n=sy?a.split(r):[\"\"];return sy&&t.indexOf(\".\")!==-1&&n[0]!==\"\"&&n.unshift(\"\"),{pathEnv:o,pathExt:n,pathExtExe:a}},xY=(t,e,r)=>{typeof e==\"function\"&&(r=e,e={}),e||(e={});let{pathEnv:o,pathExt:a,pathExtExe:n}=bY(t,e),u=[],A=h=>new Promise((C,I)=>{if(h===o.length)return e.all&&u.length?C(u):I(SY(t));let v=o[h],x=/^\".*\"$/.test(v)?v.slice(1,-1):v,E=DY.join(x,t),R=!x&&/^\\.[\\\\\\/]/.test(t)?t.slice(0,2)+E:E;C(p(R,h,0))}),p=(h,C,I)=>new Promise((v,x)=>{if(I===a.length)return v(A(C+1));let E=a[I];PY(h+E,{pathExt:n},(R,L)=>{if(!R&&L)if(e.all)u.push(h+E);else return v(h+E);return v(p(h,C,I+1))})});return r?A(0).then(h=>r(null,h),r):A(0)},V_e=(t,e)=>{e=e||{};let{pathEnv:r,pathExt:o,pathExtExe:a}=bY(t,e),n=[];for(let u=0;u<r.length;u++){let A=r[u],p=/^\".*\"$/.test(A)?A.slice(1,-1):A,h=DY.join(p,t),C=!p&&/^\\.[\\\\\\/]/.test(t)?t.slice(0,2)+h:h;for(let I=0;I<o.length;I++){let v=C+o[I];try{if(PY.sync(v,{pathExt:a}))if(e.all)n.push(v);else return v}catch{}}}if(e.all&&n.length)return n;if(e.nothrow)return null;throw SY(t)};kY.exports=xY;xY.sync=V_e});var RY=_((ubt,$R)=>{\"use strict\";var FY=(t={})=>{let e=t.env||process.env;return(t.platform||process.platform)!==\"win32\"?\"PATH\":Object.keys(e).reverse().find(o=>o.toUpperCase()===\"PATH\")||\"Path\"};$R.exports=FY;$R.exports.default=FY});var OY=_((Abt,LY)=>{\"use strict\";var TY=Be(\"path\"),z_e=QY(),J_e=RY();function NY(t,e){let r=t.options.env||process.env,o=process.cwd(),a=t.options.cwd!=null,n=a&&process.chdir!==void 0&&!process.chdir.disabled;if(n)try{process.chdir(t.options.cwd)}catch{}let u;try{u=z_e.sync(t.command,{path:r[J_e({env:r})],pathExt:e?TY.delimiter:void 0})}catch{}finally{n&&process.chdir(o)}return u&&(u=TY.resolve(a?t.options.cwd:\"\",u)),u}function X_e(t){return NY(t)||NY(t,!0)}LY.exports=X_e});var MY=_((fbt,tT)=>{\"use strict\";var eT=/([()\\][%!^\"`<>&|;, *?])/g;function Z_e(t){return t=t.replace(eT,\"^$1\"),t}function $_e(t,e){return t=`${t}`,t=t.replace(/(\\\\*)\"/g,'$1$1\\\\\"'),t=t.replace(/(\\\\*)$/,\"$1$1\"),t=`\"${t}\"`,t=t.replace(eT,\"^$1\"),e&&(t=t.replace(eT,\"^$1\")),t}tT.exports.command=Z_e;tT.exports.argument=$_e});var _Y=_((pbt,UY)=>{\"use strict\";UY.exports=/^#!(.*)/});var jY=_((hbt,HY)=>{\"use strict\";var e8e=_Y();HY.exports=(t=\"\")=>{let e=t.match(e8e);if(!e)return null;let[r,o]=e[0].replace(/#! ?/,\"\").split(\" \"),a=r.split(\"/\").pop();return a===\"env\"?o:o?`${a} ${o}`:a}});var GY=_((gbt,qY)=>{\"use strict\";var rT=Be(\"fs\"),t8e=jY();function r8e(t){let r=Buffer.alloc(150),o;try{o=rT.openSync(t,\"r\"),rT.readSync(o,r,0,150,0),rT.closeSync(o)}catch{}return t8e(r.toString())}qY.exports=r8e});var VY=_((dbt,KY)=>{\"use strict\";var n8e=Be(\"path\"),YY=OY(),WY=MY(),i8e=GY(),s8e=process.platform===\"win32\",o8e=/\\.(?:com|exe)$/i,a8e=/node_modules[\\\\/].bin[\\\\/][^\\\\/]+\\.cmd$/i;function l8e(t){t.file=YY(t);let e=t.file&&i8e(t.file);return e?(t.args.unshift(t.file),t.command=e,YY(t)):t.file}function c8e(t){if(!s8e)return t;let e=l8e(t),r=!o8e.test(e);if(t.options.forceShell||r){let o=a8e.test(e);t.command=n8e.normalize(t.command),t.command=WY.command(t.command),t.args=t.args.map(n=>WY.argument(n,o));let a=[t.command].concat(t.args).join(\" \");t.args=[\"/d\",\"/s\",\"/c\",`\"${a}\"`],t.command=process.env.comspec||\"cmd.exe\",t.options.windowsVerbatimArguments=!0}return t}function u8e(t,e,r){e&&!Array.isArray(e)&&(r=e,e=null),e=e?e.slice(0):[],r=Object.assign({},r);let o={command:t,args:e,options:r,file:void 0,original:{command:t,args:e}};return r.shell?o:c8e(o)}KY.exports=u8e});var XY=_((mbt,JY)=>{\"use strict\";var nT=process.platform===\"win32\";function iT(t,e){return Object.assign(new Error(`${e} ${t.command} ENOENT`),{code:\"ENOENT\",errno:\"ENOENT\",syscall:`${e} ${t.command}`,path:t.command,spawnargs:t.args})}function A8e(t,e){if(!nT)return;let r=t.emit;t.emit=function(o,a){if(o===\"exit\"){let n=zY(a,e,\"spawn\");if(n)return r.call(t,\"error\",n)}return r.apply(t,arguments)}}function zY(t,e){return nT&&t===1&&!e.file?iT(e.original,\"spawn\"):null}function f8e(t,e){return nT&&t===1&&!e.file?iT(e.original,\"spawnSync\"):null}JY.exports={hookChildProcess:A8e,verifyENOENT:zY,verifyENOENTSync:f8e,notFoundError:iT}});var aT=_((ybt,oy)=>{\"use strict\";var ZY=Be(\"child_process\"),sT=VY(),oT=XY();function $Y(t,e,r){let o=sT(t,e,r),a=ZY.spawn(o.command,o.args,o.options);return oT.hookChildProcess(a,o),a}function p8e(t,e,r){let o=sT(t,e,r),a=ZY.spawnSync(o.command,o.args,o.options);return a.error=a.error||oT.verifyENOENTSync(a.status,o),a}oy.exports=$Y;oy.exports.spawn=$Y;oy.exports.sync=p8e;oy.exports._parse=sT;oy.exports._enoent=oT});var tW=_((Ebt,eW)=>{\"use strict\";function h8e(t,e){function r(){this.constructor=t}r.prototype=e.prototype,t.prototype=new r}function jg(t,e,r,o){this.message=t,this.expected=e,this.found=r,this.location=o,this.name=\"SyntaxError\",typeof Error.captureStackTrace==\"function\"&&Error.captureStackTrace(this,jg)}h8e(jg,Error);jg.buildMessage=function(t,e){var r={literal:function(h){return'\"'+a(h.text)+'\"'},class:function(h){var C=\"\",I;for(I=0;I<h.parts.length;I++)C+=h.parts[I]instanceof Array?n(h.parts[I][0])+\"-\"+n(h.parts[I][1]):n(h.parts[I]);return\"[\"+(h.inverted?\"^\":\"\")+C+\"]\"},any:function(h){return\"any character\"},end:function(h){return\"end of input\"},other:function(h){return h.description}};function o(h){return h.charCodeAt(0).toString(16).toUpperCase()}function a(h){return h.replace(/\\\\/g,\"\\\\\\\\\").replace(/\"/g,'\\\\\"').replace(/\\0/g,\"\\\\0\").replace(/\\t/g,\"\\\\t\").replace(/\\n/g,\"\\\\n\").replace(/\\r/g,\"\\\\r\").replace(/[\\x00-\\x0F]/g,function(C){return\"\\\\x0\"+o(C)}).replace(/[\\x10-\\x1F\\x7F-\\x9F]/g,function(C){return\"\\\\x\"+o(C)})}function n(h){return h.replace(/\\\\/g,\"\\\\\\\\\").replace(/\\]/g,\"\\\\]\").replace(/\\^/g,\"\\\\^\").replace(/-/g,\"\\\\-\").replace(/\\0/g,\"\\\\0\").replace(/\\t/g,\"\\\\t\").replace(/\\n/g,\"\\\\n\").replace(/\\r/g,\"\\\\r\").replace(/[\\x00-\\x0F]/g,function(C){return\"\\\\x0\"+o(C)}).replace(/[\\x10-\\x1F\\x7F-\\x9F]/g,function(C){return\"\\\\x\"+o(C)})}function u(h){return r[h.type](h)}function A(h){var C=new Array(h.length),I,v;for(I=0;I<h.length;I++)C[I]=u(h[I]);if(C.sort(),C.length>0){for(I=1,v=1;I<C.length;I++)C[I-1]!==C[I]&&(C[v]=C[I],v++);C.length=v}switch(C.length){case 1:return C[0];case 2:return C[0]+\" or \"+C[1];default:return C.slice(0,-1).join(\", \")+\", or \"+C[C.length-1]}}function p(h){return h?'\"'+a(h)+'\"':\"end of input\"}return\"Expected \"+A(t)+\" but \"+p(e)+\" found.\"};function g8e(t,e){e=e!==void 0?e:{};var r={},o={Start:fg},a=fg,n=function(N){return N||[]},u=function(N,K,re){return[{command:N,type:K}].concat(re||[])},A=function(N,K){return[{command:N,type:K||\";\"}]},p=function(N){return N},h=\";\",C=Br(\";\",!1),I=\"&\",v=Br(\"&\",!1),x=function(N,K){return K?{chain:N,then:K}:{chain:N}},E=function(N,K){return{type:N,line:K}},R=\"&&\",L=Br(\"&&\",!1),U=\"||\",z=Br(\"||\",!1),te=function(N,K){return K?{...N,then:K}:N},le=function(N,K){return{type:N,chain:K}},he=\"|&\",Ae=Br(\"|&\",!1),ye=\"|\",ae=Br(\"|\",!1),Ie=\"=\",Fe=Br(\"=\",!1),g=function(N,K){return{name:N,args:[K]}},Ee=function(N){return{name:N,args:[]}},De=\"(\",ce=Br(\"(\",!1),ne=\")\",ee=Br(\")\",!1),we=function(N,K){return{type:\"subshell\",subshell:N,args:K}},xe=\"{\",ht=Br(\"{\",!1),H=\"}\",lt=Br(\"}\",!1),Te=function(N,K){return{type:\"group\",group:N,args:K}},ke=function(N,K){return{type:\"command\",args:K,envs:N}},be=function(N){return{type:\"envs\",envs:N}},_e=function(N){return N},Re=function(N){return N},ze=/^[0-9]/,He=Cs([[\"0\",\"9\"]],!1,!1),b=function(N,K,re){return{type:\"redirection\",subtype:K,fd:N!==null?parseInt(N):null,args:[re]}},w=\">>\",S=Br(\">>\",!1),y=\">&\",F=Br(\">&\",!1),J=\">\",X=Br(\">\",!1),Z=\"<<<\",ie=Br(\"<<<\",!1),Pe=\"<&\",Ne=Br(\"<&\",!1),ot=\"<\",dt=Br(\"<\",!1),jt=function(N){return{type:\"argument\",segments:[].concat(...N)}},$t=function(N){return N},bt=\"$'\",an=Br(\"$'\",!1),Qr=\"'\",mr=Br(\"'\",!1),br=function(N){return[{type:\"text\",text:N}]},Wr='\"\"',Kn=Br('\"\"',!1),Ns=function(){return{type:\"text\",text:\"\"}},Ti='\"',ps=Br('\"',!1),io=function(N){return N},Si=function(N){return{type:\"arithmetic\",arithmetic:N,quoted:!0}},Ls=function(N){return{type:\"shell\",shell:N,quoted:!0}},so=function(N){return{type:\"variable\",...N,quoted:!0}},cc=function(N){return{type:\"text\",text:N}},cu=function(N){return{type:\"arithmetic\",arithmetic:N,quoted:!1}},op=function(N){return{type:\"shell\",shell:N,quoted:!1}},ap=function(N){return{type:\"variable\",...N,quoted:!1}},Os=function(N){return{type:\"glob\",pattern:N}},Dn=/^[^']/,oo=Cs([\"'\"],!0,!1),Ms=function(N){return N.join(\"\")},ml=/^[^$\"]/,yl=Cs([\"$\",'\"'],!0,!1),ao=`\\\\\n`,Vn=Br(`\\\\\n`,!1),On=function(){return\"\"},Ni=\"\\\\\",Mn=Br(\"\\\\\",!1),_i=/^[\\\\$\"`]/,tr=Cs([\"\\\\\",\"$\",'\"',\"`\"],!1,!1),Oe=function(N){return N},ii=\"\\\\a\",Ma=Br(\"\\\\a\",!1),hr=function(){return\"a\"},uc=\"\\\\b\",uu=Br(\"\\\\b\",!1),Ac=function(){return\"\\b\"},El=/^[Ee]/,vA=Cs([\"E\",\"e\"],!1,!1),Au=function(){return\"\\x1B\"},Ce=\"\\\\f\",Rt=Br(\"\\\\f\",!1),fc=function(){return\"\\f\"},Hi=\"\\\\n\",fu=Br(\"\\\\n\",!1),Yt=function(){return`\n`},Cl=\"\\\\r\",DA=Br(\"\\\\r\",!1),lp=function(){return\"\\r\"},pc=\"\\\\t\",PA=Br(\"\\\\t\",!1),Qn=function(){return\"\t\"},hi=\"\\\\v\",hc=Br(\"\\\\v\",!1),SA=function(){return\"\\v\"},sa=/^[\\\\'\"?]/,Li=Cs([\"\\\\\",\"'\",'\"',\"?\"],!1,!1),_o=function(N){return String.fromCharCode(parseInt(N,16))},Ze=\"\\\\x\",lo=Br(\"\\\\x\",!1),gc=\"\\\\u\",pu=Br(\"\\\\u\",!1),ji=\"\\\\U\",hu=Br(\"\\\\U\",!1),bA=function(N){return String.fromCodePoint(parseInt(N,16))},Ua=/^[0-7]/,dc=Cs([[\"0\",\"7\"]],!1,!1),hs=/^[0-9a-fA-f]/,_t=Cs([[\"0\",\"9\"],[\"a\",\"f\"],[\"A\",\"f\"]],!1,!1),Fn=lg(),Ci=\"{}\",oa=Br(\"{}\",!1),co=function(){return\"{}\"},Us=\"-\",aa=Br(\"-\",!1),la=\"+\",Ho=Br(\"+\",!1),wi=\".\",gs=Br(\".\",!1),ds=function(N,K,re){return{type:\"number\",value:(N===\"-\"?-1:1)*parseFloat(K.join(\"\")+\".\"+re.join(\"\"))}},ms=function(N,K){return{type:\"number\",value:(N===\"-\"?-1:1)*parseInt(K.join(\"\"))}},_s=function(N){return{type:\"variable\",...N}},Un=function(N){return{type:\"variable\",name:N}},Pn=function(N){return N},ys=\"*\",We=Br(\"*\",!1),tt=\"/\",It=Br(\"/\",!1),nr=function(N,K,re){return{type:K===\"*\"?\"multiplication\":\"division\",right:re}},$=function(N,K){return K.reduce((re,pe)=>({left:re,...pe}),N)},me=function(N,K,re){return{type:K===\"+\"?\"addition\":\"subtraction\",right:re}},Le=\"$((\",ft=Br(\"$((\",!1),pt=\"))\",Tt=Br(\"))\",!1),er=function(N){return N},Zr=\"$(\",qi=Br(\"$(\",!1),es=function(N){return N},bi=\"${\",jo=Br(\"${\",!1),xA=\":-\",kA=Br(\":-\",!1),cp=function(N,K){return{name:N,defaultValue:K}},rg=\":-}\",gu=Br(\":-}\",!1),ng=function(N){return{name:N,defaultValue:[]}},du=\":+\",uo=Br(\":+\",!1),QA=function(N,K){return{name:N,alternativeValue:K}},mc=\":+}\",ca=Br(\":+}\",!1),ig=function(N){return{name:N,alternativeValue:[]}},yc=function(N){return{name:N}},Dm=\"$\",sg=Br(\"$\",!1),$n=function(N){return e.isGlobPattern(N)},up=function(N){return N},og=/^[a-zA-Z0-9_]/,FA=Cs([[\"a\",\"z\"],[\"A\",\"Z\"],[\"0\",\"9\"],\"_\"],!1,!1),Hs=function(){return ag()},mu=/^[$@*?#a-zA-Z0-9_\\-]/,Ha=Cs([\"$\",\"@\",\"*\",\"?\",\"#\",[\"a\",\"z\"],[\"A\",\"Z\"],[\"0\",\"9\"],\"_\",\"-\"],!1,!1),Gi=/^[()}<>$|&; \\t\"']/,ua=Cs([\"(\",\")\",\"}\",\"<\",\">\",\"$\",\"|\",\"&\",\";\",\" \",\"\t\",'\"',\"'\"],!1,!1),yu=/^[<>&; \\t\"']/,Es=Cs([\"<\",\">\",\"&\",\";\",\" \",\"\t\",'\"',\"'\"],!1,!1),Ec=/^[ \\t]/,Cc=Cs([\" \",\"\t\"],!1,!1),G=0,Dt=0,wl=[{line:1,column:1}],xi=0,wc=[],ct=0,Eu;if(\"startRule\"in e){if(!(e.startRule in o))throw new Error(`Can't start parsing from rule \"`+e.startRule+'\".');a=o[e.startRule]}function ag(){return t.substring(Dt,G)}function dw(){return Ic(Dt,G)}function RA(N,K){throw K=K!==void 0?K:Ic(Dt,G),Ag([ug(N)],t.substring(Dt,G),K)}function Ap(N,K){throw K=K!==void 0?K:Ic(Dt,G),Pm(N,K)}function Br(N,K){return{type:\"literal\",text:N,ignoreCase:K}}function Cs(N,K,re){return{type:\"class\",parts:N,inverted:K,ignoreCase:re}}function lg(){return{type:\"any\"}}function cg(){return{type:\"end\"}}function ug(N){return{type:\"other\",description:N}}function fp(N){var K=wl[N],re;if(K)return K;for(re=N-1;!wl[re];)re--;for(K=wl[re],K={line:K.line,column:K.column};re<N;)t.charCodeAt(re)===10?(K.line++,K.column=1):K.column++,re++;return wl[N]=K,K}function Ic(N,K){var re=fp(N),pe=fp(K);return{start:{offset:N,line:re.line,column:re.column},end:{offset:K,line:pe.line,column:pe.column}}}function Ct(N){G<xi||(G>xi&&(xi=G,wc=[]),wc.push(N))}function Pm(N,K){return new jg(N,null,null,K)}function Ag(N,K,re){return new jg(jg.buildMessage(N,K),N,K,re)}function fg(){var N,K,re;for(N=G,K=[],re=Qt();re!==r;)K.push(re),re=Qt();return K!==r?(re=Cu(),re===r&&(re=null),re!==r?(Dt=N,K=n(re),N=K):(G=N,N=r)):(G=N,N=r),N}function Cu(){var N,K,re,pe,Je;if(N=G,K=wu(),K!==r){for(re=[],pe=Qt();pe!==r;)re.push(pe),pe=Qt();re!==r?(pe=pg(),pe!==r?(Je=Sm(),Je===r&&(Je=null),Je!==r?(Dt=N,K=u(K,pe,Je),N=K):(G=N,N=r)):(G=N,N=r)):(G=N,N=r)}else G=N,N=r;if(N===r)if(N=G,K=wu(),K!==r){for(re=[],pe=Qt();pe!==r;)re.push(pe),pe=Qt();re!==r?(pe=pg(),pe===r&&(pe=null),pe!==r?(Dt=N,K=A(K,pe),N=K):(G=N,N=r)):(G=N,N=r)}else G=N,N=r;return N}function Sm(){var N,K,re,pe,Je;for(N=G,K=[],re=Qt();re!==r;)K.push(re),re=Qt();if(K!==r)if(re=Cu(),re!==r){for(pe=[],Je=Qt();Je!==r;)pe.push(Je),Je=Qt();pe!==r?(Dt=N,K=p(re),N=K):(G=N,N=r)}else G=N,N=r;else G=N,N=r;return N}function pg(){var N;return t.charCodeAt(G)===59?(N=h,G++):(N=r,ct===0&&Ct(C)),N===r&&(t.charCodeAt(G)===38?(N=I,G++):(N=r,ct===0&&Ct(v))),N}function wu(){var N,K,re;return N=G,K=Aa(),K!==r?(re=mw(),re===r&&(re=null),re!==r?(Dt=N,K=x(K,re),N=K):(G=N,N=r)):(G=N,N=r),N}function mw(){var N,K,re,pe,Je,mt,fr;for(N=G,K=[],re=Qt();re!==r;)K.push(re),re=Qt();if(K!==r)if(re=bm(),re!==r){for(pe=[],Je=Qt();Je!==r;)pe.push(Je),Je=Qt();if(pe!==r)if(Je=wu(),Je!==r){for(mt=[],fr=Qt();fr!==r;)mt.push(fr),fr=Qt();mt!==r?(Dt=N,K=E(re,Je),N=K):(G=N,N=r)}else G=N,N=r;else G=N,N=r}else G=N,N=r;else G=N,N=r;return N}function bm(){var N;return t.substr(G,2)===R?(N=R,G+=2):(N=r,ct===0&&Ct(L)),N===r&&(t.substr(G,2)===U?(N=U,G+=2):(N=r,ct===0&&Ct(z))),N}function Aa(){var N,K,re;return N=G,K=hg(),K!==r?(re=Bc(),re===r&&(re=null),re!==r?(Dt=N,K=te(K,re),N=K):(G=N,N=r)):(G=N,N=r),N}function Bc(){var N,K,re,pe,Je,mt,fr;for(N=G,K=[],re=Qt();re!==r;)K.push(re),re=Qt();if(K!==r)if(re=Il(),re!==r){for(pe=[],Je=Qt();Je!==r;)pe.push(Je),Je=Qt();if(pe!==r)if(Je=Aa(),Je!==r){for(mt=[],fr=Qt();fr!==r;)mt.push(fr),fr=Qt();mt!==r?(Dt=N,K=le(re,Je),N=K):(G=N,N=r)}else G=N,N=r;else G=N,N=r}else G=N,N=r;else G=N,N=r;return N}function Il(){var N;return t.substr(G,2)===he?(N=he,G+=2):(N=r,ct===0&&Ct(Ae)),N===r&&(t.charCodeAt(G)===124?(N=ye,G++):(N=r,ct===0&&Ct(ae))),N}function Iu(){var N,K,re,pe,Je,mt;if(N=G,K=yg(),K!==r)if(t.charCodeAt(G)===61?(re=Ie,G++):(re=r,ct===0&&Ct(Fe)),re!==r)if(pe=qo(),pe!==r){for(Je=[],mt=Qt();mt!==r;)Je.push(mt),mt=Qt();Je!==r?(Dt=N,K=g(K,pe),N=K):(G=N,N=r)}else G=N,N=r;else G=N,N=r;else G=N,N=r;if(N===r)if(N=G,K=yg(),K!==r)if(t.charCodeAt(G)===61?(re=Ie,G++):(re=r,ct===0&&Ct(Fe)),re!==r){for(pe=[],Je=Qt();Je!==r;)pe.push(Je),Je=Qt();pe!==r?(Dt=N,K=Ee(K),N=K):(G=N,N=r)}else G=N,N=r;else G=N,N=r;return N}function hg(){var N,K,re,pe,Je,mt,fr,Cr,yn,oi,Oi;for(N=G,K=[],re=Qt();re!==r;)K.push(re),re=Qt();if(K!==r)if(t.charCodeAt(G)===40?(re=De,G++):(re=r,ct===0&&Ct(ce)),re!==r){for(pe=[],Je=Qt();Je!==r;)pe.push(Je),Je=Qt();if(pe!==r)if(Je=Cu(),Je!==r){for(mt=[],fr=Qt();fr!==r;)mt.push(fr),fr=Qt();if(mt!==r)if(t.charCodeAt(G)===41?(fr=ne,G++):(fr=r,ct===0&&Ct(ee)),fr!==r){for(Cr=[],yn=Qt();yn!==r;)Cr.push(yn),yn=Qt();if(Cr!==r){for(yn=[],oi=ja();oi!==r;)yn.push(oi),oi=ja();if(yn!==r){for(oi=[],Oi=Qt();Oi!==r;)oi.push(Oi),Oi=Qt();oi!==r?(Dt=N,K=we(Je,yn),N=K):(G=N,N=r)}else G=N,N=r}else G=N,N=r}else G=N,N=r;else G=N,N=r}else G=N,N=r;else G=N,N=r}else G=N,N=r;else G=N,N=r;if(N===r){for(N=G,K=[],re=Qt();re!==r;)K.push(re),re=Qt();if(K!==r)if(t.charCodeAt(G)===123?(re=xe,G++):(re=r,ct===0&&Ct(ht)),re!==r){for(pe=[],Je=Qt();Je!==r;)pe.push(Je),Je=Qt();if(pe!==r)if(Je=Cu(),Je!==r){for(mt=[],fr=Qt();fr!==r;)mt.push(fr),fr=Qt();if(mt!==r)if(t.charCodeAt(G)===125?(fr=H,G++):(fr=r,ct===0&&Ct(lt)),fr!==r){for(Cr=[],yn=Qt();yn!==r;)Cr.push(yn),yn=Qt();if(Cr!==r){for(yn=[],oi=ja();oi!==r;)yn.push(oi),oi=ja();if(yn!==r){for(oi=[],Oi=Qt();Oi!==r;)oi.push(Oi),Oi=Qt();oi!==r?(Dt=N,K=Te(Je,yn),N=K):(G=N,N=r)}else G=N,N=r}else G=N,N=r}else G=N,N=r;else G=N,N=r}else G=N,N=r;else G=N,N=r}else G=N,N=r;else G=N,N=r;if(N===r){for(N=G,K=[],re=Qt();re!==r;)K.push(re),re=Qt();if(K!==r){for(re=[],pe=Iu();pe!==r;)re.push(pe),pe=Iu();if(re!==r){for(pe=[],Je=Qt();Je!==r;)pe.push(Je),Je=Qt();if(pe!==r){if(Je=[],mt=pp(),mt!==r)for(;mt!==r;)Je.push(mt),mt=pp();else Je=r;if(Je!==r){for(mt=[],fr=Qt();fr!==r;)mt.push(fr),fr=Qt();mt!==r?(Dt=N,K=ke(re,Je),N=K):(G=N,N=r)}else G=N,N=r}else G=N,N=r}else G=N,N=r}else G=N,N=r;if(N===r){for(N=G,K=[],re=Qt();re!==r;)K.push(re),re=Qt();if(K!==r){if(re=[],pe=Iu(),pe!==r)for(;pe!==r;)re.push(pe),pe=Iu();else re=r;if(re!==r){for(pe=[],Je=Qt();Je!==r;)pe.push(Je),Je=Qt();pe!==r?(Dt=N,K=be(re),N=K):(G=N,N=r)}else G=N,N=r}else G=N,N=r}}}return N}function TA(){var N,K,re,pe,Je;for(N=G,K=[],re=Qt();re!==r;)K.push(re),re=Qt();if(K!==r){if(re=[],pe=hp(),pe!==r)for(;pe!==r;)re.push(pe),pe=hp();else re=r;if(re!==r){for(pe=[],Je=Qt();Je!==r;)pe.push(Je),Je=Qt();pe!==r?(Dt=N,K=_e(re),N=K):(G=N,N=r)}else G=N,N=r}else G=N,N=r;return N}function pp(){var N,K,re;for(N=G,K=[],re=Qt();re!==r;)K.push(re),re=Qt();if(K!==r?(re=ja(),re!==r?(Dt=N,K=Re(re),N=K):(G=N,N=r)):(G=N,N=r),N===r){for(N=G,K=[],re=Qt();re!==r;)K.push(re),re=Qt();K!==r?(re=hp(),re!==r?(Dt=N,K=Re(re),N=K):(G=N,N=r)):(G=N,N=r)}return N}function ja(){var N,K,re,pe,Je;for(N=G,K=[],re=Qt();re!==r;)K.push(re),re=Qt();return K!==r?(ze.test(t.charAt(G))?(re=t.charAt(G),G++):(re=r,ct===0&&Ct(He)),re===r&&(re=null),re!==r?(pe=gg(),pe!==r?(Je=hp(),Je!==r?(Dt=N,K=b(re,pe,Je),N=K):(G=N,N=r)):(G=N,N=r)):(G=N,N=r)):(G=N,N=r),N}function gg(){var N;return t.substr(G,2)===w?(N=w,G+=2):(N=r,ct===0&&Ct(S)),N===r&&(t.substr(G,2)===y?(N=y,G+=2):(N=r,ct===0&&Ct(F)),N===r&&(t.charCodeAt(G)===62?(N=J,G++):(N=r,ct===0&&Ct(X)),N===r&&(t.substr(G,3)===Z?(N=Z,G+=3):(N=r,ct===0&&Ct(ie)),N===r&&(t.substr(G,2)===Pe?(N=Pe,G+=2):(N=r,ct===0&&Ct(Ne)),N===r&&(t.charCodeAt(G)===60?(N=ot,G++):(N=r,ct===0&&Ct(dt))))))),N}function hp(){var N,K,re;for(N=G,K=[],re=Qt();re!==r;)K.push(re),re=Qt();return K!==r?(re=qo(),re!==r?(Dt=N,K=Re(re),N=K):(G=N,N=r)):(G=N,N=r),N}function qo(){var N,K,re;if(N=G,K=[],re=ws(),re!==r)for(;re!==r;)K.push(re),re=ws();else K=r;return K!==r&&(Dt=N,K=jt(K)),N=K,N}function ws(){var N,K;return N=G,K=Ii(),K!==r&&(Dt=N,K=$t(K)),N=K,N===r&&(N=G,K=xm(),K!==r&&(Dt=N,K=$t(K)),N=K,N===r&&(N=G,K=km(),K!==r&&(Dt=N,K=$t(K)),N=K,N===r&&(N=G,K=Go(),K!==r&&(Dt=N,K=$t(K)),N=K))),N}function Ii(){var N,K,re,pe;return N=G,t.substr(G,2)===bt?(K=bt,G+=2):(K=r,ct===0&&Ct(an)),K!==r?(re=ln(),re!==r?(t.charCodeAt(G)===39?(pe=Qr,G++):(pe=r,ct===0&&Ct(mr)),pe!==r?(Dt=N,K=br(re),N=K):(G=N,N=r)):(G=N,N=r)):(G=N,N=r),N}function xm(){var N,K,re,pe;return N=G,t.charCodeAt(G)===39?(K=Qr,G++):(K=r,ct===0&&Ct(mr)),K!==r?(re=dp(),re!==r?(t.charCodeAt(G)===39?(pe=Qr,G++):(pe=r,ct===0&&Ct(mr)),pe!==r?(Dt=N,K=br(re),N=K):(G=N,N=r)):(G=N,N=r)):(G=N,N=r),N}function km(){var N,K,re,pe;if(N=G,t.substr(G,2)===Wr?(K=Wr,G+=2):(K=r,ct===0&&Ct(Kn)),K!==r&&(Dt=N,K=Ns()),N=K,N===r)if(N=G,t.charCodeAt(G)===34?(K=Ti,G++):(K=r,ct===0&&Ct(ps)),K!==r){for(re=[],pe=NA();pe!==r;)re.push(pe),pe=NA();re!==r?(t.charCodeAt(G)===34?(pe=Ti,G++):(pe=r,ct===0&&Ct(ps)),pe!==r?(Dt=N,K=io(re),N=K):(G=N,N=r)):(G=N,N=r)}else G=N,N=r;return N}function Go(){var N,K,re;if(N=G,K=[],re=gp(),re!==r)for(;re!==r;)K.push(re),re=gp();else K=r;return K!==r&&(Dt=N,K=io(K)),N=K,N}function NA(){var N,K;return N=G,K=Gr(),K!==r&&(Dt=N,K=Si(K)),N=K,N===r&&(N=G,K=mp(),K!==r&&(Dt=N,K=Ls(K)),N=K,N===r&&(N=G,K=Dc(),K!==r&&(Dt=N,K=so(K)),N=K,N===r&&(N=G,K=dg(),K!==r&&(Dt=N,K=cc(K)),N=K))),N}function gp(){var N,K;return N=G,K=Gr(),K!==r&&(Dt=N,K=cu(K)),N=K,N===r&&(N=G,K=mp(),K!==r&&(Dt=N,K=op(K)),N=K,N===r&&(N=G,K=Dc(),K!==r&&(Dt=N,K=ap(K)),N=K,N===r&&(N=G,K=yw(),K!==r&&(Dt=N,K=Os(K)),N=K,N===r&&(N=G,K=pa(),K!==r&&(Dt=N,K=cc(K)),N=K)))),N}function dp(){var N,K,re;for(N=G,K=[],Dn.test(t.charAt(G))?(re=t.charAt(G),G++):(re=r,ct===0&&Ct(oo));re!==r;)K.push(re),Dn.test(t.charAt(G))?(re=t.charAt(G),G++):(re=r,ct===0&&Ct(oo));return K!==r&&(Dt=N,K=Ms(K)),N=K,N}function dg(){var N,K,re;if(N=G,K=[],re=fa(),re===r&&(ml.test(t.charAt(G))?(re=t.charAt(G),G++):(re=r,ct===0&&Ct(yl))),re!==r)for(;re!==r;)K.push(re),re=fa(),re===r&&(ml.test(t.charAt(G))?(re=t.charAt(G),G++):(re=r,ct===0&&Ct(yl)));else K=r;return K!==r&&(Dt=N,K=Ms(K)),N=K,N}function fa(){var N,K,re;return N=G,t.substr(G,2)===ao?(K=ao,G+=2):(K=r,ct===0&&Ct(Vn)),K!==r&&(Dt=N,K=On()),N=K,N===r&&(N=G,t.charCodeAt(G)===92?(K=Ni,G++):(K=r,ct===0&&Ct(Mn)),K!==r?(_i.test(t.charAt(G))?(re=t.charAt(G),G++):(re=r,ct===0&&Ct(tr)),re!==r?(Dt=N,K=Oe(re),N=K):(G=N,N=r)):(G=N,N=r)),N}function ln(){var N,K,re;for(N=G,K=[],re=Ao(),re===r&&(Dn.test(t.charAt(G))?(re=t.charAt(G),G++):(re=r,ct===0&&Ct(oo)));re!==r;)K.push(re),re=Ao(),re===r&&(Dn.test(t.charAt(G))?(re=t.charAt(G),G++):(re=r,ct===0&&Ct(oo)));return K!==r&&(Dt=N,K=Ms(K)),N=K,N}function Ao(){var N,K,re;return N=G,t.substr(G,2)===ii?(K=ii,G+=2):(K=r,ct===0&&Ct(Ma)),K!==r&&(Dt=N,K=hr()),N=K,N===r&&(N=G,t.substr(G,2)===uc?(K=uc,G+=2):(K=r,ct===0&&Ct(uu)),K!==r&&(Dt=N,K=Ac()),N=K,N===r&&(N=G,t.charCodeAt(G)===92?(K=Ni,G++):(K=r,ct===0&&Ct(Mn)),K!==r?(El.test(t.charAt(G))?(re=t.charAt(G),G++):(re=r,ct===0&&Ct(vA)),re!==r?(Dt=N,K=Au(),N=K):(G=N,N=r)):(G=N,N=r),N===r&&(N=G,t.substr(G,2)===Ce?(K=Ce,G+=2):(K=r,ct===0&&Ct(Rt)),K!==r&&(Dt=N,K=fc()),N=K,N===r&&(N=G,t.substr(G,2)===Hi?(K=Hi,G+=2):(K=r,ct===0&&Ct(fu)),K!==r&&(Dt=N,K=Yt()),N=K,N===r&&(N=G,t.substr(G,2)===Cl?(K=Cl,G+=2):(K=r,ct===0&&Ct(DA)),K!==r&&(Dt=N,K=lp()),N=K,N===r&&(N=G,t.substr(G,2)===pc?(K=pc,G+=2):(K=r,ct===0&&Ct(PA)),K!==r&&(Dt=N,K=Qn()),N=K,N===r&&(N=G,t.substr(G,2)===hi?(K=hi,G+=2):(K=r,ct===0&&Ct(hc)),K!==r&&(Dt=N,K=SA()),N=K,N===r&&(N=G,t.charCodeAt(G)===92?(K=Ni,G++):(K=r,ct===0&&Ct(Mn)),K!==r?(sa.test(t.charAt(G))?(re=t.charAt(G),G++):(re=r,ct===0&&Ct(Li)),re!==r?(Dt=N,K=Oe(re),N=K):(G=N,N=r)):(G=N,N=r),N===r&&(N=LA()))))))))),N}function LA(){var N,K,re,pe,Je,mt,fr,Cr,yn,oi,Oi,Cg;return N=G,t.charCodeAt(G)===92?(K=Ni,G++):(K=r,ct===0&&Ct(Mn)),K!==r?(re=qa(),re!==r?(Dt=N,K=_o(re),N=K):(G=N,N=r)):(G=N,N=r),N===r&&(N=G,t.substr(G,2)===Ze?(K=Ze,G+=2):(K=r,ct===0&&Ct(lo)),K!==r?(re=G,pe=G,Je=qa(),Je!==r?(mt=si(),mt!==r?(Je=[Je,mt],pe=Je):(G=pe,pe=r)):(G=pe,pe=r),pe===r&&(pe=qa()),pe!==r?re=t.substring(re,G):re=pe,re!==r?(Dt=N,K=_o(re),N=K):(G=N,N=r)):(G=N,N=r),N===r&&(N=G,t.substr(G,2)===gc?(K=gc,G+=2):(K=r,ct===0&&Ct(pu)),K!==r?(re=G,pe=G,Je=si(),Je!==r?(mt=si(),mt!==r?(fr=si(),fr!==r?(Cr=si(),Cr!==r?(Je=[Je,mt,fr,Cr],pe=Je):(G=pe,pe=r)):(G=pe,pe=r)):(G=pe,pe=r)):(G=pe,pe=r),pe!==r?re=t.substring(re,G):re=pe,re!==r?(Dt=N,K=_o(re),N=K):(G=N,N=r)):(G=N,N=r),N===r&&(N=G,t.substr(G,2)===ji?(K=ji,G+=2):(K=r,ct===0&&Ct(hu)),K!==r?(re=G,pe=G,Je=si(),Je!==r?(mt=si(),mt!==r?(fr=si(),fr!==r?(Cr=si(),Cr!==r?(yn=si(),yn!==r?(oi=si(),oi!==r?(Oi=si(),Oi!==r?(Cg=si(),Cg!==r?(Je=[Je,mt,fr,Cr,yn,oi,Oi,Cg],pe=Je):(G=pe,pe=r)):(G=pe,pe=r)):(G=pe,pe=r)):(G=pe,pe=r)):(G=pe,pe=r)):(G=pe,pe=r)):(G=pe,pe=r)):(G=pe,pe=r),pe!==r?re=t.substring(re,G):re=pe,re!==r?(Dt=N,K=bA(re),N=K):(G=N,N=r)):(G=N,N=r)))),N}function qa(){var N;return Ua.test(t.charAt(G))?(N=t.charAt(G),G++):(N=r,ct===0&&Ct(dc)),N}function si(){var N;return hs.test(t.charAt(G))?(N=t.charAt(G),G++):(N=r,ct===0&&Ct(_t)),N}function pa(){var N,K,re,pe,Je;if(N=G,K=[],re=G,t.charCodeAt(G)===92?(pe=Ni,G++):(pe=r,ct===0&&Ct(Mn)),pe!==r?(t.length>G?(Je=t.charAt(G),G++):(Je=r,ct===0&&Ct(Fn)),Je!==r?(Dt=re,pe=Oe(Je),re=pe):(G=re,re=r)):(G=re,re=r),re===r&&(re=G,t.substr(G,2)===Ci?(pe=Ci,G+=2):(pe=r,ct===0&&Ct(oa)),pe!==r&&(Dt=re,pe=co()),re=pe,re===r&&(re=G,pe=G,ct++,Je=Qm(),ct--,Je===r?pe=void 0:(G=pe,pe=r),pe!==r?(t.length>G?(Je=t.charAt(G),G++):(Je=r,ct===0&&Ct(Fn)),Je!==r?(Dt=re,pe=Oe(Je),re=pe):(G=re,re=r)):(G=re,re=r))),re!==r)for(;re!==r;)K.push(re),re=G,t.charCodeAt(G)===92?(pe=Ni,G++):(pe=r,ct===0&&Ct(Mn)),pe!==r?(t.length>G?(Je=t.charAt(G),G++):(Je=r,ct===0&&Ct(Fn)),Je!==r?(Dt=re,pe=Oe(Je),re=pe):(G=re,re=r)):(G=re,re=r),re===r&&(re=G,t.substr(G,2)===Ci?(pe=Ci,G+=2):(pe=r,ct===0&&Ct(oa)),pe!==r&&(Dt=re,pe=co()),re=pe,re===r&&(re=G,pe=G,ct++,Je=Qm(),ct--,Je===r?pe=void 0:(G=pe,pe=r),pe!==r?(t.length>G?(Je=t.charAt(G),G++):(Je=r,ct===0&&Ct(Fn)),Je!==r?(Dt=re,pe=Oe(Je),re=pe):(G=re,re=r)):(G=re,re=r)));else K=r;return K!==r&&(Dt=N,K=Ms(K)),N=K,N}function vc(){var N,K,re,pe,Je,mt;if(N=G,t.charCodeAt(G)===45?(K=Us,G++):(K=r,ct===0&&Ct(aa)),K===r&&(t.charCodeAt(G)===43?(K=la,G++):(K=r,ct===0&&Ct(Ho))),K===r&&(K=null),K!==r){if(re=[],ze.test(t.charAt(G))?(pe=t.charAt(G),G++):(pe=r,ct===0&&Ct(He)),pe!==r)for(;pe!==r;)re.push(pe),ze.test(t.charAt(G))?(pe=t.charAt(G),G++):(pe=r,ct===0&&Ct(He));else re=r;if(re!==r)if(t.charCodeAt(G)===46?(pe=wi,G++):(pe=r,ct===0&&Ct(gs)),pe!==r){if(Je=[],ze.test(t.charAt(G))?(mt=t.charAt(G),G++):(mt=r,ct===0&&Ct(He)),mt!==r)for(;mt!==r;)Je.push(mt),ze.test(t.charAt(G))?(mt=t.charAt(G),G++):(mt=r,ct===0&&Ct(He));else Je=r;Je!==r?(Dt=N,K=ds(K,re,Je),N=K):(G=N,N=r)}else G=N,N=r;else G=N,N=r}else G=N,N=r;if(N===r){if(N=G,t.charCodeAt(G)===45?(K=Us,G++):(K=r,ct===0&&Ct(aa)),K===r&&(t.charCodeAt(G)===43?(K=la,G++):(K=r,ct===0&&Ct(Ho))),K===r&&(K=null),K!==r){if(re=[],ze.test(t.charAt(G))?(pe=t.charAt(G),G++):(pe=r,ct===0&&Ct(He)),pe!==r)for(;pe!==r;)re.push(pe),ze.test(t.charAt(G))?(pe=t.charAt(G),G++):(pe=r,ct===0&&Ct(He));else re=r;re!==r?(Dt=N,K=ms(K,re),N=K):(G=N,N=r)}else G=N,N=r;if(N===r&&(N=G,K=Dc(),K!==r&&(Dt=N,K=_s(K)),N=K,N===r&&(N=G,K=Ga(),K!==r&&(Dt=N,K=Un(K)),N=K,N===r)))if(N=G,t.charCodeAt(G)===40?(K=De,G++):(K=r,ct===0&&Ct(ce)),K!==r){for(re=[],pe=Qt();pe!==r;)re.push(pe),pe=Qt();if(re!==r)if(pe=ts(),pe!==r){for(Je=[],mt=Qt();mt!==r;)Je.push(mt),mt=Qt();Je!==r?(t.charCodeAt(G)===41?(mt=ne,G++):(mt=r,ct===0&&Ct(ee)),mt!==r?(Dt=N,K=Pn(pe),N=K):(G=N,N=r)):(G=N,N=r)}else G=N,N=r;else G=N,N=r}else G=N,N=r}return N}function Bl(){var N,K,re,pe,Je,mt,fr,Cr;if(N=G,K=vc(),K!==r){for(re=[],pe=G,Je=[],mt=Qt();mt!==r;)Je.push(mt),mt=Qt();if(Je!==r)if(t.charCodeAt(G)===42?(mt=ys,G++):(mt=r,ct===0&&Ct(We)),mt===r&&(t.charCodeAt(G)===47?(mt=tt,G++):(mt=r,ct===0&&Ct(It))),mt!==r){for(fr=[],Cr=Qt();Cr!==r;)fr.push(Cr),Cr=Qt();fr!==r?(Cr=vc(),Cr!==r?(Dt=pe,Je=nr(K,mt,Cr),pe=Je):(G=pe,pe=r)):(G=pe,pe=r)}else G=pe,pe=r;else G=pe,pe=r;for(;pe!==r;){for(re.push(pe),pe=G,Je=[],mt=Qt();mt!==r;)Je.push(mt),mt=Qt();if(Je!==r)if(t.charCodeAt(G)===42?(mt=ys,G++):(mt=r,ct===0&&Ct(We)),mt===r&&(t.charCodeAt(G)===47?(mt=tt,G++):(mt=r,ct===0&&Ct(It))),mt!==r){for(fr=[],Cr=Qt();Cr!==r;)fr.push(Cr),Cr=Qt();fr!==r?(Cr=vc(),Cr!==r?(Dt=pe,Je=nr(K,mt,Cr),pe=Je):(G=pe,pe=r)):(G=pe,pe=r)}else G=pe,pe=r;else G=pe,pe=r}re!==r?(Dt=N,K=$(K,re),N=K):(G=N,N=r)}else G=N,N=r;return N}function ts(){var N,K,re,pe,Je,mt,fr,Cr;if(N=G,K=Bl(),K!==r){for(re=[],pe=G,Je=[],mt=Qt();mt!==r;)Je.push(mt),mt=Qt();if(Je!==r)if(t.charCodeAt(G)===43?(mt=la,G++):(mt=r,ct===0&&Ct(Ho)),mt===r&&(t.charCodeAt(G)===45?(mt=Us,G++):(mt=r,ct===0&&Ct(aa))),mt!==r){for(fr=[],Cr=Qt();Cr!==r;)fr.push(Cr),Cr=Qt();fr!==r?(Cr=Bl(),Cr!==r?(Dt=pe,Je=me(K,mt,Cr),pe=Je):(G=pe,pe=r)):(G=pe,pe=r)}else G=pe,pe=r;else G=pe,pe=r;for(;pe!==r;){for(re.push(pe),pe=G,Je=[],mt=Qt();mt!==r;)Je.push(mt),mt=Qt();if(Je!==r)if(t.charCodeAt(G)===43?(mt=la,G++):(mt=r,ct===0&&Ct(Ho)),mt===r&&(t.charCodeAt(G)===45?(mt=Us,G++):(mt=r,ct===0&&Ct(aa))),mt!==r){for(fr=[],Cr=Qt();Cr!==r;)fr.push(Cr),Cr=Qt();fr!==r?(Cr=Bl(),Cr!==r?(Dt=pe,Je=me(K,mt,Cr),pe=Je):(G=pe,pe=r)):(G=pe,pe=r)}else G=pe,pe=r;else G=pe,pe=r}re!==r?(Dt=N,K=$(K,re),N=K):(G=N,N=r)}else G=N,N=r;return N}function Gr(){var N,K,re,pe,Je,mt;if(N=G,t.substr(G,3)===Le?(K=Le,G+=3):(K=r,ct===0&&Ct(ft)),K!==r){for(re=[],pe=Qt();pe!==r;)re.push(pe),pe=Qt();if(re!==r)if(pe=ts(),pe!==r){for(Je=[],mt=Qt();mt!==r;)Je.push(mt),mt=Qt();Je!==r?(t.substr(G,2)===pt?(mt=pt,G+=2):(mt=r,ct===0&&Ct(Tt)),mt!==r?(Dt=N,K=er(pe),N=K):(G=N,N=r)):(G=N,N=r)}else G=N,N=r;else G=N,N=r}else G=N,N=r;return N}function mp(){var N,K,re,pe;return N=G,t.substr(G,2)===Zr?(K=Zr,G+=2):(K=r,ct===0&&Ct(qi)),K!==r?(re=Cu(),re!==r?(t.charCodeAt(G)===41?(pe=ne,G++):(pe=r,ct===0&&Ct(ee)),pe!==r?(Dt=N,K=es(re),N=K):(G=N,N=r)):(G=N,N=r)):(G=N,N=r),N}function Dc(){var N,K,re,pe,Je,mt;return N=G,t.substr(G,2)===bi?(K=bi,G+=2):(K=r,ct===0&&Ct(jo)),K!==r?(re=Ga(),re!==r?(t.substr(G,2)===xA?(pe=xA,G+=2):(pe=r,ct===0&&Ct(kA)),pe!==r?(Je=TA(),Je!==r?(t.charCodeAt(G)===125?(mt=H,G++):(mt=r,ct===0&&Ct(lt)),mt!==r?(Dt=N,K=cp(re,Je),N=K):(G=N,N=r)):(G=N,N=r)):(G=N,N=r)):(G=N,N=r)):(G=N,N=r),N===r&&(N=G,t.substr(G,2)===bi?(K=bi,G+=2):(K=r,ct===0&&Ct(jo)),K!==r?(re=Ga(),re!==r?(t.substr(G,3)===rg?(pe=rg,G+=3):(pe=r,ct===0&&Ct(gu)),pe!==r?(Dt=N,K=ng(re),N=K):(G=N,N=r)):(G=N,N=r)):(G=N,N=r),N===r&&(N=G,t.substr(G,2)===bi?(K=bi,G+=2):(K=r,ct===0&&Ct(jo)),K!==r?(re=Ga(),re!==r?(t.substr(G,2)===du?(pe=du,G+=2):(pe=r,ct===0&&Ct(uo)),pe!==r?(Je=TA(),Je!==r?(t.charCodeAt(G)===125?(mt=H,G++):(mt=r,ct===0&&Ct(lt)),mt!==r?(Dt=N,K=QA(re,Je),N=K):(G=N,N=r)):(G=N,N=r)):(G=N,N=r)):(G=N,N=r)):(G=N,N=r),N===r&&(N=G,t.substr(G,2)===bi?(K=bi,G+=2):(K=r,ct===0&&Ct(jo)),K!==r?(re=Ga(),re!==r?(t.substr(G,3)===mc?(pe=mc,G+=3):(pe=r,ct===0&&Ct(ca)),pe!==r?(Dt=N,K=ig(re),N=K):(G=N,N=r)):(G=N,N=r)):(G=N,N=r),N===r&&(N=G,t.substr(G,2)===bi?(K=bi,G+=2):(K=r,ct===0&&Ct(jo)),K!==r?(re=Ga(),re!==r?(t.charCodeAt(G)===125?(pe=H,G++):(pe=r,ct===0&&Ct(lt)),pe!==r?(Dt=N,K=yc(re),N=K):(G=N,N=r)):(G=N,N=r)):(G=N,N=r),N===r&&(N=G,t.charCodeAt(G)===36?(K=Dm,G++):(K=r,ct===0&&Ct(sg)),K!==r?(re=Ga(),re!==r?(Dt=N,K=yc(re),N=K):(G=N,N=r)):(G=N,N=r)))))),N}function yw(){var N,K,re;return N=G,K=mg(),K!==r?(Dt=G,re=$n(K),re?re=void 0:re=r,re!==r?(Dt=N,K=up(K),N=K):(G=N,N=r)):(G=N,N=r),N}function mg(){var N,K,re,pe,Je;if(N=G,K=[],re=G,pe=G,ct++,Je=Eg(),ct--,Je===r?pe=void 0:(G=pe,pe=r),pe!==r?(t.length>G?(Je=t.charAt(G),G++):(Je=r,ct===0&&Ct(Fn)),Je!==r?(Dt=re,pe=Oe(Je),re=pe):(G=re,re=r)):(G=re,re=r),re!==r)for(;re!==r;)K.push(re),re=G,pe=G,ct++,Je=Eg(),ct--,Je===r?pe=void 0:(G=pe,pe=r),pe!==r?(t.length>G?(Je=t.charAt(G),G++):(Je=r,ct===0&&Ct(Fn)),Je!==r?(Dt=re,pe=Oe(Je),re=pe):(G=re,re=r)):(G=re,re=r);else K=r;return K!==r&&(Dt=N,K=Ms(K)),N=K,N}function yg(){var N,K,re;if(N=G,K=[],og.test(t.charAt(G))?(re=t.charAt(G),G++):(re=r,ct===0&&Ct(FA)),re!==r)for(;re!==r;)K.push(re),og.test(t.charAt(G))?(re=t.charAt(G),G++):(re=r,ct===0&&Ct(FA));else K=r;return K!==r&&(Dt=N,K=Hs()),N=K,N}function Ga(){var N,K,re;if(N=G,K=[],mu.test(t.charAt(G))?(re=t.charAt(G),G++):(re=r,ct===0&&Ct(Ha)),re!==r)for(;re!==r;)K.push(re),mu.test(t.charAt(G))?(re=t.charAt(G),G++):(re=r,ct===0&&Ct(Ha));else K=r;return K!==r&&(Dt=N,K=Hs()),N=K,N}function Qm(){var N;return Gi.test(t.charAt(G))?(N=t.charAt(G),G++):(N=r,ct===0&&Ct(ua)),N}function Eg(){var N;return yu.test(t.charAt(G))?(N=t.charAt(G),G++):(N=r,ct===0&&Ct(Es)),N}function Qt(){var N,K;if(N=[],Ec.test(t.charAt(G))?(K=t.charAt(G),G++):(K=r,ct===0&&Ct(Cc)),K!==r)for(;K!==r;)N.push(K),Ec.test(t.charAt(G))?(K=t.charAt(G),G++):(K=r,ct===0&&Ct(Cc));else N=r;return N}if(Eu=a(),Eu!==r&&G===t.length)return Eu;throw Eu!==r&&G<t.length&&Ct(cg()),Ag(wc,xi<t.length?t.charAt(xi):null,xi<t.length?Ic(xi,xi+1):Ic(xi,xi))}eW.exports={SyntaxError:jg,parse:g8e}});function LD(t,e={isGlobPattern:()=>!1}){try{return(0,rW.parse)(t,e)}catch(r){throw r.location&&(r.message=r.message.replace(/(\\.)?$/,` (line ${r.location.start.line}, column ${r.location.start.column})$1`)),r}}function ay(t,{endSemicolon:e=!1}={}){return t.map(({command:r,type:o},a)=>`${OD(r)}${o===\";\"?a!==t.length-1||e?\";\":\"\":\" &\"}`).join(\" \")}function OD(t){return`${ly(t.chain)}${t.then?` ${lT(t.then)}`:\"\"}`}function lT(t){return`${t.type} ${OD(t.line)}`}function ly(t){return`${uT(t)}${t.then?` ${cT(t.then)}`:\"\"}`}function cT(t){return`${t.type} ${ly(t.chain)}`}function uT(t){switch(t.type){case\"command\":return`${t.envs.length>0?`${t.envs.map(e=>ND(e)).join(\" \")} `:\"\"}${t.args.map(e=>AT(e)).join(\" \")}`;case\"subshell\":return`(${ay(t.subshell)})${t.args.length>0?` ${t.args.map(e=>Kw(e)).join(\" \")}`:\"\"}`;case\"group\":return`{ ${ay(t.group,{endSemicolon:!0})} }${t.args.length>0?` ${t.args.map(e=>Kw(e)).join(\" \")}`:\"\"}`;case\"envs\":return t.envs.map(e=>ND(e)).join(\" \");default:throw new Error(`Unsupported command type:  \"${t.type}\"`)}}function ND(t){return`${t.name}=${t.args[0]?qg(t.args[0]):\"\"}`}function AT(t){switch(t.type){case\"redirection\":return Kw(t);case\"argument\":return qg(t);default:throw new Error(`Unsupported argument type: \"${t.type}\"`)}}function Kw(t){return`${t.subtype} ${t.args.map(e=>qg(e)).join(\" \")}`}function qg(t){return t.segments.map(e=>fT(e)).join(\"\")}function fT(t){let e=(o,a)=>a?`\"${o}\"`:o,r=o=>o===\"\"?\"''\":o.match(/[()}<>$|&;\"'\\n\\t ]/)?o.match(/['\\t\\p{C}]/u)?o.match(/'/)?`\"${o.replace(/[\"$\\t\\p{C}]/u,m8e)}\"`:`$'${o.replace(/[\\t\\p{C}]/u,iW)}'`:`'${o}'`:o;switch(t.type){case\"text\":return r(t.text);case\"glob\":return t.pattern;case\"shell\":return e(`\\${${ay(t.shell)}}`,t.quoted);case\"variable\":return e(typeof t.defaultValue>\"u\"?typeof t.alternativeValue>\"u\"?`\\${${t.name}}`:t.alternativeValue.length===0?`\\${${t.name}:+}`:`\\${${t.name}:+${t.alternativeValue.map(o=>qg(o)).join(\" \")}}`:t.defaultValue.length===0?`\\${${t.name}:-}`:`\\${${t.name}:-${t.defaultValue.map(o=>qg(o)).join(\" \")}}`,t.quoted);case\"arithmetic\":return`$(( ${MD(t.arithmetic)} ))`;default:throw new Error(`Unsupported argument segment type: \"${t.type}\"`)}}function MD(t){let e=a=>{switch(a){case\"addition\":return\"+\";case\"subtraction\":return\"-\";case\"multiplication\":return\"*\";case\"division\":return\"/\";default:throw new Error(`Can't extract operator from arithmetic expression of type \"${a}\"`)}},r=(a,n)=>n?`( ${a} )`:a,o=a=>r(MD(a),![\"number\",\"variable\"].includes(a.type));switch(t.type){case\"number\":return String(t.value);case\"variable\":return t.name;default:return`${o(t.left)} ${e(t.type)} ${o(t.right)}`}}var rW,nW,d8e,iW,m8e,sW=Et(()=>{rW=$e(tW());nW=new Map([[\"\\f\",\"\\\\f\"],[`\n`,\"\\\\n\"],[\"\\r\",\"\\\\r\"],[\"\t\",\"\\\\t\"],[\"\\v\",\"\\\\v\"],[\"\\0\",\"\\\\0\"]]),d8e=new Map([[\"\\\\\",\"\\\\\\\\\"],[\"$\",\"\\\\$\"],['\"','\\\\\"'],...Array.from(nW,([t,e])=>[t,`\"$'${e}'\"`])]),iW=t=>nW.get(t)??`\\\\x${t.charCodeAt(0).toString(16).padStart(2,\"0\")}`,m8e=t=>d8e.get(t)??`\"$'${iW(t)}'\"`});var aW=_((Rbt,oW)=>{\"use strict\";function y8e(t,e){function r(){this.constructor=t}r.prototype=e.prototype,t.prototype=new r}function Gg(t,e,r,o){this.message=t,this.expected=e,this.found=r,this.location=o,this.name=\"SyntaxError\",typeof Error.captureStackTrace==\"function\"&&Error.captureStackTrace(this,Gg)}y8e(Gg,Error);Gg.buildMessage=function(t,e){var r={literal:function(h){return'\"'+a(h.text)+'\"'},class:function(h){var C=\"\",I;for(I=0;I<h.parts.length;I++)C+=h.parts[I]instanceof Array?n(h.parts[I][0])+\"-\"+n(h.parts[I][1]):n(h.parts[I]);return\"[\"+(h.inverted?\"^\":\"\")+C+\"]\"},any:function(h){return\"any character\"},end:function(h){return\"end of input\"},other:function(h){return h.description}};function o(h){return h.charCodeAt(0).toString(16).toUpperCase()}function a(h){return h.replace(/\\\\/g,\"\\\\\\\\\").replace(/\"/g,'\\\\\"').replace(/\\0/g,\"\\\\0\").replace(/\\t/g,\"\\\\t\").replace(/\\n/g,\"\\\\n\").replace(/\\r/g,\"\\\\r\").replace(/[\\x00-\\x0F]/g,function(C){return\"\\\\x0\"+o(C)}).replace(/[\\x10-\\x1F\\x7F-\\x9F]/g,function(C){return\"\\\\x\"+o(C)})}function n(h){return h.replace(/\\\\/g,\"\\\\\\\\\").replace(/\\]/g,\"\\\\]\").replace(/\\^/g,\"\\\\^\").replace(/-/g,\"\\\\-\").replace(/\\0/g,\"\\\\0\").replace(/\\t/g,\"\\\\t\").replace(/\\n/g,\"\\\\n\").replace(/\\r/g,\"\\\\r\").replace(/[\\x00-\\x0F]/g,function(C){return\"\\\\x0\"+o(C)}).replace(/[\\x10-\\x1F\\x7F-\\x9F]/g,function(C){return\"\\\\x\"+o(C)})}function u(h){return r[h.type](h)}function A(h){var C=new Array(h.length),I,v;for(I=0;I<h.length;I++)C[I]=u(h[I]);if(C.sort(),C.length>0){for(I=1,v=1;I<C.length;I++)C[I-1]!==C[I]&&(C[v]=C[I],v++);C.length=v}switch(C.length){case 1:return C[0];case 2:return C[0]+\" or \"+C[1];default:return C.slice(0,-1).join(\", \")+\", or \"+C[C.length-1]}}function p(h){return h?'\"'+a(h)+'\"':\"end of input\"}return\"Expected \"+A(t)+\" but \"+p(e)+\" found.\"};function E8e(t,e){e=e!==void 0?e:{};var r={},o={resolution:ke},a=ke,n=\"/\",u=De(\"/\",!1),A=function(He,b){return{from:He,descriptor:b}},p=function(He){return{descriptor:He}},h=\"@\",C=De(\"@\",!1),I=function(He,b){return{fullName:He,description:b}},v=function(He){return{fullName:He}},x=function(){return Ie()},E=/^[^\\/@]/,R=ce([\"/\",\"@\"],!0,!1),L=/^[^\\/]/,U=ce([\"/\"],!0,!1),z=0,te=0,le=[{line:1,column:1}],he=0,Ae=[],ye=0,ae;if(\"startRule\"in e){if(!(e.startRule in o))throw new Error(`Can't start parsing from rule \"`+e.startRule+'\".');a=o[e.startRule]}function Ie(){return t.substring(te,z)}function Fe(){return ht(te,z)}function g(He,b){throw b=b!==void 0?b:ht(te,z),Te([we(He)],t.substring(te,z),b)}function Ee(He,b){throw b=b!==void 0?b:ht(te,z),lt(He,b)}function De(He,b){return{type:\"literal\",text:He,ignoreCase:b}}function ce(He,b,w){return{type:\"class\",parts:He,inverted:b,ignoreCase:w}}function ne(){return{type:\"any\"}}function ee(){return{type:\"end\"}}function we(He){return{type:\"other\",description:He}}function xe(He){var b=le[He],w;if(b)return b;for(w=He-1;!le[w];)w--;for(b=le[w],b={line:b.line,column:b.column};w<He;)t.charCodeAt(w)===10?(b.line++,b.column=1):b.column++,w++;return le[He]=b,b}function ht(He,b){var w=xe(He),S=xe(b);return{start:{offset:He,line:w.line,column:w.column},end:{offset:b,line:S.line,column:S.column}}}function H(He){z<he||(z>he&&(he=z,Ae=[]),Ae.push(He))}function lt(He,b){return new Gg(He,null,null,b)}function Te(He,b,w){return new Gg(Gg.buildMessage(He,b),He,b,w)}function ke(){var He,b,w,S;return He=z,b=be(),b!==r?(t.charCodeAt(z)===47?(w=n,z++):(w=r,ye===0&&H(u)),w!==r?(S=be(),S!==r?(te=He,b=A(b,S),He=b):(z=He,He=r)):(z=He,He=r)):(z=He,He=r),He===r&&(He=z,b=be(),b!==r&&(te=He,b=p(b)),He=b),He}function be(){var He,b,w,S;return He=z,b=_e(),b!==r?(t.charCodeAt(z)===64?(w=h,z++):(w=r,ye===0&&H(C)),w!==r?(S=ze(),S!==r?(te=He,b=I(b,S),He=b):(z=He,He=r)):(z=He,He=r)):(z=He,He=r),He===r&&(He=z,b=_e(),b!==r&&(te=He,b=v(b)),He=b),He}function _e(){var He,b,w,S,y;return He=z,t.charCodeAt(z)===64?(b=h,z++):(b=r,ye===0&&H(C)),b!==r?(w=Re(),w!==r?(t.charCodeAt(z)===47?(S=n,z++):(S=r,ye===0&&H(u)),S!==r?(y=Re(),y!==r?(te=He,b=x(),He=b):(z=He,He=r)):(z=He,He=r)):(z=He,He=r)):(z=He,He=r),He===r&&(He=z,b=Re(),b!==r&&(te=He,b=x()),He=b),He}function Re(){var He,b,w;if(He=z,b=[],E.test(t.charAt(z))?(w=t.charAt(z),z++):(w=r,ye===0&&H(R)),w!==r)for(;w!==r;)b.push(w),E.test(t.charAt(z))?(w=t.charAt(z),z++):(w=r,ye===0&&H(R));else b=r;return b!==r&&(te=He,b=x()),He=b,He}function ze(){var He,b,w;if(He=z,b=[],L.test(t.charAt(z))?(w=t.charAt(z),z++):(w=r,ye===0&&H(U)),w!==r)for(;w!==r;)b.push(w),L.test(t.charAt(z))?(w=t.charAt(z),z++):(w=r,ye===0&&H(U));else b=r;return b!==r&&(te=He,b=x()),He=b,He}if(ae=a(),ae!==r&&z===t.length)return ae;throw ae!==r&&z<t.length&&H(ee()),Te(Ae,he<t.length?t.charAt(he):null,he<t.length?ht(he,he+1):ht(he,he))}oW.exports={SyntaxError:Gg,parse:E8e}});function UD(t){let e=t.match(/^\\*{1,2}\\/(.*)/);if(e)throw new Error(`The override for '${t}' includes a glob pattern. Glob patterns have been removed since their behaviours don't match what you'd expect. Set the override to '${e[1]}' instead.`);try{return(0,lW.parse)(t)}catch(r){throw r.location&&(r.message=r.message.replace(/(\\.)?$/,` (line ${r.location.start.line}, column ${r.location.start.column})$1`)),r}}function _D(t){let e=\"\";return t.from&&(e+=t.from.fullName,t.from.description&&(e+=`@${t.from.description}`),e+=\"/\"),e+=t.descriptor.fullName,t.descriptor.description&&(e+=`@${t.descriptor.description}`),e}var lW,cW=Et(()=>{lW=$e(aW())});var Wg=_((Nbt,Yg)=>{\"use strict\";function uW(t){return typeof t>\"u\"||t===null}function C8e(t){return typeof t==\"object\"&&t!==null}function w8e(t){return Array.isArray(t)?t:uW(t)?[]:[t]}function I8e(t,e){var r,o,a,n;if(e)for(n=Object.keys(e),r=0,o=n.length;r<o;r+=1)a=n[r],t[a]=e[a];return t}function B8e(t,e){var r=\"\",o;for(o=0;o<e;o+=1)r+=t;return r}function v8e(t){return t===0&&Number.NEGATIVE_INFINITY===1/t}Yg.exports.isNothing=uW;Yg.exports.isObject=C8e;Yg.exports.toArray=w8e;Yg.exports.repeat=B8e;Yg.exports.isNegativeZero=v8e;Yg.exports.extend=I8e});var cy=_((Lbt,AW)=>{\"use strict\";function Vw(t,e){Error.call(this),this.name=\"YAMLException\",this.reason=t,this.mark=e,this.message=(this.reason||\"(unknown reason)\")+(this.mark?\" \"+this.mark.toString():\"\"),Error.captureStackTrace?Error.captureStackTrace(this,this.constructor):this.stack=new Error().stack||\"\"}Vw.prototype=Object.create(Error.prototype);Vw.prototype.constructor=Vw;Vw.prototype.toString=function(e){var r=this.name+\": \";return r+=this.reason||\"(unknown reason)\",!e&&this.mark&&(r+=\" \"+this.mark.toString()),r};AW.exports=Vw});var hW=_((Obt,pW)=>{\"use strict\";var fW=Wg();function pT(t,e,r,o,a){this.name=t,this.buffer=e,this.position=r,this.line=o,this.column=a}pT.prototype.getSnippet=function(e,r){var o,a,n,u,A;if(!this.buffer)return null;for(e=e||4,r=r||75,o=\"\",a=this.position;a>0&&`\\0\\r\n\\x85\\u2028\\u2029`.indexOf(this.buffer.charAt(a-1))===-1;)if(a-=1,this.position-a>r/2-1){o=\" ... \",a+=5;break}for(n=\"\",u=this.position;u<this.buffer.length&&`\\0\\r\n\\x85\\u2028\\u2029`.indexOf(this.buffer.charAt(u))===-1;)if(u+=1,u-this.position>r/2-1){n=\" ... \",u-=5;break}return A=this.buffer.slice(a,u),fW.repeat(\" \",e)+o+A+n+`\n`+fW.repeat(\" \",e+this.position-a+o.length)+\"^\"};pT.prototype.toString=function(e){var r,o=\"\";return this.name&&(o+='in \"'+this.name+'\" '),o+=\"at line \"+(this.line+1)+\", column \"+(this.column+1),e||(r=this.getSnippet(),r&&(o+=`:\n`+r)),o};pW.exports=pT});var os=_((Mbt,dW)=>{\"use strict\";var gW=cy(),D8e=[\"kind\",\"resolve\",\"construct\",\"instanceOf\",\"predicate\",\"represent\",\"defaultStyle\",\"styleAliases\"],P8e=[\"scalar\",\"sequence\",\"mapping\"];function S8e(t){var e={};return t!==null&&Object.keys(t).forEach(function(r){t[r].forEach(function(o){e[String(o)]=r})}),e}function b8e(t,e){if(e=e||{},Object.keys(e).forEach(function(r){if(D8e.indexOf(r)===-1)throw new gW('Unknown option \"'+r+'\" is met in definition of \"'+t+'\" YAML type.')}),this.tag=t,this.kind=e.kind||null,this.resolve=e.resolve||function(){return!0},this.construct=e.construct||function(r){return r},this.instanceOf=e.instanceOf||null,this.predicate=e.predicate||null,this.represent=e.represent||null,this.defaultStyle=e.defaultStyle||null,this.styleAliases=S8e(e.styleAliases||null),P8e.indexOf(this.kind)===-1)throw new gW('Unknown kind \"'+this.kind+'\" is specified for \"'+t+'\" YAML type.')}dW.exports=b8e});var Kg=_((Ubt,yW)=>{\"use strict\";var mW=Wg(),HD=cy(),x8e=os();function hT(t,e,r){var o=[];return t.include.forEach(function(a){r=hT(a,e,r)}),t[e].forEach(function(a){r.forEach(function(n,u){n.tag===a.tag&&n.kind===a.kind&&o.push(u)}),r.push(a)}),r.filter(function(a,n){return o.indexOf(n)===-1})}function k8e(){var t={scalar:{},sequence:{},mapping:{},fallback:{}},e,r;function o(a){t[a.kind][a.tag]=t.fallback[a.tag]=a}for(e=0,r=arguments.length;e<r;e+=1)arguments[e].forEach(o);return t}function uy(t){this.include=t.include||[],this.implicit=t.implicit||[],this.explicit=t.explicit||[],this.implicit.forEach(function(e){if(e.loadKind&&e.loadKind!==\"scalar\")throw new HD(\"There is a non-scalar type in the implicit list of a schema. Implicit resolving of such types is not supported.\")}),this.compiledImplicit=hT(this,\"implicit\",[]),this.compiledExplicit=hT(this,\"explicit\",[]),this.compiledTypeMap=k8e(this.compiledImplicit,this.compiledExplicit)}uy.DEFAULT=null;uy.create=function(){var e,r;switch(arguments.length){case 1:e=uy.DEFAULT,r=arguments[0];break;case 2:e=arguments[0],r=arguments[1];break;default:throw new HD(\"Wrong number of arguments for Schema.create function\")}if(e=mW.toArray(e),r=mW.toArray(r),!e.every(function(o){return o instanceof uy}))throw new HD(\"Specified list of super schemas (or a single Schema object) contains a non-Schema object.\");if(!r.every(function(o){return o instanceof x8e}))throw new HD(\"Specified list of YAML types (or a single Type object) contains a non-Type object.\");return new uy({include:e,explicit:r})};yW.exports=uy});var CW=_((_bt,EW)=>{\"use strict\";var Q8e=os();EW.exports=new Q8e(\"tag:yaml.org,2002:str\",{kind:\"scalar\",construct:function(t){return t!==null?t:\"\"}})});var IW=_((Hbt,wW)=>{\"use strict\";var F8e=os();wW.exports=new F8e(\"tag:yaml.org,2002:seq\",{kind:\"sequence\",construct:function(t){return t!==null?t:[]}})});var vW=_((jbt,BW)=>{\"use strict\";var R8e=os();BW.exports=new R8e(\"tag:yaml.org,2002:map\",{kind:\"mapping\",construct:function(t){return t!==null?t:{}}})});var jD=_((qbt,DW)=>{\"use strict\";var T8e=Kg();DW.exports=new T8e({explicit:[CW(),IW(),vW()]})});var SW=_((Gbt,PW)=>{\"use strict\";var N8e=os();function L8e(t){if(t===null)return!0;var e=t.length;return e===1&&t===\"~\"||e===4&&(t===\"null\"||t===\"Null\"||t===\"NULL\")}function O8e(){return null}function M8e(t){return t===null}PW.exports=new N8e(\"tag:yaml.org,2002:null\",{kind:\"scalar\",resolve:L8e,construct:O8e,predicate:M8e,represent:{canonical:function(){return\"~\"},lowercase:function(){return\"null\"},uppercase:function(){return\"NULL\"},camelcase:function(){return\"Null\"}},defaultStyle:\"lowercase\"})});var xW=_((Ybt,bW)=>{\"use strict\";var U8e=os();function _8e(t){if(t===null)return!1;var e=t.length;return e===4&&(t===\"true\"||t===\"True\"||t===\"TRUE\")||e===5&&(t===\"false\"||t===\"False\"||t===\"FALSE\")}function H8e(t){return t===\"true\"||t===\"True\"||t===\"TRUE\"}function j8e(t){return Object.prototype.toString.call(t)===\"[object Boolean]\"}bW.exports=new U8e(\"tag:yaml.org,2002:bool\",{kind:\"scalar\",resolve:_8e,construct:H8e,predicate:j8e,represent:{lowercase:function(t){return t?\"true\":\"false\"},uppercase:function(t){return t?\"TRUE\":\"FALSE\"},camelcase:function(t){return t?\"True\":\"False\"}},defaultStyle:\"lowercase\"})});var QW=_((Wbt,kW)=>{\"use strict\";var q8e=Wg(),G8e=os();function Y8e(t){return 48<=t&&t<=57||65<=t&&t<=70||97<=t&&t<=102}function W8e(t){return 48<=t&&t<=55}function K8e(t){return 48<=t&&t<=57}function V8e(t){if(t===null)return!1;var e=t.length,r=0,o=!1,a;if(!e)return!1;if(a=t[r],(a===\"-\"||a===\"+\")&&(a=t[++r]),a===\"0\"){if(r+1===e)return!0;if(a=t[++r],a===\"b\"){for(r++;r<e;r++)if(a=t[r],a!==\"_\"){if(a!==\"0\"&&a!==\"1\")return!1;o=!0}return o&&a!==\"_\"}if(a===\"x\"){for(r++;r<e;r++)if(a=t[r],a!==\"_\"){if(!Y8e(t.charCodeAt(r)))return!1;o=!0}return o&&a!==\"_\"}for(;r<e;r++)if(a=t[r],a!==\"_\"){if(!W8e(t.charCodeAt(r)))return!1;o=!0}return o&&a!==\"_\"}if(a===\"_\")return!1;for(;r<e;r++)if(a=t[r],a!==\"_\"){if(a===\":\")break;if(!K8e(t.charCodeAt(r)))return!1;o=!0}return!o||a===\"_\"?!1:a!==\":\"?!0:/^(:[0-5]?[0-9])+$/.test(t.slice(r))}function z8e(t){var e=t,r=1,o,a,n=[];return e.indexOf(\"_\")!==-1&&(e=e.replace(/_/g,\"\")),o=e[0],(o===\"-\"||o===\"+\")&&(o===\"-\"&&(r=-1),e=e.slice(1),o=e[0]),e===\"0\"?0:o===\"0\"?e[1]===\"b\"?r*parseInt(e.slice(2),2):e[1]===\"x\"?r*parseInt(e,16):r*parseInt(e,8):e.indexOf(\":\")!==-1?(e.split(\":\").forEach(function(u){n.unshift(parseInt(u,10))}),e=0,a=1,n.forEach(function(u){e+=u*a,a*=60}),r*e):r*parseInt(e,10)}function J8e(t){return Object.prototype.toString.call(t)===\"[object Number]\"&&t%1===0&&!q8e.isNegativeZero(t)}kW.exports=new G8e(\"tag:yaml.org,2002:int\",{kind:\"scalar\",resolve:V8e,construct:z8e,predicate:J8e,represent:{binary:function(t){return t>=0?\"0b\"+t.toString(2):\"-0b\"+t.toString(2).slice(1)},octal:function(t){return t>=0?\"0\"+t.toString(8):\"-0\"+t.toString(8).slice(1)},decimal:function(t){return t.toString(10)},hexadecimal:function(t){return t>=0?\"0x\"+t.toString(16).toUpperCase():\"-0x\"+t.toString(16).toUpperCase().slice(1)}},defaultStyle:\"decimal\",styleAliases:{binary:[2,\"bin\"],octal:[8,\"oct\"],decimal:[10,\"dec\"],hexadecimal:[16,\"hex\"]}})});var TW=_((Kbt,RW)=>{\"use strict\";var FW=Wg(),X8e=os(),Z8e=new RegExp(\"^(?:[-+]?(?:0|[1-9][0-9_]*)(?:\\\\.[0-9_]*)?(?:[eE][-+]?[0-9]+)?|\\\\.[0-9_]+(?:[eE][-+]?[0-9]+)?|[-+]?[0-9][0-9_]*(?::[0-5]?[0-9])+\\\\.[0-9_]*|[-+]?\\\\.(?:inf|Inf|INF)|\\\\.(?:nan|NaN|NAN))$\");function $8e(t){return!(t===null||!Z8e.test(t)||t[t.length-1]===\"_\")}function eHe(t){var e,r,o,a;return e=t.replace(/_/g,\"\").toLowerCase(),r=e[0]===\"-\"?-1:1,a=[],\"+-\".indexOf(e[0])>=0&&(e=e.slice(1)),e===\".inf\"?r===1?Number.POSITIVE_INFINITY:Number.NEGATIVE_INFINITY:e===\".nan\"?NaN:e.indexOf(\":\")>=0?(e.split(\":\").forEach(function(n){a.unshift(parseFloat(n,10))}),e=0,o=1,a.forEach(function(n){e+=n*o,o*=60}),r*e):r*parseFloat(e,10)}var tHe=/^[-+]?[0-9]+e/;function rHe(t,e){var r;if(isNaN(t))switch(e){case\"lowercase\":return\".nan\";case\"uppercase\":return\".NAN\";case\"camelcase\":return\".NaN\"}else if(Number.POSITIVE_INFINITY===t)switch(e){case\"lowercase\":return\".inf\";case\"uppercase\":return\".INF\";case\"camelcase\":return\".Inf\"}else if(Number.NEGATIVE_INFINITY===t)switch(e){case\"lowercase\":return\"-.inf\";case\"uppercase\":return\"-.INF\";case\"camelcase\":return\"-.Inf\"}else if(FW.isNegativeZero(t))return\"-0.0\";return r=t.toString(10),tHe.test(r)?r.replace(\"e\",\".e\"):r}function nHe(t){return Object.prototype.toString.call(t)===\"[object Number]\"&&(t%1!==0||FW.isNegativeZero(t))}RW.exports=new X8e(\"tag:yaml.org,2002:float\",{kind:\"scalar\",resolve:$8e,construct:eHe,predicate:nHe,represent:rHe,defaultStyle:\"lowercase\"})});var gT=_((Vbt,NW)=>{\"use strict\";var iHe=Kg();NW.exports=new iHe({include:[jD()],implicit:[SW(),xW(),QW(),TW()]})});var dT=_((zbt,LW)=>{\"use strict\";var sHe=Kg();LW.exports=new sHe({include:[gT()]})});var _W=_((Jbt,UW)=>{\"use strict\";var oHe=os(),OW=new RegExp(\"^([0-9][0-9][0-9][0-9])-([0-9][0-9])-([0-9][0-9])$\"),MW=new RegExp(\"^([0-9][0-9][0-9][0-9])-([0-9][0-9]?)-([0-9][0-9]?)(?:[Tt]|[ \\\\t]+)([0-9][0-9]?):([0-9][0-9]):([0-9][0-9])(?:\\\\.([0-9]*))?(?:[ \\\\t]*(Z|([-+])([0-9][0-9]?)(?::([0-9][0-9]))?))?$\");function aHe(t){return t===null?!1:OW.exec(t)!==null||MW.exec(t)!==null}function lHe(t){var e,r,o,a,n,u,A,p=0,h=null,C,I,v;if(e=OW.exec(t),e===null&&(e=MW.exec(t)),e===null)throw new Error(\"Date resolve error\");if(r=+e[1],o=+e[2]-1,a=+e[3],!e[4])return new Date(Date.UTC(r,o,a));if(n=+e[4],u=+e[5],A=+e[6],e[7]){for(p=e[7].slice(0,3);p.length<3;)p+=\"0\";p=+p}return e[9]&&(C=+e[10],I=+(e[11]||0),h=(C*60+I)*6e4,e[9]===\"-\"&&(h=-h)),v=new Date(Date.UTC(r,o,a,n,u,A,p)),h&&v.setTime(v.getTime()-h),v}function cHe(t){return t.toISOString()}UW.exports=new oHe(\"tag:yaml.org,2002:timestamp\",{kind:\"scalar\",resolve:aHe,construct:lHe,instanceOf:Date,represent:cHe})});var jW=_((Xbt,HW)=>{\"use strict\";var uHe=os();function AHe(t){return t===\"<<\"||t===null}HW.exports=new uHe(\"tag:yaml.org,2002:merge\",{kind:\"scalar\",resolve:AHe})});var YW=_((Zbt,GW)=>{\"use strict\";var Vg;try{qW=Be,Vg=qW(\"buffer\").Buffer}catch{}var qW,fHe=os(),mT=`ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=\n\\r`;function pHe(t){if(t===null)return!1;var e,r,o=0,a=t.length,n=mT;for(r=0;r<a;r++)if(e=n.indexOf(t.charAt(r)),!(e>64)){if(e<0)return!1;o+=6}return o%8===0}function hHe(t){var e,r,o=t.replace(/[\\r\\n=]/g,\"\"),a=o.length,n=mT,u=0,A=[];for(e=0;e<a;e++)e%4===0&&e&&(A.push(u>>16&255),A.push(u>>8&255),A.push(u&255)),u=u<<6|n.indexOf(o.charAt(e));return r=a%4*6,r===0?(A.push(u>>16&255),A.push(u>>8&255),A.push(u&255)):r===18?(A.push(u>>10&255),A.push(u>>2&255)):r===12&&A.push(u>>4&255),Vg?Vg.from?Vg.from(A):new Vg(A):A}function gHe(t){var e=\"\",r=0,o,a,n=t.length,u=mT;for(o=0;o<n;o++)o%3===0&&o&&(e+=u[r>>18&63],e+=u[r>>12&63],e+=u[r>>6&63],e+=u[r&63]),r=(r<<8)+t[o];return a=n%3,a===0?(e+=u[r>>18&63],e+=u[r>>12&63],e+=u[r>>6&63],e+=u[r&63]):a===2?(e+=u[r>>10&63],e+=u[r>>4&63],e+=u[r<<2&63],e+=u[64]):a===1&&(e+=u[r>>2&63],e+=u[r<<4&63],e+=u[64],e+=u[64]),e}function dHe(t){return Vg&&Vg.isBuffer(t)}GW.exports=new fHe(\"tag:yaml.org,2002:binary\",{kind:\"scalar\",resolve:pHe,construct:hHe,predicate:dHe,represent:gHe})});var KW=_((ext,WW)=>{\"use strict\";var mHe=os(),yHe=Object.prototype.hasOwnProperty,EHe=Object.prototype.toString;function CHe(t){if(t===null)return!0;var e=[],r,o,a,n,u,A=t;for(r=0,o=A.length;r<o;r+=1){if(a=A[r],u=!1,EHe.call(a)!==\"[object Object]\")return!1;for(n in a)if(yHe.call(a,n))if(!u)u=!0;else return!1;if(!u)return!1;if(e.indexOf(n)===-1)e.push(n);else return!1}return!0}function wHe(t){return t!==null?t:[]}WW.exports=new mHe(\"tag:yaml.org,2002:omap\",{kind:\"sequence\",resolve:CHe,construct:wHe})});var zW=_((txt,VW)=>{\"use strict\";var IHe=os(),BHe=Object.prototype.toString;function vHe(t){if(t===null)return!0;var e,r,o,a,n,u=t;for(n=new Array(u.length),e=0,r=u.length;e<r;e+=1){if(o=u[e],BHe.call(o)!==\"[object Object]\"||(a=Object.keys(o),a.length!==1))return!1;n[e]=[a[0],o[a[0]]]}return!0}function DHe(t){if(t===null)return[];var e,r,o,a,n,u=t;for(n=new Array(u.length),e=0,r=u.length;e<r;e+=1)o=u[e],a=Object.keys(o),n[e]=[a[0],o[a[0]]];return n}VW.exports=new IHe(\"tag:yaml.org,2002:pairs\",{kind:\"sequence\",resolve:vHe,construct:DHe})});var XW=_((rxt,JW)=>{\"use strict\";var PHe=os(),SHe=Object.prototype.hasOwnProperty;function bHe(t){if(t===null)return!0;var e,r=t;for(e in r)if(SHe.call(r,e)&&r[e]!==null)return!1;return!0}function xHe(t){return t!==null?t:{}}JW.exports=new PHe(\"tag:yaml.org,2002:set\",{kind:\"mapping\",resolve:bHe,construct:xHe})});var Ay=_((nxt,ZW)=>{\"use strict\";var kHe=Kg();ZW.exports=new kHe({include:[dT()],implicit:[_W(),jW()],explicit:[YW(),KW(),zW(),XW()]})});var eK=_((ixt,$W)=>{\"use strict\";var QHe=os();function FHe(){return!0}function RHe(){}function THe(){return\"\"}function NHe(t){return typeof t>\"u\"}$W.exports=new QHe(\"tag:yaml.org,2002:js/undefined\",{kind:\"scalar\",resolve:FHe,construct:RHe,predicate:NHe,represent:THe})});var rK=_((sxt,tK)=>{\"use strict\";var LHe=os();function OHe(t){if(t===null||t.length===0)return!1;var e=t,r=/\\/([gim]*)$/.exec(t),o=\"\";return!(e[0]===\"/\"&&(r&&(o=r[1]),o.length>3||e[e.length-o.length-1]!==\"/\"))}function MHe(t){var e=t,r=/\\/([gim]*)$/.exec(t),o=\"\";return e[0]===\"/\"&&(r&&(o=r[1]),e=e.slice(1,e.length-o.length-1)),new RegExp(e,o)}function UHe(t){var e=\"/\"+t.source+\"/\";return t.global&&(e+=\"g\"),t.multiline&&(e+=\"m\"),t.ignoreCase&&(e+=\"i\"),e}function _He(t){return Object.prototype.toString.call(t)===\"[object RegExp]\"}tK.exports=new LHe(\"tag:yaml.org,2002:js/regexp\",{kind:\"scalar\",resolve:OHe,construct:MHe,predicate:_He,represent:UHe})});var sK=_((oxt,iK)=>{\"use strict\";var qD;try{nK=Be,qD=nK(\"esprima\")}catch{typeof window<\"u\"&&(qD=window.esprima)}var nK,HHe=os();function jHe(t){if(t===null)return!1;try{var e=\"(\"+t+\")\",r=qD.parse(e,{range:!0});return!(r.type!==\"Program\"||r.body.length!==1||r.body[0].type!==\"ExpressionStatement\"||r.body[0].expression.type!==\"ArrowFunctionExpression\"&&r.body[0].expression.type!==\"FunctionExpression\")}catch{return!1}}function qHe(t){var e=\"(\"+t+\")\",r=qD.parse(e,{range:!0}),o=[],a;if(r.type!==\"Program\"||r.body.length!==1||r.body[0].type!==\"ExpressionStatement\"||r.body[0].expression.type!==\"ArrowFunctionExpression\"&&r.body[0].expression.type!==\"FunctionExpression\")throw new Error(\"Failed to resolve function\");return r.body[0].expression.params.forEach(function(n){o.push(n.name)}),a=r.body[0].expression.body.range,r.body[0].expression.body.type===\"BlockStatement\"?new Function(o,e.slice(a[0]+1,a[1]-1)):new Function(o,\"return \"+e.slice(a[0],a[1]))}function GHe(t){return t.toString()}function YHe(t){return Object.prototype.toString.call(t)===\"[object Function]\"}iK.exports=new HHe(\"tag:yaml.org,2002:js/function\",{kind:\"scalar\",resolve:jHe,construct:qHe,predicate:YHe,represent:GHe})});var zw=_((lxt,aK)=>{\"use strict\";var oK=Kg();aK.exports=oK.DEFAULT=new oK({include:[Ay()],explicit:[eK(),rK(),sK()]})});var PK=_((cxt,Jw)=>{\"use strict\";var mf=Wg(),hK=cy(),WHe=hW(),gK=Ay(),KHe=zw(),qp=Object.prototype.hasOwnProperty,GD=1,dK=2,mK=3,YD=4,yT=1,VHe=2,lK=3,zHe=/[\\x00-\\x08\\x0B\\x0C\\x0E-\\x1F\\x7F-\\x84\\x86-\\x9F\\uFFFE\\uFFFF]|[\\uD800-\\uDBFF](?![\\uDC00-\\uDFFF])|(?:[^\\uD800-\\uDBFF]|^)[\\uDC00-\\uDFFF]/,JHe=/[\\x85\\u2028\\u2029]/,XHe=/[,\\[\\]\\{\\}]/,yK=/^(?:!|!!|![a-z\\-]+!)$/i,EK=/^(?:!|[^,\\[\\]\\{\\}])(?:%[0-9a-f]{2}|[0-9a-z\\-#;\\/\\?:@&=\\+\\$,_\\.!~\\*'\\(\\)\\[\\]])*$/i;function cK(t){return Object.prototype.toString.call(t)}function Hu(t){return t===10||t===13}function Jg(t){return t===9||t===32}function Ia(t){return t===9||t===32||t===10||t===13}function fy(t){return t===44||t===91||t===93||t===123||t===125}function ZHe(t){var e;return 48<=t&&t<=57?t-48:(e=t|32,97<=e&&e<=102?e-97+10:-1)}function $He(t){return t===120?2:t===117?4:t===85?8:0}function e6e(t){return 48<=t&&t<=57?t-48:-1}function uK(t){return t===48?\"\\0\":t===97?\"\\x07\":t===98?\"\\b\":t===116||t===9?\"\t\":t===110?`\n`:t===118?\"\\v\":t===102?\"\\f\":t===114?\"\\r\":t===101?\"\\x1B\":t===32?\" \":t===34?'\"':t===47?\"/\":t===92?\"\\\\\":t===78?\"\\x85\":t===95?\"\\xA0\":t===76?\"\\u2028\":t===80?\"\\u2029\":\"\"}function t6e(t){return t<=65535?String.fromCharCode(t):String.fromCharCode((t-65536>>10)+55296,(t-65536&1023)+56320)}var CK=new Array(256),wK=new Array(256);for(zg=0;zg<256;zg++)CK[zg]=uK(zg)?1:0,wK[zg]=uK(zg);var zg;function r6e(t,e){this.input=t,this.filename=e.filename||null,this.schema=e.schema||KHe,this.onWarning=e.onWarning||null,this.legacy=e.legacy||!1,this.json=e.json||!1,this.listener=e.listener||null,this.implicitTypes=this.schema.compiledImplicit,this.typeMap=this.schema.compiledTypeMap,this.length=t.length,this.position=0,this.line=0,this.lineStart=0,this.lineIndent=0,this.documents=[]}function IK(t,e){return new hK(e,new WHe(t.filename,t.input,t.position,t.line,t.position-t.lineStart))}function Sr(t,e){throw IK(t,e)}function WD(t,e){t.onWarning&&t.onWarning.call(null,IK(t,e))}var AK={YAML:function(e,r,o){var a,n,u;e.version!==null&&Sr(e,\"duplication of %YAML directive\"),o.length!==1&&Sr(e,\"YAML directive accepts exactly one argument\"),a=/^([0-9]+)\\.([0-9]+)$/.exec(o[0]),a===null&&Sr(e,\"ill-formed argument of the YAML directive\"),n=parseInt(a[1],10),u=parseInt(a[2],10),n!==1&&Sr(e,\"unacceptable YAML version of the document\"),e.version=o[0],e.checkLineBreaks=u<2,u!==1&&u!==2&&WD(e,\"unsupported YAML version of the document\")},TAG:function(e,r,o){var a,n;o.length!==2&&Sr(e,\"TAG directive accepts exactly two arguments\"),a=o[0],n=o[1],yK.test(a)||Sr(e,\"ill-formed tag handle (first argument) of the TAG directive\"),qp.call(e.tagMap,a)&&Sr(e,'there is a previously declared suffix for \"'+a+'\" tag handle'),EK.test(n)||Sr(e,\"ill-formed tag prefix (second argument) of the TAG directive\"),e.tagMap[a]=n}};function jp(t,e,r,o){var a,n,u,A;if(e<r){if(A=t.input.slice(e,r),o)for(a=0,n=A.length;a<n;a+=1)u=A.charCodeAt(a),u===9||32<=u&&u<=1114111||Sr(t,\"expected valid JSON character\");else zHe.test(A)&&Sr(t,\"the stream contains non-printable characters\");t.result+=A}}function fK(t,e,r,o){var a,n,u,A;for(mf.isObject(r)||Sr(t,\"cannot merge mappings; the provided source object is unacceptable\"),a=Object.keys(r),u=0,A=a.length;u<A;u+=1)n=a[u],qp.call(e,n)||(e[n]=r[n],o[n]=!0)}function py(t,e,r,o,a,n,u,A){var p,h;if(Array.isArray(a))for(a=Array.prototype.slice.call(a),p=0,h=a.length;p<h;p+=1)Array.isArray(a[p])&&Sr(t,\"nested arrays are not supported inside keys\"),typeof a==\"object\"&&cK(a[p])===\"[object Object]\"&&(a[p]=\"[object Object]\");if(typeof a==\"object\"&&cK(a)===\"[object Object]\"&&(a=\"[object Object]\"),a=String(a),e===null&&(e={}),o===\"tag:yaml.org,2002:merge\")if(Array.isArray(n))for(p=0,h=n.length;p<h;p+=1)fK(t,e,n[p],r);else fK(t,e,n,r);else!t.json&&!qp.call(r,a)&&qp.call(e,a)&&(t.line=u||t.line,t.position=A||t.position,Sr(t,\"duplicated mapping key\")),e[a]=n,delete r[a];return e}function ET(t){var e;e=t.input.charCodeAt(t.position),e===10?t.position++:e===13?(t.position++,t.input.charCodeAt(t.position)===10&&t.position++):Sr(t,\"a line break is expected\"),t.line+=1,t.lineStart=t.position}function Wi(t,e,r){for(var o=0,a=t.input.charCodeAt(t.position);a!==0;){for(;Jg(a);)a=t.input.charCodeAt(++t.position);if(e&&a===35)do a=t.input.charCodeAt(++t.position);while(a!==10&&a!==13&&a!==0);if(Hu(a))for(ET(t),a=t.input.charCodeAt(t.position),o++,t.lineIndent=0;a===32;)t.lineIndent++,a=t.input.charCodeAt(++t.position);else break}return r!==-1&&o!==0&&t.lineIndent<r&&WD(t,\"deficient indentation\"),o}function KD(t){var e=t.position,r;return r=t.input.charCodeAt(e),!!((r===45||r===46)&&r===t.input.charCodeAt(e+1)&&r===t.input.charCodeAt(e+2)&&(e+=3,r=t.input.charCodeAt(e),r===0||Ia(r)))}function CT(t,e){e===1?t.result+=\" \":e>1&&(t.result+=mf.repeat(`\n`,e-1))}function n6e(t,e,r){var o,a,n,u,A,p,h,C,I=t.kind,v=t.result,x;if(x=t.input.charCodeAt(t.position),Ia(x)||fy(x)||x===35||x===38||x===42||x===33||x===124||x===62||x===39||x===34||x===37||x===64||x===96||(x===63||x===45)&&(a=t.input.charCodeAt(t.position+1),Ia(a)||r&&fy(a)))return!1;for(t.kind=\"scalar\",t.result=\"\",n=u=t.position,A=!1;x!==0;){if(x===58){if(a=t.input.charCodeAt(t.position+1),Ia(a)||r&&fy(a))break}else if(x===35){if(o=t.input.charCodeAt(t.position-1),Ia(o))break}else{if(t.position===t.lineStart&&KD(t)||r&&fy(x))break;if(Hu(x))if(p=t.line,h=t.lineStart,C=t.lineIndent,Wi(t,!1,-1),t.lineIndent>=e){A=!0,x=t.input.charCodeAt(t.position);continue}else{t.position=u,t.line=p,t.lineStart=h,t.lineIndent=C;break}}A&&(jp(t,n,u,!1),CT(t,t.line-p),n=u=t.position,A=!1),Jg(x)||(u=t.position+1),x=t.input.charCodeAt(++t.position)}return jp(t,n,u,!1),t.result?!0:(t.kind=I,t.result=v,!1)}function i6e(t,e){var r,o,a;if(r=t.input.charCodeAt(t.position),r!==39)return!1;for(t.kind=\"scalar\",t.result=\"\",t.position++,o=a=t.position;(r=t.input.charCodeAt(t.position))!==0;)if(r===39)if(jp(t,o,t.position,!0),r=t.input.charCodeAt(++t.position),r===39)o=t.position,t.position++,a=t.position;else return!0;else Hu(r)?(jp(t,o,a,!0),CT(t,Wi(t,!1,e)),o=a=t.position):t.position===t.lineStart&&KD(t)?Sr(t,\"unexpected end of the document within a single quoted scalar\"):(t.position++,a=t.position);Sr(t,\"unexpected end of the stream within a single quoted scalar\")}function s6e(t,e){var r,o,a,n,u,A;if(A=t.input.charCodeAt(t.position),A!==34)return!1;for(t.kind=\"scalar\",t.result=\"\",t.position++,r=o=t.position;(A=t.input.charCodeAt(t.position))!==0;){if(A===34)return jp(t,r,t.position,!0),t.position++,!0;if(A===92){if(jp(t,r,t.position,!0),A=t.input.charCodeAt(++t.position),Hu(A))Wi(t,!1,e);else if(A<256&&CK[A])t.result+=wK[A],t.position++;else if((u=$He(A))>0){for(a=u,n=0;a>0;a--)A=t.input.charCodeAt(++t.position),(u=ZHe(A))>=0?n=(n<<4)+u:Sr(t,\"expected hexadecimal character\");t.result+=t6e(n),t.position++}else Sr(t,\"unknown escape sequence\");r=o=t.position}else Hu(A)?(jp(t,r,o,!0),CT(t,Wi(t,!1,e)),r=o=t.position):t.position===t.lineStart&&KD(t)?Sr(t,\"unexpected end of the document within a double quoted scalar\"):(t.position++,o=t.position)}Sr(t,\"unexpected end of the stream within a double quoted scalar\")}function o6e(t,e){var r=!0,o,a=t.tag,n,u=t.anchor,A,p,h,C,I,v={},x,E,R,L;if(L=t.input.charCodeAt(t.position),L===91)p=93,I=!1,n=[];else if(L===123)p=125,I=!0,n={};else return!1;for(t.anchor!==null&&(t.anchorMap[t.anchor]=n),L=t.input.charCodeAt(++t.position);L!==0;){if(Wi(t,!0,e),L=t.input.charCodeAt(t.position),L===p)return t.position++,t.tag=a,t.anchor=u,t.kind=I?\"mapping\":\"sequence\",t.result=n,!0;r||Sr(t,\"missed comma between flow collection entries\"),E=x=R=null,h=C=!1,L===63&&(A=t.input.charCodeAt(t.position+1),Ia(A)&&(h=C=!0,t.position++,Wi(t,!0,e))),o=t.line,hy(t,e,GD,!1,!0),E=t.tag,x=t.result,Wi(t,!0,e),L=t.input.charCodeAt(t.position),(C||t.line===o)&&L===58&&(h=!0,L=t.input.charCodeAt(++t.position),Wi(t,!0,e),hy(t,e,GD,!1,!0),R=t.result),I?py(t,n,v,E,x,R):h?n.push(py(t,null,v,E,x,R)):n.push(x),Wi(t,!0,e),L=t.input.charCodeAt(t.position),L===44?(r=!0,L=t.input.charCodeAt(++t.position)):r=!1}Sr(t,\"unexpected end of the stream within a flow collection\")}function a6e(t,e){var r,o,a=yT,n=!1,u=!1,A=e,p=0,h=!1,C,I;if(I=t.input.charCodeAt(t.position),I===124)o=!1;else if(I===62)o=!0;else return!1;for(t.kind=\"scalar\",t.result=\"\";I!==0;)if(I=t.input.charCodeAt(++t.position),I===43||I===45)yT===a?a=I===43?lK:VHe:Sr(t,\"repeat of a chomping mode identifier\");else if((C=e6e(I))>=0)C===0?Sr(t,\"bad explicit indentation width of a block scalar; it cannot be less than one\"):u?Sr(t,\"repeat of an indentation width identifier\"):(A=e+C-1,u=!0);else break;if(Jg(I)){do I=t.input.charCodeAt(++t.position);while(Jg(I));if(I===35)do I=t.input.charCodeAt(++t.position);while(!Hu(I)&&I!==0)}for(;I!==0;){for(ET(t),t.lineIndent=0,I=t.input.charCodeAt(t.position);(!u||t.lineIndent<A)&&I===32;)t.lineIndent++,I=t.input.charCodeAt(++t.position);if(!u&&t.lineIndent>A&&(A=t.lineIndent),Hu(I)){p++;continue}if(t.lineIndent<A){a===lK?t.result+=mf.repeat(`\n`,n?1+p:p):a===yT&&n&&(t.result+=`\n`);break}for(o?Jg(I)?(h=!0,t.result+=mf.repeat(`\n`,n?1+p:p)):h?(h=!1,t.result+=mf.repeat(`\n`,p+1)):p===0?n&&(t.result+=\" \"):t.result+=mf.repeat(`\n`,p):t.result+=mf.repeat(`\n`,n?1+p:p),n=!0,u=!0,p=0,r=t.position;!Hu(I)&&I!==0;)I=t.input.charCodeAt(++t.position);jp(t,r,t.position,!1)}return!0}function pK(t,e){var r,o=t.tag,a=t.anchor,n=[],u,A=!1,p;for(t.anchor!==null&&(t.anchorMap[t.anchor]=n),p=t.input.charCodeAt(t.position);p!==0&&!(p!==45||(u=t.input.charCodeAt(t.position+1),!Ia(u)));){if(A=!0,t.position++,Wi(t,!0,-1)&&t.lineIndent<=e){n.push(null),p=t.input.charCodeAt(t.position);continue}if(r=t.line,hy(t,e,mK,!1,!0),n.push(t.result),Wi(t,!0,-1),p=t.input.charCodeAt(t.position),(t.line===r||t.lineIndent>e)&&p!==0)Sr(t,\"bad indentation of a sequence entry\");else if(t.lineIndent<e)break}return A?(t.tag=o,t.anchor=a,t.kind=\"sequence\",t.result=n,!0):!1}function l6e(t,e,r){var o,a,n,u,A=t.tag,p=t.anchor,h={},C={},I=null,v=null,x=null,E=!1,R=!1,L;for(t.anchor!==null&&(t.anchorMap[t.anchor]=h),L=t.input.charCodeAt(t.position);L!==0;){if(o=t.input.charCodeAt(t.position+1),n=t.line,u=t.position,(L===63||L===58)&&Ia(o))L===63?(E&&(py(t,h,C,I,v,null),I=v=x=null),R=!0,E=!0,a=!0):E?(E=!1,a=!0):Sr(t,\"incomplete explicit mapping pair; a key node is missed; or followed by a non-tabulated empty line\"),t.position+=1,L=o;else if(hy(t,r,dK,!1,!0))if(t.line===n){for(L=t.input.charCodeAt(t.position);Jg(L);)L=t.input.charCodeAt(++t.position);if(L===58)L=t.input.charCodeAt(++t.position),Ia(L)||Sr(t,\"a whitespace character is expected after the key-value separator within a block mapping\"),E&&(py(t,h,C,I,v,null),I=v=x=null),R=!0,E=!1,a=!1,I=t.tag,v=t.result;else if(R)Sr(t,\"can not read an implicit mapping pair; a colon is missed\");else return t.tag=A,t.anchor=p,!0}else if(R)Sr(t,\"can not read a block mapping entry; a multiline key may not be an implicit key\");else return t.tag=A,t.anchor=p,!0;else break;if((t.line===n||t.lineIndent>e)&&(hy(t,e,YD,!0,a)&&(E?v=t.result:x=t.result),E||(py(t,h,C,I,v,x,n,u),I=v=x=null),Wi(t,!0,-1),L=t.input.charCodeAt(t.position)),t.lineIndent>e&&L!==0)Sr(t,\"bad indentation of a mapping entry\");else if(t.lineIndent<e)break}return E&&py(t,h,C,I,v,null),R&&(t.tag=A,t.anchor=p,t.kind=\"mapping\",t.result=h),R}function c6e(t){var e,r=!1,o=!1,a,n,u;if(u=t.input.charCodeAt(t.position),u!==33)return!1;if(t.tag!==null&&Sr(t,\"duplication of a tag property\"),u=t.input.charCodeAt(++t.position),u===60?(r=!0,u=t.input.charCodeAt(++t.position)):u===33?(o=!0,a=\"!!\",u=t.input.charCodeAt(++t.position)):a=\"!\",e=t.position,r){do u=t.input.charCodeAt(++t.position);while(u!==0&&u!==62);t.position<t.length?(n=t.input.slice(e,t.position),u=t.input.charCodeAt(++t.position)):Sr(t,\"unexpected end of the stream within a verbatim tag\")}else{for(;u!==0&&!Ia(u);)u===33&&(o?Sr(t,\"tag suffix cannot contain exclamation marks\"):(a=t.input.slice(e-1,t.position+1),yK.test(a)||Sr(t,\"named tag handle cannot contain such characters\"),o=!0,e=t.position+1)),u=t.input.charCodeAt(++t.position);n=t.input.slice(e,t.position),XHe.test(n)&&Sr(t,\"tag suffix cannot contain flow indicator characters\")}return n&&!EK.test(n)&&Sr(t,\"tag name cannot contain such characters: \"+n),r?t.tag=n:qp.call(t.tagMap,a)?t.tag=t.tagMap[a]+n:a===\"!\"?t.tag=\"!\"+n:a===\"!!\"?t.tag=\"tag:yaml.org,2002:\"+n:Sr(t,'undeclared tag handle \"'+a+'\"'),!0}function u6e(t){var e,r;if(r=t.input.charCodeAt(t.position),r!==38)return!1;for(t.anchor!==null&&Sr(t,\"duplication of an anchor property\"),r=t.input.charCodeAt(++t.position),e=t.position;r!==0&&!Ia(r)&&!fy(r);)r=t.input.charCodeAt(++t.position);return t.position===e&&Sr(t,\"name of an anchor node must contain at least one character\"),t.anchor=t.input.slice(e,t.position),!0}function A6e(t){var e,r,o;if(o=t.input.charCodeAt(t.position),o!==42)return!1;for(o=t.input.charCodeAt(++t.position),e=t.position;o!==0&&!Ia(o)&&!fy(o);)o=t.input.charCodeAt(++t.position);return t.position===e&&Sr(t,\"name of an alias node must contain at least one character\"),r=t.input.slice(e,t.position),qp.call(t.anchorMap,r)||Sr(t,'unidentified alias \"'+r+'\"'),t.result=t.anchorMap[r],Wi(t,!0,-1),!0}function hy(t,e,r,o,a){var n,u,A,p=1,h=!1,C=!1,I,v,x,E,R;if(t.listener!==null&&t.listener(\"open\",t),t.tag=null,t.anchor=null,t.kind=null,t.result=null,n=u=A=YD===r||mK===r,o&&Wi(t,!0,-1)&&(h=!0,t.lineIndent>e?p=1:t.lineIndent===e?p=0:t.lineIndent<e&&(p=-1)),p===1)for(;c6e(t)||u6e(t);)Wi(t,!0,-1)?(h=!0,A=n,t.lineIndent>e?p=1:t.lineIndent===e?p=0:t.lineIndent<e&&(p=-1)):A=!1;if(A&&(A=h||a),(p===1||YD===r)&&(GD===r||dK===r?E=e:E=e+1,R=t.position-t.lineStart,p===1?A&&(pK(t,R)||l6e(t,R,E))||o6e(t,E)?C=!0:(u&&a6e(t,E)||i6e(t,E)||s6e(t,E)?C=!0:A6e(t)?(C=!0,(t.tag!==null||t.anchor!==null)&&Sr(t,\"alias node should not have any properties\")):n6e(t,E,GD===r)&&(C=!0,t.tag===null&&(t.tag=\"?\")),t.anchor!==null&&(t.anchorMap[t.anchor]=t.result)):p===0&&(C=A&&pK(t,R))),t.tag!==null&&t.tag!==\"!\")if(t.tag===\"?\"){for(t.result!==null&&t.kind!==\"scalar\"&&Sr(t,'unacceptable node kind for !<?> tag; it should be \"scalar\", not \"'+t.kind+'\"'),I=0,v=t.implicitTypes.length;I<v;I+=1)if(x=t.implicitTypes[I],x.resolve(t.result)){t.result=x.construct(t.result),t.tag=x.tag,t.anchor!==null&&(t.anchorMap[t.anchor]=t.result);break}}else qp.call(t.typeMap[t.kind||\"fallback\"],t.tag)?(x=t.typeMap[t.kind||\"fallback\"][t.tag],t.result!==null&&x.kind!==t.kind&&Sr(t,\"unacceptable node kind for !<\"+t.tag+'> tag; it should be \"'+x.kind+'\", not \"'+t.kind+'\"'),x.resolve(t.result)?(t.result=x.construct(t.result),t.anchor!==null&&(t.anchorMap[t.anchor]=t.result)):Sr(t,\"cannot resolve a node with !<\"+t.tag+\"> explicit tag\")):Sr(t,\"unknown tag !<\"+t.tag+\">\");return t.listener!==null&&t.listener(\"close\",t),t.tag!==null||t.anchor!==null||C}function f6e(t){var e=t.position,r,o,a,n=!1,u;for(t.version=null,t.checkLineBreaks=t.legacy,t.tagMap={},t.anchorMap={};(u=t.input.charCodeAt(t.position))!==0&&(Wi(t,!0,-1),u=t.input.charCodeAt(t.position),!(t.lineIndent>0||u!==37));){for(n=!0,u=t.input.charCodeAt(++t.position),r=t.position;u!==0&&!Ia(u);)u=t.input.charCodeAt(++t.position);for(o=t.input.slice(r,t.position),a=[],o.length<1&&Sr(t,\"directive name must not be less than one character in length\");u!==0;){for(;Jg(u);)u=t.input.charCodeAt(++t.position);if(u===35){do u=t.input.charCodeAt(++t.position);while(u!==0&&!Hu(u));break}if(Hu(u))break;for(r=t.position;u!==0&&!Ia(u);)u=t.input.charCodeAt(++t.position);a.push(t.input.slice(r,t.position))}u!==0&&ET(t),qp.call(AK,o)?AK[o](t,o,a):WD(t,'unknown document directive \"'+o+'\"')}if(Wi(t,!0,-1),t.lineIndent===0&&t.input.charCodeAt(t.position)===45&&t.input.charCodeAt(t.position+1)===45&&t.input.charCodeAt(t.position+2)===45?(t.position+=3,Wi(t,!0,-1)):n&&Sr(t,\"directives end mark is expected\"),hy(t,t.lineIndent-1,YD,!1,!0),Wi(t,!0,-1),t.checkLineBreaks&&JHe.test(t.input.slice(e,t.position))&&WD(t,\"non-ASCII line breaks are interpreted as content\"),t.documents.push(t.result),t.position===t.lineStart&&KD(t)){t.input.charCodeAt(t.position)===46&&(t.position+=3,Wi(t,!0,-1));return}if(t.position<t.length-1)Sr(t,\"end of the stream or a document separator is expected\");else return}function BK(t,e){t=String(t),e=e||{},t.length!==0&&(t.charCodeAt(t.length-1)!==10&&t.charCodeAt(t.length-1)!==13&&(t+=`\n`),t.charCodeAt(0)===65279&&(t=t.slice(1)));var r=new r6e(t,e),o=t.indexOf(\"\\0\");for(o!==-1&&(r.position=o,Sr(r,\"null byte is not allowed in input\")),r.input+=\"\\0\";r.input.charCodeAt(r.position)===32;)r.lineIndent+=1,r.position+=1;for(;r.position<r.length-1;)f6e(r);return r.documents}function vK(t,e,r){e!==null&&typeof e==\"object\"&&typeof r>\"u\"&&(r=e,e=null);var o=BK(t,r);if(typeof e!=\"function\")return o;for(var a=0,n=o.length;a<n;a+=1)e(o[a])}function DK(t,e){var r=BK(t,e);if(r.length!==0){if(r.length===1)return r[0];throw new hK(\"expected a single document in the stream, but found more\")}}function p6e(t,e,r){return typeof e==\"object\"&&e!==null&&typeof r>\"u\"&&(r=e,e=null),vK(t,e,mf.extend({schema:gK},r))}function h6e(t,e){return DK(t,mf.extend({schema:gK},e))}Jw.exports.loadAll=vK;Jw.exports.load=DK;Jw.exports.safeLoadAll=p6e;Jw.exports.safeLoad=h6e});var zK=_((uxt,vT)=>{\"use strict\";var Zw=Wg(),$w=cy(),g6e=zw(),d6e=Ay(),TK=Object.prototype.toString,NK=Object.prototype.hasOwnProperty,m6e=9,Xw=10,y6e=13,E6e=32,C6e=33,w6e=34,LK=35,I6e=37,B6e=38,v6e=39,D6e=42,OK=44,P6e=45,MK=58,S6e=61,b6e=62,x6e=63,k6e=64,UK=91,_K=93,Q6e=96,HK=123,F6e=124,jK=125,vo={};vo[0]=\"\\\\0\";vo[7]=\"\\\\a\";vo[8]=\"\\\\b\";vo[9]=\"\\\\t\";vo[10]=\"\\\\n\";vo[11]=\"\\\\v\";vo[12]=\"\\\\f\";vo[13]=\"\\\\r\";vo[27]=\"\\\\e\";vo[34]='\\\\\"';vo[92]=\"\\\\\\\\\";vo[133]=\"\\\\N\";vo[160]=\"\\\\_\";vo[8232]=\"\\\\L\";vo[8233]=\"\\\\P\";var R6e=[\"y\",\"Y\",\"yes\",\"Yes\",\"YES\",\"on\",\"On\",\"ON\",\"n\",\"N\",\"no\",\"No\",\"NO\",\"off\",\"Off\",\"OFF\"];function T6e(t,e){var r,o,a,n,u,A,p;if(e===null)return{};for(r={},o=Object.keys(e),a=0,n=o.length;a<n;a+=1)u=o[a],A=String(e[u]),u.slice(0,2)===\"!!\"&&(u=\"tag:yaml.org,2002:\"+u.slice(2)),p=t.compiledTypeMap.fallback[u],p&&NK.call(p.styleAliases,A)&&(A=p.styleAliases[A]),r[u]=A;return r}function SK(t){var e,r,o;if(e=t.toString(16).toUpperCase(),t<=255)r=\"x\",o=2;else if(t<=65535)r=\"u\",o=4;else if(t<=4294967295)r=\"U\",o=8;else throw new $w(\"code point within a string may not be greater than 0xFFFFFFFF\");return\"\\\\\"+r+Zw.repeat(\"0\",o-e.length)+e}function N6e(t){this.schema=t.schema||g6e,this.indent=Math.max(1,t.indent||2),this.noArrayIndent=t.noArrayIndent||!1,this.skipInvalid=t.skipInvalid||!1,this.flowLevel=Zw.isNothing(t.flowLevel)?-1:t.flowLevel,this.styleMap=T6e(this.schema,t.styles||null),this.sortKeys=t.sortKeys||!1,this.lineWidth=t.lineWidth||80,this.noRefs=t.noRefs||!1,this.noCompatMode=t.noCompatMode||!1,this.condenseFlow=t.condenseFlow||!1,this.implicitTypes=this.schema.compiledImplicit,this.explicitTypes=this.schema.compiledExplicit,this.tag=null,this.result=\"\",this.duplicates=[],this.usedDuplicates=null}function bK(t,e){for(var r=Zw.repeat(\" \",e),o=0,a=-1,n=\"\",u,A=t.length;o<A;)a=t.indexOf(`\n`,o),a===-1?(u=t.slice(o),o=A):(u=t.slice(o,a+1),o=a+1),u.length&&u!==`\n`&&(n+=r),n+=u;return n}function wT(t,e){return`\n`+Zw.repeat(\" \",t.indent*e)}function L6e(t,e){var r,o,a;for(r=0,o=t.implicitTypes.length;r<o;r+=1)if(a=t.implicitTypes[r],a.resolve(e))return!0;return!1}function BT(t){return t===E6e||t===m6e}function gy(t){return 32<=t&&t<=126||161<=t&&t<=55295&&t!==8232&&t!==8233||57344<=t&&t<=65533&&t!==65279||65536<=t&&t<=1114111}function O6e(t){return gy(t)&&!BT(t)&&t!==65279&&t!==y6e&&t!==Xw}function xK(t,e){return gy(t)&&t!==65279&&t!==OK&&t!==UK&&t!==_K&&t!==HK&&t!==jK&&t!==MK&&(t!==LK||e&&O6e(e))}function M6e(t){return gy(t)&&t!==65279&&!BT(t)&&t!==P6e&&t!==x6e&&t!==MK&&t!==OK&&t!==UK&&t!==_K&&t!==HK&&t!==jK&&t!==LK&&t!==B6e&&t!==D6e&&t!==C6e&&t!==F6e&&t!==S6e&&t!==b6e&&t!==v6e&&t!==w6e&&t!==I6e&&t!==k6e&&t!==Q6e}function qK(t){var e=/^\\n* /;return e.test(t)}var GK=1,YK=2,WK=3,KK=4,VD=5;function U6e(t,e,r,o,a){var n,u,A,p=!1,h=!1,C=o!==-1,I=-1,v=M6e(t.charCodeAt(0))&&!BT(t.charCodeAt(t.length-1));if(e)for(n=0;n<t.length;n++){if(u=t.charCodeAt(n),!gy(u))return VD;A=n>0?t.charCodeAt(n-1):null,v=v&&xK(u,A)}else{for(n=0;n<t.length;n++){if(u=t.charCodeAt(n),u===Xw)p=!0,C&&(h=h||n-I-1>o&&t[I+1]!==\" \",I=n);else if(!gy(u))return VD;A=n>0?t.charCodeAt(n-1):null,v=v&&xK(u,A)}h=h||C&&n-I-1>o&&t[I+1]!==\" \"}return!p&&!h?v&&!a(t)?GK:YK:r>9&&qK(t)?VD:h?KK:WK}function _6e(t,e,r,o){t.dump=function(){if(e.length===0)return\"''\";if(!t.noCompatMode&&R6e.indexOf(e)!==-1)return\"'\"+e+\"'\";var a=t.indent*Math.max(1,r),n=t.lineWidth===-1?-1:Math.max(Math.min(t.lineWidth,40),t.lineWidth-a),u=o||t.flowLevel>-1&&r>=t.flowLevel;function A(p){return L6e(t,p)}switch(U6e(e,u,t.indent,n,A)){case GK:return e;case YK:return\"'\"+e.replace(/'/g,\"''\")+\"'\";case WK:return\"|\"+kK(e,t.indent)+QK(bK(e,a));case KK:return\">\"+kK(e,t.indent)+QK(bK(H6e(e,n),a));case VD:return'\"'+j6e(e,n)+'\"';default:throw new $w(\"impossible error: invalid scalar style\")}}()}function kK(t,e){var r=qK(t)?String(e):\"\",o=t[t.length-1]===`\n`,a=o&&(t[t.length-2]===`\n`||t===`\n`),n=a?\"+\":o?\"\":\"-\";return r+n+`\n`}function QK(t){return t[t.length-1]===`\n`?t.slice(0,-1):t}function H6e(t,e){for(var r=/(\\n+)([^\\n]*)/g,o=function(){var h=t.indexOf(`\n`);return h=h!==-1?h:t.length,r.lastIndex=h,FK(t.slice(0,h),e)}(),a=t[0]===`\n`||t[0]===\" \",n,u;u=r.exec(t);){var A=u[1],p=u[2];n=p[0]===\" \",o+=A+(!a&&!n&&p!==\"\"?`\n`:\"\")+FK(p,e),a=n}return o}function FK(t,e){if(t===\"\"||t[0]===\" \")return t;for(var r=/ [^ ]/g,o,a=0,n,u=0,A=0,p=\"\";o=r.exec(t);)A=o.index,A-a>e&&(n=u>a?u:A,p+=`\n`+t.slice(a,n),a=n+1),u=A;return p+=`\n`,t.length-a>e&&u>a?p+=t.slice(a,u)+`\n`+t.slice(u+1):p+=t.slice(a),p.slice(1)}function j6e(t){for(var e=\"\",r,o,a,n=0;n<t.length;n++){if(r=t.charCodeAt(n),r>=55296&&r<=56319&&(o=t.charCodeAt(n+1),o>=56320&&o<=57343)){e+=SK((r-55296)*1024+o-56320+65536),n++;continue}a=vo[r],e+=!a&&gy(r)?t[n]:a||SK(r)}return e}function q6e(t,e,r){var o=\"\",a=t.tag,n,u;for(n=0,u=r.length;n<u;n+=1)Xg(t,e,r[n],!1,!1)&&(n!==0&&(o+=\",\"+(t.condenseFlow?\"\":\" \")),o+=t.dump);t.tag=a,t.dump=\"[\"+o+\"]\"}function G6e(t,e,r,o){var a=\"\",n=t.tag,u,A;for(u=0,A=r.length;u<A;u+=1)Xg(t,e+1,r[u],!0,!0)&&((!o||u!==0)&&(a+=wT(t,e)),t.dump&&Xw===t.dump.charCodeAt(0)?a+=\"-\":a+=\"- \",a+=t.dump);t.tag=n,t.dump=a||\"[]\"}function Y6e(t,e,r){var o=\"\",a=t.tag,n=Object.keys(r),u,A,p,h,C;for(u=0,A=n.length;u<A;u+=1)C=\"\",u!==0&&(C+=\", \"),t.condenseFlow&&(C+='\"'),p=n[u],h=r[p],Xg(t,e,p,!1,!1)&&(t.dump.length>1024&&(C+=\"? \"),C+=t.dump+(t.condenseFlow?'\"':\"\")+\":\"+(t.condenseFlow?\"\":\" \"),Xg(t,e,h,!1,!1)&&(C+=t.dump,o+=C));t.tag=a,t.dump=\"{\"+o+\"}\"}function W6e(t,e,r,o){var a=\"\",n=t.tag,u=Object.keys(r),A,p,h,C,I,v;if(t.sortKeys===!0)u.sort();else if(typeof t.sortKeys==\"function\")u.sort(t.sortKeys);else if(t.sortKeys)throw new $w(\"sortKeys must be a boolean or a function\");for(A=0,p=u.length;A<p;A+=1)v=\"\",(!o||A!==0)&&(v+=wT(t,e)),h=u[A],C=r[h],Xg(t,e+1,h,!0,!0,!0)&&(I=t.tag!==null&&t.tag!==\"?\"||t.dump&&t.dump.length>1024,I&&(t.dump&&Xw===t.dump.charCodeAt(0)?v+=\"?\":v+=\"? \"),v+=t.dump,I&&(v+=wT(t,e)),Xg(t,e+1,C,!0,I)&&(t.dump&&Xw===t.dump.charCodeAt(0)?v+=\":\":v+=\": \",v+=t.dump,a+=v));t.tag=n,t.dump=a||\"{}\"}function RK(t,e,r){var o,a,n,u,A,p;for(a=r?t.explicitTypes:t.implicitTypes,n=0,u=a.length;n<u;n+=1)if(A=a[n],(A.instanceOf||A.predicate)&&(!A.instanceOf||typeof e==\"object\"&&e instanceof A.instanceOf)&&(!A.predicate||A.predicate(e))){if(t.tag=r?A.tag:\"?\",A.represent){if(p=t.styleMap[A.tag]||A.defaultStyle,TK.call(A.represent)===\"[object Function]\")o=A.represent(e,p);else if(NK.call(A.represent,p))o=A.represent[p](e,p);else throw new $w(\"!<\"+A.tag+'> tag resolver accepts not \"'+p+'\" style');t.dump=o}return!0}return!1}function Xg(t,e,r,o,a,n){t.tag=null,t.dump=r,RK(t,r,!1)||RK(t,r,!0);var u=TK.call(t.dump);o&&(o=t.flowLevel<0||t.flowLevel>e);var A=u===\"[object Object]\"||u===\"[object Array]\",p,h;if(A&&(p=t.duplicates.indexOf(r),h=p!==-1),(t.tag!==null&&t.tag!==\"?\"||h||t.indent!==2&&e>0)&&(a=!1),h&&t.usedDuplicates[p])t.dump=\"*ref_\"+p;else{if(A&&h&&!t.usedDuplicates[p]&&(t.usedDuplicates[p]=!0),u===\"[object Object]\")o&&Object.keys(t.dump).length!==0?(W6e(t,e,t.dump,a),h&&(t.dump=\"&ref_\"+p+t.dump)):(Y6e(t,e,t.dump),h&&(t.dump=\"&ref_\"+p+\" \"+t.dump));else if(u===\"[object Array]\"){var C=t.noArrayIndent&&e>0?e-1:e;o&&t.dump.length!==0?(G6e(t,C,t.dump,a),h&&(t.dump=\"&ref_\"+p+t.dump)):(q6e(t,C,t.dump),h&&(t.dump=\"&ref_\"+p+\" \"+t.dump))}else if(u===\"[object String]\")t.tag!==\"?\"&&_6e(t,t.dump,e,n);else{if(t.skipInvalid)return!1;throw new $w(\"unacceptable kind of an object to dump \"+u)}t.tag!==null&&t.tag!==\"?\"&&(t.dump=\"!<\"+t.tag+\"> \"+t.dump)}return!0}function K6e(t,e){var r=[],o=[],a,n;for(IT(t,r,o),a=0,n=o.length;a<n;a+=1)e.duplicates.push(r[o[a]]);e.usedDuplicates=new Array(n)}function IT(t,e,r){var o,a,n;if(t!==null&&typeof t==\"object\")if(a=e.indexOf(t),a!==-1)r.indexOf(a)===-1&&r.push(a);else if(e.push(t),Array.isArray(t))for(a=0,n=t.length;a<n;a+=1)IT(t[a],e,r);else for(o=Object.keys(t),a=0,n=o.length;a<n;a+=1)IT(t[o[a]],e,r)}function VK(t,e){e=e||{};var r=new N6e(e);return r.noRefs||K6e(t,r),Xg(r,0,t,!0,!0)?r.dump+`\n`:\"\"}function V6e(t,e){return VK(t,Zw.extend({schema:d6e},e))}vT.exports.dump=VK;vT.exports.safeDump=V6e});var XK=_((Axt,ki)=>{\"use strict\";var zD=PK(),JK=zK();function JD(t){return function(){throw new Error(\"Function \"+t+\" is deprecated and cannot be used.\")}}ki.exports.Type=os();ki.exports.Schema=Kg();ki.exports.FAILSAFE_SCHEMA=jD();ki.exports.JSON_SCHEMA=gT();ki.exports.CORE_SCHEMA=dT();ki.exports.DEFAULT_SAFE_SCHEMA=Ay();ki.exports.DEFAULT_FULL_SCHEMA=zw();ki.exports.load=zD.load;ki.exports.loadAll=zD.loadAll;ki.exports.safeLoad=zD.safeLoad;ki.exports.safeLoadAll=zD.safeLoadAll;ki.exports.dump=JK.dump;ki.exports.safeDump=JK.safeDump;ki.exports.YAMLException=cy();ki.exports.MINIMAL_SCHEMA=jD();ki.exports.SAFE_SCHEMA=Ay();ki.exports.DEFAULT_SCHEMA=zw();ki.exports.scan=JD(\"scan\");ki.exports.parse=JD(\"parse\");ki.exports.compose=JD(\"compose\");ki.exports.addConstructor=JD(\"addConstructor\")});var $K=_((fxt,ZK)=>{\"use strict\";var z6e=XK();ZK.exports=z6e});var tV=_((pxt,eV)=>{\"use strict\";function J6e(t,e){function r(){this.constructor=t}r.prototype=e.prototype,t.prototype=new r}function Zg(t,e,r,o){this.message=t,this.expected=e,this.found=r,this.location=o,this.name=\"SyntaxError\",typeof Error.captureStackTrace==\"function\"&&Error.captureStackTrace(this,Zg)}J6e(Zg,Error);Zg.buildMessage=function(t,e){var r={literal:function(h){return'\"'+a(h.text)+'\"'},class:function(h){var C=\"\",I;for(I=0;I<h.parts.length;I++)C+=h.parts[I]instanceof Array?n(h.parts[I][0])+\"-\"+n(h.parts[I][1]):n(h.parts[I]);return\"[\"+(h.inverted?\"^\":\"\")+C+\"]\"},any:function(h){return\"any character\"},end:function(h){return\"end of input\"},other:function(h){return h.description}};function o(h){return h.charCodeAt(0).toString(16).toUpperCase()}function a(h){return h.replace(/\\\\/g,\"\\\\\\\\\").replace(/\"/g,'\\\\\"').replace(/\\0/g,\"\\\\0\").replace(/\\t/g,\"\\\\t\").replace(/\\n/g,\"\\\\n\").replace(/\\r/g,\"\\\\r\").replace(/[\\x00-\\x0F]/g,function(C){return\"\\\\x0\"+o(C)}).replace(/[\\x10-\\x1F\\x7F-\\x9F]/g,function(C){return\"\\\\x\"+o(C)})}function n(h){return h.replace(/\\\\/g,\"\\\\\\\\\").replace(/\\]/g,\"\\\\]\").replace(/\\^/g,\"\\\\^\").replace(/-/g,\"\\\\-\").replace(/\\0/g,\"\\\\0\").replace(/\\t/g,\"\\\\t\").replace(/\\n/g,\"\\\\n\").replace(/\\r/g,\"\\\\r\").replace(/[\\x00-\\x0F]/g,function(C){return\"\\\\x0\"+o(C)}).replace(/[\\x10-\\x1F\\x7F-\\x9F]/g,function(C){return\"\\\\x\"+o(C)})}function u(h){return r[h.type](h)}function A(h){var C=new Array(h.length),I,v;for(I=0;I<h.length;I++)C[I]=u(h[I]);if(C.sort(),C.length>0){for(I=1,v=1;I<C.length;I++)C[I-1]!==C[I]&&(C[v]=C[I],v++);C.length=v}switch(C.length){case 1:return C[0];case 2:return C[0]+\" or \"+C[1];default:return C.slice(0,-1).join(\", \")+\", or \"+C[C.length-1]}}function p(h){return h?'\"'+a(h)+'\"':\"end of input\"}return\"Expected \"+A(t)+\" but \"+p(e)+\" found.\"};function X6e(t,e){e=e!==void 0?e:{};var r={},o={Start:pu},a=pu,n=function($){return[].concat(...$)},u=\"-\",A=Qn(\"-\",!1),p=function($){return $},h=function($){return Object.assign({},...$)},C=\"#\",I=Qn(\"#\",!1),v=hc(),x=function(){return{}},E=\":\",R=Qn(\":\",!1),L=function($,me){return{[$]:me}},U=\",\",z=Qn(\",\",!1),te=function($,me){return me},le=function($,me,Le){return Object.assign({},...[$].concat(me).map(ft=>({[ft]:Le})))},he=function($){return $},Ae=function($){return $},ye=sa(\"correct indentation\"),ae=\" \",Ie=Qn(\" \",!1),Fe=function($){return $.length===nr*It},g=function($){return $.length===(nr+1)*It},Ee=function(){return nr++,!0},De=function(){return nr--,!0},ce=function(){return DA()},ne=sa(\"pseudostring\"),ee=/^[^\\r\\n\\t ?:,\\][{}#&*!|>'\"%@`\\-]/,we=hi([\"\\r\",`\n`,\"\t\",\" \",\"?\",\":\",\",\",\"]\",\"[\",\"{\",\"}\",\"#\",\"&\",\"*\",\"!\",\"|\",\">\",\"'\",'\"',\"%\",\"@\",\"`\",\"-\"],!0,!1),xe=/^[^\\r\\n\\t ,\\][{}:#\"']/,ht=hi([\"\\r\",`\n`,\"\t\",\" \",\",\",\"]\",\"[\",\"{\",\"}\",\":\",\"#\",'\"',\"'\"],!0,!1),H=function(){return DA().replace(/^ *| *$/g,\"\")},lt=\"--\",Te=Qn(\"--\",!1),ke=/^[a-zA-Z\\/0-9]/,be=hi([[\"a\",\"z\"],[\"A\",\"Z\"],\"/\",[\"0\",\"9\"]],!1,!1),_e=/^[^\\r\\n\\t :,]/,Re=hi([\"\\r\",`\n`,\"\t\",\" \",\":\",\",\"],!0,!1),ze=\"null\",He=Qn(\"null\",!1),b=function(){return null},w=\"true\",S=Qn(\"true\",!1),y=function(){return!0},F=\"false\",J=Qn(\"false\",!1),X=function(){return!1},Z=sa(\"string\"),ie='\"',Pe=Qn('\"',!1),Ne=function(){return\"\"},ot=function($){return $},dt=function($){return $.join(\"\")},jt=/^[^\"\\\\\\0-\\x1F\\x7F]/,$t=hi(['\"',\"\\\\\",[\"\\0\",\"\u001f\"],\"\\x7F\"],!0,!1),bt='\\\\\"',an=Qn('\\\\\"',!1),Qr=function(){return'\"'},mr=\"\\\\\\\\\",br=Qn(\"\\\\\\\\\",!1),Wr=function(){return\"\\\\\"},Kn=\"\\\\/\",Ns=Qn(\"\\\\/\",!1),Ti=function(){return\"/\"},ps=\"\\\\b\",io=Qn(\"\\\\b\",!1),Si=function(){return\"\\b\"},Ls=\"\\\\f\",so=Qn(\"\\\\f\",!1),cc=function(){return\"\\f\"},cu=\"\\\\n\",op=Qn(\"\\\\n\",!1),ap=function(){return`\n`},Os=\"\\\\r\",Dn=Qn(\"\\\\r\",!1),oo=function(){return\"\\r\"},Ms=\"\\\\t\",ml=Qn(\"\\\\t\",!1),yl=function(){return\"\t\"},ao=\"\\\\u\",Vn=Qn(\"\\\\u\",!1),On=function($,me,Le,ft){return String.fromCharCode(parseInt(`0x${$}${me}${Le}${ft}`))},Ni=/^[0-9a-fA-F]/,Mn=hi([[\"0\",\"9\"],[\"a\",\"f\"],[\"A\",\"F\"]],!1,!1),_i=sa(\"blank space\"),tr=/^[ \\t]/,Oe=hi([\" \",\"\t\"],!1,!1),ii=sa(\"white space\"),Ma=/^[ \\t\\n\\r]/,hr=hi([\" \",\"\t\",`\n`,\"\\r\"],!1,!1),uc=`\\r\n`,uu=Qn(`\\r\n`,!1),Ac=`\n`,El=Qn(`\n`,!1),vA=\"\\r\",Au=Qn(\"\\r\",!1),Ce=0,Rt=0,fc=[{line:1,column:1}],Hi=0,fu=[],Yt=0,Cl;if(\"startRule\"in e){if(!(e.startRule in o))throw new Error(`Can't start parsing from rule \"`+e.startRule+'\".');a=o[e.startRule]}function DA(){return t.substring(Rt,Ce)}function lp(){return _o(Rt,Ce)}function pc($,me){throw me=me!==void 0?me:_o(Rt,Ce),gc([sa($)],t.substring(Rt,Ce),me)}function PA($,me){throw me=me!==void 0?me:_o(Rt,Ce),lo($,me)}function Qn($,me){return{type:\"literal\",text:$,ignoreCase:me}}function hi($,me,Le){return{type:\"class\",parts:$,inverted:me,ignoreCase:Le}}function hc(){return{type:\"any\"}}function SA(){return{type:\"end\"}}function sa($){return{type:\"other\",description:$}}function Li($){var me=fc[$],Le;if(me)return me;for(Le=$-1;!fc[Le];)Le--;for(me=fc[Le],me={line:me.line,column:me.column};Le<$;)t.charCodeAt(Le)===10?(me.line++,me.column=1):me.column++,Le++;return fc[$]=me,me}function _o($,me){var Le=Li($),ft=Li(me);return{start:{offset:$,line:Le.line,column:Le.column},end:{offset:me,line:ft.line,column:ft.column}}}function Ze($){Ce<Hi||(Ce>Hi&&(Hi=Ce,fu=[]),fu.push($))}function lo($,me){return new Zg($,null,null,me)}function gc($,me,Le){return new Zg(Zg.buildMessage($,me),$,me,Le)}function pu(){var $;return $=bA(),$}function ji(){var $,me,Le;for($=Ce,me=[],Le=hu();Le!==r;)me.push(Le),Le=hu();return me!==r&&(Rt=$,me=n(me)),$=me,$}function hu(){var $,me,Le,ft,pt;return $=Ce,me=hs(),me!==r?(t.charCodeAt(Ce)===45?(Le=u,Ce++):(Le=r,Yt===0&&Ze(A)),Le!==r?(ft=Pn(),ft!==r?(pt=dc(),pt!==r?(Rt=$,me=p(pt),$=me):(Ce=$,$=r)):(Ce=$,$=r)):(Ce=$,$=r)):(Ce=$,$=r),$}function bA(){var $,me,Le;for($=Ce,me=[],Le=Ua();Le!==r;)me.push(Le),Le=Ua();return me!==r&&(Rt=$,me=h(me)),$=me,$}function Ua(){var $,me,Le,ft,pt,Tt,er,Zr,qi;if($=Ce,me=Pn(),me===r&&(me=null),me!==r){if(Le=Ce,t.charCodeAt(Ce)===35?(ft=C,Ce++):(ft=r,Yt===0&&Ze(I)),ft!==r){if(pt=[],Tt=Ce,er=Ce,Yt++,Zr=tt(),Yt--,Zr===r?er=void 0:(Ce=er,er=r),er!==r?(t.length>Ce?(Zr=t.charAt(Ce),Ce++):(Zr=r,Yt===0&&Ze(v)),Zr!==r?(er=[er,Zr],Tt=er):(Ce=Tt,Tt=r)):(Ce=Tt,Tt=r),Tt!==r)for(;Tt!==r;)pt.push(Tt),Tt=Ce,er=Ce,Yt++,Zr=tt(),Yt--,Zr===r?er=void 0:(Ce=er,er=r),er!==r?(t.length>Ce?(Zr=t.charAt(Ce),Ce++):(Zr=r,Yt===0&&Ze(v)),Zr!==r?(er=[er,Zr],Tt=er):(Ce=Tt,Tt=r)):(Ce=Tt,Tt=r);else pt=r;pt!==r?(ft=[ft,pt],Le=ft):(Ce=Le,Le=r)}else Ce=Le,Le=r;if(Le===r&&(Le=null),Le!==r){if(ft=[],pt=We(),pt!==r)for(;pt!==r;)ft.push(pt),pt=We();else ft=r;ft!==r?(Rt=$,me=x(),$=me):(Ce=$,$=r)}else Ce=$,$=r}else Ce=$,$=r;if($===r&&($=Ce,me=hs(),me!==r?(Le=oa(),Le!==r?(ft=Pn(),ft===r&&(ft=null),ft!==r?(t.charCodeAt(Ce)===58?(pt=E,Ce++):(pt=r,Yt===0&&Ze(R)),pt!==r?(Tt=Pn(),Tt===r&&(Tt=null),Tt!==r?(er=dc(),er!==r?(Rt=$,me=L(Le,er),$=me):(Ce=$,$=r)):(Ce=$,$=r)):(Ce=$,$=r)):(Ce=$,$=r)):(Ce=$,$=r)):(Ce=$,$=r),$===r&&($=Ce,me=hs(),me!==r?(Le=co(),Le!==r?(ft=Pn(),ft===r&&(ft=null),ft!==r?(t.charCodeAt(Ce)===58?(pt=E,Ce++):(pt=r,Yt===0&&Ze(R)),pt!==r?(Tt=Pn(),Tt===r&&(Tt=null),Tt!==r?(er=dc(),er!==r?(Rt=$,me=L(Le,er),$=me):(Ce=$,$=r)):(Ce=$,$=r)):(Ce=$,$=r)):(Ce=$,$=r)):(Ce=$,$=r)):(Ce=$,$=r),$===r))){if($=Ce,me=hs(),me!==r)if(Le=co(),Le!==r)if(ft=Pn(),ft!==r)if(pt=aa(),pt!==r){if(Tt=[],er=We(),er!==r)for(;er!==r;)Tt.push(er),er=We();else Tt=r;Tt!==r?(Rt=$,me=L(Le,pt),$=me):(Ce=$,$=r)}else Ce=$,$=r;else Ce=$,$=r;else Ce=$,$=r;else Ce=$,$=r;if($===r)if($=Ce,me=hs(),me!==r)if(Le=co(),Le!==r){if(ft=[],pt=Ce,Tt=Pn(),Tt===r&&(Tt=null),Tt!==r?(t.charCodeAt(Ce)===44?(er=U,Ce++):(er=r,Yt===0&&Ze(z)),er!==r?(Zr=Pn(),Zr===r&&(Zr=null),Zr!==r?(qi=co(),qi!==r?(Rt=pt,Tt=te(Le,qi),pt=Tt):(Ce=pt,pt=r)):(Ce=pt,pt=r)):(Ce=pt,pt=r)):(Ce=pt,pt=r),pt!==r)for(;pt!==r;)ft.push(pt),pt=Ce,Tt=Pn(),Tt===r&&(Tt=null),Tt!==r?(t.charCodeAt(Ce)===44?(er=U,Ce++):(er=r,Yt===0&&Ze(z)),er!==r?(Zr=Pn(),Zr===r&&(Zr=null),Zr!==r?(qi=co(),qi!==r?(Rt=pt,Tt=te(Le,qi),pt=Tt):(Ce=pt,pt=r)):(Ce=pt,pt=r)):(Ce=pt,pt=r)):(Ce=pt,pt=r);else ft=r;ft!==r?(pt=Pn(),pt===r&&(pt=null),pt!==r?(t.charCodeAt(Ce)===58?(Tt=E,Ce++):(Tt=r,Yt===0&&Ze(R)),Tt!==r?(er=Pn(),er===r&&(er=null),er!==r?(Zr=dc(),Zr!==r?(Rt=$,me=le(Le,ft,Zr),$=me):(Ce=$,$=r)):(Ce=$,$=r)):(Ce=$,$=r)):(Ce=$,$=r)):(Ce=$,$=r)}else Ce=$,$=r;else Ce=$,$=r}return $}function dc(){var $,me,Le,ft,pt,Tt,er;if($=Ce,me=Ce,Yt++,Le=Ce,ft=tt(),ft!==r?(pt=_t(),pt!==r?(t.charCodeAt(Ce)===45?(Tt=u,Ce++):(Tt=r,Yt===0&&Ze(A)),Tt!==r?(er=Pn(),er!==r?(ft=[ft,pt,Tt,er],Le=ft):(Ce=Le,Le=r)):(Ce=Le,Le=r)):(Ce=Le,Le=r)):(Ce=Le,Le=r),Yt--,Le!==r?(Ce=me,me=void 0):me=r,me!==r?(Le=We(),Le!==r?(ft=Fn(),ft!==r?(pt=ji(),pt!==r?(Tt=Ci(),Tt!==r?(Rt=$,me=he(pt),$=me):(Ce=$,$=r)):(Ce=$,$=r)):(Ce=$,$=r)):(Ce=$,$=r)):(Ce=$,$=r),$===r&&($=Ce,me=tt(),me!==r?(Le=Fn(),Le!==r?(ft=bA(),ft!==r?(pt=Ci(),pt!==r?(Rt=$,me=he(ft),$=me):(Ce=$,$=r)):(Ce=$,$=r)):(Ce=$,$=r)):(Ce=$,$=r),$===r))if($=Ce,me=Us(),me!==r){if(Le=[],ft=We(),ft!==r)for(;ft!==r;)Le.push(ft),ft=We();else Le=r;Le!==r?(Rt=$,me=Ae(me),$=me):(Ce=$,$=r)}else Ce=$,$=r;return $}function hs(){var $,me,Le;for(Yt++,$=Ce,me=[],t.charCodeAt(Ce)===32?(Le=ae,Ce++):(Le=r,Yt===0&&Ze(Ie));Le!==r;)me.push(Le),t.charCodeAt(Ce)===32?(Le=ae,Ce++):(Le=r,Yt===0&&Ze(Ie));return me!==r?(Rt=Ce,Le=Fe(me),Le?Le=void 0:Le=r,Le!==r?(me=[me,Le],$=me):(Ce=$,$=r)):(Ce=$,$=r),Yt--,$===r&&(me=r,Yt===0&&Ze(ye)),$}function _t(){var $,me,Le;for($=Ce,me=[],t.charCodeAt(Ce)===32?(Le=ae,Ce++):(Le=r,Yt===0&&Ze(Ie));Le!==r;)me.push(Le),t.charCodeAt(Ce)===32?(Le=ae,Ce++):(Le=r,Yt===0&&Ze(Ie));return me!==r?(Rt=Ce,Le=g(me),Le?Le=void 0:Le=r,Le!==r?(me=[me,Le],$=me):(Ce=$,$=r)):(Ce=$,$=r),$}function Fn(){var $;return Rt=Ce,$=Ee(),$?$=void 0:$=r,$}function Ci(){var $;return Rt=Ce,$=De(),$?$=void 0:$=r,$}function oa(){var $;return $=ds(),$===r&&($=la()),$}function co(){var $,me,Le;if($=ds(),$===r){if($=Ce,me=[],Le=Ho(),Le!==r)for(;Le!==r;)me.push(Le),Le=Ho();else me=r;me!==r&&(Rt=$,me=ce()),$=me}return $}function Us(){var $;return $=wi(),$===r&&($=gs(),$===r&&($=ds(),$===r&&($=la()))),$}function aa(){var $;return $=wi(),$===r&&($=ds(),$===r&&($=Ho())),$}function la(){var $,me,Le,ft,pt,Tt;if(Yt++,$=Ce,ee.test(t.charAt(Ce))?(me=t.charAt(Ce),Ce++):(me=r,Yt===0&&Ze(we)),me!==r){for(Le=[],ft=Ce,pt=Pn(),pt===r&&(pt=null),pt!==r?(xe.test(t.charAt(Ce))?(Tt=t.charAt(Ce),Ce++):(Tt=r,Yt===0&&Ze(ht)),Tt!==r?(pt=[pt,Tt],ft=pt):(Ce=ft,ft=r)):(Ce=ft,ft=r);ft!==r;)Le.push(ft),ft=Ce,pt=Pn(),pt===r&&(pt=null),pt!==r?(xe.test(t.charAt(Ce))?(Tt=t.charAt(Ce),Ce++):(Tt=r,Yt===0&&Ze(ht)),Tt!==r?(pt=[pt,Tt],ft=pt):(Ce=ft,ft=r)):(Ce=ft,ft=r);Le!==r?(Rt=$,me=H(),$=me):(Ce=$,$=r)}else Ce=$,$=r;return Yt--,$===r&&(me=r,Yt===0&&Ze(ne)),$}function Ho(){var $,me,Le,ft,pt;if($=Ce,t.substr(Ce,2)===lt?(me=lt,Ce+=2):(me=r,Yt===0&&Ze(Te)),me===r&&(me=null),me!==r)if(ke.test(t.charAt(Ce))?(Le=t.charAt(Ce),Ce++):(Le=r,Yt===0&&Ze(be)),Le!==r){for(ft=[],_e.test(t.charAt(Ce))?(pt=t.charAt(Ce),Ce++):(pt=r,Yt===0&&Ze(Re));pt!==r;)ft.push(pt),_e.test(t.charAt(Ce))?(pt=t.charAt(Ce),Ce++):(pt=r,Yt===0&&Ze(Re));ft!==r?(Rt=$,me=H(),$=me):(Ce=$,$=r)}else Ce=$,$=r;else Ce=$,$=r;return $}function wi(){var $,me;return $=Ce,t.substr(Ce,4)===ze?(me=ze,Ce+=4):(me=r,Yt===0&&Ze(He)),me!==r&&(Rt=$,me=b()),$=me,$}function gs(){var $,me;return $=Ce,t.substr(Ce,4)===w?(me=w,Ce+=4):(me=r,Yt===0&&Ze(S)),me!==r&&(Rt=$,me=y()),$=me,$===r&&($=Ce,t.substr(Ce,5)===F?(me=F,Ce+=5):(me=r,Yt===0&&Ze(J)),me!==r&&(Rt=$,me=X()),$=me),$}function ds(){var $,me,Le,ft;return Yt++,$=Ce,t.charCodeAt(Ce)===34?(me=ie,Ce++):(me=r,Yt===0&&Ze(Pe)),me!==r?(t.charCodeAt(Ce)===34?(Le=ie,Ce++):(Le=r,Yt===0&&Ze(Pe)),Le!==r?(Rt=$,me=Ne(),$=me):(Ce=$,$=r)):(Ce=$,$=r),$===r&&($=Ce,t.charCodeAt(Ce)===34?(me=ie,Ce++):(me=r,Yt===0&&Ze(Pe)),me!==r?(Le=ms(),Le!==r?(t.charCodeAt(Ce)===34?(ft=ie,Ce++):(ft=r,Yt===0&&Ze(Pe)),ft!==r?(Rt=$,me=ot(Le),$=me):(Ce=$,$=r)):(Ce=$,$=r)):(Ce=$,$=r)),Yt--,$===r&&(me=r,Yt===0&&Ze(Z)),$}function ms(){var $,me,Le;if($=Ce,me=[],Le=_s(),Le!==r)for(;Le!==r;)me.push(Le),Le=_s();else me=r;return me!==r&&(Rt=$,me=dt(me)),$=me,$}function _s(){var $,me,Le,ft,pt,Tt;return jt.test(t.charAt(Ce))?($=t.charAt(Ce),Ce++):($=r,Yt===0&&Ze($t)),$===r&&($=Ce,t.substr(Ce,2)===bt?(me=bt,Ce+=2):(me=r,Yt===0&&Ze(an)),me!==r&&(Rt=$,me=Qr()),$=me,$===r&&($=Ce,t.substr(Ce,2)===mr?(me=mr,Ce+=2):(me=r,Yt===0&&Ze(br)),me!==r&&(Rt=$,me=Wr()),$=me,$===r&&($=Ce,t.substr(Ce,2)===Kn?(me=Kn,Ce+=2):(me=r,Yt===0&&Ze(Ns)),me!==r&&(Rt=$,me=Ti()),$=me,$===r&&($=Ce,t.substr(Ce,2)===ps?(me=ps,Ce+=2):(me=r,Yt===0&&Ze(io)),me!==r&&(Rt=$,me=Si()),$=me,$===r&&($=Ce,t.substr(Ce,2)===Ls?(me=Ls,Ce+=2):(me=r,Yt===0&&Ze(so)),me!==r&&(Rt=$,me=cc()),$=me,$===r&&($=Ce,t.substr(Ce,2)===cu?(me=cu,Ce+=2):(me=r,Yt===0&&Ze(op)),me!==r&&(Rt=$,me=ap()),$=me,$===r&&($=Ce,t.substr(Ce,2)===Os?(me=Os,Ce+=2):(me=r,Yt===0&&Ze(Dn)),me!==r&&(Rt=$,me=oo()),$=me,$===r&&($=Ce,t.substr(Ce,2)===Ms?(me=Ms,Ce+=2):(me=r,Yt===0&&Ze(ml)),me!==r&&(Rt=$,me=yl()),$=me,$===r&&($=Ce,t.substr(Ce,2)===ao?(me=ao,Ce+=2):(me=r,Yt===0&&Ze(Vn)),me!==r?(Le=Un(),Le!==r?(ft=Un(),ft!==r?(pt=Un(),pt!==r?(Tt=Un(),Tt!==r?(Rt=$,me=On(Le,ft,pt,Tt),$=me):(Ce=$,$=r)):(Ce=$,$=r)):(Ce=$,$=r)):(Ce=$,$=r)):(Ce=$,$=r)))))))))),$}function Un(){var $;return Ni.test(t.charAt(Ce))?($=t.charAt(Ce),Ce++):($=r,Yt===0&&Ze(Mn)),$}function Pn(){var $,me;if(Yt++,$=[],tr.test(t.charAt(Ce))?(me=t.charAt(Ce),Ce++):(me=r,Yt===0&&Ze(Oe)),me!==r)for(;me!==r;)$.push(me),tr.test(t.charAt(Ce))?(me=t.charAt(Ce),Ce++):(me=r,Yt===0&&Ze(Oe));else $=r;return Yt--,$===r&&(me=r,Yt===0&&Ze(_i)),$}function ys(){var $,me;if(Yt++,$=[],Ma.test(t.charAt(Ce))?(me=t.charAt(Ce),Ce++):(me=r,Yt===0&&Ze(hr)),me!==r)for(;me!==r;)$.push(me),Ma.test(t.charAt(Ce))?(me=t.charAt(Ce),Ce++):(me=r,Yt===0&&Ze(hr));else $=r;return Yt--,$===r&&(me=r,Yt===0&&Ze(ii)),$}function We(){var $,me,Le,ft,pt,Tt;if($=Ce,me=tt(),me!==r){for(Le=[],ft=Ce,pt=Pn(),pt===r&&(pt=null),pt!==r?(Tt=tt(),Tt!==r?(pt=[pt,Tt],ft=pt):(Ce=ft,ft=r)):(Ce=ft,ft=r);ft!==r;)Le.push(ft),ft=Ce,pt=Pn(),pt===r&&(pt=null),pt!==r?(Tt=tt(),Tt!==r?(pt=[pt,Tt],ft=pt):(Ce=ft,ft=r)):(Ce=ft,ft=r);Le!==r?(me=[me,Le],$=me):(Ce=$,$=r)}else Ce=$,$=r;return $}function tt(){var $;return t.substr(Ce,2)===uc?($=uc,Ce+=2):($=r,Yt===0&&Ze(uu)),$===r&&(t.charCodeAt(Ce)===10?($=Ac,Ce++):($=r,Yt===0&&Ze(El)),$===r&&(t.charCodeAt(Ce)===13?($=vA,Ce++):($=r,Yt===0&&Ze(Au)))),$}let It=2,nr=0;if(Cl=a(),Cl!==r&&Ce===t.length)return Cl;throw Cl!==r&&Ce<t.length&&Ze(SA()),gc(fu,Hi<t.length?t.charAt(Hi):null,Hi<t.length?_o(Hi,Hi+1):_o(Hi,Hi))}eV.exports={SyntaxError:Zg,parse:X6e}});function nV(t){return t.match(Z6e)?t:JSON.stringify(t)}function sV(t){return typeof t>\"u\"?!0:typeof t==\"object\"&&t!==null&&!Array.isArray(t)?Object.keys(t).every(e=>sV(t[e])):!1}function DT(t,e,r){if(t===null)return`null\n`;if(typeof t==\"number\"||typeof t==\"boolean\")return`${t.toString()}\n`;if(typeof t==\"string\")return`${nV(t)}\n`;if(Array.isArray(t)){if(t.length===0)return`[]\n`;let o=\"  \".repeat(e);return`\n${t.map(n=>`${o}- ${DT(n,e+1,!1)}`).join(\"\")}`}if(typeof t==\"object\"&&t){let[o,a]=t instanceof XD?[t.data,!1]:[t,!0],n=\"  \".repeat(e),u=Object.keys(o);a&&u.sort((p,h)=>{let C=rV.indexOf(p),I=rV.indexOf(h);return C===-1&&I===-1?p<h?-1:p>h?1:0:C!==-1&&I===-1?-1:C===-1&&I!==-1?1:C-I});let A=u.filter(p=>!sV(o[p])).map((p,h)=>{let C=o[p],I=nV(p),v=DT(C,e+1,!0),x=h>0||r?n:\"\",E=I.length>1024?`? ${I}\n${x}:`:`${I}:`,R=v.startsWith(`\n`)?v:` ${v}`;return`${x}${E}${R}`}).join(e===0?`\n`:\"\")||`\n`;return r?`\n${A}`:`${A}`}throw new Error(`Unsupported value type (${t})`)}function Ba(t){try{let e=DT(t,0,!1);return e!==`\n`?e:\"\"}catch(e){throw e.location&&(e.message=e.message.replace(/(\\.)?$/,` (line ${e.location.start.line}, column ${e.location.start.column})$1`)),e}}function $6e(t){return t.endsWith(`\n`)||(t+=`\n`),(0,iV.parse)(t)}function tje(t){if(eje.test(t))return $6e(t);let e=(0,ZD.safeLoad)(t,{schema:ZD.FAILSAFE_SCHEMA,json:!0});if(e==null)return{};if(typeof e!=\"object\")throw new Error(`Expected an indexed object, got a ${typeof e} instead. Does your file follow Yaml's rules?`);if(Array.isArray(e))throw new Error(\"Expected an indexed object, got an array instead. Does your file follow Yaml's rules?\");return e}function Ki(t){return tje(t)}var ZD,iV,Z6e,rV,XD,eje,oV=Et(()=>{ZD=$e($K()),iV=$e(tV()),Z6e=/^(?![-?:,\\][{}#&*!|>'\"%@` \\t\\r\\n]).([ \\t]*(?![,\\][{}:# \\t\\r\\n]).)*$/,rV=[\"__metadata\",\"version\",\"resolution\",\"dependencies\",\"peerDependencies\",\"dependenciesMeta\",\"peerDependenciesMeta\",\"binaries\"],XD=class{constructor(e){this.data=e}};Ba.PreserveOrdering=XD;eje=/^(#.*(\\r?\\n))*?#\\s+yarn\\s+lockfile\\s+v1\\r?\\n/i});var eI={};Vt(eI,{parseResolution:()=>UD,parseShell:()=>LD,parseSyml:()=>Ki,stringifyArgument:()=>AT,stringifyArgumentSegment:()=>fT,stringifyArithmeticExpression:()=>MD,stringifyCommand:()=>uT,stringifyCommandChain:()=>ly,stringifyCommandChainThen:()=>cT,stringifyCommandLine:()=>OD,stringifyCommandLineThen:()=>lT,stringifyEnvSegment:()=>ND,stringifyRedirectArgument:()=>Kw,stringifyResolution:()=>_D,stringifyShell:()=>ay,stringifyShellLine:()=>ay,stringifySyml:()=>Ba,stringifyValueArgument:()=>qg});var Nl=Et(()=>{sW();cW();oV()});var lV=_((yxt,PT)=>{\"use strict\";var rje=t=>{let e=!1,r=!1,o=!1;for(let a=0;a<t.length;a++){let n=t[a];e&&/[a-zA-Z]/.test(n)&&n.toUpperCase()===n?(t=t.slice(0,a)+\"-\"+t.slice(a),e=!1,o=r,r=!0,a++):r&&o&&/[a-zA-Z]/.test(n)&&n.toLowerCase()===n?(t=t.slice(0,a-1)+\"-\"+t.slice(a-1),o=r,r=!1,e=!0):(e=n.toLowerCase()===n&&n.toUpperCase()!==n,o=r,r=n.toUpperCase()===n&&n.toLowerCase()!==n)}return t},aV=(t,e)=>{if(!(typeof t==\"string\"||Array.isArray(t)))throw new TypeError(\"Expected the input to be `string | string[]`\");e=Object.assign({pascalCase:!1},e);let r=a=>e.pascalCase?a.charAt(0).toUpperCase()+a.slice(1):a;return Array.isArray(t)?t=t.map(a=>a.trim()).filter(a=>a.length).join(\"-\"):t=t.trim(),t.length===0?\"\":t.length===1?e.pascalCase?t.toUpperCase():t.toLowerCase():(t!==t.toLowerCase()&&(t=rje(t)),t=t.replace(/^[_.\\- ]+/,\"\").toLowerCase().replace(/[_.\\- ]+(\\w|$)/g,(a,n)=>n.toUpperCase()).replace(/\\d+(\\w|$)/g,a=>a.toUpperCase()),r(t))};PT.exports=aV;PT.exports.default=aV});var cV=_((Ext,nje)=>{nje.exports=[{name:\"AppVeyor\",constant:\"APPVEYOR\",env:\"APPVEYOR\",pr:\"APPVEYOR_PULL_REQUEST_NUMBER\"},{name:\"Azure Pipelines\",constant:\"AZURE_PIPELINES\",env:\"SYSTEM_TEAMFOUNDATIONCOLLECTIONURI\",pr:\"SYSTEM_PULLREQUEST_PULLREQUESTID\"},{name:\"Appcircle\",constant:\"APPCIRCLE\",env:\"AC_APPCIRCLE\"},{name:\"Bamboo\",constant:\"BAMBOO\",env:\"bamboo_planKey\"},{name:\"Bitbucket Pipelines\",constant:\"BITBUCKET\",env:\"BITBUCKET_COMMIT\",pr:\"BITBUCKET_PR_ID\"},{name:\"Bitrise\",constant:\"BITRISE\",env:\"BITRISE_IO\",pr:\"BITRISE_PULL_REQUEST\"},{name:\"Buddy\",constant:\"BUDDY\",env:\"BUDDY_WORKSPACE_ID\",pr:\"BUDDY_EXECUTION_PULL_REQUEST_ID\"},{name:\"Buildkite\",constant:\"BUILDKITE\",env:\"BUILDKITE\",pr:{env:\"BUILDKITE_PULL_REQUEST\",ne:\"false\"}},{name:\"CircleCI\",constant:\"CIRCLE\",env:\"CIRCLECI\",pr:\"CIRCLE_PULL_REQUEST\"},{name:\"Cirrus CI\",constant:\"CIRRUS\",env:\"CIRRUS_CI\",pr:\"CIRRUS_PR\"},{name:\"AWS CodeBuild\",constant:\"CODEBUILD\",env:\"CODEBUILD_BUILD_ARN\"},{name:\"Codefresh\",constant:\"CODEFRESH\",env:\"CF_BUILD_ID\",pr:{any:[\"CF_PULL_REQUEST_NUMBER\",\"CF_PULL_REQUEST_ID\"]}},{name:\"Codeship\",constant:\"CODESHIP\",env:{CI_NAME:\"codeship\"}},{name:\"Drone\",constant:\"DRONE\",env:\"DRONE\",pr:{DRONE_BUILD_EVENT:\"pull_request\"}},{name:\"dsari\",constant:\"DSARI\",env:\"DSARI\"},{name:\"GitHub Actions\",constant:\"GITHUB_ACTIONS\",env:\"GITHUB_ACTIONS\",pr:{GITHUB_EVENT_NAME:\"pull_request\"}},{name:\"GitLab CI\",constant:\"GITLAB\",env:\"GITLAB_CI\",pr:\"CI_MERGE_REQUEST_ID\"},{name:\"GoCD\",constant:\"GOCD\",env:\"GO_PIPELINE_LABEL\"},{name:\"LayerCI\",constant:\"LAYERCI\",env:\"LAYERCI\",pr:\"LAYERCI_PULL_REQUEST\"},{name:\"Hudson\",constant:\"HUDSON\",env:\"HUDSON_URL\"},{name:\"Jenkins\",constant:\"JENKINS\",env:[\"JENKINS_URL\",\"BUILD_ID\"],pr:{any:[\"ghprbPullId\",\"CHANGE_ID\"]}},{name:\"Magnum CI\",constant:\"MAGNUM\",env:\"MAGNUM\"},{name:\"Netlify CI\",constant:\"NETLIFY\",env:\"NETLIFY\",pr:{env:\"PULL_REQUEST\",ne:\"false\"}},{name:\"Nevercode\",constant:\"NEVERCODE\",env:\"NEVERCODE\",pr:{env:\"NEVERCODE_PULL_REQUEST\",ne:\"false\"}},{name:\"Render\",constant:\"RENDER\",env:\"RENDER\",pr:{IS_PULL_REQUEST:\"true\"}},{name:\"Sail CI\",constant:\"SAIL\",env:\"SAILCI\",pr:\"SAIL_PULL_REQUEST_NUMBER\"},{name:\"Semaphore\",constant:\"SEMAPHORE\",env:\"SEMAPHORE\",pr:\"PULL_REQUEST_NUMBER\"},{name:\"Screwdriver\",constant:\"SCREWDRIVER\",env:\"SCREWDRIVER\",pr:{env:\"SD_PULL_REQUEST\",ne:\"false\"}},{name:\"Shippable\",constant:\"SHIPPABLE\",env:\"SHIPPABLE\",pr:{IS_PULL_REQUEST:\"true\"}},{name:\"Solano CI\",constant:\"SOLANO\",env:\"TDDIUM\",pr:\"TDDIUM_PR_ID\"},{name:\"Strider CD\",constant:\"STRIDER\",env:\"STRIDER\"},{name:\"TaskCluster\",constant:\"TASKCLUSTER\",env:[\"TASK_ID\",\"RUN_ID\"]},{name:\"TeamCity\",constant:\"TEAMCITY\",env:\"TEAMCITY_VERSION\"},{name:\"Travis CI\",constant:\"TRAVIS\",env:\"TRAVIS\",pr:{env:\"TRAVIS_PULL_REQUEST\",ne:\"false\"}},{name:\"Vercel\",constant:\"VERCEL\",env:\"NOW_BUILDER\"},{name:\"Visual Studio App Center\",constant:\"APPCENTER\",env:\"APPCENTER_BUILD_ID\"}]});var $g=_(Xa=>{\"use strict\";var AV=cV(),ju=process.env;Object.defineProperty(Xa,\"_vendors\",{value:AV.map(function(t){return t.constant})});Xa.name=null;Xa.isPR=null;AV.forEach(function(t){let r=(Array.isArray(t.env)?t.env:[t.env]).every(function(o){return uV(o)});if(Xa[t.constant]=r,r)switch(Xa.name=t.name,typeof t.pr){case\"string\":Xa.isPR=!!ju[t.pr];break;case\"object\":\"env\"in t.pr?Xa.isPR=t.pr.env in ju&&ju[t.pr.env]!==t.pr.ne:\"any\"in t.pr?Xa.isPR=t.pr.any.some(function(o){return!!ju[o]}):Xa.isPR=uV(t.pr);break;default:Xa.isPR=null}});Xa.isCI=!!(ju.CI||ju.CONTINUOUS_INTEGRATION||ju.BUILD_NUMBER||ju.RUN_ID||Xa.name);function uV(t){return typeof t==\"string\"?!!ju[t]:Object.keys(t).every(function(e){return ju[e]===t[e]})}});var Hn,cn,ed,ST,$D,fV,bT,xT,eP=Et(()=>{(function(t){t.StartOfInput=\"\\0\",t.EndOfInput=\"\u0001\",t.EndOfPartialInput=\"\u0002\"})(Hn||(Hn={}));(function(t){t[t.InitialNode=0]=\"InitialNode\",t[t.SuccessNode=1]=\"SuccessNode\",t[t.ErrorNode=2]=\"ErrorNode\",t[t.CustomNode=3]=\"CustomNode\"})(cn||(cn={}));ed=-1,ST=/^(-h|--help)(?:=([0-9]+))?$/,$D=/^(--[a-z]+(?:-[a-z]+)*|-[a-zA-Z]+)$/,fV=/^-[a-zA-Z]{2,}$/,bT=/^([^=]+)=([\\s\\S]*)$/,xT=process.env.DEBUG_CLI===\"1\"});var it,dy,tP,kT,rP=Et(()=>{eP();it=class extends Error{constructor(e){super(e),this.clipanion={type:\"usage\"},this.name=\"UsageError\"}},dy=class extends Error{constructor(e,r){if(super(),this.input=e,this.candidates=r,this.clipanion={type:\"none\"},this.name=\"UnknownSyntaxError\",this.candidates.length===0)this.message=\"Command not found, but we're not sure what's the alternative.\";else if(this.candidates.every(o=>o.reason!==null&&o.reason===r[0].reason)){let[{reason:o}]=this.candidates;this.message=`${o}\n\n${this.candidates.map(({usage:a})=>`$ ${a}`).join(`\n`)}`}else if(this.candidates.length===1){let[{usage:o}]=this.candidates;this.message=`Command not found; did you mean:\n\n$ ${o}\n${kT(e)}`}else this.message=`Command not found; did you mean one of:\n\n${this.candidates.map(({usage:o},a)=>`${`${a}.`.padStart(4)} ${o}`).join(`\n`)}\n\n${kT(e)}`}},tP=class extends Error{constructor(e,r){super(),this.input=e,this.usages=r,this.clipanion={type:\"none\"},this.name=\"AmbiguousSyntaxError\",this.message=`Cannot find which to pick amongst the following alternatives:\n\n${this.usages.map((o,a)=>`${`${a}.`.padStart(4)} ${o}`).join(`\n`)}\n\n${kT(e)}`}},kT=t=>`While running ${t.filter(e=>e!==Hn.EndOfInput&&e!==Hn.EndOfPartialInput).map(e=>{let r=JSON.stringify(e);return e.match(/\\s/)||e.length===0||r!==`\"${e}\"`?r:e}).join(\" \")}`});function ije(t){let e=t.split(`\n`),r=e.filter(a=>a.match(/\\S/)),o=r.length>0?r.reduce((a,n)=>Math.min(a,n.length-n.trimStart().length),Number.MAX_VALUE):0;return e.map(a=>a.slice(o).trimRight()).join(`\n`)}function Do(t,{format:e,paragraphs:r}){return t=t.replace(/\\r\\n?/g,`\n`),t=ije(t),t=t.replace(/^\\n+|\\n+$/g,\"\"),t=t.replace(/^(\\s*)-([^\\n]*?)\\n+/gm,`$1-$2\n\n`),t=t.replace(/\\n(\\n)?\\n*/g,(o,a)=>a||\" \"),r&&(t=t.split(/\\n/).map(o=>{let a=o.match(/^\\s*[*-][\\t ]+(.*)/);if(!a)return o.match(/(.{1,80})(?: |$)/g).join(`\n`);let n=o.length-o.trimStart().length;return a[1].match(new RegExp(`(.{1,${78-n}})(?: |$)`,\"g\")).map((u,A)=>\" \".repeat(n)+(A===0?\"- \":\"  \")+u).join(`\n`)}).join(`\n\n`)),t=t.replace(/(`+)((?:.|[\\n])*?)\\1/g,(o,a,n)=>e.code(a+n+a)),t=t.replace(/(\\*\\*)((?:.|[\\n])*?)\\1/g,(o,a,n)=>e.bold(a+n+a)),t?`${t}\n`:\"\"}var QT,pV,hV,FT=Et(()=>{QT=Array(80).fill(\"\\u2501\");for(let t=0;t<=24;++t)QT[QT.length-t]=`\\x1B[38;5;${232+t}m\\u2501`;pV={header:t=>`\\x1B[1m\\u2501\\u2501\\u2501 ${t}${t.length<80-5?` ${QT.slice(t.length+5).join(\"\")}`:\":\"}\\x1B[0m`,bold:t=>`\\x1B[1m${t}\\x1B[22m`,error:t=>`\\x1B[31m\\x1B[1m${t}\\x1B[22m\\x1B[39m`,code:t=>`\\x1B[36m${t}\\x1B[39m`},hV={header:t=>t,bold:t=>t,error:t=>t,code:t=>t}});function Ko(t){return{...t,[tI]:!0}}function qu(t,e){return typeof t>\"u\"?[t,e]:typeof t==\"object\"&&t!==null&&!Array.isArray(t)?[void 0,t]:[t,e]}function nP(t,{mergeName:e=!1}={}){let r=t.match(/^([^:]+): (.*)$/m);if(!r)return\"validation failed\";let[,o,a]=r;return e&&(a=a[0].toLowerCase()+a.slice(1)),a=o!==\".\"||!e?`${o.replace(/^\\.(\\[|$)/,\"$1\")}: ${a}`:`: ${a}`,a}function rI(t,e){return e.length===1?new it(`${t}${nP(e[0],{mergeName:!0})}`):new it(`${t}:\n${e.map(r=>`\n- ${nP(r)}`).join(\"\")}`)}function td(t,e,r){if(typeof r>\"u\")return e;let o=[],a=[],n=A=>{let p=e;return e=A,n.bind(null,p)};if(!r(e,{errors:o,coercions:a,coercion:n}))throw rI(`Invalid value for ${t}`,o);for(let[,A]of a)A();return e}var tI,yf=Et(()=>{rP();tI=Symbol(\"clipanion/isOption\")});var Vo={};Vt(Vo,{KeyRelationship:()=>Gu,TypeAssertionError:()=>Yp,applyCascade:()=>sI,as:()=>Bje,assert:()=>Cje,assertWithErrors:()=>wje,cascade:()=>aP,fn:()=>vje,hasAtLeastOneKey:()=>UT,hasExactLength:()=>EV,hasForbiddenKeys:()=>qje,hasKeyRelationship:()=>aI,hasMaxLength:()=>Pje,hasMinLength:()=>Dje,hasMutuallyExclusiveKeys:()=>Gje,hasRequiredKeys:()=>jje,hasUniqueItems:()=>Sje,isArray:()=>iP,isAtLeast:()=>OT,isAtMost:()=>kje,isBase64:()=>Mje,isBoolean:()=>fje,isDate:()=>hje,isDict:()=>mje,isEnum:()=>Ks,isHexColor:()=>Oje,isISO8601:()=>Lje,isInExclusiveRange:()=>Fje,isInInclusiveRange:()=>Qje,isInstanceOf:()=>Eje,isInteger:()=>MT,isJSON:()=>Uje,isLiteral:()=>dV,isLowerCase:()=>Rje,isMap:()=>dje,isNegative:()=>bje,isNullable:()=>Hje,isNumber:()=>NT,isObject:()=>mV,isOneOf:()=>LT,isOptional:()=>_je,isPartial:()=>yje,isPayload:()=>pje,isPositive:()=>xje,isRecord:()=>oP,isSet:()=>gje,isString:()=>yy,isTuple:()=>sP,isUUID4:()=>Nje,isUnknown:()=>TT,isUpperCase:()=>Tje,makeTrait:()=>yV,makeValidator:()=>Hr,matchesRegExp:()=>iI,softAssert:()=>Ije});function jn(t){return t===null?\"null\":t===void 0?\"undefined\":t===\"\"?\"an empty string\":typeof t==\"symbol\"?`<${t.toString()}>`:Array.isArray(t)?\"an array\":JSON.stringify(t)}function my(t,e){if(t.length===0)return\"nothing\";if(t.length===1)return jn(t[0]);let r=t.slice(0,-1),o=t[t.length-1],a=t.length>2?`, ${e} `:` ${e} `;return`${r.map(n=>jn(n)).join(\", \")}${a}${jn(o)}`}function Gp(t,e){var r,o,a;return typeof e==\"number\"?`${(r=t?.p)!==null&&r!==void 0?r:\".\"}[${e}]`:sje.test(e)?`${(o=t?.p)!==null&&o!==void 0?o:\"\"}.${e}`:`${(a=t?.p)!==null&&a!==void 0?a:\".\"}[${JSON.stringify(e)}]`}function RT(t,e,r){return t===1?e:r}function pr({errors:t,p:e}={},r){return t?.push(`${e??\".\"}: ${r}`),!1}function uje(t,e){return r=>{t[e]=r}}function Yu(t,e){return r=>{let o=t[e];return t[e]=r,Yu(t,e).bind(null,o)}}function nI(t,e,r){let o=()=>(t(r()),a),a=()=>(t(e),o);return o}function TT(){return Hr({test:(t,e)=>!0})}function dV(t){return Hr({test:(e,r)=>e!==t?pr(r,`Expected ${jn(t)} (got ${jn(e)})`):!0})}function yy(){return Hr({test:(t,e)=>typeof t!=\"string\"?pr(e,`Expected a string (got ${jn(t)})`):!0})}function Ks(t){let e=Array.isArray(t)?t:Object.values(t),r=e.every(a=>typeof a==\"string\"||typeof a==\"number\"),o=new Set(e);return o.size===1?dV([...o][0]):Hr({test:(a,n)=>o.has(a)?!0:r?pr(n,`Expected one of ${my(e,\"or\")} (got ${jn(a)})`):pr(n,`Expected a valid enumeration value (got ${jn(a)})`)})}function fje(){return Hr({test:(t,e)=>{var r;if(typeof t!=\"boolean\"){if(typeof e?.coercions<\"u\"){if(typeof e?.coercion>\"u\")return pr(e,\"Unbound coercion result\");let o=Aje.get(t);if(typeof o<\"u\")return e.coercions.push([(r=e.p)!==null&&r!==void 0?r:\".\",e.coercion.bind(null,o)]),!0}return pr(e,`Expected a boolean (got ${jn(t)})`)}return!0}})}function NT(){return Hr({test:(t,e)=>{var r;if(typeof t!=\"number\"){if(typeof e?.coercions<\"u\"){if(typeof e?.coercion>\"u\")return pr(e,\"Unbound coercion result\");let o;if(typeof t==\"string\"){let a;try{a=JSON.parse(t)}catch{}if(typeof a==\"number\")if(JSON.stringify(a)===t)o=a;else return pr(e,`Received a number that can't be safely represented by the runtime (${t})`)}if(typeof o<\"u\")return e.coercions.push([(r=e.p)!==null&&r!==void 0?r:\".\",e.coercion.bind(null,o)]),!0}return pr(e,`Expected a number (got ${jn(t)})`)}return!0}})}function pje(t){return Hr({test:(e,r)=>{var o;if(typeof r?.coercions>\"u\")return pr(r,\"The isPayload predicate can only be used with coercion enabled\");if(typeof r.coercion>\"u\")return pr(r,\"Unbound coercion result\");if(typeof e!=\"string\")return pr(r,`Expected a string (got ${jn(e)})`);let a;try{a=JSON.parse(e)}catch{return pr(r,`Expected a JSON string (got ${jn(e)})`)}let n={value:a};return t(a,Object.assign(Object.assign({},r),{coercion:Yu(n,\"value\")}))?(r.coercions.push([(o=r.p)!==null&&o!==void 0?o:\".\",r.coercion.bind(null,n.value)]),!0):!1}})}function hje(){return Hr({test:(t,e)=>{var r;if(!(t instanceof Date)){if(typeof e?.coercions<\"u\"){if(typeof e?.coercion>\"u\")return pr(e,\"Unbound coercion result\");let o;if(typeof t==\"string\"&&gV.test(t))o=new Date(t);else{let a;if(typeof t==\"string\"){let n;try{n=JSON.parse(t)}catch{}typeof n==\"number\"&&(a=n)}else typeof t==\"number\"&&(a=t);if(typeof a<\"u\")if(Number.isSafeInteger(a)||!Number.isSafeInteger(a*1e3))o=new Date(a*1e3);else return pr(e,`Received a timestamp that can't be safely represented by the runtime (${t})`)}if(typeof o<\"u\")return e.coercions.push([(r=e.p)!==null&&r!==void 0?r:\".\",e.coercion.bind(null,o)]),!0}return pr(e,`Expected a date (got ${jn(t)})`)}return!0}})}function iP(t,{delimiter:e}={}){return Hr({test:(r,o)=>{var a;let n=r;if(typeof r==\"string\"&&typeof e<\"u\"&&typeof o?.coercions<\"u\"){if(typeof o?.coercion>\"u\")return pr(o,\"Unbound coercion result\");r=r.split(e)}if(!Array.isArray(r))return pr(o,`Expected an array (got ${jn(r)})`);let u=!0;for(let A=0,p=r.length;A<p&&(u=t(r[A],Object.assign(Object.assign({},o),{p:Gp(o,A),coercion:Yu(r,A)}))&&u,!(!u&&o?.errors==null));++A);return r!==n&&o.coercions.push([(a=o.p)!==null&&a!==void 0?a:\".\",o.coercion.bind(null,r)]),u}})}function gje(t,{delimiter:e}={}){let r=iP(t,{delimiter:e});return Hr({test:(o,a)=>{var n,u;if(Object.getPrototypeOf(o).toString()===\"[object Set]\")if(typeof a?.coercions<\"u\"){if(typeof a?.coercion>\"u\")return pr(a,\"Unbound coercion result\");let A=[...o],p=[...o];if(!r(p,Object.assign(Object.assign({},a),{coercion:void 0})))return!1;let h=()=>p.some((C,I)=>C!==A[I])?new Set(p):o;return a.coercions.push([(n=a.p)!==null&&n!==void 0?n:\".\",nI(a.coercion,o,h)]),!0}else{let A=!0;for(let p of o)if(A=t(p,Object.assign({},a))&&A,!A&&a?.errors==null)break;return A}if(typeof a?.coercions<\"u\"){if(typeof a?.coercion>\"u\")return pr(a,\"Unbound coercion result\");let A={value:o};return r(o,Object.assign(Object.assign({},a),{coercion:Yu(A,\"value\")}))?(a.coercions.push([(u=a.p)!==null&&u!==void 0?u:\".\",nI(a.coercion,o,()=>new Set(A.value))]),!0):!1}return pr(a,`Expected a set (got ${jn(o)})`)}})}function dje(t,e){let r=iP(sP([t,e])),o=oP(e,{keys:t});return Hr({test:(a,n)=>{var u,A,p;if(Object.getPrototypeOf(a).toString()===\"[object Map]\")if(typeof n?.coercions<\"u\"){if(typeof n?.coercion>\"u\")return pr(n,\"Unbound coercion result\");let h=[...a],C=[...a];if(!r(C,Object.assign(Object.assign({},n),{coercion:void 0})))return!1;let I=()=>C.some((v,x)=>v[0]!==h[x][0]||v[1]!==h[x][1])?new Map(C):a;return n.coercions.push([(u=n.p)!==null&&u!==void 0?u:\".\",nI(n.coercion,a,I)]),!0}else{let h=!0;for(let[C,I]of a)if(h=t(C,Object.assign({},n))&&h,!h&&n?.errors==null||(h=e(I,Object.assign(Object.assign({},n),{p:Gp(n,C)}))&&h,!h&&n?.errors==null))break;return h}if(typeof n?.coercions<\"u\"){if(typeof n?.coercion>\"u\")return pr(n,\"Unbound coercion result\");let h={value:a};return Array.isArray(a)?r(a,Object.assign(Object.assign({},n),{coercion:void 0}))?(n.coercions.push([(A=n.p)!==null&&A!==void 0?A:\".\",nI(n.coercion,a,()=>new Map(h.value))]),!0):!1:o(a,Object.assign(Object.assign({},n),{coercion:Yu(h,\"value\")}))?(n.coercions.push([(p=n.p)!==null&&p!==void 0?p:\".\",nI(n.coercion,a,()=>new Map(Object.entries(h.value)))]),!0):!1}return pr(n,`Expected a map (got ${jn(a)})`)}})}function sP(t,{delimiter:e}={}){let r=EV(t.length);return Hr({test:(o,a)=>{var n;if(typeof o==\"string\"&&typeof e<\"u\"&&typeof a?.coercions<\"u\"){if(typeof a?.coercion>\"u\")return pr(a,\"Unbound coercion result\");o=o.split(e),a.coercions.push([(n=a.p)!==null&&n!==void 0?n:\".\",a.coercion.bind(null,o)])}if(!Array.isArray(o))return pr(a,`Expected a tuple (got ${jn(o)})`);let u=r(o,Object.assign({},a));for(let A=0,p=o.length;A<p&&A<t.length&&(u=t[A](o[A],Object.assign(Object.assign({},a),{p:Gp(a,A),coercion:Yu(o,A)}))&&u,!(!u&&a?.errors==null));++A);return u}})}function oP(t,{keys:e=null}={}){let r=iP(sP([e??yy(),t]));return Hr({test:(o,a)=>{var n;if(Array.isArray(o)&&typeof a?.coercions<\"u\")return typeof a?.coercion>\"u\"?pr(a,\"Unbound coercion result\"):r(o,Object.assign(Object.assign({},a),{coercion:void 0}))?(o=Object.fromEntries(o),a.coercions.push([(n=a.p)!==null&&n!==void 0?n:\".\",a.coercion.bind(null,o)]),!0):!1;if(typeof o!=\"object\"||o===null)return pr(a,`Expected an object (got ${jn(o)})`);let u=Object.keys(o),A=!0;for(let p=0,h=u.length;p<h&&(A||a?.errors!=null);++p){let C=u[p],I=o[C];if(C===\"__proto__\"||C===\"constructor\"){A=pr(Object.assign(Object.assign({},a),{p:Gp(a,C)}),\"Unsafe property name\");continue}if(e!==null&&!e(C,a)){A=!1;continue}if(!t(I,Object.assign(Object.assign({},a),{p:Gp(a,C),coercion:Yu(o,C)}))){A=!1;continue}}return A}})}function mje(t,e={}){return oP(t,e)}function mV(t,{extra:e=null}={}){let r=Object.keys(t),o=Hr({test:(a,n)=>{if(typeof a!=\"object\"||a===null)return pr(n,`Expected an object (got ${jn(a)})`);let u=new Set([...r,...Object.keys(a)]),A={},p=!0;for(let h of u){if(h===\"constructor\"||h===\"__proto__\")p=pr(Object.assign(Object.assign({},n),{p:Gp(n,h)}),\"Unsafe property name\");else{let C=Object.prototype.hasOwnProperty.call(t,h)?t[h]:void 0,I=Object.prototype.hasOwnProperty.call(a,h)?a[h]:void 0;typeof C<\"u\"?p=C(I,Object.assign(Object.assign({},n),{p:Gp(n,h),coercion:Yu(a,h)}))&&p:e===null?p=pr(Object.assign(Object.assign({},n),{p:Gp(n,h)}),`Extraneous property (got ${jn(I)})`):Object.defineProperty(A,h,{enumerable:!0,get:()=>I,set:uje(a,h)})}if(!p&&n?.errors==null)break}return e!==null&&(p||n?.errors!=null)&&(p=e(A,n)&&p),p}});return Object.assign(o,{properties:t})}function yje(t){return mV(t,{extra:oP(TT())})}function yV(t){return()=>t}function Hr({test:t}){return yV(t)()}function Cje(t,e){if(!e(t))throw new Yp}function wje(t,e){let r=[];if(!e(t,{errors:r}))throw new Yp({errors:r})}function Ije(t,e){}function Bje(t,e,{coerce:r=!1,errors:o,throw:a}={}){let n=o?[]:void 0;if(!r){if(e(t,{errors:n}))return a?t:{value:t,errors:void 0};if(a)throw new Yp({errors:n});return{value:void 0,errors:n??!0}}let u={value:t},A=Yu(u,\"value\"),p=[];if(!e(t,{errors:n,coercion:A,coercions:p})){if(a)throw new Yp({errors:n});return{value:void 0,errors:n??!0}}for(let[,h]of p)h();return a?u.value:{value:u.value,errors:void 0}}function vje(t,e){let r=sP(t);return(...o)=>{if(!r(o))throw new Yp;return e(...o)}}function Dje(t){return Hr({test:(e,r)=>e.length>=t?!0:pr(r,`Expected to have a length of at least ${t} elements (got ${e.length})`)})}function Pje(t){return Hr({test:(e,r)=>e.length<=t?!0:pr(r,`Expected to have a length of at most ${t} elements (got ${e.length})`)})}function EV(t){return Hr({test:(e,r)=>e.length!==t?pr(r,`Expected to have a length of exactly ${t} elements (got ${e.length})`):!0})}function Sje({map:t}={}){return Hr({test:(e,r)=>{let o=new Set,a=new Set;for(let n=0,u=e.length;n<u;++n){let A=e[n],p=typeof t<\"u\"?t(A):A;if(o.has(p)){if(a.has(p))continue;pr(r,`Expected to contain unique elements; got a duplicate with ${jn(e)}`),a.add(p)}else o.add(p)}return a.size===0}})}function bje(){return Hr({test:(t,e)=>t<=0?!0:pr(e,`Expected to be negative (got ${t})`)})}function xje(){return Hr({test:(t,e)=>t>=0?!0:pr(e,`Expected to be positive (got ${t})`)})}function OT(t){return Hr({test:(e,r)=>e>=t?!0:pr(r,`Expected to be at least ${t} (got ${e})`)})}function kje(t){return Hr({test:(e,r)=>e<=t?!0:pr(r,`Expected to be at most ${t} (got ${e})`)})}function Qje(t,e){return Hr({test:(r,o)=>r>=t&&r<=e?!0:pr(o,`Expected to be in the [${t}; ${e}] range (got ${r})`)})}function Fje(t,e){return Hr({test:(r,o)=>r>=t&&r<e?!0:pr(o,`Expected to be in the [${t}; ${e}[ range (got ${r})`)})}function MT({unsafe:t=!1}={}){return Hr({test:(e,r)=>e!==Math.round(e)?pr(r,`Expected to be an integer (got ${e})`):!t&&!Number.isSafeInteger(e)?pr(r,`Expected to be a safe integer (got ${e})`):!0})}function iI(t){return Hr({test:(e,r)=>t.test(e)?!0:pr(r,`Expected to match the pattern ${t.toString()} (got ${jn(e)})`)})}function Rje(){return Hr({test:(t,e)=>t!==t.toLowerCase()?pr(e,`Expected to be all-lowercase (got ${t})`):!0})}function Tje(){return Hr({test:(t,e)=>t!==t.toUpperCase()?pr(e,`Expected to be all-uppercase (got ${t})`):!0})}function Nje(){return Hr({test:(t,e)=>cje.test(t)?!0:pr(e,`Expected to be a valid UUID v4 (got ${jn(t)})`)})}function Lje(){return Hr({test:(t,e)=>gV.test(t)?!0:pr(e,`Expected to be a valid ISO 8601 date string (got ${jn(t)})`)})}function Oje({alpha:t=!1}){return Hr({test:(e,r)=>(t?oje.test(e):aje.test(e))?!0:pr(r,`Expected to be a valid hexadecimal color string (got ${jn(e)})`)})}function Mje(){return Hr({test:(t,e)=>lje.test(t)?!0:pr(e,`Expected to be a valid base 64 string (got ${jn(t)})`)})}function Uje(t=TT()){return Hr({test:(e,r)=>{let o;try{o=JSON.parse(e)}catch{return pr(r,`Expected to be a valid JSON string (got ${jn(e)})`)}return t(o,r)}})}function aP(t,...e){let r=Array.isArray(e[0])?e[0]:e;return Hr({test:(o,a)=>{var n,u;let A={value:o},p=typeof a?.coercions<\"u\"?Yu(A,\"value\"):void 0,h=typeof a?.coercions<\"u\"?[]:void 0;if(!t(o,Object.assign(Object.assign({},a),{coercion:p,coercions:h})))return!1;let C=[];if(typeof h<\"u\")for(let[,I]of h)C.push(I());try{if(typeof a?.coercions<\"u\"){if(A.value!==o){if(typeof a?.coercion>\"u\")return pr(a,\"Unbound coercion result\");a.coercions.push([(n=a.p)!==null&&n!==void 0?n:\".\",a.coercion.bind(null,A.value)])}(u=a?.coercions)===null||u===void 0||u.push(...h)}return r.every(I=>I(A.value,a))}finally{for(let I of C)I()}}})}function sI(t,...e){let r=Array.isArray(e[0])?e[0]:e;return aP(t,r)}function _je(t){return Hr({test:(e,r)=>typeof e>\"u\"?!0:t(e,r)})}function Hje(t){return Hr({test:(e,r)=>e===null?!0:t(e,r)})}function jje(t,e){var r;let o=new Set(t),a=oI[(r=e?.missingIf)!==null&&r!==void 0?r:\"missing\"];return Hr({test:(n,u)=>{let A=new Set(Object.keys(n)),p=[];for(let h of o)a(A,h,n)||p.push(h);return p.length>0?pr(u,`Missing required ${RT(p.length,\"property\",\"properties\")} ${my(p,\"and\")}`):!0}})}function UT(t,e){var r;let o=new Set(t),a=oI[(r=e?.missingIf)!==null&&r!==void 0?r:\"missing\"];return Hr({test:(n,u)=>Object.keys(n).some(h=>a(o,h,n))?!0:pr(u,`Missing at least one property from ${my(Array.from(o),\"or\")}`)})}function qje(t,e){var r;let o=new Set(t),a=oI[(r=e?.missingIf)!==null&&r!==void 0?r:\"missing\"];return Hr({test:(n,u)=>{let A=new Set(Object.keys(n)),p=[];for(let h of o)a(A,h,n)&&p.push(h);return p.length>0?pr(u,`Forbidden ${RT(p.length,\"property\",\"properties\")} ${my(p,\"and\")}`):!0}})}function Gje(t,e){var r;let o=new Set(t),a=oI[(r=e?.missingIf)!==null&&r!==void 0?r:\"missing\"];return Hr({test:(n,u)=>{let A=new Set(Object.keys(n)),p=[];for(let h of o)a(A,h,n)&&p.push(h);return p.length>1?pr(u,`Mutually exclusive properties ${my(p,\"and\")}`):!0}})}function aI(t,e,r,o){var a,n;let u=new Set((a=o?.ignore)!==null&&a!==void 0?a:[]),A=oI[(n=o?.missingIf)!==null&&n!==void 0?n:\"missing\"],p=new Set(r),h=Yje[e],C=e===Gu.Forbids?\"or\":\"and\";return Hr({test:(I,v)=>{let x=new Set(Object.keys(I));if(!A(x,t,I)||u.has(I[t]))return!0;let E=[];for(let R of p)(A(x,R,I)&&!u.has(I[R]))!==h.expect&&E.push(R);return E.length>=1?pr(v,`Property \"${t}\" ${h.message} ${RT(E.length,\"property\",\"properties\")} ${my(E,C)}`):!0}})}var sje,oje,aje,lje,cje,gV,Aje,Eje,LT,Yp,oI,Gu,Yje,Za=Et(()=>{sje=/^[a-zA-Z_][a-zA-Z0-9_]*$/;oje=/^#[0-9a-f]{6}$/i,aje=/^#[0-9a-f]{6}([0-9a-f]{2})?$/i,lje=/^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$/,cje=/^[a-f0-9]{8}-[a-f0-9]{4}-4[a-f0-9]{3}-[89aAbB][a-f0-9]{3}-[a-f0-9]{12}$/i,gV=/^(?:[1-9]\\d{3}(-?)(?:(?:0[1-9]|1[0-2])\\1(?:0[1-9]|1\\d|2[0-8])|(?:0[13-9]|1[0-2])\\1(?:29|30)|(?:0[13578]|1[02])(?:\\1)31|00[1-9]|0[1-9]\\d|[12]\\d{2}|3(?:[0-5]\\d|6[0-5]))|(?:[1-9]\\d(?:0[48]|[2468][048]|[13579][26])|(?:[2468][048]|[13579][26])00)(?:(-?)02(?:\\2)29|-?366))T(?:[01]\\d|2[0-3])(:?)[0-5]\\d(?:\\3[0-5]\\d)?(?:Z|[+-][01]\\d(?:\\3[0-5]\\d)?)$/;Aje=new Map([[\"true\",!0],[\"True\",!0],[\"1\",!0],[1,!0],[\"false\",!1],[\"False\",!1],[\"0\",!1],[0,!1]]);Eje=t=>Hr({test:(e,r)=>e instanceof t?!0:pr(r,`Expected an instance of ${t.name} (got ${jn(e)})`)}),LT=(t,{exclusive:e=!1}={})=>Hr({test:(r,o)=>{var a,n,u;let A=[],p=typeof o?.errors<\"u\"?[]:void 0;for(let h=0,C=t.length;h<C;++h){let I=typeof o?.errors<\"u\"?[]:void 0,v=typeof o?.coercions<\"u\"?[]:void 0;if(t[h](r,Object.assign(Object.assign({},o),{errors:I,coercions:v,p:`${(a=o?.p)!==null&&a!==void 0?a:\".\"}#${h+1}`}))){if(A.push([`#${h+1}`,v]),!e)break}else p?.push(I[0])}if(A.length===1){let[,h]=A[0];return typeof h<\"u\"&&((n=o?.coercions)===null||n===void 0||n.push(...h)),!0}return A.length>1?pr(o,`Expected to match exactly a single predicate (matched ${A.join(\", \")})`):(u=o?.errors)===null||u===void 0||u.push(...p),!1}});Yp=class extends Error{constructor({errors:e}={}){let r=\"Type mismatch\";if(e&&e.length>0){r+=`\n`;for(let o of e)r+=`\n- ${o}`}super(r)}};oI={missing:(t,e)=>t.has(e),undefined:(t,e,r)=>t.has(e)&&typeof r[e]<\"u\",nil:(t,e,r)=>t.has(e)&&r[e]!=null,falsy:(t,e,r)=>t.has(e)&&!!r[e]};(function(t){t.Forbids=\"Forbids\",t.Requires=\"Requires\"})(Gu||(Gu={}));Yje={[Gu.Forbids]:{expect:!1,message:\"forbids using\"},[Gu.Requires]:{expect:!0,message:\"requires using\"}}});var nt,Wp=Et(()=>{yf();nt=class{constructor(){this.help=!1}static Usage(e){return e}async catch(e){throw e}async validateAndExecute(){let r=this.constructor.schema;if(Array.isArray(r)){let{isDict:a,isUnknown:n,applyCascade:u}=await Promise.resolve().then(()=>(Za(),Vo)),A=u(a(n()),r),p=[],h=[];if(!A(this,{errors:p,coercions:h}))throw rI(\"Invalid option schema\",p);for(let[,I]of h)I()}else if(r!=null)throw new Error(\"Invalid command schema\");let o=await this.execute();return typeof o<\"u\"?o:0}};nt.isOption=tI;nt.Default=[]});function va(t){xT&&console.log(t)}function wV(){let t={nodes:[]};for(let e=0;e<cn.CustomNode;++e)t.nodes.push($a());return t}function Wje(t){let e=wV(),r=[],o=e.nodes.length;for(let a of t){r.push(o);for(let n=0;n<a.nodes.length;++n)BV(n)||e.nodes.push(eqe(a.nodes[n],o));o+=a.nodes.length-cn.CustomNode+1}for(let a of r)Ey(e,cn.InitialNode,a);return e}function Oc(t,e){return t.nodes.push(e),t.nodes.length-1}function Kje(t){let e=new Set,r=o=>{if(e.has(o))return;e.add(o);let a=t.nodes[o];for(let u of Object.values(a.statics))for(let{to:A}of u)r(A);for(let[,{to:u}]of a.dynamics)r(u);for(let{to:u}of a.shortcuts)r(u);let n=new Set(a.shortcuts.map(({to:u})=>u));for(;a.shortcuts.length>0;){let{to:u}=a.shortcuts.shift(),A=t.nodes[u];for(let[p,h]of Object.entries(A.statics)){let C=Object.prototype.hasOwnProperty.call(a.statics,p)?a.statics[p]:a.statics[p]=[];for(let I of h)C.some(({to:v})=>I.to===v)||C.push(I)}for(let[p,h]of A.dynamics)a.dynamics.some(([C,{to:I}])=>p===C&&h.to===I)||a.dynamics.push([p,h]);for(let p of A.shortcuts)n.has(p.to)||(a.shortcuts.push(p),n.add(p.to))}};r(cn.InitialNode)}function Vje(t,{prefix:e=\"\"}={}){if(xT){va(`${e}Nodes are:`);for(let r=0;r<t.nodes.length;++r)va(`${e}  ${r}: ${JSON.stringify(t.nodes[r])}`)}}function zje(t,e,r=!1){va(`Running a vm on ${JSON.stringify(e)}`);let o=[{node:cn.InitialNode,state:{candidateUsage:null,requiredOptions:[],errorMessage:null,ignoreOptions:!1,options:[],path:[],positionals:[],remainder:null,selectedIndex:null,partial:!1,tokens:[]}}];Vje(t,{prefix:\"  \"});let a=[Hn.StartOfInput,...e];for(let n=0;n<a.length;++n){let u=a[n],A=u===Hn.EndOfInput||u===Hn.EndOfPartialInput,p=n-1;va(`  Processing ${JSON.stringify(u)}`);let h=[];for(let{node:C,state:I}of o){va(`    Current node is ${C}`);let v=t.nodes[C];if(C===cn.ErrorNode){h.push({node:C,state:I});continue}console.assert(v.shortcuts.length===0,\"Shortcuts should have been eliminated by now\");let x=Object.prototype.hasOwnProperty.call(v.statics,u);if(!r||n<a.length-1||x)if(x){let E=v.statics[u];for(let{to:R,reducer:L}of E)h.push({node:R,state:typeof L<\"u\"?lP(HT,L,I,u,p):I}),va(`      Static transition to ${R} found`)}else va(\"      No static transition found\");else{let E=!1;for(let R of Object.keys(v.statics))if(!!R.startsWith(u)){if(u===R)for(let{to:L,reducer:U}of v.statics[R])h.push({node:L,state:typeof U<\"u\"?lP(HT,U,I,u,p):I}),va(`      Static transition to ${L} found`);else for(let{to:L}of v.statics[R])h.push({node:L,state:{...I,remainder:R.slice(u.length)}}),va(`      Static transition to ${L} found (partial match)`);E=!0}E||va(\"      No partial static transition found\")}if(!A)for(let[E,{to:R,reducer:L}]of v.dynamics)lP(tqe,E,I,u,p)&&(h.push({node:R,state:typeof L<\"u\"?lP(HT,L,I,u,p):I}),va(`      Dynamic transition to ${R} found (via ${E})`))}if(h.length===0&&A&&e.length===1)return[{node:cn.InitialNode,state:CV}];if(h.length===0)throw new dy(e,o.filter(({node:C})=>C!==cn.ErrorNode).map(({state:C})=>({usage:C.candidateUsage,reason:null})));if(h.every(({node:C})=>C===cn.ErrorNode))throw new dy(e,h.map(({state:C})=>({usage:C.candidateUsage,reason:C.errorMessage})));o=Xje(h)}if(o.length>0){va(\"  Results:\");for(let n of o)va(`    - ${n.node} -> ${JSON.stringify(n.state)}`)}else va(\"  No results\");return o}function Jje(t,e,{endToken:r=Hn.EndOfInput}={}){let o=zje(t,[...e,r]);return Zje(e,o.map(({state:a})=>a))}function Xje(t){let e=0;for(let{state:r}of t)r.path.length>e&&(e=r.path.length);return t.filter(({state:r})=>r.path.length===e)}function Zje(t,e){let r=e.filter(v=>v.selectedIndex!==null),o=r.filter(v=>!v.partial);if(o.length>0&&(r=o),r.length===0)throw new Error;let a=r.filter(v=>v.selectedIndex===ed||v.requiredOptions.every(x=>x.some(E=>v.options.find(R=>R.name===E))));if(a.length===0)throw new dy(t,r.map(v=>({usage:v.candidateUsage,reason:null})));let n=0;for(let v of a)v.path.length>n&&(n=v.path.length);let u=a.filter(v=>v.path.length===n),A=v=>v.positionals.filter(({extra:x})=>!x).length+v.options.length,p=u.map(v=>({state:v,positionalCount:A(v)})),h=0;for(let{positionalCount:v}of p)v>h&&(h=v);let C=p.filter(({positionalCount:v})=>v===h).map(({state:v})=>v),I=$je(C);if(I.length>1)throw new tP(t,I.map(v=>v.candidateUsage));return I[0]}function $je(t){let e=[],r=[];for(let o of t)o.selectedIndex===ed?r.push(o):e.push(o);return r.length>0&&e.push({...CV,path:IV(...r.map(o=>o.path)),options:r.reduce((o,a)=>o.concat(a.options),[])}),e}function IV(t,e,...r){return e===void 0?Array.from(t):IV(t.filter((o,a)=>o===e[a]),...r)}function $a(){return{dynamics:[],shortcuts:[],statics:{}}}function BV(t){return t===cn.SuccessNode||t===cn.ErrorNode}function _T(t,e=0){return{to:BV(t.to)?t.to:t.to>=cn.CustomNode?t.to+e-cn.CustomNode+1:t.to+e,reducer:t.reducer}}function eqe(t,e=0){let r=$a();for(let[o,a]of t.dynamics)r.dynamics.push([o,_T(a,e)]);for(let o of t.shortcuts)r.shortcuts.push(_T(o,e));for(let[o,a]of Object.entries(t.statics))r.statics[o]=a.map(n=>_T(n,e));return r}function Ss(t,e,r,o,a){t.nodes[e].dynamics.push([r,{to:o,reducer:a}])}function Ey(t,e,r,o){t.nodes[e].shortcuts.push({to:r,reducer:o})}function zo(t,e,r,o,a){(Object.prototype.hasOwnProperty.call(t.nodes[e].statics,r)?t.nodes[e].statics[r]:t.nodes[e].statics[r]=[]).push({to:o,reducer:a})}function lP(t,e,r,o,a){if(Array.isArray(e)){let[n,...u]=e;return t[n](r,o,a,...u)}else return t[e](r,o,a)}var CV,tqe,HT,el,jT,Cy,cP=Et(()=>{eP();rP();CV={candidateUsage:null,requiredOptions:[],errorMessage:null,ignoreOptions:!1,path:[],positionals:[],options:[],remainder:null,selectedIndex:ed,partial:!1,tokens:[]};tqe={always:()=>!0,isOptionLike:(t,e)=>!t.ignoreOptions&&e!==\"-\"&&e.startsWith(\"-\"),isNotOptionLike:(t,e)=>t.ignoreOptions||e===\"-\"||!e.startsWith(\"-\"),isOption:(t,e,r,o)=>!t.ignoreOptions&&e===o,isBatchOption:(t,e,r,o)=>!t.ignoreOptions&&fV.test(e)&&[...e.slice(1)].every(a=>o.has(`-${a}`)),isBoundOption:(t,e,r,o,a)=>{let n=e.match(bT);return!t.ignoreOptions&&!!n&&$D.test(n[1])&&o.has(n[1])&&a.filter(u=>u.nameSet.includes(n[1])).every(u=>u.allowBinding)},isNegatedOption:(t,e,r,o)=>!t.ignoreOptions&&e===`--no-${o.slice(2)}`,isHelp:(t,e)=>!t.ignoreOptions&&ST.test(e),isUnsupportedOption:(t,e,r,o)=>!t.ignoreOptions&&e.startsWith(\"-\")&&$D.test(e)&&!o.has(e),isInvalidOption:(t,e)=>!t.ignoreOptions&&e.startsWith(\"-\")&&!$D.test(e)},HT={setCandidateState:(t,e,r,o)=>({...t,...o}),setSelectedIndex:(t,e,r,o)=>({...t,selectedIndex:o}),setPartialIndex:(t,e,r,o)=>({...t,selectedIndex:o,partial:!0}),pushBatch:(t,e,r,o)=>{let a=t.options.slice(),n=t.tokens.slice();for(let u=1;u<e.length;++u){let A=o.get(`-${e[u]}`),p=u===1?[0,2]:[u,u+1];a.push({name:A,value:!0}),n.push({segmentIndex:r,type:\"option\",option:A,slice:p})}return{...t,options:a,tokens:n}},pushBound:(t,e,r)=>{let[,o,a]=e.match(bT),n=t.options.concat({name:o,value:a}),u=t.tokens.concat([{segmentIndex:r,type:\"option\",slice:[0,o.length],option:o},{segmentIndex:r,type:\"assign\",slice:[o.length,o.length+1]},{segmentIndex:r,type:\"value\",slice:[o.length+1,o.length+a.length+1]}]);return{...t,options:n,tokens:u}},pushPath:(t,e,r)=>{let o=t.path.concat(e),a=t.tokens.concat({segmentIndex:r,type:\"path\"});return{...t,path:o,tokens:a}},pushPositional:(t,e,r)=>{let o=t.positionals.concat({value:e,extra:!1}),a=t.tokens.concat({segmentIndex:r,type:\"positional\"});return{...t,positionals:o,tokens:a}},pushExtra:(t,e,r)=>{let o=t.positionals.concat({value:e,extra:!0}),a=t.tokens.concat({segmentIndex:r,type:\"positional\"});return{...t,positionals:o,tokens:a}},pushExtraNoLimits:(t,e,r)=>{let o=t.positionals.concat({value:e,extra:el}),a=t.tokens.concat({segmentIndex:r,type:\"positional\"});return{...t,positionals:o,tokens:a}},pushTrue:(t,e,r,o)=>{let a=t.options.concat({name:o,value:!0}),n=t.tokens.concat({segmentIndex:r,type:\"option\",option:o});return{...t,options:a,tokens:n}},pushFalse:(t,e,r,o)=>{let a=t.options.concat({name:o,value:!1}),n=t.tokens.concat({segmentIndex:r,type:\"option\",option:o});return{...t,options:a,tokens:n}},pushUndefined:(t,e,r,o)=>{let a=t.options.concat({name:e,value:void 0}),n=t.tokens.concat({segmentIndex:r,type:\"option\",option:e});return{...t,options:a,tokens:n}},pushStringValue:(t,e,r)=>{var o;let a=t.options[t.options.length-1],n=t.options.slice(),u=t.tokens.concat({segmentIndex:r,type:\"value\"});return a.value=((o=a.value)!==null&&o!==void 0?o:[]).concat([e]),{...t,options:n,tokens:u}},setStringValue:(t,e,r)=>{let o=t.options[t.options.length-1],a=t.options.slice(),n=t.tokens.concat({segmentIndex:r,type:\"value\"});return o.value=e,{...t,options:a,tokens:n}},inhibateOptions:t=>({...t,ignoreOptions:!0}),useHelp:(t,e,r,o)=>{let[,,a]=e.match(ST);return typeof a<\"u\"?{...t,options:[{name:\"-c\",value:String(o)},{name:\"-i\",value:a}]}:{...t,options:[{name:\"-c\",value:String(o)}]}},setError:(t,e,r,o)=>e===Hn.EndOfInput||e===Hn.EndOfPartialInput?{...t,errorMessage:`${o}.`}:{...t,errorMessage:`${o} (\"${e}\").`},setOptionArityError:(t,e)=>{let r=t.options[t.options.length-1];return{...t,errorMessage:`Not enough arguments to option ${r.name}.`}}},el=Symbol(),jT=class{constructor(e,r){this.allOptionNames=new Map,this.arity={leading:[],trailing:[],extra:[],proxy:!1},this.options=[],this.paths=[],this.cliIndex=e,this.cliOpts=r}addPath(e){this.paths.push(e)}setArity({leading:e=this.arity.leading,trailing:r=this.arity.trailing,extra:o=this.arity.extra,proxy:a=this.arity.proxy}){Object.assign(this.arity,{leading:e,trailing:r,extra:o,proxy:a})}addPositional({name:e=\"arg\",required:r=!0}={}){if(!r&&this.arity.extra===el)throw new Error(\"Optional parameters cannot be declared when using .rest() or .proxy()\");if(!r&&this.arity.trailing.length>0)throw new Error(\"Optional parameters cannot be declared after the required trailing positional arguments\");!r&&this.arity.extra!==el?this.arity.extra.push(e):this.arity.extra!==el&&this.arity.extra.length===0?this.arity.leading.push(e):this.arity.trailing.push(e)}addRest({name:e=\"arg\",required:r=0}={}){if(this.arity.extra===el)throw new Error(\"Infinite lists cannot be declared multiple times in the same command\");if(this.arity.trailing.length>0)throw new Error(\"Infinite lists cannot be declared after the required trailing positional arguments\");for(let o=0;o<r;++o)this.addPositional({name:e});this.arity.extra=el}addProxy({required:e=0}={}){this.addRest({required:e}),this.arity.proxy=!0}addOption({names:e,description:r,arity:o=0,hidden:a=!1,required:n=!1,allowBinding:u=!0}){if(!u&&o>1)throw new Error(\"The arity cannot be higher than 1 when the option only supports the --arg=value syntax\");if(!Number.isInteger(o))throw new Error(`The arity must be an integer, got ${o}`);if(o<0)throw new Error(`The arity must be positive, got ${o}`);let A=e.reduce((p,h)=>h.length>p.length?h:p,\"\");for(let p of e)this.allOptionNames.set(p,A);this.options.push({preferredName:A,nameSet:e,description:r,arity:o,hidden:a,required:n,allowBinding:u})}setContext(e){this.context=e}usage({detailed:e=!0,inlineOptions:r=!0}={}){let o=[this.cliOpts.binaryName],a=[];if(this.paths.length>0&&o.push(...this.paths[0]),e){for(let{preferredName:u,nameSet:A,arity:p,hidden:h,description:C,required:I}of this.options){if(h)continue;let v=[];for(let E=0;E<p;++E)v.push(` #${E}`);let x=`${A.join(\",\")}${v.join(\"\")}`;!r&&C?a.push({preferredName:u,nameSet:A,definition:x,description:C,required:I}):o.push(I?`<${x}>`:`[${x}]`)}o.push(...this.arity.leading.map(u=>`<${u}>`)),this.arity.extra===el?o.push(\"...\"):o.push(...this.arity.extra.map(u=>`[${u}]`)),o.push(...this.arity.trailing.map(u=>`<${u}>`))}return{usage:o.join(\" \"),options:a}}compile(){if(typeof this.context>\"u\")throw new Error(\"Assertion failed: No context attached\");let e=wV(),r=cn.InitialNode,o=this.usage().usage,a=this.options.filter(A=>A.required).map(A=>A.nameSet);r=Oc(e,$a()),zo(e,cn.InitialNode,Hn.StartOfInput,r,[\"setCandidateState\",{candidateUsage:o,requiredOptions:a}]);let n=this.arity.proxy?\"always\":\"isNotOptionLike\",u=this.paths.length>0?this.paths:[[]];for(let A of u){let p=r;if(A.length>0){let v=Oc(e,$a());Ey(e,p,v),this.registerOptions(e,v),p=v}for(let v=0;v<A.length;++v){let x=Oc(e,$a());zo(e,p,A[v],x,\"pushPath\"),p=x}if(this.arity.leading.length>0||!this.arity.proxy){let v=Oc(e,$a());Ss(e,p,\"isHelp\",v,[\"useHelp\",this.cliIndex]),Ss(e,v,\"always\",v,\"pushExtra\"),zo(e,v,Hn.EndOfInput,cn.SuccessNode,[\"setSelectedIndex\",ed]),this.registerOptions(e,p)}this.arity.leading.length>0&&(zo(e,p,Hn.EndOfInput,cn.ErrorNode,[\"setError\",\"Not enough positional arguments\"]),zo(e,p,Hn.EndOfPartialInput,cn.SuccessNode,[\"setPartialIndex\",this.cliIndex]));let h=p;for(let v=0;v<this.arity.leading.length;++v){let x=Oc(e,$a());(!this.arity.proxy||v+1!==this.arity.leading.length)&&this.registerOptions(e,x),(this.arity.trailing.length>0||v+1!==this.arity.leading.length)&&(zo(e,x,Hn.EndOfInput,cn.ErrorNode,[\"setError\",\"Not enough positional arguments\"]),zo(e,x,Hn.EndOfPartialInput,cn.SuccessNode,[\"setPartialIndex\",this.cliIndex])),Ss(e,h,\"isNotOptionLike\",x,\"pushPositional\"),h=x}let C=h;if(this.arity.extra===el||this.arity.extra.length>0){let v=Oc(e,$a());if(Ey(e,h,v),this.arity.extra===el){let x=Oc(e,$a());this.arity.proxy||this.registerOptions(e,x),Ss(e,h,n,x,\"pushExtraNoLimits\"),Ss(e,x,n,x,\"pushExtraNoLimits\"),Ey(e,x,v)}else for(let x=0;x<this.arity.extra.length;++x){let E=Oc(e,$a());(!this.arity.proxy||x>0)&&this.registerOptions(e,E),Ss(e,C,n,E,\"pushExtra\"),Ey(e,E,v),C=E}C=v}this.arity.trailing.length>0&&(zo(e,C,Hn.EndOfInput,cn.ErrorNode,[\"setError\",\"Not enough positional arguments\"]),zo(e,C,Hn.EndOfPartialInput,cn.SuccessNode,[\"setPartialIndex\",this.cliIndex]));let I=C;for(let v=0;v<this.arity.trailing.length;++v){let x=Oc(e,$a());this.arity.proxy||this.registerOptions(e,x),v+1<this.arity.trailing.length&&(zo(e,x,Hn.EndOfInput,cn.ErrorNode,[\"setError\",\"Not enough positional arguments\"]),zo(e,x,Hn.EndOfPartialInput,cn.SuccessNode,[\"setPartialIndex\",this.cliIndex])),Ss(e,I,\"isNotOptionLike\",x,\"pushPositional\"),I=x}Ss(e,I,n,cn.ErrorNode,[\"setError\",\"Extraneous positional argument\"]),zo(e,I,Hn.EndOfInput,cn.SuccessNode,[\"setSelectedIndex\",this.cliIndex]),zo(e,I,Hn.EndOfPartialInput,cn.SuccessNode,[\"setSelectedIndex\",this.cliIndex])}return{machine:e,context:this.context}}registerOptions(e,r){Ss(e,r,[\"isOption\",\"--\"],r,\"inhibateOptions\"),Ss(e,r,[\"isBatchOption\",this.allOptionNames],r,[\"pushBatch\",this.allOptionNames]),Ss(e,r,[\"isBoundOption\",this.allOptionNames,this.options],r,\"pushBound\"),Ss(e,r,[\"isUnsupportedOption\",this.allOptionNames],cn.ErrorNode,[\"setError\",\"Unsupported option name\"]),Ss(e,r,[\"isInvalidOption\"],cn.ErrorNode,[\"setError\",\"Invalid option name\"]);for(let o of this.options)if(o.arity===0)for(let a of o.nameSet)Ss(e,r,[\"isOption\",a],r,[\"pushTrue\",o.preferredName]),a.startsWith(\"--\")&&!a.startsWith(\"--no-\")&&Ss(e,r,[\"isNegatedOption\",a],r,[\"pushFalse\",o.preferredName]);else{let a=Oc(e,$a());for(let n of o.nameSet)Ss(e,r,[\"isOption\",n],a,[\"pushUndefined\",o.preferredName]);for(let n=0;n<o.arity;++n){let u=Oc(e,$a());zo(e,a,Hn.EndOfInput,cn.ErrorNode,\"setOptionArityError\"),zo(e,a,Hn.EndOfPartialInput,cn.ErrorNode,\"setOptionArityError\"),Ss(e,a,\"isOptionLike\",cn.ErrorNode,\"setOptionArityError\");let A=o.arity===1?\"setStringValue\":\"pushStringValue\";Ss(e,a,\"isNotOptionLike\",u,A),a=u}Ey(e,a,r)}}},Cy=class{constructor({binaryName:e=\"...\"}={}){this.builders=[],this.opts={binaryName:e}}static build(e,r={}){return new Cy(r).commands(e).compile()}getBuilderByIndex(e){if(!(e>=0&&e<this.builders.length))throw new Error(`Assertion failed: Out-of-bound command index (${e})`);return this.builders[e]}commands(e){for(let r of e)r(this.command());return this}command(){let e=new jT(this.builders.length,this.opts);return this.builders.push(e),e}compile(){let e=[],r=[];for(let a of this.builders){let{machine:n,context:u}=a.compile();e.push(n),r.push(u)}let o=Wje(e);return Kje(o),{machine:o,contexts:r,process:(a,{partial:n}={})=>{let u=n?Hn.EndOfPartialInput:Hn.EndOfInput;return Jje(o,a,{endToken:u})}}}}});function DV(){return uP.default&&\"getColorDepth\"in uP.default.WriteStream.prototype?uP.default.WriteStream.prototype.getColorDepth():process.env.FORCE_COLOR===\"0\"?1:process.env.FORCE_COLOR===\"1\"||typeof process.stdout<\"u\"&&process.stdout.isTTY?8:1}function PV(t){let e=vV;if(typeof e>\"u\"){if(t.stdout===process.stdout&&t.stderr===process.stderr)return null;let{AsyncLocalStorage:r}=Be(\"async_hooks\");e=vV=new r;let o=process.stdout._write;process.stdout._write=function(n,u,A){let p=e.getStore();return typeof p>\"u\"?o.call(this,n,u,A):p.stdout.write(n,u,A)};let a=process.stderr._write;process.stderr._write=function(n,u,A){let p=e.getStore();return typeof p>\"u\"?a.call(this,n,u,A):p.stderr.write(n,u,A)}}return r=>e.run(t,r)}var uP,vV,SV=Et(()=>{uP=$e(Be(\"tty\"),1)});var wy,bV=Et(()=>{Wp();wy=class extends nt{constructor(e){super(),this.contexts=e,this.commands=[]}static from(e,r){let o=new wy(r);o.path=e.path;for(let a of e.options)switch(a.name){case\"-c\":o.commands.push(Number(a.value));break;case\"-i\":o.index=Number(a.value);break}return o}async execute(){let e=this.commands;if(typeof this.index<\"u\"&&this.index>=0&&this.index<e.length&&(e=[e[this.index]]),e.length===0)this.context.stdout.write(this.cli.usage());else if(e.length===1)this.context.stdout.write(this.cli.usage(this.contexts[e[0]].commandClass,{detailed:!0}));else if(e.length>1){this.context.stdout.write(`Multiple commands match your selection:\n`),this.context.stdout.write(`\n`);let r=0;for(let o of this.commands)this.context.stdout.write(this.cli.usage(this.contexts[o].commandClass,{prefix:`${r++}. `.padStart(5)}));this.context.stdout.write(`\n`),this.context.stdout.write(`Run again with -h=<index> to see the longer details of any of those commands.\n`)}}}});async function QV(...t){let{resolvedOptions:e,resolvedCommandClasses:r,resolvedArgv:o,resolvedContext:a}=RV(t);return as.from(r,e).runExit(o,a)}async function FV(...t){let{resolvedOptions:e,resolvedCommandClasses:r,resolvedArgv:o,resolvedContext:a}=RV(t);return as.from(r,e).run(o,a)}function RV(t){let e,r,o,a;switch(typeof process<\"u\"&&typeof process.argv<\"u\"&&(o=process.argv.slice(2)),t.length){case 1:r=t[0];break;case 2:t[0]&&t[0].prototype instanceof nt||Array.isArray(t[0])?(r=t[0],Array.isArray(t[1])?o=t[1]:a=t[1]):(e=t[0],r=t[1]);break;case 3:Array.isArray(t[2])?(e=t[0],r=t[1],o=t[2]):t[0]&&t[0].prototype instanceof nt||Array.isArray(t[0])?(r=t[0],o=t[1],a=t[2]):(e=t[0],r=t[1],a=t[2]);break;default:e=t[0],r=t[1],o=t[2],a=t[3];break}if(typeof o>\"u\")throw new Error(\"The argv parameter must be provided when running Clipanion outside of a Node context\");return{resolvedOptions:e,resolvedCommandClasses:r,resolvedArgv:o,resolvedContext:a}}function kV(t){return t()}var xV,as,TV=Et(()=>{eP();cP();FT();SV();Wp();bV();xV=Symbol(\"clipanion/errorCommand\");as=class{constructor({binaryLabel:e,binaryName:r=\"...\",binaryVersion:o,enableCapture:a=!1,enableColors:n}={}){this.registrations=new Map,this.builder=new Cy({binaryName:r}),this.binaryLabel=e,this.binaryName=r,this.binaryVersion=o,this.enableCapture=a,this.enableColors=n}static from(e,r={}){let o=new as(r),a=Array.isArray(e)?e:[e];for(let n of a)o.register(n);return o}register(e){var r;let o=new Map,a=new e;for(let p in a){let h=a[p];typeof h==\"object\"&&h!==null&&h[nt.isOption]&&o.set(p,h)}let n=this.builder.command(),u=n.cliIndex,A=(r=e.paths)!==null&&r!==void 0?r:a.paths;if(typeof A<\"u\")for(let p of A)n.addPath(p);this.registrations.set(e,{specs:o,builder:n,index:u});for(let[p,{definition:h}]of o.entries())h(n,p);n.setContext({commandClass:e})}process(e,r){let{input:o,context:a,partial:n}=typeof e==\"object\"&&Array.isArray(e)?{input:e,context:r}:e,{contexts:u,process:A}=this.builder.compile(),p=A(o,{partial:n}),h={...as.defaultContext,...a};switch(p.selectedIndex){case ed:{let C=wy.from(p,u);return C.context=h,C.tokens=p.tokens,C}default:{let{commandClass:C}=u[p.selectedIndex],I=this.registrations.get(C);if(typeof I>\"u\")throw new Error(\"Assertion failed: Expected the command class to have been registered.\");let v=new C;v.context=h,v.tokens=p.tokens,v.path=p.path;try{for(let[x,{transformer:E}]of I.specs.entries())v[x]=E(I.builder,x,p,h);return v}catch(x){throw x[xV]=v,x}}break}}async run(e,r){var o,a;let n,u={...as.defaultContext,...r},A=(o=this.enableColors)!==null&&o!==void 0?o:u.colorDepth>1;if(!Array.isArray(e))n=e;else try{n=this.process(e,u)}catch(C){return u.stdout.write(this.error(C,{colored:A})),1}if(n.help)return u.stdout.write(this.usage(n,{colored:A,detailed:!0})),0;n.context=u,n.cli={binaryLabel:this.binaryLabel,binaryName:this.binaryName,binaryVersion:this.binaryVersion,enableCapture:this.enableCapture,enableColors:this.enableColors,definitions:()=>this.definitions(),definition:C=>this.definition(C),error:(C,I)=>this.error(C,I),format:C=>this.format(C),process:(C,I)=>this.process(C,{...u,...I}),run:(C,I)=>this.run(C,{...u,...I}),usage:(C,I)=>this.usage(C,I)};let p=this.enableCapture&&(a=PV(u))!==null&&a!==void 0?a:kV,h;try{h=await p(()=>n.validateAndExecute().catch(C=>n.catch(C).then(()=>0)))}catch(C){return u.stdout.write(this.error(C,{colored:A,command:n})),1}return h}async runExit(e,r){process.exitCode=await this.run(e,r)}definition(e,{colored:r=!1}={}){if(!e.usage)return null;let{usage:o}=this.getUsageByRegistration(e,{detailed:!1}),{usage:a,options:n}=this.getUsageByRegistration(e,{detailed:!0,inlineOptions:!1}),u=typeof e.usage.category<\"u\"?Do(e.usage.category,{format:this.format(r),paragraphs:!1}):void 0,A=typeof e.usage.description<\"u\"?Do(e.usage.description,{format:this.format(r),paragraphs:!1}):void 0,p=typeof e.usage.details<\"u\"?Do(e.usage.details,{format:this.format(r),paragraphs:!0}):void 0,h=typeof e.usage.examples<\"u\"?e.usage.examples.map(([C,I])=>[Do(C,{format:this.format(r),paragraphs:!1}),I.replace(/\\$0/g,this.binaryName)]):void 0;return{path:o,usage:a,category:u,description:A,details:p,examples:h,options:n}}definitions({colored:e=!1}={}){let r=[];for(let o of this.registrations.keys()){let a=this.definition(o,{colored:e});!a||r.push(a)}return r}usage(e=null,{colored:r,detailed:o=!1,prefix:a=\"$ \"}={}){var n;if(e===null){for(let p of this.registrations.keys()){let h=p.paths,C=typeof p.usage<\"u\";if(!h||h.length===0||h.length===1&&h[0].length===0||((n=h?.some(x=>x.length===0))!==null&&n!==void 0?n:!1))if(e){e=null;break}else e=p;else if(C){e=null;continue}}e&&(o=!0)}let u=e!==null&&e instanceof nt?e.constructor:e,A=\"\";if(u)if(o){let{description:p=\"\",details:h=\"\",examples:C=[]}=u.usage||{};p!==\"\"&&(A+=Do(p,{format:this.format(r),paragraphs:!1}).replace(/^./,x=>x.toUpperCase()),A+=`\n`),(h!==\"\"||C.length>0)&&(A+=`${this.format(r).header(\"Usage\")}\n`,A+=`\n`);let{usage:I,options:v}=this.getUsageByRegistration(u,{inlineOptions:!1});if(A+=`${this.format(r).bold(a)}${I}\n`,v.length>0){A+=`\n`,A+=`${this.format(r).header(\"Options\")}\n`;let x=v.reduce((E,R)=>Math.max(E,R.definition.length),0);A+=`\n`;for(let{definition:E,description:R}of v)A+=`  ${this.format(r).bold(E.padEnd(x))}    ${Do(R,{format:this.format(r),paragraphs:!1})}`}if(h!==\"\"&&(A+=`\n`,A+=`${this.format(r).header(\"Details\")}\n`,A+=`\n`,A+=Do(h,{format:this.format(r),paragraphs:!0})),C.length>0){A+=`\n`,A+=`${this.format(r).header(\"Examples\")}\n`;for(let[x,E]of C)A+=`\n`,A+=Do(x,{format:this.format(r),paragraphs:!1}),A+=`${E.replace(/^/m,`  ${this.format(r).bold(a)}`).replace(/\\$0/g,this.binaryName)}\n`}}else{let{usage:p}=this.getUsageByRegistration(u);A+=`${this.format(r).bold(a)}${p}\n`}else{let p=new Map;for(let[v,{index:x}]of this.registrations.entries()){if(typeof v.usage>\"u\")continue;let E=typeof v.usage.category<\"u\"?Do(v.usage.category,{format:this.format(r),paragraphs:!1}):null,R=p.get(E);typeof R>\"u\"&&p.set(E,R=[]);let{usage:L}=this.getUsageByIndex(x);R.push({commandClass:v,usage:L})}let h=Array.from(p.keys()).sort((v,x)=>v===null?-1:x===null?1:v.localeCompare(x,\"en\",{usage:\"sort\",caseFirst:\"upper\"})),C=typeof this.binaryLabel<\"u\",I=typeof this.binaryVersion<\"u\";C||I?(C&&I?A+=`${this.format(r).header(`${this.binaryLabel} - ${this.binaryVersion}`)}\n\n`:C?A+=`${this.format(r).header(`${this.binaryLabel}`)}\n`:A+=`${this.format(r).header(`${this.binaryVersion}`)}\n`,A+=`  ${this.format(r).bold(a)}${this.binaryName} <command>\n`):A+=`${this.format(r).bold(a)}${this.binaryName} <command>\n`;for(let v of h){let x=p.get(v).slice().sort((R,L)=>R.usage.localeCompare(L.usage,\"en\",{usage:\"sort\",caseFirst:\"upper\"})),E=v!==null?v.trim():\"General commands\";A+=`\n`,A+=`${this.format(r).header(`${E}`)}\n`;for(let{commandClass:R,usage:L}of x){let U=R.usage.description||\"undocumented\";A+=`\n`,A+=`  ${this.format(r).bold(L)}\n`,A+=`    ${Do(U,{format:this.format(r),paragraphs:!1})}`}}A+=`\n`,A+=Do(\"You can also print more details about any of these commands by calling them with the `-h,--help` flag right after the command name.\",{format:this.format(r),paragraphs:!0})}return A}error(e,r){var o,{colored:a,command:n=(o=e[xV])!==null&&o!==void 0?o:null}=r===void 0?{}:r;(!e||typeof e!=\"object\"||!(\"stack\"in e))&&(e=new Error(`Execution failed with a non-error rejection (rejected value: ${JSON.stringify(e)})`));let u=\"\",A=e.name.replace(/([a-z])([A-Z])/g,\"$1 $2\");A===\"Error\"&&(A=\"Internal Error\"),u+=`${this.format(a).error(A)}: ${e.message}\n`;let p=e.clipanion;return typeof p<\"u\"?p.type===\"usage\"&&(u+=`\n`,u+=this.usage(n)):e.stack&&(u+=`${e.stack.replace(/^.*\\n/,\"\")}\n`),u}format(e){var r;return((r=e??this.enableColors)!==null&&r!==void 0?r:as.defaultContext.colorDepth>1)?pV:hV}getUsageByRegistration(e,r){let o=this.registrations.get(e);if(typeof o>\"u\")throw new Error(\"Assertion failed: Unregistered command\");return this.getUsageByIndex(o.index,r)}getUsageByIndex(e,r){return this.builder.getBuilderByIndex(e).usage(r)}};as.defaultContext={env:process.env,stdin:process.stdin,stdout:process.stdout,stderr:process.stderr,colorDepth:DV()}});var lI,NV=Et(()=>{Wp();lI=class extends nt{async execute(){this.context.stdout.write(`${JSON.stringify(this.cli.definitions(),null,2)}\n`)}};lI.paths=[[\"--clipanion=definitions\"]]});var cI,LV=Et(()=>{Wp();cI=class extends nt{async execute(){this.context.stdout.write(this.cli.usage())}};cI.paths=[[\"-h\"],[\"--help\"]]});function AP(t={}){return Ko({definition(e,r){var o;e.addProxy({name:(o=t.name)!==null&&o!==void 0?o:r,required:t.required})},transformer(e,r,o){return o.positionals.map(({value:a})=>a)}})}var qT=Et(()=>{yf()});var uI,OV=Et(()=>{Wp();qT();uI=class extends nt{constructor(){super(...arguments),this.args=AP()}async execute(){this.context.stdout.write(`${JSON.stringify(this.cli.process(this.args).tokens,null,2)}\n`)}};uI.paths=[[\"--clipanion=tokens\"]]});var AI,MV=Et(()=>{Wp();AI=class extends nt{async execute(){var e;this.context.stdout.write(`${(e=this.cli.binaryVersion)!==null&&e!==void 0?e:\"<unknown>\"}\n`)}};AI.paths=[[\"-v\"],[\"--version\"]]});var GT={};Vt(GT,{DefinitionsCommand:()=>lI,HelpCommand:()=>cI,TokensCommand:()=>uI,VersionCommand:()=>AI});var UV=Et(()=>{NV();LV();OV();MV()});function _V(t,e,r){let[o,a]=qu(e,r??{}),{arity:n=1}=a,u=t.split(\",\"),A=new Set(u);return Ko({definition(p){p.addOption({names:u,arity:n,hidden:a?.hidden,description:a?.description,required:a.required})},transformer(p,h,C){let I,v=typeof o<\"u\"?[...o]:void 0;for(let{name:x,value:E}of C.options)!A.has(x)||(I=x,v=v??[],v.push(E));return typeof v<\"u\"?td(I??h,v,a.validator):v}})}var HV=Et(()=>{yf()});function jV(t,e,r){let[o,a]=qu(e,r??{}),n=t.split(\",\"),u=new Set(n);return Ko({definition(A){A.addOption({names:n,allowBinding:!1,arity:0,hidden:a.hidden,description:a.description,required:a.required})},transformer(A,p,h){let C=o;for(let{name:I,value:v}of h.options)!u.has(I)||(C=v);return C}})}var qV=Et(()=>{yf()});function GV(t,e,r){let[o,a]=qu(e,r??{}),n=t.split(\",\"),u=new Set(n);return Ko({definition(A){A.addOption({names:n,allowBinding:!1,arity:0,hidden:a.hidden,description:a.description,required:a.required})},transformer(A,p,h){let C=o;for(let{name:I,value:v}of h.options)!u.has(I)||(C??(C=0),v?C+=1:C=0);return C}})}var YV=Et(()=>{yf()});function WV(t={}){return Ko({definition(e,r){var o;e.addRest({name:(o=t.name)!==null&&o!==void 0?o:r,required:t.required})},transformer(e,r,o){let a=u=>{let A=o.positionals[u];return A.extra===el||A.extra===!1&&u<e.arity.leading.length},n=0;for(;n<o.positionals.length&&a(n);)n+=1;return o.positionals.splice(0,n).map(({value:u})=>u)}})}var KV=Et(()=>{cP();yf()});function rqe(t,e,r){let[o,a]=qu(e,r??{}),{arity:n=1}=a,u=t.split(\",\"),A=new Set(u);return Ko({definition(p){p.addOption({names:u,arity:a.tolerateBoolean?0:n,hidden:a.hidden,description:a.description,required:a.required})},transformer(p,h,C,I){let v,x=o;typeof a.env<\"u\"&&I.env[a.env]&&(v=a.env,x=I.env[a.env]);for(let{name:E,value:R}of C.options)!A.has(E)||(v=E,x=R);return typeof x==\"string\"?td(v??h,x,a.validator):x}})}function nqe(t={}){let{required:e=!0}=t;return Ko({definition(r,o){var a;r.addPositional({name:(a=t.name)!==null&&a!==void 0?a:o,required:t.required})},transformer(r,o,a){var n;for(let u=0;u<a.positionals.length;++u){if(a.positionals[u].extra===el||e&&a.positionals[u].extra===!0||!e&&a.positionals[u].extra===!1)continue;let[A]=a.positionals.splice(u,1);return td((n=t.name)!==null&&n!==void 0?n:o,A.value,t.validator)}}})}function VV(t,...e){return typeof t==\"string\"?rqe(t,...e):nqe(t)}var zV=Et(()=>{cP();yf()});var ge={};Vt(ge,{Array:()=>_V,Boolean:()=>jV,Counter:()=>GV,Proxy:()=>AP,Rest:()=>WV,String:()=>VV,applyValidator:()=>td,cleanValidationError:()=>nP,formatError:()=>rI,isOptionSymbol:()=>tI,makeCommandOption:()=>Ko,rerouteArguments:()=>qu});var JV=Et(()=>{yf();qT();HV();qV();YV();KV();zV()});var fI={};Vt(fI,{Builtins:()=>GT,Cli:()=>as,Command:()=>nt,Option:()=>ge,UsageError:()=>it,formatMarkdownish:()=>Do,run:()=>FV,runExit:()=>QV});var qt=Et(()=>{rP();FT();Wp();TV();UV();JV()});var XV=_((Pkt,iqe)=>{iqe.exports={name:\"dotenv\",version:\"16.3.1\",description:\"Loads environment variables from .env file\",main:\"lib/main.js\",types:\"lib/main.d.ts\",exports:{\".\":{types:\"./lib/main.d.ts\",require:\"./lib/main.js\",default:\"./lib/main.js\"},\"./config\":\"./config.js\",\"./config.js\":\"./config.js\",\"./lib/env-options\":\"./lib/env-options.js\",\"./lib/env-options.js\":\"./lib/env-options.js\",\"./lib/cli-options\":\"./lib/cli-options.js\",\"./lib/cli-options.js\":\"./lib/cli-options.js\",\"./package.json\":\"./package.json\"},scripts:{\"dts-check\":\"tsc --project tests/types/tsconfig.json\",lint:\"standard\",\"lint-readme\":\"standard-markdown\",pretest:\"npm run lint && npm run dts-check\",test:\"tap tests/*.js --100 -Rspec\",prerelease:\"npm test\",release:\"standard-version\"},repository:{type:\"git\",url:\"git://github.com/motdotla/dotenv.git\"},funding:\"https://github.com/motdotla/dotenv?sponsor=1\",keywords:[\"dotenv\",\"env\",\".env\",\"environment\",\"variables\",\"config\",\"settings\"],readmeFilename:\"README.md\",license:\"BSD-2-Clause\",devDependencies:{\"@definitelytyped/dtslint\":\"^0.0.133\",\"@types/node\":\"^18.11.3\",decache:\"^4.6.1\",sinon:\"^14.0.1\",standard:\"^17.0.0\",\"standard-markdown\":\"^7.1.0\",\"standard-version\":\"^9.5.0\",tap:\"^16.3.0\",tar:\"^6.1.11\",typescript:\"^4.8.4\"},engines:{node:\">=12\"},browser:{fs:!1}}});var tz=_((Skt,Ef)=>{var ZV=Be(\"fs\"),WT=Be(\"path\"),sqe=Be(\"os\"),oqe=Be(\"crypto\"),aqe=XV(),KT=aqe.version,lqe=/(?:^|^)\\s*(?:export\\s+)?([\\w.-]+)(?:\\s*=\\s*?|:\\s+?)(\\s*'(?:\\\\'|[^'])*'|\\s*\"(?:\\\\\"|[^\"])*\"|\\s*`(?:\\\\`|[^`])*`|[^#\\r\\n]+)?\\s*(?:#.*)?(?:$|$)/mg;function cqe(t){let e={},r=t.toString();r=r.replace(/\\r\\n?/mg,`\n`);let o;for(;(o=lqe.exec(r))!=null;){let a=o[1],n=o[2]||\"\";n=n.trim();let u=n[0];n=n.replace(/^(['\"`])([\\s\\S]*)\\1$/mg,\"$2\"),u==='\"'&&(n=n.replace(/\\\\n/g,`\n`),n=n.replace(/\\\\r/g,\"\\r\")),e[a]=n}return e}function uqe(t){let e=ez(t),r=bs.configDotenv({path:e});if(!r.parsed)throw new Error(`MISSING_DATA: Cannot parse ${e} for an unknown reason`);let o=$V(t).split(\",\"),a=o.length,n;for(let u=0;u<a;u++)try{let A=o[u].trim(),p=pqe(r,A);n=bs.decrypt(p.ciphertext,p.key);break}catch(A){if(u+1>=a)throw A}return bs.parse(n)}function Aqe(t){console.log(`[dotenv@${KT}][INFO] ${t}`)}function fqe(t){console.log(`[dotenv@${KT}][WARN] ${t}`)}function YT(t){console.log(`[dotenv@${KT}][DEBUG] ${t}`)}function $V(t){return t&&t.DOTENV_KEY&&t.DOTENV_KEY.length>0?t.DOTENV_KEY:process.env.DOTENV_KEY&&process.env.DOTENV_KEY.length>0?process.env.DOTENV_KEY:\"\"}function pqe(t,e){let r;try{r=new URL(e)}catch(A){throw A.code===\"ERR_INVALID_URL\"?new Error(\"INVALID_DOTENV_KEY: Wrong format. Must be in valid uri format like dotenv://:key_1234@dotenv.org/vault/.env.vault?environment=development\"):A}let o=r.password;if(!o)throw new Error(\"INVALID_DOTENV_KEY: Missing key part\");let a=r.searchParams.get(\"environment\");if(!a)throw new Error(\"INVALID_DOTENV_KEY: Missing environment part\");let n=`DOTENV_VAULT_${a.toUpperCase()}`,u=t.parsed[n];if(!u)throw new Error(`NOT_FOUND_DOTENV_ENVIRONMENT: Cannot locate environment ${n} in your .env.vault file.`);return{ciphertext:u,key:o}}function ez(t){let e=WT.resolve(process.cwd(),\".env\");return t&&t.path&&t.path.length>0&&(e=t.path),e.endsWith(\".vault\")?e:`${e}.vault`}function hqe(t){return t[0]===\"~\"?WT.join(sqe.homedir(),t.slice(1)):t}function gqe(t){Aqe(\"Loading env from encrypted .env.vault\");let e=bs._parseVault(t),r=process.env;return t&&t.processEnv!=null&&(r=t.processEnv),bs.populate(r,e,t),{parsed:e}}function dqe(t){let e=WT.resolve(process.cwd(),\".env\"),r=\"utf8\",o=Boolean(t&&t.debug);t&&(t.path!=null&&(e=hqe(t.path)),t.encoding!=null&&(r=t.encoding));try{let a=bs.parse(ZV.readFileSync(e,{encoding:r})),n=process.env;return t&&t.processEnv!=null&&(n=t.processEnv),bs.populate(n,a,t),{parsed:a}}catch(a){return o&&YT(`Failed to load ${e} ${a.message}`),{error:a}}}function mqe(t){let e=ez(t);return $V(t).length===0?bs.configDotenv(t):ZV.existsSync(e)?bs._configVault(t):(fqe(`You set DOTENV_KEY but you are missing a .env.vault file at ${e}. Did you forget to build it?`),bs.configDotenv(t))}function yqe(t,e){let r=Buffer.from(e.slice(-64),\"hex\"),o=Buffer.from(t,\"base64\"),a=o.slice(0,12),n=o.slice(-16);o=o.slice(12,-16);try{let u=oqe.createDecipheriv(\"aes-256-gcm\",r,a);return u.setAuthTag(n),`${u.update(o)}${u.final()}`}catch(u){let A=u instanceof RangeError,p=u.message===\"Invalid key length\",h=u.message===\"Unsupported state or unable to authenticate data\";if(A||p){let C=\"INVALID_DOTENV_KEY: It must be 64 characters long (or more)\";throw new Error(C)}else if(h){let C=\"DECRYPTION_FAILED: Please check your DOTENV_KEY\";throw new Error(C)}else throw console.error(\"Error: \",u.code),console.error(\"Error: \",u.message),u}}function Eqe(t,e,r={}){let o=Boolean(r&&r.debug),a=Boolean(r&&r.override);if(typeof e!=\"object\")throw new Error(\"OBJECT_REQUIRED: Please check the processEnv argument being passed to populate\");for(let n of Object.keys(e))Object.prototype.hasOwnProperty.call(t,n)?(a===!0&&(t[n]=e[n]),o&&YT(a===!0?`\"${n}\" is already defined and WAS overwritten`:`\"${n}\" is already defined and was NOT overwritten`)):t[n]=e[n]}var bs={configDotenv:dqe,_configVault:gqe,_parseVault:uqe,config:mqe,decrypt:yqe,parse:cqe,populate:Eqe};Ef.exports.configDotenv=bs.configDotenv;Ef.exports._configVault=bs._configVault;Ef.exports._parseVault=bs._parseVault;Ef.exports.config=bs.config;Ef.exports.decrypt=bs.decrypt;Ef.exports.parse=bs.parse;Ef.exports.populate=bs.populate;Ef.exports=bs});var nz=_((bkt,rz)=>{\"use strict\";rz.exports=(t,...e)=>new Promise(r=>{r(t(...e))})});var rd=_((xkt,VT)=>{\"use strict\";var Cqe=nz(),iz=t=>{if(t<1)throw new TypeError(\"Expected `concurrency` to be a number from 1 and up\");let e=[],r=0,o=()=>{r--,e.length>0&&e.shift()()},a=(A,p,...h)=>{r++;let C=Cqe(A,...h);p(C),C.then(o,o)},n=(A,p,...h)=>{r<t?a(A,p,...h):e.push(a.bind(null,A,p,...h))},u=(A,...p)=>new Promise(h=>n(A,h,...p));return Object.defineProperties(u,{activeCount:{get:()=>r},pendingCount:{get:()=>e.length}}),u};VT.exports=iz;VT.exports.default=iz});function Wu(t){return`YN${t.toString(10).padStart(4,\"0\")}`}function fP(t){let e=Number(t.slice(2));if(typeof wr[e]>\"u\")throw new Error(`Unknown message name: \"${t}\"`);return e}var wr,pP=Et(()=>{wr=(Oe=>(Oe[Oe.UNNAMED=0]=\"UNNAMED\",Oe[Oe.EXCEPTION=1]=\"EXCEPTION\",Oe[Oe.MISSING_PEER_DEPENDENCY=2]=\"MISSING_PEER_DEPENDENCY\",Oe[Oe.CYCLIC_DEPENDENCIES=3]=\"CYCLIC_DEPENDENCIES\",Oe[Oe.DISABLED_BUILD_SCRIPTS=4]=\"DISABLED_BUILD_SCRIPTS\",Oe[Oe.BUILD_DISABLED=5]=\"BUILD_DISABLED\",Oe[Oe.SOFT_LINK_BUILD=6]=\"SOFT_LINK_BUILD\",Oe[Oe.MUST_BUILD=7]=\"MUST_BUILD\",Oe[Oe.MUST_REBUILD=8]=\"MUST_REBUILD\",Oe[Oe.BUILD_FAILED=9]=\"BUILD_FAILED\",Oe[Oe.RESOLVER_NOT_FOUND=10]=\"RESOLVER_NOT_FOUND\",Oe[Oe.FETCHER_NOT_FOUND=11]=\"FETCHER_NOT_FOUND\",Oe[Oe.LINKER_NOT_FOUND=12]=\"LINKER_NOT_FOUND\",Oe[Oe.FETCH_NOT_CACHED=13]=\"FETCH_NOT_CACHED\",Oe[Oe.YARN_IMPORT_FAILED=14]=\"YARN_IMPORT_FAILED\",Oe[Oe.REMOTE_INVALID=15]=\"REMOTE_INVALID\",Oe[Oe.REMOTE_NOT_FOUND=16]=\"REMOTE_NOT_FOUND\",Oe[Oe.RESOLUTION_PACK=17]=\"RESOLUTION_PACK\",Oe[Oe.CACHE_CHECKSUM_MISMATCH=18]=\"CACHE_CHECKSUM_MISMATCH\",Oe[Oe.UNUSED_CACHE_ENTRY=19]=\"UNUSED_CACHE_ENTRY\",Oe[Oe.MISSING_LOCKFILE_ENTRY=20]=\"MISSING_LOCKFILE_ENTRY\",Oe[Oe.WORKSPACE_NOT_FOUND=21]=\"WORKSPACE_NOT_FOUND\",Oe[Oe.TOO_MANY_MATCHING_WORKSPACES=22]=\"TOO_MANY_MATCHING_WORKSPACES\",Oe[Oe.CONSTRAINTS_MISSING_DEPENDENCY=23]=\"CONSTRAINTS_MISSING_DEPENDENCY\",Oe[Oe.CONSTRAINTS_INCOMPATIBLE_DEPENDENCY=24]=\"CONSTRAINTS_INCOMPATIBLE_DEPENDENCY\",Oe[Oe.CONSTRAINTS_EXTRANEOUS_DEPENDENCY=25]=\"CONSTRAINTS_EXTRANEOUS_DEPENDENCY\",Oe[Oe.CONSTRAINTS_INVALID_DEPENDENCY=26]=\"CONSTRAINTS_INVALID_DEPENDENCY\",Oe[Oe.CANT_SUGGEST_RESOLUTIONS=27]=\"CANT_SUGGEST_RESOLUTIONS\",Oe[Oe.FROZEN_LOCKFILE_EXCEPTION=28]=\"FROZEN_LOCKFILE_EXCEPTION\",Oe[Oe.CROSS_DRIVE_VIRTUAL_LOCAL=29]=\"CROSS_DRIVE_VIRTUAL_LOCAL\",Oe[Oe.FETCH_FAILED=30]=\"FETCH_FAILED\",Oe[Oe.DANGEROUS_NODE_MODULES=31]=\"DANGEROUS_NODE_MODULES\",Oe[Oe.NODE_GYP_INJECTED=32]=\"NODE_GYP_INJECTED\",Oe[Oe.AUTHENTICATION_NOT_FOUND=33]=\"AUTHENTICATION_NOT_FOUND\",Oe[Oe.INVALID_CONFIGURATION_KEY=34]=\"INVALID_CONFIGURATION_KEY\",Oe[Oe.NETWORK_ERROR=35]=\"NETWORK_ERROR\",Oe[Oe.LIFECYCLE_SCRIPT=36]=\"LIFECYCLE_SCRIPT\",Oe[Oe.CONSTRAINTS_MISSING_FIELD=37]=\"CONSTRAINTS_MISSING_FIELD\",Oe[Oe.CONSTRAINTS_INCOMPATIBLE_FIELD=38]=\"CONSTRAINTS_INCOMPATIBLE_FIELD\",Oe[Oe.CONSTRAINTS_EXTRANEOUS_FIELD=39]=\"CONSTRAINTS_EXTRANEOUS_FIELD\",Oe[Oe.CONSTRAINTS_INVALID_FIELD=40]=\"CONSTRAINTS_INVALID_FIELD\",Oe[Oe.AUTHENTICATION_INVALID=41]=\"AUTHENTICATION_INVALID\",Oe[Oe.PROLOG_UNKNOWN_ERROR=42]=\"PROLOG_UNKNOWN_ERROR\",Oe[Oe.PROLOG_SYNTAX_ERROR=43]=\"PROLOG_SYNTAX_ERROR\",Oe[Oe.PROLOG_EXISTENCE_ERROR=44]=\"PROLOG_EXISTENCE_ERROR\",Oe[Oe.STACK_OVERFLOW_RESOLUTION=45]=\"STACK_OVERFLOW_RESOLUTION\",Oe[Oe.AUTOMERGE_FAILED_TO_PARSE=46]=\"AUTOMERGE_FAILED_TO_PARSE\",Oe[Oe.AUTOMERGE_IMMUTABLE=47]=\"AUTOMERGE_IMMUTABLE\",Oe[Oe.AUTOMERGE_SUCCESS=48]=\"AUTOMERGE_SUCCESS\",Oe[Oe.AUTOMERGE_REQUIRED=49]=\"AUTOMERGE_REQUIRED\",Oe[Oe.DEPRECATED_CLI_SETTINGS=50]=\"DEPRECATED_CLI_SETTINGS\",Oe[Oe.PLUGIN_NAME_NOT_FOUND=51]=\"PLUGIN_NAME_NOT_FOUND\",Oe[Oe.INVALID_PLUGIN_REFERENCE=52]=\"INVALID_PLUGIN_REFERENCE\",Oe[Oe.CONSTRAINTS_AMBIGUITY=53]=\"CONSTRAINTS_AMBIGUITY\",Oe[Oe.CACHE_OUTSIDE_PROJECT=54]=\"CACHE_OUTSIDE_PROJECT\",Oe[Oe.IMMUTABLE_INSTALL=55]=\"IMMUTABLE_INSTALL\",Oe[Oe.IMMUTABLE_CACHE=56]=\"IMMUTABLE_CACHE\",Oe[Oe.INVALID_MANIFEST=57]=\"INVALID_MANIFEST\",Oe[Oe.PACKAGE_PREPARATION_FAILED=58]=\"PACKAGE_PREPARATION_FAILED\",Oe[Oe.INVALID_RANGE_PEER_DEPENDENCY=59]=\"INVALID_RANGE_PEER_DEPENDENCY\",Oe[Oe.INCOMPATIBLE_PEER_DEPENDENCY=60]=\"INCOMPATIBLE_PEER_DEPENDENCY\",Oe[Oe.DEPRECATED_PACKAGE=61]=\"DEPRECATED_PACKAGE\",Oe[Oe.INCOMPATIBLE_OS=62]=\"INCOMPATIBLE_OS\",Oe[Oe.INCOMPATIBLE_CPU=63]=\"INCOMPATIBLE_CPU\",Oe[Oe.FROZEN_ARTIFACT_EXCEPTION=64]=\"FROZEN_ARTIFACT_EXCEPTION\",Oe[Oe.TELEMETRY_NOTICE=65]=\"TELEMETRY_NOTICE\",Oe[Oe.PATCH_HUNK_FAILED=66]=\"PATCH_HUNK_FAILED\",Oe[Oe.INVALID_CONFIGURATION_VALUE=67]=\"INVALID_CONFIGURATION_VALUE\",Oe[Oe.UNUSED_PACKAGE_EXTENSION=68]=\"UNUSED_PACKAGE_EXTENSION\",Oe[Oe.REDUNDANT_PACKAGE_EXTENSION=69]=\"REDUNDANT_PACKAGE_EXTENSION\",Oe[Oe.AUTO_NM_SUCCESS=70]=\"AUTO_NM_SUCCESS\",Oe[Oe.NM_CANT_INSTALL_EXTERNAL_SOFT_LINK=71]=\"NM_CANT_INSTALL_EXTERNAL_SOFT_LINK\",Oe[Oe.NM_PRESERVE_SYMLINKS_REQUIRED=72]=\"NM_PRESERVE_SYMLINKS_REQUIRED\",Oe[Oe.UPDATE_LOCKFILE_ONLY_SKIP_LINK=73]=\"UPDATE_LOCKFILE_ONLY_SKIP_LINK\",Oe[Oe.NM_HARDLINKS_MODE_DOWNGRADED=74]=\"NM_HARDLINKS_MODE_DOWNGRADED\",Oe[Oe.PROLOG_INSTANTIATION_ERROR=75]=\"PROLOG_INSTANTIATION_ERROR\",Oe[Oe.INCOMPATIBLE_ARCHITECTURE=76]=\"INCOMPATIBLE_ARCHITECTURE\",Oe[Oe.GHOST_ARCHITECTURE=77]=\"GHOST_ARCHITECTURE\",Oe[Oe.RESOLUTION_MISMATCH=78]=\"RESOLUTION_MISMATCH\",Oe[Oe.PROLOG_LIMIT_EXCEEDED=79]=\"PROLOG_LIMIT_EXCEEDED\",Oe[Oe.NETWORK_DISABLED=80]=\"NETWORK_DISABLED\",Oe[Oe.NETWORK_UNSAFE_HTTP=81]=\"NETWORK_UNSAFE_HTTP\",Oe[Oe.RESOLUTION_FAILED=82]=\"RESOLUTION_FAILED\",Oe[Oe.AUTOMERGE_GIT_ERROR=83]=\"AUTOMERGE_GIT_ERROR\",Oe[Oe.CONSTRAINTS_CHECK_FAILED=84]=\"CONSTRAINTS_CHECK_FAILED\",Oe[Oe.UPDATED_RESOLUTION_RECORD=85]=\"UPDATED_RESOLUTION_RECORD\",Oe[Oe.EXPLAIN_PEER_DEPENDENCIES_CTA=86]=\"EXPLAIN_PEER_DEPENDENCIES_CTA\",Oe[Oe.MIGRATION_SUCCESS=87]=\"MIGRATION_SUCCESS\",Oe[Oe.VERSION_NOTICE=88]=\"VERSION_NOTICE\",Oe[Oe.TIPS_NOTICE=89]=\"TIPS_NOTICE\",Oe[Oe.OFFLINE_MODE_ENABLED=90]=\"OFFLINE_MODE_ENABLED\",Oe))(wr||{})});var pI=_((Qkt,sz)=>{var wqe=\"2.0.0\",Iqe=Number.MAX_SAFE_INTEGER||9007199254740991,Bqe=16,vqe=256-6,Dqe=[\"major\",\"premajor\",\"minor\",\"preminor\",\"patch\",\"prepatch\",\"prerelease\"];sz.exports={MAX_LENGTH:256,MAX_SAFE_COMPONENT_LENGTH:Bqe,MAX_SAFE_BUILD_LENGTH:vqe,MAX_SAFE_INTEGER:Iqe,RELEASE_TYPES:Dqe,SEMVER_SPEC_VERSION:wqe,FLAG_INCLUDE_PRERELEASE:1,FLAG_LOOSE:2}});var hI=_((Fkt,oz)=>{var Pqe=typeof process==\"object\"&&process.env&&process.env.NODE_DEBUG&&/\\bsemver\\b/i.test(process.env.NODE_DEBUG)?(...t)=>console.error(\"SEMVER\",...t):()=>{};oz.exports=Pqe});var Iy=_((Cf,az)=>{var{MAX_SAFE_COMPONENT_LENGTH:zT,MAX_SAFE_BUILD_LENGTH:Sqe,MAX_LENGTH:bqe}=pI(),xqe=hI();Cf=az.exports={};var kqe=Cf.re=[],Qqe=Cf.safeRe=[],lr=Cf.src=[],cr=Cf.t={},Fqe=0,JT=\"[a-zA-Z0-9-]\",Rqe=[[\"\\\\s\",1],[\"\\\\d\",bqe],[JT,Sqe]],Tqe=t=>{for(let[e,r]of Rqe)t=t.split(`${e}*`).join(`${e}{0,${r}}`).split(`${e}+`).join(`${e}{1,${r}}`);return t},zr=(t,e,r)=>{let o=Tqe(e),a=Fqe++;xqe(t,a,e),cr[t]=a,lr[a]=e,kqe[a]=new RegExp(e,r?\"g\":void 0),Qqe[a]=new RegExp(o,r?\"g\":void 0)};zr(\"NUMERICIDENTIFIER\",\"0|[1-9]\\\\d*\");zr(\"NUMERICIDENTIFIERLOOSE\",\"\\\\d+\");zr(\"NONNUMERICIDENTIFIER\",`\\\\d*[a-zA-Z-]${JT}*`);zr(\"MAINVERSION\",`(${lr[cr.NUMERICIDENTIFIER]})\\\\.(${lr[cr.NUMERICIDENTIFIER]})\\\\.(${lr[cr.NUMERICIDENTIFIER]})`);zr(\"MAINVERSIONLOOSE\",`(${lr[cr.NUMERICIDENTIFIERLOOSE]})\\\\.(${lr[cr.NUMERICIDENTIFIERLOOSE]})\\\\.(${lr[cr.NUMERICIDENTIFIERLOOSE]})`);zr(\"PRERELEASEIDENTIFIER\",`(?:${lr[cr.NUMERICIDENTIFIER]}|${lr[cr.NONNUMERICIDENTIFIER]})`);zr(\"PRERELEASEIDENTIFIERLOOSE\",`(?:${lr[cr.NUMERICIDENTIFIERLOOSE]}|${lr[cr.NONNUMERICIDENTIFIER]})`);zr(\"PRERELEASE\",`(?:-(${lr[cr.PRERELEASEIDENTIFIER]}(?:\\\\.${lr[cr.PRERELEASEIDENTIFIER]})*))`);zr(\"PRERELEASELOOSE\",`(?:-?(${lr[cr.PRERELEASEIDENTIFIERLOOSE]}(?:\\\\.${lr[cr.PRERELEASEIDENTIFIERLOOSE]})*))`);zr(\"BUILDIDENTIFIER\",`${JT}+`);zr(\"BUILD\",`(?:\\\\+(${lr[cr.BUILDIDENTIFIER]}(?:\\\\.${lr[cr.BUILDIDENTIFIER]})*))`);zr(\"FULLPLAIN\",`v?${lr[cr.MAINVERSION]}${lr[cr.PRERELEASE]}?${lr[cr.BUILD]}?`);zr(\"FULL\",`^${lr[cr.FULLPLAIN]}$`);zr(\"LOOSEPLAIN\",`[v=\\\\s]*${lr[cr.MAINVERSIONLOOSE]}${lr[cr.PRERELEASELOOSE]}?${lr[cr.BUILD]}?`);zr(\"LOOSE\",`^${lr[cr.LOOSEPLAIN]}$`);zr(\"GTLT\",\"((?:<|>)?=?)\");zr(\"XRANGEIDENTIFIERLOOSE\",`${lr[cr.NUMERICIDENTIFIERLOOSE]}|x|X|\\\\*`);zr(\"XRANGEIDENTIFIER\",`${lr[cr.NUMERICIDENTIFIER]}|x|X|\\\\*`);zr(\"XRANGEPLAIN\",`[v=\\\\s]*(${lr[cr.XRANGEIDENTIFIER]})(?:\\\\.(${lr[cr.XRANGEIDENTIFIER]})(?:\\\\.(${lr[cr.XRANGEIDENTIFIER]})(?:${lr[cr.PRERELEASE]})?${lr[cr.BUILD]}?)?)?`);zr(\"XRANGEPLAINLOOSE\",`[v=\\\\s]*(${lr[cr.XRANGEIDENTIFIERLOOSE]})(?:\\\\.(${lr[cr.XRANGEIDENTIFIERLOOSE]})(?:\\\\.(${lr[cr.XRANGEIDENTIFIERLOOSE]})(?:${lr[cr.PRERELEASELOOSE]})?${lr[cr.BUILD]}?)?)?`);zr(\"XRANGE\",`^${lr[cr.GTLT]}\\\\s*${lr[cr.XRANGEPLAIN]}$`);zr(\"XRANGELOOSE\",`^${lr[cr.GTLT]}\\\\s*${lr[cr.XRANGEPLAINLOOSE]}$`);zr(\"COERCE\",`(^|[^\\\\d])(\\\\d{1,${zT}})(?:\\\\.(\\\\d{1,${zT}}))?(?:\\\\.(\\\\d{1,${zT}}))?(?:$|[^\\\\d])`);zr(\"COERCERTL\",lr[cr.COERCE],!0);zr(\"LONETILDE\",\"(?:~>?)\");zr(\"TILDETRIM\",`(\\\\s*)${lr[cr.LONETILDE]}\\\\s+`,!0);Cf.tildeTrimReplace=\"$1~\";zr(\"TILDE\",`^${lr[cr.LONETILDE]}${lr[cr.XRANGEPLAIN]}$`);zr(\"TILDELOOSE\",`^${lr[cr.LONETILDE]}${lr[cr.XRANGEPLAINLOOSE]}$`);zr(\"LONECARET\",\"(?:\\\\^)\");zr(\"CARETTRIM\",`(\\\\s*)${lr[cr.LONECARET]}\\\\s+`,!0);Cf.caretTrimReplace=\"$1^\";zr(\"CARET\",`^${lr[cr.LONECARET]}${lr[cr.XRANGEPLAIN]}$`);zr(\"CARETLOOSE\",`^${lr[cr.LONECARET]}${lr[cr.XRANGEPLAINLOOSE]}$`);zr(\"COMPARATORLOOSE\",`^${lr[cr.GTLT]}\\\\s*(${lr[cr.LOOSEPLAIN]})$|^$`);zr(\"COMPARATOR\",`^${lr[cr.GTLT]}\\\\s*(${lr[cr.FULLPLAIN]})$|^$`);zr(\"COMPARATORTRIM\",`(\\\\s*)${lr[cr.GTLT]}\\\\s*(${lr[cr.LOOSEPLAIN]}|${lr[cr.XRANGEPLAIN]})`,!0);Cf.comparatorTrimReplace=\"$1$2$3\";zr(\"HYPHENRANGE\",`^\\\\s*(${lr[cr.XRANGEPLAIN]})\\\\s+-\\\\s+(${lr[cr.XRANGEPLAIN]})\\\\s*$`);zr(\"HYPHENRANGELOOSE\",`^\\\\s*(${lr[cr.XRANGEPLAINLOOSE]})\\\\s+-\\\\s+(${lr[cr.XRANGEPLAINLOOSE]})\\\\s*$`);zr(\"STAR\",\"(<|>)?=?\\\\s*\\\\*\");zr(\"GTE0\",\"^\\\\s*>=\\\\s*0\\\\.0\\\\.0\\\\s*$\");zr(\"GTE0PRE\",\"^\\\\s*>=\\\\s*0\\\\.0\\\\.0-0\\\\s*$\")});var hP=_((Rkt,lz)=>{var Nqe=Object.freeze({loose:!0}),Lqe=Object.freeze({}),Oqe=t=>t?typeof t!=\"object\"?Nqe:t:Lqe;lz.exports=Oqe});var XT=_((Tkt,Az)=>{var cz=/^[0-9]+$/,uz=(t,e)=>{let r=cz.test(t),o=cz.test(e);return r&&o&&(t=+t,e=+e),t===e?0:r&&!o?-1:o&&!r?1:t<e?-1:1},Mqe=(t,e)=>uz(e,t);Az.exports={compareIdentifiers:uz,rcompareIdentifiers:Mqe}});var Po=_((Nkt,gz)=>{var gP=hI(),{MAX_LENGTH:fz,MAX_SAFE_INTEGER:dP}=pI(),{safeRe:pz,t:hz}=Iy(),Uqe=hP(),{compareIdentifiers:By}=XT(),tl=class{constructor(e,r){if(r=Uqe(r),e instanceof tl){if(e.loose===!!r.loose&&e.includePrerelease===!!r.includePrerelease)return e;e=e.version}else if(typeof e!=\"string\")throw new TypeError(`Invalid version. Must be a string. Got type \"${typeof e}\".`);if(e.length>fz)throw new TypeError(`version is longer than ${fz} characters`);gP(\"SemVer\",e,r),this.options=r,this.loose=!!r.loose,this.includePrerelease=!!r.includePrerelease;let o=e.trim().match(r.loose?pz[hz.LOOSE]:pz[hz.FULL]);if(!o)throw new TypeError(`Invalid Version: ${e}`);if(this.raw=e,this.major=+o[1],this.minor=+o[2],this.patch=+o[3],this.major>dP||this.major<0)throw new TypeError(\"Invalid major version\");if(this.minor>dP||this.minor<0)throw new TypeError(\"Invalid minor version\");if(this.patch>dP||this.patch<0)throw new TypeError(\"Invalid patch version\");o[4]?this.prerelease=o[4].split(\".\").map(a=>{if(/^[0-9]+$/.test(a)){let n=+a;if(n>=0&&n<dP)return n}return a}):this.prerelease=[],this.build=o[5]?o[5].split(\".\"):[],this.format()}format(){return this.version=`${this.major}.${this.minor}.${this.patch}`,this.prerelease.length&&(this.version+=`-${this.prerelease.join(\".\")}`),this.version}toString(){return this.version}compare(e){if(gP(\"SemVer.compare\",this.version,this.options,e),!(e instanceof tl)){if(typeof e==\"string\"&&e===this.version)return 0;e=new tl(e,this.options)}return e.version===this.version?0:this.compareMain(e)||this.comparePre(e)}compareMain(e){return e instanceof tl||(e=new tl(e,this.options)),By(this.major,e.major)||By(this.minor,e.minor)||By(this.patch,e.patch)}comparePre(e){if(e instanceof tl||(e=new tl(e,this.options)),this.prerelease.length&&!e.prerelease.length)return-1;if(!this.prerelease.length&&e.prerelease.length)return 1;if(!this.prerelease.length&&!e.prerelease.length)return 0;let r=0;do{let o=this.prerelease[r],a=e.prerelease[r];if(gP(\"prerelease compare\",r,o,a),o===void 0&&a===void 0)return 0;if(a===void 0)return 1;if(o===void 0)return-1;if(o===a)continue;return By(o,a)}while(++r)}compareBuild(e){e instanceof tl||(e=new tl(e,this.options));let r=0;do{let o=this.build[r],a=e.build[r];if(gP(\"prerelease compare\",r,o,a),o===void 0&&a===void 0)return 0;if(a===void 0)return 1;if(o===void 0)return-1;if(o===a)continue;return By(o,a)}while(++r)}inc(e,r,o){switch(e){case\"premajor\":this.prerelease.length=0,this.patch=0,this.minor=0,this.major++,this.inc(\"pre\",r,o);break;case\"preminor\":this.prerelease.length=0,this.patch=0,this.minor++,this.inc(\"pre\",r,o);break;case\"prepatch\":this.prerelease.length=0,this.inc(\"patch\",r,o),this.inc(\"pre\",r,o);break;case\"prerelease\":this.prerelease.length===0&&this.inc(\"patch\",r,o),this.inc(\"pre\",r,o);break;case\"major\":(this.minor!==0||this.patch!==0||this.prerelease.length===0)&&this.major++,this.minor=0,this.patch=0,this.prerelease=[];break;case\"minor\":(this.patch!==0||this.prerelease.length===0)&&this.minor++,this.patch=0,this.prerelease=[];break;case\"patch\":this.prerelease.length===0&&this.patch++,this.prerelease=[];break;case\"pre\":{let a=Number(o)?1:0;if(!r&&o===!1)throw new Error(\"invalid increment argument: identifier is empty\");if(this.prerelease.length===0)this.prerelease=[a];else{let n=this.prerelease.length;for(;--n>=0;)typeof this.prerelease[n]==\"number\"&&(this.prerelease[n]++,n=-2);if(n===-1){if(r===this.prerelease.join(\".\")&&o===!1)throw new Error(\"invalid increment argument: identifier already exists\");this.prerelease.push(a)}}if(r){let n=[r,a];o===!1&&(n=[r]),By(this.prerelease[0],r)===0?isNaN(this.prerelease[1])&&(this.prerelease=n):this.prerelease=n}break}default:throw new Error(`invalid increment argument: ${e}`)}return this.raw=this.format(),this.build.length&&(this.raw+=`+${this.build.join(\".\")}`),this}};gz.exports=tl});var nd=_((Lkt,mz)=>{var dz=Po(),_qe=(t,e,r=!1)=>{if(t instanceof dz)return t;try{return new dz(t,e)}catch(o){if(!r)return null;throw o}};mz.exports=_qe});var Ez=_((Okt,yz)=>{var Hqe=nd(),jqe=(t,e)=>{let r=Hqe(t,e);return r?r.version:null};yz.exports=jqe});var wz=_((Mkt,Cz)=>{var qqe=nd(),Gqe=(t,e)=>{let r=qqe(t.trim().replace(/^[=v]+/,\"\"),e);return r?r.version:null};Cz.exports=Gqe});var vz=_((Ukt,Bz)=>{var Iz=Po(),Yqe=(t,e,r,o,a)=>{typeof r==\"string\"&&(a=o,o=r,r=void 0);try{return new Iz(t instanceof Iz?t.version:t,r).inc(e,o,a).version}catch{return null}};Bz.exports=Yqe});var Sz=_((_kt,Pz)=>{var Dz=nd(),Wqe=(t,e)=>{let r=Dz(t,null,!0),o=Dz(e,null,!0),a=r.compare(o);if(a===0)return null;let n=a>0,u=n?r:o,A=n?o:r,p=!!u.prerelease.length;if(!!A.prerelease.length&&!p)return!A.patch&&!A.minor?\"major\":u.patch?\"patch\":u.minor?\"minor\":\"major\";let C=p?\"pre\":\"\";return r.major!==o.major?C+\"major\":r.minor!==o.minor?C+\"minor\":r.patch!==o.patch?C+\"patch\":\"prerelease\"};Pz.exports=Wqe});var xz=_((Hkt,bz)=>{var Kqe=Po(),Vqe=(t,e)=>new Kqe(t,e).major;bz.exports=Vqe});var Qz=_((jkt,kz)=>{var zqe=Po(),Jqe=(t,e)=>new zqe(t,e).minor;kz.exports=Jqe});var Rz=_((qkt,Fz)=>{var Xqe=Po(),Zqe=(t,e)=>new Xqe(t,e).patch;Fz.exports=Zqe});var Nz=_((Gkt,Tz)=>{var $qe=nd(),eGe=(t,e)=>{let r=$qe(t,e);return r&&r.prerelease.length?r.prerelease:null};Tz.exports=eGe});var Ll=_((Ykt,Oz)=>{var Lz=Po(),tGe=(t,e,r)=>new Lz(t,r).compare(new Lz(e,r));Oz.exports=tGe});var Uz=_((Wkt,Mz)=>{var rGe=Ll(),nGe=(t,e,r)=>rGe(e,t,r);Mz.exports=nGe});var Hz=_((Kkt,_z)=>{var iGe=Ll(),sGe=(t,e)=>iGe(t,e,!0);_z.exports=sGe});var mP=_((Vkt,qz)=>{var jz=Po(),oGe=(t,e,r)=>{let o=new jz(t,r),a=new jz(e,r);return o.compare(a)||o.compareBuild(a)};qz.exports=oGe});var Yz=_((zkt,Gz)=>{var aGe=mP(),lGe=(t,e)=>t.sort((r,o)=>aGe(r,o,e));Gz.exports=lGe});var Kz=_((Jkt,Wz)=>{var cGe=mP(),uGe=(t,e)=>t.sort((r,o)=>cGe(o,r,e));Wz.exports=uGe});var gI=_((Xkt,Vz)=>{var AGe=Ll(),fGe=(t,e,r)=>AGe(t,e,r)>0;Vz.exports=fGe});var yP=_((Zkt,zz)=>{var pGe=Ll(),hGe=(t,e,r)=>pGe(t,e,r)<0;zz.exports=hGe});var ZT=_(($kt,Jz)=>{var gGe=Ll(),dGe=(t,e,r)=>gGe(t,e,r)===0;Jz.exports=dGe});var $T=_((eQt,Xz)=>{var mGe=Ll(),yGe=(t,e,r)=>mGe(t,e,r)!==0;Xz.exports=yGe});var EP=_((tQt,Zz)=>{var EGe=Ll(),CGe=(t,e,r)=>EGe(t,e,r)>=0;Zz.exports=CGe});var CP=_((rQt,$z)=>{var wGe=Ll(),IGe=(t,e,r)=>wGe(t,e,r)<=0;$z.exports=IGe});var eN=_((nQt,eJ)=>{var BGe=ZT(),vGe=$T(),DGe=gI(),PGe=EP(),SGe=yP(),bGe=CP(),xGe=(t,e,r,o)=>{switch(e){case\"===\":return typeof t==\"object\"&&(t=t.version),typeof r==\"object\"&&(r=r.version),t===r;case\"!==\":return typeof t==\"object\"&&(t=t.version),typeof r==\"object\"&&(r=r.version),t!==r;case\"\":case\"=\":case\"==\":return BGe(t,r,o);case\"!=\":return vGe(t,r,o);case\">\":return DGe(t,r,o);case\">=\":return PGe(t,r,o);case\"<\":return SGe(t,r,o);case\"<=\":return bGe(t,r,o);default:throw new TypeError(`Invalid operator: ${e}`)}};eJ.exports=xGe});var rJ=_((iQt,tJ)=>{var kGe=Po(),QGe=nd(),{safeRe:wP,t:IP}=Iy(),FGe=(t,e)=>{if(t instanceof kGe)return t;if(typeof t==\"number\"&&(t=String(t)),typeof t!=\"string\")return null;e=e||{};let r=null;if(!e.rtl)r=t.match(wP[IP.COERCE]);else{let o;for(;(o=wP[IP.COERCERTL].exec(t))&&(!r||r.index+r[0].length!==t.length);)(!r||o.index+o[0].length!==r.index+r[0].length)&&(r=o),wP[IP.COERCERTL].lastIndex=o.index+o[1].length+o[2].length;wP[IP.COERCERTL].lastIndex=-1}return r===null?null:QGe(`${r[2]}.${r[3]||\"0\"}.${r[4]||\"0\"}`,e)};tJ.exports=FGe});var iJ=_((sQt,nJ)=>{\"use strict\";nJ.exports=function(t){t.prototype[Symbol.iterator]=function*(){for(let e=this.head;e;e=e.next)yield e.value}}});var BP=_((oQt,sJ)=>{\"use strict\";sJ.exports=Cn;Cn.Node=id;Cn.create=Cn;function Cn(t){var e=this;if(e instanceof Cn||(e=new Cn),e.tail=null,e.head=null,e.length=0,t&&typeof t.forEach==\"function\")t.forEach(function(a){e.push(a)});else if(arguments.length>0)for(var r=0,o=arguments.length;r<o;r++)e.push(arguments[r]);return e}Cn.prototype.removeNode=function(t){if(t.list!==this)throw new Error(\"removing node which does not belong to this list\");var e=t.next,r=t.prev;return e&&(e.prev=r),r&&(r.next=e),t===this.head&&(this.head=e),t===this.tail&&(this.tail=r),t.list.length--,t.next=null,t.prev=null,t.list=null,e};Cn.prototype.unshiftNode=function(t){if(t!==this.head){t.list&&t.list.removeNode(t);var e=this.head;t.list=this,t.next=e,e&&(e.prev=t),this.head=t,this.tail||(this.tail=t),this.length++}};Cn.prototype.pushNode=function(t){if(t!==this.tail){t.list&&t.list.removeNode(t);var e=this.tail;t.list=this,t.prev=e,e&&(e.next=t),this.tail=t,this.head||(this.head=t),this.length++}};Cn.prototype.push=function(){for(var t=0,e=arguments.length;t<e;t++)TGe(this,arguments[t]);return this.length};Cn.prototype.unshift=function(){for(var t=0,e=arguments.length;t<e;t++)NGe(this,arguments[t]);return this.length};Cn.prototype.pop=function(){if(!!this.tail){var t=this.tail.value;return this.tail=this.tail.prev,this.tail?this.tail.next=null:this.head=null,this.length--,t}};Cn.prototype.shift=function(){if(!!this.head){var t=this.head.value;return this.head=this.head.next,this.head?this.head.prev=null:this.tail=null,this.length--,t}};Cn.prototype.forEach=function(t,e){e=e||this;for(var r=this.head,o=0;r!==null;o++)t.call(e,r.value,o,this),r=r.next};Cn.prototype.forEachReverse=function(t,e){e=e||this;for(var r=this.tail,o=this.length-1;r!==null;o--)t.call(e,r.value,o,this),r=r.prev};Cn.prototype.get=function(t){for(var e=0,r=this.head;r!==null&&e<t;e++)r=r.next;if(e===t&&r!==null)return r.value};Cn.prototype.getReverse=function(t){for(var e=0,r=this.tail;r!==null&&e<t;e++)r=r.prev;if(e===t&&r!==null)return r.value};Cn.prototype.map=function(t,e){e=e||this;for(var r=new Cn,o=this.head;o!==null;)r.push(t.call(e,o.value,this)),o=o.next;return r};Cn.prototype.mapReverse=function(t,e){e=e||this;for(var r=new Cn,o=this.tail;o!==null;)r.push(t.call(e,o.value,this)),o=o.prev;return r};Cn.prototype.reduce=function(t,e){var r,o=this.head;if(arguments.length>1)r=e;else if(this.head)o=this.head.next,r=this.head.value;else throw new TypeError(\"Reduce of empty list with no initial value\");for(var a=0;o!==null;a++)r=t(r,o.value,a),o=o.next;return r};Cn.prototype.reduceReverse=function(t,e){var r,o=this.tail;if(arguments.length>1)r=e;else if(this.tail)o=this.tail.prev,r=this.tail.value;else throw new TypeError(\"Reduce of empty list with no initial value\");for(var a=this.length-1;o!==null;a--)r=t(r,o.value,a),o=o.prev;return r};Cn.prototype.toArray=function(){for(var t=new Array(this.length),e=0,r=this.head;r!==null;e++)t[e]=r.value,r=r.next;return t};Cn.prototype.toArrayReverse=function(){for(var t=new Array(this.length),e=0,r=this.tail;r!==null;e++)t[e]=r.value,r=r.prev;return t};Cn.prototype.slice=function(t,e){e=e||this.length,e<0&&(e+=this.length),t=t||0,t<0&&(t+=this.length);var r=new Cn;if(e<t||e<0)return r;t<0&&(t=0),e>this.length&&(e=this.length);for(var o=0,a=this.head;a!==null&&o<t;o++)a=a.next;for(;a!==null&&o<e;o++,a=a.next)r.push(a.value);return r};Cn.prototype.sliceReverse=function(t,e){e=e||this.length,e<0&&(e+=this.length),t=t||0,t<0&&(t+=this.length);var r=new Cn;if(e<t||e<0)return r;t<0&&(t=0),e>this.length&&(e=this.length);for(var o=this.length,a=this.tail;a!==null&&o>e;o--)a=a.prev;for(;a!==null&&o>t;o--,a=a.prev)r.push(a.value);return r};Cn.prototype.splice=function(t,e,...r){t>this.length&&(t=this.length-1),t<0&&(t=this.length+t);for(var o=0,a=this.head;a!==null&&o<t;o++)a=a.next;for(var n=[],o=0;a&&o<e;o++)n.push(a.value),a=this.removeNode(a);a===null&&(a=this.tail),a!==this.head&&a!==this.tail&&(a=a.prev);for(var o=0;o<r.length;o++)a=RGe(this,a,r[o]);return n};Cn.prototype.reverse=function(){for(var t=this.head,e=this.tail,r=t;r!==null;r=r.prev){var o=r.prev;r.prev=r.next,r.next=o}return this.head=e,this.tail=t,this};function RGe(t,e,r){var o=e===t.head?new id(r,null,e,t):new id(r,e,e.next,t);return o.next===null&&(t.tail=o),o.prev===null&&(t.head=o),t.length++,o}function TGe(t,e){t.tail=new id(e,t.tail,null,t),t.head||(t.head=t.tail),t.length++}function NGe(t,e){t.head=new id(e,null,t.head,t),t.tail||(t.tail=t.head),t.length++}function id(t,e,r,o){if(!(this instanceof id))return new id(t,e,r,o);this.list=o,this.value=t,e?(e.next=this,this.prev=e):this.prev=null,r?(r.prev=this,this.next=r):this.next=null}try{iJ()(Cn)}catch{}});var uJ=_((aQt,cJ)=>{\"use strict\";var LGe=BP(),sd=Symbol(\"max\"),If=Symbol(\"length\"),vy=Symbol(\"lengthCalculator\"),mI=Symbol(\"allowStale\"),od=Symbol(\"maxAge\"),wf=Symbol(\"dispose\"),oJ=Symbol(\"noDisposeOnSet\"),xs=Symbol(\"lruList\"),Mc=Symbol(\"cache\"),lJ=Symbol(\"updateAgeOnGet\"),tN=()=>1,nN=class{constructor(e){if(typeof e==\"number\"&&(e={max:e}),e||(e={}),e.max&&(typeof e.max!=\"number\"||e.max<0))throw new TypeError(\"max must be a non-negative number\");let r=this[sd]=e.max||1/0,o=e.length||tN;if(this[vy]=typeof o!=\"function\"?tN:o,this[mI]=e.stale||!1,e.maxAge&&typeof e.maxAge!=\"number\")throw new TypeError(\"maxAge must be a number\");this[od]=e.maxAge||0,this[wf]=e.dispose,this[oJ]=e.noDisposeOnSet||!1,this[lJ]=e.updateAgeOnGet||!1,this.reset()}set max(e){if(typeof e!=\"number\"||e<0)throw new TypeError(\"max must be a non-negative number\");this[sd]=e||1/0,dI(this)}get max(){return this[sd]}set allowStale(e){this[mI]=!!e}get allowStale(){return this[mI]}set maxAge(e){if(typeof e!=\"number\")throw new TypeError(\"maxAge must be a non-negative number\");this[od]=e,dI(this)}get maxAge(){return this[od]}set lengthCalculator(e){typeof e!=\"function\"&&(e=tN),e!==this[vy]&&(this[vy]=e,this[If]=0,this[xs].forEach(r=>{r.length=this[vy](r.value,r.key),this[If]+=r.length})),dI(this)}get lengthCalculator(){return this[vy]}get length(){return this[If]}get itemCount(){return this[xs].length}rforEach(e,r){r=r||this;for(let o=this[xs].tail;o!==null;){let a=o.prev;aJ(this,e,o,r),o=a}}forEach(e,r){r=r||this;for(let o=this[xs].head;o!==null;){let a=o.next;aJ(this,e,o,r),o=a}}keys(){return this[xs].toArray().map(e=>e.key)}values(){return this[xs].toArray().map(e=>e.value)}reset(){this[wf]&&this[xs]&&this[xs].length&&this[xs].forEach(e=>this[wf](e.key,e.value)),this[Mc]=new Map,this[xs]=new LGe,this[If]=0}dump(){return this[xs].map(e=>vP(this,e)?!1:{k:e.key,v:e.value,e:e.now+(e.maxAge||0)}).toArray().filter(e=>e)}dumpLru(){return this[xs]}set(e,r,o){if(o=o||this[od],o&&typeof o!=\"number\")throw new TypeError(\"maxAge must be a number\");let a=o?Date.now():0,n=this[vy](r,e);if(this[Mc].has(e)){if(n>this[sd])return Dy(this,this[Mc].get(e)),!1;let p=this[Mc].get(e).value;return this[wf]&&(this[oJ]||this[wf](e,p.value)),p.now=a,p.maxAge=o,p.value=r,this[If]+=n-p.length,p.length=n,this.get(e),dI(this),!0}let u=new iN(e,r,n,a,o);return u.length>this[sd]?(this[wf]&&this[wf](e,r),!1):(this[If]+=u.length,this[xs].unshift(u),this[Mc].set(e,this[xs].head),dI(this),!0)}has(e){if(!this[Mc].has(e))return!1;let r=this[Mc].get(e).value;return!vP(this,r)}get(e){return rN(this,e,!0)}peek(e){return rN(this,e,!1)}pop(){let e=this[xs].tail;return e?(Dy(this,e),e.value):null}del(e){Dy(this,this[Mc].get(e))}load(e){this.reset();let r=Date.now();for(let o=e.length-1;o>=0;o--){let a=e[o],n=a.e||0;if(n===0)this.set(a.k,a.v);else{let u=n-r;u>0&&this.set(a.k,a.v,u)}}}prune(){this[Mc].forEach((e,r)=>rN(this,r,!1))}},rN=(t,e,r)=>{let o=t[Mc].get(e);if(o){let a=o.value;if(vP(t,a)){if(Dy(t,o),!t[mI])return}else r&&(t[lJ]&&(o.value.now=Date.now()),t[xs].unshiftNode(o));return a.value}},vP=(t,e)=>{if(!e||!e.maxAge&&!t[od])return!1;let r=Date.now()-e.now;return e.maxAge?r>e.maxAge:t[od]&&r>t[od]},dI=t=>{if(t[If]>t[sd])for(let e=t[xs].tail;t[If]>t[sd]&&e!==null;){let r=e.prev;Dy(t,e),e=r}},Dy=(t,e)=>{if(e){let r=e.value;t[wf]&&t[wf](r.key,r.value),t[If]-=r.length,t[Mc].delete(r.key),t[xs].removeNode(e)}},iN=class{constructor(e,r,o,a,n){this.key=e,this.value=r,this.length=o,this.now=a,this.maxAge=n||0}},aJ=(t,e,r,o)=>{let a=r.value;vP(t,a)&&(Dy(t,r),t[mI]||(a=void 0)),a&&e.call(o,a.value,a.key,t)};cJ.exports=nN});var Ol=_((lQt,hJ)=>{var ad=class{constructor(e,r){if(r=MGe(r),e instanceof ad)return e.loose===!!r.loose&&e.includePrerelease===!!r.includePrerelease?e:new ad(e.raw,r);if(e instanceof sN)return this.raw=e.value,this.set=[[e]],this.format(),this;if(this.options=r,this.loose=!!r.loose,this.includePrerelease=!!r.includePrerelease,this.raw=e.trim().split(/\\s+/).join(\" \"),this.set=this.raw.split(\"||\").map(o=>this.parseRange(o.trim())).filter(o=>o.length),!this.set.length)throw new TypeError(`Invalid SemVer Range: ${this.raw}`);if(this.set.length>1){let o=this.set[0];if(this.set=this.set.filter(a=>!fJ(a[0])),this.set.length===0)this.set=[o];else if(this.set.length>1){for(let a of this.set)if(a.length===1&&YGe(a[0])){this.set=[a];break}}}this.format()}format(){return this.range=this.set.map(e=>e.join(\" \").trim()).join(\"||\").trim(),this.range}toString(){return this.range}parseRange(e){let o=((this.options.includePrerelease&&qGe)|(this.options.loose&&GGe))+\":\"+e,a=AJ.get(o);if(a)return a;let n=this.options.loose,u=n?Da[Jo.HYPHENRANGELOOSE]:Da[Jo.HYPHENRANGE];e=e.replace(u,t5e(this.options.includePrerelease)),ci(\"hyphen replace\",e),e=e.replace(Da[Jo.COMPARATORTRIM],_Ge),ci(\"comparator trim\",e),e=e.replace(Da[Jo.TILDETRIM],HGe),ci(\"tilde trim\",e),e=e.replace(Da[Jo.CARETTRIM],jGe),ci(\"caret trim\",e);let A=e.split(\" \").map(I=>WGe(I,this.options)).join(\" \").split(/\\s+/).map(I=>e5e(I,this.options));n&&(A=A.filter(I=>(ci(\"loose invalid filter\",I,this.options),!!I.match(Da[Jo.COMPARATORLOOSE])))),ci(\"range list\",A);let p=new Map,h=A.map(I=>new sN(I,this.options));for(let I of h){if(fJ(I))return[I];p.set(I.value,I)}p.size>1&&p.has(\"\")&&p.delete(\"\");let C=[...p.values()];return AJ.set(o,C),C}intersects(e,r){if(!(e instanceof ad))throw new TypeError(\"a Range is required\");return this.set.some(o=>pJ(o,r)&&e.set.some(a=>pJ(a,r)&&o.every(n=>a.every(u=>n.intersects(u,r)))))}test(e){if(!e)return!1;if(typeof e==\"string\")try{e=new UGe(e,this.options)}catch{return!1}for(let r=0;r<this.set.length;r++)if(r5e(this.set[r],e,this.options))return!0;return!1}};hJ.exports=ad;var OGe=uJ(),AJ=new OGe({max:1e3}),MGe=hP(),sN=yI(),ci=hI(),UGe=Po(),{safeRe:Da,t:Jo,comparatorTrimReplace:_Ge,tildeTrimReplace:HGe,caretTrimReplace:jGe}=Iy(),{FLAG_INCLUDE_PRERELEASE:qGe,FLAG_LOOSE:GGe}=pI(),fJ=t=>t.value===\"<0.0.0-0\",YGe=t=>t.value===\"\",pJ=(t,e)=>{let r=!0,o=t.slice(),a=o.pop();for(;r&&o.length;)r=o.every(n=>a.intersects(n,e)),a=o.pop();return r},WGe=(t,e)=>(ci(\"comp\",t,e),t=zGe(t,e),ci(\"caret\",t),t=KGe(t,e),ci(\"tildes\",t),t=XGe(t,e),ci(\"xrange\",t),t=$Ge(t,e),ci(\"stars\",t),t),Xo=t=>!t||t.toLowerCase()===\"x\"||t===\"*\",KGe=(t,e)=>t.trim().split(/\\s+/).map(r=>VGe(r,e)).join(\" \"),VGe=(t,e)=>{let r=e.loose?Da[Jo.TILDELOOSE]:Da[Jo.TILDE];return t.replace(r,(o,a,n,u,A)=>{ci(\"tilde\",t,o,a,n,u,A);let p;return Xo(a)?p=\"\":Xo(n)?p=`>=${a}.0.0 <${+a+1}.0.0-0`:Xo(u)?p=`>=${a}.${n}.0 <${a}.${+n+1}.0-0`:A?(ci(\"replaceTilde pr\",A),p=`>=${a}.${n}.${u}-${A} <${a}.${+n+1}.0-0`):p=`>=${a}.${n}.${u} <${a}.${+n+1}.0-0`,ci(\"tilde return\",p),p})},zGe=(t,e)=>t.trim().split(/\\s+/).map(r=>JGe(r,e)).join(\" \"),JGe=(t,e)=>{ci(\"caret\",t,e);let r=e.loose?Da[Jo.CARETLOOSE]:Da[Jo.CARET],o=e.includePrerelease?\"-0\":\"\";return t.replace(r,(a,n,u,A,p)=>{ci(\"caret\",t,a,n,u,A,p);let h;return Xo(n)?h=\"\":Xo(u)?h=`>=${n}.0.0${o} <${+n+1}.0.0-0`:Xo(A)?n===\"0\"?h=`>=${n}.${u}.0${o} <${n}.${+u+1}.0-0`:h=`>=${n}.${u}.0${o} <${+n+1}.0.0-0`:p?(ci(\"replaceCaret pr\",p),n===\"0\"?u===\"0\"?h=`>=${n}.${u}.${A}-${p} <${n}.${u}.${+A+1}-0`:h=`>=${n}.${u}.${A}-${p} <${n}.${+u+1}.0-0`:h=`>=${n}.${u}.${A}-${p} <${+n+1}.0.0-0`):(ci(\"no pr\"),n===\"0\"?u===\"0\"?h=`>=${n}.${u}.${A}${o} <${n}.${u}.${+A+1}-0`:h=`>=${n}.${u}.${A}${o} <${n}.${+u+1}.0-0`:h=`>=${n}.${u}.${A} <${+n+1}.0.0-0`),ci(\"caret return\",h),h})},XGe=(t,e)=>(ci(\"replaceXRanges\",t,e),t.split(/\\s+/).map(r=>ZGe(r,e)).join(\" \")),ZGe=(t,e)=>{t=t.trim();let r=e.loose?Da[Jo.XRANGELOOSE]:Da[Jo.XRANGE];return t.replace(r,(o,a,n,u,A,p)=>{ci(\"xRange\",t,o,a,n,u,A,p);let h=Xo(n),C=h||Xo(u),I=C||Xo(A),v=I;return a===\"=\"&&v&&(a=\"\"),p=e.includePrerelease?\"-0\":\"\",h?a===\">\"||a===\"<\"?o=\"<0.0.0-0\":o=\"*\":a&&v?(C&&(u=0),A=0,a===\">\"?(a=\">=\",C?(n=+n+1,u=0,A=0):(u=+u+1,A=0)):a===\"<=\"&&(a=\"<\",C?n=+n+1:u=+u+1),a===\"<\"&&(p=\"-0\"),o=`${a+n}.${u}.${A}${p}`):C?o=`>=${n}.0.0${p} <${+n+1}.0.0-0`:I&&(o=`>=${n}.${u}.0${p} <${n}.${+u+1}.0-0`),ci(\"xRange return\",o),o})},$Ge=(t,e)=>(ci(\"replaceStars\",t,e),t.trim().replace(Da[Jo.STAR],\"\")),e5e=(t,e)=>(ci(\"replaceGTE0\",t,e),t.trim().replace(Da[e.includePrerelease?Jo.GTE0PRE:Jo.GTE0],\"\")),t5e=t=>(e,r,o,a,n,u,A,p,h,C,I,v,x)=>(Xo(o)?r=\"\":Xo(a)?r=`>=${o}.0.0${t?\"-0\":\"\"}`:Xo(n)?r=`>=${o}.${a}.0${t?\"-0\":\"\"}`:u?r=`>=${r}`:r=`>=${r}${t?\"-0\":\"\"}`,Xo(h)?p=\"\":Xo(C)?p=`<${+h+1}.0.0-0`:Xo(I)?p=`<${h}.${+C+1}.0-0`:v?p=`<=${h}.${C}.${I}-${v}`:t?p=`<${h}.${C}.${+I+1}-0`:p=`<=${p}`,`${r} ${p}`.trim()),r5e=(t,e,r)=>{for(let o=0;o<t.length;o++)if(!t[o].test(e))return!1;if(e.prerelease.length&&!r.includePrerelease){for(let o=0;o<t.length;o++)if(ci(t[o].semver),t[o].semver!==sN.ANY&&t[o].semver.prerelease.length>0){let a=t[o].semver;if(a.major===e.major&&a.minor===e.minor&&a.patch===e.patch)return!0}return!1}return!0}});var yI=_((cQt,CJ)=>{var EI=Symbol(\"SemVer ANY\"),Py=class{static get ANY(){return EI}constructor(e,r){if(r=gJ(r),e instanceof Py){if(e.loose===!!r.loose)return e;e=e.value}e=e.trim().split(/\\s+/).join(\" \"),aN(\"comparator\",e,r),this.options=r,this.loose=!!r.loose,this.parse(e),this.semver===EI?this.value=\"\":this.value=this.operator+this.semver.version,aN(\"comp\",this)}parse(e){let r=this.options.loose?dJ[mJ.COMPARATORLOOSE]:dJ[mJ.COMPARATOR],o=e.match(r);if(!o)throw new TypeError(`Invalid comparator: ${e}`);this.operator=o[1]!==void 0?o[1]:\"\",this.operator===\"=\"&&(this.operator=\"\"),o[2]?this.semver=new yJ(o[2],this.options.loose):this.semver=EI}toString(){return this.value}test(e){if(aN(\"Comparator.test\",e,this.options.loose),this.semver===EI||e===EI)return!0;if(typeof e==\"string\")try{e=new yJ(e,this.options)}catch{return!1}return oN(e,this.operator,this.semver,this.options)}intersects(e,r){if(!(e instanceof Py))throw new TypeError(\"a Comparator is required\");return this.operator===\"\"?this.value===\"\"?!0:new EJ(e.value,r).test(this.value):e.operator===\"\"?e.value===\"\"?!0:new EJ(this.value,r).test(e.semver):(r=gJ(r),r.includePrerelease&&(this.value===\"<0.0.0-0\"||e.value===\"<0.0.0-0\")||!r.includePrerelease&&(this.value.startsWith(\"<0.0.0\")||e.value.startsWith(\"<0.0.0\"))?!1:!!(this.operator.startsWith(\">\")&&e.operator.startsWith(\">\")||this.operator.startsWith(\"<\")&&e.operator.startsWith(\"<\")||this.semver.version===e.semver.version&&this.operator.includes(\"=\")&&e.operator.includes(\"=\")||oN(this.semver,\"<\",e.semver,r)&&this.operator.startsWith(\">\")&&e.operator.startsWith(\"<\")||oN(this.semver,\">\",e.semver,r)&&this.operator.startsWith(\"<\")&&e.operator.startsWith(\">\")))}};CJ.exports=Py;var gJ=hP(),{safeRe:dJ,t:mJ}=Iy(),oN=eN(),aN=hI(),yJ=Po(),EJ=Ol()});var CI=_((uQt,wJ)=>{var n5e=Ol(),i5e=(t,e,r)=>{try{e=new n5e(e,r)}catch{return!1}return e.test(t)};wJ.exports=i5e});var BJ=_((AQt,IJ)=>{var s5e=Ol(),o5e=(t,e)=>new s5e(t,e).set.map(r=>r.map(o=>o.value).join(\" \").trim().split(\" \"));IJ.exports=o5e});var DJ=_((fQt,vJ)=>{var a5e=Po(),l5e=Ol(),c5e=(t,e,r)=>{let o=null,a=null,n=null;try{n=new l5e(e,r)}catch{return null}return t.forEach(u=>{n.test(u)&&(!o||a.compare(u)===-1)&&(o=u,a=new a5e(o,r))}),o};vJ.exports=c5e});var SJ=_((pQt,PJ)=>{var u5e=Po(),A5e=Ol(),f5e=(t,e,r)=>{let o=null,a=null,n=null;try{n=new A5e(e,r)}catch{return null}return t.forEach(u=>{n.test(u)&&(!o||a.compare(u)===1)&&(o=u,a=new u5e(o,r))}),o};PJ.exports=f5e});var kJ=_((hQt,xJ)=>{var lN=Po(),p5e=Ol(),bJ=gI(),h5e=(t,e)=>{t=new p5e(t,e);let r=new lN(\"0.0.0\");if(t.test(r)||(r=new lN(\"0.0.0-0\"),t.test(r)))return r;r=null;for(let o=0;o<t.set.length;++o){let a=t.set[o],n=null;a.forEach(u=>{let A=new lN(u.semver.version);switch(u.operator){case\">\":A.prerelease.length===0?A.patch++:A.prerelease.push(0),A.raw=A.format();case\"\":case\">=\":(!n||bJ(A,n))&&(n=A);break;case\"<\":case\"<=\":break;default:throw new Error(`Unexpected operation: ${u.operator}`)}}),n&&(!r||bJ(r,n))&&(r=n)}return r&&t.test(r)?r:null};xJ.exports=h5e});var FJ=_((gQt,QJ)=>{var g5e=Ol(),d5e=(t,e)=>{try{return new g5e(t,e).range||\"*\"}catch{return null}};QJ.exports=d5e});var DP=_((dQt,LJ)=>{var m5e=Po(),NJ=yI(),{ANY:y5e}=NJ,E5e=Ol(),C5e=CI(),RJ=gI(),TJ=yP(),w5e=CP(),I5e=EP(),B5e=(t,e,r,o)=>{t=new m5e(t,o),e=new E5e(e,o);let a,n,u,A,p;switch(r){case\">\":a=RJ,n=w5e,u=TJ,A=\">\",p=\">=\";break;case\"<\":a=TJ,n=I5e,u=RJ,A=\"<\",p=\"<=\";break;default:throw new TypeError('Must provide a hilo val of \"<\" or \">\"')}if(C5e(t,e,o))return!1;for(let h=0;h<e.set.length;++h){let C=e.set[h],I=null,v=null;if(C.forEach(x=>{x.semver===y5e&&(x=new NJ(\">=0.0.0\")),I=I||x,v=v||x,a(x.semver,I.semver,o)?I=x:u(x.semver,v.semver,o)&&(v=x)}),I.operator===A||I.operator===p||(!v.operator||v.operator===A)&&n(t,v.semver))return!1;if(v.operator===p&&u(t,v.semver))return!1}return!0};LJ.exports=B5e});var MJ=_((mQt,OJ)=>{var v5e=DP(),D5e=(t,e,r)=>v5e(t,e,\">\",r);OJ.exports=D5e});var _J=_((yQt,UJ)=>{var P5e=DP(),S5e=(t,e,r)=>P5e(t,e,\"<\",r);UJ.exports=S5e});var qJ=_((EQt,jJ)=>{var HJ=Ol(),b5e=(t,e,r)=>(t=new HJ(t,r),e=new HJ(e,r),t.intersects(e,r));jJ.exports=b5e});var YJ=_((CQt,GJ)=>{var x5e=CI(),k5e=Ll();GJ.exports=(t,e,r)=>{let o=[],a=null,n=null,u=t.sort((C,I)=>k5e(C,I,r));for(let C of u)x5e(C,e,r)?(n=C,a||(a=C)):(n&&o.push([a,n]),n=null,a=null);a&&o.push([a,null]);let A=[];for(let[C,I]of o)C===I?A.push(C):!I&&C===u[0]?A.push(\"*\"):I?C===u[0]?A.push(`<=${I}`):A.push(`${C} - ${I}`):A.push(`>=${C}`);let p=A.join(\" || \"),h=typeof e.raw==\"string\"?e.raw:String(e);return p.length<h.length?p:e}});var XJ=_((wQt,JJ)=>{var WJ=Ol(),uN=yI(),{ANY:cN}=uN,wI=CI(),AN=Ll(),Q5e=(t,e,r={})=>{if(t===e)return!0;t=new WJ(t,r),e=new WJ(e,r);let o=!1;e:for(let a of t.set){for(let n of e.set){let u=R5e(a,n,r);if(o=o||u!==null,u)continue e}if(o)return!1}return!0},F5e=[new uN(\">=0.0.0-0\")],KJ=[new uN(\">=0.0.0\")],R5e=(t,e,r)=>{if(t===e)return!0;if(t.length===1&&t[0].semver===cN){if(e.length===1&&e[0].semver===cN)return!0;r.includePrerelease?t=F5e:t=KJ}if(e.length===1&&e[0].semver===cN){if(r.includePrerelease)return!0;e=KJ}let o=new Set,a,n;for(let x of t)x.operator===\">\"||x.operator===\">=\"?a=VJ(a,x,r):x.operator===\"<\"||x.operator===\"<=\"?n=zJ(n,x,r):o.add(x.semver);if(o.size>1)return null;let u;if(a&&n){if(u=AN(a.semver,n.semver,r),u>0)return null;if(u===0&&(a.operator!==\">=\"||n.operator!==\"<=\"))return null}for(let x of o){if(a&&!wI(x,String(a),r)||n&&!wI(x,String(n),r))return null;for(let E of e)if(!wI(x,String(E),r))return!1;return!0}let A,p,h,C,I=n&&!r.includePrerelease&&n.semver.prerelease.length?n.semver:!1,v=a&&!r.includePrerelease&&a.semver.prerelease.length?a.semver:!1;I&&I.prerelease.length===1&&n.operator===\"<\"&&I.prerelease[0]===0&&(I=!1);for(let x of e){if(C=C||x.operator===\">\"||x.operator===\">=\",h=h||x.operator===\"<\"||x.operator===\"<=\",a){if(v&&x.semver.prerelease&&x.semver.prerelease.length&&x.semver.major===v.major&&x.semver.minor===v.minor&&x.semver.patch===v.patch&&(v=!1),x.operator===\">\"||x.operator===\">=\"){if(A=VJ(a,x,r),A===x&&A!==a)return!1}else if(a.operator===\">=\"&&!wI(a.semver,String(x),r))return!1}if(n){if(I&&x.semver.prerelease&&x.semver.prerelease.length&&x.semver.major===I.major&&x.semver.minor===I.minor&&x.semver.patch===I.patch&&(I=!1),x.operator===\"<\"||x.operator===\"<=\"){if(p=zJ(n,x,r),p===x&&p!==n)return!1}else if(n.operator===\"<=\"&&!wI(n.semver,String(x),r))return!1}if(!x.operator&&(n||a)&&u!==0)return!1}return!(a&&h&&!n&&u!==0||n&&C&&!a&&u!==0||v||I)},VJ=(t,e,r)=>{if(!t)return e;let o=AN(t.semver,e.semver,r);return o>0?t:o<0||e.operator===\">\"&&t.operator===\">=\"?e:t},zJ=(t,e,r)=>{if(!t)return e;let o=AN(t.semver,e.semver,r);return o<0?t:o>0||e.operator===\"<\"&&t.operator===\"<=\"?e:t};JJ.exports=Q5e});var Jn=_((IQt,eX)=>{var fN=Iy(),ZJ=pI(),T5e=Po(),$J=XT(),N5e=nd(),L5e=Ez(),O5e=wz(),M5e=vz(),U5e=Sz(),_5e=xz(),H5e=Qz(),j5e=Rz(),q5e=Nz(),G5e=Ll(),Y5e=Uz(),W5e=Hz(),K5e=mP(),V5e=Yz(),z5e=Kz(),J5e=gI(),X5e=yP(),Z5e=ZT(),$5e=$T(),e9e=EP(),t9e=CP(),r9e=eN(),n9e=rJ(),i9e=yI(),s9e=Ol(),o9e=CI(),a9e=BJ(),l9e=DJ(),c9e=SJ(),u9e=kJ(),A9e=FJ(),f9e=DP(),p9e=MJ(),h9e=_J(),g9e=qJ(),d9e=YJ(),m9e=XJ();eX.exports={parse:N5e,valid:L5e,clean:O5e,inc:M5e,diff:U5e,major:_5e,minor:H5e,patch:j5e,prerelease:q5e,compare:G5e,rcompare:Y5e,compareLoose:W5e,compareBuild:K5e,sort:V5e,rsort:z5e,gt:J5e,lt:X5e,eq:Z5e,neq:$5e,gte:e9e,lte:t9e,cmp:r9e,coerce:n9e,Comparator:i9e,Range:s9e,satisfies:o9e,toComparators:a9e,maxSatisfying:l9e,minSatisfying:c9e,minVersion:u9e,validRange:A9e,outside:f9e,gtr:p9e,ltr:h9e,intersects:g9e,simplifyRange:d9e,subset:m9e,SemVer:T5e,re:fN.re,src:fN.src,tokens:fN.t,SEMVER_SPEC_VERSION:ZJ.SEMVER_SPEC_VERSION,RELEASE_TYPES:ZJ.RELEASE_TYPES,compareIdentifiers:$J.compareIdentifiers,rcompareIdentifiers:$J.rcompareIdentifiers}});var rX=_((BQt,tX)=>{\"use strict\";function y9e(t,e){function r(){this.constructor=t}r.prototype=e.prototype,t.prototype=new r}function ld(t,e,r,o){this.message=t,this.expected=e,this.found=r,this.location=o,this.name=\"SyntaxError\",typeof Error.captureStackTrace==\"function\"&&Error.captureStackTrace(this,ld)}y9e(ld,Error);ld.buildMessage=function(t,e){var r={literal:function(h){return'\"'+a(h.text)+'\"'},class:function(h){var C=\"\",I;for(I=0;I<h.parts.length;I++)C+=h.parts[I]instanceof Array?n(h.parts[I][0])+\"-\"+n(h.parts[I][1]):n(h.parts[I]);return\"[\"+(h.inverted?\"^\":\"\")+C+\"]\"},any:function(h){return\"any character\"},end:function(h){return\"end of input\"},other:function(h){return h.description}};function o(h){return h.charCodeAt(0).toString(16).toUpperCase()}function a(h){return h.replace(/\\\\/g,\"\\\\\\\\\").replace(/\"/g,'\\\\\"').replace(/\\0/g,\"\\\\0\").replace(/\\t/g,\"\\\\t\").replace(/\\n/g,\"\\\\n\").replace(/\\r/g,\"\\\\r\").replace(/[\\x00-\\x0F]/g,function(C){return\"\\\\x0\"+o(C)}).replace(/[\\x10-\\x1F\\x7F-\\x9F]/g,function(C){return\"\\\\x\"+o(C)})}function n(h){return h.replace(/\\\\/g,\"\\\\\\\\\").replace(/\\]/g,\"\\\\]\").replace(/\\^/g,\"\\\\^\").replace(/-/g,\"\\\\-\").replace(/\\0/g,\"\\\\0\").replace(/\\t/g,\"\\\\t\").replace(/\\n/g,\"\\\\n\").replace(/\\r/g,\"\\\\r\").replace(/[\\x00-\\x0F]/g,function(C){return\"\\\\x0\"+o(C)}).replace(/[\\x10-\\x1F\\x7F-\\x9F]/g,function(C){return\"\\\\x\"+o(C)})}function u(h){return r[h.type](h)}function A(h){var C=new Array(h.length),I,v;for(I=0;I<h.length;I++)C[I]=u(h[I]);if(C.sort(),C.length>0){for(I=1,v=1;I<C.length;I++)C[I-1]!==C[I]&&(C[v]=C[I],v++);C.length=v}switch(C.length){case 1:return C[0];case 2:return C[0]+\" or \"+C[1];default:return C.slice(0,-1).join(\", \")+\", or \"+C[C.length-1]}}function p(h){return h?'\"'+a(h)+'\"':\"end of input\"}return\"Expected \"+A(t)+\" but \"+p(e)+\" found.\"};function E9e(t,e){e=e!==void 0?e:{};var r={},o={Expression:y},a=y,n=\"|\",u=Te(\"|\",!1),A=\"&\",p=Te(\"&\",!1),h=\"^\",C=Te(\"^\",!1),I=function(Z,ie){return!!ie.reduce((Pe,Ne)=>{switch(Ne[1]){case\"|\":return Pe|Ne[3];case\"&\":return Pe&Ne[3];case\"^\":return Pe^Ne[3]}},Z)},v=\"!\",x=Te(\"!\",!1),E=function(Z){return!Z},R=\"(\",L=Te(\"(\",!1),U=\")\",z=Te(\")\",!1),te=function(Z){return Z},le=/^[^ \\t\\n\\r()!|&\\^]/,he=ke([\" \",\"\t\",`\n`,\"\\r\",\"(\",\")\",\"!\",\"|\",\"&\",\"^\"],!0,!1),Ae=function(Z){return e.queryPattern.test(Z)},ye=function(Z){return e.checkFn(Z)},ae=Re(\"whitespace\"),Ie=/^[ \\t\\n\\r]/,Fe=ke([\" \",\"\t\",`\n`,\"\\r\"],!1,!1),g=0,Ee=0,De=[{line:1,column:1}],ce=0,ne=[],ee=0,we;if(\"startRule\"in e){if(!(e.startRule in o))throw new Error(`Can't start parsing from rule \"`+e.startRule+'\".');a=o[e.startRule]}function xe(){return t.substring(Ee,g)}function ht(){return He(Ee,g)}function H(Z,ie){throw ie=ie!==void 0?ie:He(Ee,g),S([Re(Z)],t.substring(Ee,g),ie)}function lt(Z,ie){throw ie=ie!==void 0?ie:He(Ee,g),w(Z,ie)}function Te(Z,ie){return{type:\"literal\",text:Z,ignoreCase:ie}}function ke(Z,ie,Pe){return{type:\"class\",parts:Z,inverted:ie,ignoreCase:Pe}}function be(){return{type:\"any\"}}function _e(){return{type:\"end\"}}function Re(Z){return{type:\"other\",description:Z}}function ze(Z){var ie=De[Z],Pe;if(ie)return ie;for(Pe=Z-1;!De[Pe];)Pe--;for(ie=De[Pe],ie={line:ie.line,column:ie.column};Pe<Z;)t.charCodeAt(Pe)===10?(ie.line++,ie.column=1):ie.column++,Pe++;return De[Z]=ie,ie}function He(Z,ie){var Pe=ze(Z),Ne=ze(ie);return{start:{offset:Z,line:Pe.line,column:Pe.column},end:{offset:ie,line:Ne.line,column:Ne.column}}}function b(Z){g<ce||(g>ce&&(ce=g,ne=[]),ne.push(Z))}function w(Z,ie){return new ld(Z,null,null,ie)}function S(Z,ie,Pe){return new ld(ld.buildMessage(Z,ie),Z,ie,Pe)}function y(){var Z,ie,Pe,Ne,ot,dt,jt,$t;if(Z=g,ie=F(),ie!==r){for(Pe=[],Ne=g,ot=X(),ot!==r?(t.charCodeAt(g)===124?(dt=n,g++):(dt=r,ee===0&&b(u)),dt===r&&(t.charCodeAt(g)===38?(dt=A,g++):(dt=r,ee===0&&b(p)),dt===r&&(t.charCodeAt(g)===94?(dt=h,g++):(dt=r,ee===0&&b(C)))),dt!==r?(jt=X(),jt!==r?($t=F(),$t!==r?(ot=[ot,dt,jt,$t],Ne=ot):(g=Ne,Ne=r)):(g=Ne,Ne=r)):(g=Ne,Ne=r)):(g=Ne,Ne=r);Ne!==r;)Pe.push(Ne),Ne=g,ot=X(),ot!==r?(t.charCodeAt(g)===124?(dt=n,g++):(dt=r,ee===0&&b(u)),dt===r&&(t.charCodeAt(g)===38?(dt=A,g++):(dt=r,ee===0&&b(p)),dt===r&&(t.charCodeAt(g)===94?(dt=h,g++):(dt=r,ee===0&&b(C)))),dt!==r?(jt=X(),jt!==r?($t=F(),$t!==r?(ot=[ot,dt,jt,$t],Ne=ot):(g=Ne,Ne=r)):(g=Ne,Ne=r)):(g=Ne,Ne=r)):(g=Ne,Ne=r);Pe!==r?(Ee=Z,ie=I(ie,Pe),Z=ie):(g=Z,Z=r)}else g=Z,Z=r;return Z}function F(){var Z,ie,Pe,Ne,ot,dt;return Z=g,t.charCodeAt(g)===33?(ie=v,g++):(ie=r,ee===0&&b(x)),ie!==r?(Pe=F(),Pe!==r?(Ee=Z,ie=E(Pe),Z=ie):(g=Z,Z=r)):(g=Z,Z=r),Z===r&&(Z=g,t.charCodeAt(g)===40?(ie=R,g++):(ie=r,ee===0&&b(L)),ie!==r?(Pe=X(),Pe!==r?(Ne=y(),Ne!==r?(ot=X(),ot!==r?(t.charCodeAt(g)===41?(dt=U,g++):(dt=r,ee===0&&b(z)),dt!==r?(Ee=Z,ie=te(Ne),Z=ie):(g=Z,Z=r)):(g=Z,Z=r)):(g=Z,Z=r)):(g=Z,Z=r)):(g=Z,Z=r),Z===r&&(Z=J())),Z}function J(){var Z,ie,Pe,Ne,ot;if(Z=g,ie=X(),ie!==r){if(Pe=g,Ne=[],le.test(t.charAt(g))?(ot=t.charAt(g),g++):(ot=r,ee===0&&b(he)),ot!==r)for(;ot!==r;)Ne.push(ot),le.test(t.charAt(g))?(ot=t.charAt(g),g++):(ot=r,ee===0&&b(he));else Ne=r;Ne!==r?Pe=t.substring(Pe,g):Pe=Ne,Pe!==r?(Ee=g,Ne=Ae(Pe),Ne?Ne=void 0:Ne=r,Ne!==r?(Ee=Z,ie=ye(Pe),Z=ie):(g=Z,Z=r)):(g=Z,Z=r)}else g=Z,Z=r;return Z}function X(){var Z,ie;for(ee++,Z=[],Ie.test(t.charAt(g))?(ie=t.charAt(g),g++):(ie=r,ee===0&&b(Fe));ie!==r;)Z.push(ie),Ie.test(t.charAt(g))?(ie=t.charAt(g),g++):(ie=r,ee===0&&b(Fe));return ee--,Z===r&&(ie=r,ee===0&&b(ae)),Z}if(we=a(),we!==r&&g===t.length)return we;throw we!==r&&g<t.length&&b(_e()),S(ne,ce<t.length?t.charAt(ce):null,ce<t.length?He(ce,ce+1):He(ce,ce))}tX.exports={SyntaxError:ld,parse:E9e}});var nX=_(PP=>{var{parse:C9e}=rX();PP.makeParser=(t=/[a-z]+/)=>(e,r)=>C9e(e,{queryPattern:t,checkFn:r});PP.parse=PP.makeParser()});var sX=_((DQt,iX)=>{\"use strict\";iX.exports={aliceblue:[240,248,255],antiquewhite:[250,235,215],aqua:[0,255,255],aquamarine:[127,255,212],azure:[240,255,255],beige:[245,245,220],bisque:[255,228,196],black:[0,0,0],blanchedalmond:[255,235,205],blue:[0,0,255],blueviolet:[138,43,226],brown:[165,42,42],burlywood:[222,184,135],cadetblue:[95,158,160],chartreuse:[127,255,0],chocolate:[210,105,30],coral:[255,127,80],cornflowerblue:[100,149,237],cornsilk:[255,248,220],crimson:[220,20,60],cyan:[0,255,255],darkblue:[0,0,139],darkcyan:[0,139,139],darkgoldenrod:[184,134,11],darkgray:[169,169,169],darkgreen:[0,100,0],darkgrey:[169,169,169],darkkhaki:[189,183,107],darkmagenta:[139,0,139],darkolivegreen:[85,107,47],darkorange:[255,140,0],darkorchid:[153,50,204],darkred:[139,0,0],darksalmon:[233,150,122],darkseagreen:[143,188,143],darkslateblue:[72,61,139],darkslategray:[47,79,79],darkslategrey:[47,79,79],darkturquoise:[0,206,209],darkviolet:[148,0,211],deeppink:[255,20,147],deepskyblue:[0,191,255],dimgray:[105,105,105],dimgrey:[105,105,105],dodgerblue:[30,144,255],firebrick:[178,34,34],floralwhite:[255,250,240],forestgreen:[34,139,34],fuchsia:[255,0,255],gainsboro:[220,220,220],ghostwhite:[248,248,255],gold:[255,215,0],goldenrod:[218,165,32],gray:[128,128,128],green:[0,128,0],greenyellow:[173,255,47],grey:[128,128,128],honeydew:[240,255,240],hotpink:[255,105,180],indianred:[205,92,92],indigo:[75,0,130],ivory:[255,255,240],khaki:[240,230,140],lavender:[230,230,250],lavenderblush:[255,240,245],lawngreen:[124,252,0],lemonchiffon:[255,250,205],lightblue:[173,216,230],lightcoral:[240,128,128],lightcyan:[224,255,255],lightgoldenrodyellow:[250,250,210],lightgray:[211,211,211],lightgreen:[144,238,144],lightgrey:[211,211,211],lightpink:[255,182,193],lightsalmon:[255,160,122],lightseagreen:[32,178,170],lightskyblue:[135,206,250],lightslategray:[119,136,153],lightslategrey:[119,136,153],lightsteelblue:[176,196,222],lightyellow:[255,255,224],lime:[0,255,0],limegreen:[50,205,50],linen:[250,240,230],magenta:[255,0,255],maroon:[128,0,0],mediumaquamarine:[102,205,170],mediumblue:[0,0,205],mediumorchid:[186,85,211],mediumpurple:[147,112,219],mediumseagreen:[60,179,113],mediumslateblue:[123,104,238],mediumspringgreen:[0,250,154],mediumturquoise:[72,209,204],mediumvioletred:[199,21,133],midnightblue:[25,25,112],mintcream:[245,255,250],mistyrose:[255,228,225],moccasin:[255,228,181],navajowhite:[255,222,173],navy:[0,0,128],oldlace:[253,245,230],olive:[128,128,0],olivedrab:[107,142,35],orange:[255,165,0],orangered:[255,69,0],orchid:[218,112,214],palegoldenrod:[238,232,170],palegreen:[152,251,152],paleturquoise:[175,238,238],palevioletred:[219,112,147],papayawhip:[255,239,213],peachpuff:[255,218,185],peru:[205,133,63],pink:[255,192,203],plum:[221,160,221],powderblue:[176,224,230],purple:[128,0,128],rebeccapurple:[102,51,153],red:[255,0,0],rosybrown:[188,143,143],royalblue:[65,105,225],saddlebrown:[139,69,19],salmon:[250,128,114],sandybrown:[244,164,96],seagreen:[46,139,87],seashell:[255,245,238],sienna:[160,82,45],silver:[192,192,192],skyblue:[135,206,235],slateblue:[106,90,205],slategray:[112,128,144],slategrey:[112,128,144],snow:[255,250,250],springgreen:[0,255,127],steelblue:[70,130,180],tan:[210,180,140],teal:[0,128,128],thistle:[216,191,216],tomato:[255,99,71],turquoise:[64,224,208],violet:[238,130,238],wheat:[245,222,179],white:[255,255,255],whitesmoke:[245,245,245],yellow:[255,255,0],yellowgreen:[154,205,50]}});var pN=_((PQt,aX)=>{var II=sX(),oX={};for(let t of Object.keys(II))oX[II[t]]=t;var Ar={rgb:{channels:3,labels:\"rgb\"},hsl:{channels:3,labels:\"hsl\"},hsv:{channels:3,labels:\"hsv\"},hwb:{channels:3,labels:\"hwb\"},cmyk:{channels:4,labels:\"cmyk\"},xyz:{channels:3,labels:\"xyz\"},lab:{channels:3,labels:\"lab\"},lch:{channels:3,labels:\"lch\"},hex:{channels:1,labels:[\"hex\"]},keyword:{channels:1,labels:[\"keyword\"]},ansi16:{channels:1,labels:[\"ansi16\"]},ansi256:{channels:1,labels:[\"ansi256\"]},hcg:{channels:3,labels:[\"h\",\"c\",\"g\"]},apple:{channels:3,labels:[\"r16\",\"g16\",\"b16\"]},gray:{channels:1,labels:[\"gray\"]}};aX.exports=Ar;for(let t of Object.keys(Ar)){if(!(\"channels\"in Ar[t]))throw new Error(\"missing channels property: \"+t);if(!(\"labels\"in Ar[t]))throw new Error(\"missing channel labels property: \"+t);if(Ar[t].labels.length!==Ar[t].channels)throw new Error(\"channel and label counts mismatch: \"+t);let{channels:e,labels:r}=Ar[t];delete Ar[t].channels,delete Ar[t].labels,Object.defineProperty(Ar[t],\"channels\",{value:e}),Object.defineProperty(Ar[t],\"labels\",{value:r})}Ar.rgb.hsl=function(t){let e=t[0]/255,r=t[1]/255,o=t[2]/255,a=Math.min(e,r,o),n=Math.max(e,r,o),u=n-a,A,p;n===a?A=0:e===n?A=(r-o)/u:r===n?A=2+(o-e)/u:o===n&&(A=4+(e-r)/u),A=Math.min(A*60,360),A<0&&(A+=360);let h=(a+n)/2;return n===a?p=0:h<=.5?p=u/(n+a):p=u/(2-n-a),[A,p*100,h*100]};Ar.rgb.hsv=function(t){let e,r,o,a,n,u=t[0]/255,A=t[1]/255,p=t[2]/255,h=Math.max(u,A,p),C=h-Math.min(u,A,p),I=function(v){return(h-v)/6/C+1/2};return C===0?(a=0,n=0):(n=C/h,e=I(u),r=I(A),o=I(p),u===h?a=o-r:A===h?a=1/3+e-o:p===h&&(a=2/3+r-e),a<0?a+=1:a>1&&(a-=1)),[a*360,n*100,h*100]};Ar.rgb.hwb=function(t){let e=t[0],r=t[1],o=t[2],a=Ar.rgb.hsl(t)[0],n=1/255*Math.min(e,Math.min(r,o));return o=1-1/255*Math.max(e,Math.max(r,o)),[a,n*100,o*100]};Ar.rgb.cmyk=function(t){let e=t[0]/255,r=t[1]/255,o=t[2]/255,a=Math.min(1-e,1-r,1-o),n=(1-e-a)/(1-a)||0,u=(1-r-a)/(1-a)||0,A=(1-o-a)/(1-a)||0;return[n*100,u*100,A*100,a*100]};function w9e(t,e){return(t[0]-e[0])**2+(t[1]-e[1])**2+(t[2]-e[2])**2}Ar.rgb.keyword=function(t){let e=oX[t];if(e)return e;let r=1/0,o;for(let a of Object.keys(II)){let n=II[a],u=w9e(t,n);u<r&&(r=u,o=a)}return o};Ar.keyword.rgb=function(t){return II[t]};Ar.rgb.xyz=function(t){let e=t[0]/255,r=t[1]/255,o=t[2]/255;e=e>.04045?((e+.055)/1.055)**2.4:e/12.92,r=r>.04045?((r+.055)/1.055)**2.4:r/12.92,o=o>.04045?((o+.055)/1.055)**2.4:o/12.92;let a=e*.4124+r*.3576+o*.1805,n=e*.2126+r*.7152+o*.0722,u=e*.0193+r*.1192+o*.9505;return[a*100,n*100,u*100]};Ar.rgb.lab=function(t){let e=Ar.rgb.xyz(t),r=e[0],o=e[1],a=e[2];r/=95.047,o/=100,a/=108.883,r=r>.008856?r**(1/3):7.787*r+16/116,o=o>.008856?o**(1/3):7.787*o+16/116,a=a>.008856?a**(1/3):7.787*a+16/116;let n=116*o-16,u=500*(r-o),A=200*(o-a);return[n,u,A]};Ar.hsl.rgb=function(t){let e=t[0]/360,r=t[1]/100,o=t[2]/100,a,n,u;if(r===0)return u=o*255,[u,u,u];o<.5?a=o*(1+r):a=o+r-o*r;let A=2*o-a,p=[0,0,0];for(let h=0;h<3;h++)n=e+1/3*-(h-1),n<0&&n++,n>1&&n--,6*n<1?u=A+(a-A)*6*n:2*n<1?u=a:3*n<2?u=A+(a-A)*(2/3-n)*6:u=A,p[h]=u*255;return p};Ar.hsl.hsv=function(t){let e=t[0],r=t[1]/100,o=t[2]/100,a=r,n=Math.max(o,.01);o*=2,r*=o<=1?o:2-o,a*=n<=1?n:2-n;let u=(o+r)/2,A=o===0?2*a/(n+a):2*r/(o+r);return[e,A*100,u*100]};Ar.hsv.rgb=function(t){let e=t[0]/60,r=t[1]/100,o=t[2]/100,a=Math.floor(e)%6,n=e-Math.floor(e),u=255*o*(1-r),A=255*o*(1-r*n),p=255*o*(1-r*(1-n));switch(o*=255,a){case 0:return[o,p,u];case 1:return[A,o,u];case 2:return[u,o,p];case 3:return[u,A,o];case 4:return[p,u,o];case 5:return[o,u,A]}};Ar.hsv.hsl=function(t){let e=t[0],r=t[1]/100,o=t[2]/100,a=Math.max(o,.01),n,u;u=(2-r)*o;let A=(2-r)*a;return n=r*a,n/=A<=1?A:2-A,n=n||0,u/=2,[e,n*100,u*100]};Ar.hwb.rgb=function(t){let e=t[0]/360,r=t[1]/100,o=t[2]/100,a=r+o,n;a>1&&(r/=a,o/=a);let u=Math.floor(6*e),A=1-o;n=6*e-u,(u&1)!==0&&(n=1-n);let p=r+n*(A-r),h,C,I;switch(u){default:case 6:case 0:h=A,C=p,I=r;break;case 1:h=p,C=A,I=r;break;case 2:h=r,C=A,I=p;break;case 3:h=r,C=p,I=A;break;case 4:h=p,C=r,I=A;break;case 5:h=A,C=r,I=p;break}return[h*255,C*255,I*255]};Ar.cmyk.rgb=function(t){let e=t[0]/100,r=t[1]/100,o=t[2]/100,a=t[3]/100,n=1-Math.min(1,e*(1-a)+a),u=1-Math.min(1,r*(1-a)+a),A=1-Math.min(1,o*(1-a)+a);return[n*255,u*255,A*255]};Ar.xyz.rgb=function(t){let e=t[0]/100,r=t[1]/100,o=t[2]/100,a,n,u;return a=e*3.2406+r*-1.5372+o*-.4986,n=e*-.9689+r*1.8758+o*.0415,u=e*.0557+r*-.204+o*1.057,a=a>.0031308?1.055*a**(1/2.4)-.055:a*12.92,n=n>.0031308?1.055*n**(1/2.4)-.055:n*12.92,u=u>.0031308?1.055*u**(1/2.4)-.055:u*12.92,a=Math.min(Math.max(0,a),1),n=Math.min(Math.max(0,n),1),u=Math.min(Math.max(0,u),1),[a*255,n*255,u*255]};Ar.xyz.lab=function(t){let e=t[0],r=t[1],o=t[2];e/=95.047,r/=100,o/=108.883,e=e>.008856?e**(1/3):7.787*e+16/116,r=r>.008856?r**(1/3):7.787*r+16/116,o=o>.008856?o**(1/3):7.787*o+16/116;let a=116*r-16,n=500*(e-r),u=200*(r-o);return[a,n,u]};Ar.lab.xyz=function(t){let e=t[0],r=t[1],o=t[2],a,n,u;n=(e+16)/116,a=r/500+n,u=n-o/200;let A=n**3,p=a**3,h=u**3;return n=A>.008856?A:(n-16/116)/7.787,a=p>.008856?p:(a-16/116)/7.787,u=h>.008856?h:(u-16/116)/7.787,a*=95.047,n*=100,u*=108.883,[a,n,u]};Ar.lab.lch=function(t){let e=t[0],r=t[1],o=t[2],a;a=Math.atan2(o,r)*360/2/Math.PI,a<0&&(a+=360);let u=Math.sqrt(r*r+o*o);return[e,u,a]};Ar.lch.lab=function(t){let e=t[0],r=t[1],a=t[2]/360*2*Math.PI,n=r*Math.cos(a),u=r*Math.sin(a);return[e,n,u]};Ar.rgb.ansi16=function(t,e=null){let[r,o,a]=t,n=e===null?Ar.rgb.hsv(t)[2]:e;if(n=Math.round(n/50),n===0)return 30;let u=30+(Math.round(a/255)<<2|Math.round(o/255)<<1|Math.round(r/255));return n===2&&(u+=60),u};Ar.hsv.ansi16=function(t){return Ar.rgb.ansi16(Ar.hsv.rgb(t),t[2])};Ar.rgb.ansi256=function(t){let e=t[0],r=t[1],o=t[2];return e===r&&r===o?e<8?16:e>248?231:Math.round((e-8)/247*24)+232:16+36*Math.round(e/255*5)+6*Math.round(r/255*5)+Math.round(o/255*5)};Ar.ansi16.rgb=function(t){let e=t%10;if(e===0||e===7)return t>50&&(e+=3.5),e=e/10.5*255,[e,e,e];let r=(~~(t>50)+1)*.5,o=(e&1)*r*255,a=(e>>1&1)*r*255,n=(e>>2&1)*r*255;return[o,a,n]};Ar.ansi256.rgb=function(t){if(t>=232){let n=(t-232)*10+8;return[n,n,n]}t-=16;let e,r=Math.floor(t/36)/5*255,o=Math.floor((e=t%36)/6)/5*255,a=e%6/5*255;return[r,o,a]};Ar.rgb.hex=function(t){let r=(((Math.round(t[0])&255)<<16)+((Math.round(t[1])&255)<<8)+(Math.round(t[2])&255)).toString(16).toUpperCase();return\"000000\".substring(r.length)+r};Ar.hex.rgb=function(t){let e=t.toString(16).match(/[a-f0-9]{6}|[a-f0-9]{3}/i);if(!e)return[0,0,0];let r=e[0];e[0].length===3&&(r=r.split(\"\").map(A=>A+A).join(\"\"));let o=parseInt(r,16),a=o>>16&255,n=o>>8&255,u=o&255;return[a,n,u]};Ar.rgb.hcg=function(t){let e=t[0]/255,r=t[1]/255,o=t[2]/255,a=Math.max(Math.max(e,r),o),n=Math.min(Math.min(e,r),o),u=a-n,A,p;return u<1?A=n/(1-u):A=0,u<=0?p=0:a===e?p=(r-o)/u%6:a===r?p=2+(o-e)/u:p=4+(e-r)/u,p/=6,p%=1,[p*360,u*100,A*100]};Ar.hsl.hcg=function(t){let e=t[1]/100,r=t[2]/100,o=r<.5?2*e*r:2*e*(1-r),a=0;return o<1&&(a=(r-.5*o)/(1-o)),[t[0],o*100,a*100]};Ar.hsv.hcg=function(t){let e=t[1]/100,r=t[2]/100,o=e*r,a=0;return o<1&&(a=(r-o)/(1-o)),[t[0],o*100,a*100]};Ar.hcg.rgb=function(t){let e=t[0]/360,r=t[1]/100,o=t[2]/100;if(r===0)return[o*255,o*255,o*255];let a=[0,0,0],n=e%1*6,u=n%1,A=1-u,p=0;switch(Math.floor(n)){case 0:a[0]=1,a[1]=u,a[2]=0;break;case 1:a[0]=A,a[1]=1,a[2]=0;break;case 2:a[0]=0,a[1]=1,a[2]=u;break;case 3:a[0]=0,a[1]=A,a[2]=1;break;case 4:a[0]=u,a[1]=0,a[2]=1;break;default:a[0]=1,a[1]=0,a[2]=A}return p=(1-r)*o,[(r*a[0]+p)*255,(r*a[1]+p)*255,(r*a[2]+p)*255]};Ar.hcg.hsv=function(t){let e=t[1]/100,r=t[2]/100,o=e+r*(1-e),a=0;return o>0&&(a=e/o),[t[0],a*100,o*100]};Ar.hcg.hsl=function(t){let e=t[1]/100,o=t[2]/100*(1-e)+.5*e,a=0;return o>0&&o<.5?a=e/(2*o):o>=.5&&o<1&&(a=e/(2*(1-o))),[t[0],a*100,o*100]};Ar.hcg.hwb=function(t){let e=t[1]/100,r=t[2]/100,o=e+r*(1-e);return[t[0],(o-e)*100,(1-o)*100]};Ar.hwb.hcg=function(t){let e=t[1]/100,o=1-t[2]/100,a=o-e,n=0;return a<1&&(n=(o-a)/(1-a)),[t[0],a*100,n*100]};Ar.apple.rgb=function(t){return[t[0]/65535*255,t[1]/65535*255,t[2]/65535*255]};Ar.rgb.apple=function(t){return[t[0]/255*65535,t[1]/255*65535,t[2]/255*65535]};Ar.gray.rgb=function(t){return[t[0]/100*255,t[0]/100*255,t[0]/100*255]};Ar.gray.hsl=function(t){return[0,0,t[0]]};Ar.gray.hsv=Ar.gray.hsl;Ar.gray.hwb=function(t){return[0,100,t[0]]};Ar.gray.cmyk=function(t){return[0,0,0,t[0]]};Ar.gray.lab=function(t){return[t[0],0,0]};Ar.gray.hex=function(t){let e=Math.round(t[0]/100*255)&255,o=((e<<16)+(e<<8)+e).toString(16).toUpperCase();return\"000000\".substring(o.length)+o};Ar.rgb.gray=function(t){return[(t[0]+t[1]+t[2])/3/255*100]}});var cX=_((SQt,lX)=>{var SP=pN();function I9e(){let t={},e=Object.keys(SP);for(let r=e.length,o=0;o<r;o++)t[e[o]]={distance:-1,parent:null};return t}function B9e(t){let e=I9e(),r=[t];for(e[t].distance=0;r.length;){let o=r.pop(),a=Object.keys(SP[o]);for(let n=a.length,u=0;u<n;u++){let A=a[u],p=e[A];p.distance===-1&&(p.distance=e[o].distance+1,p.parent=o,r.unshift(A))}}return e}function v9e(t,e){return function(r){return e(t(r))}}function D9e(t,e){let r=[e[t].parent,t],o=SP[e[t].parent][t],a=e[t].parent;for(;e[a].parent;)r.unshift(e[a].parent),o=v9e(SP[e[a].parent][a],o),a=e[a].parent;return o.conversion=r,o}lX.exports=function(t){let e=B9e(t),r={},o=Object.keys(e);for(let a=o.length,n=0;n<a;n++){let u=o[n];e[u].parent!==null&&(r[u]=D9e(u,e))}return r}});var AX=_((bQt,uX)=>{var hN=pN(),P9e=cX(),Sy={},S9e=Object.keys(hN);function b9e(t){let e=function(...r){let o=r[0];return o==null?o:(o.length>1&&(r=o),t(r))};return\"conversion\"in t&&(e.conversion=t.conversion),e}function x9e(t){let e=function(...r){let o=r[0];if(o==null)return o;o.length>1&&(r=o);let a=t(r);if(typeof a==\"object\")for(let n=a.length,u=0;u<n;u++)a[u]=Math.round(a[u]);return a};return\"conversion\"in t&&(e.conversion=t.conversion),e}S9e.forEach(t=>{Sy[t]={},Object.defineProperty(Sy[t],\"channels\",{value:hN[t].channels}),Object.defineProperty(Sy[t],\"labels\",{value:hN[t].labels});let e=P9e(t);Object.keys(e).forEach(o=>{let a=e[o];Sy[t][o]=x9e(a),Sy[t][o].raw=b9e(a)})});uX.exports=Sy});var BI=_((xQt,dX)=>{\"use strict\";var fX=(t,e)=>(...r)=>`\\x1B[${t(...r)+e}m`,pX=(t,e)=>(...r)=>{let o=t(...r);return`\\x1B[${38+e};5;${o}m`},hX=(t,e)=>(...r)=>{let o=t(...r);return`\\x1B[${38+e};2;${o[0]};${o[1]};${o[2]}m`},bP=t=>t,gX=(t,e,r)=>[t,e,r],by=(t,e,r)=>{Object.defineProperty(t,e,{get:()=>{let o=r();return Object.defineProperty(t,e,{value:o,enumerable:!0,configurable:!0}),o},enumerable:!0,configurable:!0})},gN,xy=(t,e,r,o)=>{gN===void 0&&(gN=AX());let a=o?10:0,n={};for(let[u,A]of Object.entries(gN)){let p=u===\"ansi16\"?\"ansi\":u;u===e?n[p]=t(r,a):typeof A==\"object\"&&(n[p]=t(A[e],a))}return n};function k9e(){let t=new Map,e={modifier:{reset:[0,0],bold:[1,22],dim:[2,22],italic:[3,23],underline:[4,24],inverse:[7,27],hidden:[8,28],strikethrough:[9,29]},color:{black:[30,39],red:[31,39],green:[32,39],yellow:[33,39],blue:[34,39],magenta:[35,39],cyan:[36,39],white:[37,39],blackBright:[90,39],redBright:[91,39],greenBright:[92,39],yellowBright:[93,39],blueBright:[94,39],magentaBright:[95,39],cyanBright:[96,39],whiteBright:[97,39]},bgColor:{bgBlack:[40,49],bgRed:[41,49],bgGreen:[42,49],bgYellow:[43,49],bgBlue:[44,49],bgMagenta:[45,49],bgCyan:[46,49],bgWhite:[47,49],bgBlackBright:[100,49],bgRedBright:[101,49],bgGreenBright:[102,49],bgYellowBright:[103,49],bgBlueBright:[104,49],bgMagentaBright:[105,49],bgCyanBright:[106,49],bgWhiteBright:[107,49]}};e.color.gray=e.color.blackBright,e.bgColor.bgGray=e.bgColor.bgBlackBright,e.color.grey=e.color.blackBright,e.bgColor.bgGrey=e.bgColor.bgBlackBright;for(let[r,o]of Object.entries(e)){for(let[a,n]of Object.entries(o))e[a]={open:`\\x1B[${n[0]}m`,close:`\\x1B[${n[1]}m`},o[a]=e[a],t.set(n[0],n[1]);Object.defineProperty(e,r,{value:o,enumerable:!1})}return Object.defineProperty(e,\"codes\",{value:t,enumerable:!1}),e.color.close=\"\\x1B[39m\",e.bgColor.close=\"\\x1B[49m\",by(e.color,\"ansi\",()=>xy(fX,\"ansi16\",bP,!1)),by(e.color,\"ansi256\",()=>xy(pX,\"ansi256\",bP,!1)),by(e.color,\"ansi16m\",()=>xy(hX,\"rgb\",gX,!1)),by(e.bgColor,\"ansi\",()=>xy(fX,\"ansi16\",bP,!0)),by(e.bgColor,\"ansi256\",()=>xy(pX,\"ansi256\",bP,!0)),by(e.bgColor,\"ansi16m\",()=>xy(hX,\"rgb\",gX,!0)),e}Object.defineProperty(dX,\"exports\",{enumerable:!0,get:k9e})});var yX=_((kQt,mX)=>{\"use strict\";mX.exports=(t,e=process.argv)=>{let r=t.startsWith(\"-\")?\"\":t.length===1?\"-\":\"--\",o=e.indexOf(r+t),a=e.indexOf(\"--\");return o!==-1&&(a===-1||o<a)}});var yN=_((QQt,CX)=>{\"use strict\";var Q9e=Be(\"os\"),EX=Be(\"tty\"),Ml=yX(),{env:ls}=process,Kp;Ml(\"no-color\")||Ml(\"no-colors\")||Ml(\"color=false\")||Ml(\"color=never\")?Kp=0:(Ml(\"color\")||Ml(\"colors\")||Ml(\"color=true\")||Ml(\"color=always\"))&&(Kp=1);\"FORCE_COLOR\"in ls&&(ls.FORCE_COLOR===\"true\"?Kp=1:ls.FORCE_COLOR===\"false\"?Kp=0:Kp=ls.FORCE_COLOR.length===0?1:Math.min(parseInt(ls.FORCE_COLOR,10),3));function dN(t){return t===0?!1:{level:t,hasBasic:!0,has256:t>=2,has16m:t>=3}}function mN(t,e){if(Kp===0)return 0;if(Ml(\"color=16m\")||Ml(\"color=full\")||Ml(\"color=truecolor\"))return 3;if(Ml(\"color=256\"))return 2;if(t&&!e&&Kp===void 0)return 0;let r=Kp||0;if(ls.TERM===\"dumb\")return r;if(process.platform===\"win32\"){let o=Q9e.release().split(\".\");return Number(o[0])>=10&&Number(o[2])>=10586?Number(o[2])>=14931?3:2:1}if(\"CI\"in ls)return[\"TRAVIS\",\"CIRCLECI\",\"APPVEYOR\",\"GITLAB_CI\"].some(o=>o in ls)||ls.CI_NAME===\"codeship\"?1:r;if(\"TEAMCITY_VERSION\"in ls)return/^(9\\.(0*[1-9]\\d*)\\.|\\d{2,}\\.)/.test(ls.TEAMCITY_VERSION)?1:0;if(\"GITHUB_ACTIONS\"in ls)return 1;if(ls.COLORTERM===\"truecolor\")return 3;if(\"TERM_PROGRAM\"in ls){let o=parseInt((ls.TERM_PROGRAM_VERSION||\"\").split(\".\")[0],10);switch(ls.TERM_PROGRAM){case\"iTerm.app\":return o>=3?3:2;case\"Apple_Terminal\":return 2}}return/-256(color)?$/i.test(ls.TERM)?2:/^screen|^xterm|^vt100|^vt220|^rxvt|color|ansi|cygwin|linux/i.test(ls.TERM)||\"COLORTERM\"in ls?1:r}function F9e(t){let e=mN(t,t&&t.isTTY);return dN(e)}CX.exports={supportsColor:F9e,stdout:dN(mN(!0,EX.isatty(1))),stderr:dN(mN(!0,EX.isatty(2)))}});var IX=_((FQt,wX)=>{\"use strict\";var R9e=(t,e,r)=>{let o=t.indexOf(e);if(o===-1)return t;let a=e.length,n=0,u=\"\";do u+=t.substr(n,o-n)+e+r,n=o+a,o=t.indexOf(e,n);while(o!==-1);return u+=t.substr(n),u},T9e=(t,e,r,o)=>{let a=0,n=\"\";do{let u=t[o-1]===\"\\r\";n+=t.substr(a,(u?o-1:o)-a)+e+(u?`\\r\n`:`\n`)+r,a=o+1,o=t.indexOf(`\n`,a)}while(o!==-1);return n+=t.substr(a),n};wX.exports={stringReplaceAll:R9e,stringEncaseCRLFWithFirstIndex:T9e}});var SX=_((RQt,PX)=>{\"use strict\";var N9e=/(?:\\\\(u(?:[a-f\\d]{4}|\\{[a-f\\d]{1,6}\\})|x[a-f\\d]{2}|.))|(?:\\{(~)?(\\w+(?:\\([^)]*\\))?(?:\\.\\w+(?:\\([^)]*\\))?)*)(?:[ \\t]|(?=\\r?\\n)))|(\\})|((?:.|[\\r\\n\\f])+?)/gi,BX=/(?:^|\\.)(\\w+)(?:\\(([^)]*)\\))?/g,L9e=/^(['\"])((?:\\\\.|(?!\\1)[^\\\\])*)\\1$/,O9e=/\\\\(u(?:[a-f\\d]{4}|\\{[a-f\\d]{1,6}\\})|x[a-f\\d]{2}|.)|([^\\\\])/gi,M9e=new Map([[\"n\",`\n`],[\"r\",\"\\r\"],[\"t\",\"\t\"],[\"b\",\"\\b\"],[\"f\",\"\\f\"],[\"v\",\"\\v\"],[\"0\",\"\\0\"],[\"\\\\\",\"\\\\\"],[\"e\",\"\\x1B\"],[\"a\",\"\\x07\"]]);function DX(t){let e=t[0]===\"u\",r=t[1]===\"{\";return e&&!r&&t.length===5||t[0]===\"x\"&&t.length===3?String.fromCharCode(parseInt(t.slice(1),16)):e&&r?String.fromCodePoint(parseInt(t.slice(2,-1),16)):M9e.get(t)||t}function U9e(t,e){let r=[],o=e.trim().split(/\\s*,\\s*/g),a;for(let n of o){let u=Number(n);if(!Number.isNaN(u))r.push(u);else if(a=n.match(L9e))r.push(a[2].replace(O9e,(A,p,h)=>p?DX(p):h));else throw new Error(`Invalid Chalk template style argument: ${n} (in style '${t}')`)}return r}function _9e(t){BX.lastIndex=0;let e=[],r;for(;(r=BX.exec(t))!==null;){let o=r[1];if(r[2]){let a=U9e(o,r[2]);e.push([o].concat(a))}else e.push([o])}return e}function vX(t,e){let r={};for(let a of e)for(let n of a.styles)r[n[0]]=a.inverse?null:n.slice(1);let o=t;for(let[a,n]of Object.entries(r))if(!!Array.isArray(n)){if(!(a in o))throw new Error(`Unknown Chalk style: ${a}`);o=n.length>0?o[a](...n):o[a]}return o}PX.exports=(t,e)=>{let r=[],o=[],a=[];if(e.replace(N9e,(n,u,A,p,h,C)=>{if(u)a.push(DX(u));else if(p){let I=a.join(\"\");a=[],o.push(r.length===0?I:vX(t,r)(I)),r.push({inverse:A,styles:_9e(p)})}else if(h){if(r.length===0)throw new Error(\"Found extraneous } in Chalk template literal\");o.push(vX(t,r)(a.join(\"\"))),a=[],r.pop()}else a.push(C)}),o.push(a.join(\"\")),r.length>0){let n=`Chalk template literal is missing ${r.length} closing bracket${r.length===1?\"\":\"s\"} (\\`}\\`)`;throw new Error(n)}return o.join(\"\")}});var vN=_((TQt,QX)=>{\"use strict\";var vI=BI(),{stdout:CN,stderr:wN}=yN(),{stringReplaceAll:H9e,stringEncaseCRLFWithFirstIndex:j9e}=IX(),bX=[\"ansi\",\"ansi\",\"ansi256\",\"ansi16m\"],ky=Object.create(null),q9e=(t,e={})=>{if(e.level>3||e.level<0)throw new Error(\"The `level` option should be an integer from 0 to 3\");let r=CN?CN.level:0;t.level=e.level===void 0?r:e.level},IN=class{constructor(e){return xX(e)}},xX=t=>{let e={};return q9e(e,t),e.template=(...r)=>W9e(e.template,...r),Object.setPrototypeOf(e,xP.prototype),Object.setPrototypeOf(e.template,e),e.template.constructor=()=>{throw new Error(\"`chalk.constructor()` is deprecated. Use `new chalk.Instance()` instead.\")},e.template.Instance=IN,e.template};function xP(t){return xX(t)}for(let[t,e]of Object.entries(vI))ky[t]={get(){let r=kP(this,BN(e.open,e.close,this._styler),this._isEmpty);return Object.defineProperty(this,t,{value:r}),r}};ky.visible={get(){let t=kP(this,this._styler,!0);return Object.defineProperty(this,\"visible\",{value:t}),t}};var kX=[\"rgb\",\"hex\",\"keyword\",\"hsl\",\"hsv\",\"hwb\",\"ansi\",\"ansi256\"];for(let t of kX)ky[t]={get(){let{level:e}=this;return function(...r){let o=BN(vI.color[bX[e]][t](...r),vI.color.close,this._styler);return kP(this,o,this._isEmpty)}}};for(let t of kX){let e=\"bg\"+t[0].toUpperCase()+t.slice(1);ky[e]={get(){let{level:r}=this;return function(...o){let a=BN(vI.bgColor[bX[r]][t](...o),vI.bgColor.close,this._styler);return kP(this,a,this._isEmpty)}}}}var G9e=Object.defineProperties(()=>{},{...ky,level:{enumerable:!0,get(){return this._generator.level},set(t){this._generator.level=t}}}),BN=(t,e,r)=>{let o,a;return r===void 0?(o=t,a=e):(o=r.openAll+t,a=e+r.closeAll),{open:t,close:e,openAll:o,closeAll:a,parent:r}},kP=(t,e,r)=>{let o=(...a)=>Y9e(o,a.length===1?\"\"+a[0]:a.join(\" \"));return o.__proto__=G9e,o._generator=t,o._styler=e,o._isEmpty=r,o},Y9e=(t,e)=>{if(t.level<=0||!e)return t._isEmpty?\"\":e;let r=t._styler;if(r===void 0)return e;let{openAll:o,closeAll:a}=r;if(e.indexOf(\"\\x1B\")!==-1)for(;r!==void 0;)e=H9e(e,r.close,r.open),r=r.parent;let n=e.indexOf(`\n`);return n!==-1&&(e=j9e(e,a,o,n)),o+e+a},EN,W9e=(t,...e)=>{let[r]=e;if(!Array.isArray(r))return e.join(\" \");let o=e.slice(1),a=[r.raw[0]];for(let n=1;n<r.length;n++)a.push(String(o[n-1]).replace(/[{}\\\\]/g,\"\\\\$&\"),String(r.raw[n]));return EN===void 0&&(EN=SX()),EN(t,a.join(\"\"))};Object.defineProperties(xP.prototype,ky);var DI=xP();DI.supportsColor=CN;DI.stderr=xP({level:wN?wN.level:0});DI.stderr.supportsColor=wN;DI.Level={None:0,Basic:1,Ansi256:2,TrueColor:3,0:\"None\",1:\"Basic\",2:\"Ansi256\",3:\"TrueColor\"};QX.exports=DI});var QP=_(Ul=>{\"use strict\";Ul.isInteger=t=>typeof t==\"number\"?Number.isInteger(t):typeof t==\"string\"&&t.trim()!==\"\"?Number.isInteger(Number(t)):!1;Ul.find=(t,e)=>t.nodes.find(r=>r.type===e);Ul.exceedsLimit=(t,e,r=1,o)=>o===!1||!Ul.isInteger(t)||!Ul.isInteger(e)?!1:(Number(e)-Number(t))/Number(r)>=o;Ul.escapeNode=(t,e=0,r)=>{let o=t.nodes[e];!o||(r&&o.type===r||o.type===\"open\"||o.type===\"close\")&&o.escaped!==!0&&(o.value=\"\\\\\"+o.value,o.escaped=!0)};Ul.encloseBrace=t=>t.type!==\"brace\"?!1:t.commas>>0+t.ranges>>0===0?(t.invalid=!0,!0):!1;Ul.isInvalidBrace=t=>t.type!==\"brace\"?!1:t.invalid===!0||t.dollar?!0:t.commas>>0+t.ranges>>0===0||t.open!==!0||t.close!==!0?(t.invalid=!0,!0):!1;Ul.isOpenOrClose=t=>t.type===\"open\"||t.type===\"close\"?!0:t.open===!0||t.close===!0;Ul.reduce=t=>t.reduce((e,r)=>(r.type===\"text\"&&e.push(r.value),r.type===\"range\"&&(r.type=\"text\"),e),[]);Ul.flatten=(...t)=>{let e=[],r=o=>{for(let a=0;a<o.length;a++){let n=o[a];Array.isArray(n)?r(n,e):n!==void 0&&e.push(n)}return e};return r(t),e}});var FP=_((LQt,RX)=>{\"use strict\";var FX=QP();RX.exports=(t,e={})=>{let r=(o,a={})=>{let n=e.escapeInvalid&&FX.isInvalidBrace(a),u=o.invalid===!0&&e.escapeInvalid===!0,A=\"\";if(o.value)return(n||u)&&FX.isOpenOrClose(o)?\"\\\\\"+o.value:o.value;if(o.value)return o.value;if(o.nodes)for(let p of o.nodes)A+=r(p);return A};return r(t)}});var NX=_((OQt,TX)=>{\"use strict\";TX.exports=function(t){return typeof t==\"number\"?t-t===0:typeof t==\"string\"&&t.trim()!==\"\"?Number.isFinite?Number.isFinite(+t):isFinite(+t):!1}});var GX=_((MQt,qX)=>{\"use strict\";var LX=NX(),cd=(t,e,r)=>{if(LX(t)===!1)throw new TypeError(\"toRegexRange: expected the first argument to be a number\");if(e===void 0||t===e)return String(t);if(LX(e)===!1)throw new TypeError(\"toRegexRange: expected the second argument to be a number.\");let o={relaxZeros:!0,...r};typeof o.strictZeros==\"boolean\"&&(o.relaxZeros=o.strictZeros===!1);let a=String(o.relaxZeros),n=String(o.shorthand),u=String(o.capture),A=String(o.wrap),p=t+\":\"+e+\"=\"+a+n+u+A;if(cd.cache.hasOwnProperty(p))return cd.cache[p].result;let h=Math.min(t,e),C=Math.max(t,e);if(Math.abs(h-C)===1){let R=t+\"|\"+e;return o.capture?`(${R})`:o.wrap===!1?R:`(?:${R})`}let I=jX(t)||jX(e),v={min:t,max:e,a:h,b:C},x=[],E=[];if(I&&(v.isPadded=I,v.maxLen=String(v.max).length),h<0){let R=C<0?Math.abs(C):1;E=OX(R,Math.abs(h),v,o),h=v.a=0}return C>=0&&(x=OX(h,C,v,o)),v.negatives=E,v.positives=x,v.result=K9e(E,x,o),o.capture===!0?v.result=`(${v.result})`:o.wrap!==!1&&x.length+E.length>1&&(v.result=`(?:${v.result})`),cd.cache[p]=v,v.result};function K9e(t,e,r){let o=DN(t,e,\"-\",!1,r)||[],a=DN(e,t,\"\",!1,r)||[],n=DN(t,e,\"-?\",!0,r)||[];return o.concat(n).concat(a).join(\"|\")}function V9e(t,e){let r=1,o=1,a=UX(t,r),n=new Set([e]);for(;t<=a&&a<=e;)n.add(a),r+=1,a=UX(t,r);for(a=_X(e+1,o)-1;t<a&&a<=e;)n.add(a),o+=1,a=_X(e+1,o)-1;return n=[...n],n.sort(X9e),n}function z9e(t,e,r){if(t===e)return{pattern:t,count:[],digits:0};let o=J9e(t,e),a=o.length,n=\"\",u=0;for(let A=0;A<a;A++){let[p,h]=o[A];p===h?n+=p:p!==\"0\"||h!==\"9\"?n+=Z9e(p,h,r):u++}return u&&(n+=r.shorthand===!0?\"\\\\d\":\"[0-9]\"),{pattern:n,count:[u],digits:a}}function OX(t,e,r,o){let a=V9e(t,e),n=[],u=t,A;for(let p=0;p<a.length;p++){let h=a[p],C=z9e(String(u),String(h),o),I=\"\";if(!r.isPadded&&A&&A.pattern===C.pattern){A.count.length>1&&A.count.pop(),A.count.push(C.count[0]),A.string=A.pattern+HX(A.count),u=h+1;continue}r.isPadded&&(I=$9e(h,r,o)),C.string=I+C.pattern+HX(C.count),n.push(C),u=h+1,A=C}return n}function DN(t,e,r,o,a){let n=[];for(let u of t){let{string:A}=u;!o&&!MX(e,\"string\",A)&&n.push(r+A),o&&MX(e,\"string\",A)&&n.push(r+A)}return n}function J9e(t,e){let r=[];for(let o=0;o<t.length;o++)r.push([t[o],e[o]]);return r}function X9e(t,e){return t>e?1:e>t?-1:0}function MX(t,e,r){return t.some(o=>o[e]===r)}function UX(t,e){return Number(String(t).slice(0,-e)+\"9\".repeat(e))}function _X(t,e){return t-t%Math.pow(10,e)}function HX(t){let[e=0,r=\"\"]=t;return r||e>1?`{${e+(r?\",\"+r:\"\")}}`:\"\"}function Z9e(t,e,r){return`[${t}${e-t===1?\"\":\"-\"}${e}]`}function jX(t){return/^-?(0+)\\d/.test(t)}function $9e(t,e,r){if(!e.isPadded)return t;let o=Math.abs(e.maxLen-String(t).length),a=r.relaxZeros!==!1;switch(o){case 0:return\"\";case 1:return a?\"0?\":\"0\";case 2:return a?\"0{0,2}\":\"00\";default:return a?`0{0,${o}}`:`0{${o}}`}}cd.cache={};cd.clearCache=()=>cd.cache={};qX.exports=cd});var bN=_((UQt,ZX)=>{\"use strict\";var e7e=Be(\"util\"),KX=GX(),YX=t=>t!==null&&typeof t==\"object\"&&!Array.isArray(t),t7e=t=>e=>t===!0?Number(e):String(e),PN=t=>typeof t==\"number\"||typeof t==\"string\"&&t!==\"\",PI=t=>Number.isInteger(+t),SN=t=>{let e=`${t}`,r=-1;if(e[0]===\"-\"&&(e=e.slice(1)),e===\"0\")return!1;for(;e[++r]===\"0\";);return r>0},r7e=(t,e,r)=>typeof t==\"string\"||typeof e==\"string\"?!0:r.stringify===!0,n7e=(t,e,r)=>{if(e>0){let o=t[0]===\"-\"?\"-\":\"\";o&&(t=t.slice(1)),t=o+t.padStart(o?e-1:e,\"0\")}return r===!1?String(t):t},WX=(t,e)=>{let r=t[0]===\"-\"?\"-\":\"\";for(r&&(t=t.slice(1),e--);t.length<e;)t=\"0\"+t;return r?\"-\"+t:t},i7e=(t,e)=>{t.negatives.sort((u,A)=>u<A?-1:u>A?1:0),t.positives.sort((u,A)=>u<A?-1:u>A?1:0);let r=e.capture?\"\":\"?:\",o=\"\",a=\"\",n;return t.positives.length&&(o=t.positives.join(\"|\")),t.negatives.length&&(a=`-(${r}${t.negatives.join(\"|\")})`),o&&a?n=`${o}|${a}`:n=o||a,e.wrap?`(${r}${n})`:n},VX=(t,e,r,o)=>{if(r)return KX(t,e,{wrap:!1,...o});let a=String.fromCharCode(t);if(t===e)return a;let n=String.fromCharCode(e);return`[${a}-${n}]`},zX=(t,e,r)=>{if(Array.isArray(t)){let o=r.wrap===!0,a=r.capture?\"\":\"?:\";return o?`(${a}${t.join(\"|\")})`:t.join(\"|\")}return KX(t,e,r)},JX=(...t)=>new RangeError(\"Invalid range arguments: \"+e7e.inspect(...t)),XX=(t,e,r)=>{if(r.strictRanges===!0)throw JX([t,e]);return[]},s7e=(t,e)=>{if(e.strictRanges===!0)throw new TypeError(`Expected step \"${t}\" to be a number`);return[]},o7e=(t,e,r=1,o={})=>{let a=Number(t),n=Number(e);if(!Number.isInteger(a)||!Number.isInteger(n)){if(o.strictRanges===!0)throw JX([t,e]);return[]}a===0&&(a=0),n===0&&(n=0);let u=a>n,A=String(t),p=String(e),h=String(r);r=Math.max(Math.abs(r),1);let C=SN(A)||SN(p)||SN(h),I=C?Math.max(A.length,p.length,h.length):0,v=C===!1&&r7e(t,e,o)===!1,x=o.transform||t7e(v);if(o.toRegex&&r===1)return VX(WX(t,I),WX(e,I),!0,o);let E={negatives:[],positives:[]},R=z=>E[z<0?\"negatives\":\"positives\"].push(Math.abs(z)),L=[],U=0;for(;u?a>=n:a<=n;)o.toRegex===!0&&r>1?R(a):L.push(n7e(x(a,U),I,v)),a=u?a-r:a+r,U++;return o.toRegex===!0?r>1?i7e(E,o):zX(L,null,{wrap:!1,...o}):L},a7e=(t,e,r=1,o={})=>{if(!PI(t)&&t.length>1||!PI(e)&&e.length>1)return XX(t,e,o);let a=o.transform||(v=>String.fromCharCode(v)),n=`${t}`.charCodeAt(0),u=`${e}`.charCodeAt(0),A=n>u,p=Math.min(n,u),h=Math.max(n,u);if(o.toRegex&&r===1)return VX(p,h,!1,o);let C=[],I=0;for(;A?n>=u:n<=u;)C.push(a(n,I)),n=A?n-r:n+r,I++;return o.toRegex===!0?zX(C,null,{wrap:!1,options:o}):C},RP=(t,e,r,o={})=>{if(e==null&&PN(t))return[t];if(!PN(t)||!PN(e))return XX(t,e,o);if(typeof r==\"function\")return RP(t,e,1,{transform:r});if(YX(r))return RP(t,e,0,r);let a={...o};return a.capture===!0&&(a.wrap=!0),r=r||a.step||1,PI(r)?PI(t)&&PI(e)?o7e(t,e,r,a):a7e(t,e,Math.max(Math.abs(r),1),a):r!=null&&!YX(r)?s7e(r,a):RP(t,e,1,r)};ZX.exports=RP});var tZ=_((_Qt,eZ)=>{\"use strict\";var l7e=bN(),$X=QP(),c7e=(t,e={})=>{let r=(o,a={})=>{let n=$X.isInvalidBrace(a),u=o.invalid===!0&&e.escapeInvalid===!0,A=n===!0||u===!0,p=e.escapeInvalid===!0?\"\\\\\":\"\",h=\"\";if(o.isOpen===!0||o.isClose===!0)return p+o.value;if(o.type===\"open\")return A?p+o.value:\"(\";if(o.type===\"close\")return A?p+o.value:\")\";if(o.type===\"comma\")return o.prev.type===\"comma\"?\"\":A?o.value:\"|\";if(o.value)return o.value;if(o.nodes&&o.ranges>0){let C=$X.reduce(o.nodes),I=l7e(...C,{...e,wrap:!1,toRegex:!0});if(I.length!==0)return C.length>1&&I.length>1?`(${I})`:I}if(o.nodes)for(let C of o.nodes)h+=r(C,o);return h};return r(t)};eZ.exports=c7e});var iZ=_((HQt,nZ)=>{\"use strict\";var u7e=bN(),rZ=FP(),Qy=QP(),ud=(t=\"\",e=\"\",r=!1)=>{let o=[];if(t=[].concat(t),e=[].concat(e),!e.length)return t;if(!t.length)return r?Qy.flatten(e).map(a=>`{${a}}`):e;for(let a of t)if(Array.isArray(a))for(let n of a)o.push(ud(n,e,r));else for(let n of e)r===!0&&typeof n==\"string\"&&(n=`{${n}}`),o.push(Array.isArray(n)?ud(a,n,r):a+n);return Qy.flatten(o)},A7e=(t,e={})=>{let r=e.rangeLimit===void 0?1e3:e.rangeLimit,o=(a,n={})=>{a.queue=[];let u=n,A=n.queue;for(;u.type!==\"brace\"&&u.type!==\"root\"&&u.parent;)u=u.parent,A=u.queue;if(a.invalid||a.dollar){A.push(ud(A.pop(),rZ(a,e)));return}if(a.type===\"brace\"&&a.invalid!==!0&&a.nodes.length===2){A.push(ud(A.pop(),[\"{}\"]));return}if(a.nodes&&a.ranges>0){let I=Qy.reduce(a.nodes);if(Qy.exceedsLimit(...I,e.step,r))throw new RangeError(\"expanded array length exceeds range limit. Use options.rangeLimit to increase or disable the limit.\");let v=u7e(...I,e);v.length===0&&(v=rZ(a,e)),A.push(ud(A.pop(),v)),a.nodes=[];return}let p=Qy.encloseBrace(a),h=a.queue,C=a;for(;C.type!==\"brace\"&&C.type!==\"root\"&&C.parent;)C=C.parent,h=C.queue;for(let I=0;I<a.nodes.length;I++){let v=a.nodes[I];if(v.type===\"comma\"&&a.type===\"brace\"){I===1&&h.push(\"\"),h.push(\"\");continue}if(v.type===\"close\"){A.push(ud(A.pop(),h,p));continue}if(v.value&&v.type!==\"open\"){h.push(ud(h.pop(),v.value));continue}v.nodes&&o(v,a)}return h};return Qy.flatten(o(t))};nZ.exports=A7e});var oZ=_((jQt,sZ)=>{\"use strict\";sZ.exports={MAX_LENGTH:1024*64,CHAR_0:\"0\",CHAR_9:\"9\",CHAR_UPPERCASE_A:\"A\",CHAR_LOWERCASE_A:\"a\",CHAR_UPPERCASE_Z:\"Z\",CHAR_LOWERCASE_Z:\"z\",CHAR_LEFT_PARENTHESES:\"(\",CHAR_RIGHT_PARENTHESES:\")\",CHAR_ASTERISK:\"*\",CHAR_AMPERSAND:\"&\",CHAR_AT:\"@\",CHAR_BACKSLASH:\"\\\\\",CHAR_BACKTICK:\"`\",CHAR_CARRIAGE_RETURN:\"\\r\",CHAR_CIRCUMFLEX_ACCENT:\"^\",CHAR_COLON:\":\",CHAR_COMMA:\",\",CHAR_DOLLAR:\"$\",CHAR_DOT:\".\",CHAR_DOUBLE_QUOTE:'\"',CHAR_EQUAL:\"=\",CHAR_EXCLAMATION_MARK:\"!\",CHAR_FORM_FEED:\"\\f\",CHAR_FORWARD_SLASH:\"/\",CHAR_HASH:\"#\",CHAR_HYPHEN_MINUS:\"-\",CHAR_LEFT_ANGLE_BRACKET:\"<\",CHAR_LEFT_CURLY_BRACE:\"{\",CHAR_LEFT_SQUARE_BRACKET:\"[\",CHAR_LINE_FEED:`\n`,CHAR_NO_BREAK_SPACE:\"\\xA0\",CHAR_PERCENT:\"%\",CHAR_PLUS:\"+\",CHAR_QUESTION_MARK:\"?\",CHAR_RIGHT_ANGLE_BRACKET:\">\",CHAR_RIGHT_CURLY_BRACE:\"}\",CHAR_RIGHT_SQUARE_BRACKET:\"]\",CHAR_SEMICOLON:\";\",CHAR_SINGLE_QUOTE:\"'\",CHAR_SPACE:\" \",CHAR_TAB:\"\t\",CHAR_UNDERSCORE:\"_\",CHAR_VERTICAL_LINE:\"|\",CHAR_ZERO_WIDTH_NOBREAK_SPACE:\"\\uFEFF\"}});var AZ=_((qQt,uZ)=>{\"use strict\";var f7e=FP(),{MAX_LENGTH:aZ,CHAR_BACKSLASH:xN,CHAR_BACKTICK:p7e,CHAR_COMMA:h7e,CHAR_DOT:g7e,CHAR_LEFT_PARENTHESES:d7e,CHAR_RIGHT_PARENTHESES:m7e,CHAR_LEFT_CURLY_BRACE:y7e,CHAR_RIGHT_CURLY_BRACE:E7e,CHAR_LEFT_SQUARE_BRACKET:lZ,CHAR_RIGHT_SQUARE_BRACKET:cZ,CHAR_DOUBLE_QUOTE:C7e,CHAR_SINGLE_QUOTE:w7e,CHAR_NO_BREAK_SPACE:I7e,CHAR_ZERO_WIDTH_NOBREAK_SPACE:B7e}=oZ(),v7e=(t,e={})=>{if(typeof t!=\"string\")throw new TypeError(\"Expected a string\");let r=e||{},o=typeof r.maxLength==\"number\"?Math.min(aZ,r.maxLength):aZ;if(t.length>o)throw new SyntaxError(`Input length (${t.length}), exceeds max characters (${o})`);let a={type:\"root\",input:t,nodes:[]},n=[a],u=a,A=a,p=0,h=t.length,C=0,I=0,v,x={},E=()=>t[C++],R=L=>{if(L.type===\"text\"&&A.type===\"dot\"&&(A.type=\"text\"),A&&A.type===\"text\"&&L.type===\"text\"){A.value+=L.value;return}return u.nodes.push(L),L.parent=u,L.prev=A,A=L,L};for(R({type:\"bos\"});C<h;)if(u=n[n.length-1],v=E(),!(v===B7e||v===I7e)){if(v===xN){R({type:\"text\",value:(e.keepEscaping?v:\"\")+E()});continue}if(v===cZ){R({type:\"text\",value:\"\\\\\"+v});continue}if(v===lZ){p++;let L=!0,U;for(;C<h&&(U=E());){if(v+=U,U===lZ){p++;continue}if(U===xN){v+=E();continue}if(U===cZ&&(p--,p===0))break}R({type:\"text\",value:v});continue}if(v===d7e){u=R({type:\"paren\",nodes:[]}),n.push(u),R({type:\"text\",value:v});continue}if(v===m7e){if(u.type!==\"paren\"){R({type:\"text\",value:v});continue}u=n.pop(),R({type:\"text\",value:v}),u=n[n.length-1];continue}if(v===C7e||v===w7e||v===p7e){let L=v,U;for(e.keepQuotes!==!0&&(v=\"\");C<h&&(U=E());){if(U===xN){v+=U+E();continue}if(U===L){e.keepQuotes===!0&&(v+=U);break}v+=U}R({type:\"text\",value:v});continue}if(v===y7e){I++;let U={type:\"brace\",open:!0,close:!1,dollar:A.value&&A.value.slice(-1)===\"$\"||u.dollar===!0,depth:I,commas:0,ranges:0,nodes:[]};u=R(U),n.push(u),R({type:\"open\",value:v});continue}if(v===E7e){if(u.type!==\"brace\"){R({type:\"text\",value:v});continue}let L=\"close\";u=n.pop(),u.close=!0,R({type:L,value:v}),I--,u=n[n.length-1];continue}if(v===h7e&&I>0){if(u.ranges>0){u.ranges=0;let L=u.nodes.shift();u.nodes=[L,{type:\"text\",value:f7e(u)}]}R({type:\"comma\",value:v}),u.commas++;continue}if(v===g7e&&I>0&&u.commas===0){let L=u.nodes;if(I===0||L.length===0){R({type:\"text\",value:v});continue}if(A.type===\"dot\"){if(u.range=[],A.value+=v,A.type=\"range\",u.nodes.length!==3&&u.nodes.length!==5){u.invalid=!0,u.ranges=0,A.type=\"text\";continue}u.ranges++,u.args=[];continue}if(A.type===\"range\"){L.pop();let U=L[L.length-1];U.value+=A.value+v,A=U,u.ranges--;continue}R({type:\"dot\",value:v});continue}R({type:\"text\",value:v})}do if(u=n.pop(),u.type!==\"root\"){u.nodes.forEach(z=>{z.nodes||(z.type===\"open\"&&(z.isOpen=!0),z.type===\"close\"&&(z.isClose=!0),z.nodes||(z.type=\"text\"),z.invalid=!0)});let L=n[n.length-1],U=L.nodes.indexOf(u);L.nodes.splice(U,1,...u.nodes)}while(n.length>0);return R({type:\"eos\"}),a};uZ.exports=v7e});var hZ=_((GQt,pZ)=>{\"use strict\";var fZ=FP(),D7e=tZ(),P7e=iZ(),S7e=AZ(),rl=(t,e={})=>{let r=[];if(Array.isArray(t))for(let o of t){let a=rl.create(o,e);Array.isArray(a)?r.push(...a):r.push(a)}else r=[].concat(rl.create(t,e));return e&&e.expand===!0&&e.nodupes===!0&&(r=[...new Set(r)]),r};rl.parse=(t,e={})=>S7e(t,e);rl.stringify=(t,e={})=>fZ(typeof t==\"string\"?rl.parse(t,e):t,e);rl.compile=(t,e={})=>(typeof t==\"string\"&&(t=rl.parse(t,e)),D7e(t,e));rl.expand=(t,e={})=>{typeof t==\"string\"&&(t=rl.parse(t,e));let r=P7e(t,e);return e.noempty===!0&&(r=r.filter(Boolean)),e.nodupes===!0&&(r=[...new Set(r)]),r};rl.create=(t,e={})=>t===\"\"||t.length<3?[t]:e.expand!==!0?rl.compile(t,e):rl.expand(t,e);pZ.exports=rl});var SI=_((YQt,EZ)=>{\"use strict\";var b7e=Be(\"path\"),Ku=\"\\\\\\\\/\",gZ=`[^${Ku}]`,Bf=\"\\\\.\",x7e=\"\\\\+\",k7e=\"\\\\?\",TP=\"\\\\/\",Q7e=\"(?=.)\",dZ=\"[^/]\",kN=`(?:${TP}|$)`,mZ=`(?:^|${TP})`,QN=`${Bf}{1,2}${kN}`,F7e=`(?!${Bf})`,R7e=`(?!${mZ}${QN})`,T7e=`(?!${Bf}{0,1}${kN})`,N7e=`(?!${QN})`,L7e=`[^.${TP}]`,O7e=`${dZ}*?`,yZ={DOT_LITERAL:Bf,PLUS_LITERAL:x7e,QMARK_LITERAL:k7e,SLASH_LITERAL:TP,ONE_CHAR:Q7e,QMARK:dZ,END_ANCHOR:kN,DOTS_SLASH:QN,NO_DOT:F7e,NO_DOTS:R7e,NO_DOT_SLASH:T7e,NO_DOTS_SLASH:N7e,QMARK_NO_DOT:L7e,STAR:O7e,START_ANCHOR:mZ},M7e={...yZ,SLASH_LITERAL:`[${Ku}]`,QMARK:gZ,STAR:`${gZ}*?`,DOTS_SLASH:`${Bf}{1,2}(?:[${Ku}]|$)`,NO_DOT:`(?!${Bf})`,NO_DOTS:`(?!(?:^|[${Ku}])${Bf}{1,2}(?:[${Ku}]|$))`,NO_DOT_SLASH:`(?!${Bf}{0,1}(?:[${Ku}]|$))`,NO_DOTS_SLASH:`(?!${Bf}{1,2}(?:[${Ku}]|$))`,QMARK_NO_DOT:`[^.${Ku}]`,START_ANCHOR:`(?:^|[${Ku}])`,END_ANCHOR:`(?:[${Ku}]|$)`},U7e={alnum:\"a-zA-Z0-9\",alpha:\"a-zA-Z\",ascii:\"\\\\x00-\\\\x7F\",blank:\" \\\\t\",cntrl:\"\\\\x00-\\\\x1F\\\\x7F\",digit:\"0-9\",graph:\"\\\\x21-\\\\x7E\",lower:\"a-z\",print:\"\\\\x20-\\\\x7E \",punct:\"\\\\-!\\\"#$%&'()\\\\*+,./:;<=>?@[\\\\]^_`{|}~\",space:\" \\\\t\\\\r\\\\n\\\\v\\\\f\",upper:\"A-Z\",word:\"A-Za-z0-9_\",xdigit:\"A-Fa-f0-9\"};EZ.exports={MAX_LENGTH:1024*64,POSIX_REGEX_SOURCE:U7e,REGEX_BACKSLASH:/\\\\(?![*+?^${}(|)[\\]])/g,REGEX_NON_SPECIAL_CHARS:/^[^@![\\].,$*+?^{}()|\\\\/]+/,REGEX_SPECIAL_CHARS:/[-*+?.^${}(|)[\\]]/,REGEX_SPECIAL_CHARS_BACKREF:/(\\\\?)((\\W)(\\3*))/g,REGEX_SPECIAL_CHARS_GLOBAL:/([-*+?.^${}(|)[\\]])/g,REGEX_REMOVE_BACKSLASH:/(?:\\[.*?[^\\\\]\\]|\\\\(?=.))/g,REPLACEMENTS:{\"***\":\"*\",\"**/**\":\"**\",\"**/**/**\":\"**\"},CHAR_0:48,CHAR_9:57,CHAR_UPPERCASE_A:65,CHAR_LOWERCASE_A:97,CHAR_UPPERCASE_Z:90,CHAR_LOWERCASE_Z:122,CHAR_LEFT_PARENTHESES:40,CHAR_RIGHT_PARENTHESES:41,CHAR_ASTERISK:42,CHAR_AMPERSAND:38,CHAR_AT:64,CHAR_BACKWARD_SLASH:92,CHAR_CARRIAGE_RETURN:13,CHAR_CIRCUMFLEX_ACCENT:94,CHAR_COLON:58,CHAR_COMMA:44,CHAR_DOT:46,CHAR_DOUBLE_QUOTE:34,CHAR_EQUAL:61,CHAR_EXCLAMATION_MARK:33,CHAR_FORM_FEED:12,CHAR_FORWARD_SLASH:47,CHAR_GRAVE_ACCENT:96,CHAR_HASH:35,CHAR_HYPHEN_MINUS:45,CHAR_LEFT_ANGLE_BRACKET:60,CHAR_LEFT_CURLY_BRACE:123,CHAR_LEFT_SQUARE_BRACKET:91,CHAR_LINE_FEED:10,CHAR_NO_BREAK_SPACE:160,CHAR_PERCENT:37,CHAR_PLUS:43,CHAR_QUESTION_MARK:63,CHAR_RIGHT_ANGLE_BRACKET:62,CHAR_RIGHT_CURLY_BRACE:125,CHAR_RIGHT_SQUARE_BRACKET:93,CHAR_SEMICOLON:59,CHAR_SINGLE_QUOTE:39,CHAR_SPACE:32,CHAR_TAB:9,CHAR_UNDERSCORE:95,CHAR_VERTICAL_LINE:124,CHAR_ZERO_WIDTH_NOBREAK_SPACE:65279,SEP:b7e.sep,extglobChars(t){return{\"!\":{type:\"negate\",open:\"(?:(?!(?:\",close:`))${t.STAR})`},\"?\":{type:\"qmark\",open:\"(?:\",close:\")?\"},\"+\":{type:\"plus\",open:\"(?:\",close:\")+\"},\"*\":{type:\"star\",open:\"(?:\",close:\")*\"},\"@\":{type:\"at\",open:\"(?:\",close:\")\"}}},globChars(t){return t===!0?M7e:yZ}}});var bI=_(Pa=>{\"use strict\";var _7e=Be(\"path\"),H7e=process.platform===\"win32\",{REGEX_BACKSLASH:j7e,REGEX_REMOVE_BACKSLASH:q7e,REGEX_SPECIAL_CHARS:G7e,REGEX_SPECIAL_CHARS_GLOBAL:Y7e}=SI();Pa.isObject=t=>t!==null&&typeof t==\"object\"&&!Array.isArray(t);Pa.hasRegexChars=t=>G7e.test(t);Pa.isRegexChar=t=>t.length===1&&Pa.hasRegexChars(t);Pa.escapeRegex=t=>t.replace(Y7e,\"\\\\$1\");Pa.toPosixSlashes=t=>t.replace(j7e,\"/\");Pa.removeBackslashes=t=>t.replace(q7e,e=>e===\"\\\\\"?\"\":e);Pa.supportsLookbehinds=()=>{let t=process.version.slice(1).split(\".\").map(Number);return t.length===3&&t[0]>=9||t[0]===8&&t[1]>=10};Pa.isWindows=t=>t&&typeof t.windows==\"boolean\"?t.windows:H7e===!0||_7e.sep===\"\\\\\";Pa.escapeLast=(t,e,r)=>{let o=t.lastIndexOf(e,r);return o===-1?t:t[o-1]===\"\\\\\"?Pa.escapeLast(t,e,o-1):`${t.slice(0,o)}\\\\${t.slice(o)}`};Pa.removePrefix=(t,e={})=>{let r=t;return r.startsWith(\"./\")&&(r=r.slice(2),e.prefix=\"./\"),r};Pa.wrapOutput=(t,e={},r={})=>{let o=r.contains?\"\":\"^\",a=r.contains?\"\":\"$\",n=`${o}(?:${t})${a}`;return e.negated===!0&&(n=`(?:^(?!${n}).*$)`),n}});var SZ=_((KQt,PZ)=>{\"use strict\";var CZ=bI(),{CHAR_ASTERISK:FN,CHAR_AT:W7e,CHAR_BACKWARD_SLASH:xI,CHAR_COMMA:K7e,CHAR_DOT:RN,CHAR_EXCLAMATION_MARK:TN,CHAR_FORWARD_SLASH:DZ,CHAR_LEFT_CURLY_BRACE:NN,CHAR_LEFT_PARENTHESES:LN,CHAR_LEFT_SQUARE_BRACKET:V7e,CHAR_PLUS:z7e,CHAR_QUESTION_MARK:wZ,CHAR_RIGHT_CURLY_BRACE:J7e,CHAR_RIGHT_PARENTHESES:IZ,CHAR_RIGHT_SQUARE_BRACKET:X7e}=SI(),BZ=t=>t===DZ||t===xI,vZ=t=>{t.isPrefix!==!0&&(t.depth=t.isGlobstar?1/0:1)},Z7e=(t,e)=>{let r=e||{},o=t.length-1,a=r.parts===!0||r.scanToEnd===!0,n=[],u=[],A=[],p=t,h=-1,C=0,I=0,v=!1,x=!1,E=!1,R=!1,L=!1,U=!1,z=!1,te=!1,le=!1,he=!1,Ae=0,ye,ae,Ie={value:\"\",depth:0,isGlob:!1},Fe=()=>h>=o,g=()=>p.charCodeAt(h+1),Ee=()=>(ye=ae,p.charCodeAt(++h));for(;h<o;){ae=Ee();let we;if(ae===xI){z=Ie.backslashes=!0,ae=Ee(),ae===NN&&(U=!0);continue}if(U===!0||ae===NN){for(Ae++;Fe()!==!0&&(ae=Ee());){if(ae===xI){z=Ie.backslashes=!0,Ee();continue}if(ae===NN){Ae++;continue}if(U!==!0&&ae===RN&&(ae=Ee())===RN){if(v=Ie.isBrace=!0,E=Ie.isGlob=!0,he=!0,a===!0)continue;break}if(U!==!0&&ae===K7e){if(v=Ie.isBrace=!0,E=Ie.isGlob=!0,he=!0,a===!0)continue;break}if(ae===J7e&&(Ae--,Ae===0)){U=!1,v=Ie.isBrace=!0,he=!0;break}}if(a===!0)continue;break}if(ae===DZ){if(n.push(h),u.push(Ie),Ie={value:\"\",depth:0,isGlob:!1},he===!0)continue;if(ye===RN&&h===C+1){C+=2;continue}I=h+1;continue}if(r.noext!==!0&&(ae===z7e||ae===W7e||ae===FN||ae===wZ||ae===TN)===!0&&g()===LN){if(E=Ie.isGlob=!0,R=Ie.isExtglob=!0,he=!0,ae===TN&&h===C&&(le=!0),a===!0){for(;Fe()!==!0&&(ae=Ee());){if(ae===xI){z=Ie.backslashes=!0,ae=Ee();continue}if(ae===IZ){E=Ie.isGlob=!0,he=!0;break}}continue}break}if(ae===FN){if(ye===FN&&(L=Ie.isGlobstar=!0),E=Ie.isGlob=!0,he=!0,a===!0)continue;break}if(ae===wZ){if(E=Ie.isGlob=!0,he=!0,a===!0)continue;break}if(ae===V7e){for(;Fe()!==!0&&(we=Ee());){if(we===xI){z=Ie.backslashes=!0,Ee();continue}if(we===X7e){x=Ie.isBracket=!0,E=Ie.isGlob=!0,he=!0;break}}if(a===!0)continue;break}if(r.nonegate!==!0&&ae===TN&&h===C){te=Ie.negated=!0,C++;continue}if(r.noparen!==!0&&ae===LN){if(E=Ie.isGlob=!0,a===!0){for(;Fe()!==!0&&(ae=Ee());){if(ae===LN){z=Ie.backslashes=!0,ae=Ee();continue}if(ae===IZ){he=!0;break}}continue}break}if(E===!0){if(he=!0,a===!0)continue;break}}r.noext===!0&&(R=!1,E=!1);let De=p,ce=\"\",ne=\"\";C>0&&(ce=p.slice(0,C),p=p.slice(C),I-=C),De&&E===!0&&I>0?(De=p.slice(0,I),ne=p.slice(I)):E===!0?(De=\"\",ne=p):De=p,De&&De!==\"\"&&De!==\"/\"&&De!==p&&BZ(De.charCodeAt(De.length-1))&&(De=De.slice(0,-1)),r.unescape===!0&&(ne&&(ne=CZ.removeBackslashes(ne)),De&&z===!0&&(De=CZ.removeBackslashes(De)));let ee={prefix:ce,input:t,start:C,base:De,glob:ne,isBrace:v,isBracket:x,isGlob:E,isExtglob:R,isGlobstar:L,negated:te,negatedExtglob:le};if(r.tokens===!0&&(ee.maxDepth=0,BZ(ae)||u.push(Ie),ee.tokens=u),r.parts===!0||r.tokens===!0){let we;for(let xe=0;xe<n.length;xe++){let ht=we?we+1:C,H=n[xe],lt=t.slice(ht,H);r.tokens&&(xe===0&&C!==0?(u[xe].isPrefix=!0,u[xe].value=ce):u[xe].value=lt,vZ(u[xe]),ee.maxDepth+=u[xe].depth),(xe!==0||lt!==\"\")&&A.push(lt),we=H}if(we&&we+1<t.length){let xe=t.slice(we+1);A.push(xe),r.tokens&&(u[u.length-1].value=xe,vZ(u[u.length-1]),ee.maxDepth+=u[u.length-1].depth)}ee.slashes=n,ee.parts=A}return ee};PZ.exports=Z7e});var kZ=_((VQt,xZ)=>{\"use strict\";var NP=SI(),nl=bI(),{MAX_LENGTH:LP,POSIX_REGEX_SOURCE:$7e,REGEX_NON_SPECIAL_CHARS:eYe,REGEX_SPECIAL_CHARS_BACKREF:tYe,REPLACEMENTS:bZ}=NP,rYe=(t,e)=>{if(typeof e.expandRange==\"function\")return e.expandRange(...t,e);t.sort();let r=`[${t.join(\"-\")}]`;try{new RegExp(r)}catch{return t.map(a=>nl.escapeRegex(a)).join(\"..\")}return r},Fy=(t,e)=>`Missing ${t}: \"${e}\" - use \"\\\\\\\\${e}\" to match literal characters`,ON=(t,e)=>{if(typeof t!=\"string\")throw new TypeError(\"Expected a string\");t=bZ[t]||t;let r={...e},o=typeof r.maxLength==\"number\"?Math.min(LP,r.maxLength):LP,a=t.length;if(a>o)throw new SyntaxError(`Input length: ${a}, exceeds maximum allowed length: ${o}`);let n={type:\"bos\",value:\"\",output:r.prepend||\"\"},u=[n],A=r.capture?\"\":\"?:\",p=nl.isWindows(e),h=NP.globChars(p),C=NP.extglobChars(h),{DOT_LITERAL:I,PLUS_LITERAL:v,SLASH_LITERAL:x,ONE_CHAR:E,DOTS_SLASH:R,NO_DOT:L,NO_DOT_SLASH:U,NO_DOTS_SLASH:z,QMARK:te,QMARK_NO_DOT:le,STAR:he,START_ANCHOR:Ae}=h,ye=b=>`(${A}(?:(?!${Ae}${b.dot?R:I}).)*?)`,ae=r.dot?\"\":L,Ie=r.dot?te:le,Fe=r.bash===!0?ye(r):he;r.capture&&(Fe=`(${Fe})`),typeof r.noext==\"boolean\"&&(r.noextglob=r.noext);let g={input:t,index:-1,start:0,dot:r.dot===!0,consumed:\"\",output:\"\",prefix:\"\",backtrack:!1,negated:!1,brackets:0,braces:0,parens:0,quotes:0,globstar:!1,tokens:u};t=nl.removePrefix(t,g),a=t.length;let Ee=[],De=[],ce=[],ne=n,ee,we=()=>g.index===a-1,xe=g.peek=(b=1)=>t[g.index+b],ht=g.advance=()=>t[++g.index]||\"\",H=()=>t.slice(g.index+1),lt=(b=\"\",w=0)=>{g.consumed+=b,g.index+=w},Te=b=>{g.output+=b.output!=null?b.output:b.value,lt(b.value)},ke=()=>{let b=1;for(;xe()===\"!\"&&(xe(2)!==\"(\"||xe(3)===\"?\");)ht(),g.start++,b++;return b%2===0?!1:(g.negated=!0,g.start++,!0)},be=b=>{g[b]++,ce.push(b)},_e=b=>{g[b]--,ce.pop()},Re=b=>{if(ne.type===\"globstar\"){let w=g.braces>0&&(b.type===\"comma\"||b.type===\"brace\"),S=b.extglob===!0||Ee.length&&(b.type===\"pipe\"||b.type===\"paren\");b.type!==\"slash\"&&b.type!==\"paren\"&&!w&&!S&&(g.output=g.output.slice(0,-ne.output.length),ne.type=\"star\",ne.value=\"*\",ne.output=Fe,g.output+=ne.output)}if(Ee.length&&b.type!==\"paren\"&&(Ee[Ee.length-1].inner+=b.value),(b.value||b.output)&&Te(b),ne&&ne.type===\"text\"&&b.type===\"text\"){ne.value+=b.value,ne.output=(ne.output||\"\")+b.value;return}b.prev=ne,u.push(b),ne=b},ze=(b,w)=>{let S={...C[w],conditions:1,inner:\"\"};S.prev=ne,S.parens=g.parens,S.output=g.output;let y=(r.capture?\"(\":\"\")+S.open;be(\"parens\"),Re({type:b,value:w,output:g.output?\"\":E}),Re({type:\"paren\",extglob:!0,value:ht(),output:y}),Ee.push(S)},He=b=>{let w=b.close+(r.capture?\")\":\"\"),S;if(b.type===\"negate\"){let y=Fe;if(b.inner&&b.inner.length>1&&b.inner.includes(\"/\")&&(y=ye(r)),(y!==Fe||we()||/^\\)+$/.test(H()))&&(w=b.close=`)$))${y}`),b.inner.includes(\"*\")&&(S=H())&&/^\\.[^\\\\/.]+$/.test(S)){let F=ON(S,{...e,fastpaths:!1}).output;w=b.close=`)${F})${y})`}b.prev.type===\"bos\"&&(g.negatedExtglob=!0)}Re({type:\"paren\",extglob:!0,value:ee,output:w}),_e(\"parens\")};if(r.fastpaths!==!1&&!/(^[*!]|[/()[\\]{}\"])/.test(t)){let b=!1,w=t.replace(tYe,(S,y,F,J,X,Z)=>J===\"\\\\\"?(b=!0,S):J===\"?\"?y?y+J+(X?te.repeat(X.length):\"\"):Z===0?Ie+(X?te.repeat(X.length):\"\"):te.repeat(F.length):J===\".\"?I.repeat(F.length):J===\"*\"?y?y+J+(X?Fe:\"\"):Fe:y?S:`\\\\${S}`);return b===!0&&(r.unescape===!0?w=w.replace(/\\\\/g,\"\"):w=w.replace(/\\\\+/g,S=>S.length%2===0?\"\\\\\\\\\":S?\"\\\\\":\"\")),w===t&&r.contains===!0?(g.output=t,g):(g.output=nl.wrapOutput(w,g,e),g)}for(;!we();){if(ee=ht(),ee===\"\\0\")continue;if(ee===\"\\\\\"){let S=xe();if(S===\"/\"&&r.bash!==!0||S===\".\"||S===\";\")continue;if(!S){ee+=\"\\\\\",Re({type:\"text\",value:ee});continue}let y=/^\\\\+/.exec(H()),F=0;if(y&&y[0].length>2&&(F=y[0].length,g.index+=F,F%2!==0&&(ee+=\"\\\\\")),r.unescape===!0?ee=ht():ee+=ht(),g.brackets===0){Re({type:\"text\",value:ee});continue}}if(g.brackets>0&&(ee!==\"]\"||ne.value===\"[\"||ne.value===\"[^\")){if(r.posix!==!1&&ee===\":\"){let S=ne.value.slice(1);if(S.includes(\"[\")&&(ne.posix=!0,S.includes(\":\"))){let y=ne.value.lastIndexOf(\"[\"),F=ne.value.slice(0,y),J=ne.value.slice(y+2),X=$7e[J];if(X){ne.value=F+X,g.backtrack=!0,ht(),!n.output&&u.indexOf(ne)===1&&(n.output=E);continue}}}(ee===\"[\"&&xe()!==\":\"||ee===\"-\"&&xe()===\"]\")&&(ee=`\\\\${ee}`),ee===\"]\"&&(ne.value===\"[\"||ne.value===\"[^\")&&(ee=`\\\\${ee}`),r.posix===!0&&ee===\"!\"&&ne.value===\"[\"&&(ee=\"^\"),ne.value+=ee,Te({value:ee});continue}if(g.quotes===1&&ee!=='\"'){ee=nl.escapeRegex(ee),ne.value+=ee,Te({value:ee});continue}if(ee==='\"'){g.quotes=g.quotes===1?0:1,r.keepQuotes===!0&&Re({type:\"text\",value:ee});continue}if(ee===\"(\"){be(\"parens\"),Re({type:\"paren\",value:ee});continue}if(ee===\")\"){if(g.parens===0&&r.strictBrackets===!0)throw new SyntaxError(Fy(\"opening\",\"(\"));let S=Ee[Ee.length-1];if(S&&g.parens===S.parens+1){He(Ee.pop());continue}Re({type:\"paren\",value:ee,output:g.parens?\")\":\"\\\\)\"}),_e(\"parens\");continue}if(ee===\"[\"){if(r.nobracket===!0||!H().includes(\"]\")){if(r.nobracket!==!0&&r.strictBrackets===!0)throw new SyntaxError(Fy(\"closing\",\"]\"));ee=`\\\\${ee}`}else be(\"brackets\");Re({type:\"bracket\",value:ee});continue}if(ee===\"]\"){if(r.nobracket===!0||ne&&ne.type===\"bracket\"&&ne.value.length===1){Re({type:\"text\",value:ee,output:`\\\\${ee}`});continue}if(g.brackets===0){if(r.strictBrackets===!0)throw new SyntaxError(Fy(\"opening\",\"[\"));Re({type:\"text\",value:ee,output:`\\\\${ee}`});continue}_e(\"brackets\");let S=ne.value.slice(1);if(ne.posix!==!0&&S[0]===\"^\"&&!S.includes(\"/\")&&(ee=`/${ee}`),ne.value+=ee,Te({value:ee}),r.literalBrackets===!1||nl.hasRegexChars(S))continue;let y=nl.escapeRegex(ne.value);if(g.output=g.output.slice(0,-ne.value.length),r.literalBrackets===!0){g.output+=y,ne.value=y;continue}ne.value=`(${A}${y}|${ne.value})`,g.output+=ne.value;continue}if(ee===\"{\"&&r.nobrace!==!0){be(\"braces\");let S={type:\"brace\",value:ee,output:\"(\",outputIndex:g.output.length,tokensIndex:g.tokens.length};De.push(S),Re(S);continue}if(ee===\"}\"){let S=De[De.length-1];if(r.nobrace===!0||!S){Re({type:\"text\",value:ee,output:ee});continue}let y=\")\";if(S.dots===!0){let F=u.slice(),J=[];for(let X=F.length-1;X>=0&&(u.pop(),F[X].type!==\"brace\");X--)F[X].type!==\"dots\"&&J.unshift(F[X].value);y=rYe(J,r),g.backtrack=!0}if(S.comma!==!0&&S.dots!==!0){let F=g.output.slice(0,S.outputIndex),J=g.tokens.slice(S.tokensIndex);S.value=S.output=\"\\\\{\",ee=y=\"\\\\}\",g.output=F;for(let X of J)g.output+=X.output||X.value}Re({type:\"brace\",value:ee,output:y}),_e(\"braces\"),De.pop();continue}if(ee===\"|\"){Ee.length>0&&Ee[Ee.length-1].conditions++,Re({type:\"text\",value:ee});continue}if(ee===\",\"){let S=ee,y=De[De.length-1];y&&ce[ce.length-1]===\"braces\"&&(y.comma=!0,S=\"|\"),Re({type:\"comma\",value:ee,output:S});continue}if(ee===\"/\"){if(ne.type===\"dot\"&&g.index===g.start+1){g.start=g.index+1,g.consumed=\"\",g.output=\"\",u.pop(),ne=n;continue}Re({type:\"slash\",value:ee,output:x});continue}if(ee===\".\"){if(g.braces>0&&ne.type===\"dot\"){ne.value===\".\"&&(ne.output=I);let S=De[De.length-1];ne.type=\"dots\",ne.output+=ee,ne.value+=ee,S.dots=!0;continue}if(g.braces+g.parens===0&&ne.type!==\"bos\"&&ne.type!==\"slash\"){Re({type:\"text\",value:ee,output:I});continue}Re({type:\"dot\",value:ee,output:I});continue}if(ee===\"?\"){if(!(ne&&ne.value===\"(\")&&r.noextglob!==!0&&xe()===\"(\"&&xe(2)!==\"?\"){ze(\"qmark\",ee);continue}if(ne&&ne.type===\"paren\"){let y=xe(),F=ee;if(y===\"<\"&&!nl.supportsLookbehinds())throw new Error(\"Node.js v10 or higher is required for regex lookbehinds\");(ne.value===\"(\"&&!/[!=<:]/.test(y)||y===\"<\"&&!/<([!=]|\\w+>)/.test(H()))&&(F=`\\\\${ee}`),Re({type:\"text\",value:ee,output:F});continue}if(r.dot!==!0&&(ne.type===\"slash\"||ne.type===\"bos\")){Re({type:\"qmark\",value:ee,output:le});continue}Re({type:\"qmark\",value:ee,output:te});continue}if(ee===\"!\"){if(r.noextglob!==!0&&xe()===\"(\"&&(xe(2)!==\"?\"||!/[!=<:]/.test(xe(3)))){ze(\"negate\",ee);continue}if(r.nonegate!==!0&&g.index===0){ke();continue}}if(ee===\"+\"){if(r.noextglob!==!0&&xe()===\"(\"&&xe(2)!==\"?\"){ze(\"plus\",ee);continue}if(ne&&ne.value===\"(\"||r.regex===!1){Re({type:\"plus\",value:ee,output:v});continue}if(ne&&(ne.type===\"bracket\"||ne.type===\"paren\"||ne.type===\"brace\")||g.parens>0){Re({type:\"plus\",value:ee});continue}Re({type:\"plus\",value:v});continue}if(ee===\"@\"){if(r.noextglob!==!0&&xe()===\"(\"&&xe(2)!==\"?\"){Re({type:\"at\",extglob:!0,value:ee,output:\"\"});continue}Re({type:\"text\",value:ee});continue}if(ee!==\"*\"){(ee===\"$\"||ee===\"^\")&&(ee=`\\\\${ee}`);let S=eYe.exec(H());S&&(ee+=S[0],g.index+=S[0].length),Re({type:\"text\",value:ee});continue}if(ne&&(ne.type===\"globstar\"||ne.star===!0)){ne.type=\"star\",ne.star=!0,ne.value+=ee,ne.output=Fe,g.backtrack=!0,g.globstar=!0,lt(ee);continue}let b=H();if(r.noextglob!==!0&&/^\\([^?]/.test(b)){ze(\"star\",ee);continue}if(ne.type===\"star\"){if(r.noglobstar===!0){lt(ee);continue}let S=ne.prev,y=S.prev,F=S.type===\"slash\"||S.type===\"bos\",J=y&&(y.type===\"star\"||y.type===\"globstar\");if(r.bash===!0&&(!F||b[0]&&b[0]!==\"/\")){Re({type:\"star\",value:ee,output:\"\"});continue}let X=g.braces>0&&(S.type===\"comma\"||S.type===\"brace\"),Z=Ee.length&&(S.type===\"pipe\"||S.type===\"paren\");if(!F&&S.type!==\"paren\"&&!X&&!Z){Re({type:\"star\",value:ee,output:\"\"});continue}for(;b.slice(0,3)===\"/**\";){let ie=t[g.index+4];if(ie&&ie!==\"/\")break;b=b.slice(3),lt(\"/**\",3)}if(S.type===\"bos\"&&we()){ne.type=\"globstar\",ne.value+=ee,ne.output=ye(r),g.output=ne.output,g.globstar=!0,lt(ee);continue}if(S.type===\"slash\"&&S.prev.type!==\"bos\"&&!J&&we()){g.output=g.output.slice(0,-(S.output+ne.output).length),S.output=`(?:${S.output}`,ne.type=\"globstar\",ne.output=ye(r)+(r.strictSlashes?\")\":\"|$)\"),ne.value+=ee,g.globstar=!0,g.output+=S.output+ne.output,lt(ee);continue}if(S.type===\"slash\"&&S.prev.type!==\"bos\"&&b[0]===\"/\"){let ie=b[1]!==void 0?\"|$\":\"\";g.output=g.output.slice(0,-(S.output+ne.output).length),S.output=`(?:${S.output}`,ne.type=\"globstar\",ne.output=`${ye(r)}${x}|${x}${ie})`,ne.value+=ee,g.output+=S.output+ne.output,g.globstar=!0,lt(ee+ht()),Re({type:\"slash\",value:\"/\",output:\"\"});continue}if(S.type===\"bos\"&&b[0]===\"/\"){ne.type=\"globstar\",ne.value+=ee,ne.output=`(?:^|${x}|${ye(r)}${x})`,g.output=ne.output,g.globstar=!0,lt(ee+ht()),Re({type:\"slash\",value:\"/\",output:\"\"});continue}g.output=g.output.slice(0,-ne.output.length),ne.type=\"globstar\",ne.output=ye(r),ne.value+=ee,g.output+=ne.output,g.globstar=!0,lt(ee);continue}let w={type:\"star\",value:ee,output:Fe};if(r.bash===!0){w.output=\".*?\",(ne.type===\"bos\"||ne.type===\"slash\")&&(w.output=ae+w.output),Re(w);continue}if(ne&&(ne.type===\"bracket\"||ne.type===\"paren\")&&r.regex===!0){w.output=ee,Re(w);continue}(g.index===g.start||ne.type===\"slash\"||ne.type===\"dot\")&&(ne.type===\"dot\"?(g.output+=U,ne.output+=U):r.dot===!0?(g.output+=z,ne.output+=z):(g.output+=ae,ne.output+=ae),xe()!==\"*\"&&(g.output+=E,ne.output+=E)),Re(w)}for(;g.brackets>0;){if(r.strictBrackets===!0)throw new SyntaxError(Fy(\"closing\",\"]\"));g.output=nl.escapeLast(g.output,\"[\"),_e(\"brackets\")}for(;g.parens>0;){if(r.strictBrackets===!0)throw new SyntaxError(Fy(\"closing\",\")\"));g.output=nl.escapeLast(g.output,\"(\"),_e(\"parens\")}for(;g.braces>0;){if(r.strictBrackets===!0)throw new SyntaxError(Fy(\"closing\",\"}\"));g.output=nl.escapeLast(g.output,\"{\"),_e(\"braces\")}if(r.strictSlashes!==!0&&(ne.type===\"star\"||ne.type===\"bracket\")&&Re({type:\"maybe_slash\",value:\"\",output:`${x}?`}),g.backtrack===!0){g.output=\"\";for(let b of g.tokens)g.output+=b.output!=null?b.output:b.value,b.suffix&&(g.output+=b.suffix)}return g};ON.fastpaths=(t,e)=>{let r={...e},o=typeof r.maxLength==\"number\"?Math.min(LP,r.maxLength):LP,a=t.length;if(a>o)throw new SyntaxError(`Input length: ${a}, exceeds maximum allowed length: ${o}`);t=bZ[t]||t;let n=nl.isWindows(e),{DOT_LITERAL:u,SLASH_LITERAL:A,ONE_CHAR:p,DOTS_SLASH:h,NO_DOT:C,NO_DOTS:I,NO_DOTS_SLASH:v,STAR:x,START_ANCHOR:E}=NP.globChars(n),R=r.dot?I:C,L=r.dot?v:C,U=r.capture?\"\":\"?:\",z={negated:!1,prefix:\"\"},te=r.bash===!0?\".*?\":x;r.capture&&(te=`(${te})`);let le=ae=>ae.noglobstar===!0?te:`(${U}(?:(?!${E}${ae.dot?h:u}).)*?)`,he=ae=>{switch(ae){case\"*\":return`${R}${p}${te}`;case\".*\":return`${u}${p}${te}`;case\"*.*\":return`${R}${te}${u}${p}${te}`;case\"*/*\":return`${R}${te}${A}${p}${L}${te}`;case\"**\":return R+le(r);case\"**/*\":return`(?:${R}${le(r)}${A})?${L}${p}${te}`;case\"**/*.*\":return`(?:${R}${le(r)}${A})?${L}${te}${u}${p}${te}`;case\"**/.*\":return`(?:${R}${le(r)}${A})?${u}${p}${te}`;default:{let Ie=/^(.*?)\\.(\\w+)$/.exec(ae);if(!Ie)return;let Fe=he(Ie[1]);return Fe?Fe+u+Ie[2]:void 0}}},Ae=nl.removePrefix(t,z),ye=he(Ae);return ye&&r.strictSlashes!==!0&&(ye+=`${A}?`),ye};xZ.exports=ON});var FZ=_((zQt,QZ)=>{\"use strict\";var nYe=Be(\"path\"),iYe=SZ(),MN=kZ(),UN=bI(),sYe=SI(),oYe=t=>t&&typeof t==\"object\"&&!Array.isArray(t),Mi=(t,e,r=!1)=>{if(Array.isArray(t)){let C=t.map(v=>Mi(v,e,r));return v=>{for(let x of C){let E=x(v);if(E)return E}return!1}}let o=oYe(t)&&t.tokens&&t.input;if(t===\"\"||typeof t!=\"string\"&&!o)throw new TypeError(\"Expected pattern to be a non-empty string\");let a=e||{},n=UN.isWindows(e),u=o?Mi.compileRe(t,e):Mi.makeRe(t,e,!1,!0),A=u.state;delete u.state;let p=()=>!1;if(a.ignore){let C={...e,ignore:null,onMatch:null,onResult:null};p=Mi(a.ignore,C,r)}let h=(C,I=!1)=>{let{isMatch:v,match:x,output:E}=Mi.test(C,u,e,{glob:t,posix:n}),R={glob:t,state:A,regex:u,posix:n,input:C,output:E,match:x,isMatch:v};return typeof a.onResult==\"function\"&&a.onResult(R),v===!1?(R.isMatch=!1,I?R:!1):p(C)?(typeof a.onIgnore==\"function\"&&a.onIgnore(R),R.isMatch=!1,I?R:!1):(typeof a.onMatch==\"function\"&&a.onMatch(R),I?R:!0)};return r&&(h.state=A),h};Mi.test=(t,e,r,{glob:o,posix:a}={})=>{if(typeof t!=\"string\")throw new TypeError(\"Expected input to be a string\");if(t===\"\")return{isMatch:!1,output:\"\"};let n=r||{},u=n.format||(a?UN.toPosixSlashes:null),A=t===o,p=A&&u?u(t):t;return A===!1&&(p=u?u(t):t,A=p===o),(A===!1||n.capture===!0)&&(n.matchBase===!0||n.basename===!0?A=Mi.matchBase(t,e,r,a):A=e.exec(p)),{isMatch:Boolean(A),match:A,output:p}};Mi.matchBase=(t,e,r,o=UN.isWindows(r))=>(e instanceof RegExp?e:Mi.makeRe(e,r)).test(nYe.basename(t));Mi.isMatch=(t,e,r)=>Mi(e,r)(t);Mi.parse=(t,e)=>Array.isArray(t)?t.map(r=>Mi.parse(r,e)):MN(t,{...e,fastpaths:!1});Mi.scan=(t,e)=>iYe(t,e);Mi.compileRe=(t,e,r=!1,o=!1)=>{if(r===!0)return t.output;let a=e||{},n=a.contains?\"\":\"^\",u=a.contains?\"\":\"$\",A=`${n}(?:${t.output})${u}`;t&&t.negated===!0&&(A=`^(?!${A}).*$`);let p=Mi.toRegex(A,e);return o===!0&&(p.state=t),p};Mi.makeRe=(t,e={},r=!1,o=!1)=>{if(!t||typeof t!=\"string\")throw new TypeError(\"Expected a non-empty string\");let a={negated:!1,fastpaths:!0};return e.fastpaths!==!1&&(t[0]===\".\"||t[0]===\"*\")&&(a.output=MN.fastpaths(t,e)),a.output||(a=MN(t,e)),Mi.compileRe(a,e,r,o)};Mi.toRegex=(t,e)=>{try{let r=e||{};return new RegExp(t,r.flags||(r.nocase?\"i\":\"\"))}catch(r){if(e&&e.debug===!0)throw r;return/$^/}};Mi.constants=sYe;QZ.exports=Mi});var TZ=_((JQt,RZ)=>{\"use strict\";RZ.exports=FZ()});var Zo=_((XQt,MZ)=>{\"use strict\";var LZ=Be(\"util\"),OZ=hZ(),Vu=TZ(),_N=bI(),NZ=t=>t===\"\"||t===\"./\",yi=(t,e,r)=>{e=[].concat(e),t=[].concat(t);let o=new Set,a=new Set,n=new Set,u=0,A=C=>{n.add(C.output),r&&r.onResult&&r.onResult(C)};for(let C=0;C<e.length;C++){let I=Vu(String(e[C]),{...r,onResult:A},!0),v=I.state.negated||I.state.negatedExtglob;v&&u++;for(let x of t){let E=I(x,!0);!(v?!E.isMatch:E.isMatch)||(v?o.add(E.output):(o.delete(E.output),a.add(E.output)))}}let h=(u===e.length?[...n]:[...a]).filter(C=>!o.has(C));if(r&&h.length===0){if(r.failglob===!0)throw new Error(`No matches found for \"${e.join(\", \")}\"`);if(r.nonull===!0||r.nullglob===!0)return r.unescape?e.map(C=>C.replace(/\\\\/g,\"\")):e}return h};yi.match=yi;yi.matcher=(t,e)=>Vu(t,e);yi.isMatch=(t,e,r)=>Vu(e,r)(t);yi.any=yi.isMatch;yi.not=(t,e,r={})=>{e=[].concat(e).map(String);let o=new Set,a=[],n=A=>{r.onResult&&r.onResult(A),a.push(A.output)},u=new Set(yi(t,e,{...r,onResult:n}));for(let A of a)u.has(A)||o.add(A);return[...o]};yi.contains=(t,e,r)=>{if(typeof t!=\"string\")throw new TypeError(`Expected a string: \"${LZ.inspect(t)}\"`);if(Array.isArray(e))return e.some(o=>yi.contains(t,o,r));if(typeof e==\"string\"){if(NZ(t)||NZ(e))return!1;if(t.includes(e)||t.startsWith(\"./\")&&t.slice(2).includes(e))return!0}return yi.isMatch(t,e,{...r,contains:!0})};yi.matchKeys=(t,e,r)=>{if(!_N.isObject(t))throw new TypeError(\"Expected the first argument to be an object\");let o=yi(Object.keys(t),e,r),a={};for(let n of o)a[n]=t[n];return a};yi.some=(t,e,r)=>{let o=[].concat(t);for(let a of[].concat(e)){let n=Vu(String(a),r);if(o.some(u=>n(u)))return!0}return!1};yi.every=(t,e,r)=>{let o=[].concat(t);for(let a of[].concat(e)){let n=Vu(String(a),r);if(!o.every(u=>n(u)))return!1}return!0};yi.all=(t,e,r)=>{if(typeof t!=\"string\")throw new TypeError(`Expected a string: \"${LZ.inspect(t)}\"`);return[].concat(e).every(o=>Vu(o,r)(t))};yi.capture=(t,e,r)=>{let o=_N.isWindows(r),n=Vu.makeRe(String(t),{...r,capture:!0}).exec(o?_N.toPosixSlashes(e):e);if(n)return n.slice(1).map(u=>u===void 0?\"\":u)};yi.makeRe=(...t)=>Vu.makeRe(...t);yi.scan=(...t)=>Vu.scan(...t);yi.parse=(t,e)=>{let r=[];for(let o of[].concat(t||[]))for(let a of OZ(String(o),e))r.push(Vu.parse(a,e));return r};yi.braces=(t,e)=>{if(typeof t!=\"string\")throw new TypeError(\"Expected a string\");return e&&e.nobrace===!0||!/\\{.*\\}/.test(t)?[t]:OZ(t,e)};yi.braceExpand=(t,e)=>{if(typeof t!=\"string\")throw new TypeError(\"Expected a string\");return yi.braces(t,{...e,expand:!0})};MZ.exports=yi});var _Z=_((ZQt,UZ)=>{\"use strict\";UZ.exports=({onlyFirst:t=!1}={})=>{let e=[\"[\\\\u001B\\\\u009B][[\\\\]()#;?]*(?:(?:(?:(?:;[-a-zA-Z\\\\d\\\\/#&.:=?%@~_]+)*|[a-zA-Z\\\\d]+(?:;[-a-zA-Z\\\\d\\\\/#&.:=?%@~_]*)*)?\\\\u0007)\",\"(?:(?:\\\\d{1,4}(?:;\\\\d{0,4})*)?[\\\\dA-PR-TZcf-ntqry=><~]))\"].join(\"|\");return new RegExp(e,t?void 0:\"g\")}});var OP=_(($Qt,HZ)=>{\"use strict\";var aYe=_Z();HZ.exports=t=>typeof t==\"string\"?t.replace(aYe(),\"\"):t});var qZ=_((eFt,jZ)=>{function lYe(){this.__data__=[],this.size=0}jZ.exports=lYe});var Ry=_((tFt,GZ)=>{function cYe(t,e){return t===e||t!==t&&e!==e}GZ.exports=cYe});var kI=_((rFt,YZ)=>{var uYe=Ry();function AYe(t,e){for(var r=t.length;r--;)if(uYe(t[r][0],e))return r;return-1}YZ.exports=AYe});var KZ=_((nFt,WZ)=>{var fYe=kI(),pYe=Array.prototype,hYe=pYe.splice;function gYe(t){var e=this.__data__,r=fYe(e,t);if(r<0)return!1;var o=e.length-1;return r==o?e.pop():hYe.call(e,r,1),--this.size,!0}WZ.exports=gYe});var zZ=_((iFt,VZ)=>{var dYe=kI();function mYe(t){var e=this.__data__,r=dYe(e,t);return r<0?void 0:e[r][1]}VZ.exports=mYe});var XZ=_((sFt,JZ)=>{var yYe=kI();function EYe(t){return yYe(this.__data__,t)>-1}JZ.exports=EYe});var $Z=_((oFt,ZZ)=>{var CYe=kI();function wYe(t,e){var r=this.__data__,o=CYe(r,t);return o<0?(++this.size,r.push([t,e])):r[o][1]=e,this}ZZ.exports=wYe});var QI=_((aFt,e$)=>{var IYe=qZ(),BYe=KZ(),vYe=zZ(),DYe=XZ(),PYe=$Z();function Ty(t){var e=-1,r=t==null?0:t.length;for(this.clear();++e<r;){var o=t[e];this.set(o[0],o[1])}}Ty.prototype.clear=IYe;Ty.prototype.delete=BYe;Ty.prototype.get=vYe;Ty.prototype.has=DYe;Ty.prototype.set=PYe;e$.exports=Ty});var r$=_((lFt,t$)=>{var SYe=QI();function bYe(){this.__data__=new SYe,this.size=0}t$.exports=bYe});var i$=_((cFt,n$)=>{function xYe(t){var e=this.__data__,r=e.delete(t);return this.size=e.size,r}n$.exports=xYe});var o$=_((uFt,s$)=>{function kYe(t){return this.__data__.get(t)}s$.exports=kYe});var l$=_((AFt,a$)=>{function QYe(t){return this.__data__.has(t)}a$.exports=QYe});var HN=_((fFt,c$)=>{var FYe=typeof global==\"object\"&&global&&global.Object===Object&&global;c$.exports=FYe});var _l=_((pFt,u$)=>{var RYe=HN(),TYe=typeof self==\"object\"&&self&&self.Object===Object&&self,NYe=RYe||TYe||Function(\"return this\")();u$.exports=NYe});var Ad=_((hFt,A$)=>{var LYe=_l(),OYe=LYe.Symbol;A$.exports=OYe});var g$=_((gFt,h$)=>{var f$=Ad(),p$=Object.prototype,MYe=p$.hasOwnProperty,UYe=p$.toString,FI=f$?f$.toStringTag:void 0;function _Ye(t){var e=MYe.call(t,FI),r=t[FI];try{t[FI]=void 0;var o=!0}catch{}var a=UYe.call(t);return o&&(e?t[FI]=r:delete t[FI]),a}h$.exports=_Ye});var m$=_((dFt,d$)=>{var HYe=Object.prototype,jYe=HYe.toString;function qYe(t){return jYe.call(t)}d$.exports=qYe});var fd=_((mFt,C$)=>{var y$=Ad(),GYe=g$(),YYe=m$(),WYe=\"[object Null]\",KYe=\"[object Undefined]\",E$=y$?y$.toStringTag:void 0;function VYe(t){return t==null?t===void 0?KYe:WYe:E$&&E$ in Object(t)?GYe(t):YYe(t)}C$.exports=VYe});var il=_((yFt,w$)=>{function zYe(t){var e=typeof t;return t!=null&&(e==\"object\"||e==\"function\")}w$.exports=zYe});var MP=_((EFt,I$)=>{var JYe=fd(),XYe=il(),ZYe=\"[object AsyncFunction]\",$Ye=\"[object Function]\",eWe=\"[object GeneratorFunction]\",tWe=\"[object Proxy]\";function rWe(t){if(!XYe(t))return!1;var e=JYe(t);return e==$Ye||e==eWe||e==ZYe||e==tWe}I$.exports=rWe});var v$=_((CFt,B$)=>{var nWe=_l(),iWe=nWe[\"__core-js_shared__\"];B$.exports=iWe});var S$=_((wFt,P$)=>{var jN=v$(),D$=function(){var t=/[^.]+$/.exec(jN&&jN.keys&&jN.keys.IE_PROTO||\"\");return t?\"Symbol(src)_1.\"+t:\"\"}();function sWe(t){return!!D$&&D$ in t}P$.exports=sWe});var qN=_((IFt,b$)=>{var oWe=Function.prototype,aWe=oWe.toString;function lWe(t){if(t!=null){try{return aWe.call(t)}catch{}try{return t+\"\"}catch{}}return\"\"}b$.exports=lWe});var k$=_((BFt,x$)=>{var cWe=MP(),uWe=S$(),AWe=il(),fWe=qN(),pWe=/[\\\\^$.*+?()[\\]{}|]/g,hWe=/^\\[object .+?Constructor\\]$/,gWe=Function.prototype,dWe=Object.prototype,mWe=gWe.toString,yWe=dWe.hasOwnProperty,EWe=RegExp(\"^\"+mWe.call(yWe).replace(pWe,\"\\\\$&\").replace(/hasOwnProperty|(function).*?(?=\\\\\\()| for .+?(?=\\\\\\])/g,\"$1.*?\")+\"$\");function CWe(t){if(!AWe(t)||uWe(t))return!1;var e=cWe(t)?EWe:hWe;return e.test(fWe(t))}x$.exports=CWe});var F$=_((vFt,Q$)=>{function wWe(t,e){return t?.[e]}Q$.exports=wWe});var Vp=_((DFt,R$)=>{var IWe=k$(),BWe=F$();function vWe(t,e){var r=BWe(t,e);return IWe(r)?r:void 0}R$.exports=vWe});var UP=_((PFt,T$)=>{var DWe=Vp(),PWe=_l(),SWe=DWe(PWe,\"Map\");T$.exports=SWe});var RI=_((SFt,N$)=>{var bWe=Vp(),xWe=bWe(Object,\"create\");N$.exports=xWe});var M$=_((bFt,O$)=>{var L$=RI();function kWe(){this.__data__=L$?L$(null):{},this.size=0}O$.exports=kWe});var _$=_((xFt,U$)=>{function QWe(t){var e=this.has(t)&&delete this.__data__[t];return this.size-=e?1:0,e}U$.exports=QWe});var j$=_((kFt,H$)=>{var FWe=RI(),RWe=\"__lodash_hash_undefined__\",TWe=Object.prototype,NWe=TWe.hasOwnProperty;function LWe(t){var e=this.__data__;if(FWe){var r=e[t];return r===RWe?void 0:r}return NWe.call(e,t)?e[t]:void 0}H$.exports=LWe});var G$=_((QFt,q$)=>{var OWe=RI(),MWe=Object.prototype,UWe=MWe.hasOwnProperty;function _We(t){var e=this.__data__;return OWe?e[t]!==void 0:UWe.call(e,t)}q$.exports=_We});var W$=_((FFt,Y$)=>{var HWe=RI(),jWe=\"__lodash_hash_undefined__\";function qWe(t,e){var r=this.__data__;return this.size+=this.has(t)?0:1,r[t]=HWe&&e===void 0?jWe:e,this}Y$.exports=qWe});var V$=_((RFt,K$)=>{var GWe=M$(),YWe=_$(),WWe=j$(),KWe=G$(),VWe=W$();function Ny(t){var e=-1,r=t==null?0:t.length;for(this.clear();++e<r;){var o=t[e];this.set(o[0],o[1])}}Ny.prototype.clear=GWe;Ny.prototype.delete=YWe;Ny.prototype.get=WWe;Ny.prototype.has=KWe;Ny.prototype.set=VWe;K$.exports=Ny});var X$=_((TFt,J$)=>{var z$=V$(),zWe=QI(),JWe=UP();function XWe(){this.size=0,this.__data__={hash:new z$,map:new(JWe||zWe),string:new z$}}J$.exports=XWe});var $$=_((NFt,Z$)=>{function ZWe(t){var e=typeof t;return e==\"string\"||e==\"number\"||e==\"symbol\"||e==\"boolean\"?t!==\"__proto__\":t===null}Z$.exports=ZWe});var TI=_((LFt,eee)=>{var $We=$$();function eKe(t,e){var r=t.__data__;return $We(e)?r[typeof e==\"string\"?\"string\":\"hash\"]:r.map}eee.exports=eKe});var ree=_((OFt,tee)=>{var tKe=TI();function rKe(t){var e=tKe(this,t).delete(t);return this.size-=e?1:0,e}tee.exports=rKe});var iee=_((MFt,nee)=>{var nKe=TI();function iKe(t){return nKe(this,t).get(t)}nee.exports=iKe});var oee=_((UFt,see)=>{var sKe=TI();function oKe(t){return sKe(this,t).has(t)}see.exports=oKe});var lee=_((_Ft,aee)=>{var aKe=TI();function lKe(t,e){var r=aKe(this,t),o=r.size;return r.set(t,e),this.size+=r.size==o?0:1,this}aee.exports=lKe});var _P=_((HFt,cee)=>{var cKe=X$(),uKe=ree(),AKe=iee(),fKe=oee(),pKe=lee();function Ly(t){var e=-1,r=t==null?0:t.length;for(this.clear();++e<r;){var o=t[e];this.set(o[0],o[1])}}Ly.prototype.clear=cKe;Ly.prototype.delete=uKe;Ly.prototype.get=AKe;Ly.prototype.has=fKe;Ly.prototype.set=pKe;cee.exports=Ly});var Aee=_((jFt,uee)=>{var hKe=QI(),gKe=UP(),dKe=_P(),mKe=200;function yKe(t,e){var r=this.__data__;if(r instanceof hKe){var o=r.__data__;if(!gKe||o.length<mKe-1)return o.push([t,e]),this.size=++r.size,this;r=this.__data__=new dKe(o)}return r.set(t,e),this.size=r.size,this}uee.exports=yKe});var HP=_((qFt,fee)=>{var EKe=QI(),CKe=r$(),wKe=i$(),IKe=o$(),BKe=l$(),vKe=Aee();function Oy(t){var e=this.__data__=new EKe(t);this.size=e.size}Oy.prototype.clear=CKe;Oy.prototype.delete=wKe;Oy.prototype.get=IKe;Oy.prototype.has=BKe;Oy.prototype.set=vKe;fee.exports=Oy});var hee=_((GFt,pee)=>{var DKe=\"__lodash_hash_undefined__\";function PKe(t){return this.__data__.set(t,DKe),this}pee.exports=PKe});var dee=_((YFt,gee)=>{function SKe(t){return this.__data__.has(t)}gee.exports=SKe});var yee=_((WFt,mee)=>{var bKe=_P(),xKe=hee(),kKe=dee();function jP(t){var e=-1,r=t==null?0:t.length;for(this.__data__=new bKe;++e<r;)this.add(t[e])}jP.prototype.add=jP.prototype.push=xKe;jP.prototype.has=kKe;mee.exports=jP});var Cee=_((KFt,Eee)=>{function QKe(t,e){for(var r=-1,o=t==null?0:t.length;++r<o;)if(e(t[r],r,t))return!0;return!1}Eee.exports=QKe});var Iee=_((VFt,wee)=>{function FKe(t,e){return t.has(e)}wee.exports=FKe});var GN=_((zFt,Bee)=>{var RKe=yee(),TKe=Cee(),NKe=Iee(),LKe=1,OKe=2;function MKe(t,e,r,o,a,n){var u=r&LKe,A=t.length,p=e.length;if(A!=p&&!(u&&p>A))return!1;var h=n.get(t),C=n.get(e);if(h&&C)return h==e&&C==t;var I=-1,v=!0,x=r&OKe?new RKe:void 0;for(n.set(t,e),n.set(e,t);++I<A;){var E=t[I],R=e[I];if(o)var L=u?o(R,E,I,e,t,n):o(E,R,I,t,e,n);if(L!==void 0){if(L)continue;v=!1;break}if(x){if(!TKe(e,function(U,z){if(!NKe(x,z)&&(E===U||a(E,U,r,o,n)))return x.push(z)})){v=!1;break}}else if(!(E===R||a(E,R,r,o,n))){v=!1;break}}return n.delete(t),n.delete(e),v}Bee.exports=MKe});var YN=_((JFt,vee)=>{var UKe=_l(),_Ke=UKe.Uint8Array;vee.exports=_Ke});var Pee=_((XFt,Dee)=>{function HKe(t){var e=-1,r=Array(t.size);return t.forEach(function(o,a){r[++e]=[a,o]}),r}Dee.exports=HKe});var bee=_((ZFt,See)=>{function jKe(t){var e=-1,r=Array(t.size);return t.forEach(function(o){r[++e]=o}),r}See.exports=jKe});var Ree=_(($Ft,Fee)=>{var xee=Ad(),kee=YN(),qKe=Ry(),GKe=GN(),YKe=Pee(),WKe=bee(),KKe=1,VKe=2,zKe=\"[object Boolean]\",JKe=\"[object Date]\",XKe=\"[object Error]\",ZKe=\"[object Map]\",$Ke=\"[object Number]\",eVe=\"[object RegExp]\",tVe=\"[object Set]\",rVe=\"[object String]\",nVe=\"[object Symbol]\",iVe=\"[object ArrayBuffer]\",sVe=\"[object DataView]\",Qee=xee?xee.prototype:void 0,WN=Qee?Qee.valueOf:void 0;function oVe(t,e,r,o,a,n,u){switch(r){case sVe:if(t.byteLength!=e.byteLength||t.byteOffset!=e.byteOffset)return!1;t=t.buffer,e=e.buffer;case iVe:return!(t.byteLength!=e.byteLength||!n(new kee(t),new kee(e)));case zKe:case JKe:case $Ke:return qKe(+t,+e);case XKe:return t.name==e.name&&t.message==e.message;case eVe:case rVe:return t==e+\"\";case ZKe:var A=YKe;case tVe:var p=o&KKe;if(A||(A=WKe),t.size!=e.size&&!p)return!1;var h=u.get(t);if(h)return h==e;o|=VKe,u.set(t,e);var C=GKe(A(t),A(e),o,a,n,u);return u.delete(t),C;case nVe:if(WN)return WN.call(t)==WN.call(e)}return!1}Fee.exports=oVe});var qP=_((eRt,Tee)=>{function aVe(t,e){for(var r=-1,o=e.length,a=t.length;++r<o;)t[a+r]=e[r];return t}Tee.exports=aVe});var Hl=_((tRt,Nee)=>{var lVe=Array.isArray;Nee.exports=lVe});var KN=_((rRt,Lee)=>{var cVe=qP(),uVe=Hl();function AVe(t,e,r){var o=e(t);return uVe(t)?o:cVe(o,r(t))}Lee.exports=AVe});var Mee=_((nRt,Oee)=>{function fVe(t,e){for(var r=-1,o=t==null?0:t.length,a=0,n=[];++r<o;){var u=t[r];e(u,r,t)&&(n[a++]=u)}return n}Oee.exports=fVe});var VN=_((iRt,Uee)=>{function pVe(){return[]}Uee.exports=pVe});var GP=_((sRt,Hee)=>{var hVe=Mee(),gVe=VN(),dVe=Object.prototype,mVe=dVe.propertyIsEnumerable,_ee=Object.getOwnPropertySymbols,yVe=_ee?function(t){return t==null?[]:(t=Object(t),hVe(_ee(t),function(e){return mVe.call(t,e)}))}:gVe;Hee.exports=yVe});var qee=_((oRt,jee)=>{function EVe(t,e){for(var r=-1,o=Array(t);++r<t;)o[r]=e(r);return o}jee.exports=EVe});var zu=_((aRt,Gee)=>{function CVe(t){return t!=null&&typeof t==\"object\"}Gee.exports=CVe});var Wee=_((lRt,Yee)=>{var wVe=fd(),IVe=zu(),BVe=\"[object Arguments]\";function vVe(t){return IVe(t)&&wVe(t)==BVe}Yee.exports=vVe});var NI=_((cRt,zee)=>{var Kee=Wee(),DVe=zu(),Vee=Object.prototype,PVe=Vee.hasOwnProperty,SVe=Vee.propertyIsEnumerable,bVe=Kee(function(){return arguments}())?Kee:function(t){return DVe(t)&&PVe.call(t,\"callee\")&&!SVe.call(t,\"callee\")};zee.exports=bVe});var Xee=_((uRt,Jee)=>{function xVe(){return!1}Jee.exports=xVe});var OI=_((LI,My)=>{var kVe=_l(),QVe=Xee(),ete=typeof LI==\"object\"&&LI&&!LI.nodeType&&LI,Zee=ete&&typeof My==\"object\"&&My&&!My.nodeType&&My,FVe=Zee&&Zee.exports===ete,$ee=FVe?kVe.Buffer:void 0,RVe=$ee?$ee.isBuffer:void 0,TVe=RVe||QVe;My.exports=TVe});var MI=_((ARt,tte)=>{var NVe=9007199254740991,LVe=/^(?:0|[1-9]\\d*)$/;function OVe(t,e){var r=typeof t;return e=e??NVe,!!e&&(r==\"number\"||r!=\"symbol\"&&LVe.test(t))&&t>-1&&t%1==0&&t<e}tte.exports=OVe});var YP=_((fRt,rte)=>{var MVe=9007199254740991;function UVe(t){return typeof t==\"number\"&&t>-1&&t%1==0&&t<=MVe}rte.exports=UVe});var ite=_((pRt,nte)=>{var _Ve=fd(),HVe=YP(),jVe=zu(),qVe=\"[object Arguments]\",GVe=\"[object Array]\",YVe=\"[object Boolean]\",WVe=\"[object Date]\",KVe=\"[object Error]\",VVe=\"[object Function]\",zVe=\"[object Map]\",JVe=\"[object Number]\",XVe=\"[object Object]\",ZVe=\"[object RegExp]\",$Ve=\"[object Set]\",eze=\"[object String]\",tze=\"[object WeakMap]\",rze=\"[object ArrayBuffer]\",nze=\"[object DataView]\",ize=\"[object Float32Array]\",sze=\"[object Float64Array]\",oze=\"[object Int8Array]\",aze=\"[object Int16Array]\",lze=\"[object Int32Array]\",cze=\"[object Uint8Array]\",uze=\"[object Uint8ClampedArray]\",Aze=\"[object Uint16Array]\",fze=\"[object Uint32Array]\",ui={};ui[ize]=ui[sze]=ui[oze]=ui[aze]=ui[lze]=ui[cze]=ui[uze]=ui[Aze]=ui[fze]=!0;ui[qVe]=ui[GVe]=ui[rze]=ui[YVe]=ui[nze]=ui[WVe]=ui[KVe]=ui[VVe]=ui[zVe]=ui[JVe]=ui[XVe]=ui[ZVe]=ui[$Ve]=ui[eze]=ui[tze]=!1;function pze(t){return jVe(t)&&HVe(t.length)&&!!ui[_Ve(t)]}nte.exports=pze});var WP=_((hRt,ste)=>{function hze(t){return function(e){return t(e)}}ste.exports=hze});var KP=_((UI,Uy)=>{var gze=HN(),ote=typeof UI==\"object\"&&UI&&!UI.nodeType&&UI,_I=ote&&typeof Uy==\"object\"&&Uy&&!Uy.nodeType&&Uy,dze=_I&&_I.exports===ote,zN=dze&&gze.process,mze=function(){try{var t=_I&&_I.require&&_I.require(\"util\").types;return t||zN&&zN.binding&&zN.binding(\"util\")}catch{}}();Uy.exports=mze});var VP=_((gRt,cte)=>{var yze=ite(),Eze=WP(),ate=KP(),lte=ate&&ate.isTypedArray,Cze=lte?Eze(lte):yze;cte.exports=Cze});var JN=_((dRt,ute)=>{var wze=qee(),Ize=NI(),Bze=Hl(),vze=OI(),Dze=MI(),Pze=VP(),Sze=Object.prototype,bze=Sze.hasOwnProperty;function xze(t,e){var r=Bze(t),o=!r&&Ize(t),a=!r&&!o&&vze(t),n=!r&&!o&&!a&&Pze(t),u=r||o||a||n,A=u?wze(t.length,String):[],p=A.length;for(var h in t)(e||bze.call(t,h))&&!(u&&(h==\"length\"||a&&(h==\"offset\"||h==\"parent\")||n&&(h==\"buffer\"||h==\"byteLength\"||h==\"byteOffset\")||Dze(h,p)))&&A.push(h);return A}ute.exports=xze});var zP=_((mRt,Ate)=>{var kze=Object.prototype;function Qze(t){var e=t&&t.constructor,r=typeof e==\"function\"&&e.prototype||kze;return t===r}Ate.exports=Qze});var XN=_((yRt,fte)=>{function Fze(t,e){return function(r){return t(e(r))}}fte.exports=Fze});var hte=_((ERt,pte)=>{var Rze=XN(),Tze=Rze(Object.keys,Object);pte.exports=Tze});var dte=_((CRt,gte)=>{var Nze=zP(),Lze=hte(),Oze=Object.prototype,Mze=Oze.hasOwnProperty;function Uze(t){if(!Nze(t))return Lze(t);var e=[];for(var r in Object(t))Mze.call(t,r)&&r!=\"constructor\"&&e.push(r);return e}gte.exports=Uze});var HI=_((wRt,mte)=>{var _ze=MP(),Hze=YP();function jze(t){return t!=null&&Hze(t.length)&&!_ze(t)}mte.exports=jze});var JP=_((IRt,yte)=>{var qze=JN(),Gze=dte(),Yze=HI();function Wze(t){return Yze(t)?qze(t):Gze(t)}yte.exports=Wze});var ZN=_((BRt,Ete)=>{var Kze=KN(),Vze=GP(),zze=JP();function Jze(t){return Kze(t,zze,Vze)}Ete.exports=Jze});var Ite=_((vRt,wte)=>{var Cte=ZN(),Xze=1,Zze=Object.prototype,$ze=Zze.hasOwnProperty;function eJe(t,e,r,o,a,n){var u=r&Xze,A=Cte(t),p=A.length,h=Cte(e),C=h.length;if(p!=C&&!u)return!1;for(var I=p;I--;){var v=A[I];if(!(u?v in e:$ze.call(e,v)))return!1}var x=n.get(t),E=n.get(e);if(x&&E)return x==e&&E==t;var R=!0;n.set(t,e),n.set(e,t);for(var L=u;++I<p;){v=A[I];var U=t[v],z=e[v];if(o)var te=u?o(z,U,v,e,t,n):o(U,z,v,t,e,n);if(!(te===void 0?U===z||a(U,z,r,o,n):te)){R=!1;break}L||(L=v==\"constructor\")}if(R&&!L){var le=t.constructor,he=e.constructor;le!=he&&\"constructor\"in t&&\"constructor\"in e&&!(typeof le==\"function\"&&le instanceof le&&typeof he==\"function\"&&he instanceof he)&&(R=!1)}return n.delete(t),n.delete(e),R}wte.exports=eJe});var vte=_((DRt,Bte)=>{var tJe=Vp(),rJe=_l(),nJe=tJe(rJe,\"DataView\");Bte.exports=nJe});var Pte=_((PRt,Dte)=>{var iJe=Vp(),sJe=_l(),oJe=iJe(sJe,\"Promise\");Dte.exports=oJe});var bte=_((SRt,Ste)=>{var aJe=Vp(),lJe=_l(),cJe=aJe(lJe,\"Set\");Ste.exports=cJe});var kte=_((bRt,xte)=>{var uJe=Vp(),AJe=_l(),fJe=uJe(AJe,\"WeakMap\");xte.exports=fJe});var jI=_((xRt,Ote)=>{var $N=vte(),eL=UP(),tL=Pte(),rL=bte(),nL=kte(),Lte=fd(),_y=qN(),Qte=\"[object Map]\",pJe=\"[object Object]\",Fte=\"[object Promise]\",Rte=\"[object Set]\",Tte=\"[object WeakMap]\",Nte=\"[object DataView]\",hJe=_y($N),gJe=_y(eL),dJe=_y(tL),mJe=_y(rL),yJe=_y(nL),pd=Lte;($N&&pd(new $N(new ArrayBuffer(1)))!=Nte||eL&&pd(new eL)!=Qte||tL&&pd(tL.resolve())!=Fte||rL&&pd(new rL)!=Rte||nL&&pd(new nL)!=Tte)&&(pd=function(t){var e=Lte(t),r=e==pJe?t.constructor:void 0,o=r?_y(r):\"\";if(o)switch(o){case hJe:return Nte;case gJe:return Qte;case dJe:return Fte;case mJe:return Rte;case yJe:return Tte}return e});Ote.exports=pd});var Yte=_((kRt,Gte)=>{var iL=HP(),EJe=GN(),CJe=Ree(),wJe=Ite(),Mte=jI(),Ute=Hl(),_te=OI(),IJe=VP(),BJe=1,Hte=\"[object Arguments]\",jte=\"[object Array]\",XP=\"[object Object]\",vJe=Object.prototype,qte=vJe.hasOwnProperty;function DJe(t,e,r,o,a,n){var u=Ute(t),A=Ute(e),p=u?jte:Mte(t),h=A?jte:Mte(e);p=p==Hte?XP:p,h=h==Hte?XP:h;var C=p==XP,I=h==XP,v=p==h;if(v&&_te(t)){if(!_te(e))return!1;u=!0,C=!1}if(v&&!C)return n||(n=new iL),u||IJe(t)?EJe(t,e,r,o,a,n):CJe(t,e,p,r,o,a,n);if(!(r&BJe)){var x=C&&qte.call(t,\"__wrapped__\"),E=I&&qte.call(e,\"__wrapped__\");if(x||E){var R=x?t.value():t,L=E?e.value():e;return n||(n=new iL),a(R,L,r,o,n)}}return v?(n||(n=new iL),wJe(t,e,r,o,a,n)):!1}Gte.exports=DJe});var zte=_((QRt,Vte)=>{var PJe=Yte(),Wte=zu();function Kte(t,e,r,o,a){return t===e?!0:t==null||e==null||!Wte(t)&&!Wte(e)?t!==t&&e!==e:PJe(t,e,r,o,Kte,a)}Vte.exports=Kte});var Xte=_((FRt,Jte)=>{var SJe=zte();function bJe(t,e){return SJe(t,e)}Jte.exports=bJe});var sL=_((RRt,Zte)=>{var xJe=Vp(),kJe=function(){try{var t=xJe(Object,\"defineProperty\");return t({},\"\",{}),t}catch{}}();Zte.exports=kJe});var ZP=_((TRt,ere)=>{var $te=sL();function QJe(t,e,r){e==\"__proto__\"&&$te?$te(t,e,{configurable:!0,enumerable:!0,value:r,writable:!0}):t[e]=r}ere.exports=QJe});var oL=_((NRt,tre)=>{var FJe=ZP(),RJe=Ry();function TJe(t,e,r){(r!==void 0&&!RJe(t[e],r)||r===void 0&&!(e in t))&&FJe(t,e,r)}tre.exports=TJe});var nre=_((LRt,rre)=>{function NJe(t){return function(e,r,o){for(var a=-1,n=Object(e),u=o(e),A=u.length;A--;){var p=u[t?A:++a];if(r(n[p],p,n)===!1)break}return e}}rre.exports=NJe});var sre=_((ORt,ire)=>{var LJe=nre(),OJe=LJe();ire.exports=OJe});var aL=_((qI,Hy)=>{var MJe=_l(),cre=typeof qI==\"object\"&&qI&&!qI.nodeType&&qI,ore=cre&&typeof Hy==\"object\"&&Hy&&!Hy.nodeType&&Hy,UJe=ore&&ore.exports===cre,are=UJe?MJe.Buffer:void 0,lre=are?are.allocUnsafe:void 0;function _Je(t,e){if(e)return t.slice();var r=t.length,o=lre?lre(r):new t.constructor(r);return t.copy(o),o}Hy.exports=_Je});var $P=_((MRt,Are)=>{var ure=YN();function HJe(t){var e=new t.constructor(t.byteLength);return new ure(e).set(new ure(t)),e}Are.exports=HJe});var lL=_((URt,fre)=>{var jJe=$P();function qJe(t,e){var r=e?jJe(t.buffer):t.buffer;return new t.constructor(r,t.byteOffset,t.length)}fre.exports=qJe});var eS=_((_Rt,pre)=>{function GJe(t,e){var r=-1,o=t.length;for(e||(e=Array(o));++r<o;)e[r]=t[r];return e}pre.exports=GJe});var dre=_((HRt,gre)=>{var YJe=il(),hre=Object.create,WJe=function(){function t(){}return function(e){if(!YJe(e))return{};if(hre)return hre(e);t.prototype=e;var r=new t;return t.prototype=void 0,r}}();gre.exports=WJe});var tS=_((jRt,mre)=>{var KJe=XN(),VJe=KJe(Object.getPrototypeOf,Object);mre.exports=VJe});var cL=_((qRt,yre)=>{var zJe=dre(),JJe=tS(),XJe=zP();function ZJe(t){return typeof t.constructor==\"function\"&&!XJe(t)?zJe(JJe(t)):{}}yre.exports=ZJe});var Cre=_((GRt,Ere)=>{var $Je=HI(),eXe=zu();function tXe(t){return eXe(t)&&$Je(t)}Ere.exports=tXe});var uL=_((YRt,Ire)=>{var rXe=fd(),nXe=tS(),iXe=zu(),sXe=\"[object Object]\",oXe=Function.prototype,aXe=Object.prototype,wre=oXe.toString,lXe=aXe.hasOwnProperty,cXe=wre.call(Object);function uXe(t){if(!iXe(t)||rXe(t)!=sXe)return!1;var e=nXe(t);if(e===null)return!0;var r=lXe.call(e,\"constructor\")&&e.constructor;return typeof r==\"function\"&&r instanceof r&&wre.call(r)==cXe}Ire.exports=uXe});var AL=_((WRt,Bre)=>{function AXe(t,e){if(!(e===\"constructor\"&&typeof t[e]==\"function\")&&e!=\"__proto__\")return t[e]}Bre.exports=AXe});var rS=_((KRt,vre)=>{var fXe=ZP(),pXe=Ry(),hXe=Object.prototype,gXe=hXe.hasOwnProperty;function dXe(t,e,r){var o=t[e];(!(gXe.call(t,e)&&pXe(o,r))||r===void 0&&!(e in t))&&fXe(t,e,r)}vre.exports=dXe});var hd=_((VRt,Dre)=>{var mXe=rS(),yXe=ZP();function EXe(t,e,r,o){var a=!r;r||(r={});for(var n=-1,u=e.length;++n<u;){var A=e[n],p=o?o(r[A],t[A],A,r,t):void 0;p===void 0&&(p=t[A]),a?yXe(r,A,p):mXe(r,A,p)}return r}Dre.exports=EXe});var Sre=_((zRt,Pre)=>{function CXe(t){var e=[];if(t!=null)for(var r in Object(t))e.push(r);return e}Pre.exports=CXe});var xre=_((JRt,bre)=>{var wXe=il(),IXe=zP(),BXe=Sre(),vXe=Object.prototype,DXe=vXe.hasOwnProperty;function PXe(t){if(!wXe(t))return BXe(t);var e=IXe(t),r=[];for(var o in t)o==\"constructor\"&&(e||!DXe.call(t,o))||r.push(o);return r}bre.exports=PXe});var jy=_((XRt,kre)=>{var SXe=JN(),bXe=xre(),xXe=HI();function kXe(t){return xXe(t)?SXe(t,!0):bXe(t)}kre.exports=kXe});var Fre=_((ZRt,Qre)=>{var QXe=hd(),FXe=jy();function RXe(t){return QXe(t,FXe(t))}Qre.exports=RXe});var Mre=_(($Rt,Ore)=>{var Rre=oL(),TXe=aL(),NXe=lL(),LXe=eS(),OXe=cL(),Tre=NI(),Nre=Hl(),MXe=Cre(),UXe=OI(),_Xe=MP(),HXe=il(),jXe=uL(),qXe=VP(),Lre=AL(),GXe=Fre();function YXe(t,e,r,o,a,n,u){var A=Lre(t,r),p=Lre(e,r),h=u.get(p);if(h){Rre(t,r,h);return}var C=n?n(A,p,r+\"\",t,e,u):void 0,I=C===void 0;if(I){var v=Nre(p),x=!v&&UXe(p),E=!v&&!x&&qXe(p);C=p,v||x||E?Nre(A)?C=A:MXe(A)?C=LXe(A):x?(I=!1,C=TXe(p,!0)):E?(I=!1,C=NXe(p,!0)):C=[]:jXe(p)||Tre(p)?(C=A,Tre(A)?C=GXe(A):(!HXe(A)||_Xe(A))&&(C=OXe(p))):I=!1}I&&(u.set(p,C),a(C,p,o,n,u),u.delete(p)),Rre(t,r,C)}Ore.exports=YXe});var Hre=_((eTt,_re)=>{var WXe=HP(),KXe=oL(),VXe=sre(),zXe=Mre(),JXe=il(),XXe=jy(),ZXe=AL();function Ure(t,e,r,o,a){t!==e&&VXe(e,function(n,u){if(a||(a=new WXe),JXe(n))zXe(t,e,u,r,Ure,o,a);else{var A=o?o(ZXe(t,u),n,u+\"\",t,e,a):void 0;A===void 0&&(A=n),KXe(t,u,A)}},XXe)}_re.exports=Ure});var fL=_((tTt,jre)=>{function $Xe(t){return t}jre.exports=$Xe});var Gre=_((rTt,qre)=>{function eZe(t,e,r){switch(r.length){case 0:return t.call(e);case 1:return t.call(e,r[0]);case 2:return t.call(e,r[0],r[1]);case 3:return t.call(e,r[0],r[1],r[2])}return t.apply(e,r)}qre.exports=eZe});var pL=_((nTt,Wre)=>{var tZe=Gre(),Yre=Math.max;function rZe(t,e,r){return e=Yre(e===void 0?t.length-1:e,0),function(){for(var o=arguments,a=-1,n=Yre(o.length-e,0),u=Array(n);++a<n;)u[a]=o[e+a];a=-1;for(var A=Array(e+1);++a<e;)A[a]=o[a];return A[e]=r(u),tZe(t,this,A)}}Wre.exports=rZe});var Vre=_((iTt,Kre)=>{function nZe(t){return function(){return t}}Kre.exports=nZe});var Xre=_((sTt,Jre)=>{var iZe=Vre(),zre=sL(),sZe=fL(),oZe=zre?function(t,e){return zre(t,\"toString\",{configurable:!0,enumerable:!1,value:iZe(e),writable:!0})}:sZe;Jre.exports=oZe});var $re=_((oTt,Zre)=>{var aZe=800,lZe=16,cZe=Date.now;function uZe(t){var e=0,r=0;return function(){var o=cZe(),a=lZe-(o-r);if(r=o,a>0){if(++e>=aZe)return arguments[0]}else e=0;return t.apply(void 0,arguments)}}Zre.exports=uZe});var hL=_((aTt,ene)=>{var AZe=Xre(),fZe=$re(),pZe=fZe(AZe);ene.exports=pZe});var rne=_((lTt,tne)=>{var hZe=fL(),gZe=pL(),dZe=hL();function mZe(t,e){return dZe(gZe(t,e,hZe),t+\"\")}tne.exports=mZe});var ine=_((cTt,nne)=>{var yZe=Ry(),EZe=HI(),CZe=MI(),wZe=il();function IZe(t,e,r){if(!wZe(r))return!1;var o=typeof e;return(o==\"number\"?EZe(r)&&CZe(e,r.length):o==\"string\"&&e in r)?yZe(r[e],t):!1}nne.exports=IZe});var one=_((uTt,sne)=>{var BZe=rne(),vZe=ine();function DZe(t){return BZe(function(e,r){var o=-1,a=r.length,n=a>1?r[a-1]:void 0,u=a>2?r[2]:void 0;for(n=t.length>3&&typeof n==\"function\"?(a--,n):void 0,u&&vZe(r[0],r[1],u)&&(n=a<3?void 0:n,a=1),e=Object(e);++o<a;){var A=r[o];A&&t(e,A,o,n)}return e})}sne.exports=DZe});var lne=_((ATt,ane)=>{var PZe=Hre(),SZe=one(),bZe=SZe(function(t,e,r,o){PZe(t,e,r,o)});ane.exports=bZe});var je={};Vt(je,{AsyncActions:()=>mL,BufferStream:()=>dL,CachingStrategy:()=>Cne,DefaultStream:()=>yL,allSettledSafe:()=>Uc,assertNever:()=>CL,bufferStream:()=>Wy,buildIgnorePattern:()=>NZe,convertMapsToIndexableObjects:()=>iS,dynamicRequire:()=>zp,escapeRegExp:()=>kZe,getArrayWithDefault:()=>qy,getFactoryWithDefault:()=>ol,getMapWithDefault:()=>Gy,getSetWithDefault:()=>gd,groupBy:()=>BL,isIndexableObject:()=>gL,isPathLike:()=>LZe,isTaggedYarnVersion:()=>xZe,makeDeferred:()=>mne,mapAndFilter:()=>sl,mapAndFind:()=>YI,mergeIntoTarget:()=>Ine,overrideType:()=>QZe,parseBoolean:()=>WI,parseInt:()=>Ky,parseOptionalBoolean:()=>wne,plural:()=>nS,prettifyAsyncErrors:()=>Yy,prettifySyncErrors:()=>wL,releaseAfterUseAsync:()=>RZe,replaceEnvVariables:()=>sS,sortMap:()=>ks,toMerged:()=>OZe,tryParseOptionalBoolean:()=>IL,validateEnum:()=>FZe});function xZe(t){return!!(hne.default.valid(t)&&t.match(/^[^-]+(-rc\\.[0-9]+)?$/))}function nS(t,{one:e,more:r,zero:o=r}){return t===0?o:t===1?e:r}function kZe(t){return t.replace(/[.*+?^${}()|[\\]\\\\]/g,\"\\\\$&\")}function QZe(t){}function CL(t){throw new Error(`Assertion failed: Unexpected object '${t}'`)}function FZe(t,e){let r=Object.values(t);if(!r.includes(e))throw new it(`Invalid value for enumeration: ${JSON.stringify(e)} (expected one of ${r.map(o=>JSON.stringify(o)).join(\", \")})`);return e}function sl(t,e){let r=[];for(let o of t){let a=e(o);a!==gne&&r.push(a)}return r}function YI(t,e){for(let r of t){let o=e(r);if(o!==dne)return o}}function gL(t){return typeof t==\"object\"&&t!==null}async function Uc(t){let e=await Promise.allSettled(t),r=[];for(let o of e){if(o.status===\"rejected\")throw o.reason;r.push(o.value)}return r}function iS(t){if(t instanceof Map&&(t=Object.fromEntries(t)),gL(t))for(let e of Object.keys(t)){let r=t[e];gL(r)&&(t[e]=iS(r))}return t}function ol(t,e,r){let o=t.get(e);return typeof o>\"u\"&&t.set(e,o=r()),o}function qy(t,e){let r=t.get(e);return typeof r>\"u\"&&t.set(e,r=[]),r}function gd(t,e){let r=t.get(e);return typeof r>\"u\"&&t.set(e,r=new Set),r}function Gy(t,e){let r=t.get(e);return typeof r>\"u\"&&t.set(e,r=new Map),r}async function RZe(t,e){if(e==null)return await t();try{return await t()}finally{await e()}}async function Yy(t,e){try{return await t()}catch(r){throw r.message=e(r.message),r}}function wL(t,e){try{return t()}catch(r){throw r.message=e(r.message),r}}async function Wy(t){return await new Promise((e,r)=>{let o=[];t.on(\"error\",a=>{r(a)}),t.on(\"data\",a=>{o.push(a)}),t.on(\"end\",()=>{e(Buffer.concat(o))})})}function mne(){let t,e;return{promise:new Promise((o,a)=>{t=o,e=a}),resolve:t,reject:e}}function yne(t){return GI(ue.fromPortablePath(t))}function Ene(path){let physicalPath=ue.fromPortablePath(path),currentCacheEntry=GI.cache[physicalPath];delete GI.cache[physicalPath];let result;try{result=yne(physicalPath);let freshCacheEntry=GI.cache[physicalPath],dynamicModule=eval(\"module\"),freshCacheIndex=dynamicModule.children.indexOf(freshCacheEntry);freshCacheIndex!==-1&&dynamicModule.children.splice(freshCacheIndex,1)}finally{GI.cache[physicalPath]=currentCacheEntry}return result}function TZe(t){let e=cne.get(t),r=oe.statSync(t);if(e?.mtime===r.mtimeMs)return e.instance;let o=Ene(t);return cne.set(t,{mtime:r.mtimeMs,instance:o}),o}function zp(t,{cachingStrategy:e=2}={}){switch(e){case 0:return Ene(t);case 1:return TZe(t);case 2:return yne(t);default:throw new Error(\"Unsupported caching strategy\")}}function ks(t,e){let r=Array.from(t);Array.isArray(e)||(e=[e]);let o=[];for(let n of e)o.push(r.map(u=>n(u)));let a=r.map((n,u)=>u);return a.sort((n,u)=>{for(let A of o){let p=A[n]<A[u]?-1:A[n]>A[u]?1:0;if(p!==0)return p}return 0}),a.map(n=>r[n])}function NZe(t){return t.length===0?null:t.map(e=>`(${fne.default.makeRe(e,{windows:!1,dot:!0}).source})`).join(\"|\")}function sS(t,{env:e}){let r=/\\${(?<variableName>[\\d\\w_]+)(?<colon>:)?(?:-(?<fallback>[^}]*))?}/g;return t.replace(r,(...o)=>{let{variableName:a,colon:n,fallback:u}=o[o.length-1],A=Object.hasOwn(e,a),p=e[a];if(p||A&&!n)return p;if(u!=null)return u;throw new it(`Environment variable not found (${a})`)})}function WI(t){switch(t){case\"true\":case\"1\":case 1:case!0:return!0;case\"false\":case\"0\":case 0:case!1:return!1;default:throw new Error(`Couldn't parse \"${t}\" as a boolean`)}}function wne(t){return typeof t>\"u\"?t:WI(t)}function IL(t){try{return wne(t)}catch{return null}}function LZe(t){return!!(ue.isAbsolute(t)||t.match(/^(\\.{1,2}|~)\\//))}function Ine(t,...e){let r=u=>({value:u}),o=r(t),a=e.map(u=>r(u)),{value:n}=(0,Ane.default)(o,...a,(u,A)=>{if(Array.isArray(u)&&Array.isArray(A)){for(let p of A)u.find(h=>(0,une.default)(h,p))||u.push(p);return u}});return n}function OZe(...t){return Ine({},...t)}function BL(t,e){let r=Object.create(null);for(let o of t){let a=o[e];r[a]??=[],r[a].push(o)}return r}function Ky(t){return typeof t==\"string\"?Number.parseInt(t,10):t}var une,Ane,fne,pne,hne,EL,gne,dne,dL,mL,yL,GI,cne,Cne,jl=Et(()=>{Pt();qt();une=$e(Xte()),Ane=$e(lne()),fne=$e(Zo()),pne=$e(rd()),hne=$e(Jn()),EL=Be(\"stream\");gne=Symbol();sl.skip=gne;dne=Symbol();YI.skip=dne;dL=class extends EL.Transform{constructor(){super(...arguments);this.chunks=[]}_transform(r,o,a){if(o!==\"buffer\"||!Buffer.isBuffer(r))throw new Error(\"Assertion failed: BufferStream only accept buffers\");this.chunks.push(r),a(null,null)}_flush(r){r(null,Buffer.concat(this.chunks))}};mL=class{constructor(e){this.deferred=new Map;this.promises=new Map;this.limit=(0,pne.default)(e)}set(e,r){let o=this.deferred.get(e);typeof o>\"u\"&&this.deferred.set(e,o=mne());let a=this.limit(()=>r());return this.promises.set(e,a),a.then(()=>{this.promises.get(e)===a&&o.resolve()},n=>{this.promises.get(e)===a&&o.reject(n)}),o.promise}reduce(e,r){let o=this.promises.get(e)??Promise.resolve();this.set(e,()=>r(o))}async wait(){await Promise.all(this.promises.values())}},yL=class extends EL.Transform{constructor(r=Buffer.alloc(0)){super();this.active=!0;this.ifEmpty=r}_transform(r,o,a){if(o!==\"buffer\"||!Buffer.isBuffer(r))throw new Error(\"Assertion failed: DefaultStream only accept buffers\");this.active=!1,a(null,r)}_flush(r){this.active&&this.ifEmpty.length>0?r(null,this.ifEmpty):r(null)}},GI=eval(\"require\");cne=new Map;Cne=(o=>(o[o.NoCache=0]=\"NoCache\",o[o.FsTime=1]=\"FsTime\",o[o.Node=2]=\"Node\",o))(Cne||{})});var Vy,vL,DL,Bne=Et(()=>{Vy=(r=>(r.HARD=\"HARD\",r.SOFT=\"SOFT\",r))(Vy||{}),vL=(o=>(o.Dependency=\"Dependency\",o.PeerDependency=\"PeerDependency\",o.PeerDependencyMeta=\"PeerDependencyMeta\",o))(vL||{}),DL=(o=>(o.Inactive=\"inactive\",o.Redundant=\"redundant\",o.Active=\"active\",o))(DL||{})});var de={};Vt(de,{LogLevel:()=>uS,Style:()=>aS,Type:()=>yt,addLogFilterSupport:()=>zI,applyColor:()=>Vs,applyHyperlink:()=>Jy,applyStyle:()=>dd,json:()=>md,jsonOrPretty:()=>_Ze,mark:()=>kL,pretty:()=>Mt,prettyField:()=>Ju,prettyList:()=>xL,prettyTruncatedLocatorList:()=>cS,stripAnsi:()=>zy.default,supportsColor:()=>lS,supportsHyperlinks:()=>bL,tuple:()=>_c});function vne(t){let e=[\"KiB\",\"MiB\",\"GiB\",\"TiB\"],r=e.length;for(;r>1&&t<1024**r;)r-=1;let o=1024**r;return`${Math.floor(t*100/o)/100} ${e[r-1]}`}function _c(t,e){return[e,t]}function dd(t,e,r){return t.get(\"enableColors\")&&r&2&&(e=VI.default.bold(e)),e}function Vs(t,e,r){if(!t.get(\"enableColors\"))return e;let o=MZe.get(r);if(o===null)return e;let a=typeof o>\"u\"?r:SL.level>=3?o[0]:o[1],n=typeof a==\"number\"?PL.ansi256(a):a.startsWith(\"#\")?PL.hex(a):PL[a];if(typeof n!=\"function\")throw new Error(`Invalid format type ${a}`);return n(e)}function Jy(t,e,r){return t.get(\"enableHyperlinks\")?UZe?`\\x1B]8;;${r}\\x1B\\\\${e}\\x1B]8;;\\x1B\\\\`:`\\x1B]8;;${r}\\x07${e}\\x1B]8;;\\x07`:e}function Mt(t,e,r){if(e===null)return Vs(t,\"null\",yt.NULL);if(Object.hasOwn(oS,r))return oS[r].pretty(t,e);if(typeof e!=\"string\")throw new Error(`Assertion failed: Expected the value to be a string, got ${typeof e}`);return Vs(t,e,r)}function xL(t,e,r,{separator:o=\", \"}={}){return[...e].map(a=>Mt(t,a,r)).join(o)}function md(t,e){if(t===null)return null;if(Object.hasOwn(oS,e))return oS[e].json(t);if(typeof t!=\"string\")throw new Error(`Assertion failed: Expected the value to be a string, got ${typeof t}`);return t}function _Ze(t,e,[r,o]){return t?md(r,o):Mt(e,r,o)}function kL(t){return{Check:Vs(t,\"\\u2713\",\"green\"),Cross:Vs(t,\"\\u2718\",\"red\"),Question:Vs(t,\"?\",\"cyan\")}}function Ju(t,{label:e,value:[r,o]}){return`${Mt(t,e,yt.CODE)}: ${Mt(t,r,o)}`}function cS(t,e,r){let o=[],a=[...e],n=r;for(;a.length>0;){let h=a[0],C=`${jr(t,h)}, `,I=QL(h).length+2;if(o.length>0&&n<I)break;o.push([C,I]),n-=I,a.shift()}if(a.length===0)return o.map(([h])=>h).join(\"\").slice(0,-2);let u=\"X\".repeat(a.length.toString().length),A=`and ${u} more.`,p=a.length;for(;o.length>1&&n<A.length;)n+=o[o.length-1][1],p+=1,o.pop();return[o.map(([h])=>h).join(\"\"),A.replace(u,Mt(t,p,yt.NUMBER))].join(\"\")}function zI(t,{configuration:e}){let r=e.get(\"logFilters\"),o=new Map,a=new Map,n=[];for(let I of r){let v=I.get(\"level\");if(typeof v>\"u\")continue;let x=I.get(\"code\");typeof x<\"u\"&&o.set(x,v);let E=I.get(\"text\");typeof E<\"u\"&&a.set(E,v);let R=I.get(\"pattern\");typeof R<\"u\"&&n.push([Dne.default.matcher(R,{contains:!0}),v])}n.reverse();let u=(I,v,x)=>{if(I===null||I===0)return x;let E=a.size>0||n.length>0?(0,zy.default)(v):v;if(a.size>0){let R=a.get(E);if(typeof R<\"u\")return R??x}if(n.length>0){for(let[R,L]of n)if(R(E))return L??x}if(o.size>0){let R=o.get(Wu(I));if(typeof R<\"u\")return R??x}return x},A=t.reportInfo,p=t.reportWarning,h=t.reportError,C=function(I,v,x,E){switch(u(v,x,E)){case\"info\":A.call(I,v,x);break;case\"warning\":p.call(I,v??0,x);break;case\"error\":h.call(I,v??0,x);break}};t.reportInfo=function(...I){return C(this,...I,\"info\")},t.reportWarning=function(...I){return C(this,...I,\"warning\")},t.reportError=function(...I){return C(this,...I,\"error\")}}var VI,KI,Dne,zy,Pne,yt,aS,SL,lS,bL,PL,MZe,So,oS,UZe,uS,ql=Et(()=>{Pt();VI=$e(vN()),KI=$e($g());qt();Dne=$e(Zo()),zy=$e(OP()),Pne=Be(\"util\");pP();bo();yt={NO_HINT:\"NO_HINT\",ID:\"ID\",NULL:\"NULL\",SCOPE:\"SCOPE\",NAME:\"NAME\",RANGE:\"RANGE\",REFERENCE:\"REFERENCE\",NUMBER:\"NUMBER\",PATH:\"PATH\",URL:\"URL\",ADDED:\"ADDED\",REMOVED:\"REMOVED\",CODE:\"CODE\",INSPECT:\"INSPECT\",DURATION:\"DURATION\",SIZE:\"SIZE\",SIZE_DIFF:\"SIZE_DIFF\",IDENT:\"IDENT\",DESCRIPTOR:\"DESCRIPTOR\",LOCATOR:\"LOCATOR\",RESOLUTION:\"RESOLUTION\",DEPENDENT:\"DEPENDENT\",PACKAGE_EXTENSION:\"PACKAGE_EXTENSION\",SETTING:\"SETTING\",MARKDOWN:\"MARKDOWN\",MARKDOWN_INLINE:\"MARKDOWN_INLINE\"},aS=(e=>(e[e.BOLD=2]=\"BOLD\",e))(aS||{}),SL=KI.default.GITHUB_ACTIONS?{level:2}:VI.default.supportsColor?{level:VI.default.supportsColor.level}:{level:0},lS=SL.level!==0,bL=lS&&!KI.default.GITHUB_ACTIONS&&!KI.default.CIRCLE&&!KI.default.GITLAB,PL=new VI.default.Instance(SL),MZe=new Map([[yt.NO_HINT,null],[yt.NULL,[\"#a853b5\",129]],[yt.SCOPE,[\"#d75f00\",166]],[yt.NAME,[\"#d7875f\",173]],[yt.RANGE,[\"#00afaf\",37]],[yt.REFERENCE,[\"#87afff\",111]],[yt.NUMBER,[\"#ffd700\",220]],[yt.PATH,[\"#d75fd7\",170]],[yt.URL,[\"#d75fd7\",170]],[yt.ADDED,[\"#5faf00\",70]],[yt.REMOVED,[\"#ff3131\",160]],[yt.CODE,[\"#87afff\",111]],[yt.SIZE,[\"#ffd700\",220]]]),So=t=>t;oS={[yt.ID]:So({pretty:(t,e)=>typeof e==\"number\"?Vs(t,`${e}`,yt.NUMBER):Vs(t,e,yt.CODE),json:t=>t}),[yt.INSPECT]:So({pretty:(t,e)=>(0,Pne.inspect)(e,{depth:1/0,colors:t.get(\"enableColors\"),compact:!0,breakLength:1/0}),json:t=>t}),[yt.NUMBER]:So({pretty:(t,e)=>Vs(t,`${e}`,yt.NUMBER),json:t=>t}),[yt.IDENT]:So({pretty:(t,e)=>cs(t,e),json:t=>fn(t)}),[yt.LOCATOR]:So({pretty:(t,e)=>jr(t,e),json:t=>ba(t)}),[yt.DESCRIPTOR]:So({pretty:(t,e)=>qn(t,e),json:t=>Sa(t)}),[yt.RESOLUTION]:So({pretty:(t,{descriptor:e,locator:r})=>JI(t,e,r),json:({descriptor:t,locator:e})=>({descriptor:Sa(t),locator:e!==null?ba(e):null})}),[yt.DEPENDENT]:So({pretty:(t,{locator:e,descriptor:r})=>FL(t,e,r),json:({locator:t,descriptor:e})=>({locator:ba(t),descriptor:Sa(e)})}),[yt.PACKAGE_EXTENSION]:So({pretty:(t,e)=>{switch(e.type){case\"Dependency\":return`${cs(t,e.parentDescriptor)} \\u27A4 ${Vs(t,\"dependencies\",yt.CODE)} \\u27A4 ${cs(t,e.descriptor)}`;case\"PeerDependency\":return`${cs(t,e.parentDescriptor)} \\u27A4 ${Vs(t,\"peerDependencies\",yt.CODE)} \\u27A4 ${cs(t,e.descriptor)}`;case\"PeerDependencyMeta\":return`${cs(t,e.parentDescriptor)} \\u27A4 ${Vs(t,\"peerDependenciesMeta\",yt.CODE)} \\u27A4 ${cs(t,zs(e.selector))} \\u27A4 ${Vs(t,e.key,yt.CODE)}`;default:throw new Error(`Assertion failed: Unsupported package extension type: ${e.type}`)}},json:t=>{switch(t.type){case\"Dependency\":return`${fn(t.parentDescriptor)} > ${fn(t.descriptor)}`;case\"PeerDependency\":return`${fn(t.parentDescriptor)} >> ${fn(t.descriptor)}`;case\"PeerDependencyMeta\":return`${fn(t.parentDescriptor)} >> ${t.selector} / ${t.key}`;default:throw new Error(`Assertion failed: Unsupported package extension type: ${t.type}`)}}}),[yt.SETTING]:So({pretty:(t,e)=>(t.get(e),Jy(t,Vs(t,e,yt.CODE),`https://yarnpkg.com/configuration/yarnrc#${e}`)),json:t=>t}),[yt.DURATION]:So({pretty:(t,e)=>{if(e>1e3*60){let r=Math.floor(e/1e3/60),o=Math.ceil((e-r*60*1e3)/1e3);return o===0?`${r}m`:`${r}m ${o}s`}else{let r=Math.floor(e/1e3),o=e-r*1e3;return o===0?`${r}s`:`${r}s ${o}ms`}},json:t=>t}),[yt.SIZE]:So({pretty:(t,e)=>Vs(t,vne(e),yt.NUMBER),json:t=>t}),[yt.SIZE_DIFF]:So({pretty:(t,e)=>{let r=e>=0?\"+\":\"-\",o=r===\"+\"?yt.REMOVED:yt.ADDED;return Vs(t,`${r} ${vne(Math.max(Math.abs(e),1))}`,o)},json:t=>t}),[yt.PATH]:So({pretty:(t,e)=>Vs(t,ue.fromPortablePath(e),yt.PATH),json:t=>ue.fromPortablePath(t)}),[yt.MARKDOWN]:So({pretty:(t,{text:e,format:r,paragraphs:o})=>Do(e,{format:r,paragraphs:o}),json:({text:t})=>t}),[yt.MARKDOWN_INLINE]:So({pretty:(t,e)=>(e=e.replace(/(`+)((?:.|[\\n])*?)\\1/g,(r,o,a)=>Mt(t,o+a+o,yt.CODE)),e=e.replace(/(\\*\\*)((?:.|[\\n])*?)\\1/g,(r,o,a)=>dd(t,a,2)),e),json:t=>t})};UZe=!!process.env.KONSOLE_VERSION;uS=(a=>(a.Error=\"error\",a.Warning=\"warning\",a.Info=\"info\",a.Discard=\"discard\",a))(uS||{})});var Sne=_(Xy=>{\"use strict\";Object.defineProperty(Xy,\"__esModule\",{value:!0});Xy.splitWhen=Xy.flatten=void 0;function HZe(t){return t.reduce((e,r)=>[].concat(e,r),[])}Xy.flatten=HZe;function jZe(t,e){let r=[[]],o=0;for(let a of t)e(a)?(o++,r[o]=[]):r[o].push(a);return r}Xy.splitWhen=jZe});var bne=_(AS=>{\"use strict\";Object.defineProperty(AS,\"__esModule\",{value:!0});AS.isEnoentCodeError=void 0;function qZe(t){return t.code===\"ENOENT\"}AS.isEnoentCodeError=qZe});var xne=_(fS=>{\"use strict\";Object.defineProperty(fS,\"__esModule\",{value:!0});fS.createDirentFromStats=void 0;var RL=class{constructor(e,r){this.name=e,this.isBlockDevice=r.isBlockDevice.bind(r),this.isCharacterDevice=r.isCharacterDevice.bind(r),this.isDirectory=r.isDirectory.bind(r),this.isFIFO=r.isFIFO.bind(r),this.isFile=r.isFile.bind(r),this.isSocket=r.isSocket.bind(r),this.isSymbolicLink=r.isSymbolicLink.bind(r)}};function GZe(t,e){return new RL(t,e)}fS.createDirentFromStats=GZe});var kne=_(Xu=>{\"use strict\";Object.defineProperty(Xu,\"__esModule\",{value:!0});Xu.removeLeadingDotSegment=Xu.escape=Xu.makeAbsolute=Xu.unixify=void 0;var YZe=Be(\"path\"),WZe=2,KZe=/(\\\\?)([()*?[\\]{|}]|^!|[!+@](?=\\())/g;function VZe(t){return t.replace(/\\\\/g,\"/\")}Xu.unixify=VZe;function zZe(t,e){return YZe.resolve(t,e)}Xu.makeAbsolute=zZe;function JZe(t){return t.replace(KZe,\"\\\\$2\")}Xu.escape=JZe;function XZe(t){if(t.charAt(0)===\".\"){let e=t.charAt(1);if(e===\"/\"||e===\"\\\\\")return t.slice(WZe)}return t}Xu.removeLeadingDotSegment=XZe});var Fne=_((PTt,Qne)=>{Qne.exports=function(e){if(typeof e!=\"string\"||e===\"\")return!1;for(var r;r=/(\\\\).|([@?!+*]\\(.*\\))/g.exec(e);){if(r[2])return!0;e=e.slice(r.index+r[0].length)}return!1}});var Nne=_((STt,Tne)=>{var ZZe=Fne(),Rne={\"{\":\"}\",\"(\":\")\",\"[\":\"]\"},$Ze=function(t){if(t[0]===\"!\")return!0;for(var e=0,r=-2,o=-2,a=-2,n=-2,u=-2;e<t.length;){if(t[e]===\"*\"||t[e+1]===\"?\"&&/[\\].+)]/.test(t[e])||o!==-1&&t[e]===\"[\"&&t[e+1]!==\"]\"&&(o<e&&(o=t.indexOf(\"]\",e)),o>e&&(u===-1||u>o||(u=t.indexOf(\"\\\\\",e),u===-1||u>o)))||a!==-1&&t[e]===\"{\"&&t[e+1]!==\"}\"&&(a=t.indexOf(\"}\",e),a>e&&(u=t.indexOf(\"\\\\\",e),u===-1||u>a))||n!==-1&&t[e]===\"(\"&&t[e+1]===\"?\"&&/[:!=]/.test(t[e+2])&&t[e+3]!==\")\"&&(n=t.indexOf(\")\",e),n>e&&(u=t.indexOf(\"\\\\\",e),u===-1||u>n))||r!==-1&&t[e]===\"(\"&&t[e+1]!==\"|\"&&(r<e&&(r=t.indexOf(\"|\",e)),r!==-1&&t[r+1]!==\")\"&&(n=t.indexOf(\")\",r),n>r&&(u=t.indexOf(\"\\\\\",r),u===-1||u>n))))return!0;if(t[e]===\"\\\\\"){var A=t[e+1];e+=2;var p=Rne[A];if(p){var h=t.indexOf(p,e);h!==-1&&(e=h+1)}if(t[e]===\"!\")return!0}else e++}return!1},e$e=function(t){if(t[0]===\"!\")return!0;for(var e=0;e<t.length;){if(/[*?{}()[\\]]/.test(t[e]))return!0;if(t[e]===\"\\\\\"){var r=t[e+1];e+=2;var o=Rne[r];if(o){var a=t.indexOf(o,e);a!==-1&&(e=a+1)}if(t[e]===\"!\")return!0}else e++}return!1};Tne.exports=function(e,r){if(typeof e!=\"string\"||e===\"\")return!1;if(ZZe(e))return!0;var o=$Ze;return r&&r.strict===!1&&(o=e$e),o(e)}});var One=_((bTt,Lne)=>{\"use strict\";var t$e=Nne(),r$e=Be(\"path\").posix.dirname,n$e=Be(\"os\").platform()===\"win32\",TL=\"/\",i$e=/\\\\/g,s$e=/[\\{\\[].*[\\}\\]]$/,o$e=/(^|[^\\\\])([\\{\\[]|\\([^\\)]+$)/,a$e=/\\\\([\\!\\*\\?\\|\\[\\]\\(\\)\\{\\}])/g;Lne.exports=function(e,r){var o=Object.assign({flipBackslashes:!0},r);o.flipBackslashes&&n$e&&e.indexOf(TL)<0&&(e=e.replace(i$e,TL)),s$e.test(e)&&(e+=TL),e+=\"a\";do e=r$e(e);while(t$e(e)||o$e.test(e));return e.replace(a$e,\"$1\")}});var Yne=_(qr=>{\"use strict\";Object.defineProperty(qr,\"__esModule\",{value:!0});qr.matchAny=qr.convertPatternsToRe=qr.makeRe=qr.getPatternParts=qr.expandBraceExpansion=qr.expandPatternsWithBraceExpansion=qr.isAffectDepthOfReadingPattern=qr.endsWithSlashGlobStar=qr.hasGlobStar=qr.getBaseDirectory=qr.isPatternRelatedToParentDirectory=qr.getPatternsOutsideCurrentDirectory=qr.getPatternsInsideCurrentDirectory=qr.getPositivePatterns=qr.getNegativePatterns=qr.isPositivePattern=qr.isNegativePattern=qr.convertToNegativePattern=qr.convertToPositivePattern=qr.isDynamicPattern=qr.isStaticPattern=void 0;var l$e=Be(\"path\"),c$e=One(),NL=Zo(),Mne=\"**\",u$e=\"\\\\\",A$e=/[*?]|^!/,f$e=/\\[[^[]*]/,p$e=/(?:^|[^!*+?@])\\([^(]*\\|[^|]*\\)/,h$e=/[!*+?@]\\([^(]*\\)/,g$e=/,|\\.\\./;function Une(t,e={}){return!_ne(t,e)}qr.isStaticPattern=Une;function _ne(t,e={}){return t===\"\"?!1:!!(e.caseSensitiveMatch===!1||t.includes(u$e)||A$e.test(t)||f$e.test(t)||p$e.test(t)||e.extglob!==!1&&h$e.test(t)||e.braceExpansion!==!1&&d$e(t))}qr.isDynamicPattern=_ne;function d$e(t){let e=t.indexOf(\"{\");if(e===-1)return!1;let r=t.indexOf(\"}\",e+1);if(r===-1)return!1;let o=t.slice(e,r);return g$e.test(o)}function m$e(t){return pS(t)?t.slice(1):t}qr.convertToPositivePattern=m$e;function y$e(t){return\"!\"+t}qr.convertToNegativePattern=y$e;function pS(t){return t.startsWith(\"!\")&&t[1]!==\"(\"}qr.isNegativePattern=pS;function Hne(t){return!pS(t)}qr.isPositivePattern=Hne;function E$e(t){return t.filter(pS)}qr.getNegativePatterns=E$e;function C$e(t){return t.filter(Hne)}qr.getPositivePatterns=C$e;function w$e(t){return t.filter(e=>!LL(e))}qr.getPatternsInsideCurrentDirectory=w$e;function I$e(t){return t.filter(LL)}qr.getPatternsOutsideCurrentDirectory=I$e;function LL(t){return t.startsWith(\"..\")||t.startsWith(\"./..\")}qr.isPatternRelatedToParentDirectory=LL;function B$e(t){return c$e(t,{flipBackslashes:!1})}qr.getBaseDirectory=B$e;function v$e(t){return t.includes(Mne)}qr.hasGlobStar=v$e;function jne(t){return t.endsWith(\"/\"+Mne)}qr.endsWithSlashGlobStar=jne;function D$e(t){let e=l$e.basename(t);return jne(t)||Une(e)}qr.isAffectDepthOfReadingPattern=D$e;function P$e(t){return t.reduce((e,r)=>e.concat(qne(r)),[])}qr.expandPatternsWithBraceExpansion=P$e;function qne(t){return NL.braces(t,{expand:!0,nodupes:!0})}qr.expandBraceExpansion=qne;function S$e(t,e){let{parts:r}=NL.scan(t,Object.assign(Object.assign({},e),{parts:!0}));return r.length===0&&(r=[t]),r[0].startsWith(\"/\")&&(r[0]=r[0].slice(1),r.unshift(\"\")),r}qr.getPatternParts=S$e;function Gne(t,e){return NL.makeRe(t,e)}qr.makeRe=Gne;function b$e(t,e){return t.map(r=>Gne(r,e))}qr.convertPatternsToRe=b$e;function x$e(t,e){return e.some(r=>r.test(t))}qr.matchAny=x$e});var zne=_((kTt,Vne)=>{\"use strict\";var k$e=Be(\"stream\"),Wne=k$e.PassThrough,Q$e=Array.prototype.slice;Vne.exports=F$e;function F$e(){let t=[],e=Q$e.call(arguments),r=!1,o=e[e.length-1];o&&!Array.isArray(o)&&o.pipe==null?e.pop():o={};let a=o.end!==!1,n=o.pipeError===!0;o.objectMode==null&&(o.objectMode=!0),o.highWaterMark==null&&(o.highWaterMark=64*1024);let u=Wne(o);function A(){for(let C=0,I=arguments.length;C<I;C++)t.push(Kne(arguments[C],o));return p(),this}function p(){if(r)return;r=!0;let C=t.shift();if(!C){process.nextTick(h);return}Array.isArray(C)||(C=[C]);let I=C.length+1;function v(){--I>0||(r=!1,p())}function x(E){function R(){E.removeListener(\"merge2UnpipeEnd\",R),E.removeListener(\"end\",R),n&&E.removeListener(\"error\",L),v()}function L(U){u.emit(\"error\",U)}if(E._readableState.endEmitted)return v();E.on(\"merge2UnpipeEnd\",R),E.on(\"end\",R),n&&E.on(\"error\",L),E.pipe(u,{end:!1}),E.resume()}for(let E=0;E<C.length;E++)x(C[E]);v()}function h(){r=!1,u.emit(\"queueDrain\"),a&&u.end()}return u.setMaxListeners(0),u.add=A,u.on(\"unpipe\",function(C){C.emit(\"merge2UnpipeEnd\")}),e.length&&A.apply(null,e),u}function Kne(t,e){if(Array.isArray(t))for(let r=0,o=t.length;r<o;r++)t[r]=Kne(t[r],e);else{if(!t._readableState&&t.pipe&&(t=t.pipe(Wne(e))),!t._readableState||!t.pause||!t.pipe)throw new Error(\"Only readable stream can be merged.\");t.pause()}return t}});var Xne=_(hS=>{\"use strict\";Object.defineProperty(hS,\"__esModule\",{value:!0});hS.merge=void 0;var R$e=zne();function T$e(t){let e=R$e(t);return t.forEach(r=>{r.once(\"error\",o=>e.emit(\"error\",o))}),e.once(\"close\",()=>Jne(t)),e.once(\"end\",()=>Jne(t)),e}hS.merge=T$e;function Jne(t){t.forEach(e=>e.emit(\"close\"))}});var Zne=_(Zy=>{\"use strict\";Object.defineProperty(Zy,\"__esModule\",{value:!0});Zy.isEmpty=Zy.isString=void 0;function N$e(t){return typeof t==\"string\"}Zy.isString=N$e;function L$e(t){return t===\"\"}Zy.isEmpty=L$e});var vf=_(xo=>{\"use strict\";Object.defineProperty(xo,\"__esModule\",{value:!0});xo.string=xo.stream=xo.pattern=xo.path=xo.fs=xo.errno=xo.array=void 0;var O$e=Sne();xo.array=O$e;var M$e=bne();xo.errno=M$e;var U$e=xne();xo.fs=U$e;var _$e=kne();xo.path=_$e;var H$e=Yne();xo.pattern=H$e;var j$e=Xne();xo.stream=j$e;var q$e=Zne();xo.string=q$e});var tie=_(ko=>{\"use strict\";Object.defineProperty(ko,\"__esModule\",{value:!0});ko.convertPatternGroupToTask=ko.convertPatternGroupsToTasks=ko.groupPatternsByBaseDirectory=ko.getNegativePatternsAsPositive=ko.getPositivePatterns=ko.convertPatternsToTasks=ko.generate=void 0;var Df=vf();function G$e(t,e){let r=$ne(t),o=eie(t,e.ignore),a=r.filter(p=>Df.pattern.isStaticPattern(p,e)),n=r.filter(p=>Df.pattern.isDynamicPattern(p,e)),u=OL(a,o,!1),A=OL(n,o,!0);return u.concat(A)}ko.generate=G$e;function OL(t,e,r){let o=[],a=Df.pattern.getPatternsOutsideCurrentDirectory(t),n=Df.pattern.getPatternsInsideCurrentDirectory(t),u=ML(a),A=ML(n);return o.push(...UL(u,e,r)),\".\"in A?o.push(_L(\".\",n,e,r)):o.push(...UL(A,e,r)),o}ko.convertPatternsToTasks=OL;function $ne(t){return Df.pattern.getPositivePatterns(t)}ko.getPositivePatterns=$ne;function eie(t,e){return Df.pattern.getNegativePatterns(t).concat(e).map(Df.pattern.convertToPositivePattern)}ko.getNegativePatternsAsPositive=eie;function ML(t){let e={};return t.reduce((r,o)=>{let a=Df.pattern.getBaseDirectory(o);return a in r?r[a].push(o):r[a]=[o],r},e)}ko.groupPatternsByBaseDirectory=ML;function UL(t,e,r){return Object.keys(t).map(o=>_L(o,t[o],e,r))}ko.convertPatternGroupsToTasks=UL;function _L(t,e,r,o){return{dynamic:o,positive:e,negative:r,base:t,patterns:[].concat(e,r.map(Df.pattern.convertToNegativePattern))}}ko.convertPatternGroupToTask=_L});var nie=_($y=>{\"use strict\";Object.defineProperty($y,\"__esModule\",{value:!0});$y.removeDuplicateSlashes=$y.transform=void 0;var Y$e=/(?!^)\\/{2,}/g;function W$e(t){return t.map(e=>rie(e))}$y.transform=W$e;function rie(t){return t.replace(Y$e,\"/\")}$y.removeDuplicateSlashes=rie});var sie=_(gS=>{\"use strict\";Object.defineProperty(gS,\"__esModule\",{value:!0});gS.read=void 0;function K$e(t,e,r){e.fs.lstat(t,(o,a)=>{if(o!==null){iie(r,o);return}if(!a.isSymbolicLink()||!e.followSymbolicLink){HL(r,a);return}e.fs.stat(t,(n,u)=>{if(n!==null){if(e.throwErrorOnBrokenSymbolicLink){iie(r,n);return}HL(r,a);return}e.markSymbolicLink&&(u.isSymbolicLink=()=>!0),HL(r,u)})})}gS.read=K$e;function iie(t,e){t(e)}function HL(t,e){t(null,e)}});var oie=_(dS=>{\"use strict\";Object.defineProperty(dS,\"__esModule\",{value:!0});dS.read=void 0;function V$e(t,e){let r=e.fs.lstatSync(t);if(!r.isSymbolicLink()||!e.followSymbolicLink)return r;try{let o=e.fs.statSync(t);return e.markSymbolicLink&&(o.isSymbolicLink=()=>!0),o}catch(o){if(!e.throwErrorOnBrokenSymbolicLink)return r;throw o}}dS.read=V$e});var aie=_(Jp=>{\"use strict\";Object.defineProperty(Jp,\"__esModule\",{value:!0});Jp.createFileSystemAdapter=Jp.FILE_SYSTEM_ADAPTER=void 0;var mS=Be(\"fs\");Jp.FILE_SYSTEM_ADAPTER={lstat:mS.lstat,stat:mS.stat,lstatSync:mS.lstatSync,statSync:mS.statSync};function z$e(t){return t===void 0?Jp.FILE_SYSTEM_ADAPTER:Object.assign(Object.assign({},Jp.FILE_SYSTEM_ADAPTER),t)}Jp.createFileSystemAdapter=z$e});var lie=_(qL=>{\"use strict\";Object.defineProperty(qL,\"__esModule\",{value:!0});var J$e=aie(),jL=class{constructor(e={}){this._options=e,this.followSymbolicLink=this._getValue(this._options.followSymbolicLink,!0),this.fs=J$e.createFileSystemAdapter(this._options.fs),this.markSymbolicLink=this._getValue(this._options.markSymbolicLink,!1),this.throwErrorOnBrokenSymbolicLink=this._getValue(this._options.throwErrorOnBrokenSymbolicLink,!0)}_getValue(e,r){return e??r}};qL.default=jL});var yd=_(Xp=>{\"use strict\";Object.defineProperty(Xp,\"__esModule\",{value:!0});Xp.statSync=Xp.stat=Xp.Settings=void 0;var cie=sie(),X$e=oie(),YL=lie();Xp.Settings=YL.default;function Z$e(t,e,r){if(typeof e==\"function\"){cie.read(t,WL(),e);return}cie.read(t,WL(e),r)}Xp.stat=Z$e;function $$e(t,e){let r=WL(e);return X$e.read(t,r)}Xp.statSync=$$e;function WL(t={}){return t instanceof YL.default?t:new YL.default(t)}});var Aie=_((HTt,uie)=>{uie.exports=eet;function eet(t,e){var r,o,a,n=!0;Array.isArray(t)?(r=[],o=t.length):(a=Object.keys(t),r={},o=a.length);function u(p){function h(){e&&e(p,r),e=null}n?process.nextTick(h):h()}function A(p,h,C){r[p]=C,(--o===0||h)&&u(h)}o?a?a.forEach(function(p){t[p](function(h,C){A(p,h,C)})}):t.forEach(function(p,h){p(function(C,I){A(h,C,I)})}):u(null),n=!1}});var KL=_(ES=>{\"use strict\";Object.defineProperty(ES,\"__esModule\",{value:!0});ES.IS_SUPPORT_READDIR_WITH_FILE_TYPES=void 0;var yS=process.versions.node.split(\".\");if(yS[0]===void 0||yS[1]===void 0)throw new Error(`Unexpected behavior. The 'process.versions.node' variable has invalid value: ${process.versions.node}`);var fie=Number.parseInt(yS[0],10),tet=Number.parseInt(yS[1],10),pie=10,ret=10,net=fie>pie,iet=fie===pie&&tet>=ret;ES.IS_SUPPORT_READDIR_WITH_FILE_TYPES=net||iet});var hie=_(CS=>{\"use strict\";Object.defineProperty(CS,\"__esModule\",{value:!0});CS.createDirentFromStats=void 0;var VL=class{constructor(e,r){this.name=e,this.isBlockDevice=r.isBlockDevice.bind(r),this.isCharacterDevice=r.isCharacterDevice.bind(r),this.isDirectory=r.isDirectory.bind(r),this.isFIFO=r.isFIFO.bind(r),this.isFile=r.isFile.bind(r),this.isSocket=r.isSocket.bind(r),this.isSymbolicLink=r.isSymbolicLink.bind(r)}};function set(t,e){return new VL(t,e)}CS.createDirentFromStats=set});var zL=_(wS=>{\"use strict\";Object.defineProperty(wS,\"__esModule\",{value:!0});wS.fs=void 0;var oet=hie();wS.fs=oet});var JL=_(IS=>{\"use strict\";Object.defineProperty(IS,\"__esModule\",{value:!0});IS.joinPathSegments=void 0;function aet(t,e,r){return t.endsWith(r)?t+e:t+r+e}IS.joinPathSegments=aet});var Cie=_(Zp=>{\"use strict\";Object.defineProperty(Zp,\"__esModule\",{value:!0});Zp.readdir=Zp.readdirWithFileTypes=Zp.read=void 0;var cet=yd(),gie=Aie(),uet=KL(),die=zL(),mie=JL();function Aet(t,e,r){if(!e.stats&&uet.IS_SUPPORT_READDIR_WITH_FILE_TYPES){yie(t,e,r);return}Eie(t,e,r)}Zp.read=Aet;function yie(t,e,r){e.fs.readdir(t,{withFileTypes:!0},(o,a)=>{if(o!==null){BS(r,o);return}let n=a.map(A=>({dirent:A,name:A.name,path:mie.joinPathSegments(t,A.name,e.pathSegmentSeparator)}));if(!e.followSymbolicLinks){XL(r,n);return}let u=n.map(A=>fet(A,e));gie(u,(A,p)=>{if(A!==null){BS(r,A);return}XL(r,p)})})}Zp.readdirWithFileTypes=yie;function fet(t,e){return r=>{if(!t.dirent.isSymbolicLink()){r(null,t);return}e.fs.stat(t.path,(o,a)=>{if(o!==null){if(e.throwErrorOnBrokenSymbolicLink){r(o);return}r(null,t);return}t.dirent=die.fs.createDirentFromStats(t.name,a),r(null,t)})}}function Eie(t,e,r){e.fs.readdir(t,(o,a)=>{if(o!==null){BS(r,o);return}let n=a.map(u=>{let A=mie.joinPathSegments(t,u,e.pathSegmentSeparator);return p=>{cet.stat(A,e.fsStatSettings,(h,C)=>{if(h!==null){p(h);return}let I={name:u,path:A,dirent:die.fs.createDirentFromStats(u,C)};e.stats&&(I.stats=C),p(null,I)})}});gie(n,(u,A)=>{if(u!==null){BS(r,u);return}XL(r,A)})})}Zp.readdir=Eie;function BS(t,e){t(e)}function XL(t,e){t(null,e)}});var Die=_($p=>{\"use strict\";Object.defineProperty($p,\"__esModule\",{value:!0});$p.readdir=$p.readdirWithFileTypes=$p.read=void 0;var pet=yd(),het=KL(),wie=zL(),Iie=JL();function get(t,e){return!e.stats&&het.IS_SUPPORT_READDIR_WITH_FILE_TYPES?Bie(t,e):vie(t,e)}$p.read=get;function Bie(t,e){return e.fs.readdirSync(t,{withFileTypes:!0}).map(o=>{let a={dirent:o,name:o.name,path:Iie.joinPathSegments(t,o.name,e.pathSegmentSeparator)};if(a.dirent.isSymbolicLink()&&e.followSymbolicLinks)try{let n=e.fs.statSync(a.path);a.dirent=wie.fs.createDirentFromStats(a.name,n)}catch(n){if(e.throwErrorOnBrokenSymbolicLink)throw n}return a})}$p.readdirWithFileTypes=Bie;function vie(t,e){return e.fs.readdirSync(t).map(o=>{let a=Iie.joinPathSegments(t,o,e.pathSegmentSeparator),n=pet.statSync(a,e.fsStatSettings),u={name:o,path:a,dirent:wie.fs.createDirentFromStats(o,n)};return e.stats&&(u.stats=n),u})}$p.readdir=vie});var Pie=_(eh=>{\"use strict\";Object.defineProperty(eh,\"__esModule\",{value:!0});eh.createFileSystemAdapter=eh.FILE_SYSTEM_ADAPTER=void 0;var eE=Be(\"fs\");eh.FILE_SYSTEM_ADAPTER={lstat:eE.lstat,stat:eE.stat,lstatSync:eE.lstatSync,statSync:eE.statSync,readdir:eE.readdir,readdirSync:eE.readdirSync};function det(t){return t===void 0?eh.FILE_SYSTEM_ADAPTER:Object.assign(Object.assign({},eh.FILE_SYSTEM_ADAPTER),t)}eh.createFileSystemAdapter=det});var Sie=_($L=>{\"use strict\";Object.defineProperty($L,\"__esModule\",{value:!0});var met=Be(\"path\"),yet=yd(),Eet=Pie(),ZL=class{constructor(e={}){this._options=e,this.followSymbolicLinks=this._getValue(this._options.followSymbolicLinks,!1),this.fs=Eet.createFileSystemAdapter(this._options.fs),this.pathSegmentSeparator=this._getValue(this._options.pathSegmentSeparator,met.sep),this.stats=this._getValue(this._options.stats,!1),this.throwErrorOnBrokenSymbolicLink=this._getValue(this._options.throwErrorOnBrokenSymbolicLink,!0),this.fsStatSettings=new yet.Settings({followSymbolicLink:this.followSymbolicLinks,fs:this.fs,throwErrorOnBrokenSymbolicLink:this.throwErrorOnBrokenSymbolicLink})}_getValue(e,r){return e??r}};$L.default=ZL});var vS=_(th=>{\"use strict\";Object.defineProperty(th,\"__esModule\",{value:!0});th.Settings=th.scandirSync=th.scandir=void 0;var bie=Cie(),Cet=Die(),eO=Sie();th.Settings=eO.default;function wet(t,e,r){if(typeof e==\"function\"){bie.read(t,tO(),e);return}bie.read(t,tO(e),r)}th.scandir=wet;function Iet(t,e){let r=tO(e);return Cet.read(t,r)}th.scandirSync=Iet;function tO(t={}){return t instanceof eO.default?t:new eO.default(t)}});var kie=_((XTt,xie)=>{\"use strict\";function Bet(t){var e=new t,r=e;function o(){var n=e;return n.next?e=n.next:(e=new t,r=e),n.next=null,n}function a(n){r.next=n,r=n}return{get:o,release:a}}xie.exports=Bet});var Fie=_((ZTt,rO)=>{\"use strict\";var vet=kie();function Qie(t,e,r){if(typeof t==\"function\"&&(r=e,e=t,t=null),r<1)throw new Error(\"fastqueue concurrency must be greater than 1\");var o=vet(Det),a=null,n=null,u=0,A=null,p={push:R,drain:Gl,saturated:Gl,pause:C,paused:!1,concurrency:r,running:h,resume:x,idle:E,length:I,getQueue:v,unshift:L,empty:Gl,kill:z,killAndDrain:te,error:le};return p;function h(){return u}function C(){p.paused=!0}function I(){for(var he=a,Ae=0;he;)he=he.next,Ae++;return Ae}function v(){for(var he=a,Ae=[];he;)Ae.push(he.value),he=he.next;return Ae}function x(){if(!!p.paused){p.paused=!1;for(var he=0;he<p.concurrency;he++)u++,U()}}function E(){return u===0&&p.length()===0}function R(he,Ae){var ye=o.get();ye.context=t,ye.release=U,ye.value=he,ye.callback=Ae||Gl,ye.errorHandler=A,u===p.concurrency||p.paused?n?(n.next=ye,n=ye):(a=ye,n=ye,p.saturated()):(u++,e.call(t,ye.value,ye.worked))}function L(he,Ae){var ye=o.get();ye.context=t,ye.release=U,ye.value=he,ye.callback=Ae||Gl,u===p.concurrency||p.paused?a?(ye.next=a,a=ye):(a=ye,n=ye,p.saturated()):(u++,e.call(t,ye.value,ye.worked))}function U(he){he&&o.release(he);var Ae=a;Ae?p.paused?u--:(n===a&&(n=null),a=Ae.next,Ae.next=null,e.call(t,Ae.value,Ae.worked),n===null&&p.empty()):--u===0&&p.drain()}function z(){a=null,n=null,p.drain=Gl}function te(){a=null,n=null,p.drain(),p.drain=Gl}function le(he){A=he}}function Gl(){}function Det(){this.value=null,this.callback=Gl,this.next=null,this.release=Gl,this.context=null,this.errorHandler=null;var t=this;this.worked=function(r,o){var a=t.callback,n=t.errorHandler,u=t.value;t.value=null,t.callback=Gl,t.errorHandler&&n(r,u),a.call(t.context,r,o),t.release(t)}}function Pet(t,e,r){typeof t==\"function\"&&(r=e,e=t,t=null);function o(C,I){e.call(this,C).then(function(v){I(null,v)},I)}var a=Qie(t,o,r),n=a.push,u=a.unshift;return a.push=A,a.unshift=p,a.drained=h,a;function A(C){var I=new Promise(function(v,x){n(C,function(E,R){if(E){x(E);return}v(R)})});return I.catch(Gl),I}function p(C){var I=new Promise(function(v,x){u(C,function(E,R){if(E){x(E);return}v(R)})});return I.catch(Gl),I}function h(){var C=a.drain,I=new Promise(function(v){a.drain=function(){C(),v()}});return I}}rO.exports=Qie;rO.exports.promise=Pet});var DS=_(Zu=>{\"use strict\";Object.defineProperty(Zu,\"__esModule\",{value:!0});Zu.joinPathSegments=Zu.replacePathSegmentSeparator=Zu.isAppliedFilter=Zu.isFatalError=void 0;function bet(t,e){return t.errorFilter===null?!0:!t.errorFilter(e)}Zu.isFatalError=bet;function xet(t,e){return t===null||t(e)}Zu.isAppliedFilter=xet;function ket(t,e){return t.split(/[/\\\\]/).join(e)}Zu.replacePathSegmentSeparator=ket;function Qet(t,e,r){return t===\"\"?e:t.endsWith(r)?t+e:t+r+e}Zu.joinPathSegments=Qet});var sO=_(iO=>{\"use strict\";Object.defineProperty(iO,\"__esModule\",{value:!0});var Fet=DS(),nO=class{constructor(e,r){this._root=e,this._settings=r,this._root=Fet.replacePathSegmentSeparator(e,r.pathSegmentSeparator)}};iO.default=nO});var lO=_(aO=>{\"use strict\";Object.defineProperty(aO,\"__esModule\",{value:!0});var Ret=Be(\"events\"),Tet=vS(),Net=Fie(),PS=DS(),Let=sO(),oO=class extends Let.default{constructor(e,r){super(e,r),this._settings=r,this._scandir=Tet.scandir,this._emitter=new Ret.EventEmitter,this._queue=Net(this._worker.bind(this),this._settings.concurrency),this._isFatalError=!1,this._isDestroyed=!1,this._queue.drain=()=>{this._isFatalError||this._emitter.emit(\"end\")}}read(){return this._isFatalError=!1,this._isDestroyed=!1,setImmediate(()=>{this._pushToQueue(this._root,this._settings.basePath)}),this._emitter}get isDestroyed(){return this._isDestroyed}destroy(){if(this._isDestroyed)throw new Error(\"The reader is already destroyed\");this._isDestroyed=!0,this._queue.killAndDrain()}onEntry(e){this._emitter.on(\"entry\",e)}onError(e){this._emitter.once(\"error\",e)}onEnd(e){this._emitter.once(\"end\",e)}_pushToQueue(e,r){let o={directory:e,base:r};this._queue.push(o,a=>{a!==null&&this._handleError(a)})}_worker(e,r){this._scandir(e.directory,this._settings.fsScandirSettings,(o,a)=>{if(o!==null){r(o,void 0);return}for(let n of a)this._handleEntry(n,e.base);r(null,void 0)})}_handleError(e){this._isDestroyed||!PS.isFatalError(this._settings,e)||(this._isFatalError=!0,this._isDestroyed=!0,this._emitter.emit(\"error\",e))}_handleEntry(e,r){if(this._isDestroyed||this._isFatalError)return;let o=e.path;r!==void 0&&(e.path=PS.joinPathSegments(r,e.name,this._settings.pathSegmentSeparator)),PS.isAppliedFilter(this._settings.entryFilter,e)&&this._emitEntry(e),e.dirent.isDirectory()&&PS.isAppliedFilter(this._settings.deepFilter,e)&&this._pushToQueue(o,r===void 0?void 0:e.path)}_emitEntry(e){this._emitter.emit(\"entry\",e)}};aO.default=oO});var Rie=_(uO=>{\"use strict\";Object.defineProperty(uO,\"__esModule\",{value:!0});var Oet=lO(),cO=class{constructor(e,r){this._root=e,this._settings=r,this._reader=new Oet.default(this._root,this._settings),this._storage=[]}read(e){this._reader.onError(r=>{Met(e,r)}),this._reader.onEntry(r=>{this._storage.push(r)}),this._reader.onEnd(()=>{Uet(e,this._storage)}),this._reader.read()}};uO.default=cO;function Met(t,e){t(e)}function Uet(t,e){t(null,e)}});var Tie=_(fO=>{\"use strict\";Object.defineProperty(fO,\"__esModule\",{value:!0});var _et=Be(\"stream\"),Het=lO(),AO=class{constructor(e,r){this._root=e,this._settings=r,this._reader=new Het.default(this._root,this._settings),this._stream=new _et.Readable({objectMode:!0,read:()=>{},destroy:()=>{this._reader.isDestroyed||this._reader.destroy()}})}read(){return this._reader.onError(e=>{this._stream.emit(\"error\",e)}),this._reader.onEntry(e=>{this._stream.push(e)}),this._reader.onEnd(()=>{this._stream.push(null)}),this._reader.read(),this._stream}};fO.default=AO});var Nie=_(hO=>{\"use strict\";Object.defineProperty(hO,\"__esModule\",{value:!0});var jet=vS(),SS=DS(),qet=sO(),pO=class extends qet.default{constructor(){super(...arguments),this._scandir=jet.scandirSync,this._storage=[],this._queue=new Set}read(){return this._pushToQueue(this._root,this._settings.basePath),this._handleQueue(),this._storage}_pushToQueue(e,r){this._queue.add({directory:e,base:r})}_handleQueue(){for(let e of this._queue.values())this._handleDirectory(e.directory,e.base)}_handleDirectory(e,r){try{let o=this._scandir(e,this._settings.fsScandirSettings);for(let a of o)this._handleEntry(a,r)}catch(o){this._handleError(o)}}_handleError(e){if(!!SS.isFatalError(this._settings,e))throw e}_handleEntry(e,r){let o=e.path;r!==void 0&&(e.path=SS.joinPathSegments(r,e.name,this._settings.pathSegmentSeparator)),SS.isAppliedFilter(this._settings.entryFilter,e)&&this._pushToStorage(e),e.dirent.isDirectory()&&SS.isAppliedFilter(this._settings.deepFilter,e)&&this._pushToQueue(o,r===void 0?void 0:e.path)}_pushToStorage(e){this._storage.push(e)}};hO.default=pO});var Lie=_(dO=>{\"use strict\";Object.defineProperty(dO,\"__esModule\",{value:!0});var Get=Nie(),gO=class{constructor(e,r){this._root=e,this._settings=r,this._reader=new Get.default(this._root,this._settings)}read(){return this._reader.read()}};dO.default=gO});var Oie=_(yO=>{\"use strict\";Object.defineProperty(yO,\"__esModule\",{value:!0});var Yet=Be(\"path\"),Wet=vS(),mO=class{constructor(e={}){this._options=e,this.basePath=this._getValue(this._options.basePath,void 0),this.concurrency=this._getValue(this._options.concurrency,Number.POSITIVE_INFINITY),this.deepFilter=this._getValue(this._options.deepFilter,null),this.entryFilter=this._getValue(this._options.entryFilter,null),this.errorFilter=this._getValue(this._options.errorFilter,null),this.pathSegmentSeparator=this._getValue(this._options.pathSegmentSeparator,Yet.sep),this.fsScandirSettings=new Wet.Settings({followSymbolicLinks:this._options.followSymbolicLinks,fs:this._options.fs,pathSegmentSeparator:this._options.pathSegmentSeparator,stats:this._options.stats,throwErrorOnBrokenSymbolicLink:this._options.throwErrorOnBrokenSymbolicLink})}_getValue(e,r){return e??r}};yO.default=mO});var xS=_($u=>{\"use strict\";Object.defineProperty($u,\"__esModule\",{value:!0});$u.Settings=$u.walkStream=$u.walkSync=$u.walk=void 0;var Mie=Rie(),Ket=Tie(),Vet=Lie(),EO=Oie();$u.Settings=EO.default;function zet(t,e,r){if(typeof e==\"function\"){new Mie.default(t,bS()).read(e);return}new Mie.default(t,bS(e)).read(r)}$u.walk=zet;function Jet(t,e){let r=bS(e);return new Vet.default(t,r).read()}$u.walkSync=Jet;function Xet(t,e){let r=bS(e);return new Ket.default(t,r).read()}$u.walkStream=Xet;function bS(t={}){return t instanceof EO.default?t:new EO.default(t)}});var kS=_(wO=>{\"use strict\";Object.defineProperty(wO,\"__esModule\",{value:!0});var Zet=Be(\"path\"),$et=yd(),Uie=vf(),CO=class{constructor(e){this._settings=e,this._fsStatSettings=new $et.Settings({followSymbolicLink:this._settings.followSymbolicLinks,fs:this._settings.fs,throwErrorOnBrokenSymbolicLink:this._settings.followSymbolicLinks})}_getFullEntryPath(e){return Zet.resolve(this._settings.cwd,e)}_makeEntry(e,r){let o={name:r,path:r,dirent:Uie.fs.createDirentFromStats(r,e)};return this._settings.stats&&(o.stats=e),o}_isFatalError(e){return!Uie.errno.isEnoentCodeError(e)&&!this._settings.suppressErrors}};wO.default=CO});var vO=_(BO=>{\"use strict\";Object.defineProperty(BO,\"__esModule\",{value:!0});var ett=Be(\"stream\"),ttt=yd(),rtt=xS(),ntt=kS(),IO=class extends ntt.default{constructor(){super(...arguments),this._walkStream=rtt.walkStream,this._stat=ttt.stat}dynamic(e,r){return this._walkStream(e,r)}static(e,r){let o=e.map(this._getFullEntryPath,this),a=new ett.PassThrough({objectMode:!0});a._write=(n,u,A)=>this._getEntry(o[n],e[n],r).then(p=>{p!==null&&r.entryFilter(p)&&a.push(p),n===o.length-1&&a.end(),A()}).catch(A);for(let n=0;n<o.length;n++)a.write(n);return a}_getEntry(e,r,o){return this._getStat(e).then(a=>this._makeEntry(a,r)).catch(a=>{if(o.errorFilter(a))return null;throw a})}_getStat(e){return new Promise((r,o)=>{this._stat(e,this._fsStatSettings,(a,n)=>a===null?r(n):o(a))})}};BO.default=IO});var _ie=_(PO=>{\"use strict\";Object.defineProperty(PO,\"__esModule\",{value:!0});var itt=xS(),stt=kS(),ott=vO(),DO=class extends stt.default{constructor(){super(...arguments),this._walkAsync=itt.walk,this._readerStream=new ott.default(this._settings)}dynamic(e,r){return new Promise((o,a)=>{this._walkAsync(e,r,(n,u)=>{n===null?o(u):a(n)})})}async static(e,r){let o=[],a=this._readerStream.static(e,r);return new Promise((n,u)=>{a.once(\"error\",u),a.on(\"data\",A=>o.push(A)),a.once(\"end\",()=>n(o))})}};PO.default=DO});var Hie=_(bO=>{\"use strict\";Object.defineProperty(bO,\"__esModule\",{value:!0});var tE=vf(),SO=class{constructor(e,r,o){this._patterns=e,this._settings=r,this._micromatchOptions=o,this._storage=[],this._fillStorage()}_fillStorage(){let e=tE.pattern.expandPatternsWithBraceExpansion(this._patterns);for(let r of e){let o=this._getPatternSegments(r),a=this._splitSegmentsIntoSections(o);this._storage.push({complete:a.length<=1,pattern:r,segments:o,sections:a})}}_getPatternSegments(e){return tE.pattern.getPatternParts(e,this._micromatchOptions).map(o=>tE.pattern.isDynamicPattern(o,this._settings)?{dynamic:!0,pattern:o,patternRe:tE.pattern.makeRe(o,this._micromatchOptions)}:{dynamic:!1,pattern:o})}_splitSegmentsIntoSections(e){return tE.array.splitWhen(e,r=>r.dynamic&&tE.pattern.hasGlobStar(r.pattern))}};bO.default=SO});var jie=_(kO=>{\"use strict\";Object.defineProperty(kO,\"__esModule\",{value:!0});var att=Hie(),xO=class extends att.default{match(e){let r=e.split(\"/\"),o=r.length,a=this._storage.filter(n=>!n.complete||n.segments.length>o);for(let n of a){let u=n.sections[0];if(!n.complete&&o>u.length||r.every((p,h)=>{let C=n.segments[h];return!!(C.dynamic&&C.patternRe.test(p)||!C.dynamic&&C.pattern===p)}))return!0}return!1}};kO.default=xO});var qie=_(FO=>{\"use strict\";Object.defineProperty(FO,\"__esModule\",{value:!0});var QS=vf(),ltt=jie(),QO=class{constructor(e,r){this._settings=e,this._micromatchOptions=r}getFilter(e,r,o){let a=this._getMatcher(r),n=this._getNegativePatternsRe(o);return u=>this._filter(e,u,a,n)}_getMatcher(e){return new ltt.default(e,this._settings,this._micromatchOptions)}_getNegativePatternsRe(e){let r=e.filter(QS.pattern.isAffectDepthOfReadingPattern);return QS.pattern.convertPatternsToRe(r,this._micromatchOptions)}_filter(e,r,o,a){if(this._isSkippedByDeep(e,r.path)||this._isSkippedSymbolicLink(r))return!1;let n=QS.path.removeLeadingDotSegment(r.path);return this._isSkippedByPositivePatterns(n,o)?!1:this._isSkippedByNegativePatterns(n,a)}_isSkippedByDeep(e,r){return this._settings.deep===1/0?!1:this._getEntryLevel(e,r)>=this._settings.deep}_getEntryLevel(e,r){let o=r.split(\"/\").length;if(e===\"\")return o;let a=e.split(\"/\").length;return o-a}_isSkippedSymbolicLink(e){return!this._settings.followSymbolicLinks&&e.dirent.isSymbolicLink()}_isSkippedByPositivePatterns(e,r){return!this._settings.baseNameMatch&&!r.match(e)}_isSkippedByNegativePatterns(e,r){return!QS.pattern.matchAny(e,r)}};FO.default=QO});var Gie=_(TO=>{\"use strict\";Object.defineProperty(TO,\"__esModule\",{value:!0});var Ed=vf(),RO=class{constructor(e,r){this._settings=e,this._micromatchOptions=r,this.index=new Map}getFilter(e,r){let o=Ed.pattern.convertPatternsToRe(e,this._micromatchOptions),a=Ed.pattern.convertPatternsToRe(r,this._micromatchOptions);return n=>this._filter(n,o,a)}_filter(e,r,o){if(this._settings.unique&&this._isDuplicateEntry(e)||this._onlyFileFilter(e)||this._onlyDirectoryFilter(e)||this._isSkippedByAbsoluteNegativePatterns(e.path,o))return!1;let a=this._settings.baseNameMatch?e.name:e.path,n=e.dirent.isDirectory(),u=this._isMatchToPatterns(a,r,n)&&!this._isMatchToPatterns(e.path,o,n);return this._settings.unique&&u&&this._createIndexRecord(e),u}_isDuplicateEntry(e){return this.index.has(e.path)}_createIndexRecord(e){this.index.set(e.path,void 0)}_onlyFileFilter(e){return this._settings.onlyFiles&&!e.dirent.isFile()}_onlyDirectoryFilter(e){return this._settings.onlyDirectories&&!e.dirent.isDirectory()}_isSkippedByAbsoluteNegativePatterns(e,r){if(!this._settings.absolute)return!1;let o=Ed.path.makeAbsolute(this._settings.cwd,e);return Ed.pattern.matchAny(o,r)}_isMatchToPatterns(e,r,o){let a=Ed.path.removeLeadingDotSegment(e),n=Ed.pattern.matchAny(a,r);return!n&&o?Ed.pattern.matchAny(a+\"/\",r):n}};TO.default=RO});var Yie=_(LO=>{\"use strict\";Object.defineProperty(LO,\"__esModule\",{value:!0});var ctt=vf(),NO=class{constructor(e){this._settings=e}getFilter(){return e=>this._isNonFatalError(e)}_isNonFatalError(e){return ctt.errno.isEnoentCodeError(e)||this._settings.suppressErrors}};LO.default=NO});var Kie=_(MO=>{\"use strict\";Object.defineProperty(MO,\"__esModule\",{value:!0});var Wie=vf(),OO=class{constructor(e){this._settings=e}getTransformer(){return e=>this._transform(e)}_transform(e){let r=e.path;return this._settings.absolute&&(r=Wie.path.makeAbsolute(this._settings.cwd,r),r=Wie.path.unixify(r)),this._settings.markDirectories&&e.dirent.isDirectory()&&(r+=\"/\"),this._settings.objectMode?Object.assign(Object.assign({},e),{path:r}):r}};MO.default=OO});var RS=_(_O=>{\"use strict\";Object.defineProperty(_O,\"__esModule\",{value:!0});var utt=Be(\"path\"),Att=qie(),ftt=Gie(),ptt=Yie(),htt=Kie(),UO=class{constructor(e){this._settings=e,this.errorFilter=new ptt.default(this._settings),this.entryFilter=new ftt.default(this._settings,this._getMicromatchOptions()),this.deepFilter=new Att.default(this._settings,this._getMicromatchOptions()),this.entryTransformer=new htt.default(this._settings)}_getRootDirectory(e){return utt.resolve(this._settings.cwd,e.base)}_getReaderOptions(e){let r=e.base===\".\"?\"\":e.base;return{basePath:r,pathSegmentSeparator:\"/\",concurrency:this._settings.concurrency,deepFilter:this.deepFilter.getFilter(r,e.positive,e.negative),entryFilter:this.entryFilter.getFilter(e.positive,e.negative),errorFilter:this.errorFilter.getFilter(),followSymbolicLinks:this._settings.followSymbolicLinks,fs:this._settings.fs,stats:this._settings.stats,throwErrorOnBrokenSymbolicLink:this._settings.throwErrorOnBrokenSymbolicLink,transform:this.entryTransformer.getTransformer()}}_getMicromatchOptions(){return{dot:this._settings.dot,matchBase:this._settings.baseNameMatch,nobrace:!this._settings.braceExpansion,nocase:!this._settings.caseSensitiveMatch,noext:!this._settings.extglob,noglobstar:!this._settings.globstar,posix:!0,strictSlashes:!1}}};_O.default=UO});var Vie=_(jO=>{\"use strict\";Object.defineProperty(jO,\"__esModule\",{value:!0});var gtt=_ie(),dtt=RS(),HO=class extends dtt.default{constructor(){super(...arguments),this._reader=new gtt.default(this._settings)}async read(e){let r=this._getRootDirectory(e),o=this._getReaderOptions(e);return(await this.api(r,e,o)).map(n=>o.transform(n))}api(e,r,o){return r.dynamic?this._reader.dynamic(e,o):this._reader.static(r.patterns,o)}};jO.default=HO});var zie=_(GO=>{\"use strict\";Object.defineProperty(GO,\"__esModule\",{value:!0});var mtt=Be(\"stream\"),ytt=vO(),Ett=RS(),qO=class extends Ett.default{constructor(){super(...arguments),this._reader=new ytt.default(this._settings)}read(e){let r=this._getRootDirectory(e),o=this._getReaderOptions(e),a=this.api(r,e,o),n=new mtt.Readable({objectMode:!0,read:()=>{}});return a.once(\"error\",u=>n.emit(\"error\",u)).on(\"data\",u=>n.emit(\"data\",o.transform(u))).once(\"end\",()=>n.emit(\"end\")),n.once(\"close\",()=>a.destroy()),n}api(e,r,o){return r.dynamic?this._reader.dynamic(e,o):this._reader.static(r.patterns,o)}};GO.default=qO});var Jie=_(WO=>{\"use strict\";Object.defineProperty(WO,\"__esModule\",{value:!0});var Ctt=yd(),wtt=xS(),Itt=kS(),YO=class extends Itt.default{constructor(){super(...arguments),this._walkSync=wtt.walkSync,this._statSync=Ctt.statSync}dynamic(e,r){return this._walkSync(e,r)}static(e,r){let o=[];for(let a of e){let n=this._getFullEntryPath(a),u=this._getEntry(n,a,r);u===null||!r.entryFilter(u)||o.push(u)}return o}_getEntry(e,r,o){try{let a=this._getStat(e);return this._makeEntry(a,r)}catch(a){if(o.errorFilter(a))return null;throw a}}_getStat(e){return this._statSync(e,this._fsStatSettings)}};WO.default=YO});var Xie=_(VO=>{\"use strict\";Object.defineProperty(VO,\"__esModule\",{value:!0});var Btt=Jie(),vtt=RS(),KO=class extends vtt.default{constructor(){super(...arguments),this._reader=new Btt.default(this._settings)}read(e){let r=this._getRootDirectory(e),o=this._getReaderOptions(e);return this.api(r,e,o).map(o.transform)}api(e,r,o){return r.dynamic?this._reader.dynamic(e,o):this._reader.static(r.patterns,o)}};VO.default=KO});var Zie=_(nE=>{\"use strict\";Object.defineProperty(nE,\"__esModule\",{value:!0});nE.DEFAULT_FILE_SYSTEM_ADAPTER=void 0;var rE=Be(\"fs\"),Dtt=Be(\"os\"),Ptt=Math.max(Dtt.cpus().length,1);nE.DEFAULT_FILE_SYSTEM_ADAPTER={lstat:rE.lstat,lstatSync:rE.lstatSync,stat:rE.stat,statSync:rE.statSync,readdir:rE.readdir,readdirSync:rE.readdirSync};var zO=class{constructor(e={}){this._options=e,this.absolute=this._getValue(this._options.absolute,!1),this.baseNameMatch=this._getValue(this._options.baseNameMatch,!1),this.braceExpansion=this._getValue(this._options.braceExpansion,!0),this.caseSensitiveMatch=this._getValue(this._options.caseSensitiveMatch,!0),this.concurrency=this._getValue(this._options.concurrency,Ptt),this.cwd=this._getValue(this._options.cwd,process.cwd()),this.deep=this._getValue(this._options.deep,1/0),this.dot=this._getValue(this._options.dot,!1),this.extglob=this._getValue(this._options.extglob,!0),this.followSymbolicLinks=this._getValue(this._options.followSymbolicLinks,!0),this.fs=this._getFileSystemMethods(this._options.fs),this.globstar=this._getValue(this._options.globstar,!0),this.ignore=this._getValue(this._options.ignore,[]),this.markDirectories=this._getValue(this._options.markDirectories,!1),this.objectMode=this._getValue(this._options.objectMode,!1),this.onlyDirectories=this._getValue(this._options.onlyDirectories,!1),this.onlyFiles=this._getValue(this._options.onlyFiles,!0),this.stats=this._getValue(this._options.stats,!1),this.suppressErrors=this._getValue(this._options.suppressErrors,!1),this.throwErrorOnBrokenSymbolicLink=this._getValue(this._options.throwErrorOnBrokenSymbolicLink,!1),this.unique=this._getValue(this._options.unique,!0),this.onlyDirectories&&(this.onlyFiles=!1),this.stats&&(this.objectMode=!0)}_getValue(e,r){return e===void 0?r:e}_getFileSystemMethods(e={}){return Object.assign(Object.assign({},nE.DEFAULT_FILE_SYSTEM_ADAPTER),e)}};nE.default=zO});var TS=_((BNt,tse)=>{\"use strict\";var $ie=tie(),ese=nie(),Stt=Vie(),btt=zie(),xtt=Xie(),JO=Zie(),Cd=vf();async function XO(t,e){iE(t);let r=ZO(t,Stt.default,e),o=await Promise.all(r);return Cd.array.flatten(o)}(function(t){function e(u,A){iE(u);let p=ZO(u,xtt.default,A);return Cd.array.flatten(p)}t.sync=e;function r(u,A){iE(u);let p=ZO(u,btt.default,A);return Cd.stream.merge(p)}t.stream=r;function o(u,A){iE(u);let p=ese.transform([].concat(u)),h=new JO.default(A);return $ie.generate(p,h)}t.generateTasks=o;function a(u,A){iE(u);let p=new JO.default(A);return Cd.pattern.isDynamicPattern(u,p)}t.isDynamicPattern=a;function n(u){return iE(u),Cd.path.escape(u)}t.escapePath=n})(XO||(XO={}));function ZO(t,e,r){let o=ese.transform([].concat(t)),a=new JO.default(r),n=$ie.generate(o,a),u=new e(a);return n.map(u.read,u)}function iE(t){if(![].concat(t).every(o=>Cd.string.isString(o)&&!Cd.string.isEmpty(o)))throw new TypeError(\"Patterns must be a string (non empty) or an array of strings\")}tse.exports=XO});var wn={};Vt(wn,{checksumFile:()=>LS,checksumPattern:()=>OS,makeHash:()=>Js});function Js(...t){let e=(0,NS.createHash)(\"sha512\"),r=\"\";for(let o of t)typeof o==\"string\"?r+=o:o&&(r&&(e.update(r),r=\"\"),e.update(o));return r&&e.update(r),e.digest(\"hex\")}async function LS(t,{baseFs:e,algorithm:r}={baseFs:oe,algorithm:\"sha512\"}){let o=await e.openPromise(t,\"r\");try{let n=Buffer.allocUnsafeSlow(65536),u=(0,NS.createHash)(r),A=0;for(;(A=await e.readPromise(o,n,0,65536))!==0;)u.update(A===65536?n:n.slice(0,A));return u.digest(\"hex\")}finally{await e.closePromise(o)}}async function OS(t,{cwd:e}){let o=(await(0,$O.default)(t,{cwd:ue.fromPortablePath(e),onlyDirectories:!0})).map(A=>`${A}/**/*`),a=await(0,$O.default)([t,...o],{cwd:ue.fromPortablePath(e),onlyFiles:!1});a.sort();let n=await Promise.all(a.map(async A=>{let p=[Buffer.from(A)],h=ue.toPortablePath(A),C=await oe.lstatPromise(h);return C.isSymbolicLink()?p.push(Buffer.from(await oe.readlinkPromise(h))):C.isFile()&&p.push(await oe.readFilePromise(h)),p.join(\"\\0\")})),u=(0,NS.createHash)(\"sha512\");for(let A of n)u.update(A);return u.digest(\"hex\")}var NS,$O,rh=Et(()=>{Pt();NS=Be(\"crypto\"),$O=$e(TS())});var W={};Vt(W,{areDescriptorsEqual:()=>ose,areIdentsEqual:()=>t1,areLocatorsEqual:()=>r1,areVirtualPackagesEquivalent:()=>Mtt,bindDescriptor:()=>Ltt,bindLocator:()=>Ott,convertDescriptorToLocator:()=>MS,convertLocatorToDescriptor:()=>tM,convertPackageToLocator:()=>Rtt,convertToIdent:()=>Ftt,convertToManifestRange:()=>Vtt,copyPackage:()=>ZI,devirtualizeDescriptor:()=>$I,devirtualizeLocator:()=>e1,ensureDevirtualizedDescriptor:()=>Ttt,ensureDevirtualizedLocator:()=>Ntt,getIdentVendorPath:()=>sM,isPackageCompatible:()=>qS,isVirtualDescriptor:()=>Pf,isVirtualLocator:()=>Hc,makeDescriptor:()=>In,makeIdent:()=>eA,makeLocator:()=>Qs,makeRange:()=>HS,parseDescriptor:()=>nh,parseFileStyleRange:()=>Wtt,parseIdent:()=>zs,parseLocator:()=>Sf,parseRange:()=>wd,prettyDependent:()=>FL,prettyDescriptor:()=>qn,prettyIdent:()=>cs,prettyLocator:()=>jr,prettyLocatorNoColors:()=>QL,prettyRange:()=>aE,prettyReference:()=>i1,prettyResolution:()=>JI,prettyWorkspace:()=>s1,renamePackage:()=>rM,slugifyIdent:()=>eM,slugifyLocator:()=>oE,sortDescriptors:()=>lE,stringifyDescriptor:()=>Sa,stringifyIdent:()=>fn,stringifyLocator:()=>ba,tryParseDescriptor:()=>n1,tryParseIdent:()=>ase,tryParseLocator:()=>_S,tryParseRange:()=>Ytt,virtualizeDescriptor:()=>nM,virtualizePackage:()=>iM});function eA(t,e){if(t?.startsWith(\"@\"))throw new Error(\"Invalid scope: don't prefix it with '@'\");return{identHash:Js(t,e),scope:t,name:e}}function In(t,e){return{identHash:t.identHash,scope:t.scope,name:t.name,descriptorHash:Js(t.identHash,e),range:e}}function Qs(t,e){return{identHash:t.identHash,scope:t.scope,name:t.name,locatorHash:Js(t.identHash,e),reference:e}}function Ftt(t){return{identHash:t.identHash,scope:t.scope,name:t.name}}function MS(t){return{identHash:t.identHash,scope:t.scope,name:t.name,locatorHash:t.descriptorHash,reference:t.range}}function tM(t){return{identHash:t.identHash,scope:t.scope,name:t.name,descriptorHash:t.locatorHash,range:t.reference}}function Rtt(t){return{identHash:t.identHash,scope:t.scope,name:t.name,locatorHash:t.locatorHash,reference:t.reference}}function rM(t,e){return{identHash:e.identHash,scope:e.scope,name:e.name,locatorHash:e.locatorHash,reference:e.reference,version:t.version,languageName:t.languageName,linkType:t.linkType,conditions:t.conditions,dependencies:new Map(t.dependencies),peerDependencies:new Map(t.peerDependencies),dependenciesMeta:new Map(t.dependenciesMeta),peerDependenciesMeta:new Map(t.peerDependenciesMeta),bin:new Map(t.bin)}}function ZI(t){return rM(t,t)}function nM(t,e){if(e.includes(\"#\"))throw new Error(\"Invalid entropy\");return In(t,`virtual:${e}#${t.range}`)}function iM(t,e){if(e.includes(\"#\"))throw new Error(\"Invalid entropy\");return rM(t,Qs(t,`virtual:${e}#${t.reference}`))}function Pf(t){return t.range.startsWith(XI)}function Hc(t){return t.reference.startsWith(XI)}function $I(t){if(!Pf(t))throw new Error(\"Not a virtual descriptor\");return In(t,t.range.replace(US,\"\"))}function e1(t){if(!Hc(t))throw new Error(\"Not a virtual descriptor\");return Qs(t,t.reference.replace(US,\"\"))}function Ttt(t){return Pf(t)?In(t,t.range.replace(US,\"\")):t}function Ntt(t){return Hc(t)?Qs(t,t.reference.replace(US,\"\")):t}function Ltt(t,e){return t.range.includes(\"::\")?t:In(t,`${t.range}::${sE.default.stringify(e)}`)}function Ott(t,e){return t.reference.includes(\"::\")?t:Qs(t,`${t.reference}::${sE.default.stringify(e)}`)}function t1(t,e){return t.identHash===e.identHash}function ose(t,e){return t.descriptorHash===e.descriptorHash}function r1(t,e){return t.locatorHash===e.locatorHash}function Mtt(t,e){if(!Hc(t))throw new Error(\"Invalid package type\");if(!Hc(e))throw new Error(\"Invalid package type\");if(!t1(t,e)||t.dependencies.size!==e.dependencies.size)return!1;for(let r of t.dependencies.values()){let o=e.dependencies.get(r.identHash);if(!o||!ose(r,o))return!1}return!0}function zs(t){let e=ase(t);if(!e)throw new Error(`Invalid ident (${t})`);return e}function ase(t){let e=t.match(Utt);if(!e)return null;let[,r,o]=e;return eA(typeof r<\"u\"?r:null,o)}function nh(t,e=!1){let r=n1(t,e);if(!r)throw new Error(`Invalid descriptor (${t})`);return r}function n1(t,e=!1){let r=e?t.match(_tt):t.match(Htt);if(!r)return null;let[,o,a,n]=r;if(n===\"unknown\")throw new Error(`Invalid range (${t})`);let u=typeof o<\"u\"?o:null,A=typeof n<\"u\"?n:\"unknown\";return In(eA(u,a),A)}function Sf(t,e=!1){let r=_S(t,e);if(!r)throw new Error(`Invalid locator (${t})`);return r}function _S(t,e=!1){let r=e?t.match(jtt):t.match(qtt);if(!r)return null;let[,o,a,n]=r;if(n===\"unknown\")throw new Error(`Invalid reference (${t})`);let u=typeof o<\"u\"?o:null,A=typeof n<\"u\"?n:\"unknown\";return Qs(eA(u,a),A)}function wd(t,e){let r=t.match(Gtt);if(r===null)throw new Error(`Invalid range (${t})`);let o=typeof r[1]<\"u\"?r[1]:null;if(typeof e?.requireProtocol==\"string\"&&o!==e.requireProtocol)throw new Error(`Invalid protocol (${o})`);if(e?.requireProtocol&&o===null)throw new Error(`Missing protocol (${o})`);let a=typeof r[3]<\"u\"?decodeURIComponent(r[2]):null;if(e?.requireSource&&a===null)throw new Error(`Missing source (${t})`);let n=typeof r[3]<\"u\"?decodeURIComponent(r[3]):decodeURIComponent(r[2]),u=e?.parseSelector?sE.default.parse(n):n,A=typeof r[4]<\"u\"?sE.default.parse(r[4]):null;return{protocol:o,source:a,selector:u,params:A}}function Ytt(t,e){try{return wd(t,e)}catch{return null}}function Wtt(t,{protocol:e}){let{selector:r,params:o}=wd(t,{requireProtocol:e,requireBindings:!0});if(typeof o.locator!=\"string\")throw new Error(`Assertion failed: Invalid bindings for ${t}`);return{parentLocator:Sf(o.locator,!0),path:r}}function rse(t){return t=t.replaceAll(\"%\",\"%25\"),t=t.replaceAll(\":\",\"%3A\"),t=t.replaceAll(\"#\",\"%23\"),t}function Ktt(t){return t===null?!1:Object.entries(t).length>0}function HS({protocol:t,source:e,selector:r,params:o}){let a=\"\";return t!==null&&(a+=`${t}`),e!==null&&(a+=`${rse(e)}#`),a+=rse(r),Ktt(o)&&(a+=`::${sE.default.stringify(o)}`),a}function Vtt(t){let{params:e,protocol:r,source:o,selector:a}=wd(t);for(let n in e)n.startsWith(\"__\")&&delete e[n];return HS({protocol:r,source:o,params:e,selector:a})}function fn(t){return t.scope?`@${t.scope}/${t.name}`:`${t.name}`}function Sa(t){return t.scope?`@${t.scope}/${t.name}@${t.range}`:`${t.name}@${t.range}`}function ba(t){return t.scope?`@${t.scope}/${t.name}@${t.reference}`:`${t.name}@${t.reference}`}function eM(t){return t.scope!==null?`@${t.scope}-${t.name}`:t.name}function oE(t){let{protocol:e,selector:r}=wd(t.reference),o=e!==null?e.replace(ztt,\"\"):\"exotic\",a=nse.default.valid(r),n=a!==null?`${o}-${a}`:`${o}`,u=10;return t.scope?`${eM(t)}-${n}-${t.locatorHash.slice(0,u)}`:`${eM(t)}-${n}-${t.locatorHash.slice(0,u)}`}function cs(t,e){return e.scope?`${Mt(t,`@${e.scope}/`,yt.SCOPE)}${Mt(t,e.name,yt.NAME)}`:`${Mt(t,e.name,yt.NAME)}`}function jS(t){if(t.startsWith(XI)){let e=jS(t.substring(t.indexOf(\"#\")+1)),r=t.substring(XI.length,XI.length+ktt);return`${e} [${r}]`}else return t.replace(Jtt,\"?[...]\")}function aE(t,e){return`${Mt(t,jS(e),yt.RANGE)}`}function qn(t,e){return`${cs(t,e)}${Mt(t,\"@\",yt.RANGE)}${aE(t,e.range)}`}function i1(t,e){return`${Mt(t,jS(e),yt.REFERENCE)}`}function jr(t,e){return`${cs(t,e)}${Mt(t,\"@\",yt.REFERENCE)}${i1(t,e.reference)}`}function QL(t){return`${fn(t)}@${jS(t.reference)}`}function lE(t){return ks(t,[e=>fn(e),e=>e.range])}function s1(t,e){return cs(t,e.anchoredLocator)}function JI(t,e,r){let o=Pf(e)?$I(e):e;return r===null?`${qn(t,o)} \\u2192 ${kL(t).Cross}`:o.identHash===r.identHash?`${qn(t,o)} \\u2192 ${i1(t,r.reference)}`:`${qn(t,o)} \\u2192 ${jr(t,r)}`}function FL(t,e,r){return r===null?`${jr(t,e)}`:`${jr(t,e)} (via ${aE(t,r.range)})`}function sM(t){return`node_modules/${fn(t)}`}function qS(t,e){return t.conditions?Qtt(t.conditions,r=>{let[,o,a]=r.match(sse),n=e[o];return n?n.includes(a):!0}):!0}var sE,nse,ise,XI,ktt,sse,Qtt,US,Utt,_tt,Htt,jtt,qtt,Gtt,ztt,Jtt,bo=Et(()=>{sE=$e(Be(\"querystring\")),nse=$e(Jn()),ise=$e(nX());ql();rh();jl();bo();XI=\"virtual:\",ktt=5,sse=/(os|cpu|libc)=([a-z0-9_-]+)/,Qtt=(0,ise.makeParser)(sse);US=/^[^#]*#/;Utt=/^(?:@([^/]+?)\\/)?([^@/]+)$/;_tt=/^(?:@([^/]+?)\\/)?([^@/]+?)(?:@(.+))$/,Htt=/^(?:@([^/]+?)\\/)?([^@/]+?)(?:@(.+))?$/;jtt=/^(?:@([^/]+?)\\/)?([^@/]+?)(?:@(.+))$/,qtt=/^(?:@([^/]+?)\\/)?([^@/]+?)(?:@(.+))?$/;Gtt=/^([^#:]*:)?((?:(?!::)[^#])*)(?:#((?:(?!::).)*))?(?:::(.*))?$/;ztt=/:$/;Jtt=/\\?.*/});var lse,cse=Et(()=>{bo();lse={hooks:{reduceDependency:(t,e,r,o,{resolver:a,resolveOptions:n})=>{for(let{pattern:u,reference:A}of e.topLevelWorkspace.manifest.resolutions){if(u.from&&(u.from.fullName!==fn(r)||e.configuration.normalizeLocator(Qs(zs(u.from.fullName),u.from.description??r.reference)).locatorHash!==r.locatorHash)||u.descriptor.fullName!==fn(t)||e.configuration.normalizeDependency(In(Sf(u.descriptor.fullName),u.descriptor.description??t.range)).descriptorHash!==t.descriptorHash)continue;return a.bindDescriptor(e.configuration.normalizeDependency(In(t,A)),e.topLevelWorkspace.anchoredLocator,n)}return t},validateProject:async(t,e)=>{for(let r of t.workspaces){let o=s1(t.configuration,r);await t.configuration.triggerHook(a=>a.validateWorkspace,r,{reportWarning:(a,n)=>e.reportWarning(a,`${o}: ${n}`),reportError:(a,n)=>e.reportError(a,`${o}: ${n}`)})}},validateWorkspace:async(t,e)=>{let{manifest:r}=t;r.resolutions.length&&t.cwd!==t.project.cwd&&r.errors.push(new Error(\"Resolutions field will be ignored\"));for(let o of r.errors)e.reportWarning(57,o.message)}}}});var o1,Xn,Id=Et(()=>{o1=class{supportsDescriptor(e,r){return!!(e.range.startsWith(o1.protocol)||r.project.tryWorkspaceByDescriptor(e)!==null)}supportsLocator(e,r){return!!e.reference.startsWith(o1.protocol)}shouldPersistResolution(e,r){return!1}bindDescriptor(e,r,o){return e}getResolutionDependencies(e,r){return{}}async getCandidates(e,r,o){return[o.project.getWorkspaceByDescriptor(e).anchoredLocator]}async getSatisfying(e,r,o,a){let[n]=await this.getCandidates(e,r,a);return{locators:o.filter(u=>u.locatorHash===n.locatorHash),sorted:!1}}async resolve(e,r){let o=r.project.getWorkspaceByCwd(e.reference.slice(o1.protocol.length));return{...e,version:o.manifest.version||\"0.0.0\",languageName:\"unknown\",linkType:\"SOFT\",conditions:null,dependencies:r.project.configuration.normalizeDependencyMap(new Map([...o.manifest.dependencies,...o.manifest.devDependencies])),peerDependencies:new Map([...o.manifest.peerDependencies]),dependenciesMeta:o.manifest.dependenciesMeta,peerDependenciesMeta:o.manifest.peerDependenciesMeta,bin:o.manifest.bin}}},Xn=o1;Xn.protocol=\"workspace:\"});var kr={};Vt(kr,{SemVer:()=>hse.SemVer,clean:()=>Ztt,getComparator:()=>fse,mergeComparators:()=>oM,satisfiesWithPrereleases:()=>bf,simplifyRanges:()=>aM,stringifyComparator:()=>pse,validRange:()=>xa});function bf(t,e,r=!1){if(!t)return!1;let o=`${e}${r}`,a=use.get(o);if(typeof a>\"u\")try{a=new ih.default.Range(e,{includePrerelease:!0,loose:r})}catch{return!1}finally{use.set(o,a||null)}else if(a===null)return!1;let n;try{n=new ih.default.SemVer(t,a)}catch{return!1}return a.test(n)?!0:(n.prerelease&&(n.prerelease=[]),a.set.some(u=>{for(let A of u)A.semver.prerelease&&(A.semver.prerelease=[]);return u.every(A=>A.test(n))}))}function xa(t){if(t.indexOf(\":\")!==-1)return null;let e=Ase.get(t);if(typeof e<\"u\")return e;try{e=new ih.default.Range(t)}catch{e=null}return Ase.set(t,e),e}function Ztt(t){let e=Xtt.exec(t);return e?e[1]:null}function fse(t){if(t.semver===ih.default.Comparator.ANY)return{gt:null,lt:null};switch(t.operator){case\"\":return{gt:[\">=\",t.semver],lt:[\"<=\",t.semver]};case\">\":case\">=\":return{gt:[t.operator,t.semver],lt:null};case\"<\":case\"<=\":return{gt:null,lt:[t.operator,t.semver]};default:throw new Error(`Assertion failed: Unexpected comparator operator (${t.operator})`)}}function oM(t){if(t.length===0)return null;let e=null,r=null;for(let o of t){if(o.gt){let a=e!==null?ih.default.compare(o.gt[1],e[1]):null;(a===null||a>0||a===0&&o.gt[0]===\">\")&&(e=o.gt)}if(o.lt){let a=r!==null?ih.default.compare(o.lt[1],r[1]):null;(a===null||a<0||a===0&&o.lt[0]===\"<\")&&(r=o.lt)}}if(e&&r){let o=ih.default.compare(e[1],r[1]);if(o===0&&(e[0]===\">\"||r[0]===\"<\")||o>0)return null}return{gt:e,lt:r}}function pse(t){if(t.gt&&t.lt){if(t.gt[0]===\">=\"&&t.lt[0]===\"<=\"&&t.gt[1].version===t.lt[1].version)return t.gt[1].version;if(t.gt[0]===\">=\"&&t.lt[0]===\"<\"){if(t.lt[1].version===`${t.gt[1].major+1}.0.0-0`)return`^${t.gt[1].version}`;if(t.lt[1].version===`${t.gt[1].major}.${t.gt[1].minor+1}.0-0`)return`~${t.gt[1].version}`}}let e=[];return t.gt&&e.push(t.gt[0]+t.gt[1].version),t.lt&&e.push(t.lt[0]+t.lt[1].version),e.length?e.join(\" \"):\"*\"}function aM(t){let e=t.map(o=>xa(o).set.map(a=>a.map(n=>fse(n)))),r=e.shift().map(o=>oM(o)).filter(o=>o!==null);for(let o of e){let a=[];for(let n of r)for(let u of o){let A=oM([n,...u]);A!==null&&a.push(A)}r=a}return r.length===0?null:r.map(o=>pse(o)).join(\" || \")}var ih,hse,use,Ase,Xtt,xf=Et(()=>{ih=$e(Jn()),hse=$e(Jn()),use=new Map;Ase=new Map;Xtt=/^(?:[\\sv=]*?)((0|[1-9]\\d*)\\.(0|[1-9]\\d*)\\.(0|[1-9]\\d*)(?:-((?:0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\\.(?:0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\\+([0-9a-zA-Z-]+(?:\\.[0-9a-zA-Z-]+)*))?)(?:\\s*)$/});function gse(t){let e=t.match(/^[ \\t]+/m);return e?e[0]:\"  \"}function dse(t){return t.charCodeAt(0)===65279?t.slice(1):t}function $o(t){return t.replace(/\\\\/g,\"/\")}function GS(t,{yamlCompatibilityMode:e}){return e?IL(t):typeof t>\"u\"||typeof t==\"boolean\"?t:null}function mse(t,e){let r=e.search(/[^!]/);if(r===-1)return\"invalid\";let o=r%2===0?\"\":\"!\",a=e.slice(r);return`${o}${t}=${a}`}function lM(t,e){return e.length===1?mse(t,e[0]):`(${e.map(r=>mse(t,r)).join(\" | \")})`}var yse,cE,Ot,uE=Et(()=>{Pt();Nl();yse=$e(Jn());Id();jl();xf();bo();cE=class{constructor(){this.indent=\"  \";this.name=null;this.version=null;this.os=null;this.cpu=null;this.libc=null;this.type=null;this.packageManager=null;this.private=!1;this.license=null;this.main=null;this.module=null;this.browser=null;this.languageName=null;this.bin=new Map;this.scripts=new Map;this.dependencies=new Map;this.devDependencies=new Map;this.peerDependencies=new Map;this.workspaceDefinitions=[];this.dependenciesMeta=new Map;this.peerDependenciesMeta=new Map;this.resolutions=[];this.files=null;this.publishConfig=null;this.installConfig=null;this.preferUnplugged=null;this.raw={};this.errors=[]}static async tryFind(e,{baseFs:r=new Tn}={}){let o=V.join(e,\"package.json\");try{return await cE.fromFile(o,{baseFs:r})}catch(a){if(a.code===\"ENOENT\")return null;throw a}}static async find(e,{baseFs:r}={}){let o=await cE.tryFind(e,{baseFs:r});if(o===null)throw new Error(\"Manifest not found\");return o}static async fromFile(e,{baseFs:r=new Tn}={}){let o=new cE;return await o.loadFile(e,{baseFs:r}),o}static fromText(e){let r=new cE;return r.loadFromText(e),r}loadFromText(e){let r;try{r=JSON.parse(dse(e)||\"{}\")}catch(o){throw o.message+=` (when parsing ${e})`,o}this.load(r),this.indent=gse(e)}async loadFile(e,{baseFs:r=new Tn}){let o=await r.readFilePromise(e,\"utf8\"),a;try{a=JSON.parse(dse(o)||\"{}\")}catch(n){throw n.message+=` (when parsing ${e})`,n}this.load(a),this.indent=gse(o)}load(e,{yamlCompatibilityMode:r=!1}={}){if(typeof e!=\"object\"||e===null)throw new Error(`Utterly invalid manifest data (${e})`);this.raw=e;let o=[];if(this.name=null,typeof e.name==\"string\")try{this.name=zs(e.name)}catch{o.push(new Error(\"Parsing failed for the 'name' field\"))}if(typeof e.version==\"string\"?this.version=e.version:this.version=null,Array.isArray(e.os)){let n=[];this.os=n;for(let u of e.os)typeof u!=\"string\"?o.push(new Error(\"Parsing failed for the 'os' field\")):n.push(u)}else this.os=null;if(Array.isArray(e.cpu)){let n=[];this.cpu=n;for(let u of e.cpu)typeof u!=\"string\"?o.push(new Error(\"Parsing failed for the 'cpu' field\")):n.push(u)}else this.cpu=null;if(Array.isArray(e.libc)){let n=[];this.libc=n;for(let u of e.libc)typeof u!=\"string\"?o.push(new Error(\"Parsing failed for the 'libc' field\")):n.push(u)}else this.libc=null;if(typeof e.type==\"string\"?this.type=e.type:this.type=null,typeof e.packageManager==\"string\"?this.packageManager=e.packageManager:this.packageManager=null,typeof e.private==\"boolean\"?this.private=e.private:this.private=!1,typeof e.license==\"string\"?this.license=e.license:this.license=null,typeof e.languageName==\"string\"?this.languageName=e.languageName:this.languageName=null,typeof e.main==\"string\"?this.main=$o(e.main):this.main=null,typeof e.module==\"string\"?this.module=$o(e.module):this.module=null,e.browser!=null)if(typeof e.browser==\"string\")this.browser=$o(e.browser);else{this.browser=new Map;for(let[n,u]of Object.entries(e.browser))this.browser.set($o(n),typeof u==\"string\"?$o(u):u)}else this.browser=null;if(this.bin=new Map,typeof e.bin==\"string\")e.bin.trim()===\"\"?o.push(new Error(\"Invalid bin field\")):this.name!==null?this.bin.set(this.name.name,$o(e.bin)):o.push(new Error(\"String bin field, but no attached package name\"));else if(typeof e.bin==\"object\"&&e.bin!==null)for(let[n,u]of Object.entries(e.bin)){if(typeof u!=\"string\"||u.trim()===\"\"){o.push(new Error(`Invalid bin definition for '${n}'`));continue}let A=zs(n);this.bin.set(A.name,$o(u))}if(this.scripts=new Map,typeof e.scripts==\"object\"&&e.scripts!==null)for(let[n,u]of Object.entries(e.scripts)){if(typeof u!=\"string\"){o.push(new Error(`Invalid script definition for '${n}'`));continue}this.scripts.set(n,u)}if(this.dependencies=new Map,typeof e.dependencies==\"object\"&&e.dependencies!==null)for(let[n,u]of Object.entries(e.dependencies)){if(typeof u!=\"string\"){o.push(new Error(`Invalid dependency range for '${n}'`));continue}let A;try{A=zs(n)}catch{o.push(new Error(`Parsing failed for the dependency name '${n}'`));continue}let p=In(A,u);this.dependencies.set(p.identHash,p)}if(this.devDependencies=new Map,typeof e.devDependencies==\"object\"&&e.devDependencies!==null)for(let[n,u]of Object.entries(e.devDependencies)){if(typeof u!=\"string\"){o.push(new Error(`Invalid dependency range for '${n}'`));continue}let A;try{A=zs(n)}catch{o.push(new Error(`Parsing failed for the dependency name '${n}'`));continue}let p=In(A,u);this.devDependencies.set(p.identHash,p)}if(this.peerDependencies=new Map,typeof e.peerDependencies==\"object\"&&e.peerDependencies!==null)for(let[n,u]of Object.entries(e.peerDependencies)){let A;try{A=zs(n)}catch{o.push(new Error(`Parsing failed for the dependency name '${n}'`));continue}(typeof u!=\"string\"||!u.startsWith(Xn.protocol)&&!xa(u))&&(o.push(new Error(`Invalid dependency range for '${n}'`)),u=\"*\");let p=In(A,u);this.peerDependencies.set(p.identHash,p)}typeof e.workspaces==\"object\"&&e.workspaces!==null&&e.workspaces.nohoist&&o.push(new Error(\"'nohoist' is deprecated, please use 'installConfig.hoistingLimits' instead\"));let a=Array.isArray(e.workspaces)?e.workspaces:typeof e.workspaces==\"object\"&&e.workspaces!==null&&Array.isArray(e.workspaces.packages)?e.workspaces.packages:[];this.workspaceDefinitions=[];for(let n of a){if(typeof n!=\"string\"){o.push(new Error(`Invalid workspace definition for '${n}'`));continue}this.workspaceDefinitions.push({pattern:n})}if(this.dependenciesMeta=new Map,typeof e.dependenciesMeta==\"object\"&&e.dependenciesMeta!==null)for(let[n,u]of Object.entries(e.dependenciesMeta)){if(typeof u!=\"object\"||u===null){o.push(new Error(`Invalid meta field for '${n}`));continue}let A=nh(n),p=this.ensureDependencyMeta(A),h=GS(u.built,{yamlCompatibilityMode:r});if(h===null){o.push(new Error(`Invalid built meta field for '${n}'`));continue}let C=GS(u.optional,{yamlCompatibilityMode:r});if(C===null){o.push(new Error(`Invalid optional meta field for '${n}'`));continue}let I=GS(u.unplugged,{yamlCompatibilityMode:r});if(I===null){o.push(new Error(`Invalid unplugged meta field for '${n}'`));continue}Object.assign(p,{built:h,optional:C,unplugged:I})}if(this.peerDependenciesMeta=new Map,typeof e.peerDependenciesMeta==\"object\"&&e.peerDependenciesMeta!==null)for(let[n,u]of Object.entries(e.peerDependenciesMeta)){if(typeof u!=\"object\"||u===null){o.push(new Error(`Invalid meta field for '${n}'`));continue}let A=nh(n),p=this.ensurePeerDependencyMeta(A),h=GS(u.optional,{yamlCompatibilityMode:r});if(h===null){o.push(new Error(`Invalid optional meta field for '${n}'`));continue}Object.assign(p,{optional:h})}if(this.resolutions=[],typeof e.resolutions==\"object\"&&e.resolutions!==null)for(let[n,u]of Object.entries(e.resolutions)){if(typeof u!=\"string\"){o.push(new Error(`Invalid resolution entry for '${n}'`));continue}try{this.resolutions.push({pattern:UD(n),reference:u})}catch(A){o.push(A);continue}}if(Array.isArray(e.files)){this.files=new Set;for(let n of e.files){if(typeof n!=\"string\"){o.push(new Error(`Invalid files entry for '${n}'`));continue}this.files.add(n)}}else this.files=null;if(typeof e.publishConfig==\"object\"&&e.publishConfig!==null){if(this.publishConfig={},typeof e.publishConfig.access==\"string\"&&(this.publishConfig.access=e.publishConfig.access),typeof e.publishConfig.main==\"string\"&&(this.publishConfig.main=$o(e.publishConfig.main)),typeof e.publishConfig.module==\"string\"&&(this.publishConfig.module=$o(e.publishConfig.module)),e.publishConfig.browser!=null)if(typeof e.publishConfig.browser==\"string\")this.publishConfig.browser=$o(e.publishConfig.browser);else{this.publishConfig.browser=new Map;for(let[n,u]of Object.entries(e.publishConfig.browser))this.publishConfig.browser.set($o(n),typeof u==\"string\"?$o(u):u)}if(typeof e.publishConfig.registry==\"string\"&&(this.publishConfig.registry=e.publishConfig.registry),typeof e.publishConfig.bin==\"string\")this.name!==null?this.publishConfig.bin=new Map([[this.name.name,$o(e.publishConfig.bin)]]):o.push(new Error(\"String bin field, but no attached package name\"));else if(typeof e.publishConfig.bin==\"object\"&&e.publishConfig.bin!==null){this.publishConfig.bin=new Map;for(let[n,u]of Object.entries(e.publishConfig.bin)){if(typeof u!=\"string\"){o.push(new Error(`Invalid bin definition for '${n}'`));continue}this.publishConfig.bin.set(n,$o(u))}}if(Array.isArray(e.publishConfig.executableFiles)){this.publishConfig.executableFiles=new Set;for(let n of e.publishConfig.executableFiles){if(typeof n!=\"string\"){o.push(new Error(\"Invalid executable file definition\"));continue}this.publishConfig.executableFiles.add($o(n))}}}else this.publishConfig=null;if(typeof e.installConfig==\"object\"&&e.installConfig!==null){this.installConfig={};for(let n of Object.keys(e.installConfig))n===\"hoistingLimits\"?typeof e.installConfig.hoistingLimits==\"string\"?this.installConfig.hoistingLimits=e.installConfig.hoistingLimits:o.push(new Error(\"Invalid hoisting limits definition\")):n==\"selfReferences\"?typeof e.installConfig.selfReferences==\"boolean\"?this.installConfig.selfReferences=e.installConfig.selfReferences:o.push(new Error(\"Invalid selfReferences definition, must be a boolean value\")):o.push(new Error(`Unrecognized installConfig key: ${n}`))}else this.installConfig=null;if(typeof e.optionalDependencies==\"object\"&&e.optionalDependencies!==null)for(let[n,u]of Object.entries(e.optionalDependencies)){if(typeof u!=\"string\"){o.push(new Error(`Invalid dependency range for '${n}'`));continue}let A;try{A=zs(n)}catch{o.push(new Error(`Parsing failed for the dependency name '${n}'`));continue}let p=In(A,u);this.dependencies.set(p.identHash,p);let h=In(A,\"unknown\"),C=this.ensureDependencyMeta(h);Object.assign(C,{optional:!0})}typeof e.preferUnplugged==\"boolean\"?this.preferUnplugged=e.preferUnplugged:this.preferUnplugged=null,this.errors=o}getForScope(e){switch(e){case\"dependencies\":return this.dependencies;case\"devDependencies\":return this.devDependencies;case\"peerDependencies\":return this.peerDependencies;default:throw new Error(`Unsupported value (\"${e}\")`)}}hasConsumerDependency(e){return!!(this.dependencies.has(e.identHash)||this.peerDependencies.has(e.identHash))}hasHardDependency(e){return!!(this.dependencies.has(e.identHash)||this.devDependencies.has(e.identHash))}hasSoftDependency(e){return!!this.peerDependencies.has(e.identHash)}hasDependency(e){return!!(this.hasHardDependency(e)||this.hasSoftDependency(e))}getConditions(){let e=[];return this.os&&this.os.length>0&&e.push(lM(\"os\",this.os)),this.cpu&&this.cpu.length>0&&e.push(lM(\"cpu\",this.cpu)),this.libc&&this.libc.length>0&&e.push(lM(\"libc\",this.libc)),e.length>0?e.join(\" & \"):null}ensureDependencyMeta(e){if(e.range!==\"unknown\"&&!yse.default.valid(e.range))throw new Error(`Invalid meta field range for '${Sa(e)}'`);let r=fn(e),o=e.range!==\"unknown\"?e.range:null,a=this.dependenciesMeta.get(r);a||this.dependenciesMeta.set(r,a=new Map);let n=a.get(o);return n||a.set(o,n={}),n}ensurePeerDependencyMeta(e){if(e.range!==\"unknown\")throw new Error(`Invalid meta field range for '${Sa(e)}'`);let r=fn(e),o=this.peerDependenciesMeta.get(r);return o||this.peerDependenciesMeta.set(r,o={}),o}setRawField(e,r,{after:o=[]}={}){let a=new Set(o.filter(n=>Object.hasOwn(this.raw,n)));if(a.size===0||Object.hasOwn(this.raw,e))this.raw[e]=r;else{let n=this.raw,u=this.raw={},A=!1;for(let p of Object.keys(n))u[p]=n[p],A||(a.delete(p),a.size===0&&(u[e]=r,A=!0))}}exportTo(e,{compatibilityMode:r=!0}={}){if(Object.assign(e,this.raw),this.name!==null?e.name=fn(this.name):delete e.name,this.version!==null?e.version=this.version:delete e.version,this.os!==null?e.os=this.os:delete e.os,this.cpu!==null?e.cpu=this.cpu:delete e.cpu,this.type!==null?e.type=this.type:delete e.type,this.packageManager!==null?e.packageManager=this.packageManager:delete e.packageManager,this.private?e.private=!0:delete e.private,this.license!==null?e.license=this.license:delete e.license,this.languageName!==null?e.languageName=this.languageName:delete e.languageName,this.main!==null?e.main=this.main:delete e.main,this.module!==null?e.module=this.module:delete e.module,this.browser!==null){let n=this.browser;typeof n==\"string\"?e.browser=n:n instanceof Map&&(e.browser=Object.assign({},...Array.from(n.keys()).sort().map(u=>({[u]:n.get(u)}))))}else delete e.browser;this.bin.size===1&&this.name!==null&&this.bin.has(this.name.name)?e.bin=this.bin.get(this.name.name):this.bin.size>0?e.bin=Object.assign({},...Array.from(this.bin.keys()).sort().map(n=>({[n]:this.bin.get(n)}))):delete e.bin,this.workspaceDefinitions.length>0?this.raw.workspaces&&!Array.isArray(this.raw.workspaces)?e.workspaces={...this.raw.workspaces,packages:this.workspaceDefinitions.map(({pattern:n})=>n)}:e.workspaces=this.workspaceDefinitions.map(({pattern:n})=>n):this.raw.workspaces&&!Array.isArray(this.raw.workspaces)&&Object.keys(this.raw.workspaces).length>0?e.workspaces=this.raw.workspaces:delete e.workspaces;let o=[],a=[];for(let n of this.dependencies.values()){let u=this.dependenciesMeta.get(fn(n)),A=!1;if(r&&u){let p=u.get(null);p&&p.optional&&(A=!0)}A?a.push(n):o.push(n)}o.length>0?e.dependencies=Object.assign({},...lE(o).map(n=>({[fn(n)]:n.range}))):delete e.dependencies,a.length>0?e.optionalDependencies=Object.assign({},...lE(a).map(n=>({[fn(n)]:n.range}))):delete e.optionalDependencies,this.devDependencies.size>0?e.devDependencies=Object.assign({},...lE(this.devDependencies.values()).map(n=>({[fn(n)]:n.range}))):delete e.devDependencies,this.peerDependencies.size>0?e.peerDependencies=Object.assign({},...lE(this.peerDependencies.values()).map(n=>({[fn(n)]:n.range}))):delete e.peerDependencies,e.dependenciesMeta={};for(let[n,u]of ks(this.dependenciesMeta.entries(),([A,p])=>A))for(let[A,p]of ks(u.entries(),([h,C])=>h!==null?`0${h}`:\"1\")){let h=A!==null?Sa(In(zs(n),A)):n,C={...p};r&&A===null&&delete C.optional,Object.keys(C).length!==0&&(e.dependenciesMeta[h]=C)}if(Object.keys(e.dependenciesMeta).length===0&&delete e.dependenciesMeta,this.peerDependenciesMeta.size>0?e.peerDependenciesMeta=Object.assign({},...ks(this.peerDependenciesMeta.entries(),([n,u])=>n).map(([n,u])=>({[n]:u}))):delete e.peerDependenciesMeta,this.resolutions.length>0?e.resolutions=Object.assign({},...this.resolutions.map(({pattern:n,reference:u})=>({[_D(n)]:u}))):delete e.resolutions,this.files!==null?e.files=Array.from(this.files):delete e.files,this.preferUnplugged!==null?e.preferUnplugged=this.preferUnplugged:delete e.preferUnplugged,this.scripts!==null&&this.scripts.size>0){e.scripts??={};for(let n of Object.keys(e.scripts))this.scripts.has(n)||delete e.scripts[n];for(let[n,u]of this.scripts.entries())e.scripts[n]=u}else delete e.scripts;return e}},Ot=cE;Ot.fileName=\"package.json\",Ot.allDependencies=[\"dependencies\",\"devDependencies\",\"peerDependencies\"],Ot.hardDependencies=[\"dependencies\",\"devDependencies\"]});var Cse=_((MNt,Ese)=>{var $tt=_l(),ert=function(){return $tt.Date.now()};Ese.exports=ert});var Ise=_((UNt,wse)=>{var trt=/\\s/;function rrt(t){for(var e=t.length;e--&&trt.test(t.charAt(e)););return e}wse.exports=rrt});var vse=_((_Nt,Bse)=>{var nrt=Ise(),irt=/^\\s+/;function srt(t){return t&&t.slice(0,nrt(t)+1).replace(irt,\"\")}Bse.exports=srt});var AE=_((HNt,Dse)=>{var ort=fd(),art=zu(),lrt=\"[object Symbol]\";function crt(t){return typeof t==\"symbol\"||art(t)&&ort(t)==lrt}Dse.exports=crt});var xse=_((jNt,bse)=>{var urt=vse(),Pse=il(),Art=AE(),Sse=0/0,frt=/^[-+]0x[0-9a-f]+$/i,prt=/^0b[01]+$/i,hrt=/^0o[0-7]+$/i,grt=parseInt;function drt(t){if(typeof t==\"number\")return t;if(Art(t))return Sse;if(Pse(t)){var e=typeof t.valueOf==\"function\"?t.valueOf():t;t=Pse(e)?e+\"\":e}if(typeof t!=\"string\")return t===0?t:+t;t=urt(t);var r=prt.test(t);return r||hrt.test(t)?grt(t.slice(2),r?2:8):frt.test(t)?Sse:+t}bse.exports=drt});var Fse=_((qNt,Qse)=>{var mrt=il(),cM=Cse(),kse=xse(),yrt=\"Expected a function\",Ert=Math.max,Crt=Math.min;function wrt(t,e,r){var o,a,n,u,A,p,h=0,C=!1,I=!1,v=!0;if(typeof t!=\"function\")throw new TypeError(yrt);e=kse(e)||0,mrt(r)&&(C=!!r.leading,I=\"maxWait\"in r,n=I?Ert(kse(r.maxWait)||0,e):n,v=\"trailing\"in r?!!r.trailing:v);function x(Ae){var ye=o,ae=a;return o=a=void 0,h=Ae,u=t.apply(ae,ye),u}function E(Ae){return h=Ae,A=setTimeout(U,e),C?x(Ae):u}function R(Ae){var ye=Ae-p,ae=Ae-h,Ie=e-ye;return I?Crt(Ie,n-ae):Ie}function L(Ae){var ye=Ae-p,ae=Ae-h;return p===void 0||ye>=e||ye<0||I&&ae>=n}function U(){var Ae=cM();if(L(Ae))return z(Ae);A=setTimeout(U,R(Ae))}function z(Ae){return A=void 0,v&&o?x(Ae):(o=a=void 0,u)}function te(){A!==void 0&&clearTimeout(A),h=0,o=p=a=A=void 0}function le(){return A===void 0?u:z(cM())}function he(){var Ae=cM(),ye=L(Ae);if(o=arguments,a=this,p=Ae,ye){if(A===void 0)return E(p);if(I)return clearTimeout(A),A=setTimeout(U,e),x(p)}return A===void 0&&(A=setTimeout(U,e)),u}return he.cancel=te,he.flush=le,he}Qse.exports=wrt});var uM=_((GNt,Rse)=>{var Irt=Fse(),Brt=il(),vrt=\"Expected a function\";function Drt(t,e,r){var o=!0,a=!0;if(typeof t!=\"function\")throw new TypeError(vrt);return Brt(r)&&(o=\"leading\"in r?!!r.leading:o,a=\"trailing\"in r?!!r.trailing:a),Irt(t,e,{leading:o,maxWait:e,trailing:a})}Rse.exports=Drt});function Srt(t){return typeof t.reportCode<\"u\"}var Tse,Nse,Lse,Prt,Jt,Xs,Yl=Et(()=>{Tse=$e(uM()),Nse=Be(\"stream\"),Lse=Be(\"string_decoder\"),Prt=15,Jt=class extends Error{constructor(r,o,a){super(o);this.reportExtra=a;this.reportCode=r}};Xs=class{constructor(){this.cacheHits=new Set;this.cacheMisses=new Set;this.reportedInfos=new Set;this.reportedWarnings=new Set;this.reportedErrors=new Set}getRecommendedLength(){return 180}reportCacheHit(e){this.cacheHits.add(e.locatorHash)}reportCacheMiss(e,r){this.cacheMisses.add(e.locatorHash)}static progressViaCounter(e){let r=0,o,a=new Promise(p=>{o=p}),n=p=>{let h=o;a=new Promise(C=>{o=C}),r=p,h()},u=(p=0)=>{n(r+1)},A=async function*(){for(;r<e;)await a,yield{progress:r/e}}();return{[Symbol.asyncIterator](){return A},hasProgress:!0,hasTitle:!1,set:n,tick:u}}static progressViaTitle(){let e,r,o=new Promise(u=>{r=u}),a=(0,Tse.default)(u=>{let A=r;o=new Promise(p=>{r=p}),e=u,A()},1e3/Prt),n=async function*(){for(;;)await o,yield{title:e}}();return{[Symbol.asyncIterator](){return n},hasProgress:!1,hasTitle:!0,setTitle:a}}async startProgressPromise(e,r){let o=this.reportProgress(e);try{return await r(e)}finally{o.stop()}}startProgressSync(e,r){let o=this.reportProgress(e);try{return r(e)}finally{o.stop()}}reportInfoOnce(e,r,o){let a=o&&o.key?o.key:r;this.reportedInfos.has(a)||(this.reportedInfos.add(a),this.reportInfo(e,r),o?.reportExtra?.(this))}reportWarningOnce(e,r,o){let a=o&&o.key?o.key:r;this.reportedWarnings.has(a)||(this.reportedWarnings.add(a),this.reportWarning(e,r),o?.reportExtra?.(this))}reportErrorOnce(e,r,o){let a=o&&o.key?o.key:r;this.reportedErrors.has(a)||(this.reportedErrors.add(a),this.reportError(e,r),o?.reportExtra?.(this))}reportExceptionOnce(e){Srt(e)?this.reportErrorOnce(e.reportCode,e.message,{key:e,reportExtra:e.reportExtra}):this.reportErrorOnce(1,e.stack||e.message,{key:e})}createStreamReporter(e=null){let r=new Nse.PassThrough,o=new Lse.StringDecoder,a=\"\";return r.on(\"data\",n=>{let u=o.write(n),A;do if(A=u.indexOf(`\n`),A!==-1){let p=a+u.substring(0,A);u=u.substring(A+1),a=\"\",e!==null?this.reportInfo(null,`${e} ${p}`):this.reportInfo(null,p)}while(A!==-1);a+=u}),r.on(\"end\",()=>{let n=o.end();n!==\"\"&&(e!==null?this.reportInfo(null,`${e} ${n}`):this.reportInfo(null,n))}),r}}});var fE,AM=Et(()=>{Yl();bo();fE=class{constructor(e){this.fetchers=e}supports(e,r){return!!this.tryFetcher(e,r)}getLocalPath(e,r){return this.getFetcher(e,r).getLocalPath(e,r)}async fetch(e,r){return await this.getFetcher(e,r).fetch(e,r)}tryFetcher(e,r){let o=this.fetchers.find(a=>a.supports(e,r));return o||null}getFetcher(e,r){let o=this.fetchers.find(a=>a.supports(e,r));if(!o)throw new Jt(11,`${jr(r.project.configuration,e)} isn't supported by any available fetcher`);return o}}});var Bd,fM=Et(()=>{bo();Bd=class{constructor(e){this.resolvers=e.filter(r=>r)}supportsDescriptor(e,r){return!!this.tryResolverByDescriptor(e,r)}supportsLocator(e,r){return!!this.tryResolverByLocator(e,r)}shouldPersistResolution(e,r){return this.getResolverByLocator(e,r).shouldPersistResolution(e,r)}bindDescriptor(e,r,o){return this.getResolverByDescriptor(e,o).bindDescriptor(e,r,o)}getResolutionDependencies(e,r){return this.getResolverByDescriptor(e,r).getResolutionDependencies(e,r)}async getCandidates(e,r,o){return await this.getResolverByDescriptor(e,o).getCandidates(e,r,o)}async getSatisfying(e,r,o,a){return this.getResolverByDescriptor(e,a).getSatisfying(e,r,o,a)}async resolve(e,r){return await this.getResolverByLocator(e,r).resolve(e,r)}tryResolverByDescriptor(e,r){let o=this.resolvers.find(a=>a.supportsDescriptor(e,r));return o||null}getResolverByDescriptor(e,r){let o=this.resolvers.find(a=>a.supportsDescriptor(e,r));if(!o)throw new Error(`${qn(r.project.configuration,e)} isn't supported by any available resolver`);return o}tryResolverByLocator(e,r){let o=this.resolvers.find(a=>a.supportsLocator(e,r));return o||null}getResolverByLocator(e,r){let o=this.resolvers.find(a=>a.supportsLocator(e,r));if(!o)throw new Error(`${jr(r.project.configuration,e)} isn't supported by any available resolver`);return o}}});var pE,pM=Et(()=>{Pt();bo();pE=class{supports(e){return!!e.reference.startsWith(\"virtual:\")}getLocalPath(e,r){let o=e.reference.indexOf(\"#\");if(o===-1)throw new Error(\"Invalid virtual package reference\");let a=e.reference.slice(o+1),n=Qs(e,a);return r.fetcher.getLocalPath(n,r)}async fetch(e,r){let o=e.reference.indexOf(\"#\");if(o===-1)throw new Error(\"Invalid virtual package reference\");let a=e.reference.slice(o+1),n=Qs(e,a),u=await r.fetcher.fetch(n,r);return await this.ensureVirtualLink(e,u,r)}getLocatorFilename(e){return oE(e)}async ensureVirtualLink(e,r,o){let a=r.packageFs.getRealPath(),n=o.project.configuration.get(\"virtualFolder\"),u=this.getLocatorFilename(e),A=mi.makeVirtualPath(n,u,a),p=new Uu(A,{baseFs:r.packageFs,pathUtils:V});return{...r,packageFs:p}}}});var hE,a1,Ose=Et(()=>{hE=class{static isVirtualDescriptor(e){return!!e.range.startsWith(hE.protocol)}static isVirtualLocator(e){return!!e.reference.startsWith(hE.protocol)}supportsDescriptor(e,r){return hE.isVirtualDescriptor(e)}supportsLocator(e,r){return hE.isVirtualLocator(e)}shouldPersistResolution(e,r){return!1}bindDescriptor(e,r,o){throw new Error('Assertion failed: calling \"bindDescriptor\" on a virtual descriptor is unsupported')}getResolutionDependencies(e,r){throw new Error('Assertion failed: calling \"getResolutionDependencies\" on a virtual descriptor is unsupported')}async getCandidates(e,r,o){throw new Error('Assertion failed: calling \"getCandidates\" on a virtual descriptor is unsupported')}async getSatisfying(e,r,o,a){throw new Error('Assertion failed: calling \"getSatisfying\" on a virtual descriptor is unsupported')}async resolve(e,r){throw new Error('Assertion failed: calling \"resolve\" on a virtual locator is unsupported')}},a1=hE;a1.protocol=\"virtual:\"});var gE,hM=Et(()=>{Pt();Id();gE=class{supports(e){return!!e.reference.startsWith(Xn.protocol)}getLocalPath(e,r){return this.getWorkspace(e,r).cwd}async fetch(e,r){let o=this.getWorkspace(e,r).cwd;return{packageFs:new gn(o),prefixPath:Bt.dot,localPath:o}}getWorkspace(e,r){return r.project.getWorkspaceByCwd(e.reference.slice(Xn.protocol.length))}}});function l1(t){return typeof t==\"object\"&&t!==null&&!Array.isArray(t)}function Mse(t){return typeof t>\"u\"?3:l1(t)?0:Array.isArray(t)?1:2}function mM(t,e){return Object.hasOwn(t,e)}function xrt(t){return l1(t)&&mM(t,\"onConflict\")&&typeof t.onConflict==\"string\"}function krt(t){if(typeof t>\"u\")return{onConflict:\"default\",value:t};if(!xrt(t))return{onConflict:\"default\",value:t};if(mM(t,\"value\"))return t;let{onConflict:e,...r}=t;return{onConflict:e,value:r}}function Use(t,e){let r=l1(t)&&mM(t,e)?t[e]:void 0;return krt(r)}function dE(t,e){return[t,e,_se]}function yM(t){return Array.isArray(t)?t[2]===_se:!1}function gM(t,e){if(l1(t)){let r={};for(let o of Object.keys(t))r[o]=gM(t[o],e);return dE(e,r)}return Array.isArray(t)?dE(e,t.map(r=>gM(r,e))):dE(e,t)}function dM(t,e,r,o,a){let n,u=[],A=a,p=0;for(let C=a-1;C>=o;--C){let[I,v]=t[C],{onConflict:x,value:E}=Use(v,r),R=Mse(E);if(R!==3){if(n??=R,R!==n||x===\"hardReset\"){p=A;break}if(R===2)return dE(I,E);if(u.unshift([I,E]),x===\"reset\"){p=C;break}x===\"extend\"&&C===o&&(o=0),A=C}}if(typeof n>\"u\")return null;let h=u.map(([C])=>C).join(\", \");switch(n){case 1:return dE(h,new Array().concat(...u.map(([C,I])=>I.map(v=>gM(v,C)))));case 0:{let C=Object.assign({},...u.map(([,R])=>R)),I=Object.keys(C),v={},x=t.map(([R,L])=>[R,Use(L,r).value]),E=brt(x,([R,L])=>{let U=Mse(L);return U!==0&&U!==3});if(E!==-1){let R=x.slice(E+1);for(let L of I)v[L]=dM(R,e,L,0,R.length)}else for(let R of I)v[R]=dM(x,e,R,p,x.length);return dE(h,v)}default:throw new Error(\"Assertion failed: Non-extendable value type\")}}function Hse(t){return dM(t.map(([e,r])=>[e,{[\".\"]:r}]),[],\".\",0,t.length)}function c1(t){return yM(t)?t[1]:t}function YS(t){let e=yM(t)?t[1]:t;if(Array.isArray(e))return e.map(r=>YS(r));if(l1(e)){let r={};for(let[o,a]of Object.entries(e))r[o]=YS(a);return r}return e}function EM(t){return yM(t)?t[0]:null}var brt,_se,jse=Et(()=>{brt=(t,e,r)=>{let o=[...t];return o.reverse(),o.findIndex(e,r)};_se=Symbol()});var WS={};Vt(WS,{getDefaultGlobalFolder:()=>wM,getHomeFolder:()=>mE,isFolderInside:()=>IM});function wM(){if(process.platform===\"win32\"){let t=ue.toPortablePath(process.env.LOCALAPPDATA||ue.join((0,CM.homedir)(),\"AppData\",\"Local\"));return V.resolve(t,\"Yarn/Berry\")}if(process.env.XDG_DATA_HOME){let t=ue.toPortablePath(process.env.XDG_DATA_HOME);return V.resolve(t,\"yarn/berry\")}return V.resolve(mE(),\".yarn/berry\")}function mE(){return ue.toPortablePath((0,CM.homedir)()||\"/usr/local/share\")}function IM(t,e){let r=V.relative(e,t);return r&&!r.startsWith(\"..\")&&!V.isAbsolute(r)}var CM,KS=Et(()=>{Pt();CM=Be(\"os\")});var Wse=_(yE=>{\"use strict\";var nLt=Be(\"net\"),Frt=Be(\"tls\"),BM=Be(\"http\"),qse=Be(\"https\"),Rrt=Be(\"events\"),iLt=Be(\"assert\"),Trt=Be(\"util\");yE.httpOverHttp=Nrt;yE.httpsOverHttp=Lrt;yE.httpOverHttps=Ort;yE.httpsOverHttps=Mrt;function Nrt(t){var e=new kf(t);return e.request=BM.request,e}function Lrt(t){var e=new kf(t);return e.request=BM.request,e.createSocket=Gse,e.defaultPort=443,e}function Ort(t){var e=new kf(t);return e.request=qse.request,e}function Mrt(t){var e=new kf(t);return e.request=qse.request,e.createSocket=Gse,e.defaultPort=443,e}function kf(t){var e=this;e.options=t||{},e.proxyOptions=e.options.proxy||{},e.maxSockets=e.options.maxSockets||BM.Agent.defaultMaxSockets,e.requests=[],e.sockets=[],e.on(\"free\",function(o,a,n,u){for(var A=Yse(a,n,u),p=0,h=e.requests.length;p<h;++p){var C=e.requests[p];if(C.host===A.host&&C.port===A.port){e.requests.splice(p,1),C.request.onSocket(o);return}}o.destroy(),e.removeSocket(o)})}Trt.inherits(kf,Rrt.EventEmitter);kf.prototype.addRequest=function(e,r,o,a){var n=this,u=vM({request:e},n.options,Yse(r,o,a));if(n.sockets.length>=this.maxSockets){n.requests.push(u);return}n.createSocket(u,function(A){A.on(\"free\",p),A.on(\"close\",h),A.on(\"agentRemove\",h),e.onSocket(A);function p(){n.emit(\"free\",A,u)}function h(C){n.removeSocket(A),A.removeListener(\"free\",p),A.removeListener(\"close\",h),A.removeListener(\"agentRemove\",h)}})};kf.prototype.createSocket=function(e,r){var o=this,a={};o.sockets.push(a);var n=vM({},o.proxyOptions,{method:\"CONNECT\",path:e.host+\":\"+e.port,agent:!1,headers:{host:e.host+\":\"+e.port}});e.localAddress&&(n.localAddress=e.localAddress),n.proxyAuth&&(n.headers=n.headers||{},n.headers[\"Proxy-Authorization\"]=\"Basic \"+new Buffer(n.proxyAuth).toString(\"base64\")),sh(\"making CONNECT request\");var u=o.request(n);u.useChunkedEncodingByDefault=!1,u.once(\"response\",A),u.once(\"upgrade\",p),u.once(\"connect\",h),u.once(\"error\",C),u.end();function A(I){I.upgrade=!0}function p(I,v,x){process.nextTick(function(){h(I,v,x)})}function h(I,v,x){if(u.removeAllListeners(),v.removeAllListeners(),I.statusCode!==200){sh(\"tunneling socket could not be established, statusCode=%d\",I.statusCode),v.destroy();var E=new Error(\"tunneling socket could not be established, statusCode=\"+I.statusCode);E.code=\"ECONNRESET\",e.request.emit(\"error\",E),o.removeSocket(a);return}if(x.length>0){sh(\"got illegal response body from proxy\"),v.destroy();var E=new Error(\"got illegal response body from proxy\");E.code=\"ECONNRESET\",e.request.emit(\"error\",E),o.removeSocket(a);return}return sh(\"tunneling connection has established\"),o.sockets[o.sockets.indexOf(a)]=v,r(v)}function C(I){u.removeAllListeners(),sh(`tunneling socket could not be established, cause=%s\n`,I.message,I.stack);var v=new Error(\"tunneling socket could not be established, cause=\"+I.message);v.code=\"ECONNRESET\",e.request.emit(\"error\",v),o.removeSocket(a)}};kf.prototype.removeSocket=function(e){var r=this.sockets.indexOf(e);if(r!==-1){this.sockets.splice(r,1);var o=this.requests.shift();o&&this.createSocket(o,function(a){o.request.onSocket(a)})}};function Gse(t,e){var r=this;kf.prototype.createSocket.call(r,t,function(o){var a=t.request.getHeader(\"host\"),n=vM({},r.options,{socket:o,servername:a?a.replace(/:.*$/,\"\"):t.host}),u=Frt.connect(0,n);r.sockets[r.sockets.indexOf(o)]=u,e(u)})}function Yse(t,e,r){return typeof t==\"string\"?{host:t,port:e,localAddress:r}:t}function vM(t){for(var e=1,r=arguments.length;e<r;++e){var o=arguments[e];if(typeof o==\"object\")for(var a=Object.keys(o),n=0,u=a.length;n<u;++n){var A=a[n];o[A]!==void 0&&(t[A]=o[A])}}return t}var sh;process.env.NODE_DEBUG&&/\\btunnel\\b/.test(process.env.NODE_DEBUG)?sh=function(){var t=Array.prototype.slice.call(arguments);typeof t[0]==\"string\"?t[0]=\"TUNNEL: \"+t[0]:t.unshift(\"TUNNEL:\"),console.error.apply(console,t)}:sh=function(){};yE.debug=sh});var Vse=_((oLt,Kse)=>{Kse.exports=Wse()});var Ff=_((Qf,VS)=>{\"use strict\";Object.defineProperty(Qf,\"__esModule\",{value:!0});var zse=[\"Int8Array\",\"Uint8Array\",\"Uint8ClampedArray\",\"Int16Array\",\"Uint16Array\",\"Int32Array\",\"Uint32Array\",\"Float32Array\",\"Float64Array\",\"BigInt64Array\",\"BigUint64Array\"];function Urt(t){return zse.includes(t)}var _rt=[\"Function\",\"Generator\",\"AsyncGenerator\",\"GeneratorFunction\",\"AsyncGeneratorFunction\",\"AsyncFunction\",\"Observable\",\"Array\",\"Buffer\",\"Object\",\"RegExp\",\"Date\",\"Error\",\"Map\",\"Set\",\"WeakMap\",\"WeakSet\",\"ArrayBuffer\",\"SharedArrayBuffer\",\"DataView\",\"Promise\",\"URL\",\"FormData\",\"URLSearchParams\",\"HTMLElement\",...zse];function Hrt(t){return _rt.includes(t)}var jrt=[\"null\",\"undefined\",\"string\",\"number\",\"bigint\",\"boolean\",\"symbol\"];function qrt(t){return jrt.includes(t)}function EE(t){return e=>typeof e===t}var{toString:Jse}=Object.prototype,u1=t=>{let e=Jse.call(t).slice(8,-1);if(/HTML\\w+Element/.test(e)&&Se.domElement(t))return\"HTMLElement\";if(Hrt(e))return e},ei=t=>e=>u1(e)===t;function Se(t){if(t===null)return\"null\";switch(typeof t){case\"undefined\":return\"undefined\";case\"string\":return\"string\";case\"number\":return\"number\";case\"boolean\":return\"boolean\";case\"function\":return\"Function\";case\"bigint\":return\"bigint\";case\"symbol\":return\"symbol\";default:}if(Se.observable(t))return\"Observable\";if(Se.array(t))return\"Array\";if(Se.buffer(t))return\"Buffer\";let e=u1(t);if(e)return e;if(t instanceof String||t instanceof Boolean||t instanceof Number)throw new TypeError(\"Please don't use object wrappers for primitive types\");return\"Object\"}Se.undefined=EE(\"undefined\");Se.string=EE(\"string\");var Grt=EE(\"number\");Se.number=t=>Grt(t)&&!Se.nan(t);Se.bigint=EE(\"bigint\");Se.function_=EE(\"function\");Se.null_=t=>t===null;Se.class_=t=>Se.function_(t)&&t.toString().startsWith(\"class \");Se.boolean=t=>t===!0||t===!1;Se.symbol=EE(\"symbol\");Se.numericString=t=>Se.string(t)&&!Se.emptyStringOrWhitespace(t)&&!Number.isNaN(Number(t));Se.array=(t,e)=>Array.isArray(t)?Se.function_(e)?t.every(e):!0:!1;Se.buffer=t=>{var e,r,o,a;return(a=(o=(r=(e=t)===null||e===void 0?void 0:e.constructor)===null||r===void 0?void 0:r.isBuffer)===null||o===void 0?void 0:o.call(r,t))!==null&&a!==void 0?a:!1};Se.nullOrUndefined=t=>Se.null_(t)||Se.undefined(t);Se.object=t=>!Se.null_(t)&&(typeof t==\"object\"||Se.function_(t));Se.iterable=t=>{var e;return Se.function_((e=t)===null||e===void 0?void 0:e[Symbol.iterator])};Se.asyncIterable=t=>{var e;return Se.function_((e=t)===null||e===void 0?void 0:e[Symbol.asyncIterator])};Se.generator=t=>Se.iterable(t)&&Se.function_(t.next)&&Se.function_(t.throw);Se.asyncGenerator=t=>Se.asyncIterable(t)&&Se.function_(t.next)&&Se.function_(t.throw);Se.nativePromise=t=>ei(\"Promise\")(t);var Yrt=t=>{var e,r;return Se.function_((e=t)===null||e===void 0?void 0:e.then)&&Se.function_((r=t)===null||r===void 0?void 0:r.catch)};Se.promise=t=>Se.nativePromise(t)||Yrt(t);Se.generatorFunction=ei(\"GeneratorFunction\");Se.asyncGeneratorFunction=t=>u1(t)===\"AsyncGeneratorFunction\";Se.asyncFunction=t=>u1(t)===\"AsyncFunction\";Se.boundFunction=t=>Se.function_(t)&&!t.hasOwnProperty(\"prototype\");Se.regExp=ei(\"RegExp\");Se.date=ei(\"Date\");Se.error=ei(\"Error\");Se.map=t=>ei(\"Map\")(t);Se.set=t=>ei(\"Set\")(t);Se.weakMap=t=>ei(\"WeakMap\")(t);Se.weakSet=t=>ei(\"WeakSet\")(t);Se.int8Array=ei(\"Int8Array\");Se.uint8Array=ei(\"Uint8Array\");Se.uint8ClampedArray=ei(\"Uint8ClampedArray\");Se.int16Array=ei(\"Int16Array\");Se.uint16Array=ei(\"Uint16Array\");Se.int32Array=ei(\"Int32Array\");Se.uint32Array=ei(\"Uint32Array\");Se.float32Array=ei(\"Float32Array\");Se.float64Array=ei(\"Float64Array\");Se.bigInt64Array=ei(\"BigInt64Array\");Se.bigUint64Array=ei(\"BigUint64Array\");Se.arrayBuffer=ei(\"ArrayBuffer\");Se.sharedArrayBuffer=ei(\"SharedArrayBuffer\");Se.dataView=ei(\"DataView\");Se.directInstanceOf=(t,e)=>Object.getPrototypeOf(t)===e.prototype;Se.urlInstance=t=>ei(\"URL\")(t);Se.urlString=t=>{if(!Se.string(t))return!1;try{return new URL(t),!0}catch{return!1}};Se.truthy=t=>Boolean(t);Se.falsy=t=>!t;Se.nan=t=>Number.isNaN(t);Se.primitive=t=>Se.null_(t)||qrt(typeof t);Se.integer=t=>Number.isInteger(t);Se.safeInteger=t=>Number.isSafeInteger(t);Se.plainObject=t=>{if(Jse.call(t)!==\"[object Object]\")return!1;let e=Object.getPrototypeOf(t);return e===null||e===Object.getPrototypeOf({})};Se.typedArray=t=>Urt(u1(t));var Wrt=t=>Se.safeInteger(t)&&t>=0;Se.arrayLike=t=>!Se.nullOrUndefined(t)&&!Se.function_(t)&&Wrt(t.length);Se.inRange=(t,e)=>{if(Se.number(e))return t>=Math.min(0,e)&&t<=Math.max(e,0);if(Se.array(e)&&e.length===2)return t>=Math.min(...e)&&t<=Math.max(...e);throw new TypeError(`Invalid range: ${JSON.stringify(e)}`)};var Krt=1,Vrt=[\"innerHTML\",\"ownerDocument\",\"style\",\"attributes\",\"nodeValue\"];Se.domElement=t=>Se.object(t)&&t.nodeType===Krt&&Se.string(t.nodeName)&&!Se.plainObject(t)&&Vrt.every(e=>e in t);Se.observable=t=>{var e,r,o,a;return t?t===((r=(e=t)[Symbol.observable])===null||r===void 0?void 0:r.call(e))||t===((a=(o=t)[\"@@observable\"])===null||a===void 0?void 0:a.call(o)):!1};Se.nodeStream=t=>Se.object(t)&&Se.function_(t.pipe)&&!Se.observable(t);Se.infinite=t=>t===1/0||t===-1/0;var Xse=t=>e=>Se.integer(e)&&Math.abs(e%2)===t;Se.evenInteger=Xse(0);Se.oddInteger=Xse(1);Se.emptyArray=t=>Se.array(t)&&t.length===0;Se.nonEmptyArray=t=>Se.array(t)&&t.length>0;Se.emptyString=t=>Se.string(t)&&t.length===0;Se.nonEmptyString=t=>Se.string(t)&&t.length>0;var zrt=t=>Se.string(t)&&!/\\S/.test(t);Se.emptyStringOrWhitespace=t=>Se.emptyString(t)||zrt(t);Se.emptyObject=t=>Se.object(t)&&!Se.map(t)&&!Se.set(t)&&Object.keys(t).length===0;Se.nonEmptyObject=t=>Se.object(t)&&!Se.map(t)&&!Se.set(t)&&Object.keys(t).length>0;Se.emptySet=t=>Se.set(t)&&t.size===0;Se.nonEmptySet=t=>Se.set(t)&&t.size>0;Se.emptyMap=t=>Se.map(t)&&t.size===0;Se.nonEmptyMap=t=>Se.map(t)&&t.size>0;Se.propertyKey=t=>Se.any([Se.string,Se.number,Se.symbol],t);Se.formData=t=>ei(\"FormData\")(t);Se.urlSearchParams=t=>ei(\"URLSearchParams\")(t);var Zse=(t,e,r)=>{if(!Se.function_(e))throw new TypeError(`Invalid predicate: ${JSON.stringify(e)}`);if(r.length===0)throw new TypeError(\"Invalid number of values\");return t.call(r,e)};Se.any=(t,...e)=>(Se.array(t)?t:[t]).some(o=>Zse(Array.prototype.some,o,e));Se.all=(t,...e)=>Zse(Array.prototype.every,t,e);var Ht=(t,e,r,o={})=>{if(!t){let{multipleValues:a}=o,n=a?`received values of types ${[...new Set(r.map(u=>`\\`${Se(u)}\\``))].join(\", \")}`:`received value of type \\`${Se(r)}\\``;throw new TypeError(`Expected value which is \\`${e}\\`, ${n}.`)}};Qf.assert={undefined:t=>Ht(Se.undefined(t),\"undefined\",t),string:t=>Ht(Se.string(t),\"string\",t),number:t=>Ht(Se.number(t),\"number\",t),bigint:t=>Ht(Se.bigint(t),\"bigint\",t),function_:t=>Ht(Se.function_(t),\"Function\",t),null_:t=>Ht(Se.null_(t),\"null\",t),class_:t=>Ht(Se.class_(t),\"Class\",t),boolean:t=>Ht(Se.boolean(t),\"boolean\",t),symbol:t=>Ht(Se.symbol(t),\"symbol\",t),numericString:t=>Ht(Se.numericString(t),\"string with a number\",t),array:(t,e)=>{Ht(Se.array(t),\"Array\",t),e&&t.forEach(e)},buffer:t=>Ht(Se.buffer(t),\"Buffer\",t),nullOrUndefined:t=>Ht(Se.nullOrUndefined(t),\"null or undefined\",t),object:t=>Ht(Se.object(t),\"Object\",t),iterable:t=>Ht(Se.iterable(t),\"Iterable\",t),asyncIterable:t=>Ht(Se.asyncIterable(t),\"AsyncIterable\",t),generator:t=>Ht(Se.generator(t),\"Generator\",t),asyncGenerator:t=>Ht(Se.asyncGenerator(t),\"AsyncGenerator\",t),nativePromise:t=>Ht(Se.nativePromise(t),\"native Promise\",t),promise:t=>Ht(Se.promise(t),\"Promise\",t),generatorFunction:t=>Ht(Se.generatorFunction(t),\"GeneratorFunction\",t),asyncGeneratorFunction:t=>Ht(Se.asyncGeneratorFunction(t),\"AsyncGeneratorFunction\",t),asyncFunction:t=>Ht(Se.asyncFunction(t),\"AsyncFunction\",t),boundFunction:t=>Ht(Se.boundFunction(t),\"Function\",t),regExp:t=>Ht(Se.regExp(t),\"RegExp\",t),date:t=>Ht(Se.date(t),\"Date\",t),error:t=>Ht(Se.error(t),\"Error\",t),map:t=>Ht(Se.map(t),\"Map\",t),set:t=>Ht(Se.set(t),\"Set\",t),weakMap:t=>Ht(Se.weakMap(t),\"WeakMap\",t),weakSet:t=>Ht(Se.weakSet(t),\"WeakSet\",t),int8Array:t=>Ht(Se.int8Array(t),\"Int8Array\",t),uint8Array:t=>Ht(Se.uint8Array(t),\"Uint8Array\",t),uint8ClampedArray:t=>Ht(Se.uint8ClampedArray(t),\"Uint8ClampedArray\",t),int16Array:t=>Ht(Se.int16Array(t),\"Int16Array\",t),uint16Array:t=>Ht(Se.uint16Array(t),\"Uint16Array\",t),int32Array:t=>Ht(Se.int32Array(t),\"Int32Array\",t),uint32Array:t=>Ht(Se.uint32Array(t),\"Uint32Array\",t),float32Array:t=>Ht(Se.float32Array(t),\"Float32Array\",t),float64Array:t=>Ht(Se.float64Array(t),\"Float64Array\",t),bigInt64Array:t=>Ht(Se.bigInt64Array(t),\"BigInt64Array\",t),bigUint64Array:t=>Ht(Se.bigUint64Array(t),\"BigUint64Array\",t),arrayBuffer:t=>Ht(Se.arrayBuffer(t),\"ArrayBuffer\",t),sharedArrayBuffer:t=>Ht(Se.sharedArrayBuffer(t),\"SharedArrayBuffer\",t),dataView:t=>Ht(Se.dataView(t),\"DataView\",t),urlInstance:t=>Ht(Se.urlInstance(t),\"URL\",t),urlString:t=>Ht(Se.urlString(t),\"string with a URL\",t),truthy:t=>Ht(Se.truthy(t),\"truthy\",t),falsy:t=>Ht(Se.falsy(t),\"falsy\",t),nan:t=>Ht(Se.nan(t),\"NaN\",t),primitive:t=>Ht(Se.primitive(t),\"primitive\",t),integer:t=>Ht(Se.integer(t),\"integer\",t),safeInteger:t=>Ht(Se.safeInteger(t),\"integer\",t),plainObject:t=>Ht(Se.plainObject(t),\"plain object\",t),typedArray:t=>Ht(Se.typedArray(t),\"TypedArray\",t),arrayLike:t=>Ht(Se.arrayLike(t),\"array-like\",t),domElement:t=>Ht(Se.domElement(t),\"HTMLElement\",t),observable:t=>Ht(Se.observable(t),\"Observable\",t),nodeStream:t=>Ht(Se.nodeStream(t),\"Node.js Stream\",t),infinite:t=>Ht(Se.infinite(t),\"infinite number\",t),emptyArray:t=>Ht(Se.emptyArray(t),\"empty array\",t),nonEmptyArray:t=>Ht(Se.nonEmptyArray(t),\"non-empty array\",t),emptyString:t=>Ht(Se.emptyString(t),\"empty string\",t),nonEmptyString:t=>Ht(Se.nonEmptyString(t),\"non-empty string\",t),emptyStringOrWhitespace:t=>Ht(Se.emptyStringOrWhitespace(t),\"empty string or whitespace\",t),emptyObject:t=>Ht(Se.emptyObject(t),\"empty object\",t),nonEmptyObject:t=>Ht(Se.nonEmptyObject(t),\"non-empty object\",t),emptySet:t=>Ht(Se.emptySet(t),\"empty set\",t),nonEmptySet:t=>Ht(Se.nonEmptySet(t),\"non-empty set\",t),emptyMap:t=>Ht(Se.emptyMap(t),\"empty map\",t),nonEmptyMap:t=>Ht(Se.nonEmptyMap(t),\"non-empty map\",t),propertyKey:t=>Ht(Se.propertyKey(t),\"PropertyKey\",t),formData:t=>Ht(Se.formData(t),\"FormData\",t),urlSearchParams:t=>Ht(Se.urlSearchParams(t),\"URLSearchParams\",t),evenInteger:t=>Ht(Se.evenInteger(t),\"even integer\",t),oddInteger:t=>Ht(Se.oddInteger(t),\"odd integer\",t),directInstanceOf:(t,e)=>Ht(Se.directInstanceOf(t,e),\"T\",t),inRange:(t,e)=>Ht(Se.inRange(t,e),\"in range\",t),any:(t,...e)=>Ht(Se.any(t,...e),\"predicate returns truthy for any value\",e,{multipleValues:!0}),all:(t,...e)=>Ht(Se.all(t,...e),\"predicate returns truthy for all values\",e,{multipleValues:!0})};Object.defineProperties(Se,{class:{value:Se.class_},function:{value:Se.function_},null:{value:Se.null_}});Object.defineProperties(Qf.assert,{class:{value:Qf.assert.class_},function:{value:Qf.assert.function_},null:{value:Qf.assert.null_}});Qf.default=Se;VS.exports=Se;VS.exports.default=Se;VS.exports.assert=Qf.assert});var $se=_((aLt,DM)=>{\"use strict\";var zS=class extends Error{constructor(e){super(e||\"Promise was canceled\"),this.name=\"CancelError\"}get isCanceled(){return!0}},CE=class{static fn(e){return(...r)=>new CE((o,a,n)=>{r.push(n),e(...r).then(o,a)})}constructor(e){this._cancelHandlers=[],this._isPending=!0,this._isCanceled=!1,this._rejectOnCancel=!0,this._promise=new Promise((r,o)=>{this._reject=o;let a=A=>{this._isPending=!1,r(A)},n=A=>{this._isPending=!1,o(A)},u=A=>{if(!this._isPending)throw new Error(\"The `onCancel` handler was attached after the promise settled.\");this._cancelHandlers.push(A)};return Object.defineProperties(u,{shouldReject:{get:()=>this._rejectOnCancel,set:A=>{this._rejectOnCancel=A}}}),e(a,n,u)})}then(e,r){return this._promise.then(e,r)}catch(e){return this._promise.catch(e)}finally(e){return this._promise.finally(e)}cancel(e){if(!(!this._isPending||this._isCanceled)){if(this._cancelHandlers.length>0)try{for(let r of this._cancelHandlers)r()}catch(r){this._reject(r)}this._isCanceled=!0,this._rejectOnCancel&&this._reject(new zS(e))}}get isCanceled(){return this._isCanceled}};Object.setPrototypeOf(CE.prototype,Promise.prototype);DM.exports=CE;DM.exports.CancelError=zS});var eoe=_((SM,bM)=>{\"use strict\";Object.defineProperty(SM,\"__esModule\",{value:!0});var Jrt=Be(\"tls\"),PM=(t,e)=>{let r;typeof e==\"function\"?r={connect:e}:r=e;let o=typeof r.connect==\"function\",a=typeof r.secureConnect==\"function\",n=typeof r.close==\"function\",u=()=>{o&&r.connect(),t instanceof Jrt.TLSSocket&&a&&(t.authorized?r.secureConnect():t.authorizationError||t.once(\"secureConnect\",r.secureConnect)),n&&t.once(\"close\",r.close)};t.writable&&!t.connecting?u():t.connecting?t.once(\"connect\",u):t.destroyed&&n&&r.close(t._hadError)};SM.default=PM;bM.exports=PM;bM.exports.default=PM});var toe=_((kM,QM)=>{\"use strict\";Object.defineProperty(kM,\"__esModule\",{value:!0});var Xrt=eoe(),Zrt=Number(process.versions.node.split(\".\")[0]),xM=t=>{let e={start:Date.now(),socket:void 0,lookup:void 0,connect:void 0,secureConnect:void 0,upload:void 0,response:void 0,end:void 0,error:void 0,abort:void 0,phases:{wait:void 0,dns:void 0,tcp:void 0,tls:void 0,request:void 0,firstByte:void 0,download:void 0,total:void 0}};t.timings=e;let r=u=>{let A=u.emit.bind(u);u.emit=(p,...h)=>(p===\"error\"&&(e.error=Date.now(),e.phases.total=e.error-e.start,u.emit=A),A(p,...h))};r(t),t.prependOnceListener(\"abort\",()=>{e.abort=Date.now(),(!e.response||Zrt>=13)&&(e.phases.total=Date.now()-e.start)});let o=u=>{e.socket=Date.now(),e.phases.wait=e.socket-e.start;let A=()=>{e.lookup=Date.now(),e.phases.dns=e.lookup-e.socket};u.prependOnceListener(\"lookup\",A),Xrt.default(u,{connect:()=>{e.connect=Date.now(),e.lookup===void 0&&(u.removeListener(\"lookup\",A),e.lookup=e.connect,e.phases.dns=e.lookup-e.socket),e.phases.tcp=e.connect-e.lookup},secureConnect:()=>{e.secureConnect=Date.now(),e.phases.tls=e.secureConnect-e.connect}})};t.socket?o(t.socket):t.prependOnceListener(\"socket\",o);let a=()=>{var u;e.upload=Date.now(),e.phases.request=e.upload-(u=e.secureConnect,u??e.connect)};return(()=>typeof t.writableFinished==\"boolean\"?t.writableFinished:t.finished&&t.outputSize===0&&(!t.socket||t.socket.writableLength===0))()?a():t.prependOnceListener(\"finish\",a),t.prependOnceListener(\"response\",u=>{e.response=Date.now(),e.phases.firstByte=e.response-e.upload,u.timings=e,r(u),u.prependOnceListener(\"end\",()=>{e.end=Date.now(),e.phases.download=e.end-e.response,e.phases.total=e.end-e.start})}),e};kM.default=xM;QM.exports=xM;QM.exports.default=xM});var loe=_((lLt,TM)=>{\"use strict\";var{V4MAPPED:$rt,ADDRCONFIG:ent,ALL:aoe,promises:{Resolver:roe},lookup:tnt}=Be(\"dns\"),{promisify:FM}=Be(\"util\"),rnt=Be(\"os\"),wE=Symbol(\"cacheableLookupCreateConnection\"),RM=Symbol(\"cacheableLookupInstance\"),noe=Symbol(\"expires\"),nnt=typeof aoe==\"number\",ioe=t=>{if(!(t&&typeof t.createConnection==\"function\"))throw new Error(\"Expected an Agent instance as the first argument\")},int=t=>{for(let e of t)e.family!==6&&(e.address=`::ffff:${e.address}`,e.family=6)},soe=()=>{let t=!1,e=!1;for(let r of Object.values(rnt.networkInterfaces()))for(let o of r)if(!o.internal&&(o.family===\"IPv6\"?e=!0:t=!0,t&&e))return{has4:t,has6:e};return{has4:t,has6:e}},snt=t=>Symbol.iterator in t,ooe={ttl:!0},ont={all:!0},JS=class{constructor({cache:e=new Map,maxTtl:r=1/0,fallbackDuration:o=3600,errorTtl:a=.15,resolver:n=new roe,lookup:u=tnt}={}){if(this.maxTtl=r,this.errorTtl=a,this._cache=e,this._resolver=n,this._dnsLookup=FM(u),this._resolver instanceof roe?(this._resolve4=this._resolver.resolve4.bind(this._resolver),this._resolve6=this._resolver.resolve6.bind(this._resolver)):(this._resolve4=FM(this._resolver.resolve4.bind(this._resolver)),this._resolve6=FM(this._resolver.resolve6.bind(this._resolver))),this._iface=soe(),this._pending={},this._nextRemovalTime=!1,this._hostnamesToFallback=new Set,o<1)this._fallback=!1;else{this._fallback=!0;let A=setInterval(()=>{this._hostnamesToFallback.clear()},o*1e3);A.unref&&A.unref()}this.lookup=this.lookup.bind(this),this.lookupAsync=this.lookupAsync.bind(this)}set servers(e){this.clear(),this._resolver.setServers(e)}get servers(){return this._resolver.getServers()}lookup(e,r,o){if(typeof r==\"function\"?(o=r,r={}):typeof r==\"number\"&&(r={family:r}),!o)throw new Error(\"Callback must be a function.\");this.lookupAsync(e,r).then(a=>{r.all?o(null,a):o(null,a.address,a.family,a.expires,a.ttl)},o)}async lookupAsync(e,r={}){typeof r==\"number\"&&(r={family:r});let o=await this.query(e);if(r.family===6){let a=o.filter(n=>n.family===6);r.hints&$rt&&(nnt&&r.hints&aoe||a.length===0)?int(o):o=a}else r.family===4&&(o=o.filter(a=>a.family===4));if(r.hints&ent){let{_iface:a}=this;o=o.filter(n=>n.family===6?a.has6:a.has4)}if(o.length===0){let a=new Error(`cacheableLookup ENOTFOUND ${e}`);throw a.code=\"ENOTFOUND\",a.hostname=e,a}return r.all?o:o[0]}async query(e){let r=await this._cache.get(e);if(!r){let o=this._pending[e];if(o)r=await o;else{let a=this.queryAndCache(e);this._pending[e]=a,r=await a}}return r=r.map(o=>({...o})),r}async _resolve(e){let r=async h=>{try{return await h}catch(C){if(C.code===\"ENODATA\"||C.code===\"ENOTFOUND\")return[];throw C}},[o,a]=await Promise.all([this._resolve4(e,ooe),this._resolve6(e,ooe)].map(h=>r(h))),n=0,u=0,A=0,p=Date.now();for(let h of o)h.family=4,h.expires=p+h.ttl*1e3,n=Math.max(n,h.ttl);for(let h of a)h.family=6,h.expires=p+h.ttl*1e3,u=Math.max(u,h.ttl);return o.length>0?a.length>0?A=Math.min(n,u):A=n:A=u,{entries:[...o,...a],cacheTtl:A}}async _lookup(e){try{return{entries:await this._dnsLookup(e,{all:!0}),cacheTtl:0}}catch{return{entries:[],cacheTtl:0}}}async _set(e,r,o){if(this.maxTtl>0&&o>0){o=Math.min(o,this.maxTtl)*1e3,r[noe]=Date.now()+o;try{await this._cache.set(e,r,o)}catch(a){this.lookupAsync=async()=>{let n=new Error(\"Cache Error. Please recreate the CacheableLookup instance.\");throw n.cause=a,n}}snt(this._cache)&&this._tick(o)}}async queryAndCache(e){if(this._hostnamesToFallback.has(e))return this._dnsLookup(e,ont);try{let r=await this._resolve(e);r.entries.length===0&&this._fallback&&(r=await this._lookup(e),r.entries.length!==0&&this._hostnamesToFallback.add(e));let o=r.entries.length===0?this.errorTtl:r.cacheTtl;return await this._set(e,r.entries,o),delete this._pending[e],r.entries}catch(r){throw delete this._pending[e],r}}_tick(e){let r=this._nextRemovalTime;(!r||e<r)&&(clearTimeout(this._removalTimeout),this._nextRemovalTime=e,this._removalTimeout=setTimeout(()=>{this._nextRemovalTime=!1;let o=1/0,a=Date.now();for(let[n,u]of this._cache){let A=u[noe];a>=A?this._cache.delete(n):A<o&&(o=A)}o!==1/0&&this._tick(o-a)},e),this._removalTimeout.unref&&this._removalTimeout.unref())}install(e){if(ioe(e),wE in e)throw new Error(\"CacheableLookup has been already installed\");e[wE]=e.createConnection,e[RM]=this,e.createConnection=(r,o)=>(\"lookup\"in r||(r.lookup=this.lookup),e[wE](r,o))}uninstall(e){if(ioe(e),e[wE]){if(e[RM]!==this)throw new Error(\"The agent is not owned by this CacheableLookup instance\");e.createConnection=e[wE],delete e[wE],delete e[RM]}}updateInterfaceInfo(){let{_iface:e}=this;this._iface=soe(),(e.has4&&!this._iface.has4||e.has6&&!this._iface.has6)&&this._cache.clear()}clear(e){if(e){this._cache.delete(e);return}this._cache.clear()}};TM.exports=JS;TM.exports.default=JS});var Aoe=_((cLt,NM)=>{\"use strict\";var ant=typeof URL>\"u\"?Be(\"url\").URL:URL,lnt=\"text/plain\",cnt=\"us-ascii\",coe=(t,e)=>e.some(r=>r instanceof RegExp?r.test(t):r===t),unt=(t,{stripHash:e})=>{let r=t.match(/^data:([^,]*?),([^#]*?)(?:#(.*))?$/);if(!r)throw new Error(`Invalid URL: ${t}`);let o=r[1].split(\";\"),a=r[2],n=e?\"\":r[3],u=!1;o[o.length-1]===\"base64\"&&(o.pop(),u=!0);let A=(o.shift()||\"\").toLowerCase(),h=[...o.map(C=>{let[I,v=\"\"]=C.split(\"=\").map(x=>x.trim());return I===\"charset\"&&(v=v.toLowerCase(),v===cnt)?\"\":`${I}${v?`=${v}`:\"\"}`}).filter(Boolean)];return u&&h.push(\"base64\"),(h.length!==0||A&&A!==lnt)&&h.unshift(A),`data:${h.join(\";\")},${u?a.trim():a}${n?`#${n}`:\"\"}`},uoe=(t,e)=>{if(e={defaultProtocol:\"http:\",normalizeProtocol:!0,forceHttp:!1,forceHttps:!1,stripAuthentication:!0,stripHash:!1,stripWWW:!0,removeQueryParameters:[/^utm_\\w+/i],removeTrailingSlash:!0,removeDirectoryIndex:!1,sortQueryParameters:!0,...e},Reflect.has(e,\"normalizeHttps\"))throw new Error(\"options.normalizeHttps is renamed to options.forceHttp\");if(Reflect.has(e,\"normalizeHttp\"))throw new Error(\"options.normalizeHttp is renamed to options.forceHttps\");if(Reflect.has(e,\"stripFragment\"))throw new Error(\"options.stripFragment is renamed to options.stripHash\");if(t=t.trim(),/^data:/i.test(t))return unt(t,e);let r=t.startsWith(\"//\");!r&&/^\\.*\\//.test(t)||(t=t.replace(/^(?!(?:\\w+:)?\\/\\/)|^\\/\\//,e.defaultProtocol));let a=new ant(t);if(e.forceHttp&&e.forceHttps)throw new Error(\"The `forceHttp` and `forceHttps` options cannot be used together\");if(e.forceHttp&&a.protocol===\"https:\"&&(a.protocol=\"http:\"),e.forceHttps&&a.protocol===\"http:\"&&(a.protocol=\"https:\"),e.stripAuthentication&&(a.username=\"\",a.password=\"\"),e.stripHash&&(a.hash=\"\"),a.pathname&&(a.pathname=a.pathname.replace(/((?!:).|^)\\/{2,}/g,(n,u)=>/^(?!\\/)/g.test(u)?`${u}/`:\"/\")),a.pathname&&(a.pathname=decodeURI(a.pathname)),e.removeDirectoryIndex===!0&&(e.removeDirectoryIndex=[/^index\\.[a-z]+$/]),Array.isArray(e.removeDirectoryIndex)&&e.removeDirectoryIndex.length>0){let n=a.pathname.split(\"/\"),u=n[n.length-1];coe(u,e.removeDirectoryIndex)&&(n=n.slice(0,n.length-1),a.pathname=n.slice(1).join(\"/\")+\"/\")}if(a.hostname&&(a.hostname=a.hostname.replace(/\\.$/,\"\"),e.stripWWW&&/^www\\.([a-z\\-\\d]{2,63})\\.([a-z.]{2,5})$/.test(a.hostname)&&(a.hostname=a.hostname.replace(/^www\\./,\"\"))),Array.isArray(e.removeQueryParameters))for(let n of[...a.searchParams.keys()])coe(n,e.removeQueryParameters)&&a.searchParams.delete(n);return e.sortQueryParameters&&a.searchParams.sort(),e.removeTrailingSlash&&(a.pathname=a.pathname.replace(/\\/$/,\"\")),t=a.toString(),(e.removeTrailingSlash||a.pathname===\"/\")&&a.hash===\"\"&&(t=t.replace(/\\/$/,\"\")),r&&!e.normalizeProtocol&&(t=t.replace(/^http:\\/\\//,\"//\")),e.stripProtocol&&(t=t.replace(/^(?:https?:)?\\/\\//,\"\")),t};NM.exports=uoe;NM.exports.default=uoe});var hoe=_((uLt,poe)=>{poe.exports=foe;function foe(t,e){if(t&&e)return foe(t)(e);if(typeof t!=\"function\")throw new TypeError(\"need wrapper function\");return Object.keys(t).forEach(function(o){r[o]=t[o]}),r;function r(){for(var o=new Array(arguments.length),a=0;a<o.length;a++)o[a]=arguments[a];var n=t.apply(this,o),u=o[o.length-1];return typeof n==\"function\"&&n!==u&&Object.keys(u).forEach(function(A){n[A]=u[A]}),n}}});var OM=_((ALt,LM)=>{var goe=hoe();LM.exports=goe(XS);LM.exports.strict=goe(doe);XS.proto=XS(function(){Object.defineProperty(Function.prototype,\"once\",{value:function(){return XS(this)},configurable:!0}),Object.defineProperty(Function.prototype,\"onceStrict\",{value:function(){return doe(this)},configurable:!0})});function XS(t){var e=function(){return e.called?e.value:(e.called=!0,e.value=t.apply(this,arguments))};return e.called=!1,e}function doe(t){var e=function(){if(e.called)throw new Error(e.onceError);return e.called=!0,e.value=t.apply(this,arguments)},r=t.name||\"Function wrapped with `once`\";return e.onceError=r+\" shouldn't be called more than once\",e.called=!1,e}});var MM=_((fLt,yoe)=>{var Ant=OM(),fnt=function(){},pnt=function(t){return t.setHeader&&typeof t.abort==\"function\"},hnt=function(t){return t.stdio&&Array.isArray(t.stdio)&&t.stdio.length===3},moe=function(t,e,r){if(typeof e==\"function\")return moe(t,null,e);e||(e={}),r=Ant(r||fnt);var o=t._writableState,a=t._readableState,n=e.readable||e.readable!==!1&&t.readable,u=e.writable||e.writable!==!1&&t.writable,A=function(){t.writable||p()},p=function(){u=!1,n||r.call(t)},h=function(){n=!1,u||r.call(t)},C=function(E){r.call(t,E?new Error(\"exited with error code: \"+E):null)},I=function(E){r.call(t,E)},v=function(){if(n&&!(a&&a.ended))return r.call(t,new Error(\"premature close\"));if(u&&!(o&&o.ended))return r.call(t,new Error(\"premature close\"))},x=function(){t.req.on(\"finish\",p)};return pnt(t)?(t.on(\"complete\",p),t.on(\"abort\",v),t.req?x():t.on(\"request\",x)):u&&!o&&(t.on(\"end\",A),t.on(\"close\",A)),hnt(t)&&t.on(\"exit\",C),t.on(\"end\",h),t.on(\"finish\",p),e.error!==!1&&t.on(\"error\",I),t.on(\"close\",v),function(){t.removeListener(\"complete\",p),t.removeListener(\"abort\",v),t.removeListener(\"request\",x),t.req&&t.req.removeListener(\"finish\",p),t.removeListener(\"end\",A),t.removeListener(\"close\",A),t.removeListener(\"finish\",p),t.removeListener(\"exit\",C),t.removeListener(\"end\",h),t.removeListener(\"error\",I),t.removeListener(\"close\",v)}};yoe.exports=moe});var woe=_((pLt,Coe)=>{var gnt=OM(),dnt=MM(),UM=Be(\"fs\"),A1=function(){},mnt=/^v?\\.0/.test(process.version),ZS=function(t){return typeof t==\"function\"},ynt=function(t){return!mnt||!UM?!1:(t instanceof(UM.ReadStream||A1)||t instanceof(UM.WriteStream||A1))&&ZS(t.close)},Ent=function(t){return t.setHeader&&ZS(t.abort)},Cnt=function(t,e,r,o){o=gnt(o);var a=!1;t.on(\"close\",function(){a=!0}),dnt(t,{readable:e,writable:r},function(u){if(u)return o(u);a=!0,o()});var n=!1;return function(u){if(!a&&!n){if(n=!0,ynt(t))return t.close(A1);if(Ent(t))return t.abort();if(ZS(t.destroy))return t.destroy();o(u||new Error(\"stream was destroyed\"))}}},Eoe=function(t){t()},wnt=function(t,e){return t.pipe(e)},Int=function(){var t=Array.prototype.slice.call(arguments),e=ZS(t[t.length-1]||A1)&&t.pop()||A1;if(Array.isArray(t[0])&&(t=t[0]),t.length<2)throw new Error(\"pump requires two streams per minimum\");var r,o=t.map(function(a,n){var u=n<t.length-1,A=n>0;return Cnt(a,u,A,function(p){r||(r=p),p&&o.forEach(Eoe),!u&&(o.forEach(Eoe),e(r))})});return t.reduce(wnt)};Coe.exports=Int});var Boe=_((hLt,Ioe)=>{\"use strict\";var{PassThrough:Bnt}=Be(\"stream\");Ioe.exports=t=>{t={...t};let{array:e}=t,{encoding:r}=t,o=r===\"buffer\",a=!1;e?a=!(r||o):r=r||\"utf8\",o&&(r=null);let n=new Bnt({objectMode:a});r&&n.setEncoding(r);let u=0,A=[];return n.on(\"data\",p=>{A.push(p),a?u=A.length:u+=p.length}),n.getBufferedValue=()=>e?A:o?Buffer.concat(A,u):A.join(\"\"),n.getBufferedLength=()=>u,n}});var voe=_((gLt,IE)=>{\"use strict\";var vnt=woe(),Dnt=Boe(),$S=class extends Error{constructor(){super(\"maxBuffer exceeded\"),this.name=\"MaxBufferError\"}};async function eb(t,e){if(!t)return Promise.reject(new Error(\"Expected a stream\"));e={maxBuffer:1/0,...e};let{maxBuffer:r}=e,o;return await new Promise((a,n)=>{let u=A=>{A&&(A.bufferedData=o.getBufferedValue()),n(A)};o=vnt(t,Dnt(e),A=>{if(A){u(A);return}a()}),o.on(\"data\",()=>{o.getBufferedLength()>r&&u(new $S)})}),o.getBufferedValue()}IE.exports=eb;IE.exports.default=eb;IE.exports.buffer=(t,e)=>eb(t,{...e,encoding:\"buffer\"});IE.exports.array=(t,e)=>eb(t,{...e,array:!0});IE.exports.MaxBufferError=$S});var Poe=_((mLt,Doe)=>{\"use strict\";var Pnt=new Set([200,203,204,206,300,301,404,405,410,414,501]),Snt=new Set([200,203,204,300,301,302,303,307,308,404,405,410,414,501]),bnt=new Set([500,502,503,504]),xnt={date:!0,connection:!0,\"keep-alive\":!0,\"proxy-authenticate\":!0,\"proxy-authorization\":!0,te:!0,trailer:!0,\"transfer-encoding\":!0,upgrade:!0},knt={\"content-length\":!0,\"content-encoding\":!0,\"transfer-encoding\":!0,\"content-range\":!0};function vd(t){let e=parseInt(t,10);return isFinite(e)?e:0}function Qnt(t){return t?bnt.has(t.status):!0}function _M(t){let e={};if(!t)return e;let r=t.trim().split(/\\s*,\\s*/);for(let o of r){let[a,n]=o.split(/\\s*=\\s*/,2);e[a]=n===void 0?!0:n.replace(/^\"|\"$/g,\"\")}return e}function Fnt(t){let e=[];for(let r in t){let o=t[r];e.push(o===!0?r:r+\"=\"+o)}if(!!e.length)return e.join(\", \")}Doe.exports=class{constructor(e,r,{shared:o,cacheHeuristic:a,immutableMinTimeToLive:n,ignoreCargoCult:u,_fromObject:A}={}){if(A){this._fromObject(A);return}if(!r||!r.headers)throw Error(\"Response headers missing\");this._assertRequestHasHeaders(e),this._responseTime=this.now(),this._isShared=o!==!1,this._cacheHeuristic=a!==void 0?a:.1,this._immutableMinTtl=n!==void 0?n:24*3600*1e3,this._status=\"status\"in r?r.status:200,this._resHeaders=r.headers,this._rescc=_M(r.headers[\"cache-control\"]),this._method=\"method\"in e?e.method:\"GET\",this._url=e.url,this._host=e.headers.host,this._noAuthorization=!e.headers.authorization,this._reqHeaders=r.headers.vary?e.headers:null,this._reqcc=_M(e.headers[\"cache-control\"]),u&&\"pre-check\"in this._rescc&&\"post-check\"in this._rescc&&(delete this._rescc[\"pre-check\"],delete this._rescc[\"post-check\"],delete this._rescc[\"no-cache\"],delete this._rescc[\"no-store\"],delete this._rescc[\"must-revalidate\"],this._resHeaders=Object.assign({},this._resHeaders,{\"cache-control\":Fnt(this._rescc)}),delete this._resHeaders.expires,delete this._resHeaders.pragma),r.headers[\"cache-control\"]==null&&/no-cache/.test(r.headers.pragma)&&(this._rescc[\"no-cache\"]=!0)}now(){return Date.now()}storable(){return!!(!this._reqcc[\"no-store\"]&&(this._method===\"GET\"||this._method===\"HEAD\"||this._method===\"POST\"&&this._hasExplicitExpiration())&&Snt.has(this._status)&&!this._rescc[\"no-store\"]&&(!this._isShared||!this._rescc.private)&&(!this._isShared||this._noAuthorization||this._allowsStoringAuthenticated())&&(this._resHeaders.expires||this._rescc[\"max-age\"]||this._isShared&&this._rescc[\"s-maxage\"]||this._rescc.public||Pnt.has(this._status)))}_hasExplicitExpiration(){return this._isShared&&this._rescc[\"s-maxage\"]||this._rescc[\"max-age\"]||this._resHeaders.expires}_assertRequestHasHeaders(e){if(!e||!e.headers)throw Error(\"Request headers missing\")}satisfiesWithoutRevalidation(e){this._assertRequestHasHeaders(e);let r=_M(e.headers[\"cache-control\"]);return r[\"no-cache\"]||/no-cache/.test(e.headers.pragma)||r[\"max-age\"]&&this.age()>r[\"max-age\"]||r[\"min-fresh\"]&&this.timeToLive()<1e3*r[\"min-fresh\"]||this.stale()&&!(r[\"max-stale\"]&&!this._rescc[\"must-revalidate\"]&&(r[\"max-stale\"]===!0||r[\"max-stale\"]>this.age()-this.maxAge()))?!1:this._requestMatches(e,!1)}_requestMatches(e,r){return(!this._url||this._url===e.url)&&this._host===e.headers.host&&(!e.method||this._method===e.method||r&&e.method===\"HEAD\")&&this._varyMatches(e)}_allowsStoringAuthenticated(){return this._rescc[\"must-revalidate\"]||this._rescc.public||this._rescc[\"s-maxage\"]}_varyMatches(e){if(!this._resHeaders.vary)return!0;if(this._resHeaders.vary===\"*\")return!1;let r=this._resHeaders.vary.trim().toLowerCase().split(/\\s*,\\s*/);for(let o of r)if(e.headers[o]!==this._reqHeaders[o])return!1;return!0}_copyWithoutHopByHopHeaders(e){let r={};for(let o in e)xnt[o]||(r[o]=e[o]);if(e.connection){let o=e.connection.trim().split(/\\s*,\\s*/);for(let a of o)delete r[a]}if(r.warning){let o=r.warning.split(/,/).filter(a=>!/^\\s*1[0-9][0-9]/.test(a));o.length?r.warning=o.join(\",\").trim():delete r.warning}return r}responseHeaders(){let e=this._copyWithoutHopByHopHeaders(this._resHeaders),r=this.age();return r>3600*24&&!this._hasExplicitExpiration()&&this.maxAge()>3600*24&&(e.warning=(e.warning?`${e.warning}, `:\"\")+'113 - \"rfc7234 5.5.4\"'),e.age=`${Math.round(r)}`,e.date=new Date(this.now()).toUTCString(),e}date(){let e=Date.parse(this._resHeaders.date);return isFinite(e)?e:this._responseTime}age(){let e=this._ageValue(),r=(this.now()-this._responseTime)/1e3;return e+r}_ageValue(){return vd(this._resHeaders.age)}maxAge(){if(!this.storable()||this._rescc[\"no-cache\"]||this._isShared&&this._resHeaders[\"set-cookie\"]&&!this._rescc.public&&!this._rescc.immutable||this._resHeaders.vary===\"*\")return 0;if(this._isShared){if(this._rescc[\"proxy-revalidate\"])return 0;if(this._rescc[\"s-maxage\"])return vd(this._rescc[\"s-maxage\"])}if(this._rescc[\"max-age\"])return vd(this._rescc[\"max-age\"]);let e=this._rescc.immutable?this._immutableMinTtl:0,r=this.date();if(this._resHeaders.expires){let o=Date.parse(this._resHeaders.expires);return Number.isNaN(o)||o<r?0:Math.max(e,(o-r)/1e3)}if(this._resHeaders[\"last-modified\"]){let o=Date.parse(this._resHeaders[\"last-modified\"]);if(isFinite(o)&&r>o)return Math.max(e,(r-o)/1e3*this._cacheHeuristic)}return e}timeToLive(){let e=this.maxAge()-this.age(),r=e+vd(this._rescc[\"stale-if-error\"]),o=e+vd(this._rescc[\"stale-while-revalidate\"]);return Math.max(0,e,r,o)*1e3}stale(){return this.maxAge()<=this.age()}_useStaleIfError(){return this.maxAge()+vd(this._rescc[\"stale-if-error\"])>this.age()}useStaleWhileRevalidate(){return this.maxAge()+vd(this._rescc[\"stale-while-revalidate\"])>this.age()}static fromObject(e){return new this(void 0,void 0,{_fromObject:e})}_fromObject(e){if(this._responseTime)throw Error(\"Reinitialized\");if(!e||e.v!==1)throw Error(\"Invalid serialization\");this._responseTime=e.t,this._isShared=e.sh,this._cacheHeuristic=e.ch,this._immutableMinTtl=e.imm!==void 0?e.imm:24*3600*1e3,this._status=e.st,this._resHeaders=e.resh,this._rescc=e.rescc,this._method=e.m,this._url=e.u,this._host=e.h,this._noAuthorization=e.a,this._reqHeaders=e.reqh,this._reqcc=e.reqcc}toObject(){return{v:1,t:this._responseTime,sh:this._isShared,ch:this._cacheHeuristic,imm:this._immutableMinTtl,st:this._status,resh:this._resHeaders,rescc:this._rescc,m:this._method,u:this._url,h:this._host,a:this._noAuthorization,reqh:this._reqHeaders,reqcc:this._reqcc}}revalidationHeaders(e){this._assertRequestHasHeaders(e);let r=this._copyWithoutHopByHopHeaders(e.headers);if(delete r[\"if-range\"],!this._requestMatches(e,!0)||!this.storable())return delete r[\"if-none-match\"],delete r[\"if-modified-since\"],r;if(this._resHeaders.etag&&(r[\"if-none-match\"]=r[\"if-none-match\"]?`${r[\"if-none-match\"]}, ${this._resHeaders.etag}`:this._resHeaders.etag),r[\"accept-ranges\"]||r[\"if-match\"]||r[\"if-unmodified-since\"]||this._method&&this._method!=\"GET\"){if(delete r[\"if-modified-since\"],r[\"if-none-match\"]){let a=r[\"if-none-match\"].split(/,/).filter(n=>!/^\\s*W\\//.test(n));a.length?r[\"if-none-match\"]=a.join(\",\").trim():delete r[\"if-none-match\"]}}else this._resHeaders[\"last-modified\"]&&!r[\"if-modified-since\"]&&(r[\"if-modified-since\"]=this._resHeaders[\"last-modified\"]);return r}revalidatedPolicy(e,r){if(this._assertRequestHasHeaders(e),this._useStaleIfError()&&Qnt(r))return{modified:!1,matches:!1,policy:this};if(!r||!r.headers)throw Error(\"Response headers missing\");let o=!1;if(r.status!==void 0&&r.status!=304?o=!1:r.headers.etag&&!/^\\s*W\\//.test(r.headers.etag)?o=this._resHeaders.etag&&this._resHeaders.etag.replace(/^\\s*W\\//,\"\")===r.headers.etag:this._resHeaders.etag&&r.headers.etag?o=this._resHeaders.etag.replace(/^\\s*W\\//,\"\")===r.headers.etag.replace(/^\\s*W\\//,\"\"):this._resHeaders[\"last-modified\"]?o=this._resHeaders[\"last-modified\"]===r.headers[\"last-modified\"]:!this._resHeaders.etag&&!this._resHeaders[\"last-modified\"]&&!r.headers.etag&&!r.headers[\"last-modified\"]&&(o=!0),!o)return{policy:new this.constructor(e,r),modified:r.status!=304,matches:!1};let a={};for(let u in this._resHeaders)a[u]=u in r.headers&&!knt[u]?r.headers[u]:this._resHeaders[u];let n=Object.assign({},r,{status:this._status,method:this._method,headers:a});return{policy:new this.constructor(e,n,{shared:this._isShared,cacheHeuristic:this._cacheHeuristic,immutableMinTimeToLive:this._immutableMinTtl}),modified:!1,matches:!0}}}});var tb=_((yLt,Soe)=>{\"use strict\";Soe.exports=t=>{let e={};for(let[r,o]of Object.entries(t))e[r.toLowerCase()]=o;return e}});var xoe=_((ELt,boe)=>{\"use strict\";var Rnt=Be(\"stream\").Readable,Tnt=tb(),HM=class extends Rnt{constructor(e,r,o,a){if(typeof e!=\"number\")throw new TypeError(\"Argument `statusCode` should be a number\");if(typeof r!=\"object\")throw new TypeError(\"Argument `headers` should be an object\");if(!(o instanceof Buffer))throw new TypeError(\"Argument `body` should be a buffer\");if(typeof a!=\"string\")throw new TypeError(\"Argument `url` should be a string\");super(),this.statusCode=e,this.headers=Tnt(r),this.body=o,this.url=a}_read(){this.push(this.body),this.push(null)}};boe.exports=HM});var Qoe=_((CLt,koe)=>{\"use strict\";var Nnt=[\"destroy\",\"setTimeout\",\"socket\",\"headers\",\"trailers\",\"rawHeaders\",\"statusCode\",\"httpVersion\",\"httpVersionMinor\",\"httpVersionMajor\",\"rawTrailers\",\"statusMessage\"];koe.exports=(t,e)=>{let r=new Set(Object.keys(t).concat(Nnt));for(let o of r)o in e||(e[o]=typeof t[o]==\"function\"?t[o].bind(t):t[o])}});var Roe=_((wLt,Foe)=>{\"use strict\";var Lnt=Be(\"stream\").PassThrough,Ont=Qoe(),Mnt=t=>{if(!(t&&t.pipe))throw new TypeError(\"Parameter `response` must be a response stream.\");let e=new Lnt;return Ont(t,e),t.pipe(e)};Foe.exports=Mnt});var Toe=_(jM=>{jM.stringify=function t(e){if(typeof e>\"u\")return e;if(e&&Buffer.isBuffer(e))return JSON.stringify(\":base64:\"+e.toString(\"base64\"));if(e&&e.toJSON&&(e=e.toJSON()),e&&typeof e==\"object\"){var r=\"\",o=Array.isArray(e);r=o?\"[\":\"{\";var a=!0;for(var n in e){var u=typeof e[n]==\"function\"||!o&&typeof e[n]>\"u\";Object.hasOwnProperty.call(e,n)&&!u&&(a||(r+=\",\"),a=!1,o?e[n]==null?r+=\"null\":r+=t(e[n]):e[n]!==void 0&&(r+=t(n)+\":\"+t(e[n])))}return r+=o?\"]\":\"}\",r}else return typeof e==\"string\"?JSON.stringify(/^:/.test(e)?\":\"+e:e):typeof e>\"u\"?\"null\":JSON.stringify(e)};jM.parse=function(t){return JSON.parse(t,function(e,r){return typeof r==\"string\"?/^:base64:/.test(r)?Buffer.from(r.substring(8),\"base64\"):/^:/.test(r)?r.substring(1):r:r})}});var Ooe=_((BLt,Loe)=>{\"use strict\";var Unt=Be(\"events\"),Noe=Toe(),_nt=t=>{let e={redis:\"@keyv/redis\",mongodb:\"@keyv/mongo\",mongo:\"@keyv/mongo\",sqlite:\"@keyv/sqlite\",postgresql:\"@keyv/postgres\",postgres:\"@keyv/postgres\",mysql:\"@keyv/mysql\"};if(t.adapter||t.uri){let r=t.adapter||/^[^:]*/.exec(t.uri)[0];return new(Be(e[r]))(t)}return new Map},qM=class extends Unt{constructor(e,r){if(super(),this.opts=Object.assign({namespace:\"keyv\",serialize:Noe.stringify,deserialize:Noe.parse},typeof e==\"string\"?{uri:e}:e,r),!this.opts.store){let o=Object.assign({},this.opts);this.opts.store=_nt(o)}typeof this.opts.store.on==\"function\"&&this.opts.store.on(\"error\",o=>this.emit(\"error\",o)),this.opts.store.namespace=this.opts.namespace}_getKeyPrefix(e){return`${this.opts.namespace}:${e}`}get(e,r){e=this._getKeyPrefix(e);let{store:o}=this.opts;return Promise.resolve().then(()=>o.get(e)).then(a=>typeof a==\"string\"?this.opts.deserialize(a):a).then(a=>{if(a!==void 0){if(typeof a.expires==\"number\"&&Date.now()>a.expires){this.delete(e);return}return r&&r.raw?a:a.value}})}set(e,r,o){e=this._getKeyPrefix(e),typeof o>\"u\"&&(o=this.opts.ttl),o===0&&(o=void 0);let{store:a}=this.opts;return Promise.resolve().then(()=>{let n=typeof o==\"number\"?Date.now()+o:null;return r={value:r,expires:n},this.opts.serialize(r)}).then(n=>a.set(e,n,o)).then(()=>!0)}delete(e){e=this._getKeyPrefix(e);let{store:r}=this.opts;return Promise.resolve().then(()=>r.delete(e))}clear(){let{store:e}=this.opts;return Promise.resolve().then(()=>e.clear())}};Loe.exports=qM});var _oe=_((DLt,Uoe)=>{\"use strict\";var Hnt=Be(\"events\"),rb=Be(\"url\"),jnt=Aoe(),qnt=voe(),GM=Poe(),Moe=xoe(),Gnt=tb(),Ynt=Roe(),Wnt=Ooe(),jc=class{constructor(e,r){if(typeof e!=\"function\")throw new TypeError(\"Parameter `request` must be a function\");return this.cache=new Wnt({uri:typeof r==\"string\"&&r,store:typeof r!=\"string\"&&r,namespace:\"cacheable-request\"}),this.createCacheableRequest(e)}createCacheableRequest(e){return(r,o)=>{let a;if(typeof r==\"string\")a=YM(rb.parse(r)),r={};else if(r instanceof rb.URL)a=YM(rb.parse(r.toString())),r={};else{let[I,...v]=(r.path||\"\").split(\"?\"),x=v.length>0?`?${v.join(\"?\")}`:\"\";a=YM({...r,pathname:I,search:x})}r={headers:{},method:\"GET\",cache:!0,strictTtl:!1,automaticFailover:!1,...r,...Knt(a)},r.headers=Gnt(r.headers);let n=new Hnt,u=jnt(rb.format(a),{stripWWW:!1,removeTrailingSlash:!1,stripAuthentication:!1}),A=`${r.method}:${u}`,p=!1,h=!1,C=I=>{h=!0;let v=!1,x,E=new Promise(L=>{x=()=>{v||(v=!0,L())}}),R=L=>{if(p&&!I.forceRefresh){L.status=L.statusCode;let z=GM.fromObject(p.cachePolicy).revalidatedPolicy(I,L);if(!z.modified){let te=z.policy.responseHeaders();L=new Moe(p.statusCode,te,p.body,p.url),L.cachePolicy=z.policy,L.fromCache=!0}}L.fromCache||(L.cachePolicy=new GM(I,L,I),L.fromCache=!1);let U;I.cache&&L.cachePolicy.storable()?(U=Ynt(L),(async()=>{try{let z=qnt.buffer(L);if(await Promise.race([E,new Promise(Ae=>L.once(\"end\",Ae))]),v)return;let te=await z,le={cachePolicy:L.cachePolicy.toObject(),url:L.url,statusCode:L.fromCache?p.statusCode:L.statusCode,body:te},he=I.strictTtl?L.cachePolicy.timeToLive():void 0;I.maxTtl&&(he=he?Math.min(he,I.maxTtl):I.maxTtl),await this.cache.set(A,le,he)}catch(z){n.emit(\"error\",new jc.CacheError(z))}})()):I.cache&&p&&(async()=>{try{await this.cache.delete(A)}catch(z){n.emit(\"error\",new jc.CacheError(z))}})(),n.emit(\"response\",U||L),typeof o==\"function\"&&o(U||L)};try{let L=e(I,R);L.once(\"error\",x),L.once(\"abort\",x),n.emit(\"request\",L)}catch(L){n.emit(\"error\",new jc.RequestError(L))}};return(async()=>{let I=async x=>{await Promise.resolve();let E=x.cache?await this.cache.get(A):void 0;if(typeof E>\"u\")return C(x);let R=GM.fromObject(E.cachePolicy);if(R.satisfiesWithoutRevalidation(x)&&!x.forceRefresh){let L=R.responseHeaders(),U=new Moe(E.statusCode,L,E.body,E.url);U.cachePolicy=R,U.fromCache=!0,n.emit(\"response\",U),typeof o==\"function\"&&o(U)}else p=E,x.headers=R.revalidationHeaders(x),C(x)},v=x=>n.emit(\"error\",new jc.CacheError(x));this.cache.once(\"error\",v),n.on(\"response\",()=>this.cache.removeListener(\"error\",v));try{await I(r)}catch(x){r.automaticFailover&&!h&&C(r),n.emit(\"error\",new jc.CacheError(x))}})(),n}}};function Knt(t){let e={...t};return e.path=`${t.pathname||\"/\"}${t.search||\"\"}`,delete e.pathname,delete e.search,e}function YM(t){return{protocol:t.protocol,auth:t.auth,hostname:t.hostname||t.host||\"localhost\",port:t.port,pathname:t.pathname,search:t.search}}jc.RequestError=class extends Error{constructor(t){super(t.message),this.name=\"RequestError\",Object.assign(this,t)}};jc.CacheError=class extends Error{constructor(t){super(t.message),this.name=\"CacheError\",Object.assign(this,t)}};Uoe.exports=jc});var joe=_((bLt,Hoe)=>{\"use strict\";var Vnt=[\"aborted\",\"complete\",\"headers\",\"httpVersion\",\"httpVersionMinor\",\"httpVersionMajor\",\"method\",\"rawHeaders\",\"rawTrailers\",\"setTimeout\",\"socket\",\"statusCode\",\"statusMessage\",\"trailers\",\"url\"];Hoe.exports=(t,e)=>{if(e._readableState.autoDestroy)throw new Error(\"The second stream must have the `autoDestroy` option set to `false`\");let r=new Set(Object.keys(t).concat(Vnt)),o={};for(let a of r)a in e||(o[a]={get(){let n=t[a];return typeof n==\"function\"?n.bind(t):n},set(n){t[a]=n},enumerable:!0,configurable:!1});return Object.defineProperties(e,o),t.once(\"aborted\",()=>{e.destroy(),e.emit(\"aborted\")}),t.once(\"close\",()=>{t.complete&&e.readable?e.once(\"end\",()=>{e.emit(\"close\")}):e.emit(\"close\")}),e}});var Goe=_((xLt,qoe)=>{\"use strict\";var{Transform:znt,PassThrough:Jnt}=Be(\"stream\"),WM=Be(\"zlib\"),Xnt=joe();qoe.exports=t=>{let e=(t.headers[\"content-encoding\"]||\"\").toLowerCase();if(![\"gzip\",\"deflate\",\"br\"].includes(e))return t;let r=e===\"br\";if(r&&typeof WM.createBrotliDecompress!=\"function\")return t.destroy(new Error(\"Brotli is not supported on Node.js < 12\")),t;let o=!0,a=new znt({transform(A,p,h){o=!1,h(null,A)},flush(A){A()}}),n=new Jnt({autoDestroy:!1,destroy(A,p){t.destroy(),p(A)}}),u=r?WM.createBrotliDecompress():WM.createUnzip();return u.once(\"error\",A=>{if(o&&!t.readable){n.end();return}n.destroy(A)}),Xnt(t,n),t.pipe(a).pipe(u).pipe(n),n}});var VM=_((kLt,Yoe)=>{\"use strict\";var KM=class{constructor(e={}){if(!(e.maxSize&&e.maxSize>0))throw new TypeError(\"`maxSize` must be a number greater than 0\");this.maxSize=e.maxSize,this.onEviction=e.onEviction,this.cache=new Map,this.oldCache=new Map,this._size=0}_set(e,r){if(this.cache.set(e,r),this._size++,this._size>=this.maxSize){if(this._size=0,typeof this.onEviction==\"function\")for(let[o,a]of this.oldCache.entries())this.onEviction(o,a);this.oldCache=this.cache,this.cache=new Map}}get(e){if(this.cache.has(e))return this.cache.get(e);if(this.oldCache.has(e)){let r=this.oldCache.get(e);return this.oldCache.delete(e),this._set(e,r),r}}set(e,r){return this.cache.has(e)?this.cache.set(e,r):this._set(e,r),this}has(e){return this.cache.has(e)||this.oldCache.has(e)}peek(e){if(this.cache.has(e))return this.cache.get(e);if(this.oldCache.has(e))return this.oldCache.get(e)}delete(e){let r=this.cache.delete(e);return r&&this._size--,this.oldCache.delete(e)||r}clear(){this.cache.clear(),this.oldCache.clear(),this._size=0}*keys(){for(let[e]of this)yield e}*values(){for(let[,e]of this)yield e}*[Symbol.iterator](){for(let e of this.cache)yield e;for(let e of this.oldCache){let[r]=e;this.cache.has(r)||(yield e)}}get size(){let e=0;for(let r of this.oldCache.keys())this.cache.has(r)||e++;return Math.min(this._size+e,this.maxSize)}};Yoe.exports=KM});var JM=_((QLt,zoe)=>{\"use strict\";var Znt=Be(\"events\"),$nt=Be(\"tls\"),eit=Be(\"http2\"),tit=VM(),ea=Symbol(\"currentStreamsCount\"),Woe=Symbol(\"request\"),Wl=Symbol(\"cachedOriginSet\"),BE=Symbol(\"gracefullyClosing\"),rit=[\"maxDeflateDynamicTableSize\",\"maxSessionMemory\",\"maxHeaderListPairs\",\"maxOutstandingPings\",\"maxReservedRemoteStreams\",\"maxSendHeaderBlockLength\",\"paddingStrategy\",\"localAddress\",\"path\",\"rejectUnauthorized\",\"minDHSize\",\"ca\",\"cert\",\"clientCertEngine\",\"ciphers\",\"key\",\"pfx\",\"servername\",\"minVersion\",\"maxVersion\",\"secureProtocol\",\"crl\",\"honorCipherOrder\",\"ecdhCurve\",\"dhparam\",\"secureOptions\",\"sessionIdContext\"],nit=(t,e,r)=>{let o=0,a=t.length;for(;o<a;){let n=o+a>>>1;r(t[n],e)?o=n+1:a=n}return o},iit=(t,e)=>t.remoteSettings.maxConcurrentStreams>e.remoteSettings.maxConcurrentStreams,zM=(t,e)=>{for(let r of t)r[Wl].length<e[Wl].length&&r[Wl].every(o=>e[Wl].includes(o))&&r[ea]+e[ea]<=e.remoteSettings.maxConcurrentStreams&&Voe(r)},sit=(t,e)=>{for(let r of t)e[Wl].length<r[Wl].length&&e[Wl].every(o=>r[Wl].includes(o))&&e[ea]+r[ea]<=r.remoteSettings.maxConcurrentStreams&&Voe(e)},Koe=({agent:t,isFree:e})=>{let r={};for(let o in t.sessions){let n=t.sessions[o].filter(u=>{let A=u[tA.kCurrentStreamsCount]<u.remoteSettings.maxConcurrentStreams;return e?A:!A});n.length!==0&&(r[o]=n)}return r},Voe=t=>{t[BE]=!0,t[ea]===0&&t.close()},tA=class extends Znt{constructor({timeout:e=6e4,maxSessions:r=1/0,maxFreeSessions:o=10,maxCachedTlsSessions:a=100}={}){super(),this.sessions={},this.queue={},this.timeout=e,this.maxSessions=r,this.maxFreeSessions=o,this._freeSessionsCount=0,this._sessionsCount=0,this.settings={enablePush:!1},this.tlsSessionCache=new tit({maxSize:a})}static normalizeOrigin(e,r){return typeof e==\"string\"&&(e=new URL(e)),r&&e.hostname!==r&&(e.hostname=r),e.origin}normalizeOptions(e){let r=\"\";if(e)for(let o of rit)e[o]&&(r+=`:${e[o]}`);return r}_tryToCreateNewSession(e,r){if(!(e in this.queue)||!(r in this.queue[e]))return;let o=this.queue[e][r];this._sessionsCount<this.maxSessions&&!o.completed&&(o.completed=!0,o())}getSession(e,r,o){return new Promise((a,n)=>{Array.isArray(o)?(o=[...o],a()):o=[{resolve:a,reject:n}];let u=this.normalizeOptions(r),A=tA.normalizeOrigin(e,r&&r.servername);if(A===void 0){for(let{reject:C}of o)C(new TypeError(\"The `origin` argument needs to be a string or an URL object\"));return}if(u in this.sessions){let C=this.sessions[u],I=-1,v=-1,x;for(let E of C){let R=E.remoteSettings.maxConcurrentStreams;if(R<I)break;if(E[Wl].includes(A)){let L=E[ea];if(L>=R||E[BE]||E.destroyed)continue;x||(I=R),L>v&&(x=E,v=L)}}if(x){if(o.length!==1){for(let{reject:E}of o){let R=new Error(`Expected the length of listeners to be 1, got ${o.length}.\nPlease report this to https://github.com/szmarczak/http2-wrapper/`);E(R)}return}o[0].resolve(x);return}}if(u in this.queue){if(A in this.queue[u]){this.queue[u][A].listeners.push(...o),this._tryToCreateNewSession(u,A);return}}else this.queue[u]={};let p=()=>{u in this.queue&&this.queue[u][A]===h&&(delete this.queue[u][A],Object.keys(this.queue[u]).length===0&&delete this.queue[u])},h=()=>{let C=`${A}:${u}`,I=!1;try{let v=eit.connect(e,{createConnection:this.createConnection,settings:this.settings,session:this.tlsSessionCache.get(C),...r});v[ea]=0,v[BE]=!1;let x=()=>v[ea]<v.remoteSettings.maxConcurrentStreams,E=!0;v.socket.once(\"session\",L=>{this.tlsSessionCache.set(C,L)}),v.once(\"error\",L=>{for(let{reject:U}of o)U(L);this.tlsSessionCache.delete(C)}),v.setTimeout(this.timeout,()=>{v.destroy()}),v.once(\"close\",()=>{if(I){E&&this._freeSessionsCount--,this._sessionsCount--;let L=this.sessions[u];L.splice(L.indexOf(v),1),L.length===0&&delete this.sessions[u]}else{let L=new Error(\"Session closed without receiving a SETTINGS frame\");L.code=\"HTTP2WRAPPER_NOSETTINGS\";for(let{reject:U}of o)U(L);p()}this._tryToCreateNewSession(u,A)});let R=()=>{if(!(!(u in this.queue)||!x())){for(let L of v[Wl])if(L in this.queue[u]){let{listeners:U}=this.queue[u][L];for(;U.length!==0&&x();)U.shift().resolve(v);let z=this.queue[u];if(z[L].listeners.length===0&&(delete z[L],Object.keys(z).length===0)){delete this.queue[u];break}if(!x())break}}};v.on(\"origin\",()=>{v[Wl]=v.originSet,x()&&(R(),zM(this.sessions[u],v))}),v.once(\"remoteSettings\",()=>{if(v.ref(),v.unref(),this._sessionsCount++,h.destroyed){let L=new Error(\"Agent has been destroyed\");for(let U of o)U.reject(L);v.destroy();return}v[Wl]=v.originSet;{let L=this.sessions;if(u in L){let U=L[u];U.splice(nit(U,v,iit),0,v)}else L[u]=[v]}this._freeSessionsCount+=1,I=!0,this.emit(\"session\",v),R(),p(),v[ea]===0&&this._freeSessionsCount>this.maxFreeSessions&&v.close(),o.length!==0&&(this.getSession(A,r,o),o.length=0),v.on(\"remoteSettings\",()=>{R(),zM(this.sessions[u],v)})}),v[Woe]=v.request,v.request=(L,U)=>{if(v[BE])throw new Error(\"The session is gracefully closing. No new streams are allowed.\");let z=v[Woe](L,U);return v.ref(),++v[ea],v[ea]===v.remoteSettings.maxConcurrentStreams&&this._freeSessionsCount--,z.once(\"close\",()=>{if(E=x(),--v[ea],!v.destroyed&&!v.closed&&(sit(this.sessions[u],v),x()&&!v.closed)){E||(this._freeSessionsCount++,E=!0);let te=v[ea]===0;te&&v.unref(),te&&(this._freeSessionsCount>this.maxFreeSessions||v[BE])?v.close():(zM(this.sessions[u],v),R())}}),z}}catch(v){for(let x of o)x.reject(v);p()}};h.listeners=o,h.completed=!1,h.destroyed=!1,this.queue[u][A]=h,this._tryToCreateNewSession(u,A)})}request(e,r,o,a){return new Promise((n,u)=>{this.getSession(e,r,[{reject:u,resolve:A=>{try{n(A.request(o,a))}catch(p){u(p)}}}])})}createConnection(e,r){return tA.connect(e,r)}static connect(e,r){r.ALPNProtocols=[\"h2\"];let o=e.port||443,a=e.hostname||e.host;return typeof r.servername>\"u\"&&(r.servername=a),$nt.connect(o,a,r)}closeFreeSessions(){for(let e of Object.values(this.sessions))for(let r of e)r[ea]===0&&r.close()}destroy(e){for(let r of Object.values(this.sessions))for(let o of r)o.destroy(e);for(let r of Object.values(this.queue))for(let o of Object.values(r))o.destroyed=!0;this.queue={}}get freeSessions(){return Koe({agent:this,isFree:!0})}get busySessions(){return Koe({agent:this,isFree:!1})}};tA.kCurrentStreamsCount=ea;tA.kGracefullyClosing=BE;zoe.exports={Agent:tA,globalAgent:new tA}});var ZM=_((FLt,Joe)=>{\"use strict\";var{Readable:oit}=Be(\"stream\"),XM=class extends oit{constructor(e,r){super({highWaterMark:r,autoDestroy:!1}),this.statusCode=null,this.statusMessage=\"\",this.httpVersion=\"2.0\",this.httpVersionMajor=2,this.httpVersionMinor=0,this.headers={},this.trailers={},this.req=null,this.aborted=!1,this.complete=!1,this.upgrade=null,this.rawHeaders=[],this.rawTrailers=[],this.socket=e,this.connection=e,this._dumped=!1}_destroy(e){this.req._request.destroy(e)}setTimeout(e,r){return this.req.setTimeout(e,r),this}_dump(){this._dumped||(this._dumped=!0,this.removeAllListeners(\"data\"),this.resume())}_read(){this.req&&this.req._request.resume()}};Joe.exports=XM});var $M=_((RLt,Xoe)=>{\"use strict\";Xoe.exports=t=>{let e={protocol:t.protocol,hostname:typeof t.hostname==\"string\"&&t.hostname.startsWith(\"[\")?t.hostname.slice(1,-1):t.hostname,host:t.host,hash:t.hash,search:t.search,pathname:t.pathname,href:t.href,path:`${t.pathname||\"\"}${t.search||\"\"}`};return typeof t.port==\"string\"&&t.port.length!==0&&(e.port=Number(t.port)),(t.username||t.password)&&(e.auth=`${t.username||\"\"}:${t.password||\"\"}`),e}});var $oe=_((TLt,Zoe)=>{\"use strict\";Zoe.exports=(t,e,r)=>{for(let o of r)t.on(o,(...a)=>e.emit(o,...a))}});var tae=_((NLt,eae)=>{\"use strict\";eae.exports=t=>{switch(t){case\":method\":case\":scheme\":case\":authority\":case\":path\":return!0;default:return!1}}});var nae=_((OLt,rae)=>{\"use strict\";var vE=(t,e,r)=>{rae.exports[e]=class extends t{constructor(...a){super(typeof r==\"string\"?r:r(a)),this.name=`${super.name} [${e}]`,this.code=e}}};vE(TypeError,\"ERR_INVALID_ARG_TYPE\",t=>{let e=t[0].includes(\".\")?\"property\":\"argument\",r=t[1],o=Array.isArray(r);return o&&(r=`${r.slice(0,-1).join(\", \")} or ${r.slice(-1)}`),`The \"${t[0]}\" ${e} must be ${o?\"one of\":\"of\"} type ${r}. Received ${typeof t[2]}`});vE(TypeError,\"ERR_INVALID_PROTOCOL\",t=>`Protocol \"${t[0]}\" not supported. Expected \"${t[1]}\"`);vE(Error,\"ERR_HTTP_HEADERS_SENT\",t=>`Cannot ${t[0]} headers after they are sent to the client`);vE(TypeError,\"ERR_INVALID_HTTP_TOKEN\",t=>`${t[0]} must be a valid HTTP token [${t[1]}]`);vE(TypeError,\"ERR_HTTP_INVALID_HEADER_VALUE\",t=>`Invalid value \"${t[0]} for header \"${t[1]}\"`);vE(TypeError,\"ERR_INVALID_CHAR\",t=>`Invalid character in ${t[0]} [${t[1]}]`)});var i4=_((MLt,uae)=>{\"use strict\";var ait=Be(\"http2\"),{Writable:lit}=Be(\"stream\"),{Agent:iae,globalAgent:cit}=JM(),uit=ZM(),Ait=$M(),fit=$oe(),pit=tae(),{ERR_INVALID_ARG_TYPE:e4,ERR_INVALID_PROTOCOL:hit,ERR_HTTP_HEADERS_SENT:sae,ERR_INVALID_HTTP_TOKEN:git,ERR_HTTP_INVALID_HEADER_VALUE:dit,ERR_INVALID_CHAR:mit}=nae(),{HTTP2_HEADER_STATUS:oae,HTTP2_HEADER_METHOD:aae,HTTP2_HEADER_PATH:lae,HTTP2_METHOD_CONNECT:yit}=ait.constants,Qo=Symbol(\"headers\"),t4=Symbol(\"origin\"),r4=Symbol(\"session\"),cae=Symbol(\"options\"),nb=Symbol(\"flushedHeaders\"),f1=Symbol(\"jobs\"),Eit=/^[\\^`\\-\\w!#$%&*+.|~]+$/,Cit=/[^\\t\\u0020-\\u007E\\u0080-\\u00FF]/,n4=class extends lit{constructor(e,r,o){super({autoDestroy:!1});let a=typeof e==\"string\"||e instanceof URL;if(a&&(e=Ait(e instanceof URL?e:new URL(e))),typeof r==\"function\"||r===void 0?(o=r,r=a?e:{...e}):r={...e,...r},r.h2session)this[r4]=r.h2session;else if(r.agent===!1)this.agent=new iae({maxFreeSessions:0});else if(typeof r.agent>\"u\"||r.agent===null)typeof r.createConnection==\"function\"?(this.agent=new iae({maxFreeSessions:0}),this.agent.createConnection=r.createConnection):this.agent=cit;else if(typeof r.agent.request==\"function\")this.agent=r.agent;else throw new e4(\"options.agent\",[\"Agent-like Object\",\"undefined\",\"false\"],r.agent);if(r.protocol&&r.protocol!==\"https:\")throw new hit(r.protocol,\"https:\");let n=r.port||r.defaultPort||this.agent&&this.agent.defaultPort||443,u=r.hostname||r.host||\"localhost\";delete r.hostname,delete r.host,delete r.port;let{timeout:A}=r;if(r.timeout=void 0,this[Qo]=Object.create(null),this[f1]=[],this.socket=null,this.connection=null,this.method=r.method||\"GET\",this.path=r.path,this.res=null,this.aborted=!1,this.reusedSocket=!1,r.headers)for(let[p,h]of Object.entries(r.headers))this.setHeader(p,h);r.auth&&!(\"authorization\"in this[Qo])&&(this[Qo].authorization=\"Basic \"+Buffer.from(r.auth).toString(\"base64\")),r.session=r.tlsSession,r.path=r.socketPath,this[cae]=r,n===443?(this[t4]=`https://${u}`,\":authority\"in this[Qo]||(this[Qo][\":authority\"]=u)):(this[t4]=`https://${u}:${n}`,\":authority\"in this[Qo]||(this[Qo][\":authority\"]=`${u}:${n}`)),A&&this.setTimeout(A),o&&this.once(\"response\",o),this[nb]=!1}get method(){return this[Qo][aae]}set method(e){e&&(this[Qo][aae]=e.toUpperCase())}get path(){return this[Qo][lae]}set path(e){e&&(this[Qo][lae]=e)}get _mustNotHaveABody(){return this.method===\"GET\"||this.method===\"HEAD\"||this.method===\"DELETE\"}_write(e,r,o){if(this._mustNotHaveABody){o(new Error(\"The GET, HEAD and DELETE methods must NOT have a body\"));return}this.flushHeaders();let a=()=>this._request.write(e,r,o);this._request?a():this[f1].push(a)}_final(e){if(this.destroyed)return;this.flushHeaders();let r=()=>{if(this._mustNotHaveABody){e();return}this._request.end(e)};this._request?r():this[f1].push(r)}abort(){this.res&&this.res.complete||(this.aborted||process.nextTick(()=>this.emit(\"abort\")),this.aborted=!0,this.destroy())}_destroy(e,r){this.res&&this.res._dump(),this._request&&this._request.destroy(),r(e)}async flushHeaders(){if(this[nb]||this.destroyed)return;this[nb]=!0;let e=this.method===yit,r=o=>{if(this._request=o,this.destroyed){o.destroy();return}e||fit(o,this,[\"timeout\",\"continue\",\"close\",\"error\"]);let a=u=>(...A)=>{!this.writable&&!this.destroyed?u(...A):this.once(\"finish\",()=>{u(...A)})};o.once(\"response\",a((u,A,p)=>{let h=new uit(this.socket,o.readableHighWaterMark);this.res=h,h.req=this,h.statusCode=u[oae],h.headers=u,h.rawHeaders=p,h.once(\"end\",()=>{this.aborted?(h.aborted=!0,h.emit(\"aborted\")):(h.complete=!0,h.socket=null,h.connection=null)}),e?(h.upgrade=!0,this.emit(\"connect\",h,o,Buffer.alloc(0))?this.emit(\"close\"):o.destroy()):(o.on(\"data\",C=>{!h._dumped&&!h.push(C)&&o.pause()}),o.once(\"end\",()=>{h.push(null)}),this.emit(\"response\",h)||h._dump())})),o.once(\"headers\",a(u=>this.emit(\"information\",{statusCode:u[oae]}))),o.once(\"trailers\",a((u,A,p)=>{let{res:h}=this;h.trailers=u,h.rawTrailers=p}));let{socket:n}=o.session;this.socket=n,this.connection=n;for(let u of this[f1])u();this.emit(\"socket\",this.socket)};if(this[r4])try{r(this[r4].request(this[Qo]))}catch(o){this.emit(\"error\",o)}else{this.reusedSocket=!0;try{r(await this.agent.request(this[t4],this[cae],this[Qo]))}catch(o){this.emit(\"error\",o)}}}getHeader(e){if(typeof e!=\"string\")throw new e4(\"name\",\"string\",e);return this[Qo][e.toLowerCase()]}get headersSent(){return this[nb]}removeHeader(e){if(typeof e!=\"string\")throw new e4(\"name\",\"string\",e);if(this.headersSent)throw new sae(\"remove\");delete this[Qo][e.toLowerCase()]}setHeader(e,r){if(this.headersSent)throw new sae(\"set\");if(typeof e!=\"string\"||!Eit.test(e)&&!pit(e))throw new git(\"Header name\",e);if(typeof r>\"u\")throw new dit(r,e);if(Cit.test(r))throw new mit(\"header content\",e);this[Qo][e.toLowerCase()]=r}setNoDelay(){}setSocketKeepAlive(){}setTimeout(e,r){let o=()=>this._request.setTimeout(e,r);return this._request?o():this[f1].push(o),this}get maxHeadersCount(){if(!this.destroyed&&this._request)return this._request.session.localSettings.maxHeaderListSize}set maxHeadersCount(e){}};uae.exports=n4});var fae=_((ULt,Aae)=>{\"use strict\";var wit=Be(\"tls\");Aae.exports=(t={})=>new Promise((e,r)=>{let o=wit.connect(t,()=>{t.resolveSocket?(o.off(\"error\",r),e({alpnProtocol:o.alpnProtocol,socket:o})):(o.destroy(),e({alpnProtocol:o.alpnProtocol}))});o.on(\"error\",r)})});var hae=_((_Lt,pae)=>{\"use strict\";var Iit=Be(\"net\");pae.exports=t=>{let e=t.host,r=t.headers&&t.headers.host;return r&&(r.startsWith(\"[\")?r.indexOf(\"]\")===-1?e=r:e=r.slice(1,-1):e=r.split(\":\",1)[0]),Iit.isIP(e)?\"\":e}});var mae=_((HLt,o4)=>{\"use strict\";var gae=Be(\"http\"),s4=Be(\"https\"),Bit=fae(),vit=VM(),Dit=i4(),Pit=hae(),Sit=$M(),ib=new vit({maxSize:100}),p1=new Map,dae=(t,e,r)=>{e._httpMessage={shouldKeepAlive:!0};let o=()=>{t.emit(\"free\",e,r)};e.on(\"free\",o);let a=()=>{t.removeSocket(e,r)};e.on(\"close\",a);let n=()=>{t.removeSocket(e,r),e.off(\"close\",a),e.off(\"free\",o),e.off(\"agentRemove\",n)};e.on(\"agentRemove\",n),t.emit(\"free\",e,r)},bit=async t=>{let e=`${t.host}:${t.port}:${t.ALPNProtocols.sort()}`;if(!ib.has(e)){if(p1.has(e))return(await p1.get(e)).alpnProtocol;let{path:r,agent:o}=t;t.path=t.socketPath;let a=Bit(t);p1.set(e,a);try{let{socket:n,alpnProtocol:u}=await a;if(ib.set(e,u),t.path=r,u===\"h2\")n.destroy();else{let{globalAgent:A}=s4,p=s4.Agent.prototype.createConnection;o?o.createConnection===p?dae(o,n,t):n.destroy():A.createConnection===p?dae(A,n,t):n.destroy()}return p1.delete(e),u}catch(n){throw p1.delete(e),n}}return ib.get(e)};o4.exports=async(t,e,r)=>{if((typeof t==\"string\"||t instanceof URL)&&(t=Sit(new URL(t))),typeof e==\"function\"&&(r=e,e=void 0),e={ALPNProtocols:[\"h2\",\"http/1.1\"],...t,...e,resolveSocket:!0},!Array.isArray(e.ALPNProtocols)||e.ALPNProtocols.length===0)throw new Error(\"The `ALPNProtocols` option must be an Array with at least one entry\");e.protocol=e.protocol||\"https:\";let o=e.protocol===\"https:\";e.host=e.hostname||e.host||\"localhost\",e.session=e.tlsSession,e.servername=e.servername||Pit(e),e.port=e.port||(o?443:80),e._defaultAgent=o?s4.globalAgent:gae.globalAgent;let a=e.agent;if(a){if(a.addRequest)throw new Error(\"The `options.agent` object can contain only `http`, `https` or `http2` properties\");e.agent=a[o?\"https\":\"http\"]}return o&&await bit(e)===\"h2\"?(a&&(e.agent=a.http2),new Dit(e,r)):gae.request(e,r)};o4.exports.protocolCache=ib});var Eae=_((jLt,yae)=>{\"use strict\";var xit=Be(\"http2\"),kit=JM(),a4=i4(),Qit=ZM(),Fit=mae(),Rit=(t,e,r)=>new a4(t,e,r),Tit=(t,e,r)=>{let o=new a4(t,e,r);return o.end(),o};yae.exports={...xit,ClientRequest:a4,IncomingMessage:Qit,...kit,request:Rit,get:Tit,auto:Fit}});var c4=_(l4=>{\"use strict\";Object.defineProperty(l4,\"__esModule\",{value:!0});var Cae=Ff();l4.default=t=>Cae.default.nodeStream(t)&&Cae.default.function_(t.getBoundary)});var vae=_(u4=>{\"use strict\";Object.defineProperty(u4,\"__esModule\",{value:!0});var Iae=Be(\"fs\"),Bae=Be(\"util\"),wae=Ff(),Nit=c4(),Lit=Bae.promisify(Iae.stat);u4.default=async(t,e)=>{if(e&&\"content-length\"in e)return Number(e[\"content-length\"]);if(!t)return 0;if(wae.default.string(t))return Buffer.byteLength(t);if(wae.default.buffer(t))return t.length;if(Nit.default(t))return Bae.promisify(t.getLength.bind(t))();if(t instanceof Iae.ReadStream){let{size:r}=await Lit(t.path);return r===0?void 0:r}}});var f4=_(A4=>{\"use strict\";Object.defineProperty(A4,\"__esModule\",{value:!0});function Oit(t,e,r){let o={};for(let a of r)o[a]=(...n)=>{e.emit(a,...n)},t.on(a,o[a]);return()=>{for(let a of r)t.off(a,o[a])}}A4.default=Oit});var Dae=_(p4=>{\"use strict\";Object.defineProperty(p4,\"__esModule\",{value:!0});p4.default=()=>{let t=[];return{once(e,r,o){e.once(r,o),t.push({origin:e,event:r,fn:o})},unhandleAll(){for(let e of t){let{origin:r,event:o,fn:a}=e;r.removeListener(o,a)}t.length=0}}}});var Sae=_(h1=>{\"use strict\";Object.defineProperty(h1,\"__esModule\",{value:!0});h1.TimeoutError=void 0;var Mit=Be(\"net\"),Uit=Dae(),Pae=Symbol(\"reentry\"),_it=()=>{},sb=class extends Error{constructor(e,r){super(`Timeout awaiting '${r}' for ${e}ms`),this.event=r,this.name=\"TimeoutError\",this.code=\"ETIMEDOUT\"}};h1.TimeoutError=sb;h1.default=(t,e,r)=>{if(Pae in t)return _it;t[Pae]=!0;let o=[],{once:a,unhandleAll:n}=Uit.default(),u=(I,v,x)=>{var E;let R=setTimeout(v,I,I,x);(E=R.unref)===null||E===void 0||E.call(R);let L=()=>{clearTimeout(R)};return o.push(L),L},{host:A,hostname:p}=r,h=(I,v)=>{t.destroy(new sb(I,v))},C=()=>{for(let I of o)I();n()};if(t.once(\"error\",I=>{if(C(),t.listenerCount(\"error\")===0)throw I}),t.once(\"close\",C),a(t,\"response\",I=>{a(I,\"end\",C)}),typeof e.request<\"u\"&&u(e.request,h,\"request\"),typeof e.socket<\"u\"){let I=()=>{h(e.socket,\"socket\")};t.setTimeout(e.socket,I),o.push(()=>{t.removeListener(\"timeout\",I)})}return a(t,\"socket\",I=>{var v;let{socketPath:x}=t;if(I.connecting){let E=Boolean(x??Mit.isIP((v=p??A)!==null&&v!==void 0?v:\"\")!==0);if(typeof e.lookup<\"u\"&&!E&&typeof I.address().address>\"u\"){let R=u(e.lookup,h,\"lookup\");a(I,\"lookup\",R)}if(typeof e.connect<\"u\"){let R=()=>u(e.connect,h,\"connect\");E?a(I,\"connect\",R()):a(I,\"lookup\",L=>{L===null&&a(I,\"connect\",R())})}typeof e.secureConnect<\"u\"&&r.protocol===\"https:\"&&a(I,\"connect\",()=>{let R=u(e.secureConnect,h,\"secureConnect\");a(I,\"secureConnect\",R)})}if(typeof e.send<\"u\"){let E=()=>u(e.send,h,\"send\");I.connecting?a(I,\"connect\",()=>{a(t,\"upload-complete\",E())}):a(t,\"upload-complete\",E())}}),typeof e.response<\"u\"&&a(t,\"upload-complete\",()=>{let I=u(e.response,h,\"response\");a(t,\"response\",I)}),C}});var xae=_(h4=>{\"use strict\";Object.defineProperty(h4,\"__esModule\",{value:!0});var bae=Ff();h4.default=t=>{t=t;let e={protocol:t.protocol,hostname:bae.default.string(t.hostname)&&t.hostname.startsWith(\"[\")?t.hostname.slice(1,-1):t.hostname,host:t.host,hash:t.hash,search:t.search,pathname:t.pathname,href:t.href,path:`${t.pathname||\"\"}${t.search||\"\"}`};return bae.default.string(t.port)&&t.port.length>0&&(e.port=Number(t.port)),(t.username||t.password)&&(e.auth=`${t.username||\"\"}:${t.password||\"\"}`),e}});var kae=_(g4=>{\"use strict\";Object.defineProperty(g4,\"__esModule\",{value:!0});var Hit=Be(\"url\"),jit=[\"protocol\",\"host\",\"hostname\",\"port\",\"pathname\",\"search\"];g4.default=(t,e)=>{var r,o;if(e.path){if(e.pathname)throw new TypeError(\"Parameters `path` and `pathname` are mutually exclusive.\");if(e.search)throw new TypeError(\"Parameters `path` and `search` are mutually exclusive.\");if(e.searchParams)throw new TypeError(\"Parameters `path` and `searchParams` are mutually exclusive.\")}if(e.search&&e.searchParams)throw new TypeError(\"Parameters `search` and `searchParams` are mutually exclusive.\");if(!t){if(!e.protocol)throw new TypeError(\"No URL protocol specified\");t=`${e.protocol}//${(o=(r=e.hostname)!==null&&r!==void 0?r:e.host)!==null&&o!==void 0?o:\"\"}`}let a=new Hit.URL(t);if(e.path){let n=e.path.indexOf(\"?\");n===-1?e.pathname=e.path:(e.pathname=e.path.slice(0,n),e.search=e.path.slice(n+1)),delete e.path}for(let n of jit)e[n]&&(a[n]=e[n].toString());return a}});var Qae=_(m4=>{\"use strict\";Object.defineProperty(m4,\"__esModule\",{value:!0});var d4=class{constructor(){this.weakMap=new WeakMap,this.map=new Map}set(e,r){typeof e==\"object\"?this.weakMap.set(e,r):this.map.set(e,r)}get(e){return typeof e==\"object\"?this.weakMap.get(e):this.map.get(e)}has(e){return typeof e==\"object\"?this.weakMap.has(e):this.map.has(e)}};m4.default=d4});var E4=_(y4=>{\"use strict\";Object.defineProperty(y4,\"__esModule\",{value:!0});var qit=async t=>{let e=[],r=0;for await(let o of t)e.push(o),r+=Buffer.byteLength(o);return Buffer.isBuffer(e[0])?Buffer.concat(e,r):Buffer.from(e.join(\"\"))};y4.default=qit});var Rae=_(Dd=>{\"use strict\";Object.defineProperty(Dd,\"__esModule\",{value:!0});Dd.dnsLookupIpVersionToFamily=Dd.isDnsLookupIpVersion=void 0;var Fae={auto:0,ipv4:4,ipv6:6};Dd.isDnsLookupIpVersion=t=>t in Fae;Dd.dnsLookupIpVersionToFamily=t=>{if(Dd.isDnsLookupIpVersion(t))return Fae[t];throw new Error(\"Invalid DNS lookup IP version\")}});var C4=_(ob=>{\"use strict\";Object.defineProperty(ob,\"__esModule\",{value:!0});ob.isResponseOk=void 0;ob.isResponseOk=t=>{let{statusCode:e}=t,r=t.request.options.followRedirect?299:399;return e>=200&&e<=r||e===304}});var Nae=_(w4=>{\"use strict\";Object.defineProperty(w4,\"__esModule\",{value:!0});var Tae=new Set;w4.default=t=>{Tae.has(t)||(Tae.add(t),process.emitWarning(`Got: ${t}`,{type:\"DeprecationWarning\"}))}});var Lae=_(I4=>{\"use strict\";Object.defineProperty(I4,\"__esModule\",{value:!0});var Ai=Ff(),Git=(t,e)=>{if(Ai.default.null_(t.encoding))throw new TypeError(\"To get a Buffer, set `options.responseType` to `buffer` instead\");Ai.assert.any([Ai.default.string,Ai.default.undefined],t.encoding),Ai.assert.any([Ai.default.boolean,Ai.default.undefined],t.resolveBodyOnly),Ai.assert.any([Ai.default.boolean,Ai.default.undefined],t.methodRewriting),Ai.assert.any([Ai.default.boolean,Ai.default.undefined],t.isStream),Ai.assert.any([Ai.default.string,Ai.default.undefined],t.responseType),t.responseType===void 0&&(t.responseType=\"text\");let{retry:r}=t;if(e?t.retry={...e.retry}:t.retry={calculateDelay:o=>o.computedValue,limit:0,methods:[],statusCodes:[],errorCodes:[],maxRetryAfter:void 0},Ai.default.object(r)?(t.retry={...t.retry,...r},t.retry.methods=[...new Set(t.retry.methods.map(o=>o.toUpperCase()))],t.retry.statusCodes=[...new Set(t.retry.statusCodes)],t.retry.errorCodes=[...new Set(t.retry.errorCodes)]):Ai.default.number(r)&&(t.retry.limit=r),Ai.default.undefined(t.retry.maxRetryAfter)&&(t.retry.maxRetryAfter=Math.min(...[t.timeout.request,t.timeout.connect].filter(Ai.default.number))),Ai.default.object(t.pagination)){e&&(t.pagination={...e.pagination,...t.pagination});let{pagination:o}=t;if(!Ai.default.function_(o.transform))throw new Error(\"`options.pagination.transform` must be implemented\");if(!Ai.default.function_(o.shouldContinue))throw new Error(\"`options.pagination.shouldContinue` must be implemented\");if(!Ai.default.function_(o.filter))throw new TypeError(\"`options.pagination.filter` must be implemented\");if(!Ai.default.function_(o.paginate))throw new Error(\"`options.pagination.paginate` must be implemented\")}return t.responseType===\"json\"&&t.headers.accept===void 0&&(t.headers.accept=\"application/json\"),t};I4.default=Git});var Oae=_(g1=>{\"use strict\";Object.defineProperty(g1,\"__esModule\",{value:!0});g1.retryAfterStatusCodes=void 0;g1.retryAfterStatusCodes=new Set([413,429,503]);var Yit=({attemptCount:t,retryOptions:e,error:r,retryAfter:o})=>{if(t>e.limit)return 0;let a=e.methods.includes(r.options.method),n=e.errorCodes.includes(r.code),u=r.response&&e.statusCodes.includes(r.response.statusCode);if(!a||!n&&!u)return 0;if(r.response){if(o)return e.maxRetryAfter===void 0||o>e.maxRetryAfter?0:o;if(r.response.statusCode===413)return 0}let A=Math.random()*100;return 2**(t-1)*1e3+A};g1.default=Yit});var y1=_(Bn=>{\"use strict\";Object.defineProperty(Bn,\"__esModule\",{value:!0});Bn.UnsupportedProtocolError=Bn.ReadError=Bn.TimeoutError=Bn.UploadError=Bn.CacheError=Bn.HTTPError=Bn.MaxRedirectsError=Bn.RequestError=Bn.setNonEnumerableProperties=Bn.knownHookEvents=Bn.withoutBody=Bn.kIsNormalizedAlready=void 0;var Mae=Be(\"util\"),Uae=Be(\"stream\"),Wit=Be(\"fs\"),oh=Be(\"url\"),_ae=Be(\"http\"),B4=Be(\"http\"),Kit=Be(\"https\"),Vit=toe(),zit=loe(),Hae=_oe(),Jit=Goe(),Xit=Eae(),Zit=tb(),st=Ff(),$it=vae(),jae=c4(),est=f4(),qae=Sae(),tst=xae(),Gae=kae(),rst=Qae(),nst=E4(),Yae=Rae(),ist=C4(),ah=Nae(),sst=Lae(),ost=Oae(),v4,Zs=Symbol(\"request\"),ub=Symbol(\"response\"),DE=Symbol(\"responseSize\"),PE=Symbol(\"downloadedSize\"),SE=Symbol(\"bodySize\"),bE=Symbol(\"uploadedSize\"),ab=Symbol(\"serverResponsesPiped\"),Wae=Symbol(\"unproxyEvents\"),Kae=Symbol(\"isFromCache\"),D4=Symbol(\"cancelTimeouts\"),Vae=Symbol(\"startedReading\"),xE=Symbol(\"stopReading\"),lb=Symbol(\"triggerRead\"),lh=Symbol(\"body\"),d1=Symbol(\"jobs\"),zae=Symbol(\"originalResponse\"),Jae=Symbol(\"retryTimeout\");Bn.kIsNormalizedAlready=Symbol(\"isNormalizedAlready\");var ast=st.default.string(process.versions.brotli);Bn.withoutBody=new Set([\"GET\",\"HEAD\"]);Bn.knownHookEvents=[\"init\",\"beforeRequest\",\"beforeRedirect\",\"beforeError\",\"beforeRetry\",\"afterResponse\"];function lst(t){for(let e in t){let r=t[e];if(!st.default.string(r)&&!st.default.number(r)&&!st.default.boolean(r)&&!st.default.null_(r)&&!st.default.undefined(r))throw new TypeError(`The \\`searchParams\\` value '${String(r)}' must be a string, number, boolean or null`)}}function cst(t){return st.default.object(t)&&!(\"statusCode\"in t)}var P4=new rst.default,ust=async t=>new Promise((e,r)=>{let o=a=>{r(a)};t.pending||e(),t.once(\"error\",o),t.once(\"ready\",()=>{t.off(\"error\",o),e()})}),Ast=new Set([300,301,302,303,304,307,308]),fst=[\"context\",\"body\",\"json\",\"form\"];Bn.setNonEnumerableProperties=(t,e)=>{let r={};for(let o of t)if(!!o)for(let a of fst)a in o&&(r[a]={writable:!0,configurable:!0,enumerable:!1,value:o[a]});Object.defineProperties(e,r)};var Vi=class extends Error{constructor(e,r,o){var a;if(super(e),Error.captureStackTrace(this,this.constructor),this.name=\"RequestError\",this.code=r.code,o instanceof mb?(Object.defineProperty(this,\"request\",{enumerable:!1,value:o}),Object.defineProperty(this,\"response\",{enumerable:!1,value:o[ub]}),Object.defineProperty(this,\"options\",{enumerable:!1,value:o.options})):Object.defineProperty(this,\"options\",{enumerable:!1,value:o}),this.timings=(a=this.request)===null||a===void 0?void 0:a.timings,st.default.string(r.stack)&&st.default.string(this.stack)){let n=this.stack.indexOf(this.message)+this.message.length,u=this.stack.slice(n).split(`\n`).reverse(),A=r.stack.slice(r.stack.indexOf(r.message)+r.message.length).split(`\n`).reverse();for(;A.length!==0&&A[0]===u[0];)u.shift();this.stack=`${this.stack.slice(0,n)}${u.reverse().join(`\n`)}${A.reverse().join(`\n`)}`}}};Bn.RequestError=Vi;var Ab=class extends Vi{constructor(e){super(`Redirected ${e.options.maxRedirects} times. Aborting.`,{},e),this.name=\"MaxRedirectsError\"}};Bn.MaxRedirectsError=Ab;var fb=class extends Vi{constructor(e){super(`Response code ${e.statusCode} (${e.statusMessage})`,{},e.request),this.name=\"HTTPError\"}};Bn.HTTPError=fb;var pb=class extends Vi{constructor(e,r){super(e.message,e,r),this.name=\"CacheError\"}};Bn.CacheError=pb;var hb=class extends Vi{constructor(e,r){super(e.message,e,r),this.name=\"UploadError\"}};Bn.UploadError=hb;var gb=class extends Vi{constructor(e,r,o){super(e.message,e,o),this.name=\"TimeoutError\",this.event=e.event,this.timings=r}};Bn.TimeoutError=gb;var m1=class extends Vi{constructor(e,r){super(e.message,e,r),this.name=\"ReadError\"}};Bn.ReadError=m1;var db=class extends Vi{constructor(e){super(`Unsupported protocol \"${e.url.protocol}\"`,{},e),this.name=\"UnsupportedProtocolError\"}};Bn.UnsupportedProtocolError=db;var pst=[\"socket\",\"connect\",\"continue\",\"information\",\"upgrade\",\"timeout\"],mb=class extends Uae.Duplex{constructor(e,r={},o){super({autoDestroy:!1,highWaterMark:0}),this[PE]=0,this[bE]=0,this.requestInitialized=!1,this[ab]=new Set,this.redirects=[],this[xE]=!1,this[lb]=!1,this[d1]=[],this.retryCount=0,this._progressCallbacks=[];let a=()=>this._unlockWrite(),n=()=>this._lockWrite();this.on(\"pipe\",h=>{h.prependListener(\"data\",a),h.on(\"data\",n),h.prependListener(\"end\",a),h.on(\"end\",n)}),this.on(\"unpipe\",h=>{h.off(\"data\",a),h.off(\"data\",n),h.off(\"end\",a),h.off(\"end\",n)}),this.on(\"pipe\",h=>{h instanceof B4.IncomingMessage&&(this.options.headers={...h.headers,...this.options.headers})});let{json:u,body:A,form:p}=r;if((u||A||p)&&this._lockWrite(),Bn.kIsNormalizedAlready in r)this.options=r;else try{this.options=this.constructor.normalizeArguments(e,r,o)}catch(h){st.default.nodeStream(r.body)&&r.body.destroy(),this.destroy(h);return}(async()=>{var h;try{this.options.body instanceof Wit.ReadStream&&await ust(this.options.body);let{url:C}=this.options;if(!C)throw new TypeError(\"Missing `url` property\");if(this.requestUrl=C.toString(),decodeURI(this.requestUrl),await this._finalizeBody(),await this._makeRequest(),this.destroyed){(h=this[Zs])===null||h===void 0||h.destroy();return}for(let I of this[d1])I();this[d1].length=0,this.requestInitialized=!0}catch(C){if(C instanceof Vi){this._beforeError(C);return}this.destroyed||this.destroy(C)}})()}static normalizeArguments(e,r,o){var a,n,u,A,p;let h=r;if(st.default.object(e)&&!st.default.urlInstance(e))r={...o,...e,...r};else{if(e&&r&&r.url!==void 0)throw new TypeError(\"The `url` option is mutually exclusive with the `input` argument\");r={...o,...r},e!==void 0&&(r.url=e),st.default.urlInstance(r.url)&&(r.url=new oh.URL(r.url.toString()))}if(r.cache===!1&&(r.cache=void 0),r.dnsCache===!1&&(r.dnsCache=void 0),st.assert.any([st.default.string,st.default.undefined],r.method),st.assert.any([st.default.object,st.default.undefined],r.headers),st.assert.any([st.default.string,st.default.urlInstance,st.default.undefined],r.prefixUrl),st.assert.any([st.default.object,st.default.undefined],r.cookieJar),st.assert.any([st.default.object,st.default.string,st.default.undefined],r.searchParams),st.assert.any([st.default.object,st.default.string,st.default.undefined],r.cache),st.assert.any([st.default.object,st.default.number,st.default.undefined],r.timeout),st.assert.any([st.default.object,st.default.undefined],r.context),st.assert.any([st.default.object,st.default.undefined],r.hooks),st.assert.any([st.default.boolean,st.default.undefined],r.decompress),st.assert.any([st.default.boolean,st.default.undefined],r.ignoreInvalidCookies),st.assert.any([st.default.boolean,st.default.undefined],r.followRedirect),st.assert.any([st.default.number,st.default.undefined],r.maxRedirects),st.assert.any([st.default.boolean,st.default.undefined],r.throwHttpErrors),st.assert.any([st.default.boolean,st.default.undefined],r.http2),st.assert.any([st.default.boolean,st.default.undefined],r.allowGetBody),st.assert.any([st.default.string,st.default.undefined],r.localAddress),st.assert.any([Yae.isDnsLookupIpVersion,st.default.undefined],r.dnsLookupIpVersion),st.assert.any([st.default.object,st.default.undefined],r.https),st.assert.any([st.default.boolean,st.default.undefined],r.rejectUnauthorized),r.https&&(st.assert.any([st.default.boolean,st.default.undefined],r.https.rejectUnauthorized),st.assert.any([st.default.function_,st.default.undefined],r.https.checkServerIdentity),st.assert.any([st.default.string,st.default.object,st.default.array,st.default.undefined],r.https.certificateAuthority),st.assert.any([st.default.string,st.default.object,st.default.array,st.default.undefined],r.https.key),st.assert.any([st.default.string,st.default.object,st.default.array,st.default.undefined],r.https.certificate),st.assert.any([st.default.string,st.default.undefined],r.https.passphrase),st.assert.any([st.default.string,st.default.buffer,st.default.array,st.default.undefined],r.https.pfx)),st.assert.any([st.default.object,st.default.undefined],r.cacheOptions),st.default.string(r.method)?r.method=r.method.toUpperCase():r.method=\"GET\",r.headers===o?.headers?r.headers={...r.headers}:r.headers=Zit({...o?.headers,...r.headers}),\"slashes\"in r)throw new TypeError(\"The legacy `url.Url` has been deprecated. Use `URL` instead.\");if(\"auth\"in r)throw new TypeError(\"Parameter `auth` is deprecated. Use `username` / `password` instead.\");if(\"searchParams\"in r&&r.searchParams&&r.searchParams!==o?.searchParams){let x;if(st.default.string(r.searchParams)||r.searchParams instanceof oh.URLSearchParams)x=new oh.URLSearchParams(r.searchParams);else{lst(r.searchParams),x=new oh.URLSearchParams;for(let E in r.searchParams){let R=r.searchParams[E];R===null?x.append(E,\"\"):R!==void 0&&x.append(E,R)}}(a=o?.searchParams)===null||a===void 0||a.forEach((E,R)=>{x.has(R)||x.append(R,E)}),r.searchParams=x}if(r.username=(n=r.username)!==null&&n!==void 0?n:\"\",r.password=(u=r.password)!==null&&u!==void 0?u:\"\",st.default.undefined(r.prefixUrl)?r.prefixUrl=(A=o?.prefixUrl)!==null&&A!==void 0?A:\"\":(r.prefixUrl=r.prefixUrl.toString(),r.prefixUrl!==\"\"&&!r.prefixUrl.endsWith(\"/\")&&(r.prefixUrl+=\"/\")),st.default.string(r.url)){if(r.url.startsWith(\"/\"))throw new Error(\"`input` must not start with a slash when using `prefixUrl`\");r.url=Gae.default(r.prefixUrl+r.url,r)}else(st.default.undefined(r.url)&&r.prefixUrl!==\"\"||r.protocol)&&(r.url=Gae.default(r.prefixUrl,r));if(r.url){\"port\"in r&&delete r.port;let{prefixUrl:x}=r;Object.defineProperty(r,\"prefixUrl\",{set:R=>{let L=r.url;if(!L.href.startsWith(R))throw new Error(`Cannot change \\`prefixUrl\\` from ${x} to ${R}: ${L.href}`);r.url=new oh.URL(R+L.href.slice(x.length)),x=R},get:()=>x});let{protocol:E}=r.url;if(E===\"unix:\"&&(E=\"http:\",r.url=new oh.URL(`http://unix${r.url.pathname}${r.url.search}`)),r.searchParams&&(r.url.search=r.searchParams.toString()),E!==\"http:\"&&E!==\"https:\")throw new db(r);r.username===\"\"?r.username=r.url.username:r.url.username=r.username,r.password===\"\"?r.password=r.url.password:r.url.password=r.password}let{cookieJar:C}=r;if(C){let{setCookie:x,getCookieString:E}=C;st.assert.function_(x),st.assert.function_(E),x.length===4&&E.length===0&&(x=Mae.promisify(x.bind(r.cookieJar)),E=Mae.promisify(E.bind(r.cookieJar)),r.cookieJar={setCookie:x,getCookieString:E})}let{cache:I}=r;if(I&&(P4.has(I)||P4.set(I,new Hae((x,E)=>{let R=x[Zs](x,E);return st.default.promise(R)&&(R.once=(L,U)=>{if(L===\"error\")R.catch(U);else if(L===\"abort\")(async()=>{try{(await R).once(\"abort\",U)}catch{}})();else throw new Error(`Unknown HTTP2 promise event: ${L}`);return R}),R},I))),r.cacheOptions={...r.cacheOptions},r.dnsCache===!0)v4||(v4=new zit.default),r.dnsCache=v4;else if(!st.default.undefined(r.dnsCache)&&!r.dnsCache.lookup)throw new TypeError(`Parameter \\`dnsCache\\` must be a CacheableLookup instance or a boolean, got ${st.default(r.dnsCache)}`);st.default.number(r.timeout)?r.timeout={request:r.timeout}:o&&r.timeout!==o.timeout?r.timeout={...o.timeout,...r.timeout}:r.timeout={...r.timeout},r.context||(r.context={});let v=r.hooks===o?.hooks;r.hooks={...r.hooks};for(let x of Bn.knownHookEvents)if(x in r.hooks)if(st.default.array(r.hooks[x]))r.hooks[x]=[...r.hooks[x]];else throw new TypeError(`Parameter \\`${x}\\` must be an Array, got ${st.default(r.hooks[x])}`);else r.hooks[x]=[];if(o&&!v)for(let x of Bn.knownHookEvents)o.hooks[x].length>0&&(r.hooks[x]=[...o.hooks[x],...r.hooks[x]]);if(\"family\"in r&&ah.default('\"options.family\" was never documented, please use \"options.dnsLookupIpVersion\"'),o?.https&&(r.https={...o.https,...r.https}),\"rejectUnauthorized\"in r&&ah.default('\"options.rejectUnauthorized\" is now deprecated, please use \"options.https.rejectUnauthorized\"'),\"checkServerIdentity\"in r&&ah.default('\"options.checkServerIdentity\" was never documented, please use \"options.https.checkServerIdentity\"'),\"ca\"in r&&ah.default('\"options.ca\" was never documented, please use \"options.https.certificateAuthority\"'),\"key\"in r&&ah.default('\"options.key\" was never documented, please use \"options.https.key\"'),\"cert\"in r&&ah.default('\"options.cert\" was never documented, please use \"options.https.certificate\"'),\"passphrase\"in r&&ah.default('\"options.passphrase\" was never documented, please use \"options.https.passphrase\"'),\"pfx\"in r&&ah.default('\"options.pfx\" was never documented, please use \"options.https.pfx\"'),\"followRedirects\"in r)throw new TypeError(\"The `followRedirects` option does not exist. Use `followRedirect` instead.\");if(r.agent){for(let x in r.agent)if(x!==\"http\"&&x!==\"https\"&&x!==\"http2\")throw new TypeError(`Expected the \\`options.agent\\` properties to be \\`http\\`, \\`https\\` or \\`http2\\`, got \\`${x}\\``)}return r.maxRedirects=(p=r.maxRedirects)!==null&&p!==void 0?p:0,Bn.setNonEnumerableProperties([o,h],r),sst.default(r,o)}_lockWrite(){let e=()=>{throw new TypeError(\"The payload has been already provided\")};this.write=e,this.end=e}_unlockWrite(){this.write=super.write,this.end=super.end}async _finalizeBody(){let{options:e}=this,{headers:r}=e,o=!st.default.undefined(e.form),a=!st.default.undefined(e.json),n=!st.default.undefined(e.body),u=o||a||n,A=Bn.withoutBody.has(e.method)&&!(e.method===\"GET\"&&e.allowGetBody);if(this._cannotHaveBody=A,u){if(A)throw new TypeError(`The \\`${e.method}\\` method cannot be used with a body`);if([n,o,a].filter(p=>p).length>1)throw new TypeError(\"The `body`, `json` and `form` options are mutually exclusive\");if(n&&!(e.body instanceof Uae.Readable)&&!st.default.string(e.body)&&!st.default.buffer(e.body)&&!jae.default(e.body))throw new TypeError(\"The `body` option must be a stream.Readable, string or Buffer\");if(o&&!st.default.object(e.form))throw new TypeError(\"The `form` option must be an Object\");{let p=!st.default.string(r[\"content-type\"]);n?(jae.default(e.body)&&p&&(r[\"content-type\"]=`multipart/form-data; boundary=${e.body.getBoundary()}`),this[lh]=e.body):o?(p&&(r[\"content-type\"]=\"application/x-www-form-urlencoded\"),this[lh]=new oh.URLSearchParams(e.form).toString()):(p&&(r[\"content-type\"]=\"application/json\"),this[lh]=e.stringifyJson(e.json));let h=await $it.default(this[lh],e.headers);st.default.undefined(r[\"content-length\"])&&st.default.undefined(r[\"transfer-encoding\"])&&!A&&!st.default.undefined(h)&&(r[\"content-length\"]=String(h))}}else A?this._lockWrite():this._unlockWrite();this[SE]=Number(r[\"content-length\"])||void 0}async _onResponseBase(e){let{options:r}=this,{url:o}=r;this[zae]=e,r.decompress&&(e=Jit(e));let a=e.statusCode,n=e;n.statusMessage=n.statusMessage?n.statusMessage:_ae.STATUS_CODES[a],n.url=r.url.toString(),n.requestUrl=this.requestUrl,n.redirectUrls=this.redirects,n.request=this,n.isFromCache=e.fromCache||!1,n.ip=this.ip,n.retryCount=this.retryCount,this[Kae]=n.isFromCache,this[DE]=Number(e.headers[\"content-length\"])||void 0,this[ub]=e,e.once(\"end\",()=>{this[DE]=this[PE],this.emit(\"downloadProgress\",this.downloadProgress)}),e.once(\"error\",A=>{e.destroy(),this._beforeError(new m1(A,this))}),e.once(\"aborted\",()=>{this._beforeError(new m1({name:\"Error\",message:\"The server aborted pending request\",code:\"ECONNRESET\"},this))}),this.emit(\"downloadProgress\",this.downloadProgress);let u=e.headers[\"set-cookie\"];if(st.default.object(r.cookieJar)&&u){let A=u.map(async p=>r.cookieJar.setCookie(p,o.toString()));r.ignoreInvalidCookies&&(A=A.map(async p=>p.catch(()=>{})));try{await Promise.all(A)}catch(p){this._beforeError(p);return}}if(r.followRedirect&&e.headers.location&&Ast.has(a)){if(e.resume(),this[Zs]&&(this[D4](),delete this[Zs],this[Wae]()),(a===303&&r.method!==\"GET\"&&r.method!==\"HEAD\"||!r.methodRewriting)&&(r.method=\"GET\",\"body\"in r&&delete r.body,\"json\"in r&&delete r.json,\"form\"in r&&delete r.form,this[lh]=void 0,delete r.headers[\"content-length\"]),this.redirects.length>=r.maxRedirects){this._beforeError(new Ab(this));return}try{let p=Buffer.from(e.headers.location,\"binary\").toString(),h=new oh.URL(p,o),C=h.toString();decodeURI(C),h.hostname!==o.hostname||h.port!==o.port?(\"host\"in r.headers&&delete r.headers.host,\"cookie\"in r.headers&&delete r.headers.cookie,\"authorization\"in r.headers&&delete r.headers.authorization,(r.username||r.password)&&(r.username=\"\",r.password=\"\")):(h.username=r.username,h.password=r.password),this.redirects.push(C),r.url=h;for(let I of r.hooks.beforeRedirect)await I(r,n);this.emit(\"redirect\",n,r),await this._makeRequest()}catch(p){this._beforeError(p);return}return}if(r.isStream&&r.throwHttpErrors&&!ist.isResponseOk(n)){this._beforeError(new fb(n));return}e.on(\"readable\",()=>{this[lb]&&this._read()}),this.on(\"resume\",()=>{e.resume()}),this.on(\"pause\",()=>{e.pause()}),e.once(\"end\",()=>{this.push(null)}),this.emit(\"response\",e);for(let A of this[ab])if(!A.headersSent){for(let p in e.headers){let h=r.decompress?p!==\"content-encoding\":!0,C=e.headers[p];h&&A.setHeader(p,C)}A.statusCode=a}}async _onResponse(e){try{await this._onResponseBase(e)}catch(r){this._beforeError(r)}}_onRequest(e){let{options:r}=this,{timeout:o,url:a}=r;Vit.default(e),this[D4]=qae.default(e,o,a);let n=r.cache?\"cacheableResponse\":\"response\";e.once(n,p=>{this._onResponse(p)}),e.once(\"error\",p=>{var h;e.destroy(),(h=e.res)===null||h===void 0||h.removeAllListeners(\"end\"),p=p instanceof qae.TimeoutError?new gb(p,this.timings,this):new Vi(p.message,p,this),this._beforeError(p)}),this[Wae]=est.default(e,this,pst),this[Zs]=e,this.emit(\"uploadProgress\",this.uploadProgress);let u=this[lh],A=this.redirects.length===0?this:e;st.default.nodeStream(u)?(u.pipe(A),u.once(\"error\",p=>{this._beforeError(new hb(p,this))})):(this._unlockWrite(),st.default.undefined(u)?(this._cannotHaveBody||this._noPipe)&&(A.end(),this._lockWrite()):(this._writeRequest(u,void 0,()=>{}),A.end(),this._lockWrite())),this.emit(\"request\",e)}async _createCacheableRequest(e,r){return new Promise((o,a)=>{Object.assign(r,tst.default(e)),delete r.url;let n,u=P4.get(r.cache)(r,async A=>{A._readableState.autoDestroy=!1,n&&(await n).emit(\"cacheableResponse\",A),o(A)});r.url=e,u.once(\"error\",a),u.once(\"request\",async A=>{n=A,o(n)})})}async _makeRequest(){var e,r,o,a,n;let{options:u}=this,{headers:A}=u;for(let U in A)if(st.default.undefined(A[U]))delete A[U];else if(st.default.null_(A[U]))throw new TypeError(`Use \\`undefined\\` instead of \\`null\\` to delete the \\`${U}\\` header`);if(u.decompress&&st.default.undefined(A[\"accept-encoding\"])&&(A[\"accept-encoding\"]=ast?\"gzip, deflate, br\":\"gzip, deflate\"),u.cookieJar){let U=await u.cookieJar.getCookieString(u.url.toString());st.default.nonEmptyString(U)&&(u.headers.cookie=U)}for(let U of u.hooks.beforeRequest){let z=await U(u);if(!st.default.undefined(z)){u.request=()=>z;break}}u.body&&this[lh]!==u.body&&(this[lh]=u.body);let{agent:p,request:h,timeout:C,url:I}=u;if(u.dnsCache&&!(\"lookup\"in u)&&(u.lookup=u.dnsCache.lookup),I.hostname===\"unix\"){let U=/(?<socketPath>.+?):(?<path>.+)/.exec(`${I.pathname}${I.search}`);if(U?.groups){let{socketPath:z,path:te}=U.groups;Object.assign(u,{socketPath:z,path:te,host:\"\"})}}let v=I.protocol===\"https:\",x;u.http2?x=Xit.auto:x=v?Kit.request:_ae.request;let E=(e=u.request)!==null&&e!==void 0?e:x,R=u.cache?this._createCacheableRequest:E;p&&!u.http2&&(u.agent=p[v?\"https\":\"http\"]),u[Zs]=E,delete u.request,delete u.timeout;let L=u;if(L.shared=(r=u.cacheOptions)===null||r===void 0?void 0:r.shared,L.cacheHeuristic=(o=u.cacheOptions)===null||o===void 0?void 0:o.cacheHeuristic,L.immutableMinTimeToLive=(a=u.cacheOptions)===null||a===void 0?void 0:a.immutableMinTimeToLive,L.ignoreCargoCult=(n=u.cacheOptions)===null||n===void 0?void 0:n.ignoreCargoCult,u.dnsLookupIpVersion!==void 0)try{L.family=Yae.dnsLookupIpVersionToFamily(u.dnsLookupIpVersion)}catch{throw new Error(\"Invalid `dnsLookupIpVersion` option value\")}u.https&&(\"rejectUnauthorized\"in u.https&&(L.rejectUnauthorized=u.https.rejectUnauthorized),u.https.checkServerIdentity&&(L.checkServerIdentity=u.https.checkServerIdentity),u.https.certificateAuthority&&(L.ca=u.https.certificateAuthority),u.https.certificate&&(L.cert=u.https.certificate),u.https.key&&(L.key=u.https.key),u.https.passphrase&&(L.passphrase=u.https.passphrase),u.https.pfx&&(L.pfx=u.https.pfx));try{let U=await R(I,L);st.default.undefined(U)&&(U=x(I,L)),u.request=h,u.timeout=C,u.agent=p,u.https&&(\"rejectUnauthorized\"in u.https&&delete L.rejectUnauthorized,u.https.checkServerIdentity&&delete L.checkServerIdentity,u.https.certificateAuthority&&delete L.ca,u.https.certificate&&delete L.cert,u.https.key&&delete L.key,u.https.passphrase&&delete L.passphrase,u.https.pfx&&delete L.pfx),cst(U)?this._onRequest(U):this.writable?(this.once(\"finish\",()=>{this._onResponse(U)}),this._unlockWrite(),this.end(),this._lockWrite()):this._onResponse(U)}catch(U){throw U instanceof Hae.CacheError?new pb(U,this):new Vi(U.message,U,this)}}async _error(e){try{for(let r of this.options.hooks.beforeError)e=await r(e)}catch(r){e=new Vi(r.message,r,this)}this.destroy(e)}_beforeError(e){if(this[xE])return;let{options:r}=this,o=this.retryCount+1;this[xE]=!0,e instanceof Vi||(e=new Vi(e.message,e,this));let a=e,{response:n}=a;(async()=>{if(n&&!n.body){n.setEncoding(this._readableState.encoding);try{n.rawBody=await nst.default(n),n.body=n.rawBody.toString()}catch{}}if(this.listenerCount(\"retry\")!==0){let u;try{let A;n&&\"retry-after\"in n.headers&&(A=Number(n.headers[\"retry-after\"]),Number.isNaN(A)?(A=Date.parse(n.headers[\"retry-after\"])-Date.now(),A<=0&&(A=1)):A*=1e3),u=await r.retry.calculateDelay({attemptCount:o,retryOptions:r.retry,error:a,retryAfter:A,computedValue:ost.default({attemptCount:o,retryOptions:r.retry,error:a,retryAfter:A,computedValue:0})})}catch(A){this._error(new Vi(A.message,A,this));return}if(u){let A=async()=>{try{for(let p of this.options.hooks.beforeRetry)await p(this.options,a,o)}catch(p){this._error(new Vi(p.message,e,this));return}this.destroyed||(this.destroy(),this.emit(\"retry\",o,e))};this[Jae]=setTimeout(A,u);return}}this._error(a)})()}_read(){this[lb]=!0;let e=this[ub];if(e&&!this[xE]){e.readableLength&&(this[lb]=!1);let r;for(;(r=e.read())!==null;){this[PE]+=r.length,this[Vae]=!0;let o=this.downloadProgress;o.percent<1&&this.emit(\"downloadProgress\",o),this.push(r)}}}_write(e,r,o){let a=()=>{this._writeRequest(e,r,o)};this.requestInitialized?a():this[d1].push(a)}_writeRequest(e,r,o){this[Zs].destroyed||(this._progressCallbacks.push(()=>{this[bE]+=Buffer.byteLength(e,r);let a=this.uploadProgress;a.percent<1&&this.emit(\"uploadProgress\",a)}),this[Zs].write(e,r,a=>{!a&&this._progressCallbacks.length>0&&this._progressCallbacks.shift()(),o(a)}))}_final(e){let r=()=>{for(;this._progressCallbacks.length!==0;)this._progressCallbacks.shift()();if(!(Zs in this)){e();return}if(this[Zs].destroyed){e();return}this[Zs].end(o=>{o||(this[SE]=this[bE],this.emit(\"uploadProgress\",this.uploadProgress),this[Zs].emit(\"upload-complete\")),e(o)})};this.requestInitialized?r():this[d1].push(r)}_destroy(e,r){var o;this[xE]=!0,clearTimeout(this[Jae]),Zs in this&&(this[D4](),!((o=this[ub])===null||o===void 0)&&o.complete||this[Zs].destroy()),e!==null&&!st.default.undefined(e)&&!(e instanceof Vi)&&(e=new Vi(e.message,e,this)),r(e)}get _isAboutToError(){return this[xE]}get ip(){var e;return(e=this.socket)===null||e===void 0?void 0:e.remoteAddress}get aborted(){var e,r,o;return((r=(e=this[Zs])===null||e===void 0?void 0:e.destroyed)!==null&&r!==void 0?r:this.destroyed)&&!(!((o=this[zae])===null||o===void 0)&&o.complete)}get socket(){var e,r;return(r=(e=this[Zs])===null||e===void 0?void 0:e.socket)!==null&&r!==void 0?r:void 0}get downloadProgress(){let e;return this[DE]?e=this[PE]/this[DE]:this[DE]===this[PE]?e=1:e=0,{percent:e,transferred:this[PE],total:this[DE]}}get uploadProgress(){let e;return this[SE]?e=this[bE]/this[SE]:this[SE]===this[bE]?e=1:e=0,{percent:e,transferred:this[bE],total:this[SE]}}get timings(){var e;return(e=this[Zs])===null||e===void 0?void 0:e.timings}get isFromCache(){return this[Kae]}pipe(e,r){if(this[Vae])throw new Error(\"Failed to pipe. The response has been emitted already.\");return e instanceof B4.ServerResponse&&this[ab].add(e),super.pipe(e,r)}unpipe(e){return e instanceof B4.ServerResponse&&this[ab].delete(e),super.unpipe(e),this}};Bn.default=mb});var E1=_(qc=>{\"use strict\";var hst=qc&&qc.__createBinding||(Object.create?function(t,e,r,o){o===void 0&&(o=r),Object.defineProperty(t,o,{enumerable:!0,get:function(){return e[r]}})}:function(t,e,r,o){o===void 0&&(o=r),t[o]=e[r]}),gst=qc&&qc.__exportStar||function(t,e){for(var r in t)r!==\"default\"&&!Object.prototype.hasOwnProperty.call(e,r)&&hst(e,t,r)};Object.defineProperty(qc,\"__esModule\",{value:!0});qc.CancelError=qc.ParseError=void 0;var Xae=y1(),S4=class extends Xae.RequestError{constructor(e,r){let{options:o}=r.request;super(`${e.message} in \"${o.url.toString()}\"`,e,r.request),this.name=\"ParseError\"}};qc.ParseError=S4;var b4=class extends Xae.RequestError{constructor(e){super(\"Promise was canceled\",{},e),this.name=\"CancelError\"}get isCanceled(){return!0}};qc.CancelError=b4;gst(y1(),qc)});var $ae=_(x4=>{\"use strict\";Object.defineProperty(x4,\"__esModule\",{value:!0});var Zae=E1(),dst=(t,e,r,o)=>{let{rawBody:a}=t;try{if(e===\"text\")return a.toString(o);if(e===\"json\")return a.length===0?\"\":r(a.toString());if(e===\"buffer\")return a;throw new Zae.ParseError({message:`Unknown body type '${e}'`,name:\"Error\"},t)}catch(n){throw new Zae.ParseError(n,t)}};x4.default=dst});var k4=_(ch=>{\"use strict\";var mst=ch&&ch.__createBinding||(Object.create?function(t,e,r,o){o===void 0&&(o=r),Object.defineProperty(t,o,{enumerable:!0,get:function(){return e[r]}})}:function(t,e,r,o){o===void 0&&(o=r),t[o]=e[r]}),yst=ch&&ch.__exportStar||function(t,e){for(var r in t)r!==\"default\"&&!Object.prototype.hasOwnProperty.call(e,r)&&mst(e,t,r)};Object.defineProperty(ch,\"__esModule\",{value:!0});var Est=Be(\"events\"),Cst=Ff(),wst=$se(),yb=E1(),ele=$ae(),tle=y1(),Ist=f4(),Bst=E4(),rle=C4(),vst=[\"request\",\"response\",\"redirect\",\"uploadProgress\",\"downloadProgress\"];function nle(t){let e,r,o=new Est.EventEmitter,a=new wst((u,A,p)=>{let h=C=>{let I=new tle.default(void 0,t);I.retryCount=C,I._noPipe=!0,p(()=>I.destroy()),p.shouldReject=!1,p(()=>A(new yb.CancelError(I))),e=I,I.once(\"response\",async E=>{var R;if(E.retryCount=C,E.request.aborted)return;let L;try{L=await Bst.default(I),E.rawBody=L}catch{return}if(I._isAboutToError)return;let U=((R=E.headers[\"content-encoding\"])!==null&&R!==void 0?R:\"\").toLowerCase(),z=[\"gzip\",\"deflate\",\"br\"].includes(U),{options:te}=I;if(z&&!te.decompress)E.body=L;else try{E.body=ele.default(E,te.responseType,te.parseJson,te.encoding)}catch(le){if(E.body=L.toString(),rle.isResponseOk(E)){I._beforeError(le);return}}try{for(let[le,he]of te.hooks.afterResponse.entries())E=await he(E,async Ae=>{let ye=tle.default.normalizeArguments(void 0,{...Ae,retry:{calculateDelay:()=>0},throwHttpErrors:!1,resolveBodyOnly:!1},te);ye.hooks.afterResponse=ye.hooks.afterResponse.slice(0,le);for(let Ie of ye.hooks.beforeRetry)await Ie(ye);let ae=nle(ye);return p(()=>{ae.catch(()=>{}),ae.cancel()}),ae})}catch(le){I._beforeError(new yb.RequestError(le.message,le,I));return}if(!rle.isResponseOk(E)){I._beforeError(new yb.HTTPError(E));return}r=E,u(I.options.resolveBodyOnly?E.body:E)});let v=E=>{if(a.isCanceled)return;let{options:R}=I;if(E instanceof yb.HTTPError&&!R.throwHttpErrors){let{response:L}=E;u(I.options.resolveBodyOnly?L.body:L);return}A(E)};I.once(\"error\",v);let x=I.options.body;I.once(\"retry\",(E,R)=>{var L,U;if(x===((L=R.request)===null||L===void 0?void 0:L.options.body)&&Cst.default.nodeStream((U=R.request)===null||U===void 0?void 0:U.options.body)){v(R);return}h(E)}),Ist.default(I,o,vst)};h(0)});a.on=(u,A)=>(o.on(u,A),a);let n=u=>{let A=(async()=>{await a;let{options:p}=r.request;return ele.default(r,u,p.parseJson,p.encoding)})();return Object.defineProperties(A,Object.getOwnPropertyDescriptors(a)),A};return a.json=()=>{let{headers:u}=e.options;return!e.writableFinished&&u.accept===void 0&&(u.accept=\"application/json\"),n(\"json\")},a.buffer=()=>n(\"buffer\"),a.text=()=>n(\"text\"),a}ch.default=nle;yst(E1(),ch)});var ile=_(Q4=>{\"use strict\";Object.defineProperty(Q4,\"__esModule\",{value:!0});var Dst=E1();function Pst(t,...e){let r=(async()=>{if(t instanceof Dst.RequestError)try{for(let a of e)if(a)for(let n of a)t=await n(t)}catch(a){t=a}throw t})(),o=()=>r;return r.json=o,r.text=o,r.buffer=o,r.on=o,r}Q4.default=Pst});var ale=_(F4=>{\"use strict\";Object.defineProperty(F4,\"__esModule\",{value:!0});var sle=Ff();function ole(t){for(let e of Object.values(t))(sle.default.plainObject(e)||sle.default.array(e))&&ole(e);return Object.freeze(t)}F4.default=ole});var cle=_(lle=>{\"use strict\";Object.defineProperty(lle,\"__esModule\",{value:!0})});var R4=_(Vl=>{\"use strict\";var Sst=Vl&&Vl.__createBinding||(Object.create?function(t,e,r,o){o===void 0&&(o=r),Object.defineProperty(t,o,{enumerable:!0,get:function(){return e[r]}})}:function(t,e,r,o){o===void 0&&(o=r),t[o]=e[r]}),bst=Vl&&Vl.__exportStar||function(t,e){for(var r in t)r!==\"default\"&&!Object.prototype.hasOwnProperty.call(e,r)&&Sst(e,t,r)};Object.defineProperty(Vl,\"__esModule\",{value:!0});Vl.defaultHandler=void 0;var ule=Ff(),Kl=k4(),xst=ile(),Cb=y1(),kst=ale(),Qst={RequestError:Kl.RequestError,CacheError:Kl.CacheError,ReadError:Kl.ReadError,HTTPError:Kl.HTTPError,MaxRedirectsError:Kl.MaxRedirectsError,TimeoutError:Kl.TimeoutError,ParseError:Kl.ParseError,CancelError:Kl.CancelError,UnsupportedProtocolError:Kl.UnsupportedProtocolError,UploadError:Kl.UploadError},Fst=async t=>new Promise(e=>{setTimeout(e,t)}),{normalizeArguments:Eb}=Cb.default,Ale=(...t)=>{let e;for(let r of t)e=Eb(void 0,r,e);return e},Rst=t=>t.isStream?new Cb.default(void 0,t):Kl.default(t),Tst=t=>\"defaults\"in t&&\"options\"in t.defaults,Nst=[\"get\",\"post\",\"put\",\"patch\",\"head\",\"delete\"];Vl.defaultHandler=(t,e)=>e(t);var fle=(t,e)=>{if(t)for(let r of t)r(e)},ple=t=>{t._rawHandlers=t.handlers,t.handlers=t.handlers.map(o=>(a,n)=>{let u,A=o(a,p=>(u=n(p),u));if(A!==u&&!a.isStream&&u){let p=A,{then:h,catch:C,finally:I}=p;Object.setPrototypeOf(p,Object.getPrototypeOf(u)),Object.defineProperties(p,Object.getOwnPropertyDescriptors(u)),p.then=h,p.catch=C,p.finally=I}return A});let e=(o,a={},n)=>{var u,A;let p=0,h=C=>t.handlers[p++](C,p===t.handlers.length?Rst:h);if(ule.default.plainObject(o)){let C={...o,...a};Cb.setNonEnumerableProperties([o,a],C),a=C,o=void 0}try{let C;try{fle(t.options.hooks.init,a),fle((u=a.hooks)===null||u===void 0?void 0:u.init,a)}catch(v){C=v}let I=Eb(o,a,n??t.options);if(I[Cb.kIsNormalizedAlready]=!0,C)throw new Kl.RequestError(C.message,C,I);return h(I)}catch(C){if(a.isStream)throw C;return xst.default(C,t.options.hooks.beforeError,(A=a.hooks)===null||A===void 0?void 0:A.beforeError)}};e.extend=(...o)=>{let a=[t.options],n=[...t._rawHandlers],u;for(let A of o)Tst(A)?(a.push(A.defaults.options),n.push(...A.defaults._rawHandlers),u=A.defaults.mutableDefaults):(a.push(A),\"handlers\"in A&&n.push(...A.handlers),u=A.mutableDefaults);return n=n.filter(A=>A!==Vl.defaultHandler),n.length===0&&n.push(Vl.defaultHandler),ple({options:Ale(...a),handlers:n,mutableDefaults:Boolean(u)})};let r=async function*(o,a){let n=Eb(o,a,t.options);n.resolveBodyOnly=!1;let u=n.pagination;if(!ule.default.object(u))throw new TypeError(\"`options.pagination` must be implemented\");let A=[],{countLimit:p}=u,h=0;for(;h<u.requestLimit;){h!==0&&await Fst(u.backoff);let C=await e(void 0,void 0,n),I=await u.transform(C),v=[];for(let E of I)if(u.filter(E,A,v)&&(!u.shouldContinue(E,A,v)||(yield E,u.stackAllItems&&A.push(E),v.push(E),--p<=0)))return;let x=u.paginate(C,A,v);if(x===!1)return;x===C.request.options?n=C.request.options:x!==void 0&&(n=Eb(void 0,x,n)),h++}};e.paginate=r,e.paginate.all=async(o,a)=>{let n=[];for await(let u of r(o,a))n.push(u);return n},e.paginate.each=r,e.stream=(o,a)=>e(o,{...a,isStream:!0});for(let o of Nst)e[o]=(a,n)=>e(a,{...n,method:o}),e.stream[o]=(a,n)=>e(a,{...n,method:o,isStream:!0});return Object.assign(e,Qst),Object.defineProperty(e,\"defaults\",{value:t.mutableDefaults?t:kst.default(t),writable:t.mutableDefaults,configurable:t.mutableDefaults,enumerable:!0}),e.mergeOptions=Ale,e};Vl.default=ple;bst(cle(),Vl)});var dle=_((Rf,wb)=>{\"use strict\";var Lst=Rf&&Rf.__createBinding||(Object.create?function(t,e,r,o){o===void 0&&(o=r),Object.defineProperty(t,o,{enumerable:!0,get:function(){return e[r]}})}:function(t,e,r,o){o===void 0&&(o=r),t[o]=e[r]}),hle=Rf&&Rf.__exportStar||function(t,e){for(var r in t)r!==\"default\"&&!Object.prototype.hasOwnProperty.call(e,r)&&Lst(e,t,r)};Object.defineProperty(Rf,\"__esModule\",{value:!0});var Ost=Be(\"url\"),gle=R4(),Mst={options:{method:\"GET\",retry:{limit:2,methods:[\"GET\",\"PUT\",\"HEAD\",\"DELETE\",\"OPTIONS\",\"TRACE\"],statusCodes:[408,413,429,500,502,503,504,521,522,524],errorCodes:[\"ETIMEDOUT\",\"ECONNRESET\",\"EADDRINUSE\",\"ECONNREFUSED\",\"EPIPE\",\"ENOTFOUND\",\"ENETUNREACH\",\"EAI_AGAIN\"],maxRetryAfter:void 0,calculateDelay:({computedValue:t})=>t},timeout:{},headers:{\"user-agent\":\"got (https://github.com/sindresorhus/got)\"},hooks:{init:[],beforeRequest:[],beforeRedirect:[],beforeRetry:[],beforeError:[],afterResponse:[]},cache:void 0,dnsCache:void 0,decompress:!0,throwHttpErrors:!0,followRedirect:!0,isStream:!1,responseType:\"text\",resolveBodyOnly:!1,maxRedirects:10,prefixUrl:\"\",methodRewriting:!0,ignoreInvalidCookies:!1,context:{},http2:!1,allowGetBody:!1,https:void 0,pagination:{transform:t=>t.request.options.responseType===\"json\"?t.body:JSON.parse(t.body),paginate:t=>{if(!Reflect.has(t.headers,\"link\"))return!1;let e=t.headers.link.split(\",\"),r;for(let o of e){let a=o.split(\";\");if(a[1].includes(\"next\")){r=a[0].trimStart().trim(),r=r.slice(1,-1);break}}return r?{url:new Ost.URL(r)}:!1},filter:()=>!0,shouldContinue:()=>!0,countLimit:1/0,backoff:0,requestLimit:1e4,stackAllItems:!0},parseJson:t=>JSON.parse(t),stringifyJson:t=>JSON.stringify(t),cacheOptions:{}},handlers:[gle.defaultHandler],mutableDefaults:!1},T4=gle.default(Mst);Rf.default=T4;wb.exports=T4;wb.exports.default=T4;wb.exports.__esModule=!0;hle(R4(),Rf);hle(k4(),Rf)});var rn={};Vt(rn,{Method:()=>Ble,del:()=>qst,get:()=>M4,getNetworkSettings:()=>Ile,post:()=>U4,put:()=>jst,request:()=>C1});function Ele(t){let e=new Ib.URL(t),r={host:e.hostname,headers:{}};return e.port&&(r.port=Number(e.port)),e.username&&e.password&&(r.proxyAuth=`${e.username}:${e.password}`),{proxy:r}}async function N4(t){return ol(yle,t,()=>oe.readFilePromise(t).then(e=>(yle.set(t,e),e)))}function Hst({statusCode:t,statusMessage:e},r){let o=Mt(r,t,yt.NUMBER),a=`https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/${t}`;return Jy(r,`${o}${e?` (${e})`:\"\"}`,a)}async function Bb(t,{configuration:e,customErrorMessage:r}){try{return await t}catch(o){if(o.name!==\"HTTPError\")throw o;let a=r?.(o,e)??o.response.body?.error;a==null&&(o.message.startsWith(\"Response code\")?a=\"The remote server failed to provide the requested resource\":a=o.message),o.code===\"ETIMEDOUT\"&&o.event===\"socket\"&&(a+=`(can be increased via ${Mt(e,\"httpTimeout\",yt.SETTING)})`);let n=new Jt(35,a,u=>{o.response&&u.reportError(35,`  ${Ju(e,{label:\"Response Code\",value:_c(yt.NO_HINT,Hst(o.response,e))})}`),o.request&&(u.reportError(35,`  ${Ju(e,{label:\"Request Method\",value:_c(yt.NO_HINT,o.request.options.method)})}`),u.reportError(35,`  ${Ju(e,{label:\"Request URL\",value:_c(yt.URL,o.request.requestUrl)})}`)),o.request.redirects.length>0&&u.reportError(35,`  ${Ju(e,{label:\"Request Redirects\",value:_c(yt.NO_HINT,xL(e,o.request.redirects,yt.URL))})}`),o.request.retryCount===o.request.options.retry.limit&&u.reportError(35,`  ${Ju(e,{label:\"Request Retry Count\",value:_c(yt.NO_HINT,`${Mt(e,o.request.retryCount,yt.NUMBER)} (can be increased via ${Mt(e,\"httpRetry\",yt.SETTING)})`)})}`)});throw n.originalError=o,n}}function Ile(t,e){let r=[...e.configuration.get(\"networkSettings\")].sort(([u],[A])=>A.length-u.length),o={enableNetwork:void 0,httpsCaFilePath:void 0,httpProxy:void 0,httpsProxy:void 0,httpsKeyFilePath:void 0,httpsCertFilePath:void 0},a=Object.keys(o),n=typeof t==\"string\"?new Ib.URL(t):t;for(let[u,A]of r)if(O4.default.isMatch(n.hostname,u))for(let p of a){let h=A.get(p);h!==null&&typeof o[p]>\"u\"&&(o[p]=h)}for(let u of a)typeof o[u]>\"u\"&&(o[u]=e.configuration.get(u));return o}async function C1(t,e,{configuration:r,headers:o,jsonRequest:a,jsonResponse:n,method:u=\"GET\",wrapNetworkRequest:A}){let p={target:t,body:e,configuration:r,headers:o,jsonRequest:a,jsonResponse:n,method:u},h=async()=>await Gst(t,e,p),C=typeof A<\"u\"?await A(h,p):h;return await(await r.reduceHook(v=>v.wrapNetworkRequest,C,p))()}async function M4(t,{configuration:e,jsonResponse:r,customErrorMessage:o,wrapNetworkRequest:a,...n}){let u=()=>Bb(C1(t,null,{configuration:e,wrapNetworkRequest:a,...n}),{configuration:e,customErrorMessage:o}).then(p=>p.body),A=await(typeof a<\"u\"?u():ol(mle,t,()=>u().then(p=>(mle.set(t,p),p))));return r?JSON.parse(A.toString()):A}async function jst(t,e,{customErrorMessage:r,...o}){return(await Bb(C1(t,e,{...o,method:\"PUT\"}),{customErrorMessage:r,configuration:o.configuration})).body}async function U4(t,e,{customErrorMessage:r,...o}){return(await Bb(C1(t,e,{...o,method:\"POST\"}),{customErrorMessage:r,configuration:o.configuration})).body}async function qst(t,{customErrorMessage:e,...r}){return(await Bb(C1(t,null,{...r,method:\"DELETE\"}),{customErrorMessage:e,configuration:r.configuration})).body}async function Gst(t,e,{configuration:r,headers:o,jsonRequest:a,jsonResponse:n,method:u=\"GET\"}){let A=typeof t==\"string\"?new Ib.URL(t):t,p=Ile(A,{configuration:r});if(p.enableNetwork===!1)throw new Jt(80,`Request to '${A.href}' has been blocked because of your configuration settings`);if(A.protocol===\"http:\"&&!O4.default.isMatch(A.hostname,r.get(\"unsafeHttpWhitelist\")))throw new Jt(81,`Unsafe http requests must be explicitly whitelisted in your configuration (${A.hostname})`);let C={agent:{http:p.httpProxy?L4.default.httpOverHttp(Ele(p.httpProxy)):Ust,https:p.httpsProxy?L4.default.httpsOverHttp(Ele(p.httpsProxy)):_st},headers:o,method:u};C.responseType=n?\"json\":\"buffer\",e!==null&&(Buffer.isBuffer(e)||!a&&typeof e==\"string\"?C.body=e:C.json=e);let I=r.get(\"httpTimeout\"),v=r.get(\"httpRetry\"),x=r.get(\"enableStrictSsl\"),E=p.httpsCaFilePath,R=p.httpsCertFilePath,L=p.httpsKeyFilePath,{default:U}=await Promise.resolve().then(()=>$e(dle())),z=E?await N4(E):void 0,te=R?await N4(R):void 0,le=L?await N4(L):void 0,he=U.extend({timeout:{socket:I},retry:v,https:{rejectUnauthorized:x,certificateAuthority:z,certificate:te,key:le},...C});return r.getLimit(\"networkConcurrency\")(()=>he(A))}var Cle,wle,O4,L4,Ib,mle,yle,Ust,_st,Ble,vb=Et(()=>{Pt();Cle=Be(\"https\"),wle=Be(\"http\"),O4=$e(Zo()),L4=$e(Vse()),Ib=Be(\"url\");Yl();ql();jl();mle=new Map,yle=new Map,Ust=new wle.Agent({keepAlive:!0}),_st=new Cle.Agent({keepAlive:!0});Ble=(a=>(a.GET=\"GET\",a.PUT=\"PUT\",a.POST=\"POST\",a.DELETE=\"DELETE\",a))(Ble||{})});var zi={};Vt(zi,{availableParallelism:()=>H4,getArchitecture:()=>w1,getArchitectureName:()=>Vst,getArchitectureSet:()=>_4,getCaller:()=>Zst,major:()=>Yst,openUrl:()=>Wst});function Kst(){if(process.platform===\"darwin\"||process.platform===\"win32\")return null;let e=(process.report?.getReport()??{}).sharedObjects??[],r=/\\/(?:(ld-linux-|[^/]+-linux-gnu\\/)|(libc.musl-|ld-musl-))/;return YI(e,o=>{let a=o.match(r);if(!a)return YI.skip;if(a[1])return\"glibc\";if(a[2])return\"musl\";throw new Error(\"Assertion failed: Expected the libc variant to have been detected\")})??null}function w1(){return Dle=Dle??{os:process.platform,cpu:process.arch,libc:Kst()}}function Vst(t=w1()){return t.libc?`${t.os}-${t.cpu}-${t.libc}`:`${t.os}-${t.cpu}`}function _4(){let t=w1();return Ple=Ple??{os:[t.os],cpu:[t.cpu],libc:t.libc?[t.libc]:[]}}function Xst(t){let e=zst.exec(t);if(!e)return null;let r=e[2]&&e[2].indexOf(\"native\")===0,o=e[2]&&e[2].indexOf(\"eval\")===0,a=Jst.exec(e[2]);return o&&a!=null&&(e[2]=a[1],e[3]=a[2],e[4]=a[3]),{file:r?null:e[2],methodName:e[1]||\"<unknown>\",arguments:r?[e[2]]:[],line:e[3]?+e[3]:null,column:e[4]?+e[4]:null}}function Zst(){let e=new Error().stack.split(`\n`)[3];return Xst(e)}function H4(){return typeof Db.default.availableParallelism<\"u\"?Db.default.availableParallelism():Math.max(1,Db.default.cpus().length)}var Db,Yst,vle,Wst,Dle,Ple,zst,Jst,Pb=Et(()=>{Pt();Db=$e(Be(\"os\"));Sb();jl();Yst=Number(process.versions.node.split(\".\")[0]),vle=new Map([[\"darwin\",\"open\"],[\"linux\",\"xdg-open\"],[\"win32\",\"explorer.exe\"]]).get(process.platform),Wst=typeof vle<\"u\"?async t=>{try{return await j4(vle,[t],{cwd:V.cwd()}),!0}catch{return!1}}:void 0;zst=/^\\s*at (.*?) ?\\(((?:file|https?|blob|chrome-extension|native|eval|webpack|<anonymous>|\\/|[a-z]:\\\\|\\\\\\\\).*?)(?::(\\d+))?(?::(\\d+))?\\)?\\s*$/i,Jst=/\\((\\S*)(?::(\\d+))(?::(\\d+))\\)/});function K4(t,e,r,o,a){let n=c1(r);if(o.isArray||o.type===\"ANY\"&&Array.isArray(n))return Array.isArray(n)?n.map((u,A)=>q4(t,`${e}[${A}]`,u,o,a)):String(n).split(/,/).map(u=>q4(t,e,u,o,a));if(Array.isArray(n))throw new Error(`Non-array configuration settings \"${e}\" cannot be an array`);return q4(t,e,r,o,a)}function q4(t,e,r,o,a){let n=c1(r);switch(o.type){case\"ANY\":return YS(n);case\"SHAPE\":return rot(t,e,r,o,a);case\"MAP\":return not(t,e,r,o,a)}if(n===null&&!o.isNullable&&o.default!==null)throw new Error(`Non-nullable configuration settings \"${e}\" cannot be set to null`);if(o.values?.includes(n))return n;let A=(()=>{if(o.type===\"BOOLEAN\"&&typeof n!=\"string\")return WI(n);if(typeof n!=\"string\")throw new Error(`Expected configuration setting \"${e}\" to be a string, got ${typeof n}`);let p=sS(n,{env:t.env});switch(o.type){case\"ABSOLUTE_PATH\":{let h=a,C=EM(r);return C&&C[0]!==\"<\"&&(h=V.dirname(C)),V.resolve(h,ue.toPortablePath(p))}case\"LOCATOR_LOOSE\":return Sf(p,!1);case\"NUMBER\":return parseInt(p);case\"LOCATOR\":return Sf(p);case\"BOOLEAN\":return WI(p);default:return p}})();if(o.values&&!o.values.includes(A))throw new Error(`Invalid value, expected one of ${o.values.join(\", \")}`);return A}function rot(t,e,r,o,a){let n=c1(r);if(typeof n!=\"object\"||Array.isArray(n))throw new it(`Object configuration settings \"${e}\" must be an object`);let u=V4(t,o,{ignoreArrays:!0});if(n===null)return u;for(let[A,p]of Object.entries(n)){let h=`${e}.${A}`;if(!o.properties[A])throw new it(`Unrecognized configuration settings found: ${e}.${A} - run \"yarn config -v\" to see the list of settings supported in Yarn`);u.set(A,K4(t,h,p,o.properties[A],a))}return u}function not(t,e,r,o,a){let n=c1(r),u=new Map;if(typeof n!=\"object\"||Array.isArray(n))throw new it(`Map configuration settings \"${e}\" must be an object`);if(n===null)return u;for(let[A,p]of Object.entries(n)){let h=o.normalizeKeys?o.normalizeKeys(A):A,C=`${e}['${h}']`,I=o.valueDefinition;u.set(h,K4(t,C,p,I,a))}return u}function V4(t,e,{ignoreArrays:r=!1}={}){switch(e.type){case\"SHAPE\":{if(e.isArray&&!r)return[];let o=new Map;for(let[a,n]of Object.entries(e.properties))o.set(a,V4(t,n));return o}break;case\"MAP\":return e.isArray&&!r?[]:new Map;case\"ABSOLUTE_PATH\":return e.default===null?null:t.projectCwd===null?Array.isArray(e.default)?e.default.map(o=>V.normalize(o)):V.isAbsolute(e.default)?V.normalize(e.default):e.isNullable?null:void 0:Array.isArray(e.default)?e.default.map(o=>V.resolve(t.projectCwd,o)):V.resolve(t.projectCwd,e.default);default:return e.default}}function xb(t,e,r){if(e.type===\"SECRET\"&&typeof t==\"string\"&&r.hideSecrets)return tot;if(e.type===\"ABSOLUTE_PATH\"&&typeof t==\"string\"&&r.getNativePaths)return ue.fromPortablePath(t);if(e.isArray&&Array.isArray(t)){let o=[];for(let a of t)o.push(xb(a,e,r));return o}if(e.type===\"MAP\"&&t instanceof Map){if(t.size===0)return;let o=new Map;for(let[a,n]of t.entries()){let u=xb(n,e.valueDefinition,r);typeof u<\"u\"&&o.set(a,u)}return o}if(e.type===\"SHAPE\"&&t instanceof Map){if(t.size===0)return;let o=new Map;for(let[a,n]of t.entries()){let u=e.properties[a],A=xb(n,u,r);typeof A<\"u\"&&o.set(a,A)}return o}return t}function iot(){let t={};for(let[e,r]of Object.entries(process.env))e=e.toLowerCase(),e.startsWith(kb)&&(e=(0,ble.default)(e.slice(kb.length)),t[e]=r);return t}function Y4(){let t=`${kb}rc_filename`;for(let[e,r]of Object.entries(process.env))if(e.toLowerCase()===t&&typeof r==\"string\")return r;return W4}async function Sle(t){try{return await oe.readFilePromise(t)}catch{return Buffer.of()}}async function sot(t,e){return Buffer.compare(...await Promise.all([Sle(t),Sle(e)]))===0}async function oot(t,e){let[r,o]=await Promise.all([oe.statPromise(t),oe.statPromise(e)]);return r.dev===o.dev&&r.ino===o.ino}async function lot({configuration:t,selfPath:e}){let r=t.get(\"yarnPath\");return t.get(\"ignorePath\")||r===null||r===e||await aot(r,e)?null:r}var ble,Tf,xle,kle,Qle,G4,$st,I1,eot,kE,kb,W4,tot,B1,Fle,Qb,bb,aot,rA,Ke,v1=Et(()=>{Pt();Nl();ble=$e(lV()),Tf=$e($g());qt();xle=$e(tz()),kle=Be(\"module\"),Qle=$e(rd()),G4=Be(\"stream\");cse();uE();AM();fM();pM();Ose();hM();Id();jse();KS();ql();rh();vb();jl();Pb();xf();bo();$st=function(){if(Tf.GITHUB_ACTIONS&&process.env.GITHUB_EVENT_PATH){let t=ue.toPortablePath(process.env.GITHUB_EVENT_PATH);try{return!(oe.readJsonSync(t).repository?.private??!0)}catch{return!1}}return!1}(),I1=new Set([\"@yarnpkg/plugin-constraints\",\"@yarnpkg/plugin-exec\",\"@yarnpkg/plugin-interactive-tools\",\"@yarnpkg/plugin-stage\",\"@yarnpkg/plugin-typescript\",\"@yarnpkg/plugin-version\",\"@yarnpkg/plugin-workspace-tools\"]),eot=new Set([\"isTestEnv\",\"injectNpmUser\",\"injectNpmPassword\",\"injectNpm2FaToken\",\"cacheCheckpointOverride\",\"cacheVersionOverride\",\"lockfileVersionOverride\",\"binFolder\",\"version\",\"flags\",\"profile\",\"gpg\",\"ignoreNode\",\"wrapOutput\",\"home\",\"confDir\",\"registry\",\"ignoreCwd\"]),kE=/^(?!v)[a-z0-9._-]+$/i,kb=\"yarn_\",W4=\".yarnrc.yml\",tot=\"********\",B1=(C=>(C.ANY=\"ANY\",C.BOOLEAN=\"BOOLEAN\",C.ABSOLUTE_PATH=\"ABSOLUTE_PATH\",C.LOCATOR=\"LOCATOR\",C.LOCATOR_LOOSE=\"LOCATOR_LOOSE\",C.NUMBER=\"NUMBER\",C.STRING=\"STRING\",C.SECRET=\"SECRET\",C.SHAPE=\"SHAPE\",C.MAP=\"MAP\",C))(B1||{}),Fle=yt,Qb=(r=>(r.JUNCTIONS=\"junctions\",r.SYMLINKS=\"symlinks\",r))(Qb||{}),bb={lastUpdateCheck:{description:\"Last timestamp we checked whether new Yarn versions were available\",type:\"STRING\",default:null},yarnPath:{description:\"Path to the local executable that must be used over the global one\",type:\"ABSOLUTE_PATH\",default:null},ignorePath:{description:\"If true, the local executable will be ignored when using the global one\",type:\"BOOLEAN\",default:!1},globalFolder:{description:\"Folder where all system-global files are stored\",type:\"ABSOLUTE_PATH\",default:wM()},cacheFolder:{description:\"Folder where the cache files must be written\",type:\"ABSOLUTE_PATH\",default:\"./.yarn/cache\"},compressionLevel:{description:\"Zip files compression level, from 0 to 9 or mixed (a variant of 9, which stores some files uncompressed, when compression doesn't yield good results)\",type:\"NUMBER\",values:[\"mixed\",0,1,2,3,4,5,6,7,8,9],default:0},virtualFolder:{description:\"Folder where the virtual packages (cf doc) will be mapped on the disk (must be named __virtual__)\",type:\"ABSOLUTE_PATH\",default:\"./.yarn/__virtual__\"},installStatePath:{description:\"Path of the file where the install state will be persisted\",type:\"ABSOLUTE_PATH\",default:\"./.yarn/install-state.gz\"},immutablePatterns:{description:\"Array of glob patterns; files matching them won't be allowed to change during immutable installs\",type:\"STRING\",default:[],isArray:!0},rcFilename:{description:\"Name of the files where the configuration can be found\",type:\"STRING\",default:Y4()},enableGlobalCache:{description:\"If true, the system-wide cache folder will be used regardless of `cache-folder`\",type:\"BOOLEAN\",default:!0},cacheMigrationMode:{description:\"Defines the conditions under which Yarn upgrades should cause the cache archives to be regenerated.\",type:\"STRING\",values:[\"always\",\"match-spec\",\"required-only\"],default:\"always\"},enableColors:{description:\"If true, the CLI is allowed to use colors in its output\",type:\"BOOLEAN\",default:lS,defaultText:\"<dynamic>\"},enableHyperlinks:{description:\"If true, the CLI is allowed to use hyperlinks in its output\",type:\"BOOLEAN\",default:bL,defaultText:\"<dynamic>\"},enableInlineBuilds:{description:\"If true, the CLI will print the build output on the command line\",type:\"BOOLEAN\",default:Tf.isCI,defaultText:\"<dynamic>\"},enableMessageNames:{description:\"If true, the CLI will prefix most messages with codes suitable for search engines\",type:\"BOOLEAN\",default:!0},enableProgressBars:{description:\"If true, the CLI is allowed to show a progress bar for long-running events\",type:\"BOOLEAN\",default:!Tf.isCI,defaultText:\"<dynamic>\"},enableTimers:{description:\"If true, the CLI is allowed to print the time spent executing commands\",type:\"BOOLEAN\",default:!0},enableTips:{description:\"If true, installs will print a helpful message every day of the week\",type:\"BOOLEAN\",default:!Tf.isCI,defaultText:\"<dynamic>\"},preferInteractive:{description:\"If true, the CLI will automatically use the interactive mode when called from a TTY\",type:\"BOOLEAN\",default:!1},preferTruncatedLines:{description:\"If true, the CLI will truncate lines that would go beyond the size of the terminal\",type:\"BOOLEAN\",default:!1},progressBarStyle:{description:\"Which style of progress bar should be used (only when progress bars are enabled)\",type:\"STRING\",default:void 0,defaultText:\"<dynamic>\"},defaultLanguageName:{description:\"Default language mode that should be used when a package doesn't offer any insight\",type:\"STRING\",default:\"node\"},defaultProtocol:{description:\"Default resolution protocol used when resolving pure semver and tag ranges\",type:\"STRING\",default:\"npm:\"},enableTransparentWorkspaces:{description:\"If false, Yarn won't automatically resolve workspace dependencies unless they use the `workspace:` protocol\",type:\"BOOLEAN\",default:!0},supportedArchitectures:{description:\"Architectures that Yarn will fetch and inject into the resolver\",type:\"SHAPE\",properties:{os:{description:\"Array of supported process.platform strings, or null to target them all\",type:\"STRING\",isArray:!0,isNullable:!0,default:[\"current\"]},cpu:{description:\"Array of supported process.arch strings, or null to target them all\",type:\"STRING\",isArray:!0,isNullable:!0,default:[\"current\"]},libc:{description:\"Array of supported libc libraries, or null to target them all\",type:\"STRING\",isArray:!0,isNullable:!0,default:[\"current\"]}}},enableMirror:{description:\"If true, the downloaded packages will be retrieved and stored in both the local and global folders\",type:\"BOOLEAN\",default:!0},enableNetwork:{description:\"If false, Yarn will refuse to use the network if required to\",type:\"BOOLEAN\",default:!0},enableOfflineMode:{description:\"If true, Yarn will attempt to retrieve files and metadata from the global cache rather than the network\",type:\"BOOLEAN\",default:!1},httpProxy:{description:\"URL of the http proxy that must be used for outgoing http requests\",type:\"STRING\",default:null},httpsProxy:{description:\"URL of the http proxy that must be used for outgoing https requests\",type:\"STRING\",default:null},unsafeHttpWhitelist:{description:\"List of the hostnames for which http queries are allowed (glob patterns are supported)\",type:\"STRING\",default:[],isArray:!0},httpTimeout:{description:\"Timeout of each http request in milliseconds\",type:\"NUMBER\",default:6e4},httpRetry:{description:\"Retry times on http failure\",type:\"NUMBER\",default:3},networkConcurrency:{description:\"Maximal number of concurrent requests\",type:\"NUMBER\",default:50},taskPoolConcurrency:{description:\"Maximal amount of concurrent heavy task processing\",type:\"NUMBER\",default:H4()},taskPoolMode:{description:\"Execution strategy for heavy tasks\",type:\"STRING\",values:[\"async\",\"workers\"],default:\"workers\"},networkSettings:{description:\"Network settings per hostname (glob patterns are supported)\",type:\"MAP\",valueDefinition:{description:\"\",type:\"SHAPE\",properties:{httpsCaFilePath:{description:\"Path to file containing one or multiple Certificate Authority signing certificates\",type:\"ABSOLUTE_PATH\",default:null},enableNetwork:{description:\"If false, the package manager will refuse to use the network if required to\",type:\"BOOLEAN\",default:null},httpProxy:{description:\"URL of the http proxy that must be used for outgoing http requests\",type:\"STRING\",default:null},httpsProxy:{description:\"URL of the http proxy that must be used for outgoing https requests\",type:\"STRING\",default:null},httpsKeyFilePath:{description:\"Path to file containing private key in PEM format\",type:\"ABSOLUTE_PATH\",default:null},httpsCertFilePath:{description:\"Path to file containing certificate chain in PEM format\",type:\"ABSOLUTE_PATH\",default:null}}}},httpsCaFilePath:{description:\"A path to a file containing one or multiple Certificate Authority signing certificates\",type:\"ABSOLUTE_PATH\",default:null},httpsKeyFilePath:{description:\"Path to file containing private key in PEM format\",type:\"ABSOLUTE_PATH\",default:null},httpsCertFilePath:{description:\"Path to file containing certificate chain in PEM format\",type:\"ABSOLUTE_PATH\",default:null},enableStrictSsl:{description:\"If false, SSL certificate errors will be ignored\",type:\"BOOLEAN\",default:!0},logFilters:{description:\"Overrides for log levels\",type:\"SHAPE\",isArray:!0,concatenateValues:!0,properties:{code:{description:\"Code of the messages covered by this override\",type:\"STRING\",default:void 0},text:{description:\"Code of the texts covered by this override\",type:\"STRING\",default:void 0},pattern:{description:\"Code of the patterns covered by this override\",type:\"STRING\",default:void 0},level:{description:\"Log level override, set to null to remove override\",type:\"STRING\",values:Object.values(uS),isNullable:!0,default:void 0}}},enableTelemetry:{description:\"If true, telemetry will be periodically sent, following the rules in https://yarnpkg.com/advanced/telemetry\",type:\"BOOLEAN\",default:!0},telemetryInterval:{description:\"Minimal amount of time between two telemetry uploads, in days\",type:\"NUMBER\",default:7},telemetryUserId:{description:\"If you desire to tell us which project you are, you can set this field. Completely optional and opt-in.\",type:\"STRING\",default:null},enableHardenedMode:{description:\"If true, automatically enable --check-resolutions --refresh-lockfile on installs\",type:\"BOOLEAN\",default:Tf.isPR&&$st,defaultText:\"<true on public PRs>\"},enableScripts:{description:\"If true, packages are allowed to have install scripts by default\",type:\"BOOLEAN\",default:!0},enableStrictSettings:{description:\"If true, unknown settings will cause Yarn to abort\",type:\"BOOLEAN\",default:!0},enableImmutableCache:{description:\"If true, the cache is reputed immutable and actions that would modify it will throw\",type:\"BOOLEAN\",default:!1},checksumBehavior:{description:\"Enumeration defining what to do when a checksum doesn't match expectations\",type:\"STRING\",default:\"throw\"},injectEnvironmentFiles:{description:\"List of all the environment files that Yarn should inject inside the process when it starts\",type:\"ABSOLUTE_PATH\",default:[\".env.yarn?\"],isArray:!0},packageExtensions:{description:\"Map of package corrections to apply on the dependency tree\",type:\"MAP\",valueDefinition:{description:\"The extension that will be applied to any package whose version matches the specified range\",type:\"SHAPE\",properties:{dependencies:{description:\"The set of dependencies that must be made available to the current package in order for it to work properly\",type:\"MAP\",valueDefinition:{description:\"A range\",type:\"STRING\"}},peerDependencies:{description:\"Inherited dependencies - the consumer of the package will be tasked to provide them\",type:\"MAP\",valueDefinition:{description:\"A semver range\",type:\"STRING\"}},peerDependenciesMeta:{description:\"Extra information related to the dependencies listed in the peerDependencies field\",type:\"MAP\",valueDefinition:{description:\"The peerDependency meta\",type:\"SHAPE\",properties:{optional:{description:\"If true, the selected peer dependency will be marked as optional by the package manager and the consumer omitting it won't be reported as an error\",type:\"BOOLEAN\",default:!1}}}}}}}};aot=process.platform===\"win32\"?sot:oot;rA=class{constructor(e){this.isCI=Tf.isCI;this.projectCwd=null;this.plugins=new Map;this.settings=new Map;this.values=new Map;this.sources=new Map;this.invalid=new Map;this.env={};this.limits=new Map;this.packageExtensions=null;this.startingCwd=e}static create(e,r,o){let a=new rA(e);typeof r<\"u\"&&!(r instanceof Map)&&(a.projectCwd=r),a.importSettings(bb);let n=typeof o<\"u\"?o:r instanceof Map?r:new Map;for(let[u,A]of n)a.activatePlugin(u,A);return a}static async find(e,r,{strict:o=!0,usePathCheck:a=null,useRc:n=!0}={}){let u=iot();delete u.rcFilename;let A=new rA(e),p=await rA.findRcFiles(e),h=await rA.findFolderRcFile(mE());h&&(p.find(ye=>ye.path===h.path)||p.unshift(h));let C=Hse(p.map(Ae=>[Ae.path,Ae.data])),I=Bt.dot,v=new Set(Object.keys(bb)),x=({yarnPath:Ae,ignorePath:ye,injectEnvironmentFiles:ae})=>({yarnPath:Ae,ignorePath:ye,injectEnvironmentFiles:ae}),E=({yarnPath:Ae,ignorePath:ye,injectEnvironmentFiles:ae,...Ie})=>{let Fe={};for(let[g,Ee]of Object.entries(Ie))v.has(g)&&(Fe[g]=Ee);return Fe},R=({yarnPath:Ae,ignorePath:ye,...ae})=>{let Ie={};for(let[Fe,g]of Object.entries(ae))v.has(Fe)||(Ie[Fe]=g);return Ie};if(A.importSettings(x(bb)),A.useWithSource(\"<environment>\",x(u),e,{strict:!1}),C){let[Ae,ye]=C;A.useWithSource(Ae,x(ye),I,{strict:!1})}if(a){if(await lot({configuration:A,selfPath:a})!==null)return A;A.useWithSource(\"<override>\",{ignorePath:!0},e,{strict:!1,overwrite:!0})}let L=await rA.findProjectCwd(e);A.startingCwd=e,A.projectCwd=L;let U=Object.assign(Object.create(null),process.env);A.env=U;let z=await Promise.all(A.get(\"injectEnvironmentFiles\").map(async Ae=>{let ye=Ae.endsWith(\"?\")?await oe.readFilePromise(Ae.slice(0,-1),\"utf8\").catch(()=>\"\"):await oe.readFilePromise(Ae,\"utf8\");return(0,xle.parse)(ye)}));for(let Ae of z)for(let[ye,ae]of Object.entries(Ae))A.env[ye]=sS(ae,{env:U});if(A.importSettings(E(bb)),A.useWithSource(\"<environment>\",E(u),e,{strict:o}),C){let[Ae,ye]=C;A.useWithSource(Ae,E(ye),I,{strict:o})}let te=Ae=>\"default\"in Ae?Ae.default:Ae,le=new Map([[\"@@core\",lse]]);if(r!==null)for(let Ae of r.plugins.keys())le.set(Ae,te(r.modules.get(Ae)));for(let[Ae,ye]of le)A.activatePlugin(Ae,ye);let he=new Map([]);if(r!==null){let Ae=new Map;for(let Ie of kle.builtinModules)Ae.set(Ie,()=>zp(Ie));for(let[Ie,Fe]of r.modules)Ae.set(Ie,()=>Fe);let ye=new Set,ae=async(Ie,Fe)=>{let{factory:g,name:Ee}=zp(Ie);if(!g||ye.has(Ee))return;let De=new Map(Ae),ce=ee=>{if(De.has(ee))return De.get(ee)();throw new it(`This plugin cannot access the package referenced via ${ee} which is neither a builtin, nor an exposed entry`)},ne=await Yy(async()=>te(await g(ce)),ee=>`${ee} (when initializing ${Ee}, defined in ${Fe})`);Ae.set(Ee,()=>ne),ye.add(Ee),he.set(Ee,ne)};if(u.plugins)for(let Ie of u.plugins.split(\";\")){let Fe=V.resolve(e,ue.toPortablePath(Ie));await ae(Fe,\"<environment>\")}for(let{path:Ie,cwd:Fe,data:g}of p)if(!!n&&!!Array.isArray(g.plugins))for(let Ee of g.plugins){let De=typeof Ee!=\"string\"?Ee.path:Ee,ce=Ee?.spec??\"\",ne=Ee?.checksum??\"\";if(I1.has(ce))continue;let ee=V.resolve(Fe,ue.toPortablePath(De));if(!await oe.existsPromise(ee)){if(!ce){let ht=Mt(A,V.basename(ee,\".cjs\"),yt.NAME),H=Mt(A,\".gitignore\",yt.NAME),lt=Mt(A,A.values.get(\"rcFilename\"),yt.NAME),Te=Mt(A,\"https://yarnpkg.com/getting-started/qa#which-files-should-be-gitignored\",yt.URL);throw new it(`Missing source for the ${ht} plugin - please try to remove the plugin from ${lt} then reinstall it manually. This error usually occurs because ${H} is incorrect, check ${Te} to make sure your plugin folder isn't gitignored.`)}if(!ce.match(/^https?:/)){let ht=Mt(A,V.basename(ee,\".cjs\"),yt.NAME),H=Mt(A,A.values.get(\"rcFilename\"),yt.NAME);throw new it(`Failed to recognize the source for the ${ht} plugin - please try to delete the plugin from ${H} then reinstall it manually.`)}let we=await M4(ce,{configuration:A}),xe=Js(we);if(ne&&ne!==xe){let ht=Mt(A,V.basename(ee,\".cjs\"),yt.NAME),H=Mt(A,A.values.get(\"rcFilename\"),yt.NAME),lt=Mt(A,`yarn plugin import ${ce}`,yt.CODE);throw new it(`Failed to fetch the ${ht} plugin from its remote location: its checksum seems to have changed. If this is expected, please remove the plugin from ${H} then run ${lt} to reimport it.`)}await oe.mkdirPromise(V.dirname(ee),{recursive:!0}),await oe.writeFilePromise(ee,we)}await ae(ee,Ie)}}for(let[Ae,ye]of he)A.activatePlugin(Ae,ye);if(A.useWithSource(\"<environment>\",R(u),e,{strict:o}),C){let[Ae,ye]=C;A.useWithSource(Ae,R(ye),I,{strict:o})}return A.get(\"enableGlobalCache\")&&(A.values.set(\"cacheFolder\",`${A.get(\"globalFolder\")}/cache`),A.sources.set(\"cacheFolder\",\"<internal>\")),A}static async findRcFiles(e){let r=Y4(),o=[],a=e,n=null;for(;a!==n;){n=a;let u=V.join(n,r);if(oe.existsSync(u)){let A=await oe.readFilePromise(u,\"utf8\"),p;try{p=Ki(A)}catch{let C=\"\";throw A.match(/^\\s+(?!-)[^:]+\\s+\\S+/m)&&(C=\" (in particular, make sure you list the colons after each key name)\"),new it(`Parse error when loading ${u}; please check it's proper Yaml${C}`)}o.unshift({path:u,cwd:n,data:p})}a=V.dirname(n)}return o}static async findFolderRcFile(e){let r=V.join(e,dr.rc),o;try{o=await oe.readFilePromise(r,\"utf8\")}catch(n){if(n.code===\"ENOENT\")return null;throw n}let a=Ki(o);return{path:r,cwd:e,data:a}}static async findProjectCwd(e){let r=null,o=e,a=null;for(;o!==a;){if(a=o,oe.existsSync(V.join(a,dr.lockfile)))return a;oe.existsSync(V.join(a,dr.manifest))&&(r=a),o=V.dirname(a)}return r}static async updateConfiguration(e,r,o={}){let a=Y4(),n=V.join(e,a),u=oe.existsSync(n)?Ki(await oe.readFilePromise(n,\"utf8\")):{},A=!1,p;if(typeof r==\"function\"){try{p=r(u)}catch{p=r({})}if(p===u)return!1}else{p=u;for(let h of Object.keys(r)){let C=u[h],I=r[h],v;if(typeof I==\"function\")try{v=I(C)}catch{v=I(void 0)}else v=I;C!==v&&(v===rA.deleteProperty?delete p[h]:p[h]=v,A=!0)}if(!A)return!1}return await oe.changeFilePromise(n,Ba(p),{automaticNewlines:!0}),!0}static async addPlugin(e,r){r.length!==0&&await rA.updateConfiguration(e,o=>{let a=o.plugins??[];if(a.length===0)return{...o,plugins:r};let n=[],u=[...r];for(let A of a){let p=typeof A!=\"string\"?A.path:A,h=u.find(C=>C.path===p);h?(n.push(h),u=u.filter(C=>C!==h)):n.push(A)}return n.push(...u),{...o,plugins:n}})}static async updateHomeConfiguration(e){let r=mE();return await rA.updateConfiguration(r,e)}activatePlugin(e,r){this.plugins.set(e,r),typeof r.configuration<\"u\"&&this.importSettings(r.configuration)}importSettings(e){for(let[r,o]of Object.entries(e))if(o!=null){if(this.settings.has(r))throw new Error(`Cannot redefine settings \"${r}\"`);this.settings.set(r,o),this.values.set(r,V4(this,o))}}useWithSource(e,r,o,a){try{this.use(e,r,o,a)}catch(n){throw n.message+=` (in ${Mt(this,e,yt.PATH)})`,n}}use(e,r,o,{strict:a=!0,overwrite:n=!1}={}){a=a&&this.get(\"enableStrictSettings\");for(let u of[\"enableStrictSettings\",...Object.keys(r)]){let A=r[u],p=EM(A);if(p&&(e=p),typeof A>\"u\"||u===\"plugins\"||e===\"<environment>\"&&eot.has(u))continue;if(u===\"rcFilename\")throw new it(`The rcFilename settings can only be set via ${`${kb}RC_FILENAME`.toUpperCase()}, not via a rc file`);let h=this.settings.get(u);if(!h){let I=mE(),v=e[0]!==\"<\"?V.dirname(e):null;if(a&&!(v!==null?I===v:!1))throw new it(`Unrecognized or legacy configuration settings found: ${u} - run \"yarn config -v\" to see the list of settings supported in Yarn`);this.invalid.set(u,e);continue}if(this.sources.has(u)&&!(n||h.type===\"MAP\"||h.isArray&&h.concatenateValues))continue;let C;try{C=K4(this,u,A,h,o)}catch(I){throw I.message+=` in ${Mt(this,e,yt.PATH)}`,I}if(u===\"enableStrictSettings\"&&e!==\"<environment>\"){a=C;continue}if(h.type===\"MAP\"){let I=this.values.get(u);this.values.set(u,new Map(n?[...I,...C]:[...C,...I])),this.sources.set(u,`${this.sources.get(u)}, ${e}`)}else if(h.isArray&&h.concatenateValues){let I=this.values.get(u);this.values.set(u,n?[...I,...C]:[...C,...I]),this.sources.set(u,`${this.sources.get(u)}, ${e}`)}else this.values.set(u,C),this.sources.set(u,e)}}get(e){if(!this.values.has(e))throw new Error(`Invalid configuration key \"${e}\"`);return this.values.get(e)}getSpecial(e,{hideSecrets:r=!1,getNativePaths:o=!1}){let a=this.get(e),n=this.settings.get(e);if(typeof n>\"u\")throw new it(`Couldn't find a configuration settings named \"${e}\"`);return xb(a,n,{hideSecrets:r,getNativePaths:o})}getSubprocessStreams(e,{header:r,prefix:o,report:a}){let n,u,A=oe.createWriteStream(e);if(this.get(\"enableInlineBuilds\")){let p=a.createStreamReporter(`${o} ${Mt(this,\"STDOUT\",\"green\")}`),h=a.createStreamReporter(`${o} ${Mt(this,\"STDERR\",\"red\")}`);n=new G4.PassThrough,n.pipe(p),n.pipe(A),u=new G4.PassThrough,u.pipe(h),u.pipe(A)}else n=A,u=A,typeof r<\"u\"&&n.write(`${r}\n`);return{stdout:n,stderr:u}}makeResolver(){let e=[];for(let r of this.plugins.values())for(let o of r.resolvers||[])e.push(new o);return new Bd([new a1,new Xn,...e])}makeFetcher(){let e=[];for(let r of this.plugins.values())for(let o of r.fetchers||[])e.push(new o);return new fE([new pE,new gE,...e])}getLinkers(){let e=[];for(let r of this.plugins.values())for(let o of r.linkers||[])e.push(new o);return e}getSupportedArchitectures(){let e=w1(),r=this.get(\"supportedArchitectures\"),o=r.get(\"os\");o!==null&&(o=o.map(u=>u===\"current\"?e.os:u));let a=r.get(\"cpu\");a!==null&&(a=a.map(u=>u===\"current\"?e.cpu:u));let n=r.get(\"libc\");return n!==null&&(n=sl(n,u=>u===\"current\"?e.libc??sl.skip:u)),{os:o,cpu:a,libc:n}}async getPackageExtensions(){if(this.packageExtensions!==null)return this.packageExtensions;this.packageExtensions=new Map;let e=this.packageExtensions,r=(o,a,{userProvided:n=!1}={})=>{if(!xa(o.range))throw new Error(\"Only semver ranges are allowed as keys for the packageExtensions setting\");let u=new Ot;u.load(a,{yamlCompatibilityMode:!0});let A=qy(e,o.identHash),p=[];A.push([o.range,p]);let h={status:\"inactive\",userProvided:n,parentDescriptor:o};for(let C of u.dependencies.values())p.push({...h,type:\"Dependency\",descriptor:C});for(let C of u.peerDependencies.values())p.push({...h,type:\"PeerDependency\",descriptor:C});for(let[C,I]of u.peerDependenciesMeta)for(let[v,x]of Object.entries(I))p.push({...h,type:\"PeerDependencyMeta\",selector:C,key:v,value:x})};await this.triggerHook(o=>o.registerPackageExtensions,this,r);for(let[o,a]of this.get(\"packageExtensions\"))r(nh(o,!0),iS(a),{userProvided:!0});return e}normalizeLocator(e){return xa(e.reference)?Qs(e,`${this.get(\"defaultProtocol\")}${e.reference}`):kE.test(e.reference)?Qs(e,`${this.get(\"defaultProtocol\")}${e.reference}`):e}normalizeDependency(e){return xa(e.range)?In(e,`${this.get(\"defaultProtocol\")}${e.range}`):kE.test(e.range)?In(e,`${this.get(\"defaultProtocol\")}${e.range}`):e}normalizeDependencyMap(e){return new Map([...e].map(([r,o])=>[r,this.normalizeDependency(o)]))}normalizePackage(e,{packageExtensions:r}){let o=ZI(e),a=r.get(e.identHash);if(typeof a<\"u\"){let u=e.version;if(u!==null){for(let[A,p]of a)if(!!bf(u,A))for(let h of p)switch(h.status===\"inactive\"&&(h.status=\"redundant\"),h.type){case\"Dependency\":typeof o.dependencies.get(h.descriptor.identHash)>\"u\"&&(h.status=\"active\",o.dependencies.set(h.descriptor.identHash,this.normalizeDependency(h.descriptor)));break;case\"PeerDependency\":typeof o.peerDependencies.get(h.descriptor.identHash)>\"u\"&&(h.status=\"active\",o.peerDependencies.set(h.descriptor.identHash,h.descriptor));break;case\"PeerDependencyMeta\":{let C=o.peerDependenciesMeta.get(h.selector);(typeof C>\"u\"||!Object.hasOwn(C,h.key)||C[h.key]!==h.value)&&(h.status=\"active\",ol(o.peerDependenciesMeta,h.selector,()=>({}))[h.key]=h.value)}break;default:CL(h);break}}}let n=u=>u.scope?`${u.scope}__${u.name}`:`${u.name}`;for(let u of o.peerDependenciesMeta.keys()){let A=zs(u);o.peerDependencies.has(A.identHash)||o.peerDependencies.set(A.identHash,In(A,\"*\"))}for(let u of o.peerDependencies.values()){if(u.scope===\"types\")continue;let A=n(u),p=eA(\"types\",A),h=fn(p);o.peerDependencies.has(p.identHash)||o.peerDependenciesMeta.has(h)||(o.peerDependencies.set(p.identHash,In(p,\"*\")),o.peerDependenciesMeta.set(h,{optional:!0}))}return o.dependencies=new Map(ks(o.dependencies,([,u])=>Sa(u))),o.peerDependencies=new Map(ks(o.peerDependencies,([,u])=>Sa(u))),o}getLimit(e){return ol(this.limits,e,()=>(0,Qle.default)(this.get(e)))}async triggerHook(e,...r){for(let o of this.plugins.values()){let a=o.hooks;if(!a)continue;let n=e(a);!n||await n(...r)}}async triggerMultipleHooks(e,r){for(let o of r)await this.triggerHook(e,...o)}async reduceHook(e,r,...o){let a=r;for(let n of this.plugins.values()){let u=n.hooks;if(!u)continue;let A=e(u);!A||(a=await A(a,...o))}return a}async firstHook(e,...r){for(let o of this.plugins.values()){let a=o.hooks;if(!a)continue;let n=e(a);if(!n)continue;let u=await n(...r);if(typeof u<\"u\")return u}return null}},Ke=rA;Ke.deleteProperty=Symbol(),Ke.telemetry=null});var Ur={};Vt(Ur,{EndStrategy:()=>Z4,ExecError:()=>Fb,PipeError:()=>D1,execvp:()=>j4,pipevp:()=>Gc});function Pd(t){return t!==null&&typeof t.fd==\"number\"}function z4(){}function J4(){for(let t of Sd)t.kill()}async function Gc(t,e,{cwd:r,env:o=process.env,strict:a=!1,stdin:n=null,stdout:u,stderr:A,end:p=2}){let h=[\"pipe\",\"pipe\",\"pipe\"];n===null?h[0]=\"ignore\":Pd(n)&&(h[0]=n),Pd(u)&&(h[1]=u),Pd(A)&&(h[2]=A);let C=(0,X4.default)(t,e,{cwd:ue.fromPortablePath(r),env:{...o,PWD:ue.fromPortablePath(r)},stdio:h});Sd.add(C),Sd.size===1&&(process.on(\"SIGINT\",z4),process.on(\"SIGTERM\",J4)),!Pd(n)&&n!==null&&n.pipe(C.stdin),Pd(u)||C.stdout.pipe(u,{end:!1}),Pd(A)||C.stderr.pipe(A,{end:!1});let I=()=>{for(let v of new Set([u,A]))Pd(v)||v.end()};return new Promise((v,x)=>{C.on(\"error\",E=>{Sd.delete(C),Sd.size===0&&(process.off(\"SIGINT\",z4),process.off(\"SIGTERM\",J4)),(p===2||p===1)&&I(),x(E)}),C.on(\"close\",(E,R)=>{Sd.delete(C),Sd.size===0&&(process.off(\"SIGINT\",z4),process.off(\"SIGTERM\",J4)),(p===2||p===1&&E!==0)&&I(),E===0||!a?v({code:$4(E,R)}):x(new D1({fileName:t,code:E,signal:R}))})})}async function j4(t,e,{cwd:r,env:o=process.env,encoding:a=\"utf8\",strict:n=!1}){let u=[\"ignore\",\"pipe\",\"pipe\"],A=[],p=[],h=ue.fromPortablePath(r);typeof o.PWD<\"u\"&&(o={...o,PWD:h});let C=(0,X4.default)(t,e,{cwd:h,env:o,stdio:u});return C.stdout.on(\"data\",I=>{A.push(I)}),C.stderr.on(\"data\",I=>{p.push(I)}),await new Promise((I,v)=>{C.on(\"error\",x=>{let E=Ke.create(r),R=Mt(E,t,yt.PATH);v(new Jt(1,`Process ${R} failed to spawn`,L=>{L.reportError(1,`  ${Ju(E,{label:\"Thrown Error\",value:_c(yt.NO_HINT,x.message)})}`)}))}),C.on(\"close\",(x,E)=>{let R=a===\"buffer\"?Buffer.concat(A):Buffer.concat(A).toString(a),L=a===\"buffer\"?Buffer.concat(p):Buffer.concat(p).toString(a);x===0||!n?I({code:$4(x,E),stdout:R,stderr:L}):v(new Fb({fileName:t,code:x,signal:E,stdout:R,stderr:L}))})})}function $4(t,e){let r=cot.get(e);return typeof r<\"u\"?128+r:t??1}function uot(t,e,{configuration:r,report:o}){o.reportError(1,`  ${Ju(r,t!==null?{label:\"Exit Code\",value:_c(yt.NUMBER,t)}:{label:\"Exit Signal\",value:_c(yt.CODE,e)})}`)}var X4,Z4,D1,Fb,Sd,cot,Sb=Et(()=>{Pt();X4=$e(aT());v1();Yl();ql();Z4=(o=>(o[o.Never=0]=\"Never\",o[o.ErrorCode=1]=\"ErrorCode\",o[o.Always=2]=\"Always\",o))(Z4||{}),D1=class extends Jt{constructor({fileName:r,code:o,signal:a}){let n=Ke.create(V.cwd()),u=Mt(n,r,yt.PATH);super(1,`Child ${u} reported an error`,A=>{uot(o,a,{configuration:n,report:A})});this.code=$4(o,a)}},Fb=class extends D1{constructor({fileName:r,code:o,signal:a,stdout:n,stderr:u}){super({fileName:r,code:o,signal:a});this.stdout=n,this.stderr=u}};Sd=new Set;cot=new Map([[\"SIGINT\",2],[\"SIGQUIT\",3],[\"SIGKILL\",9],[\"SIGTERM\",15]])});function Tle(t){Rle=t}function P1(){return typeof eU>\"u\"&&(eU=Rle()),eU}var eU,Rle,tU=Et(()=>{Rle=()=>{throw new Error(\"Assertion failed: No libzip instance is available, and no factory was configured\")}});var Nle=_((Rb,nU)=>{var Aot=Object.assign({},Be(\"fs\")),rU=function(){var t=typeof document<\"u\"&&document.currentScript?document.currentScript.src:void 0;return typeof __filename<\"u\"&&(t=t||__filename),function(e){e=e||{};var r=typeof e<\"u\"?e:{},o,a;r.ready=new Promise(function(We,tt){o=We,a=tt});var n={},u;for(u in r)r.hasOwnProperty(u)&&(n[u]=r[u]);var A=[],p=\"./this.program\",h=function(We,tt){throw tt},C=!1,I=!0,v=\"\";function x(We){return r.locateFile?r.locateFile(We,v):v+We}var E,R,L,U;I&&(C?v=Be(\"path\").dirname(v)+\"/\":v=__dirname+\"/\",E=function(tt,It){var nr=ii(tt);return nr?It?nr:nr.toString():(L||(L=Aot),U||(U=Be(\"path\")),tt=U.normalize(tt),L.readFileSync(tt,It?null:\"utf8\"))},R=function(tt){var It=E(tt,!0);return It.buffer||(It=new Uint8Array(It)),Ee(It.buffer),It},process.argv.length>1&&(p=process.argv[1].replace(/\\\\/g,\"/\")),A=process.argv.slice(2),h=function(We){process.exit(We)},r.inspect=function(){return\"[Emscripten Module object]\"});var z=r.print||console.log.bind(console),te=r.printErr||console.warn.bind(console);for(u in n)n.hasOwnProperty(u)&&(r[u]=n[u]);n=null,r.arguments&&(A=r.arguments),r.thisProgram&&(p=r.thisProgram),r.quit&&(h=r.quit);var le=0,he=function(We){le=We},Ae;r.wasmBinary&&(Ae=r.wasmBinary);var ye=r.noExitRuntime||!0;typeof WebAssembly!=\"object\"&&Ti(\"no native wasm support detected\");function ae(We,tt,It){switch(tt=tt||\"i8\",tt.charAt(tt.length-1)===\"*\"&&(tt=\"i32\"),tt){case\"i1\":return _e[We>>0];case\"i8\":return _e[We>>0];case\"i16\":return ap((We>>1)*2);case\"i32\":return Os((We>>2)*4);case\"i64\":return Os((We>>2)*4);case\"float\":return cu((We>>2)*4);case\"double\":return op((We>>3)*8);default:Ti(\"invalid type for getValue: \"+tt)}return null}var Ie,Fe=!1,g;function Ee(We,tt){We||Ti(\"Assertion failed: \"+tt)}function De(We){var tt=r[\"_\"+We];return Ee(tt,\"Cannot call unknown function \"+We+\", make sure it is exported\"),tt}function ce(We,tt,It,nr,$){var me={string:function(es){var bi=0;if(es!=null&&es!==0){var jo=(es.length<<2)+1;bi=Un(jo),ht(es,bi,jo)}return bi},array:function(es){var bi=Un(es.length);return Te(es,bi),bi}};function Le(es){return tt===\"string\"?we(es):tt===\"boolean\"?Boolean(es):es}var ft=De(We),pt=[],Tt=0;if(nr)for(var er=0;er<nr.length;er++){var Zr=me[It[er]];Zr?(Tt===0&&(Tt=ms()),pt[er]=Zr(nr[er])):pt[er]=nr[er]}var qi=ft.apply(null,pt);return qi=Le(qi),Tt!==0&&_s(Tt),qi}function ne(We,tt,It,nr){It=It||[];var $=It.every(function(Le){return Le===\"number\"}),me=tt!==\"string\";return me&&$&&!nr?De(We):function(){return ce(We,tt,It,arguments,nr)}}var ee=new TextDecoder(\"utf8\");function we(We,tt){if(!We)return\"\";for(var It=We+tt,nr=We;!(nr>=It)&&Re[nr];)++nr;return ee.decode(Re.subarray(We,nr))}function xe(We,tt,It,nr){if(!(nr>0))return 0;for(var $=It,me=It+nr-1,Le=0;Le<We.length;++Le){var ft=We.charCodeAt(Le);if(ft>=55296&&ft<=57343){var pt=We.charCodeAt(++Le);ft=65536+((ft&1023)<<10)|pt&1023}if(ft<=127){if(It>=me)break;tt[It++]=ft}else if(ft<=2047){if(It+1>=me)break;tt[It++]=192|ft>>6,tt[It++]=128|ft&63}else if(ft<=65535){if(It+2>=me)break;tt[It++]=224|ft>>12,tt[It++]=128|ft>>6&63,tt[It++]=128|ft&63}else{if(It+3>=me)break;tt[It++]=240|ft>>18,tt[It++]=128|ft>>12&63,tt[It++]=128|ft>>6&63,tt[It++]=128|ft&63}}return tt[It]=0,It-$}function ht(We,tt,It){return xe(We,Re,tt,It)}function H(We){for(var tt=0,It=0;It<We.length;++It){var nr=We.charCodeAt(It);nr>=55296&&nr<=57343&&(nr=65536+((nr&1023)<<10)|We.charCodeAt(++It)&1023),nr<=127?++tt:nr<=2047?tt+=2:nr<=65535?tt+=3:tt+=4}return tt}function lt(We){var tt=H(We)+1,It=Li(tt);return It&&xe(We,_e,It,tt),It}function Te(We,tt){_e.set(We,tt)}function ke(We,tt){return We%tt>0&&(We+=tt-We%tt),We}var be,_e,Re,ze,He,b,w,S,y,F;function J(We){be=We,r.HEAP_DATA_VIEW=F=new DataView(We),r.HEAP8=_e=new Int8Array(We),r.HEAP16=ze=new Int16Array(We),r.HEAP32=b=new Int32Array(We),r.HEAPU8=Re=new Uint8Array(We),r.HEAPU16=He=new Uint16Array(We),r.HEAPU32=w=new Uint32Array(We),r.HEAPF32=S=new Float32Array(We),r.HEAPF64=y=new Float64Array(We)}var X=r.INITIAL_MEMORY||16777216,Z,ie=[],Pe=[],Ne=[],ot=!1;function dt(){if(r.preRun)for(typeof r.preRun==\"function\"&&(r.preRun=[r.preRun]);r.preRun.length;)bt(r.preRun.shift());oo(ie)}function jt(){ot=!0,oo(Pe)}function $t(){if(r.postRun)for(typeof r.postRun==\"function\"&&(r.postRun=[r.postRun]);r.postRun.length;)Qr(r.postRun.shift());oo(Ne)}function bt(We){ie.unshift(We)}function an(We){Pe.unshift(We)}function Qr(We){Ne.unshift(We)}var mr=0,br=null,Wr=null;function Kn(We){mr++,r.monitorRunDependencies&&r.monitorRunDependencies(mr)}function Ns(We){if(mr--,r.monitorRunDependencies&&r.monitorRunDependencies(mr),mr==0&&(br!==null&&(clearInterval(br),br=null),Wr)){var tt=Wr;Wr=null,tt()}}r.preloadedImages={},r.preloadedAudios={};function Ti(We){r.onAbort&&r.onAbort(We),We+=\"\",te(We),Fe=!0,g=1,We=\"abort(\"+We+\"). Build with -s ASSERTIONS=1 for more info.\";var tt=new WebAssembly.RuntimeError(We);throw a(tt),tt}var ps=\"data:application/octet-stream;base64,\";function io(We){return We.startsWith(ps)}var Si=\"data:application/octet-stream;base64,AGFzbQEAAAAB/wEkYAN/f38Bf2ABfwF/YAJ/fwF/YAF/AGAEf39/fwF/YAN/f38AYAV/f39/fwF/YAJ/fwBgBH9/f38AYAABf2AFf39/fn8BfmAEf35/fwF/YAR/f35/AX5gAn9+AX9gA398fwBgA39/fgF/YAF/AX5gBn9/f39/fwF/YAN/fn8Bf2AEf39/fwF+YAV/f35/fwF/YAR/f35/AX9gA39/fgF+YAJ/fgBgAn9/AX5gBX9/f39/AGADf35/AX5gBX5+f35/AX5gA39/fwF+YAZ/fH9/f38Bf2AAAGAHf35/f39+fwF/YAV/fn9/fwF/YAV/f39/fwF+YAJ+fwF/YAJ/fAACJQYBYQFhAAMBYQFiAAEBYQFjAAABYQFkAAEBYQFlAAIBYQFmAAED5wHlAQMAAwEDAwEHDAgDFgcNEgEDDRcFAQ8DEAUQAwIBAhgECxkEAQMBBQsFAwMDARACBAMAAggLBwEAAwADGgQDGwYGABwBBgMTFBEHBwcVCx4ABAgHBAICAgAfAQICAgIGFSAAIQAiAAIBBgIHAg0LEw0FAQUCACMDAQAUAAAGBQECBQUDCwsSAgEDBQIHAQEICAACCQQEAQABCAEBCQoBAwkBAQEBBgEGBgYABAIEBAQGEQQEAAARAAEDCQEJAQAJCQkBAQECCgoAAAMPAQEBAwACAgICBQIABwAKBgwHAAADAgICBQEEBQFwAT8/BQcBAYACgIACBgkBfwFBgInBAgsH+gEzAWcCAAFoAFQBaQDqAQFqALsBAWsAwQEBbACpAQFtAKgBAW4ApwEBbwClAQFwAKMBAXEAoAEBcgCbAQFzAMABAXQAugEBdQC5AQF2AEsBdwDiAQF4AMgBAXkAxwEBegDCAQFBAMkBAUIAuAEBQwAGAUQACQFFAKYBAUYAtwEBRwC2AQFIALUBAUkAtAEBSgCzAQFLALIBAUwAsQEBTQCwAQFOAK8BAU8AvAEBUACuAQFRAK0BAVIArAEBUwAaAVQACwFVAKQBAVYAMgFXAQABWACrAQFZAKoBAVoAxgEBXwDFAQEkAMQBAmFhAL8BAmJhAL4BAmNhAL0BCXgBAEEBCz6iAeMBjgGQAVpbjwFYnwGdAVeeAV1coQFZVlWcAZoBmQGYAZcBlgGVAZQBkwGSAZEB6QHoAecB5gHlAeQB4QHfAeAB3gHdAdwB2gHbAYUB2QHYAdcB1gHVAdQB0wHSAdEB0AHPAc4BzQHMAcsBygE4wwEK1N8G5QHMDAEHfwJAIABFDQAgAEEIayIDIABBBGsoAgAiAUF4cSIAaiEFAkAgAUEBcQ0AIAFBA3FFDQEgAyADKAIAIgFrIgNBxIQBKAIASQ0BIAAgAWohACADQciEASgCAEcEQCABQf8BTQRAIAMoAggiAiABQQN2IgRBA3RB3IQBakYaIAIgAygCDCIBRgRAQbSEAUG0hAEoAgBBfiAEd3E2AgAMAwsgAiABNgIMIAEgAjYCCAwCCyADKAIYIQYCQCADIAMoAgwiAUcEQCADKAIIIgIgATYCDCABIAI2AggMAQsCQCADQRRqIgIoAgAiBA0AIANBEGoiAigCACIEDQBBACEBDAELA0AgAiEHIAQiAUEUaiICKAIAIgQNACABQRBqIQIgASgCECIEDQALIAdBADYCAAsgBkUNAQJAIAMgAygCHCICQQJ0QeSGAWoiBCgCAEYEQCAEIAE2AgAgAQ0BQbiEAUG4hAEoAgBBfiACd3E2AgAMAwsgBkEQQRQgBigCECADRhtqIAE2AgAgAUUNAgsgASAGNgIYIAMoAhAiAgRAIAEgAjYCECACIAE2AhgLIAMoAhQiAkUNASABIAI2AhQgAiABNgIYDAELIAUoAgQiAUEDcUEDRw0AQbyEASAANgIAIAUgAUF+cTYCBCADIABBAXI2AgQgACADaiAANgIADwsgAyAFTw0AIAUoAgQiAUEBcUUNAAJAIAFBAnFFBEAgBUHMhAEoAgBGBEBBzIQBIAM2AgBBwIQBQcCEASgCACAAaiIANgIAIAMgAEEBcjYCBCADQciEASgCAEcNA0G8hAFBADYCAEHIhAFBADYCAA8LIAVByIQBKAIARgRAQciEASADNgIAQbyEAUG8hAEoAgAgAGoiADYCACADIABBAXI2AgQgACADaiAANgIADwsgAUF4cSAAaiEAAkAgAUH/AU0EQCAFKAIIIgIgAUEDdiIEQQN0QdyEAWpGGiACIAUoAgwiAUYEQEG0hAFBtIQBKAIAQX4gBHdxNgIADAILIAIgATYCDCABIAI2AggMAQsgBSgCGCEGAkAgBSAFKAIMIgFHBEAgBSgCCCICQcSEASgCAEkaIAIgATYCDCABIAI2AggMAQsCQCAFQRRqIgIoAgAiBA0AIAVBEGoiAigCACIEDQBBACEBDAELA0AgAiEHIAQiAUEUaiICKAIAIgQNACABQRBqIQIgASgCECIEDQALIAdBADYCAAsgBkUNAAJAIAUgBSgCHCICQQJ0QeSGAWoiBCgCAEYEQCAEIAE2AgAgAQ0BQbiEAUG4hAEoAgBBfiACd3E2AgAMAgsgBkEQQRQgBigCECAFRhtqIAE2AgAgAUUNAQsgASAGNgIYIAUoAhAiAgRAIAEgAjYCECACIAE2AhgLIAUoAhQiAkUNACABIAI2AhQgAiABNgIYCyADIABBAXI2AgQgACADaiAANgIAIANByIQBKAIARw0BQbyEASAANgIADwsgBSABQX5xNgIEIAMgAEEBcjYCBCAAIANqIAA2AgALIABB/wFNBEAgAEEDdiIBQQN0QdyEAWohAAJ/QbSEASgCACICQQEgAXQiAXFFBEBBtIQBIAEgAnI2AgAgAAwBCyAAKAIICyECIAAgAzYCCCACIAM2AgwgAyAANgIMIAMgAjYCCA8LQR8hAiADQgA3AhAgAEH///8HTQRAIABBCHYiASABQYD+P2pBEHZBCHEiAXQiAiACQYDgH2pBEHZBBHEiAnQiBCAEQYCAD2pBEHZBAnEiBHRBD3YgASACciAEcmsiAUEBdCAAIAFBFWp2QQFxckEcaiECCyADIAI2AhwgAkECdEHkhgFqIQECQAJAAkBBuIQBKAIAIgRBASACdCIHcUUEQEG4hAEgBCAHcjYCACABIAM2AgAgAyABNgIYDAELIABBAEEZIAJBAXZrIAJBH0YbdCECIAEoAgAhAQNAIAEiBCgCBEF4cSAARg0CIAJBHXYhASACQQF0IQIgBCABQQRxaiIHQRBqKAIAIgENAAsgByADNgIQIAMgBDYCGAsgAyADNgIMIAMgAzYCCAwBCyAEKAIIIgAgAzYCDCAEIAM2AgggA0EANgIYIAMgBDYCDCADIAA2AggLQdSEAUHUhAEoAgBBAWsiAEF/IAAbNgIACwuDBAEDfyACQYAETwRAIAAgASACEAIaIAAPCyAAIAJqIQMCQCAAIAFzQQNxRQRAAkAgAEEDcUUEQCAAIQIMAQsgAkEBSARAIAAhAgwBCyAAIQIDQCACIAEtAAA6AAAgAUEBaiEBIAJBAWoiAkEDcUUNASACIANJDQALCwJAIANBfHEiBEHAAEkNACACIARBQGoiBUsNAANAIAIgASgCADYCACACIAEoAgQ2AgQgAiABKAIINgIIIAIgASgCDDYCDCACIAEoAhA2AhAgAiABKAIUNgIUIAIgASgCGDYCGCACIAEoAhw2AhwgAiABKAIgNgIgIAIgASgCJDYCJCACIAEoAig2AiggAiABKAIsNgIsIAIgASgCMDYCMCACIAEoAjQ2AjQgAiABKAI4NgI4IAIgASgCPDYCPCABQUBrIQEgAkFAayICIAVNDQALCyACIARPDQEDQCACIAEoAgA2AgAgAUEEaiEBIAJBBGoiAiAESQ0ACwwBCyADQQRJBEAgACECDAELIAAgA0EEayIESwRAIAAhAgwBCyAAIQIDQCACIAEtAAA6AAAgAiABLQABOgABIAIgAS0AAjoAAiACIAEtAAM6AAMgAUEEaiEBIAJBBGoiAiAETQ0ACwsgAiADSQRAA0AgAiABLQAAOgAAIAFBAWohASACQQFqIgIgA0cNAAsLIAALGgAgAARAIAAtAAEEQCAAKAIEEAYLIAAQBgsLoi4BDH8jAEEQayIMJAACQAJAAkACQAJAAkACQAJAAkACQAJAAkAgAEH0AU0EQEG0hAEoAgAiBUEQIABBC2pBeHEgAEELSRsiCEEDdiICdiIBQQNxBEAgAUF/c0EBcSACaiIDQQN0IgFB5IQBaigCACIEQQhqIQACQCAEKAIIIgIgAUHchAFqIgFGBEBBtIQBIAVBfiADd3E2AgAMAQsgAiABNgIMIAEgAjYCCAsgBCADQQN0IgFBA3I2AgQgASAEaiIBIAEoAgRBAXI2AgQMDQsgCEG8hAEoAgAiCk0NASABBEACQEECIAJ0IgBBACAAa3IgASACdHEiAEEAIABrcUEBayIAIABBDHZBEHEiAnYiAUEFdkEIcSIAIAJyIAEgAHYiAUECdkEEcSIAciABIAB2IgFBAXZBAnEiAHIgASAAdiIBQQF2QQFxIgByIAEgAHZqIgNBA3QiAEHkhAFqKAIAIgQoAggiASAAQdyEAWoiAEYEQEG0hAEgBUF+IAN3cSIFNgIADAELIAEgADYCDCAAIAE2AggLIARBCGohACAEIAhBA3I2AgQgBCAIaiICIANBA3QiASAIayIDQQFyNgIEIAEgBGogAzYCACAKBEAgCkEDdiIBQQN0QdyEAWohB0HIhAEoAgAhBAJ/IAVBASABdCIBcUUEQEG0hAEgASAFcjYCACAHDAELIAcoAggLIQEgByAENgIIIAEgBDYCDCAEIAc2AgwgBCABNgIIC0HIhAEgAjYCAEG8hAEgAzYCAAwNC0G4hAEoAgAiBkUNASAGQQAgBmtxQQFrIgAgAEEMdkEQcSICdiIBQQV2QQhxIgAgAnIgASAAdiIBQQJ2QQRxIgByIAEgAHYiAUEBdkECcSIAciABIAB2IgFBAXZBAXEiAHIgASAAdmpBAnRB5IYBaigCACIBKAIEQXhxIAhrIQMgASECA0ACQCACKAIQIgBFBEAgAigCFCIARQ0BCyAAKAIEQXhxIAhrIgIgAyACIANJIgIbIQMgACABIAIbIQEgACECDAELCyABIAhqIgkgAU0NAiABKAIYIQsgASABKAIMIgRHBEAgASgCCCIAQcSEASgCAEkaIAAgBDYCDCAEIAA2AggMDAsgAUEUaiICKAIAIgBFBEAgASgCECIARQ0EIAFBEGohAgsDQCACIQcgACIEQRRqIgIoAgAiAA0AIARBEGohAiAEKAIQIgANAAsgB0EANgIADAsLQX8hCCAAQb9/Sw0AIABBC2oiAEF4cSEIQbiEASgCACIJRQ0AQQAgCGshAwJAAkACQAJ/QQAgCEGAAkkNABpBHyAIQf///wdLDQAaIABBCHYiACAAQYD+P2pBEHZBCHEiAnQiACAAQYDgH2pBEHZBBHEiAXQiACAAQYCAD2pBEHZBAnEiAHRBD3YgASACciAAcmsiAEEBdCAIIABBFWp2QQFxckEcagsiBUECdEHkhgFqKAIAIgJFBEBBACEADAELQQAhACAIQQBBGSAFQQF2ayAFQR9GG3QhAQNAAkAgAigCBEF4cSAIayIHIANPDQAgAiEEIAciAw0AQQAhAyACIQAMAwsgACACKAIUIgcgByACIAFBHXZBBHFqKAIQIgJGGyAAIAcbIQAgAUEBdCEBIAINAAsLIAAgBHJFBEBBAiAFdCIAQQAgAGtyIAlxIgBFDQMgAEEAIABrcUEBayIAIABBDHZBEHEiAnYiAUEFdkEIcSIAIAJyIAEgAHYiAUECdkEEcSIAciABIAB2IgFBAXZBAnEiAHIgASAAdiIBQQF2QQFxIgByIAEgAHZqQQJ0QeSGAWooAgAhAAsgAEUNAQsDQCAAKAIEQXhxIAhrIgEgA0khAiABIAMgAhshAyAAIAQgAhshBCAAKAIQIgEEfyABBSAAKAIUCyIADQALCyAERQ0AIANBvIQBKAIAIAhrTw0AIAQgCGoiBiAETQ0BIAQoAhghBSAEIAQoAgwiAUcEQCAEKAIIIgBBxIQBKAIASRogACABNgIMIAEgADYCCAwKCyAEQRRqIgIoAgAiAEUEQCAEKAIQIgBFDQQgBEEQaiECCwNAIAIhByAAIgFBFGoiAigCACIADQAgAUEQaiECIAEoAhAiAA0ACyAHQQA2AgAMCQsgCEG8hAEoAgAiAk0EQEHIhAEoAgAhAwJAIAIgCGsiAUEQTwRAQbyEASABNgIAQciEASADIAhqIgA2AgAgACABQQFyNgIEIAIgA2ogATYCACADIAhBA3I2AgQMAQtByIQBQQA2AgBBvIQBQQA2AgAgAyACQQNyNgIEIAIgA2oiACAAKAIEQQFyNgIECyADQQhqIQAMCwsgCEHAhAEoAgAiBkkEQEHAhAEgBiAIayIBNgIAQcyEAUHMhAEoAgAiAiAIaiIANgIAIAAgAUEBcjYCBCACIAhBA3I2AgQgAkEIaiEADAsLQQAhACAIQS9qIgkCf0GMiAEoAgAEQEGUiAEoAgAMAQtBmIgBQn83AgBBkIgBQoCggICAgAQ3AgBBjIgBIAxBDGpBcHFB2KrVqgVzNgIAQaCIAUEANgIAQfCHAUEANgIAQYAgCyIBaiIFQQAgAWsiB3EiAiAITQ0KQeyHASgCACIEBEBB5IcBKAIAIgMgAmoiASADTQ0LIAEgBEsNCwtB8IcBLQAAQQRxDQUCQAJAQcyEASgCACIDBEBB9IcBIQADQCADIAAoAgAiAU8EQCABIAAoAgRqIANLDQMLIAAoAggiAA0ACwtBABApIgFBf0YNBiACIQVBkIgBKAIAIgNBAWsiACABcQRAIAIgAWsgACABakEAIANrcWohBQsgBSAITQ0GIAVB/v///wdLDQZB7IcBKAIAIgQEQEHkhwEoAgAiAyAFaiIAIANNDQcgACAESw0HCyAFECkiACABRw0BDAgLIAUgBmsgB3EiBUH+////B0sNBSAFECkiASAAKAIAIAAoAgRqRg0EIAEhAAsCQCAAQX9GDQAgCEEwaiAFTQ0AQZSIASgCACIBIAkgBWtqQQAgAWtxIgFB/v///wdLBEAgACEBDAgLIAEQKUF/RwRAIAEgBWohBSAAIQEMCAtBACAFaxApGgwFCyAAIgFBf0cNBgwECwALQQAhBAwHC0EAIQEMBQsgAUF/Rw0CC0HwhwFB8IcBKAIAQQRyNgIACyACQf7///8HSw0BIAIQKSEBQQAQKSEAIAFBf0YNASAAQX9GDQEgACABTQ0BIAAgAWsiBSAIQShqTQ0BC0HkhwFB5IcBKAIAIAVqIgA2AgBB6IcBKAIAIABJBEBB6IcBIAA2AgALAkACQAJAQcyEASgCACIHBEBB9IcBIQADQCABIAAoAgAiAyAAKAIEIgJqRg0CIAAoAggiAA0ACwwCC0HEhAEoAgAiAEEAIAAgAU0bRQRAQcSEASABNgIAC0EAIQBB+IcBIAU2AgBB9IcBIAE2AgBB1IQBQX82AgBB2IQBQYyIASgCADYCAEGAiAFBADYCAANAIABBA3QiA0HkhAFqIANB3IQBaiICNgIAIANB6IQBaiACNgIAIABBAWoiAEEgRw0AC0HAhAEgBUEoayIDQXggAWtBB3FBACABQQhqQQdxGyIAayICNgIAQcyEASAAIAFqIgA2AgAgACACQQFyNgIEIAEgA2pBKDYCBEHQhAFBnIgBKAIANgIADAILIAAtAAxBCHENACADIAdLDQAgASAHTQ0AIAAgAiAFajYCBEHMhAEgB0F4IAdrQQdxQQAgB0EIakEHcRsiAGoiAjYCAEHAhAFBwIQBKAIAIAVqIgEgAGsiADYCACACIABBAXI2AgQgASAHakEoNgIEQdCEAUGciAEoAgA2AgAMAQtBxIQBKAIAIAFLBEBBxIQBIAE2AgALIAEgBWohAkH0hwEhAAJAAkACQAJAAkACQANAIAIgACgCAEcEQCAAKAIIIgANAQwCCwsgAC0ADEEIcUUNAQtB9IcBIQADQCAHIAAoAgAiAk8EQCACIAAoAgRqIgQgB0sNAwsgACgCCCEADAALAAsgACABNgIAIAAgACgCBCAFajYCBCABQXggAWtBB3FBACABQQhqQQdxG2oiCSAIQQNyNgIEIAJBeCACa0EHcUEAIAJBCGpBB3EbaiIFIAggCWoiBmshAiAFIAdGBEBBzIQBIAY2AgBBwIQBQcCEASgCACACaiIANgIAIAYgAEEBcjYCBAwDCyAFQciEASgCAEYEQEHIhAEgBjYCAEG8hAFBvIQBKAIAIAJqIgA2AgAgBiAAQQFyNgIEIAAgBmogADYCAAwDCyAFKAIEIgBBA3FBAUYEQCAAQXhxIQcCQCAAQf8BTQRAIAUoAggiAyAAQQN2IgBBA3RB3IQBakYaIAMgBSgCDCIBRgRAQbSEAUG0hAEoAgBBfiAAd3E2AgAMAgsgAyABNgIMIAEgAzYCCAwBCyAFKAIYIQgCQCAFIAUoAgwiAUcEQCAFKAIIIgAgATYCDCABIAA2AggMAQsCQCAFQRRqIgAoAgAiAw0AIAVBEGoiACgCACIDDQBBACEBDAELA0AgACEEIAMiAUEUaiIAKAIAIgMNACABQRBqIQAgASgCECIDDQALIARBADYCAAsgCEUNAAJAIAUgBSgCHCIDQQJ0QeSGAWoiACgCAEYEQCAAIAE2AgAgAQ0BQbiEAUG4hAEoAgBBfiADd3E2AgAMAgsgCEEQQRQgCCgCECAFRhtqIAE2AgAgAUUNAQsgASAINgIYIAUoAhAiAARAIAEgADYCECAAIAE2AhgLIAUoAhQiAEUNACABIAA2AhQgACABNgIYCyAFIAdqIQUgAiAHaiECCyAFIAUoAgRBfnE2AgQgBiACQQFyNgIEIAIgBmogAjYCACACQf8BTQRAIAJBA3YiAEEDdEHchAFqIQICf0G0hAEoAgAiAUEBIAB0IgBxRQRAQbSEASAAIAFyNgIAIAIMAQsgAigCCAshACACIAY2AgggACAGNgIMIAYgAjYCDCAGIAA2AggMAwtBHyEAIAJB////B00EQCACQQh2IgAgAEGA/j9qQRB2QQhxIgN0IgAgAEGA4B9qQRB2QQRxIgF0IgAgAEGAgA9qQRB2QQJxIgB0QQ92IAEgA3IgAHJrIgBBAXQgAiAAQRVqdkEBcXJBHGohAAsgBiAANgIcIAZCADcCECAAQQJ0QeSGAWohBAJAQbiEASgCACIDQQEgAHQiAXFFBEBBuIQBIAEgA3I2AgAgBCAGNgIAIAYgBDYCGAwBCyACQQBBGSAAQQF2ayAAQR9GG3QhACAEKAIAIQEDQCABIgMoAgRBeHEgAkYNAyAAQR12IQEgAEEBdCEAIAMgAUEEcWoiBCgCECIBDQALIAQgBjYCECAGIAM2AhgLIAYgBjYCDCAGIAY2AggMAgtBwIQBIAVBKGsiA0F4IAFrQQdxQQAgAUEIakEHcRsiAGsiAjYCAEHMhAEgACABaiIANgIAIAAgAkEBcjYCBCABIANqQSg2AgRB0IQBQZyIASgCADYCACAHIARBJyAEa0EHcUEAIARBJ2tBB3EbakEvayIAIAAgB0EQakkbIgJBGzYCBCACQfyHASkCADcCECACQfSHASkCADcCCEH8hwEgAkEIajYCAEH4hwEgBTYCAEH0hwEgATYCAEGAiAFBADYCACACQRhqIQADQCAAQQc2AgQgAEEIaiEBIABBBGohACABIARJDQALIAIgB0YNAyACIAIoAgRBfnE2AgQgByACIAdrIgRBAXI2AgQgAiAENgIAIARB/wFNBEAgBEEDdiIAQQN0QdyEAWohAgJ/QbSEASgCACIBQQEgAHQiAHFFBEBBtIQBIAAgAXI2AgAgAgwBCyACKAIICyEAIAIgBzYCCCAAIAc2AgwgByACNgIMIAcgADYCCAwEC0EfIQAgB0IANwIQIARB////B00EQCAEQQh2IgAgAEGA/j9qQRB2QQhxIgJ0IgAgAEGA4B9qQRB2QQRxIgF0IgAgAEGAgA9qQRB2QQJxIgB0QQ92IAEgAnIgAHJrIgBBAXQgBCAAQRVqdkEBcXJBHGohAAsgByAANgIcIABBAnRB5IYBaiEDAkBBuIQBKAIAIgJBASAAdCIBcUUEQEG4hAEgASACcjYCACADIAc2AgAgByADNgIYDAELIARBAEEZIABBAXZrIABBH0YbdCEAIAMoAgAhAQNAIAEiAigCBEF4cSAERg0EIABBHXYhASAAQQF0IQAgAiABQQRxaiIDKAIQIgENAAsgAyAHNgIQIAcgAjYCGAsgByAHNgIMIAcgBzYCCAwDCyADKAIIIgAgBjYCDCADIAY2AgggBkEANgIYIAYgAzYCDCAGIAA2AggLIAlBCGohAAwFCyACKAIIIgAgBzYCDCACIAc2AgggB0EANgIYIAcgAjYCDCAHIAA2AggLQcCEASgCACIAIAhNDQBBwIQBIAAgCGsiATYCAEHMhAFBzIQBKAIAIgIgCGoiADYCACAAIAFBAXI2AgQgAiAIQQNyNgIEIAJBCGohAAwDC0GEhAFBMDYCAEEAIQAMAgsCQCAFRQ0AAkAgBCgCHCICQQJ0QeSGAWoiACgCACAERgRAIAAgATYCACABDQFBuIQBIAlBfiACd3EiCTYCAAwCCyAFQRBBFCAFKAIQIARGG2ogATYCACABRQ0BCyABIAU2AhggBCgCECIABEAgASAANgIQIAAgATYCGAsgBCgCFCIARQ0AIAEgADYCFCAAIAE2AhgLAkAgA0EPTQRAIAQgAyAIaiIAQQNyNgIEIAAgBGoiACAAKAIEQQFyNgIEDAELIAQgCEEDcjYCBCAGIANBAXI2AgQgAyAGaiADNgIAIANB/wFNBEAgA0EDdiIAQQN0QdyEAWohAgJ/QbSEASgCACIBQQEgAHQiAHFFBEBBtIQBIAAgAXI2AgAgAgwBCyACKAIICyEAIAIgBjYCCCAAIAY2AgwgBiACNgIMIAYgADYCCAwBC0EfIQAgA0H///8HTQRAIANBCHYiACAAQYD+P2pBEHZBCHEiAnQiACAAQYDgH2pBEHZBBHEiAXQiACAAQYCAD2pBEHZBAnEiAHRBD3YgASACciAAcmsiAEEBdCADIABBFWp2QQFxckEcaiEACyAGIAA2AhwgBkIANwIQIABBAnRB5IYBaiECAkACQCAJQQEgAHQiAXFFBEBBuIQBIAEgCXI2AgAgAiAGNgIAIAYgAjYCGAwBCyADQQBBGSAAQQF2ayAAQR9GG3QhACACKAIAIQgDQCAIIgEoAgRBeHEgA0YNAiAAQR12IQIgAEEBdCEAIAEgAkEEcWoiAigCECIIDQALIAIgBjYCECAGIAE2AhgLIAYgBjYCDCAGIAY2AggMAQsgASgCCCIAIAY2AgwgASAGNgIIIAZBADYCGCAGIAE2AgwgBiAANgIICyAEQQhqIQAMAQsCQCALRQ0AAkAgASgCHCICQQJ0QeSGAWoiACgCACABRgRAIAAgBDYCACAEDQFBuIQBIAZBfiACd3E2AgAMAgsgC0EQQRQgCygCECABRhtqIAQ2AgAgBEUNAQsgBCALNgIYIAEoAhAiAARAIAQgADYCECAAIAQ2AhgLIAEoAhQiAEUNACAEIAA2AhQgACAENgIYCwJAIANBD00EQCABIAMgCGoiAEEDcjYCBCAAIAFqIgAgACgCBEEBcjYCBAwBCyABIAhBA3I2AgQgCSADQQFyNgIEIAMgCWogAzYCACAKBEAgCkEDdiIAQQN0QdyEAWohBEHIhAEoAgAhAgJ/QQEgAHQiACAFcUUEQEG0hAEgACAFcjYCACAEDAELIAQoAggLIQAgBCACNgIIIAAgAjYCDCACIAQ2AgwgAiAANgIIC0HIhAEgCTYCAEG8hAEgAzYCAAsgAUEIaiEACyAMQRBqJAAgAAuJAQEDfyAAKAIcIgEQMAJAIAAoAhAiAiABKAIQIgMgAiADSRsiAkUNACAAKAIMIAEoAgggAhAHGiAAIAAoAgwgAmo2AgwgASABKAIIIAJqNgIIIAAgACgCFCACajYCFCAAIAAoAhAgAms2AhAgASABKAIQIAJrIgA2AhAgAA0AIAEgASgCBDYCCAsLzgEBBX8CQCAARQ0AIAAoAjAiAQRAIAAgAUEBayIBNgIwIAENAQsgACgCIARAIABBATYCICAAEBoaCyAAKAIkQQFGBEAgABBDCwJAIAAoAiwiAUUNACAALQAoDQACQCABKAJEIgNFDQAgASgCTCEEA0AgACAEIAJBAnRqIgUoAgBHBEAgAyACQQFqIgJHDQEMAgsLIAUgBCADQQFrIgJBAnRqKAIANgIAIAEgAjYCRAsLIABBAEIAQQUQDhogACgCACIBBEAgARALCyAAEAYLC1oCAn4BfwJ/AkACQCAALQAARQ0AIAApAxAiAUJ9Vg0AIAFCAnwiAiAAKQMIWA0BCyAAQQA6AABBAAwBC0EAIAAoAgQiA0UNABogACACNwMQIAMgAadqLwAACwthAgJ+AX8CQAJAIAAtAABFDQAgACkDECICQn1WDQAgAkICfCIDIAApAwhYDQELIABBADoAAA8LIAAoAgQiBEUEQA8LIAAgAzcDECAEIAKnaiIAIAFBCHY6AAEgACABOgAAC8wCAQJ/IwBBEGsiBCQAAkAgACkDGCADrYinQQFxRQRAIABBDGoiAARAIABBADYCBCAAQRw2AgALQn8hAgwBCwJ+IAAoAgAiBUUEQCAAKAIIIAEgAiADIAAoAgQRDAAMAQsgBSAAKAIIIAEgAiADIAAoAgQRCgALIgJCf1UNAAJAIANBBGsOCwEAAAAAAAAAAAABAAsCQAJAIAAtABhBEHFFBEAgAEEMaiIBBEAgAUEANgIEIAFBHDYCAAsMAQsCfiAAKAIAIgFFBEAgACgCCCAEQQhqQghBBCAAKAIEEQwADAELIAEgACgCCCAEQQhqQghBBCAAKAIEEQoAC0J/VQ0BCyAAQQxqIgAEQCAAQQA2AgQgAEEUNgIACwwBCyAEKAIIIQEgBCgCDCEDIABBDGoiAARAIAAgAzYCBCAAIAE2AgALCyAEQRBqJAAgAguTFQIOfwN+AkACQAJAAkACQAJAAkACQAJAAkACQCAAKALwLQRAIAAoAogBQQFIDQEgACgCACIEKAIsQQJHDQQgAC8B5AENAyAALwHoAQ0DIAAvAewBDQMgAC8B8AENAyAALwH0AQ0DIAAvAfgBDQMgAC8B/AENAyAALwGcAg0DIAAvAaACDQMgAC8BpAINAyAALwGoAg0DIAAvAawCDQMgAC8BsAINAyAALwG0Ag0DIAAvAbgCDQMgAC8BvAINAyAALwHAAg0DIAAvAcQCDQMgAC8ByAINAyAALwHUAg0DIAAvAdgCDQMgAC8B3AINAyAALwHgAg0DIAAvAYgCDQIgAC8BjAINAiAALwGYAg0CQSAhBgNAIAAgBkECdCIFai8B5AENAyAAIAVBBHJqLwHkAQ0DIAAgBUEIcmovAeQBDQMgACAFQQxyai8B5AENAyAGQQRqIgZBgAJHDQALDAMLIABBBzYC/C0gAkF8Rw0FIAFFDQUMBgsgAkEFaiIEIQcMAwtBASEHCyAEIAc2AiwLIAAgAEHoFmoQUSAAIABB9BZqEFEgAC8B5gEhBCAAIABB7BZqKAIAIgxBAnRqQf//AzsB6gEgAEGQFmohECAAQZQWaiERIABBjBZqIQdBACEGIAxBAE4EQEEHQYoBIAQbIQ1BBEEDIAQbIQpBfyEJA0AgBCEIIAAgCyIOQQFqIgtBAnRqLwHmASEEAkACQCAGQQFqIgVB//8DcSIPIA1B//8DcU8NACAEIAhHDQAgBSEGDAELAn8gACAIQQJ0akHMFWogCkH//wNxIA9LDQAaIAgEQEEBIQUgByAIIAlGDQEaIAAgCEECdGpBzBVqIgYgBi8BAEEBajsBACAHDAELQQEhBSAQIBEgBkH//wNxQQpJGwsiBiAGLwEAIAVqOwEAQQAhBgJ/IARFBEBBAyEKQYoBDAELQQNBBCAEIAhGIgUbIQpBBkEHIAUbCyENIAghCQsgDCAORw0ACwsgAEHaE2ovAQAhBCAAIABB+BZqKAIAIgxBAnRqQd4TakH//wM7AQBBACEGIAxBAE4EQEEHQYoBIAQbIQ1BBEEDIAQbIQpBfyEJQQAhCwNAIAQhCCAAIAsiDkEBaiILQQJ0akHaE2ovAQAhBAJAAkAgBkEBaiIFQf//A3EiDyANQf//A3FPDQAgBCAIRw0AIAUhBgwBCwJ/IAAgCEECdGpBzBVqIApB//8DcSAPSw0AGiAIBEBBASEFIAcgCCAJRg0BGiAAIAhBAnRqQcwVaiIGIAYvAQBBAWo7AQAgBwwBC0EBIQUgECARIAZB//8DcUEKSRsLIgYgBi8BACAFajsBAEEAIQYCfyAERQRAQQMhCkGKAQwBC0EDQQQgBCAIRiIFGyEKQQZBByAFGwshDSAIIQkLIAwgDkcNAAsLIAAgAEGAF2oQUSAAIAAoAvgtAn9BEiAAQYoWai8BAA0AGkERIABB0hVqLwEADQAaQRAgAEGGFmovAQANABpBDyAAQdYVai8BAA0AGkEOIABBghZqLwEADQAaQQ0gAEHaFWovAQANABpBDCAAQf4Vai8BAA0AGkELIABB3hVqLwEADQAaQQogAEH6FWovAQANABpBCSAAQeIVai8BAA0AGkEIIABB9hVqLwEADQAaQQcgAEHmFWovAQANABpBBiAAQfIVai8BAA0AGkEFIABB6hVqLwEADQAaQQQgAEHuFWovAQANABpBA0ECIABBzhVqLwEAGwsiBkEDbGoiBEERajYC+C0gACgC/C1BCmpBA3YiByAEQRtqQQN2IgRNBEAgByEEDAELIAAoAowBQQRHDQAgByEECyAEIAJBBGpPQQAgARsNASAEIAdHDQQLIANBAmqtIRIgACkDmC4hFCAAKAKgLiIBQQNqIgdBP0sNASASIAGthiAUhCESDAILIAAgASACIAMQOQwDCyABQcAARgRAIAAoAgQgACgCEGogFDcAACAAIAAoAhBBCGo2AhBBAyEHDAELIAAoAgQgACgCEGogEiABrYYgFIQ3AAAgACAAKAIQQQhqNgIQIAFBPWshByASQcAAIAFrrYghEgsgACASNwOYLiAAIAc2AqAuIABBgMEAQYDKABCHAQwBCyADQQRqrSESIAApA5guIRQCQCAAKAKgLiIBQQNqIgRBP00EQCASIAGthiAUhCESDAELIAFBwABGBEAgACgCBCAAKAIQaiAUNwAAIAAgACgCEEEIajYCEEEDIQQMAQsgACgCBCAAKAIQaiASIAGthiAUhDcAACAAIAAoAhBBCGo2AhAgAUE9ayEEIBJBwAAgAWutiCESCyAAIBI3A5guIAAgBDYCoC4gAEHsFmooAgAiC6xCgAJ9IRMgAEH4FmooAgAhCQJAAkACfwJ+AkACfwJ/IARBOk0EQCATIASthiAShCETIARBBWoMAQsgBEHAAEYEQCAAKAIEIAAoAhBqIBI3AAAgACAAKAIQQQhqNgIQIAmsIRJCBSEUQQoMAgsgACgCBCAAKAIQaiATIASthiAShDcAACAAIAAoAhBBCGo2AhAgE0HAACAEa62IIRMgBEE7awshBSAJrCESIAVBOksNASAFrSEUIAVBBWoLIQcgEiAUhiAThAwBCyAFQcAARgRAIAAoAgQgACgCEGogEzcAACAAIAAoAhBBCGo2AhAgBq1CA30hE0IFIRRBCQwCCyAAKAIEIAAoAhBqIBIgBa2GIBOENwAAIAAgACgCEEEIajYCECAFQTtrIQcgEkHAACAFa62ICyESIAatQgN9IRMgB0E7Sw0BIAetIRQgB0EEagshBCATIBSGIBKEIRMMAQsgB0HAAEYEQCAAKAIEIAAoAhBqIBI3AAAgACAAKAIQQQhqNgIQQQQhBAwBCyAAKAIEIAAoAhBqIBMgB62GIBKENwAAIAAgACgCEEEIajYCECAHQTxrIQQgE0HAACAHa62IIRMLQQAhBQNAIAAgBSIBQZDWAGotAABBAnRqQc4VajMBACEUAn8gBEE8TQRAIBQgBK2GIBOEIRMgBEEDagwBCyAEQcAARgRAIAAoAgQgACgCEGogEzcAACAAIAAoAhBBCGo2AhAgFCETQQMMAQsgACgCBCAAKAIQaiAUIASthiAThDcAACAAIAAoAhBBCGo2AhAgFEHAACAEa62IIRMgBEE9awshBCABQQFqIQUgASAGRw0ACyAAIAQ2AqAuIAAgEzcDmC4gACAAQeQBaiICIAsQhgEgACAAQdgTaiIBIAkQhgEgACACIAEQhwELIAAQiAEgAwRAAkAgACgCoC4iBEE5TgRAIAAoAgQgACgCEGogACkDmC43AAAgACAAKAIQQQhqNgIQDAELIARBGU4EQCAAKAIEIAAoAhBqIAApA5guPgAAIAAgAEGcLmo1AgA3A5guIAAgACgCEEEEajYCECAAIAAoAqAuQSBrIgQ2AqAuCyAEQQlOBH8gACgCBCAAKAIQaiAAKQOYLj0AACAAIAAoAhBBAmo2AhAgACAAKQOYLkIQiDcDmC4gACgCoC5BEGsFIAQLQQFIDQAgACAAKAIQIgFBAWo2AhAgASAAKAIEaiAAKQOYLjwAAAsgAEEANgKgLiAAQgA3A5guCwsZACAABEAgACgCABAGIAAoAgwQBiAAEAYLC6wBAQJ+Qn8hAwJAIAAtACgNAAJAAkAgACgCIEUNACACQgBTDQAgAlANASABDQELIABBDGoiAARAIABBADYCBCAAQRI2AgALQn8PCyAALQA1DQBCACEDIAAtADQNACACUA0AA0AgACABIAOnaiACIAN9QQEQDiIEQn9XBEAgAEEBOgA1Qn8gAyADUBsPCyAEUEUEQCADIAR8IgMgAloNAgwBCwsgAEEBOgA0CyADC3UCAn4BfwJAAkAgAC0AAEUNACAAKQMQIgJCe1YNACACQgR8IgMgACkDCFgNAQsgAEEAOgAADwsgACgCBCIERQRADwsgACADNwMQIAQgAqdqIgAgAUEYdjoAAyAAIAFBEHY6AAIgACABQQh2OgABIAAgAToAAAtUAgF+AX8CQAJAIAAtAABFDQAgASAAKQMQIgF8IgIgAVQNACACIAApAwhYDQELIABBADoAAEEADwsgACgCBCIDRQRAQQAPCyAAIAI3AxAgAyABp2oLdwECfyMAQRBrIgMkAEF/IQQCQCAALQAoDQAgACgCIEEAIAJBA0kbRQRAIABBDGoiAARAIABBADYCBCAAQRI2AgALDAELIAMgAjYCCCADIAE3AwAgACADQhBBBhAOQgBTDQBBACEEIABBADoANAsgA0EQaiQAIAQLVwICfgF/AkACQCAALQAARQ0AIAApAxAiAUJ7Vg0AIAFCBHwiAiAAKQMIWA0BCyAAQQA6AABBAA8LIAAoAgQiA0UEQEEADwsgACACNwMQIAMgAadqKAAAC1UCAX4BfyAABEACQCAAKQMIUA0AQgEhAQNAIAAoAgAgAkEEdGoQPiABIAApAwhaDQEgAachAiABQgF8IQEMAAsACyAAKAIAEAYgACgCKBAQIAAQBgsLZAECfwJAAkACQCAARQRAIAGnEAkiA0UNAkEYEAkiAkUNAQwDCyAAIQNBGBAJIgINAkEADwsgAxAGC0EADwsgAkIANwMQIAIgATcDCCACIAM2AgQgAkEBOgAAIAIgAEU6AAEgAgudAQICfgF/AkACQCAALQAARQ0AIAApAxAiAkJ3Vg0AIAJCCHwiAyAAKQMIWA0BCyAAQQA6AAAPCyAAKAIEIgRFBEAPCyAAIAM3AxAgBCACp2oiACABQjiIPAAHIAAgAUIwiDwABiAAIAFCKIg8AAUgACABQiCIPAAEIAAgAUIYiDwAAyAAIAFCEIg8AAIgACABQgiIPAABIAAgATwAAAvwAgICfwF+AkAgAkUNACAAIAJqIgNBAWsgAToAACAAIAE6AAAgAkEDSQ0AIANBAmsgAToAACAAIAE6AAEgA0EDayABOgAAIAAgAToAAiACQQdJDQAgA0EEayABOgAAIAAgAToAAyACQQlJDQAgAEEAIABrQQNxIgRqIgMgAUH/AXFBgYKECGwiADYCACADIAIgBGtBfHEiAmoiAUEEayAANgIAIAJBCUkNACADIAA2AgggAyAANgIEIAFBCGsgADYCACABQQxrIAA2AgAgAkEZSQ0AIAMgADYCGCADIAA2AhQgAyAANgIQIAMgADYCDCABQRBrIAA2AgAgAUEUayAANgIAIAFBGGsgADYCACABQRxrIAA2AgAgAiADQQRxQRhyIgFrIgJBIEkNACAArUKBgICAEH4hBSABIANqIQEDQCABIAU3AxggASAFNwMQIAEgBTcDCCABIAU3AwAgAUEgaiEBIAJBIGsiAkEfSw0ACwsLbwEDfyAAQQxqIQICQAJ/IAAoAiAiAUUEQEF/IQFBEgwBCyAAIAFBAWsiAzYCIEEAIQEgAw0BIABBAEIAQQIQDhogACgCACIARQ0BIAAQGkF/Sg0BQRQLIQAgAgRAIAJBADYCBCACIAA2AgALCyABC58BAgF/AX4CfwJAAn4gACgCACIDKAIkQQFGQQAgAkJ/VRtFBEAgA0EMaiIBBEAgAUEANgIEIAFBEjYCAAtCfwwBCyADIAEgAkELEA4LIgRCf1cEQCAAKAIAIQEgAEEIaiIABEAgACABKAIMNgIAIAAgASgCEDYCBAsMAQtBACACIARRDQEaIABBCGoEQCAAQRs2AgwgAEEGNgIICwtBfwsLJAEBfyAABEADQCAAKAIAIQEgACgCDBAGIAAQBiABIgANAAsLC5gBAgJ+AX8CQAJAIAAtAABFDQAgACkDECIBQndWDQAgAUIIfCICIAApAwhYDQELIABBADoAAEIADwsgACgCBCIDRQRAQgAPCyAAIAI3AxAgAyABp2oiADEABkIwhiAAMQAHQjiGhCAAMQAFQiiGhCAAMQAEQiCGhCAAMQADQhiGhCAAMQACQhCGhCAAMQABQgiGhCAAMQAAfAsjACAAQShGBEAgAhAGDwsgAgRAIAEgAkEEaygCACAAEQcACwsyACAAKAIkQQFHBEAgAEEMaiIABEAgAEEANgIEIABBEjYCAAtCfw8LIABBAEIAQQ0QDgsPACAABEAgABA2IAAQBgsLgAEBAX8gAC0AKAR/QX8FIAFFBEAgAEEMagRAIABBADYCECAAQRI2AgwLQX8PCyABECoCQCAAKAIAIgJFDQAgAiABECFBf0oNACAAKAIAIQEgAEEMaiIABEAgACABKAIMNgIAIAAgASgCEDYCBAtBfw8LIAAgAUI4QQMQDkI/h6cLC38BA38gACEBAkAgAEEDcQRAA0AgAS0AAEUNAiABQQFqIgFBA3ENAAsLA0AgASICQQRqIQEgAigCACIDQX9zIANBgYKECGtxQYCBgoR4cUUNAAsgA0H/AXFFBEAgAiAAaw8LA0AgAi0AASEDIAJBAWoiASECIAMNAAsLIAEgAGsL3wIBCH8gAEUEQEEBDwsCQCAAKAIIIgINAEEBIQQgAC8BBCIHRQRAQQEhAgwBCyAAKAIAIQgDQAJAIAMgCGoiBS0AACICQSBPBEAgAkEYdEEYdUF/Sg0BCyACQQ1NQQBBASACdEGAzABxGw0AAn8CfyACQeABcUHAAUYEQEEBIQYgA0EBagwBCyACQfABcUHgAUYEQCADQQJqIQNBACEGQQEMAgsgAkH4AXFB8AFHBEBBBCECDAULQQAhBiADQQNqCyEDQQALIQlBBCECIAMgB08NAiAFLQABQcABcUGAAUcNAkEDIQQgBg0AIAUtAAJBwAFxQYABRw0CIAkNACAFLQADQcABcUGAAUcNAgsgBCECIANBAWoiAyAHSQ0ACwsgACACNgIIAn8CQCABRQ0AAkAgAUECRw0AIAJBA0cNAEECIQIgAEECNgIICyABIAJGDQBBBSACQQFHDQEaCyACCwtIAgJ+An8jAEEQayIEIAE2AgxCASAArYYhAgNAIAQgAUEEaiIANgIMIAIiA0IBIAEoAgAiBa2GhCECIAAhASAFQX9KDQALIAMLhwUBB38CQAJAIABFBEBBxRQhAiABRQ0BIAFBADYCAEHFFA8LIAJBwABxDQEgACgCCEUEQCAAQQAQIxoLIAAoAgghBAJAIAJBgAFxBEAgBEEBa0ECTw0BDAMLIARBBEcNAgsCQCAAKAIMIgINACAAAn8gACgCACEIIABBEGohCUEAIQICQAJAAkACQCAALwEEIgUEQEEBIQQgBUEBcSEHIAVBAUcNAQwCCyAJRQ0CIAlBADYCAEEADAQLIAVBfnEhBgNAIARBAUECQQMgAiAIai0AAEEBdEHQFGovAQAiCkGAEEkbIApBgAFJG2pBAUECQQMgCCACQQFyai0AAEEBdEHQFGovAQAiBEGAEEkbIARBgAFJG2ohBCACQQJqIQIgBkECayIGDQALCwJ/IAcEQCAEQQFBAkEDIAIgCGotAABBAXRB0BRqLwEAIgJBgBBJGyACQYABSRtqIQQLIAQLEAkiB0UNASAFQQEgBUEBSxshCkEAIQVBACEGA0AgBSAHaiEDAn8gBiAIai0AAEEBdEHQFGovAQAiAkH/AE0EQCADIAI6AAAgBUEBagwBCyACQf8PTQRAIAMgAkE/cUGAAXI6AAEgAyACQQZ2QcABcjoAACAFQQJqDAELIAMgAkE/cUGAAXI6AAIgAyACQQx2QeABcjoAACADIAJBBnZBP3FBgAFyOgABIAVBA2oLIQUgBkEBaiIGIApHDQALIAcgBEEBayICakEAOgAAIAlFDQAgCSACNgIACyAHDAELIAMEQCADQQA2AgQgA0EONgIAC0EACyICNgIMIAINAEEADwsgAUUNACABIAAoAhA2AgALIAIPCyABBEAgASAALwEENgIACyAAKAIAC4MBAQR/QRIhBQJAAkAgACkDMCABWA0AIAGnIQYgACgCQCEEIAJBCHEiB0UEQCAEIAZBBHRqKAIEIgINAgsgBCAGQQR0aiIEKAIAIgJFDQAgBC0ADEUNAUEXIQUgBw0BC0EAIQIgAyAAQQhqIAMbIgAEQCAAQQA2AgQgACAFNgIACwsgAgtuAQF/IwBBgAJrIgUkAAJAIARBgMAEcQ0AIAIgA0wNACAFIAFB/wFxIAIgA2siAkGAAiACQYACSSIBGxAZIAFFBEADQCAAIAVBgAIQLiACQYACayICQf8BSw0ACwsgACAFIAIQLgsgBUGAAmokAAuBAQEBfyMAQRBrIgQkACACIANsIQICQCAAQSdGBEAgBEEMaiACEIwBIQBBACAEKAIMIAAbIQAMAQsgAUEBIAJBxABqIAARAAAiAUUEQEEAIQAMAQtBwAAgAUE/cWsiACABakHAAEEAIABBBEkbaiIAQQRrIAE2AAALIARBEGokACAAC1IBAn9BhIEBKAIAIgEgAEEDakF8cSICaiEAAkAgAkEAIAAgAU0bDQAgAD8AQRB0SwRAIAAQA0UNAQtBhIEBIAA2AgAgAQ8LQYSEAUEwNgIAQX8LNwAgAEJ/NwMQIABBADYCCCAAQgA3AwAgAEEANgIwIABC/////w83AyggAEIANwMYIABCADcDIAulAQEBf0HYABAJIgFFBEBBAA8LAkAgAARAIAEgAEHYABAHGgwBCyABQgA3AyAgAUEANgIYIAFC/////w83AxAgAUEAOwEMIAFBv4YoNgIIIAFBAToABiABQQA6AAQgAUIANwNIIAFBgIDYjXg2AkQgAUIANwMoIAFCADcDMCABQgA3AzggAUFAa0EAOwEAIAFCADcDUAsgAUEBOgAFIAFBADYCACABC1gCAn4BfwJAAkAgAC0AAEUNACAAKQMQIgMgAq18IgQgA1QNACAEIAApAwhYDQELIABBADoAAA8LIAAoAgQiBUUEQA8LIAAgBDcDECAFIAOnaiABIAIQBxoLlgEBAn8CQAJAIAJFBEAgAacQCSIFRQ0BQRgQCSIEDQIgBRAGDAELIAIhBUEYEAkiBA0BCyADBEAgA0EANgIEIANBDjYCAAtBAA8LIARCADcDECAEIAE3AwggBCAFNgIEIARBAToAACAEIAJFOgABIAAgBSABIAMQZUEASAR/IAQtAAEEQCAEKAIEEAYLIAQQBkEABSAECwubAgEDfyAALQAAQSBxRQRAAkAgASEDAkAgAiAAIgEoAhAiAAR/IAAFAn8gASABLQBKIgBBAWsgAHI6AEogASgCACIAQQhxBEAgASAAQSByNgIAQX8MAQsgAUIANwIEIAEgASgCLCIANgIcIAEgADYCFCABIAAgASgCMGo2AhBBAAsNASABKAIQCyABKAIUIgVrSwRAIAEgAyACIAEoAiQRAAAaDAILAn8gASwAS0F/SgRAIAIhAANAIAIgACIERQ0CGiADIARBAWsiAGotAABBCkcNAAsgASADIAQgASgCJBEAACAESQ0CIAMgBGohAyABKAIUIQUgAiAEawwBCyACCyEAIAUgAyAAEAcaIAEgASgCFCAAajYCFAsLCwvNBQEGfyAAKAIwIgNBhgJrIQYgACgCPCECIAMhAQNAIAAoAkQgAiAAKAJoIgRqayECIAEgBmogBE0EQCAAKAJIIgEgASADaiADEAcaAkAgAyAAKAJsIgFNBEAgACABIANrNgJsDAELIABCADcCbAsgACAAKAJoIANrIgE2AmggACAAKAJYIANrNgJYIAEgACgChC5JBEAgACABNgKELgsgAEH8gAEoAgARAwAgAiADaiECCwJAIAAoAgAiASgCBCIERQ0AIAAoAjwhBSAAIAIgBCACIARJGyICBH8gACgCSCAAKAJoaiAFaiEFIAEgBCACazYCBAJAAkACQAJAIAEoAhwiBCgCFEEBaw4CAQACCyAEQaABaiAFIAEoAgAgAkHcgAEoAgARCAAMAgsgASABKAIwIAUgASgCACACQcSAASgCABEEADYCMAwBCyAFIAEoAgAgAhAHGgsgASABKAIAIAJqNgIAIAEgASgCCCACajYCCCAAKAI8BSAFCyACaiICNgI8AkAgACgChC4iASACakEDSQ0AIAAoAmggAWshAQJAIAAoAnRBgQhPBEAgACAAIAAoAkggAWoiAi0AACACLQABIAAoAnwRAAA2AlQMAQsgAUUNACAAIAFBAWsgACgChAERAgAaCyAAKAKELiAAKAI8IgJBAUZrIgRFDQAgACABIAQgACgCgAERBQAgACAAKAKELiAEazYChC4gACgCPCECCyACQYUCSw0AIAAoAgAoAgRFDQAgACgCMCEBDAELCwJAIAAoAkQiAiAAKAJAIgNNDQAgAAJ/IAAoAjwgACgCaGoiASADSwRAIAAoAkggAWpBACACIAFrIgNBggIgA0GCAkkbIgMQGSABIANqDAELIAFBggJqIgEgA00NASAAKAJIIANqQQAgAiADayICIAEgA2siAyACIANJGyIDEBkgACgCQCADags2AkALC50CAQF/AkAgAAJ/IAAoAqAuIgFBwABGBEAgACgCBCAAKAIQaiAAKQOYLjcAACAAQgA3A5guIAAgACgCEEEIajYCEEEADAELIAFBIE4EQCAAKAIEIAAoAhBqIAApA5guPgAAIAAgAEGcLmo1AgA3A5guIAAgACgCEEEEajYCECAAIAAoAqAuQSBrIgE2AqAuCyABQRBOBEAgACgCBCAAKAIQaiAAKQOYLj0AACAAIAAoAhBBAmo2AhAgACAAKQOYLkIQiDcDmC4gACAAKAKgLkEQayIBNgKgLgsgAUEISA0BIAAgACgCECIBQQFqNgIQ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KAJUIgEEfyABQQAgARAiEBkgACgCVAVBAAsQBiAAQQA2AlQLC9wMAgl/AX4jAEFAaiIGJAACQAJAAkACQAJAIAEoAjBBABAjIgVBAkZBACABKAI4QQAQIyIEQQFGGw0AIAVBAUZBACAEQQJGGw0AIAVBAkciAw0BIARBAkcNAQsgASABLwEMQYAQcjsBDEEAIQMMAQsgASABLwEMQf/vA3E7AQxBACEFIANFBEBB9eABIAEoAjAgAEEIahBpIgVFDQILIAJBgAJxBEAgBSEDDAELIARBAkcEQCAFIQMMAQtB9cYBIAEoAjggAEEIahBpIgNFBEAgBRAcDAILIAMgBTYCAAsgASABLwEMQf7/A3EgAS8BUiIFQQBHcjsBDAJAAkACQAJAAn8CQAJAIAEpAyhC/v///w9WDQAgASkDIEL+////D1YNACACQYAEcUUNASABKQNIQv////8PVA0BCyAFQYECa0H//wNxQQNJIQdBAQwBCyAFQYECa0H//wNxIQQgAkGACnFBgApHDQEgBEEDSSEHQQALIQkgBkIcEBciBEUEQCAAQQhqIgAEQCAAQQA2AgQgAEEONgIACyADEBwMBQsgAkGACHEhBQJAAkAgAkGAAnEEQAJAIAUNACABKQMgQv////8PVg0AIAEpAyhCgICAgBBUDQMLIAQgASkDKBAYIAEpAyAhDAwBCwJAAkACQCAFDQAgASkDIEL/////D1YNACABKQMoIgxC/////w9WDQEgASkDSEKAgICAEFQNBAsgASkDKCIMQv////8PVA0BCyAEIAwQGAsgASkDICIMQv////8PWgRAIAQgDBAYCyABKQNIIgxC/////w9UDQELIAQgDBAYCyAELQAARQRAIABBCGoiAARAIABBADYCBCAAQRQ2AgALIAQQCCADEBwMBQtBASEKQQEgBC0AAAR+IAQpAxAFQgALp0H//wNxIAYQRyEFIAQQCCAFIAM2AgAgBw0BDAILIAMhBSAEQQJLDQELIAZCBxAXIgRFBEAgAEEIaiIABEAgAEEANgIEIABBDjYCAAsgBRAcDAMLIARBAhANIARBhxJBAhAsIAQgAS0AUhBwIAQgAS8BEBANIAQtAABFBEAgAEEIaiIABEAgAEEANgIEIABBFDYCAAsgBBAIDAILQYGyAkEHIAYQRyEDIAQQCCADIAU2AgBBASELIAMhBQsgBkIuEBciA0UEQCAAQQhqIgAEQCAAQQA2AgQgAEEONgIACyAFEBwMAgsgA0GjEkGoEiACQYACcSIHG0EEECwgB0UEQCADIAkEf0EtBSABLwEIC0H//wNxEA0LIAMgCQR/QS0FIAEvAQoLQf//A3EQDSADIAEvAQwQDSADIAsEf0HjAAUgASgCEAtB//8DcRANIAYgASgCFDYCPAJ/IAZBPGoQjQEiCEUEQEEAIQlBIQwBCwJ/IAgoAhQiBEHQAE4EQCAEQQl0DAELIAhB0AA2AhRBgMACCyEEIAgoAgRBBXQgCCgCCEELdGogCCgCAEEBdmohCSAIKAIMIAQgCCgCEEEFdGpqQaDAAWoLIQQgAyAJQf//A3EQDSADIARB//8DcRANIAMCfyALBEBBACABKQMoQhRUDQEaCyABKAIYCxASIAEpAyAhDCADAn8gAwJ/AkAgBwRAIAxC/v///w9YBEAgASkDKEL/////D1QNAgsgA0F/EBJBfwwDC0F/IAxC/v///w9WDQEaCyAMpwsQEiABKQMoIgxC/////w8gDEL/////D1QbpwsQEiADIAEoAjAiBAR/IAQvAQQFQQALQf//A3EQDSADIAEoAjQgAhBsIAVBgAYQbGpB//8DcRANIAdFBEAgAyABKAI4IgQEfyAELwEEBUEAC0H//wNxEA0gAyABLwE8EA0gAyABLwFAEA0gAyABKAJEEBIgAyABKQNIIgxC/////w8gDEL/////D1QbpxASCyADLQAARQRAIABBCGoiAARAIABBADYCBCAAQRQ2AgALIAMQCCAFEBwMAgsgACAGIAMtAAAEfiADKQMQBUIACxAbIQQgAxAIIARBf0wNACABKAIwIgMEQCAAIAMQYUF/TA0BCyAFBEAgACAFQYAGEGtBf0wNAQsgBRAcIAEoAjQiBQRAIAAgBSACEGtBAEgNAgsgBw0CIAEoAjgiAUUNAiAAIAEQYUEATg0CDAELIAUQHAtBfyEKCyAGQUBrJAAgCgtNAQJ/IAEtAAAhAgJAIAAtAAAiA0UNACACIANHDQADQCABLQABIQIgAC0AASIDRQ0BIAFBAWohASAAQQFqIQAgAiADRg0ACwsgAyACawvcAwICfgF/IAOtIQQgACkDmC4hBQJAIAACfyAAAn4gACgCoC4iBkEDaiIDQT9NBEAgBCAGrYYgBYQMAQsgBkHAAEYEQCAAKAIEIAAoAhBqIAU3AAAgACgCEEEIagwCCyAAKAIEIAAoAhBqIAQgBq2GIAWENwAAIAAgACgCEEEIajYCECAGQT1rIQMgBEHAACAGa62ICyIENwOYLiAAIAM2AqAuIANBOU4EQCAAKAIEIAAoAhBqIAQ3AAAgACAAKAIQQQhqNgIQDAILIANBGU4EQCAAKAIEIAAoAhBqIAQ+AAAgACAAKAIQQQRqNgIQIAAgACkDmC5CIIgiBDcDmC4gACAAKAKgLkEgayIDNgKgLgsgA0EJTgR/IAAoAgQgACgCEGogBD0AACAAIAAoAhBBAmo2AhAgACkDmC5CEIghBCAAKAKgLkEQawUgAwtBAUgNASAAKAIQCyIDQQFqNgIQIAAoAgQgA2ogBDwAAAsgAEEANgKgLiAAQgA3A5guIAAoAgQgACgCEGogAjsAACAAIAAoAhBBAmoiAzYCECAAKAIEIANqIAJBf3M7AAAgACAAKAIQQQJqIgM2AhAgAgRAIAAoAgQgA2ogASACEAcaIAAgACgCECACajYCEAsLrAQCAX8BfgJAIAANACABUA0AIAMEQCADQQA2AgQgA0ESNgIAC0EADwsCQAJAIAAgASACIAMQiQEiBEUNAEEYEAkiAkUEQCADBEAgA0EANgIEIANBDjYCAAsCQCAEKAIoIgBFBEAgBCkDGCEBDAELIABBADYCKCAEKAIoQgA3AyAgBCAEKQMYIgUgBCkDICIBIAEgBVQbIgE3AxgLIAQpAwggAVYEQANAIAQoAgAgAadBBHRqKAIAEAYgAUIBfCIBIAQpAwhUDQALCyAEKAIAEAYgBCgCBBAGIAQQBgwBCyACQQA2AhQgAiAENgIQIAJBABABNgIMIAJBADYCCCACQgA3AgACf0E4EAkiAEUEQCADBEAgA0EANgIEIANBDjYCAAtBAAwBCyAAQQA2AgggAEIANwMAIABCADcDICAAQoCAgIAQNwIsIABBADoAKCAAQQA2AhQgAEIANwIMIABBADsBNCAAIAI2AgggAEEkNgIEIABCPyACQQBCAEEOQSQRDAAiASABQgBTGzcDGCAACyIADQEgAigCECIDBEACQCADKAIoIgBFBEAgAykDGCEBDAELIABBADYCKCADKAIoQgA3AyAgAyADKQMYIgUgAykDICIBIAEgBVQbIgE3AxgLIAMpAwggAVYEQANAIAMoAgAgAadBBHRqKAIAEAYgAUIBfCIBIAMpAwhUDQALCyADKAIAEAYgAygCBBAGIAMQBgsgAhAGC0EAIQALIAALiwwBBn8gACABaiEFAkACQCAAKAIEIgJBAXENACACQQNxRQ0BIAAoAgAiAiABaiEBAkAgACACayIAQciEASgCAEcEQCACQf8BTQRAIAAoAggiBCACQQN2IgJBA3RB3IQBakYaIAAoAgwiAyAERw0CQbSEAUG0hAEoAgBBfiACd3E2AgAMAwsgACgCGCEGAkAgACAAKAIMIgNHBEAgACgCCCICQcSEASgCAEkaIAIgAzYCDCADIAI2AggMAQsCQCAAQRRqIgIoAgAiBA0AIABBEGoiAigCACIEDQBBACEDDAELA0AgAiEHIAQiA0EUaiICKAIAIgQNACADQRBqIQIgAygCECIEDQALIAdBADYCAAsgBkUNAgJAIAAgACgCHCIEQQJ0QeSGAWoiAigCAEYEQCACIAM2AgAgAw0BQbiEAUG4hAEoAgBBfiAEd3E2AgAMBAsgBkEQQRQgBigCECAARhtqIAM2AgAgA0UNAwsgAyAGNgIYIAAoAhAiAgRAIAMgAjYCECACIAM2AhgLIAAoAhQiAkUNAiADIAI2AhQgAiADNgIYDAILIAUoAgQiAkEDcUEDRw0BQbyEASABNgIAIAUgAkF+cTYCBCAAIAFBAXI2AgQgBSABNgIADwsgBCADNgIMIAMgBDYCCAsCQCAFKAIEIgJBAnFFBEAgBUHMhAEoAgBGBEBBzIQBIAA2AgBBwIQBQcCEASgCACABaiIBNgIAIAAgAUEBcjYCBCAAQciEASgCAEcNA0G8hAFBADYCAEHIhAFBADYCAA8LIAVByIQBKAIARgRAQciEASAANgIAQbyEAUG8hAEoAgAgAWoiATYCACAAIAFBAXI2AgQgACABaiABNgIADwsgAkF4cSABaiEBAkAgAkH/AU0EQCAFKAIIIgQgAkEDdiICQQN0QdyEAWpGGiAEIAUoAgwiA0YEQEG0hAFBtIQBKAIAQX4gAndxNgIADAILIAQgAzYCDCADIAQ2AggMAQsgBSgCGCEGAkAgBSAFKAIMIgNHBEAgBSgCCCICQcSEASgCAEkaIAIgAzYCDCADIAI2AggMAQsCQCAFQRRqIgQoAgAiAg0AIAVBEGoiBCgCACICDQBBACEDDAELA0AgBCEHIAIiA0EUaiIEKAIAIgINACADQRBqIQQgAygCECICDQALIAdBADYCAAsgBkUNAAJAIAUgBSgCHCIEQQJ0QeSGAWoiAigCAEYEQCACIAM2AgAgAw0BQbiEAUG4hAEoAgBBfiAEd3E2AgAMAgsgBkEQQRQgBigCECAFRhtqIAM2AgAgA0UNAQsgAyAGNgIYIAUoAhAiAgRAIAMgAjYCECACIAM2AhgLIAUoAhQiAkUNACADIAI2AhQgAiADNgIYCyAAIAFBAXI2AgQgACABaiABNgIAIABByIQBKAIARw0BQbyEASABNgIADwsgBSACQX5xNgIEIAAgAUEBcjYCBCAAIAFqIAE2AgALIAFB/wFNBEAgAUEDdiICQQN0QdyEAWohAQJ/QbSEASgCACIDQQEgAnQiAnFFBEBBtIQBIAIgA3I2AgAgAQwBCyABKAIICyECIAEgADYCCCACIAA2AgwgACABNgIMIAAgAjYCCA8LQR8hAiAAQgA3AhAgAUH///8HTQRAIAFBCHYiAiACQYD+P2pBEHZBCHEiBHQiAiACQYDgH2pBEHZBBHEiA3QiAiACQYCAD2pBEHZBAnEiAnRBD3YgAyAEciACcmsiAkEBdCABIAJBFWp2QQFxckEcaiECCyAAIAI2AhwgAkECdEHkhgFqIQcCQAJAQbiEASgCACIEQQEgAnQiA3FFBEBBuIQBIAMgBHI2AgAgByAANgIAIAAgBzYCGAwBCyABQQBBGSACQQF2ayACQR9GG3QhAiAHKAIAIQMDQCADIgQoAgRBeHEgAUYNAiACQR12IQMgAkEBdCECIAQgA0EEcWoiB0EQaigCACIDDQALIAcgADYCECAAIAQ2AhgLIAAgADYCDCAAIAA2AggPCyAEKAIIIgEgADYCDCAEIAA2AgggAEEANgIYIAAgBDYCDCAAIAE2AggLC1gCAX8BfgJAAn9BACAARQ0AGiAArUIChiICpyIBIABBBHJBgIAESQ0AGkF/IAEgAkIgiKcbCyIBEAkiAEUNACAAQQRrLQAAQQNxRQ0AIABBACABEBkLIAALQwEDfwJAIAJFDQADQCAALQAAIgQgAS0AACIFRgRAIAFBAWohASAAQQFqIQAgAkEBayICDQEMAgsLIAQgBWshAwsgAwsUACAAEEAgACgCABAgIAAoAgQQIAutBAIBfgV/IwBBEGsiBCQAIAAgAWshBgJAAkAgAUEBRgRAIAAgBi0AACACEBkMAQsgAUEJTwRAIAAgBikAADcAACAAIAJBAWtBB3FBAWoiBWohACACIAVrIgFFDQIgBSAGaiECA0AgACACKQAANwAAIAJBCGohAiAAQQhqIQAgAUEIayIBDQALDAILAkACQAJAAkAgAUEEaw4FAAICAgECCyAEIAYoAAAiATYCBCAEIAE2AgAMAgsgBCAGKQAANwMADAELQQghByAEQQhqIQgDQCAIIAYgByABIAEgB0sbIgUQByAFaiEIIAcgBWsiBw0ACyAEIAQpAwg3AwALAkAgBQ0AIAJBEEkNACAEKQMAIQMgAkEQayIGQQR2QQFqQQdxIgEEQANAIAAgAzcACCAAIAM3AAAgAkEQayECIABBEGohACABQQFrIgENAAsLIAZB8ABJDQADQCAAIAM3AHggACADNwBwIAAgAzcAaCAAIAM3AGAgACADNwBYIAAgAzcAUCAAIAM3AEggACADNwBAIAAgAzcAOCAAIAM3ADAgACADNwAoIAAgAzcAICAAIAM3ABggACADNwAQIAAgAzcACCAAIAM3AAAgAEGAAWohACACQYABayICQQ9LDQALCyACQQhPBEBBCCAFayEBA0AgACAEKQMANwAAIAAgAWohACACIAFrIgJBB0sNAAsLIAJFDQEgACAEIAIQBxoLIAAgAmohAAsgBEEQaiQAIAALXwECfyAAKAIIIgEEQCABEAsgAEEANgIICwJAIAAoAgQiAUUNACABKAIAIgJBAXFFDQAgASgCEEF+Rw0AIAEgAkF+cSICNgIAIAINACABECAgAEEANgIECyAAQQA6AAwL1wICBH8BfgJAAkAgACgCQCABp0EEdGooAgAiA0UEQCACBEAgAkEANgIEIAJBFDYCAAsMAQsgACgCACADKQNIIgdBABAUIQMgACgCACEAIANBf0wEQCACBEAgAiAAKAIMNgIAIAIgACgCEDYCBAsMAQtCACEBIwBBEGsiBiQAQX8hAwJAIABCGkEBEBRBf0wEQCACBEAgAiAAKAIMNgIAIAIgACgCEDYCBAsMAQsgAEIEIAZBCmogAhAtIgRFDQBBHiEAQQEhBQNAIAQQDCAAaiEAIAVBAkcEQCAFQQFqIQUMAQsLIAQtAAAEfyAEKQMQIAQpAwhRBUEAC0UEQCACBEAgAkEANgIEIAJBFDYCAAsgBBAIDAELIAQQCCAAIQMLIAZBEGokACADIgBBAEgNASAHIACtfCIBQn9VDQEgAgRAIAJBFjYCBCACQQQ2AgALC0IAIQELIAELYAIBfgF/AkAgAEUNACAAQQhqEF8iAEUNACABIAEoAjBBAWo2AjAgACADNgIIIAAgAjYCBCAAIAE2AgAgAEI/IAEgA0EAQgBBDiACEQoAIgQgBEIAUxs3AxggACEFCyAFCyIAIAAoAiRBAWtBAU0EQCAAQQBCAEEKEA4aIABBADYCJAsLbgACQAJAAkAgA0IQVA0AIAJFDQECfgJAAkACQCACKAIIDgMCAAEECyACKQMAIAB8DAILIAIpAwAgAXwMAQsgAikDAAsiA0IAUw0AIAEgA1oNAgsgBARAIARBADYCBCAEQRI2AgALC0J/IQMLIAMLggICAX8CfgJAQQEgAiADGwRAIAIgA2oQCSIFRQRAIAQEQCAEQQA2AgQgBEEONgIAC0EADwsgAq0hBgJAAkAgAARAIAAgBhATIgBFBEAgBARAIARBADYCBCAEQQ42AgALDAULIAUgACACEAcaIAMNAQwCCyABIAUgBhARIgdCf1cEQCAEBEAgBCABKAIMNgIAIAQgASgCEDYCBAsMBAsgBiAHVQRAIAQEQCAEQQA2AgQgBEERNgIACwwECyADRQ0BCyACIAVqIgBBADoAACACQQFIDQAgBSECA0AgAi0AAEUEQCACQSA6AAALIAJBAWoiAiAASQ0ACwsLIAUPCyAFEAZBAAuBAQEBfwJAIAAEQCADQYAGcSEFQQAhAwNAAkAgAC8BCCACRw0AIAUgACgCBHFFDQAgA0EATg0DIANBAWohAwsgACgCACIADQALCyAEBEAgBEEANgIEIARBCTYCAAtBAA8LIAEEQCABIAAvAQo7AQALIAAvAQpFBEBBwBQPCyAAKAIMC1cBAX9BEBAJIgNFBEBBAA8LIAMgATsBCiADIAA7AQggA0GABjYCBCADQQA2AgACQCABBEAgAyACIAEQYyIANgIMIAANASADEAZBAA8LIANBADYCDAsgAwvuBQIEfwV+IwBB4ABrIgQkACAEQQhqIgNCADcDICADQQA2AhggA0L/////DzcDECADQQA7AQwgA0G/hig2AgggA0EBOgAGIANBADsBBCADQQA2AgAgA0IANwNIIANBgIDYjXg2AkQgA0IANwMoIANCADcDMCADQgA3AzggA0FAa0EAOwEAIANCADcDUCABKQMIUCIDRQRAIAEoAgAoAgApA0ghBwsCfgJAIAMEQCAHIQkMAQsgByEJA0AgCqdBBHQiBSABKAIAaigCACIDKQNIIgggCSAIIAlUGyIJIAEpAyBWBEAgAgRAIAJBADYCBCACQRM2AgALQn8MAwsgAygCMCIGBH8gBi8BBAVBAAtB//8Dca0gCCADKQMgfHxCHnwiCCAHIAcgCFQbIgcgASkDIFYEQCACBEAgAkEANgIEIAJBEzYCAAtCfwwDCyAAKAIAIAEoAgAgBWooAgApA0hBABAUIQYgACgCACEDIAZBf0wEQCACBEAgAiADKAIMNgIAIAIgAygCEDYCBAtCfwwDCyAEQQhqIANBAEEBIAIQaEJ/UQRAIARBCGoQNkJ/DAMLAkACQCABKAIAIAVqKAIAIgMvAQogBC8BEkkNACADKAIQIAQoAhhHDQAgAygCFCAEKAIcRw0AIAMoAjAgBCgCOBBiRQ0AAkAgBCgCICIGIAMoAhhHBEAgBCkDKCEIDAELIAMpAyAiCyAEKQMoIghSDQAgCyEIIAMpAyggBCkDMFENAgsgBC0AFEEIcUUNACAGDQAgCEIAUg0AIAQpAzBQDQELIAIEQCACQQA2AgQgAkEVNgIACyAEQQhqEDZCfwwDCyABKAIAIAVqKAIAKAI0IAQoAjwQbyEDIAEoAgAgBWooAgAiBUEBOgAEIAUgAzYCNCAEQQA2AjwgBEEIahA2IApCAXwiCiABKQMIVA0ACwsgByAJfSIHQv///////////wAgB0L///////////8AVBsLIQcgBEHgAGokACAHC8YBAQJ/QdgAEAkiAUUEQCAABEAgAEEANgIEIABBDjYCAAtBAA8LIAECf0EYEAkiAkUEQCAABEAgAEEANgIEIABBDjYCAAtBAAwBCyACQQA2AhAgAkIANwMIIAJBADYCACACCyIANgJQIABFBEAgARAGQQAPCyABQgA3AwAgAUEANgIQIAFCADcCCCABQgA3AhQgAUEANgJUIAFCADcCHCABQgA3ACEgAUIANwMwIAFCADcDOCABQUBrQgA3AwAgAUIANwNIIAELgBMCD38CfiMAQdAAayIFJAAgBSABNgJMIAVBN2ohEyAFQThqIRBBACEBA0ACQCAOQQBIDQBB/////wcgDmsgAUgEQEGEhAFBPTYCAEF/IQ4MAQsgASAOaiEOCyAFKAJMIgchAQJAAkACQAJAAkACQAJAAkAgBQJ/AkAgBy0AACIGBEADQAJAAkAgBkH/AXEiBkUEQCABIQYMAQsgBkElRw0BIAEhBgNAIAEtAAFBJUcNASAFIAFBAmoiCDYCTCAGQQFqIQYgAS0AAiEMIAghASAMQSVGDQALCyAGIAdrIQEgAARAIAAgByABEC4LIAENDSAFKAJMIQEgBSgCTCwAAUEwa0EKTw0DIAEtAAJBJEcNAyABLAABQTBrIQ9BASERIAFBA2oMBAsgBSABQQFqIgg2AkwgAS0AASEGIAghAQwACwALIA4hDSAADQggEUUNAkEBIQEDQCAEIAFBAnRqKAIAIgAEQCADIAFBA3RqIAAgAhB4QQEhDSABQQFqIgFBCkcNAQwKCwtBASENIAFBCk8NCANAIAQgAUECdGooAgANCCABQQFqIgFBCkcNAAsMCAtBfyEPIAFBAWoLIgE2AkxBACEIAkAgASwAACIKQSBrIgZBH0sNAEEBIAZ0IgZBidEEcUUNAANAAkAgBSABQQFqIgg2AkwgASwAASIKQSBrIgFBIE8NAEEBIAF0IgFBidEEcUUNACABIAZyIQYgCCEBDAELCyAIIQEgBiEICwJAIApBKkYEQCAFAn8CQCABLAABQTBrQQpPDQAgBSgCTCIBLQACQSRHDQAgASwAAUECdCAEakHAAWtBCjYCACABLAABQQN0IANqQYADaygCACELQQEhESABQQNqDAELIBENCEEAIRFBACELIAAEQCACIAIoAgAiAUEEajYCACABKAIAIQsLIAUoAkxBAWoLIgE2AkwgC0F/Sg0BQQAgC2shCyAIQYDAAHIhCAwBCyAFQcwAahB3IgtBAEgNBiAFKAJMIQELQX8hCQJAIAEtAABBLkcNACABLQABQSpGBEACQCABLAACQTBrQQpPDQAgBSgCTCIBLQADQSRHDQAgASwAAkECdCAEakHAAWtBCjYCACABLAACQQN0IANqQYADaygCACEJIAUgAUEEaiIBNgJMDAILIBENByAABH8gAiACKAIAIgFBBGo2AgAgASgCAAVBAAshCSAFIAUoAkxBAmoiATYCTAwBCyAFIAFBAWo2AkwgBUHMAGoQdyEJIAUoAkwhAQtBACEGA0AgBiESQX8hDSABLAAAQcEAa0E5Sw0HIAUgAUEBaiIKNgJMIAEsAAAhBiAKIQEgBiASQTpsakGf7ABqLQAAIgZBAWtBCEkNAAsgBkETRg0CIAZFDQYgD0EATgRAIAQgD0ECdGogBjYCACAFIAMgD0EDdGopAwA3A0AMBAsgAA0BC0EAIQ0MBQsgBUFAayAGIAIQeCAFKAJMIQoMAgsgD0F/Sg0DC0EAIQEgAEUNBAsgCEH//3txIgwgCCAIQYDAAHEbIQZBACENQaQIIQ8gECEIAkACQAJAAn8CQAJAAkACQAJ/AkACQAJAAkACQAJAAkAgCkEBaywAACIBQV9xIAEgAUEPcUEDRhsgASASGyIBQdgAaw4hBBISEhISEhISDhIPBg4ODhIGEhISEgIFAxISCRIBEhIEAAsCQCABQcEAaw4HDhILEg4ODgALIAFB0wBGDQkMEQsgBSkDQCEUQaQIDAULQQAhAQJAAkACQAJAAkACQAJAIBJB/wFxDggAAQIDBBcFBhcLIAUoAkAgDjYCAAwWCyAFKAJAIA42AgAMFQsgBSgCQCAOrDcDAAwUCyAFKAJAIA47AQAMEwsgBSgCQCAOOgAADBILIAUoAkAgDjYCAAwRCyAFKAJAIA6sNwMADBALIAlBCCAJQQhLGyEJIAZBCHIhBkH4ACEBCyAQIQcgAUEgcSEMIAUpA0AiFFBFBEADQCAHQQFrIgcgFKdBD3FBsPAAai0AACAMcjoAACAUQg9WIQogFEIEiCEUIAoNAAsLIAUpA0BQDQMgBkEIcUUNAyABQQR2QaQIaiEPQQIhDQwDCyAQIQEgBSkDQCIUUEUEQANAIAFBAWsiASAUp0EHcUEwcjoAACAUQgdWIQcgFEIDiCEUIAcNAAsLIAEhByAGQQhxRQ0CIAkgECAHayIBQQFqIAEgCUgbIQkMAgsgBSkDQCIUQn9XBEAgBUIAIBR9IhQ3A0BBASENQaQIDAELIAZBgBBxBEBBASENQaUIDAELQaYIQaQIIAZBAXEiDRsLIQ8gECEBAkAgFEKAgICAEFQEQCAUIRUMAQsDQCABQQFrIgEgFCAUQgqAIhVCCn59p0EwcjoAACAUQv////+fAVYhByAVIRQgBw0ACwsgFaciBwRAA0AgAUEBayIBIAcgB0EKbiIMQQpsa0EwcjoAACAHQQlLIQogDCEHIAoNAAsLIAEhBwsgBkH//3txIAYgCUF/ShshBgJAIAUpA0AiFEIAUg0AIAkNAEEAIQkgECEHDAoLIAkgFFAgECAHa2oiASABIAlIGyEJDAkLIAUoAkAiAUGKEiABGyIHQQAgCRB6IgEgByAJaiABGyEIIAwhBiABIAdrIAkgARshCQwICyAJBEAgBSgCQAwCC0EAIQEgAEEgIAtBACAGECcMAgsgBUEANgIMIAUgBSkDQD4CCCAFIAVBCGo2AkBBfyEJIAVBCGoLIQhBACEBAkADQCAIKAIAIgdFDQECQCAFQQRqIAcQeSIHQQBIIgwNACAHIAkgAWtLDQAgCEEEaiEIIAkgASAHaiIBSw0BDAILC0F/IQ0gDA0FCyAAQSAgCyABIAYQJyABRQRAQQAhAQwBC0EAIQggBSgCQCEKA0AgCigCACIHRQ0BIAVBBGogBxB5IgcgCGoiCCABSg0BIAAgBUEEaiAHEC4gCkEEaiEKIAEgCEsNAAsLIABBICALIAEgBkGAwABzECcgCyABIAEgC0gbIQEMBQsgACAFKwNAIAsgCSAGIAFBABEdACEBDAQLIAUgBSkDQDwAN0EBIQkgEyEHIAwhBgwCC0F/IQ0LIAVB0ABqJAAgDQ8LIABBICANIAggB2siDCAJIAkgDEgbIgpqIgggCyAIIAtKGyIBIAggBhAnIAAgDyANEC4gAEEwIAEgCCAGQYCABHMQJyAAQTAgCiAMQQAQJyAAIAcgDBAuIABBICABIAggBkGAwABzECcMAAsAC54DAgR/AX4gAARAIAAoAgAiAQRAIAEQGhogACgCABALCyAAKAIcEAYgACgCIBAQIAAoAiQQECAAKAJQIgMEQCADKAIQIgIEQCADKAIAIgEEfwNAIAIgBEECdGooAgAiAgRAA0AgAigCGCEBIAIQBiABIgINAAsgAygCACEBCyABIARBAWoiBEsEQCADKAIQIQIMAQsLIAMoAhAFIAILEAYLIAMQBgsgACgCQCIBBEAgACkDMFAEfyABBSABED5CAiEFAkAgACkDMEICVA0AQQEhAgNAIAAoAkAgAkEEdGoQPiAFIAApAzBaDQEgBachAiAFQgF8IQUMAAsACyAAKAJACxAGCwJAIAAoAkRFDQBBACECQgEhBQNAIAAoAkwgAkECdGooAgAiAUEBOgAoIAFBDGoiASgCAEUEQCABBEAgAUEANgIEIAFBCDYCAAsLIAUgADUCRFoNASAFpyECIAVCAXwhBQwACwALIAAoAkwQBiAAKAJUIgIEQCACKAIIIgEEQCACKAIMIAERAwALIAIQBgsgAEEIahAxIAAQBgsL6gMCAX4EfwJAIAAEfiABRQRAIAMEQCADQQA2AgQgA0ESNgIAC0J/DwsgAkGDIHEEQAJAIAApAzBQDQBBPEE9IAJBAXEbIQcgAkECcUUEQANAIAAgBCACIAMQUyIFBEAgASAFIAcRAgBFDQYLIARCAXwiBCAAKQMwVA0ADAILAAsDQCAAIAQgAiADEFMiBQRAIAECfyAFECJBAWohBgNAQQAgBkUNARogBSAGQQFrIgZqIggtAABBL0cNAAsgCAsiBkEBaiAFIAYbIAcRAgBFDQULIARCAXwiBCAAKQMwVA0ACwsgAwRAIANBADYCBCADQQk2AgALQn8PC0ESIQYCQAJAIAAoAlAiBUUNACABRQ0AQQkhBiAFKQMIUA0AIAUoAhAgAS0AACIHBH9CpesKIQQgASEAA0AgBCAHrUL/AYN8IQQgAC0AASIHBEAgAEEBaiEAIARC/////w+DQiF+IQQMAQsLIASnBUGFKgsgBSgCAHBBAnRqKAIAIgBFDQADQCABIAAoAgAQOEUEQCACQQhxBEAgACkDCCIEQn9RDQMMBAsgACkDECIEQn9RDQIMAwsgACgCGCIADQALCyADBEAgA0EANgIEIAMgBjYCAAtCfyEECyAEBUJ/Cw8LIAMEQCADQgA3AgALIAQL3AQCB38BfgJAAkAgAEUNACABRQ0AIAJCf1UNAQsgBARAIARBADYCBCAEQRI2AgALQQAPCwJAIAAoAgAiB0UEQEGAAiEHQYACEDwiBkUNASAAKAIQEAYgAEGAAjYCACAAIAY2AhALAkACQCAAKAIQIAEtAAAiBQR/QqXrCiEMIAEhBgNAIAwgBa1C/wGDfCEMIAYtAAEiBQRAIAZBAWohBiAMQv////8Pg0IhfiEMDAELCyAMpwVBhSoLIgYgB3BBAnRqIggoAgAiBQRAA0ACQCAFKAIcIAZHDQAgASAFKAIAEDgNAAJAIANBCHEEQCAFKQMIQn9SDQELIAUpAxBCf1ENBAsgBARAIARBADYCBCAEQQo2AgALQQAPCyAFKAIYIgUNAAsLQSAQCSIFRQ0CIAUgATYCACAFIAgoAgA2AhggCCAFNgIAIAVCfzcDCCAFIAY2AhwgACAAKQMIQgF8Igw3AwggDLogB7hEAAAAAAAA6D+iZEUNACAHQQBIDQAgByAHQQF0IghGDQAgCBA8IgpFDQECQCAMQgAgBxtQBEAgACgCECEJDAELIAAoAhAhCUEAIQQDQCAJIARBAnRqKAIAIgYEQANAIAYoAhghASAGIAogBigCHCAIcEECdGoiCygCADYCGCALIAY2AgAgASIGDQALCyAEQQFqIgQgB0cNAAsLIAkQBiAAIAg2AgAgACAKNgIQCyADQQhxBEAgBSACNwMICyAFIAI3AxBBAQ8LIAQEQCAEQQA2AgQgBEEONgIAC0EADwsgBARAIARBADYCBCAEQQ42AgALQQAL3Q8BF38jAEFAaiIHQgA3AzAgB0IANwM4IAdCADcDICAHQgA3AygCQAJAAkACQAJAIAIEQCACQQNxIQggAkEBa0EDTwRAIAJBfHEhBgNAIAdBIGogASAJQQF0IgxqLwEAQQF0aiIKIAovAQBBAWo7AQAgB0EgaiABIAxBAnJqLwEAQQF0aiIKIAovAQBBAWo7AQAgB0EgaiABIAxBBHJqLwEAQQF0aiIKIAovAQBBAWo7AQAgB0EgaiABIAxBBnJqLwEAQQF0aiIKIAovAQBBAWo7AQAgCUEEaiEJIAZBBGsiBg0ACwsgCARAA0AgB0EgaiABIAlBAXRqLwEAQQF0aiIGIAYvAQBBAWo7AQAgCUEBaiEJIAhBAWsiCA0ACwsgBCgCACEJQQ8hCyAHLwE+IhENAgwBCyAEKAIAIQkLQQ4hC0EAIREgBy8BPA0AQQ0hCyAHLwE6DQBBDCELIAcvATgNAEELIQsgBy8BNg0AQQohCyAHLwE0DQBBCSELIAcvATINAEEIIQsgBy8BMA0AQQchCyAHLwEuDQBBBiELIAcvASwNAEEFIQsgBy8BKg0AQQQhCyAHLwEoDQBBAyELIAcvASYNAEECIQsgBy8BJA0AIAcvASJFBEAgAyADKAIAIgBBBGo2AgAgAEHAAjYBACADIAMoAgAiAEEEajYCACAAQcACNgEAQQEhDQwDCyAJQQBHIRtBASELQQEhCQwBCyALIAkgCSALSxshG0EBIQ5BASEJA0AgB0EgaiAJQQF0ai8BAA0BIAlBAWoiCSALRw0ACyALIQkLQX8hCCAHLwEiIg9BAksNAUEEIAcvASQiECAPQQF0amsiBkEASA0BIAZBAXQgBy8BJiISayIGQQBIDQEgBkEBdCAHLwEoIhNrIgZBAEgNASAGQQF0IAcvASoiFGsiBkEASA0BIAZBAXQgBy8BLCIVayIGQQBIDQEgBkEBdCAHLwEuIhZrIgZBAEgNASAGQQF0IAcvATAiF2siBkEASA0BIAZBAXQgBy8BMiIZayIGQQBIDQEgBkEBdCAHLwE0IhxrIgZBAEgNASAGQQF0IAcvATYiDWsiBkEASA0BIAZBAXQgBy8BOCIYayIGQQBIDQEgBkEBdCAHLwE6IgxrIgZBAEgNASAGQQF0IAcvATwiCmsiBkEASA0BIAZBAXQgEWsiBkEASA0BIAZBACAARSAOchsNASAJIBtLIRpBACEIIAdBADsBAiAHIA87AQQgByAPIBBqIgY7AQYgByAGIBJqIgY7AQggByAGIBNqIgY7AQogByAGIBRqIgY7AQwgByAGIBVqIgY7AQ4gByAGIBZqIgY7ARAgByAGIBdqIgY7ARIgByAGIBlqIgY7ARQgByAGIBxqIgY7ARYgByAGIA1qIgY7ARggByAGIBhqIgY7ARogByAGIAxqIgY7ARwgByAGIApqOwEeAkAgAkUNACACQQFHBEAgAkF+cSEGA0AgASAIQQF0ai8BACIKBEAgByAKQQF0aiIKIAovAQAiCkEBajsBACAFIApBAXRqIAg7AQALIAEgCEEBciIMQQF0ai8BACIKBEAgByAKQQF0aiIKIAovAQAiCkEBajsBACAFIApBAXRqIAw7AQALIAhBAmohCCAGQQJrIgYNAAsLIAJBAXFFDQAgASAIQQF0ai8BACICRQ0AIAcgAkEBdGoiAiACLwEAIgJBAWo7AQAgBSACQQF0aiAIOwEACyAJIBsgGhshDUEUIRBBACEWIAUiCiEYQQAhEgJAAkACQCAADgICAAELQQEhCCANQQpLDQNBgQIhEEHw2QAhGEGw2QAhCkEBIRIMAQsgAEECRiEWQQAhEEHw2gAhGEGw2gAhCiAAQQJHBEAMAQtBASEIIA1BCUsNAgtBASANdCITQQFrIRwgAygCACEUQQAhFSANIQZBACEPQQAhDkF/IQIDQEEBIAZ0IRoCQANAIAkgD2shFwJAIAUgFUEBdGovAQAiCCAQTwRAIAogCCAQa0EBdCIAai8BACERIAAgGGotAAAhAAwBC0EAQeAAIAhBAWogEEkiBhshACAIQQAgBhshEQsgDiAPdiEMQX8gF3QhBiAaIQgDQCAUIAYgCGoiCCAMakECdGoiGSAROwECIBkgFzoAASAZIAA6AAAgCA0AC0EBIAlBAWt0IQYDQCAGIgBBAXYhBiAAIA5xDQALIAdBIGogCUEBdGoiBiAGLwEAQQFrIgY7AQAgAEEBayAOcSAAakEAIAAbIQ4gFUEBaiEVIAZB//8DcUUEQCAJIAtGDQIgASAFIBVBAXRqLwEAQQF0ai8BACEJCyAJIA1NDQAgDiAccSIAIAJGDQALQQEgCSAPIA0gDxsiD2siBnQhAiAJIAtJBEAgCyAPayEMIAkhCAJAA0AgAiAHQSBqIAhBAXRqLwEAayICQQFIDQEgAkEBdCECIAZBAWoiBiAPaiIIIAtJDQALIAwhBgtBASAGdCECC0EBIQggEiACIBNqIhNBtApLcQ0DIBYgE0HQBEtxDQMgAygCACICIABBAnRqIgggDToAASAIIAY6AAAgCCAUIBpBAnRqIhQgAmtBAnY7AQIgACECDAELCyAOBEAgFCAOQQJ0aiIAQQA7AQIgACAXOgABIABBwAA6AAALIAMgAygCACATQQJ0ajYCAAsgBCANNgIAQQAhCAsgCAusAQICfgF/IAFBAmqtIQIgACkDmC4hAwJAIAAoAqAuIgFBA2oiBEE/TQRAIAIgAa2GIAOEIQIMAQsgAUHAAEYEQCAAKAIEIAAoAhBqIAM3AAAgACAAKAIQQQhqNgIQQQMhBAwBCyAAKAIEIAAoAhBqIAIgAa2GIAOENwAAIAAgACgCEEEIajYCECABQT1rIQQgAkHAACABa62IIQILIAAgAjcDmC4gACAENgKgLguXAwICfgN/QYDJADMBACECIAApA5guIQMCQCAAKAKgLiIFQYLJAC8BACIGaiIEQT9NBEAgAiAFrYYgA4QhAgwBCyAFQcAARgRAIAAoAgQgACgCEGogAzcAACAAIAAoAhBBCGo2AhAgBiEEDAELIAAoAgQgACgCEGogAiAFrYYgA4Q3AAAgACAAKAIQQQhqNgIQIARBQGohBCACQcAAIAVrrYghAgsgACACNwOYLiAAIAQ2AqAuIAEEQAJAIARBOU4EQCAAKAIEIAAoAhBqIAI3AAAgACAAKAIQQQhqNgIQDAELIARBGU4EQCAAKAIEIAAoAhBqIAI+AAAgACAAKAIQQQRqNgIQIAAgACkDmC5CIIgiAjcDmC4gACAAKAKgLkEgayIENgKgLgsgBEEJTgR/IAAoAgQgACgCEGogAj0AACAAIAAoAhBBAmo2AhAgACkDmC5CEIghAiAAKAKgLkEQawUgBAtBAUgNACAAIAAoAhAiAUEBajYCECABIAAoAgRqIAI8AAALIABBADYCoC4gAEIANwOYLgsL8hQBEn8gASgCCCICKAIAIQUgAigCDCEHIAEoAgAhCCAAQoCAgIDQxwA3A6ApQQAhAgJAAkAgB0EASgRAQX8hDANAAkAgCCACQQJ0aiIDLwEABEAgACAAKAKgKUEBaiIDNgKgKSAAIANBAnRqQawXaiACNgIAIAAgAmpBqClqQQA6AAAgAiEMDAELIANBADsBAgsgAkEBaiICIAdHDQALIABB/C1qIQ8gAEH4LWohESAAKAKgKSIEQQFKDQIMAQsgAEH8LWohDyAAQfgtaiERQX8hDAsDQCAAIARBAWoiAjYCoCkgACACQQJ0akGsF2ogDEEBaiIDQQAgDEECSCIGGyICNgIAIAggAkECdCIEakEBOwEAIAAgAmpBqClqQQA6AAAgACAAKAL4LUEBazYC+C0gBQRAIA8gDygCACAEIAVqLwECazYCAAsgAyAMIAYbIQwgACgCoCkiBEECSA0ACwsgASAMNgIEIARBAXYhBgNAIAAgBkECdGpBrBdqKAIAIQkCQCAGIgJBAXQiAyAESg0AIAggCUECdGohCiAAIAlqQagpaiENIAYhBQNAAkAgAyAETgRAIAMhAgwBCyAIIABBrBdqIgIgA0EBciIEQQJ0aigCACILQQJ0ai8BACIOIAggAiADQQJ0aigCACIQQQJ0ai8BACICTwRAIAIgDkcEQCADIQIMAgsgAyECIABBqClqIgMgC2otAAAgAyAQai0AAEsNAQsgBCECCyAKLwEAIgQgCCAAIAJBAnRqQawXaigCACIDQQJ0ai8BACILSQRAIAUhAgwCCwJAIAQgC0cNACANLQAAIAAgA2pBqClqLQAASw0AIAUhAgwCCyAAIAVBAnRqQawXaiADNgIAIAIhBSACQQF0IgMgACgCoCkiBEwNAAsLIAAgAkECdGpBrBdqIAk2AgAgBkECTgRAIAZBAWshBiAAKAKgKSEEDAELCyAAKAKgKSEDA0AgByEGIAAgA0EBayIENgKgKSAAKAKwFyEKIAAgACADQQJ0akGsF2ooAgAiCTYCsBdBASECAkAgA0EDSA0AIAggCUECdGohDSAAIAlqQagpaiELQQIhA0EBIQUDQAJAIAMgBE4EQCADIQIMAQsgCCAAQawXaiICIANBAXIiB0ECdGooAgAiBEECdGovAQAiDiAIIAIgA0ECdGooAgAiEEECdGovAQAiAk8EQCACIA5HBEAgAyECDAILIAMhAiAAQagpaiIDIARqLQAAIAMgEGotAABLDQELIAchAgsgDS8BACIHIAggACACQQJ0akGsF2ooAgAiA0ECdGovAQAiBEkEQCAFIQIMAgsCQCAEIAdHDQAgCy0AACAAIANqQagpai0AAEsNACAFIQIMAgsgACAFQQJ0akGsF2ogAzYCACACIQUgAkEBdCIDIAAoAqApIgRMDQALC0ECIQMgAEGsF2oiByACQQJ0aiAJNgIAIAAgACgCpClBAWsiBTYCpCkgACgCsBchAiAHIAVBAnRqIAo2AgAgACAAKAKkKUEBayIFNgKkKSAHIAVBAnRqIAI2AgAgCCAGQQJ0aiINIAggAkECdGoiBS8BACAIIApBAnRqIgQvAQBqOwEAIABBqClqIgkgBmoiCyACIAlqLQAAIgIgCSAKai0AACIKIAIgCksbQQFqOgAAIAUgBjsBAiAEIAY7AQIgACAGNgKwF0EBIQVBASECAkAgACgCoCkiBEECSA0AA0AgDS8BACIKIAggAAJ/IAMgAyAETg0AGiAIIAcgA0EBciICQQJ0aigCACIEQQJ0ai8BACIOIAggByADQQJ0aigCACIQQQJ0ai8BACISTwRAIAMgDiASRw0BGiADIAQgCWotAAAgCSAQai0AAEsNARoLIAILIgJBAnRqQawXaigCACIDQQJ0ai8BACIESQRAIAUhAgwCCwJAIAQgCkcNACALLQAAIAAgA2pBqClqLQAASw0AIAUhAgwCCyAAIAVBAnRqQawXaiADNgIAIAIhBSACQQF0IgMgACgCoCkiBEwNAAsLIAZBAWohByAAIAJBAnRqQawXaiAGNgIAIAAoAqApIgNBAUoNAAsgACAAKAKkKUEBayICNgKkKSAAQawXaiIDIAJBAnRqIAAoArAXNgIAIAEoAgQhCSABKAIIIgIoAhAhBiACKAIIIQogAigCBCEQIAIoAgAhDSABKAIAIQcgAEGkF2pCADcBACAAQZwXakIANwEAIABBlBdqQgA3AQAgAEGMF2oiAUIANwEAQQAhBSAHIAMgACgCpClBAnRqKAIAQQJ0akEAOwECAkAgACgCpCkiAkG7BEoNACACQQFqIQIDQCAHIAAgAkECdGpBrBdqKAIAIgRBAnQiEmoiCyAHIAsvAQJBAnRqLwECIgNBAWogBiADIAZJGyIOOwECIAMgBk8hEwJAIAQgCUoNACAAIA5BAXRqQYwXaiIDIAMvAQBBAWo7AQBBACEDIAQgCk4EQCAQIAQgCmtBAnRqKAIAIQMLIBEgESgCACALLwEAIgQgAyAOamxqNgIAIA1FDQAgDyAPKAIAIAMgDSASai8BAmogBGxqNgIACyAFIBNqIQUgAkEBaiICQb0ERw0ACyAFRQ0AIAAgBkEBdGpBjBdqIQQDQCAGIQIDQCAAIAIiA0EBayICQQF0akGMF2oiDy8BACIKRQ0ACyAPIApBAWs7AQAgACADQQF0akGMF2oiAiACLwEAQQJqOwEAIAQgBC8BAEEBayIDOwEAIAVBAkohAiAFQQJrIQUgAg0ACyAGRQ0AQb0EIQIDQCADQf//A3EiBQRAA0AgACACQQFrIgJBAnRqQawXaigCACIDIAlKDQAgByADQQJ0aiIDLwECIAZHBEAgESARKAIAIAYgAy8BAGxqIgQ2AgAgESAEIAMvAQAgAy8BAmxrNgIAIAMgBjsBAgsgBUEBayIFDQALCyAGQQFrIgZFDQEgACAGQQF0akGMF2ovAQAhAwwACwALIwBBIGsiAiABIgAvAQBBAXQiATsBAiACIAEgAC8BAmpBAXQiATsBBCACIAEgAC8BBGpBAXQiATsBBiACIAEgAC8BBmpBAXQiATsBCCACIAEgAC8BCGpBAXQiATsBCiACIAEgAC8BCmpBAXQiATsBDCACIAEgAC8BDGpBAXQiATsBDiACIAEgAC8BDmpBAXQiATsBECACIAEgAC8BEGpBAXQiATsBEiACIAEgAC8BEmpBAXQiATsBFCACIAEgAC8BFGpBAXQiATsBFiACIAEgAC8BFmpBAXQiATsBGCACIAEgAC8BGGpBAXQiATsBGiACIAEgAC8BGmpBAXQiATsBHCACIAAvARwgAWpBAXQ7AR5BACEAIAxBAE4EQANAIAggAEECdGoiAy8BAiIBBEAgAiABQQF0aiIFIAUvAQAiBUEBajsBACADIAWtQoD+A4NCCIhCgpCAgQh+QpDCiKKIAYNCgYKEiBB+QiCIp0H/AXEgBUH/AXGtQoKQgIEIfkKQwoiiiAGDQoGChIgQfkIYiKdBgP4DcXJBECABa3Y7AQALIAAgDEchASAAQQFqIQAgAQ0ACwsLcgEBfyMAQRBrIgQkAAJ/QQAgAEUNABogAEEIaiEAIAFFBEAgAlBFBEAgAARAIABBADYCBCAAQRI2AgALQQAMAgtBAEIAIAMgABA6DAELIAQgAjcDCCAEIAE2AgAgBEIBIAMgABA6CyEAIARBEGokACAACyIAIAAgASACIAMQJiIARQRAQQAPCyAAKAIwQQAgAiADECULAwABC8gFAQR/IABB//8DcSEDIABBEHYhBEEBIQAgAkEBRgRAIAMgAS0AAGpB8f8DcCIAIARqQfH/A3BBEHQgAHIPCwJAIAEEfyACQRBJDQECQCACQa8rSwRAA0AgAkGwK2shAkG1BSEFIAEhAANAIAMgAC0AAGoiAyAEaiADIAAtAAFqIgNqIAMgAC0AAmoiA2ogAyAALQADaiIDaiADIAAtAARqIgNqIAMgAC0ABWoiA2ogAyAALQAGaiIDaiADIAAtAAdqIgNqIQQgBQRAIABBCGohACAFQQFrIQUMAQsLIARB8f8DcCEEIANB8f8DcCEDIAFBsCtqIQEgAkGvK0sNAAsgAkEISQ0BCwNAIAMgAS0AAGoiACAEaiAAIAEtAAFqIgBqIAAgAS0AAmoiAGogACABLQADaiIAaiAAIAEtAARqIgBqIAAgAS0ABWoiAGogACABLQAGaiIAaiAAIAEtAAdqIgNqIQQgAUEIaiEBIAJBCGsiAkEHSw0ACwsCQCACRQ0AIAJBAWshBiACQQNxIgUEQCABIQADQCACQQFrIQIgAyAALQAAaiIDIARqIQQgAEEBaiIBIQAgBUEBayIFDQALCyAGQQNJDQADQCADIAEtAABqIgAgAS0AAWoiBSABLQACaiIGIAEtAANqIgMgBiAFIAAgBGpqamohBCABQQRqIQEgAkEEayICDQALCyADQfH/A3AgBEHx/wNwQRB0cgVBAQsPCwJAIAJFDQAgAkEBayEGIAJBA3EiBQRAIAEhAANAIAJBAWshAiADIAAtAABqIgMgBGohBCAAQQFqIgEhACAFQQFrIgUNAAsLIAZBA0kNAANAIAMgAS0AAGoiACABLQABaiIFIAEtAAJqIgYgAS0AA2oiAyAGIAUgACAEampqaiEEIAFBBGohASACQQRrIgINAAsLIANB8f8DcCAEQfH/A3BBEHRyCx8AIAAgAiADQcCAASgCABEAACEAIAEgAiADEAcaIAALIwAgACAAKAJAIAIgA0HUgAEoAgARAAA2AkAgASACIAMQBxoLzSoCGH8HfiAAKAIMIgIgACgCECIDaiEQIAMgAWshASAAKAIAIgUgACgCBGohA0F/IAAoAhwiBygCpAF0IQRBfyAHKAKgAXQhCyAHKAI4IQwCf0EAIAcoAiwiEUUNABpBACACIAxJDQAaIAJBhAJqIAwgEWpNCyEWIBBBgwJrIRMgASACaiEXIANBDmshFCAEQX9zIRggC0F/cyESIAcoApwBIRUgBygCmAEhDSAHKAKIASEIIAc1AoQBIR0gBygCNCEOIAcoAjAhGSAQQQFqIQ8DQCAIQThyIQYgBSAIQQN2QQdxayELAn8gAiANIAUpAAAgCK2GIB2EIh2nIBJxQQJ0IgFqIgMtAAAiBA0AGiACIAEgDWoiAS0AAjoAACAGIAEtAAEiAWshBiACQQFqIA0gHSABrYgiHacgEnFBAnQiAWoiAy0AACIEDQAaIAIgASANaiIDLQACOgABIAYgAy0AASIDayEGIA0gHSADrYgiHacgEnFBAnRqIgMtAAAhBCACQQJqCyEBIAtBB2ohBSAGIAMtAAEiAmshCCAdIAKtiCEdAkACQAJAIARB/wFxRQ0AAkACQAJAAkACQANAIARBEHEEQCAVIB0gBK1CD4OIIhqnIBhxQQJ0aiECAn8gCCAEQQ9xIgZrIgRBG0sEQCAEIQggBQwBCyAEQThyIQggBSkAACAErYYgGoQhGiAFIARBA3ZrQQdqCyELIAMzAQIhGyAIIAItAAEiA2shCCAaIAOtiCEaIAItAAAiBEEQcQ0CA0AgBEHAAHFFBEAgCCAVIAIvAQJBAnRqIBqnQX8gBHRBf3NxQQJ0aiICLQABIgNrIQggGiADrYghGiACLQAAIgRBEHFFDQEMBAsLIAdB0f4ANgIEIABB7A42AhggGiEdDAMLIARB/wFxIgJBwABxRQRAIAggDSADLwECQQJ0aiAdp0F/IAJ0QX9zcUECdGoiAy0AASICayEIIB0gAq2IIR0gAy0AACIERQ0HDAELCyAEQSBxBEAgB0G//gA2AgQgASECDAgLIAdB0f4ANgIEIABB0A42AhggASECDAcLIB1BfyAGdEF/c62DIBt8IhunIQUgCCAEQQ9xIgNrIQggGiAErUIPg4ghHSABIBdrIgYgAjMBAiAaQX8gA3RBf3Otg3ynIgRPDQIgBCAGayIGIBlNDQEgBygCjEdFDQEgB0HR/gA2AgQgAEG5DDYCGAsgASECIAshBQwFCwJAIA5FBEAgDCARIAZraiEDDAELIAYgDk0EQCAMIA4gBmtqIQMMAQsgDCARIAYgDmsiBmtqIQMgBSAGTQ0AIAUgBmshBQJAAkAgASADTSABIA8gAWusIhogBq0iGyAaIBtUGyIapyIGaiICIANLcQ0AIAMgBmogAUsgASADT3ENACABIAMgBhAHGiACIQEMAQsgASADIAMgAWsiASABQR91IgFqIAFzIgIQByACaiEBIBogAq0iHn0iHFANACACIANqIQIDQAJAIBwgHiAcIB5UGyIbQiBUBEAgGyEaDAELIBsiGkIgfSIgQgWIQgF8QgODIh9QRQRAA0AgASACKQAANwAAIAEgAikAGDcAGCABIAIpABA3ABAgASACKQAINwAIIBpCIH0hGiACQSBqIQIgAUEgaiEBIB9CAX0iH0IAUg0ACwsgIELgAFQNAANAIAEgAikAADcAACABIAIpABg3ABggASACKQAQNwAQIAEgAikACDcACCABIAIpADg3ADggASACKQAwNwAwIAEgAikAKDcAKCABIAIpACA3ACAgASACKQBYNwBYIAEgAikAUDcAUCABIAIpAEg3AEggASACKQBANwBAIAEgAikAYDcAYCABIAIpAGg3AGggASACKQBwNwBwIAEgAikAeDcAeCACQYABaiECIAFBgAFqIQEgGkKAAX0iGkIfVg0ACwsgGkIQWgRAIAEgAikAADcAACABIAIpAAg3AAggGkIQfSEaIAJBEGohAiABQRBqIQELIBpCCFoEQCABIAIpAAA3AAAgGkIIfSEaIAJBCGohAiABQQhqIQELIBpCBFoEQCABIAIoAAA2AAAgGkIEfSEaIAJBBGohAiABQQRqIQELIBpCAloEQCABIAIvAAA7AAAgGkICfSEaIAJBAmohAiABQQJqIQELIBwgG30hHCAaUEUEQCABIAItAAA6AAAgAkEBaiECIAFBAWohAQsgHEIAUg0ACwsgDiEGIAwhAwsgBSAGSwRAAkACQCABIANNIAEgDyABa6wiGiAGrSIbIBogG1QbIhqnIglqIgIgA0txDQAgAyAJaiABSyABIANPcQ0AIAEgAyAJEAcaDAELIAEgAyADIAFrIgEgAUEfdSIBaiABcyIBEAcgAWohAiAaIAGtIh59IhxQDQAgASADaiEBA0ACQCAcIB4gHCAeVBsiG0IgVARAIBshGgwBCyAbIhpCIH0iIEIFiEIBfEIDgyIfUEUEQANAIAIgASkAADcAACACIAEpABg3ABggAiABKQAQNwAQIAIgASkACDcACCAaQiB9IRogAUEgaiEBIAJBIGohAiAfQgF9Ih9CAFINAAsLICBC4ABUDQADQCACIAEpAAA3AAAgAiABKQAYNwAYIAIgASkAEDcAECACIAEpAAg3AAggAiABKQA4NwA4IAIgASkAMDcAMCACIAEpACg3ACggAiABKQAgNwAgIAIgASkAWDcAWCACIAEpAFA3AFAgAiABKQBINwBIIAIgASkAQDcAQCACIAEpAGA3AGAgAiABKQBoNwBoIAIgASkAcDcAcCACIAEpAHg3AHggAUGAAWohASACQYABaiECIBpCgAF9IhpCH1YNAAsLIBpCEFoEQCACIAEpAAA3AAAgAiABKQAINwAIIBpCEH0hGiACQRBqIQIgAUEQaiEBCyAaQghaBEAgAiABKQAANwAAIBpCCH0hGiACQQhqIQIgAUEIaiEBCyAaQgRaBEAgAiABKAAANgAAIBpCBH0hGiACQQRqIQIgAUEEaiEBCyAaQgJaBEAgAiABLwAAOwAAIBpCAn0hGiACQQJqIQIgAUECaiEBCyAcIBt9IRwgGlBFBEAgAiABLQAAOgAAIAJBAWohAiABQQFqIQELIBxCAFINAAsLIAUgBmshAUEAIARrIQUCQCAEQQdLBEAgBCEDDAELIAEgBE0EQCAEIQMMAQsgAiAEayEFA0ACQCACIAUpAAA3AAAgBEEBdCEDIAEgBGshASACIARqIQIgBEEDSw0AIAMhBCABIANLDQELC0EAIANrIQULIAIgBWohBAJAIAUgDyACa6wiGiABrSIbIBogG1QbIhqnIgFIIAVBf0pxDQAgBUEBSCABIARqIAJLcQ0AIAIgBCABEAcgAWohAgwDCyACIAQgAyADQR91IgFqIAFzIgEQByABaiECIBogAa0iHn0iHFANAiABIARqIQEDQAJAIBwgHiAcIB5UGyIbQiBUBEAgGyEaDAELIBsiGkIgfSIgQgWIQgF8QgODIh9QRQRAA0AgAiABKQAANwAAIAIgASkAGDcAGCACIAEpABA3ABAgAiABKQAINwAIIBpCIH0hGiABQSBqIQEgAkEgaiECIB9CAX0iH0IAUg0ACwsgIELgAFQNAANAIAIgASkAADcAACACIAEpABg3ABggAiABKQAQNwAQIAIgASkACDcACCACIAEpADg3ADggAiABKQAwNwAwIAIgASkAKDcAKCACIAEpACA3ACAgAiABKQBYNwBYIAIgASkAUDcAUCACIAEpAEg3AEggAiABKQBANwBAIAIgASkAYDcAYCACIAEpAGg3AGggAiABKQBwNwBwIAIgASkAeDcAeCABQYABaiEBIAJBgAFqIQIgGkKAAX0iGkIfVg0ACwsgGkIQWgRAIAIgASkAADcAACACIAEpAAg3AAggGkIQfSEaIAJBEGohAiABQRBqIQELIBpCCFoEQCACIAEpAAA3AAAgGkIIfSEaIAJBCGohAiABQQhqIQELIBpCBFoEQCACIAEoAAA2AAAgGkIEfSEaIAJBBGohAiABQQRqIQELIBpCAloEQCACIAEvAAA7AAAgGkICfSEaIAJBAmohAiABQQJqIQELIBwgG30hHCAaUEUEQCACIAEtAAA6AAAgAkEBaiECIAFBAWohAQsgHFBFDQALDAILAkAgASADTSABIA8gAWusIhogBa0iGyAaIBtUGyIapyIEaiICIANLcQ0AIAMgBGogAUsgASADT3ENACABIAMgBBAHGgwCCyABIAMgAyABayIBIAFBH3UiAWogAXMiARAHIAFqIQIgGiABrSIefSIcUA0BIAEgA2ohAQNAAkAgHCAeIBwgHlQbIhtCIFQEQCAbIRoMAQsgGyIaQiB9IiBCBYhCAXxCA4MiH1BFBEADQCACIAEpAAA3AAAgAiABKQAYNwAYIAIgASkAEDcAECACIAEpAAg3AAggGkIgfSEaIAFBIGohASACQSBqIQIgH0IBfSIfQgBSDQALCyAgQuAAVA0AA0AgAiABKQAANwAAIAIgASkAGDcAGCACIAEpABA3ABAgAiABKQAINwAIIAIgASkAODcAOCACIAEpADA3ADAgAiABKQAoNwAoIAIgASkAIDcAICACIAEpAFg3AFggAiABKQBQNwBQIAIgASkASDcASCACIAEpAEA3AEAgAiABKQBgNwBgIAIgASkAaDcAaCACIAEpAHA3AHAgAiABKQB4NwB4IAFBgAFqIQEgAkGAAWohAiAaQoABfSIaQh9WDQALCyAaQhBaBEAgAiABKQAANwAAIAIgASkACDcACCAaQhB9IRogAkEQaiECIAFBEGohAQsgGkIIWgRAIAIgASkAADcAACAaQgh9IRogAkEIaiECIAFBCGohAQsgGkIEWgRAIAIgASgAADYAACAaQgR9IRogAkEEaiECIAFBBGohAQsgGkICWgRAIAIgAS8AADsAACAaQgJ9IRogAkECaiECIAFBAmohAQsgHCAbfSEcIBpQRQRAIAIgAS0AADoAACACQQFqIQIgAUEBaiEBCyAcUEUNAAsMAQsCQAJAIBYEQAJAIAQgBUkEQCAHKAKYRyAESw0BCyABIARrIQMCQEEAIARrIgVBf0ogDyABa6wiGiAbIBogG1QbIhqnIgIgBUpxDQAgBUEBSCACIANqIAFLcQ0AIAEgAyACEAcgAmohAgwFCyABIAMgBCAEQR91IgFqIAFzIgEQByABaiECIBogAa0iHn0iHFANBCABIANqIQEDQAJAIBwgHiAcIB5UGyIbQiBUBEAgGyEaDAELIBsiGkIgfSIgQgWIQgF8QgODIh9QRQRAA0AgAiABKQAANwAAIAIgASkAGDcAGCACIAEpABA3ABAgAiABKQAINwAIIBpCIH0hGiABQSBqIQEgAkEgaiECIB9CAX0iH0IAUg0ACwsgIELgAFQNAANAIAIgASkAADcAACACIAEpABg3ABggAiABKQAQNwAQIAIgASkACDcACCACIAEpADg3ADggAiABKQAwNwAwIAIgASkAKDcAKCACIAEpACA3ACAgAiABKQBYNwBYIAIgASkAUDcAUCACIAEpAEg3AEggAiABKQBANwBAIAIgASkAYDcAYCACIAEpAGg3AGggAiABKQBwNwBwIAIgASkAeDcAeCABQYABaiEBIAJBgAFqIQIgGkKAAX0iGkIfVg0ACwsgGkIQWgRAIAIgASkAADcAACACIAEpAAg3AAggGkIQfSEaIAJBEGohAiABQRBqIQELIBpCCFoEQCACIAEpAAA3AAAgGkIIfSEaIAJBCGohAiABQQhqIQELIBpCBFoEQCACIAEoAAA2AAAgGkIEfSEaIAJBBGohAiABQQRqIQELIBpCAloEQCACIAEvAAA7AAAgGkICfSEaIAJBAmohAiABQQJqIQELIBwgG30hHCAaUEUEQCACIAEtAAA6AAAgAkEBaiECIAFBAWohAQsgHFBFDQALDAQLIBAgAWsiCUEBaiIGIAUgBSAGSxshAyABIARrIQIgAUEHcUUNAiADRQ0CIAEgAi0AADoAACACQQFqIQIgAUEBaiIGQQdxQQAgA0EBayIFGw0BIAYhASAFIQMgCSEGDAILAkAgBCAFSQRAIAcoAphHIARLDQELIAEgASAEayIGKQAANwAAIAEgBUEBa0EHcUEBaiIDaiECIAUgA2siBEUNAyADIAZqIQEDQCACIAEpAAA3AAAgAUEIaiEBIAJBCGohAiAEQQhrIgQNAAsMAwsgASAEIAUQPyECDAILIAEgAi0AADoAASAJQQFrIQYgA0ECayEFIAJBAWohAgJAIAFBAmoiCkEHcUUNACAFRQ0AIAEgAi0AADoAAiAJQQJrIQYgA0EDayEFIAJBAWohAgJAIAFBA2oiCkEHcUUNACAFRQ0AIAEgAi0AADoAAyAJQQNrIQYgA0EEayEFIAJBAWohAgJAIAFBBGoiCkEHcUUNACAFRQ0AIAEgAi0AADoABCAJQQRrIQYgA0EFayEFIAJBAWohAgJAIAFBBWoiCkEHcUUNACAFRQ0AIAEgAi0AADoABSAJQQVrIQYgA0EGayEFIAJBAWohAgJAIAFBBmoiCkEHcUUNACAFRQ0AIAEgAi0AADoABiAJQQZrIQYgA0EHayEFIAJBAWohAgJAIAFBB2oiCkEHcUUNACAFRQ0AIAEgAi0AADoAByAJQQdrIQYgA0EIayEDIAFBCGohASACQQFqIQIMBgsgCiEBIAUhAwwFCyAKIQEgBSEDDAQLIAohASAFIQMMAwsgCiEBIAUhAwwCCyAKIQEgBSEDDAELIAohASAFIQMLAkACQCAGQRdNBEAgA0UNASADQQFrIQUgA0EHcSIEBEADQCABIAItAAA6AAAgA0EBayEDIAFBAWohASACQQFqIQIgBEEBayIEDQALCyAFQQdJDQEDQCABIAItAAA6AAAgASACLQABOgABIAEgAi0AAjoAAiABIAItAAM6AAMgASACLQAEOgAEIAEgAi0ABToABSABIAItAAY6AAYgASACLQAHOgAHIAFBCGohASACQQhqIQIgA0EIayIDDQALDAELIAMNAQsgASECDAELIAEgBCADED8hAgsgCyEFDAELIAEgAy0AAjoAACABQQFqIQILIAUgFE8NACACIBNJDQELCyAAIAI2AgwgACAFIAhBA3ZrIgE2AgAgACATIAJrQYMCajYCECAAIBQgAWtBDmo2AgQgByAIQQdxIgA2AogBIAcgHUJ/IACthkJ/hYM+AoQBC+cFAQR/IAMgAiACIANLGyEEIAAgAWshAgJAIABBB3FFDQAgBEUNACAAIAItAAA6AAAgA0EBayEGIAJBAWohAiAAQQFqIgdBB3FBACAEQQFrIgUbRQRAIAchACAFIQQgBiEDDAELIAAgAi0AADoAASADQQJrIQYgBEECayEFIAJBAWohAgJAIABBAmoiB0EHcUUNACAFRQ0AIAAgAi0AADoAAiADQQNrIQYgBEEDayEFIAJBAWohAgJAIABBA2oiB0EHcUUNACAFRQ0AIAAgAi0AADoAAyADQQRrIQYgBEEEayEFIAJBAWohAgJAIABBBGoiB0EHcUUNACAFRQ0AIAAgAi0AADoABCADQQVrIQYgBEEFayEFIAJBAWohAgJAIABBBWoiB0EHcUUNACAFRQ0AIAAgAi0AADoABSADQQZrIQYgBEEGayEFIAJBAWohAgJAIABBBmoiB0EHcUUNACAFRQ0AIAAgAi0AADoABiADQQdrIQYgBEEHayEFIAJBAWohAgJAIABBB2oiB0EHcUUNACAFRQ0AIAAgAi0AADoAByADQQhrIQMgBEEIayEEIABBCGohACACQQFqIQIMBgsgByEAIAUhBCAGIQMMBQsgByEAIAUhBCAGIQMMBAsgByEAIAUhBCAGIQMMAwsgByEAIAUhBCAGIQMMAgsgByEAIAUhBCAGIQMMAQsgByEAIAUhBCAGIQMLAkAgA0EXTQRAIARFDQEgBEEBayEBIARBB3EiAwRAA0AgACACLQAAOgAAIARBAWshBCAAQQFqIQAgAkEBaiECIANBAWsi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CyAAIAMtAAAEfiADKQMQBUIAC6dB//8DcSADKAIEEEcLIQUgAxAICyAEQRBqJAAgBQvgAQICfwF+QTAQCSICRQRAIAEEQCABQQA2AgQgAUEONgIAC0EADwsgAkIANwMIIAJBADYCACACQgA3AxAgAkIANwMYIAJCADcDICACQgA3ACUgAFAEQCACDwsCQCAAQv////8AVg0AIACnQQR0EAkiA0UNACACIAM2AgBBACEBQgEhBANAIAMgAUEEdGoiAUIANwIAIAFCADcABSAAIARSBEAgBKchASAEQgF8IQQMAQsLIAIgADcDCCACIAA3AxAgAg8LIAEEQCABQQA2AgQgAUEONgIAC0EAEBAgAhAGQQAL7gECA38BfiMAQRBrIgQkAAJAIARBDGpCBBAXIgNFBEBBfyECDAELAkAgAQRAIAJBgAZxIQUDQAJAIAUgASgCBHFFDQACQCADKQMIQgBUBEAgA0EAOgAADAELIANCADcDECADQQE6AAALIAMgAS8BCBANIAMgAS8BChANIAMtAABFBEAgAEEIaiIABEAgAEEANgIEIABBFDYCAAtBfyECDAQLQX8hAiAAIARBDGpCBBAbQQBIDQMgATMBCiIGUA0AIAAgASgCDCAGEBtBAEgNAwsgASgCACIBDQALC0EAIQILIAMQCAsgBEEQaiQAIAILPAEBfyAABEAgAUGABnEhAQNAIAEgACgCBHEEQCACIAAvAQpqQQRqIQILIAAoAgAiAA0ACwsgAkH//wNxC5wBAQN/IABFBEBBAA8LIAAhAwNAAn8CQAJAIAAvAQgiAUH04AFNBEAgAUEBRg0BIAFB9cYBRg0BDAILIAFBgbICRg0AIAFB9eABRw0BCyAAKAIAIQEgAEEANgIAIAAoAgwQBiAAEAYgASADIAAgA0YbIQMCQCACRQRAQQAhAgwBCyACIAE2AgALIAEMAQsgACICKAIACyIADQALIAMLsgQCBX8BfgJAAkACQCAAIAGtEBciAQRAIAEtAAANAUEAIQAMAgsgBARAIARBADYCBCAEQQ42AgALQQAPC0EAIQADQCABLQAABH4gASkDCCABKQMQfQVCAAtCBFQNASABEAwhByABIAEQDCIGrRATIghFBEBBACECIAQEQCAEQQA2AgQgBEEVNgIACyABEAggAEUNAwNAIAAoAgAhASAAKAIMEAYg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DCAAQRg2AggLDAMLIAAgBiAFLwFqQQAgBCABEQYAIQEgBhALIAFFDQILAkAgDUUEQCABIQMMAQsgACABIAUvAWgQgQEhAyABEAsgA0UNAQsCQCAJRSAMckUEQCADIQEMAQsgACADQQEQgAEhASADEAsgAUUNAQsgASEDDAELQQAhAwsgBUHwAGokACADC4UBAQF/IAFFBEAgAEEIaiIABEAgAEEANgIEIABBEjYCAAtBAA8LQTgQCSIDRQRAIABBCGoiAARAIABBADYCBCAAQQ42AgALQQAPCyADQQA2AhAgA0IANwIIIANCADcDKCADQQA2AgQgAyACNgIAIANCADcDGCADQQA2AjAgACABQTsgAxBCCw8AIAAgASACQQBBABCCAQusAgECfyABRQRAIABBCGoiAARAIABBADYCBCAAQRI2AgALQQAPCwJAIAJBfUsNACACQf//A3FBCEYNACAAQQhqIgAEQCAAQQA2AgQgAEEQNgIAC0EADwsCQEGwwAAQCSIFBEAgBUEANgIIIAVCADcCACAFQYiBAUGogQEgAxs2AqhAIAUgAjYCFCAFIAM6ABAgBUEAOgAPIAVBADsBDCAFIAMgAkF9SyIGcToADiAFQQggAiAGG0H//wNxIAQgBUGIgQFBqIEBIAMbKAIAEQAAIgI2AqxAIAINASAFEDEgBRAGCyAAQQhqIgAEQCAAQQA2AgQgAEEONgIAC0EADwsgACABQTogBRBCIgAEfyAABSAFKAKsQCAFKAKoQCgCBBEDACAFEDEgBRAGQQALC6ABAQF/IAIgACgCBCIDIAIgA0kbIgIEQCAAIAMgAms2AgQCQAJAAkACQCAAKAIcIgMoAhRBAWsOAgEAAgsgA0GgAWogASAAKAIAIAJB3IABKAIAEQgADAILIAAgACgCMCABIAAoAgAgAkHEgAEoAgARBAA2AjAMAQsgASAAKAIAIAIQBxoLIAAgACgCACACajYCACAAIAAoAgggAmo2AggLC7cCAQR/QX4hAgJAIABFDQAgACgCIEUNACAAKAIkIgRFDQAgACgCHCIBRQ0AIAEoAgAgAEcNAAJAAkAgASgCICIDQTlrDjkBAgICAgICAgICAgIBAgICAQICAgICAgICAgICAgICAgICAQICAgICAgICAgICAQICAgICAgICAgEACyADQZoFRg0AIANBKkcN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DCABajYCDCAGIAYoAgggAWo2AgggBSAFKAIUIAFqNgIUIAUgBSgCECABazYCECAGIAYoAhAgAWsiATYCECABDQAgBiAGKAIENgIIC0EAIQRBACEJIAMoAhBFDQAMCgsgAygCHCgCJCEGIAMgAygCGCIBQQFqNgIYIAEgBmotAAAhASADIARBAWo2AhAgAygCBCAEaiABOgAAIAEEQCADKAIQIQQMAQsLIAMoAhwoAixFDQAgAygCECIGIAlNDQAgBQJ/IAUoAjAhBEEAIAMoAgQgCWoiAUUNABogBCABIAYgCWtB1IABKAIAEQAACzYCMAsgA0HnADYCIAsCQCADKAIcKAIsBEAgAygCDCADKAIQIgFBAmpJBH8gBRAKIAMoAhANAkEABSABCyADKAIEaiAFKAIwOwAAIAMgAygCEEECajYCECADQaABakHkgAEoAgARAQAaCyADQfEANgIgIAUQCiADKAIQRQ0BDAcLDAYLIAUoAgQNAQsgAygCPA0AIApFDQEgAygCIEGaBUYNAQsCfyADKAKIASIBRQRAIAMgChCFAQwBCwJAAkACQCADKAKMAUECaw4CAAECCwJ/AkADQAJAAkAgAygCPA0AIAMQLyADKAI8DQAgCg0BQQAMBAsgAygCSCADKAJoai0AACEEIAMgAygC8C0iAUEBajYC8C0gASADKALsLWpBADoAACADIAMoAvAtIgFBAWo2AvAtIAEgAygC7C1qQQA6AAAgAyADKALwLSIBQQFqNgLwLSABIAMoAuwtaiAEOgAAIAMgBEECdGoiASABLwHkAUEBajsB5AEgAyADKAI8QQFrNgI8IAMgAygCaEEBaiIBNgJoIAMoAvAtIAMoAvQtRw0BQQAhBCADIAMoAlgiBkEATgR/IAMoAkggBmoFQQALIAEgBmtBABAPIAMgAygCaDYCWCADKAIAEAogAygCACgCEA0BDAILCyADQQA2AoQuIApBBEYEQCADIAMoAlgiAUEATgR/IAMoAkggAWoFQQALIAMoAmggAWtBARAPIAMgAygCaDYCWCADKAIAEApBA0ECIAMoAgAoAhAbDAILIAMoAvAtBEBBACEEIAMgAygCWCIBQQBOBH8gAygCSCABagVBAAsgAygCaCABa0EAEA8gAyADKAJoNgJYIAMoAgAQCiADKAIAKAIQRQ0BC0EBIQQLIAQL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bGl0ZXJhbC9sZW5ndGhzIHNldABpbnZhbGlkIGNvZGUgbGVuZ3RocyBzZXQAdW5rbm93biBoZWFkZXIgZmxhZ3Mgc2V0AGludmFsaWQgZGlzdGFuY2VzIHNldABpbnZhbGlkIGJpdCBsZW5ndGggcmVwZWF0AEZpbGUgYWxyZWFkeSBleGlzdHMAdG9vIG1hbnkgbGVuZ3RoIG9yIGRpc3RhbmNlIHN5bWJvbHMAaW52YWxpZCBzdG9yZWQgYmxvY2sgbGVuZ3RocwAlcyVzJXMAYnVmZmVyIGVycm9yAE5vIGVycm9yAHN0cmVhbSBlcnJvcgBUZWxsIGVycm9yAEludGVybmFsIGVycm9yAFNlZWsgZXJyb3IAV3JpdGUgZXJyb3IAZmlsZSBlcnJvcgBSZWFkIGVycm9yAFpsaWIgZXJyb3IAZGF0YSBlcnJvcgBDUkMgZXJyb3IAaW5jb21wYXRpYmxlIHZlcnNpb24AaW52YWxpZCBjb2RlIC0tIG1pc3NpbmcgZW5kLW9mLWJsb2NrAGluY29ycmVjdCBoZWFkZXIgY2hlY2sAaW5jb3JyZWN0IGxlbmd0aCBjaGVjawBpbmNvcnJlY3QgZGF0YSBjaGVjawBpbnZhbGlkIGRpc3RhbmNlIHRvbyBmYXIgYmFjawBoZWFkZXIgY3JjIG1pc21hdGNoADEuMi4xMy56bGliLW5nAGludmFsaWQgd2luZG93IHNpemUAUmVhZC1vbmx5IGFyY2hpdmUATm90IGEgemlwIGFyY2hpdmUAUmVzb3VyY2Ugc3RpbGwgaW4gdXNlAE1hbGxvYyBmYWlsdXJlAGludmFsaWQgYmxvY2sgdHlwZQBGYWlsdXJlIHRvIGNyZWF0ZSB0ZW1wb3JhcnkgZmlsZQBDYW4ndCBvcGVuIGZpbGUATm8gc3VjaCBmaWxlAFByZW1hdHVyZSBlbmQgb2YgZmlsZQBDYW4ndCByZW1vdmUgZmlsZQBpbnZhbGlkIGxpdGVyYWwvbGVuZ3RoIGNvZGUAaW52YWxpZCBkaXN0YW5jZSBjb2RlAHVua25vd24gY29tcHJlc3Npb24gbWV0aG9kAHN0cmVhbSBlbmQAQ29tcHJlc3NlZCBkYXRhIGludmFsaWQATXVsdGktZGlzayB6aXAgYXJjaGl2ZXMgbm90IHN1cHBvcnRlZABPcGVyYXRpb24gbm90IHN1cHBvcnRlZABFbmNyeXB0aW9uIG1ldGhvZCBub3Qgc3VwcG9ydGVkAENvbXByZXNzaW9uIG1ldGhvZCBub3Qgc3VwcG9ydGVkAEVudHJ5IGhhcyBiZWVuIGRlbGV0ZWQAQ29udGFpbmluZyB6aXAgYXJjaGl2ZSB3YXMgY2xvc2VkAENsb3NpbmcgemlwIGFyY2hpdmUgZmFpbGVkAFJlbmFtaW5nIHRlbXBvcmFyeSBmaWxlIGZhaWxlZABFbnRyeSBoYXMgYmVlbiBjaGFuZ2VkAE5vIHBhc3N3b3JkIHByb3ZpZGVkAFdyb25nIHBhc3N3b3JkIHByb3ZpZGVkAFVua25vd24gZXJyb3IgJWQAQUUAKG51bGwpADogAFBLBgcAUEsGBgBQSwUGAFBLAwQAUEsBAgAAAAA/BQAAwAcAAJMIAAB4CAAAbwUAAJEFAAB6BQAAsgUAAFYIAAAbBwAA1gQAAAsHAADqBgAAnAUAAMgGAACyCAAAHggAACgHAABHBAAAoAYAAGAFAAAuBAAAPgcAAD8IAAD+BwAAjgYAAMkIAADeCAAA5gcAALIGAABVBQAAqAcAACAAQcgTCxEBAAAAAQAAAAEAAAABAAAAAQBB7BMLCQEAAAABAAAAAgBBmBQLAQEAQbgUCwEBAEHSFAukLDomOyZlJmYmYyZgJiIg2CXLJdklQiZAJmomayY8JrolxCWVITwgtgCnAKwlqCGRIZMhkiGQIR8ilCGyJbwlIAAhACIAIwAkACUAJgAnACgAKQAqACsALAAtAC4ALwAwADEAMgAzADQANQA2ADcAOAA5ADoAOwA8AD0APgA/AEAAQQBCAEMARABFAEYARwBIAEkASgBLAEwATQBOAE8AUABRAFIAUwBUAFUAVgBXAFgAWQBaAFsAXABdAF4AXwBgAGEAYgBjAGQAZQBmAGcAaABpAGoAawBsAG0AbgBvAHAAcQByAHMAdAB1AHYAdwB4AHkAegB7AHwAfQB+AAIjxwD8AOkA4gDkAOAA5QDnAOoA6wDoAO8A7gDsAMQAxQDJAOYAxgD0APYA8gD7APkA/wDWANwAogCjAKUApyCSAeEA7QDzAPoA8QDRAKoAugC/ABAjrAC9ALwAoQCrALsAkSWSJZMlAiUkJWElYiVWJVUlYyVRJVclXSVcJVslECUUJTQlLCUcJQAlPCVeJV8lWiVUJWklZiVgJVAlbCVnJWglZCVlJVklWCVSJVMlayVqJRglDCWIJYQljCWQJYAlsQPfAJMDwAOjA8MDtQDEA6YDmAOpA7QDHiLGA7UDKSJhIrEAZSJkIiAjISP3AEgisAAZIrcAGiJ/ILIAoCWgAAAAAACWMAd3LGEO7rpRCZkZxG0Hj/RqcDWlY+mjlWSeMojbDqS43Hke6dXgiNnSlytMtgm9fLF+By2455Edv5BkELcd8iCwakhxufPeQb6EfdTaGuvk3W1RtdT0x4XTg1aYbBPAqGtkevli/ezJZYpPXAEU2WwGY2M9D/r1DQiNyCBuO14QaUzkQWDVcnFnotHkAzxH1ARL/YUN0mu1CqX6qLU1bJiyQtbJu9tA+bys42zYMnVc30XPDdbcWT3Rq6ww2SY6AN5RgFHXyBZh0L+19LQhI8SzVpmVus8Ppb24nrgCKAiIBV+y2QzGJOkLsYd8by8RTGhYqx1hwT0tZraQQdx2BnHbAbwg0pgqENXviYWxcR+1tgal5L+fM9S46KLJB3g0+QAPjqgJlhiYDuG7DWp/LT1tCJdsZJEBXGPm9FFra2JhbBzYMGWFTgBi8u2VBmx7pQEbwfQIglfED/XG2bBlUOm3Euq4vot8iLn83x3dYkkt2hXzfNOMZUzU+1hhsk3OUbU6dAC8o+Iwu9RBpd9K15XYPW3E0aT79NbTaulpQ/zZbjRGiGet0Lhg2nMtBETlHQMzX0wKqsl8Dd08cQVQqkECJxAQC76GIAzJJbVoV7OFbyAJ1Ga5n+Rhzg753l6YydkpIpjQsLSo18cXPbNZgQ20LjtcvbetbLrAIIO47bazv5oM4rYDmtKxdDlH1eqvd9KdFSbbBIMW3HMSC2PjhDtklD5qbQ2oWmp6C88O5J3/CZMnrgAKsZ4HfUSTD/DSowiHaPIBHv7CBmldV2L3y2dlgHE2bBnnBmtudhvU/uAr04laetoQzErdZ2/fufn5776OQ763F9WOsGDoo9bWfpPRocTC2DhS8t9P8We70WdXvKbdBrU/SzaySNorDdhMGwqv9koDNmB6BEHD72DfVd9nqO+ObjF5vmlGjLNhyxqDZryg0m8lNuJoUpV3DMwDRwu7uRYCIi8mBVW+O7rFKAu9spJatCsEarNcp//XwjHP0LWLntksHa7eW7DCZJsm8mPsnKNqdQqTbQKpBgmcPzYO64VnB3ITVwAFgkq/lRR6uOKuK7F7OBu2DJuO0pINvtXlt+/cfCHf2wvU0tOGQuLU8fiz3Whug9ofzRa+gVsmufbhd7Bvd0e3GOZaCIhwag//yjsGZlwLARH/nmWPaa5i+NP/a2FFz2wWeOIKoO7SDddUgwROwrMDOWEmZ6f3FmDQTUdpSdt3bj5KatGu3FrW2WYL30DwO9g3U668qcWeu95/z7JH6f+1MBzyvb2KwrrKMJOzU6ajtCQFNtC6kwbXzSlX3lS/Z9kjLnpms7hKYcQCG2hdlCtvKje+C7ShjgzDG98FWo3vAi0AAAAARjtnZYx2zsrKTamvWevtTh/QiivVnSOEk6ZE4bLW25307bz4PqAVV3ibcjLrPTbTrQZRtmdL+BkhcJ98JavG4GOQoYWp3Qgq7+ZvT3xAK646e0zL8DblZLYNggGXfR190UZ6GBsL07ddMLTSzpbwM4itl1ZC4D75BNtZnAtQ/BpNa5t/hyYy0MEdVbVSuxFUFIB2Md7N356Y9rj7uYYnh/+9QOI18OlNc8uOKOBtysmmVq2sbBsEAyogY2Yu+zr6aMBdn6KN9DDktpNVdxDXtDErsNH7Zhl+vV1+G5wt4WfaFoYCEFsvrVZgSMjFxgwpg/1rTEmwwuMPi6WGFqD4NVCbn1Ca1jb/3O1Rmk9LFXsJcHIewz3bsYUGvNSkdiOo4k1EzSgA7WJuO4oH/Z3O5rumqYNx6wAsN9BnSTMLPtV1MFmwv33wH/lGl3pq4NObLNu0/uaWHVGgrXo0gd3lSMfmgi0NqyuCS5BM59g2CAaeDW9jVEDGzBJ7oakd8AQvW8tjSpGGyuXXva2ARBvpYQIgjgTIbSerjlZAzq8m37LpHbjXI1AReGVrdh32zTL8sPZVmXq7/DY8gJtTOFvCz35gpaq0LQwF8hZrYGGwL4Eni0jk7cbhS6v9hi6KjRlSzLZ+Nwb715hAwLD902b0HJVdk3lfEDrWGStdsyxA8Wtqe5YOoDY/oeYNWMR1qxwlM5B7QPnd0u+/5rWKnpYq9titTZMS4OQ8VNuDWcd9x7iBRqDdSwsJcg0wbhcJ6zeLT9BQ7oWd+UHDpp4kUADaxRY7vaDcdhQPmk1zars97Bb9BotzN0si3HFwRbni1gFYpO1mPW6gz5Iom6j3JxANcWErahSrZsO77V2k3n774D84wIda8o0u9bS2SZCVxtbs0/2xiRmwGCZfi39DzC07oooWXMdAW/VoBmCSDQK7y5FEgKz0js0FW8j2Yj5bUCbfHWtButcm6BWRHY9wsG0QDPZWd2k8G97GeiC5o+mG/UKvvZonZfAziCPLVO064AlefNtuO7aWx5TwraDxYwvkECUwg3XvfSraqUZNv4g20sPODbWmBEAcCUJ7e2zR3T+Nl+ZY6F2r8UcbkJYiH0vPvllwqNuTPQF01QZmEUagIvAAm0WVytbsOozti1+tnRQj66ZzRiHr2uln0L2M9Hb5bbJNngh4ADenPjtQwjGw9UR3i5IhvcY7jvv9XOtoWxgKLmB/b+Qt1sCiFrGlg2Yu2cVdSbwPEOATSSuHdtqNw5ectqTyVvsNXRDAajgUGzOkUiBUwZht/W7eVpoLTfDe6gvLuY/BhhAgh713RabN6Dng9o9cKrsm82yAQZb/JgV3uR1iEnNQy701a6zYAAAAAFiA4tfxBrR0qYZWo+INaOm6jYo+EwvcnUuLPkqFHaEJ3Z1D3nQbFX0sm/eqZxDJ4D+QKzeWFn2UzpafQwo7QhNSu6DE+z32Z6O9FLDoNir6sLbILRkwno5BsHxZjybjGtemAc1+IFduJqC1uW0ri/M1q2kknC0/h8St3VAUdoQmTPZm8eVwMFK98NKF9nvsz677DhgHfVi7X/26bJFrJS/J68f4YG2RWzjtc4xzZk3GK+avEYJg+bLa4BtlHk3GNUbNJOLvS3JBt8uQlvxArtykwEwLDUYaqFXG+H+bUGc8w9CF62pW00gy1jGfeV0P1SHd7QKIW7uh0NtZdijsCE1wbOqa2eq8OYFqXu7K4WCkkmGCczvn1NBjZzYHrfGpRPVxS5Nc9x0wBHf/50/8wa0XfCN6vvp12eZ6lw4i10peeleoidPR/iqLURz9wNoit5hawGAx3JbDaVx0FKfK61f/SgmAVsxfIw5MvfRFx4O+HUdhabTBN8rsQdUdPJqMa2QabrzNnDgflRzayN6X5IKGFwZVL5FQ9ncRsiG5hy1i4QfPtUiBmRYQAXvBW4pFiwMKp1yqjPH/8gwTKDahznhuISyvx6d6DJ8nmNvUrKaRjCxERiWqEuV9KvAys7xvces8jaZCutsFGjo50lGxB5gJMeVPoLez7Pg3UTtQ2BGaCFjzTaHepe75Xkc5stV5c+pVm6RD080HG1Mv0NXFsJONRVJEJMME53xD5jA3yNh6b0g6rcbObA6eTo7ZWuNTiQJjsV6r5ef982UFKrjuO2Dgbtm3SeiPFBFobcPf/vKAh34QVy74RvR2eKQjPfOaaWVzeL7M9S4dlHXMykSulbwcLndrtaghyO0owx+mo/1V/iMfglelSSEPJav2wbM0tZkz1mIwtYDBaDViFiO+XFx7Pr6L0rjoKIo4Cv9OldevFhU1eL+TY9vnE4EMrJi/RvQYXZFdngsyBR7p5cuIdqaTCJRxOo7C0mIOIAUphR5PcQX8mNiDqjuAA0jseDQZ1yC0+wCJMq2j0bJPdJo5cT7CuZPpaz/FSjO/J539KbjepalaCQwvDKpUr+59HyTQN0ekMuDuImRDtqKGlHIPW8Qqj7kTgwnvsNuJDWeQAjMtyILR+mEEh1k5hGWO9xL6za+SGBoGFE65XpSsbhUfkiRNn3Dz5BkmULyZxIdsQp3xNMJ/Jp1EKYXFxMtSjk/1GNbPF89/SUFsJ8mju+lfPPix394vGFmIjEDZalsLUlQRU9K2xvpU4GWi1AKyZnnf4j75PTWXf2uWz/+JQYR0twvc9FXcdXIDfy3y4ajjZH7ru+ScPBJiyp9K4ihIAWkWAlnp9NXwb6J2qO9AoQAAAADhtlLvg2vUBWLdhuoG16gL52H65IW8fA5kCi7hDK5RF+0YA/iPxYUSbnPX/Qp5+Rzrz6vziRItGWikf/YYXKMu+erxwZs3dyt6gSXEHosLJf89Wcqd4N8gfFaNzxTy8jn1RKDWl5kmPHYvdNMSJVoy85MI3ZFOjjdw+NzYMLhGXdEOFLKz05JYUmXAtzZv7lbX2by5tQQ6U1SyaLw8FhdK3aBFpb99w09ey5GgOsG/Qdt37a65qmtEWBw5qyjk5XPJUrecq48xdko5Y5kuM014z4Ufl61YmX1M7suSJEq0ZMX85ounIWBhRpcyjiKdHG/DK06AofbIakBAmoVgcI26gcbfVeMbWb8CrQtQZqclsYcRd17lzPG0BHqjW2ze3K2NaI5C77UIqA4DWkdqCXSmi78mSelioKMI1PJMeCwulJmafHv7R/qRGvGofn77hp+fTdRw/ZBSmhwmAHV0gn+DlTQtbPfpq4YWX/lpclXXiJPjhWfxPgONEIhRYlDIy+exfpkI06Mf4jIVTQ1WH2Pst6kxA9V0t+k0wuUGXGaa8L3QyB/fDU71PrscGlqxMvu7B2AU2drm/jhstBFIlGjJqSI6Jsv/vMwqSe4jTkPAwq/1ki3NKBTHLJ5GKEQ6Od6ljGsxx1Ht2ybnvzRC7ZHVo1vDOsGGRdAgMBc/geZrrmBQOUECjb+r4zvtRIcxw6Vmh5FKBFoXoOXsRU+NSDq5bP5oVg4j7rzvlbxTi5+SsmopwF0I9Ea36UIUWJm6yIB4DJpvGtEchftnTmqfbWCLftsyZBwGtI79sOZhlRSZl3Siy3gWf02S98kffZPDMZxydWNzEKjlmfEet3axXi3zUOh/HDI1+fbTg6sZt4mF+FY/1xc04lH91VQDEr3wfORcRi4LPpuo4d8t+g67J9TvWpGGADhMAOrZ+lIFqQKO3Ui03DIqaVrYy98IN6/VJtZOY3Q5LL7y080IoDylrN/KRBqNJSbHC8/HcVkgo3t3wULNJS4gEKPEwabxK+GW5hQAILT7Yv0yEYNLYP7nQU4fBvcc8GQqmhqFnMj17Ti3AwyO5exuU2MGj+Ux6evvHwgKWU3naITLDYkymeL5ykU6GHwX1XqhkT+bF8PQ/x3tMR6rv958djk0ncBr2/VkFC0U0kbCdg/AKJe5ksfzs7wmEgXuyXDYaCORbjrM0S6gSTCY8qZSRXRMs/Mmo9f5CEI2T1qtVJLcR7UkjqjdgPFePDajsV7rJVu/XXe021dZVTrhC7pYPI1QuYrfv8lyA2coxFGIShnXYquvhY3PpatsLhP5g0zOf2mteC2GxdxScCRqAJ9Gt4Z1pwHUmsML+nsivaiUQGAufqHWfJEAAAAAQ8umh8eQPNSEW5pTzycIc4zsrvQItzSnS3ySIJ5PEObdhLZhWd8sMhoUirVRaBiVEqO+Epb4JEHVM4LGfZlRFz5S95C6CW3D+cLLRLK+WWTxdf/jdS5lsDblwzfj1kHxoB3ndiRGfSVnjduiLPFJgm867wXrYXVWqKrT0foyoy65+QWpPaKf+n5pOX01Fatddt4N2vKFl4mxTjEOZH2zyCe2FU+j7Y8c4CYpm6tau7vokR08bMqHby8BIeiHq/I5xGBUvkA7zu0D8GhqSIz6SgtHXM2PHMaezNdgGRnk4t9aL0RY3nTeC52/eIzWw+qslQhMKxFT1nhSmHD/9GVGXbeu4Noz9XqJcD7cDjtCTi54ieip/NJy+r8Z1H1qKla7KeHwPK26am/ucczopQ1eyObG+E9inWIcIVbEm4n8F0rKN7HNTmwrng2njRlG2x85BRC5voFLI+3CgIVqF7MHrFR4oSvQIzt4k+id/9iUD9+bX6lYHwQzC1zPlYwOV+VzTZxD9MnH2aeKDH8gwXDtAIK7S4cG4NHURSt3U5AY9ZXT01MSV4jJQRRDb8ZfP/3mHPRbYZivwTLbZGe1c860ZDAFEuO0Xoiw95UuN7zpvBf/IhqQe3mAwziyJkTtgaSCrkoCBSoRmFZp2j7RIqas8WFtCnblNpAlpv02oujLjLqrACo9L1uwbmyQFukn7ITJZCciTuB8uB2jtx6adoScXDVPOtuxFKCI8t8GD7mjlC/6aDKofjOo+z34DnyVUt2t1pl7KlLC4XkRCUf+WnXV3hm+c1md5ekK3i5PjQsdzUtI1mvMzI3xn49GVxjEOsU4h/FjvwOq+exAYV9rEvkvlFEyiRPVaRNAlqK1x93eJ+eeFYFgGk4bM1mFvbSMtj9yz32Z9UsmA6YI7aUhQ5E3AQBakYaEAQvVx8qtUm9gfoMsq9gEqPBCV+s75NCgR3bw44zQd2fXSiQkHOyj8S9uZbLkyOI2v1KxdXT0Nj4IZhZ9w8CR+ZhawrpT/EUcrsrnX2VsYNs+9jOY9VC004nClJBCZBMUGf5AV9JYx4Lh2gHBKnyGRXHm1Qa6QFJNxtJyDg109YpW7qbJnUghYTeb8CL8PXemp6ck5WwBo64Qk4Pt2zUEaYCvVypLCdD/eIsWvLMtkTjot8J7IxFFMF+DZXOUJeL3z7+xtAQZNuacacmlV89OIQxVHWLH85opu2G6anDHPe4rXW6t4PvpeNN5LzsY36i/Q0X7/IjjfLf0cVz0P9fbcGRNiDOv6w+bBTje2M6eWVyVBAofXqKNVCIwrRfpliqTsgx50Hmq/gVKKDhGgY6/wtoU7IERsmvKbSBLiaaGzA39HJ9ONroYFAQAAJ0HAAAsCQAAhgUAAEgFAACnBQAAAAQAADIFAAC8BQAALAkAQYDBAAv3CQwACACMAAgATAAIAMwACAAsAAgArAAIAGwACADsAAgAHAAIAJwACABcAAgA3AAIADwACAC8AAgAfAAIAPwACAACAAgAggAIAEIACADCAAgAIgAIAKIACABiAAgA4gAIABIACACSAAgAUgAIANIACAAyAAgAsgAIAHIACADyAAgACgAIAIoACABKAAgAygAIACoACACqAAgAagAIAOoACAAaAAgAmgAIAFoACADaAAgAOgAIALoACAB6AAgA+gAIAAYACACGAAgARgAIAMYACAAmAAgApgAIAGYACADmAAgAFgAIAJYACABWAAgA1gAIADYACAC2AAgAdgAIAPYACAAOAAgAjgAIAE4ACADOAAgALgAIAK4ACABuAAgA7gAIAB4ACACeAAgAXgAIAN4ACAA+AAgAvgAIAH4ACAD+AAgAAQAIAIEACABBAAgAwQAIACEACAChAAgAYQAIAOEACAARAAgAkQAIAFEACADRAAgAMQAIALEACABxAAgA8QAIAAkACACJAAgASQAIAMkACAApAAgAqQAIAGkACADpAAgAGQAIAJkACABZAAgA2QAIADkACAC5AAgAeQAIAPkACAAFAAgAhQAIAEUACADFAAgAJQAIAKUACABlAAgA5QAIABUACACVAAgAVQAIANUACAA1AAgAtQAIAHUACAD1AAgADQAIAI0ACABNAAgAzQAIAC0ACACtAAgAbQAIAO0ACAAdAAgAnQAIAF0ACADdAAgAPQAIAL0ACAB9AAgA/QAIABMACQATAQkAkwAJAJMBCQBTAAkAUwEJANMACQDTAQkAMwAJADMBCQCzAAkAswEJAHMACQBzAQkA8wAJAPMBCQALAAkACwEJAIsACQCLAQkASwAJAEsBCQDLAAkAywEJACsACQArAQkAqwAJAKsBCQBrAAkAawEJAOsACQDrAQkAGwAJABsBCQCbAAkAmwEJAFsACQBbAQkA2wAJANsBCQA7AAkAOwEJALsACQC7AQkAewAJAHsBCQD7AAkA+wEJAAcACQAHAQkAhwAJAIcBCQBHAAkARwEJAMcACQDHAQkAJwAJACcBCQCnAAkApwEJAGcACQBnAQkA5wAJAOcBCQAXAAkAFwEJAJcACQCXAQkAVwAJAFcBCQDXAAkA1wEJADcACQA3AQkAtwAJALcBCQB3AAkAdwEJAPcACQD3AQkADwAJAA8BCQCPAAkAjwEJAE8ACQBPAQkAzwAJAM8BCQAvAAkALwEJAK8ACQCvAQkAbwAJAG8BCQDvAAkA7wEJAB8ACQAfAQkAnwAJAJ8BCQBfAAkAXwEJAN8ACQDfAQkAPwAJAD8BCQC/AAkA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SXMgYSBkaXJlY3RvcnkAVGV4dCBmaWxlIGJ1c3kARXhlYyBmb3JtYXQgZXJyb3IASW52YWxpZCBhcmd1bWVudABBcmd1bWVudCBsaXN0IHRvbyBsb25nAFN5bWJvbGljIGxpbmsgbG9vcABGaWxlbmFtZSB0b28gbG9uZwBUb28gbWFueSBvcGVuIGZpbGVzIGluIHN5c3RlbQBObyBmaWxlIGRlc2NyaXB0b3JzIGF2YWlsYWJsZQBCYWQgZmlsZSBkZXNjcmlwdG9yAE5vIGNoaWxkIHByb2Nlc3MAQmFkIGFkZHJlc3MARmlsZSB0b28gbGFyZ2UAVG9vIG1hbnkgbGlua3MATm8gbG9ja3MgYXZhaWxhYmxlAFJlc291cmNlIGRlYWRsb2NrIHdvdWxkIG9jY3VyAFN0YXRlIG5vdCByZWNvdmVyYWJsZQBQcmV2aW91cyBvd25lciBkaWVkAE9wZXJhdGlvbiBjYW5jZWxlZABGdW5jdGlvbiBub3QgaW1wbGVtZW50ZWQATm8gbWVzc2FnZSBvZiBkZXNpcmVkIHR5cGUASWRlbnRpZmllciByZW1vdmVkAERldmljZSBub3QgYSBzdHJlYW0ATm8gZGF0YSBhdmFpbGFibGUARGV2aWNlIHRpbWVvdXQAT3V0IG9mIHN0cmVhbXMgcmVzb3VyY2VzAExpbmsgaGFzIGJlZW4gc2V2ZXJlZABQcm90b2NvbCBlcnJvcgBCYWQgbWVzc2FnZQBGaWxlIGRlc2NyaXB0b3IgaW4gYmFkIHN0YXRlAE5vdCBhIHNvY2tldABEZXN0aW5hdGlvbiBhZGRyZXNzIHJlcXVpcmVkAE1lc3NhZ2UgdG9vIGxhcmdlAFByb3RvY29sIHdyb25nIHR5cGUgZm9yIHNvY2tldABQcm90b2NvbCBub3QgYXZhaWxhYmxlAFByb3RvY29sIG5vdCBzdXBwb3J0ZWQAU29ja2V0IHR5cGUgbm90IHN1cHBvcnRlZABOb3Qgc3VwcG9ydGVkAFByb3RvY29sIGZhbWlseSBub3Qgc3VwcG9ydGVkAEFkZHJlc3MgZmFtaWx5IG5vdCBzdXBwb3J0ZWQgYnkgcHJvdG9jb2wAQWRkcmVzcyBub3QgYXZhaWxhYmxlAE5ldHdvcmsgaXMgZG93bgBOZXR3b3JrIHVucmVhY2hhYmxlAENvbm5lY3Rpb24gcmVzZXQgYnkgbmV0d29yawBDb25uZWN0aW9uIGFib3J0ZWQATm8gYnVmZmVyIHNwYWNlIGF2YWlsYWJsZQBTb2NrZXQgaXMgY29ubmVjdGVkAFNvY2tldCBub3QgY29ubmVjdGVkAENhbm5vdCBzZW5kIGFmdGVyIHNvY2tldCBzaHV0ZG93bgBPcGVyYXRpb24gYWxyZWFkeSBpbiBwcm9ncmVzcwBPcGVyYXRpb24gaW4gcHJvZ3Jlc3MAU3RhbGUgZmlsZSBoYW5kbGUAUmVtb3RlIEkvTyBlcnJvcgBRdW90YSBleGNlZWRlZABObyBtZWRpdW0gZm91bmQAV3JvbmcgbWVkaXVtIHR5cGUATm8gZXJyb3IgaW5mb3JtYXRpb24AQcCAAQuFARMAAAAUAAAAFQAAABYAAAAXAAAAGAAAABkAAAAaAAAAGwAAABwAAAAdAAAAHgAAAB8AAAAgAAAAIQAAACIAAAAjAAAAgERQADEAAAAyAAAAMwAAADQAAAA1AAAANgAAADcAAAA4AAAAOQAAADIAAAAzAAAANAAAADUAAAA2AAAANwAAADgAQfSCAQsCXEQAQbCDAQsQ/////////////////////w==\";io(Si)||(Si=x(Si));function Ls(We){try{if(We==Si&&Ae)return new Uint8Array(Ae);var tt=ii(We);if(tt)return tt;if(R)return R(We);throw\"sync fetching of the wasm failed: you can preload it to Module['wasmBinary'] manually, or emcc.py will do that for you when generating HTML (but not JS)\"}catch(It){Ti(It)}}function so(We,tt){var It,nr,$;try{$=Ls(We),nr=new WebAssembly.Module($),It=new WebAssembly.Instance(nr,tt)}catch(Le){var me=Le.toString();throw te(\"failed to compile wasm module: \"+me),(me.includes(\"imported Memory\")||me.includes(\"memory import\"))&&te(\"Memory size incompatibility issues may be due to changing INITIAL_MEMORY at runtime to something too large. Use ALLOW_MEMORY_GROWTH to allow any size memory (and also make sure not to set INITIAL_MEMORY at runtime to something smaller than it was at compile time).\"),Le}return[It,nr]}function cc(){var We={a:Ma};function tt($,me){var Le=$.exports;r.asm=Le,Ie=r.asm.g,J(Ie.buffer),Z=r.asm.W,an(r.asm.h),Ns(\"wasm-instantiate\")}if(Kn(\"wasm-instantiate\"),r.instantiateWasm)try{var It=r.instantiateWasm(We,tt);return It}catch($){return te(\"Module.instantiateWasm callback failed with error: \"+$),!1}var nr=so(Si,We);return tt(nr[0]),r.asm}function cu(We){return F.getFloat32(We,!0)}function op(We){return F.getFloat64(We,!0)}function ap(We){return F.getInt16(We,!0)}function Os(We){return F.getInt32(We,!0)}function Dn(We,tt){F.setInt32(We,tt,!0)}function oo(We){for(;We.length>0;){var tt=We.shift();if(typeof tt==\"function\"){tt(r);continue}var It=tt.func;typeof It==\"number\"?tt.arg===void 0?Z.get(It)():Z.get(It)(tt.arg):It(tt.arg===void 0?null:tt.arg)}}function Ms(We,tt){var It=new Date(Os((We>>2)*4)*1e3);Dn((tt>>2)*4,It.getUTCSeconds()),Dn((tt+4>>2)*4,It.getUTCMinutes()),Dn((tt+8>>2)*4,It.getUTCHours()),Dn((tt+12>>2)*4,It.getUTCDate()),Dn((tt+16>>2)*4,It.getUTCMonth()),Dn((tt+20>>2)*4,It.getUTCFullYear()-1900),Dn((tt+24>>2)*4,It.getUTCDay()),Dn((tt+36>>2)*4,0),Dn((tt+32>>2)*4,0);var nr=Date.UTC(It.getUTCFullYear(),0,1,0,0,0,0),$=(It.getTime()-nr)/(1e3*60*60*24)|0;return Dn((tt+28>>2)*4,$),Ms.GMTString||(Ms.GMTString=lt(\"GMT\")),Dn((tt+40>>2)*4,Ms.GMTString),tt}function ml(We,tt){return Ms(We,tt)}function yl(We,tt,It){Re.copyWithin(We,tt,tt+It)}function ao(We){try{return Ie.grow(We-be.byteLength+65535>>>16),J(Ie.buffer),1}catch{}}function Vn(We){var tt=Re.length;We=We>>>0;var It=2147483648;if(We>It)return!1;for(var nr=1;nr<=4;nr*=2){var $=tt*(1+.2/nr);$=Math.min($,We+100663296);var me=Math.min(It,ke(Math.max(We,$),65536)),Le=ao(me);if(Le)return!0}return!1}function On(We){he(We)}function Ni(We){var tt=Date.now()/1e3|0;return We&&Dn((We>>2)*4,tt),tt}function Mn(){if(Mn.called)return;Mn.called=!0;var We=new Date().getFullYear(),tt=new Date(We,0,1),It=new Date(We,6,1),nr=tt.getTimezoneOffset(),$=It.getTimezoneOffset(),me=Math.max(nr,$);Dn((ds()>>2)*4,me*60),Dn((gs()>>2)*4,Number(nr!=$));function Le(Zr){var qi=Zr.toTimeString().match(/\\(([A-Za-z ]+)\\)$/);return qi?qi[1]:\"GMT\"}var ft=Le(tt),pt=Le(It),Tt=lt(ft),er=lt(pt);$<nr?(Dn((wi()>>2)*4,Tt),Dn((wi()+4>>2)*4,er)):(Dn((wi()>>2)*4,er),Dn((wi()+4>>2)*4,Tt))}function _i(We){Mn();var tt=Date.UTC(Os((We+20>>2)*4)+1900,Os((We+16>>2)*4),Os((We+12>>2)*4),Os((We+8>>2)*4),Os((We+4>>2)*4),Os((We>>2)*4),0),It=new Date(tt);Dn((We+24>>2)*4,It.getUTCDay());var nr=Date.UTC(It.getUTCFullYear(),0,1,0,0,0,0),$=(It.getTime()-nr)/(1e3*60*60*24)|0;return Dn((We+28>>2)*4,$),It.getTime()/1e3|0}var tr=typeof atob==\"function\"?atob:function(We){var tt=\"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=\",It=\"\",nr,$,me,Le,ft,pt,Tt,er=0;We=We.replace(/[^A-Za-z0-9\\+\\/\\=]/g,\"\");do Le=tt.indexOf(We.charAt(er++)),ft=tt.indexOf(We.charAt(er++)),pt=tt.indexOf(We.charAt(er++)),Tt=tt.indexOf(We.charAt(er++)),nr=Le<<2|ft>>4,$=(ft&15)<<4|pt>>2,me=(pt&3)<<6|Tt,It=It+String.fromCharCode(nr),pt!==64&&(It=It+String.fromCharCode($)),Tt!==64&&(It=It+String.fromCharCode(me));while(er<We.length);return It};function Oe(We){if(typeof I==\"boolean\"&&I){var tt;try{tt=Buffer.from(We,\"base64\")}catch{tt=new Buffer(We,\"base64\")}return new Uint8Array(tt.buffer,tt.byteOffset,tt.byteLength)}try{for(var It=tr(We),nr=new Uint8Array(It.length),$=0;$<It.length;++$)nr[$]=It.charCodeAt($);return nr}catch{throw new Error(\"Converting base64 string to bytes failed.\")}}function ii(We){if(!!io(We))return Oe(We.slice(ps.length))}var Ma={e:ml,c:yl,d:Vn,a:On,b:Ni,f:_i},hr=cc(),uc=r.___wasm_call_ctors=hr.h,uu=r._zip_ext_count_symlinks=hr.i,Ac=r._zip_file_get_external_attributes=hr.j,El=r._zipstruct_statS=hr.k,vA=r._zipstruct_stat_size=hr.l,Au=r._zipstruct_stat_mtime=hr.m,Ce=r._zipstruct_stat_crc=hr.n,Rt=r._zipstruct_errorS=hr.o,fc=r._zipstruct_error_code_zip=hr.p,Hi=r._zipstruct_stat_comp_size=hr.q,fu=r._zipstruct_stat_comp_method=hr.r,Yt=r._zip_close=hr.s,Cl=r._zip_delete=hr.t,DA=r._zip_dir_add=hr.u,lp=r._zip_discard=hr.v,pc=r._zip_error_init_with_code=hr.w,PA=r._zip_get_error=hr.x,Qn=r._zip_file_get_error=hr.y,hi=r._zip_error_strerror=hr.z,hc=r._zip_fclose=hr.A,SA=r._zip_file_add=hr.B,sa=r._free=hr.C,Li=r._malloc=hr.D,_o=r._zip_source_error=hr.E,Ze=r._zip_source_seek=hr.F,lo=r._zip_file_set_external_attributes=hr.G,gc=r._zip_file_set_mtime=hr.H,pu=r._zip_fopen_index=hr.I,ji=r._zip_fread=hr.J,hu=r._zip_get_name=hr.K,bA=r._zip_get_num_entries=hr.L,Ua=r._zip_source_read=hr.M,dc=r._zip_name_locate=hr.N,hs=r._zip_open_from_source=hr.O,_t=r._zip_set_file_compression=hr.P,Fn=r._zip_source_buffer=hr.Q,Ci=r._zip_source_buffer_create=hr.R,oa=r._zip_source_close=hr.S,co=r._zip_source_free=hr.T,Us=r._zip_source_keep=hr.U,aa=r._zip_source_open=hr.V,la=r._zip_source_tell=hr.X,Ho=r._zip_stat_index=hr.Y,wi=r.__get_tzname=hr.Z,gs=r.__get_daylight=hr._,ds=r.__get_timezone=hr.$,ms=r.stackSave=hr.aa,_s=r.stackRestore=hr.ba,Un=r.stackAlloc=hr.ca;r.cwrap=ne,r.getValue=ae;var Pn;Wr=function We(){Pn||ys(),Pn||(Wr=We)};function ys(We){if(We=We||A,mr>0||(dt(),mr>0))return;function tt(){Pn||(Pn=!0,r.calledRun=!0,!Fe&&(jt(),o(r),r.onRuntimeInitialized&&r.onRuntimeInitialized(),$t()))}r.setStatus?(r.setStatus(\"Running...\"),setTimeout(function(){setTimeout(function(){r.setStatus(\"\")},1),tt()},1)):tt()}if(r.run=ys,r.preInit)for(typeof r.preInit==\"function\"&&(r.preInit=[r.preInit]);r.preInit.length>0;)r.preInit.pop()();return ys(),e}}();typeof Rb==\"object\"&&typeof nU==\"object\"?nU.exports=rU:typeof define==\"function\"&&define.amd?define([],function(){return rU}):typeof Rb==\"object\"&&(Rb.createModule=rU)});var Nf,Lle,Ole,Mle=Et(()=>{Nf=[\"number\",\"number\"],Lle=(ee=>(ee[ee.ZIP_ER_OK=0]=\"ZIP_ER_OK\",ee[ee.ZIP_ER_MULTIDISK=1]=\"ZIP_ER_MULTIDISK\",ee[ee.ZIP_ER_RENAME=2]=\"ZIP_ER_RENAME\",ee[ee.ZIP_ER_CLOSE=3]=\"ZIP_ER_CLOSE\",ee[ee.ZIP_ER_SEEK=4]=\"ZIP_ER_SEEK\",ee[ee.ZIP_ER_READ=5]=\"ZIP_ER_READ\",ee[ee.ZIP_ER_WRITE=6]=\"ZIP_ER_WRITE\",ee[ee.ZIP_ER_CRC=7]=\"ZIP_ER_CRC\",ee[ee.ZIP_ER_ZIPCLOSED=8]=\"ZIP_ER_ZIPCLOSED\",ee[ee.ZIP_ER_NOENT=9]=\"ZIP_ER_NOENT\",ee[ee.ZIP_ER_EXISTS=10]=\"ZIP_ER_EXISTS\",ee[ee.ZIP_ER_OPEN=11]=\"ZIP_ER_OPEN\",ee[ee.ZIP_ER_TMPOPEN=12]=\"ZIP_ER_TMPOPEN\",ee[ee.ZIP_ER_ZLIB=13]=\"ZIP_ER_ZLIB\",ee[ee.ZIP_ER_MEMORY=14]=\"ZIP_ER_MEMORY\",ee[ee.ZIP_ER_CHANGED=15]=\"ZIP_ER_CHANGED\",ee[ee.ZIP_ER_COMPNOTSUPP=16]=\"ZIP_ER_COMPNOTSUPP\",ee[ee.ZIP_ER_EOF=17]=\"ZIP_ER_EOF\",ee[ee.ZIP_ER_INVAL=18]=\"ZIP_ER_INVAL\",ee[ee.ZIP_ER_NOZIP=19]=\"ZIP_ER_NOZIP\",ee[ee.ZIP_ER_INTERNAL=20]=\"ZIP_ER_INTERNAL\",ee[ee.ZIP_ER_INCONS=21]=\"ZIP_ER_INCONS\",ee[ee.ZIP_ER_REMOVE=22]=\"ZIP_ER_REMOVE\",ee[ee.ZIP_ER_DELETED=23]=\"ZIP_ER_DELETED\",ee[ee.ZIP_ER_ENCRNOTSUPP=24]=\"ZIP_ER_ENCRNOTSUPP\",ee[ee.ZIP_ER_RDONLY=25]=\"ZIP_ER_RDONLY\",ee[ee.ZIP_ER_NOPASSWD=26]=\"ZIP_ER_NOPASSWD\",ee[ee.ZIP_ER_WRONGPASSWD=27]=\"ZIP_ER_WRONGPASSWD\",ee[ee.ZIP_ER_OPNOTSUPP=28]=\"ZIP_ER_OPNOTSUPP\",ee[ee.ZIP_ER_INUSE=29]=\"ZIP_ER_INUSE\",ee[ee.ZIP_ER_TELL=30]=\"ZIP_ER_TELL\",ee[ee.ZIP_ER_COMPRESSED_DATA=31]=\"ZIP_ER_COMPRESSED_DATA\",ee))(Lle||{}),Ole=t=>({get HEAPU8(){return t.HEAPU8},errors:Lle,SEEK_SET:0,SEEK_CUR:1,SEEK_END:2,ZIP_CHECKCONS:4,ZIP_EXCL:2,ZIP_RDONLY:16,ZIP_FL_OVERWRITE:8192,ZIP_FL_COMPRESSED:4,ZIP_OPSYS_DOS:0,ZIP_OPSYS_AMIGA:1,ZIP_OPSYS_OPENVMS:2,ZIP_OPSYS_UNIX:3,ZIP_OPSYS_VM_CMS:4,ZIP_OPSYS_ATARI_ST:5,ZIP_OPSYS_OS_2:6,ZIP_OPSYS_MACINTOSH:7,ZIP_OPSYS_Z_SYSTEM:8,ZIP_OPSYS_CPM:9,ZIP_OPSYS_WINDOWS_NTFS:10,ZIP_OPSYS_MVS:11,ZIP_OPSYS_VSE:12,ZIP_OPSYS_ACORN_RISC:13,ZIP_OPSYS_VFAT:14,ZIP_OPSYS_ALTERNATE_MVS:15,ZIP_OPSYS_BEOS:16,ZIP_OPSYS_TANDEM:17,ZIP_OPSYS_OS_400:18,ZIP_OPSYS_OS_X:19,ZIP_CM_DEFAULT:-1,ZIP_CM_STORE:0,ZIP_CM_DEFLATE:8,uint08S:t._malloc(1),uint32S:t._malloc(4),malloc:t._malloc,free:t._free,getValue:t.getValue,openFromSource:t.cwrap(\"zip_open_from_source\",\"number\",[\"number\",\"number\",\"number\"]),close:t.cwrap(\"zip_close\",\"number\",[\"number\"]),discard:t.cwrap(\"zip_discard\",null,[\"number\"]),getError:t.cwrap(\"zip_get_error\",\"number\",[\"number\"]),getName:t.cwrap(\"zip_get_name\",\"string\",[\"number\",\"number\",\"number\"]),getNumEntries:t.cwrap(\"zip_get_num_entries\",\"number\",[\"number\",\"number\"]),delete:t.cwrap(\"zip_delete\",\"number\",[\"number\",\"number\"]),statIndex:t.cwrap(\"zip_stat_index\",\"number\",[\"number\",...Nf,\"number\",\"number\"]),fopenIndex:t.cwrap(\"zip_fopen_index\",\"number\",[\"number\",...Nf,\"number\"]),fread:t.cwrap(\"zip_fread\",\"number\",[\"number\",\"number\",\"number\",\"number\"]),fclose:t.cwrap(\"zip_fclose\",\"number\",[\"number\"]),dir:{add:t.cwrap(\"zip_dir_add\",\"number\",[\"number\",\"string\"])},file:{add:t.cwrap(\"zip_file_add\",\"number\",[\"number\",\"string\",\"number\",\"number\"]),getError:t.cwrap(\"zip_file_get_error\",\"number\",[\"number\"]),getExternalAttributes:t.cwrap(\"zip_file_get_external_attributes\",\"number\",[\"number\",...Nf,\"number\",\"number\",\"number\"]),setExternalAttributes:t.cwrap(\"zip_file_set_external_attributes\",\"number\",[\"number\",...Nf,\"number\",\"number\",\"number\"]),setMtime:t.cwrap(\"zip_file_set_mtime\",\"number\",[\"number\",...Nf,\"number\",\"number\"]),setCompression:t.cwrap(\"zip_set_file_compression\",\"number\",[\"number\",...Nf,\"number\",\"number\"])},ext:{countSymlinks:t.cwrap(\"zip_ext_count_symlinks\",\"number\",[\"number\"])},error:{initWithCode:t.cwrap(\"zip_error_init_with_code\",null,[\"number\",\"number\"]),strerror:t.cwrap(\"zip_error_strerror\",\"string\",[\"number\"])},name:{locate:t.cwrap(\"zip_name_locate\",\"number\",[\"number\",\"string\",\"number\"])},source:{fromUnattachedBuffer:t.cwrap(\"zip_source_buffer_create\",\"number\",[\"number\",...Nf,\"number\",\"number\"]),fromBuffer:t.cwrap(\"zip_source_buffer\",\"number\",[\"number\",\"number\",...Nf,\"number\"]),free:t.cwrap(\"zip_source_free\",null,[\"number\"]),keep:t.cwrap(\"zip_source_keep\",null,[\"number\"]),open:t.cwrap(\"zip_source_open\",\"number\",[\"number\"]),close:t.cwrap(\"zip_source_close\",\"number\",[\"number\"]),seek:t.cwrap(\"zip_source_seek\",\"number\",[\"number\",...Nf,\"number\"]),tell:t.cwrap(\"zip_source_tell\",\"number\",[\"number\"]),read:t.cwrap(\"zip_source_read\",\"number\",[\"number\",\"number\",\"number\"]),error:t.cwrap(\"zip_source_error\",\"number\",[\"number\"])},struct:{statS:t.cwrap(\"zipstruct_statS\",\"number\",[]),statSize:t.cwrap(\"zipstruct_stat_size\",\"number\",[\"number\"]),statCompSize:t.cwrap(\"zipstruct_stat_comp_size\",\"number\",[\"number\"]),statCompMethod:t.cwrap(\"zipstruct_stat_comp_method\",\"number\",[\"number\"]),statMtime:t.cwrap(\"zipstruct_stat_mtime\",\"number\",[\"number\"]),statCrc:t.cwrap(\"zipstruct_stat_crc\",\"number\",[\"number\"]),errorS:t.cwrap(\"zipstruct_errorS\",\"number\",[]),errorCodeZip:t.cwrap(\"zipstruct_error_code_zip\",\"number\",[\"number\"])}})});function iU(t,e){let r=t.indexOf(e);if(r<=0)return null;let o=r;for(;r>=0&&(o=r+e.length,t[o]!==V.sep);){if(t[r-1]===V.sep)return null;r=t.indexOf(e,o)}return t.length>o&&t[o]!==V.sep?null:t.slice(0,o)}var zl,Ule=Et(()=>{Pt();Pt();nA();zl=class extends Up{static async openPromise(e,r){let o=new zl(r);try{return await e(o)}finally{o.saveAndClose()}}constructor(e={}){let r=e.fileExtensions,o=e.readOnlyArchives,a=typeof r>\"u\"?A=>iU(A,\".zip\"):A=>{for(let p of r){let h=iU(A,p);if(h)return h}return null},n=(A,p)=>new Ji(p,{baseFs:A,readOnly:o,stats:A.statSync(p)}),u=async(A,p)=>{let h={baseFs:A,readOnly:o,stats:await A.statPromise(p)};return()=>new Ji(p,h)};super({...e,factorySync:n,factoryPromise:u,getMountPoint:a})}}});function fot(t){if(typeof t==\"string\"&&String(+t)===t)return+t;if(typeof t==\"number\"&&Number.isFinite(t))return t<0?Date.now()/1e3:t;if(_le.types.isDate(t))return t.getTime()/1e3;throw new Error(\"Invalid time\")}function Tb(){return Buffer.from([80,75,5,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0])}var ta,sU,_le,oU,Hle,Nb,Ji,aU=Et(()=>{Pt();Pt();Pt();Pt();Pt();Pt();ta=Be(\"fs\"),sU=Be(\"stream\"),_le=Be(\"util\"),oU=$e(Be(\"zlib\"));tU();Hle=\"mixed\";Nb=class extends Error{constructor(r,o){super(r);this.name=\"Libzip Error\",this.code=o}},Ji=class extends Mu{constructor(r,o={}){super();this.listings=new Map;this.entries=new Map;this.fileSources=new Map;this.fds=new Map;this.nextFd=0;this.ready=!1;this.readOnly=!1;let a=o;if(this.level=typeof a.level<\"u\"?a.level:Hle,r??=Tb(),typeof r==\"string\"){let{baseFs:A=new Tn}=a;this.baseFs=A,this.path=r}else this.path=null,this.baseFs=null;if(o.stats)this.stats=o.stats;else if(typeof r==\"string\")try{this.stats=this.baseFs.statSync(r)}catch(A){if(A.code===\"ENOENT\"&&a.create)this.stats=Ea.makeDefaultStats();else throw A}else this.stats=Ea.makeDefaultStats();this.libzip=P1();let n=this.libzip.malloc(4);try{let A=0;o.readOnly&&(A|=this.libzip.ZIP_RDONLY,this.readOnly=!0),typeof r==\"string\"&&(r=a.create?Tb():this.baseFs.readFileSync(r));let p=this.allocateUnattachedSource(r);try{this.zip=this.libzip.openFromSource(p,A,n),this.lzSource=p}catch(h){throw this.libzip.source.free(p),h}if(this.zip===0){let h=this.libzip.struct.errorS();throw this.libzip.error.initWithCode(h,this.libzip.getValue(n,\"i32\")),this.makeLibzipError(h)}}finally{this.libzip.free(n)}this.listings.set(Bt.root,new Set);let u=this.libzip.getNumEntries(this.zip,0);for(let A=0;A<u;++A){let p=this.libzip.getName(this.zip,A,0);if(V.isAbsolute(p))continue;let h=V.resolve(Bt.root,p);this.registerEntry(h,A),p.endsWith(\"/\")&&this.registerListing(h)}if(this.symlinkCount=this.libzip.ext.countSymlinks(this.zip),this.symlinkCount===-1)throw this.makeLibzipError(this.libzip.getError(this.zip));this.ready=!0}makeLibzipError(r){let o=this.libzip.struct.errorCodeZip(r),a=this.libzip.error.strerror(r),n=new Nb(a,this.libzip.errors[o]);if(o===this.libzip.errors.ZIP_ER_CHANGED)throw new Error(`Assertion failed: Unexpected libzip error: ${n.message}`);return n}getExtractHint(r){for(let o of this.entries.keys()){let a=this.pathUtils.extname(o);if(r.relevantExtensions.has(a))return!0}return!1}getAllFiles(){return Array.from(this.entries.keys())}getRealPath(){if(!this.path)throw new Error(\"ZipFS don't have real paths when loaded from a buffer\");return this.path}prepareClose(){if(!this.ready)throw ar.EBUSY(\"archive closed, close\");Og(this)}getBufferAndClose(){if(this.prepareClose(),this.entries.size===0)return this.discardAndClose(),Tb();try{if(this.libzip.source.keep(this.lzSource),this.libzip.close(this.zip)===-1)throw this.makeLibzipError(this.libzip.getError(this.zip));if(this.libzip.source.open(this.lzSource)===-1)throw this.makeLibzipError(this.libzip.source.error(this.lzSource));if(this.libzip.source.seek(this.lzSource,0,0,this.libzip.SEEK_END)===-1)throw this.makeLibzipError(this.libzip.source.error(this.lzSource));let r=this.libzip.source.tell(this.lzSource);if(r===-1)throw this.makeLibzipError(this.libzip.source.error(this.lzSource));if(this.libzip.source.seek(this.lzSource,0,0,this.libzip.SEEK_SET)===-1)throw this.makeLibzipError(this.libzip.source.error(this.lzSource));let o=this.libzip.malloc(r);if(!o)throw new Error(\"Couldn't allocate enough memory\");try{let a=this.libzip.source.read(this.lzSource,o,r);if(a===-1)throw this.makeLibzipError(this.libzip.source.error(this.lzSource));if(a<r)throw new Error(\"Incomplete read\");if(a>r)throw new Error(\"Overread\");let n=this.libzip.HEAPU8.subarray(o,o+r);return Buffer.from(n)}finally{this.libzip.free(o)}}finally{this.libzip.source.close(this.lzSource),this.libzip.source.free(this.lzSource),this.ready=!1}}discardAndClose(){this.prepareClose(),this.libzip.discard(this.zip),this.ready=!1}saveAndClose(){if(!this.path||!this.baseFs)throw new Error(\"ZipFS cannot be saved and must be discarded when loaded from a buffer\");if(this.readOnly){this.discardAndClose();return}let r=this.baseFs.existsSync(this.path)||this.stats.mode===Ea.DEFAULT_MODE?void 0:this.stats.mode;this.baseFs.writeFileSync(this.path,this.getBufferAndClose(),{mode:r}),this.ready=!1}resolve(r){return V.resolve(Bt.root,r)}async openPromise(r,o,a){return this.openSync(r,o,a)}openSync(r,o,a){let n=this.nextFd++;return this.fds.set(n,{cursor:0,p:r}),n}hasOpenFileHandles(){return!!this.fds.size}async opendirPromise(r,o){return this.opendirSync(r,o)}opendirSync(r,o={}){let a=this.resolveFilename(`opendir '${r}'`,r);if(!this.entries.has(a)&&!this.listings.has(a))throw ar.ENOENT(`opendir '${r}'`);let n=this.listings.get(a);if(!n)throw ar.ENOTDIR(`opendir '${r}'`);let u=[...n],A=this.openSync(a,\"r\");return SD(this,a,u,{onClose:()=>{this.closeSync(A)}})}async readPromise(r,o,a,n,u){return this.readSync(r,o,a,n,u)}readSync(r,o,a=0,n=o.byteLength,u=-1){let A=this.fds.get(r);if(typeof A>\"u\")throw ar.EBADF(\"read\");let p=u===-1||u===null?A.cursor:u,h=this.readFileSync(A.p);h.copy(o,a,p,p+n);let C=Math.max(0,Math.min(h.length-p,n));return(u===-1||u===null)&&(A.cursor+=C),C}async writePromise(r,o,a,n,u){return typeof o==\"string\"?this.writeSync(r,o,u):this.writeSync(r,o,a,n,u)}writeSync(r,o,a,n,u){throw typeof this.fds.get(r)>\"u\"?ar.EBADF(\"read\"):new Error(\"Unimplemented\")}async closePromise(r){return this.closeSync(r)}closeSync(r){if(typeof this.fds.get(r)>\"u\")throw ar.EBADF(\"read\");this.fds.delete(r)}createReadStream(r,{encoding:o}={}){if(r===null)throw new Error(\"Unimplemented\");let a=this.openSync(r,\"r\"),n=Object.assign(new sU.PassThrough({emitClose:!0,autoDestroy:!0,destroy:(A,p)=>{clearImmediate(u),this.closeSync(a),p(A)}}),{close(){n.destroy()},bytesRead:0,path:r,pending:!1}),u=setImmediate(async()=>{try{let A=await this.readFilePromise(r,o);n.bytesRead=A.length,n.end(A)}catch(A){n.destroy(A)}});return n}createWriteStream(r,{encoding:o}={}){if(this.readOnly)throw ar.EROFS(`open '${r}'`);if(r===null)throw new Error(\"Unimplemented\");let a=[],n=this.openSync(r,\"w\"),u=Object.assign(new sU.PassThrough({autoDestroy:!0,emitClose:!0,destroy:(A,p)=>{try{A?p(A):(this.writeFileSync(r,Buffer.concat(a),o),p(null))}catch(h){p(h)}finally{this.closeSync(n)}}}),{close(){u.destroy()},bytesWritten:0,path:r,pending:!1});return u.on(\"data\",A=>{let p=Buffer.from(A);u.bytesWritten+=p.length,a.push(p)}),u}async realpathPromise(r){return this.realpathSync(r)}realpathSync(r){let o=this.resolveFilename(`lstat '${r}'`,r);if(!this.entries.has(o)&&!this.listings.has(o))throw ar.ENOENT(`lstat '${r}'`);return o}async existsPromise(r){return this.existsSync(r)}existsSync(r){if(!this.ready)throw ar.EBUSY(`archive closed, existsSync '${r}'`);if(this.symlinkCount===0){let a=V.resolve(Bt.root,r);return this.entries.has(a)||this.listings.has(a)}let o;try{o=this.resolveFilename(`stat '${r}'`,r,void 0,!1)}catch{return!1}return o===void 0?!1:this.entries.has(o)||this.listings.has(o)}async accessPromise(r,o){return this.accessSync(r,o)}accessSync(r,o=ta.constants.F_OK){let a=this.resolveFilename(`access '${r}'`,r);if(!this.entries.has(a)&&!this.listings.has(a))throw ar.ENOENT(`access '${r}'`);if(this.readOnly&&o&ta.constants.W_OK)throw ar.EROFS(`access '${r}'`)}async statPromise(r,o={bigint:!1}){return o.bigint?this.statSync(r,{bigint:!0}):this.statSync(r)}statSync(r,o={bigint:!1,throwIfNoEntry:!0}){let a=this.resolveFilename(`stat '${r}'`,r,void 0,o.throwIfNoEntry);if(a!==void 0){if(!this.entries.has(a)&&!this.listings.has(a)){if(o.throwIfNoEntry===!1)return;throw ar.ENOENT(`stat '${r}'`)}if(r[r.length-1]===\"/\"&&!this.listings.has(a))throw ar.ENOTDIR(`stat '${r}'`);return this.statImpl(`stat '${r}'`,a,o)}}async fstatPromise(r,o){return this.fstatSync(r,o)}fstatSync(r,o){let a=this.fds.get(r);if(typeof a>\"u\")throw ar.EBADF(\"fstatSync\");let{p:n}=a,u=this.resolveFilename(`stat '${n}'`,n);if(!this.entries.has(u)&&!this.listings.has(u))throw ar.ENOENT(`stat '${n}'`);if(n[n.length-1]===\"/\"&&!this.listings.has(u))throw ar.ENOTDIR(`stat '${n}'`);return this.statImpl(`fstat '${n}'`,u,o)}async lstatPromise(r,o={bigint:!1}){return o.bigint?this.lstatSync(r,{bigint:!0}):this.lstatSync(r)}lstatSync(r,o={bigint:!1,throwIfNoEntry:!0}){let a=this.resolveFilename(`lstat '${r}'`,r,!1,o.throwIfNoEntry);if(a!==void 0){if(!this.entries.has(a)&&!this.listings.has(a)){if(o.throwIfNoEntry===!1)return;throw ar.ENOENT(`lstat '${r}'`)}if(r[r.length-1]===\"/\"&&!this.listings.has(a))throw ar.ENOTDIR(`lstat '${r}'`);return this.statImpl(`lstat '${r}'`,a,o)}}statImpl(r,o,a={}){let n=this.entries.get(o);if(typeof n<\"u\"){let u=this.libzip.struct.statS();if(this.libzip.statIndex(this.zip,n,0,0,u)===-1)throw this.makeLibzipError(this.libzip.getError(this.zip));let p=this.stats.uid,h=this.stats.gid,C=this.libzip.struct.statSize(u)>>>0,I=512,v=Math.ceil(C/I),x=(this.libzip.struct.statMtime(u)>>>0)*1e3,E=x,R=x,L=x,U=new Date(E),z=new Date(R),te=new Date(L),le=new Date(x),he=this.listings.has(o)?ta.constants.S_IFDIR:this.isSymbolicLink(n)?ta.constants.S_IFLNK:ta.constants.S_IFREG,Ae=he===ta.constants.S_IFDIR?493:420,ye=he|this.getUnixMode(n,Ae)&511,ae=this.libzip.struct.statCrc(u),Ie=Object.assign(new Ea.StatEntry,{uid:p,gid:h,size:C,blksize:I,blocks:v,atime:U,birthtime:z,ctime:te,mtime:le,atimeMs:E,birthtimeMs:R,ctimeMs:L,mtimeMs:x,mode:ye,crc:ae});return a.bigint===!0?Ea.convertToBigIntStats(Ie):Ie}if(this.listings.has(o)){let u=this.stats.uid,A=this.stats.gid,p=0,h=512,C=0,I=this.stats.mtimeMs,v=this.stats.mtimeMs,x=this.stats.mtimeMs,E=this.stats.mtimeMs,R=new Date(I),L=new Date(v),U=new Date(x),z=new Date(E),te=ta.constants.S_IFDIR|493,le=0,he=Object.assign(new Ea.StatEntry,{uid:u,gid:A,size:p,blksize:h,blocks:C,atime:R,birthtime:L,ctime:U,mtime:z,atimeMs:I,birthtimeMs:v,ctimeMs:x,mtimeMs:E,mode:te,crc:le});return a.bigint===!0?Ea.convertToBigIntStats(he):he}throw new Error(\"Unreachable\")}getUnixMode(r,o){if(this.libzip.file.getExternalAttributes(this.zip,r,0,0,this.libzip.uint08S,this.libzip.uint32S)===-1)throw this.makeLibzipError(this.libzip.getError(this.zip));return this.libzip.getValue(this.libzip.uint08S,\"i8\")>>>0!==this.libzip.ZIP_OPSYS_UNIX?o:this.libzip.getValue(this.libzip.uint32S,\"i32\")>>>16}registerListing(r){let o=this.listings.get(r);if(o)return o;this.registerListing(V.dirname(r)).add(V.basename(r));let n=new Set;return this.listings.set(r,n),n}registerEntry(r,o){this.registerListing(V.dirname(r)).add(V.basename(r)),this.entries.set(r,o)}unregisterListing(r){this.listings.delete(r),this.listings.get(V.dirname(r))?.delete(V.basename(r))}unregisterEntry(r){this.unregisterListing(r);let o=this.entries.get(r);this.entries.delete(r),!(typeof o>\"u\")&&(this.fileSources.delete(o),this.isSymbolicLink(o)&&this.symlinkCount--)}deleteEntry(r,o){if(this.unregisterEntry(r),this.libzip.delete(this.zip,o)===-1)throw this.makeLibzipError(this.libzip.getError(this.zip))}resolveFilename(r,o,a=!0,n=!0){if(!this.ready)throw ar.EBUSY(`archive closed, ${r}`);let u=V.resolve(Bt.root,o);if(u===\"/\")return Bt.root;let A=this.entries.get(u);if(a&&A!==void 0)if(this.symlinkCount!==0&&this.isSymbolicLink(A)){let p=this.getFileSource(A).toString();return this.resolveFilename(r,V.resolve(V.dirname(u),p),!0,n)}else return u;for(;;){let p=this.resolveFilename(r,V.dirname(u),!0,n);if(p===void 0)return p;let h=this.listings.has(p),C=this.entries.has(p);if(!h&&!C){if(n===!1)return;throw ar.ENOENT(r)}if(!h)throw ar.ENOTDIR(r);if(u=V.resolve(p,V.basename(u)),!a||this.symlinkCount===0)break;let I=this.libzip.name.locate(this.zip,u.slice(1),0);if(I===-1)break;if(this.isSymbolicLink(I)){let v=this.getFileSource(I).toString();u=V.resolve(V.dirname(u),v)}else break}return u}allocateBuffer(r){Buffer.isBuffer(r)||(r=Buffer.from(r));let o=this.libzip.malloc(r.byteLength);if(!o)throw new Error(\"Couldn't allocate enough memory\");return new Uint8Array(this.libzip.HEAPU8.buffer,o,r.byteLength).set(r),{buffer:o,byteLength:r.byteLength}}allocateUnattachedSource(r){let o=this.libzip.struct.errorS(),{buffer:a,byteLength:n}=this.allocateBuffer(r),u=this.libzip.source.fromUnattachedBuffer(a,n,0,1,o);if(u===0)throw this.libzip.free(o),this.makeLibzipError(o);return u}allocateSource(r){let{buffer:o,byteLength:a}=this.allocateBuffer(r),n=this.libzip.source.fromBuffer(this.zip,o,a,0,1);if(n===0)throw this.libzip.free(o),this.makeLibzipError(this.libzip.getError(this.zip));return n}setFileSource(r,o){let a=Buffer.isBuffer(o)?o:Buffer.from(o),n=V.relative(Bt.root,r),u=this.allocateSource(o);try{let A=this.libzip.file.add(this.zip,n,u,this.libzip.ZIP_FL_OVERWRITE);if(A===-1)throw this.makeLibzipError(this.libzip.getError(this.zip));if(this.level!==\"mixed\"){let p=this.level===0?this.libzip.ZIP_CM_STORE:this.libzip.ZIP_CM_DEFLATE;if(this.libzip.file.setCompression(this.zip,A,0,p,this.level)===-1)throw this.makeLibzipError(this.libzip.getError(this.zip))}return this.fileSources.set(A,a),A}catch(A){throw this.libzip.source.free(u),A}}isSymbolicLink(r){if(this.symlinkCount===0)return!1;if(this.libzip.file.getExternalAttributes(this.zip,r,0,0,this.libzip.uint08S,this.libzip.uint32S)===-1)throw this.makeLibzipError(this.libzip.getError(this.zip));return this.libzip.getValue(this.libzip.uint08S,\"i8\")>>>0!==this.libzip.ZIP_OPSYS_UNIX?!1:(this.libzip.getValue(this.libzip.uint32S,\"i32\")>>>16&ta.constants.S_IFMT)===ta.constants.S_IFLNK}getFileSource(r,o={asyncDecompress:!1}){let a=this.fileSources.get(r);if(typeof a<\"u\")return a;let n=this.libzip.struct.statS();if(this.libzip.statIndex(this.zip,r,0,0,n)===-1)throw this.makeLibzipError(this.libzip.getError(this.zip));let A=this.libzip.struct.statCompSize(n),p=this.libzip.struct.statCompMethod(n),h=this.libzip.malloc(A);try{let C=this.libzip.fopenIndex(this.zip,r,0,this.libzip.ZIP_FL_COMPRESSED);if(C===0)throw this.makeLibzipError(this.libzip.getError(this.zip));try{let I=this.libzip.fread(C,h,A,0);if(I===-1)throw this.makeLibzipError(this.libzip.file.getError(C));if(I<A)throw new Error(\"Incomplete read\");if(I>A)throw new Error(\"Overread\");let v=this.libzip.HEAPU8.subarray(h,h+A),x=Buffer.from(v);if(p===0)return this.fileSources.set(r,x),x;if(o.asyncDecompress)return new Promise((E,R)=>{oU.default.inflateRaw(x,(L,U)=>{L?R(L):(this.fileSources.set(r,U),E(U))})});{let E=oU.default.inflateRawSync(x);return this.fileSources.set(r,E),E}}finally{this.libzip.fclose(C)}}finally{this.libzip.free(h)}}async fchmodPromise(r,o){return this.chmodPromise(this.fdToPath(r,\"fchmod\"),o)}fchmodSync(r,o){return this.chmodSync(this.fdToPath(r,\"fchmodSync\"),o)}async chmodPromise(r,o){return this.chmodSync(r,o)}chmodSync(r,o){if(this.readOnly)throw ar.EROFS(`chmod '${r}'`);o&=493;let a=this.resolveFilename(`chmod '${r}'`,r,!1),n=this.entries.get(a);if(typeof n>\"u\")throw new Error(`Assertion failed: The entry should have been registered (${a})`);let A=this.getUnixMode(n,ta.constants.S_IFREG|0)&-512|o;if(this.libzip.file.setExternalAttributes(this.zip,n,0,0,this.libzip.ZIP_OPSYS_UNIX,A<<16)===-1)throw this.makeLibzipError(this.libzip.getError(this.zip))}async fchownPromise(r,o,a){return this.chownPromise(this.fdToPath(r,\"fchown\"),o,a)}fchownSync(r,o,a){return this.chownSync(this.fdToPath(r,\"fchownSync\"),o,a)}async chownPromise(r,o,a){return this.chownSync(r,o,a)}chownSync(r,o,a){throw new Error(\"Unimplemented\")}async renamePromise(r,o){return this.renameSync(r,o)}renameSync(r,o){throw new Error(\"Unimplemented\")}async copyFilePromise(r,o,a){let{indexSource:n,indexDest:u,resolvedDestP:A}=this.prepareCopyFile(r,o,a),p=await this.getFileSource(n,{asyncDecompress:!0}),h=this.setFileSource(A,p);h!==u&&this.registerEntry(A,h)}copyFileSync(r,o,a=0){let{indexSource:n,indexDest:u,resolvedDestP:A}=this.prepareCopyFile(r,o,a),p=this.getFileSource(n),h=this.setFileSource(A,p);h!==u&&this.registerEntry(A,h)}prepareCopyFile(r,o,a=0){if(this.readOnly)throw ar.EROFS(`copyfile '${r} -> '${o}'`);if((a&ta.constants.COPYFILE_FICLONE_FORCE)!==0)throw ar.ENOSYS(\"unsupported clone operation\",`copyfile '${r}' -> ${o}'`);let n=this.resolveFilename(`copyfile '${r} -> ${o}'`,r),u=this.entries.get(n);if(typeof u>\"u\")throw ar.EINVAL(`copyfile '${r}' -> '${o}'`);let A=this.resolveFilename(`copyfile '${r}' -> ${o}'`,o),p=this.entries.get(A);if((a&(ta.constants.COPYFILE_EXCL|ta.constants.COPYFILE_FICLONE_FORCE))!==0&&typeof p<\"u\")throw ar.EEXIST(`copyfile '${r}' -> '${o}'`);return{indexSource:u,resolvedDestP:A,indexDest:p}}async appendFilePromise(r,o,a){if(this.readOnly)throw ar.EROFS(`open '${r}'`);return typeof a>\"u\"?a={flag:\"a\"}:typeof a==\"string\"?a={flag:\"a\",encoding:a}:typeof a.flag>\"u\"&&(a={flag:\"a\",...a}),this.writeFilePromise(r,o,a)}appendFileSync(r,o,a={}){if(this.readOnly)throw ar.EROFS(`open '${r}'`);return typeof a>\"u\"?a={flag:\"a\"}:typeof a==\"string\"?a={flag:\"a\",encoding:a}:typeof a.flag>\"u\"&&(a={flag:\"a\",...a}),this.writeFileSync(r,o,a)}fdToPath(r,o){let a=this.fds.get(r)?.p;if(typeof a>\"u\")throw ar.EBADF(o);return a}async writeFilePromise(r,o,a){let{encoding:n,mode:u,index:A,resolvedP:p}=this.prepareWriteFile(r,a);A!==void 0&&typeof a==\"object\"&&a.flag&&a.flag.includes(\"a\")&&(o=Buffer.concat([await this.getFileSource(A,{asyncDecompress:!0}),Buffer.from(o)])),n!==null&&(o=o.toString(n));let h=this.setFileSource(p,o);h!==A&&this.registerEntry(p,h),u!==null&&await this.chmodPromise(p,u)}writeFileSync(r,o,a){let{encoding:n,mode:u,index:A,resolvedP:p}=this.prepareWriteFile(r,a);A!==void 0&&typeof a==\"object\"&&a.flag&&a.flag.includes(\"a\")&&(o=Buffer.concat([this.getFileSource(A),Buffer.from(o)])),n!==null&&(o=o.toString(n));let h=this.setFileSource(p,o);h!==A&&this.registerEntry(p,h),u!==null&&this.chmodSync(p,u)}prepareWriteFile(r,o){if(typeof r==\"number\"&&(r=this.fdToPath(r,\"read\")),this.readOnly)throw ar.EROFS(`open '${r}'`);let a=this.resolveFilename(`open '${r}'`,r);if(this.listings.has(a))throw ar.EISDIR(`open '${r}'`);let n=null,u=null;typeof o==\"string\"?n=o:typeof o==\"object\"&&({encoding:n=null,mode:u=null}=o);let A=this.entries.get(a);return{encoding:n,mode:u,resolvedP:a,index:A}}async unlinkPromise(r){return this.unlinkSync(r)}unlinkSync(r){if(this.readOnly)throw ar.EROFS(`unlink '${r}'`);let o=this.resolveFilename(`unlink '${r}'`,r);if(this.listings.has(o))throw ar.EISDIR(`unlink '${r}'`);let a=this.entries.get(o);if(typeof a>\"u\")throw ar.EINVAL(`unlink '${r}'`);this.deleteEntry(o,a)}async utimesPromise(r,o,a){return this.utimesSync(r,o,a)}utimesSync(r,o,a){if(this.readOnly)throw ar.EROFS(`utimes '${r}'`);let n=this.resolveFilename(`utimes '${r}'`,r);this.utimesImpl(n,a)}async lutimesPromise(r,o,a){return this.lutimesSync(r,o,a)}lutimesSync(r,o,a){if(this.readOnly)throw ar.EROFS(`lutimes '${r}'`);let n=this.resolveFilename(`utimes '${r}'`,r,!1);this.utimesImpl(n,a)}utimesImpl(r,o){this.listings.has(r)&&(this.entries.has(r)||this.hydrateDirectory(r));let a=this.entries.get(r);if(a===void 0)throw new Error(\"Unreachable\");if(this.libzip.file.setMtime(this.zip,a,0,fot(o),0)===-1)throw this.makeLibzipError(this.libzip.getError(this.zip))}async mkdirPromise(r,o){return this.mkdirSync(r,o)}mkdirSync(r,{mode:o=493,recursive:a=!1}={}){if(a)return this.mkdirpSync(r,{chmod:o});if(this.readOnly)throw ar.EROFS(`mkdir '${r}'`);let n=this.resolveFilename(`mkdir '${r}'`,r);if(this.entries.has(n)||this.listings.has(n))throw ar.EEXIST(`mkdir '${r}'`);this.hydrateDirectory(n),this.chmodSync(n,o)}async rmdirPromise(r,o){return this.rmdirSync(r,o)}rmdirSync(r,{recursive:o=!1}={}){if(this.readOnly)throw ar.EROFS(`rmdir '${r}'`);if(o){this.removeSync(r);return}let a=this.resolveFilename(`rmdir '${r}'`,r),n=this.listings.get(a);if(!n)throw ar.ENOTDIR(`rmdir '${r}'`);if(n.size>0)throw ar.ENOTEMPTY(`rmdir '${r}'`);let u=this.entries.get(a);if(typeof u>\"u\")throw ar.EINVAL(`rmdir '${r}'`);this.deleteEntry(r,u)}hydrateDirectory(r){let o=this.libzip.dir.add(this.zip,V.relative(Bt.root,r));if(o===-1)throw this.makeLibzipError(this.libzip.getError(this.zip));return this.registerListing(r),this.registerEntry(r,o),o}async linkPromise(r,o){return this.linkSync(r,o)}linkSync(r,o){throw ar.EOPNOTSUPP(`link '${r}' -> '${o}'`)}async symlinkPromise(r,o){return this.symlinkSync(r,o)}symlinkSync(r,o){if(this.readOnly)throw ar.EROFS(`symlink '${r}' -> '${o}'`);let a=this.resolveFilename(`symlink '${r}' -> '${o}'`,o);if(this.listings.has(a))throw ar.EISDIR(`symlink '${r}' -> '${o}'`);if(this.entries.has(a))throw ar.EEXIST(`symlink '${r}' -> '${o}'`);let n=this.setFileSource(a,r);if(this.registerEntry(a,n),this.libzip.file.setExternalAttributes(this.zip,n,0,0,this.libzip.ZIP_OPSYS_UNIX,(ta.constants.S_IFLNK|511)<<16)===-1)throw this.makeLibzipError(this.libzip.getError(this.zip));this.symlinkCount+=1}async readFilePromise(r,o){typeof o==\"object\"&&(o=o?o.encoding:void 0);let a=await this.readFileBuffer(r,{asyncDecompress:!0});return o?a.toString(o):a}readFileSync(r,o){typeof o==\"object\"&&(o=o?o.encoding:void 0);let a=this.readFileBuffer(r);return o?a.toString(o):a}readFileBuffer(r,o={asyncDecompress:!1}){typeof r==\"number\"&&(r=this.fdToPath(r,\"read\"));let a=this.resolveFilename(`open '${r}'`,r);if(!this.entries.has(a)&&!this.listings.has(a))throw ar.ENOENT(`open '${r}'`);if(r[r.length-1]===\"/\"&&!this.listings.has(a))throw ar.ENOTDIR(`open '${r}'`);if(this.listings.has(a))throw ar.EISDIR(\"read\");let n=this.entries.get(a);if(n===void 0)throw new Error(\"Unreachable\");return this.getFileSource(n,o)}async readdirPromise(r,o){return this.readdirSync(r,o)}readdirSync(r,o){let a=this.resolveFilename(`scandir '${r}'`,r);if(!this.entries.has(a)&&!this.listings.has(a))throw ar.ENOENT(`scandir '${r}'`);let n=this.listings.get(a);if(!n)throw ar.ENOTDIR(`scandir '${r}'`);if(o?.recursive)if(o?.withFileTypes){let u=Array.from(n,A=>Object.assign(this.statImpl(\"lstat\",V.join(r,A)),{name:A,path:Bt.dot}));for(let A of u){if(!A.isDirectory())continue;let p=V.join(A.path,A.name),h=this.listings.get(V.join(a,p));for(let C of h)u.push(Object.assign(this.statImpl(\"lstat\",V.join(r,p,C)),{name:C,path:p}))}return u}else{let u=[...n];for(let A of u){let p=this.listings.get(V.join(a,A));if(!(typeof p>\"u\"))for(let h of p)u.push(V.join(A,h))}return u}else return o?.withFileTypes?Array.from(n,u=>Object.assign(this.statImpl(\"lstat\",V.join(r,u)),{name:u,path:void 0})):[...n]}async readlinkPromise(r){let o=this.prepareReadlink(r);return(await this.getFileSource(o,{asyncDecompress:!0})).toString()}readlinkSync(r){let o=this.prepareReadlink(r);return this.getFileSource(o).toString()}prepareReadlink(r){let o=this.resolveFilename(`readlink '${r}'`,r,!1);if(!this.entries.has(o)&&!this.listings.has(o))throw ar.ENOENT(`readlink '${r}'`);if(r[r.length-1]===\"/\"&&!this.listings.has(o))throw ar.ENOTDIR(`open '${r}'`);if(this.listings.has(o))throw ar.EINVAL(`readlink '${r}'`);let a=this.entries.get(o);if(a===void 0)throw new Error(\"Unreachable\");if(!this.isSymbolicLink(a))throw ar.EINVAL(`readlink '${r}'`);return a}async truncatePromise(r,o=0){let a=this.resolveFilename(`open '${r}'`,r),n=this.entries.get(a);if(typeof n>\"u\")throw ar.EINVAL(`open '${r}'`);let u=await this.getFileSource(n,{asyncDecompress:!0}),A=Buffer.alloc(o,0);return u.copy(A),await this.writeFilePromise(r,A)}truncateSync(r,o=0){let a=this.resolveFilename(`open '${r}'`,r),n=this.entries.get(a);if(typeof n>\"u\")throw ar.EINVAL(`open '${r}'`);let u=this.getFileSource(n),A=Buffer.alloc(o,0);return u.copy(A),this.writeFileSync(r,A)}async ftruncatePromise(r,o){return this.truncatePromise(this.fdToPath(r,\"ftruncate\"),o)}ftruncateSync(r,o){return this.truncateSync(this.fdToPath(r,\"ftruncateSync\"),o)}watch(r,o,a){let n;switch(typeof o){case\"function\":case\"string\":case\"undefined\":n=!0;break;default:({persistent:n=!0}=o);break}if(!n)return{on:()=>{},close:()=>{}};let u=setInterval(()=>{},24*60*60*1e3);return{on:()=>{},close:()=>{clearInterval(u)}}}watchFile(r,o,a){let n=V.resolve(Bt.root,r);return ty(this,n,o,a)}unwatchFile(r,o){let a=V.resolve(Bt.root,r);return Lg(this,a,o)}}});function qle(t,e,r=Buffer.alloc(0),o){let a=new Ji(r),n=I=>I===e||I.startsWith(`${e}/`)?I.slice(0,e.length):null,u=async(I,v)=>()=>a,A=(I,v)=>a,p={...t},h=new Tn(p),C=new Up({baseFs:h,getMountPoint:n,factoryPromise:u,factorySync:A,magicByte:21,maxAge:1/0,typeCheck:o?.typeCheck});return Yw(jle.default,new _p(C)),a}var jle,Gle=Et(()=>{Pt();jle=$e(Be(\"fs\"));aU()});var Yle=Et(()=>{Ule();aU();Gle()});var S1={};Vt(S1,{DEFAULT_COMPRESSION_LEVEL:()=>Hle,LibzipError:()=>Nb,ZipFS:()=>Ji,ZipOpenFS:()=>zl,getArchivePart:()=>iU,getLibzipPromise:()=>hot,getLibzipSync:()=>pot,makeEmptyArchive:()=>Tb,mountMemoryDrive:()=>qle});function pot(){return P1()}async function hot(){return P1()}var Wle,nA=Et(()=>{tU();Wle=$e(Nle());Mle();Yle();Tle(()=>{let t=(0,Wle.default)();return Ole(t)})});var QE,Kle=Et(()=>{Pt();qt();b1();QE=class extends nt{constructor(){super(...arguments);this.cwd=ge.String(\"--cwd\",process.cwd(),{description:\"The directory to run the command in\"});this.commandName=ge.String();this.args=ge.Proxy()}async execute(){let r=this.args.length>0?`${this.commandName} ${this.args.join(\" \")}`:this.commandName;return await FE(r,[],{cwd:ue.toPortablePath(this.cwd),stdin:this.context.stdin,stdout:this.context.stdout,stderr:this.context.stderr})}};QE.usage={description:\"run a command using yarn's portable shell\",details:`\n      This command will run a command using Yarn's portable shell.\n\n      Make sure to escape glob patterns, redirections, and other features that might be expanded by your own shell.\n\n      Note: To escape something from Yarn's shell, you might have to escape it twice, the first time from your own shell.\n\n      Note: Don't use this command in Yarn scripts, as Yarn's shell is automatically used.\n\n      For a list of features, visit: https://github.com/yarnpkg/berry/blob/master/packages/yarnpkg-shell/README.md.\n    `,examples:[[\"Run a simple command\",\"$0 echo Hello\"],[\"Run a command with a glob pattern\",\"$0 echo '*.js'\"],[\"Run a command with a redirection\",\"$0 echo Hello World '>' hello.txt\"],[\"Run a command with an escaped glob pattern (The double escape is needed in Unix shells)\",`$0 echo '\"*.js\"'`],[\"Run a command with a variable (Double quotes are needed in Unix shells, to prevent them from expanding the variable)\",'$0 \"GREETING=Hello echo $GREETING World\"']]}});var al,Vle=Et(()=>{al=class extends Error{constructor(e){super(e),this.name=\"ShellError\"}}});var Mb={};Vt(Mb,{fastGlobOptions:()=>Xle,isBraceExpansion:()=>lU,isGlobPattern:()=>got,match:()=>dot,micromatchOptions:()=>Ob});function got(t){if(!Lb.default.scan(t,Ob).isGlob)return!1;try{Lb.default.parse(t,Ob)}catch{return!1}return!0}function dot(t,{cwd:e,baseFs:r}){return(0,zle.default)(t,{...Xle,cwd:ue.fromPortablePath(e),fs:RD(Jle.default,new _p(r))})}function lU(t){return Lb.default.scan(t,Ob).isBrace}var zle,Jle,Lb,Ob,Xle,Zle=Et(()=>{Pt();zle=$e(TS()),Jle=$e(Be(\"fs\")),Lb=$e(Zo()),Ob={strictBrackets:!0},Xle={onlyDirectories:!1,onlyFiles:!1}});function cU(){}function uU(){for(let t of bd)t.kill()}function rce(t,e,r,o){return a=>{let n=a[0]instanceof iA.Transform?\"pipe\":a[0],u=a[1]instanceof iA.Transform?\"pipe\":a[1],A=a[2]instanceof iA.Transform?\"pipe\":a[2],p=(0,ece.default)(t,e,{...o,stdio:[n,u,A]});return bd.add(p),bd.size===1&&(process.on(\"SIGINT\",cU),process.on(\"SIGTERM\",uU)),a[0]instanceof iA.Transform&&a[0].pipe(p.stdin),a[1]instanceof iA.Transform&&p.stdout.pipe(a[1],{end:!1}),a[2]instanceof iA.Transform&&p.stderr.pipe(a[2],{end:!1}),{stdin:p.stdin,promise:new Promise(h=>{p.on(\"error\",C=>{switch(bd.delete(p),bd.size===0&&(process.off(\"SIGINT\",cU),process.off(\"SIGTERM\",uU)),C.code){case\"ENOENT\":a[2].write(`command not found: ${t}\n`),h(127);break;case\"EACCES\":a[2].write(`permission denied: ${t}\n`),h(128);break;default:a[2].write(`uncaught error: ${C.message}\n`),h(1);break}}),p.on(\"close\",C=>{bd.delete(p),bd.size===0&&(process.off(\"SIGINT\",cU),process.off(\"SIGTERM\",uU)),h(C!==null?C:129)})})}}}function nce(t){return e=>{let r=e[0]===\"pipe\"?new iA.PassThrough:e[0];return{stdin:r,promise:Promise.resolve().then(()=>t({stdin:r,stdout:e[1],stderr:e[2]}))}}}function Ub(t,e){return RE.start(t,e)}function $le(t,e=null){let r=new iA.PassThrough,o=new tce.StringDecoder,a=\"\";return r.on(\"data\",n=>{let u=o.write(n),A;do if(A=u.indexOf(`\n`),A!==-1){let p=a+u.substring(0,A);u=u.substring(A+1),a=\"\",t(e!==null?`${e} ${p}`:p)}while(A!==-1);a+=u}),r.on(\"end\",()=>{let n=o.end();n!==\"\"&&t(e!==null?`${e} ${n}`:n)}),r}function ice(t,{prefix:e}){return{stdout:$le(r=>t.stdout.write(`${r}\n`),t.stdout.isTTY?e:null),stderr:$le(r=>t.stderr.write(`${r}\n`),t.stderr.isTTY?e:null)}}var ece,iA,tce,bd,Jl,AU,RE,fU=Et(()=>{ece=$e(aT()),iA=Be(\"stream\"),tce=Be(\"string_decoder\"),bd=new Set;Jl=class{constructor(e){this.stream=e}close(){}get(){return this.stream}},AU=class{constructor(){this.stream=null}close(){if(this.stream===null)throw new Error(\"Assertion failed: No stream attached\");this.stream.end()}attach(e){this.stream=e}get(){if(this.stream===null)throw new Error(\"Assertion failed: No stream attached\");return this.stream}},RE=class{constructor(e,r){this.stdin=null;this.stdout=null;this.stderr=null;this.pipe=null;this.ancestor=e,this.implementation=r}static start(e,{stdin:r,stdout:o,stderr:a}){let n=new RE(null,e);return n.stdin=r,n.stdout=o,n.stderr=a,n}pipeTo(e,r=1){let o=new RE(this,e),a=new AU;return o.pipe=a,o.stdout=this.stdout,o.stderr=this.stderr,(r&1)===1?this.stdout=a:this.ancestor!==null&&(this.stderr=this.ancestor.stdout),(r&2)===2?this.stderr=a:this.ancestor!==null&&(this.stderr=this.ancestor.stderr),o}async exec(){let e=[\"ignore\",\"ignore\",\"ignore\"];if(this.pipe)e[0]=\"pipe\";else{if(this.stdin===null)throw new Error(\"Assertion failed: No input stream registered\");e[0]=this.stdin.get()}let r;if(this.stdout===null)throw new Error(\"Assertion failed: No output stream registered\");r=this.stdout,e[1]=r.get();let o;if(this.stderr===null)throw new Error(\"Assertion failed: No error stream registered\");o=this.stderr,e[2]=o.get();let a=this.implementation(e);return this.pipe&&this.pipe.attach(a.stdin),await a.promise.then(n=>(r.close(),o.close(),n))}async run(){let e=[];for(let o=this;o;o=o.ancestor)e.push(o.exec());return(await Promise.all(e))[0]}}});var F1={};Vt(F1,{EntryCommand:()=>QE,ShellError:()=>al,execute:()=>FE,globUtils:()=>Mb});function sce(t,e,r){let o=new ll.PassThrough({autoDestroy:!0});switch(t){case 0:(e&1)===1&&r.stdin.pipe(o,{end:!1}),(e&2)===2&&r.stdin instanceof ll.Writable&&o.pipe(r.stdin,{end:!1});break;case 1:(e&1)===1&&r.stdout.pipe(o,{end:!1}),(e&2)===2&&o.pipe(r.stdout,{end:!1});break;case 2:(e&1)===1&&r.stderr.pipe(o,{end:!1}),(e&2)===2&&o.pipe(r.stderr,{end:!1});break;default:throw new al(`Bad file descriptor: \"${t}\"`)}return o}function Hb(t,e={}){let r={...t,...e};return r.environment={...t.environment,...e.environment},r.variables={...t.variables,...e.variables},r}async function yot(t,e,r){let o=[],a=new ll.PassThrough;return a.on(\"data\",n=>o.push(n)),await jb(t,e,Hb(r,{stdout:a})),Buffer.concat(o).toString().replace(/[\\r\\n]+$/,\"\")}async function oce(t,e,r){let o=t.map(async n=>{let u=await xd(n.args,e,r);return{name:n.name,value:u.join(\" \")}});return(await Promise.all(o)).reduce((n,u)=>(n[u.name]=u.value,n),{})}function _b(t){return t.match(/[^ \\r\\n\\t]+/g)||[]}async function fce(t,e,r,o,a=o){switch(t.name){case\"$\":o(String(process.pid));break;case\"#\":o(String(e.args.length));break;case\"@\":if(t.quoted)for(let n of e.args)a(n);else for(let n of e.args){let u=_b(n);for(let A=0;A<u.length-1;++A)a(u[A]);o(u[u.length-1])}break;case\"*\":{let n=e.args.join(\" \");if(t.quoted)o(n);else for(let u of _b(n))a(u)}break;case\"PPID\":o(String(process.ppid));break;case\"RANDOM\":o(String(Math.floor(Math.random()*32768)));break;default:{let n=parseInt(t.name,10),u,A=Number.isFinite(n);if(A?n>=0&&n<e.args.length&&(u=e.args[n]):Object.hasOwn(r.variables,t.name)?u=r.variables[t.name]:Object.hasOwn(r.environment,t.name)&&(u=r.environment[t.name]),typeof u<\"u\"&&t.alternativeValue?u=(await xd(t.alternativeValue,e,r)).join(\" \"):typeof u>\"u\"&&(t.defaultValue?u=(await xd(t.defaultValue,e,r)).join(\" \"):t.alternativeValue&&(u=\"\")),typeof u>\"u\")throw A?new al(`Unbound argument #${n}`):new al(`Unbound variable \"${t.name}\"`);if(t.quoted)o(u);else{let p=_b(u);for(let C=0;C<p.length-1;++C)a(p[C]);let h=p[p.length-1];typeof h<\"u\"&&o(h)}}break}}async function x1(t,e,r){if(t.type===\"number\"){if(Number.isInteger(t.value))return t.value;throw new Error(`Invalid number: \"${t.value}\", only integers are allowed`)}else if(t.type===\"variable\"){let o=[];await fce({...t,quoted:!0},e,r,n=>o.push(n));let a=Number(o.join(\" \"));return Number.isNaN(a)?x1({type:\"variable\",name:o.join(\" \")},e,r):x1({type:\"number\",value:a},e,r)}else return Eot[t.type](await x1(t.left,e,r),await x1(t.right,e,r))}async function xd(t,e,r){let o=new Map,a=[],n=[],u=C=>{n.push(C)},A=()=>{n.length>0&&a.push(n.join(\"\")),n=[]},p=C=>{u(C),A()},h=(C,I,v)=>{let x=JSON.stringify({type:C,fd:I}),E=o.get(x);typeof E>\"u\"&&o.set(x,E=[]),E.push(v)};for(let C of t){let I=!1;switch(C.type){case\"redirection\":{let v=await xd(C.args,e,r);for(let x of v)h(C.subtype,C.fd,x)}break;case\"argument\":for(let v of C.segments)switch(v.type){case\"text\":u(v.text);break;case\"glob\":u(v.pattern),I=!0;break;case\"shell\":{let x=await yot(v.shell,e,r);if(v.quoted)u(x);else{let E=_b(x);for(let R=0;R<E.length-1;++R)p(E[R]);u(E[E.length-1])}}break;case\"variable\":await fce(v,e,r,u,p);break;case\"arithmetic\":u(String(await x1(v.arithmetic,e,r)));break}break}if(A(),I){let v=a.pop();if(typeof v>\"u\")throw new Error(\"Assertion failed: Expected a glob pattern to have been set\");let x=await e.glob.match(v,{cwd:r.cwd,baseFs:e.baseFs});if(x.length===0){let E=lU(v)?\". Note: Brace expansion of arbitrary strings isn't currently supported. For more details, please read this issue: https://github.com/yarnpkg/berry/issues/22\":\"\";throw new al(`No matches found: \"${v}\"${E}`)}for(let E of x.sort())p(E)}}if(o.size>0){let C=[];for(let[I,v]of o.entries())C.splice(C.length,0,I,String(v.length),...v);a.splice(0,0,\"__ysh_set_redirects\",...C,\"--\")}return a}function k1(t,e,r){e.builtins.has(t[0])||(t=[\"command\",...t]);let o=ue.fromPortablePath(r.cwd),a=r.environment;typeof a.PWD<\"u\"&&(a={...a,PWD:o});let[n,...u]=t;if(n===\"command\")return rce(u[0],u.slice(1),e,{cwd:o,env:a});let A=e.builtins.get(n);if(typeof A>\"u\")throw new Error(`Assertion failed: A builtin should exist for \"${n}\"`);return nce(async({stdin:p,stdout:h,stderr:C})=>{let{stdin:I,stdout:v,stderr:x}=r;r.stdin=p,r.stdout=h,r.stderr=C;try{return await A(u,e,r)}finally{r.stdin=I,r.stdout=v,r.stderr=x}})}function Cot(t,e,r){return o=>{let a=new ll.PassThrough,n=jb(t,e,Hb(r,{stdin:a}));return{stdin:a,promise:n}}}function wot(t,e,r){return o=>{let a=new ll.PassThrough,n=jb(t,e,r);return{stdin:a,promise:n}}}function ace(t,e,r,o){if(e.length===0)return t;{let a;do a=String(Math.random());while(Object.hasOwn(o.procedures,a));return o.procedures={...o.procedures},o.procedures[a]=t,k1([...e,\"__ysh_run_procedure\",a],r,o)}}async function lce(t,e,r){let o=t,a=null,n=null;for(;o;){let u=o.then?{...r}:r,A;switch(o.type){case\"command\":{let p=await xd(o.args,e,r),h=await oce(o.envs,e,r);A=o.envs.length?k1(p,e,Hb(u,{environment:h})):k1(p,e,u)}break;case\"subshell\":{let p=await xd(o.args,e,r),h=Cot(o.subshell,e,u);A=ace(h,p,e,u)}break;case\"group\":{let p=await xd(o.args,e,r),h=wot(o.group,e,u);A=ace(h,p,e,u)}break;case\"envs\":{let p=await oce(o.envs,e,r);u.environment={...u.environment,...p},A=k1([\"true\"],e,u)}break}if(typeof A>\"u\")throw new Error(\"Assertion failed: An action should have been generated\");if(a===null)n=Ub(A,{stdin:new Jl(u.stdin),stdout:new Jl(u.stdout),stderr:new Jl(u.stderr)});else{if(n===null)throw new Error(\"Assertion failed: The execution pipeline should have been setup\");switch(a){case\"|\":n=n.pipeTo(A,1);break;case\"|&\":n=n.pipeTo(A,3);break}}o.then?(a=o.then.type,o=o.then.chain):o=null}if(n===null)throw new Error(\"Assertion failed: The execution pipeline should have been setup\");return await n.run()}async function Iot(t,e,r,{background:o=!1}={}){function a(n){let u=[\"#2E86AB\",\"#A23B72\",\"#F18F01\",\"#C73E1D\",\"#CCE2A3\"],A=u[n%u.length];return cce.default.hex(A)}if(o){let n=r.nextBackgroundJobIndex++,u=a(n),A=`[${n}]`,p=u(A),{stdout:h,stderr:C}=ice(r,{prefix:p});return r.backgroundJobs.push(lce(t,e,Hb(r,{stdout:h,stderr:C})).catch(I=>C.write(`${I.message}\n`)).finally(()=>{r.stdout.isTTY&&r.stdout.write(`Job ${p}, '${u(ly(t))}' has ended\n`)})),0}return await lce(t,e,r)}async function Bot(t,e,r,{background:o=!1}={}){let a,n=A=>{a=A,r.variables[\"?\"]=String(A)},u=async A=>{try{return await Iot(A.chain,e,r,{background:o&&typeof A.then>\"u\"})}catch(p){if(!(p instanceof al))throw p;return r.stderr.write(`${p.message}\n`),1}};for(n(await u(t));t.then;){if(r.exitCode!==null)return r.exitCode;switch(t.then.type){case\"&&\":a===0&&n(await u(t.then.line));break;case\"||\":a!==0&&n(await u(t.then.line));break;default:throw new Error(`Assertion failed: Unsupported command type: \"${t.then.type}\"`)}t=t.then.line}return a}async function jb(t,e,r){let o=r.backgroundJobs;r.backgroundJobs=[];let a=0;for(let{command:n,type:u}of t){if(a=await Bot(n,e,r,{background:u===\"&\"}),r.exitCode!==null)return r.exitCode;r.variables[\"?\"]=String(a)}return await Promise.all(r.backgroundJobs),r.backgroundJobs=o,a}function pce(t){switch(t.type){case\"variable\":return t.name===\"@\"||t.name===\"#\"||t.name===\"*\"||Number.isFinite(parseInt(t.name,10))||\"defaultValue\"in t&&!!t.defaultValue&&t.defaultValue.some(e=>Q1(e))||\"alternativeValue\"in t&&!!t.alternativeValue&&t.alternativeValue.some(e=>Q1(e));case\"arithmetic\":return pU(t.arithmetic);case\"shell\":return hU(t.shell);default:return!1}}function Q1(t){switch(t.type){case\"redirection\":return t.args.some(e=>Q1(e));case\"argument\":return t.segments.some(e=>pce(e));default:throw new Error(`Assertion failed: Unsupported argument type: \"${t.type}\"`)}}function pU(t){switch(t.type){case\"variable\":return pce(t);case\"number\":return!1;default:return pU(t.left)||pU(t.right)}}function hU(t){return t.some(({command:e})=>{for(;e;){let r=e.chain;for(;r;){let o;switch(r.type){case\"subshell\":o=hU(r.subshell);break;case\"command\":o=r.envs.some(a=>a.args.some(n=>Q1(n)))||r.args.some(a=>Q1(a));break}if(o)return!0;if(!r.then)break;r=r.then.chain}if(!e.then)break;e=e.then.line}return!1})}async function FE(t,e=[],{baseFs:r=new Tn,builtins:o={},cwd:a=ue.toPortablePath(process.cwd()),env:n=process.env,stdin:u=process.stdin,stdout:A=process.stdout,stderr:p=process.stderr,variables:h={},glob:C=Mb}={}){let I={};for(let[E,R]of Object.entries(n))typeof R<\"u\"&&(I[E]=R);let v=new Map(mot);for(let[E,R]of Object.entries(o))v.set(E,R);u===null&&(u=new ll.PassThrough,u.end());let x=LD(t,C);if(!hU(x)&&x.length>0&&e.length>0){let{command:E}=x[x.length-1];for(;E.then;)E=E.then.line;let R=E.chain;for(;R.then;)R=R.then.chain;R.type===\"command\"&&(R.args=R.args.concat(e.map(L=>({type:\"argument\",segments:[{type:\"text\",text:L}]}))))}return await jb(x,{args:e,baseFs:r,builtins:v,initialStdin:u,initialStdout:A,initialStderr:p,glob:C},{cwd:a,environment:I,exitCode:null,procedures:{},stdin:u,stdout:A,stderr:p,variables:Object.assign({},h,{[\"?\"]:0}),nextBackgroundJobIndex:1,backgroundJobs:[]})}var cce,uce,ll,Ace,mot,Eot,b1=Et(()=>{Pt();Nl();cce=$e(vN()),uce=Be(\"os\"),ll=Be(\"stream\"),Ace=Be(\"timers/promises\");Kle();Vle();Zle();fU();fU();mot=new Map([[\"cd\",async([t=(0,uce.homedir)(),...e],r,o)=>{let a=V.resolve(o.cwd,ue.toPortablePath(t));if(!(await r.baseFs.statPromise(a).catch(u=>{throw u.code===\"ENOENT\"?new al(`cd: no such file or directory: ${t}`):u})).isDirectory())throw new al(`cd: not a directory: ${t}`);return o.cwd=a,0}],[\"pwd\",async(t,e,r)=>(r.stdout.write(`${ue.fromPortablePath(r.cwd)}\n`),0)],[\":\",async(t,e,r)=>0],[\"true\",async(t,e,r)=>0],[\"false\",async(t,e,r)=>1],[\"exit\",async([t,...e],r,o)=>o.exitCode=parseInt(t??o.variables[\"?\"],10)],[\"echo\",async(t,e,r)=>(r.stdout.write(`${t.join(\" \")}\n`),0)],[\"sleep\",async([t],e,r)=>{if(typeof t>\"u\")throw new al(\"sleep: missing operand\");let o=Number(t);if(Number.isNaN(o))throw new al(`sleep: invalid time interval '${t}'`);return await(0,Ace.setTimeout)(1e3*o,0)}],[\"__ysh_run_procedure\",async(t,e,r)=>{let o=r.procedures[t[0]];return await Ub(o,{stdin:new Jl(r.stdin),stdout:new Jl(r.stdout),stderr:new Jl(r.stderr)}).run()}],[\"__ysh_set_redirects\",async(t,e,r)=>{let o=r.stdin,a=r.stdout,n=r.stderr,u=[],A=[],p=[],h=0;for(;t[h]!==\"--\";){let I=t[h++],{type:v,fd:x}=JSON.parse(I),E=z=>{switch(x){case null:case 0:u.push(z);break;default:throw new Error(`Unsupported file descriptor: \"${x}\"`)}},R=z=>{switch(x){case null:case 1:A.push(z);break;case 2:p.push(z);break;default:throw new Error(`Unsupported file descriptor: \"${x}\"`)}},L=Number(t[h++]),U=h+L;for(let z=h;z<U;++h,++z)switch(v){case\"<\":E(()=>e.baseFs.createReadStream(V.resolve(r.cwd,ue.toPortablePath(t[z]))));break;case\"<<<\":E(()=>{let te=new ll.PassThrough;return process.nextTick(()=>{te.write(`${t[z]}\n`),te.end()}),te});break;case\"<&\":E(()=>sce(Number(t[z]),1,r));break;case\">\":case\">>\":{let te=V.resolve(r.cwd,ue.toPortablePath(t[z]));R(te===\"/dev/null\"?new ll.Writable({autoDestroy:!0,emitClose:!0,write(le,he,Ae){setImmediate(Ae)}}):e.baseFs.createWriteStream(te,v===\">>\"?{flags:\"a\"}:void 0))}break;case\">&\":R(sce(Number(t[z]),2,r));break;default:throw new Error(`Assertion failed: Unsupported redirection type: \"${v}\"`)}}if(u.length>0){let I=new ll.PassThrough;o=I;let v=x=>{if(x===u.length)I.end();else{let E=u[x]();E.pipe(I,{end:!1}),E.on(\"end\",()=>{v(x+1)})}};v(0)}if(A.length>0){let I=new ll.PassThrough;a=I;for(let v of A)I.pipe(v)}if(p.length>0){let I=new ll.PassThrough;n=I;for(let v of p)I.pipe(v)}let C=await Ub(k1(t.slice(h+1),e,r),{stdin:new Jl(o),stdout:new Jl(a),stderr:new Jl(n)}).run();return await Promise.all(A.map(I=>new Promise((v,x)=>{I.on(\"error\",E=>{x(E)}),I.on(\"close\",()=>{v()}),I.end()}))),await Promise.all(p.map(I=>new Promise((v,x)=>{I.on(\"error\",E=>{x(E)}),I.on(\"close\",()=>{v()}),I.end()}))),C}]]);Eot={addition:(t,e)=>t+e,subtraction:(t,e)=>t-e,multiplication:(t,e)=>t*e,division:(t,e)=>Math.trunc(t/e)}});var qb=_((e4t,hce)=>{function vot(t,e){for(var r=-1,o=t==null?0:t.length,a=Array(o);++r<o;)a[r]=e(t[r],r,t);return a}hce.exports=vot});var Cce=_((t4t,Ece)=>{var gce=Ad(),Dot=qb(),Pot=Hl(),Sot=AE(),bot=1/0,dce=gce?gce.prototype:void 0,mce=dce?dce.toString:void 0;function yce(t){if(typeof t==\"string\")return t;if(Pot(t))return Dot(t,yce)+\"\";if(Sot(t))return mce?mce.call(t):\"\";var e=t+\"\";return e==\"0\"&&1/t==-bot?\"-0\":e}Ece.exports=yce});var R1=_((r4t,wce)=>{var xot=Cce();function kot(t){return t==null?\"\":xot(t)}wce.exports=kot});var gU=_((n4t,Ice)=>{function Qot(t,e,r){var o=-1,a=t.length;e<0&&(e=-e>a?0:a+e),r=r>a?a:r,r<0&&(r+=a),a=e>r?0:r-e>>>0,e>>>=0;for(var n=Array(a);++o<a;)n[o]=t[o+e];return n}Ice.exports=Qot});var vce=_((i4t,Bce)=>{var Fot=gU();function Rot(t,e,r){var o=t.length;return r=r===void 0?o:r,!e&&r>=o?t:Fot(t,e,r)}Bce.exports=Rot});var dU=_((s4t,Dce)=>{var Tot=\"\\\\ud800-\\\\udfff\",Not=\"\\\\u0300-\\\\u036f\",Lot=\"\\\\ufe20-\\\\ufe2f\",Oot=\"\\\\u20d0-\\\\u20ff\",Mot=Not+Lot+Oot,Uot=\"\\\\ufe0e\\\\ufe0f\",_ot=\"\\\\u200d\",Hot=RegExp(\"[\"+_ot+Tot+Mot+Uot+\"]\");function jot(t){return Hot.test(t)}Dce.exports=jot});var Sce=_((o4t,Pce)=>{function qot(t){return t.split(\"\")}Pce.exports=qot});var Nce=_((a4t,Tce)=>{var bce=\"\\\\ud800-\\\\udfff\",Got=\"\\\\u0300-\\\\u036f\",Yot=\"\\\\ufe20-\\\\ufe2f\",Wot=\"\\\\u20d0-\\\\u20ff\",Kot=Got+Yot+Wot,Vot=\"\\\\ufe0e\\\\ufe0f\",zot=\"[\"+bce+\"]\",mU=\"[\"+Kot+\"]\",yU=\"\\\\ud83c[\\\\udffb-\\\\udfff]\",Jot=\"(?:\"+mU+\"|\"+yU+\")\",xce=\"[^\"+bce+\"]\",kce=\"(?:\\\\ud83c[\\\\udde6-\\\\uddff]){2}\",Qce=\"[\\\\ud800-\\\\udbff][\\\\udc00-\\\\udfff]\",Xot=\"\\\\u200d\",Fce=Jot+\"?\",Rce=\"[\"+Vot+\"]?\",Zot=\"(?:\"+Xot+\"(?:\"+[xce,kce,Qce].join(\"|\")+\")\"+Rce+Fce+\")*\",$ot=Rce+Fce+Zot,eat=\"(?:\"+[xce+mU+\"?\",mU,kce,Qce,zot].join(\"|\")+\")\",tat=RegExp(yU+\"(?=\"+yU+\")|\"+eat+$ot,\"g\");function rat(t){return t.match(tat)||[]}Tce.exports=rat});var Oce=_((l4t,Lce)=>{var nat=Sce(),iat=dU(),sat=Nce();function oat(t){return iat(t)?sat(t):nat(t)}Lce.exports=oat});var Uce=_((c4t,Mce)=>{var aat=vce(),lat=dU(),cat=Oce(),uat=R1();function Aat(t){return function(e){e=uat(e);var r=lat(e)?cat(e):void 0,o=r?r[0]:e.charAt(0),a=r?aat(r,1).join(\"\"):e.slice(1);return o[t]()+a}}Mce.exports=Aat});var Hce=_((u4t,_ce)=>{var fat=Uce(),pat=fat(\"toUpperCase\");_ce.exports=pat});var EU=_((A4t,jce)=>{var hat=R1(),gat=Hce();function dat(t){return gat(hat(t).toLowerCase())}jce.exports=dat});var qce=_((f4t,Gb)=>{function mat(){var t=0,e=1,r=2,o=3,a=4,n=5,u=6,A=7,p=8,h=9,C=10,I=11,v=12,x=13,E=14,R=15,L=16,U=17,z=0,te=1,le=2,he=3,Ae=4;function ye(g,Ee){return 55296<=g.charCodeAt(Ee)&&g.charCodeAt(Ee)<=56319&&56320<=g.charCodeAt(Ee+1)&&g.charCodeAt(Ee+1)<=57343}function ae(g,Ee){Ee===void 0&&(Ee=0);var De=g.charCodeAt(Ee);if(55296<=De&&De<=56319&&Ee<g.length-1){var ce=De,ne=g.charCodeAt(Ee+1);return 56320<=ne&&ne<=57343?(ce-55296)*1024+(ne-56320)+65536:ce}if(56320<=De&&De<=57343&&Ee>=1){var ce=g.charCodeAt(Ee-1),ne=De;return 55296<=ce&&ce<=56319?(ce-55296)*1024+(ne-56320)+65536:ne}return De}function Ie(g,Ee,De){var ce=[g].concat(Ee).concat([De]),ne=ce[ce.length-2],ee=De,we=ce.lastIndexOf(E);if(we>1&&ce.slice(1,we).every(function(H){return H==o})&&[o,x,U].indexOf(g)==-1)return le;var xe=ce.lastIndexOf(a);if(xe>0&&ce.slice(1,xe).every(function(H){return H==a})&&[v,a].indexOf(ne)==-1)return ce.filter(function(H){return H==a}).length%2==1?he:Ae;if(ne==t&&ee==e)return z;if(ne==r||ne==t||ne==e)return ee==E&&Ee.every(function(H){return H==o})?le:te;if(ee==r||ee==t||ee==e)return te;if(ne==u&&(ee==u||ee==A||ee==h||ee==C))return z;if((ne==h||ne==A)&&(ee==A||ee==p))return z;if((ne==C||ne==p)&&ee==p)return z;if(ee==o||ee==R)return z;if(ee==n)return z;if(ne==v)return z;var ht=ce.indexOf(o)!=-1?ce.lastIndexOf(o)-1:ce.length-2;return[x,U].indexOf(ce[ht])!=-1&&ce.slice(ht+1,-1).every(function(H){return H==o})&&ee==E||ne==R&&[L,U].indexOf(ee)!=-1?z:Ee.indexOf(a)!=-1?le:ne==a&&ee==a?z:te}this.nextBreak=function(g,Ee){if(Ee===void 0&&(Ee=0),Ee<0)return 0;if(Ee>=g.length-1)return g.length;for(var De=Fe(ae(g,Ee)),ce=[],ne=Ee+1;ne<g.length;ne++)if(!ye(g,ne-1)){var ee=Fe(ae(g,ne));if(Ie(De,ce,ee))return ne;ce.push(ee)}return g.length},this.splitGraphemes=function(g){for(var Ee=[],De=0,ce;(ce=this.nextBreak(g,De))<g.length;)Ee.push(g.slice(De,ce)),De=ce;return De<g.length&&Ee.push(g.slice(De)),Ee},this.iterateGraphemes=function(g){var Ee=0,De={next:function(){var ce,ne;return(ne=this.nextBreak(g,Ee))<g.length?(ce=g.slice(Ee,ne),Ee=ne,{value:ce,done:!1}):Ee<g.length?(ce=g.slice(Ee),Ee=g.length,{value:ce,done:!1}):{value:void 0,done:!0}}.bind(this)};return typeof Symbol<\"u\"&&Symbol.iterator&&(De[Symbol.iterator]=function(){return De}),De},this.countGraphemes=function(g){for(var Ee=0,De=0,ce;(ce=this.nextBreak(g,De))<g.length;)De=ce,Ee++;return De<g.length&&Ee++,Ee};function Fe(g){return 1536<=g&&g<=1541||g==1757||g==1807||g==2274||g==3406||g==69821||70082<=g&&g<=70083||g==72250||72326<=g&&g<=72329||g==73030?v:g==13?t:g==10?e:0<=g&&g<=9||11<=g&&g<=12||14<=g&&g<=31||127<=g&&g<=159||g==173||g==1564||g==6158||g==8203||8206<=g&&g<=8207||g==8232||g==8233||8234<=g&&g<=8238||8288<=g&&g<=8292||g==8293||8294<=g&&g<=8303||55296<=g&&g<=57343||g==65279||65520<=g&&g<=65528||65529<=g&&g<=65531||113824<=g&&g<=113827||119155<=g&&g<=119162||g==917504||g==917505||917506<=g&&g<=917535||917632<=g&&g<=917759||918e3<=g&&g<=921599?r:768<=g&&g<=879||1155<=g&&g<=1159||1160<=g&&g<=1161||1425<=g&&g<=1469||g==1471||1473<=g&&g<=1474||1476<=g&&g<=1477||g==1479||1552<=g&&g<=1562||1611<=g&&g<=1631||g==1648||1750<=g&&g<=1756||1759<=g&&g<=1764||1767<=g&&g<=1768||1770<=g&&g<=1773||g==1809||1840<=g&&g<=1866||1958<=g&&g<=1968||2027<=g&&g<=2035||2070<=g&&g<=2073||2075<=g&&g<=2083||2085<=g&&g<=2087||2089<=g&&g<=2093||2137<=g&&g<=2139||2260<=g&&g<=2273||2275<=g&&g<=2306||g==2362||g==2364||2369<=g&&g<=2376||g==2381||2385<=g&&g<=2391||2402<=g&&g<=2403||g==2433||g==2492||g==2494||2497<=g&&g<=2500||g==2509||g==2519||2530<=g&&g<=2531||2561<=g&&g<=2562||g==2620||2625<=g&&g<=2626||2631<=g&&g<=2632||2635<=g&&g<=2637||g==2641||2672<=g&&g<=2673||g==2677||2689<=g&&g<=2690||g==2748||2753<=g&&g<=2757||2759<=g&&g<=2760||g==2765||2786<=g&&g<=2787||2810<=g&&g<=2815||g==2817||g==2876||g==2878||g==2879||2881<=g&&g<=2884||g==2893||g==2902||g==2903||2914<=g&&g<=2915||g==2946||g==3006||g==3008||g==3021||g==3031||g==3072||3134<=g&&g<=3136||3142<=g&&g<=3144||3146<=g&&g<=3149||3157<=g&&g<=3158||3170<=g&&g<=3171||g==3201||g==3260||g==3263||g==3266||g==3270||3276<=g&&g<=3277||3285<=g&&g<=3286||3298<=g&&g<=3299||3328<=g&&g<=3329||3387<=g&&g<=3388||g==3390||3393<=g&&g<=3396||g==3405||g==3415||3426<=g&&g<=3427||g==3530||g==3535||3538<=g&&g<=3540||g==3542||g==3551||g==3633||3636<=g&&g<=3642||3655<=g&&g<=3662||g==3761||3764<=g&&g<=3769||3771<=g&&g<=3772||3784<=g&&g<=3789||3864<=g&&g<=3865||g==3893||g==3895||g==3897||3953<=g&&g<=3966||3968<=g&&g<=3972||3974<=g&&g<=3975||3981<=g&&g<=3991||3993<=g&&g<=4028||g==4038||4141<=g&&g<=4144||4146<=g&&g<=4151||4153<=g&&g<=4154||4157<=g&&g<=4158||4184<=g&&g<=4185||4190<=g&&g<=4192||4209<=g&&g<=4212||g==4226||4229<=g&&g<=4230||g==4237||g==4253||4957<=g&&g<=4959||5906<=g&&g<=5908||5938<=g&&g<=5940||5970<=g&&g<=5971||6002<=g&&g<=6003||6068<=g&&g<=6069||6071<=g&&g<=6077||g==6086||6089<=g&&g<=6099||g==6109||6155<=g&&g<=6157||6277<=g&&g<=6278||g==6313||6432<=g&&g<=6434||6439<=g&&g<=6440||g==6450||6457<=g&&g<=6459||6679<=g&&g<=6680||g==6683||g==6742||6744<=g&&g<=6750||g==6752||g==6754||6757<=g&&g<=6764||6771<=g&&g<=6780||g==6783||6832<=g&&g<=6845||g==6846||6912<=g&&g<=6915||g==6964||6966<=g&&g<=6970||g==6972||g==6978||7019<=g&&g<=7027||7040<=g&&g<=7041||7074<=g&&g<=7077||7080<=g&&g<=7081||7083<=g&&g<=7085||g==7142||7144<=g&&g<=7145||g==7149||7151<=g&&g<=7153||7212<=g&&g<=7219||7222<=g&&g<=7223||7376<=g&&g<=7378||7380<=g&&g<=7392||7394<=g&&g<=7400||g==7405||g==7412||7416<=g&&g<=7417||7616<=g&&g<=7673||7675<=g&&g<=7679||g==8204||8400<=g&&g<=8412||8413<=g&&g<=8416||g==8417||8418<=g&&g<=8420||8421<=g&&g<=8432||11503<=g&&g<=11505||g==11647||11744<=g&&g<=11775||12330<=g&&g<=12333||12334<=g&&g<=12335||12441<=g&&g<=12442||g==42607||42608<=g&&g<=42610||42612<=g&&g<=42621||42654<=g&&g<=42655||42736<=g&&g<=42737||g==43010||g==43014||g==43019||43045<=g&&g<=43046||43204<=g&&g<=43205||43232<=g&&g<=43249||43302<=g&&g<=43309||43335<=g&&g<=43345||43392<=g&&g<=43394||g==43443||43446<=g&&g<=43449||g==43452||g==43493||43561<=g&&g<=43566||43569<=g&&g<=43570||43573<=g&&g<=43574||g==43587||g==43596||g==43644||g==43696||43698<=g&&g<=43700||43703<=g&&g<=43704||43710<=g&&g<=43711||g==43713||43756<=g&&g<=43757||g==43766||g==44005||g==44008||g==44013||g==64286||65024<=g&&g<=65039||65056<=g&&g<=65071||65438<=g&&g<=65439||g==66045||g==66272||66422<=g&&g<=66426||68097<=g&&g<=68099||68101<=g&&g<=68102||68108<=g&&g<=68111||68152<=g&&g<=68154||g==68159||68325<=g&&g<=68326||g==69633||69688<=g&&g<=69702||69759<=g&&g<=69761||69811<=g&&g<=69814||69817<=g&&g<=69818||69888<=g&&g<=69890||69927<=g&&g<=69931||69933<=g&&g<=69940||g==70003||70016<=g&&g<=70017||70070<=g&&g<=70078||70090<=g&&g<=70092||70191<=g&&g<=70193||g==70196||70198<=g&&g<=70199||g==70206||g==70367||70371<=g&&g<=70378||70400<=g&&g<=70401||g==70460||g==70462||g==70464||g==70487||70502<=g&&g<=70508||70512<=g&&g<=70516||70712<=g&&g<=70719||70722<=g&&g<=70724||g==70726||g==70832||70835<=g&&g<=70840||g==70842||g==70845||70847<=g&&g<=70848||70850<=g&&g<=70851||g==71087||71090<=g&&g<=71093||71100<=g&&g<=71101||71103<=g&&g<=71104||71132<=g&&g<=71133||71219<=g&&g<=71226||g==71229||71231<=g&&g<=71232||g==71339||g==71341||71344<=g&&g<=71349||g==71351||71453<=g&&g<=71455||71458<=g&&g<=71461||71463<=g&&g<=71467||72193<=g&&g<=72198||72201<=g&&g<=72202||72243<=g&&g<=72248||72251<=g&&g<=72254||g==72263||72273<=g&&g<=72278||72281<=g&&g<=72283||72330<=g&&g<=72342||72344<=g&&g<=72345||72752<=g&&g<=72758||72760<=g&&g<=72765||g==72767||72850<=g&&g<=72871||72874<=g&&g<=72880||72882<=g&&g<=72883||72885<=g&&g<=72886||73009<=g&&g<=73014||g==73018||73020<=g&&g<=73021||73023<=g&&g<=73029||g==73031||92912<=g&&g<=92916||92976<=g&&g<=92982||94095<=g&&g<=94098||113821<=g&&g<=113822||g==119141||119143<=g&&g<=119145||119150<=g&&g<=119154||119163<=g&&g<=119170||119173<=g&&g<=119179||119210<=g&&g<=119213||119362<=g&&g<=119364||121344<=g&&g<=121398||121403<=g&&g<=121452||g==121461||g==121476||121499<=g&&g<=121503||121505<=g&&g<=121519||122880<=g&&g<=122886||122888<=g&&g<=122904||122907<=g&&g<=122913||122915<=g&&g<=122916||122918<=g&&g<=122922||125136<=g&&g<=125142||125252<=g&&g<=125258||917536<=g&&g<=917631||917760<=g&&g<=917999?o:127462<=g&&g<=127487?a:g==2307||g==2363||2366<=g&&g<=2368||2377<=g&&g<=2380||2382<=g&&g<=2383||2434<=g&&g<=2435||2495<=g&&g<=2496||2503<=g&&g<=2504||2507<=g&&g<=2508||g==2563||2622<=g&&g<=2624||g==2691||2750<=g&&g<=2752||g==2761||2763<=g&&g<=2764||2818<=g&&g<=2819||g==2880||2887<=g&&g<=2888||2891<=g&&g<=2892||g==3007||3009<=g&&g<=3010||3014<=g&&g<=3016||3018<=g&&g<=3020||3073<=g&&g<=3075||3137<=g&&g<=3140||3202<=g&&g<=3203||g==3262||3264<=g&&g<=3265||3267<=g&&g<=3268||3271<=g&&g<=3272||3274<=g&&g<=3275||3330<=g&&g<=3331||3391<=g&&g<=3392||3398<=g&&g<=3400||3402<=g&&g<=3404||3458<=g&&g<=3459||3536<=g&&g<=3537||3544<=g&&g<=3550||3570<=g&&g<=3571||g==3635||g==3763||3902<=g&&g<=3903||g==3967||g==4145||4155<=g&&g<=4156||4182<=g&&g<=4183||g==4228||g==6070||6078<=g&&g<=6085||6087<=g&&g<=6088||6435<=g&&g<=6438||6441<=g&&g<=6443||6448<=g&&g<=6449||6451<=g&&g<=6456||6681<=g&&g<=6682||g==6741||g==6743||6765<=g&&g<=6770||g==6916||g==6965||g==6971||6973<=g&&g<=6977||6979<=g&&g<=6980||g==7042||g==7073||7078<=g&&g<=7079||g==7082||g==7143||7146<=g&&g<=7148||g==7150||7154<=g&&g<=7155||7204<=g&&g<=7211||7220<=g&&g<=7221||g==7393||7410<=g&&g<=7411||g==7415||43043<=g&&g<=43044||g==43047||43136<=g&&g<=43137||43188<=g&&g<=43203||43346<=g&&g<=43347||g==43395||43444<=g&&g<=43445||43450<=g&&g<=43451||43453<=g&&g<=43456||43567<=g&&g<=43568||43571<=g&&g<=43572||g==43597||g==43755||43758<=g&&g<=43759||g==43765||44003<=g&&g<=44004||44006<=g&&g<=44007||44009<=g&&g<=44010||g==44012||g==69632||g==69634||g==69762||69808<=g&&g<=69810||69815<=g&&g<=69816||g==69932||g==70018||70067<=g&&g<=70069||70079<=g&&g<=70080||70188<=g&&g<=70190||70194<=g&&g<=70195||g==70197||70368<=g&&g<=70370||70402<=g&&g<=70403||g==70463||70465<=g&&g<=70468||70471<=g&&g<=70472||70475<=g&&g<=70477||70498<=g&&g<=70499||70709<=g&&g<=70711||70720<=g&&g<=70721||g==70725||70833<=g&&g<=70834||g==70841||70843<=g&&g<=70844||g==70846||g==70849||71088<=g&&g<=71089||71096<=g&&g<=71099||g==71102||71216<=g&&g<=71218||71227<=g&&g<=71228||g==71230||g==71340||71342<=g&&g<=71343||g==71350||71456<=g&&g<=71457||g==71462||72199<=g&&g<=72200||g==72249||72279<=g&&g<=72280||g==72343||g==72751||g==72766||g==72873||g==72881||g==72884||94033<=g&&g<=94078||g==119142||g==119149?n:4352<=g&&g<=4447||43360<=g&&g<=43388?u:4448<=g&&g<=4519||55216<=g&&g<=55238?A:4520<=g&&g<=4607||55243<=g&&g<=55291?p:g==44032||g==44060||g==44088||g==44116||g==44144||g==44172||g==44200||g==44228||g==44256||g==44284||g==44312||g==44340||g==44368||g==44396||g==44424||g==44452||g==44480||g==44508||g==44536||g==44564||g==44592||g==44620||g==44648||g==44676||g==44704||g==44732||g==44760||g==44788||g==44816||g==44844||g==44872||g==44900||g==44928||g==44956||g==44984||g==45012||g==45040||g==45068||g==45096||g==45124||g==45152||g==45180||g==45208||g==45236||g==45264||g==45292||g==45320||g==45348||g==45376||g==45404||g==45432||g==45460||g==45488||g==45516||g==45544||g==45572||g==45600||g==45628||g==45656||g==45684||g==45712||g==45740||g==45768||g==45796||g==45824||g==45852||g==45880||g==45908||g==45936||g==45964||g==45992||g==46020||g==46048||g==46076||g==46104||g==46132||g==46160||g==46188||g==46216||g==46244||g==46272||g==46300||g==46328||g==46356||g==46384||g==46412||g==46440||g==46468||g==46496||g==46524||g==46552||g==46580||g==46608||g==46636||g==46664||g==46692||g==46720||g==46748||g==46776||g==46804||g==46832||g==46860||g==46888||g==46916||g==46944||g==46972||g==47e3||g==47028||g==47056||g==47084||g==47112||g==47140||g==47168||g==47196||g==47224||g==47252||g==47280||g==47308||g==47336||g==47364||g==47392||g==47420||g==47448||g==47476||g==47504||g==47532||g==47560||g==47588||g==47616||g==47644||g==47672||g==47700||g==47728||g==47756||g==47784||g==47812||g==47840||g==47868||g==47896||g==47924||g==47952||g==47980||g==48008||g==48036||g==48064||g==48092||g==48120||g==48148||g==48176||g==48204||g==48232||g==48260||g==48288||g==48316||g==48344||g==48372||g==48400||g==48428||g==48456||g==48484||g==48512||g==48540||g==48568||g==48596||g==48624||g==48652||g==48680||g==48708||g==48736||g==48764||g==48792||g==48820||g==48848||g==48876||g==48904||g==48932||g==48960||g==48988||g==49016||g==49044||g==49072||g==49100||g==49128||g==49156||g==49184||g==49212||g==49240||g==49268||g==49296||g==49324||g==49352||g==49380||g==49408||g==49436||g==49464||g==49492||g==49520||g==49548||g==49576||g==49604||g==49632||g==49660||g==49688||g==49716||g==49744||g==49772||g==49800||g==49828||g==49856||g==49884||g==49912||g==49940||g==49968||g==49996||g==50024||g==50052||g==50080||g==50108||g==50136||g==50164||g==50192||g==50220||g==50248||g==50276||g==50304||g==50332||g==50360||g==50388||g==50416||g==50444||g==50472||g==50500||g==50528||g==50556||g==50584||g==50612||g==50640||g==50668||g==50696||g==50724||g==50752||g==50780||g==50808||g==50836||g==50864||g==50892||g==50920||g==50948||g==50976||g==51004||g==51032||g==51060||g==51088||g==51116||g==51144||g==51172||g==51200||g==51228||g==51256||g==51284||g==51312||g==51340||g==51368||g==51396||g==51424||g==51452||g==51480||g==51508||g==51536||g==51564||g==51592||g==51620||g==51648||g==51676||g==51704||g==51732||g==51760||g==51788||g==51816||g==51844||g==51872||g==51900||g==51928||g==51956||g==51984||g==52012||g==52040||g==52068||g==52096||g==52124||g==52152||g==52180||g==52208||g==52236||g==52264||g==52292||g==52320||g==52348||g==52376||g==52404||g==52432||g==52460||g==52488||g==52516||g==52544||g==52572||g==52600||g==52628||g==52656||g==52684||g==52712||g==52740||g==52768||g==52796||g==52824||g==52852||g==52880||g==52908||g==52936||g==52964||g==52992||g==53020||g==53048||g==53076||g==53104||g==53132||g==53160||g==53188||g==53216||g==53244||g==53272||g==53300||g==53328||g==53356||g==53384||g==53412||g==53440||g==53468||g==53496||g==53524||g==53552||g==53580||g==53608||g==53636||g==53664||g==53692||g==53720||g==53748||g==53776||g==53804||g==53832||g==53860||g==53888||g==53916||g==53944||g==53972||g==54e3||g==54028||g==54056||g==54084||g==54112||g==54140||g==54168||g==54196||g==54224||g==54252||g==54280||g==54308||g==54336||g==54364||g==54392||g==54420||g==54448||g==54476||g==54504||g==54532||g==54560||g==54588||g==54616||g==54644||g==54672||g==54700||g==54728||g==54756||g==54784||g==54812||g==54840||g==54868||g==54896||g==54924||g==54952||g==54980||g==55008||g==55036||g==55064||g==55092||g==55120||g==55148||g==55176?h:44033<=g&&g<=44059||44061<=g&&g<=44087||44089<=g&&g<=44115||44117<=g&&g<=44143||44145<=g&&g<=44171||44173<=g&&g<=44199||44201<=g&&g<=44227||44229<=g&&g<=44255||44257<=g&&g<=44283||44285<=g&&g<=44311||44313<=g&&g<=44339||44341<=g&&g<=44367||44369<=g&&g<=44395||44397<=g&&g<=44423||44425<=g&&g<=44451||44453<=g&&g<=44479||44481<=g&&g<=44507||44509<=g&&g<=44535||44537<=g&&g<=44563||44565<=g&&g<=44591||44593<=g&&g<=44619||44621<=g&&g<=44647||44649<=g&&g<=44675||44677<=g&&g<=44703||44705<=g&&g<=44731||44733<=g&&g<=44759||44761<=g&&g<=44787||44789<=g&&g<=44815||44817<=g&&g<=44843||44845<=g&&g<=44871||44873<=g&&g<=44899||44901<=g&&g<=44927||44929<=g&&g<=44955||44957<=g&&g<=44983||44985<=g&&g<=45011||45013<=g&&g<=45039||45041<=g&&g<=45067||45069<=g&&g<=45095||45097<=g&&g<=45123||45125<=g&&g<=45151||45153<=g&&g<=45179||45181<=g&&g<=45207||45209<=g&&g<=45235||45237<=g&&g<=45263||45265<=g&&g<=45291||45293<=g&&g<=45319||45321<=g&&g<=45347||45349<=g&&g<=45375||45377<=g&&g<=45403||45405<=g&&g<=45431||45433<=g&&g<=45459||45461<=g&&g<=45487||45489<=g&&g<=45515||45517<=g&&g<=45543||45545<=g&&g<=45571||45573<=g&&g<=45599||45601<=g&&g<=45627||45629<=g&&g<=45655||45657<=g&&g<=45683||45685<=g&&g<=45711||45713<=g&&g<=45739||45741<=g&&g<=45767||45769<=g&&g<=45795||45797<=g&&g<=45823||45825<=g&&g<=45851||45853<=g&&g<=45879||45881<=g&&g<=45907||45909<=g&&g<=45935||45937<=g&&g<=45963||45965<=g&&g<=45991||45993<=g&&g<=46019||46021<=g&&g<=46047||46049<=g&&g<=46075||46077<=g&&g<=46103||46105<=g&&g<=46131||46133<=g&&g<=46159||46161<=g&&g<=46187||46189<=g&&g<=46215||46217<=g&&g<=46243||46245<=g&&g<=46271||46273<=g&&g<=46299||46301<=g&&g<=46327||46329<=g&&g<=46355||46357<=g&&g<=46383||46385<=g&&g<=46411||46413<=g&&g<=46439||46441<=g&&g<=46467||46469<=g&&g<=46495||46497<=g&&g<=46523||46525<=g&&g<=46551||46553<=g&&g<=46579||46581<=g&&g<=46607||46609<=g&&g<=46635||46637<=g&&g<=46663||46665<=g&&g<=46691||46693<=g&&g<=46719||46721<=g&&g<=46747||46749<=g&&g<=46775||46777<=g&&g<=46803||46805<=g&&g<=46831||46833<=g&&g<=46859||46861<=g&&g<=46887||46889<=g&&g<=46915||46917<=g&&g<=46943||46945<=g&&g<=46971||46973<=g&&g<=46999||47001<=g&&g<=47027||47029<=g&&g<=47055||47057<=g&&g<=47083||47085<=g&&g<=47111||47113<=g&&g<=47139||47141<=g&&g<=47167||47169<=g&&g<=47195||47197<=g&&g<=47223||47225<=g&&g<=47251||47253<=g&&g<=47279||47281<=g&&g<=47307||47309<=g&&g<=47335||47337<=g&&g<=47363||47365<=g&&g<=47391||47393<=g&&g<=47419||47421<=g&&g<=47447||47449<=g&&g<=47475||47477<=g&&g<=47503||47505<=g&&g<=47531||47533<=g&&g<=47559||47561<=g&&g<=47587||47589<=g&&g<=47615||47617<=g&&g<=47643||47645<=g&&g<=47671||47673<=g&&g<=47699||47701<=g&&g<=47727||47729<=g&&g<=47755||47757<=g&&g<=47783||47785<=g&&g<=47811||47813<=g&&g<=47839||47841<=g&&g<=47867||47869<=g&&g<=47895||47897<=g&&g<=47923||47925<=g&&g<=47951||47953<=g&&g<=47979||47981<=g&&g<=48007||48009<=g&&g<=48035||48037<=g&&g<=48063||48065<=g&&g<=48091||48093<=g&&g<=48119||48121<=g&&g<=48147||48149<=g&&g<=48175||48177<=g&&g<=48203||48205<=g&&g<=48231||48233<=g&&g<=48259||48261<=g&&g<=48287||48289<=g&&g<=48315||48317<=g&&g<=48343||48345<=g&&g<=48371||48373<=g&&g<=48399||48401<=g&&g<=48427||48429<=g&&g<=48455||48457<=g&&g<=48483||48485<=g&&g<=48511||48513<=g&&g<=48539||48541<=g&&g<=48567||48569<=g&&g<=48595||48597<=g&&g<=48623||48625<=g&&g<=48651||48653<=g&&g<=48679||48681<=g&&g<=48707||48709<=g&&g<=48735||48737<=g&&g<=48763||48765<=g&&g<=48791||48793<=g&&g<=48819||48821<=g&&g<=48847||48849<=g&&g<=48875||48877<=g&&g<=48903||48905<=g&&g<=48931||48933<=g&&g<=48959||48961<=g&&g<=48987||48989<=g&&g<=49015||49017<=g&&g<=49043||49045<=g&&g<=49071||49073<=g&&g<=49099||49101<=g&&g<=49127||49129<=g&&g<=49155||49157<=g&&g<=49183||49185<=g&&g<=49211||49213<=g&&g<=49239||49241<=g&&g<=49267||49269<=g&&g<=49295||49297<=g&&g<=49323||49325<=g&&g<=49351||49353<=g&&g<=49379||49381<=g&&g<=49407||49409<=g&&g<=49435||49437<=g&&g<=49463||49465<=g&&g<=49491||49493<=g&&g<=49519||49521<=g&&g<=49547||49549<=g&&g<=49575||49577<=g&&g<=49603||49605<=g&&g<=49631||49633<=g&&g<=49659||49661<=g&&g<=49687||49689<=g&&g<=49715||49717<=g&&g<=49743||49745<=g&&g<=49771||49773<=g&&g<=49799||49801<=g&&g<=49827||49829<=g&&g<=49855||49857<=g&&g<=49883||49885<=g&&g<=49911||49913<=g&&g<=49939||49941<=g&&g<=49967||49969<=g&&g<=49995||49997<=g&&g<=50023||50025<=g&&g<=50051||50053<=g&&g<=50079||50081<=g&&g<=50107||50109<=g&&g<=50135||50137<=g&&g<=50163||50165<=g&&g<=50191||50193<=g&&g<=50219||50221<=g&&g<=50247||50249<=g&&g<=50275||50277<=g&&g<=50303||50305<=g&&g<=50331||50333<=g&&g<=50359||50361<=g&&g<=50387||50389<=g&&g<=50415||50417<=g&&g<=50443||50445<=g&&g<=50471||50473<=g&&g<=50499||50501<=g&&g<=50527||50529<=g&&g<=50555||50557<=g&&g<=50583||50585<=g&&g<=50611||50613<=g&&g<=50639||50641<=g&&g<=50667||50669<=g&&g<=50695||50697<=g&&g<=50723||50725<=g&&g<=50751||50753<=g&&g<=50779||50781<=g&&g<=50807||50809<=g&&g<=50835||50837<=g&&g<=50863||50865<=g&&g<=50891||50893<=g&&g<=50919||50921<=g&&g<=50947||50949<=g&&g<=50975||50977<=g&&g<=51003||51005<=g&&g<=51031||51033<=g&&g<=51059||51061<=g&&g<=51087||51089<=g&&g<=51115||51117<=g&&g<=51143||51145<=g&&g<=51171||51173<=g&&g<=51199||51201<=g&&g<=51227||51229<=g&&g<=51255||51257<=g&&g<=51283||51285<=g&&g<=51311||51313<=g&&g<=51339||51341<=g&&g<=51367||51369<=g&&g<=51395||51397<=g&&g<=51423||51425<=g&&g<=51451||51453<=g&&g<=51479||51481<=g&&g<=51507||51509<=g&&g<=51535||51537<=g&&g<=51563||51565<=g&&g<=51591||51593<=g&&g<=51619||51621<=g&&g<=51647||51649<=g&&g<=51675||51677<=g&&g<=51703||51705<=g&&g<=51731||51733<=g&&g<=51759||51761<=g&&g<=51787||51789<=g&&g<=51815||51817<=g&&g<=51843||51845<=g&&g<=51871||51873<=g&&g<=51899||51901<=g&&g<=51927||51929<=g&&g<=51955||51957<=g&&g<=51983||51985<=g&&g<=52011||52013<=g&&g<=52039||52041<=g&&g<=52067||52069<=g&&g<=52095||52097<=g&&g<=52123||52125<=g&&g<=52151||52153<=g&&g<=52179||52181<=g&&g<=52207||52209<=g&&g<=52235||52237<=g&&g<=52263||52265<=g&&g<=52291||52293<=g&&g<=52319||52321<=g&&g<=52347||52349<=g&&g<=52375||52377<=g&&g<=52403||52405<=g&&g<=52431||52433<=g&&g<=52459||52461<=g&&g<=52487||52489<=g&&g<=52515||52517<=g&&g<=52543||52545<=g&&g<=52571||52573<=g&&g<=52599||52601<=g&&g<=52627||52629<=g&&g<=52655||52657<=g&&g<=52683||52685<=g&&g<=52711||52713<=g&&g<=52739||52741<=g&&g<=52767||52769<=g&&g<=52795||52797<=g&&g<=52823||52825<=g&&g<=52851||52853<=g&&g<=52879||52881<=g&&g<=52907||52909<=g&&g<=52935||52937<=g&&g<=52963||52965<=g&&g<=52991||52993<=g&&g<=53019||53021<=g&&g<=53047||53049<=g&&g<=53075||53077<=g&&g<=53103||53105<=g&&g<=53131||53133<=g&&g<=53159||53161<=g&&g<=53187||53189<=g&&g<=53215||53217<=g&&g<=53243||53245<=g&&g<=53271||53273<=g&&g<=53299||53301<=g&&g<=53327||53329<=g&&g<=53355||53357<=g&&g<=53383||53385<=g&&g<=53411||53413<=g&&g<=53439||53441<=g&&g<=53467||53469<=g&&g<=53495||53497<=g&&g<=53523||53525<=g&&g<=53551||53553<=g&&g<=53579||53581<=g&&g<=53607||53609<=g&&g<=53635||53637<=g&&g<=53663||53665<=g&&g<=53691||53693<=g&&g<=53719||53721<=g&&g<=53747||53749<=g&&g<=53775||53777<=g&&g<=53803||53805<=g&&g<=53831||53833<=g&&g<=53859||53861<=g&&g<=53887||53889<=g&&g<=53915||53917<=g&&g<=53943||53945<=g&&g<=53971||53973<=g&&g<=53999||54001<=g&&g<=54027||54029<=g&&g<=54055||54057<=g&&g<=54083||54085<=g&&g<=54111||54113<=g&&g<=54139||54141<=g&&g<=54167||54169<=g&&g<=54195||54197<=g&&g<=54223||54225<=g&&g<=54251||54253<=g&&g<=54279||54281<=g&&g<=54307||54309<=g&&g<=54335||54337<=g&&g<=54363||54365<=g&&g<=54391||54393<=g&&g<=54419||54421<=g&&g<=54447||54449<=g&&g<=54475||54477<=g&&g<=54503||54505<=g&&g<=54531||54533<=g&&g<=54559||54561<=g&&g<=54587||54589<=g&&g<=54615||54617<=g&&g<=54643||54645<=g&&g<=54671||54673<=g&&g<=54699||54701<=g&&g<=54727||54729<=g&&g<=54755||54757<=g&&g<=54783||54785<=g&&g<=54811||54813<=g&&g<=54839||54841<=g&&g<=54867||54869<=g&&g<=54895||54897<=g&&g<=54923||54925<=g&&g<=54951||54953<=g&&g<=54979||54981<=g&&g<=55007||55009<=g&&g<=55035||55037<=g&&g<=55063||55065<=g&&g<=55091||55093<=g&&g<=55119||55121<=g&&g<=55147||55149<=g&&g<=55175||55177<=g&&g<=55203?C:g==9757||g==9977||9994<=g&&g<=9997||g==127877||127938<=g&&g<=127940||g==127943||127946<=g&&g<=127948||128066<=g&&g<=128067||128070<=g&&g<=128080||g==128110||128112<=g&&g<=128120||g==128124||128129<=g&&g<=128131||128133<=g&&g<=128135||g==128170||128372<=g&&g<=128373||g==128378||g==128400||128405<=g&&g<=128406||128581<=g&&g<=128583||128587<=g&&g<=128591||g==128675||128692<=g&&g<=128694||g==128704||g==128716||129304<=g&&g<=129308||129310<=g&&g<=129311||g==129318||129328<=g&&g<=129337||129341<=g&&g<=129342||129489<=g&&g<=129501?x:127995<=g&&g<=127999?E:g==8205?R:g==9792||g==9794||9877<=g&&g<=9878||g==9992||g==10084||g==127752||g==127806||g==127859||g==127891||g==127908||g==127912||g==127979||g==127981||g==128139||128187<=g&&g<=128188||g==128295||g==128300||g==128488||g==128640||g==128658?L:128102<=g&&g<=128105?U:I}return this}typeof Gb<\"u\"&&Gb.exports&&(Gb.exports=mat)});var Yce=_((p4t,Gce)=>{var yat=/^(.*?)(\\x1b\\[[^m]+m|\\x1b\\]8;;.*?(\\x1b\\\\|\\u0007))/,Yb;function Eat(){if(Yb)return Yb;if(typeof Intl.Segmenter<\"u\"){let t=new Intl.Segmenter(\"en\",{granularity:\"grapheme\"});return Yb=e=>Array.from(t.segment(e),({segment:r})=>r)}else{let t=qce(),e=new t;return Yb=r=>e.splitGraphemes(r)}}Gce.exports=(t,e=0,r=t.length)=>{if(e<0||r<0)throw new RangeError(\"Negative indices aren't supported by this implementation\");let o=r-e,a=\"\",n=0,u=0;for(;t.length>0;){let A=t.match(yat)||[t,t,void 0],p=Eat()(A[1]),h=Math.min(e-n,p.length);p=p.slice(h);let C=Math.min(o-u,p.length);a+=p.slice(0,C).join(\"\"),n+=h,u+=C,typeof A[2]<\"u\"&&(a+=A[2]),t=t.slice(A[0].length)}return a}});var tn,T1=Et(()=>{tn=process.env.YARN_IS_TEST_ENV?\"0.0.0\":\"4.0.1\"});function Xce(t,{configuration:e,json:r}){if(!e.get(\"enableMessageNames\"))return\"\";let a=Wu(t===null?0:t);return!r&&t===null?Mt(e,a,\"grey\"):a}function CU(t,{configuration:e,json:r}){let o=Xce(t,{configuration:e,json:r});if(!o||t===null||t===0)return o;let a=wr[t],n=`https://yarnpkg.com/advanced/error-codes#${o}---${a}`.toLowerCase();return Jy(e,o,n)}async function TE({configuration:t,stdout:e,forceError:r},o){let a=await Nt.start({configuration:t,stdout:e,includeFooter:!1},async n=>{let u=!1,A=!1;for(let p of o)typeof p.option<\"u\"&&(p.error||r?(A=!0,n.reportError(50,p.message)):(u=!0,n.reportWarning(50,p.message)),p.callback?.());u&&!A&&n.reportSeparator()});return a.hasErrors()?a.exitCode():null}var zce,Wb,Cat,Wce,Kce,uh,Jce,Vce,wat,Iat,Kb,Bat,Nt,N1=Et(()=>{zce=$e(Yce()),Wb=$e($g());pP();Yl();T1();ql();Cat=\"\\xB7\",Wce=[\"\\u280B\",\"\\u2819\",\"\\u2839\",\"\\u2838\",\"\\u283C\",\"\\u2834\",\"\\u2826\",\"\\u2827\",\"\\u2807\",\"\\u280F\"],Kce=80,uh=Wb.default.GITHUB_ACTIONS?{start:t=>`::group::${t}\n`,end:t=>`::endgroup::\n`}:Wb.default.TRAVIS?{start:t=>`travis_fold:start:${t}\n`,end:t=>`travis_fold:end:${t}\n`}:Wb.default.GITLAB?{start:t=>`section_start:${Math.floor(Date.now()/1e3)}:${t.toLowerCase().replace(/\\W+/g,\"_\")}[collapsed=true]\\r\\x1B[0K${t}\n`,end:t=>`section_end:${Math.floor(Date.now()/1e3)}:${t.toLowerCase().replace(/\\W+/g,\"_\")}\\r\\x1B[0K`}:null,Jce=uh!==null,Vce=new Date,wat=[\"iTerm.app\",\"Apple_Terminal\",\"WarpTerminal\",\"vscode\"].includes(process.env.TERM_PROGRAM)||!!process.env.WT_SESSION,Iat=t=>t,Kb=Iat({patrick:{date:[17,3],chars:[\"\\u{1F340}\",\"\\u{1F331}\"],size:40},simba:{date:[19,7],chars:[\"\\u{1F981}\",\"\\u{1F334}\"],size:40},jack:{date:[31,10],chars:[\"\\u{1F383}\",\"\\u{1F987}\"],size:40},hogsfather:{date:[31,12],chars:[\"\\u{1F389}\",\"\\u{1F384}\"],size:40},default:{chars:[\"=\",\"-\"],size:80}}),Bat=wat&&Object.keys(Kb).find(t=>{let e=Kb[t];return!(e.date&&(e.date[0]!==Vce.getDate()||e.date[1]!==Vce.getMonth()+1))})||\"default\";Nt=class extends Xs{constructor({configuration:r,stdout:o,json:a=!1,forceSectionAlignment:n=!1,includeNames:u=!0,includePrefix:A=!0,includeFooter:p=!0,includeLogs:h=!a,includeInfos:C=h,includeWarnings:I=h}){super();this.uncommitted=new Set;this.warningCount=0;this.errorCount=0;this.timerFooter=[];this.startTime=Date.now();this.indent=0;this.level=0;this.progress=new Map;this.progressTime=0;this.progressFrame=0;this.progressTimeout=null;this.progressStyle=null;this.progressMaxScaledSize=null;if(zI(this,{configuration:r}),this.configuration=r,this.forceSectionAlignment=n,this.includeNames=u,this.includePrefix=A,this.includeFooter=p,this.includeInfos=C,this.includeWarnings=I,this.json=a,this.stdout=o,r.get(\"enableProgressBars\")&&!a&&o.isTTY&&o.columns>22){let v=r.get(\"progressBarStyle\")||Bat;if(!Object.hasOwn(Kb,v))throw new Error(\"Assertion failed: Invalid progress bar style\");this.progressStyle=Kb[v];let x=Math.min(this.getRecommendedLength(),80);this.progressMaxScaledSize=Math.floor(this.progressStyle.size*x/80)}}static async start(r,o){let a=new this(r),n=process.emitWarning;process.emitWarning=(u,A)=>{if(typeof u!=\"string\"){let h=u;u=h.message,A=A??h.name}let p=typeof A<\"u\"?`${A}: ${u}`:u;a.reportWarning(0,p)},r.includeVersion&&a.reportInfo(0,dd(r.configuration,`Yarn ${tn}`,2));try{await o(a)}catch(u){a.reportExceptionOnce(u)}finally{await a.finalize(),process.emitWarning=n}return a}hasErrors(){return this.errorCount>0}exitCode(){return this.hasErrors()?1:0}getRecommendedLength(){let o=this.progressStyle!==null?this.stdout.columns-1:super.getRecommendedLength();return Math.max(40,o-12-this.indent*2)}startSectionSync({reportHeader:r,reportFooter:o,skipIfEmpty:a},n){let u={committed:!1,action:()=>{r?.()}};a?this.uncommitted.add(u):(u.action(),u.committed=!0);let A=Date.now();try{return n()}catch(p){throw this.reportExceptionOnce(p),p}finally{let p=Date.now();this.uncommitted.delete(u),u.committed&&o?.(p-A)}}async startSectionPromise({reportHeader:r,reportFooter:o,skipIfEmpty:a},n){let u={committed:!1,action:()=>{r?.()}};a?this.uncommitted.add(u):(u.action(),u.committed=!0);let A=Date.now();try{return await n()}catch(p){throw this.reportExceptionOnce(p),p}finally{let p=Date.now();this.uncommitted.delete(u),u.committed&&o?.(p-A)}}startTimerImpl(r,o,a){return{cb:typeof o==\"function\"?o:a,reportHeader:()=>{this.level+=1,this.reportInfo(null,`\\u250C ${r}`),this.indent+=1,uh!==null&&!this.json&&this.includeInfos&&this.stdout.write(uh.start(r))},reportFooter:A=>{if(this.indent-=1,uh!==null&&!this.json&&this.includeInfos){this.stdout.write(uh.end(r));for(let p of this.timerFooter)p()}this.configuration.get(\"enableTimers\")&&A>200?this.reportInfo(null,`\\u2514 Completed in ${Mt(this.configuration,A,yt.DURATION)}`):this.reportInfo(null,\"\\u2514 Completed\"),this.level-=1},skipIfEmpty:(typeof o==\"function\"?{}:o).skipIfEmpty}}startTimerSync(r,o,a){let{cb:n,...u}=this.startTimerImpl(r,o,a);return this.startSectionSync(u,n)}async startTimerPromise(r,o,a){let{cb:n,...u}=this.startTimerImpl(r,o,a);return this.startSectionPromise(u,n)}reportSeparator(){this.indent===0?this.writeLine(\"\"):this.reportInfo(null,\"\")}reportInfo(r,o){if(!this.includeInfos)return;this.commit();let a=this.formatNameWithHyperlink(r),n=a?`${a}: `:\"\",u=`${this.formatPrefix(n,\"blueBright\")}${o}`;this.json?this.reportJson({type:\"info\",name:r,displayName:this.formatName(r),indent:this.formatIndent(),data:o}):this.writeLine(u)}reportWarning(r,o){if(this.warningCount+=1,!this.includeWarnings)return;this.commit();let a=this.formatNameWithHyperlink(r),n=a?`${a}: `:\"\";this.json?this.reportJson({type:\"warning\",name:r,displayName:this.formatName(r),indent:this.formatIndent(),data:o}):this.writeLine(`${this.formatPrefix(n,\"yellowBright\")}${o}`)}reportError(r,o){this.errorCount+=1,this.timerFooter.push(()=>this.reportErrorImpl(r,o)),this.reportErrorImpl(r,o)}reportErrorImpl(r,o){this.commit();let a=this.formatNameWithHyperlink(r),n=a?`${a}: `:\"\";this.json?this.reportJson({type:\"error\",name:r,displayName:this.formatName(r),indent:this.formatIndent(),data:o}):this.writeLine(`${this.formatPrefix(n,\"redBright\")}${o}`,{truncate:!1})}reportFold(r,o){if(!uh)return;let a=`${uh.start(r)}${o}${uh.end(r)}`;this.timerFooter.push(()=>this.stdout.write(a))}reportProgress(r){if(this.progressStyle===null)return{...Promise.resolve(),stop:()=>{}};if(r.hasProgress&&r.hasTitle)throw new Error(\"Unimplemented: Progress bars can't have both progress and titles.\");let o=!1,a=Promise.resolve().then(async()=>{let u={progress:r.hasProgress?0:void 0,title:r.hasTitle?\"\":void 0};this.progress.set(r,{definition:u,lastScaledSize:r.hasProgress?-1:void 0,lastTitle:void 0}),this.refreshProgress({delta:-1});for await(let{progress:A,title:p}of r)o||u.progress===A&&u.title===p||(u.progress=A,u.title=p,this.refreshProgress());n()}),n=()=>{o||(o=!0,this.progress.delete(r),this.refreshProgress({delta:1}))};return{...a,stop:n}}reportJson(r){this.json&&this.writeLine(`${JSON.stringify(r)}`)}async finalize(){if(!this.includeFooter)return;let r=\"\";this.errorCount>0?r=\"Failed with errors\":this.warningCount>0?r=\"Done with warnings\":r=\"Done\";let o=Mt(this.configuration,Date.now()-this.startTime,yt.DURATION),a=this.configuration.get(\"enableTimers\")?`${r} in ${o}`:r;this.errorCount>0?this.reportError(0,a):this.warningCount>0?this.reportWarning(0,a):this.reportInfo(0,a)}writeLine(r,{truncate:o}={}){this.clearProgress({clear:!0}),this.stdout.write(`${this.truncate(r,{truncate:o})}\n`),this.writeProgress()}writeLines(r,{truncate:o}={}){this.clearProgress({delta:r.length});for(let a of r)this.stdout.write(`${this.truncate(a,{truncate:o})}\n`);this.writeProgress()}commit(){let r=this.uncommitted;this.uncommitted=new Set;for(let o of r)o.committed=!0,o.action()}clearProgress({delta:r=0,clear:o=!1}){this.progressStyle!==null&&this.progress.size+r>0&&(this.stdout.write(`\\x1B[${this.progress.size+r}A`),(r>0||o)&&this.stdout.write(\"\\x1B[0J\"))}writeProgress(){if(this.progressStyle===null||(this.progressTimeout!==null&&clearTimeout(this.progressTimeout),this.progressTimeout=null,this.progress.size===0))return;let r=Date.now();r-this.progressTime>Kce&&(this.progressFrame=(this.progressFrame+1)%Wce.length,this.progressTime=r);let o=Wce[this.progressFrame];for(let a of this.progress.values()){let n=\"\";if(typeof a.lastScaledSize<\"u\"){let h=this.progressStyle.chars[0].repeat(a.lastScaledSize),C=this.progressStyle.chars[1].repeat(this.progressMaxScaledSize-a.lastScaledSize);n=` ${h}${C}`}let u=this.formatName(null),A=u?`${u}: `:\"\",p=a.definition.title?` ${a.definition.title}`:\"\";this.stdout.write(`${Mt(this.configuration,\"\\u27A4\",\"blueBright\")} ${A}${o}${n}${p}\n`)}this.progressTimeout=setTimeout(()=>{this.refreshProgress({force:!0})},Kce)}refreshProgress({delta:r=0,force:o=!1}={}){let a=!1,n=!1;if(o||this.progress.size===0)a=!0;else for(let u of this.progress.values()){let A=typeof u.definition.progress<\"u\"?Math.trunc(this.progressMaxScaledSize*u.definition.progress):void 0,p=u.lastScaledSize;u.lastScaledSize=A;let h=u.lastTitle;if(u.lastTitle=u.definition.title,A!==p||(n=h!==u.definition.title)){a=!0;break}}a&&(this.clearProgress({delta:r,clear:n}),this.writeProgress())}truncate(r,{truncate:o}={}){return this.progressStyle===null&&(o=!1),typeof o>\"u\"&&(o=this.configuration.get(\"preferTruncatedLines\")),o&&(r=(0,zce.default)(r,0,this.stdout.columns-1)),r}formatName(r){return this.includeNames?Xce(r,{configuration:this.configuration,json:this.json}):\"\"}formatPrefix(r,o){return this.includePrefix?`${Mt(this.configuration,\"\\u27A4\",o)} ${r}${this.formatIndent()}`:\"\"}formatNameWithHyperlink(r){return this.includeNames?CU(r,{configuration:this.configuration,json:this.json}):\"\"}formatIndent(){return this.level>0||!this.forceSectionAlignment?\"\\u2502 \".repeat(this.indent):`${Cat} `}}});var un={};Vt(un,{PackageManager:()=>eue,detectPackageManager:()=>tue,executePackageAccessibleBinary:()=>oue,executePackageScript:()=>Vb,executePackageShellcode:()=>wU,executeWorkspaceAccessibleBinary:()=>kat,executeWorkspaceLifecycleScript:()=>iue,executeWorkspaceScript:()=>nue,getPackageAccessibleBinaries:()=>zb,getWorkspaceAccessibleBinaries:()=>sue,hasPackageScript:()=>Sat,hasWorkspaceScript:()=>IU,isNodeScript:()=>BU,makeScriptEnv:()=>L1,maybeExecuteWorkspaceLifecycleScript:()=>xat,prepareExternalProject:()=>Pat});async function Ah(t,e,r,o=[]){if(process.platform===\"win32\"){let a=`@goto #_undefined_# 2>NUL || @title %COMSPEC% & @setlocal & @\"${r}\" ${o.map(n=>`\"${n.replace('\"','\"\"')}\"`).join(\" \")} %*`;await oe.writeFilePromise(V.format({dir:t,name:e,ext:\".cmd\"}),a)}await oe.writeFilePromise(V.join(t,e),`#!/bin/sh\nexec \"${r}\" ${o.map(a=>`'${a.replace(/'/g,`'\"'\"'`)}'`).join(\" \")} \"$@\"\n`,{mode:493})}async function tue(t){let e=await Ot.tryFind(t);if(e?.packageManager){let o=_S(e.packageManager);if(o?.name){let a=`found ${JSON.stringify({packageManager:e.packageManager})} in manifest`,[n]=o.reference.split(\".\");switch(o.name){case\"yarn\":return{packageManagerField:!0,packageManager:Number(n)===1?\"Yarn Classic\":\"Yarn\",reason:a};case\"npm\":return{packageManagerField:!0,packageManager:\"npm\",reason:a};case\"pnpm\":return{packageManagerField:!0,packageManager:\"pnpm\",reason:a}}}}let r;try{r=await oe.readFilePromise(V.join(t,dr.lockfile),\"utf8\")}catch{}return r!==void 0?r.match(/^__metadata:$/m)?{packageManager:\"Yarn\",reason:'\"__metadata\" key found in yarn.lock'}:{packageManager:\"Yarn Classic\",reason:'\"__metadata\" key not found in yarn.lock, must be a Yarn classic lockfile'}:oe.existsSync(V.join(t,\"package-lock.json\"))?{packageManager:\"npm\",reason:`found npm's \"package-lock.json\" lockfile`}:oe.existsSync(V.join(t,\"pnpm-lock.yaml\"))?{packageManager:\"pnpm\",reason:`found pnpm's \"pnpm-lock.yaml\" lockfile`}:null}async function L1({project:t,locator:e,binFolder:r,ignoreCorepack:o,lifecycleScript:a,baseEnv:n=t?.configuration.env??process.env}){let u={};for(let[C,I]of Object.entries(n))typeof I<\"u\"&&(u[C.toLowerCase()!==\"path\"?C:\"PATH\"]=I);let A=ue.fromPortablePath(r);u.BERRY_BIN_FOLDER=ue.fromPortablePath(A);let p=process.env.COREPACK_ROOT&&!o?ue.join(process.env.COREPACK_ROOT,\"dist/yarn.js\"):process.argv[1];if(await Promise.all([Ah(r,\"node\",process.execPath),...tn!==null?[Ah(r,\"run\",process.execPath,[p,\"run\"]),Ah(r,\"yarn\",process.execPath,[p]),Ah(r,\"yarnpkg\",process.execPath,[p]),Ah(r,\"node-gyp\",process.execPath,[p,\"run\",\"--top-level\",\"node-gyp\"])]:[]]),t&&(u.INIT_CWD=ue.cwd(),u.PROJECT_CWD=ue.fromPortablePath(t.cwd)),u.PATH=u.PATH?`${A}${ue.delimiter}${u.PATH}`:`${A}`,u.npm_execpath=`${A}${ue.sep}yarn`,u.npm_node_execpath=`${A}${ue.sep}node`,e){if(!t)throw new Error(\"Assertion failed: Missing project\");let C=t.tryWorkspaceByLocator(e),I=C?C.manifest.version??\"\":t.storedPackages.get(e.locatorHash).version??\"\";u.npm_package_name=fn(e),u.npm_package_version=I;let v;if(C)v=C.cwd;else{let x=t.storedPackages.get(e.locatorHash);if(!x)throw new Error(`Package for ${jr(t.configuration,e)} not found in the project`);let E=t.configuration.getLinkers(),R={project:t,report:new Nt({stdout:new fh.PassThrough,configuration:t.configuration})},L=E.find(U=>U.supportsPackage(x,R));if(!L)throw new Error(`The package ${jr(t.configuration,x)} isn't supported by any of the available linkers`);v=await L.findPackageLocation(x,R)}u.npm_package_json=ue.fromPortablePath(V.join(v,dr.manifest))}let h=tn!==null?`yarn/${tn}`:`yarn/${zp(\"@yarnpkg/core\").version}-core`;return u.npm_config_user_agent=`${h} npm/? node/${process.version} ${process.platform} ${process.arch}`,a&&(u.npm_lifecycle_event=a),t&&await t.configuration.triggerHook(C=>C.setupScriptEnvironment,t,u,async(C,I,v)=>await Ah(r,C,I,v)),u}async function Pat(t,e,{configuration:r,report:o,workspace:a=null,locator:n=null}){await Dat(async()=>{await oe.mktempPromise(async u=>{let A=V.join(u,\"pack.log\"),p=null,{stdout:h,stderr:C}=r.getSubprocessStreams(A,{prefix:ue.fromPortablePath(t),report:o}),I=n&&Hc(n)?e1(n):n,v=I?ba(I):\"an external project\";h.write(`Packing ${v} from sources\n`);let x=await tue(t),E;x!==null?(h.write(`Using ${x.packageManager} for bootstrap. Reason: ${x.reason}\n\n`),E=x.packageManager):(h.write(`No package manager configuration detected; defaulting to Yarn\n\n`),E=\"Yarn\");let R=E===\"Yarn\"&&!x?.packageManagerField;await oe.mktempPromise(async L=>{let U=await L1({binFolder:L,ignoreCorepack:R}),te=new Map([[\"Yarn Classic\",async()=>{let he=a!==null?[\"workspace\",a]:[],Ae=V.join(t,dr.manifest),ye=await oe.readFilePromise(Ae),ae=await Gc(process.execPath,[process.argv[1],\"set\",\"version\",\"classic\",\"--only-if-needed\",\"--yarn-path\"],{cwd:t,env:U,stdin:p,stdout:h,stderr:C,end:1});if(ae.code!==0)return ae.code;await oe.writeFilePromise(Ae,ye),await oe.appendFilePromise(V.join(t,\".npmignore\"),`/.yarn\n`),h.write(`\n`),delete U.NODE_ENV;let Ie=await Gc(\"yarn\",[\"install\"],{cwd:t,env:U,stdin:p,stdout:h,stderr:C,end:1});if(Ie.code!==0)return Ie.code;h.write(`\n`);let Fe=await Gc(\"yarn\",[...he,\"pack\",\"--filename\",ue.fromPortablePath(e)],{cwd:t,env:U,stdin:p,stdout:h,stderr:C});return Fe.code!==0?Fe.code:0}],[\"Yarn\",async()=>{let he=a!==null?[\"workspace\",a]:[];U.YARN_ENABLE_INLINE_BUILDS=\"1\";let Ae=V.join(t,dr.lockfile);await oe.existsPromise(Ae)||await oe.writeFilePromise(Ae,\"\");let ye=await Gc(\"yarn\",[...he,\"pack\",\"--install-if-needed\",\"--filename\",ue.fromPortablePath(e)],{cwd:t,env:U,stdin:p,stdout:h,stderr:C});return ye.code!==0?ye.code:0}],[\"npm\",async()=>{if(a!==null){let Ee=new fh.PassThrough,De=Wy(Ee);Ee.pipe(h,{end:!1});let ce=await Gc(\"npm\",[\"--version\"],{cwd:t,env:U,stdin:p,stdout:Ee,stderr:C,end:0});if(Ee.end(),ce.code!==0)return h.end(),C.end(),ce.code;let ne=(await De).toString().trim();if(!bf(ne,\">=7.x\")){let ee=eA(null,\"npm\"),we=In(ee,ne),xe=In(ee,\">=7.x\");throw new Error(`Workspaces aren't supported by ${qn(r,we)}; please upgrade to ${qn(r,xe)} (npm has been detected as the primary package manager for ${Mt(r,t,yt.PATH)})`)}}let he=a!==null?[\"--workspace\",a]:[];delete U.npm_config_user_agent,delete U.npm_config_production,delete U.NPM_CONFIG_PRODUCTION,delete U.NODE_ENV;let Ae=await Gc(\"npm\",[\"install\",\"--legacy-peer-deps\"],{cwd:t,env:U,stdin:p,stdout:h,stderr:C,end:1});if(Ae.code!==0)return Ae.code;let ye=new fh.PassThrough,ae=Wy(ye);ye.pipe(h);let Ie=await Gc(\"npm\",[\"pack\",\"--silent\",...he],{cwd:t,env:U,stdin:p,stdout:ye,stderr:C});if(Ie.code!==0)return Ie.code;let Fe=(await ae).toString().trim().replace(/^.*\\n/s,\"\"),g=V.resolve(t,ue.toPortablePath(Fe));return await oe.renamePromise(g,e),0}]]).get(E);if(typeof te>\"u\")throw new Error(\"Assertion failed: Unsupported workflow\");let le=await te();if(!(le===0||typeof le>\"u\"))throw oe.detachTemp(u),new Jt(58,`Packing the package failed (exit code ${le}, logs can be found here: ${Mt(r,A,yt.PATH)})`)})})})}async function Sat(t,e,{project:r}){let o=r.tryWorkspaceByLocator(t);if(o!==null)return IU(o,e);let a=r.storedPackages.get(t.locatorHash);if(!a)throw new Error(`Package for ${jr(r.configuration,t)} not found in the project`);return await zl.openPromise(async n=>{let u=r.configuration,A=r.configuration.getLinkers(),p={project:r,report:new Nt({stdout:new fh.PassThrough,configuration:u})},h=A.find(x=>x.supportsPackage(a,p));if(!h)throw new Error(`The package ${jr(r.configuration,a)} isn't supported by any of the available linkers`);let C=await h.findPackageLocation(a,p),I=new gn(C,{baseFs:n});return(await Ot.find(Bt.dot,{baseFs:I})).scripts.has(e)})}async function Vb(t,e,r,{cwd:o,project:a,stdin:n,stdout:u,stderr:A}){return await oe.mktempPromise(async p=>{let{manifest:h,env:C,cwd:I}=await rue(t,{project:a,binFolder:p,cwd:o,lifecycleScript:e}),v=h.scripts.get(e);if(typeof v>\"u\")return 1;let x=async()=>await FE(v,r,{cwd:I,env:C,stdin:n,stdout:u,stderr:A});return await(await a.configuration.reduceHook(R=>R.wrapScriptExecution,x,a,t,e,{script:v,args:r,cwd:I,env:C,stdin:n,stdout:u,stderr:A}))()})}async function wU(t,e,r,{cwd:o,project:a,stdin:n,stdout:u,stderr:A}){return await oe.mktempPromise(async p=>{let{env:h,cwd:C}=await rue(t,{project:a,binFolder:p,cwd:o});return await FE(e,r,{cwd:C,env:h,stdin:n,stdout:u,stderr:A})})}async function bat(t,{binFolder:e,cwd:r,lifecycleScript:o}){let a=await L1({project:t.project,locator:t.anchoredLocator,binFolder:e,lifecycleScript:o});return await vU(e,await sue(t)),typeof r>\"u\"&&(r=V.dirname(await oe.realpathPromise(V.join(t.cwd,\"package.json\")))),{manifest:t.manifest,binFolder:e,env:a,cwd:r}}async function rue(t,{project:e,binFolder:r,cwd:o,lifecycleScript:a}){let n=e.tryWorkspaceByLocator(t);if(n!==null)return bat(n,{binFolder:r,cwd:o,lifecycleScript:a});let u=e.storedPackages.get(t.locatorHash);if(!u)throw new Error(`Package for ${jr(e.configuration,t)} not found in the project`);return await zl.openPromise(async A=>{let p=e.configuration,h=e.configuration.getLinkers(),C={project:e,report:new Nt({stdout:new fh.PassThrough,configuration:p})},I=h.find(L=>L.supportsPackage(u,C));if(!I)throw new Error(`The package ${jr(e.configuration,u)} isn't supported by any of the available linkers`);let v=await L1({project:e,locator:t,binFolder:r,lifecycleScript:a});await vU(r,await zb(t,{project:e}));let x=await I.findPackageLocation(u,C),E=new gn(x,{baseFs:A}),R=await Ot.find(Bt.dot,{baseFs:E});return typeof o>\"u\"&&(o=x),{manifest:R,binFolder:r,env:v,cwd:o}})}async function nue(t,e,r,{cwd:o,stdin:a,stdout:n,stderr:u}){return await Vb(t.anchoredLocator,e,r,{cwd:o,project:t.project,stdin:a,stdout:n,stderr:u})}function IU(t,e){return t.manifest.scripts.has(e)}async function iue(t,e,{cwd:r,report:o}){let{configuration:a}=t.project,n=null;await oe.mktempPromise(async u=>{let A=V.join(u,`${e}.log`),p=`# This file contains the result of Yarn calling the \"${e}\" lifecycle script inside a workspace (\"${ue.fromPortablePath(t.cwd)}\")\n`,{stdout:h,stderr:C}=a.getSubprocessStreams(A,{report:o,prefix:jr(a,t.anchoredLocator),header:p});o.reportInfo(36,`Calling the \"${e}\" lifecycle script`);let I=await nue(t,e,[],{cwd:r,stdin:n,stdout:h,stderr:C});if(h.end(),C.end(),I!==0)throw oe.detachTemp(u),new Jt(36,`${(0,Zce.default)(e)} script failed (exit code ${Mt(a,I,yt.NUMBER)}, logs can be found here: ${Mt(a,A,yt.PATH)}); run ${Mt(a,`yarn ${e}`,yt.CODE)} to investigate`)})}async function xat(t,e,r){IU(t,e)&&await iue(t,e,r)}function BU(t){let e=V.extname(t);if(e.match(/\\.[cm]?[jt]sx?$/))return!0;if(e===\".exe\"||e===\".bin\")return!1;let r=Buffer.alloc(4),o;try{o=oe.openSync(t,\"r\")}catch{return!0}try{oe.readSync(o,r,0,r.length,0)}finally{oe.closeSync(o)}let a=r.readUint32BE();return!(a===3405691582||a===3489328638||a===2135247942||(a&4294901760)===1297743872)}async function zb(t,{project:e}){let r=e.configuration,o=new Map,a=e.storedPackages.get(t.locatorHash);if(!a)throw new Error(`Package for ${jr(r,t)} not found in the project`);let n=new fh.Writable,u=r.getLinkers(),A={project:e,report:new Nt({configuration:r,stdout:n})},p=new Set([t.locatorHash]);for(let C of a.dependencies.values()){let I=e.storedResolutions.get(C.descriptorHash);if(!I)throw new Error(`Assertion failed: The resolution (${qn(r,C)}) should have been registered`);p.add(I)}let h=await Promise.all(Array.from(p,async C=>{let I=e.storedPackages.get(C);if(!I)throw new Error(`Assertion failed: The package (${C}) should have been registered`);if(I.bin.size===0)return sl.skip;let v=u.find(E=>E.supportsPackage(I,A));if(!v)return sl.skip;let x=null;try{x=await v.findPackageLocation(I,A)}catch(E){if(E.code===\"LOCATOR_NOT_INSTALLED\")return sl.skip;throw E}return{dependency:I,packageLocation:x}}));for(let C of h){if(C===sl.skip)continue;let{dependency:I,packageLocation:v}=C;for(let[x,E]of I.bin){let R=V.resolve(v,E);o.set(x,[I,ue.fromPortablePath(R),BU(R)])}}return o}async function sue(t){return await zb(t.anchoredLocator,{project:t.project})}async function vU(t,e){await Promise.all(Array.from(e,([r,[,o,a]])=>a?Ah(t,r,process.execPath,[o]):Ah(t,r,o,[])))}async function oue(t,e,r,{cwd:o,project:a,stdin:n,stdout:u,stderr:A,nodeArgs:p=[],packageAccessibleBinaries:h}){h??=await zb(t,{project:a});let C=h.get(e);if(!C)throw new Error(`Binary not found (${e}) for ${jr(a.configuration,t)}`);return await oe.mktempPromise(async I=>{let[,v]=C,x=await L1({project:a,locator:t,binFolder:I});await vU(x.BERRY_BIN_FOLDER,h);let E=BU(ue.toPortablePath(v))?Gc(process.execPath,[...p,v,...r],{cwd:o,env:x,stdin:n,stdout:u,stderr:A}):Gc(v,r,{cwd:o,env:x,stdin:n,stdout:u,stderr:A}),R;try{R=await E}finally{await oe.removePromise(x.BERRY_BIN_FOLDER)}return R.code})}async function kat(t,e,r,{cwd:o,stdin:a,stdout:n,stderr:u,packageAccessibleBinaries:A}){return await oue(t.anchoredLocator,e,r,{project:t.project,cwd:o,stdin:a,stdout:n,stderr:u,packageAccessibleBinaries:A})}var Zce,$ce,fh,eue,vat,Dat,DU=Et(()=>{Pt();Pt();nA();b1();Zce=$e(EU()),$ce=$e(rd()),fh=Be(\"stream\");uE();Yl();N1();T1();Sb();ql();jl();xf();bo();eue=(a=>(a.Yarn1=\"Yarn Classic\",a.Yarn2=\"Yarn\",a.Npm=\"npm\",a.Pnpm=\"pnpm\",a))(eue||{});vat=2,Dat=(0,$ce.default)(vat)});var NE=_((T4t,lue)=>{\"use strict\";var aue=new Map([[\"C\",\"cwd\"],[\"f\",\"file\"],[\"z\",\"gzip\"],[\"P\",\"preservePaths\"],[\"U\",\"unlink\"],[\"strip-components\",\"strip\"],[\"stripComponents\",\"strip\"],[\"keep-newer\",\"newer\"],[\"keepNewer\",\"newer\"],[\"keep-newer-files\",\"newer\"],[\"keepNewerFiles\",\"newer\"],[\"k\",\"keep\"],[\"keep-existing\",\"keep\"],[\"keepExisting\",\"keep\"],[\"m\",\"noMtime\"],[\"no-mtime\",\"noMtime\"],[\"p\",\"preserveOwner\"],[\"L\",\"follow\"],[\"h\",\"follow\"]]);lue.exports=t=>t?Object.keys(t).map(e=>[aue.has(e)?aue.get(e):e,t[e]]).reduce((e,r)=>(e[r[0]]=r[1],e),Object.create(null)):{}});var OE=_((N4t,mue)=>{\"use strict\";var cue=typeof process==\"object\"&&process?process:{stdout:null,stderr:null},Qat=Be(\"events\"),uue=Be(\"stream\"),Aue=Be(\"string_decoder\").StringDecoder,Lf=Symbol(\"EOF\"),Of=Symbol(\"maybeEmitEnd\"),ph=Symbol(\"emittedEnd\"),Jb=Symbol(\"emittingEnd\"),O1=Symbol(\"emittedError\"),Xb=Symbol(\"closed\"),fue=Symbol(\"read\"),Zb=Symbol(\"flush\"),pue=Symbol(\"flushChunk\"),ka=Symbol(\"encoding\"),Mf=Symbol(\"decoder\"),$b=Symbol(\"flowing\"),M1=Symbol(\"paused\"),LE=Symbol(\"resume\"),Fs=Symbol(\"bufferLength\"),PU=Symbol(\"bufferPush\"),SU=Symbol(\"bufferShift\"),Fo=Symbol(\"objectMode\"),Ro=Symbol(\"destroyed\"),bU=Symbol(\"emitData\"),hue=Symbol(\"emitEnd\"),xU=Symbol(\"emitEnd2\"),Uf=Symbol(\"async\"),U1=t=>Promise.resolve().then(t),gue=global._MP_NO_ITERATOR_SYMBOLS_!==\"1\",Fat=gue&&Symbol.asyncIterator||Symbol(\"asyncIterator not implemented\"),Rat=gue&&Symbol.iterator||Symbol(\"iterator not implemented\"),Tat=t=>t===\"end\"||t===\"finish\"||t===\"prefinish\",Nat=t=>t instanceof ArrayBuffer||typeof t==\"object\"&&t.constructor&&t.constructor.name===\"ArrayBuffer\"&&t.byteLength>=0,Lat=t=>!Buffer.isBuffer(t)&&ArrayBuffer.isView(t),ex=class{constructor(e,r,o){this.src=e,this.dest=r,this.opts=o,this.ondrain=()=>e[LE](),r.on(\"drain\",this.ondrain)}unpipe(){this.dest.removeListener(\"drain\",this.ondrain)}proxyErrors(){}end(){this.unpipe(),this.opts.end&&this.dest.end()}},kU=class extends ex{unpipe(){this.src.removeListener(\"error\",this.proxyErrors),super.unpipe()}constructor(e,r,o){super(e,r,o),this.proxyErrors=a=>r.emit(\"error\",a),e.on(\"error\",this.proxyErrors)}};mue.exports=class due extends uue{constructor(e){super(),this[$b]=!1,this[M1]=!1,this.pipes=[],this.buffer=[],this[Fo]=e&&e.objectMode||!1,this[Fo]?this[ka]=null:this[ka]=e&&e.encoding||null,this[ka]===\"buffer\"&&(this[ka]=null),this[Uf]=e&&!!e.async||!1,this[Mf]=this[ka]?new Aue(this[ka]):null,this[Lf]=!1,this[ph]=!1,this[Jb]=!1,this[Xb]=!1,this[O1]=null,this.writable=!0,this.readable=!0,this[Fs]=0,this[Ro]=!1}get bufferLength(){return this[Fs]}get encoding(){return this[ka]}set encoding(e){if(this[Fo])throw new Error(\"cannot set encoding in objectMode\");if(this[ka]&&e!==this[ka]&&(this[Mf]&&this[Mf].lastNeed||this[Fs]))throw new Error(\"cannot change encoding\");this[ka]!==e&&(this[Mf]=e?new Aue(e):null,this.buffer.length&&(this.buffer=this.buffer.map(r=>this[Mf].write(r)))),this[ka]=e}setEncoding(e){this.encoding=e}get objectMode(){return this[Fo]}set objectMode(e){this[Fo]=this[Fo]||!!e}get async(){return this[Uf]}set async(e){this[Uf]=this[Uf]||!!e}write(e,r,o){if(this[Lf])throw new Error(\"write after end\");if(this[Ro])return this.emit(\"error\",Object.assign(new Error(\"Cannot call write after a stream was destroyed\"),{code:\"ERR_STREAM_DESTROYED\"})),!0;typeof r==\"function\"&&(o=r,r=\"utf8\"),r||(r=\"utf8\");let a=this[Uf]?U1:n=>n();return!this[Fo]&&!Buffer.isBuffer(e)&&(Lat(e)?e=Buffer.from(e.buffer,e.byteOffset,e.byteLength):Nat(e)?e=Buffer.from(e):typeof e!=\"string\"&&(this.objectMode=!0)),this[Fo]?(this.flowing&&this[Fs]!==0&&this[Zb](!0),this.flowing?this.emit(\"data\",e):this[PU](e),this[Fs]!==0&&this.emit(\"readable\"),o&&a(o),this.flowing):e.length?(typeof e==\"string\"&&!(r===this[ka]&&!this[Mf].lastNeed)&&(e=Buffer.from(e,r)),Buffer.isBuffer(e)&&this[ka]&&(e=this[Mf].write(e)),this.flowing&&this[Fs]!==0&&this[Zb](!0),this.flowing?this.emit(\"data\",e):this[PU](e),this[Fs]!==0&&this.emit(\"readable\"),o&&a(o),this.flowing):(this[Fs]!==0&&this.emit(\"readable\"),o&&a(o),this.flowing)}read(e){if(this[Ro])return null;if(this[Fs]===0||e===0||e>this[Fs])return this[Of](),null;this[Fo]&&(e=null),this.buffer.length>1&&!this[Fo]&&(this.encoding?this.buffer=[this.buffer.join(\"\")]:this.buffer=[Buffer.concat(this.buffer,this[Fs])]);let r=this[fue](e||null,this.buffer[0]);return this[Of](),r}[fue](e,r){return e===r.length||e===null?this[SU]():(this.buffer[0]=r.slice(e),r=r.slice(0,e),this[Fs]-=e),this.emit(\"data\",r),!this.buffer.length&&!this[Lf]&&this.emit(\"drain\"),r}end(e,r,o){return typeof e==\"function\"&&(o=e,e=null),typeof r==\"function\"&&(o=r,r=\"utf8\"),e&&this.write(e,r),o&&this.once(\"end\",o),this[Lf]=!0,this.writable=!1,(this.flowing||!this[M1])&&this[Of](),this}[LE](){this[Ro]||(this[M1]=!1,this[$b]=!0,this.emit(\"resume\"),this.buffer.length?this[Zb]():this[Lf]?this[Of]():this.emit(\"drain\"))}resume(){return this[LE]()}pause(){this[$b]=!1,this[M1]=!0}get destroyed(){return this[Ro]}get flowing(){return this[$b]}get paused(){return this[M1]}[PU](e){this[Fo]?this[Fs]+=1:this[Fs]+=e.length,this.buffer.push(e)}[SU](){return this.buffer.length&&(this[Fo]?this[Fs]-=1:this[Fs]-=this.buffer[0].length),this.buffer.shift()}[Zb](e){do;while(this[pue](this[SU]()));!e&&!this.buffer.length&&!this[Lf]&&this.emit(\"drain\")}[pue](e){return e?(this.emit(\"data\",e),this.flowing):!1}pipe(e,r){if(this[Ro])return;let o=this[ph];return r=r||{},e===cue.stdout||e===cue.stderr?r.end=!1:r.end=r.end!==!1,r.proxyErrors=!!r.proxyErrors,o?r.end&&e.end():(this.pipes.push(r.proxyErrors?new kU(this,e,r):new ex(this,e,r)),this[Uf]?U1(()=>this[LE]()):this[LE]()),e}unpipe(e){let r=this.pipes.find(o=>o.dest===e);r&&(this.pipes.splice(this.pipes.indexOf(r),1),r.unpipe())}addListener(e,r){return this.on(e,r)}on(e,r){let o=super.on(e,r);return e===\"data\"&&!this.pipes.length&&!this.flowing?this[LE]():e===\"readable\"&&this[Fs]!==0?super.emit(\"readable\"):Tat(e)&&this[ph]?(super.emit(e),this.removeAllListeners(e)):e===\"error\"&&this[O1]&&(this[Uf]?U1(()=>r.call(this,this[O1])):r.call(this,this[O1])),o}get emittedEnd(){return this[ph]}[Of](){!this[Jb]&&!this[ph]&&!this[Ro]&&this.buffer.length===0&&this[Lf]&&(this[Jb]=!0,this.emit(\"end\"),this.emit(\"prefinish\"),this.emit(\"finish\"),this[Xb]&&this.emit(\"close\"),this[Jb]=!1)}emit(e,r,...o){if(e!==\"error\"&&e!==\"close\"&&e!==Ro&&this[Ro])return;if(e===\"data\")return r?this[Uf]?U1(()=>this[bU](r)):this[bU](r):!1;if(e===\"end\")return this[hue]();if(e===\"close\"){if(this[Xb]=!0,!this[ph]&&!this[Ro])return;let n=super.emit(\"close\");return this.removeAllListeners(\"close\"),n}else if(e===\"error\"){this[O1]=r;let n=super.emit(\"error\",r);return this[Of](),n}else if(e===\"resume\"){let n=super.emit(\"resume\");return this[Of](),n}else if(e===\"finish\"||e===\"prefinish\"){let n=super.emit(e);return this.removeAllListeners(e),n}let a=super.emit(e,r,...o);return this[Of](),a}[bU](e){for(let o of this.pipes)o.dest.write(e)===!1&&this.pause();let r=super.emit(\"data\",e);return this[Of](),r}[hue](){this[ph]||(this[ph]=!0,this.readable=!1,this[Uf]?U1(()=>this[xU]()):this[xU]())}[xU](){if(this[Mf]){let r=this[Mf].end();if(r){for(let o of this.pipes)o.dest.write(r);super.emit(\"data\",r)}}for(let r of this.pipes)r.end();let e=super.emit(\"end\");return this.removeAllListeners(\"end\"),e}collect(){let e=[];this[Fo]||(e.dataLength=0);let r=this.promise();return this.on(\"data\",o=>{e.push(o),this[Fo]||(e.dataLength+=o.length)}),r.then(()=>e)}concat(){return this[Fo]?Promise.reject(new Error(\"cannot concat in objectMode\")):this.collect().then(e=>this[Fo]?Promise.reject(new Error(\"cannot concat in objectMode\")):this[ka]?e.join(\"\"):Buffer.concat(e,e.dataLength))}promise(){return new Promise((e,r)=>{this.on(Ro,()=>r(new Error(\"stream destroyed\"))),this.on(\"error\",o=>r(o)),this.on(\"end\",()=>e())})}[Fat](){return{next:()=>{let r=this.read();if(r!==null)return Promise.resolve({done:!1,value:r});if(this[Lf])return Promise.resolve({done:!0});let o=null,a=null,n=h=>{this.removeListener(\"data\",u),this.removeListener(\"end\",A),a(h)},u=h=>{this.removeListener(\"error\",n),this.removeListener(\"end\",A),this.pause(),o({value:h,done:!!this[Lf]})},A=()=>{this.removeListener(\"error\",n),this.removeListener(\"data\",u),o({done:!0})},p=()=>n(new Error(\"stream destroyed\"));return new Promise((h,C)=>{a=C,o=h,this.once(Ro,p),this.once(\"error\",n),this.once(\"end\",A),this.once(\"data\",u)})}}}[Rat](){return{next:()=>{let r=this.read();return{value:r,done:r===null}}}}destroy(e){return this[Ro]?(e?this.emit(\"error\",e):this.emit(Ro),this):(this[Ro]=!0,this.buffer.length=0,this[Fs]=0,typeof this.close==\"function\"&&!this[Xb]&&this.close(),e?this.emit(\"error\",e):this.emit(Ro),this)}static isStream(e){return!!e&&(e instanceof due||e instanceof uue||e instanceof Qat&&(typeof e.pipe==\"function\"||typeof e.write==\"function\"&&typeof e.end==\"function\"))}}});var Eue=_((L4t,yue)=>{var Oat=Be(\"zlib\").constants||{ZLIB_VERNUM:4736};yue.exports=Object.freeze(Object.assign(Object.create(null),{Z_NO_FLUSH:0,Z_PARTIAL_FLUSH:1,Z_SYNC_FLUSH:2,Z_FULL_FLUSH:3,Z_FINISH:4,Z_BLOCK:5,Z_OK:0,Z_STREAM_END:1,Z_NEED_DICT:2,Z_ERRNO:-1,Z_STREAM_ERROR:-2,Z_DATA_ERROR:-3,Z_MEM_ERROR:-4,Z_BUF_ERROR:-5,Z_VERSION_ERROR:-6,Z_NO_COMPRESSION:0,Z_BEST_SPEED:1,Z_BEST_COMPRESSION:9,Z_DEFAULT_COMPRESSION:-1,Z_FILTERED:1,Z_HUFFMAN_ONLY:2,Z_RLE:3,Z_FIXED:4,Z_DEFAULT_STRATEGY:0,DEFLATE:1,INFLATE:2,GZIP:3,GUNZIP:4,DEFLATERAW:5,INFLATERAW:6,UNZIP:7,BROTLI_DECODE:8,BROTLI_ENCODE:9,Z_MIN_WINDOWBITS:8,Z_MAX_WINDOWBITS:15,Z_DEFAULT_WINDOWBITS:15,Z_MIN_CHUNK:64,Z_MAX_CHUNK:1/0,Z_DEFAULT_CHUNK:16384,Z_MIN_MEMLEVEL:1,Z_MAX_MEMLEVEL:9,Z_DEFAULT_MEMLEVEL:8,Z_MIN_LEVEL:-1,Z_MAX_LEVEL:9,Z_DEFAULT_LEVEL:-1,BROTLI_OPERATION_PROCESS:0,BROTLI_OPERATION_FLUSH:1,BROTLI_OPERATION_FINISH:2,BROTLI_OPERATION_EMIT_METADATA:3,BROTLI_MODE_GENERIC:0,BROTLI_MODE_TEXT:1,BROTLI_MODE_FONT:2,BROTLI_DEFAULT_MODE:0,BROTLI_MIN_QUALITY:0,BROTLI_MAX_QUALITY:11,BROTLI_DEFAULT_QUALITY:11,BROTLI_MIN_WINDOW_BITS:10,BROTLI_MAX_WINDOW_BITS:24,BROTLI_LARGE_MAX_WINDOW_BITS:30,BROTLI_DEFAULT_WINDOW:22,BROTLI_MIN_INPUT_BLOCK_BITS:16,BROTLI_MAX_INPUT_BLOCK_BITS:24,BROTLI_PARAM_MODE:0,BROTLI_PARAM_QUALITY:1,BROTLI_PARAM_LGWIN:2,BROTLI_PARAM_LGBLOCK:3,BROTLI_PARAM_DISABLE_LITERAL_CONTEXT_MODELING:4,BROTLI_PARAM_SIZE_HINT:5,BROTLI_PARAM_LARGE_WINDOW:6,BROTLI_PARAM_NPOSTFIX:7,BROTLI_PARAM_NDIRECT:8,BROTLI_DECODER_RESULT_ERROR:0,BROTLI_DECODER_RESULT_SUCCESS:1,BROTLI_DECODER_RESULT_NEEDS_MORE_INPUT:2,BROTLI_DECODER_RESULT_NEEDS_MORE_OUTPUT:3,BROTLI_DECODER_PARAM_DISABLE_RING_BUFFER_REALLOCATION:0,BROTLI_DECODER_PARAM_LARGE_WINDOW:1,BROTLI_DECODER_NO_ERROR:0,BROTLI_DECODER_SUCCESS:1,BROTLI_DECODER_NEEDS_MORE_INPUT:2,BROTLI_DECODER_NEEDS_MORE_OUTPUT:3,BROTLI_DECODER_ERROR_FORMAT_EXUBERANT_NIBBLE:-1,BROTLI_DECODER_ERROR_FORMAT_RESERVED:-2,BROTLI_DECODER_ERROR_FORMAT_EXUBERANT_META_NIBBLE:-3,BROTLI_DECODER_ERROR_FORMAT_SIMPLE_HUFFMAN_ALPHABET:-4,BROTLI_DECODER_ERROR_FORMAT_SIMPLE_HUFFMAN_SAME:-5,BROTLI_DECODER_ERROR_FORMAT_CL_SPACE:-6,BROTLI_DECODER_ERROR_FORMAT_HUFFMAN_SPACE:-7,BROTLI_DECODER_ERROR_FORMAT_CONTEXT_MAP_REPEAT:-8,BROTLI_DECODER_ERROR_FORMAT_BLOCK_LENGTH_1:-9,BROTLI_DECODER_ERROR_FORMAT_BLOCK_LENGTH_2:-10,BROTLI_DECODER_ERROR_FORMAT_TRANSFORM:-11,BROTLI_DECODER_ERROR_FORMAT_DICTIONARY:-12,BROTLI_DECODER_ERROR_FORMAT_WINDOW_BITS:-13,BROTLI_DECODER_ERROR_FORMAT_PADDING_1:-14,BROTLI_DECODER_ERROR_FORMAT_PADDING_2:-15,BROTLI_DECODER_ERROR_FORMAT_DISTANCE:-16,BROTLI_DECODER_ERROR_DICTIONARY_NOT_SET:-19,BROTLI_DECODER_ERROR_INVALID_ARGUMENTS:-20,BROTLI_DECODER_ERROR_ALLOC_CONTEXT_MODES:-21,BROTLI_DECODER_ERROR_ALLOC_TREE_GROUPS:-22,BROTLI_DECODER_ERROR_ALLOC_CONTEXT_MAP:-25,BROTLI_DECODER_ERROR_ALLOC_RING_BUFFER_1:-26,BROTLI_DECODER_ERROR_ALLOC_RING_BUFFER_2:-27,BROTLI_DECODER_ERROR_ALLOC_BLOCK_TYPE_TREES:-30,BROTLI_DECODER_ERROR_UNREACHABLE:-31},Oat))});var WU=_(cl=>{\"use strict\";var NU=Be(\"assert\"),hh=Be(\"buffer\").Buffer,Iue=Be(\"zlib\"),kd=cl.constants=Eue(),Mat=OE(),Cue=hh.concat,Qd=Symbol(\"_superWrite\"),UE=class extends Error{constructor(e){super(\"zlib: \"+e.message),this.code=e.code,this.errno=e.errno,this.code||(this.code=\"ZLIB_ERROR\"),this.message=\"zlib: \"+e.message,Error.captureStackTrace(this,this.constructor)}get name(){return\"ZlibError\"}},Uat=Symbol(\"opts\"),_1=Symbol(\"flushFlag\"),wue=Symbol(\"finishFlushFlag\"),YU=Symbol(\"fullFlushFlag\"),ti=Symbol(\"handle\"),tx=Symbol(\"onError\"),ME=Symbol(\"sawError\"),QU=Symbol(\"level\"),FU=Symbol(\"strategy\"),RU=Symbol(\"ended\"),O4t=Symbol(\"_defaultFullFlush\"),rx=class extends Mat{constructor(e,r){if(!e||typeof e!=\"object\")throw new TypeError(\"invalid options for ZlibBase constructor\");super(e),this[ME]=!1,this[RU]=!1,this[Uat]=e,this[_1]=e.flush,this[wue]=e.finishFlush;try{this[ti]=new Iue[r](e)}catch(o){throw new UE(o)}this[tx]=o=>{this[ME]||(this[ME]=!0,this.close(),this.emit(\"error\",o))},this[ti].on(\"error\",o=>this[tx](new UE(o))),this.once(\"end\",()=>this.close)}close(){this[ti]&&(this[ti].close(),this[ti]=null,this.emit(\"close\"))}reset(){if(!this[ME])return NU(this[ti],\"zlib binding closed\"),this[ti].reset()}flush(e){this.ended||(typeof e!=\"number\"&&(e=this[YU]),this.write(Object.assign(hh.alloc(0),{[_1]:e})))}end(e,r,o){return e&&this.write(e,r),this.flush(this[wue]),this[RU]=!0,super.end(null,null,o)}get ended(){return this[RU]}write(e,r,o){if(typeof r==\"function\"&&(o=r,r=\"utf8\"),typeof e==\"string\"&&(e=hh.from(e,r)),this[ME])return;NU(this[ti],\"zlib binding closed\");let a=this[ti]._handle,n=a.close;a.close=()=>{};let u=this[ti].close;this[ti].close=()=>{},hh.concat=h=>h;let A;try{let h=typeof e[_1]==\"number\"?e[_1]:this[_1];A=this[ti]._processChunk(e,h),hh.concat=Cue}catch(h){hh.concat=Cue,this[tx](new UE(h))}finally{this[ti]&&(this[ti]._handle=a,a.close=n,this[ti].close=u,this[ti].removeAllListeners(\"error\"))}this[ti]&&this[ti].on(\"error\",h=>this[tx](new UE(h)));let p;if(A)if(Array.isArray(A)&&A.length>0){p=this[Qd](hh.from(A[0]));for(let h=1;h<A.length;h++)p=this[Qd](A[h])}else p=this[Qd](hh.from(A));return o&&o(),p}[Qd](e){return super.write(e)}},_f=class extends rx{constructor(e,r){e=e||{},e.flush=e.flush||kd.Z_NO_FLUSH,e.finishFlush=e.finishFlush||kd.Z_FINISH,super(e,r),this[YU]=kd.Z_FULL_FLUSH,this[QU]=e.level,this[FU]=e.strategy}params(e,r){if(!this[ME]){if(!this[ti])throw new Error(\"cannot switch params when binding is closed\");if(!this[ti].params)throw new Error(\"not supported in this implementation\");if(this[QU]!==e||this[FU]!==r){this.flush(kd.Z_SYNC_FLUSH),NU(this[ti],\"zlib binding closed\");let o=this[ti].flush;this[ti].flush=(a,n)=>{this.flush(a),n()};try{this[ti].params(e,r)}finally{this[ti].flush=o}this[ti]&&(this[QU]=e,this[FU]=r)}}}},LU=class extends _f{constructor(e){super(e,\"Deflate\")}},OU=class extends _f{constructor(e){super(e,\"Inflate\")}},TU=Symbol(\"_portable\"),MU=class extends _f{constructor(e){super(e,\"Gzip\"),this[TU]=e&&!!e.portable}[Qd](e){return this[TU]?(this[TU]=!1,e[9]=255,super[Qd](e)):super[Qd](e)}},UU=class extends _f{constructor(e){super(e,\"Gunzip\")}},_U=class extends _f{constructor(e){super(e,\"DeflateRaw\")}},HU=class extends _f{constructor(e){super(e,\"InflateRaw\")}},jU=class extends _f{constructor(e){super(e,\"Unzip\")}},nx=class extends rx{constructor(e,r){e=e||{},e.flush=e.flush||kd.BROTLI_OPERATION_PROCESS,e.finishFlush=e.finishFlush||kd.BROTLI_OPERATION_FINISH,super(e,r),this[YU]=kd.BROTLI_OPERATION_FLUSH}},qU=class extends nx{constructor(e){super(e,\"BrotliCompress\")}},GU=class extends nx{constructor(e){super(e,\"BrotliDecompress\")}};cl.Deflate=LU;cl.Inflate=OU;cl.Gzip=MU;cl.Gunzip=UU;cl.DeflateRaw=_U;cl.InflateRaw=HU;cl.Unzip=jU;typeof Iue.BrotliCompress==\"function\"?(cl.BrotliCompress=qU,cl.BrotliDecompress=GU):cl.BrotliCompress=cl.BrotliDecompress=class{constructor(){throw new Error(\"Brotli is not supported in this version of Node.js\")}}});var _E=_((_4t,Bue)=>{var _at=process.env.TESTING_TAR_FAKE_PLATFORM||process.platform;Bue.exports=_at!==\"win32\"?t=>t:t=>t&&t.replace(/\\\\/g,\"/\")});var ix=_((j4t,vue)=>{\"use strict\";var Hat=OE(),KU=_E(),VU=Symbol(\"slurp\");vue.exports=class extends Hat{constructor(e,r,o){switch(super(),this.pause(),this.extended=r,this.globalExtended=o,this.header=e,this.startBlockSize=512*Math.ceil(e.size/512),this.blockRemain=this.startBlockSize,this.remain=e.size,this.type=e.type,this.meta=!1,this.ignore=!1,this.type){case\"File\":case\"OldFile\":case\"Link\":case\"SymbolicLink\":case\"CharacterDevice\":case\"BlockDevice\":case\"Directory\":case\"FIFO\":case\"ContiguousFile\":case\"GNUDumpDir\":break;case\"NextFileHasLongLinkpath\":case\"NextFileHasLongPath\":case\"OldGnuLongPath\":case\"GlobalExtendedHeader\":case\"ExtendedHeader\":case\"OldExtendedHeader\":this.meta=!0;break;default:this.ignore=!0}this.path=KU(e.path),this.mode=e.mode,this.mode&&(this.mode=this.mode&4095),this.uid=e.uid,this.gid=e.gid,this.uname=e.uname,this.gname=e.gname,this.size=e.size,this.mtime=e.mtime,this.atime=e.atime,this.ctime=e.ctime,this.linkpath=KU(e.linkpath),this.uname=e.uname,this.gname=e.gname,r&&this[VU](r),o&&this[VU](o,!0)}write(e){let r=e.length;if(r>this.blockRemain)throw new Error(\"writing more to entry than is appropriate\");let o=this.remain,a=this.blockRemain;return this.remain=Math.max(0,o-r),this.blockRemain=Math.max(0,a-r),this.ignore?!0:o>=r?super.write(e):super.write(e.slice(0,o))}[VU](e,r){for(let o in e)e[o]!==null&&e[o]!==void 0&&!(r&&o===\"path\")&&(this[o]=o===\"path\"||o===\"linkpath\"?KU(e[o]):e[o])}}});var zU=_(sx=>{\"use strict\";sx.name=new Map([[\"0\",\"File\"],[\"\",\"OldFile\"],[\"1\",\"Link\"],[\"2\",\"SymbolicLink\"],[\"3\",\"CharacterDevice\"],[\"4\",\"BlockDevice\"],[\"5\",\"Directory\"],[\"6\",\"FIFO\"],[\"7\",\"ContiguousFile\"],[\"g\",\"GlobalExtendedHeader\"],[\"x\",\"ExtendedHeader\"],[\"A\",\"SolarisACL\"],[\"D\",\"GNUDumpDir\"],[\"I\",\"Inode\"],[\"K\",\"NextFileHasLongLinkpath\"],[\"L\",\"NextFileHasLongPath\"],[\"M\",\"ContinuationFile\"],[\"N\",\"OldGnuLongPath\"],[\"S\",\"SparseFile\"],[\"V\",\"TapeVolumeHeader\"],[\"X\",\"OldExtendedHeader\"]]);sx.code=new Map(Array.from(sx.name).map(t=>[t[1],t[0]]))});var bue=_((G4t,Sue)=>{\"use strict\";var jat=(t,e)=>{if(Number.isSafeInteger(t))t<0?Gat(t,e):qat(t,e);else throw Error(\"cannot encode number outside of javascript safe integer range\");return e},qat=(t,e)=>{e[0]=128;for(var r=e.length;r>1;r--)e[r-1]=t&255,t=Math.floor(t/256)},Gat=(t,e)=>{e[0]=255;var r=!1;t=t*-1;for(var o=e.length;o>1;o--){var a=t&255;t=Math.floor(t/256),r?e[o-1]=Due(a):a===0?e[o-1]=0:(r=!0,e[o-1]=Pue(a))}},Yat=t=>{let e=t[0],r=e===128?Kat(t.slice(1,t.length)):e===255?Wat(t):null;if(r===null)throw Error(\"invalid base256 encoding\");if(!Number.isSafeInteger(r))throw Error(\"parsed number outside of javascript safe integer range\");return r},Wat=t=>{for(var e=t.length,r=0,o=!1,a=e-1;a>-1;a--){var n=t[a],u;o?u=Due(n):n===0?u=n:(o=!0,u=Pue(n)),u!==0&&(r-=u*Math.pow(256,e-a-1))}return r},Kat=t=>{for(var e=t.length,r=0,o=e-1;o>-1;o--){var a=t[o];a!==0&&(r+=a*Math.pow(256,e-o-1))}return r},Due=t=>(255^t)&255,Pue=t=>(255^t)+1&255;Sue.exports={encode:jat,parse:Yat}});var jE=_((Y4t,kue)=>{\"use strict\";var JU=zU(),HE=Be(\"path\").posix,xue=bue(),XU=Symbol(\"slurp\"),ul=Symbol(\"type\"),e3=class{constructor(e,r,o,a){this.cksumValid=!1,this.needPax=!1,this.nullBlock=!1,this.block=null,this.path=null,this.mode=null,this.uid=null,this.gid=null,this.size=null,this.mtime=null,this.cksum=null,this[ul]=\"0\",this.linkpath=null,this.uname=null,this.gname=null,this.devmaj=0,this.devmin=0,this.atime=null,this.ctime=null,Buffer.isBuffer(e)?this.decode(e,r||0,o,a):e&&this.set(e)}decode(e,r,o,a){if(r||(r=0),!e||!(e.length>=r+512))throw new Error(\"need 512 bytes for header\");if(this.path=Fd(e,r,100),this.mode=gh(e,r+100,8),this.uid=gh(e,r+108,8),this.gid=gh(e,r+116,8),this.size=gh(e,r+124,12),this.mtime=ZU(e,r+136,12),this.cksum=gh(e,r+148,12),this[XU](o),this[XU](a,!0),this[ul]=Fd(e,r+156,1),this[ul]===\"\"&&(this[ul]=\"0\"),this[ul]===\"0\"&&this.path.substr(-1)===\"/\"&&(this[ul]=\"5\"),this[ul]===\"5\"&&(this.size=0),this.linkpath=Fd(e,r+157,100),e.slice(r+257,r+265).toString()===\"ustar\\x0000\")if(this.uname=Fd(e,r+265,32),this.gname=Fd(e,r+297,32),this.devmaj=gh(e,r+329,8),this.devmin=gh(e,r+337,8),e[r+475]!==0){let u=Fd(e,r+345,155);this.path=u+\"/\"+this.path}else{let u=Fd(e,r+345,130);u&&(this.path=u+\"/\"+this.path),this.atime=ZU(e,r+476,12),this.ctime=ZU(e,r+488,12)}let n=8*32;for(let u=r;u<r+148;u++)n+=e[u];for(let u=r+156;u<r+512;u++)n+=e[u];this.cksumValid=n===this.cksum,this.cksum===null&&n===8*32&&(this.nullBlock=!0)}[XU](e,r){for(let o in e)e[o]!==null&&e[o]!==void 0&&!(r&&o===\"path\")&&(this[o]=e[o])}encode(e,r){if(e||(e=this.block=Buffer.alloc(512),r=0),r||(r=0),!(e.length>=r+512))throw new Error(\"need 512 bytes for header\");let o=this.ctime||this.atime?130:155,a=Vat(this.path||\"\",o),n=a[0],u=a[1];this.needPax=a[2],this.needPax=Rd(e,r,100,n)||this.needPax,this.needPax=dh(e,r+100,8,this.mode)||this.needPax,this.needPax=dh(e,r+108,8,this.uid)||this.needPax,this.needPax=dh(e,r+116,8,this.gid)||this.needPax,this.needPax=dh(e,r+124,12,this.size)||this.needPax,this.needPax=$U(e,r+136,12,this.mtime)||this.needPax,e[r+156]=this[ul].charCodeAt(0),this.needPax=Rd(e,r+157,100,this.linkpath)||this.needPax,e.write(\"ustar\\x0000\",r+257,8),this.needPax=Rd(e,r+265,32,this.uname)||this.needPax,this.needPax=Rd(e,r+297,32,this.gname)||this.needPax,this.needPax=dh(e,r+329,8,this.devmaj)||this.needPax,this.needPax=dh(e,r+337,8,this.devmin)||this.needPax,this.needPax=Rd(e,r+345,o,u)||this.needPax,e[r+475]!==0?this.needPax=Rd(e,r+345,155,u)||this.needPax:(this.needPax=Rd(e,r+345,130,u)||this.needPax,this.needPax=$U(e,r+476,12,this.atime)||this.needPax,this.needPax=$U(e,r+488,12,this.ctime)||this.needPax);let A=8*32;for(let p=r;p<r+148;p++)A+=e[p];for(let p=r+156;p<r+512;p++)A+=e[p];return this.cksum=A,dh(e,r+148,8,this.cksum),this.cksumValid=!0,this.needPax}set(e){for(let r in e)e[r]!==null&&e[r]!==void 0&&(this[r]=e[r])}get type(){return JU.name.get(this[ul])||this[ul]}get typeKey(){return this[ul]}set type(e){JU.code.has(e)?this[ul]=JU.code.get(e):this[ul]=e}},Vat=(t,e)=>{let o=t,a=\"\",n,u=HE.parse(t).root||\".\";if(Buffer.byteLength(o)<100)n=[o,a,!1];else{a=HE.dirname(o),o=HE.basename(o);do Buffer.byteLength(o)<=100&&Buffer.byteLength(a)<=e?n=[o,a,!1]:Buffer.byteLength(o)>100&&Buffer.byteLength(a)<=e?n=[o.substr(0,100-1),a,!0]:(o=HE.join(HE.basename(a),o),a=HE.dirname(a));while(a!==u&&!n);n||(n=[t.substr(0,100-1),\"\",!0])}return n},Fd=(t,e,r)=>t.slice(e,e+r).toString(\"utf8\").replace(/\\0.*/,\"\"),ZU=(t,e,r)=>zat(gh(t,e,r)),zat=t=>t===null?null:new Date(t*1e3),gh=(t,e,r)=>t[e]&128?xue.parse(t.slice(e,e+r)):Xat(t,e,r),Jat=t=>isNaN(t)?null:t,Xat=(t,e,r)=>Jat(parseInt(t.slice(e,e+r).toString(\"utf8\").replace(/\\0.*$/,\"\").trim(),8)),Zat={12:8589934591,8:2097151},dh=(t,e,r,o)=>o===null?!1:o>Zat[r]||o<0?(xue.encode(o,t.slice(e,e+r)),!0):($at(t,e,r,o),!1),$at=(t,e,r,o)=>t.write(elt(o,r),e,r,\"ascii\"),elt=(t,e)=>tlt(Math.floor(t).toString(8),e),tlt=(t,e)=>(t.length===e-1?t:new Array(e-t.length-1).join(\"0\")+t+\" \")+\"\\0\",$U=(t,e,r,o)=>o===null?!1:dh(t,e,r,o.getTime()/1e3),rlt=new Array(156).join(\"\\0\"),Rd=(t,e,r,o)=>o===null?!1:(t.write(o+rlt,e,r,\"utf8\"),o.length!==Buffer.byteLength(o)||o.length>r);kue.exports=e3});var ox=_((W4t,Que)=>{\"use strict\";var nlt=jE(),ilt=Be(\"path\"),H1=class{constructor(e,r){this.atime=e.atime||null,this.charset=e.charset||null,this.comment=e.comment||null,this.ctime=e.ctime||null,this.gid=e.gid||null,this.gname=e.gname||null,this.linkpath=e.linkpath||null,this.mtime=e.mtime||null,this.path=e.path||null,this.size=e.size||null,this.uid=e.uid||null,this.uname=e.uname||null,this.dev=e.dev||null,this.ino=e.ino||null,this.nlink=e.nlink||null,this.global=r||!1}encode(){let e=this.encodeBody();if(e===\"\")return null;let r=Buffer.byteLength(e),o=512*Math.ceil(1+r/512),a=Buffer.allocUnsafe(o);for(let n=0;n<512;n++)a[n]=0;new nlt({path:(\"PaxHeader/\"+ilt.basename(this.path)).slice(0,99),mode:this.mode||420,uid:this.uid||null,gid:this.gid||null,size:r,mtime:this.mtime||null,type:this.global?\"GlobalExtendedHeader\":\"ExtendedHeader\",linkpath:\"\",uname:this.uname||\"\",gname:this.gname||\"\",devmaj:0,devmin:0,atime:this.atime||null,ctime:this.ctime||null}).encode(a),a.write(e,512,r,\"utf8\");for(let n=r+512;n<a.length;n++)a[n]=0;return a}encodeBody(){return this.encodeField(\"path\")+this.encodeField(\"ctime\")+this.encodeField(\"atime\")+this.encodeField(\"dev\")+this.encodeField(\"ino\")+this.encodeField(\"nlink\")+this.encodeField(\"charset\")+this.encodeField(\"comment\")+this.encodeField(\"gid\")+this.encodeField(\"gname\")+this.encodeField(\"linkpath\")+this.encodeField(\"mtime\")+this.encodeField(\"size\")+this.encodeField(\"uid\")+this.encodeField(\"uname\")}encodeField(e){if(this[e]===null||this[e]===void 0)return\"\";let r=this[e]instanceof Date?this[e].getTime()/1e3:this[e],o=\" \"+(e===\"dev\"||e===\"ino\"||e===\"nlink\"?\"SCHILY.\":\"\")+e+\"=\"+r+`\n`,a=Buffer.byteLength(o),n=Math.floor(Math.log(a)/Math.log(10))+1;return a+n>=Math.pow(10,n)&&(n+=1),n+a+o}};H1.parse=(t,e,r)=>new H1(slt(olt(t),e),r);var slt=(t,e)=>e?Object.keys(t).reduce((r,o)=>(r[o]=t[o],r),e):t,olt=t=>t.replace(/\\n$/,\"\").split(`\n`).reduce(alt,Object.create(null)),alt=(t,e)=>{let r=parseInt(e,10);if(r!==Buffer.byteLength(e)+1)return t;e=e.substr((r+\" \").length);let o=e.split(\"=\"),a=o.shift().replace(/^SCHILY\\.(dev|ino|nlink)/,\"$1\");if(!a)return t;let n=o.join(\"=\");return t[a]=/^([A-Z]+\\.)?([mac]|birth|creation)time$/.test(a)?new Date(n*1e3):/^[0-9]+$/.test(n)?+n:n,t};Que.exports=H1});var qE=_((K4t,Fue)=>{Fue.exports=t=>{let e=t.length-1,r=-1;for(;e>-1&&t.charAt(e)===\"/\";)r=e,e--;return r===-1?t:t.slice(0,r)}});var ax=_((V4t,Rue)=>{\"use strict\";Rue.exports=t=>class extends t{warn(e,r,o={}){this.file&&(o.file=this.file),this.cwd&&(o.cwd=this.cwd),o.code=r instanceof Error&&r.code||e,o.tarCode=e,!this.strict&&o.recoverable!==!1?(r instanceof Error&&(o=Object.assign(r,o),r=r.message),this.emit(\"warn\",o.tarCode,r,o)):r instanceof Error?this.emit(\"error\",Object.assign(r,o)):this.emit(\"error\",Object.assign(new Error(`${e}: ${r}`),o))}}});var r3=_((J4t,Tue)=>{\"use strict\";var lx=[\"|\",\"<\",\">\",\"?\",\":\"],t3=lx.map(t=>String.fromCharCode(61440+t.charCodeAt(0))),llt=new Map(lx.map((t,e)=>[t,t3[e]])),clt=new Map(t3.map((t,e)=>[t,lx[e]]));Tue.exports={encode:t=>lx.reduce((e,r)=>e.split(r).join(llt.get(r)),t),decode:t=>t3.reduce((e,r)=>e.split(r).join(clt.get(r)),t)}});var n3=_((X4t,Lue)=>{var{isAbsolute:ult,parse:Nue}=Be(\"path\").win32;Lue.exports=t=>{let e=\"\",r=Nue(t);for(;ult(t)||r.root;){let o=t.charAt(0)===\"/\"&&t.slice(0,4)!==\"//?/\"?\"/\":r.root;t=t.substr(o.length),e+=o,r=Nue(t)}return[e,t]}});var Mue=_((Z4t,Oue)=>{\"use strict\";Oue.exports=(t,e,r)=>(t&=4095,r&&(t=(t|384)&-19),e&&(t&256&&(t|=64),t&32&&(t|=8),t&4&&(t|=1)),t)});var p3=_((tUt,Zue)=>{\"use strict\";var Yue=OE(),Wue=ox(),Kue=jE(),oA=Be(\"fs\"),Uue=Be(\"path\"),sA=_E(),Alt=qE(),Vue=(t,e)=>e?(t=sA(t).replace(/^\\.(\\/|$)/,\"\"),Alt(e)+\"/\"+t):sA(t),flt=16*1024*1024,_ue=Symbol(\"process\"),Hue=Symbol(\"file\"),jue=Symbol(\"directory\"),s3=Symbol(\"symlink\"),que=Symbol(\"hardlink\"),j1=Symbol(\"header\"),cx=Symbol(\"read\"),o3=Symbol(\"lstat\"),ux=Symbol(\"onlstat\"),a3=Symbol(\"onread\"),l3=Symbol(\"onreadlink\"),c3=Symbol(\"openfile\"),u3=Symbol(\"onopenfile\"),mh=Symbol(\"close\"),Ax=Symbol(\"mode\"),A3=Symbol(\"awaitDrain\"),i3=Symbol(\"ondrain\"),aA=Symbol(\"prefix\"),Gue=Symbol(\"hadError\"),zue=ax(),plt=r3(),Jue=n3(),Xue=Mue(),fx=zue(class extends Yue{constructor(e,r){if(r=r||{},super(r),typeof e!=\"string\")throw new TypeError(\"path is required\");this.path=sA(e),this.portable=!!r.portable,this.myuid=process.getuid&&process.getuid()||0,this.myuser=process.env.USER||\"\",this.maxReadSize=r.maxReadSize||flt,this.linkCache=r.linkCache||new Map,this.statCache=r.statCache||new Map,this.preservePaths=!!r.preservePaths,this.cwd=sA(r.cwd||process.cwd()),this.strict=!!r.strict,this.noPax=!!r.noPax,this.noMtime=!!r.noMtime,this.mtime=r.mtime||null,this.prefix=r.prefix?sA(r.prefix):null,this.fd=null,this.blockLen=null,this.blockRemain=null,this.buf=null,this.offset=null,this.length=null,this.pos=null,this.remain=null,typeof r.onwarn==\"function\"&&this.on(\"warn\",r.onwarn);let o=!1;if(!this.preservePaths){let[a,n]=Jue(this.path);a&&(this.path=n,o=a)}this.win32=!!r.win32||process.platform===\"win32\",this.win32&&(this.path=plt.decode(this.path.replace(/\\\\/g,\"/\")),e=e.replace(/\\\\/g,\"/\")),this.absolute=sA(r.absolute||Uue.resolve(this.cwd,e)),this.path===\"\"&&(this.path=\"./\"),o&&this.warn(\"TAR_ENTRY_INFO\",`stripping ${o} from absolute path`,{entry:this,path:o+this.path}),this.statCache.has(this.absolute)?this[ux](this.statCache.get(this.absolute)):this[o3]()}emit(e,...r){return e===\"error\"&&(this[Gue]=!0),super.emit(e,...r)}[o3](){oA.lstat(this.absolute,(e,r)=>{if(e)return this.emit(\"error\",e);this[ux](r)})}[ux](e){this.statCache.set(this.absolute,e),this.stat=e,e.isFile()||(e.size=0),this.type=glt(e),this.emit(\"stat\",e),this[_ue]()}[_ue](){switch(this.type){case\"File\":return this[Hue]();case\"Directory\":return this[jue]();case\"SymbolicLink\":return this[s3]();default:return this.end()}}[Ax](e){return Xue(e,this.type===\"Directory\",this.portable)}[aA](e){return Vue(e,this.prefix)}[j1](){this.type===\"Directory\"&&this.portable&&(this.noMtime=!0),this.header=new Kue({path:this[aA](this.path),linkpath:this.type===\"Link\"?this[aA](this.linkpath):this.linkpath,mode:this[Ax](this.stat.mode),uid:this.portable?null:this.stat.uid,gid:this.portable?null:this.stat.gid,size:this.stat.size,mtime:this.noMtime?null:this.mtime||this.stat.mtime,type:this.type,uname:this.portable?null:this.stat.uid===this.myuid?this.myuser:\"\",atime:this.portable?null:this.stat.atime,ctime:this.portable?null:this.stat.ctime}),this.header.encode()&&!this.noPax&&super.write(new Wue({atime:this.portable?null:this.header.atime,ctime:this.portable?null:this.header.ctime,gid:this.portable?null:this.header.gid,mtime:this.noMtime?null:this.mtime||this.header.mtime,path:this[aA](this.path),linkpath:this.type===\"Link\"?this[aA](this.linkpath):this.linkpath,size:this.header.size,uid:this.portable?null:this.header.uid,uname:this.portable?null:this.header.uname,dev:this.portable?null:this.stat.dev,ino:this.portable?null:this.stat.ino,nlink:this.portable?null:this.stat.nlink}).encode()),super.write(this.header.block)}[jue](){this.path.substr(-1)!==\"/\"&&(this.path+=\"/\"),this.stat.size=0,this[j1](),this.end()}[s3](){oA.readlink(this.absolute,(e,r)=>{if(e)return this.emit(\"error\",e);this[l3](r)})}[l3](e){this.linkpath=sA(e),this[j1](),this.end()}[que](e){this.type=\"Link\",this.linkpath=sA(Uue.relative(this.cwd,e)),this.stat.size=0,this[j1](),this.end()}[Hue](){if(this.stat.nlink>1){let e=this.stat.dev+\":\"+this.stat.ino;if(this.linkCache.has(e)){let r=this.linkCache.get(e);if(r.indexOf(this.cwd)===0)return this[que](r)}this.linkCache.set(e,this.absolute)}if(this[j1](),this.stat.size===0)return this.end();this[c3]()}[c3](){oA.open(this.absolute,\"r\",(e,r)=>{if(e)return this.emit(\"error\",e);this[u3](r)})}[u3](e){if(this.fd=e,this[Gue])return this[mh]();this.blockLen=512*Math.ceil(this.stat.size/512),this.blockRemain=this.blockLen;let r=Math.min(this.blockLen,this.maxReadSize);this.buf=Buffer.allocUnsafe(r),this.offset=0,this.pos=0,this.remain=this.stat.size,this.length=this.buf.length,this[cx]()}[cx](){let{fd:e,buf:r,offset:o,length:a,pos:n}=this;oA.read(e,r,o,a,n,(u,A)=>{if(u)return this[mh](()=>this.emit(\"error\",u));this[a3](A)})}[mh](e){oA.close(this.fd,e)}[a3](e){if(e<=0&&this.remain>0){let a=new Error(\"encountered unexpected EOF\");return a.path=this.absolute,a.syscall=\"read\",a.code=\"EOF\",this[mh](()=>this.emit(\"error\",a))}if(e>this.remain){let a=new Error(\"did not encounter expected EOF\");return a.path=this.absolute,a.syscall=\"read\",a.code=\"EOF\",this[mh](()=>this.emit(\"error\",a))}if(e===this.remain)for(let a=e;a<this.length&&e<this.blockRemain;a++)this.buf[a+this.offset]=0,e++,this.remain++;let r=this.offset===0&&e===this.buf.length?this.buf:this.buf.slice(this.offset,this.offset+e);this.write(r)?this[i3]():this[A3](()=>this[i3]())}[A3](e){this.once(\"drain\",e)}write(e){if(this.blockRemain<e.length){let r=new Error(\"writing more data than expected\");return r.path=this.absolute,this.emit(\"error\",r)}return this.remain-=e.length,this.blockRemain-=e.length,this.pos+=e.length,this.offset+=e.length,super.write(e)}[i3](){if(!this.remain)return this.blockRemain&&super.write(Buffer.alloc(this.blockRemain)),this[mh](e=>e?this.emit(\"error\",e):this.end());this.offset>=this.length&&(this.buf=Buffer.allocUnsafe(Math.min(this.blockRemain,this.buf.length)),this.offset=0),this.length=this.buf.length-this.offset,this[cx]()}}),f3=class extends fx{[o3](){this[ux](oA.lstatSync(this.absolute))}[s3](){this[l3](oA.readlinkSync(this.absolute))}[c3](){this[u3](oA.openSync(this.absolute,\"r\"))}[cx](){let e=!0;try{let{fd:r,buf:o,offset:a,length:n,pos:u}=this,A=oA.readSync(r,o,a,n,u);this[a3](A),e=!1}finally{if(e)try{this[mh](()=>{})}catch{}}}[A3](e){e()}[mh](e){oA.closeSync(this.fd),e()}},hlt=zue(class extends Yue{constructor(e,r){r=r||{},super(r),this.preservePaths=!!r.preservePaths,this.portable=!!r.portable,this.strict=!!r.strict,this.noPax=!!r.noPax,this.noMtime=!!r.noMtime,this.readEntry=e,this.type=e.type,this.type===\"Directory\"&&this.portable&&(this.noMtime=!0),this.prefix=r.prefix||null,this.path=sA(e.path),this.mode=this[Ax](e.mode),this.uid=this.portable?null:e.uid,this.gid=this.portable?null:e.gid,this.uname=this.portable?null:e.uname,this.gname=this.portable?null:e.gname,this.size=e.size,this.mtime=this.noMtime?null:r.mtime||e.mtime,this.atime=this.portable?null:e.atime,this.ctime=this.portable?null:e.ctime,this.linkpath=sA(e.linkpath),typeof r.onwarn==\"function\"&&this.on(\"warn\",r.onwarn);let o=!1;if(!this.preservePaths){let[a,n]=Jue(this.path);a&&(this.path=n,o=a)}this.remain=e.size,this.blockRemain=e.startBlockSize,this.header=new Kue({path:this[aA](this.path),linkpath:this.type===\"Link\"?this[aA](this.linkpath):this.linkpath,mode:this.mode,uid:this.portable?null:this.uid,gid:this.portable?null:this.gid,size:this.size,mtime:this.noMtime?null:this.mtime,type:this.type,uname:this.portable?null:this.uname,atime:this.portable?null:this.atime,ctime:this.portable?null:this.ctime}),o&&this.warn(\"TAR_ENTRY_INFO\",`stripping ${o} from absolute path`,{entry:this,path:o+this.path}),this.header.encode()&&!this.noPax&&super.write(new Wue({atime:this.portable?null:this.atime,ctime:this.portable?null:this.ctime,gid:this.portable?null:this.gid,mtime:this.noMtime?null:this.mtime,path:this[aA](this.path),linkpath:this.type===\"Link\"?this[aA](this.linkpath):this.linkpath,size:this.size,uid:this.portable?null:this.uid,uname:this.portable?null:this.uname,dev:this.portable?null:this.readEntry.dev,ino:this.portable?null:this.readEntry.ino,nlink:this.portable?null:this.readEntry.nlink}).encode()),super.write(this.header.block),e.pipe(this)}[aA](e){return Vue(e,this.prefix)}[Ax](e){return Xue(e,this.type===\"Directory\",this.portable)}write(e){let r=e.length;if(r>this.blockRemain)throw new Error(\"writing more to entry than is appropriate\");return this.blockRemain-=r,super.write(e)}end(){return this.blockRemain&&super.write(Buffer.alloc(this.blockRemain)),super.end()}});fx.Sync=f3;fx.Tar=hlt;var glt=t=>t.isFile()?\"File\":t.isDirectory()?\"Directory\":t.isSymbolicLink()?\"SymbolicLink\":\"Unsupported\";Zue.exports=fx});var wx=_((nUt,sAe)=>{\"use strict\";var Ex=class{constructor(e,r){this.path=e||\"./\",this.absolute=r,this.entry=null,this.stat=null,this.readdir=null,this.pending=!1,this.ignore=!1,this.piped=!1}},dlt=OE(),mlt=WU(),ylt=ix(),I3=p3(),Elt=I3.Sync,Clt=I3.Tar,wlt=BP(),$ue=Buffer.alloc(1024),gx=Symbol(\"onStat\"),px=Symbol(\"ended\"),lA=Symbol(\"queue\"),GE=Symbol(\"current\"),Td=Symbol(\"process\"),hx=Symbol(\"processing\"),eAe=Symbol(\"processJob\"),cA=Symbol(\"jobs\"),h3=Symbol(\"jobDone\"),dx=Symbol(\"addFSEntry\"),tAe=Symbol(\"addTarEntry\"),y3=Symbol(\"stat\"),E3=Symbol(\"readdir\"),mx=Symbol(\"onreaddir\"),yx=Symbol(\"pipe\"),rAe=Symbol(\"entry\"),g3=Symbol(\"entryOpt\"),C3=Symbol(\"writeEntryClass\"),iAe=Symbol(\"write\"),d3=Symbol(\"ondrain\"),Cx=Be(\"fs\"),nAe=Be(\"path\"),Ilt=ax(),m3=_E(),B3=Ilt(class extends dlt{constructor(e){super(e),e=e||Object.create(null),this.opt=e,this.file=e.file||\"\",this.cwd=e.cwd||process.cwd(),this.maxReadSize=e.maxReadSize,this.preservePaths=!!e.preservePaths,this.strict=!!e.strict,this.noPax=!!e.noPax,this.prefix=m3(e.prefix||\"\"),this.linkCache=e.linkCache||new Map,this.statCache=e.statCache||new Map,this.readdirCache=e.readdirCache||new Map,this[C3]=I3,typeof e.onwarn==\"function\"&&this.on(\"warn\",e.onwarn),this.portable=!!e.portable,this.zip=null,e.gzip?(typeof e.gzip!=\"object\"&&(e.gzip={}),this.portable&&(e.gzip.portable=!0),this.zip=new mlt.Gzip(e.gzip),this.zip.on(\"data\",r=>super.write(r)),this.zip.on(\"end\",r=>super.end()),this.zip.on(\"drain\",r=>this[d3]()),this.on(\"resume\",r=>this.zip.resume())):this.on(\"drain\",this[d3]),this.noDirRecurse=!!e.noDirRecurse,this.follow=!!e.follow,this.noMtime=!!e.noMtime,this.mtime=e.mtime||null,this.filter=typeof e.filter==\"function\"?e.filter:r=>!0,this[lA]=new wlt,this[cA]=0,this.jobs=+e.jobs||4,this[hx]=!1,this[px]=!1}[iAe](e){return super.write(e)}add(e){return this.write(e),this}end(e){return e&&this.write(e),this[px]=!0,this[Td](),this}write(e){if(this[px])throw new Error(\"write after end\");return e instanceof ylt?this[tAe](e):this[dx](e),this.flowing}[tAe](e){let r=m3(nAe.resolve(this.cwd,e.path));if(!this.filter(e.path,e))e.resume();else{let o=new Ex(e.path,r,!1);o.entry=new Clt(e,this[g3](o)),o.entry.on(\"end\",a=>this[h3](o)),this[cA]+=1,this[lA].push(o)}this[Td]()}[dx](e){let r=m3(nAe.resolve(this.cwd,e));this[lA].push(new Ex(e,r)),this[Td]()}[y3](e){e.pending=!0,this[cA]+=1;let r=this.follow?\"stat\":\"lstat\";Cx[r](e.absolute,(o,a)=>{e.pending=!1,this[cA]-=1,o?this.emit(\"error\",o):this[gx](e,a)})}[gx](e,r){this.statCache.set(e.absolute,r),e.stat=r,this.filter(e.path,r)||(e.ignore=!0),this[Td]()}[E3](e){e.pending=!0,this[cA]+=1,Cx.readdir(e.absolute,(r,o)=>{if(e.pending=!1,this[cA]-=1,r)return this.emit(\"error\",r);this[mx](e,o)})}[mx](e,r){this.readdirCache.set(e.absolute,r),e.readdir=r,this[Td]()}[Td](){if(!this[hx]){this[hx]=!0;for(let e=this[lA].head;e!==null&&this[cA]<this.jobs;e=e.next)if(this[eAe](e.value),e.value.ignore){let r=e.next;this[lA].removeNode(e),e.next=r}this[hx]=!1,this[px]&&!this[lA].length&&this[cA]===0&&(this.zip?this.zip.end($ue):(super.write($ue),super.end()))}}get[GE](){return this[lA]&&this[lA].head&&this[lA].head.value}[h3](e){this[lA].shift(),this[cA]-=1,this[Td]()}[eAe](e){if(!e.pending){if(e.entry){e===this[GE]&&!e.piped&&this[yx](e);return}if(e.stat||(this.statCache.has(e.absolute)?this[gx](e,this.statCache.get(e.absolute)):this[y3](e)),!!e.stat&&!e.ignore&&!(!this.noDirRecurse&&e.stat.isDirectory()&&!e.readdir&&(this.readdirCache.has(e.absolute)?this[mx](e,this.readdirCache.get(e.absolute)):this[E3](e),!e.readdir))){if(e.entry=this[rAe](e),!e.entry){e.ignore=!0;return}e===this[GE]&&!e.piped&&this[yx](e)}}}[g3](e){return{onwarn:(r,o,a)=>this.warn(r,o,a),noPax:this.noPax,cwd:this.cwd,absolute:e.absolute,preservePaths:this.preservePaths,maxReadSize:this.maxReadSize,strict:this.strict,portable:this.portable,linkCache:this.linkCache,statCache:this.statCache,noMtime:this.noMtime,mtime:this.mtime,prefix:this.prefix}}[rAe](e){this[cA]+=1;try{return new this[C3](e.path,this[g3](e)).on(\"end\",()=>this[h3](e)).on(\"error\",r=>this.emit(\"error\",r))}catch(r){this.emit(\"error\",r)}}[d3](){this[GE]&&this[GE].entry&&this[GE].entry.resume()}[yx](e){e.piped=!0,e.readdir&&e.readdir.forEach(a=>{let n=e.path,u=n===\"./\"?\"\":n.replace(/\\/*$/,\"/\");this[dx](u+a)});let r=e.entry,o=this.zip;o?r.on(\"data\",a=>{o.write(a)||r.pause()}):r.on(\"data\",a=>{super.write(a)||r.pause()})}pause(){return this.zip&&this.zip.pause(),super.pause()}}),w3=class extends B3{constructor(e){super(e),this[C3]=Elt}pause(){}resume(){}[y3](e){let r=this.follow?\"statSync\":\"lstatSync\";this[gx](e,Cx[r](e.absolute))}[E3](e,r){this[mx](e,Cx.readdirSync(e.absolute))}[yx](e){let r=e.entry,o=this.zip;e.readdir&&e.readdir.forEach(a=>{let n=e.path,u=n===\"./\"?\"\":n.replace(/\\/*$/,\"/\");this[dx](u+a)}),o?r.on(\"data\",a=>{o.write(a)}):r.on(\"data\",a=>{super[iAe](a)})}};B3.Sync=w3;sAe.exports=B3});var ZE=_(G1=>{\"use strict\";var Blt=OE(),vlt=Be(\"events\").EventEmitter,Qa=Be(\"fs\"),P3=Qa.writev;if(!P3){let t=process.binding(\"fs\"),e=t.FSReqWrap||t.FSReqCallback;P3=(r,o,a,n)=>{let u=(p,h)=>n(p,h,o),A=new e;A.oncomplete=u,t.writeBuffers(r,o,a,A)}}var JE=Symbol(\"_autoClose\"),Yc=Symbol(\"_close\"),q1=Symbol(\"_ended\"),Gn=Symbol(\"_fd\"),oAe=Symbol(\"_finished\"),Eh=Symbol(\"_flags\"),v3=Symbol(\"_flush\"),S3=Symbol(\"_handleChunk\"),b3=Symbol(\"_makeBuf\"),Px=Symbol(\"_mode\"),Ix=Symbol(\"_needDrain\"),VE=Symbol(\"_onerror\"),XE=Symbol(\"_onopen\"),D3=Symbol(\"_onread\"),WE=Symbol(\"_onwrite\"),Ch=Symbol(\"_open\"),Hf=Symbol(\"_path\"),Nd=Symbol(\"_pos\"),uA=Symbol(\"_queue\"),KE=Symbol(\"_read\"),aAe=Symbol(\"_readSize\"),yh=Symbol(\"_reading\"),Bx=Symbol(\"_remain\"),lAe=Symbol(\"_size\"),vx=Symbol(\"_write\"),YE=Symbol(\"_writing\"),Dx=Symbol(\"_defaultFlag\"),zE=Symbol(\"_errored\"),Sx=class extends Blt{constructor(e,r){if(r=r||{},super(r),this.readable=!0,this.writable=!1,typeof e!=\"string\")throw new TypeError(\"path must be a string\");this[zE]=!1,this[Gn]=typeof r.fd==\"number\"?r.fd:null,this[Hf]=e,this[aAe]=r.readSize||16*1024*1024,this[yh]=!1,this[lAe]=typeof r.size==\"number\"?r.size:1/0,this[Bx]=this[lAe],this[JE]=typeof r.autoClose==\"boolean\"?r.autoClose:!0,typeof this[Gn]==\"number\"?this[KE]():this[Ch]()}get fd(){return this[Gn]}get path(){return this[Hf]}write(){throw new TypeError(\"this is a readable stream\")}end(){throw new TypeError(\"this is a readable stream\")}[Ch](){Qa.open(this[Hf],\"r\",(e,r)=>this[XE](e,r))}[XE](e,r){e?this[VE](e):(this[Gn]=r,this.emit(\"open\",r),this[KE]())}[b3](){return Buffer.allocUnsafe(Math.min(this[aAe],this[Bx]))}[KE](){if(!this[yh]){this[yh]=!0;let e=this[b3]();if(e.length===0)return process.nextTick(()=>this[D3](null,0,e));Qa.read(this[Gn],e,0,e.length,null,(r,o,a)=>this[D3](r,o,a))}}[D3](e,r,o){this[yh]=!1,e?this[VE](e):this[S3](r,o)&&this[KE]()}[Yc](){if(this[JE]&&typeof this[Gn]==\"number\"){let e=this[Gn];this[Gn]=null,Qa.close(e,r=>r?this.emit(\"error\",r):this.emit(\"close\"))}}[VE](e){this[yh]=!0,this[Yc](),this.emit(\"error\",e)}[S3](e,r){let o=!1;return this[Bx]-=e,e>0&&(o=super.write(e<r.length?r.slice(0,e):r)),(e===0||this[Bx]<=0)&&(o=!1,this[Yc](),super.end()),o}emit(e,r){switch(e){case\"prefinish\":case\"finish\":break;case\"drain\":typeof this[Gn]==\"number\"&&this[KE]();break;case\"error\":return this[zE]?void 0:(this[zE]=!0,super.emit(e,r));default:return super.emit(e,r)}}},x3=class extends Sx{[Ch](){let e=!0;try{this[XE](null,Qa.openSync(this[Hf],\"r\")),e=!1}finally{e&&this[Yc]()}}[KE](){let e=!0;try{if(!this[yh]){this[yh]=!0;do{let r=this[b3](),o=r.length===0?0:Qa.readSync(this[Gn],r,0,r.length,null);if(!this[S3](o,r))break}while(!0);this[yh]=!1}e=!1}finally{e&&this[Yc]()}}[Yc](){if(this[JE]&&typeof this[Gn]==\"number\"){let e=this[Gn];this[Gn]=null,Qa.closeSync(e),this.emit(\"close\")}}},bx=class extends vlt{constructor(e,r){r=r||{},super(r),this.readable=!1,this.writable=!0,this[zE]=!1,this[YE]=!1,this[q1]=!1,this[Ix]=!1,this[uA]=[],this[Hf]=e,this[Gn]=typeof r.fd==\"number\"?r.fd:null,this[Px]=r.mode===void 0?438:r.mode,this[Nd]=typeof r.start==\"number\"?r.start:null,this[JE]=typeof r.autoClose==\"boolean\"?r.autoClose:!0;let o=this[Nd]!==null?\"r+\":\"w\";this[Dx]=r.flags===void 0,this[Eh]=this[Dx]?o:r.flags,this[Gn]===null&&this[Ch]()}emit(e,r){if(e===\"error\"){if(this[zE])return;this[zE]=!0}return super.emit(e,r)}get fd(){return this[Gn]}get path(){return this[Hf]}[VE](e){this[Yc](),this[YE]=!0,this.emit(\"error\",e)}[Ch](){Qa.open(this[Hf],this[Eh],this[Px],(e,r)=>this[XE](e,r))}[XE](e,r){this[Dx]&&this[Eh]===\"r+\"&&e&&e.code===\"ENOENT\"?(this[Eh]=\"w\",this[Ch]()):e?this[VE](e):(this[Gn]=r,this.emit(\"open\",r),this[v3]())}end(e,r){return e&&this.write(e,r),this[q1]=!0,!this[YE]&&!this[uA].length&&typeof this[Gn]==\"number\"&&this[WE](null,0),this}write(e,r){return typeof e==\"string\"&&(e=Buffer.from(e,r)),this[q1]?(this.emit(\"error\",new Error(\"write() after end()\")),!1):this[Gn]===null||this[YE]||this[uA].length?(this[uA].push(e),this[Ix]=!0,!1):(this[YE]=!0,this[vx](e),!0)}[vx](e){Qa.write(this[Gn],e,0,e.length,this[Nd],(r,o)=>this[WE](r,o))}[WE](e,r){e?this[VE](e):(this[Nd]!==null&&(this[Nd]+=r),this[uA].length?this[v3]():(this[YE]=!1,this[q1]&&!this[oAe]?(this[oAe]=!0,this[Yc](),this.emit(\"finish\")):this[Ix]&&(this[Ix]=!1,this.emit(\"drain\"))))}[v3](){if(this[uA].length===0)this[q1]&&this[WE](null,0);else if(this[uA].length===1)this[vx](this[uA].pop());else{let e=this[uA];this[uA]=[],P3(this[Gn],e,this[Nd],(r,o)=>this[WE](r,o))}}[Yc](){if(this[JE]&&typeof this[Gn]==\"number\"){let e=this[Gn];this[Gn]=null,Qa.close(e,r=>r?this.emit(\"error\",r):this.emit(\"close\"))}}},k3=class extends bx{[Ch](){let e;if(this[Dx]&&this[Eh]===\"r+\")try{e=Qa.openSync(this[Hf],this[Eh],this[Px])}catch(r){if(r.code===\"ENOENT\")return this[Eh]=\"w\",this[Ch]();throw r}else e=Qa.openSync(this[Hf],this[Eh],this[Px]);this[XE](null,e)}[Yc](){if(this[JE]&&typeof this[Gn]==\"number\"){let e=this[Gn];this[Gn]=null,Qa.closeSync(e),this.emit(\"close\")}}[vx](e){let r=!0;try{this[WE](null,Qa.writeSync(this[Gn],e,0,e.length,this[Nd])),r=!1}finally{if(r)try{this[Yc]()}catch{}}}};G1.ReadStream=Sx;G1.ReadStreamSync=x3;G1.WriteStream=bx;G1.WriteStreamSync=k3});var Nx=_((oUt,gAe)=>{\"use strict\";var Dlt=ax(),Plt=jE(),Slt=Be(\"events\"),blt=BP(),xlt=1024*1024,klt=ix(),cAe=ox(),Qlt=WU(),Q3=Buffer.from([31,139]),Xl=Symbol(\"state\"),Ld=Symbol(\"writeEntry\"),jf=Symbol(\"readEntry\"),F3=Symbol(\"nextEntry\"),uAe=Symbol(\"processEntry\"),Zl=Symbol(\"extendedHeader\"),Y1=Symbol(\"globalExtendedHeader\"),wh=Symbol(\"meta\"),AAe=Symbol(\"emitMeta\"),fi=Symbol(\"buffer\"),qf=Symbol(\"queue\"),Od=Symbol(\"ended\"),fAe=Symbol(\"emittedEnd\"),Md=Symbol(\"emit\"),Fa=Symbol(\"unzip\"),xx=Symbol(\"consumeChunk\"),kx=Symbol(\"consumeChunkSub\"),R3=Symbol(\"consumeBody\"),pAe=Symbol(\"consumeMeta\"),hAe=Symbol(\"consumeHeader\"),Qx=Symbol(\"consuming\"),T3=Symbol(\"bufferConcat\"),N3=Symbol(\"maybeEnd\"),W1=Symbol(\"writing\"),Ih=Symbol(\"aborted\"),Fx=Symbol(\"onDone\"),Ud=Symbol(\"sawValidEntry\"),Rx=Symbol(\"sawNullBlock\"),Tx=Symbol(\"sawEOF\"),Flt=t=>!0;gAe.exports=Dlt(class extends Slt{constructor(e){e=e||{},super(e),this.file=e.file||\"\",this[Ud]=null,this.on(Fx,r=>{(this[Xl]===\"begin\"||this[Ud]===!1)&&this.warn(\"TAR_BAD_ARCHIVE\",\"Unrecognized archive format\")}),e.ondone?this.on(Fx,e.ondone):this.on(Fx,r=>{this.emit(\"prefinish\"),this.emit(\"finish\"),this.emit(\"end\"),this.emit(\"close\")}),this.strict=!!e.strict,this.maxMetaEntrySize=e.maxMetaEntrySize||xlt,this.filter=typeof e.filter==\"function\"?e.filter:Flt,this.writable=!0,this.readable=!1,this[qf]=new blt,this[fi]=null,this[jf]=null,this[Ld]=null,this[Xl]=\"begin\",this[wh]=\"\",this[Zl]=null,this[Y1]=null,this[Od]=!1,this[Fa]=null,this[Ih]=!1,this[Rx]=!1,this[Tx]=!1,typeof e.onwarn==\"function\"&&this.on(\"warn\",e.onwarn),typeof e.onentry==\"function\"&&this.on(\"entry\",e.onentry)}[hAe](e,r){this[Ud]===null&&(this[Ud]=!1);let o;try{o=new Plt(e,r,this[Zl],this[Y1])}catch(a){return this.warn(\"TAR_ENTRY_INVALID\",a)}if(o.nullBlock)this[Rx]?(this[Tx]=!0,this[Xl]===\"begin\"&&(this[Xl]=\"header\"),this[Md](\"eof\")):(this[Rx]=!0,this[Md](\"nullBlock\"));else if(this[Rx]=!1,!o.cksumValid)this.warn(\"TAR_ENTRY_INVALID\",\"checksum failure\",{header:o});else if(!o.path)this.warn(\"TAR_ENTRY_INVALID\",\"path is required\",{header:o});else{let a=o.type;if(/^(Symbolic)?Link$/.test(a)&&!o.linkpath)this.warn(\"TAR_ENTRY_INVALID\",\"linkpath required\",{header:o});else if(!/^(Symbolic)?Link$/.test(a)&&o.linkpath)this.warn(\"TAR_ENTRY_INVALID\",\"linkpath forbidden\",{header:o});else{let n=this[Ld]=new klt(o,this[Zl],this[Y1]);if(!this[Ud])if(n.remain){let u=()=>{n.invalid||(this[Ud]=!0)};n.on(\"end\",u)}else this[Ud]=!0;n.meta?n.size>this.maxMetaEntrySize?(n.ignore=!0,this[Md](\"ignoredEntry\",n),this[Xl]=\"ignore\",n.resume()):n.size>0&&(this[wh]=\"\",n.on(\"data\",u=>this[wh]+=u),this[Xl]=\"meta\"):(this[Zl]=null,n.ignore=n.ignore||!this.filter(n.path,n),n.ignore?(this[Md](\"ignoredEntry\",n),this[Xl]=n.remain?\"ignore\":\"header\",n.resume()):(n.remain?this[Xl]=\"body\":(this[Xl]=\"header\",n.end()),this[jf]?this[qf].push(n):(this[qf].push(n),this[F3]())))}}}[uAe](e){let r=!0;return e?Array.isArray(e)?this.emit.apply(this,e):(this[jf]=e,this.emit(\"entry\",e),e.emittedEnd||(e.on(\"end\",o=>this[F3]()),r=!1)):(this[jf]=null,r=!1),r}[F3](){do;while(this[uAe](this[qf].shift()));if(!this[qf].length){let e=this[jf];!e||e.flowing||e.size===e.remain?this[W1]||this.emit(\"drain\"):e.once(\"drain\",o=>this.emit(\"drain\"))}}[R3](e,r){let o=this[Ld],a=o.blockRemain,n=a>=e.length&&r===0?e:e.slice(r,r+a);return o.write(n),o.blockRemain||(this[Xl]=\"header\",this[Ld]=null,o.end()),n.length}[pAe](e,r){let o=this[Ld],a=this[R3](e,r);return this[Ld]||this[AAe](o),a}[Md](e,r,o){!this[qf].length&&!this[jf]?this.emit(e,r,o):this[qf].push([e,r,o])}[AAe](e){switch(this[Md](\"meta\",this[wh]),e.type){case\"ExtendedHeader\":case\"OldExtendedHeader\":this[Zl]=cAe.parse(this[wh],this[Zl],!1);break;case\"GlobalExtendedHeader\":this[Y1]=cAe.parse(this[wh],this[Y1],!0);break;case\"NextFileHasLongPath\":case\"OldGnuLongPath\":this[Zl]=this[Zl]||Object.create(null),this[Zl].path=this[wh].replace(/\\0.*/,\"\");break;case\"NextFileHasLongLinkpath\":this[Zl]=this[Zl]||Object.create(null),this[Zl].linkpath=this[wh].replace(/\\0.*/,\"\");break;default:throw new Error(\"unknown meta: \"+e.type)}}abort(e){this[Ih]=!0,this.emit(\"abort\",e),this.warn(\"TAR_ABORT\",e,{recoverable:!1})}write(e){if(this[Ih])return;if(this[Fa]===null&&e){if(this[fi]&&(e=Buffer.concat([this[fi],e]),this[fi]=null),e.length<Q3.length)return this[fi]=e,!0;for(let o=0;this[Fa]===null&&o<Q3.length;o++)e[o]!==Q3[o]&&(this[Fa]=!1);if(this[Fa]===null){let o=this[Od];this[Od]=!1,this[Fa]=new Qlt.Unzip,this[Fa].on(\"data\",n=>this[xx](n)),this[Fa].on(\"error\",n=>this.abort(n)),this[Fa].on(\"end\",n=>{this[Od]=!0,this[xx]()}),this[W1]=!0;let a=this[Fa][o?\"end\":\"write\"](e);return this[W1]=!1,a}}this[W1]=!0,this[Fa]?this[Fa].write(e):this[xx](e),this[W1]=!1;let r=this[qf].length?!1:this[jf]?this[jf].flowing:!0;return!r&&!this[qf].length&&this[jf].once(\"drain\",o=>this.emit(\"drain\")),r}[T3](e){e&&!this[Ih]&&(this[fi]=this[fi]?Buffer.concat([this[fi],e]):e)}[N3](){if(this[Od]&&!this[fAe]&&!this[Ih]&&!this[Qx]){this[fAe]=!0;let e=this[Ld];if(e&&e.blockRemain){let r=this[fi]?this[fi].length:0;this.warn(\"TAR_BAD_ARCHIVE\",`Truncated input (needed ${e.blockRemain} more bytes, only ${r} available)`,{entry:e}),this[fi]&&e.write(this[fi]),e.end()}this[Md](Fx)}}[xx](e){if(this[Qx])this[T3](e);else if(!e&&!this[fi])this[N3]();else{if(this[Qx]=!0,this[fi]){this[T3](e);let r=this[fi];this[fi]=null,this[kx](r)}else this[kx](e);for(;this[fi]&&this[fi].length>=512&&!this[Ih]&&!this[Tx];){let r=this[fi];this[fi]=null,this[kx](r)}this[Qx]=!1}(!this[fi]||this[Od])&&this[N3]()}[kx](e){let r=0,o=e.length;for(;r+512<=o&&!this[Ih]&&!this[Tx];)switch(this[Xl]){case\"begin\":case\"header\":this[hAe](e,r),r+=512;break;case\"ignore\":case\"body\":r+=this[R3](e,r);break;case\"meta\":r+=this[pAe](e,r);break;default:throw new Error(\"invalid state: \"+this[Xl])}r<o&&(this[fi]?this[fi]=Buffer.concat([e.slice(r),this[fi]]):this[fi]=e.slice(r))}end(e){this[Ih]||(this[Fa]?this[Fa].end(e):(this[Od]=!0,this.write(e)))}})});var Lx=_((aUt,EAe)=>{\"use strict\";var Rlt=NE(),mAe=Nx(),$E=Be(\"fs\"),Tlt=ZE(),dAe=Be(\"path\"),L3=qE();EAe.exports=(t,e,r)=>{typeof t==\"function\"?(r=t,e=null,t={}):Array.isArray(t)&&(e=t,t={}),typeof e==\"function\"&&(r=e,e=null),e?e=Array.from(e):e=[];let o=Rlt(t);if(o.sync&&typeof r==\"function\")throw new TypeError(\"callback not supported for sync tar functions\");if(!o.file&&typeof r==\"function\")throw new TypeError(\"callback only supported with file option\");return e.length&&Llt(o,e),o.noResume||Nlt(o),o.file&&o.sync?Olt(o):o.file?Mlt(o,r):yAe(o)};var Nlt=t=>{let e=t.onentry;t.onentry=e?r=>{e(r),r.resume()}:r=>r.resume()},Llt=(t,e)=>{let r=new Map(e.map(n=>[L3(n),!0])),o=t.filter,a=(n,u)=>{let A=u||dAe.parse(n).root||\".\",p=n===A?!1:r.has(n)?r.get(n):a(dAe.dirname(n),A);return r.set(n,p),p};t.filter=o?(n,u)=>o(n,u)&&a(L3(n)):n=>a(L3(n))},Olt=t=>{let e=yAe(t),r=t.file,o=!0,a;try{let n=$E.statSync(r),u=t.maxReadSize||16*1024*1024;if(n.size<u)e.end($E.readFileSync(r));else{let A=0,p=Buffer.allocUnsafe(u);for(a=$E.openSync(r,\"r\");A<n.size;){let h=$E.readSync(a,p,0,u,A);A+=h,e.write(p.slice(0,h))}e.end()}o=!1}finally{if(o&&a)try{$E.closeSync(a)}catch{}}},Mlt=(t,e)=>{let r=new mAe(t),o=t.maxReadSize||16*1024*1024,a=t.file,n=new Promise((u,A)=>{r.on(\"error\",A),r.on(\"end\",u),$E.stat(a,(p,h)=>{if(p)A(p);else{let C=new Tlt.ReadStream(a,{readSize:o,size:h.size});C.on(\"error\",A),C.pipe(r)}})});return e?n.then(e,e):n},yAe=t=>new mAe(t)});var DAe=_((lUt,vAe)=>{\"use strict\";var Ult=NE(),Ox=wx(),CAe=ZE(),wAe=Lx(),IAe=Be(\"path\");vAe.exports=(t,e,r)=>{if(typeof e==\"function\"&&(r=e),Array.isArray(t)&&(e=t,t={}),!e||!Array.isArray(e)||!e.length)throw new TypeError(\"no files or directories specified\");e=Array.from(e);let o=Ult(t);if(o.sync&&typeof r==\"function\")throw new TypeError(\"callback not supported for sync tar functions\");if(!o.file&&typeof r==\"function\")throw new TypeError(\"callback only supported with file option\");return o.file&&o.sync?_lt(o,e):o.file?Hlt(o,e,r):o.sync?jlt(o,e):qlt(o,e)};var _lt=(t,e)=>{let r=new Ox.Sync(t),o=new CAe.WriteStreamSync(t.file,{mode:t.mode||438});r.pipe(o),BAe(r,e)},Hlt=(t,e,r)=>{let o=new Ox(t),a=new CAe.WriteStream(t.file,{mode:t.mode||438});o.pipe(a);let n=new Promise((u,A)=>{a.on(\"error\",A),a.on(\"close\",u),o.on(\"error\",A)});return O3(o,e),r?n.then(r,r):n},BAe=(t,e)=>{e.forEach(r=>{r.charAt(0)===\"@\"?wAe({file:IAe.resolve(t.cwd,r.substr(1)),sync:!0,noResume:!0,onentry:o=>t.add(o)}):t.add(r)}),t.end()},O3=(t,e)=>{for(;e.length;){let r=e.shift();if(r.charAt(0)===\"@\")return wAe({file:IAe.resolve(t.cwd,r.substr(1)),noResume:!0,onentry:o=>t.add(o)}).then(o=>O3(t,e));t.add(r)}t.end()},jlt=(t,e)=>{let r=new Ox.Sync(t);return BAe(r,e),r},qlt=(t,e)=>{let r=new Ox(t);return O3(r,e),r}});var M3=_((cUt,FAe)=>{\"use strict\";var Glt=NE(),PAe=wx(),Al=Be(\"fs\"),SAe=ZE(),bAe=Lx(),xAe=Be(\"path\"),kAe=jE();FAe.exports=(t,e,r)=>{let o=Glt(t);if(!o.file)throw new TypeError(\"file is required\");if(o.gzip)throw new TypeError(\"cannot append to compressed archives\");if(!e||!Array.isArray(e)||!e.length)throw new TypeError(\"no files or directories specified\");return e=Array.from(e),o.sync?Ylt(o,e):Klt(o,e,r)};var Ylt=(t,e)=>{let r=new PAe.Sync(t),o=!0,a,n;try{try{a=Al.openSync(t.file,\"r+\")}catch(p){if(p.code===\"ENOENT\")a=Al.openSync(t.file,\"w+\");else throw p}let u=Al.fstatSync(a),A=Buffer.alloc(512);e:for(n=0;n<u.size;n+=512){for(let C=0,I=0;C<512;C+=I){if(I=Al.readSync(a,A,C,A.length-C,n+C),n===0&&A[0]===31&&A[1]===139)throw new Error(\"cannot append to compressed archives\");if(!I)break e}let p=new kAe(A);if(!p.cksumValid)break;let h=512*Math.ceil(p.size/512);if(n+h+512>u.size)break;n+=h,t.mtimeCache&&t.mtimeCache.set(p.path,p.mtime)}o=!1,Wlt(t,r,n,a,e)}finally{if(o)try{Al.closeSync(a)}catch{}}},Wlt=(t,e,r,o,a)=>{let n=new SAe.WriteStreamSync(t.file,{fd:o,start:r});e.pipe(n),Vlt(e,a)},Klt=(t,e,r)=>{e=Array.from(e);let o=new PAe(t),a=(u,A,p)=>{let h=(E,R)=>{E?Al.close(u,L=>p(E)):p(null,R)},C=0;if(A===0)return h(null,0);let I=0,v=Buffer.alloc(512),x=(E,R)=>{if(E)return h(E);if(I+=R,I<512&&R)return Al.read(u,v,I,v.length-I,C+I,x);if(C===0&&v[0]===31&&v[1]===139)return h(new Error(\"cannot append to compressed archives\"));if(I<512)return h(null,C);let L=new kAe(v);if(!L.cksumValid)return h(null,C);let U=512*Math.ceil(L.size/512);if(C+U+512>A||(C+=U+512,C>=A))return h(null,C);t.mtimeCache&&t.mtimeCache.set(L.path,L.mtime),I=0,Al.read(u,v,0,512,C,x)};Al.read(u,v,0,512,C,x)},n=new Promise((u,A)=>{o.on(\"error\",A);let p=\"r+\",h=(C,I)=>{if(C&&C.code===\"ENOENT\"&&p===\"r+\")return p=\"w+\",Al.open(t.file,p,h);if(C)return A(C);Al.fstat(I,(v,x)=>{if(v)return Al.close(I,()=>A(v));a(I,x.size,(E,R)=>{if(E)return A(E);let L=new SAe.WriteStream(t.file,{fd:I,start:R});o.pipe(L),L.on(\"error\",A),L.on(\"close\",u),QAe(o,e)})})};Al.open(t.file,p,h)});return r?n.then(r,r):n},Vlt=(t,e)=>{e.forEach(r=>{r.charAt(0)===\"@\"?bAe({file:xAe.resolve(t.cwd,r.substr(1)),sync:!0,noResume:!0,onentry:o=>t.add(o)}):t.add(r)}),t.end()},QAe=(t,e)=>{for(;e.length;){let r=e.shift();if(r.charAt(0)===\"@\")return bAe({file:xAe.resolve(t.cwd,r.substr(1)),noResume:!0,onentry:o=>t.add(o)}).then(o=>QAe(t,e));t.add(r)}t.end()}});var TAe=_((uUt,RAe)=>{\"use strict\";var zlt=NE(),Jlt=M3();RAe.exports=(t,e,r)=>{let o=zlt(t);if(!o.file)throw new TypeError(\"file is required\");if(o.gzip)throw new TypeError(\"cannot append to compressed archives\");if(!e||!Array.isArray(e)||!e.length)throw new TypeError(\"no files or directories specified\");return e=Array.from(e),Xlt(o),Jlt(o,e,r)};var Xlt=t=>{let e=t.filter;t.mtimeCache||(t.mtimeCache=new Map),t.filter=e?(r,o)=>e(r,o)&&!(t.mtimeCache.get(r)>o.mtime):(r,o)=>!(t.mtimeCache.get(r)>o.mtime)}});var OAe=_((AUt,LAe)=>{var{promisify:NAe}=Be(\"util\"),Bh=Be(\"fs\"),Zlt=t=>{if(!t)t={mode:511,fs:Bh};else if(typeof t==\"object\")t={mode:511,fs:Bh,...t};else if(typeof t==\"number\")t={mode:t,fs:Bh};else if(typeof t==\"string\")t={mode:parseInt(t,8),fs:Bh};else throw new TypeError(\"invalid options argument\");return t.mkdir=t.mkdir||t.fs.mkdir||Bh.mkdir,t.mkdirAsync=NAe(t.mkdir),t.stat=t.stat||t.fs.stat||Bh.stat,t.statAsync=NAe(t.stat),t.statSync=t.statSync||t.fs.statSync||Bh.statSync,t.mkdirSync=t.mkdirSync||t.fs.mkdirSync||Bh.mkdirSync,t};LAe.exports=Zlt});var UAe=_((fUt,MAe)=>{var $lt=process.platform,{resolve:ect,parse:tct}=Be(\"path\"),rct=t=>{if(/\\0/.test(t))throw Object.assign(new TypeError(\"path must be a string without null bytes\"),{path:t,code:\"ERR_INVALID_ARG_VALUE\"});if(t=ect(t),$lt===\"win32\"){let e=/[*|\"<>?:]/,{root:r}=tct(t);if(e.test(t.substr(r.length)))throw Object.assign(new Error(\"Illegal characters in path.\"),{path:t,code:\"EINVAL\"})}return t};MAe.exports=rct});var GAe=_((pUt,qAe)=>{var{dirname:_Ae}=Be(\"path\"),HAe=(t,e,r=void 0)=>r===e?Promise.resolve():t.statAsync(e).then(o=>o.isDirectory()?r:void 0,o=>o.code===\"ENOENT\"?HAe(t,_Ae(e),e):void 0),jAe=(t,e,r=void 0)=>{if(r!==e)try{return t.statSync(e).isDirectory()?r:void 0}catch(o){return o.code===\"ENOENT\"?jAe(t,_Ae(e),e):void 0}};qAe.exports={findMade:HAe,findMadeSync:jAe}});var H3=_((hUt,WAe)=>{var{dirname:YAe}=Be(\"path\"),U3=(t,e,r)=>{e.recursive=!1;let o=YAe(t);return o===t?e.mkdirAsync(t,e).catch(a=>{if(a.code!==\"EISDIR\")throw a}):e.mkdirAsync(t,e).then(()=>r||t,a=>{if(a.code===\"ENOENT\")return U3(o,e).then(n=>U3(t,e,n));if(a.code!==\"EEXIST\"&&a.code!==\"EROFS\")throw a;return e.statAsync(t).then(n=>{if(n.isDirectory())return r;throw a},()=>{throw a})})},_3=(t,e,r)=>{let o=YAe(t);if(e.recursive=!1,o===t)try{return e.mkdirSync(t,e)}catch(a){if(a.code!==\"EISDIR\")throw a;return}try{return e.mkdirSync(t,e),r||t}catch(a){if(a.code===\"ENOENT\")return _3(t,e,_3(o,e,r));if(a.code!==\"EEXIST\"&&a.code!==\"EROFS\")throw a;try{if(!e.statSync(t).isDirectory())throw a}catch{throw a}}};WAe.exports={mkdirpManual:U3,mkdirpManualSync:_3}});var zAe=_((gUt,VAe)=>{var{dirname:KAe}=Be(\"path\"),{findMade:nct,findMadeSync:ict}=GAe(),{mkdirpManual:sct,mkdirpManualSync:oct}=H3(),act=(t,e)=>(e.recursive=!0,KAe(t)===t?e.mkdirAsync(t,e):nct(e,t).then(o=>e.mkdirAsync(t,e).then(()=>o).catch(a=>{if(a.code===\"ENOENT\")return sct(t,e);throw a}))),lct=(t,e)=>{if(e.recursive=!0,KAe(t)===t)return e.mkdirSync(t,e);let o=ict(e,t);try{return e.mkdirSync(t,e),o}catch(a){if(a.code===\"ENOENT\")return oct(t,e);throw a}};VAe.exports={mkdirpNative:act,mkdirpNativeSync:lct}});var $Ae=_((dUt,ZAe)=>{var JAe=Be(\"fs\"),cct=process.version,j3=cct.replace(/^v/,\"\").split(\".\"),XAe=+j3[0]>10||+j3[0]==10&&+j3[1]>=12,uct=XAe?t=>t.mkdir===JAe.mkdir:()=>!1,Act=XAe?t=>t.mkdirSync===JAe.mkdirSync:()=>!1;ZAe.exports={useNative:uct,useNativeSync:Act}});var sfe=_((mUt,ife)=>{var eC=OAe(),tC=UAe(),{mkdirpNative:efe,mkdirpNativeSync:tfe}=zAe(),{mkdirpManual:rfe,mkdirpManualSync:nfe}=H3(),{useNative:fct,useNativeSync:pct}=$Ae(),rC=(t,e)=>(t=tC(t),e=eC(e),fct(e)?efe(t,e):rfe(t,e)),hct=(t,e)=>(t=tC(t),e=eC(e),pct(e)?tfe(t,e):nfe(t,e));rC.sync=hct;rC.native=(t,e)=>efe(tC(t),eC(e));rC.manual=(t,e)=>rfe(tC(t),eC(e));rC.nativeSync=(t,e)=>tfe(tC(t),eC(e));rC.manualSync=(t,e)=>nfe(tC(t),eC(e));ife.exports=rC});var ffe=_((yUt,Afe)=>{\"use strict\";var $l=Be(\"fs\"),_d=Be(\"path\"),gct=$l.lchown?\"lchown\":\"chown\",dct=$l.lchownSync?\"lchownSync\":\"chownSync\",afe=$l.lchown&&!process.version.match(/v1[1-9]+\\./)&&!process.version.match(/v10\\.[6-9]/),ofe=(t,e,r)=>{try{return $l[dct](t,e,r)}catch(o){if(o.code!==\"ENOENT\")throw o}},mct=(t,e,r)=>{try{return $l.chownSync(t,e,r)}catch(o){if(o.code!==\"ENOENT\")throw o}},yct=afe?(t,e,r,o)=>a=>{!a||a.code!==\"EISDIR\"?o(a):$l.chown(t,e,r,o)}:(t,e,r,o)=>o,q3=afe?(t,e,r)=>{try{return ofe(t,e,r)}catch(o){if(o.code!==\"EISDIR\")throw o;mct(t,e,r)}}:(t,e,r)=>ofe(t,e,r),Ect=process.version,lfe=(t,e,r)=>$l.readdir(t,e,r),Cct=(t,e)=>$l.readdirSync(t,e);/^v4\\./.test(Ect)&&(lfe=(t,e,r)=>$l.readdir(t,r));var Mx=(t,e,r,o)=>{$l[gct](t,e,r,yct(t,e,r,a=>{o(a&&a.code!==\"ENOENT\"?a:null)}))},cfe=(t,e,r,o,a)=>{if(typeof e==\"string\")return $l.lstat(_d.resolve(t,e),(n,u)=>{if(n)return a(n.code!==\"ENOENT\"?n:null);u.name=e,cfe(t,u,r,o,a)});if(e.isDirectory())G3(_d.resolve(t,e.name),r,o,n=>{if(n)return a(n);let u=_d.resolve(t,e.name);Mx(u,r,o,a)});else{let n=_d.resolve(t,e.name);Mx(n,r,o,a)}},G3=(t,e,r,o)=>{lfe(t,{withFileTypes:!0},(a,n)=>{if(a){if(a.code===\"ENOENT\")return o();if(a.code!==\"ENOTDIR\"&&a.code!==\"ENOTSUP\")return o(a)}if(a||!n.length)return Mx(t,e,r,o);let u=n.length,A=null,p=h=>{if(!A){if(h)return o(A=h);if(--u===0)return Mx(t,e,r,o)}};n.forEach(h=>cfe(t,h,e,r,p))})},wct=(t,e,r,o)=>{if(typeof e==\"string\")try{let a=$l.lstatSync(_d.resolve(t,e));a.name=e,e=a}catch(a){if(a.code===\"ENOENT\")return;throw a}e.isDirectory()&&ufe(_d.resolve(t,e.name),r,o),q3(_d.resolve(t,e.name),r,o)},ufe=(t,e,r)=>{let o;try{o=Cct(t,{withFileTypes:!0})}catch(a){if(a.code===\"ENOENT\")return;if(a.code===\"ENOTDIR\"||a.code===\"ENOTSUP\")return q3(t,e,r);throw a}return o&&o.length&&o.forEach(a=>wct(t,a,e,r)),q3(t,e,r)};Afe.exports=G3;G3.sync=ufe});var dfe=_((EUt,Y3)=>{\"use strict\";var pfe=sfe(),ec=Be(\"fs\"),Ux=Be(\"path\"),hfe=ffe(),Wc=_E(),_x=class extends Error{constructor(e,r){super(\"Cannot extract through symbolic link\"),this.path=r,this.symlink=e}get name(){return\"SylinkError\"}},Hx=class extends Error{constructor(e,r){super(r+\": Cannot cd into '\"+e+\"'\"),this.path=e,this.code=r}get name(){return\"CwdError\"}},jx=(t,e)=>t.get(Wc(e)),K1=(t,e,r)=>t.set(Wc(e),r),Ict=(t,e)=>{ec.stat(t,(r,o)=>{(r||!o.isDirectory())&&(r=new Hx(t,r&&r.code||\"ENOTDIR\")),e(r)})};Y3.exports=(t,e,r)=>{t=Wc(t);let o=e.umask,a=e.mode|448,n=(a&o)!==0,u=e.uid,A=e.gid,p=typeof u==\"number\"&&typeof A==\"number\"&&(u!==e.processUid||A!==e.processGid),h=e.preserve,C=e.unlink,I=e.cache,v=Wc(e.cwd),x=(L,U)=>{L?r(L):(K1(I,t,!0),U&&p?hfe(U,u,A,z=>x(z)):n?ec.chmod(t,a,r):r())};if(I&&jx(I,t)===!0)return x();if(t===v)return Ict(t,x);if(h)return pfe(t,{mode:a}).then(L=>x(null,L),x);let R=Wc(Ux.relative(v,t)).split(\"/\");qx(v,R,a,I,C,v,null,x)};var qx=(t,e,r,o,a,n,u,A)=>{if(!e.length)return A(null,u);let p=e.shift(),h=Wc(Ux.resolve(t+\"/\"+p));if(jx(o,h))return qx(h,e,r,o,a,n,u,A);ec.mkdir(h,r,gfe(h,e,r,o,a,n,u,A))},gfe=(t,e,r,o,a,n,u,A)=>p=>{p?ec.lstat(t,(h,C)=>{if(h)h.path=h.path&&Wc(h.path),A(h);else if(C.isDirectory())qx(t,e,r,o,a,n,u,A);else if(a)ec.unlink(t,I=>{if(I)return A(I);ec.mkdir(t,r,gfe(t,e,r,o,a,n,u,A))});else{if(C.isSymbolicLink())return A(new _x(t,t+\"/\"+e.join(\"/\")));A(p)}}):(u=u||t,qx(t,e,r,o,a,n,u,A))},Bct=t=>{let e=!1,r=\"ENOTDIR\";try{e=ec.statSync(t).isDirectory()}catch(o){r=o.code}finally{if(!e)throw new Hx(t,r)}};Y3.exports.sync=(t,e)=>{t=Wc(t);let r=e.umask,o=e.mode|448,a=(o&r)!==0,n=e.uid,u=e.gid,A=typeof n==\"number\"&&typeof u==\"number\"&&(n!==e.processUid||u!==e.processGid),p=e.preserve,h=e.unlink,C=e.cache,I=Wc(e.cwd),v=L=>{K1(C,t,!0),L&&A&&hfe.sync(L,n,u),a&&ec.chmodSync(t,o)};if(C&&jx(C,t)===!0)return v();if(t===I)return Bct(I),v();if(p)return v(pfe.sync(t,o));let E=Wc(Ux.relative(I,t)).split(\"/\"),R=null;for(let L=E.shift(),U=I;L&&(U+=\"/\"+L);L=E.shift())if(U=Wc(Ux.resolve(U)),!jx(C,U))try{ec.mkdirSync(U,o),R=R||U,K1(C,U,!0)}catch{let te=ec.lstatSync(U);if(te.isDirectory()){K1(C,U,!0);continue}else if(h){ec.unlinkSync(U),ec.mkdirSync(U,o),R=R||U,K1(C,U,!0);continue}else if(te.isSymbolicLink())return new _x(U,U+\"/\"+E.join(\"/\"))}return v(R)}});var K3=_((CUt,mfe)=>{var W3=Object.create(null),{hasOwnProperty:vct}=Object.prototype;mfe.exports=t=>(vct.call(W3,t)||(W3[t]=t.normalize(\"NFKD\")),W3[t])});var wfe=_((wUt,Cfe)=>{var yfe=Be(\"assert\"),Dct=K3(),Pct=qE(),{join:Efe}=Be(\"path\"),Sct=process.env.TESTING_TAR_FAKE_PLATFORM||process.platform,bct=Sct===\"win32\";Cfe.exports=()=>{let t=new Map,e=new Map,r=h=>h.split(\"/\").slice(0,-1).reduce((I,v)=>(I.length&&(v=Efe(I[I.length-1],v)),I.push(v||\"/\"),I),[]),o=new Set,a=h=>{let C=e.get(h);if(!C)throw new Error(\"function does not have any path reservations\");return{paths:C.paths.map(I=>t.get(I)),dirs:[...C.dirs].map(I=>t.get(I))}},n=h=>{let{paths:C,dirs:I}=a(h);return C.every(v=>v[0]===h)&&I.every(v=>v[0]instanceof Set&&v[0].has(h))},u=h=>o.has(h)||!n(h)?!1:(o.add(h),h(()=>A(h)),!0),A=h=>{if(!o.has(h))return!1;let{paths:C,dirs:I}=e.get(h),v=new Set;return C.forEach(x=>{let E=t.get(x);yfe.equal(E[0],h),E.length===1?t.delete(x):(E.shift(),typeof E[0]==\"function\"?v.add(E[0]):E[0].forEach(R=>v.add(R)))}),I.forEach(x=>{let E=t.get(x);yfe(E[0]instanceof Set),E[0].size===1&&E.length===1?t.delete(x):E[0].size===1?(E.shift(),v.add(E[0])):E[0].delete(h)}),o.delete(h),v.forEach(x=>u(x)),!0};return{check:n,reserve:(h,C)=>{h=bct?[\"win32 parallelization disabled\"]:h.map(v=>Dct(Pct(Efe(v))).toLowerCase());let I=new Set(h.map(v=>r(v)).reduce((v,x)=>v.concat(x)));return e.set(C,{dirs:I,paths:h}),h.forEach(v=>{let x=t.get(v);x?x.push(C):t.set(v,[C])}),I.forEach(v=>{let x=t.get(v);x?x[x.length-1]instanceof Set?x[x.length-1].add(C):x.push(new Set([C])):t.set(v,[new Set([C])])}),u(C)}}}});var vfe=_((IUt,Bfe)=>{var xct=process.platform,kct=xct===\"win32\",Qct=global.__FAKE_TESTING_FS__||Be(\"fs\"),{O_CREAT:Fct,O_TRUNC:Rct,O_WRONLY:Tct,UV_FS_O_FILEMAP:Ife=0}=Qct.constants,Nct=kct&&!!Ife,Lct=512*1024,Oct=Ife|Rct|Fct|Tct;Bfe.exports=Nct?t=>t<Lct?Oct:\"w\":()=>\"w\"});var r_=_((BUt,Mfe)=>{\"use strict\";var Mct=Be(\"assert\"),Uct=Nx(),vn=Be(\"fs\"),_ct=ZE(),Gf=Be(\"path\"),Nfe=dfe(),Dfe=r3(),Hct=wfe(),jct=n3(),fl=_E(),qct=qE(),Gct=K3(),Pfe=Symbol(\"onEntry\"),J3=Symbol(\"checkFs\"),Sfe=Symbol(\"checkFs2\"),Wx=Symbol(\"pruneCache\"),X3=Symbol(\"isReusable\"),tc=Symbol(\"makeFs\"),Z3=Symbol(\"file\"),$3=Symbol(\"directory\"),Kx=Symbol(\"link\"),bfe=Symbol(\"symlink\"),xfe=Symbol(\"hardlink\"),kfe=Symbol(\"unsupported\"),Qfe=Symbol(\"checkPath\"),vh=Symbol(\"mkdir\"),To=Symbol(\"onError\"),Gx=Symbol(\"pending\"),Ffe=Symbol(\"pend\"),nC=Symbol(\"unpend\"),V3=Symbol(\"ended\"),z3=Symbol(\"maybeClose\"),e_=Symbol(\"skip\"),V1=Symbol(\"doChown\"),z1=Symbol(\"uid\"),J1=Symbol(\"gid\"),X1=Symbol(\"checkedCwd\"),Lfe=Be(\"crypto\"),Ofe=vfe(),Yct=process.env.TESTING_TAR_FAKE_PLATFORM||process.platform,Z1=Yct===\"win32\",Wct=(t,e)=>{if(!Z1)return vn.unlink(t,e);let r=t+\".DELETE.\"+Lfe.randomBytes(16).toString(\"hex\");vn.rename(t,r,o=>{if(o)return e(o);vn.unlink(r,e)})},Kct=t=>{if(!Z1)return vn.unlinkSync(t);let e=t+\".DELETE.\"+Lfe.randomBytes(16).toString(\"hex\");vn.renameSync(t,e),vn.unlinkSync(e)},Rfe=(t,e,r)=>t===t>>>0?t:e===e>>>0?e:r,Tfe=t=>Gct(qct(fl(t))).toLowerCase(),Vct=(t,e)=>{e=Tfe(e);for(let r of t.keys()){let o=Tfe(r);(o===e||o.indexOf(e+\"/\")===0)&&t.delete(r)}},zct=t=>{for(let e of t.keys())t.delete(e)},$1=class extends Uct{constructor(e){if(e||(e={}),e.ondone=r=>{this[V3]=!0,this[z3]()},super(e),this[X1]=!1,this.reservations=Hct(),this.transform=typeof e.transform==\"function\"?e.transform:null,this.writable=!0,this.readable=!1,this[Gx]=0,this[V3]=!1,this.dirCache=e.dirCache||new Map,typeof e.uid==\"number\"||typeof e.gid==\"number\"){if(typeof e.uid!=\"number\"||typeof e.gid!=\"number\")throw new TypeError(\"cannot set owner without number uid and gid\");if(e.preserveOwner)throw new TypeError(\"cannot preserve owner in archive and also set owner explicitly\");this.uid=e.uid,this.gid=e.gid,this.setOwner=!0}else this.uid=null,this.gid=null,this.setOwner=!1;e.preserveOwner===void 0&&typeof e.uid!=\"number\"?this.preserveOwner=process.getuid&&process.getuid()===0:this.preserveOwner=!!e.preserveOwner,this.processUid=(this.preserveOwner||this.setOwner)&&process.getuid?process.getuid():null,this.processGid=(this.preserveOwner||this.setOwner)&&process.getgid?process.getgid():null,this.forceChown=e.forceChown===!0,this.win32=!!e.win32||Z1,this.newer=!!e.newer,this.keep=!!e.keep,this.noMtime=!!e.noMtime,this.preservePaths=!!e.preservePaths,this.unlink=!!e.unlink,this.cwd=fl(Gf.resolve(e.cwd||process.cwd())),this.strip=+e.strip||0,this.processUmask=e.noChmod?0:process.umask(),this.umask=typeof e.umask==\"number\"?e.umask:this.processUmask,this.dmode=e.dmode||511&~this.umask,this.fmode=e.fmode||438&~this.umask,this.on(\"entry\",r=>this[Pfe](r))}warn(e,r,o={}){return(e===\"TAR_BAD_ARCHIVE\"||e===\"TAR_ABORT\")&&(o.recoverable=!1),super.warn(e,r,o)}[z3](){this[V3]&&this[Gx]===0&&(this.emit(\"prefinish\"),this.emit(\"finish\"),this.emit(\"end\"),this.emit(\"close\"))}[Qfe](e){if(this.strip){let r=fl(e.path).split(\"/\");if(r.length<this.strip)return!1;if(e.path=r.slice(this.strip).join(\"/\"),e.type===\"Link\"){let o=fl(e.linkpath).split(\"/\");if(o.length>=this.strip)e.linkpath=o.slice(this.strip).join(\"/\");else return!1}}if(!this.preservePaths){let r=fl(e.path),o=r.split(\"/\");if(o.includes(\"..\")||Z1&&/^[a-z]:\\.\\.$/i.test(o[0]))return this.warn(\"TAR_ENTRY_ERROR\",\"path contains '..'\",{entry:e,path:r}),!1;let[a,n]=jct(r);a&&(e.path=n,this.warn(\"TAR_ENTRY_INFO\",`stripping ${a} from absolute path`,{entry:e,path:r}))}if(Gf.isAbsolute(e.path)?e.absolute=fl(Gf.resolve(e.path)):e.absolute=fl(Gf.resolve(this.cwd,e.path)),!this.preservePaths&&e.absolute.indexOf(this.cwd+\"/\")!==0&&e.absolute!==this.cwd)return this.warn(\"TAR_ENTRY_ERROR\",\"path escaped extraction target\",{entry:e,path:fl(e.path),resolvedPath:e.absolute,cwd:this.cwd}),!1;if(e.absolute===this.cwd&&e.type!==\"Directory\"&&e.type!==\"GNUDumpDir\")return!1;if(this.win32){let{root:r}=Gf.win32.parse(e.absolute);e.absolute=r+Dfe.encode(e.absolute.substr(r.length));let{root:o}=Gf.win32.parse(e.path);e.path=o+Dfe.encode(e.path.substr(o.length))}return!0}[Pfe](e){if(!this[Qfe](e))return e.resume();switch(Mct.equal(typeof e.absolute,\"string\"),e.type){case\"Directory\":case\"GNUDumpDir\":e.mode&&(e.mode=e.mode|448);case\"File\":case\"OldFile\":case\"ContiguousFile\":case\"Link\":case\"SymbolicLink\":return this[J3](e);case\"CharacterDevice\":case\"BlockDevice\":case\"FIFO\":default:return this[kfe](e)}}[To](e,r){e.name===\"CwdError\"?this.emit(\"error\",e):(this.warn(\"TAR_ENTRY_ERROR\",e,{entry:r}),this[nC](),r.resume())}[vh](e,r,o){Nfe(fl(e),{uid:this.uid,gid:this.gid,processUid:this.processUid,processGid:this.processGid,umask:this.processUmask,preserve:this.preservePaths,unlink:this.unlink,cache:this.dirCache,cwd:this.cwd,mode:r,noChmod:this.noChmod},o)}[V1](e){return this.forceChown||this.preserveOwner&&(typeof e.uid==\"number\"&&e.uid!==this.processUid||typeof e.gid==\"number\"&&e.gid!==this.processGid)||typeof this.uid==\"number\"&&this.uid!==this.processUid||typeof this.gid==\"number\"&&this.gid!==this.processGid}[z1](e){return Rfe(this.uid,e.uid,this.processUid)}[J1](e){return Rfe(this.gid,e.gid,this.processGid)}[Z3](e,r){let o=e.mode&4095||this.fmode,a=new _ct.WriteStream(e.absolute,{flags:Ofe(e.size),mode:o,autoClose:!1});a.on(\"error\",p=>{a.fd&&vn.close(a.fd,()=>{}),a.write=()=>!0,this[To](p,e),r()});let n=1,u=p=>{if(p){a.fd&&vn.close(a.fd,()=>{}),this[To](p,e),r();return}--n===0&&vn.close(a.fd,h=>{h?this[To](h,e):this[nC](),r()})};a.on(\"finish\",p=>{let h=e.absolute,C=a.fd;if(e.mtime&&!this.noMtime){n++;let I=e.atime||new Date,v=e.mtime;vn.futimes(C,I,v,x=>x?vn.utimes(h,I,v,E=>u(E&&x)):u())}if(this[V1](e)){n++;let I=this[z1](e),v=this[J1](e);vn.fchown(C,I,v,x=>x?vn.chown(h,I,v,E=>u(E&&x)):u())}u()});let A=this.transform&&this.transform(e)||e;A!==e&&(A.on(\"error\",p=>{this[To](p,e),r()}),e.pipe(A)),A.pipe(a)}[$3](e,r){let o=e.mode&4095||this.dmode;this[vh](e.absolute,o,a=>{if(a){this[To](a,e),r();return}let n=1,u=A=>{--n===0&&(r(),this[nC](),e.resume())};e.mtime&&!this.noMtime&&(n++,vn.utimes(e.absolute,e.atime||new Date,e.mtime,u)),this[V1](e)&&(n++,vn.chown(e.absolute,this[z1](e),this[J1](e),u)),u()})}[kfe](e){e.unsupported=!0,this.warn(\"TAR_ENTRY_UNSUPPORTED\",`unsupported entry type: ${e.type}`,{entry:e}),e.resume()}[bfe](e,r){this[Kx](e,e.linkpath,\"symlink\",r)}[xfe](e,r){let o=fl(Gf.resolve(this.cwd,e.linkpath));this[Kx](e,o,\"link\",r)}[Ffe](){this[Gx]++}[nC](){this[Gx]--,this[z3]()}[e_](e){this[nC](),e.resume()}[X3](e,r){return e.type===\"File\"&&!this.unlink&&r.isFile()&&r.nlink<=1&&!Z1}[J3](e){this[Ffe]();let r=[e.path];e.linkpath&&r.push(e.linkpath),this.reservations.reserve(r,o=>this[Sfe](e,o))}[Wx](e){e.type===\"SymbolicLink\"?zct(this.dirCache):e.type!==\"Directory\"&&Vct(this.dirCache,e.absolute)}[Sfe](e,r){this[Wx](e);let o=A=>{this[Wx](e),r(A)},a=()=>{this[vh](this.cwd,this.dmode,A=>{if(A){this[To](A,e),o();return}this[X1]=!0,n()})},n=()=>{if(e.absolute!==this.cwd){let A=fl(Gf.dirname(e.absolute));if(A!==this.cwd)return this[vh](A,this.dmode,p=>{if(p){this[To](p,e),o();return}u()})}u()},u=()=>{vn.lstat(e.absolute,(A,p)=>{if(p&&(this.keep||this.newer&&p.mtime>e.mtime)){this[e_](e),o();return}if(A||this[X3](e,p))return this[tc](null,e,o);if(p.isDirectory()){if(e.type===\"Directory\"){let h=!this.noChmod&&e.mode&&(p.mode&4095)!==e.mode,C=I=>this[tc](I,e,o);return h?vn.chmod(e.absolute,e.mode,C):C()}if(e.absolute!==this.cwd)return vn.rmdir(e.absolute,h=>this[tc](h,e,o))}if(e.absolute===this.cwd)return this[tc](null,e,o);Wct(e.absolute,h=>this[tc](h,e,o))})};this[X1]?n():a()}[tc](e,r,o){if(e){this[To](e,r),o();return}switch(r.type){case\"File\":case\"OldFile\":case\"ContiguousFile\":return this[Z3](r,o);case\"Link\":return this[xfe](r,o);case\"SymbolicLink\":return this[bfe](r,o);case\"Directory\":case\"GNUDumpDir\":return this[$3](r,o)}}[Kx](e,r,o,a){vn[o](r,e.absolute,n=>{n?this[To](n,e):(this[nC](),e.resume()),a()})}},Yx=t=>{try{return[null,t()]}catch(e){return[e,null]}},t_=class extends $1{[tc](e,r){return super[tc](e,r,()=>{})}[J3](e){if(this[Wx](e),!this[X1]){let n=this[vh](this.cwd,this.dmode);if(n)return this[To](n,e);this[X1]=!0}if(e.absolute!==this.cwd){let n=fl(Gf.dirname(e.absolute));if(n!==this.cwd){let u=this[vh](n,this.dmode);if(u)return this[To](u,e)}}let[r,o]=Yx(()=>vn.lstatSync(e.absolute));if(o&&(this.keep||this.newer&&o.mtime>e.mtime))return this[e_](e);if(r||this[X3](e,o))return this[tc](null,e);if(o.isDirectory()){if(e.type===\"Directory\"){let u=!this.noChmod&&e.mode&&(o.mode&4095)!==e.mode,[A]=u?Yx(()=>{vn.chmodSync(e.absolute,e.mode)}):[];return this[tc](A,e)}let[n]=Yx(()=>vn.rmdirSync(e.absolute));this[tc](n,e)}let[a]=e.absolute===this.cwd?[]:Yx(()=>Kct(e.absolute));this[tc](a,e)}[Z3](e,r){let o=e.mode&4095||this.fmode,a=A=>{let p;try{vn.closeSync(n)}catch(h){p=h}(A||p)&&this[To](A||p,e),r()},n;try{n=vn.openSync(e.absolute,Ofe(e.size),o)}catch(A){return a(A)}let u=this.transform&&this.transform(e)||e;u!==e&&(u.on(\"error\",A=>this[To](A,e)),e.pipe(u)),u.on(\"data\",A=>{try{vn.writeSync(n,A,0,A.length)}catch(p){a(p)}}),u.on(\"end\",A=>{let p=null;if(e.mtime&&!this.noMtime){let h=e.atime||new Date,C=e.mtime;try{vn.futimesSync(n,h,C)}catch(I){try{vn.utimesSync(e.absolute,h,C)}catch{p=I}}}if(this[V1](e)){let h=this[z1](e),C=this[J1](e);try{vn.fchownSync(n,h,C)}catch(I){try{vn.chownSync(e.absolute,h,C)}catch{p=p||I}}}a(p)})}[$3](e,r){let o=e.mode&4095||this.dmode,a=this[vh](e.absolute,o);if(a){this[To](a,e),r();return}if(e.mtime&&!this.noMtime)try{vn.utimesSync(e.absolute,e.atime||new Date,e.mtime)}catch{}if(this[V1](e))try{vn.chownSync(e.absolute,this[z1](e),this[J1](e))}catch{}r(),e.resume()}[vh](e,r){try{return Nfe.sync(fl(e),{uid:this.uid,gid:this.gid,processUid:this.processUid,processGid:this.processGid,umask:this.processUmask,preserve:this.preservePaths,unlink:this.unlink,cache:this.dirCache,cwd:this.cwd,mode:r})}catch(o){return o}}[Kx](e,r,o,a){try{vn[o+\"Sync\"](r,e.absolute),a(),e.resume()}catch(n){return this[To](n,e)}}};$1.Sync=t_;Mfe.exports=$1});var qfe=_((vUt,jfe)=>{\"use strict\";var Jct=NE(),Vx=r_(),_fe=Be(\"fs\"),Hfe=ZE(),Ufe=Be(\"path\"),n_=qE();jfe.exports=(t,e,r)=>{typeof t==\"function\"?(r=t,e=null,t={}):Array.isArray(t)&&(e=t,t={}),typeof e==\"function\"&&(r=e,e=null),e?e=Array.from(e):e=[];let o=Jct(t);if(o.sync&&typeof r==\"function\")throw new TypeError(\"callback not supported for sync tar functions\");if(!o.file&&typeof r==\"function\")throw new TypeError(\"callback only supported with file option\");return e.length&&Xct(o,e),o.file&&o.sync?Zct(o):o.file?$ct(o,r):o.sync?eut(o):tut(o)};var Xct=(t,e)=>{let r=new Map(e.map(n=>[n_(n),!0])),o=t.filter,a=(n,u)=>{let A=u||Ufe.parse(n).root||\".\",p=n===A?!1:r.has(n)?r.get(n):a(Ufe.dirname(n),A);return r.set(n,p),p};t.filter=o?(n,u)=>o(n,u)&&a(n_(n)):n=>a(n_(n))},Zct=t=>{let e=new Vx.Sync(t),r=t.file,o=_fe.statSync(r),a=t.maxReadSize||16*1024*1024;new Hfe.ReadStreamSync(r,{readSize:a,size:o.size}).pipe(e)},$ct=(t,e)=>{let r=new Vx(t),o=t.maxReadSize||16*1024*1024,a=t.file,n=new Promise((u,A)=>{r.on(\"error\",A),r.on(\"close\",u),_fe.stat(a,(p,h)=>{if(p)A(p);else{let C=new Hfe.ReadStream(a,{readSize:o,size:h.size});C.on(\"error\",A),C.pipe(r)}})});return e?n.then(e,e):n},eut=t=>new Vx.Sync(t),tut=t=>new Vx(t)});var Gfe=_(us=>{\"use strict\";us.c=us.create=DAe();us.r=us.replace=M3();us.t=us.list=Lx();us.u=us.update=TAe();us.x=us.extract=qfe();us.Pack=wx();us.Unpack=r_();us.Parse=Nx();us.ReadEntry=ix();us.WriteEntry=p3();us.Header=jE();us.Pax=ox();us.types=zU()});var i_,Yfe,Dh,e2,t2,Wfe=Et(()=>{i_=$e(rd()),Yfe=Be(\"worker_threads\"),Dh=Symbol(\"kTaskInfo\"),e2=class{constructor(e,r){this.fn=e;this.limit=(0,i_.default)(r.poolSize)}run(e){return this.limit(()=>this.fn(e))}},t2=class{constructor(e,r){this.source=e;this.workers=[];this.limit=(0,i_.default)(r.poolSize),this.cleanupInterval=setInterval(()=>{if(this.limit.pendingCount===0&&this.limit.activeCount===0){let o=this.workers.pop();o?o.terminate():clearInterval(this.cleanupInterval)}},5e3).unref()}createWorker(){this.cleanupInterval.refresh();let e=new Yfe.Worker(this.source,{eval:!0,execArgv:[...process.execArgv,\"--unhandled-rejections=strict\"]});return e.on(\"message\",r=>{if(!e[Dh])throw new Error(\"Assertion failed: Worker sent a result without having a task assigned\");e[Dh].resolve(r),e[Dh]=null,e.unref(),this.workers.push(e)}),e.on(\"error\",r=>{e[Dh]?.reject(r),e[Dh]=null}),e.on(\"exit\",r=>{r!==0&&e[Dh]?.reject(new Error(`Worker exited with code ${r}`)),e[Dh]=null}),e}run(e){return this.limit(()=>{let r=this.workers.pop()??this.createWorker();return r.ref(),new Promise((o,a)=>{r[Dh]={resolve:o,reject:a},r.postMessage(e)})})}}});var Vfe=_((bUt,Kfe)=>{var s_;Kfe.exports.getContent=()=>(typeof s_>\"u\"&&(s_=Be(\"zlib\").brotliDecompressSync(Buffer.from(\"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\",\"base64\")).toString()),s_)});var Xi={};Vt(Xi,{convertToZip:()=>sut,convertToZipWorker:()=>l_,extractArchiveTo:()=>$fe,getDefaultTaskPool:()=>Xfe,getTaskPoolForConfiguration:()=>Zfe,makeArchiveFromDirectory:()=>iut});function rut(t,e){switch(t){case\"async\":return new e2(l_,{poolSize:e});case\"workers\":return new t2((0,a_.getContent)(),{poolSize:e});default:throw new Error(`Assertion failed: Unknown value ${t} for taskPoolMode`)}}function Xfe(){return typeof o_>\"u\"&&(o_=rut(\"workers\",zi.availableParallelism())),o_}function Zfe(t){return typeof t>\"u\"?Xfe():ol(nut,t,()=>{let e=t.get(\"taskPoolMode\"),r=t.get(\"taskPoolConcurrency\");switch(e){case\"async\":return new e2(l_,{poolSize:r});case\"workers\":return new t2((0,a_.getContent)(),{poolSize:r});default:throw new Error(`Assertion failed: Unknown value ${e} for taskPoolMode`)}})}async function l_(t){let{tmpFile:e,tgz:r,compressionLevel:o,extractBufferOpts:a}=t,n=new Ji(e,{create:!0,level:o,stats:Ea.makeDefaultStats()}),u=Buffer.from(r.buffer,r.byteOffset,r.byteLength);return await $fe(u,n,a),n.saveAndClose(),e}async function iut(t,{baseFs:e=new Tn,prefixPath:r=Bt.root,compressionLevel:o,inMemory:a=!1}={}){let n;if(a)n=new Ji(null,{level:o});else{let A=await oe.mktempPromise(),p=V.join(A,\"archive.zip\");n=new Ji(p,{create:!0,level:o})}let u=V.resolve(Bt.root,r);return await n.copyPromise(u,t,{baseFs:e,stableTime:!0,stableSort:!0}),n}async function sut(t,e={}){let r=await oe.mktempPromise(),o=V.join(r,\"archive.zip\"),a=e.compressionLevel??e.configuration?.get(\"compressionLevel\")??\"mixed\",n={prefixPath:e.prefixPath,stripComponents:e.stripComponents};return await(e.taskPool??Zfe(e.configuration)).run({tmpFile:o,tgz:t,compressionLevel:a,extractBufferOpts:n}),new Ji(o,{level:e.compressionLevel})}async function*out(t){let e=new Jfe.default.Parse,r=new zfe.PassThrough({objectMode:!0,autoDestroy:!0,emitClose:!0});e.on(\"entry\",o=>{r.write(o)}),e.on(\"error\",o=>{r.destroy(o)}),e.on(\"close\",()=>{r.destroyed||r.end()}),e.end(t);for await(let o of r){let a=o;yield a,a.resume()}}async function $fe(t,e,{stripComponents:r=0,prefixPath:o=Bt.dot}={}){function a(n){if(n.path[0]===\"/\")return!0;let u=n.path.split(/\\//g);return!!(u.some(A=>A===\"..\")||u.length<=r)}for await(let n of out(t)){if(a(n))continue;let u=V.normalize(ue.toPortablePath(n.path)).replace(/\\/$/,\"\").split(/\\//g);if(u.length<=r)continue;let A=u.slice(r).join(\"/\"),p=V.join(o,A),h=420;switch((n.type===\"Directory\"||((n.mode??0)&73)!==0)&&(h|=73),n.type){case\"Directory\":e.mkdirpSync(V.dirname(p),{chmod:493,utimes:[vi.SAFE_TIME,vi.SAFE_TIME]}),e.mkdirSync(p,{mode:h}),e.utimesSync(p,vi.SAFE_TIME,vi.SAFE_TIME);break;case\"OldFile\":case\"File\":e.mkdirpSync(V.dirname(p),{chmod:493,utimes:[vi.SAFE_TIME,vi.SAFE_TIME]}),e.writeFileSync(p,await Wy(n),{mode:h}),e.utimesSync(p,vi.SAFE_TIME,vi.SAFE_TIME);break;case\"SymbolicLink\":e.mkdirpSync(V.dirname(p),{chmod:493,utimes:[vi.SAFE_TIME,vi.SAFE_TIME]}),e.symlinkSync(n.linkpath,p),e.lutimesSync(p,vi.SAFE_TIME,vi.SAFE_TIME);break}}return e}var zfe,Jfe,a_,o_,nut,epe=Et(()=>{Ye();Pt();nA();zfe=Be(\"stream\"),Jfe=$e(Gfe());Wfe();jl();a_=$e(Vfe());nut=new WeakMap});var rpe=_((c_,tpe)=>{(function(t,e){typeof c_==\"object\"?tpe.exports=e():typeof define==\"function\"&&define.amd?define(e):t.treeify=e()})(c_,function(){function t(a,n){var u=n?\"\\u2514\":\"\\u251C\";return a?u+=\"\\u2500 \":u+=\"\\u2500\\u2500\\u2510\",u}function e(a,n){var u=[];for(var A in a)!a.hasOwnProperty(A)||n&&typeof a[A]==\"function\"||u.push(A);return u}function r(a,n,u,A,p,h,C){var I=\"\",v=0,x,E,R=A.slice(0);if(R.push([n,u])&&A.length>0&&(A.forEach(function(U,z){z>0&&(I+=(U[1]?\" \":\"\\u2502\")+\"  \"),!E&&U[0]===n&&(E=!0)}),I+=t(a,u)+a,p&&(typeof n!=\"object\"||n instanceof Date)&&(I+=\": \"+n),E&&(I+=\" (circular ref.)\"),C(I)),!E&&typeof n==\"object\"){var L=e(n,h);L.forEach(function(U){x=++v===L.length,r(U,n[U],x,R,p,h,C)})}}var o={};return o.asLines=function(a,n,u,A){var p=typeof u!=\"function\"?u:!1;r(\".\",a,!1,[],n,p,A||u)},o.asTree=function(a,n,u){var A=\"\";return r(\".\",a,!1,[],n,u,function(p){A+=p+`\n`}),A},o})});var $s={};Vt($s,{emitList:()=>aut,emitTree:()=>ope,treeNodeToJson:()=>spe,treeNodeToTreeify:()=>ipe});function ipe(t,{configuration:e}){let r={},o=0,a=(n,u)=>{let A=Array.isArray(n)?n.entries():Object.entries(n);for(let[p,h]of A){if(!h)continue;let{label:C,value:I,children:v}=h,x=[];typeof C<\"u\"&&x.push(dd(e,C,2)),typeof I<\"u\"&&x.push(Mt(e,I[0],I[1])),x.length===0&&x.push(dd(e,`${p}`,2));let E=x.join(\": \").trim(),R=`\\0${o++}\\0`,L=u[`${R}${E}`]={};typeof v<\"u\"&&a(v,L)}};if(typeof t.children>\"u\")throw new Error(\"The root node must only contain children\");return a(t.children,r),r}function spe(t){let e=r=>{if(typeof r.children>\"u\"){if(typeof r.value>\"u\")throw new Error(\"Assertion failed: Expected a value to be set if the children are missing\");return md(r.value[0],r.value[1])}let o=Array.isArray(r.children)?r.children.entries():Object.entries(r.children??{}),a=Array.isArray(r.children)?[]:{};for(let[n,u]of o)u&&(a[lut(n)]=e(u));return typeof r.value>\"u\"?a:{value:md(r.value[0],r.value[1]),children:a}};return e(t)}function aut(t,{configuration:e,stdout:r,json:o}){let a=t.map(n=>({value:n}));ope({children:a},{configuration:e,stdout:r,json:o})}function ope(t,{configuration:e,stdout:r,json:o,separators:a=0}){if(o){let u=Array.isArray(t.children)?t.children.values():Object.values(t.children??{});for(let A of u)A&&r.write(`${JSON.stringify(spe(A))}\n`);return}let n=(0,npe.asTree)(ipe(t,{configuration:e}),!1,!1);if(n=n.replace(/\\0[0-9]+\\0/g,\"\"),a>=1&&(n=n.replace(/^([├└]─)/gm,`\\u2502\n$1`).replace(/^│\\n/,\"\")),a>=2)for(let u=0;u<2;++u)n=n.replace(/^([│ ].{2}[├│ ].{2}[^\\n]+\\n)(([│ ]).{2}[├└].{2}[^\\n]*\\n[│ ].{2}[│ ].{2}[├└]─)/gm,`$1$3  \\u2502 \n$2`).replace(/^│\\n/,\"\");if(a>=3)throw new Error(\"Only the first two levels are accepted by treeUtils.emitTree\");r.write(n)}function lut(t){return typeof t==\"string\"?t.replace(/^\\0[0-9]+\\0/,\"\"):t}var npe,ape=Et(()=>{npe=$e(rpe());ql()});function r2(t){let e=t.match(cut);if(!e?.groups)throw new Error(\"Assertion failed: Expected the checksum to match the requested pattern\");let r=e.groups.cacheVersion?parseInt(e.groups.cacheVersion):null;return{cacheKey:e.groups.cacheKey??null,cacheVersion:r,cacheSpec:e.groups.cacheSpec??null,hash:e.groups.hash}}var lpe,u_,A_,zx,Lr,cut,f_=Et(()=>{Ye();Pt();Pt();nA();lpe=Be(\"crypto\"),u_=$e(Be(\"fs\"));Yl();rh();jl();bo();A_=Ky(process.env.YARN_CACHE_CHECKPOINT_OVERRIDE??process.env.YARN_CACHE_VERSION_OVERRIDE??9),zx=Ky(process.env.YARN_CACHE_VERSION_OVERRIDE??10),Lr=class{constructor(e,{configuration:r,immutable:o=r.get(\"enableImmutableCache\"),check:a=!1}){this.markedFiles=new Set;this.mutexes=new Map;this.cacheId=`-${(0,lpe.randomBytes)(8).toString(\"hex\")}.tmp`;this.configuration=r,this.cwd=e,this.immutable=o,this.check=a;let{cacheSpec:n,cacheKey:u}=Lr.getCacheKey(r);this.cacheSpec=n,this.cacheKey=u}static async find(e,{immutable:r,check:o}={}){let a=new Lr(e.get(\"cacheFolder\"),{configuration:e,immutable:r,check:o});return await a.setup(),a}static getCacheKey(e){let r=e.get(\"compressionLevel\"),o=r!==\"mixed\"?`c${r}`:\"\";return{cacheKey:[zx,o].join(\"\"),cacheSpec:o}}get mirrorCwd(){if(!this.configuration.get(\"enableMirror\"))return null;let e=`${this.configuration.get(\"globalFolder\")}/cache`;return e!==this.cwd?e:null}getVersionFilename(e){return`${oE(e)}-${this.cacheKey}.zip`}getChecksumFilename(e,r){let a=r2(r).hash.slice(0,10);return`${oE(e)}-${a}.zip`}isChecksumCompatible(e){if(e===null)return!1;let{cacheVersion:r,cacheSpec:o}=r2(e);if(r===null||r<A_)return!1;let a=this.configuration.get(\"cacheMigrationMode\");return!(r<zx&&a===\"always\"||o!==this.cacheSpec&&a!==\"required-only\")}getLocatorPath(e,r){return this.mirrorCwd===null?V.resolve(this.cwd,this.getVersionFilename(e)):r===null?V.resolve(this.cwd,this.getVersionFilename(e)):V.resolve(this.cwd,this.getChecksumFilename(e,r))}getLocatorMirrorPath(e){let r=this.mirrorCwd;return r!==null?V.resolve(r,this.getVersionFilename(e)):null}async setup(){if(!this.configuration.get(\"enableGlobalCache\"))if(this.immutable){if(!await oe.existsPromise(this.cwd))throw new Jt(56,\"Cache path does not exist.\")}else{await oe.mkdirPromise(this.cwd,{recursive:!0});let e=V.resolve(this.cwd,\".gitignore\");await oe.changeFilePromise(e,`/.gitignore\n*.flock\n*.tmp\n`)}(this.mirrorCwd||!this.immutable)&&await oe.mkdirPromise(this.mirrorCwd||this.cwd,{recursive:!0})}async fetchPackageFromCache(e,r,{onHit:o,onMiss:a,loader:n,...u}){let A=this.getLocatorMirrorPath(e),p=new Tn,h=()=>{let ae=new Ji,Ie=V.join(Bt.root,sM(e));return ae.mkdirSync(Ie,{recursive:!0}),ae.writeJsonSync(V.join(Ie,dr.manifest),{name:fn(e),mocked:!0}),ae},C=async(ae,{isColdHit:Ie,controlPath:Fe=null})=>{if(Fe===null&&u.unstablePackages?.has(e.locatorHash))return{isValid:!0,hash:null};let g=r&&!Ie?r2(r).cacheKey:this.cacheKey,Ee=!u.skipIntegrityCheck||!r?`${g}/${await LS(ae)}`:r;if(Fe!==null){let ce=!u.skipIntegrityCheck||!r?`${this.cacheKey}/${await LS(Fe)}`:r;if(Ee!==ce)throw new Jt(18,\"The remote archive doesn't match the local checksum - has the local cache been corrupted?\")}let De=null;switch(r!==null&&Ee!==r&&(this.check?De=\"throw\":r2(r).cacheKey!==r2(Ee).cacheKey?De=\"update\":De=this.configuration.get(\"checksumBehavior\")),De){case null:case\"update\":return{isValid:!0,hash:Ee};case\"ignore\":return{isValid:!0,hash:r};case\"reset\":return{isValid:!1,hash:r};default:case\"throw\":throw new Jt(18,\"The remote archive doesn't match the expected checksum\")}},I=async ae=>{if(!n)throw new Error(`Cache check required but no loader configured for ${jr(this.configuration,e)}`);let Ie=await n(),Fe=Ie.getRealPath();Ie.saveAndClose(),await oe.chmodPromise(Fe,420);let g=await C(ae,{controlPath:Fe,isColdHit:!1});if(!g.isValid)throw new Error(\"Assertion failed: Expected a valid checksum\");return g.hash},v=async()=>{if(A===null||!await oe.existsPromise(A)){let ae=await n(),Ie=ae.getRealPath();return ae.saveAndClose(),{source:\"loader\",path:Ie}}return{source:\"mirror\",path:A}},x=async()=>{if(!n)throw new Error(`Cache entry required but missing for ${jr(this.configuration,e)}`);if(this.immutable)throw new Jt(56,`Cache entry required but missing for ${jr(this.configuration,e)}`);let{path:ae,source:Ie}=await v(),{hash:Fe}=await C(ae,{isColdHit:!0}),g=this.getLocatorPath(e,Fe),Ee=[];Ie!==\"mirror\"&&A!==null&&Ee.push(async()=>{let ce=`${A}${this.cacheId}`;await oe.copyFilePromise(ae,ce,u_.default.constants.COPYFILE_FICLONE),await oe.chmodPromise(ce,420),await oe.renamePromise(ce,A)}),(!u.mirrorWriteOnly||A===null)&&Ee.push(async()=>{let ce=`${g}${this.cacheId}`;await oe.copyFilePromise(ae,ce,u_.default.constants.COPYFILE_FICLONE),await oe.chmodPromise(ce,420),await oe.renamePromise(ce,g)});let De=u.mirrorWriteOnly?A??g:g;return await Promise.all(Ee.map(ce=>ce())),[!1,De,Fe]},E=async()=>{let Ie=(async()=>{let Fe=u.unstablePackages?.has(e.locatorHash),g=Fe||!r||this.isChecksumCompatible(r)?this.getLocatorPath(e,r):null,Ee=g!==null?this.markedFiles.has(g)||await p.existsPromise(g):!1,De=!!u.mockedPackages?.has(e.locatorHash)&&(!this.check||!Ee),ce=De||Ee,ne=ce?o:a;if(ne&&ne(),ce){let ee=null,we=g;if(!De)if(this.check)ee=await I(we);else{let xe=await C(we,{isColdHit:!1});if(xe.isValid)ee=xe.hash;else return x()}return[De,we,ee]}else{if(this.immutable&&Fe)throw new Jt(56,`Cache entry required but missing for ${jr(this.configuration,e)}; consider defining ${de.pretty(this.configuration,\"supportedArchitectures\",de.Type.CODE)} to cache packages for multiple systems`);return x()}})();this.mutexes.set(e.locatorHash,Ie);try{return await Ie}finally{this.mutexes.delete(e.locatorHash)}};for(let ae;ae=this.mutexes.get(e.locatorHash);)await ae;let[R,L,U]=await E();R||this.markedFiles.add(L);let z,te=R?()=>h():()=>new Ji(L,{baseFs:p,readOnly:!0}),le=new ry(()=>wL(()=>z=te(),ae=>`Failed to open the cache entry for ${jr(this.configuration,e)}: ${ae}`),V),he=new Uu(L,{baseFs:le,pathUtils:V}),Ae=()=>{z?.discardAndClose()},ye=u.unstablePackages?.has(e.locatorHash)?null:U;return[he,Ae,ye]}},cut=/^(?:(?<cacheKey>(?<cacheVersion>[0-9]+)(?<cacheSpec>.*))\\/)?(?<hash>.*)$/});var Jx,cpe=Et(()=>{Jx=(r=>(r[r.SCRIPT=0]=\"SCRIPT\",r[r.SHELLCODE=1]=\"SHELLCODE\",r))(Jx||{})});var uut,iC,p_=Et(()=>{Pt();Nl();xf();bo();uut=[[/^(git(?:\\+(?:https|ssh))?:\\/\\/.*(?:\\.git)?)#(.*)$/,(t,e,r,o)=>`${r}#commit=${o}`],[/^https:\\/\\/((?:[^/]+?)@)?codeload\\.github\\.com\\/([^/]+\\/[^/]+)\\/tar\\.gz\\/([0-9a-f]+)$/,(t,e,r=\"\",o,a)=>`https://${r}github.com/${o}.git#commit=${a}`],[/^https:\\/\\/((?:[^/]+?)@)?github\\.com\\/([^/]+\\/[^/]+?)(?:\\.git)?#([0-9a-f]+)$/,(t,e,r=\"\",o,a)=>`https://${r}github.com/${o}.git#commit=${a}`],[/^https?:\\/\\/[^/]+\\/(?:[^/]+\\/)*(?:@.+(?:\\/|(?:%2f)))?([^/]+)\\/(?:-|download)\\/\\1-[^/]+\\.tgz(?:#|$)/,t=>`npm:${t}`],[/^https:\\/\\/npm\\.pkg\\.github\\.com\\/download\\/(?:@[^/]+)\\/(?:[^/]+)\\/(?:[^/]+)\\/(?:[0-9a-f]+)(?:#|$)/,t=>`npm:${t}`],[/^https:\\/\\/npm\\.fontawesome\\.com\\/(?:@[^/]+)\\/([^/]+)\\/-\\/([^/]+)\\/\\1-\\2.tgz(?:#|$)/,t=>`npm:${t}`],[/^https?:\\/\\/[^/]+\\/.*\\/(@[^/]+)\\/([^/]+)\\/-\\/\\1\\/\\2-(?:[.\\d\\w-]+)\\.tgz(?:#|$)/,(t,e)=>HS({protocol:\"npm:\",source:null,selector:t,params:{__archiveUrl:e}})],[/^[^/]+\\.tgz#[0-9a-f]+$/,t=>`npm:${t}`]],iC=class{constructor(e){this.resolver=e;this.resolutions=null}async setup(e,{report:r}){let o=V.join(e.cwd,dr.lockfile);if(!oe.existsSync(o))return;let a=await oe.readFilePromise(o,\"utf8\"),n=Ki(a);if(Object.hasOwn(n,\"__metadata\"))return;let u=this.resolutions=new Map;for(let A of Object.keys(n)){let p=n1(A);if(!p){r.reportWarning(14,`Failed to parse the string \"${A}\" into a proper descriptor`);continue}let h=xa(p.range)?In(p,`npm:${p.range}`):p,{version:C,resolved:I}=n[A];if(!I)continue;let v;for(let[E,R]of uut){let L=I.match(E);if(L){v=R(C,...L);break}}if(!v){r.reportWarning(14,`${qn(e.configuration,h)}: Only some patterns can be imported from legacy lockfiles (not \"${I}\")`);continue}let x=h;try{let E=wd(h.range),R=n1(E.selector,!0);R&&(x=R)}catch{}u.set(h.descriptorHash,Qs(x,v))}}supportsDescriptor(e,r){return this.resolutions?this.resolutions.has(e.descriptorHash):!1}supportsLocator(e,r){return!1}shouldPersistResolution(e,r){throw new Error(\"Assertion failed: This resolver doesn't support resolving locators to packages\")}bindDescriptor(e,r,o){return e}getResolutionDependencies(e,r){return{}}async getCandidates(e,r,o){if(!this.resolutions)throw new Error(\"Assertion failed: The resolution store should have been setup\");let a=this.resolutions.get(e.descriptorHash);if(!a)throw new Error(\"Assertion failed: The resolution should have been registered\");let n=tM(a),u=o.project.configuration.normalizeDependency(n);return await this.resolver.getCandidates(u,r,o)}async getSatisfying(e,r,o,a){let[n]=await this.getCandidates(e,r,a);return{locators:o.filter(u=>u.locatorHash===n.locatorHash),sorted:!1}}async resolve(e,r){throw new Error(\"Assertion failed: This resolver doesn't support resolving locators to packages\")}}});var AA,upe=Et(()=>{Yl();N1();ql();AA=class extends Xs{constructor({configuration:r,stdout:o,suggestInstall:a=!0}){super();this.errorCount=0;zI(this,{configuration:r}),this.configuration=r,this.stdout=o,this.suggestInstall=a}static async start(r,o){let a=new this(r);try{await o(a)}catch(n){a.reportExceptionOnce(n)}finally{await a.finalize()}return a}hasErrors(){return this.errorCount>0}exitCode(){return this.hasErrors()?1:0}reportCacheHit(r){}reportCacheMiss(r){}startSectionSync(r,o){return o()}async startSectionPromise(r,o){return await o()}startTimerSync(r,o,a){return(typeof o==\"function\"?o:a)()}async startTimerPromise(r,o,a){return await(typeof o==\"function\"?o:a)()}reportSeparator(){}reportInfo(r,o){}reportWarning(r,o){}reportError(r,o){this.errorCount+=1,this.stdout.write(`${Mt(this.configuration,\"\\u27A4\",\"redBright\")} ${this.formatNameWithHyperlink(r)}: ${o}\n`)}reportProgress(r){return{...Promise.resolve().then(async()=>{for await(let{}of r);}),stop:()=>{}}}reportJson(r){}reportFold(r,o){}async finalize(){this.errorCount>0&&(this.stdout.write(`\n`),this.stdout.write(`${Mt(this.configuration,\"\\u27A4\",\"redBright\")} Errors happened when preparing the environment required to run this command.\n`),this.suggestInstall&&this.stdout.write(`${Mt(this.configuration,\"\\u27A4\",\"redBright\")} This might be caused by packages being missing from the lockfile, in which case running \"yarn install\" might help.\n`))}formatNameWithHyperlink(r){return CU(r,{configuration:this.configuration,json:!1})}}});var sC,h_=Et(()=>{bo();sC=class{constructor(e){this.resolver=e}supportsDescriptor(e,r){return!!(r.project.storedResolutions.get(e.descriptorHash)||r.project.originalPackages.has(MS(e).locatorHash))}supportsLocator(e,r){return!!(r.project.originalPackages.has(e.locatorHash)&&!r.project.lockfileNeedsRefresh)}shouldPersistResolution(e,r){throw new Error(\"The shouldPersistResolution method shouldn't be called on the lockfile resolver, which would always answer yes\")}bindDescriptor(e,r,o){return e}getResolutionDependencies(e,r){return this.resolver.getResolutionDependencies(e,r)}async getCandidates(e,r,o){let a=o.project.storedResolutions.get(e.descriptorHash);if(a){let u=o.project.originalPackages.get(a);if(u)return[u]}let n=o.project.originalPackages.get(MS(e).locatorHash);if(n)return[n];throw new Error(\"Resolution expected from the lockfile data\")}async getSatisfying(e,r,o,a){let[n]=await this.getCandidates(e,r,a);return{locators:o.filter(u=>u.locatorHash===n.locatorHash),sorted:!1}}async resolve(e,r){let o=r.project.originalPackages.get(e.locatorHash);if(!o)throw new Error(\"The lockfile resolver isn't meant to resolve packages - they should already have been stored into a cache\");return o}}});function Yf(){}function Aut(t,e,r,o,a){for(var n=0,u=e.length,A=0,p=0;n<u;n++){var h=e[n];if(h.removed){if(h.value=t.join(o.slice(p,p+h.count)),p+=h.count,n&&e[n-1].added){var I=e[n-1];e[n-1]=e[n],e[n]=I}}else{if(!h.added&&a){var C=r.slice(A,A+h.count);C=C.map(function(x,E){var R=o[p+E];return R.length>x.length?R:x}),h.value=t.join(C)}else h.value=t.join(r.slice(A,A+h.count));A+=h.count,h.added||(p+=h.count)}}var v=e[u-1];return u>1&&typeof v.value==\"string\"&&(v.added||v.removed)&&t.equals(\"\",v.value)&&(e[u-2].value+=v.value,e.pop()),e}function fut(t){return{newPos:t.newPos,components:t.components.slice(0)}}function put(t,e){if(typeof t==\"function\")e.callback=t;else if(t)for(var r in t)t.hasOwnProperty(r)&&(e[r]=t[r]);return e}function ppe(t,e,r){return r=put(r,{ignoreWhitespace:!0}),E_.diff(t,e,r)}function hut(t,e,r){return C_.diff(t,e,r)}function Xx(t){return typeof Symbol==\"function\"&&typeof Symbol.iterator==\"symbol\"?Xx=function(e){return typeof e}:Xx=function(e){return e&&typeof Symbol==\"function\"&&e.constructor===Symbol&&e!==Symbol.prototype?\"symbol\":typeof e},Xx(t)}function g_(t){return mut(t)||yut(t)||Eut(t)||Cut()}function mut(t){if(Array.isArray(t))return d_(t)}function yut(t){if(typeof Symbol<\"u\"&&Symbol.iterator in Object(t))return Array.from(t)}function Eut(t,e){if(!!t){if(typeof t==\"string\")return d_(t,e);var r=Object.prototype.toString.call(t).slice(8,-1);if(r===\"Object\"&&t.constructor&&(r=t.constructor.name),r===\"Map\"||r===\"Set\")return Array.from(t);if(r===\"Arguments\"||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(r))return d_(t,e)}}function d_(t,e){(e==null||e>t.length)&&(e=t.length);for(var r=0,o=new Array(e);r<e;r++)o[r]=t[r];return o}function Cut(){throw new TypeError(`Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.`)}function m_(t,e,r,o,a){e=e||[],r=r||[],o&&(t=o(a,t));var n;for(n=0;n<e.length;n+=1)if(e[n]===t)return r[n];var u;if(wut.call(t)===\"[object Array]\"){for(e.push(t),u=new Array(t.length),r.push(u),n=0;n<t.length;n+=1)u[n]=m_(t[n],e,r,o,a);return e.pop(),r.pop(),u}if(t&&t.toJSON&&(t=t.toJSON()),Xx(t)===\"object\"&&t!==null){e.push(t),u={},r.push(u);var A=[],p;for(p in t)t.hasOwnProperty(p)&&A.push(p);for(A.sort(),n=0;n<A.length;n+=1)p=A[n],u[p]=m_(t[p],e,r,o,p);e.pop(),r.pop()}else u=t;return u}function hpe(t,e,r,o,a,n,u){u||(u={}),typeof u.context>\"u\"&&(u.context=4);var A=hut(r,o,u);if(!A)return;A.push({value:\"\",lines:[]});function p(U){return U.map(function(z){return\" \"+z})}for(var h=[],C=0,I=0,v=[],x=1,E=1,R=function(z){var te=A[z],le=te.lines||te.value.replace(/\\n$/,\"\").split(`\n`);if(te.lines=le,te.added||te.removed){var he;if(!C){var Ae=A[z-1];C=x,I=E,Ae&&(v=u.context>0?p(Ae.lines.slice(-u.context)):[],C-=v.length,I-=v.length)}(he=v).push.apply(he,g_(le.map(function(ce){return(te.added?\"+\":\"-\")+ce}))),te.added?E+=le.length:x+=le.length}else{if(C)if(le.length<=u.context*2&&z<A.length-2){var ye;(ye=v).push.apply(ye,g_(p(le)))}else{var ae,Ie=Math.min(le.length,u.context);(ae=v).push.apply(ae,g_(p(le.slice(0,Ie))));var Fe={oldStart:C,oldLines:x-C+Ie,newStart:I,newLines:E-I+Ie,lines:v};if(z>=A.length-2&&le.length<=u.context){var g=/\\n$/.test(r),Ee=/\\n$/.test(o),De=le.length==0&&v.length>Fe.oldLines;!g&&De&&r.length>0&&v.splice(Fe.oldLines,0,\"\\\\ No newline at end of file\"),(!g&&!De||!Ee)&&v.push(\"\\\\ No newline at end of file\")}h.push(Fe),C=0,I=0,v=[]}x+=le.length,E+=le.length}},L=0;L<A.length;L++)R(L);return{oldFileName:t,newFileName:e,oldHeader:a,newHeader:n,hunks:h}}var t3t,Ape,fpe,E_,C_,gut,dut,wut,n2,y_,w_=Et(()=>{Yf.prototype={diff:function(e,r){var o=arguments.length>2&&arguments[2]!==void 0?arguments[2]:{},a=o.callback;typeof o==\"function\"&&(a=o,o={}),this.options=o;var n=this;function u(R){return a?(setTimeout(function(){a(void 0,R)},0),!0):R}e=this.castInput(e),r=this.castInput(r),e=this.removeEmpty(this.tokenize(e)),r=this.removeEmpty(this.tokenize(r));var A=r.length,p=e.length,h=1,C=A+p;o.maxEditLength&&(C=Math.min(C,o.maxEditLength));var I=[{newPos:-1,components:[]}],v=this.extractCommon(I[0],r,e,0);if(I[0].newPos+1>=A&&v+1>=p)return u([{value:this.join(r),count:r.length}]);function x(){for(var R=-1*h;R<=h;R+=2){var L=void 0,U=I[R-1],z=I[R+1],te=(z?z.newPos:0)-R;U&&(I[R-1]=void 0);var le=U&&U.newPos+1<A,he=z&&0<=te&&te<p;if(!le&&!he){I[R]=void 0;continue}if(!le||he&&U.newPos<z.newPos?(L=fut(z),n.pushComponent(L.components,void 0,!0)):(L=U,L.newPos++,n.pushComponent(L.components,!0,void 0)),te=n.extractCommon(L,r,e,R),L.newPos+1>=A&&te+1>=p)return u(Aut(n,L.components,r,e,n.useLongestToken));I[R]=L}h++}if(a)(function R(){setTimeout(function(){if(h>C)return a();x()||R()},0)})();else for(;h<=C;){var E=x();if(E)return E}},pushComponent:function(e,r,o){var a=e[e.length-1];a&&a.added===r&&a.removed===o?e[e.length-1]={count:a.count+1,added:r,removed:o}:e.push({count:1,added:r,removed:o})},extractCommon:function(e,r,o,a){for(var n=r.length,u=o.length,A=e.newPos,p=A-a,h=0;A+1<n&&p+1<u&&this.equals(r[A+1],o[p+1]);)A++,p++,h++;return h&&e.components.push({count:h}),e.newPos=A,p},equals:function(e,r){return this.options.comparator?this.options.comparator(e,r):e===r||this.options.ignoreCase&&e.toLowerCase()===r.toLowerCase()},removeEmpty:function(e){for(var r=[],o=0;o<e.length;o++)e[o]&&r.push(e[o]);return r},castInput:function(e){return e},tokenize:function(e){return e.split(\"\")},join:function(e){return e.join(\"\")}};t3t=new Yf;Ape=/^[A-Za-z\\xC0-\\u02C6\\u02C8-\\u02D7\\u02DE-\\u02FF\\u1E00-\\u1EFF]+$/,fpe=/\\S/,E_=new Yf;E_.equals=function(t,e){return this.options.ignoreCase&&(t=t.toLowerCase(),e=e.toLowerCase()),t===e||this.options.ignoreWhitespace&&!fpe.test(t)&&!fpe.test(e)};E_.tokenize=function(t){for(var e=t.split(/([^\\S\\r\\n]+|[()[\\]{}'\"\\r\\n]|\\b)/),r=0;r<e.length-1;r++)!e[r+1]&&e[r+2]&&Ape.test(e[r])&&Ape.test(e[r+2])&&(e[r]+=e[r+2],e.splice(r+1,2),r--);return e};C_=new Yf;C_.tokenize=function(t){var e=[],r=t.split(/(\\n|\\r\\n)/);r[r.length-1]||r.pop();for(var o=0;o<r.length;o++){var a=r[o];o%2&&!this.options.newlineIsToken?e[e.length-1]+=a:(this.options.ignoreWhitespace&&(a=a.trim()),e.push(a))}return e};gut=new Yf;gut.tokenize=function(t){return t.split(/(\\S.+?[.!?])(?=\\s+|$)/)};dut=new Yf;dut.tokenize=function(t){return t.split(/([{}:;,]|\\s+)/)};wut=Object.prototype.toString,n2=new Yf;n2.useLongestToken=!0;n2.tokenize=C_.tokenize;n2.castInput=function(t){var e=this.options,r=e.undefinedReplacement,o=e.stringifyReplacer,a=o===void 0?function(n,u){return typeof u>\"u\"?r:u}:o;return typeof t==\"string\"?t:JSON.stringify(m_(t,null,null,a),a,\"  \")};n2.equals=function(t,e){return Yf.prototype.equals.call(n2,t.replace(/,([\\r\\n])/g,\"$1\"),e.replace(/,([\\r\\n])/g,\"$1\"))};y_=new Yf;y_.tokenize=function(t){return t.slice()};y_.join=y_.removeEmpty=function(t){return t}});var dpe=_((n3t,gpe)=>{var Iut=Hl(),But=AE(),vut=/\\.|\\[(?:[^[\\]]*|([\"'])(?:(?!\\1)[^\\\\]|\\\\.)*?\\1)\\]/,Dut=/^\\w*$/;function Put(t,e){if(Iut(t))return!1;var r=typeof t;return r==\"number\"||r==\"symbol\"||r==\"boolean\"||t==null||But(t)?!0:Dut.test(t)||!vut.test(t)||e!=null&&t in Object(e)}gpe.exports=Put});var Epe=_((i3t,ype)=>{var mpe=_P(),Sut=\"Expected a function\";function I_(t,e){if(typeof t!=\"function\"||e!=null&&typeof e!=\"function\")throw new TypeError(Sut);var r=function(){var o=arguments,a=e?e.apply(this,o):o[0],n=r.cache;if(n.has(a))return n.get(a);var u=t.apply(this,o);return r.cache=n.set(a,u)||n,u};return r.cache=new(I_.Cache||mpe),r}I_.Cache=mpe;ype.exports=I_});var wpe=_((s3t,Cpe)=>{var but=Epe(),xut=500;function kut(t){var e=but(t,function(o){return r.size===xut&&r.clear(),o}),r=e.cache;return e}Cpe.exports=kut});var B_=_((o3t,Ipe)=>{var Qut=wpe(),Fut=/[^.[\\]]+|\\[(?:(-?\\d+(?:\\.\\d+)?)|([\"'])((?:(?!\\2)[^\\\\]|\\\\.)*?)\\2)\\]|(?=(?:\\.|\\[\\])(?:\\.|\\[\\]|$))/g,Rut=/\\\\(\\\\)?/g,Tut=Qut(function(t){var e=[];return t.charCodeAt(0)===46&&e.push(\"\"),t.replace(Fut,function(r,o,a,n){e.push(a?n.replace(Rut,\"$1\"):o||r)}),e});Ipe.exports=Tut});var Hd=_((a3t,Bpe)=>{var Nut=Hl(),Lut=dpe(),Out=B_(),Mut=R1();function Uut(t,e){return Nut(t)?t:Lut(t,e)?[t]:Out(Mut(t))}Bpe.exports=Uut});var oC=_((l3t,vpe)=>{var _ut=AE(),Hut=1/0;function jut(t){if(typeof t==\"string\"||_ut(t))return t;var e=t+\"\";return e==\"0\"&&1/t==-Hut?\"-0\":e}vpe.exports=jut});var Zx=_((c3t,Dpe)=>{var qut=Hd(),Gut=oC();function Yut(t,e){e=qut(e,t);for(var r=0,o=e.length;t!=null&&r<o;)t=t[Gut(e[r++])];return r&&r==o?t:void 0}Dpe.exports=Yut});var v_=_((u3t,Spe)=>{var Wut=rS(),Kut=Hd(),Vut=MI(),Ppe=il(),zut=oC();function Jut(t,e,r,o){if(!Ppe(t))return t;e=Kut(e,t);for(var a=-1,n=e.length,u=n-1,A=t;A!=null&&++a<n;){var p=zut(e[a]),h=r;if(p===\"__proto__\"||p===\"constructor\"||p===\"prototype\")return t;if(a!=u){var C=A[p];h=o?o(C,p,A):void 0,h===void 0&&(h=Ppe(C)?C:Vut(e[a+1])?[]:{})}Wut(A,p,h),A=A[p]}return t}Spe.exports=Jut});var xpe=_((A3t,bpe)=>{var Xut=Zx(),Zut=v_(),$ut=Hd();function eAt(t,e,r){for(var o=-1,a=e.length,n={};++o<a;){var u=e[o],A=Xut(t,u);r(A,u)&&Zut(n,$ut(u,t),A)}return n}bpe.exports=eAt});var Qpe=_((f3t,kpe)=>{function tAt(t,e){return t!=null&&e in Object(t)}kpe.exports=tAt});var D_=_((p3t,Fpe)=>{var rAt=Hd(),nAt=NI(),iAt=Hl(),sAt=MI(),oAt=YP(),aAt=oC();function lAt(t,e,r){e=rAt(e,t);for(var o=-1,a=e.length,n=!1;++o<a;){var u=aAt(e[o]);if(!(n=t!=null&&r(t,u)))break;t=t[u]}return n||++o!=a?n:(a=t==null?0:t.length,!!a&&oAt(a)&&sAt(u,a)&&(iAt(t)||nAt(t)))}Fpe.exports=lAt});var Tpe=_((h3t,Rpe)=>{var cAt=Qpe(),uAt=D_();function AAt(t,e){return t!=null&&uAt(t,e,cAt)}Rpe.exports=AAt});var Lpe=_((g3t,Npe)=>{var fAt=xpe(),pAt=Tpe();function hAt(t,e){return fAt(t,e,function(r,o){return pAt(t,o)})}Npe.exports=hAt});var _pe=_((d3t,Upe)=>{var Ope=Ad(),gAt=NI(),dAt=Hl(),Mpe=Ope?Ope.isConcatSpreadable:void 0;function mAt(t){return dAt(t)||gAt(t)||!!(Mpe&&t&&t[Mpe])}Upe.exports=mAt});var qpe=_((m3t,jpe)=>{var yAt=qP(),EAt=_pe();function Hpe(t,e,r,o,a){var n=-1,u=t.length;for(r||(r=EAt),a||(a=[]);++n<u;){var A=t[n];e>0&&r(A)?e>1?Hpe(A,e-1,r,o,a):yAt(a,A):o||(a[a.length]=A)}return a}jpe.exports=Hpe});var Ype=_((y3t,Gpe)=>{var CAt=qpe();function wAt(t){var e=t==null?0:t.length;return e?CAt(t,1):[]}Gpe.exports=wAt});var P_=_((E3t,Wpe)=>{var IAt=Ype(),BAt=pL(),vAt=hL();function DAt(t){return vAt(BAt(t,void 0,IAt),t+\"\")}Wpe.exports=DAt});var S_=_((C3t,Kpe)=>{var PAt=Lpe(),SAt=P_(),bAt=SAt(function(t,e){return t==null?{}:PAt(t,e)});Kpe.exports=bAt});var $x,Vpe=Et(()=>{Yl();$x=class{constructor(e){this.resolver=e}supportsDescriptor(e,r){return this.resolver.supportsDescriptor(e,r)}supportsLocator(e,r){return this.resolver.supportsLocator(e,r)}shouldPersistResolution(e,r){return this.resolver.shouldPersistResolution(e,r)}bindDescriptor(e,r,o){return this.resolver.bindDescriptor(e,r,o)}getResolutionDependencies(e,r){return this.resolver.getResolutionDependencies(e,r)}async getCandidates(e,r,o){throw new Jt(20,`This package doesn't seem to be present in your lockfile; run \"yarn install\" to update the lockfile`)}async getSatisfying(e,r,o,a){throw new Jt(20,`This package doesn't seem to be present in your lockfile; run \"yarn install\" to update the lockfile`)}async resolve(e,r){throw new Jt(20,`This package doesn't seem to be present in your lockfile; run \"yarn install\" to update the lockfile`)}}});var Qi,b_=Et(()=>{Yl();Qi=class extends Xs{reportCacheHit(e){}reportCacheMiss(e){}startSectionSync(e,r){return r()}async startSectionPromise(e,r){return await r()}startTimerSync(e,r,o){return(typeof r==\"function\"?r:o)()}async startTimerPromise(e,r,o){return await(typeof r==\"function\"?r:o)()}reportSeparator(){}reportInfo(e,r){}reportWarning(e,r){}reportError(e,r){}reportProgress(e){return{...Promise.resolve().then(async()=>{for await(let{}of e);}),stop:()=>{}}}reportJson(e){}reportFold(e,r){}async finalize(){}}});var zpe,aC,x_=Et(()=>{Pt();zpe=$e(TS());uE();Id();ql();rh();xf();bo();aC=class{constructor(e,{project:r}){this.workspacesCwds=new Set;this.project=r,this.cwd=e}async setup(){this.manifest=await Ot.tryFind(this.cwd)??new Ot,this.relativeCwd=V.relative(this.project.cwd,this.cwd)||Bt.dot;let e=this.manifest.name?this.manifest.name:eA(null,`${this.computeCandidateName()}-${Js(this.relativeCwd).substring(0,6)}`);this.anchoredDescriptor=In(e,`${Xn.protocol}${this.relativeCwd}`),this.anchoredLocator=Qs(e,`${Xn.protocol}${this.relativeCwd}`);let r=this.manifest.workspaceDefinitions.map(({pattern:a})=>a);if(r.length===0)return;let o=await(0,zpe.default)(r,{cwd:ue.fromPortablePath(this.cwd),onlyDirectories:!0,ignore:[\"**/node_modules\",\"**/.git\",\"**/.yarn\"]});o.sort(),await o.reduce(async(a,n)=>{let u=V.resolve(this.cwd,ue.toPortablePath(n)),A=await oe.existsPromise(V.join(u,\"package.json\"));await a,A&&this.workspacesCwds.add(u)},Promise.resolve())}get anchoredPackage(){let e=this.project.storedPackages.get(this.anchoredLocator.locatorHash);if(!e)throw new Error(`Assertion failed: Expected workspace ${s1(this.project.configuration,this)} (${Mt(this.project.configuration,V.join(this.cwd,dr.manifest),yt.PATH)}) to have been resolved. Run \"yarn install\" to update the lockfile`);return e}accepts(e){let r=e.indexOf(\":\"),o=r!==-1?e.slice(0,r+1):null,a=r!==-1?e.slice(r+1):e;if(o===Xn.protocol&&V.normalize(a)===this.relativeCwd||o===Xn.protocol&&(a===\"*\"||a===\"^\"||a===\"~\"))return!0;let n=xa(a);return n?o===Xn.protocol?n.test(this.manifest.version??\"0.0.0\"):this.project.configuration.get(\"enableTransparentWorkspaces\")&&this.manifest.version!==null?n.test(this.manifest.version):!1:!1}computeCandidateName(){return this.cwd===this.project.cwd?\"root-workspace\":`${V.basename(this.cwd)}`||\"unnamed-workspace\"}getRecursiveWorkspaceDependencies({dependencies:e=Ot.hardDependencies}={}){let r=new Set,o=a=>{for(let n of e)for(let u of a.manifest[n].values()){let A=this.project.tryWorkspaceByDescriptor(u);A===null||r.has(A)||(r.add(A),o(A))}};return o(this),r}getRecursiveWorkspaceDependents({dependencies:e=Ot.hardDependencies}={}){let r=new Set,o=a=>{for(let n of this.project.workspaces)e.some(A=>[...n.manifest[A].values()].some(p=>{let h=this.project.tryWorkspaceByDescriptor(p);return h!==null&&r1(h.anchoredLocator,a.anchoredLocator)}))&&!r.has(n)&&(r.add(n),o(n))};return o(this),r}getRecursiveWorkspaceChildren(){let e=[];for(let r of this.workspacesCwds){let o=this.project.workspacesByCwd.get(r);o&&e.push(o,...o.getRecursiveWorkspaceChildren())}return e}async persistManifest(){let e={};this.manifest.exportTo(e);let r=V.join(this.cwd,Ot.fileName),o=`${JSON.stringify(e,null,this.manifest.indent)}\n`;await oe.changeFilePromise(r,o,{automaticNewlines:!0}),this.manifest.raw=e}}});function TAt({project:t,allDescriptors:e,allResolutions:r,allPackages:o,accessibleLocators:a=new Set,optionalBuilds:n=new Set,peerRequirements:u=new Map,peerWarnings:A=[],volatileDescriptors:p=new Set}){let h=new Map,C=[],I=new Map,v=new Map,x=new Map,E=new Map,R=new Map,L=new Map(t.workspaces.map(Ae=>{let ye=Ae.anchoredLocator.locatorHash,ae=o.get(ye);if(typeof ae>\"u\")throw new Error(\"Assertion failed: The workspace should have an associated package\");return[ye,ZI(ae)]})),U=()=>{let Ae=oe.mktempSync(),ye=V.join(Ae,\"stacktrace.log\"),ae=String(C.length+1).length,Ie=C.map((Fe,g)=>`${`${g+1}.`.padStart(ae,\" \")} ${ba(Fe)}\n`).join(\"\");throw oe.writeFileSync(ye,Ie),oe.detachTemp(Ae),new Jt(45,`Encountered a stack overflow when resolving peer dependencies; cf ${ue.fromPortablePath(ye)}`)},z=Ae=>{let ye=r.get(Ae.descriptorHash);if(typeof ye>\"u\")throw new Error(\"Assertion failed: The resolution should have been registered\");let ae=o.get(ye);if(!ae)throw new Error(\"Assertion failed: The package could not be found\");return ae},te=(Ae,ye,ae,{top:Ie,optional:Fe})=>{C.length>1e3&&U(),C.push(ye);let g=le(Ae,ye,ae,{top:Ie,optional:Fe});return C.pop(),g},le=(Ae,ye,ae,{top:Ie,optional:Fe})=>{if(a.has(ye.locatorHash))return;a.add(ye.locatorHash),Fe||n.delete(ye.locatorHash);let g=o.get(ye.locatorHash);if(!g)throw new Error(`Assertion failed: The package (${jr(t.configuration,ye)}) should have been registered`);let Ee=[],De=[],ce=[],ne=[],ee=[];for(let xe of Array.from(g.dependencies.values())){if(g.peerDependencies.has(xe.identHash)&&g.locatorHash!==Ie)continue;if(Pf(xe))throw new Error(\"Assertion failed: Virtual packages shouldn't be encountered when virtualizing a branch\");p.delete(xe.descriptorHash);let ht=Fe;if(!ht){let Re=g.dependenciesMeta.get(fn(xe));if(typeof Re<\"u\"){let ze=Re.get(null);typeof ze<\"u\"&&ze.optional&&(ht=!0)}}let H=r.get(xe.descriptorHash);if(!H)throw new Error(`Assertion failed: The resolution (${qn(t.configuration,xe)}) should have been registered`);let lt=L.get(H)||o.get(H);if(!lt)throw new Error(`Assertion failed: The package (${H}, resolved from ${qn(t.configuration,xe)}) should have been registered`);if(lt.peerDependencies.size===0){te(xe,lt,new Map,{top:Ie,optional:ht});continue}let Te,ke,be=new Set,_e;De.push(()=>{Te=nM(xe,ye.locatorHash),ke=iM(lt,ye.locatorHash),g.dependencies.delete(xe.identHash),g.dependencies.set(Te.identHash,Te),r.set(Te.descriptorHash,ke.locatorHash),e.set(Te.descriptorHash,Te),o.set(ke.locatorHash,ke),Ee.push([lt,Te,ke])}),ce.push(()=>{_e=new Map;for(let Re of ke.peerDependencies.values()){let ze=g.dependencies.get(Re.identHash);if(!ze&&t1(ye,Re)&&(Ae.identHash===ye.identHash?ze=Ae:(ze=In(ye,Ae.range),e.set(ze.descriptorHash,ze),r.set(ze.descriptorHash,ye.locatorHash),p.delete(ze.descriptorHash))),(!ze||ze.range===\"missing:\")&&ke.dependencies.has(Re.identHash)){ke.peerDependencies.delete(Re.identHash);continue}ze||(ze=In(Re,\"missing:\")),ke.dependencies.set(ze.identHash,ze),Pf(ze)&&gd(x,ze.descriptorHash).add(ke.locatorHash),I.set(ze.identHash,ze),ze.range===\"missing:\"&&be.add(ze.identHash),_e.set(Re.identHash,ae.get(Re.identHash)??ke.locatorHash)}ke.dependencies=new Map(ks(ke.dependencies,([Re,ze])=>fn(ze)))}),ne.push(()=>{if(!o.has(ke.locatorHash))return;let Re=h.get(lt.locatorHash);typeof Re==\"number\"&&Re>=2&&U();let ze=h.get(lt.locatorHash),He=typeof ze<\"u\"?ze+1:1;h.set(lt.locatorHash,He),te(Te,ke,_e,{top:Ie,optional:ht}),h.set(lt.locatorHash,He-1)}),ee.push(()=>{let Re=g.dependencies.get(xe.identHash);if(typeof Re>\"u\")throw new Error(\"Assertion failed: Expected the peer dependency to have been turned into a dependency\");let ze=r.get(Re.descriptorHash);if(typeof ze>\"u\")throw new Error(\"Assertion failed: Expected the descriptor to be registered\");if(gd(R,ze).add(ye.locatorHash),!!o.has(ke.locatorHash)){for(let He of ke.peerDependencies.values()){let b=_e.get(He.identHash);if(typeof b>\"u\")throw new Error(\"Assertion failed: Expected the peer dependency ident to be registered\");qy(Gy(E,b),fn(He)).push(ke.locatorHash)}for(let He of be)ke.dependencies.delete(He)}})}for(let xe of[...De,...ce])xe();let we;do{we=!0;for(let[xe,ht,H]of Ee){let lt=Gy(v,xe.locatorHash),Te=Js(...[...H.dependencies.values()].map(Re=>{let ze=Re.range!==\"missing:\"?r.get(Re.descriptorHash):\"missing:\";if(typeof ze>\"u\")throw new Error(`Assertion failed: Expected the resolution for ${qn(t.configuration,Re)} to have been registered`);return ze===Ie?`${ze} (top)`:ze}),ht.identHash),ke=lt.get(Te);if(typeof ke>\"u\"){lt.set(Te,ht);continue}if(ke===ht)continue;o.delete(H.locatorHash),e.delete(ht.descriptorHash),r.delete(ht.descriptorHash),a.delete(H.locatorHash);let be=x.get(ht.descriptorHash)||[],_e=[g.locatorHash,...be];x.delete(ht.descriptorHash);for(let Re of _e){let ze=o.get(Re);typeof ze>\"u\"||(ze.dependencies.get(ht.identHash).descriptorHash!==ke.descriptorHash&&(we=!1),ze.dependencies.set(ht.identHash,ke))}}}while(!we);for(let xe of[...ne,...ee])xe()};for(let Ae of t.workspaces){let ye=Ae.anchoredLocator;p.delete(Ae.anchoredDescriptor.descriptorHash),te(Ae.anchoredDescriptor,ye,new Map,{top:ye.locatorHash,optional:!1})}let he=new Map;for(let[Ae,ye]of R){let ae=o.get(Ae);if(typeof ae>\"u\")throw new Error(\"Assertion failed: Expected the root to be registered\");let Ie=E.get(Ae);if(!(typeof Ie>\"u\"))for(let Fe of ye){let g=o.get(Fe);if(!(typeof g>\"u\")&&!!t.tryWorkspaceByLocator(g))for(let[Ee,De]of Ie){let ce=zs(Ee);if(g.peerDependencies.has(ce.identHash))continue;let ne=`p${Js(Fe,Ee,Ae).slice(0,5)}`;u.set(ne,{subject:Fe,requested:ce,rootRequester:Ae,allRequesters:De});let ee=ae.dependencies.get(ce.identHash);if(typeof ee<\"u\"){let we=z(ee),xe=we.version??\"0.0.0\",ht=new Set;for(let lt of De){let Te=o.get(lt);if(typeof Te>\"u\")throw new Error(\"Assertion failed: Expected the link to be registered\");let ke=Te.peerDependencies.get(ce.identHash);if(typeof ke>\"u\")throw new Error(\"Assertion failed: Expected the ident to be registered\");ht.add(ke.range)}if(![...ht].every(lt=>{if(lt.startsWith(Xn.protocol)){if(!t.tryWorkspaceByLocator(we))return!1;lt=lt.slice(Xn.protocol.length),(lt===\"^\"||lt===\"~\")&&(lt=\"*\")}return bf(xe,lt)})){let lt=ol(he,we.locatorHash,()=>({type:2,requested:ce,subject:we,dependents:new Map,requesters:new Map,links:new Map,version:xe,hash:`p${we.locatorHash.slice(0,5)}`}));lt.dependents.set(g.locatorHash,g),lt.requesters.set(ae.locatorHash,ae);for(let Te of De)lt.links.set(Te,o.get(Te));A.push({type:1,subject:g,requested:ce,requester:ae,version:xe,hash:ne,requirementCount:De.length})}}else ae.peerDependenciesMeta.get(Ee)?.optional||A.push({type:0,subject:g,requested:ce,requester:ae,hash:ne})}}}A.push(...he.values())}function NAt(t,e){let r=BL(t.peerWarnings,\"type\"),o=r[2]?.map(n=>{let u=Array.from(n.links.values(),C=>{let I=t.storedPackages.get(C.locatorHash);if(typeof I>\"u\")throw new Error(\"Assertion failed: Expected the package to be registered\");let v=I.peerDependencies.get(n.requested.identHash);if(typeof v>\"u\")throw new Error(\"Assertion failed: Expected the ident to be registered\");return v.range}),A=n.links.size>1?\"and other dependencies request\":\"requests\",p=aM(u),h=p?aE(t.configuration,p):Mt(t.configuration,\"but they have non-overlapping ranges!\",\"redBright\");return`${cs(t.configuration,n.requested)} is listed by your project with version ${i1(t.configuration,n.version)}, which doesn't satisfy what ${cs(t.configuration,n.requesters.values().next().value)} (${Mt(t.configuration,n.hash,yt.CODE)}) ${A} (${h}).`})??[],a=r[0]?.map(n=>`${jr(t.configuration,n.subject)} doesn't provide ${cs(t.configuration,n.requested)} (${Mt(t.configuration,n.hash,yt.CODE)}), requested by ${cs(t.configuration,n.requester)}.`)??[];e.startSectionSync({reportFooter:()=>{e.reportWarning(86,`Some peer dependencies are incorrectly met; run ${Mt(t.configuration,\"yarn explain peer-requirements <hash>\",yt.CODE)} for details, where ${Mt(t.configuration,\"<hash>\",yt.CODE)} is the six-letter p-prefixed code.`)},skipIfEmpty:!0},()=>{for(let n of ks(o,u=>zy.default(u)))e.reportWarning(60,n);for(let n of ks(a,u=>zy.default(u)))e.reportWarning(2,n)})}var ek,tk,rk,Zpe,F_,Q_,R_,nk,xAt,kAt,Jpe,QAt,FAt,RAt,pl,k_,ik,Xpe,St,$pe=Et(()=>{Pt();Pt();Nl();qt();ek=Be(\"crypto\");w_();tk=$e(S_()),rk=$e(rd()),Zpe=$e(Jn()),F_=Be(\"util\"),Q_=$e(Be(\"v8\")),R_=$e(Be(\"zlib\"));f_();v1();p_();h_();uE();fM();Yl();Vpe();N1();b_();Id();x_();KS();ql();rh();jl();Pb();DU();xf();bo();nk=Ky(process.env.YARN_LOCKFILE_VERSION_OVERRIDE??8),xAt=3,kAt=/ *, */g,Jpe=/\\/$/,QAt=32,FAt=(0,F_.promisify)(R_.default.gzip),RAt=(0,F_.promisify)(R_.default.gunzip),pl=(r=>(r.UpdateLockfile=\"update-lockfile\",r.SkipBuild=\"skip-build\",r))(pl||{}),k_={restoreLinkersCustomData:[\"linkersCustomData\"],restoreResolutions:[\"accessibleLocators\",\"conditionalLocators\",\"disabledLocators\",\"optionalBuilds\",\"storedDescriptors\",\"storedResolutions\",\"storedPackages\",\"lockFileChecksum\"],restoreBuildState:[\"skippedBuilds\",\"storedBuildState\"]},ik=(o=>(o[o.NotProvided=0]=\"NotProvided\",o[o.NotCompatible=1]=\"NotCompatible\",o[o.NotCompatibleAggregate=2]=\"NotCompatibleAggregate\",o))(ik||{}),Xpe=t=>Js(`${xAt}`,t),St=class{constructor(e,{configuration:r}){this.resolutionAliases=new Map;this.workspaces=[];this.workspacesByCwd=new Map;this.workspacesByIdent=new Map;this.storedResolutions=new Map;this.storedDescriptors=new Map;this.storedPackages=new Map;this.storedChecksums=new Map;this.storedBuildState=new Map;this.accessibleLocators=new Set;this.conditionalLocators=new Set;this.disabledLocators=new Set;this.originalPackages=new Map;this.optionalBuilds=new Set;this.skippedBuilds=new Set;this.lockfileLastVersion=null;this.lockfileNeedsRefresh=!1;this.peerRequirements=new Map;this.peerWarnings=[];this.linkersCustomData=new Map;this.lockFileChecksum=null;this.installStateChecksum=null;this.configuration=r,this.cwd=e}static async find(e,r){if(!e.projectCwd)throw new it(`No project found in ${r}`);let o=e.projectCwd,a=r,n=null;for(;n!==e.projectCwd;){if(n=a,oe.existsSync(V.join(n,dr.manifest))){o=n;break}a=V.dirname(n)}let u=new St(e.projectCwd,{configuration:e});Ke.telemetry?.reportProject(u.cwd),await u.setupResolutions(),await u.setupWorkspaces(),Ke.telemetry?.reportWorkspaceCount(u.workspaces.length),Ke.telemetry?.reportDependencyCount(u.workspaces.reduce((E,R)=>E+R.manifest.dependencies.size+R.manifest.devDependencies.size,0));let A=u.tryWorkspaceByCwd(o);if(A)return{project:u,workspace:A,locator:A.anchoredLocator};let p=await u.findLocatorForLocation(`${o}/`,{strict:!0});if(p)return{project:u,locator:p,workspace:null};let h=Mt(e,u.cwd,yt.PATH),C=Mt(e,V.relative(u.cwd,o),yt.PATH),I=`- If ${h} isn't intended to be a project, remove any yarn.lock and/or package.json file there.`,v=`- If ${h} is intended to be a project, it might be that you forgot to list ${C} in its workspace configuration.`,x=`- Finally, if ${h} is fine and you intend ${C} to be treated as a completely separate project (not even a workspace), create an empty yarn.lock file in it.`;throw new it(`The nearest package directory (${Mt(e,o,yt.PATH)}) doesn't seem to be part of the project declared in ${Mt(e,u.cwd,yt.PATH)}.\n\n${[I,v,x].join(`\n`)}`)}async setupResolutions(){this.storedResolutions=new Map,this.storedDescriptors=new Map,this.storedPackages=new Map,this.lockFileChecksum=null;let e=V.join(this.cwd,dr.lockfile),r=this.configuration.get(\"defaultLanguageName\");if(oe.existsSync(e)){let o=await oe.readFilePromise(e,\"utf8\");this.lockFileChecksum=Xpe(o);let a=Ki(o);if(a.__metadata){let n=a.__metadata.version,u=a.__metadata.cacheKey;this.lockfileLastVersion=n,this.lockfileNeedsRefresh=n<nk;for(let A of Object.keys(a)){if(A===\"__metadata\")continue;let p=a[A];if(typeof p.resolution>\"u\")throw new Error(`Assertion failed: Expected the lockfile entry to have a resolution field (${A})`);let h=Sf(p.resolution,!0),C=new Ot;C.load(p,{yamlCompatibilityMode:!0});let I=C.version,v=C.languageName||r,x=p.linkType.toUpperCase(),E=p.conditions??null,R=C.dependencies,L=C.peerDependencies,U=C.dependenciesMeta,z=C.peerDependenciesMeta,te=C.bin;if(p.checksum!=null){let he=typeof u<\"u\"&&!p.checksum.includes(\"/\")?`${u}/${p.checksum}`:p.checksum;this.storedChecksums.set(h.locatorHash,he)}let le={...h,version:I,languageName:v,linkType:x,conditions:E,dependencies:R,peerDependencies:L,dependenciesMeta:U,peerDependenciesMeta:z,bin:te};this.originalPackages.set(le.locatorHash,le);for(let he of A.split(kAt)){let Ae=nh(he);n<=6&&(Ae=this.configuration.normalizeDependency(Ae),Ae=In(Ae,Ae.range.replace(/^patch:[^@]+@(?!npm(:|%3A))/,\"$1npm%3A\"))),this.storedDescriptors.set(Ae.descriptorHash,Ae),this.storedResolutions.set(Ae.descriptorHash,h.locatorHash)}}}else o.includes(\"yarn lockfile v1\")&&(this.lockfileLastVersion=-1)}}async setupWorkspaces(){this.workspaces=[],this.workspacesByCwd=new Map,this.workspacesByIdent=new Map;let e=new Set,r=(0,rk.default)(4),o=async(a,n)=>{if(e.has(n))return a;e.add(n);let u=new aC(n,{project:this});await r(()=>u.setup());let A=a.then(()=>{this.addWorkspace(u)});return Array.from(u.workspacesCwds).reduce(o,A)};await o(Promise.resolve(),this.cwd)}addWorkspace(e){let r=this.workspacesByIdent.get(e.anchoredLocator.identHash);if(typeof r<\"u\")throw new Error(`Duplicate workspace name ${cs(this.configuration,e.anchoredLocator)}: ${ue.fromPortablePath(e.cwd)} conflicts with ${ue.fromPortablePath(r.cwd)}`);this.workspaces.push(e),this.workspacesByCwd.set(e.cwd,e),this.workspacesByIdent.set(e.anchoredLocator.identHash,e)}get topLevelWorkspace(){return this.getWorkspaceByCwd(this.cwd)}tryWorkspaceByCwd(e){V.isAbsolute(e)||(e=V.resolve(this.cwd,e)),e=V.normalize(e).replace(/\\/+$/,\"\");let r=this.workspacesByCwd.get(e);return r||null}getWorkspaceByCwd(e){let r=this.tryWorkspaceByCwd(e);if(!r)throw new Error(`Workspace not found (${e})`);return r}tryWorkspaceByFilePath(e){let r=null;for(let o of this.workspaces)V.relative(o.cwd,e).startsWith(\"../\")||r&&r.cwd.length>=o.cwd.length||(r=o);return r||null}getWorkspaceByFilePath(e){let r=this.tryWorkspaceByFilePath(e);if(!r)throw new Error(`Workspace not found (${e})`);return r}tryWorkspaceByIdent(e){let r=this.workspacesByIdent.get(e.identHash);return typeof r>\"u\"?null:r}getWorkspaceByIdent(e){let r=this.tryWorkspaceByIdent(e);if(!r)throw new Error(`Workspace not found (${cs(this.configuration,e)})`);return r}tryWorkspaceByDescriptor(e){if(e.range.startsWith(Xn.protocol)){let o=e.range.slice(Xn.protocol.length);if(o!==\"^\"&&o!==\"~\"&&o!==\"*\"&&!xa(o))return this.tryWorkspaceByCwd(o)}let r=this.tryWorkspaceByIdent(e);return r===null||(Pf(e)&&(e=$I(e)),!r.accepts(e.range))?null:r}getWorkspaceByDescriptor(e){let r=this.tryWorkspaceByDescriptor(e);if(r===null)throw new Error(`Workspace not found (${qn(this.configuration,e)})`);return r}tryWorkspaceByLocator(e){let r=this.tryWorkspaceByIdent(e);return r===null||(Hc(e)&&(e=e1(e)),r.anchoredLocator.locatorHash!==e.locatorHash)?null:r}getWorkspaceByLocator(e){let r=this.tryWorkspaceByLocator(e);if(!r)throw new Error(`Workspace not found (${jr(this.configuration,e)})`);return r}deleteDescriptor(e){this.storedResolutions.delete(e),this.storedDescriptors.delete(e)}deleteLocator(e){this.originalPackages.delete(e),this.storedPackages.delete(e),this.accessibleLocators.delete(e)}forgetResolution(e){if(\"descriptorHash\"in e){let r=this.storedResolutions.get(e.descriptorHash);this.deleteDescriptor(e.descriptorHash);let o=new Set(this.storedResolutions.values());typeof r<\"u\"&&!o.has(r)&&this.deleteLocator(r)}if(\"locatorHash\"in e){this.deleteLocator(e.locatorHash);for(let[r,o]of this.storedResolutions)o===e.locatorHash&&this.deleteDescriptor(r)}}forgetTransientResolutions(){let e=this.configuration.makeResolver(),r=new Map;for(let[o,a]of this.storedResolutions.entries()){let n=r.get(a);n||r.set(a,n=new Set),n.add(o)}for(let o of this.originalPackages.values()){let a;try{a=e.shouldPersistResolution(o,{project:this,resolver:e})}catch{a=!1}if(!a){this.deleteLocator(o.locatorHash);let n=r.get(o.locatorHash);if(n){r.delete(o.locatorHash);for(let u of n)this.deleteDescriptor(u)}}}}forgetVirtualResolutions(){for(let e of this.storedPackages.values())for(let[r,o]of e.dependencies)Pf(o)&&e.dependencies.set(r,$I(o))}getDependencyMeta(e,r){let o={},n=this.topLevelWorkspace.manifest.dependenciesMeta.get(fn(e));if(!n)return o;let u=n.get(null);if(u&&Object.assign(o,u),r===null||!Zpe.default.valid(r))return o;for(let[A,p]of n)A!==null&&A===r&&Object.assign(o,p);return o}async findLocatorForLocation(e,{strict:r=!1}={}){let o=new Qi,a=this.configuration.getLinkers(),n={project:this,report:o};for(let u of a){let A=await u.findPackageLocator(e,n);if(A){if(r&&(await u.findPackageLocation(A,n)).replace(Jpe,\"\")!==e.replace(Jpe,\"\"))continue;return A}}return null}async loadUserConfig(){let e=V.join(this.cwd,\"yarn.config.cjs\");return await oe.existsPromise(e)?zp(e):null}async preparePackage(e,{resolver:r,resolveOptions:o}){let a=await this.configuration.getPackageExtensions(),n=this.configuration.normalizePackage(e,{packageExtensions:a});for(let[u,A]of n.dependencies){let p=await this.configuration.reduceHook(C=>C.reduceDependency,A,this,n,A,{resolver:r,resolveOptions:o});if(!t1(A,p))throw new Error(\"Assertion failed: The descriptor ident cannot be changed through aliases\");let h=r.bindDescriptor(p,n,o);n.dependencies.set(u,h)}return n}async resolveEverything(e){if(!this.workspacesByCwd||!this.workspacesByIdent)throw new Error(\"Workspaces must have been setup before calling this function\");this.forgetVirtualResolutions();let r=new Map(this.originalPackages),o=[];e.lockfileOnly||this.forgetTransientResolutions();let a=e.resolver||this.configuration.makeResolver(),n=new iC(a);await n.setup(this,{report:e.report});let u=e.lockfileOnly?[new $x(a)]:[n,a],A=new Bd([new sC(a),...u]),p=new Bd([...u]),h=this.configuration.makeFetcher(),C=e.lockfileOnly?{project:this,report:e.report,resolver:A}:{project:this,report:e.report,resolver:A,fetchOptions:{project:this,cache:e.cache,checksums:this.storedChecksums,report:e.report,fetcher:h,cacheOptions:{mirrorWriteOnly:!0}}},I=new Map,v=new Map,x=new Map,E=new Map,R=new Map,L=new Map,U=this.topLevelWorkspace.anchoredLocator,z=new Set,te=[],le=_4(),he=this.configuration.getSupportedArchitectures();await e.report.startProgressPromise(Xs.progressViaTitle(),async ce=>{let ne=async H=>{let lt=await Yy(async()=>await A.resolve(H,C),_e=>`${jr(this.configuration,H)}: ${_e}`);if(!r1(H,lt))throw new Error(`Assertion failed: The locator cannot be changed by the resolver (went from ${jr(this.configuration,H)} to ${jr(this.configuration,lt)})`);E.set(lt.locatorHash,lt),!r.delete(lt.locatorHash)&&!this.tryWorkspaceByLocator(lt)&&o.push(lt);let ke=await this.preparePackage(lt,{resolver:A,resolveOptions:C}),be=Uc([...ke.dependencies.values()].map(_e=>ht(_e)));return te.push(be),be.catch(()=>{}),v.set(ke.locatorHash,ke),ke},ee=async H=>{let lt=R.get(H.locatorHash);if(typeof lt<\"u\")return lt;let Te=Promise.resolve().then(()=>ne(H));return R.set(H.locatorHash,Te),Te},we=async(H,lt)=>{let Te=await ht(lt);return I.set(H.descriptorHash,H),x.set(H.descriptorHash,Te.locatorHash),Te},xe=async H=>{ce.setTitle(qn(this.configuration,H));let lt=this.resolutionAliases.get(H.descriptorHash);if(typeof lt<\"u\")return we(H,this.storedDescriptors.get(lt));let Te=A.getResolutionDependencies(H,C),ke=Object.fromEntries(await Uc(Object.entries(Te).map(async([Re,ze])=>{let He=A.bindDescriptor(ze,U,C),b=await ht(He);return z.add(b.locatorHash),[Re,b]}))),_e=(await Yy(async()=>await A.getCandidates(H,ke,C),Re=>`${qn(this.configuration,H)}: ${Re}`))[0];if(typeof _e>\"u\")throw new Jt(82,`${qn(this.configuration,H)}: No candidates found`);if(e.checkResolutions){let{locators:Re}=await p.getSatisfying(H,ke,[_e],{...C,resolver:p});if(!Re.find(ze=>ze.locatorHash===_e.locatorHash))throw new Jt(78,`Invalid resolution ${JI(this.configuration,H,_e)}`)}return I.set(H.descriptorHash,H),x.set(H.descriptorHash,_e.locatorHash),ee(_e)},ht=H=>{let lt=L.get(H.descriptorHash);if(typeof lt<\"u\")return lt;I.set(H.descriptorHash,H);let Te=Promise.resolve().then(()=>xe(H));return L.set(H.descriptorHash,Te),Te};for(let H of this.workspaces){let lt=H.anchoredDescriptor;te.push(ht(lt))}for(;te.length>0;){let H=[...te];te.length=0,await Uc(H)}});let Ae=sl(r.values(),ce=>this.tryWorkspaceByLocator(ce)?sl.skip:ce);if(o.length>0||Ae.length>0){let ce=new Set(this.workspaces.flatMap(H=>{let lt=v.get(H.anchoredLocator.locatorHash);if(!lt)throw new Error(\"Assertion failed: The workspace should have been resolved\");return Array.from(lt.dependencies.values(),Te=>{let ke=x.get(Te.descriptorHash);if(!ke)throw new Error(\"Assertion failed: The resolution should have been registered\");return ke})})),ne=H=>ce.has(H.locatorHash)?\"0\":\"1\",ee=H=>ba(H),we=ks(o,[ne,ee]),xe=ks(Ae,[ne,ee]),ht=e.report.getRecommendedLength();we.length>0&&e.report.reportInfo(85,`${Mt(this.configuration,\"+\",yt.ADDED)} ${cS(this.configuration,we,ht)}`),xe.length>0&&e.report.reportInfo(85,`${Mt(this.configuration,\"-\",yt.REMOVED)} ${cS(this.configuration,xe,ht)}`)}let ye=new Set(this.resolutionAliases.values()),ae=new Set(v.keys()),Ie=new Set,Fe=new Map,g=[];TAt({project:this,accessibleLocators:Ie,volatileDescriptors:ye,optionalBuilds:ae,peerRequirements:Fe,peerWarnings:g,allDescriptors:I,allResolutions:x,allPackages:v});for(let ce of z)ae.delete(ce);for(let ce of ye)I.delete(ce),x.delete(ce);let Ee=new Set,De=new Set;for(let ce of v.values())ce.conditions!=null&&(!ae.has(ce.locatorHash)||(qS(ce,he)||(qS(ce,le)&&e.report.reportWarningOnce(77,`${jr(this.configuration,ce)}: Your current architecture (${process.platform}-${process.arch}) is supported by this package, but is missing from the ${Mt(this.configuration,\"supportedArchitectures\",yt.SETTING)} setting`),De.add(ce.locatorHash)),Ee.add(ce.locatorHash)));this.storedResolutions=x,this.storedDescriptors=I,this.storedPackages=v,this.accessibleLocators=Ie,this.conditionalLocators=Ee,this.disabledLocators=De,this.originalPackages=E,this.optionalBuilds=ae,this.peerRequirements=Fe,this.peerWarnings=g}async fetchEverything({cache:e,report:r,fetcher:o,mode:a,persistProject:n=!0}){let u={mockedPackages:this.disabledLocators,unstablePackages:this.conditionalLocators},A=o||this.configuration.makeFetcher(),p={checksums:this.storedChecksums,project:this,cache:e,fetcher:A,report:r,cacheOptions:u},h=Array.from(new Set(ks(this.storedResolutions.values(),[E=>{let R=this.storedPackages.get(E);if(!R)throw new Error(\"Assertion failed: The locator should have been registered\");return ba(R)}])));a===\"update-lockfile\"&&(h=h.filter(E=>!this.storedChecksums.has(E)));let C=!1,I=Xs.progressViaCounter(h.length);await r.reportProgress(I);let v=(0,rk.default)(QAt);if(await Uc(h.map(E=>v(async()=>{let R=this.storedPackages.get(E);if(!R)throw new Error(\"Assertion failed: The locator should have been registered\");if(Hc(R))return;let L;try{L=await A.fetch(R,p)}catch(U){U.message=`${jr(this.configuration,R)}: ${U.message}`,r.reportExceptionOnce(U),C=U;return}L.checksum!=null?this.storedChecksums.set(R.locatorHash,L.checksum):this.storedChecksums.delete(R.locatorHash),L.releaseFs&&L.releaseFs()}).finally(()=>{I.tick()}))),C)throw C;let x=n&&a!==\"update-lockfile\"?await this.cacheCleanup({cache:e,report:r}):null;if(r.cacheMisses.size>0||x){let R=(await Promise.all([...r.cacheMisses].map(async Ae=>{let ye=this.storedPackages.get(Ae),ae=this.storedChecksums.get(Ae)??null,Ie=e.getLocatorPath(ye,ae);return(await oe.statPromise(Ie)).size}))).reduce((Ae,ye)=>Ae+ye,0)-(x?.size??0),L=r.cacheMisses.size,U=x?.count??0,z=`${nS(L,{zero:\"No new packages\",one:\"A package was\",more:`${Mt(this.configuration,L,yt.NUMBER)} packages were`})} added to the project`,te=`${nS(U,{zero:\"none were\",one:\"one was\",more:`${Mt(this.configuration,U,yt.NUMBER)} were`})} removed`,le=R!==0?` (${Mt(this.configuration,R,yt.SIZE_DIFF)})`:\"\",he=U>0?L>0?`${z}, and ${te}${le}.`:`${z}, but ${te}${le}.`:`${z}${le}.`;r.reportInfo(13,he)}}async linkEverything({cache:e,report:r,fetcher:o,mode:a}){let n={mockedPackages:this.disabledLocators,unstablePackages:this.conditionalLocators,skipIntegrityCheck:!0},u=o||this.configuration.makeFetcher(),A={checksums:this.storedChecksums,project:this,cache:e,fetcher:u,report:r,cacheOptions:n},p=this.configuration.getLinkers(),h={project:this,report:r},C=new Map(p.map(ce=>{let ne=ce.makeInstaller(h),ee=ce.getCustomDataKey(),we=this.linkersCustomData.get(ee);return typeof we<\"u\"&&ne.attachCustomData(we),[ce,ne]})),I=new Map,v=new Map,x=new Map,E=new Map(await Uc([...this.accessibleLocators].map(async ce=>{let ne=this.storedPackages.get(ce);if(!ne)throw new Error(\"Assertion failed: The locator should have been registered\");return[ce,await u.fetch(ne,A)]}))),R=[],L=new Set,U=[];for(let ce of this.accessibleLocators){let ne=this.storedPackages.get(ce);if(typeof ne>\"u\")throw new Error(\"Assertion failed: The locator should have been registered\");let ee=E.get(ne.locatorHash);if(typeof ee>\"u\")throw new Error(\"Assertion failed: The fetch result should have been registered\");let we=[],xe=H=>{we.push(H)},ht=this.tryWorkspaceByLocator(ne);if(ht!==null){let H=[],{scripts:lt}=ht.manifest;for(let ke of[\"preinstall\",\"install\",\"postinstall\"])lt.has(ke)&&H.push({type:0,script:ke});try{for(let[ke,be]of C)if(ke.supportsPackage(ne,h)&&(await be.installPackage(ne,ee,{holdFetchResult:xe})).buildRequest!==null)throw new Error(\"Assertion failed: Linkers can't return build directives for workspaces; this responsibility befalls to the Yarn core\")}finally{we.length===0?ee.releaseFs?.():R.push(Uc(we).catch(()=>{}).then(()=>{ee.releaseFs?.()}))}let Te=V.join(ee.packageFs.getRealPath(),ee.prefixPath);v.set(ne.locatorHash,Te),!Hc(ne)&&H.length>0&&x.set(ne.locatorHash,{buildDirectives:H,buildLocations:[Te]})}else{let H=p.find(ke=>ke.supportsPackage(ne,h));if(!H)throw new Jt(12,`${jr(this.configuration,ne)} isn't supported by any available linker`);let lt=C.get(H);if(!lt)throw new Error(\"Assertion failed: The installer should have been registered\");let Te;try{Te=await lt.installPackage(ne,ee,{holdFetchResult:xe})}finally{we.length===0?ee.releaseFs?.():R.push(Uc(we).then(()=>{}).then(()=>{ee.releaseFs?.()}))}I.set(ne.locatorHash,H),v.set(ne.locatorHash,Te.packageLocation),Te.buildRequest&&Te.packageLocation&&(Te.buildRequest.skipped?(L.add(ne.locatorHash),this.skippedBuilds.has(ne.locatorHash)||U.push([ne,Te.buildRequest.explain])):x.set(ne.locatorHash,{buildDirectives:Te.buildRequest.directives,buildLocations:[Te.packageLocation]}))}}let z=new Map;for(let ce of this.accessibleLocators){let ne=this.storedPackages.get(ce);if(!ne)throw new Error(\"Assertion failed: The locator should have been registered\");let ee=this.tryWorkspaceByLocator(ne)!==null,we=async(xe,ht)=>{let H=v.get(ne.locatorHash);if(typeof H>\"u\")throw new Error(`Assertion failed: The package (${jr(this.configuration,ne)}) should have been registered`);let lt=[];for(let Te of ne.dependencies.values()){let ke=this.storedResolutions.get(Te.descriptorHash);if(typeof ke>\"u\")throw new Error(`Assertion failed: The resolution (${qn(this.configuration,Te)}, from ${jr(this.configuration,ne)})should have been registered`);let be=this.storedPackages.get(ke);if(typeof be>\"u\")throw new Error(`Assertion failed: The package (${ke}, resolved from ${qn(this.configuration,Te)}) should have been registered`);let _e=this.tryWorkspaceByLocator(be)===null?I.get(ke):null;if(typeof _e>\"u\")throw new Error(`Assertion failed: The package (${ke}, resolved from ${qn(this.configuration,Te)}) should have been registered`);_e===xe||_e===null?v.get(be.locatorHash)!==null&&lt.push([Te,be]):!ee&&H!==null&&qy(z,ke).push(H)}H!==null&&await ht.attachInternalDependencies(ne,lt)};if(ee)for(let[xe,ht]of C)xe.supportsPackage(ne,h)&&await we(xe,ht);else{let xe=I.get(ne.locatorHash);if(!xe)throw new Error(\"Assertion failed: The linker should have been found\");let ht=C.get(xe);if(!ht)throw new Error(\"Assertion failed: The installer should have been registered\");await we(xe,ht)}}for(let[ce,ne]of z){let ee=this.storedPackages.get(ce);if(!ee)throw new Error(\"Assertion failed: The package should have been registered\");let we=I.get(ee.locatorHash);if(!we)throw new Error(\"Assertion failed: The linker should have been found\");let xe=C.get(we);if(!xe)throw new Error(\"Assertion failed: The installer should have been registered\");await xe.attachExternalDependents(ee,ne)}let te=new Map;for(let[ce,ne]of C){let ee=await ne.finalizeInstall();for(let we of ee?.records??[])we.buildRequest.skipped?(L.add(we.locator.locatorHash),this.skippedBuilds.has(we.locator.locatorHash)||U.push([we.locator,we.buildRequest.explain])):x.set(we.locator.locatorHash,{buildDirectives:we.buildRequest.directives,buildLocations:we.buildLocations});typeof ee?.customData<\"u\"&&te.set(ce.getCustomDataKey(),ee.customData)}if(this.linkersCustomData=te,await Uc(R),a===\"skip-build\")return;for(let[,ce]of ks(U,([ne])=>ba(ne)))ce(r);let le=new Set(this.storedPackages.keys()),he=new Set(x.keys());for(let ce of he)le.delete(ce);let Ae=(0,ek.createHash)(\"sha512\");Ae.update(process.versions.node),await this.configuration.triggerHook(ce=>ce.globalHashGeneration,this,ce=>{Ae.update(\"\\0\"),Ae.update(ce)});let ye=Ae.digest(\"hex\"),ae=new Map,Ie=ce=>{let ne=ae.get(ce.locatorHash);if(typeof ne<\"u\")return ne;let ee=this.storedPackages.get(ce.locatorHash);if(typeof ee>\"u\")throw new Error(\"Assertion failed: The package should have been registered\");let we=(0,ek.createHash)(\"sha512\");we.update(ce.locatorHash),ae.set(ce.locatorHash,\"<recursive>\");for(let xe of ee.dependencies.values()){let ht=this.storedResolutions.get(xe.descriptorHash);if(typeof ht>\"u\")throw new Error(`Assertion failed: The resolution (${qn(this.configuration,xe)}) should have been registered`);let H=this.storedPackages.get(ht);if(typeof H>\"u\")throw new Error(\"Assertion failed: The package should have been registered\");we.update(Ie(H))}return ne=we.digest(\"hex\"),ae.set(ce.locatorHash,ne),ne},Fe=(ce,ne)=>{let ee=(0,ek.createHash)(\"sha512\");ee.update(ye),ee.update(Ie(ce));for(let we of ne)ee.update(we);return ee.digest(\"hex\")},g=new Map,Ee=!1,De=ce=>{let ne=new Set([ce.locatorHash]);for(let ee of ne){let we=this.storedPackages.get(ee);if(!we)throw new Error(\"Assertion failed: The package should have been registered\");for(let xe of we.dependencies.values()){let ht=this.storedResolutions.get(xe.descriptorHash);if(!ht)throw new Error(`Assertion failed: The resolution (${qn(this.configuration,xe)}) should have been registered`);if(ht!==ce.locatorHash&&he.has(ht))return!1;let H=this.storedPackages.get(ht);if(!H)throw new Error(\"Assertion failed: The package should have been registered\");let lt=this.tryWorkspaceByLocator(H);if(lt){if(lt.anchoredLocator.locatorHash!==ce.locatorHash&&he.has(lt.anchoredLocator.locatorHash))return!1;ne.add(lt.anchoredLocator.locatorHash)}ne.add(ht)}}return!0};for(;he.size>0;){let ce=he.size,ne=[];for(let ee of he){let we=this.storedPackages.get(ee);if(!we)throw new Error(\"Assertion failed: The package should have been registered\");if(!De(we))continue;let xe=x.get(we.locatorHash);if(!xe)throw new Error(\"Assertion failed: The build directive should have been registered\");let ht=Fe(we,xe.buildLocations);if(this.storedBuildState.get(we.locatorHash)===ht){g.set(we.locatorHash,ht),he.delete(ee);continue}Ee||(await this.persistInstallStateFile(),Ee=!0),this.storedBuildState.has(we.locatorHash)?r.reportInfo(8,`${jr(this.configuration,we)} must be rebuilt because its dependency tree changed`):r.reportInfo(7,`${jr(this.configuration,we)} must be built because it never has been before or the last one failed`);let H=xe.buildLocations.map(async lt=>{if(!V.isAbsolute(lt))throw new Error(`Assertion failed: Expected the build location to be absolute (not ${lt})`);for(let Te of xe.buildDirectives){let ke=`# This file contains the result of Yarn building a package (${ba(we)})\n`;switch(Te.type){case 0:ke+=`# Script name: ${Te.script}\n`;break;case 1:ke+=`# Script code: ${Te.script}\n`;break}let be=null;if(!await oe.mktempPromise(async Re=>{let ze=V.join(Re,\"build.log\"),{stdout:He,stderr:b}=this.configuration.getSubprocessStreams(ze,{header:ke,prefix:jr(this.configuration,we),report:r}),w;try{switch(Te.type){case 0:w=await Vb(we,Te.script,[],{cwd:lt,project:this,stdin:be,stdout:He,stderr:b});break;case 1:w=await wU(we,Te.script,[],{cwd:lt,project:this,stdin:be,stdout:He,stderr:b});break}}catch(F){b.write(F.stack),w=1}if(He.end(),b.end(),w===0)return!0;oe.detachTemp(Re);let S=`${jr(this.configuration,we)} couldn't be built successfully (exit code ${Mt(this.configuration,w,yt.NUMBER)}, logs can be found here: ${Mt(this.configuration,ze,yt.PATH)})`,y=this.optionalBuilds.has(we.locatorHash);return y?r.reportInfo(9,S):r.reportError(9,S),Jce&&r.reportFold(ue.fromPortablePath(ze),oe.readFileSync(ze,\"utf8\")),y}))return!1}return!0});ne.push(...H,Promise.allSettled(H).then(lt=>{he.delete(ee),lt.every(Te=>Te.status===\"fulfilled\"&&Te.value===!0)&&g.set(we.locatorHash,ht)}))}if(await Uc(ne),ce===he.size){let ee=Array.from(he).map(we=>{let xe=this.storedPackages.get(we);if(!xe)throw new Error(\"Assertion failed: The package should have been registered\");return jr(this.configuration,xe)}).join(\", \");r.reportError(3,`Some packages have circular dependencies that make their build order unsatisfiable - as a result they won't be built (affected packages are: ${ee})`);break}}this.storedBuildState=g,this.skippedBuilds=L}async installWithNewReport(e,r){return(await Nt.start({configuration:this.configuration,json:e.json,stdout:e.stdout,forceSectionAlignment:!0,includeLogs:!e.json&&!e.quiet,includeVersion:!0},async a=>{await this.install({...r,report:a})})).exitCode()}async install(e){let r=this.configuration.get(\"nodeLinker\");Ke.telemetry?.reportInstall(r);let o=!1;if(await e.report.startTimerPromise(\"Project validation\",{skipIfEmpty:!0},async()=>{this.configuration.get(\"enableOfflineMode\")&&e.report.reportWarning(90,\"Offline work is enabled; Yarn won't fetch packages from the remote registry if it can avoid it\"),await this.configuration.triggerHook(C=>C.validateProject,this,{reportWarning:(C,I)=>{e.report.reportWarning(C,I)},reportError:(C,I)=>{e.report.reportError(C,I),o=!0}})}),o)return;let a=await this.configuration.getPackageExtensions();for(let C of a.values())for(let[,I]of C)for(let v of I)v.status=\"inactive\";let n=V.join(this.cwd,dr.lockfile),u=null;if(e.immutable)try{u=await oe.readFilePromise(n,\"utf8\")}catch(C){throw C.code===\"ENOENT\"?new Jt(28,\"The lockfile would have been created by this install, which is explicitly forbidden.\"):C}await e.report.startTimerPromise(\"Resolution step\",async()=>{await this.resolveEverything(e)}),await e.report.startTimerPromise(\"Post-resolution validation\",{skipIfEmpty:!0},async()=>{NAt(this,e.report);for(let[,C]of a)for(let[,I]of C)for(let v of I)if(v.userProvided){let x=Mt(this.configuration,v,yt.PACKAGE_EXTENSION);switch(v.status){case\"inactive\":e.report.reportWarning(68,`${x}: No matching package in the dependency tree; you may not need this rule anymore.`);break;case\"redundant\":e.report.reportWarning(69,`${x}: This rule seems redundant when applied on the original package; the extension may have been applied upstream.`);break}}if(u!==null){let C=Mg(u,this.generateLockfile());if(C!==u){let I=hpe(n,n,u,C,void 0,void 0,{maxEditLength:100});if(I){e.report.reportSeparator();for(let v of I.hunks){e.report.reportInfo(null,`@@ -${v.oldStart},${v.oldLines} +${v.newStart},${v.newLines} @@`);for(let x of v.lines)x.startsWith(\"+\")?e.report.reportError(28,Mt(this.configuration,x,yt.ADDED)):x.startsWith(\"-\")?e.report.reportError(28,Mt(this.configuration,x,yt.REMOVED)):e.report.reportInfo(null,Mt(this.configuration,x,\"grey\"))}e.report.reportSeparator()}throw new Jt(28,\"The lockfile would have been modified by this install, which is explicitly forbidden.\")}}});for(let C of a.values())for(let[,I]of C)for(let v of I)v.userProvided&&v.status===\"active\"&&Ke.telemetry?.reportPackageExtension(md(v,yt.PACKAGE_EXTENSION));await e.report.startTimerPromise(\"Fetch step\",async()=>{await this.fetchEverything(e)});let A=e.immutable?[...new Set(this.configuration.get(\"immutablePatterns\"))].sort():[],p=await Promise.all(A.map(async C=>OS(C,{cwd:this.cwd})));(typeof e.persistProject>\"u\"||e.persistProject)&&await this.persist(),await e.report.startTimerPromise(\"Link step\",async()=>{if(e.mode===\"update-lockfile\"){e.report.reportWarning(73,`Skipped due to ${Mt(this.configuration,\"mode=update-lockfile\",yt.CODE)}`);return}await this.linkEverything(e);let C=await Promise.all(A.map(async I=>OS(I,{cwd:this.cwd})));for(let I=0;I<A.length;++I)p[I]!==C[I]&&e.report.reportError(64,`The checksum for ${A[I]} has been modified by this install, which is explicitly forbidden.`)}),await this.persistInstallStateFile();let h=!1;await e.report.startTimerPromise(\"Post-install validation\",{skipIfEmpty:!0},async()=>{await this.configuration.triggerHook(C=>C.validateProjectAfterInstall,this,{reportWarning:(C,I)=>{e.report.reportWarning(C,I)},reportError:(C,I)=>{e.report.reportError(C,I),h=!0}})}),!h&&await this.configuration.triggerHook(C=>C.afterAllInstalled,this,e)}generateLockfile(){let e=new Map;for(let[n,u]of this.storedResolutions.entries()){let A=e.get(u);A||e.set(u,A=new Set),A.add(n)}let r={},{cacheKey:o}=Lr.getCacheKey(this.configuration);r.__metadata={version:nk,cacheKey:o};for(let[n,u]of e.entries()){let A=this.originalPackages.get(n);if(!A)continue;let p=[];for(let x of u){let E=this.storedDescriptors.get(x);if(!E)throw new Error(\"Assertion failed: The descriptor should have been registered\");p.push(E)}let h=p.map(x=>Sa(x)).sort().join(\", \"),C=new Ot;C.version=A.linkType===\"HARD\"?A.version:\"0.0.0-use.local\",C.languageName=A.languageName,C.dependencies=new Map(A.dependencies),C.peerDependencies=new Map(A.peerDependencies),C.dependenciesMeta=new Map(A.dependenciesMeta),C.peerDependenciesMeta=new Map(A.peerDependenciesMeta),C.bin=new Map(A.bin);let I,v=this.storedChecksums.get(A.locatorHash);if(typeof v<\"u\"){let x=v.indexOf(\"/\");if(x===-1)throw new Error(\"Assertion failed: Expected the checksum to reference its cache key\");let E=v.slice(0,x),R=v.slice(x+1);E===o?I=R:I=v}r[h]={...C.exportTo({},{compatibilityMode:!1}),linkType:A.linkType.toLowerCase(),resolution:ba(A),checksum:I,conditions:A.conditions||void 0}}return`${[`# This file is generated by running \"yarn install\" inside your project.\n`,`# Manual changes might be lost - proceed with caution!\n`].join(\"\")}\n`+Ba(r)}async persistLockfile(){let e=V.join(this.cwd,dr.lockfile),r=\"\";try{r=await oe.readFilePromise(e,\"utf8\")}catch{}let o=this.generateLockfile(),a=Mg(r,o);a!==r&&(await oe.writeFilePromise(e,a),this.lockFileChecksum=Xpe(a),this.lockfileNeedsRefresh=!1)}async persistInstallStateFile(){let e=[];for(let u of Object.values(k_))e.push(...u);let r=(0,tk.default)(this,e),o=Q_.default.serialize(r),a=Js(o);if(this.installStateChecksum===a)return;let n=this.configuration.get(\"installStatePath\");await oe.mkdirPromise(V.dirname(n),{recursive:!0}),await oe.writeFilePromise(n,await FAt(o)),this.installStateChecksum=a}async restoreInstallState({restoreLinkersCustomData:e=!0,restoreResolutions:r=!0,restoreBuildState:o=!0}={}){let a=this.configuration.get(\"installStatePath\"),n;try{let u=await RAt(await oe.readFilePromise(a));n=Q_.default.deserialize(u),this.installStateChecksum=Js(u)}catch{r&&await this.applyLightResolution();return}e&&typeof n.linkersCustomData<\"u\"&&(this.linkersCustomData=n.linkersCustomData),o&&Object.assign(this,(0,tk.default)(n,k_.restoreBuildState)),r&&(n.lockFileChecksum===this.lockFileChecksum?Object.assign(this,(0,tk.default)(n,k_.restoreResolutions)):await this.applyLightResolution())}async applyLightResolution(){await this.resolveEverything({lockfileOnly:!0,report:new Qi}),await this.persistInstallStateFile()}async persist(){let e=(0,rk.default)(4);await Promise.all([this.persistLockfile(),...this.workspaces.map(r=>e(()=>r.persistManifest()))])}async cacheCleanup({cache:e,report:r}){if(this.configuration.get(\"enableGlobalCache\"))return null;let o=new Set([\".gitignore\"]);if(!IM(e.cwd,this.cwd)||!await oe.existsPromise(e.cwd))return null;let a=[];for(let u of await oe.readdirPromise(e.cwd)){if(o.has(u))continue;let A=V.resolve(e.cwd,u);e.markedFiles.has(A)||(e.immutable?r.reportError(56,`${Mt(this.configuration,V.basename(A),\"magenta\")} appears to be unused and would be marked for deletion, but the cache is immutable`):a.push(oe.lstatPromise(A).then(async p=>(await oe.removePromise(A),p.size))))}if(a.length===0)return null;let n=await Promise.all(a);return{count:a.length,size:n.reduce((u,A)=>u+A,0)}}}});function LAt(t){let o=Math.floor(t.timeNow/864e5),a=t.updateInterval*864e5,n=t.state.lastUpdate??t.timeNow+a+Math.floor(a*t.randomInitialInterval),u=n+a,A=t.state.lastTips??o*864e5,p=A+864e5+8*36e5-t.timeZone,h=u<=t.timeNow,C=p<=t.timeNow,I=null;return(h||C||!t.state.lastUpdate||!t.state.lastTips)&&(I={},I.lastUpdate=h?t.timeNow:n,I.lastTips=A,I.blocks=h?{}:t.state.blocks,I.displayedTips=t.state.displayedTips),{nextState:I,triggerUpdate:h,triggerTips:C,nextTips:C?o*864e5:A}}var lC,ehe=Et(()=>{Pt();T1();rh();vb();jl();xf();lC=class{constructor(e,r){this.values=new Map;this.hits=new Map;this.enumerators=new Map;this.nextTips=0;this.displayedTips=[];this.shouldCommitTips=!1;this.configuration=e;let o=this.getRegistryPath();this.isNew=!oe.existsSync(o),this.shouldShowTips=!1,this.sendReport(r),this.startBuffer()}commitTips(){this.shouldShowTips&&(this.shouldCommitTips=!0)}selectTip(e){let r=new Set(this.displayedTips),o=A=>A&&tn?bf(tn,A):!1,a=e.map((A,p)=>p).filter(A=>e[A]&&o(e[A]?.selector));if(a.length===0)return null;let n=a.filter(A=>!r.has(A));if(n.length===0){let A=Math.floor(a.length*.2);this.displayedTips=A>0?this.displayedTips.slice(-A):[],n=a.filter(p=>!r.has(p))}let u=n[Math.floor(Math.random()*n.length)];return this.displayedTips.push(u),this.commitTips(),e[u]}reportVersion(e){this.reportValue(\"version\",e.replace(/-git\\..*/,\"-git\"))}reportCommandName(e){this.reportValue(\"commandName\",e||\"<none>\")}reportPluginName(e){this.reportValue(\"pluginName\",e)}reportProject(e){this.reportEnumerator(\"projectCount\",e)}reportInstall(e){this.reportHit(\"installCount\",e)}reportPackageExtension(e){this.reportValue(\"packageExtension\",e)}reportWorkspaceCount(e){this.reportValue(\"workspaceCount\",String(e))}reportDependencyCount(e){this.reportValue(\"dependencyCount\",String(e))}reportValue(e,r){gd(this.values,e).add(r)}reportEnumerator(e,r){gd(this.enumerators,e).add(Js(r))}reportHit(e,r=\"*\"){let o=Gy(this.hits,e),a=ol(o,r,()=>0);o.set(r,a+1)}getRegistryPath(){let e=this.configuration.get(\"globalFolder\");return V.join(e,\"telemetry.json\")}sendReport(e){let r=this.getRegistryPath(),o;try{o=oe.readJsonSync(r)}catch{o={}}let{nextState:a,triggerUpdate:n,triggerTips:u,nextTips:A}=LAt({state:o,timeNow:Date.now(),timeZone:new Date().getTimezoneOffset()*60*1e3,randomInitialInterval:Math.random(),updateInterval:this.configuration.get(\"telemetryInterval\")});if(this.nextTips=A,this.displayedTips=o.displayedTips??[],a!==null)try{oe.mkdirSync(V.dirname(r),{recursive:!0}),oe.writeJsonSync(r,a)}catch{return!1}if(u&&this.configuration.get(\"enableTips\")&&(this.shouldShowTips=!0),n){let p=o.blocks??{};if(Object.keys(p).length===0){let h=`https://browser-http-intake.logs.datadoghq.eu/v1/input/${e}?ddsource=yarn`,C=I=>U4(h,I,{configuration:this.configuration}).catch(()=>{});for(let[I,v]of Object.entries(o.blocks??{})){if(Object.keys(v).length===0)continue;let x=v;x.userId=I,x.reportType=\"primary\";for(let L of Object.keys(x.enumerators??{}))x.enumerators[L]=x.enumerators[L].length;C(x);let E=new Map,R=20;for(let[L,U]of Object.entries(x.values))U.length>0&&E.set(L,U.slice(0,R));for(;E.size>0;){let L={};L.userId=I,L.reportType=\"secondary\",L.metrics={};for(let[U,z]of E)L.metrics[U]=z.shift(),z.length===0&&E.delete(U);C(L)}}}}return!0}applyChanges(){let e=this.getRegistryPath(),r;try{r=oe.readJsonSync(e)}catch{r={}}let o=this.configuration.get(\"telemetryUserId\")??\"*\",a=r.blocks=r.blocks??{},n=a[o]=a[o]??{};for(let u of this.hits.keys()){let A=n.hits=n.hits??{},p=A[u]=A[u]??{};for(let[h,C]of this.hits.get(u))p[h]=(p[h]??0)+C}for(let u of[\"values\",\"enumerators\"])for(let A of this[u].keys()){let p=n[u]=n[u]??{};p[A]=[...new Set([...p[A]??[],...this[u].get(A)??[]])]}this.shouldCommitTips&&(r.lastTips=this.nextTips,r.displayedTips=this.displayedTips),oe.mkdirSync(V.dirname(e),{recursive:!0}),oe.writeJsonSync(e,r)}startBuffer(){process.on(\"exit\",()=>{try{this.applyChanges()}catch{}})}}});var i2={};Vt(i2,{BuildDirectiveType:()=>Jx,CACHE_CHECKPOINT:()=>A_,CACHE_VERSION:()=>zx,Cache:()=>Lr,Configuration:()=>Ke,DEFAULT_RC_FILENAME:()=>W4,FormatType:()=>Fle,InstallMode:()=>pl,LEGACY_PLUGINS:()=>I1,LOCKFILE_VERSION:()=>nk,LegacyMigrationResolver:()=>iC,LightReport:()=>AA,LinkType:()=>Vy,LockfileResolver:()=>sC,Manifest:()=>Ot,MessageName:()=>wr,MultiFetcher:()=>fE,PackageExtensionStatus:()=>DL,PackageExtensionType:()=>vL,PeerWarningType:()=>ik,Project:()=>St,Report:()=>Xs,ReportError:()=>Jt,SettingsType:()=>B1,StreamReport:()=>Nt,TAG_REGEXP:()=>kE,TelemetryManager:()=>lC,ThrowReport:()=>Qi,VirtualFetcher:()=>pE,WindowsLinkType:()=>Qb,Workspace:()=>aC,WorkspaceFetcher:()=>gE,WorkspaceResolver:()=>Xn,YarnVersion:()=>tn,execUtils:()=>Ur,folderUtils:()=>WS,formatUtils:()=>de,hashUtils:()=>wn,httpUtils:()=>rn,miscUtils:()=>je,nodeUtils:()=>zi,parseMessageName:()=>fP,reportOptionDeprecations:()=>TE,scriptUtils:()=>un,semverUtils:()=>kr,stringifyMessageName:()=>Wu,structUtils:()=>W,tgzUtils:()=>Xi,treeUtils:()=>$s});var Ye=Et(()=>{Sb();KS();ql();rh();vb();jl();Pb();DU();xf();bo();epe();ape();f_();v1();v1();cpe();p_();upe();h_();uE();pP();AM();$pe();Yl();N1();ehe();b_();pM();hM();Id();x_();T1();Bne()});var ohe=_((Y_t,o2)=>{\"use strict\";var MAt=process.env.TERM_PROGRAM===\"Hyper\",UAt=process.platform===\"win32\",nhe=process.platform===\"linux\",T_={ballotDisabled:\"\\u2612\",ballotOff:\"\\u2610\",ballotOn:\"\\u2611\",bullet:\"\\u2022\",bulletWhite:\"\\u25E6\",fullBlock:\"\\u2588\",heart:\"\\u2764\",identicalTo:\"\\u2261\",line:\"\\u2500\",mark:\"\\u203B\",middot:\"\\xB7\",minus:\"\\uFF0D\",multiplication:\"\\xD7\",obelus:\"\\xF7\",pencilDownRight:\"\\u270E\",pencilRight:\"\\u270F\",pencilUpRight:\"\\u2710\",percent:\"%\",pilcrow2:\"\\u2761\",pilcrow:\"\\xB6\",plusMinus:\"\\xB1\",section:\"\\xA7\",starsOff:\"\\u2606\",starsOn:\"\\u2605\",upDownArrow:\"\\u2195\"},ihe=Object.assign({},T_,{check:\"\\u221A\",cross:\"\\xD7\",ellipsisLarge:\"...\",ellipsis:\"...\",info:\"i\",question:\"?\",questionSmall:\"?\",pointer:\">\",pointerSmall:\"\\xBB\",radioOff:\"( )\",radioOn:\"(*)\",warning:\"\\u203C\"}),she=Object.assign({},T_,{ballotCross:\"\\u2718\",check:\"\\u2714\",cross:\"\\u2716\",ellipsisLarge:\"\\u22EF\",ellipsis:\"\\u2026\",info:\"\\u2139\",question:\"?\",questionFull:\"\\uFF1F\",questionSmall:\"\\uFE56\",pointer:nhe?\"\\u25B8\":\"\\u276F\",pointerSmall:nhe?\"\\u2023\":\"\\u203A\",radioOff:\"\\u25EF\",radioOn:\"\\u25C9\",warning:\"\\u26A0\"});o2.exports=UAt&&!MAt?ihe:she;Reflect.defineProperty(o2.exports,\"common\",{enumerable:!1,value:T_});Reflect.defineProperty(o2.exports,\"windows\",{enumerable:!1,value:ihe});Reflect.defineProperty(o2.exports,\"other\",{enumerable:!1,value:she})});var Kc=_((W_t,N_)=>{\"use strict\";var _At=t=>t!==null&&typeof t==\"object\"&&!Array.isArray(t),HAt=/[\\u001b\\u009b][[\\]#;?()]*(?:(?:(?:[^\\W_]*;?[^\\W_]*)\\u0007)|(?:(?:[0-9]{1,4}(;[0-9]{0,4})*)?[~0-9=<>cf-nqrtyA-PRZ]))/g,ahe=()=>{let t={enabled:!0,visible:!0,styles:{},keys:{}};\"FORCE_COLOR\"in process.env&&(t.enabled=process.env.FORCE_COLOR!==\"0\");let e=n=>{let u=n.open=`\\x1B[${n.codes[0]}m`,A=n.close=`\\x1B[${n.codes[1]}m`,p=n.regex=new RegExp(`\\\\u001b\\\\[${n.codes[1]}m`,\"g\");return n.wrap=(h,C)=>{h.includes(A)&&(h=h.replace(p,A+u));let I=u+h+A;return C?I.replace(/\\r*\\n/g,`${A}$&${u}`):I},n},r=(n,u,A)=>typeof n==\"function\"?n(u):n.wrap(u,A),o=(n,u)=>{if(n===\"\"||n==null)return\"\";if(t.enabled===!1)return n;if(t.visible===!1)return\"\";let A=\"\"+n,p=A.includes(`\n`),h=u.length;for(h>0&&u.includes(\"unstyle\")&&(u=[...new Set([\"unstyle\",...u])].reverse());h-- >0;)A=r(t.styles[u[h]],A,p);return A},a=(n,u,A)=>{t.styles[n]=e({name:n,codes:u}),(t.keys[A]||(t.keys[A]=[])).push(n),Reflect.defineProperty(t,n,{configurable:!0,enumerable:!0,set(h){t.alias(n,h)},get(){let h=C=>o(C,h.stack);return Reflect.setPrototypeOf(h,t),h.stack=this.stack?this.stack.concat(n):[n],h}})};return a(\"reset\",[0,0],\"modifier\"),a(\"bold\",[1,22],\"modifier\"),a(\"dim\",[2,22],\"modifier\"),a(\"italic\",[3,23],\"modifier\"),a(\"underline\",[4,24],\"modifier\"),a(\"inverse\",[7,27],\"modifier\"),a(\"hidden\",[8,28],\"modifier\"),a(\"strikethrough\",[9,29],\"modifier\"),a(\"black\",[30,39],\"color\"),a(\"red\",[31,39],\"color\"),a(\"green\",[32,39],\"color\"),a(\"yellow\",[33,39],\"color\"),a(\"blue\",[34,39],\"color\"),a(\"magenta\",[35,39],\"color\"),a(\"cyan\",[36,39],\"color\"),a(\"white\",[37,39],\"color\"),a(\"gray\",[90,39],\"color\"),a(\"grey\",[90,39],\"color\"),a(\"bgBlack\",[40,49],\"bg\"),a(\"bgRed\",[41,49],\"bg\"),a(\"bgGreen\",[42,49],\"bg\"),a(\"bgYellow\",[43,49],\"bg\"),a(\"bgBlue\",[44,49],\"bg\"),a(\"bgMagenta\",[45,49],\"bg\"),a(\"bgCyan\",[46,49],\"bg\"),a(\"bgWhite\",[47,49],\"bg\"),a(\"blackBright\",[90,39],\"bright\"),a(\"redBright\",[91,39],\"bright\"),a(\"greenBright\",[92,39],\"bright\"),a(\"yellowBright\",[93,39],\"bright\"),a(\"blueBright\",[94,39],\"bright\"),a(\"magentaBright\",[95,39],\"bright\"),a(\"cyanBright\",[96,39],\"bright\"),a(\"whiteBright\",[97,39],\"bright\"),a(\"bgBlackBright\",[100,49],\"bgBright\"),a(\"bgRedBright\",[101,49],\"bgBright\"),a(\"bgGreenBright\",[102,49],\"bgBright\"),a(\"bgYellowBright\",[103,49],\"bgBright\"),a(\"bgBlueBright\",[104,49],\"bgBright\"),a(\"bgMagentaBright\",[105,49],\"bgBright\"),a(\"bgCyanBright\",[106,49],\"bgBright\"),a(\"bgWhiteBright\",[107,49],\"bgBright\"),t.ansiRegex=HAt,t.hasColor=t.hasAnsi=n=>(t.ansiRegex.lastIndex=0,typeof n==\"string\"&&n!==\"\"&&t.ansiRegex.test(n)),t.alias=(n,u)=>{let A=typeof u==\"string\"?t[u]:u;if(typeof A!=\"function\")throw new TypeError(\"Expected alias to be the name of an existing color (string) or a function\");A.stack||(Reflect.defineProperty(A,\"name\",{value:n}),t.styles[n]=A,A.stack=[n]),Reflect.defineProperty(t,n,{configurable:!0,enumerable:!0,set(p){t.alias(n,p)},get(){let p=h=>o(h,p.stack);return Reflect.setPrototypeOf(p,t),p.stack=this.stack?this.stack.concat(A.stack):A.stack,p}})},t.theme=n=>{if(!_At(n))throw new TypeError(\"Expected theme to be an object\");for(let u of Object.keys(n))t.alias(u,n[u]);return t},t.alias(\"unstyle\",n=>typeof n==\"string\"&&n!==\"\"?(t.ansiRegex.lastIndex=0,n.replace(t.ansiRegex,\"\")):\"\"),t.alias(\"noop\",n=>n),t.none=t.clear=t.noop,t.stripColor=t.unstyle,t.symbols=ohe(),t.define=a,t};N_.exports=ahe();N_.exports.create=ahe});var No=_(nn=>{\"use strict\";var jAt=Object.prototype.toString,rc=Kc(),lhe=!1,L_=[],che={yellow:\"blue\",cyan:\"red\",green:\"magenta\",black:\"white\",blue:\"yellow\",red:\"cyan\",magenta:\"green\",white:\"black\"};nn.longest=(t,e)=>t.reduce((r,o)=>Math.max(r,e?o[e].length:o.length),0);nn.hasColor=t=>!!t&&rc.hasColor(t);var ok=nn.isObject=t=>t!==null&&typeof t==\"object\"&&!Array.isArray(t);nn.nativeType=t=>jAt.call(t).slice(8,-1).toLowerCase().replace(/\\s/g,\"\");nn.isAsyncFn=t=>nn.nativeType(t)===\"asyncfunction\";nn.isPrimitive=t=>t!=null&&typeof t!=\"object\"&&typeof t!=\"function\";nn.resolve=(t,e,...r)=>typeof e==\"function\"?e.call(t,...r):e;nn.scrollDown=(t=[])=>[...t.slice(1),t[0]];nn.scrollUp=(t=[])=>[t.pop(),...t];nn.reorder=(t=[])=>{let e=t.slice();return e.sort((r,o)=>r.index>o.index?1:r.index<o.index?-1:0),e};nn.swap=(t,e,r)=>{let o=t.length,a=r===o?0:r<0?o-1:r,n=t[e];t[e]=t[a],t[a]=n};nn.width=(t,e=80)=>{let r=t&&t.columns?t.columns:e;return t&&typeof t.getWindowSize==\"function\"&&(r=t.getWindowSize()[0]),process.platform===\"win32\"?r-1:r};nn.height=(t,e=20)=>{let r=t&&t.rows?t.rows:e;return t&&typeof t.getWindowSize==\"function\"&&(r=t.getWindowSize()[1]),r};nn.wordWrap=(t,e={})=>{if(!t)return t;typeof e==\"number\"&&(e={width:e});let{indent:r=\"\",newline:o=`\n`+r,width:a=80}=e,n=(o+r).match(/[^\\S\\n]/g)||[];a-=n.length;let u=`.{1,${a}}([\\\\s\\\\u200B]+|$)|[^\\\\s\\\\u200B]+?([\\\\s\\\\u200B]+|$)`,A=t.trim(),p=new RegExp(u,\"g\"),h=A.match(p)||[];return h=h.map(C=>C.replace(/\\n$/,\"\")),e.padEnd&&(h=h.map(C=>C.padEnd(a,\" \"))),e.padStart&&(h=h.map(C=>C.padStart(a,\" \"))),r+h.join(o)};nn.unmute=t=>{let e=t.stack.find(o=>rc.keys.color.includes(o));return e?rc[e]:t.stack.find(o=>o.slice(2)===\"bg\")?rc[e.slice(2)]:o=>o};nn.pascal=t=>t?t[0].toUpperCase()+t.slice(1):\"\";nn.inverse=t=>{if(!t||!t.stack)return t;let e=t.stack.find(o=>rc.keys.color.includes(o));if(e){let o=rc[\"bg\"+nn.pascal(e)];return o?o.black:t}let r=t.stack.find(o=>o.slice(0,2)===\"bg\");return r?rc[r.slice(2).toLowerCase()]||t:rc.none};nn.complement=t=>{if(!t||!t.stack)return t;let e=t.stack.find(o=>rc.keys.color.includes(o)),r=t.stack.find(o=>o.slice(0,2)===\"bg\");if(e&&!r)return rc[che[e]||e];if(r){let o=r.slice(2).toLowerCase(),a=che[o];return a&&rc[\"bg\"+nn.pascal(a)]||t}return rc.none};nn.meridiem=t=>{let e=t.getHours(),r=t.getMinutes(),o=e>=12?\"pm\":\"am\";e=e%12;let a=e===0?12:e,n=r<10?\"0\"+r:r;return a+\":\"+n+\" \"+o};nn.set=(t={},e=\"\",r)=>e.split(\".\").reduce((o,a,n,u)=>{let A=u.length-1>n?o[a]||{}:r;return!nn.isObject(A)&&n<u.length-1&&(A={}),o[a]=A},t);nn.get=(t={},e=\"\",r)=>{let o=t[e]==null?e.split(\".\").reduce((a,n)=>a&&a[n],t):t[e];return o??r};nn.mixin=(t,e)=>{if(!ok(t))return e;if(!ok(e))return t;for(let r of Object.keys(e)){let o=Object.getOwnPropertyDescriptor(e,r);if(o.hasOwnProperty(\"value\"))if(t.hasOwnProperty(r)&&ok(o.value)){let a=Object.getOwnPropertyDescriptor(t,r);ok(a.value)?t[r]=nn.merge({},t[r],e[r]):Reflect.defineProperty(t,r,o)}else Reflect.defineProperty(t,r,o);else Reflect.defineProperty(t,r,o)}return t};nn.merge=(...t)=>{let e={};for(let r of t)nn.mixin(e,r);return e};nn.mixinEmitter=(t,e)=>{let r=e.constructor.prototype;for(let o of Object.keys(r)){let a=r[o];typeof a==\"function\"?nn.define(t,o,a.bind(e)):nn.define(t,o,a)}};nn.onExit=t=>{let e=(r,o)=>{lhe||(lhe=!0,L_.forEach(a=>a()),r===!0&&process.exit(128+o))};L_.length===0&&(process.once(\"SIGTERM\",e.bind(null,!0,15)),process.once(\"SIGINT\",e.bind(null,!0,2)),process.once(\"exit\",e)),L_.push(t)};nn.define=(t,e,r)=>{Reflect.defineProperty(t,e,{value:r})};nn.defineExport=(t,e,r)=>{let o;Reflect.defineProperty(t,e,{enumerable:!0,configurable:!0,set(a){o=a},get(){return o?o():r()}})}});var uhe=_(fC=>{\"use strict\";fC.ctrl={a:\"first\",b:\"backward\",c:\"cancel\",d:\"deleteForward\",e:\"last\",f:\"forward\",g:\"reset\",i:\"tab\",k:\"cutForward\",l:\"reset\",n:\"newItem\",m:\"cancel\",j:\"submit\",p:\"search\",r:\"remove\",s:\"save\",u:\"undo\",w:\"cutLeft\",x:\"toggleCursor\",v:\"paste\"};fC.shift={up:\"shiftUp\",down:\"shiftDown\",left:\"shiftLeft\",right:\"shiftRight\",tab:\"prev\"};fC.fn={up:\"pageUp\",down:\"pageDown\",left:\"pageLeft\",right:\"pageRight\",delete:\"deleteForward\"};fC.option={b:\"backward\",f:\"forward\",d:\"cutRight\",left:\"cutLeft\",up:\"altUp\",down:\"altDown\"};fC.keys={pageup:\"pageUp\",pagedown:\"pageDown\",home:\"home\",end:\"end\",cancel:\"cancel\",delete:\"deleteForward\",backspace:\"delete\",down:\"down\",enter:\"submit\",escape:\"cancel\",left:\"left\",space:\"space\",number:\"number\",return:\"submit\",right:\"right\",tab:\"next\",up:\"up\"}});var phe=_((z_t,fhe)=>{\"use strict\";var Ahe=Be(\"readline\"),qAt=uhe(),GAt=/^(?:\\x1b)([a-zA-Z0-9])$/,YAt=/^(?:\\x1b+)(O|N|\\[|\\[\\[)(?:(\\d+)(?:;(\\d+))?([~^$])|(?:1;)?(\\d+)?([a-zA-Z]))/,WAt={OP:\"f1\",OQ:\"f2\",OR:\"f3\",OS:\"f4\",\"[11~\":\"f1\",\"[12~\":\"f2\",\"[13~\":\"f3\",\"[14~\":\"f4\",\"[[A\":\"f1\",\"[[B\":\"f2\",\"[[C\":\"f3\",\"[[D\":\"f4\",\"[[E\":\"f5\",\"[15~\":\"f5\",\"[17~\":\"f6\",\"[18~\":\"f7\",\"[19~\":\"f8\",\"[20~\":\"f9\",\"[21~\":\"f10\",\"[23~\":\"f11\",\"[24~\":\"f12\",\"[A\":\"up\",\"[B\":\"down\",\"[C\":\"right\",\"[D\":\"left\",\"[E\":\"clear\",\"[F\":\"end\",\"[H\":\"home\",OA:\"up\",OB:\"down\",OC:\"right\",OD:\"left\",OE:\"clear\",OF:\"end\",OH:\"home\",\"[1~\":\"home\",\"[2~\":\"insert\",\"[3~\":\"delete\",\"[4~\":\"end\",\"[5~\":\"pageup\",\"[6~\":\"pagedown\",\"[[5~\":\"pageup\",\"[[6~\":\"pagedown\",\"[7~\":\"home\",\"[8~\":\"end\",\"[a\":\"up\",\"[b\":\"down\",\"[c\":\"right\",\"[d\":\"left\",\"[e\":\"clear\",\"[2$\":\"insert\",\"[3$\":\"delete\",\"[5$\":\"pageup\",\"[6$\":\"pagedown\",\"[7$\":\"home\",\"[8$\":\"end\",Oa:\"up\",Ob:\"down\",Oc:\"right\",Od:\"left\",Oe:\"clear\",\"[2^\":\"insert\",\"[3^\":\"delete\",\"[5^\":\"pageup\",\"[6^\":\"pagedown\",\"[7^\":\"home\",\"[8^\":\"end\",\"[Z\":\"tab\"};function KAt(t){return[\"[a\",\"[b\",\"[c\",\"[d\",\"[e\",\"[2$\",\"[3$\",\"[5$\",\"[6$\",\"[7$\",\"[8$\",\"[Z\"].includes(t)}function VAt(t){return[\"Oa\",\"Ob\",\"Oc\",\"Od\",\"Oe\",\"[2^\",\"[3^\",\"[5^\",\"[6^\",\"[7^\",\"[8^\"].includes(t)}var ak=(t=\"\",e={})=>{let r,o={name:e.name,ctrl:!1,meta:!1,shift:!1,option:!1,sequence:t,raw:t,...e};if(Buffer.isBuffer(t)?t[0]>127&&t[1]===void 0?(t[0]-=128,t=\"\\x1B\"+String(t)):t=String(t):t!==void 0&&typeof t!=\"string\"?t=String(t):t||(t=o.sequence||\"\"),o.sequence=o.sequence||t||o.name,t===\"\\r\")o.raw=void 0,o.name=\"return\";else if(t===`\n`)o.name=\"enter\";else if(t===\"\t\")o.name=\"tab\";else if(t===\"\\b\"||t===\"\\x7F\"||t===\"\\x1B\\x7F\"||t===\"\\x1B\\b\")o.name=\"backspace\",o.meta=t.charAt(0)===\"\\x1B\";else if(t===\"\\x1B\"||t===\"\\x1B\\x1B\")o.name=\"escape\",o.meta=t.length===2;else if(t===\" \"||t===\"\\x1B \")o.name=\"space\",o.meta=t.length===2;else if(t<=\"\u001a\")o.name=String.fromCharCode(t.charCodeAt(0)+\"a\".charCodeAt(0)-1),o.ctrl=!0;else if(t.length===1&&t>=\"0\"&&t<=\"9\")o.name=\"number\";else if(t.length===1&&t>=\"a\"&&t<=\"z\")o.name=t;else if(t.length===1&&t>=\"A\"&&t<=\"Z\")o.name=t.toLowerCase(),o.shift=!0;else if(r=GAt.exec(t))o.meta=!0,o.shift=/^[A-Z]$/.test(r[1]);else if(r=YAt.exec(t)){let a=[...t];a[0]===\"\\x1B\"&&a[1]===\"\\x1B\"&&(o.option=!0);let n=[r[1],r[2],r[4],r[6]].filter(Boolean).join(\"\"),u=(r[3]||r[5]||1)-1;o.ctrl=!!(u&4),o.meta=!!(u&10),o.shift=!!(u&1),o.code=n,o.name=WAt[n],o.shift=KAt(n)||o.shift,o.ctrl=VAt(n)||o.ctrl}return o};ak.listen=(t={},e)=>{let{stdin:r}=t;if(!r||r!==process.stdin&&!r.isTTY)throw new Error(\"Invalid stream passed\");let o=Ahe.createInterface({terminal:!0,input:r});Ahe.emitKeypressEvents(r,o);let a=(A,p)=>e(A,ak(A,p),o),n=r.isRaw;return r.isTTY&&r.setRawMode(!0),r.on(\"keypress\",a),o.resume(),()=>{r.isTTY&&r.setRawMode(n),r.removeListener(\"keypress\",a),o.pause(),o.close()}};ak.action=(t,e,r)=>{let o={...qAt,...r};return e.ctrl?(e.action=o.ctrl[e.name],e):e.option&&o.option?(e.action=o.option[e.name],e):e.shift?(e.action=o.shift[e.name],e):(e.action=o.keys[e.name],e)};fhe.exports=ak});var ghe=_((J_t,hhe)=>{\"use strict\";hhe.exports=t=>{t.timers=t.timers||{};let e=t.options.timers;if(!!e)for(let r of Object.keys(e)){let o=e[r];typeof o==\"number\"&&(o={interval:o}),zAt(t,r,o)}};function zAt(t,e,r={}){let o=t.timers[e]={name:e,start:Date.now(),ms:0,tick:0},a=r.interval||120;o.frames=r.frames||[],o.loading=!0;let n=setInterval(()=>{o.ms=Date.now()-o.start,o.tick++,t.render()},a);return o.stop=()=>{o.loading=!1,clearInterval(n)},Reflect.defineProperty(o,\"interval\",{value:n}),t.once(\"close\",()=>o.stop()),o.stop}});var mhe=_((X_t,dhe)=>{\"use strict\";var{define:JAt,width:XAt}=No(),O_=class{constructor(e){let r=e.options;JAt(this,\"_prompt\",e),this.type=e.type,this.name=e.name,this.message=\"\",this.header=\"\",this.footer=\"\",this.error=\"\",this.hint=\"\",this.input=\"\",this.cursor=0,this.index=0,this.lines=0,this.tick=0,this.prompt=\"\",this.buffer=\"\",this.width=XAt(r.stdout||process.stdout),Object.assign(this,r),this.name=this.name||this.message,this.message=this.message||this.name,this.symbols=e.symbols,this.styles=e.styles,this.required=new Set,this.cancelled=!1,this.submitted=!1}clone(){let e={...this};return e.status=this.status,e.buffer=Buffer.from(e.buffer),delete e.clone,e}set color(e){this._color=e}get color(){let e=this.prompt.styles;if(this.cancelled)return e.cancelled;if(this.submitted)return e.submitted;let r=this._color||e[this.status];return typeof r==\"function\"?r:e.pending}set loading(e){this._loading=e}get loading(){return typeof this._loading==\"boolean\"?this._loading:this.loadingChoices?\"choices\":!1}get status(){return this.cancelled?\"cancelled\":this.submitted?\"submitted\":\"pending\"}};dhe.exports=O_});var Ehe=_((Z_t,yhe)=>{\"use strict\";var M_=No(),eo=Kc(),U_={default:eo.noop,noop:eo.noop,set inverse(t){this._inverse=t},get inverse(){return this._inverse||M_.inverse(this.primary)},set complement(t){this._complement=t},get complement(){return this._complement||M_.complement(this.primary)},primary:eo.cyan,success:eo.green,danger:eo.magenta,strong:eo.bold,warning:eo.yellow,muted:eo.dim,disabled:eo.gray,dark:eo.dim.gray,underline:eo.underline,set info(t){this._info=t},get info(){return this._info||this.primary},set em(t){this._em=t},get em(){return this._em||this.primary.underline},set heading(t){this._heading=t},get heading(){return this._heading||this.muted.underline},set pending(t){this._pending=t},get pending(){return this._pending||this.primary},set submitted(t){this._submitted=t},get submitted(){return this._submitted||this.success},set cancelled(t){this._cancelled=t},get cancelled(){return this._cancelled||this.danger},set typing(t){this._typing=t},get typing(){return this._typing||this.dim},set placeholder(t){this._placeholder=t},get placeholder(){return this._placeholder||this.primary.dim},set highlight(t){this._highlight=t},get highlight(){return this._highlight||this.inverse}};U_.merge=(t={})=>{t.styles&&typeof t.styles.enabled==\"boolean\"&&(eo.enabled=t.styles.enabled),t.styles&&typeof t.styles.visible==\"boolean\"&&(eo.visible=t.styles.visible);let e=M_.merge({},U_,t.styles);delete e.merge;for(let r of Object.keys(eo))e.hasOwnProperty(r)||Reflect.defineProperty(e,r,{get:()=>eo[r]});for(let r of Object.keys(eo.styles))e.hasOwnProperty(r)||Reflect.defineProperty(e,r,{get:()=>eo[r]});return e};yhe.exports=U_});var whe=_(($_t,Che)=>{\"use strict\";var __=process.platform===\"win32\",Wf=Kc(),ZAt=No(),H_={...Wf.symbols,upDownDoubleArrow:\"\\u21D5\",upDownDoubleArrow2:\"\\u2B0D\",upDownArrow:\"\\u2195\",asterisk:\"*\",asterism:\"\\u2042\",bulletWhite:\"\\u25E6\",electricArrow:\"\\u2301\",ellipsisLarge:\"\\u22EF\",ellipsisSmall:\"\\u2026\",fullBlock:\"\\u2588\",identicalTo:\"\\u2261\",indicator:Wf.symbols.check,leftAngle:\"\\u2039\",mark:\"\\u203B\",minus:\"\\u2212\",multiplication:\"\\xD7\",obelus:\"\\xF7\",percent:\"%\",pilcrow:\"\\xB6\",pilcrow2:\"\\u2761\",pencilUpRight:\"\\u2710\",pencilDownRight:\"\\u270E\",pencilRight:\"\\u270F\",plus:\"+\",plusMinus:\"\\xB1\",pointRight:\"\\u261E\",rightAngle:\"\\u203A\",section:\"\\xA7\",hexagon:{off:\"\\u2B21\",on:\"\\u2B22\",disabled:\"\\u2B22\"},ballot:{on:\"\\u2611\",off:\"\\u2610\",disabled:\"\\u2612\"},stars:{on:\"\\u2605\",off:\"\\u2606\",disabled:\"\\u2606\"},folder:{on:\"\\u25BC\",off:\"\\u25B6\",disabled:\"\\u25B6\"},prefix:{pending:Wf.symbols.question,submitted:Wf.symbols.check,cancelled:Wf.symbols.cross},separator:{pending:Wf.symbols.pointerSmall,submitted:Wf.symbols.middot,cancelled:Wf.symbols.middot},radio:{off:__?\"( )\":\"\\u25EF\",on:__?\"(*)\":\"\\u25C9\",disabled:__?\"(|)\":\"\\u24BE\"},numbers:[\"\\u24EA\",\"\\u2460\",\"\\u2461\",\"\\u2462\",\"\\u2463\",\"\\u2464\",\"\\u2465\",\"\\u2466\",\"\\u2467\",\"\\u2468\",\"\\u2469\",\"\\u246A\",\"\\u246B\",\"\\u246C\",\"\\u246D\",\"\\u246E\",\"\\u246F\",\"\\u2470\",\"\\u2471\",\"\\u2472\",\"\\u2473\",\"\\u3251\",\"\\u3252\",\"\\u3253\",\"\\u3254\",\"\\u3255\",\"\\u3256\",\"\\u3257\",\"\\u3258\",\"\\u3259\",\"\\u325A\",\"\\u325B\",\"\\u325C\",\"\\u325D\",\"\\u325E\",\"\\u325F\",\"\\u32B1\",\"\\u32B2\",\"\\u32B3\",\"\\u32B4\",\"\\u32B5\",\"\\u32B6\",\"\\u32B7\",\"\\u32B8\",\"\\u32B9\",\"\\u32BA\",\"\\u32BB\",\"\\u32BC\",\"\\u32BD\",\"\\u32BE\",\"\\u32BF\"]};H_.merge=t=>{let e=ZAt.merge({},Wf.symbols,H_,t.symbols);return delete e.merge,e};Che.exports=H_});var Bhe=_((e8t,Ihe)=>{\"use strict\";var $At=Ehe(),eft=whe(),tft=No();Ihe.exports=t=>{t.options=tft.merge({},t.options.theme,t.options),t.symbols=eft.merge(t.options),t.styles=$At.merge(t.options)}});var bhe=_((Phe,She)=>{\"use strict\";var vhe=process.env.TERM_PROGRAM===\"Apple_Terminal\",rft=Kc(),j_=No(),Vc=She.exports=Phe,Di=\"\\x1B[\",Dhe=\"\\x07\",q_=!1,Ph=Vc.code={bell:Dhe,beep:Dhe,beginning:`${Di}G`,down:`${Di}J`,esc:Di,getPosition:`${Di}6n`,hide:`${Di}?25l`,line:`${Di}2K`,lineEnd:`${Di}K`,lineStart:`${Di}1K`,restorePosition:Di+(vhe?\"8\":\"u\"),savePosition:Di+(vhe?\"7\":\"s\"),screen:`${Di}2J`,show:`${Di}?25h`,up:`${Di}1J`},jd=Vc.cursor={get hidden(){return q_},hide(){return q_=!0,Ph.hide},show(){return q_=!1,Ph.show},forward:(t=1)=>`${Di}${t}C`,backward:(t=1)=>`${Di}${t}D`,nextLine:(t=1)=>`${Di}E`.repeat(t),prevLine:(t=1)=>`${Di}F`.repeat(t),up:(t=1)=>t?`${Di}${t}A`:\"\",down:(t=1)=>t?`${Di}${t}B`:\"\",right:(t=1)=>t?`${Di}${t}C`:\"\",left:(t=1)=>t?`${Di}${t}D`:\"\",to(t,e){return e?`${Di}${e+1};${t+1}H`:`${Di}${t+1}G`},move(t=0,e=0){let r=\"\";return r+=t<0?jd.left(-t):t>0?jd.right(t):\"\",r+=e<0?jd.up(-e):e>0?jd.down(e):\"\",r},restore(t={}){let{after:e,cursor:r,initial:o,input:a,prompt:n,size:u,value:A}=t;if(o=j_.isPrimitive(o)?String(o):\"\",a=j_.isPrimitive(a)?String(a):\"\",A=j_.isPrimitive(A)?String(A):\"\",u){let p=Vc.cursor.up(u)+Vc.cursor.to(n.length),h=a.length-r;return h>0&&(p+=Vc.cursor.left(h)),p}if(A||e){let p=!a&&!!o?-o.length:-a.length+r;return e&&(p-=e.length),a===\"\"&&o&&!n.includes(o)&&(p+=o.length),Vc.cursor.move(p)}}},G_=Vc.erase={screen:Ph.screen,up:Ph.up,down:Ph.down,line:Ph.line,lineEnd:Ph.lineEnd,lineStart:Ph.lineStart,lines(t){let e=\"\";for(let r=0;r<t;r++)e+=Vc.erase.line+(r<t-1?Vc.cursor.up(1):\"\");return t&&(e+=Vc.code.beginning),e}};Vc.clear=(t=\"\",e=process.stdout.columns)=>{if(!e)return G_.line+jd.to(0);let r=n=>[...rft.unstyle(n)].length,o=t.split(/\\r?\\n/),a=0;for(let n of o)a+=1+Math.floor(Math.max(r(n)-1,0)/e);return(G_.line+jd.prevLine()).repeat(a-1)+G_.line+jd.to(0)}});var pC=_((t8t,khe)=>{\"use strict\";var nft=Be(\"events\"),xhe=Kc(),Y_=phe(),ift=ghe(),sft=mhe(),oft=Bhe(),Ra=No(),qd=bhe(),a2=class extends nft{constructor(e={}){super(),this.name=e.name,this.type=e.type,this.options=e,oft(this),ift(this),this.state=new sft(this),this.initial=[e.initial,e.default].find(r=>r!=null),this.stdout=e.stdout||process.stdout,this.stdin=e.stdin||process.stdin,this.scale=e.scale||1,this.term=this.options.term||process.env.TERM_PROGRAM,this.margin=lft(this.options.margin),this.setMaxListeners(0),aft(this)}async keypress(e,r={}){this.keypressed=!0;let o=Y_.action(e,Y_(e,r),this.options.actions);this.state.keypress=o,this.emit(\"keypress\",e,o),this.emit(\"state\",this.state.clone());let a=this.options[o.action]||this[o.action]||this.dispatch;if(typeof a==\"function\")return await a.call(this,e,o);this.alert()}alert(){delete this.state.alert,this.options.show===!1?this.emit(\"alert\"):this.stdout.write(qd.code.beep)}cursorHide(){this.stdout.write(qd.cursor.hide()),Ra.onExit(()=>this.cursorShow())}cursorShow(){this.stdout.write(qd.cursor.show())}write(e){!e||(this.stdout&&this.state.show!==!1&&this.stdout.write(e),this.state.buffer+=e)}clear(e=0){let r=this.state.buffer;this.state.buffer=\"\",!(!r&&!e||this.options.show===!1)&&this.stdout.write(qd.cursor.down(e)+qd.clear(r,this.width))}restore(){if(this.state.closed||this.options.show===!1)return;let{prompt:e,after:r,rest:o}=this.sections(),{cursor:a,initial:n=\"\",input:u=\"\",value:A=\"\"}=this,p=this.state.size=o.length,h={after:r,cursor:a,initial:n,input:u,prompt:e,size:p,value:A},C=qd.cursor.restore(h);C&&this.stdout.write(C)}sections(){let{buffer:e,input:r,prompt:o}=this.state;o=xhe.unstyle(o);let a=xhe.unstyle(e),n=a.indexOf(o),u=a.slice(0,n),p=a.slice(n).split(`\n`),h=p[0],C=p[p.length-1],v=(o+(r?\" \"+r:\"\")).length,x=v<h.length?h.slice(v+1):\"\";return{header:u,prompt:h,after:x,rest:p.slice(1),last:C}}async submit(){this.state.submitted=!0,this.state.validating=!0,this.options.onSubmit&&await this.options.onSubmit.call(this,this.name,this.value,this);let e=this.state.error||await this.validate(this.value,this.state);if(e!==!0){let r=`\n`+this.symbols.pointer+\" \";typeof e==\"string\"?r+=e.trim():r+=\"Invalid input\",this.state.error=`\n`+this.styles.danger(r),this.state.submitted=!1,await this.render(),await this.alert(),this.state.validating=!1,this.state.error=void 0;return}this.state.validating=!1,await this.render(),await this.close(),this.value=await this.result(this.value),this.emit(\"submit\",this.value)}async cancel(e){this.state.cancelled=this.state.submitted=!0,await this.render(),await this.close(),typeof this.options.onCancel==\"function\"&&await this.options.onCancel.call(this,this.name,this.value,this),this.emit(\"cancel\",await this.error(e))}async close(){this.state.closed=!0;try{let e=this.sections(),r=Math.ceil(e.prompt.length/this.width);e.rest&&this.write(qd.cursor.down(e.rest.length)),this.write(`\n`.repeat(r))}catch{}this.emit(\"close\")}start(){!this.stop&&this.options.show!==!1&&(this.stop=Y_.listen(this,this.keypress.bind(this)),this.once(\"close\",this.stop))}async skip(){return this.skipped=this.options.skip===!0,typeof this.options.skip==\"function\"&&(this.skipped=await this.options.skip.call(this,this.name,this.value)),this.skipped}async initialize(){let{format:e,options:r,result:o}=this;if(this.format=()=>e.call(this,this.value),this.result=()=>o.call(this,this.value),typeof r.initial==\"function\"&&(this.initial=await r.initial.call(this,this)),typeof r.onRun==\"function\"&&await r.onRun.call(this,this),typeof r.onSubmit==\"function\"){let a=r.onSubmit.bind(this),n=this.submit.bind(this);delete this.options.onSubmit,this.submit=async()=>(await a(this.name,this.value,this),n())}await this.start(),await this.render()}render(){throw new Error(\"expected prompt to have a custom render method\")}run(){return new Promise(async(e,r)=>{if(this.once(\"submit\",e),this.once(\"cancel\",r),await this.skip())return this.render=()=>{},this.submit();await this.initialize(),this.emit(\"run\")})}async element(e,r,o){let{options:a,state:n,symbols:u,timers:A}=this,p=A&&A[e];n.timer=p;let h=a[e]||n[e]||u[e],C=r&&r[e]!=null?r[e]:await h;if(C===\"\")return C;let I=await this.resolve(C,n,r,o);return!I&&r&&r[e]?this.resolve(h,n,r,o):I}async prefix(){let e=await this.element(\"prefix\")||this.symbols,r=this.timers&&this.timers.prefix,o=this.state;return o.timer=r,Ra.isObject(e)&&(e=e[o.status]||e.pending),Ra.hasColor(e)?e:(this.styles[o.status]||this.styles.pending)(e)}async message(){let e=await this.element(\"message\");return Ra.hasColor(e)?e:this.styles.strong(e)}async separator(){let e=await this.element(\"separator\")||this.symbols,r=this.timers&&this.timers.separator,o=this.state;o.timer=r;let a=e[o.status]||e.pending||o.separator,n=await this.resolve(a,o);return Ra.isObject(n)&&(n=n[o.status]||n.pending),Ra.hasColor(n)?n:this.styles.muted(n)}async pointer(e,r){let o=await this.element(\"pointer\",e,r);if(typeof o==\"string\"&&Ra.hasColor(o))return o;if(o){let a=this.styles,n=this.index===r,u=n?a.primary:h=>h,A=await this.resolve(o[n?\"on\":\"off\"]||o,this.state),p=Ra.hasColor(A)?A:u(A);return n?p:\" \".repeat(A.length)}}async indicator(e,r){let o=await this.element(\"indicator\",e,r);if(typeof o==\"string\"&&Ra.hasColor(o))return o;if(o){let a=this.styles,n=e.enabled===!0,u=n?a.success:a.dark,A=o[n?\"on\":\"off\"]||o;return Ra.hasColor(A)?A:u(A)}return\"\"}body(){return null}footer(){if(this.state.status===\"pending\")return this.element(\"footer\")}header(){if(this.state.status===\"pending\")return this.element(\"header\")}async hint(){if(this.state.status===\"pending\"&&!this.isValue(this.state.input)){let e=await this.element(\"hint\");return Ra.hasColor(e)?e:this.styles.muted(e)}}error(e){return this.state.submitted?\"\":e||this.state.error}format(e){return e}result(e){return e}validate(e){return this.options.required===!0?this.isValue(e):!0}isValue(e){return e!=null&&e!==\"\"}resolve(e,...r){return Ra.resolve(this,e,...r)}get base(){return a2.prototype}get style(){return this.styles[this.state.status]}get height(){return this.options.rows||Ra.height(this.stdout,25)}get width(){return this.options.columns||Ra.width(this.stdout,80)}get size(){return{width:this.width,height:this.height}}set cursor(e){this.state.cursor=e}get cursor(){return this.state.cursor}set input(e){this.state.input=e}get input(){return this.state.input}set value(e){this.state.value=e}get value(){let{input:e,value:r}=this.state,o=[r,e].find(this.isValue.bind(this));return this.isValue(o)?o:this.initial}static get prompt(){return e=>new this(e).run()}};function aft(t){let e=a=>t[a]===void 0||typeof t[a]==\"function\",r=[\"actions\",\"choices\",\"initial\",\"margin\",\"roles\",\"styles\",\"symbols\",\"theme\",\"timers\",\"value\"],o=[\"body\",\"footer\",\"error\",\"header\",\"hint\",\"indicator\",\"message\",\"prefix\",\"separator\",\"skip\"];for(let a of Object.keys(t.options)){if(r.includes(a)||/^on[A-Z]/.test(a))continue;let n=t.options[a];typeof n==\"function\"&&e(a)?o.includes(a)||(t[a]=n.bind(t)):typeof t[a]!=\"function\"&&(t[a]=n)}}function lft(t){typeof t==\"number\"&&(t=[t,t,t,t]);let e=[].concat(t||[]),r=a=>a%2===0?`\n`:\" \",o=[];for(let a=0;a<4;a++){let n=r(a);e[a]?o.push(n.repeat(e[a])):o.push(\"\")}return o}khe.exports=a2});var Rhe=_((r8t,Fhe)=>{\"use strict\";var cft=No(),Qhe={default(t,e){return e},checkbox(t,e){throw new Error(\"checkbox role is not implemented yet\")},editable(t,e){throw new Error(\"editable role is not implemented yet\")},expandable(t,e){throw new Error(\"expandable role is not implemented yet\")},heading(t,e){return e.disabled=\"\",e.indicator=[e.indicator,\" \"].find(r=>r!=null),e.message=e.message||\"\",e},input(t,e){throw new Error(\"input role is not implemented yet\")},option(t,e){return Qhe.default(t,e)},radio(t,e){throw new Error(\"radio role is not implemented yet\")},separator(t,e){return e.disabled=\"\",e.indicator=[e.indicator,\" \"].find(r=>r!=null),e.message=e.message||t.symbols.line.repeat(5),e},spacer(t,e){return e}};Fhe.exports=(t,e={})=>{let r=cft.merge({},Qhe,e.roles);return r[t]||r.default}});var l2=_((n8t,Lhe)=>{\"use strict\";var uft=Kc(),Aft=pC(),fft=Rhe(),lk=No(),{reorder:W_,scrollUp:pft,scrollDown:hft,isObject:The,swap:gft}=lk,K_=class extends Aft{constructor(e){super(e),this.cursorHide(),this.maxSelected=e.maxSelected||1/0,this.multiple=e.multiple||!1,this.initial=e.initial||0,this.delay=e.delay||0,this.longest=0,this.num=\"\"}async initialize(){typeof this.options.initial==\"function\"&&(this.initial=await this.options.initial.call(this)),await this.reset(!0),await super.initialize()}async reset(){let{choices:e,initial:r,autofocus:o,suggest:a}=this.options;if(this.state._choices=[],this.state.choices=[],this.choices=await Promise.all(await this.toChoices(e)),this.choices.forEach(n=>n.enabled=!1),typeof a!=\"function\"&&this.selectable.length===0)throw new Error(\"At least one choice must be selectable\");The(r)&&(r=Object.keys(r)),Array.isArray(r)?(o!=null&&(this.index=this.findIndex(o)),r.forEach(n=>this.enable(this.find(n))),await this.render()):(o!=null&&(r=o),typeof r==\"string\"&&(r=this.findIndex(r)),typeof r==\"number\"&&r>-1&&(this.index=Math.max(0,Math.min(r,this.choices.length)),this.enable(this.find(this.index)))),this.isDisabled(this.focused)&&await this.down()}async toChoices(e,r){this.state.loadingChoices=!0;let o=[],a=0,n=async(u,A)=>{typeof u==\"function\"&&(u=await u.call(this)),u instanceof Promise&&(u=await u);for(let p=0;p<u.length;p++){let h=u[p]=await this.toChoice(u[p],a++,A);o.push(h),h.choices&&await n(h.choices,h)}return o};return n(e,r).then(u=>(this.state.loadingChoices=!1,u))}async toChoice(e,r,o){if(typeof e==\"function\"&&(e=await e.call(this,this)),e instanceof Promise&&(e=await e),typeof e==\"string\"&&(e={name:e}),e.normalized)return e;e.normalized=!0;let a=e.value;if(e=fft(e.role,this.options)(this,e),typeof e.disabled==\"string\"&&!e.hint&&(e.hint=e.disabled,e.disabled=!0),e.disabled===!0&&e.hint==null&&(e.hint=\"(disabled)\"),e.index!=null)return e;e.name=e.name||e.key||e.title||e.value||e.message,e.message=e.message||e.name||\"\",e.value=[e.value,e.name].find(this.isValue.bind(this)),e.input=\"\",e.index=r,e.cursor=0,lk.define(e,\"parent\",o),e.level=o?o.level+1:1,e.indent==null&&(e.indent=o?o.indent+\"  \":e.indent||\"\"),e.path=o?o.path+\".\"+e.name:e.name,e.enabled=!!(this.multiple&&!this.isDisabled(e)&&(e.enabled||this.isSelected(e))),this.isDisabled(e)||(this.longest=Math.max(this.longest,uft.unstyle(e.message).length));let u={...e};return e.reset=(A=u.input,p=u.value)=>{for(let h of Object.keys(u))e[h]=u[h];e.input=A,e.value=p},a==null&&typeof e.initial==\"function\"&&(e.input=await e.initial.call(this,this.state,e,r)),e}async onChoice(e,r){this.emit(\"choice\",e,r,this),typeof e.onChoice==\"function\"&&await e.onChoice.call(this,this.state,e,r)}async addChoice(e,r,o){let a=await this.toChoice(e,r,o);return this.choices.push(a),this.index=this.choices.length-1,this.limit=this.choices.length,a}async newItem(e,r,o){let a={name:\"New choice name?\",editable:!0,newChoice:!0,...e},n=await this.addChoice(a,r,o);return n.updateChoice=()=>{delete n.newChoice,n.name=n.message=n.input,n.input=\"\",n.cursor=0},this.render()}indent(e){return e.indent==null?e.level>1?\"  \".repeat(e.level-1):\"\":e.indent}dispatch(e,r){if(this.multiple&&this[r.name])return this[r.name]();this.alert()}focus(e,r){return typeof r!=\"boolean\"&&(r=e.enabled),r&&!e.enabled&&this.selected.length>=this.maxSelected?this.alert():(this.index=e.index,e.enabled=r&&!this.isDisabled(e),e)}space(){return this.multiple?(this.toggle(this.focused),this.render()):this.alert()}a(){if(this.maxSelected<this.choices.length)return this.alert();let e=this.selectable.every(r=>r.enabled);return this.choices.forEach(r=>r.enabled=!e),this.render()}i(){return this.choices.length-this.selected.length>this.maxSelected?this.alert():(this.choices.forEach(e=>e.enabled=!e.enabled),this.render())}g(e=this.focused){return this.choices.some(r=>!!r.parent)?(this.toggle(e.parent&&!e.choices?e.parent:e),this.render()):this.a()}toggle(e,r){if(!e.enabled&&this.selected.length>=this.maxSelected)return this.alert();typeof r!=\"boolean\"&&(r=!e.enabled),e.enabled=r,e.choices&&e.choices.forEach(a=>this.toggle(a,r));let o=e.parent;for(;o;){let a=o.choices.filter(n=>this.isDisabled(n));o.enabled=a.every(n=>n.enabled===!0),o=o.parent}return Nhe(this,this.choices),this.emit(\"toggle\",e,this),e}enable(e){return this.selected.length>=this.maxSelected?this.alert():(e.enabled=!this.isDisabled(e),e.choices&&e.choices.forEach(this.enable.bind(this)),e)}disable(e){return e.enabled=!1,e.choices&&e.choices.forEach(this.disable.bind(this)),e}number(e){this.num+=e;let r=o=>{let a=Number(o);if(a>this.choices.length-1)return this.alert();let n=this.focused,u=this.choices.find(A=>a===A.index);if(!u.enabled&&this.selected.length>=this.maxSelected)return this.alert();if(this.visible.indexOf(u)===-1){let A=W_(this.choices),p=A.indexOf(u);if(n.index>p){let h=A.slice(p,p+this.limit),C=A.filter(I=>!h.includes(I));this.choices=h.concat(C)}else{let h=p-this.limit+1;this.choices=A.slice(h).concat(A.slice(0,h))}}return this.index=this.choices.indexOf(u),this.toggle(this.focused),this.render()};return clearTimeout(this.numberTimeout),new Promise(o=>{let a=this.choices.length,n=this.num,u=(A=!1,p)=>{clearTimeout(this.numberTimeout),A&&(p=r(n)),this.num=\"\",o(p)};if(n===\"0\"||n.length===1&&Number(n+\"0\")>a)return u(!0);if(Number(n)>a)return u(!1,this.alert());this.numberTimeout=setTimeout(()=>u(!0),this.delay)})}home(){return this.choices=W_(this.choices),this.index=0,this.render()}end(){let e=this.choices.length-this.limit,r=W_(this.choices);return this.choices=r.slice(e).concat(r.slice(0,e)),this.index=this.limit-1,this.render()}first(){return this.index=0,this.render()}last(){return this.index=this.visible.length-1,this.render()}prev(){return this.visible.length<=1?this.alert():this.up()}next(){return this.visible.length<=1?this.alert():this.down()}right(){return this.cursor>=this.input.length?this.alert():(this.cursor++,this.render())}left(){return this.cursor<=0?this.alert():(this.cursor--,this.render())}up(){let e=this.choices.length,r=this.visible.length,o=this.index;return this.options.scroll===!1&&o===0?this.alert():e>r&&o===0?this.scrollUp():(this.index=(o-1%e+e)%e,this.isDisabled()?this.up():this.render())}down(){let e=this.choices.length,r=this.visible.length,o=this.index;return this.options.scroll===!1&&o===r-1?this.alert():e>r&&o===r-1?this.scrollDown():(this.index=(o+1)%e,this.isDisabled()?this.down():this.render())}scrollUp(e=0){return this.choices=pft(this.choices),this.index=e,this.isDisabled()?this.up():this.render()}scrollDown(e=this.visible.length-1){return this.choices=hft(this.choices),this.index=e,this.isDisabled()?this.down():this.render()}async shiftUp(){if(this.options.sort===!0){this.sorting=!0,this.swap(this.index-1),await this.up(),this.sorting=!1;return}return this.scrollUp(this.index)}async shiftDown(){if(this.options.sort===!0){this.sorting=!0,this.swap(this.index+1),await this.down(),this.sorting=!1;return}return this.scrollDown(this.index)}pageUp(){return this.visible.length<=1?this.alert():(this.limit=Math.max(this.limit-1,0),this.index=Math.min(this.limit-1,this.index),this._limit=this.limit,this.isDisabled()?this.up():this.render())}pageDown(){return this.visible.length>=this.choices.length?this.alert():(this.index=Math.max(0,this.index),this.limit=Math.min(this.limit+1,this.choices.length),this._limit=this.limit,this.isDisabled()?this.down():this.render())}swap(e){gft(this.choices,this.index,e)}isDisabled(e=this.focused){return e&&[\"disabled\",\"collapsed\",\"hidden\",\"completing\",\"readonly\"].some(o=>e[o]===!0)?!0:e&&e.role===\"heading\"}isEnabled(e=this.focused){if(Array.isArray(e))return e.every(r=>this.isEnabled(r));if(e.choices){let r=e.choices.filter(o=>!this.isDisabled(o));return e.enabled&&r.every(o=>this.isEnabled(o))}return e.enabled&&!this.isDisabled(e)}isChoice(e,r){return e.name===r||e.index===Number(r)}isSelected(e){return Array.isArray(this.initial)?this.initial.some(r=>this.isChoice(e,r)):this.isChoice(e,this.initial)}map(e=[],r=\"value\"){return[].concat(e||[]).reduce((o,a)=>(o[a]=this.find(a,r),o),{})}filter(e,r){let a=typeof e==\"function\"?e:(A,p)=>[A.name,p].includes(e),u=(this.options.multiple?this.state._choices:this.choices).filter(a);return r?u.map(A=>A[r]):u}find(e,r){if(The(e))return r?e[r]:e;let a=typeof e==\"function\"?e:(u,A)=>[u.name,A].includes(e),n=this.choices.find(a);if(n)return r?n[r]:n}findIndex(e){return this.choices.indexOf(this.find(e))}async submit(){let e=this.focused;if(!e)return this.alert();if(e.newChoice)return e.input?(e.updateChoice(),this.render()):this.alert();if(this.choices.some(u=>u.newChoice))return this.alert();let{reorder:r,sort:o}=this.options,a=this.multiple===!0,n=this.selected;return n===void 0?this.alert():(Array.isArray(n)&&r!==!1&&o!==!0&&(n=lk.reorder(n)),this.value=a?n.map(u=>u.name):n.name,super.submit())}set choices(e=[]){this.state._choices=this.state._choices||[],this.state.choices=e;for(let r of e)this.state._choices.some(o=>o.name===r.name)||this.state._choices.push(r);if(!this._initial&&this.options.initial){this._initial=!0;let r=this.initial;if(typeof r==\"string\"||typeof r==\"number\"){let o=this.find(r);o&&(this.initial=o.index,this.focus(o,!0))}}}get choices(){return Nhe(this,this.state.choices||[])}set visible(e){this.state.visible=e}get visible(){return(this.state.visible||this.choices).slice(0,this.limit)}set limit(e){this.state.limit=e}get limit(){let{state:e,options:r,choices:o}=this,a=e.limit||this._limit||r.limit||o.length;return Math.min(a,this.height)}set value(e){super.value=e}get value(){return typeof super.value!=\"string\"&&super.value===this.initial?this.input:super.value}set index(e){this.state.index=e}get index(){return Math.max(0,this.state?this.state.index:0)}get enabled(){return this.filter(this.isEnabled.bind(this))}get focused(){let e=this.choices[this.index];return e&&this.state.submitted&&this.multiple!==!0&&(e.enabled=!0),e}get selectable(){return this.choices.filter(e=>!this.isDisabled(e))}get selected(){return this.multiple?this.enabled:this.focused}};function Nhe(t,e){if(e instanceof Promise)return e;if(typeof e==\"function\"){if(lk.isAsyncFn(e))return e;e=e.call(t,t)}for(let r of e){if(Array.isArray(r.choices)){let o=r.choices.filter(a=>!t.isDisabled(a));r.enabled=o.every(a=>a.enabled===!0)}t.isDisabled(r)===!0&&delete r.enabled}return e}Lhe.exports=K_});var Sh=_((i8t,Ohe)=>{\"use strict\";var dft=l2(),V_=No(),z_=class extends dft{constructor(e){super(e),this.emptyError=this.options.emptyError||\"No items were selected\"}async dispatch(e,r){if(this.multiple)return this[r.name]?await this[r.name](e,r):await super.dispatch(e,r);this.alert()}separator(){if(this.options.separator)return super.separator();let e=this.styles.muted(this.symbols.ellipsis);return this.state.submitted?super.separator():e}pointer(e,r){return!this.multiple||this.options.pointer?super.pointer(e,r):\"\"}indicator(e,r){return this.multiple?super.indicator(e,r):\"\"}choiceMessage(e,r){let o=this.resolve(e.message,this.state,e,r);return e.role===\"heading\"&&!V_.hasColor(o)&&(o=this.styles.strong(o)),this.resolve(o,this.state,e,r)}choiceSeparator(){return\":\"}async renderChoice(e,r){await this.onChoice(e,r);let o=this.index===r,a=await this.pointer(e,r),n=await this.indicator(e,r)+(e.pad||\"\"),u=await this.resolve(e.hint,this.state,e,r);u&&!V_.hasColor(u)&&(u=this.styles.muted(u));let A=this.indent(e),p=await this.choiceMessage(e,r),h=()=>[this.margin[3],A+a+n,p,this.margin[1],u].filter(Boolean).join(\" \");return e.role===\"heading\"?h():e.disabled?(V_.hasColor(p)||(p=this.styles.disabled(p)),h()):(o&&(p=this.styles.em(p)),h())}async renderChoices(){if(this.state.loading===\"choices\")return this.styles.warning(\"Loading choices\");if(this.state.submitted)return\"\";let e=this.visible.map(async(n,u)=>await this.renderChoice(n,u)),r=await Promise.all(e);r.length||r.push(this.styles.danger(\"No matching choices\"));let o=this.margin[0]+r.join(`\n`),a;return this.options.choicesHeader&&(a=await this.resolve(this.options.choicesHeader,this.state)),[a,o].filter(Boolean).join(`\n`)}format(){return!this.state.submitted||this.state.cancelled?\"\":Array.isArray(this.selected)?this.selected.map(e=>this.styles.primary(e.name)).join(\", \"):this.styles.primary(this.selected.name)}async render(){let{submitted:e,size:r}=this.state,o=\"\",a=await this.header(),n=await this.prefix(),u=await this.separator(),A=await this.message();this.options.promptLine!==!1&&(o=[n,A,u,\"\"].join(\" \"),this.state.prompt=o);let p=await this.format(),h=await this.error()||await this.hint(),C=await this.renderChoices(),I=await this.footer();p&&(o+=p),h&&!o.includes(h)&&(o+=\" \"+h),e&&!p&&!C.trim()&&this.multiple&&this.emptyError!=null&&(o+=this.styles.danger(this.emptyError)),this.clear(r),this.write([a,o,C,I].filter(Boolean).join(`\n`)),this.write(this.margin[2]),this.restore()}};Ohe.exports=z_});var Uhe=_((s8t,Mhe)=>{\"use strict\";var mft=Sh(),yft=(t,e)=>{let r=t.toLowerCase();return o=>{let n=o.toLowerCase().indexOf(r),u=e(o.slice(n,n+r.length));return n>=0?o.slice(0,n)+u+o.slice(n+r.length):o}},J_=class extends mft{constructor(e){super(e),this.cursorShow()}moveCursor(e){this.state.cursor+=e}dispatch(e){return this.append(e)}space(e){return this.options.multiple?super.space(e):this.append(e)}append(e){let{cursor:r,input:o}=this.state;return this.input=o.slice(0,r)+e+o.slice(r),this.moveCursor(1),this.complete()}delete(){let{cursor:e,input:r}=this.state;return r?(this.input=r.slice(0,e-1)+r.slice(e),this.moveCursor(-1),this.complete()):this.alert()}deleteForward(){let{cursor:e,input:r}=this.state;return r[e]===void 0?this.alert():(this.input=`${r}`.slice(0,e)+`${r}`.slice(e+1),this.complete())}number(e){return this.append(e)}async complete(){this.completing=!0,this.choices=await this.suggest(this.input,this.state._choices),this.state.limit=void 0,this.index=Math.min(Math.max(this.visible.length-1,0),this.index),await this.render(),this.completing=!1}suggest(e=this.input,r=this.state._choices){if(typeof this.options.suggest==\"function\")return this.options.suggest.call(this,e,r);let o=e.toLowerCase();return r.filter(a=>a.message.toLowerCase().includes(o))}pointer(){return\"\"}format(){if(!this.focused)return this.input;if(this.options.multiple&&this.state.submitted)return this.selected.map(e=>this.styles.primary(e.message)).join(\", \");if(this.state.submitted){let e=this.value=this.input=this.focused.value;return this.styles.primary(e)}return this.input}async render(){if(this.state.status!==\"pending\")return super.render();let e=this.options.highlight?this.options.highlight.bind(this):this.styles.placeholder,r=yft(this.input,e),o=this.choices;this.choices=o.map(a=>({...a,message:r(a.message)})),await super.render(),this.choices=o}submit(){return this.options.multiple&&(this.value=this.selected.map(e=>e.name)),super.submit()}};Mhe.exports=J_});var Z_=_((o8t,_he)=>{\"use strict\";var X_=No();_he.exports=(t,e={})=>{t.cursorHide();let{input:r=\"\",initial:o=\"\",pos:a,showCursor:n=!0,color:u}=e,A=u||t.styles.placeholder,p=X_.inverse(t.styles.primary),h=R=>p(t.styles.black(R)),C=r,I=\" \",v=h(I);if(t.blink&&t.blink.off===!0&&(h=R=>R,v=\"\"),n&&a===0&&o===\"\"&&r===\"\")return h(I);if(n&&a===0&&(r===o||r===\"\"))return h(o[0])+A(o.slice(1));o=X_.isPrimitive(o)?`${o}`:\"\",r=X_.isPrimitive(r)?`${r}`:\"\";let x=o&&o.startsWith(r)&&o!==r,E=x?h(o[r.length]):v;if(a!==r.length&&n===!0&&(C=r.slice(0,a)+h(r[a])+r.slice(a+1),E=\"\"),n===!1&&(E=\"\"),x){let R=t.styles.unstyle(C+E);return C+E+A(o.slice(R.length))}return C+E}});var ck=_((a8t,Hhe)=>{\"use strict\";var Eft=Kc(),Cft=Sh(),wft=Z_(),$_=class extends Cft{constructor(e){super({...e,multiple:!0}),this.type=\"form\",this.initial=this.options.initial,this.align=[this.options.align,\"right\"].find(r=>r!=null),this.emptyError=\"\",this.values={}}async reset(e){return await super.reset(),e===!0&&(this._index=this.index),this.index=this._index,this.values={},this.choices.forEach(r=>r.reset&&r.reset()),this.render()}dispatch(e){return!!e&&this.append(e)}append(e){let r=this.focused;if(!r)return this.alert();let{cursor:o,input:a}=r;return r.value=r.input=a.slice(0,o)+e+a.slice(o),r.cursor++,this.render()}delete(){let e=this.focused;if(!e||e.cursor<=0)return this.alert();let{cursor:r,input:o}=e;return e.value=e.input=o.slice(0,r-1)+o.slice(r),e.cursor--,this.render()}deleteForward(){let e=this.focused;if(!e)return this.alert();let{cursor:r,input:o}=e;if(o[r]===void 0)return this.alert();let a=`${o}`.slice(0,r)+`${o}`.slice(r+1);return e.value=e.input=a,this.render()}right(){let e=this.focused;return e?e.cursor>=e.input.length?this.alert():(e.cursor++,this.render()):this.alert()}left(){let e=this.focused;return e?e.cursor<=0?this.alert():(e.cursor--,this.render()):this.alert()}space(e,r){return this.dispatch(e,r)}number(e,r){return this.dispatch(e,r)}next(){let e=this.focused;if(!e)return this.alert();let{initial:r,input:o}=e;return r&&r.startsWith(o)&&o!==r?(e.value=e.input=r,e.cursor=e.value.length,this.render()):super.next()}prev(){let e=this.focused;return e?e.cursor===0?super.prev():(e.value=e.input=\"\",e.cursor=0,this.render()):this.alert()}separator(){return\"\"}format(e){return this.state.submitted?\"\":super.format(e)}pointer(){return\"\"}indicator(e){return e.input?\"\\u29BF\":\"\\u2299\"}async choiceSeparator(e,r){let o=await this.resolve(e.separator,this.state,e,r)||\":\";return o?\" \"+this.styles.disabled(o):\"\"}async renderChoice(e,r){await this.onChoice(e,r);let{state:o,styles:a}=this,{cursor:n,initial:u=\"\",name:A,hint:p,input:h=\"\"}=e,{muted:C,submitted:I,primary:v,danger:x}=a,E=p,R=this.index===r,L=e.validate||(()=>!0),U=await this.choiceSeparator(e,r),z=e.message;this.align===\"right\"&&(z=z.padStart(this.longest+1,\" \")),this.align===\"left\"&&(z=z.padEnd(this.longest+1,\" \"));let te=this.values[A]=h||u,le=h?\"success\":\"dark\";await L.call(e,te,this.state)!==!0&&(le=\"danger\");let he=a[le],Ae=he(await this.indicator(e,r))+(e.pad||\"\"),ye=this.indent(e),ae=()=>[ye,Ae,z+U,h,E].filter(Boolean).join(\" \");if(o.submitted)return z=Eft.unstyle(z),h=I(h),E=\"\",ae();if(e.format)h=await e.format.call(this,h,e,r);else{let Ie=this.styles.muted;h=wft(this,{input:h,initial:u,pos:n,showCursor:R,color:Ie})}return this.isValue(h)||(h=this.styles.muted(this.symbols.ellipsis)),e.result&&(this.values[A]=await e.result.call(this,te,e,r)),R&&(z=v(z)),e.error?h+=(h?\" \":\"\")+x(e.error.trim()):e.hint&&(h+=(h?\" \":\"\")+C(e.hint.trim())),ae()}async submit(){return this.value=this.values,super.base.submit.call(this)}};Hhe.exports=$_});var e8=_((l8t,qhe)=>{\"use strict\";var Ift=ck(),Bft=()=>{throw new Error(\"expected prompt to have a custom authenticate method\")},jhe=(t=Bft)=>{class e extends Ift{constructor(o){super(o)}async submit(){this.value=await t.call(this,this.values,this.state),super.base.submit.call(this)}static create(o){return jhe(o)}}return e};qhe.exports=jhe()});var Whe=_((c8t,Yhe)=>{\"use strict\";var vft=e8();function Dft(t,e){return t.username===this.options.username&&t.password===this.options.password}var Ghe=(t=Dft)=>{let e=[{name:\"username\",message:\"username\"},{name:\"password\",message:\"password\",format(o){return this.options.showPassword?o:(this.state.submitted?this.styles.primary:this.styles.muted)(this.symbols.asterisk.repeat(o.length))}}];class r extends vft.create(t){constructor(a){super({...a,choices:e})}static create(a){return Ghe(a)}}return r};Yhe.exports=Ghe()});var uk=_((u8t,Khe)=>{\"use strict\";var Pft=pC(),{isPrimitive:Sft,hasColor:bft}=No(),t8=class extends Pft{constructor(e){super(e),this.cursorHide()}async initialize(){let e=await this.resolve(this.initial,this.state);this.input=await this.cast(e),await super.initialize()}dispatch(e){return this.isValue(e)?(this.input=e,this.submit()):this.alert()}format(e){let{styles:r,state:o}=this;return o.submitted?r.success(e):r.primary(e)}cast(e){return this.isTrue(e)}isTrue(e){return/^[ty1]/i.test(e)}isFalse(e){return/^[fn0]/i.test(e)}isValue(e){return Sft(e)&&(this.isTrue(e)||this.isFalse(e))}async hint(){if(this.state.status===\"pending\"){let e=await this.element(\"hint\");return bft(e)?e:this.styles.muted(e)}}async render(){let{input:e,size:r}=this.state,o=await this.prefix(),a=await this.separator(),n=await this.message(),u=this.styles.muted(this.default),A=[o,n,u,a].filter(Boolean).join(\" \");this.state.prompt=A;let p=await this.header(),h=this.value=this.cast(e),C=await this.format(h),I=await this.error()||await this.hint(),v=await this.footer();I&&!A.includes(I)&&(C+=\" \"+I),A+=\" \"+C,this.clear(r),this.write([p,A,v].filter(Boolean).join(`\n`)),this.restore()}set value(e){super.value=e}get value(){return this.cast(super.value)}};Khe.exports=t8});var zhe=_((A8t,Vhe)=>{\"use strict\";var xft=uk(),r8=class extends xft{constructor(e){super(e),this.default=this.options.default||(this.initial?\"(Y/n)\":\"(y/N)\")}};Vhe.exports=r8});var Xhe=_((f8t,Jhe)=>{\"use strict\";var kft=Sh(),Qft=ck(),hC=Qft.prototype,n8=class extends kft{constructor(e){super({...e,multiple:!0}),this.align=[this.options.align,\"left\"].find(r=>r!=null),this.emptyError=\"\",this.values={}}dispatch(e,r){let o=this.focused,a=o.parent||{};return!o.editable&&!a.editable&&(e===\"a\"||e===\"i\")?super[e]():hC.dispatch.call(this,e,r)}append(e,r){return hC.append.call(this,e,r)}delete(e,r){return hC.delete.call(this,e,r)}space(e){return this.focused.editable?this.append(e):super.space()}number(e){return this.focused.editable?this.append(e):super.number(e)}next(){return this.focused.editable?hC.next.call(this):super.next()}prev(){return this.focused.editable?hC.prev.call(this):super.prev()}async indicator(e,r){let o=e.indicator||\"\",a=e.editable?o:super.indicator(e,r);return await this.resolve(a,this.state,e,r)||\"\"}indent(e){return e.role===\"heading\"?\"\":e.editable?\" \":\"  \"}async renderChoice(e,r){return e.indent=\"\",e.editable?hC.renderChoice.call(this,e,r):super.renderChoice(e,r)}error(){return\"\"}footer(){return this.state.error}async validate(){let e=!0;for(let r of this.choices){if(typeof r.validate!=\"function\"||r.role===\"heading\")continue;let o=r.parent?this.value[r.parent.name]:this.value;if(r.editable?o=r.value===r.name?r.initial||\"\":r.value:this.isDisabled(r)||(o=r.enabled===!0),e=await r.validate(o,this.state),e!==!0)break}return e!==!0&&(this.state.error=typeof e==\"string\"?e:\"Invalid Input\"),e}submit(){if(this.focused.newChoice===!0)return super.submit();if(this.choices.some(e=>e.newChoice))return this.alert();this.value={};for(let e of this.choices){let r=e.parent?this.value[e.parent.name]:this.value;if(e.role===\"heading\"){this.value[e.name]={};continue}e.editable?r[e.name]=e.value===e.name?e.initial||\"\":e.value:this.isDisabled(e)||(r[e.name]=e.enabled===!0)}return this.base.submit.call(this)}};Jhe.exports=n8});var Gd=_((p8t,Zhe)=>{\"use strict\";var Fft=pC(),Rft=Z_(),{isPrimitive:Tft}=No(),i8=class extends Fft{constructor(e){super(e),this.initial=Tft(this.initial)?String(this.initial):\"\",this.initial&&this.cursorHide(),this.state.prevCursor=0,this.state.clipboard=[]}async keypress(e,r={}){let o=this.state.prevKeypress;return this.state.prevKeypress=r,this.options.multiline===!0&&r.name===\"return\"&&(!o||o.name!==\"return\")?this.append(`\n`,r):super.keypress(e,r)}moveCursor(e){this.cursor+=e}reset(){return this.input=this.value=\"\",this.cursor=0,this.render()}dispatch(e,r){if(!e||r.ctrl||r.code)return this.alert();this.append(e)}append(e){let{cursor:r,input:o}=this.state;this.input=`${o}`.slice(0,r)+e+`${o}`.slice(r),this.moveCursor(String(e).length),this.render()}insert(e){this.append(e)}delete(){let{cursor:e,input:r}=this.state;if(e<=0)return this.alert();this.input=`${r}`.slice(0,e-1)+`${r}`.slice(e),this.moveCursor(-1),this.render()}deleteForward(){let{cursor:e,input:r}=this.state;if(r[e]===void 0)return this.alert();this.input=`${r}`.slice(0,e)+`${r}`.slice(e+1),this.render()}cutForward(){let e=this.cursor;if(this.input.length<=e)return this.alert();this.state.clipboard.push(this.input.slice(e)),this.input=this.input.slice(0,e),this.render()}cutLeft(){let e=this.cursor;if(e===0)return this.alert();let r=this.input.slice(0,e),o=this.input.slice(e),a=r.split(\" \");this.state.clipboard.push(a.pop()),this.input=a.join(\" \"),this.cursor=this.input.length,this.input+=o,this.render()}paste(){if(!this.state.clipboard.length)return this.alert();this.insert(this.state.clipboard.pop()),this.render()}toggleCursor(){this.state.prevCursor?(this.cursor=this.state.prevCursor,this.state.prevCursor=0):(this.state.prevCursor=this.cursor,this.cursor=0),this.render()}first(){this.cursor=0,this.render()}last(){this.cursor=this.input.length-1,this.render()}next(){let e=this.initial!=null?String(this.initial):\"\";if(!e||!e.startsWith(this.input))return this.alert();this.input=this.initial,this.cursor=this.initial.length,this.render()}prev(){if(!this.input)return this.alert();this.reset()}backward(){return this.left()}forward(){return this.right()}right(){return this.cursor>=this.input.length?this.alert():(this.moveCursor(1),this.render())}left(){return this.cursor<=0?this.alert():(this.moveCursor(-1),this.render())}isValue(e){return!!e}async format(e=this.value){let r=await this.resolve(this.initial,this.state);return this.state.submitted?this.styles.submitted(e||r):Rft(this,{input:e,initial:r,pos:this.cursor})}async render(){let e=this.state.size,r=await this.prefix(),o=await this.separator(),a=await this.message(),n=[r,a,o].filter(Boolean).join(\" \");this.state.prompt=n;let u=await this.header(),A=await this.format(),p=await this.error()||await this.hint(),h=await this.footer();p&&!A.includes(p)&&(A+=\" \"+p),n+=\" \"+A,this.clear(e),this.write([u,n,h].filter(Boolean).join(`\n`)),this.restore()}};Zhe.exports=i8});var e0e=_((h8t,$he)=>{\"use strict\";var Nft=t=>t.filter((e,r)=>t.lastIndexOf(e)===r),Ak=t=>Nft(t).filter(Boolean);$he.exports=(t,e={},r=\"\")=>{let{past:o=[],present:a=\"\"}=e,n,u;switch(t){case\"prev\":case\"undo\":return n=o.slice(0,o.length-1),u=o[o.length-1]||\"\",{past:Ak([r,...n]),present:u};case\"next\":case\"redo\":return n=o.slice(1),u=o[0]||\"\",{past:Ak([...n,r]),present:u};case\"save\":return{past:Ak([...o,r]),present:\"\"};case\"remove\":return u=Ak(o.filter(A=>A!==r)),a=\"\",u.length&&(a=u.pop()),{past:u,present:a};default:throw new Error(`Invalid action: \"${t}\"`)}}});var o8=_((g8t,r0e)=>{\"use strict\";var Lft=Gd(),t0e=e0e(),s8=class extends Lft{constructor(e){super(e);let r=this.options.history;if(r&&r.store){let o=r.values||this.initial;this.autosave=!!r.autosave,this.store=r.store,this.data=this.store.get(\"values\")||{past:[],present:o},this.initial=this.data.present||this.data.past[this.data.past.length-1]}}completion(e){return this.store?(this.data=t0e(e,this.data,this.input),this.data.present?(this.input=this.data.present,this.cursor=this.input.length,this.render()):this.alert()):this.alert()}altUp(){return this.completion(\"prev\")}altDown(){return this.completion(\"next\")}prev(){return this.save(),super.prev()}save(){!this.store||(this.data=t0e(\"save\",this.data,this.input),this.store.set(\"values\",this.data))}submit(){return this.store&&this.autosave===!0&&this.save(),super.submit()}};r0e.exports=s8});var i0e=_((d8t,n0e)=>{\"use strict\";var Oft=Gd(),a8=class extends Oft{format(){return\"\"}};n0e.exports=a8});var o0e=_((m8t,s0e)=>{\"use strict\";var Mft=Gd(),l8=class extends Mft{constructor(e={}){super(e),this.sep=this.options.separator||/, */,this.initial=e.initial||\"\"}split(e=this.value){return e?String(e).split(this.sep):[]}format(){let e=this.state.submitted?this.styles.primary:r=>r;return this.list.map(e).join(\", \")}async submit(e){let r=this.state.error||await this.validate(this.list,this.state);return r!==!0?(this.state.error=r,super.submit()):(this.value=this.list,super.submit())}get list(){return this.split()}};s0e.exports=l8});var l0e=_((y8t,a0e)=>{\"use strict\";var Uft=Sh(),c8=class extends Uft{constructor(e){super({...e,multiple:!0})}};a0e.exports=c8});var A8=_((E8t,c0e)=>{\"use strict\";var _ft=Gd(),u8=class extends _ft{constructor(e={}){super({style:\"number\",...e}),this.min=this.isValue(e.min)?this.toNumber(e.min):-1/0,this.max=this.isValue(e.max)?this.toNumber(e.max):1/0,this.delay=e.delay!=null?e.delay:1e3,this.float=e.float!==!1,this.round=e.round===!0||e.float===!1,this.major=e.major||10,this.minor=e.minor||1,this.initial=e.initial!=null?e.initial:\"\",this.input=String(this.initial),this.cursor=this.input.length,this.cursorShow()}append(e){return!/[-+.]/.test(e)||e===\".\"&&this.input.includes(\".\")?this.alert(\"invalid number\"):super.append(e)}number(e){return super.append(e)}next(){return this.input&&this.input!==this.initial?this.alert():this.isValue(this.initial)?(this.input=this.initial,this.cursor=String(this.initial).length,this.render()):this.alert()}up(e){let r=e||this.minor,o=this.toNumber(this.input);return o>this.max+r?this.alert():(this.input=`${o+r}`,this.render())}down(e){let r=e||this.minor,o=this.toNumber(this.input);return o<this.min-r?this.alert():(this.input=`${o-r}`,this.render())}shiftDown(){return this.down(this.major)}shiftUp(){return this.up(this.major)}format(e=this.input){return typeof this.options.format==\"function\"?this.options.format.call(this,e):this.styles.info(e)}toNumber(e=\"\"){return this.float?+e:Math.round(+e)}isValue(e){return/^[-+]?[0-9]+((\\.)|(\\.[0-9]+))?$/.test(e)}submit(){let e=[this.input,this.initial].find(r=>this.isValue(r));return this.value=this.toNumber(e||0),super.submit()}};c0e.exports=u8});var A0e=_((C8t,u0e)=>{u0e.exports=A8()});var p0e=_((w8t,f0e)=>{\"use strict\";var Hft=Gd(),f8=class extends Hft{constructor(e){super(e),this.cursorShow()}format(e=this.input){return this.keypressed?(this.state.submitted?this.styles.primary:this.styles.muted)(this.symbols.asterisk.repeat(e.length)):\"\"}};f0e.exports=f8});var d0e=_((I8t,g0e)=>{\"use strict\";var jft=Kc(),qft=l2(),h0e=No(),p8=class extends qft{constructor(e={}){super(e),this.widths=[].concat(e.messageWidth||50),this.align=[].concat(e.align||\"left\"),this.linebreak=e.linebreak||!1,this.edgeLength=e.edgeLength||3,this.newline=e.newline||`\n   `;let r=e.startNumber||1;typeof this.scale==\"number\"&&(this.scaleKey=!1,this.scale=Array(this.scale).fill(0).map((o,a)=>({name:a+r})))}async reset(){return this.tableized=!1,await super.reset(),this.render()}tableize(){if(this.tableized===!0)return;this.tableized=!0;let e=0;for(let r of this.choices){e=Math.max(e,r.message.length),r.scaleIndex=r.initial||2,r.scale=[];for(let o=0;o<this.scale.length;o++)r.scale.push({index:o})}this.widths[0]=Math.min(this.widths[0],e+3)}async dispatch(e,r){if(this.multiple)return this[r.name]?await this[r.name](e,r):await super.dispatch(e,r);this.alert()}heading(e,r,o){return this.styles.strong(e)}separator(){return this.styles.muted(this.symbols.ellipsis)}right(){let e=this.focused;return e.scaleIndex>=this.scale.length-1?this.alert():(e.scaleIndex++,this.render())}left(){let e=this.focused;return e.scaleIndex<=0?this.alert():(e.scaleIndex--,this.render())}indent(){return\"\"}format(){return this.state.submitted?this.choices.map(r=>this.styles.info(r.index)).join(\", \"):\"\"}pointer(){return\"\"}renderScaleKey(){return this.scaleKey===!1||this.state.submitted?\"\":[\"\",...this.scale.map(o=>`   ${o.name} - ${o.message}`)].map(o=>this.styles.muted(o)).join(`\n`)}renderScaleHeading(e){let r=this.scale.map(p=>p.name);typeof this.options.renderScaleHeading==\"function\"&&(r=this.options.renderScaleHeading.call(this,e));let o=this.scaleLength-r.join(\"\").length,a=Math.round(o/(r.length-1)),u=r.map(p=>this.styles.strong(p)).join(\" \".repeat(a)),A=\" \".repeat(this.widths[0]);return this.margin[3]+A+this.margin[1]+u}scaleIndicator(e,r,o){if(typeof this.options.scaleIndicator==\"function\")return this.options.scaleIndicator.call(this,e,r,o);let a=e.scaleIndex===r.index;return r.disabled?this.styles.hint(this.symbols.radio.disabled):a?this.styles.success(this.symbols.radio.on):this.symbols.radio.off}renderScale(e,r){let o=e.scale.map(n=>this.scaleIndicator(e,n,r)),a=this.term===\"Hyper\"?\"\":\" \";return o.join(a+this.symbols.line.repeat(this.edgeLength))}async renderChoice(e,r){await this.onChoice(e,r);let o=this.index===r,a=await this.pointer(e,r),n=await e.hint;n&&!h0e.hasColor(n)&&(n=this.styles.muted(n));let u=E=>this.margin[3]+E.replace(/\\s+$/,\"\").padEnd(this.widths[0],\" \"),A=this.newline,p=this.indent(e),h=await this.resolve(e.message,this.state,e,r),C=await this.renderScale(e,r),I=this.margin[1]+this.margin[3];this.scaleLength=jft.unstyle(C).length,this.widths[0]=Math.min(this.widths[0],this.width-this.scaleLength-I.length);let x=h0e.wordWrap(h,{width:this.widths[0],newline:A}).split(`\n`).map(E=>u(E)+this.margin[1]);return o&&(C=this.styles.info(C),x=x.map(E=>this.styles.info(E))),x[0]+=C,this.linebreak&&x.push(\"\"),[p+a,x.join(`\n`)].filter(Boolean)}async renderChoices(){if(this.state.submitted)return\"\";this.tableize();let e=this.visible.map(async(a,n)=>await this.renderChoice(a,n)),r=await Promise.all(e),o=await this.renderScaleHeading();return this.margin[0]+[o,...r.map(a=>a.join(\" \"))].join(`\n`)}async render(){let{submitted:e,size:r}=this.state,o=await this.prefix(),a=await this.separator(),n=await this.message(),u=\"\";this.options.promptLine!==!1&&(u=[o,n,a,\"\"].join(\" \"),this.state.prompt=u);let A=await this.header(),p=await this.format(),h=await this.renderScaleKey(),C=await this.error()||await this.hint(),I=await this.renderChoices(),v=await this.footer(),x=this.emptyError;p&&(u+=p),C&&!u.includes(C)&&(u+=\" \"+C),e&&!p&&!I.trim()&&this.multiple&&x!=null&&(u+=this.styles.danger(x)),this.clear(r),this.write([A,u,h,I,v].filter(Boolean).join(`\n`)),this.state.submitted||this.write(this.margin[2]),this.restore()}submit(){this.value={};for(let e of this.choices)this.value[e.name]=e.scaleIndex;return this.base.submit.call(this)}};g0e.exports=p8});var E0e=_((B8t,y0e)=>{\"use strict\";var m0e=Kc(),Gft=(t=\"\")=>typeof t==\"string\"?t.replace(/^['\"]|['\"]$/g,\"\"):\"\",g8=class{constructor(e){this.name=e.key,this.field=e.field||{},this.value=Gft(e.initial||this.field.initial||\"\"),this.message=e.message||this.name,this.cursor=0,this.input=\"\",this.lines=[]}},Yft=async(t={},e={},r=o=>o)=>{let o=new Set,a=t.fields||[],n=t.template,u=[],A=[],p=[],h=1;typeof n==\"function\"&&(n=await n());let C=-1,I=()=>n[++C],v=()=>n[C+1],x=E=>{E.line=h,u.push(E)};for(x({type:\"bos\",value:\"\"});C<n.length-1;){let E=I();if(/^[^\\S\\n ]$/.test(E)){x({type:\"text\",value:E});continue}if(E===`\n`){x({type:\"newline\",value:E}),h++;continue}if(E===\"\\\\\"){E+=I(),x({type:\"text\",value:E});continue}if((E===\"$\"||E===\"#\"||E===\"{\")&&v()===\"{\"){let L=I();E+=L;let U={type:\"template\",open:E,inner:\"\",close:\"\",value:E},z;for(;z=I();){if(z===\"}\"){v()===\"}\"&&(z+=I()),U.value+=z,U.close=z;break}z===\":\"?(U.initial=\"\",U.key=U.inner):U.initial!==void 0&&(U.initial+=z),U.value+=z,U.inner+=z}U.template=U.open+(U.initial||U.inner)+U.close,U.key=U.key||U.inner,e.hasOwnProperty(U.key)&&(U.initial=e[U.key]),U=r(U),x(U),p.push(U.key),o.add(U.key);let te=A.find(le=>le.name===U.key);U.field=a.find(le=>le.name===U.key),te||(te=new g8(U),A.push(te)),te.lines.push(U.line-1);continue}let R=u[u.length-1];R.type===\"text\"&&R.line===h?R.value+=E:x({type:\"text\",value:E})}return x({type:\"eos\",value:\"\"}),{input:n,tabstops:u,unique:o,keys:p,items:A}};y0e.exports=async t=>{let e=t.options,r=new Set(e.required===!0?[]:e.required||[]),o={...e.values,...e.initial},{tabstops:a,items:n,keys:u}=await Yft(e,o),A=h8(\"result\",t,e),p=h8(\"format\",t,e),h=h8(\"validate\",t,e,!0),C=t.isValue.bind(t);return async(I={},v=!1)=>{let x=0;I.required=r,I.items=n,I.keys=u,I.output=\"\";let E=async(z,te,le,he)=>{let Ae=await h(z,te,le,he);return Ae===!1?\"Invalid field \"+le.name:Ae};for(let z of a){let te=z.value,le=z.key;if(z.type!==\"template\"){te&&(I.output+=te);continue}if(z.type===\"template\"){let he=n.find(Fe=>Fe.name===le);e.required===!0&&I.required.add(he.name);let Ae=[he.input,I.values[he.value],he.value,te].find(C),ae=(he.field||{}).message||z.inner;if(v){let Fe=await E(I.values[le],I,he,x);if(Fe&&typeof Fe==\"string\"||Fe===!1){I.invalid.set(le,Fe);continue}I.invalid.delete(le);let g=await A(I.values[le],I,he,x);I.output+=m0e.unstyle(g);continue}he.placeholder=!1;let Ie=te;te=await p(te,I,he,x),Ae!==te?(I.values[le]=Ae,te=t.styles.typing(Ae),I.missing.delete(ae)):(I.values[le]=void 0,Ae=`<${ae}>`,te=t.styles.primary(Ae),he.placeholder=!0,I.required.has(le)&&I.missing.add(ae)),I.missing.has(ae)&&I.validating&&(te=t.styles.warning(Ae)),I.invalid.has(le)&&I.validating&&(te=t.styles.danger(Ae)),x===I.index&&(Ie!==te?te=t.styles.underline(te):te=t.styles.heading(m0e.unstyle(te))),x++}te&&(I.output+=te)}let R=I.output.split(`\n`).map(z=>\" \"+z),L=n.length,U=0;for(let z of n)I.invalid.has(z.name)&&z.lines.forEach(te=>{R[te][0]===\" \"&&(R[te]=I.styles.danger(I.symbols.bullet)+R[te].slice(1))}),t.isValue(I.values[z.name])&&U++;return I.completed=(U/L*100).toFixed(0),I.output=R.join(`\n`),I.output}};function h8(t,e,r,o){return(a,n,u,A)=>typeof u.field[t]==\"function\"?u.field[t].call(e,a,n,u,A):[o,a].find(p=>e.isValue(p))}});var w0e=_((v8t,C0e)=>{\"use strict\";var Wft=Kc(),Kft=E0e(),Vft=pC(),d8=class extends Vft{constructor(e){super(e),this.cursorHide(),this.reset(!0)}async initialize(){this.interpolate=await Kft(this),await super.initialize()}async reset(e){this.state.keys=[],this.state.invalid=new Map,this.state.missing=new Set,this.state.completed=0,this.state.values={},e!==!0&&(await this.initialize(),await this.render())}moveCursor(e){let r=this.getItem();this.cursor+=e,r.cursor+=e}dispatch(e,r){if(!r.code&&!r.ctrl&&e!=null&&this.getItem()){this.append(e,r);return}this.alert()}append(e,r){let o=this.getItem(),a=o.input.slice(0,this.cursor),n=o.input.slice(this.cursor);this.input=o.input=`${a}${e}${n}`,this.moveCursor(1),this.render()}delete(){let e=this.getItem();if(this.cursor<=0||!e.input)return this.alert();let r=e.input.slice(this.cursor),o=e.input.slice(0,this.cursor-1);this.input=e.input=`${o}${r}`,this.moveCursor(-1),this.render()}increment(e){return e>=this.state.keys.length-1?0:e+1}decrement(e){return e<=0?this.state.keys.length-1:e-1}first(){this.state.index=0,this.render()}last(){this.state.index=this.state.keys.length-1,this.render()}right(){if(this.cursor>=this.input.length)return this.alert();this.moveCursor(1),this.render()}left(){if(this.cursor<=0)return this.alert();this.moveCursor(-1),this.render()}prev(){this.state.index=this.decrement(this.state.index),this.getItem(),this.render()}next(){this.state.index=this.increment(this.state.index),this.getItem(),this.render()}up(){this.prev()}down(){this.next()}format(e){let r=this.state.completed<100?this.styles.warning:this.styles.success;return this.state.submitted===!0&&this.state.completed!==100&&(r=this.styles.danger),r(`${this.state.completed}% completed`)}async render(){let{index:e,keys:r=[],submitted:o,size:a}=this.state,n=[this.options.newline,`\n`].find(z=>z!=null),u=await this.prefix(),A=await this.separator(),p=await this.message(),h=[u,p,A].filter(Boolean).join(\" \");this.state.prompt=h;let C=await this.header(),I=await this.error()||\"\",v=await this.hint()||\"\",x=o?\"\":await this.interpolate(this.state),E=this.state.key=r[e]||\"\",R=await this.format(E),L=await this.footer();R&&(h+=\" \"+R),v&&!R&&this.state.completed===0&&(h+=\" \"+v),this.clear(a);let U=[C,h,x,L,I.trim()];this.write(U.filter(Boolean).join(n)),this.restore()}getItem(e){let{items:r,keys:o,index:a}=this.state,n=r.find(u=>u.name===o[a]);return n&&n.input!=null&&(this.input=n.input,this.cursor=n.cursor),n}async submit(){typeof this.interpolate!=\"function\"&&await this.initialize(),await this.interpolate(this.state,!0);let{invalid:e,missing:r,output:o,values:a}=this.state;if(e.size){let A=\"\";for(let[p,h]of e)A+=`Invalid ${p}: ${h}\n`;return this.state.error=A,super.submit()}if(r.size)return this.state.error=\"Required: \"+[...r.keys()].join(\", \"),super.submit();let u=Wft.unstyle(o).split(`\n`).map(A=>A.slice(1)).join(`\n`);return this.value={values:a,result:u},super.submit()}};C0e.exports=d8});var B0e=_((D8t,I0e)=>{\"use strict\";var zft=\"(Use <shift>+<up/down> to sort)\",Jft=Sh(),m8=class extends Jft{constructor(e){super({...e,reorder:!1,sort:!0,multiple:!0}),this.state.hint=[this.options.hint,zft].find(this.isValue.bind(this))}indicator(){return\"\"}async renderChoice(e,r){let o=await super.renderChoice(e,r),a=this.symbols.identicalTo+\" \",n=this.index===r&&this.sorting?this.styles.muted(a):\"  \";return this.options.drag===!1&&(n=\"\"),this.options.numbered===!0?n+`${r+1} - `+o:n+o}get selected(){return this.choices}submit(){return this.value=this.choices.map(e=>e.value),super.submit()}};I0e.exports=m8});var D0e=_((P8t,v0e)=>{\"use strict\";var Xft=l2(),y8=class extends Xft{constructor(e={}){if(super(e),this.emptyError=e.emptyError||\"No items were selected\",this.term=process.env.TERM_PROGRAM,!this.options.header){let r=[\"\",\"4 - Strongly Agree\",\"3 - Agree\",\"2 - Neutral\",\"1 - Disagree\",\"0 - Strongly Disagree\",\"\"];r=r.map(o=>this.styles.muted(o)),this.state.header=r.join(`\n   `)}}async toChoices(...e){if(this.createdScales)return!1;this.createdScales=!0;let r=await super.toChoices(...e);for(let o of r)o.scale=Zft(5,this.options),o.scaleIdx=2;return r}dispatch(){this.alert()}space(){let e=this.focused,r=e.scale[e.scaleIdx],o=r.selected;return e.scale.forEach(a=>a.selected=!1),r.selected=!o,this.render()}indicator(){return\"\"}pointer(){return\"\"}separator(){return this.styles.muted(this.symbols.ellipsis)}right(){let e=this.focused;return e.scaleIdx>=e.scale.length-1?this.alert():(e.scaleIdx++,this.render())}left(){let e=this.focused;return e.scaleIdx<=0?this.alert():(e.scaleIdx--,this.render())}indent(){return\"   \"}async renderChoice(e,r){await this.onChoice(e,r);let o=this.index===r,a=this.term===\"Hyper\",n=a?9:8,u=a?\"\":\" \",A=this.symbols.line.repeat(n),p=\" \".repeat(n+(a?0:1)),h=te=>(te?this.styles.success(\"\\u25C9\"):\"\\u25EF\")+u,C=r+1+\".\",I=o?this.styles.heading:this.styles.noop,v=await this.resolve(e.message,this.state,e,r),x=this.indent(e),E=x+e.scale.map((te,le)=>h(le===e.scaleIdx)).join(A),R=te=>te===e.scaleIdx?I(te):te,L=x+e.scale.map((te,le)=>R(le)).join(p),U=()=>[C,v].filter(Boolean).join(\" \"),z=()=>[U(),E,L,\" \"].filter(Boolean).join(`\n`);return o&&(E=this.styles.cyan(E),L=this.styles.cyan(L)),z()}async renderChoices(){if(this.state.submitted)return\"\";let e=this.visible.map(async(o,a)=>await this.renderChoice(o,a)),r=await Promise.all(e);return r.length||r.push(this.styles.danger(\"No matching choices\")),r.join(`\n`)}format(){return this.state.submitted?this.choices.map(r=>this.styles.info(r.scaleIdx)).join(\", \"):\"\"}async render(){let{submitted:e,size:r}=this.state,o=await this.prefix(),a=await this.separator(),n=await this.message(),u=[o,n,a].filter(Boolean).join(\" \");this.state.prompt=u;let A=await this.header(),p=await this.format(),h=await this.error()||await this.hint(),C=await this.renderChoices(),I=await this.footer();(p||!h)&&(u+=\" \"+p),h&&!u.includes(h)&&(u+=\" \"+h),e&&!p&&!C&&this.multiple&&this.type!==\"form\"&&(u+=this.styles.danger(this.emptyError)),this.clear(r),this.write([u,A,C,I].filter(Boolean).join(`\n`)),this.restore()}submit(){this.value={};for(let e of this.choices)this.value[e.name]=e.scaleIdx;return this.base.submit.call(this)}};function Zft(t,e={}){if(Array.isArray(e.scale))return e.scale.map(o=>({...o}));let r=[];for(let o=1;o<t+1;o++)r.push({i:o,selected:!1});return r}v0e.exports=y8});var S0e=_((S8t,P0e)=>{P0e.exports=o8()});var x0e=_((b8t,b0e)=>{\"use strict\";var $ft=uk(),E8=class extends $ft{async initialize(){await super.initialize(),this.value=this.initial=!!this.options.initial,this.disabled=this.options.disabled||\"no\",this.enabled=this.options.enabled||\"yes\",await this.render()}reset(){this.value=this.initial,this.render()}delete(){this.alert()}toggle(){this.value=!this.value,this.render()}enable(){if(this.value===!0)return this.alert();this.value=!0,this.render()}disable(){if(this.value===!1)return this.alert();this.value=!1,this.render()}up(){this.toggle()}down(){this.toggle()}right(){this.toggle()}left(){this.toggle()}next(){this.toggle()}prev(){this.toggle()}dispatch(e=\"\",r){switch(e.toLowerCase()){case\" \":return this.toggle();case\"1\":case\"y\":case\"t\":return this.enable();case\"0\":case\"n\":case\"f\":return this.disable();default:return this.alert()}}format(){let e=o=>this.styles.primary.underline(o);return[this.value?this.disabled:e(this.disabled),this.value?e(this.enabled):this.enabled].join(this.styles.muted(\" / \"))}async render(){let{size:e}=this.state,r=await this.header(),o=await this.prefix(),a=await this.separator(),n=await this.message(),u=await this.format(),A=await this.error()||await this.hint(),p=await this.footer(),h=[o,n,a,u].join(\" \");this.state.prompt=h,A&&!h.includes(A)&&(h+=\" \"+A),this.clear(e),this.write([r,h,p].filter(Boolean).join(`\n`)),this.write(this.margin[2]),this.restore()}};b0e.exports=E8});var Q0e=_((x8t,k0e)=>{\"use strict\";var ept=Sh(),C8=class extends ept{constructor(e){if(super(e),typeof this.options.correctChoice!=\"number\"||this.options.correctChoice<0)throw new Error(\"Please specify the index of the correct answer from the list of choices\")}async toChoices(e,r){let o=await super.toChoices(e,r);if(o.length<2)throw new Error(\"Please give at least two choices to the user\");if(this.options.correctChoice>o.length)throw new Error(\"Please specify the index of the correct answer from the list of choices\");return o}check(e){return e.index===this.options.correctChoice}async result(e){return{selectedAnswer:e,correctAnswer:this.options.choices[this.options.correctChoice].value,correct:await this.check(this.state)}}};k0e.exports=C8});var R0e=_(w8=>{\"use strict\";var F0e=No(),As=(t,e)=>{F0e.defineExport(w8,t,e),F0e.defineExport(w8,t.toLowerCase(),e)};As(\"AutoComplete\",()=>Uhe());As(\"BasicAuth\",()=>Whe());As(\"Confirm\",()=>zhe());As(\"Editable\",()=>Xhe());As(\"Form\",()=>ck());As(\"Input\",()=>o8());As(\"Invisible\",()=>i0e());As(\"List\",()=>o0e());As(\"MultiSelect\",()=>l0e());As(\"Numeral\",()=>A0e());As(\"Password\",()=>p0e());As(\"Scale\",()=>d0e());As(\"Select\",()=>Sh());As(\"Snippet\",()=>w0e());As(\"Sort\",()=>B0e());As(\"Survey\",()=>D0e());As(\"Text\",()=>S0e());As(\"Toggle\",()=>x0e());As(\"Quiz\",()=>Q0e())});var N0e=_((Q8t,T0e)=>{T0e.exports={ArrayPrompt:l2(),AuthPrompt:e8(),BooleanPrompt:uk(),NumberPrompt:A8(),StringPrompt:Gd()}});var u2=_((F8t,O0e)=>{\"use strict\";var L0e=Be(\"assert\"),B8=Be(\"events\"),bh=No(),zc=class extends B8{constructor(e,r){super(),this.options=bh.merge({},e),this.answers={...r}}register(e,r){if(bh.isObject(e)){for(let a of Object.keys(e))this.register(a,e[a]);return this}L0e.equal(typeof r,\"function\",\"expected a function\");let o=e.toLowerCase();return r.prototype instanceof this.Prompt?this.prompts[o]=r:this.prompts[o]=r(this.Prompt,this),this}async prompt(e=[]){for(let r of[].concat(e))try{typeof r==\"function\"&&(r=await r.call(this)),await this.ask(bh.merge({},this.options,r))}catch(o){return Promise.reject(o)}return this.answers}async ask(e){typeof e==\"function\"&&(e=await e.call(this));let r=bh.merge({},this.options,e),{type:o,name:a}=e,{set:n,get:u}=bh;if(typeof o==\"function\"&&(o=await o.call(this,e,this.answers)),!o)return this.answers[a];L0e(this.prompts[o],`Prompt \"${o}\" is not registered`);let A=new this.prompts[o](r),p=u(this.answers,a);A.state.answers=this.answers,A.enquirer=this,a&&A.on(\"submit\",C=>{this.emit(\"answer\",a,C,A),n(this.answers,a,C)});let h=A.emit.bind(A);return A.emit=(...C)=>(this.emit.call(this,...C),h(...C)),this.emit(\"prompt\",A,this),r.autofill&&p!=null?(A.value=A.input=p,r.autofill===\"show\"&&await A.submit()):p=A.value=await A.run(),p}use(e){return e.call(this,this),this}set Prompt(e){this._Prompt=e}get Prompt(){return this._Prompt||this.constructor.Prompt}get prompts(){return this.constructor.prompts}static set Prompt(e){this._Prompt=e}static get Prompt(){return this._Prompt||pC()}static get prompts(){return R0e()}static get types(){return N0e()}static get prompt(){let e=(r,...o)=>{let a=new this(...o),n=a.emit.bind(a);return a.emit=(...u)=>(e.emit(...u),n(...u)),a.prompt(r)};return bh.mixinEmitter(e,new B8),e}};bh.mixinEmitter(zc,new B8);var I8=zc.prompts;for(let t of Object.keys(I8)){let e=t.toLowerCase(),r=o=>new I8[t](o).run();zc.prompt[e]=r,zc[e]=r,zc[t]||Reflect.defineProperty(zc,t,{get:()=>I8[t]})}var c2=t=>{bh.defineExport(zc,t,()=>zc.types[t])};c2(\"ArrayPrompt\");c2(\"AuthPrompt\");c2(\"BooleanPrompt\");c2(\"NumberPrompt\");c2(\"StringPrompt\");O0e.exports=zc});var h2=_((hHt,G0e)=>{var opt=Zx();function apt(t,e,r){var o=t==null?void 0:opt(t,e);return o===void 0?r:o}G0e.exports=apt});var K0e=_((CHt,W0e)=>{function lpt(t,e){for(var r=-1,o=t==null?0:t.length;++r<o&&e(t[r],r,t)!==!1;);return t}W0e.exports=lpt});var z0e=_((wHt,V0e)=>{var cpt=hd(),upt=JP();function Apt(t,e){return t&&cpt(e,upt(e),t)}V0e.exports=Apt});var X0e=_((IHt,J0e)=>{var fpt=hd(),ppt=jy();function hpt(t,e){return t&&fpt(e,ppt(e),t)}J0e.exports=hpt});var $0e=_((BHt,Z0e)=>{var gpt=hd(),dpt=GP();function mpt(t,e){return gpt(t,dpt(t),e)}Z0e.exports=mpt});var x8=_((vHt,ege)=>{var ypt=qP(),Ept=tS(),Cpt=GP(),wpt=VN(),Ipt=Object.getOwnPropertySymbols,Bpt=Ipt?function(t){for(var e=[];t;)ypt(e,Cpt(t)),t=Ept(t);return e}:wpt;ege.exports=Bpt});var rge=_((DHt,tge)=>{var vpt=hd(),Dpt=x8();function Ppt(t,e){return vpt(t,Dpt(t),e)}tge.exports=Ppt});var k8=_((PHt,nge)=>{var Spt=KN(),bpt=x8(),xpt=jy();function kpt(t){return Spt(t,xpt,bpt)}nge.exports=kpt});var sge=_((SHt,ige)=>{var Qpt=Object.prototype,Fpt=Qpt.hasOwnProperty;function Rpt(t){var e=t.length,r=new t.constructor(e);return e&&typeof t[0]==\"string\"&&Fpt.call(t,\"index\")&&(r.index=t.index,r.input=t.input),r}ige.exports=Rpt});var age=_((bHt,oge)=>{var Tpt=$P();function Npt(t,e){var r=e?Tpt(t.buffer):t.buffer;return new t.constructor(r,t.byteOffset,t.byteLength)}oge.exports=Npt});var cge=_((xHt,lge)=>{var Lpt=/\\w*$/;function Opt(t){var e=new t.constructor(t.source,Lpt.exec(t));return e.lastIndex=t.lastIndex,e}lge.exports=Opt});var hge=_((kHt,pge)=>{var uge=Ad(),Age=uge?uge.prototype:void 0,fge=Age?Age.valueOf:void 0;function Mpt(t){return fge?Object(fge.call(t)):{}}pge.exports=Mpt});var dge=_((QHt,gge)=>{var Upt=$P(),_pt=age(),Hpt=cge(),jpt=hge(),qpt=lL(),Gpt=\"[object Boolean]\",Ypt=\"[object Date]\",Wpt=\"[object Map]\",Kpt=\"[object Number]\",Vpt=\"[object RegExp]\",zpt=\"[object Set]\",Jpt=\"[object String]\",Xpt=\"[object Symbol]\",Zpt=\"[object ArrayBuffer]\",$pt=\"[object DataView]\",eht=\"[object Float32Array]\",tht=\"[object Float64Array]\",rht=\"[object Int8Array]\",nht=\"[object Int16Array]\",iht=\"[object Int32Array]\",sht=\"[object Uint8Array]\",oht=\"[object Uint8ClampedArray]\",aht=\"[object Uint16Array]\",lht=\"[object Uint32Array]\";function cht(t,e,r){var o=t.constructor;switch(e){case Zpt:return Upt(t);case Gpt:case Ypt:return new o(+t);case $pt:return _pt(t,r);case eht:case tht:case rht:case nht:case iht:case sht:case oht:case aht:case lht:return qpt(t,r);case Wpt:return new o;case Kpt:case Jpt:return new o(t);case Vpt:return Hpt(t);case zpt:return new o;case Xpt:return jpt(t)}}gge.exports=cht});var yge=_((FHt,mge)=>{var uht=jI(),Aht=zu(),fht=\"[object Map]\";function pht(t){return Aht(t)&&uht(t)==fht}mge.exports=pht});var Ige=_((RHt,wge)=>{var hht=yge(),ght=WP(),Ege=KP(),Cge=Ege&&Ege.isMap,dht=Cge?ght(Cge):hht;wge.exports=dht});var vge=_((THt,Bge)=>{var mht=jI(),yht=zu(),Eht=\"[object Set]\";function Cht(t){return yht(t)&&mht(t)==Eht}Bge.exports=Cht});var bge=_((NHt,Sge)=>{var wht=vge(),Iht=WP(),Dge=KP(),Pge=Dge&&Dge.isSet,Bht=Pge?Iht(Pge):wht;Sge.exports=Bht});var Q8=_((LHt,Fge)=>{var vht=HP(),Dht=K0e(),Pht=rS(),Sht=z0e(),bht=X0e(),xht=aL(),kht=eS(),Qht=$0e(),Fht=rge(),Rht=ZN(),Tht=k8(),Nht=jI(),Lht=sge(),Oht=dge(),Mht=cL(),Uht=Hl(),_ht=OI(),Hht=Ige(),jht=il(),qht=bge(),Ght=JP(),Yht=jy(),Wht=1,Kht=2,Vht=4,xge=\"[object Arguments]\",zht=\"[object Array]\",Jht=\"[object Boolean]\",Xht=\"[object Date]\",Zht=\"[object Error]\",kge=\"[object Function]\",$ht=\"[object GeneratorFunction]\",e0t=\"[object Map]\",t0t=\"[object Number]\",Qge=\"[object Object]\",r0t=\"[object RegExp]\",n0t=\"[object Set]\",i0t=\"[object String]\",s0t=\"[object Symbol]\",o0t=\"[object WeakMap]\",a0t=\"[object ArrayBuffer]\",l0t=\"[object DataView]\",c0t=\"[object Float32Array]\",u0t=\"[object Float64Array]\",A0t=\"[object Int8Array]\",f0t=\"[object Int16Array]\",p0t=\"[object Int32Array]\",h0t=\"[object Uint8Array]\",g0t=\"[object Uint8ClampedArray]\",d0t=\"[object Uint16Array]\",m0t=\"[object Uint32Array]\",ri={};ri[xge]=ri[zht]=ri[a0t]=ri[l0t]=ri[Jht]=ri[Xht]=ri[c0t]=ri[u0t]=ri[A0t]=ri[f0t]=ri[p0t]=ri[e0t]=ri[t0t]=ri[Qge]=ri[r0t]=ri[n0t]=ri[i0t]=ri[s0t]=ri[h0t]=ri[g0t]=ri[d0t]=ri[m0t]=!0;ri[Zht]=ri[kge]=ri[o0t]=!1;function pk(t,e,r,o,a,n){var u,A=e&Wht,p=e&Kht,h=e&Vht;if(r&&(u=a?r(t,o,a,n):r(t)),u!==void 0)return u;if(!jht(t))return t;var C=Uht(t);if(C){if(u=Lht(t),!A)return kht(t,u)}else{var I=Nht(t),v=I==kge||I==$ht;if(_ht(t))return xht(t,A);if(I==Qge||I==xge||v&&!a){if(u=p||v?{}:Mht(t),!A)return p?Fht(t,bht(u,t)):Qht(t,Sht(u,t))}else{if(!ri[I])return a?t:{};u=Oht(t,I,A)}}n||(n=new vht);var x=n.get(t);if(x)return x;n.set(t,u),qht(t)?t.forEach(function(L){u.add(pk(L,e,r,L,t,n))}):Hht(t)&&t.forEach(function(L,U){u.set(U,pk(L,e,r,U,t,n))});var E=h?p?Tht:Rht:p?Yht:Ght,R=C?void 0:E(t);return Dht(R||t,function(L,U){R&&(U=L,L=t[U]),Pht(u,U,pk(L,e,r,U,t,n))}),u}Fge.exports=pk});var F8=_((OHt,Rge)=>{var y0t=Q8(),E0t=1,C0t=4;function w0t(t){return y0t(t,E0t|C0t)}Rge.exports=w0t});var R8=_((MHt,Tge)=>{var I0t=v_();function B0t(t,e,r){return t==null?t:I0t(t,e,r)}Tge.exports=B0t});var Uge=_((GHt,Mge)=>{var v0t=Object.prototype,D0t=v0t.hasOwnProperty;function P0t(t,e){return t!=null&&D0t.call(t,e)}Mge.exports=P0t});var Hge=_((YHt,_ge)=>{var S0t=Uge(),b0t=D_();function x0t(t,e){return t!=null&&b0t(t,e,S0t)}_ge.exports=x0t});var qge=_((WHt,jge)=>{function k0t(t){var e=t==null?0:t.length;return e?t[e-1]:void 0}jge.exports=k0t});var Yge=_((KHt,Gge)=>{var Q0t=Zx(),F0t=gU();function R0t(t,e){return e.length<2?t:Q0t(t,F0t(e,0,-1))}Gge.exports=R0t});var N8=_((VHt,Wge)=>{var T0t=Hd(),N0t=qge(),L0t=Yge(),O0t=oC();function M0t(t,e){return e=T0t(e,t),t=L0t(t,e),t==null||delete t[O0t(N0t(e))]}Wge.exports=M0t});var L8=_((zHt,Kge)=>{var U0t=N8();function _0t(t,e){return t==null?!0:U0t(t,e)}Kge.exports=_0t});var Zge=_((v6t,q0t)=>{q0t.exports={name:\"@yarnpkg/cli\",version:\"4.0.1\",license:\"BSD-2-Clause\",main:\"./sources/index.ts\",exports:{\".\":\"./sources/index.ts\",\"./polyfills\":\"./sources/polyfills.ts\",\"./package.json\":\"./package.json\"},dependencies:{\"@yarnpkg/core\":\"workspace:^\",\"@yarnpkg/fslib\":\"workspace:^\",\"@yarnpkg/libzip\":\"workspace:^\",\"@yarnpkg/parsers\":\"workspace:^\",\"@yarnpkg/plugin-compat\":\"workspace:^\",\"@yarnpkg/plugin-constraints\":\"workspace:^\",\"@yarnpkg/plugin-dlx\":\"workspace:^\",\"@yarnpkg/plugin-essentials\":\"workspace:^\",\"@yarnpkg/plugin-exec\":\"workspace:^\",\"@yarnpkg/plugin-file\":\"workspace:^\",\"@yarnpkg/plugin-git\":\"workspace:^\",\"@yarnpkg/plugin-github\":\"workspace:^\",\"@yarnpkg/plugin-http\":\"workspace:^\",\"@yarnpkg/plugin-init\":\"workspace:^\",\"@yarnpkg/plugin-interactive-tools\":\"workspace:^\",\"@yarnpkg/plugin-link\":\"workspace:^\",\"@yarnpkg/plugin-nm\":\"workspace:^\",\"@yarnpkg/plugin-npm\":\"workspace:^\",\"@yarnpkg/plugin-npm-cli\":\"workspace:^\",\"@yarnpkg/plugin-pack\":\"workspace:^\",\"@yarnpkg/plugin-patch\":\"workspace:^\",\"@yarnpkg/plugin-pnp\":\"workspace:^\",\"@yarnpkg/plugin-pnpm\":\"workspace:^\",\"@yarnpkg/plugin-stage\":\"workspace:^\",\"@yarnpkg/plugin-typescript\":\"workspace:^\",\"@yarnpkg/plugin-version\":\"workspace:^\",\"@yarnpkg/plugin-workspace-tools\":\"workspace:^\",\"@yarnpkg/shell\":\"workspace:^\",\"ci-info\":\"^3.2.0\",clipanion:\"^4.0.0-rc.2\",semver:\"^7.1.2\",tslib:\"^2.4.0\",typanion:\"^3.14.0\"},devDependencies:{\"@types/semver\":\"^7.1.0\",\"@yarnpkg/builder\":\"workspace:^\",\"@yarnpkg/monorepo\":\"workspace:^\",\"@yarnpkg/pnpify\":\"workspace:^\"},peerDependencies:{\"@yarnpkg/core\":\"workspace:^\"},scripts:{postpack:\"rm -rf lib\",prepack:'run build:compile \"$(pwd)\"',\"build:cli+hook\":\"run build:pnp:hook && builder build bundle\",\"build:cli\":\"builder build bundle\",\"run:cli\":\"builder run\",\"update-local\":\"run build:cli --no-git-hash && rsync -a --delete bundles/ bin/\"},publishConfig:{main:\"./lib/index.js\",bin:null,exports:{\".\":\"./lib/index.js\",\"./package.json\":\"./package.json\"}},files:[\"/lib/**/*\",\"!/lib/pluginConfiguration.*\",\"!/lib/cli.*\"],\"@yarnpkg/builder\":{bundles:{standard:[\"@yarnpkg/plugin-essentials\",\"@yarnpkg/plugin-compat\",\"@yarnpkg/plugin-constraints\",\"@yarnpkg/plugin-dlx\",\"@yarnpkg/plugin-exec\",\"@yarnpkg/plugin-file\",\"@yarnpkg/plugin-git\",\"@yarnpkg/plugin-github\",\"@yarnpkg/plugin-http\",\"@yarnpkg/plugin-init\",\"@yarnpkg/plugin-interactive-tools\",\"@yarnpkg/plugin-link\",\"@yarnpkg/plugin-nm\",\"@yarnpkg/plugin-npm\",\"@yarnpkg/plugin-npm-cli\",\"@yarnpkg/plugin-pack\",\"@yarnpkg/plugin-patch\",\"@yarnpkg/plugin-pnp\",\"@yarnpkg/plugin-pnpm\",\"@yarnpkg/plugin-stage\",\"@yarnpkg/plugin-typescript\",\"@yarnpkg/plugin-version\",\"@yarnpkg/plugin-workspace-tools\"]}},repository:{type:\"git\",url:\"ssh://git@github.com/yarnpkg/berry.git\",directory:\"packages/yarnpkg-cli\"},engines:{node:\">=18.12.0\"}}});var Y8=_((e5t,Ade)=>{\"use strict\";Ade.exports=function(e,r){r===!0&&(r=0);var o=\"\";if(typeof e==\"string\")try{o=new URL(e).protocol}catch{}else e&&e.constructor===URL&&(o=e.protocol);var a=o.split(/\\:|\\+/).filter(Boolean);return typeof r==\"number\"?a[r]:a}});var pde=_((t5t,fde)=>{\"use strict\";var agt=Y8();function lgt(t){var e={protocols:[],protocol:null,port:null,resource:\"\",host:\"\",user:\"\",password:\"\",pathname:\"\",hash:\"\",search:\"\",href:t,query:{},parse_failed:!1};try{var r=new URL(t);e.protocols=agt(r),e.protocol=e.protocols[0],e.port=r.port,e.resource=r.hostname,e.host=r.host,e.user=r.username||\"\",e.password=r.password||\"\",e.pathname=r.pathname,e.hash=r.hash.slice(1),e.search=r.search.slice(1),e.href=r.href,e.query=Object.fromEntries(r.searchParams)}catch{e.protocols=[\"file\"],e.protocol=e.protocols[0],e.port=\"\",e.resource=\"\",e.user=\"\",e.pathname=\"\",e.hash=\"\",e.search=\"\",e.href=t,e.query={},e.parse_failed=!0}return e}fde.exports=lgt});var dde=_((r5t,gde)=>{\"use strict\";var cgt=pde();function ugt(t){return t&&typeof t==\"object\"&&\"default\"in t?t:{default:t}}var Agt=ugt(cgt),fgt=\"text/plain\",pgt=\"us-ascii\",hde=(t,e)=>e.some(r=>r instanceof RegExp?r.test(t):r===t),hgt=(t,{stripHash:e})=>{let r=/^data:(?<type>[^,]*?),(?<data>[^#]*?)(?:#(?<hash>.*))?$/.exec(t);if(!r)throw new Error(`Invalid URL: ${t}`);let{type:o,data:a,hash:n}=r.groups,u=o.split(\";\");n=e?\"\":n;let A=!1;u[u.length-1]===\"base64\"&&(u.pop(),A=!0);let p=(u.shift()||\"\").toLowerCase(),C=[...u.map(I=>{let[v,x=\"\"]=I.split(\"=\").map(E=>E.trim());return v===\"charset\"&&(x=x.toLowerCase(),x===pgt)?\"\":`${v}${x?`=${x}`:\"\"}`}).filter(Boolean)];return A&&C.push(\"base64\"),(C.length>0||p&&p!==fgt)&&C.unshift(p),`data:${C.join(\";\")},${A?a.trim():a}${n?`#${n}`:\"\"}`};function ggt(t,e){if(e={defaultProtocol:\"http:\",normalizeProtocol:!0,forceHttp:!1,forceHttps:!1,stripAuthentication:!0,stripHash:!1,stripTextFragment:!0,stripWWW:!0,removeQueryParameters:[/^utm_\\w+/i],removeTrailingSlash:!0,removeSingleSlash:!0,removeDirectoryIndex:!1,sortQueryParameters:!0,...e},t=t.trim(),/^data:/i.test(t))return hgt(t,e);if(/^view-source:/i.test(t))throw new Error(\"`view-source:` is not supported as it is a non-standard protocol\");let r=t.startsWith(\"//\");!r&&/^\\.*\\//.test(t)||(t=t.replace(/^(?!(?:\\w+:)?\\/\\/)|^\\/\\//,e.defaultProtocol));let a=new URL(t);if(e.forceHttp&&e.forceHttps)throw new Error(\"The `forceHttp` and `forceHttps` options cannot be used together\");if(e.forceHttp&&a.protocol===\"https:\"&&(a.protocol=\"http:\"),e.forceHttps&&a.protocol===\"http:\"&&(a.protocol=\"https:\"),e.stripAuthentication&&(a.username=\"\",a.password=\"\"),e.stripHash?a.hash=\"\":e.stripTextFragment&&(a.hash=a.hash.replace(/#?:~:text.*?$/i,\"\")),a.pathname){let u=/\\b[a-z][a-z\\d+\\-.]{1,50}:\\/\\//g,A=0,p=\"\";for(;;){let C=u.exec(a.pathname);if(!C)break;let I=C[0],v=C.index,x=a.pathname.slice(A,v);p+=x.replace(/\\/{2,}/g,\"/\"),p+=I,A=v+I.length}let h=a.pathname.slice(A,a.pathname.length);p+=h.replace(/\\/{2,}/g,\"/\"),a.pathname=p}if(a.pathname)try{a.pathname=decodeURI(a.pathname)}catch{}if(e.removeDirectoryIndex===!0&&(e.removeDirectoryIndex=[/^index\\.[a-z]+$/]),Array.isArray(e.removeDirectoryIndex)&&e.removeDirectoryIndex.length>0){let u=a.pathname.split(\"/\"),A=u[u.length-1];hde(A,e.removeDirectoryIndex)&&(u=u.slice(0,-1),a.pathname=u.slice(1).join(\"/\")+\"/\")}if(a.hostname&&(a.hostname=a.hostname.replace(/\\.$/,\"\"),e.stripWWW&&/^www\\.(?!www\\.)[a-z\\-\\d]{1,63}\\.[a-z.\\-\\d]{2,63}$/.test(a.hostname)&&(a.hostname=a.hostname.replace(/^www\\./,\"\"))),Array.isArray(e.removeQueryParameters))for(let u of[...a.searchParams.keys()])hde(u,e.removeQueryParameters)&&a.searchParams.delete(u);if(e.removeQueryParameters===!0&&(a.search=\"\"),e.sortQueryParameters){a.searchParams.sort();try{a.search=decodeURIComponent(a.search)}catch{}}e.removeTrailingSlash&&(a.pathname=a.pathname.replace(/\\/$/,\"\"));let n=t;return t=a.toString(),!e.removeSingleSlash&&a.pathname===\"/\"&&!n.endsWith(\"/\")&&a.hash===\"\"&&(t=t.replace(/\\/$/,\"\")),(e.removeTrailingSlash||a.pathname===\"/\")&&a.hash===\"\"&&e.removeSingleSlash&&(t=t.replace(/\\/$/,\"\")),r&&!e.normalizeProtocol&&(t=t.replace(/^http:\\/\\//,\"//\")),e.stripProtocol&&(t=t.replace(/^(?:https?:)?\\/\\//,\"\")),t}var W8=(t,e=!1)=>{let r=/^(?:([a-z_][a-z0-9_-]{0,31})@|https?:\\/\\/)([\\w\\.\\-@]+)[\\/:]([\\~,\\.\\w,\\-,\\_,\\/]+?(?:\\.git|\\/)?)$/,o=n=>{let u=new Error(n);throw u.subject_url=t,u};(typeof t!=\"string\"||!t.trim())&&o(\"Invalid url.\"),t.length>W8.MAX_INPUT_LENGTH&&o(\"Input exceeds maximum length. If needed, change the value of parseUrl.MAX_INPUT_LENGTH.\"),e&&(typeof e!=\"object\"&&(e={stripHash:!1}),t=ggt(t,e));let a=Agt.default(t);if(a.parse_failed){let n=a.href.match(r);n?(a.protocols=[\"ssh\"],a.protocol=\"ssh\",a.resource=n[2],a.host=n[2],a.user=n[1],a.pathname=`/${n[3]}`,a.parse_failed=!1):o(\"URL parsing failed.\")}return a};W8.MAX_INPUT_LENGTH=2048;gde.exports=W8});var Ede=_((n5t,yde)=>{\"use strict\";var dgt=Y8();function mde(t){if(Array.isArray(t))return t.indexOf(\"ssh\")!==-1||t.indexOf(\"rsync\")!==-1;if(typeof t!=\"string\")return!1;var e=dgt(t);if(t=t.substring(t.indexOf(\"://\")+3),mde(e))return!0;var r=new RegExp(\".([a-zA-Z\\\\d]+):(\\\\d+)/\");return!t.match(r)&&t.indexOf(\"@\")<t.indexOf(\":\")}yde.exports=mde});var Ide=_((i5t,wde)=>{\"use strict\";var mgt=dde(),Cde=Ede();function ygt(t){var e=mgt(t);return e.token=\"\",e.password===\"x-oauth-basic\"?e.token=e.user:e.user===\"x-token-auth\"&&(e.token=e.password),Cde(e.protocols)||e.protocols.length===0&&Cde(t)?e.protocol=\"ssh\":e.protocols.length?e.protocol=e.protocols[0]:(e.protocol=\"file\",e.protocols=[\"file\"]),e.href=e.href.replace(/\\/$/,\"\"),e}wde.exports=ygt});var vde=_((s5t,Bde)=>{\"use strict\";var Egt=Ide();function K8(t){if(typeof t!=\"string\")throw new Error(\"The url must be a string.\");var e=/^([a-z\\d-]{1,39})\\/([-\\.\\w]{1,100})$/i;e.test(t)&&(t=\"https://github.com/\"+t);var r=Egt(t),o=r.resource.split(\".\"),a=null;switch(r.toString=function(L){return K8.stringify(this,L)},r.source=o.length>2?o.slice(1-o.length).join(\".\"):r.source=r.resource,r.git_suffix=/\\.git$/.test(r.pathname),r.name=decodeURIComponent((r.pathname||r.href).replace(/(^\\/)|(\\/$)/g,\"\").replace(/\\.git$/,\"\")),r.owner=decodeURIComponent(r.user),r.source){case\"git.cloudforge.com\":r.owner=r.user,r.organization=o[0],r.source=\"cloudforge.com\";break;case\"visualstudio.com\":if(r.resource===\"vs-ssh.visualstudio.com\"){a=r.name.split(\"/\"),a.length===4&&(r.organization=a[1],r.owner=a[2],r.name=a[3],r.full_name=a[2]+\"/\"+a[3]);break}else{a=r.name.split(\"/\"),a.length===2?(r.owner=a[1],r.name=a[1],r.full_name=\"_git/\"+r.name):a.length===3?(r.name=a[2],a[0]===\"DefaultCollection\"?(r.owner=a[2],r.organization=a[0],r.full_name=r.organization+\"/_git/\"+r.name):(r.owner=a[0],r.full_name=r.owner+\"/_git/\"+r.name)):a.length===4&&(r.organization=a[0],r.owner=a[1],r.name=a[3],r.full_name=r.organization+\"/\"+r.owner+\"/_git/\"+r.name);break}case\"dev.azure.com\":case\"azure.com\":if(r.resource===\"ssh.dev.azure.com\"){a=r.name.split(\"/\"),a.length===4&&(r.organization=a[1],r.owner=a[2],r.name=a[3]);break}else{a=r.name.split(\"/\"),a.length===5?(r.organization=a[0],r.owner=a[1],r.name=a[4],r.full_name=\"_git/\"+r.name):a.length===3?(r.name=a[2],a[0]===\"DefaultCollection\"?(r.owner=a[2],r.organization=a[0],r.full_name=r.organization+\"/_git/\"+r.name):(r.owner=a[0],r.full_name=r.owner+\"/_git/\"+r.name)):a.length===4&&(r.organization=a[0],r.owner=a[1],r.name=a[3],r.full_name=r.organization+\"/\"+r.owner+\"/_git/\"+r.name),r.query&&r.query.path&&(r.filepath=r.query.path.replace(/^\\/+/g,\"\")),r.query&&r.query.version&&(r.ref=r.query.version.replace(/^GB/,\"\"));break}default:a=r.name.split(\"/\");var n=a.length-1;if(a.length>=2){var u=a.indexOf(\"-\",2),A=a.indexOf(\"blob\",2),p=a.indexOf(\"tree\",2),h=a.indexOf(\"commit\",2),C=a.indexOf(\"src\",2),I=a.indexOf(\"raw\",2),v=a.indexOf(\"edit\",2);n=u>0?u-1:A>0?A-1:p>0?p-1:h>0?h-1:C>0?C-1:I>0?I-1:v>0?v-1:n,r.owner=a.slice(0,n).join(\"/\"),r.name=a[n],h&&(r.commit=a[n+2])}r.ref=\"\",r.filepathtype=\"\",r.filepath=\"\";var x=a.length>n&&a[n+1]===\"-\"?n+1:n;a.length>x+2&&[\"raw\",\"src\",\"blob\",\"tree\",\"edit\"].indexOf(a[x+1])>=0&&(r.filepathtype=a[x+1],r.ref=a[x+2],a.length>x+3&&(r.filepath=a.slice(x+3).join(\"/\"))),r.organization=r.owner;break}r.full_name||(r.full_name=r.owner,r.name&&(r.full_name&&(r.full_name+=\"/\"),r.full_name+=r.name)),r.owner.startsWith(\"scm/\")&&(r.source=\"bitbucket-server\",r.owner=r.owner.replace(\"scm/\",\"\"),r.organization=r.owner,r.full_name=r.owner+\"/\"+r.name);var E=/(projects|users)\\/(.*?)\\/repos\\/(.*?)((\\/.*$)|$)/,R=E.exec(r.pathname);return R!=null&&(r.source=\"bitbucket-server\",R[1]===\"users\"?r.owner=\"~\"+R[2]:r.owner=R[2],r.organization=r.owner,r.name=R[3],a=R[4].split(\"/\"),a.length>1&&([\"raw\",\"browse\"].indexOf(a[1])>=0?(r.filepathtype=a[1],a.length>2&&(r.filepath=a.slice(2).join(\"/\"))):a[1]===\"commits\"&&a.length>2&&(r.commit=a[2])),r.full_name=r.owner+\"/\"+r.name,r.query.at?r.ref=r.query.at:r.ref=\"\"),r}K8.stringify=function(t,e){e=e||(t.protocols&&t.protocols.length?t.protocols.join(\"+\"):t.protocol);var r=t.port?\":\"+t.port:\"\",o=t.user||\"git\",a=t.git_suffix?\".git\":\"\";switch(e){case\"ssh\":return r?\"ssh://\"+o+\"@\"+t.resource+r+\"/\"+t.full_name+a:o+\"@\"+t.resource+\":\"+t.full_name+a;case\"git+ssh\":case\"ssh+git\":case\"ftp\":case\"ftps\":return e+\"://\"+o+\"@\"+t.resource+r+\"/\"+t.full_name+a;case\"http\":case\"https\":var n=t.token?Cgt(t):t.user&&(t.protocols.includes(\"http\")||t.protocols.includes(\"https\"))?t.user+\"@\":\"\";return e+\"://\"+n+t.resource+r+\"/\"+wgt(t)+a;default:return t.href}};function Cgt(t){switch(t.source){case\"bitbucket.org\":return\"x-token-auth:\"+t.token+\"@\";default:return t.token+\"@\"}}function wgt(t){switch(t.source){case\"bitbucket-server\":return\"scm/\"+t.full_name;default:return\"\"+t.full_name}}Bde.exports=K8});var _de=_((M9t,Ude)=>{var Fgt=qb(),Rgt=eS(),Tgt=Hl(),Ngt=AE(),Lgt=B_(),Ogt=oC(),Mgt=R1();function Ugt(t){return Tgt(t)?Fgt(t,Ogt):Ngt(t)?[t]:Rgt(Lgt(Mgt(t)))}Ude.exports=Ugt});function qgt(t,e){return e===1&&jgt.has(t[0])}function w2(t){let e=Array.isArray(t)?t:(0,qde.default)(t);return e.map((o,a)=>_gt.test(o)?`[${o}]`:Hgt.test(o)&&!qgt(e,a)?`.${o}`:`[${JSON.stringify(o)}]`).join(\"\").replace(/^\\./,\"\")}function Ggt(t,e){let r=[];if(e.methodName!==null&&r.push(de.pretty(t,e.methodName,de.Type.CODE)),e.file!==null){let o=[];o.push(de.pretty(t,e.file,de.Type.PATH)),e.line!==null&&(o.push(de.pretty(t,e.line,de.Type.NUMBER)),e.column!==null&&o.push(de.pretty(t,e.column,de.Type.NUMBER))),r.push(`(${o.join(de.pretty(t,\":\",\"grey\"))})`)}return r.join(\" \")}function mk(t,{manifestUpdates:e,reportedErrors:r},{fix:o}={}){let a=new Map,n=new Map,u=[...r.keys()].map(A=>[A,new Map]);for(let[A,p]of[...u,...e]){let h=r.get(A)?.map(x=>({text:x,fixable:!1}))??[],C=!1,I=t.getWorkspaceByCwd(A),v=I.manifest.exportTo({});for(let[x,E]of p){if(E.size>1){let R=[...E].map(([L,U])=>{let z=de.pretty(t.configuration,L,de.Type.INSPECT),te=U.size>0?Ggt(t.configuration,U.values().next().value):null;return te!==null?`\n${z} at ${te}`:`\n${z}`}).join(\"\");h.push({text:`Conflict detected in constraint targeting ${de.pretty(t.configuration,x,de.Type.CODE)}; conflicting values are:${R}`,fixable:!1})}else{let[[R]]=E,L=(0,Hde.default)(v,x);if(L===R)continue;if(!o){let U=typeof L>\"u\"?`Missing field ${de.pretty(t.configuration,x,de.Type.CODE)}; expected ${de.pretty(t.configuration,R,de.Type.INSPECT)}`:typeof R>\"u\"?`Extraneous field ${de.pretty(t.configuration,x,de.Type.CODE)} currently set to ${de.pretty(t.configuration,L,de.Type.INSPECT)}`:`Invalid field ${de.pretty(t.configuration,x,de.Type.CODE)}; expected ${de.pretty(t.configuration,R,de.Type.INSPECT)}, found ${de.pretty(t.configuration,L,de.Type.INSPECT)}`;h.push({text:U,fixable:!0});continue}typeof R>\"u\"?(0,Gde.default)(v,x):(0,jde.default)(v,x,R),C=!0}C&&a.set(I,v)}h.length>0&&n.set(I,h)}return{changedWorkspaces:a,remainingErrors:n}}function Yde(t,{configuration:e}){let r={children:[]};for(let[o,a]of t){let n=[];for(let A of a){let p=A.text.split(/\\n/);A.fixable&&(p[0]=`${de.pretty(e,\"\\u2699\",\"gray\")} ${p[0]}`),n.push({value:de.tuple(de.Type.NO_HINT,p[0]),children:p.slice(1).map(h=>({value:de.tuple(de.Type.NO_HINT,h)}))})}let u={value:de.tuple(de.Type.LOCATOR,o.anchoredLocator),children:je.sortMap(n,A=>A.value[1])};r.children.push(u)}return r.children=je.sortMap(r.children,o=>o.value[1]),r}var Hde,jde,qde,Gde,EC,_gt,Hgt,jgt,I2=Et(()=>{Ye();Hde=$e(h2()),jde=$e(R8()),qde=$e(_de()),Gde=$e(L8()),EC=class{constructor(e){this.indexedFields=e;this.items=[];this.indexes={};this.clear()}clear(){this.items=[];for(let e of this.indexedFields)this.indexes[e]=new Map}insert(e){this.items.push(e);for(let r of this.indexedFields){let o=Object.hasOwn(e,r)?e[r]:void 0;if(typeof o>\"u\")continue;je.getArrayWithDefault(this.indexes[r],o).push(e)}return e}find(e){if(typeof e>\"u\")return this.items;let r=Object.entries(e);if(r.length===0)return this.items;let o=[],a;for(let[u,A]of r){let p=u,h=Object.hasOwn(this.indexes,p)?this.indexes[p]:void 0;if(typeof h>\"u\"){o.push([p,A]);continue}let C=new Set(h.get(A)??[]);if(C.size===0)return[];if(typeof a>\"u\")a=C;else for(let I of a)C.has(I)||a.delete(I);if(a.size===0)break}let n=[...a??[]];return o.length>0&&(n=n.filter(u=>{for(let[A,p]of o)if(!(typeof p<\"u\"?Object.hasOwn(u,A)&&u[A]===p:Object.hasOwn(u,A)===!1))return!1;return!0})),n}},_gt=/^[0-9]+$/,Hgt=/^[a-zA-Z0-9_]+$/,jgt=new Set([\"scripts\",...Ot.allDependencies])});var Wde=_((J9t,aH)=>{var Ygt;(function(t){var e=function(){return{\"append/2\":[new t.type.Rule(new t.type.Term(\"append\",[new t.type.Var(\"X\"),new t.type.Var(\"L\")]),new t.type.Term(\"foldl\",[new t.type.Term(\"append\",[]),new t.type.Var(\"X\"),new t.type.Term(\"[]\",[]),new t.type.Var(\"L\")]))],\"append/3\":[new t.type.Rule(new t.type.Term(\"append\",[new t.type.Term(\"[]\",[]),new t.type.Var(\"X\"),new t.type.Var(\"X\")]),null),new t.type.Rule(new t.type.Term(\"append\",[new t.type.Term(\".\",[new t.type.Var(\"H\"),new t.type.Var(\"T\")]),new t.type.Var(\"X\"),new t.type.Term(\".\",[new t.type.Var(\"H\"),new t.type.Var(\"S\")])]),new t.type.Term(\"append\",[new t.type.Var(\"T\"),new t.type.Var(\"X\"),new t.type.Var(\"S\")]))],\"member/2\":[new t.type.Rule(new t.type.Term(\"member\",[new t.type.Var(\"X\"),new t.type.Term(\".\",[new t.type.Var(\"X\"),new t.type.Var(\"_\")])]),null),new t.type.Rule(new t.type.Term(\"member\",[new t.type.Var(\"X\"),new t.type.Term(\".\",[new t.type.Var(\"_\"),new t.type.Var(\"Xs\")])]),new t.type.Term(\"member\",[new t.type.Var(\"X\"),new t.type.Var(\"Xs\")]))],\"permutation/2\":[new t.type.Rule(new t.type.Term(\"permutation\",[new t.type.Term(\"[]\",[]),new t.type.Term(\"[]\",[])]),null),new t.type.Rule(new t.type.Term(\"permutation\",[new t.type.Term(\".\",[new t.type.Var(\"H\"),new t.type.Var(\"T\")]),new t.type.Var(\"S\")]),new t.type.Term(\",\",[new t.type.Term(\"permutation\",[new t.type.Var(\"T\"),new t.type.Var(\"P\")]),new t.type.Term(\",\",[new t.type.Term(\"append\",[new t.type.Var(\"X\"),new t.type.Var(\"Y\"),new t.type.Var(\"P\")]),new t.type.Term(\"append\",[new t.type.Var(\"X\"),new t.type.Term(\".\",[new t.type.Var(\"H\"),new t.type.Var(\"Y\")]),new t.type.Var(\"S\")])])]))],\"maplist/2\":[new t.type.Rule(new t.type.Term(\"maplist\",[new t.type.Var(\"_\"),new t.type.Term(\"[]\",[])]),null),new t.type.Rule(new t.type.Term(\"maplist\",[new t.type.Var(\"P\"),new t.type.Term(\".\",[new t.type.Var(\"X\"),new t.type.Var(\"Xs\")])]),new t.type.Term(\",\",[new t.type.Term(\"call\",[new t.type.Var(\"P\"),new t.type.Var(\"X\")]),new t.type.Term(\"maplist\",[new t.type.Var(\"P\"),new t.type.Var(\"Xs\")])]))],\"maplist/3\":[new t.type.Rule(new t.type.Term(\"maplist\",[new t.type.Var(\"_\"),new t.type.Term(\"[]\",[]),new t.type.Term(\"[]\",[])]),null),new t.type.Rule(new t.type.Term(\"maplist\",[new t.type.Var(\"P\"),new t.type.Term(\".\",[new t.type.Var(\"A\"),new t.type.Var(\"As\")]),new t.type.Term(\".\",[new t.type.Var(\"B\"),new t.type.Var(\"Bs\")])]),new t.type.Term(\",\",[new t.type.Term(\"call\",[new t.type.Var(\"P\"),new t.type.Var(\"A\"),new t.type.Var(\"B\")]),new t.type.Term(\"maplist\",[new t.type.Var(\"P\"),new t.type.Var(\"As\"),new t.type.Var(\"Bs\")])]))],\"maplist/4\":[new t.type.Rule(new t.type.Term(\"maplist\",[new t.type.Var(\"_\"),new t.type.Term(\"[]\",[]),new t.type.Term(\"[]\",[]),new t.type.Term(\"[]\",[])]),null),new t.type.Rule(new t.type.Term(\"maplist\",[new t.type.Var(\"P\"),new t.type.Term(\".\",[new t.type.Var(\"A\"),new t.type.Var(\"As\")]),new t.type.Term(\".\",[new t.type.Var(\"B\"),new t.type.Var(\"Bs\")]),new t.type.Term(\".\",[new t.type.Var(\"C\"),new t.type.Var(\"Cs\")])]),new t.type.Term(\",\",[new t.type.Term(\"call\",[new t.type.Var(\"P\"),new t.type.Var(\"A\"),new t.type.Var(\"B\"),new t.type.Var(\"C\")]),new t.type.Term(\"maplist\",[new t.type.Var(\"P\"),new t.type.Var(\"As\"),new t.type.Var(\"Bs\"),new t.type.Var(\"Cs\")])]))],\"maplist/5\":[new t.type.Rule(new t.type.Term(\"maplist\",[new t.type.Var(\"_\"),new t.type.Term(\"[]\",[]),new t.type.Term(\"[]\",[]),new t.type.Term(\"[]\",[]),new t.type.Term(\"[]\",[])]),null),new t.type.Rule(new t.type.Term(\"maplist\",[new t.type.Var(\"P\"),new t.type.Term(\".\",[new t.type.Var(\"A\"),new t.type.Var(\"As\")]),new t.type.Term(\".\",[new t.type.Var(\"B\"),new t.type.Var(\"Bs\")]),new t.type.Term(\".\",[new t.type.Var(\"C\"),new t.type.Var(\"Cs\")]),new t.type.Term(\".\",[new t.type.Var(\"D\"),new t.type.Var(\"Ds\")])]),new t.type.Term(\",\",[new t.type.Term(\"call\",[new t.type.Var(\"P\"),new t.type.Var(\"A\"),new t.type.Var(\"B\"),new t.type.Var(\"C\"),new t.type.Var(\"D\")]),new t.type.Term(\"maplist\",[new t.type.Var(\"P\"),new t.type.Var(\"As\"),new t.type.Var(\"Bs\"),new t.type.Var(\"Cs\"),new t.type.Var(\"Ds\")])]))],\"maplist/6\":[new t.type.Rule(new t.type.Term(\"maplist\",[new t.type.Var(\"_\"),new t.type.Term(\"[]\",[]),new t.type.Term(\"[]\",[]),new t.type.Term(\"[]\",[]),new t.type.Term(\"[]\",[]),new t.type.Term(\"[]\",[])]),null),new t.type.Rule(new t.type.Term(\"maplist\",[new t.type.Var(\"P\"),new t.type.Term(\".\",[new t.type.Var(\"A\"),new t.type.Var(\"As\")]),new t.type.Term(\".\",[new t.type.Var(\"B\"),new t.type.Var(\"Bs\")]),new t.type.Term(\".\",[new t.type.Var(\"C\"),new t.type.Var(\"Cs\")]),new t.type.Term(\".\",[new t.type.Var(\"D\"),new t.type.Var(\"Ds\")]),new t.type.Term(\".\",[new t.type.Var(\"E\"),new t.type.Var(\"Es\")])]),new t.type.Term(\",\",[new t.type.Term(\"call\",[new t.type.Var(\"P\"),new t.type.Var(\"A\"),new t.type.Var(\"B\"),new t.type.Var(\"C\"),new t.type.Var(\"D\"),new t.type.Var(\"E\")]),new t.type.Term(\"maplist\",[new t.type.Var(\"P\"),new t.type.Var(\"As\"),new t.type.Var(\"Bs\"),new t.type.Var(\"Cs\"),new t.type.Var(\"Ds\"),new t.type.Var(\"Es\")])]))],\"maplist/7\":[new t.type.Rule(new t.type.Term(\"maplist\",[new t.type.Var(\"_\"),new t.type.Term(\"[]\",[]),new t.type.Term(\"[]\",[]),new t.type.Term(\"[]\",[]),new t.type.Term(\"[]\",[]),new t.type.Term(\"[]\",[]),new t.type.Term(\"[]\",[])]),null),new t.type.Rule(new t.type.Term(\"maplist\",[new t.type.Var(\"P\"),new t.type.Term(\".\",[new t.type.Var(\"A\"),new t.type.Var(\"As\")]),new t.type.Term(\".\",[new t.type.Var(\"B\"),new t.type.Var(\"Bs\")]),new t.type.Term(\".\",[new t.type.Var(\"C\"),new t.type.Var(\"Cs\")]),new t.type.Term(\".\",[new t.type.Var(\"D\"),new t.type.Var(\"Ds\")]),new t.type.Term(\".\",[new t.type.Var(\"E\"),new t.type.Var(\"Es\")]),new t.type.Term(\".\",[new t.type.Var(\"F\"),new t.type.Var(\"Fs\")])]),new t.type.Term(\",\",[new t.type.Term(\"call\",[new t.type.Var(\"P\"),new t.type.Var(\"A\"),new t.type.Var(\"B\"),new t.type.Var(\"C\"),new t.type.Var(\"D\"),new t.type.Var(\"E\"),new t.type.Var(\"F\")]),new t.type.Term(\"maplist\",[new t.type.Var(\"P\"),new t.type.Var(\"As\"),new t.type.Var(\"Bs\"),new t.type.Var(\"Cs\"),new t.type.Var(\"Ds\"),new t.type.Var(\"Es\"),new t.type.Var(\"Fs\")])]))],\"maplist/8\":[new t.type.Rule(new t.type.Term(\"maplist\",[new t.type.Var(\"_\"),new t.type.Term(\"[]\",[]),new t.type.Term(\"[]\",[]),new t.type.Term(\"[]\",[]),new t.type.Term(\"[]\",[]),new t.type.Term(\"[]\",[]),new t.type.Term(\"[]\",[]),new t.type.Term(\"[]\",[])]),null),new t.type.Rule(new t.type.Term(\"maplist\",[new t.type.Var(\"P\"),new t.type.Term(\".\",[new t.type.Var(\"A\"),new t.type.Var(\"As\")]),new t.type.Term(\".\",[new t.type.Var(\"B\"),new t.type.Var(\"Bs\")]),new t.type.Term(\".\",[new t.type.Var(\"C\"),new t.type.Var(\"Cs\")]),new t.type.Term(\".\",[new t.type.Var(\"D\"),new t.type.Var(\"Ds\")]),new t.type.Term(\".\",[new t.type.Var(\"E\"),new t.type.Var(\"Es\")]),new t.type.Term(\".\",[new t.type.Var(\"F\"),new t.type.Var(\"Fs\")]),new t.type.Term(\".\",[new t.type.Var(\"G\"),new t.type.Var(\"Gs\")])]),new t.type.Term(\",\",[new t.type.Term(\"call\",[new t.type.Var(\"P\"),new t.type.Var(\"A\"),new t.type.Var(\"B\"),new t.type.Var(\"C\"),new t.type.Var(\"D\"),new t.type.Var(\"E\"),new t.type.Var(\"F\"),new t.type.Var(\"G\")]),new t.type.Term(\"maplist\",[new t.type.Var(\"P\"),new t.type.Var(\"As\"),new t.type.Var(\"Bs\"),new t.type.Var(\"Cs\"),new t.type.Var(\"Ds\"),new t.type.Var(\"Es\"),new t.type.Var(\"Fs\"),new t.type.Var(\"Gs\")])]))],\"include/3\":[new t.type.Rule(new t.type.Term(\"include\",[new t.type.Var(\"_\"),new t.type.Term(\"[]\",[]),new t.type.Term(\"[]\",[])]),null),new t.type.Rule(new t.type.Term(\"include\",[new t.type.Var(\"P\"),new t.type.Term(\".\",[new t.type.Var(\"H\"),new t.type.Var(\"T\")]),new t.type.Var(\"L\")]),new t.type.Term(\",\",[new t.type.Term(\"=..\",[new t.type.Var(\"P\"),new t.type.Var(\"A\")]),new t.type.Term(\",\",[new t.type.Term(\"append\",[new t.type.Var(\"A\"),new t.type.Term(\".\",[new t.type.Var(\"H\"),new t.type.Term(\"[]\",[])]),new t.type.Var(\"B\")]),new t.type.Term(\",\",[new t.type.Term(\"=..\",[new t.type.Var(\"F\"),new t.type.Var(\"B\")]),new t.type.Term(\",\",[new t.type.Term(\";\",[new t.type.Term(\",\",[new t.type.Term(\"call\",[new t.type.Var(\"F\")]),new t.type.Term(\",\",[new t.type.Term(\"=\",[new t.type.Var(\"L\"),new t.type.Term(\".\",[new t.type.Var(\"H\"),new t.type.Var(\"S\")])]),new t.type.Term(\"!\",[])])]),new t.type.Term(\"=\",[new t.type.Var(\"L\"),new t.type.Var(\"S\")])]),new t.type.Term(\"include\",[new t.type.Var(\"P\"),new t.type.Var(\"T\"),new t.type.Var(\"S\")])])])])]))],\"exclude/3\":[new t.type.Rule(new t.type.Term(\"exclude\",[new t.type.Var(\"_\"),new t.type.Term(\"[]\",[]),new t.type.Term(\"[]\",[])]),null),new t.type.Rule(new t.type.Term(\"exclude\",[new t.type.Var(\"P\"),new t.type.Term(\".\",[new t.type.Var(\"H\"),new t.type.Var(\"T\")]),new t.type.Var(\"S\")]),new t.type.Term(\",\",[new t.type.Term(\"exclude\",[new t.type.Var(\"P\"),new t.type.Var(\"T\"),new t.type.Var(\"E\")]),new t.type.Term(\",\",[new t.type.Term(\"=..\",[new t.type.Var(\"P\"),new t.type.Var(\"L\")]),new t.type.Term(\",\",[new t.type.Term(\"append\",[new t.type.Var(\"L\"),new t.type.Term(\".\",[new t.type.Var(\"H\"),new t.type.Term(\"[]\",[])]),new t.type.Var(\"Q\")]),new t.type.Term(\",\",[new t.type.Term(\"=..\",[new t.type.Var(\"R\"),new t.type.Var(\"Q\")]),new t.type.Term(\";\",[new t.type.Term(\",\",[new t.type.Term(\"call\",[new t.type.Var(\"R\")]),new t.type.Term(\",\",[new t.type.Term(\"!\",[]),new t.type.Term(\"=\",[new t.type.Var(\"S\"),new t.type.Var(\"E\")])])]),new t.type.Term(\"=\",[new t.type.Var(\"S\"),new t.type.Term(\".\",[new t.type.Var(\"H\"),new t.type.Var(\"E\")])])])])])])]))],\"foldl/4\":[new t.type.Rule(new t.type.Term(\"foldl\",[new t.type.Var(\"_\"),new t.type.Term(\"[]\",[]),new t.type.Var(\"I\"),new t.type.Var(\"I\")]),null),new t.type.Rule(new t.type.Term(\"foldl\",[new t.type.Var(\"P\"),new t.type.Term(\".\",[new t.type.Var(\"H\"),new t.type.Var(\"T\")]),new t.type.Var(\"I\"),new t.type.Var(\"R\")]),new t.type.Term(\",\",[new t.type.Term(\"=..\",[new t.type.Var(\"P\"),new t.type.Var(\"L\")]),new t.type.Term(\",\",[new t.type.Term(\"append\",[new t.type.Var(\"L\"),new t.type.Term(\".\",[new t.type.Var(\"I\"),new t.type.Term(\".\",[new t.type.Var(\"H\"),new t.type.Term(\".\",[new t.type.Var(\"X\"),new t.type.Term(\"[]\",[])])])]),new t.type.Var(\"L2\")]),new t.type.Term(\",\",[new t.type.Term(\"=..\",[new t.type.Var(\"P2\"),new t.type.Var(\"L2\")]),new t.type.Term(\",\",[new t.type.Term(\"call\",[new t.type.Var(\"P2\")]),new t.type.Term(\"foldl\",[new t.type.Var(\"P\"),new t.type.Var(\"T\"),new t.type.Var(\"X\"),new t.type.Var(\"R\")])])])])]))],\"select/3\":[new t.type.Rule(new t.type.Term(\"select\",[new t.type.Var(\"E\"),new t.type.Term(\".\",[new t.type.Var(\"E\"),new t.type.Var(\"Xs\")]),new t.type.Var(\"Xs\")]),null),new t.type.Rule(new t.type.Term(\"select\",[new t.type.Var(\"E\"),new t.type.Term(\".\",[new t.type.Var(\"X\"),new t.type.Var(\"Xs\")]),new t.type.Term(\".\",[new t.type.Var(\"X\"),new t.type.Var(\"Ys\")])]),new t.type.Term(\"select\",[new t.type.Var(\"E\"),new t.type.Var(\"Xs\"),new t.type.Var(\"Ys\")]))],\"sum_list/2\":[new t.type.Rule(new t.type.Term(\"sum_list\",[new t.type.Term(\"[]\",[]),new t.type.Num(0,!1)]),null),new t.type.Rule(new t.type.Term(\"sum_list\",[new t.type.Term(\".\",[new t.type.Var(\"X\"),new t.type.Var(\"Xs\")]),new t.type.Var(\"S\")]),new t.type.Term(\",\",[new t.type.Term(\"sum_list\",[new t.type.Var(\"Xs\"),new t.type.Var(\"Y\")]),new t.type.Term(\"is\",[new t.type.Var(\"S\"),new t.type.Term(\"+\",[new t.type.Var(\"X\"),new t.type.Var(\"Y\")])])]))],\"max_list/2\":[new t.type.Rule(new t.type.Term(\"max_list\",[new t.type.Term(\".\",[new t.type.Var(\"X\"),new t.type.Term(\"[]\",[])]),new t.type.Var(\"X\")]),null),new t.type.Rule(new t.type.Term(\"max_list\",[new t.type.Term(\".\",[new t.type.Var(\"X\"),new t.type.Var(\"Xs\")]),new t.type.Var(\"S\")]),new t.type.Term(\",\",[new t.type.Term(\"max_list\",[new t.type.Var(\"Xs\"),new t.type.Var(\"Y\")]),new t.type.Term(\";\",[new t.type.Term(\",\",[new t.type.Term(\">=\",[new t.type.Var(\"X\"),new t.type.Var(\"Y\")]),new t.type.Term(\",\",[new t.type.Term(\"=\",[new t.type.Var(\"S\"),new t.type.Var(\"X\")]),new t.type.Term(\"!\",[])])]),new t.type.Term(\"=\",[new t.type.Var(\"S\"),new t.type.Var(\"Y\")])])]))],\"min_list/2\":[new t.type.Rule(new t.type.Term(\"min_list\",[new t.type.Term(\".\",[new t.type.Var(\"X\"),new t.type.Term(\"[]\",[])]),new t.type.Var(\"X\")]),null),new t.type.Rule(new t.type.Term(\"min_list\",[new t.type.Term(\".\",[new t.type.Var(\"X\"),new t.type.Var(\"Xs\")]),new t.type.Var(\"S\")]),new t.type.Term(\",\",[new t.type.Term(\"min_list\",[new t.type.Var(\"Xs\"),new t.type.Var(\"Y\")]),new t.type.Term(\";\",[new t.type.Term(\",\",[new t.type.Term(\"=<\",[new t.type.Var(\"X\"),new t.type.Var(\"Y\")]),new t.type.Term(\",\",[new t.type.Term(\"=\",[new t.type.Var(\"S\"),new t.type.Var(\"X\")]),new t.type.Term(\"!\",[])])]),new t.type.Term(\"=\",[new t.type.Var(\"S\"),new t.type.Var(\"Y\")])])]))],\"prod_list/2\":[new t.type.Rule(new t.type.Term(\"prod_list\",[new t.type.Term(\"[]\",[]),new t.type.Num(1,!1)]),null),new t.type.Rule(new t.type.Term(\"prod_list\",[new t.type.Term(\".\",[new t.type.Var(\"X\"),new t.type.Var(\"Xs\")]),new t.type.Var(\"S\")]),new t.type.Term(\",\",[new t.type.Term(\"prod_list\",[new t.type.Var(\"Xs\"),new t.type.Var(\"Y\")]),new t.type.Term(\"is\",[new t.type.Var(\"S\"),new t.type.Term(\"*\",[new t.type.Var(\"X\"),new t.type.Var(\"Y\")])])]))],\"last/2\":[new t.type.Rule(new t.type.Term(\"last\",[new t.type.Term(\".\",[new t.type.Var(\"X\"),new t.type.Term(\"[]\",[])]),new t.type.Var(\"X\")]),null),new t.type.Rule(new t.type.Term(\"last\",[new t.type.Term(\".\",[new t.type.Var(\"_\"),new t.type.Var(\"Xs\")]),new t.type.Var(\"X\")]),new t.type.Term(\"last\",[new t.type.Var(\"Xs\"),new t.type.Var(\"X\")]))],\"prefix/2\":[new t.type.Rule(new t.type.Term(\"prefix\",[new t.type.Var(\"Part\"),new t.type.Var(\"Whole\")]),new t.type.Term(\"append\",[new t.type.Var(\"Part\"),new t.type.Var(\"_\"),new t.type.Var(\"Whole\")]))],\"nth0/3\":[new t.type.Rule(new t.type.Term(\"nth0\",[new t.type.Var(\"X\"),new t.type.Var(\"Y\"),new t.type.Var(\"Z\")]),new t.type.Term(\";\",[new t.type.Term(\"->\",[new t.type.Term(\"var\",[new t.type.Var(\"X\")]),new t.type.Term(\"nth\",[new t.type.Num(0,!1),new t.type.Var(\"X\"),new t.type.Var(\"Y\"),new t.type.Var(\"Z\"),new t.type.Var(\"_\")])]),new t.type.Term(\",\",[new t.type.Term(\">=\",[new t.type.Var(\"X\"),new t.type.Num(0,!1)]),new t.type.Term(\",\",[new t.type.Term(\"nth\",[new t.type.Num(0,!1),new t.type.Var(\"X\"),new t.type.Var(\"Y\"),new t.type.Var(\"Z\"),new t.type.Var(\"_\")]),new t.type.Term(\"!\",[])])])]))],\"nth1/3\":[new t.type.Rule(new t.type.Term(\"nth1\",[new t.type.Var(\"X\"),new t.type.Var(\"Y\"),new t.type.Var(\"Z\")]),new t.type.Term(\";\",[new t.type.Term(\"->\",[new t.type.Term(\"var\",[new t.type.Var(\"X\")]),new t.type.Term(\"nth\",[new t.type.Num(1,!1),new t.type.Var(\"X\"),new t.type.Var(\"Y\"),new t.type.Var(\"Z\"),new t.type.Var(\"_\")])]),new t.type.Term(\",\",[new t.type.Term(\">\",[new t.type.Var(\"X\"),new t.type.Num(0,!1)]),new t.type.Term(\",\",[new t.type.Term(\"nth\",[new t.type.Num(1,!1),new t.type.Var(\"X\"),new t.type.Var(\"Y\"),new t.type.Var(\"Z\"),new t.type.Var(\"_\")]),new t.type.Term(\"!\",[])])])]))],\"nth0/4\":[new t.type.Rule(new t.type.Term(\"nth0\",[new t.type.Var(\"X\"),new t.type.Var(\"Y\"),new t.type.Var(\"Z\"),new t.type.Var(\"W\")]),new t.type.Term(\";\",[new t.type.Term(\"->\",[new t.type.Term(\"var\",[new t.type.Var(\"X\")]),new t.type.Term(\"nth\",[new t.type.Num(0,!1),new t.type.Var(\"X\"),new t.type.Var(\"Y\"),new t.type.Var(\"Z\"),new t.type.Var(\"W\")])]),new t.type.Term(\",\",[new t.type.Term(\">=\",[new t.type.Var(\"X\"),new t.type.Num(0,!1)]),new t.type.Term(\",\",[new t.type.Term(\"nth\",[new t.type.Num(0,!1),new t.type.Var(\"X\"),new t.type.Var(\"Y\"),new t.type.Var(\"Z\"),new t.type.Var(\"W\")]),new t.type.Term(\"!\",[])])])]))],\"nth1/4\":[new t.type.Rule(new t.type.Term(\"nth1\",[new t.type.Var(\"X\"),new t.type.Var(\"Y\"),new t.type.Var(\"Z\"),new t.type.Var(\"W\")]),new t.type.Term(\";\",[new t.type.Term(\"->\",[new t.type.Term(\"var\",[new t.type.Var(\"X\")]),new t.type.Term(\"nth\",[new t.type.Num(1,!1),new t.type.Var(\"X\"),new t.type.Var(\"Y\"),new t.type.Var(\"Z\"),new t.type.Var(\"W\")])]),new t.type.Term(\",\",[new t.type.Term(\">\",[new t.type.Var(\"X\"),new t.type.Num(0,!1)]),new t.type.Term(\",\",[new t.type.Term(\"nth\",[new t.type.Num(1,!1),new t.type.Var(\"X\"),new t.type.Var(\"Y\"),new t.type.Var(\"Z\"),new t.type.Var(\"W\")]),new t.type.Term(\"!\",[])])])]))],\"nth/5\":[new t.type.Rule(new t.type.Term(\"nth\",[new t.type.Var(\"N\"),new t.type.Var(\"N\"),new t.type.Term(\".\",[new t.type.Var(\"X\"),new t.type.Var(\"Xs\")]),new t.type.Var(\"X\"),new t.type.Var(\"Xs\")]),null),new t.type.Rule(new t.type.Term(\"nth\",[new t.type.Var(\"N\"),new t.type.Var(\"O\"),new t.type.Term(\".\",[new t.type.Var(\"X\"),new t.type.Var(\"Xs\")]),new t.type.Var(\"Y\"),new t.type.Term(\".\",[new t.type.Var(\"X\"),new t.type.Var(\"Ys\")])]),new t.type.Term(\",\",[new t.type.Term(\"is\",[new t.type.Var(\"M\"),new t.type.Term(\"+\",[new t.type.Var(\"N\"),new t.type.Num(1,!1)])]),new t.type.Term(\"nth\",[new t.type.Var(\"M\"),new t.type.Var(\"O\"),new t.type.Var(\"Xs\"),new t.type.Var(\"Y\"),new t.type.Var(\"Ys\")])]))],\"length/2\":function(o,a,n){var u=n.args[0],A=n.args[1];if(!t.type.is_variable(A)&&!t.type.is_integer(A))o.throw_error(t.error.type(\"integer\",A,n.indicator));else if(t.type.is_integer(A)&&A.value<0)o.throw_error(t.error.domain(\"not_less_than_zero\",A,n.indicator));else{var p=new t.type.Term(\"length\",[u,new t.type.Num(0,!1),A]);t.type.is_integer(A)&&(p=new t.type.Term(\",\",[p,new t.type.Term(\"!\",[])])),o.prepend([new t.type.State(a.goal.replace(p),a.substitution,a)])}},\"length/3\":[new t.type.Rule(new t.type.Term(\"length\",[new t.type.Term(\"[]\",[]),new t.type.Var(\"N\"),new t.type.Var(\"N\")]),null),new t.type.Rule(new t.type.Term(\"length\",[new t.type.Term(\".\",[new t.type.Var(\"_\"),new t.type.Var(\"X\")]),new t.type.Var(\"A\"),new t.type.Var(\"N\")]),new t.type.Term(\",\",[new t.type.Term(\"succ\",[new t.type.Var(\"A\"),new t.type.Var(\"B\")]),new t.type.Term(\"length\",[new t.type.Var(\"X\"),new t.type.Var(\"B\"),new t.type.Var(\"N\")])]))],\"replicate/3\":function(o,a,n){var u=n.args[0],A=n.args[1],p=n.args[2];if(t.type.is_variable(A))o.throw_error(t.error.instantiation(n.indicator));else if(!t.type.is_integer(A))o.throw_error(t.error.type(\"integer\",A,n.indicator));else if(A.value<0)o.throw_error(t.error.domain(\"not_less_than_zero\",A,n.indicator));else if(!t.type.is_variable(p)&&!t.type.is_list(p))o.throw_error(t.error.type(\"list\",p,n.indicator));else{for(var h=new t.type.Term(\"[]\"),C=0;C<A.value;C++)h=new t.type.Term(\".\",[u,h]);o.prepend([new t.type.State(a.goal.replace(new t.type.Term(\"=\",[h,p])),a.substitution,a)])}},\"sort/2\":function(o,a,n){var u=n.args[0],A=n.args[1];if(t.type.is_variable(u))o.throw_error(t.error.instantiation(n.indicator));else if(!t.type.is_variable(A)&&!t.type.is_fully_list(A))o.throw_error(t.error.type(\"list\",A,n.indicator));else{for(var p=[],h=u;h.indicator===\"./2\";)p.push(h.args[0]),h=h.args[1];if(t.type.is_variable(h))o.throw_error(t.error.instantiation(n.indicator));else if(!t.type.is_empty_list(h))o.throw_error(t.error.type(\"list\",u,n.indicator));else{for(var C=p.sort(t.compare),I=C.length-1;I>0;I--)C[I].equals(C[I-1])&&C.splice(I,1);for(var v=new t.type.Term(\"[]\"),I=C.length-1;I>=0;I--)v=new t.type.Term(\".\",[C[I],v]);o.prepend([new t.type.State(a.goal.replace(new t.type.Term(\"=\",[v,A])),a.substitution,a)])}}},\"msort/2\":function(o,a,n){var u=n.args[0],A=n.args[1];if(t.type.is_variable(u))o.throw_error(t.error.instantiation(n.indicator));else if(!t.type.is_variable(A)&&!t.type.is_fully_list(A))o.throw_error(t.error.type(\"list\",A,n.indicator));else{for(var p=[],h=u;h.indicator===\"./2\";)p.push(h.args[0]),h=h.args[1];if(t.type.is_variable(h))o.throw_error(t.error.instantiation(n.indicator));else if(!t.type.is_empty_list(h))o.throw_error(t.error.type(\"list\",u,n.indicator));else{for(var C=p.sort(t.compare),I=new t.type.Term(\"[]\"),v=C.length-1;v>=0;v--)I=new t.type.Term(\".\",[C[v],I]);o.prepend([new t.type.State(a.goal.replace(new t.type.Term(\"=\",[I,A])),a.substitution,a)])}}},\"keysort/2\":function(o,a,n){var u=n.args[0],A=n.args[1];if(t.type.is_variable(u))o.throw_error(t.error.instantiation(n.indicator));else if(!t.type.is_variable(A)&&!t.type.is_fully_list(A))o.throw_error(t.error.type(\"list\",A,n.indicator));else{for(var p=[],h,C=u;C.indicator===\"./2\";){if(h=C.args[0],t.type.is_variable(h)){o.throw_error(t.error.instantiation(n.indicator));return}else if(!t.type.is_term(h)||h.indicator!==\"-/2\"){o.throw_error(t.error.type(\"pair\",h,n.indicator));return}h.args[0].pair=h.args[1],p.push(h.args[0]),C=C.args[1]}if(t.type.is_variable(C))o.throw_error(t.error.instantiation(n.indicator));else if(!t.type.is_empty_list(C))o.throw_error(t.error.type(\"list\",u,n.indicator));else{for(var I=p.sort(t.compare),v=new t.type.Term(\"[]\"),x=I.length-1;x>=0;x--)v=new t.type.Term(\".\",[new t.type.Term(\"-\",[I[x],I[x].pair]),v]),delete I[x].pair;o.prepend([new t.type.State(a.goal.replace(new t.type.Term(\"=\",[v,A])),a.substitution,a)])}}},\"take/3\":function(o,a,n){var u=n.args[0],A=n.args[1],p=n.args[2];if(t.type.is_variable(A)||t.type.is_variable(u))o.throw_error(t.error.instantiation(n.indicator));else if(!t.type.is_list(A))o.throw_error(t.error.type(\"list\",A,n.indicator));else if(!t.type.is_integer(u))o.throw_error(t.error.type(\"integer\",u,n.indicator));else if(!t.type.is_variable(p)&&!t.type.is_list(p))o.throw_error(t.error.type(\"list\",p,n.indicator));else{for(var h=u.value,C=[],I=A;h>0&&I.indicator===\"./2\";)C.push(I.args[0]),I=I.args[1],h--;if(h===0){for(var v=new t.type.Term(\"[]\"),h=C.length-1;h>=0;h--)v=new t.type.Term(\".\",[C[h],v]);o.prepend([new t.type.State(a.goal.replace(new t.type.Term(\"=\",[v,p])),a.substitution,a)])}}},\"drop/3\":function(o,a,n){var u=n.args[0],A=n.args[1],p=n.args[2];if(t.type.is_variable(A)||t.type.is_variable(u))o.throw_error(t.error.instantiation(n.indicator));else if(!t.type.is_list(A))o.throw_error(t.error.type(\"list\",A,n.indicator));else if(!t.type.is_integer(u))o.throw_error(t.error.type(\"integer\",u,n.indicator));else if(!t.type.is_variable(p)&&!t.type.is_list(p))o.throw_error(t.error.type(\"list\",p,n.indicator));else{for(var h=u.value,C=[],I=A;h>0&&I.indicator===\"./2\";)C.push(I.args[0]),I=I.args[1],h--;h===0&&o.prepend([new t.type.State(a.goal.replace(new t.type.Term(\"=\",[I,p])),a.substitution,a)])}},\"reverse/2\":function(o,a,n){var u=n.args[0],A=n.args[1],p=t.type.is_instantiated_list(u),h=t.type.is_instantiated_list(A);if(t.type.is_variable(u)&&t.type.is_variable(A))o.throw_error(t.error.instantiation(n.indicator));else if(!t.type.is_variable(u)&&!t.type.is_fully_list(u))o.throw_error(t.error.type(\"list\",u,n.indicator));else if(!t.type.is_variable(A)&&!t.type.is_fully_list(A))o.throw_error(t.error.type(\"list\",A,n.indicator));else if(!p&&!h)o.throw_error(t.error.instantiation(n.indicator));else{for(var C=p?u:A,I=new t.type.Term(\"[]\",[]);C.indicator===\"./2\";)I=new t.type.Term(\".\",[C.args[0],I]),C=C.args[1];o.prepend([new t.type.State(a.goal.replace(new t.type.Term(\"=\",[I,p?A:u])),a.substitution,a)])}},\"list_to_set/2\":function(o,a,n){var u=n.args[0],A=n.args[1];if(t.type.is_variable(u))o.throw_error(t.error.instantiation(n.indicator));else{for(var p=u,h=[];p.indicator===\"./2\";)h.push(p.args[0]),p=p.args[1];if(t.type.is_variable(p))o.throw_error(t.error.instantiation(n.indicator));else if(!t.type.is_term(p)||p.indicator!==\"[]/0\")o.throw_error(t.error.type(\"list\",u,n.indicator));else{for(var C=[],I=new t.type.Term(\"[]\",[]),v,x=0;x<h.length;x++){v=!1;for(var E=0;E<C.length&&!v;E++)v=t.compare(h[x],C[E])===0;v||C.push(h[x])}for(x=C.length-1;x>=0;x--)I=new t.type.Term(\".\",[C[x],I]);o.prepend([new t.type.State(a.goal.replace(new t.type.Term(\"=\",[A,I])),a.substitution,a)])}}}}},r=[\"append/2\",\"append/3\",\"member/2\",\"permutation/2\",\"maplist/2\",\"maplist/3\",\"maplist/4\",\"maplist/5\",\"maplist/6\",\"maplist/7\",\"maplist/8\",\"include/3\",\"exclude/3\",\"foldl/4\",\"sum_list/2\",\"max_list/2\",\"min_list/2\",\"prod_list/2\",\"last/2\",\"prefix/2\",\"nth0/3\",\"nth1/3\",\"nth0/4\",\"nth1/4\",\"length/2\",\"replicate/3\",\"select/3\",\"sort/2\",\"msort/2\",\"keysort/2\",\"take/3\",\"drop/3\",\"reverse/2\",\"list_to_set/2\"];typeof aH<\"u\"?aH.exports=function(o){t=o,new t.type.Module(\"lists\",e(),r)}:new t.type.Module(\"lists\",e(),r)})(Ygt)});var ame=_(Yr=>{\"use strict\";var Xd=process.platform===\"win32\",lH=\"aes-256-cbc\",Wgt=\"sha256\",zde=\"The current environment doesn't support interactive reading from TTY.\",Yn=Be(\"fs\"),Kde=process.binding(\"tty_wrap\").TTY,uH=Be(\"child_process\"),l0=Be(\"path\"),AH={prompt:\"> \",hideEchoBack:!1,mask:\"*\",limit:[],limitMessage:\"Input another, please.$<( [)limit(])>\",defaultInput:\"\",trueValue:[],falseValue:[],caseSensitive:!1,keepWhitespace:!1,encoding:\"utf8\",bufferSize:1024,print:void 0,history:!0,cd:!1,phContent:void 0,preCheck:void 0},Vf=\"none\",Xc,wC,Vde=!1,a0,Ek,cH,Kgt=0,dH=\"\",Jd=[],Ck,Jde=!1,fH=!1,B2=!1;function Xde(t){function e(r){return r.replace(/[^\\w\\u0080-\\uFFFF]/g,function(o){return\"#\"+o.charCodeAt(0)+\";\"})}return Ek.concat(function(r){var o=[];return Object.keys(r).forEach(function(a){r[a]===\"boolean\"?t[a]&&o.push(\"--\"+a):r[a]===\"string\"&&t[a]&&o.push(\"--\"+a,e(t[a]))}),o}({display:\"string\",displayOnly:\"boolean\",keyIn:\"boolean\",hideEchoBack:\"boolean\",mask:\"string\",limit:\"string\",caseSensitive:\"boolean\"}))}function Vgt(t,e){function r(U){var z,te=\"\",le;for(cH=cH||Be(\"os\").tmpdir();;){z=l0.join(cH,U+te);try{le=Yn.openSync(z,\"wx\")}catch(he){if(he.code===\"EEXIST\"){te++;continue}else throw he}Yn.closeSync(le);break}return z}var o,a,n,u={},A,p,h=r(\"readline-sync.stdout\"),C=r(\"readline-sync.stderr\"),I=r(\"readline-sync.exit\"),v=r(\"readline-sync.done\"),x=Be(\"crypto\"),E,R,L;E=x.createHash(Wgt),E.update(\"\"+process.pid+Kgt+++Math.random()),L=E.digest(\"hex\"),R=x.createDecipher(lH,L),o=Xde(t),Xd?(a=process.env.ComSpec||\"cmd.exe\",process.env.Q='\"',n=[\"/V:ON\",\"/S\",\"/C\",\"(%Q%\"+a+\"%Q% /V:ON /S /C %Q%%Q%\"+a0+\"%Q%\"+o.map(function(U){return\" %Q%\"+U+\"%Q%\"}).join(\"\")+\" & (echo !ERRORLEVEL!)>%Q%\"+I+\"%Q%%Q%) 2>%Q%\"+C+\"%Q% |%Q%\"+process.execPath+\"%Q% %Q%\"+__dirname+\"\\\\encrypt.js%Q% %Q%\"+lH+\"%Q% %Q%\"+L+\"%Q% >%Q%\"+h+\"%Q% & (echo 1)>%Q%\"+v+\"%Q%\"]):(a=\"/bin/sh\",n=[\"-c\",'(\"'+a0+'\"'+o.map(function(U){return\" '\"+U.replace(/'/g,\"'\\\\''\")+\"'\"}).join(\"\")+'; echo $?>\"'+I+'\") 2>\"'+C+'\" |\"'+process.execPath+'\" \"'+__dirname+'/encrypt.js\" \"'+lH+'\" \"'+L+'\" >\"'+h+'\"; echo 1 >\"'+v+'\"']),B2&&B2(\"_execFileSync\",o);try{uH.spawn(a,n,e)}catch(U){u.error=new Error(U.message),u.error.method=\"_execFileSync - spawn\",u.error.program=a,u.error.args=n}for(;Yn.readFileSync(v,{encoding:t.encoding}).trim()!==\"1\";);return(A=Yn.readFileSync(I,{encoding:t.encoding}).trim())===\"0\"?u.input=R.update(Yn.readFileSync(h,{encoding:\"binary\"}),\"hex\",t.encoding)+R.final(t.encoding):(p=Yn.readFileSync(C,{encoding:t.encoding}).trim(),u.error=new Error(zde+(p?`\n`+p:\"\")),u.error.method=\"_execFileSync\",u.error.program=a,u.error.args=n,u.error.extMessage=p,u.error.exitCode=+A),Yn.unlinkSync(h),Yn.unlinkSync(C),Yn.unlinkSync(I),Yn.unlinkSync(v),u}function zgt(t){var e,r={},o,a={env:process.env,encoding:t.encoding};if(a0||(Xd?process.env.PSModulePath?(a0=\"powershell.exe\",Ek=[\"-ExecutionPolicy\",\"Bypass\",\"-File\",__dirname+\"\\\\read.ps1\"]):(a0=\"cscript.exe\",Ek=[\"//nologo\",__dirname+\"\\\\read.cs.js\"]):(a0=\"/bin/sh\",Ek=[__dirname+\"/read.sh\"])),Xd&&!process.env.PSModulePath&&(a.stdio=[process.stdin]),uH.execFileSync){e=Xde(t),B2&&B2(\"execFileSync\",e);try{r.input=uH.execFileSync(a0,e,a)}catch(n){o=n.stderr?(n.stderr+\"\").trim():\"\",r.error=new Error(zde+(o?`\n`+o:\"\")),r.error.method=\"execFileSync\",r.error.program=a0,r.error.args=e,r.error.extMessage=o,r.error.exitCode=n.status,r.error.code=n.code,r.error.signal=n.signal}}else r=Vgt(t,a);return r.error||(r.input=r.input.replace(/^\\s*'|'\\s*$/g,\"\"),t.display=\"\"),r}function pH(t){var e=\"\",r=t.display,o=!t.display&&t.keyIn&&t.hideEchoBack&&!t.mask;function a(){var n=zgt(t);if(n.error)throw n.error;return n.input}return fH&&fH(t),function(){var n,u,A;function p(){return n||(n=process.binding(\"fs\"),u=process.binding(\"constants\")),n}if(typeof Vf==\"string\")if(Vf=null,Xd){if(A=function(h){var C=h.replace(/^\\D+/,\"\").split(\".\"),I=0;return(C[0]=+C[0])&&(I+=C[0]*1e4),(C[1]=+C[1])&&(I+=C[1]*100),(C[2]=+C[2])&&(I+=C[2]),I}(process.version),!(A>=20302&&A<40204||A>=5e4&&A<50100||A>=50600&&A<60200)&&process.stdin.isTTY)process.stdin.pause(),Vf=process.stdin.fd,wC=process.stdin._handle;else try{Vf=p().open(\"CONIN$\",u.O_RDWR,parseInt(\"0666\",8)),wC=new Kde(Vf,!0)}catch{}if(process.stdout.isTTY)Xc=process.stdout.fd;else{try{Xc=Yn.openSync(\"\\\\\\\\.\\\\CON\",\"w\")}catch{}if(typeof Xc!=\"number\")try{Xc=p().open(\"CONOUT$\",u.O_RDWR,parseInt(\"0666\",8))}catch{}}}else{if(process.stdin.isTTY){process.stdin.pause();try{Vf=Yn.openSync(\"/dev/tty\",\"r\"),wC=process.stdin._handle}catch{}}else try{Vf=Yn.openSync(\"/dev/tty\",\"r\"),wC=new Kde(Vf,!1)}catch{}if(process.stdout.isTTY)Xc=process.stdout.fd;else try{Xc=Yn.openSync(\"/dev/tty\",\"w\")}catch{}}}(),function(){var n,u,A=!t.hideEchoBack&&!t.keyIn,p,h,C,I,v;Ck=\"\";function x(E){return E===Vde?!0:wC.setRawMode(E)!==0?!1:(Vde=E,!0)}if(Jde||!wC||typeof Xc!=\"number\"&&(t.display||!A)){e=a();return}if(t.display&&(Yn.writeSync(Xc,t.display),t.display=\"\"),!t.displayOnly){if(!x(!A)){e=a();return}for(h=t.keyIn?1:t.bufferSize,p=Buffer.allocUnsafe&&Buffer.alloc?Buffer.alloc(h):new Buffer(h),t.keyIn&&t.limit&&(u=new RegExp(\"[^\"+t.limit+\"]\",\"g\"+(t.caseSensitive?\"\":\"i\")));;){C=0;try{C=Yn.readSync(Vf,p,0,h)}catch(E){if(E.code!==\"EOF\"){x(!1),e+=a();return}}if(C>0?(I=p.toString(t.encoding,0,C),Ck+=I):(I=`\n`,Ck+=String.fromCharCode(0)),I&&typeof(v=(I.match(/^(.*?)[\\r\\n]/)||[])[1])==\"string\"&&(I=v,n=!0),I&&(I=I.replace(/[\\x00-\\x08\\x0b\\x0c\\x0e-\\x1f\\x7f]/g,\"\")),I&&u&&(I=I.replace(u,\"\")),I&&(A||(t.hideEchoBack?t.mask&&Yn.writeSync(Xc,new Array(I.length+1).join(t.mask)):Yn.writeSync(Xc,I)),e+=I),!t.keyIn&&n||t.keyIn&&e.length>=h)break}!A&&!o&&Yn.writeSync(Xc,`\n`),x(!1)}}(),t.print&&!o&&t.print(r+(t.displayOnly?\"\":(t.hideEchoBack?new Array(e.length+1).join(t.mask):e)+`\n`),t.encoding),t.displayOnly?\"\":dH=t.keepWhitespace||t.keyIn?e:e.trim()}function Jgt(t,e){var r=[];function o(a){a!=null&&(Array.isArray(a)?a.forEach(o):(!e||e(a))&&r.push(a))}return o(t),r}function mH(t){return t.replace(/[\\x00-\\x7f]/g,function(e){return\"\\\\x\"+(\"00\"+e.charCodeAt().toString(16)).substr(-2)})}function Rs(){var t=Array.prototype.slice.call(arguments),e,r;return t.length&&typeof t[0]==\"boolean\"&&(r=t.shift(),r&&(e=Object.keys(AH),t.unshift(AH))),t.reduce(function(o,a){return a==null||(a.hasOwnProperty(\"noEchoBack\")&&!a.hasOwnProperty(\"hideEchoBack\")&&(a.hideEchoBack=a.noEchoBack,delete a.noEchoBack),a.hasOwnProperty(\"noTrim\")&&!a.hasOwnProperty(\"keepWhitespace\")&&(a.keepWhitespace=a.noTrim,delete a.noTrim),r||(e=Object.keys(a)),e.forEach(function(n){var u;if(!!a.hasOwnProperty(n))switch(u=a[n],n){case\"mask\":case\"limitMessage\":case\"defaultInput\":case\"encoding\":u=u!=null?u+\"\":\"\",u&&n!==\"limitMessage\"&&(u=u.replace(/[\\r\\n]/g,\"\")),o[n]=u;break;case\"bufferSize\":!isNaN(u=parseInt(u,10))&&typeof u==\"number\"&&(o[n]=u);break;case\"displayOnly\":case\"keyIn\":case\"hideEchoBack\":case\"caseSensitive\":case\"keepWhitespace\":case\"history\":case\"cd\":o[n]=!!u;break;case\"limit\":case\"trueValue\":case\"falseValue\":o[n]=Jgt(u,function(A){var p=typeof A;return p===\"string\"||p===\"number\"||p===\"function\"||A instanceof RegExp}).map(function(A){return typeof A==\"string\"?A.replace(/[\\r\\n]/g,\"\"):A});break;case\"print\":case\"phContent\":case\"preCheck\":o[n]=typeof u==\"function\"?u:void 0;break;case\"prompt\":case\"display\":o[n]=u??\"\";break}})),o},{})}function hH(t,e,r){return e.some(function(o){var a=typeof o;return a===\"string\"?r?t===o:t.toLowerCase()===o.toLowerCase():a===\"number\"?parseFloat(t)===o:a===\"function\"?o(t):o instanceof RegExp?o.test(t):!1})}function yH(t,e){var r=l0.normalize(Xd?(process.env.HOMEDRIVE||\"\")+(process.env.HOMEPATH||\"\"):process.env.HOME||\"\").replace(/[\\/\\\\]+$/,\"\");return t=l0.normalize(t),e?t.replace(/^~(?=\\/|\\\\|$)/,r):t.replace(new RegExp(\"^\"+mH(r)+\"(?=\\\\/|\\\\\\\\|$)\",Xd?\"i\":\"\"),\"~\")}function IC(t,e){var r=\"(?:\\\\(([\\\\s\\\\S]*?)\\\\))?(\\\\w+|.-.)(?:\\\\(([\\\\s\\\\S]*?)\\\\))?\",o=new RegExp(\"(\\\\$)?(\\\\$<\"+r+\">)\",\"g\"),a=new RegExp(\"(\\\\$)?(\\\\$\\\\{\"+r+\"\\\\})\",\"g\");function n(u,A,p,h,C,I){var v;return A||typeof(v=e(C))!=\"string\"?p:v?(h||\"\")+v+(I||\"\"):\"\"}return t.replace(o,n).replace(a,n)}function Zde(t,e,r){var o,a=[],n=-1,u=0,A=\"\",p;function h(C,I){return I.length>3?(C.push(I[0]+\"...\"+I[I.length-1]),p=!0):I.length&&(C=C.concat(I)),C}return o=t.reduce(function(C,I){return C.concat((I+\"\").split(\"\"))},[]).reduce(function(C,I){var v,x;return e||(I=I.toLowerCase()),v=/^\\d$/.test(I)?1:/^[A-Z]$/.test(I)?2:/^[a-z]$/.test(I)?3:0,r&&v===0?A+=I:(x=I.charCodeAt(0),v&&v===n&&x===u+1?a.push(I):(C=h(C,a),a=[I],n=v),u=x),C},[]),o=h(o,a),A&&(o.push(A),p=!0),{values:o,suppressed:p}}function $de(t,e){return t.join(t.length>2?\", \":e?\" / \":\"/\")}function eme(t,e){var r,o,a={},n;if(e.phContent&&(r=e.phContent(t,e)),typeof r!=\"string\")switch(t){case\"hideEchoBack\":case\"mask\":case\"defaultInput\":case\"caseSensitive\":case\"keepWhitespace\":case\"encoding\":case\"bufferSize\":case\"history\":case\"cd\":r=e.hasOwnProperty(t)?typeof e[t]==\"boolean\"?e[t]?\"on\":\"off\":e[t]+\"\":\"\";break;case\"limit\":case\"trueValue\":case\"falseValue\":o=e[e.hasOwnProperty(t+\"Src\")?t+\"Src\":t],e.keyIn?(a=Zde(o,e.caseSensitive),o=a.values):o=o.filter(function(u){var A=typeof u;return A===\"string\"||A===\"number\"}),r=$de(o,a.suppressed);break;case\"limitCount\":case\"limitCountNotZero\":r=e[e.hasOwnProperty(\"limitSrc\")?\"limitSrc\":\"limit\"].length,r=r||t!==\"limitCountNotZero\"?r+\"\":\"\";break;case\"lastInput\":r=dH;break;case\"cwd\":case\"CWD\":case\"cwdHome\":r=process.cwd(),t===\"CWD\"?r=l0.basename(r):t===\"cwdHome\"&&(r=yH(r));break;case\"date\":case\"time\":case\"localeDate\":case\"localeTime\":r=new Date()[\"to\"+t.replace(/^./,function(u){return u.toUpperCase()})+\"String\"]();break;default:typeof(n=(t.match(/^history_m(\\d+)$/)||[])[1])==\"string\"&&(r=Jd[Jd.length-n]||\"\")}return r}function tme(t){var e=/^(.)-(.)$/.exec(t),r=\"\",o,a,n,u;if(!e)return null;for(o=e[1].charCodeAt(0),a=e[2].charCodeAt(0),u=o<a?1:-1,n=o;n!==a+u;n+=u)r+=String.fromCharCode(n);return r}function gH(t){var e=new RegExp(/(\\s*)(?:(\"|')(.*?)(?:\\2|$)|(\\S+))/g),r,o=\"\",a=[],n;for(t=t.trim();r=e.exec(t);)n=r[3]||r[4]||\"\",r[1]&&(a.push(o),o=\"\"),o+=n;return o&&a.push(o),a}function rme(t,e){return e.trueValue.length&&hH(t,e.trueValue,e.caseSensitive)?!0:e.falseValue.length&&hH(t,e.falseValue,e.caseSensitive)?!1:t}function nme(t){var e,r,o,a,n,u,A;function p(C){return eme(C,t)}function h(C){t.display+=(/[^\\r\\n]$/.test(t.display)?`\n`:\"\")+C}for(t.limitSrc=t.limit,t.displaySrc=t.display,t.limit=\"\",t.display=IC(t.display+\"\",p);;){if(e=pH(t),r=!1,o=\"\",t.defaultInput&&!e&&(e=t.defaultInput),t.history&&((a=/^\\s*\\!(?:\\!|-1)(:p)?\\s*$/.exec(e))?(n=Jd[0]||\"\",a[1]?r=!0:e=n,h(n+`\n`),r||(t.displayOnly=!0,pH(t),t.displayOnly=!1)):e&&e!==Jd[Jd.length-1]&&(Jd=[e])),!r&&t.cd&&e)switch(u=gH(e),u[0].toLowerCase()){case\"cd\":if(u[1])try{process.chdir(yH(u[1],!0))}catch(C){h(C+\"\")}r=!0;break;case\"pwd\":h(process.cwd()),r=!0;break}if(!r&&t.preCheck&&(A=t.preCheck(e,t),e=A.res,A.forceNext&&(r=!0)),!r){if(!t.limitSrc.length||hH(e,t.limitSrc,t.caseSensitive))break;t.limitMessage&&(o=IC(t.limitMessage,p))}h((o?o+`\n`:\"\")+IC(t.displaySrc+\"\",p))}return rme(e,t)}Yr._DBG_set_useExt=function(t){Jde=t};Yr._DBG_set_checkOptions=function(t){fH=t};Yr._DBG_set_checkMethod=function(t){B2=t};Yr._DBG_clearHistory=function(){dH=\"\",Jd=[]};Yr.setDefaultOptions=function(t){return AH=Rs(!0,t),Rs(!0)};Yr.question=function(t,e){return nme(Rs(Rs(!0,e),{display:t}))};Yr.prompt=function(t){var e=Rs(!0,t);return e.display=e.prompt,nme(e)};Yr.keyIn=function(t,e){var r=Rs(Rs(!0,e),{display:t,keyIn:!0,keepWhitespace:!0});return r.limitSrc=r.limit.filter(function(o){var a=typeof o;return a===\"string\"||a===\"number\"}).map(function(o){return IC(o+\"\",tme)}),r.limit=mH(r.limitSrc.join(\"\")),[\"trueValue\",\"falseValue\"].forEach(function(o){r[o]=r[o].reduce(function(a,n){var u=typeof n;return u===\"string\"||u===\"number\"?a=a.concat((n+\"\").split(\"\")):a.push(n),a},[])}),r.display=IC(r.display+\"\",function(o){return eme(o,r)}),rme(pH(r),r)};Yr.questionEMail=function(t,e){return t==null&&(t=\"Input e-mail address: \"),Yr.question(t,Rs({hideEchoBack:!1,limit:/^[a-zA-Z0-9.!#$%&'*+\\/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/,limitMessage:\"Input valid e-mail address, please.\",trueValue:null,falseValue:null},e,{keepWhitespace:!1,cd:!1}))};Yr.questionNewPassword=function(t,e){var r,o,a,n=Rs({hideEchoBack:!0,mask:\"*\",limitMessage:`It can include: $<charlist>\nAnd the length must be: $<length>`,trueValue:null,falseValue:null,caseSensitive:!0},e,{history:!1,cd:!1,phContent:function(x){return x===\"charlist\"?r.text:x===\"length\"?o+\"...\"+a:null}}),u,A,p,h,C,I,v;for(e=e||{},u=IC(e.charlist?e.charlist+\"\":\"$<!-~>\",tme),(isNaN(o=parseInt(e.min,10))||typeof o!=\"number\")&&(o=12),(isNaN(a=parseInt(e.max,10))||typeof a!=\"number\")&&(a=24),h=new RegExp(\"^[\"+mH(u)+\"]{\"+o+\",\"+a+\"}$\"),r=Zde([u],n.caseSensitive,!0),r.text=$de(r.values,r.suppressed),A=e.confirmMessage!=null?e.confirmMessage:\"Reinput a same one to confirm it: \",p=e.unmatchMessage!=null?e.unmatchMessage:\"It differs from first one. Hit only the Enter key if you want to retry from first one.\",t==null&&(t=\"Input new password: \"),C=n.limitMessage;!v;)n.limit=h,n.limitMessage=C,I=Yr.question(t,n),n.limit=[I,\"\"],n.limitMessage=p,v=Yr.question(A,n);return I};function ime(t,e,r){var o;function a(n){return o=r(n),!isNaN(o)&&typeof o==\"number\"}return Yr.question(t,Rs({limitMessage:\"Input valid number, please.\"},e,{limit:a,cd:!1})),o}Yr.questionInt=function(t,e){return ime(t,e,function(r){return parseInt(r,10)})};Yr.questionFloat=function(t,e){return ime(t,e,parseFloat)};Yr.questionPath=function(t,e){var r,o=\"\",a=Rs({hideEchoBack:!1,limitMessage:`$<error(\n)>Input valid path, please.$<( Min:)min>$<( Max:)max>`,history:!0,cd:!0},e,{keepWhitespace:!1,limit:function(n){var u,A,p;n=yH(n,!0),o=\"\";function h(C){C.split(/\\/|\\\\/).reduce(function(I,v){var x=l0.resolve(I+=v+l0.sep);if(!Yn.existsSync(x))Yn.mkdirSync(x);else if(!Yn.statSync(x).isDirectory())throw new Error(\"Non directory already exists: \"+x);return I},\"\")}try{if(u=Yn.existsSync(n),r=u?Yn.realpathSync(n):l0.resolve(n),!e.hasOwnProperty(\"exists\")&&!u||typeof e.exists==\"boolean\"&&e.exists!==u)return o=(u?\"Already exists\":\"No such file or directory\")+\": \"+r,!1;if(!u&&e.create&&(e.isDirectory?h(r):(h(l0.dirname(r)),Yn.closeSync(Yn.openSync(r,\"w\"))),r=Yn.realpathSync(r)),u&&(e.min||e.max||e.isFile||e.isDirectory)){if(A=Yn.statSync(r),e.isFile&&!A.isFile())return o=\"Not file: \"+r,!1;if(e.isDirectory&&!A.isDirectory())return o=\"Not directory: \"+r,!1;if(e.min&&A.size<+e.min||e.max&&A.size>+e.max)return o=\"Size \"+A.size+\" is out of range: \"+r,!1}if(typeof e.validate==\"function\"&&(p=e.validate(r))!==!0)return typeof p==\"string\"&&(o=p),!1}catch(C){return o=C+\"\",!1}return!0},phContent:function(n){return n===\"error\"?o:n!==\"min\"&&n!==\"max\"?null:e.hasOwnProperty(n)?e[n]+\"\":\"\"}});return e=e||{},t==null&&(t='Input path (you can \"cd\" and \"pwd\"): '),Yr.question(t,a),r};function sme(t,e){var r={},o={};return typeof t==\"object\"?(Object.keys(t).forEach(function(a){typeof t[a]==\"function\"&&(o[e.caseSensitive?a:a.toLowerCase()]=t[a])}),r.preCheck=function(a){var n;return r.args=gH(a),n=r.args[0]||\"\",e.caseSensitive||(n=n.toLowerCase()),r.hRes=n!==\"_\"&&o.hasOwnProperty(n)?o[n].apply(a,r.args.slice(1)):o.hasOwnProperty(\"_\")?o._.apply(a,r.args):null,{res:a,forceNext:!1}},o.hasOwnProperty(\"_\")||(r.limit=function(){var a=r.args[0]||\"\";return e.caseSensitive||(a=a.toLowerCase()),o.hasOwnProperty(a)})):r.preCheck=function(a){return r.args=gH(a),r.hRes=typeof t==\"function\"?t.apply(a,r.args):!0,{res:a,forceNext:!1}},r}Yr.promptCL=function(t,e){var r=Rs({hideEchoBack:!1,limitMessage:\"Requested command is not available.\",caseSensitive:!1,history:!0},e),o=sme(t,r);return r.limit=o.limit,r.preCheck=o.preCheck,Yr.prompt(r),o.args};Yr.promptLoop=function(t,e){for(var r=Rs({hideEchoBack:!1,trueValue:null,falseValue:null,caseSensitive:!1,history:!0},e);!t(Yr.prompt(r)););};Yr.promptCLLoop=function(t,e){var r=Rs({hideEchoBack:!1,limitMessage:\"Requested command is not available.\",caseSensitive:!1,history:!0},e),o=sme(t,r);for(r.limit=o.limit,r.preCheck=o.preCheck;Yr.prompt(r),!o.hRes;);};Yr.promptSimShell=function(t){return Yr.prompt(Rs({hideEchoBack:!1,history:!0},t,{prompt:function(){return Xd?\"$<cwd>>\":(process.env.USER||\"\")+(process.env.HOSTNAME?\"@\"+process.env.HOSTNAME.replace(/\\..*$/,\"\"):\"\")+\":$<cwdHome>$ \"}()}))};function ome(t,e,r){var o;return t==null&&(t=\"Are you sure? \"),(!e||e.guide!==!1)&&(t+=\"\")&&(t=t.replace(/\\s*:?\\s*$/,\"\")+\" [y/n]: \"),o=Yr.keyIn(t,Rs(e,{hideEchoBack:!1,limit:r,trueValue:\"y\",falseValue:\"n\",caseSensitive:!1})),typeof o==\"boolean\"?o:\"\"}Yr.keyInYN=function(t,e){return ome(t,e)};Yr.keyInYNStrict=function(t,e){return ome(t,e,\"yn\")};Yr.keyInPause=function(t,e){t==null&&(t=\"Continue...\"),(!e||e.guide!==!1)&&(t+=\"\")&&(t=t.replace(/\\s+$/,\"\")+\" (Hit any key)\"),Yr.keyIn(t,Rs({limit:null},e,{hideEchoBack:!0,mask:\"\"}))};Yr.keyInSelect=function(t,e,r){var o=Rs({hideEchoBack:!1},r,{trueValue:null,falseValue:null,caseSensitive:!1,phContent:function(p){return p===\"itemsCount\"?t.length+\"\":p===\"firstItem\"?(t[0]+\"\").trim():p===\"lastItem\"?(t[t.length-1]+\"\").trim():null}}),a=\"\",n={},u=49,A=`\n`;if(!Array.isArray(t)||!t.length||t.length>35)throw\"`items` must be Array (max length: 35).\";return t.forEach(function(p,h){var C=String.fromCharCode(u);a+=C,n[C]=h,A+=\"[\"+C+\"] \"+(p+\"\").trim()+`\n`,u=u===57?97:u+1}),(!r||r.cancel!==!1)&&(a+=\"0\",n[0]=-1,A+=\"[0] \"+(r&&r.cancel!=null&&typeof r.cancel!=\"boolean\"?(r.cancel+\"\").trim():\"CANCEL\")+`\n`),o.limit=a,A+=`\n`,e==null&&(e=\"Choose one from list: \"),(e+=\"\")&&((!r||r.guide!==!1)&&(e=e.replace(/\\s*:?\\s*$/,\"\")+\" [$<limit>]: \"),A+=e),n[Yr.keyIn(A,o).toLowerCase()]};Yr.getRawInput=function(){return Ck};function v2(t,e){var r;return e.length&&(r={},r[t]=e[0]),Yr.setDefaultOptions(r)[t]}Yr.setPrint=function(){return v2(\"print\",arguments)};Yr.setPrompt=function(){return v2(\"prompt\",arguments)};Yr.setEncoding=function(){return v2(\"encoding\",arguments)};Yr.setMask=function(){return v2(\"mask\",arguments)};Yr.setBufferSize=function(){return v2(\"bufferSize\",arguments)}});var EH=_((Z9t,hl)=>{(function(){var t={major:0,minor:2,patch:66,status:\"beta\"};tau_file_system={files:{},open:function(w,S,y){var F=tau_file_system.files[w];if(!F){if(y===\"read\")return null;F={path:w,text:\"\",type:S,get:function(J,X){return X===this.text.length||X>this.text.length?\"end_of_file\":this.text.substring(X,X+J)},put:function(J,X){return X===\"end_of_file\"?(this.text+=J,!0):X===\"past_end_of_file\"?null:(this.text=this.text.substring(0,X)+J+this.text.substring(X+J.length),!0)},get_byte:function(J){if(J===\"end_of_stream\")return-1;var X=Math.floor(J/2);if(this.text.length<=X)return-1;var Z=n(this.text[Math.floor(J/2)],0);return J%2===0?Z&255:Z/256>>>0},put_byte:function(J,X){var Z=X===\"end_of_stream\"?this.text.length:Math.floor(X/2);if(this.text.length<Z)return null;var ie=this.text.length===Z?-1:n(this.text[Math.floor(X/2)],0);return X%2===0?(ie=ie/256>>>0,ie=(ie&255)<<8|J&255):(ie=ie&255,ie=(J&255)<<8|ie&255),this.text.length===Z?this.text+=u(ie):this.text=this.text.substring(0,Z)+u(ie)+this.text.substring(Z+1),!0},flush:function(){return!0},close:function(){var J=tau_file_system.files[this.path];return J?!0:null}},tau_file_system.files[w]=F}return y===\"write\"&&(F.text=\"\"),F}},tau_user_input={buffer:\"\",get:function(w,S){for(var y;tau_user_input.buffer.length<w;)y=window.prompt(),y&&(tau_user_input.buffer+=y);return y=tau_user_input.buffer.substr(0,w),tau_user_input.buffer=tau_user_input.buffer.substr(w),y}},tau_user_output={put:function(w,S){return console.log(w),!0},flush:function(){return!0}},nodejs_file_system={open:function(w,S,y){var F=Be(\"fs\"),J=F.openSync(w,y[0]);return y===\"read\"&&!F.existsSync(w)?null:{get:function(X,Z){var ie=new Buffer(X);return F.readSync(J,ie,0,X,Z),ie.toString()},put:function(X,Z){var ie=Buffer.from(X);if(Z===\"end_of_file\")F.writeSync(J,ie);else{if(Z===\"past_end_of_file\")return null;F.writeSync(J,ie,0,ie.length,Z)}return!0},get_byte:function(X){return null},put_byte:function(X,Z){return null},flush:function(){return!0},close:function(){return F.closeSync(J),!0}}}},nodejs_user_input={buffer:\"\",get:function(w,S){for(var y,F=ame();nodejs_user_input.buffer.length<w;)nodejs_user_input.buffer+=F.question();return y=nodejs_user_input.buffer.substr(0,w),nodejs_user_input.buffer=nodejs_user_input.buffer.substr(w),y}},nodejs_user_output={put:function(w,S){return process.stdout.write(w),!0},flush:function(){return!0}};var e;Array.prototype.indexOf?e=function(w,S){return w.indexOf(S)}:e=function(w,S){for(var y=w.length,F=0;F<y;F++)if(S===w[F])return F;return-1};var r=function(w,S){if(w.length!==0){for(var y=w[0],F=w.length,J=1;J<F;J++)y=S(y,w[J]);return y}},o;Array.prototype.map?o=function(w,S){return w.map(S)}:o=function(w,S){for(var y=[],F=w.length,J=0;J<F;J++)y.push(S(w[J]));return y};var a;Array.prototype.filter?a=function(w,S){return w.filter(S)}:a=function(w,S){for(var y=[],F=w.length,J=0;J<F;J++)S(w[J])&&y.push(w[J]);return y};var n;String.prototype.codePointAt?n=function(w,S){return w.codePointAt(S)}:n=function(w,S){return w.charCodeAt(S)};var u;String.fromCodePoint?u=function(){return String.fromCodePoint.apply(null,arguments)}:u=function(){return String.fromCharCode.apply(null,arguments)};var A=0,p=1,h=/(\\\\a)|(\\\\b)|(\\\\f)|(\\\\n)|(\\\\r)|(\\\\t)|(\\\\v)|\\\\x([0-9a-fA-F]+)\\\\|\\\\([0-7]+)\\\\|(\\\\\\\\)|(\\\\')|('')|(\\\\\")|(\\\\`)|(\\\\.)|(.)/g,C={\"\\\\a\":7,\"\\\\b\":8,\"\\\\f\":12,\"\\\\n\":10,\"\\\\r\":13,\"\\\\t\":9,\"\\\\v\":11};function I(w){var S=[],y=!1;return w.replace(h,function(F,J,X,Z,ie,Pe,Ne,ot,dt,jt,$t,bt,an,Qr,mr,br,Wr){switch(!0){case dt!==void 0:return S.push(parseInt(dt,16)),\"\";case jt!==void 0:return S.push(parseInt(jt,8)),\"\";case $t!==void 0:case bt!==void 0:case an!==void 0:case Qr!==void 0:case mr!==void 0:return S.push(n(F.substr(1),0)),\"\";case Wr!==void 0:return S.push(n(Wr,0)),\"\";case br!==void 0:y=!0;default:return S.push(C[F]),\"\"}}),y?null:S}function v(w,S){var y=\"\";if(w.length<2)return w;try{w=w.replace(/\\\\([0-7]+)\\\\/g,function(Z,ie){return u(parseInt(ie,8))}),w=w.replace(/\\\\x([0-9a-fA-F]+)\\\\/g,function(Z,ie){return u(parseInt(ie,16))})}catch{return null}for(var F=0;F<w.length;F++){var J=w.charAt(F),X=w.charAt(F+1);if(J===S&&X===S)F++,y+=S;else if(J===\"\\\\\")if([\"a\",\"b\",\"f\",\"n\",\"r\",\"t\",\"v\",\"'\",'\"',\"\\\\\",\"a\",\"\\b\",\"\\f\",`\n`,\"\\r\",\"\t\",\"\\v\"].indexOf(X)!==-1)switch(F+=1,X){case\"a\":y+=\"a\";break;case\"b\":y+=\"\\b\";break;case\"f\":y+=\"\\f\";break;case\"n\":y+=`\n`;break;case\"r\":y+=\"\\r\";break;case\"t\":y+=\"\t\";break;case\"v\":y+=\"\\v\";break;case\"'\":y+=\"'\";break;case'\"':y+='\"';break;case\"\\\\\":y+=\"\\\\\";break}else return null;else y+=J}return y}function x(w){for(var S=\"\",y=0;y<w.length;y++)switch(w.charAt(y)){case\"'\":S+=\"\\\\'\";break;case\"\\\\\":S+=\"\\\\\\\\\";break;case\"\\b\":S+=\"\\\\b\";break;case\"\\f\":S+=\"\\\\f\";break;case`\n`:S+=\"\\\\n\";break;case\"\\r\":S+=\"\\\\r\";break;case\"\t\":S+=\"\\\\t\";break;case\"\\v\":S+=\"\\\\v\";break;default:S+=w.charAt(y);break}return S}function E(w){var S=w.substr(2);switch(w.substr(0,2).toLowerCase()){case\"0x\":return parseInt(S,16);case\"0b\":return parseInt(S,2);case\"0o\":return parseInt(S,8);case\"0'\":return I(S)[0];default:return parseFloat(w)}}var R={whitespace:/^\\s*(?:(?:%.*)|(?:\\/\\*(?:\\n|\\r|.)*?\\*\\/)|(?:\\s+))\\s*/,variable:/^(?:[A-Z_][a-zA-Z0-9_]*)/,atom:/^(\\!|,|;|[a-z][0-9a-zA-Z_]*|[#\\$\\&\\*\\+\\-\\.\\/\\:\\<\\=\\>\\?\\@\\^\\~\\\\]+|'(?:[^']*?(?:\\\\(?:x?\\d+)?\\\\)*(?:'')*(?:\\\\')*)*')/,number:/^(?:0o[0-7]+|0x[0-9a-fA-F]+|0b[01]+|0'(?:''|\\\\[abfnrtv\\\\'\"`]|\\\\x?\\d+\\\\|[^\\\\])|\\d+(?:\\.\\d+(?:[eE][+-]?\\d+)?)?)/,string:/^(?:\"([^\"]|\"\"|\\\\\")*\"|`([^`]|``|\\\\`)*`)/,l_brace:/^(?:\\[)/,r_brace:/^(?:\\])/,l_bracket:/^(?:\\{)/,r_bracket:/^(?:\\})/,bar:/^(?:\\|)/,l_paren:/^(?:\\()/,r_paren:/^(?:\\))/};function L(w,S){return w.get_flag(\"char_conversion\").id===\"on\"?S.replace(/./g,function(y){return w.get_char_conversion(y)}):S}function U(w){this.thread=w,this.text=\"\",this.tokens=[]}U.prototype.set_last_tokens=function(w){return this.tokens=w},U.prototype.new_text=function(w){this.text=w,this.tokens=[]},U.prototype.get_tokens=function(w){var S,y=0,F=0,J=0,X=[],Z=!1;if(w){var ie=this.tokens[w-1];y=ie.len,S=L(this.thread,this.text.substr(ie.len)),F=ie.line,J=ie.start}else S=this.text;if(/^\\s*$/.test(S))return null;for(;S!==\"\";){var Pe=[],Ne=!1;if(/^\\n/.exec(S)!==null){F++,J=0,y++,S=S.replace(/\\n/,\"\"),Z=!0;continue}for(var ot in R)if(R.hasOwnProperty(ot)){var dt=R[ot].exec(S);dt&&Pe.push({value:dt[0],name:ot,matches:dt})}if(!Pe.length)return this.set_last_tokens([{value:S,matches:[],name:\"lexical\",line:F,start:J}]);var ie=r(Pe,function(Qr,mr){return Qr.value.length>=mr.value.length?Qr:mr});switch(ie.start=J,ie.line=F,S=S.replace(ie.value,\"\"),J+=ie.value.length,y+=ie.value.length,ie.name){case\"atom\":ie.raw=ie.value,ie.value.charAt(0)===\"'\"&&(ie.value=v(ie.value.substr(1,ie.value.length-2),\"'\"),ie.value===null&&(ie.name=\"lexical\",ie.value=\"unknown escape sequence\"));break;case\"number\":ie.float=ie.value.substring(0,2)!==\"0x\"&&ie.value.match(/[.eE]/)!==null&&ie.value!==\"0'.\",ie.value=E(ie.value),ie.blank=Ne;break;case\"string\":var jt=ie.value.charAt(0);ie.value=v(ie.value.substr(1,ie.value.length-2),jt),ie.value===null&&(ie.name=\"lexical\",ie.value=\"unknown escape sequence\");break;case\"whitespace\":var $t=X[X.length-1];$t&&($t.space=!0),Ne=!0;continue;case\"r_bracket\":X.length>0&&X[X.length-1].name===\"l_bracket\"&&(ie=X.pop(),ie.name=\"atom\",ie.value=\"{}\",ie.raw=\"{}\",ie.space=!1);break;case\"r_brace\":X.length>0&&X[X.length-1].name===\"l_brace\"&&(ie=X.pop(),ie.name=\"atom\",ie.value=\"[]\",ie.raw=\"[]\",ie.space=!1);break}ie.len=y,X.push(ie),Ne=!1}var bt=this.set_last_tokens(X);return bt.length===0?null:bt};function z(w,S,y,F,J){if(!S[y])return{type:A,value:b.error.syntax(S[y-1],\"expression expected\",!0)};var X;if(F===\"0\"){var Z=S[y];switch(Z.name){case\"number\":return{type:p,len:y+1,value:new b.type.Num(Z.value,Z.float)};case\"variable\":return{type:p,len:y+1,value:new b.type.Var(Z.value)};case\"string\":var ie;switch(w.get_flag(\"double_quotes\").id){case\"atom\":ie=new H(Z.value,[]);break;case\"codes\":ie=new H(\"[]\",[]);for(var Pe=Z.value.length-1;Pe>=0;Pe--)ie=new H(\".\",[new b.type.Num(n(Z.value,Pe),!1),ie]);break;case\"chars\":ie=new H(\"[]\",[]);for(var Pe=Z.value.length-1;Pe>=0;Pe--)ie=new H(\".\",[new b.type.Term(Z.value.charAt(Pe),[]),ie]);break}return{type:p,len:y+1,value:ie};case\"l_paren\":var bt=z(w,S,y+1,w.__get_max_priority(),!0);return bt.type!==p?bt:S[bt.len]&&S[bt.len].name===\"r_paren\"?(bt.len++,bt):{type:A,derived:!0,value:b.error.syntax(S[bt.len]?S[bt.len]:S[bt.len-1],\") or operator expected\",!S[bt.len])};case\"l_bracket\":var bt=z(w,S,y+1,w.__get_max_priority(),!0);return bt.type!==p?bt:S[bt.len]&&S[bt.len].name===\"r_bracket\"?(bt.len++,bt.value=new H(\"{}\",[bt.value]),bt):{type:A,derived:!0,value:b.error.syntax(S[bt.len]?S[bt.len]:S[bt.len-1],\"} or operator expected\",!S[bt.len])}}var Ne=te(w,S,y,J);return Ne.type===p||Ne.derived||(Ne=le(w,S,y),Ne.type===p||Ne.derived)?Ne:{type:A,derived:!1,value:b.error.syntax(S[y],\"unexpected token\")}}var ot=w.__get_max_priority(),dt=w.__get_next_priority(F),jt=y;if(S[y].name===\"atom\"&&S[y+1]&&(S[y].space||S[y+1].name!==\"l_paren\")){var Z=S[y++],$t=w.__lookup_operator_classes(F,Z.value);if($t&&$t.indexOf(\"fy\")>-1){var bt=z(w,S,y,F,J);if(bt.type!==A)return Z.value===\"-\"&&!Z.space&&b.type.is_number(bt.value)?{value:new b.type.Num(-bt.value.value,bt.value.is_float),len:bt.len,type:p}:{value:new b.type.Term(Z.value,[bt.value]),len:bt.len,type:p};X=bt}else if($t&&$t.indexOf(\"fx\")>-1){var bt=z(w,S,y,dt,J);if(bt.type!==A)return{value:new b.type.Term(Z.value,[bt.value]),len:bt.len,type:p};X=bt}}y=jt;var bt=z(w,S,y,dt,J);if(bt.type===p){y=bt.len;var Z=S[y];if(S[y]&&(S[y].name===\"atom\"&&w.__lookup_operator_classes(F,Z.value)||S[y].name===\"bar\"&&w.__lookup_operator_classes(F,\"|\"))){var an=dt,Qr=F,$t=w.__lookup_operator_classes(F,Z.value);if($t.indexOf(\"xf\")>-1)return{value:new b.type.Term(Z.value,[bt.value]),len:++bt.len,type:p};if($t.indexOf(\"xfx\")>-1){var mr=z(w,S,y+1,an,J);return mr.type===p?{value:new b.type.Term(Z.value,[bt.value,mr.value]),len:mr.len,type:p}:(mr.derived=!0,mr)}else if($t.indexOf(\"xfy\")>-1){var mr=z(w,S,y+1,Qr,J);return mr.type===p?{value:new b.type.Term(Z.value,[bt.value,mr.value]),len:mr.len,type:p}:(mr.derived=!0,mr)}else if(bt.type!==A)for(;;){y=bt.len;var Z=S[y];if(Z&&Z.name===\"atom\"&&w.__lookup_operator_classes(F,Z.value)){var $t=w.__lookup_operator_classes(F,Z.value);if($t.indexOf(\"yf\")>-1)bt={value:new b.type.Term(Z.value,[bt.value]),len:++y,type:p};else if($t.indexOf(\"yfx\")>-1){var mr=z(w,S,++y,an,J);if(mr.type===A)return mr.derived=!0,mr;y=mr.len,bt={value:new b.type.Term(Z.value,[bt.value,mr.value]),len:y,type:p}}else break}else break}}else X={type:A,value:b.error.syntax(S[bt.len-1],\"operator expected\")};return bt}return bt}function te(w,S,y,F){if(!S[y]||S[y].name===\"atom\"&&S[y].raw===\".\"&&!F&&(S[y].space||!S[y+1]||S[y+1].name!==\"l_paren\"))return{type:A,derived:!1,value:b.error.syntax(S[y-1],\"unfounded token\")};var J=S[y],X=[];if(S[y].name===\"atom\"&&S[y].raw!==\",\"){if(y++,S[y-1].space)return{type:p,len:y,value:new b.type.Term(J.value,X)};if(S[y]&&S[y].name===\"l_paren\"){if(S[y+1]&&S[y+1].name===\"r_paren\")return{type:A,derived:!0,value:b.error.syntax(S[y+1],\"argument expected\")};var Z=z(w,S,++y,\"999\",!0);if(Z.type===A)return Z.derived?Z:{type:A,derived:!0,value:b.error.syntax(S[y]?S[y]:S[y-1],\"argument expected\",!S[y])};for(X.push(Z.value),y=Z.len;S[y]&&S[y].name===\"atom\"&&S[y].value===\",\";){if(Z=z(w,S,y+1,\"999\",!0),Z.type===A)return Z.derived?Z:{type:A,derived:!0,value:b.error.syntax(S[y+1]?S[y+1]:S[y],\"argument expected\",!S[y+1])};X.push(Z.value),y=Z.len}if(S[y]&&S[y].name===\"r_paren\")y++;else return{type:A,derived:!0,value:b.error.syntax(S[y]?S[y]:S[y-1],\", or ) expected\",!S[y])}}return{type:p,len:y,value:new b.type.Term(J.value,X)}}return{type:A,derived:!1,value:b.error.syntax(S[y],\"term expected\")}}function le(w,S,y){if(!S[y])return{type:A,derived:!1,value:b.error.syntax(S[y-1],\"[ expected\")};if(S[y]&&S[y].name===\"l_brace\"){var F=z(w,S,++y,\"999\",!0),J=[F.value],X=void 0;if(F.type===A)return S[y]&&S[y].name===\"r_brace\"?{type:p,len:y+1,value:new b.type.Term(\"[]\",[])}:{type:A,derived:!0,value:b.error.syntax(S[y],\"] expected\")};for(y=F.len;S[y]&&S[y].name===\"atom\"&&S[y].value===\",\";){if(F=z(w,S,y+1,\"999\",!0),F.type===A)return F.derived?F:{type:A,derived:!0,value:b.error.syntax(S[y+1]?S[y+1]:S[y],\"argument expected\",!S[y+1])};J.push(F.value),y=F.len}var Z=!1;if(S[y]&&S[y].name===\"bar\"){if(Z=!0,F=z(w,S,y+1,\"999\",!0),F.type===A)return F.derived?F:{type:A,derived:!0,value:b.error.syntax(S[y+1]?S[y+1]:S[y],\"argument expected\",!S[y+1])};X=F.value,y=F.len}return S[y]&&S[y].name===\"r_brace\"?{type:p,len:y+1,value:g(J,X)}:{type:A,derived:!0,value:b.error.syntax(S[y]?S[y]:S[y-1],Z?\"] expected\":\", or | or ] expected\",!S[y])}}return{type:A,derived:!1,value:b.error.syntax(S[y],\"list expected\")}}function he(w,S,y){var F=S[y].line,J=z(w,S,y,w.__get_max_priority(),!1),X=null,Z;if(J.type!==A)if(y=J.len,S[y]&&S[y].name===\"atom\"&&S[y].raw===\".\")if(y++,b.type.is_term(J.value)){if(J.value.indicator===\":-/2\"?(X=new b.type.Rule(J.value.args[0],Fe(J.value.args[1])),Z={value:X,len:y,type:p}):J.value.indicator===\"-->/2\"?(X=ae(new b.type.Rule(J.value.args[0],J.value.args[1]),w),X.body=Fe(X.body),Z={value:X,len:y,type:b.type.is_rule(X)?p:A}):(X=new b.type.Rule(J.value,null),Z={value:X,len:y,type:p}),X){var ie=X.singleton_variables();ie.length>0&&w.throw_warning(b.warning.singleton(ie,X.head.indicator,F))}return Z}else return{type:A,value:b.error.syntax(S[y],\"callable expected\")};else return{type:A,value:b.error.syntax(S[y]?S[y]:S[y-1],\". or operator expected\")};return J}function Ae(w,S,y){y=y||{},y.from=y.from?y.from:\"$tau-js\",y.reconsult=y.reconsult!==void 0?y.reconsult:!0;var F=new U(w),J={},X;F.new_text(S);var Z=0,ie=F.get_tokens(Z);do{if(ie===null||!ie[Z])break;var Pe=he(w,ie,Z);if(Pe.type===A)return new H(\"throw\",[Pe.value]);if(Pe.value.body===null&&Pe.value.head.indicator===\"?-/1\"){var Ne=new ze(w.session);Ne.add_goal(Pe.value.head.args[0]),Ne.answer(function(dt){b.type.is_error(dt)?w.throw_warning(dt.args[0]):(dt===!1||dt===null)&&w.throw_warning(b.warning.failed_goal(Pe.value.head.args[0],Pe.len))}),Z=Pe.len;var ot=!0}else if(Pe.value.body===null&&Pe.value.head.indicator===\":-/1\"){var ot=w.run_directive(Pe.value.head.args[0]);Z=Pe.len,Pe.value.head.args[0].indicator===\"char_conversion/2\"&&(ie=F.get_tokens(Z),Z=0)}else{X=Pe.value.head.indicator,y.reconsult!==!1&&J[X]!==!0&&!w.is_multifile_predicate(X)&&(w.session.rules[X]=a(w.session.rules[X]||[],function(jt){return jt.dynamic}),J[X]=!0);var ot=w.add_rule(Pe.value,y);Z=Pe.len}if(!ot)return ot}while(!0);return!0}function ye(w,S){var y=new U(w);y.new_text(S);var F=0;do{var J=y.get_tokens(F);if(J===null)break;var X=z(w,J,0,w.__get_max_priority(),!1);if(X.type!==A){var Z=X.len,ie=Z;if(J[Z]&&J[Z].name===\"atom\"&&J[Z].raw===\".\")w.add_goal(Fe(X.value));else{var Pe=J[Z];return new H(\"throw\",[b.error.syntax(Pe||J[Z-1],\". or operator expected\",!Pe)])}F=X.len+1}else return new H(\"throw\",[X.value])}while(!0);return!0}function ae(w,S){w=w.rename(S);var y=S.next_free_variable(),F=Ie(w.body,y,S);return F.error?F.value:(w.body=F.value,w.head.args=w.head.args.concat([y,F.variable]),w.head=new H(w.head.id,w.head.args),w)}function Ie(w,S,y){var F;if(b.type.is_term(w)&&w.indicator===\"!/0\")return{value:w,variable:S,error:!1};if(b.type.is_term(w)&&w.indicator===\",/2\"){var J=Ie(w.args[0],S,y);if(J.error)return J;var X=Ie(w.args[1],J.variable,y);return X.error?X:{value:new H(\",\",[J.value,X.value]),variable:X.variable,error:!1}}else{if(b.type.is_term(w)&&w.indicator===\"{}/1\")return{value:w.args[0],variable:S,error:!1};if(b.type.is_empty_list(w))return{value:new H(\"true\",[]),variable:S,error:!1};if(b.type.is_list(w)){F=y.next_free_variable();for(var Z=w,ie;Z.indicator===\"./2\";)ie=Z,Z=Z.args[1];return b.type.is_variable(Z)?{value:b.error.instantiation(\"DCG\"),variable:S,error:!0}:b.type.is_empty_list(Z)?(ie.args[1]=F,{value:new H(\"=\",[S,w]),variable:F,error:!1}):{value:b.error.type(\"list\",w,\"DCG\"),variable:S,error:!0}}else return b.type.is_callable(w)?(F=y.next_free_variable(),w.args=w.args.concat([S,F]),w=new H(w.id,w.args),{value:w,variable:F,error:!1}):{value:b.error.type(\"callable\",w,\"DCG\"),variable:S,error:!0}}}function Fe(w){return b.type.is_variable(w)?new H(\"call\",[w]):b.type.is_term(w)&&[\",/2\",\";/2\",\"->/2\"].indexOf(w.indicator)!==-1?new H(w.id,[Fe(w.args[0]),Fe(w.args[1])]):w}function g(w,S){for(var y=S||new b.type.Term(\"[]\",[]),F=w.length-1;F>=0;F--)y=new b.type.Term(\".\",[w[F],y]);return y}function Ee(w,S){for(var y=w.length-1;y>=0;y--)w[y]===S&&w.splice(y,1)}function De(w){for(var S={},y=[],F=0;F<w.length;F++)w[F]in S||(y.push(w[F]),S[w[F]]=!0);return y}function ce(w,S,y,F){if(w.session.rules[y]!==null){for(var J=0;J<w.session.rules[y].length;J++)if(w.session.rules[y][J]===F){w.session.rules[y].splice(J,1),w.success(S);break}}}function ne(w){return function(S,y,F){var J=F.args[0],X=F.args.slice(1,w);if(b.type.is_variable(J))S.throw_error(b.error.instantiation(S.level));else if(!b.type.is_callable(J))S.throw_error(b.error.type(\"callable\",J,S.level));else{var Z=new H(J.id,J.args.concat(X));S.prepend([new be(y.goal.replace(Z),y.substitution,y)])}}}function ee(w){for(var S=w.length-1;S>=0;S--)if(w.charAt(S)===\"/\")return new H(\"/\",[new H(w.substring(0,S)),new xe(parseInt(w.substring(S+1)),!1)])}function we(w){this.id=w}function xe(w,S){this.is_float=S!==void 0?S:parseInt(w)!==w,this.value=this.is_float?w:parseInt(w)}var ht=0;function H(w,S,y){this.ref=y||++ht,this.id=w,this.args=S||[],this.indicator=w+\"/\"+this.args.length}var lt=0;function Te(w,S,y,F,J,X){this.id=lt++,this.stream=w,this.mode=S,this.alias=y,this.type=F!==void 0?F:\"text\",this.reposition=J!==void 0?J:!0,this.eof_action=X!==void 0?X:\"eof_code\",this.position=this.mode===\"append\"?\"end_of_stream\":0,this.output=this.mode===\"write\"||this.mode===\"append\",this.input=this.mode===\"read\"}function ke(w){w=w||{},this.links=w}function be(w,S,y){S=S||new ke,y=y||null,this.goal=w,this.substitution=S,this.parent=y}function _e(w,S,y){this.head=w,this.body=S,this.dynamic=y||!1}function Re(w){w=w===void 0||w<=0?1e3:w,this.rules={},this.src_predicates={},this.rename=0,this.modules=[],this.thread=new ze(this),this.total_threads=1,this.renamed_variables={},this.public_predicates={},this.multifile_predicates={},this.limit=w,this.streams={user_input:new Te(typeof hl<\"u\"&&hl.exports?nodejs_user_input:tau_user_input,\"read\",\"user_input\",\"text\",!1,\"reset\"),user_output:new Te(typeof hl<\"u\"&&hl.exports?nodejs_user_output:tau_user_output,\"write\",\"user_output\",\"text\",!1,\"eof_code\")},this.file_system=typeof hl<\"u\"&&hl.exports?nodejs_file_system:tau_file_system,this.standard_input=this.streams.user_input,this.standard_output=this.streams.user_output,this.current_input=this.streams.user_input,this.current_output=this.streams.user_output,this.format_success=function(S){return S.substitution},this.format_error=function(S){return S.goal},this.flag={bounded:b.flag.bounded.value,max_integer:b.flag.max_integer.value,min_integer:b.flag.min_integer.value,integer_rounding_function:b.flag.integer_rounding_function.value,char_conversion:b.flag.char_conversion.value,debug:b.flag.debug.value,max_arity:b.flag.max_arity.value,unknown:b.flag.unknown.value,double_quotes:b.flag.double_quotes.value,occurs_check:b.flag.occurs_check.value,dialect:b.flag.dialect.value,version_data:b.flag.version_data.value,nodejs:b.flag.nodejs.value},this.__loaded_modules=[],this.__char_conversion={},this.__operators={1200:{\":-\":[\"fx\",\"xfx\"],\"-->\":[\"xfx\"],\"?-\":[\"fx\"]},1100:{\";\":[\"xfy\"]},1050:{\"->\":[\"xfy\"]},1e3:{\",\":[\"xfy\"]},900:{\"\\\\+\":[\"fy\"]},700:{\"=\":[\"xfx\"],\"\\\\=\":[\"xfx\"],\"==\":[\"xfx\"],\"\\\\==\":[\"xfx\"],\"@<\":[\"xfx\"],\"@=<\":[\"xfx\"],\"@>\":[\"xfx\"],\"@>=\":[\"xfx\"],\"=..\":[\"xfx\"],is:[\"xfx\"],\"=:=\":[\"xfx\"],\"=\\\\=\":[\"xfx\"],\"<\":[\"xfx\"],\"=<\":[\"xfx\"],\">\":[\"xfx\"],\">=\":[\"xfx\"]},600:{\":\":[\"xfy\"]},500:{\"+\":[\"yfx\"],\"-\":[\"yfx\"],\"/\\\\\":[\"yfx\"],\"\\\\/\":[\"yfx\"]},400:{\"*\":[\"yfx\"],\"/\":[\"yfx\"],\"//\":[\"yfx\"],rem:[\"yfx\"],mod:[\"yfx\"],\"<<\":[\"yfx\"],\">>\":[\"yfx\"]},200:{\"**\":[\"xfx\"],\"^\":[\"xfy\"],\"-\":[\"fy\"],\"+\":[\"fy\"],\"\\\\\":[\"fy\"]}}}function ze(w){this.epoch=Date.now(),this.session=w,this.session.total_threads++,this.total_steps=0,this.cpu_time=0,this.cpu_time_last=0,this.points=[],this.debugger=!1,this.debugger_states=[],this.level=\"top_level/0\",this.__calls=[],this.current_limit=this.session.limit,this.warnings=[]}function He(w,S,y){this.id=w,this.rules=S,this.exports=y,b.module[w]=this}He.prototype.exports_predicate=function(w){return this.exports.indexOf(w)!==-1},we.prototype.unify=function(w,S){if(S&&e(w.variables(),this.id)!==-1&&!b.type.is_variable(w))return null;var y={};return y[this.id]=w,new ke(y)},xe.prototype.unify=function(w,S){return b.type.is_number(w)&&this.value===w.value&&this.is_float===w.is_float?new ke:null},H.prototype.unify=function(w,S){if(b.type.is_term(w)&&this.indicator===w.indicator){for(var y=new ke,F=0;F<this.args.length;F++){var J=b.unify(this.args[F].apply(y),w.args[F].apply(y),S);if(J===null)return null;for(var X in J.links)y.links[X]=J.links[X];y=y.apply(J)}return y}return null},Te.prototype.unify=function(w,S){return b.type.is_stream(w)&&this.id===w.id?new ke:null},we.prototype.toString=function(w){return this.id},xe.prototype.toString=function(w){return this.is_float&&e(this.value.toString(),\".\")===-1?this.value+\".0\":this.value.toString()},H.prototype.toString=function(w,S,y){if(w=w||{},w.quoted=w.quoted===void 0?!0:w.quoted,w.ignore_ops=w.ignore_ops===void 0?!1:w.ignore_ops,w.numbervars=w.numbervars===void 0?!1:w.numbervars,S=S===void 0?1200:S,y=y===void 0?\"\":y,w.numbervars&&this.indicator===\"$VAR/1\"&&b.type.is_integer(this.args[0])&&this.args[0].value>=0){var F=this.args[0].value,J=Math.floor(F/26),X=F%26;return\"ABCDEFGHIJKLMNOPQRSTUVWXYZ\"[X]+(J!==0?J:\"\")}switch(this.indicator){case\"[]/0\":case\"{}/0\":case\"!/0\":return this.id;case\"{}/1\":return\"{\"+this.args[0].toString(w)+\"}\";case\"./2\":for(var Z=\"[\"+this.args[0].toString(w),ie=this.args[1];ie.indicator===\"./2\";)Z+=\", \"+ie.args[0].toString(w),ie=ie.args[1];return ie.indicator!==\"[]/0\"&&(Z+=\"|\"+ie.toString(w)),Z+=\"]\",Z;case\",/2\":return\"(\"+this.args[0].toString(w)+\", \"+this.args[1].toString(w)+\")\";default:var Pe=this.id,Ne=w.session?w.session.lookup_operator(this.id,this.args.length):null;if(w.session===void 0||w.ignore_ops||Ne===null)return w.quoted&&!/^(!|,|;|[a-z][0-9a-zA-Z_]*)$/.test(Pe)&&Pe!==\"{}\"&&Pe!==\"[]\"&&(Pe=\"'\"+x(Pe)+\"'\"),Pe+(this.args.length?\"(\"+o(this.args,function($t){return $t.toString(w)}).join(\", \")+\")\":\"\");var ot=Ne.priority>S.priority||Ne.priority===S.priority&&(Ne.class===\"xfy\"&&this.indicator!==S.indicator||Ne.class===\"yfx\"&&this.indicator!==S.indicator||this.indicator===S.indicator&&Ne.class===\"yfx\"&&y===\"right\"||this.indicator===S.indicator&&Ne.class===\"xfy\"&&y===\"left\");Ne.indicator=this.indicator;var dt=ot?\"(\":\"\",jt=ot?\")\":\"\";return this.args.length===0?\"(\"+this.id+\")\":[\"fy\",\"fx\"].indexOf(Ne.class)!==-1?dt+Pe+\" \"+this.args[0].toString(w,Ne)+jt:[\"yf\",\"xf\"].indexOf(Ne.class)!==-1?dt+this.args[0].toString(w,Ne)+\" \"+Pe+jt:dt+this.args[0].toString(w,Ne,\"left\")+\" \"+this.id+\" \"+this.args[1].toString(w,Ne,\"right\")+jt}},Te.prototype.toString=function(w){return\"<stream>(\"+this.id+\")\"},ke.prototype.toString=function(w){var S=\"{\";for(var y in this.links)!this.links.hasOwnProperty(y)||(S!==\"{\"&&(S+=\", \"),S+=y+\"/\"+this.links[y].toString(w));return S+=\"}\",S},be.prototype.toString=function(w){return this.goal===null?\"<\"+this.substitution.toString(w)+\">\":\"<\"+this.goal.toString(w)+\", \"+this.substitution.toString(w)+\">\"},_e.prototype.toString=function(w){return this.body?this.head.toString(w)+\" :- \"+this.body.toString(w)+\".\":this.head.toString(w)+\".\"},Re.prototype.toString=function(w){for(var S=\"\",y=0;y<this.modules.length;y++)S+=\":- use_module(library(\"+this.modules[y]+`)).\n`;S+=`\n`;for(key in this.rules)for(y=0;y<this.rules[key].length;y++)S+=this.rules[key][y].toString(w),S+=`\n`;return S},we.prototype.clone=function(){return new we(this.id)},xe.prototype.clone=function(){return new xe(this.value,this.is_float)},H.prototype.clone=function(){return new H(this.id,o(this.args,function(w){return w.clone()}))},Te.prototype.clone=function(){return new Stram(this.stream,this.mode,this.alias,this.type,this.reposition,this.eof_action)},ke.prototype.clone=function(){var w={};for(var S in this.links)!this.links.hasOwnProperty(S)||(w[S]=this.links[S].clone());return new ke(w)},be.prototype.clone=function(){return new be(this.goal.clone(),this.substitution.clone(),this.parent)},_e.prototype.clone=function(){return new _e(this.head.clone(),this.body!==null?this.body.clone():null)},we.prototype.equals=function(w){return b.type.is_variable(w)&&this.id===w.id},xe.prototype.equals=function(w){return b.type.is_number(w)&&this.value===w.value&&this.is_float===w.is_float},H.prototype.equals=function(w){if(!b.type.is_term(w)||this.indicator!==w.indicator)return!1;for(var S=0;S<this.args.length;S++)if(!this.args[S].equals(w.args[S]))return!1;return!0},Te.prototype.equals=function(w){return b.type.is_stream(w)&&this.id===w.id},ke.prototype.equals=function(w){var S;if(!b.type.is_substitution(w))return!1;for(S in this.links)if(!!this.links.hasOwnProperty(S)&&(!w.links[S]||!this.links[S].equals(w.links[S])))return!1;for(S in w.links)if(!!w.links.hasOwnProperty(S)&&!this.links[S])return!1;return!0},be.prototype.equals=function(w){return b.type.is_state(w)&&this.goal.equals(w.goal)&&this.substitution.equals(w.substitution)&&this.parent===w.parent},_e.prototype.equals=function(w){return b.type.is_rule(w)&&this.head.equals(w.head)&&(this.body===null&&w.body===null||this.body!==null&&this.body.equals(w.body))},we.prototype.rename=function(w){return w.get_free_variable(this)},xe.prototype.rename=function(w){return this},H.prototype.rename=function(w){return new H(this.id,o(this.args,function(S){return S.rename(w)}))},Te.prototype.rename=function(w){return this},_e.prototype.rename=function(w){return new _e(this.head.rename(w),this.body!==null?this.body.rename(w):null)},we.prototype.variables=function(){return[this.id]},xe.prototype.variables=function(){return[]},H.prototype.variables=function(){return[].concat.apply([],o(this.args,function(w){return w.variables()}))},Te.prototype.variables=function(){return[]},_e.prototype.variables=function(){return this.body===null?this.head.variables():this.head.variables().concat(this.body.variables())},we.prototype.apply=function(w){return w.lookup(this.id)?w.lookup(this.id):this},xe.prototype.apply=function(w){return this},H.prototype.apply=function(w){if(this.indicator===\"./2\"){for(var S=[],y=this;y.indicator===\"./2\";)S.push(y.args[0].apply(w)),y=y.args[1];for(var F=y.apply(w),J=S.length-1;J>=0;J--)F=new H(\".\",[S[J],F]);return F}return new H(this.id,o(this.args,function(X){return X.apply(w)}),this.ref)},Te.prototype.apply=function(w){return this},_e.prototype.apply=function(w){return new _e(this.head.apply(w),this.body!==null?this.body.apply(w):null)},ke.prototype.apply=function(w){var S,y={};for(S in this.links)!this.links.hasOwnProperty(S)||(y[S]=this.links[S].apply(w));return new ke(y)},H.prototype.select=function(){for(var w=this;w.indicator===\",/2\";)w=w.args[0];return w},H.prototype.replace=function(w){return this.indicator===\",/2\"?this.args[0].indicator===\",/2\"?new H(\",\",[this.args[0].replace(w),this.args[1]]):w===null?this.args[1]:new H(\",\",[w,this.args[1]]):w},H.prototype.search=function(w){if(b.type.is_term(w)&&w.ref!==void 0&&this.ref===w.ref)return!0;for(var S=0;S<this.args.length;S++)if(b.type.is_term(this.args[S])&&this.args[S].search(w))return!0;return!1},Re.prototype.get_current_input=function(){return this.current_input},ze.prototype.get_current_input=function(){return this.session.get_current_input()},Re.prototype.get_current_output=function(){return this.current_output},ze.prototype.get_current_output=function(){return this.session.get_current_output()},Re.prototype.set_current_input=function(w){this.current_input=w},ze.prototype.set_current_input=function(w){return this.session.set_current_input(w)},Re.prototype.set_current_output=function(w){this.current_input=w},ze.prototype.set_current_output=function(w){return this.session.set_current_output(w)},Re.prototype.get_stream_by_alias=function(w){return this.streams[w]},ze.prototype.get_stream_by_alias=function(w){return this.session.get_stream_by_alias(w)},Re.prototype.file_system_open=function(w,S,y){return this.file_system.open(w,S,y)},ze.prototype.file_system_open=function(w,S,y){return this.session.file_system_open(w,S,y)},Re.prototype.get_char_conversion=function(w){return this.__char_conversion[w]||w},ze.prototype.get_char_conversion=function(w){return this.session.get_char_conversion(w)},Re.prototype.parse=function(w){return this.thread.parse(w)},ze.prototype.parse=function(w){var S=new U(this);S.new_text(w);var y=S.get_tokens();if(y===null)return!1;var F=z(this,y,0,this.__get_max_priority(),!1);return F.len!==y.length?!1:{value:F.value,expr:F,tokens:y}},Re.prototype.get_flag=function(w){return this.flag[w]},ze.prototype.get_flag=function(w){return this.session.get_flag(w)},Re.prototype.add_rule=function(w,S){return S=S||{},S.from=S.from?S.from:\"$tau-js\",this.src_predicates[w.head.indicator]=S.from,this.rules[w.head.indicator]||(this.rules[w.head.indicator]=[]),this.rules[w.head.indicator].push(w),this.public_predicates.hasOwnProperty(w.head.indicator)||(this.public_predicates[w.head.indicator]=!1),!0},ze.prototype.add_rule=function(w,S){return this.session.add_rule(w,S)},Re.prototype.run_directive=function(w){this.thread.run_directive(w)},ze.prototype.run_directive=function(w){return b.type.is_directive(w)?(b.directive[w.indicator](this,w),!0):!1},Re.prototype.__get_max_priority=function(){return\"1200\"},ze.prototype.__get_max_priority=function(){return this.session.__get_max_priority()},Re.prototype.__get_next_priority=function(w){var S=0;w=parseInt(w);for(var y in this.__operators)if(!!this.__operators.hasOwnProperty(y)){var F=parseInt(y);F>S&&F<w&&(S=F)}return S.toString()},ze.prototype.__get_next_priority=function(w){return this.session.__get_next_priority(w)},Re.prototype.__lookup_operator_classes=function(w,S){return this.__operators.hasOwnProperty(w)&&this.__operators[w][S]instanceof Array&&this.__operators[w][S]||!1},ze.prototype.__lookup_operator_classes=function(w,S){return this.session.__lookup_operator_classes(w,S)},Re.prototype.lookup_operator=function(w,S){for(var y in this.__operators)if(this.__operators[y][w]){for(var F=0;F<this.__operators[y][w].length;F++)if(S===0||this.__operators[y][w][F].length===S+1)return{priority:y,class:this.__operators[y][w][F]}}return null},ze.prototype.lookup_operator=function(w,S){return this.session.lookup_operator(w,S)},Re.prototype.throw_warning=function(w){this.thread.throw_warning(w)},ze.prototype.throw_warning=function(w){this.warnings.push(w)},Re.prototype.get_warnings=function(){return this.thread.get_warnings()},ze.prototype.get_warnings=function(){return this.warnings},Re.prototype.add_goal=function(w,S){this.thread.add_goal(w,S)},ze.prototype.add_goal=function(w,S,y){y=y||null,S===!0&&(this.points=[]);for(var F=w.variables(),J={},X=0;X<F.length;X++)J[F[X]]=new we(F[X]);this.points.push(new be(w,new ke(J),y))},Re.prototype.consult=function(w,S){return this.thread.consult(w,S)},ze.prototype.consult=function(w,S){var y=\"\";if(typeof w==\"string\"){y=w;var F=y.length;if(y.substring(F-3,F)===\".pl\"&&document.getElementById(y)){var J=document.getElementById(y),X=J.getAttribute(\"type\");X!==null&&X.replace(/ /g,\"\").toLowerCase()===\"text/prolog\"&&(y=J.text)}}else if(w.nodeName)switch(w.nodeName.toLowerCase()){case\"input\":case\"textarea\":y=w.value;break;default:y=w.innerHTML;break}else return!1;return this.warnings=[],Ae(this,y,S)},Re.prototype.query=function(w){return this.thread.query(w)},ze.prototype.query=function(w){return this.points=[],this.debugger_points=[],ye(this,w)},Re.prototype.head_point=function(){return this.thread.head_point()},ze.prototype.head_point=function(){return this.points[this.points.length-1]},Re.prototype.get_free_variable=function(w){return this.thread.get_free_variable(w)},ze.prototype.get_free_variable=function(w){var S=[];if(w.id===\"_\"||this.session.renamed_variables[w.id]===void 0){for(this.session.rename++,this.points.length>0&&(S=this.head_point().substitution.domain());e(S,b.format_variable(this.session.rename))!==-1;)this.session.rename++;if(w.id===\"_\")return new we(b.format_variable(this.session.rename));this.session.renamed_variables[w.id]=b.format_variable(this.session.rename)}return new we(this.session.renamed_variables[w.id])},Re.prototype.next_free_variable=function(){return this.thread.next_free_variable()},ze.prototype.next_free_variable=function(){this.session.rename++;var w=[];for(this.points.length>0&&(w=this.head_point().substitution.domain());e(w,b.format_variable(this.session.rename))!==-1;)this.session.rename++;return new we(b.format_variable(this.session.rename))},Re.prototype.is_public_predicate=function(w){return!this.public_predicates.hasOwnProperty(w)||this.public_predicates[w]===!0},ze.prototype.is_public_predicate=function(w){return this.session.is_public_predicate(w)},Re.prototype.is_multifile_predicate=function(w){return this.multifile_predicates.hasOwnProperty(w)&&this.multifile_predicates[w]===!0},ze.prototype.is_multifile_predicate=function(w){return this.session.is_multifile_predicate(w)},Re.prototype.prepend=function(w){return this.thread.prepend(w)},ze.prototype.prepend=function(w){for(var S=w.length-1;S>=0;S--)this.points.push(w[S])},Re.prototype.success=function(w,S){return this.thread.success(w,S)},ze.prototype.success=function(w,y){var y=typeof y>\"u\"?w:y;this.prepend([new be(w.goal.replace(null),w.substitution,y)])},Re.prototype.throw_error=function(w){return this.thread.throw_error(w)},ze.prototype.throw_error=function(w){this.prepend([new be(new H(\"throw\",[w]),new ke,null,null)])},Re.prototype.step_rule=function(w,S){return this.thread.step_rule(w,S)},ze.prototype.step_rule=function(w,S){var y=S.indicator;if(w===\"user\"&&(w=null),w===null&&this.session.rules.hasOwnProperty(y))return this.session.rules[y];for(var F=w===null?this.session.modules:e(this.session.modules,w)===-1?[]:[w],J=0;J<F.length;J++){var X=b.module[F[J]];if(X.rules.hasOwnProperty(y)&&(X.rules.hasOwnProperty(this.level)||X.exports_predicate(y)))return b.module[F[J]].rules[y]}return null},Re.prototype.step=function(){return this.thread.step()},ze.prototype.step=function(){if(this.points.length!==0){var w=!1,S=this.points.pop();if(this.debugger&&this.debugger_states.push(S),b.type.is_term(S.goal)){var y=S.goal.select(),F=null,J=[];if(y!==null){this.total_steps++;for(var X=S;X.parent!==null&&X.parent.goal.search(y);)X=X.parent;if(this.level=X.parent===null?\"top_level/0\":X.parent.goal.select().indicator,b.type.is_term(y)&&y.indicator===\":/2\"&&(F=y.args[0].id,y=y.args[1]),F===null&&b.type.is_builtin(y))this.__call_indicator=y.indicator,w=b.predicate[y.indicator](this,S,y);else{var Z=this.step_rule(F,y);if(Z===null)this.session.rules.hasOwnProperty(y.indicator)||(this.get_flag(\"unknown\").id===\"error\"?this.throw_error(b.error.existence(\"procedure\",y.indicator,this.level)):this.get_flag(\"unknown\").id===\"warning\"&&this.throw_warning(\"unknown procedure \"+y.indicator+\" (from \"+this.level+\")\"));else if(Z instanceof Function)w=Z(this,S,y);else{for(var ie in Z)if(!!Z.hasOwnProperty(ie)){var Pe=Z[ie];this.session.renamed_variables={},Pe=Pe.rename(this);var Ne=this.get_flag(\"occurs_check\").indicator===\"true/0\",ot=new be,dt=b.unify(y,Pe.head,Ne);dt!==null&&(ot.goal=S.goal.replace(Pe.body),ot.goal!==null&&(ot.goal=ot.goal.apply(dt)),ot.substitution=S.substitution.apply(dt),ot.parent=S,J.push(ot))}this.prepend(J)}}}}else b.type.is_variable(S.goal)?this.throw_error(b.error.instantiation(this.level)):this.throw_error(b.error.type(\"callable\",S.goal,this.level));return w}},Re.prototype.answer=function(w){return this.thread.answer(w)},ze.prototype.answer=function(w){w=w||function(S){},this.__calls.push(w),!(this.__calls.length>1)&&this.again()},Re.prototype.answers=function(w,S,y){return this.thread.answers(w,S,y)},ze.prototype.answers=function(w,S,y){var F=S||1e3,J=this;if(S<=0){y&&y();return}this.answer(function(X){w(X),X!==!1?setTimeout(function(){J.answers(w,S-1,y)},1):y&&y()})},Re.prototype.again=function(w){return this.thread.again(w)},ze.prototype.again=function(w){for(var S,y=Date.now();this.__calls.length>0;){for(this.warnings=[],w!==!1&&(this.current_limit=this.session.limit);this.current_limit>0&&this.points.length>0&&this.head_point().goal!==null&&!b.type.is_error(this.head_point().goal);)if(this.current_limit--,this.step()===!0)return;var F=Date.now();this.cpu_time_last=F-y,this.cpu_time+=this.cpu_time_last;var J=this.__calls.shift();this.current_limit<=0?J(null):this.points.length===0?J(!1):b.type.is_error(this.head_point().goal)?(S=this.session.format_error(this.points.pop()),this.points=[],J(S)):(this.debugger&&this.debugger_states.push(this.head_point()),S=this.session.format_success(this.points.pop()),J(S))}},Re.prototype.unfold=function(w){if(w.body===null)return!1;var S=w.head,y=w.body,F=y.select(),J=new ze(this),X=[];J.add_goal(F),J.step();for(var Z=J.points.length-1;Z>=0;Z--){var ie=J.points[Z],Pe=S.apply(ie.substitution),Ne=y.replace(ie.goal);Ne!==null&&(Ne=Ne.apply(ie.substitution)),X.push(new _e(Pe,Ne))}var ot=this.rules[S.indicator],dt=e(ot,w);return X.length>0&&dt!==-1?(ot.splice.apply(ot,[dt,1].concat(X)),!0):!1},ze.prototype.unfold=function(w){return this.session.unfold(w)},we.prototype.interpret=function(w){return b.error.instantiation(w.level)},xe.prototype.interpret=function(w){return this},H.prototype.interpret=function(w){return b.type.is_unitary_list(this)?this.args[0].interpret(w):b.operate(w,this)},we.prototype.compare=function(w){return this.id<w.id?-1:this.id>w.id?1:0},xe.prototype.compare=function(w){if(this.value===w.value&&this.is_float===w.is_float)return 0;if(this.value<w.value||this.value===w.value&&this.is_float&&!w.is_float)return-1;if(this.value>w.value)return 1},H.prototype.compare=function(w){if(this.args.length<w.args.length||this.args.length===w.args.length&&this.id<w.id)return-1;if(this.args.length>w.args.length||this.args.length===w.args.length&&this.id>w.id)return 1;for(var S=0;S<this.args.length;S++){var y=b.compare(this.args[S],w.args[S]);if(y!==0)return y}return 0},ke.prototype.lookup=function(w){return this.links[w]?this.links[w]:null},ke.prototype.filter=function(w){var S={};for(var y in this.links)if(!!this.links.hasOwnProperty(y)){var F=this.links[y];w(y,F)&&(S[y]=F)}return new ke(S)},ke.prototype.exclude=function(w){var S={};for(var y in this.links)!this.links.hasOwnProperty(y)||e(w,y)===-1&&(S[y]=this.links[y]);return new ke(S)},ke.prototype.add=function(w,S){this.links[w]=S},ke.prototype.domain=function(w){var S=w===!0?function(J){return J}:function(J){return new we(J)},y=[];for(var F in this.links)y.push(S(F));return y},we.prototype.compile=function(){return'new pl.type.Var(\"'+this.id.toString()+'\")'},xe.prototype.compile=function(){return\"new pl.type.Num(\"+this.value.toString()+\", \"+this.is_float.toString()+\")\"},H.prototype.compile=function(){return'new pl.type.Term(\"'+this.id.replace(/\"/g,'\\\\\"')+'\", ['+o(this.args,function(w){return w.compile()})+\"])\"},_e.prototype.compile=function(){return\"new pl.type.Rule(\"+this.head.compile()+\", \"+(this.body===null?\"null\":this.body.compile())+\")\"},Re.prototype.compile=function(){var w,S=[],y;for(var F in this.rules)if(!!this.rules.hasOwnProperty(F)){var J=this.rules[F];y=[],w='\"'+F+'\": [';for(var X=0;X<J.length;X++)y.push(J[X].compile());w+=y.join(),w+=\"]\",S.push(w)}return\"{\"+S.join()+\"};\"},we.prototype.toJavaScript=function(){},xe.prototype.toJavaScript=function(){return this.value},H.prototype.toJavaScript=function(){if(this.args.length===0&&this.indicator!==\"[]/0\")return this.id;if(b.type.is_list(this)){for(var w=[],S=this,y;S.indicator===\"./2\";){if(y=S.args[0].toJavaScript(),y===void 0)return;w.push(y),S=S.args[1]}if(S.indicator===\"[]/0\")return w}},_e.prototype.singleton_variables=function(){var w=this.head.variables(),S={},y=[];this.body!==null&&(w=w.concat(this.body.variables()));for(var F=0;F<w.length;F++)S[w[F]]===void 0&&(S[w[F]]=0),S[w[F]]++;for(var J in S)J!==\"_\"&&S[J]===1&&y.push(J);return y};var b={__env:typeof hl<\"u\"&&hl.exports?global:window,module:{},version:t,parser:{tokenizer:U,expression:z},utils:{str_indicator:ee,codePointAt:n,fromCodePoint:u},statistics:{getCountTerms:function(){return ht}},fromJavaScript:{test:{boolean:function(w){return w===!0||w===!1},number:function(w){return typeof w==\"number\"},string:function(w){return typeof w==\"string\"},list:function(w){return w instanceof Array},variable:function(w){return w===void 0},any:function(w){return!0}},conversion:{boolean:function(w){return new H(w?\"true\":\"false\",[])},number:function(w){return new xe(w,w%1!==0)},string:function(w){return new H(w,[])},list:function(w){for(var S=[],y,F=0;F<w.length;F++){if(y=b.fromJavaScript.apply(w[F]),y===void 0)return;S.push(y)}return g(S)},variable:function(w){return new we(\"_\")},any:function(w){}},apply:function(w){for(var S in b.fromJavaScript.test)if(S!==\"any\"&&b.fromJavaScript.test[S](w))return b.fromJavaScript.conversion[S](w);return b.fromJavaScript.conversion.any(w)}},type:{Var:we,Num:xe,Term:H,Rule:_e,State:be,Stream:Te,Module:He,Thread:ze,Session:Re,Substitution:ke,order:[we,xe,H,Te],compare:function(w,S){var y=e(b.type.order,w.constructor),F=e(b.type.order,S.constructor);if(y<F)return-1;if(y>F)return 1;if(w.constructor===xe){if(w.is_float&&S.is_float)return 0;if(w.is_float)return-1;if(S.is_float)return 1}return 0},is_substitution:function(w){return w instanceof ke},is_state:function(w){return w instanceof be},is_rule:function(w){return w instanceof _e},is_variable:function(w){return w instanceof we},is_stream:function(w){return w instanceof Te},is_anonymous_var:function(w){return w instanceof we&&w.id===\"_\"},is_callable:function(w){return w instanceof H},is_number:function(w){return w instanceof xe},is_integer:function(w){return w instanceof xe&&!w.is_float},is_float:function(w){return w instanceof xe&&w.is_float},is_term:function(w){return w instanceof H},is_atom:function(w){return w instanceof H&&w.args.length===0},is_ground:function(w){if(w instanceof we)return!1;if(w instanceof H){for(var S=0;S<w.args.length;S++)if(!b.type.is_ground(w.args[S]))return!1}return!0},is_atomic:function(w){return w instanceof H&&w.args.length===0||w instanceof xe},is_compound:function(w){return w instanceof H&&w.args.length>0},is_list:function(w){return w instanceof H&&(w.indicator===\"[]/0\"||w.indicator===\"./2\")},is_empty_list:function(w){return w instanceof H&&w.indicator===\"[]/0\"},is_non_empty_list:function(w){return w instanceof H&&w.indicator===\"./2\"},is_fully_list:function(w){for(;w instanceof H&&w.indicator===\"./2\";)w=w.args[1];return w instanceof we||w instanceof H&&w.indicator===\"[]/0\"},is_instantiated_list:function(w){for(;w instanceof H&&w.indicator===\"./2\";)w=w.args[1];return w instanceof H&&w.indicator===\"[]/0\"},is_unitary_list:function(w){return w instanceof H&&w.indicator===\"./2\"&&w.args[1]instanceof H&&w.args[1].indicator===\"[]/0\"},is_character:function(w){return w instanceof H&&(w.id.length===1||w.id.length>0&&w.id.length<=2&&n(w.id,0)>=65536)},is_character_code:function(w){return w instanceof xe&&!w.is_float&&w.value>=0&&w.value<=1114111},is_byte:function(w){return w instanceof xe&&!w.is_float&&w.value>=0&&w.value<=255},is_operator:function(w){return w instanceof H&&b.arithmetic.evaluation[w.indicator]},is_directive:function(w){return w instanceof H&&b.directive[w.indicator]!==void 0},is_builtin:function(w){return w instanceof H&&b.predicate[w.indicator]!==void 0},is_error:function(w){return w instanceof H&&w.indicator===\"throw/1\"},is_predicate_indicator:function(w){return w instanceof H&&w.indicator===\"//2\"&&w.args[0]instanceof H&&w.args[0].args.length===0&&w.args[1]instanceof xe&&w.args[1].is_float===!1},is_flag:function(w){return w instanceof H&&w.args.length===0&&b.flag[w.id]!==void 0},is_value_flag:function(w,S){if(!b.type.is_flag(w))return!1;for(var y in b.flag[w.id].allowed)if(!!b.flag[w.id].allowed.hasOwnProperty(y)&&b.flag[w.id].allowed[y].equals(S))return!0;return!1},is_io_mode:function(w){return b.type.is_atom(w)&&[\"read\",\"write\",\"append\"].indexOf(w.id)!==-1},is_stream_option:function(w){return b.type.is_term(w)&&(w.indicator===\"alias/1\"&&b.type.is_atom(w.args[0])||w.indicator===\"reposition/1\"&&b.type.is_atom(w.args[0])&&(w.args[0].id===\"true\"||w.args[0].id===\"false\")||w.indicator===\"type/1\"&&b.type.is_atom(w.args[0])&&(w.args[0].id===\"text\"||w.args[0].id===\"binary\")||w.indicator===\"eof_action/1\"&&b.type.is_atom(w.args[0])&&(w.args[0].id===\"error\"||w.args[0].id===\"eof_code\"||w.args[0].id===\"reset\"))},is_stream_position:function(w){return b.type.is_integer(w)&&w.value>=0||b.type.is_atom(w)&&(w.id===\"end_of_stream\"||w.id===\"past_end_of_stream\")},is_stream_property:function(w){return b.type.is_term(w)&&(w.indicator===\"input/0\"||w.indicator===\"output/0\"||w.indicator===\"alias/1\"&&(b.type.is_variable(w.args[0])||b.type.is_atom(w.args[0]))||w.indicator===\"file_name/1\"&&(b.type.is_variable(w.args[0])||b.type.is_atom(w.args[0]))||w.indicator===\"position/1\"&&(b.type.is_variable(w.args[0])||b.type.is_stream_position(w.args[0]))||w.indicator===\"reposition/1\"&&(b.type.is_variable(w.args[0])||b.type.is_atom(w.args[0])&&(w.args[0].id===\"true\"||w.args[0].id===\"false\"))||w.indicator===\"type/1\"&&(b.type.is_variable(w.args[0])||b.type.is_atom(w.args[0])&&(w.args[0].id===\"text\"||w.args[0].id===\"binary\"))||w.indicator===\"mode/1\"&&(b.type.is_variable(w.args[0])||b.type.is_atom(w.args[0])&&(w.args[0].id===\"read\"||w.args[0].id===\"write\"||w.args[0].id===\"append\"))||w.indicator===\"eof_action/1\"&&(b.type.is_variable(w.args[0])||b.type.is_atom(w.args[0])&&(w.args[0].id===\"error\"||w.args[0].id===\"eof_code\"||w.args[0].id===\"reset\"))||w.indicator===\"end_of_stream/1\"&&(b.type.is_variable(w.args[0])||b.type.is_atom(w.args[0])&&(w.args[0].id===\"at\"||w.args[0].id===\"past\"||w.args[0].id===\"not\")))},is_streamable:function(w){return w.__proto__.stream!==void 0},is_read_option:function(w){return b.type.is_term(w)&&[\"variables/1\",\"variable_names/1\",\"singletons/1\"].indexOf(w.indicator)!==-1},is_write_option:function(w){return b.type.is_term(w)&&(w.indicator===\"quoted/1\"&&b.type.is_atom(w.args[0])&&(w.args[0].id===\"true\"||w.args[0].id===\"false\")||w.indicator===\"ignore_ops/1\"&&b.type.is_atom(w.args[0])&&(w.args[0].id===\"true\"||w.args[0].id===\"false\")||w.indicator===\"numbervars/1\"&&b.type.is_atom(w.args[0])&&(w.args[0].id===\"true\"||w.args[0].id===\"false\"))},is_close_option:function(w){return b.type.is_term(w)&&w.indicator===\"force/1\"&&b.type.is_atom(w.args[0])&&(w.args[0].id===\"true\"||w.args[0].id===\"false\")},is_modifiable_flag:function(w){return b.type.is_flag(w)&&b.flag[w.id].changeable},is_module:function(w){return w instanceof H&&w.indicator===\"library/1\"&&w.args[0]instanceof H&&w.args[0].args.length===0&&b.module[w.args[0].id]!==void 0}},arithmetic:{evaluation:{\"e/0\":{type_args:null,type_result:!0,fn:function(w){return Math.E}},\"pi/0\":{type_args:null,type_result:!0,fn:function(w){return Math.PI}},\"tau/0\":{type_args:null,type_result:!0,fn:function(w){return 2*Math.PI}},\"epsilon/0\":{type_args:null,type_result:!0,fn:function(w){return Number.EPSILON}},\"+/1\":{type_args:null,type_result:null,fn:function(w,S){return w}},\"-/1\":{type_args:null,type_result:null,fn:function(w,S){return-w}},\"\\\\/1\":{type_args:!1,type_result:!1,fn:function(w,S){return~w}},\"abs/1\":{type_args:null,type_result:null,fn:function(w,S){return Math.abs(w)}},\"sign/1\":{type_args:null,type_result:null,fn:function(w,S){return Math.sign(w)}},\"float_integer_part/1\":{type_args:!0,type_result:!1,fn:function(w,S){return parseInt(w)}},\"float_fractional_part/1\":{type_args:!0,type_result:!0,fn:function(w,S){return w-parseInt(w)}},\"float/1\":{type_args:null,type_result:!0,fn:function(w,S){return parseFloat(w)}},\"floor/1\":{type_args:!0,type_result:!1,fn:function(w,S){return Math.floor(w)}},\"truncate/1\":{type_args:!0,type_result:!1,fn:function(w,S){return parseInt(w)}},\"round/1\":{type_args:!0,type_result:!1,fn:function(w,S){return Math.round(w)}},\"ceiling/1\":{type_args:!0,type_result:!1,fn:function(w,S){return Math.ceil(w)}},\"sin/1\":{type_args:null,type_result:!0,fn:function(w,S){return Math.sin(w)}},\"cos/1\":{type_args:null,type_result:!0,fn:function(w,S){return Math.cos(w)}},\"tan/1\":{type_args:null,type_result:!0,fn:function(w,S){return Math.tan(w)}},\"asin/1\":{type_args:null,type_result:!0,fn:function(w,S){return Math.asin(w)}},\"acos/1\":{type_args:null,type_result:!0,fn:function(w,S){return Math.acos(w)}},\"atan/1\":{type_args:null,type_result:!0,fn:function(w,S){return Math.atan(w)}},\"atan2/2\":{type_args:null,type_result:!0,fn:function(w,S,y){return Math.atan2(w,S)}},\"exp/1\":{type_args:null,type_result:!0,fn:function(w,S){return Math.exp(w)}},\"sqrt/1\":{type_args:null,type_result:!0,fn:function(w,S){return Math.sqrt(w)}},\"log/1\":{type_args:null,type_result:!0,fn:function(w,S){return w>0?Math.log(w):b.error.evaluation(\"undefined\",S.__call_indicator)}},\"+/2\":{type_args:null,type_result:null,fn:function(w,S,y){return w+S}},\"-/2\":{type_args:null,type_result:null,fn:function(w,S,y){return w-S}},\"*/2\":{type_args:null,type_result:null,fn:function(w,S,y){return w*S}},\"//2\":{type_args:null,type_result:!0,fn:function(w,S,y){return S?w/S:b.error.evaluation(\"zero_division\",y.__call_indicator)}},\"///2\":{type_args:!1,type_result:!1,fn:function(w,S,y){return S?parseInt(w/S):b.error.evaluation(\"zero_division\",y.__call_indicator)}},\"**/2\":{type_args:null,type_result:!0,fn:function(w,S,y){return Math.pow(w,S)}},\"^/2\":{type_args:null,type_result:null,fn:function(w,S,y){return Math.pow(w,S)}},\"<</2\":{type_args:!1,type_result:!1,fn:function(w,S,y){return w<<S}},\">>/2\":{type_args:!1,type_result:!1,fn:function(w,S,y){return w>>S}},\"/\\\\/2\":{type_args:!1,type_result:!1,fn:function(w,S,y){return w&S}},\"\\\\//2\":{type_args:!1,type_result:!1,fn:function(w,S,y){return w|S}},\"xor/2\":{type_args:!1,type_result:!1,fn:function(w,S,y){return w^S}},\"rem/2\":{type_args:!1,type_result:!1,fn:function(w,S,y){return S?w%S:b.error.evaluation(\"zero_division\",y.__call_indicator)}},\"mod/2\":{type_args:!1,type_result:!1,fn:function(w,S,y){return S?w-parseInt(w/S)*S:b.error.evaluation(\"zero_division\",y.__call_indicator)}},\"max/2\":{type_args:null,type_result:null,fn:function(w,S,y){return Math.max(w,S)}},\"min/2\":{type_args:null,type_result:null,fn:function(w,S,y){return Math.min(w,S)}}}},directive:{\"dynamic/1\":function(w,S){var y=S.args[0];if(b.type.is_variable(y))w.throw_error(b.error.instantiation(S.indicator));else if(!b.type.is_compound(y)||y.indicator!==\"//2\")w.throw_error(b.error.type(\"predicate_indicator\",y,S.indicator));else if(b.type.is_variable(y.args[0])||b.type.is_variable(y.args[1]))w.throw_error(b.error.instantiation(S.indicator));else if(!b.type.is_atom(y.args[0]))w.throw_error(b.error.type(\"atom\",y.args[0],S.indicator));else if(!b.type.is_integer(y.args[1]))w.throw_error(b.error.type(\"integer\",y.args[1],S.indicator));else{var F=S.args[0].args[0].id+\"/\"+S.args[0].args[1].value;w.session.public_predicates[F]=!0,w.session.rules[F]||(w.session.rules[F]=[])}},\"multifile/1\":function(w,S){var y=S.args[0];b.type.is_variable(y)?w.throw_error(b.error.instantiation(S.indicator)):!b.type.is_compound(y)||y.indicator!==\"//2\"?w.throw_error(b.error.type(\"predicate_indicator\",y,S.indicator)):b.type.is_variable(y.args[0])||b.type.is_variable(y.args[1])?w.throw_error(b.error.instantiation(S.indicator)):b.type.is_atom(y.args[0])?b.type.is_integer(y.args[1])?w.session.multifile_predicates[S.args[0].args[0].id+\"/\"+S.args[0].args[1].value]=!0:w.throw_error(b.error.type(\"integer\",y.args[1],S.indicator)):w.throw_error(b.error.type(\"atom\",y.args[0],S.indicator))},\"set_prolog_flag/2\":function(w,S){var y=S.args[0],F=S.args[1];b.type.is_variable(y)||b.type.is_variable(F)?w.throw_error(b.error.instantiation(S.indicator)):b.type.is_atom(y)?b.type.is_flag(y)?b.type.is_value_flag(y,F)?b.type.is_modifiable_flag(y)?w.session.flag[y.id]=F:w.throw_error(b.error.permission(\"modify\",\"flag\",y)):w.throw_error(b.error.domain(\"flag_value\",new H(\"+\",[y,F]),S.indicator)):w.throw_error(b.error.domain(\"prolog_flag\",y,S.indicator)):w.throw_error(b.error.type(\"atom\",y,S.indicator))},\"use_module/1\":function(w,S){var y=S.args[0];if(b.type.is_variable(y))w.throw_error(b.error.instantiation(S.indicator));else if(!b.type.is_term(y))w.throw_error(b.error.type(\"term\",y,S.indicator));else if(b.type.is_module(y)){var F=y.args[0].id;e(w.session.modules,F)===-1&&w.session.modules.push(F)}},\"char_conversion/2\":function(w,S){var y=S.args[0],F=S.args[1];b.type.is_variable(y)||b.type.is_variable(F)?w.throw_error(b.error.instantiation(S.indicator)):b.type.is_character(y)?b.type.is_character(F)?y.id===F.id?delete w.session.__char_conversion[y.id]:w.session.__char_conversion[y.id]=F.id:w.throw_error(b.error.type(\"character\",F,S.indicator)):w.throw_error(b.error.type(\"character\",y,S.indicator))},\"op/3\":function(w,S){var y=S.args[0],F=S.args[1],J=S.args[2];if(b.type.is_variable(y)||b.type.is_variable(F)||b.type.is_variable(J))w.throw_error(b.error.instantiation(S.indicator));else if(!b.type.is_integer(y))w.throw_error(b.error.type(\"integer\",y,S.indicator));else if(!b.type.is_atom(F))w.throw_error(b.error.type(\"atom\",F,S.indicator));else if(!b.type.is_atom(J))w.throw_error(b.error.type(\"atom\",J,S.indicator));else if(y.value<0||y.value>1200)w.throw_error(b.error.domain(\"operator_priority\",y,S.indicator));else if(J.id===\",\")w.throw_error(b.error.permission(\"modify\",\"operator\",J,S.indicator));else if(J.id===\"|\"&&(y.value<1001||F.id.length!==3))w.throw_error(b.error.permission(\"modify\",\"operator\",J,S.indicator));else if([\"fy\",\"fx\",\"yf\",\"xf\",\"xfx\",\"yfx\",\"xfy\"].indexOf(F.id)===-1)w.throw_error(b.error.domain(\"operator_specifier\",F,S.indicator));else{var X={prefix:null,infix:null,postfix:null};for(var Z in w.session.__operators)if(!!w.session.__operators.hasOwnProperty(Z)){var ie=w.session.__operators[Z][J.id];ie&&(e(ie,\"fx\")!==-1&&(X.prefix={priority:Z,type:\"fx\"}),e(ie,\"fy\")!==-1&&(X.prefix={priority:Z,type:\"fy\"}),e(ie,\"xf\")!==-1&&(X.postfix={priority:Z,type:\"xf\"}),e(ie,\"yf\")!==-1&&(X.postfix={priority:Z,type:\"yf\"}),e(ie,\"xfx\")!==-1&&(X.infix={priority:Z,type:\"xfx\"}),e(ie,\"xfy\")!==-1&&(X.infix={priority:Z,type:\"xfy\"}),e(ie,\"yfx\")!==-1&&(X.infix={priority:Z,type:\"yfx\"}))}var Pe;switch(F.id){case\"fy\":case\"fx\":Pe=\"prefix\";break;case\"yf\":case\"xf\":Pe=\"postfix\";break;default:Pe=\"infix\";break}if(((X.prefix&&Pe===\"prefix\"||X.postfix&&Pe===\"postfix\"||X.infix&&Pe===\"infix\")&&X[Pe].type!==F.id||X.infix&&Pe===\"postfix\"||X.postfix&&Pe===\"infix\")&&y.value!==0)w.throw_error(b.error.permission(\"create\",\"operator\",J,S.indicator));else return X[Pe]&&(Ee(w.session.__operators[X[Pe].priority][J.id],F.id),w.session.__operators[X[Pe].priority][J.id].length===0&&delete w.session.__operators[X[Pe].priority][J.id]),y.value>0&&(w.session.__operators[y.value]||(w.session.__operators[y.value.toString()]={}),w.session.__operators[y.value][J.id]||(w.session.__operators[y.value][J.id]=[]),w.session.__operators[y.value][J.id].push(F.id)),!0}}},predicate:{\"op/3\":function(w,S,y){b.directive[\"op/3\"](w,y)&&w.success(S)},\"current_op/3\":function(w,S,y){var F=y.args[0],J=y.args[1],X=y.args[2],Z=[];for(var ie in w.session.__operators)for(var Pe in w.session.__operators[ie])for(var Ne=0;Ne<w.session.__operators[ie][Pe].length;Ne++)Z.push(new be(S.goal.replace(new H(\",\",[new H(\"=\",[new xe(ie,!1),F]),new H(\",\",[new H(\"=\",[new H(w.session.__operators[ie][Pe][Ne],[]),J]),new H(\"=\",[new H(Pe,[]),X])])])),S.substitution,S));w.prepend(Z)},\";/2\":function(w,S,y){if(b.type.is_term(y.args[0])&&y.args[0].indicator===\"->/2\"){var F=w.points,J=w.session.format_success,X=w.session.format_error;w.session.format_success=function(Ne){return Ne.substitution},w.session.format_error=function(Ne){return Ne.goal},w.points=[new be(y.args[0].args[0],S.substitution,S)];var Z=function(Ne){w.points=F,w.session.format_success=J,w.session.format_error=X,Ne===!1?w.prepend([new be(S.goal.replace(y.args[1]),S.substitution,S)]):b.type.is_error(Ne)?w.throw_error(Ne.args[0]):Ne===null?(w.prepend([S]),w.__calls.shift()(null)):w.prepend([new be(S.goal.replace(y.args[0].args[1]).apply(Ne),S.substitution.apply(Ne),S)])};w.__calls.unshift(Z)}else{var ie=new be(S.goal.replace(y.args[0]),S.substitution,S),Pe=new be(S.goal.replace(y.args[1]),S.substitution,S);w.prepend([ie,Pe])}},\"!/0\":function(w,S,y){var F,J,X=[];for(F=S,J=null;F.parent!==null&&F.parent.goal.search(y);)if(J=F,F=F.parent,F.goal!==null){var Z=F.goal.select();if(Z&&Z.id===\"call\"&&Z.search(y)){F=J;break}}for(var ie=w.points.length-1;ie>=0;ie--){for(var Pe=w.points[ie],Ne=Pe.parent;Ne!==null&&Ne!==F.parent;)Ne=Ne.parent;Ne===null&&Ne!==F.parent&&X.push(Pe)}w.points=X.reverse(),w.success(S)},\"\\\\+/1\":function(w,S,y){var F=y.args[0];b.type.is_variable(F)?w.throw_error(b.error.instantiation(w.level)):b.type.is_callable(F)?w.prepend([new be(S.goal.replace(new H(\",\",[new H(\",\",[new H(\"call\",[F]),new H(\"!\",[])]),new H(\"fail\",[])])),S.substitution,S),new be(S.goal.replace(null),S.substitution,S)]):w.throw_error(b.error.type(\"callable\",F,w.level))},\"->/2\":function(w,S,y){var F=S.goal.replace(new H(\",\",[y.args[0],new H(\",\",[new H(\"!\"),y.args[1]])]));w.prepend([new be(F,S.substitution,S)])},\"fail/0\":function(w,S,y){},\"false/0\":function(w,S,y){},\"true/0\":function(w,S,y){w.success(S)},\"call/1\":ne(1),\"call/2\":ne(2),\"call/3\":ne(3),\"call/4\":ne(4),\"call/5\":ne(5),\"call/6\":ne(6),\"call/7\":ne(7),\"call/8\":ne(8),\"once/1\":function(w,S,y){var F=y.args[0];w.prepend([new be(S.goal.replace(new H(\",\",[new H(\"call\",[F]),new H(\"!\",[])])),S.substitution,S)])},\"forall/2\":function(w,S,y){var F=y.args[0],J=y.args[1];w.prepend([new be(S.goal.replace(new H(\"\\\\+\",[new H(\",\",[new H(\"call\",[F]),new H(\"\\\\+\",[new H(\"call\",[J])])])])),S.substitution,S)])},\"repeat/0\":function(w,S,y){w.prepend([new be(S.goal.replace(null),S.substitution,S),S])},\"throw/1\":function(w,S,y){b.type.is_variable(y.args[0])?w.throw_error(b.error.instantiation(w.level)):w.throw_error(y.args[0])},\"catch/3\":function(w,S,y){var F=w.points;w.points=[],w.prepend([new be(y.args[0],S.substitution,S)]);var J=w.session.format_success,X=w.session.format_error;w.session.format_success=function(ie){return ie.substitution},w.session.format_error=function(ie){return ie.goal};var Z=function(ie){var Pe=w.points;if(w.points=F,w.session.format_success=J,w.session.format_error=X,b.type.is_error(ie)){for(var Ne=[],ot=w.points.length-1;ot>=0;ot--){for(var $t=w.points[ot],dt=$t.parent;dt!==null&&dt!==S.parent;)dt=dt.parent;dt===null&&dt!==S.parent&&Ne.push($t)}w.points=Ne;var jt=w.get_flag(\"occurs_check\").indicator===\"true/0\",$t=new be,bt=b.unify(ie.args[0],y.args[1],jt);bt!==null?($t.substitution=S.substitution.apply(bt),$t.goal=S.goal.replace(y.args[2]).apply(bt),$t.parent=S,w.prepend([$t])):w.throw_error(ie.args[0])}else if(ie!==!1){for(var an=ie===null?[]:[new be(S.goal.apply(ie).replace(null),S.substitution.apply(ie),S)],Qr=[],ot=Pe.length-1;ot>=0;ot--){Qr.push(Pe[ot]);var mr=Pe[ot].goal!==null?Pe[ot].goal.select():null;if(b.type.is_term(mr)&&mr.indicator===\"!/0\")break}var br=o(Qr,function(Wr){return Wr.goal===null&&(Wr.goal=new H(\"true\",[])),Wr=new be(S.goal.replace(new H(\"catch\",[Wr.goal,y.args[1],y.args[2]])),S.substitution.apply(Wr.substitution),Wr.parent),Wr.exclude=y.args[0].variables(),Wr}).reverse();w.prepend(br),w.prepend(an),ie===null&&(this.current_limit=0,w.__calls.shift()(null))}};w.__calls.unshift(Z)},\"=/2\":function(w,S,y){var F=w.get_flag(\"occurs_check\").indicator===\"true/0\",J=new be,X=b.unify(y.args[0],y.args[1],F);X!==null&&(J.goal=S.goal.apply(X).replace(null),J.substitution=S.substitution.apply(X),J.parent=S,w.prepend([J]))},\"unify_with_occurs_check/2\":function(w,S,y){var F=new be,J=b.unify(y.args[0],y.args[1],!0);J!==null&&(F.goal=S.goal.apply(J).replace(null),F.substitution=S.substitution.apply(J),F.parent=S,w.prepend([F]))},\"\\\\=/2\":function(w,S,y){var F=w.get_flag(\"occurs_check\").indicator===\"true/0\",J=b.unify(y.args[0],y.args[1],F);J===null&&w.success(S)},\"subsumes_term/2\":function(w,S,y){var F=w.get_flag(\"occurs_check\").indicator===\"true/0\",J=b.unify(y.args[1],y.args[0],F);J!==null&&y.args[1].apply(J).equals(y.args[1])&&w.success(S)},\"findall/3\":function(w,S,y){var F=y.args[0],J=y.args[1],X=y.args[2];if(b.type.is_variable(J))w.throw_error(b.error.instantiation(y.indicator));else if(!b.type.is_callable(J))w.throw_error(b.error.type(\"callable\",J,y.indicator));else if(!b.type.is_variable(X)&&!b.type.is_list(X))w.throw_error(b.error.type(\"list\",X,y.indicator));else{var Z=w.next_free_variable(),ie=new H(\",\",[J,new H(\"=\",[Z,F])]),Pe=w.points,Ne=w.session.limit,ot=w.session.format_success;w.session.format_success=function($t){return $t.substitution},w.add_goal(ie,!0,S);var dt=[],jt=function($t){if($t!==!1&&$t!==null&&!b.type.is_error($t))w.__calls.unshift(jt),dt.push($t.links[Z.id]),w.session.limit=w.current_limit;else if(w.points=Pe,w.session.limit=Ne,w.session.format_success=ot,b.type.is_error($t))w.throw_error($t.args[0]);else if(w.current_limit>0){for(var bt=new H(\"[]\"),an=dt.length-1;an>=0;an--)bt=new H(\".\",[dt[an],bt]);w.prepend([new be(S.goal.replace(new H(\"=\",[X,bt])),S.substitution,S)])}};w.__calls.unshift(jt)}},\"bagof/3\":function(w,S,y){var F,J=y.args[0],X=y.args[1],Z=y.args[2];if(b.type.is_variable(X))w.throw_error(b.error.instantiation(y.indicator));else if(!b.type.is_callable(X))w.throw_error(b.error.type(\"callable\",X,y.indicator));else if(!b.type.is_variable(Z)&&!b.type.is_list(Z))w.throw_error(b.error.type(\"list\",Z,y.indicator));else{var ie=w.next_free_variable(),Pe;X.indicator===\"^/2\"?(Pe=X.args[0].variables(),X=X.args[1]):Pe=[],Pe=Pe.concat(J.variables());for(var Ne=X.variables().filter(function(br){return e(Pe,br)===-1}),ot=new H(\"[]\"),dt=Ne.length-1;dt>=0;dt--)ot=new H(\".\",[new we(Ne[dt]),ot]);var jt=new H(\",\",[X,new H(\"=\",[ie,new H(\",\",[ot,J])])]),$t=w.points,bt=w.session.limit,an=w.session.format_success;w.session.format_success=function(br){return br.substitution},w.add_goal(jt,!0,S);var Qr=[],mr=function(br){if(br!==!1&&br!==null&&!b.type.is_error(br)){w.__calls.unshift(mr);var Wr=!1,Kn=br.links[ie.id].args[0],Ns=br.links[ie.id].args[1];for(var Ti in Qr)if(!!Qr.hasOwnProperty(Ti)){var ps=Qr[Ti];if(ps.variables.equals(Kn)){ps.answers.push(Ns),Wr=!0;break}}Wr||Qr.push({variables:Kn,answers:[Ns]}),w.session.limit=w.current_limit}else if(w.points=$t,w.session.limit=bt,w.session.format_success=an,b.type.is_error(br))w.throw_error(br.args[0]);else if(w.current_limit>0){for(var io=[],Si=0;Si<Qr.length;Si++){br=Qr[Si].answers;for(var Ls=new H(\"[]\"),so=br.length-1;so>=0;so--)Ls=new H(\".\",[br[so],Ls]);io.push(new be(S.goal.replace(new H(\",\",[new H(\"=\",[ot,Qr[Si].variables]),new H(\"=\",[Z,Ls])])),S.substitution,S))}w.prepend(io)}};w.__calls.unshift(mr)}},\"setof/3\":function(w,S,y){var F,J=y.args[0],X=y.args[1],Z=y.args[2];if(b.type.is_variable(X))w.throw_error(b.error.instantiation(y.indicator));else if(!b.type.is_callable(X))w.throw_error(b.error.type(\"callable\",X,y.indicator));else if(!b.type.is_variable(Z)&&!b.type.is_list(Z))w.throw_error(b.error.type(\"list\",Z,y.indicator));else{var ie=w.next_free_variable(),Pe;X.indicator===\"^/2\"?(Pe=X.args[0].variables(),X=X.args[1]):Pe=[],Pe=Pe.concat(J.variables());for(var Ne=X.variables().filter(function(br){return e(Pe,br)===-1}),ot=new H(\"[]\"),dt=Ne.length-1;dt>=0;dt--)ot=new H(\".\",[new we(Ne[dt]),ot]);var jt=new H(\",\",[X,new H(\"=\",[ie,new H(\",\",[ot,J])])]),$t=w.points,bt=w.session.limit,an=w.session.format_success;w.session.format_success=function(br){return br.substitution},w.add_goal(jt,!0,S);var Qr=[],mr=function(br){if(br!==!1&&br!==null&&!b.type.is_error(br)){w.__calls.unshift(mr);var Wr=!1,Kn=br.links[ie.id].args[0],Ns=br.links[ie.id].args[1];for(var Ti in Qr)if(!!Qr.hasOwnProperty(Ti)){var ps=Qr[Ti];if(ps.variables.equals(Kn)){ps.answers.push(Ns),Wr=!0;break}}Wr||Qr.push({variables:Kn,answers:[Ns]}),w.session.limit=w.current_limit}else if(w.points=$t,w.session.limit=bt,w.session.format_success=an,b.type.is_error(br))w.throw_error(br.args[0]);else if(w.current_limit>0){for(var io=[],Si=0;Si<Qr.length;Si++){br=Qr[Si].answers.sort(b.compare);for(var Ls=new H(\"[]\"),so=br.length-1;so>=0;so--)Ls=new H(\".\",[br[so],Ls]);io.push(new be(S.goal.replace(new H(\",\",[new H(\"=\",[ot,Qr[Si].variables]),new H(\"=\",[Z,Ls])])),S.substitution,S))}w.prepend(io)}};w.__calls.unshift(mr)}},\"functor/3\":function(w,S,y){var F,J=y.args[0],X=y.args[1],Z=y.args[2];if(b.type.is_variable(J)&&(b.type.is_variable(X)||b.type.is_variable(Z)))w.throw_error(b.error.instantiation(\"functor/3\"));else if(!b.type.is_variable(Z)&&!b.type.is_integer(Z))w.throw_error(b.error.type(\"integer\",y.args[2],\"functor/3\"));else if(!b.type.is_variable(X)&&!b.type.is_atomic(X))w.throw_error(b.error.type(\"atomic\",y.args[1],\"functor/3\"));else if(b.type.is_integer(X)&&b.type.is_integer(Z)&&Z.value!==0)w.throw_error(b.error.type(\"atom\",y.args[1],\"functor/3\"));else if(b.type.is_variable(J)){if(y.args[2].value>=0){for(var ie=[],Pe=0;Pe<Z.value;Pe++)ie.push(w.next_free_variable());var Ne=b.type.is_integer(X)?X:new H(X.id,ie);w.prepend([new be(S.goal.replace(new H(\"=\",[J,Ne])),S.substitution,S)])}}else{var ot=b.type.is_integer(J)?J:new H(J.id,[]),dt=b.type.is_integer(J)?new xe(0,!1):new xe(J.args.length,!1),jt=new H(\",\",[new H(\"=\",[ot,X]),new H(\"=\",[dt,Z])]);w.prepend([new be(S.goal.replace(jt),S.substitution,S)])}},\"arg/3\":function(w,S,y){if(b.type.is_variable(y.args[0])||b.type.is_variable(y.args[1]))w.throw_error(b.error.instantiation(y.indicator));else if(y.args[0].value<0)w.throw_error(b.error.domain(\"not_less_than_zero\",y.args[0],y.indicator));else if(!b.type.is_compound(y.args[1]))w.throw_error(b.error.type(\"compound\",y.args[1],y.indicator));else{var F=y.args[0].value;if(F>0&&F<=y.args[1].args.length){var J=new H(\"=\",[y.args[1].args[F-1],y.args[2]]);w.prepend([new be(S.goal.replace(J),S.substitution,S)])}}},\"=../2\":function(w,S,y){var F;if(b.type.is_variable(y.args[0])&&(b.type.is_variable(y.args[1])||b.type.is_non_empty_list(y.args[1])&&b.type.is_variable(y.args[1].args[0])))w.throw_error(b.error.instantiation(y.indicator));else if(!b.type.is_fully_list(y.args[1]))w.throw_error(b.error.type(\"list\",y.args[1],y.indicator));else if(b.type.is_variable(y.args[0])){if(!b.type.is_variable(y.args[1])){var X=[];for(F=y.args[1].args[1];F.indicator===\"./2\";)X.push(F.args[0]),F=F.args[1];b.type.is_variable(y.args[0])&&b.type.is_variable(F)?w.throw_error(b.error.instantiation(y.indicator)):X.length===0&&b.type.is_compound(y.args[1].args[0])?w.throw_error(b.error.type(\"atomic\",y.args[1].args[0],y.indicator)):X.length>0&&(b.type.is_compound(y.args[1].args[0])||b.type.is_number(y.args[1].args[0]))?w.throw_error(b.error.type(\"atom\",y.args[1].args[0],y.indicator)):X.length===0?w.prepend([new be(S.goal.replace(new H(\"=\",[y.args[1].args[0],y.args[0]],S)),S.substitution,S)]):w.prepend([new be(S.goal.replace(new H(\"=\",[new H(y.args[1].args[0].id,X),y.args[0]])),S.substitution,S)])}}else{if(b.type.is_atomic(y.args[0]))F=new H(\".\",[y.args[0],new H(\"[]\")]);else{F=new H(\"[]\");for(var J=y.args[0].args.length-1;J>=0;J--)F=new H(\".\",[y.args[0].args[J],F]);F=new H(\".\",[new H(y.args[0].id),F])}w.prepend([new be(S.goal.replace(new H(\"=\",[F,y.args[1]])),S.substitution,S)])}},\"copy_term/2\":function(w,S,y){var F=y.args[0].rename(w);w.prepend([new be(S.goal.replace(new H(\"=\",[F,y.args[1]])),S.substitution,S.parent)])},\"term_variables/2\":function(w,S,y){var F=y.args[0],J=y.args[1];if(!b.type.is_fully_list(J))w.throw_error(b.error.type(\"list\",J,y.indicator));else{var X=g(o(De(F.variables()),function(Z){return new we(Z)}));w.prepend([new be(S.goal.replace(new H(\"=\",[J,X])),S.substitution,S)])}},\"clause/2\":function(w,S,y){if(b.type.is_variable(y.args[0]))w.throw_error(b.error.instantiation(y.indicator));else if(!b.type.is_callable(y.args[0]))w.throw_error(b.error.type(\"callable\",y.args[0],y.indicator));else if(!b.type.is_variable(y.args[1])&&!b.type.is_callable(y.args[1]))w.throw_error(b.error.type(\"callable\",y.args[1],y.indicator));else if(w.session.rules[y.args[0].indicator]!==void 0)if(w.is_public_predicate(y.args[0].indicator)){var F=[];for(var J in w.session.rules[y.args[0].indicator])if(!!w.session.rules[y.args[0].indicator].hasOwnProperty(J)){var X=w.session.rules[y.args[0].indicator][J];w.session.renamed_variables={},X=X.rename(w),X.body===null&&(X.body=new H(\"true\"));var Z=new H(\",\",[new H(\"=\",[X.head,y.args[0]]),new H(\"=\",[X.body,y.args[1]])]);F.push(new be(S.goal.replace(Z),S.substitution,S))}w.prepend(F)}else w.throw_error(b.error.permission(\"access\",\"private_procedure\",y.args[0].indicator,y.indicator))},\"current_predicate/1\":function(w,S,y){var F=y.args[0];if(!b.type.is_variable(F)&&(!b.type.is_compound(F)||F.indicator!==\"//2\"))w.throw_error(b.error.type(\"predicate_indicator\",F,y.indicator));else if(!b.type.is_variable(F)&&!b.type.is_variable(F.args[0])&&!b.type.is_atom(F.args[0]))w.throw_error(b.error.type(\"atom\",F.args[0],y.indicator));else if(!b.type.is_variable(F)&&!b.type.is_variable(F.args[1])&&!b.type.is_integer(F.args[1]))w.throw_error(b.error.type(\"integer\",F.args[1],y.indicator));else{var J=[];for(var X in w.session.rules)if(!!w.session.rules.hasOwnProperty(X)){var Z=X.lastIndexOf(\"/\"),ie=X.substr(0,Z),Pe=parseInt(X.substr(Z+1,X.length-(Z+1))),Ne=new H(\"/\",[new H(ie),new xe(Pe,!1)]),ot=new H(\"=\",[Ne,F]);J.push(new be(S.goal.replace(ot),S.substitution,S))}w.prepend(J)}},\"asserta/1\":function(w,S,y){if(b.type.is_variable(y.args[0]))w.throw_error(b.error.instantiation(y.indicator));else if(!b.type.is_callable(y.args[0]))w.throw_error(b.error.type(\"callable\",y.args[0],y.indicator));else{var F,J;y.args[0].indicator===\":-/2\"?(F=y.args[0].args[0],J=Fe(y.args[0].args[1])):(F=y.args[0],J=null),b.type.is_callable(F)?J!==null&&!b.type.is_callable(J)?w.throw_error(b.error.type(\"callable\",J,y.indicator)):w.is_public_predicate(F.indicator)?(w.session.rules[F.indicator]===void 0&&(w.session.rules[F.indicator]=[]),w.session.public_predicates[F.indicator]=!0,w.session.rules[F.indicator]=[new _e(F,J,!0)].concat(w.session.rules[F.indicator]),w.success(S)):w.throw_error(b.error.permission(\"modify\",\"static_procedure\",F.indicator,y.indicator)):w.throw_error(b.error.type(\"callable\",F,y.indicator))}},\"assertz/1\":function(w,S,y){if(b.type.is_variable(y.args[0]))w.throw_error(b.error.instantiation(y.indicator));else if(!b.type.is_callable(y.args[0]))w.throw_error(b.error.type(\"callable\",y.args[0],y.indicator));else{var F,J;y.args[0].indicator===\":-/2\"?(F=y.args[0].args[0],J=Fe(y.args[0].args[1])):(F=y.args[0],J=null),b.type.is_callable(F)?J!==null&&!b.type.is_callable(J)?w.throw_error(b.error.type(\"callable\",J,y.indicator)):w.is_public_predicate(F.indicator)?(w.session.rules[F.indicator]===void 0&&(w.session.rules[F.indicator]=[]),w.session.public_predicates[F.indicator]=!0,w.session.rules[F.indicator].push(new _e(F,J,!0)),w.success(S)):w.throw_error(b.error.permission(\"modify\",\"static_procedure\",F.indicator,y.indicator)):w.throw_error(b.error.type(\"callable\",F,y.indicator))}},\"retract/1\":function(w,S,y){if(b.type.is_variable(y.args[0]))w.throw_error(b.error.instantiation(y.indicator));else if(!b.type.is_callable(y.args[0]))w.throw_error(b.error.type(\"callable\",y.args[0],y.indicator));else{var F,J;if(y.args[0].indicator===\":-/2\"?(F=y.args[0].args[0],J=y.args[0].args[1]):(F=y.args[0],J=new H(\"true\")),typeof S.retract>\"u\")if(w.is_public_predicate(F.indicator)){if(w.session.rules[F.indicator]!==void 0){for(var X=[],Z=0;Z<w.session.rules[F.indicator].length;Z++){w.session.renamed_variables={};var ie=w.session.rules[F.indicator][Z],Pe=ie.rename(w);Pe.body===null&&(Pe.body=new H(\"true\",[]));var Ne=w.get_flag(\"occurs_check\").indicator===\"true/0\",ot=b.unify(new H(\",\",[F,J]),new H(\",\",[Pe.head,Pe.body]),Ne);if(ot!==null){var dt=new be(S.goal.replace(new H(\",\",[new H(\"retract\",[new H(\":-\",[F,J])]),new H(\",\",[new H(\"=\",[F,Pe.head]),new H(\"=\",[J,Pe.body])])])),S.substitution,S);dt.retract=ie,X.push(dt)}}w.prepend(X)}}else w.throw_error(b.error.permission(\"modify\",\"static_procedure\",F.indicator,y.indicator));else ce(w,S,F.indicator,S.retract)}},\"retractall/1\":function(w,S,y){var F=y.args[0];b.type.is_variable(F)?w.throw_error(b.error.instantiation(y.indicator)):b.type.is_callable(F)?w.prepend([new be(S.goal.replace(new H(\",\",[new H(\"retract\",[new b.type.Term(\":-\",[F,new we(\"_\")])]),new H(\"fail\",[])])),S.substitution,S),new be(S.goal.replace(null),S.substitution,S)]):w.throw_error(b.error.type(\"callable\",F,y.indicator))},\"abolish/1\":function(w,S,y){if(b.type.is_variable(y.args[0])||b.type.is_term(y.args[0])&&y.args[0].indicator===\"//2\"&&(b.type.is_variable(y.args[0].args[0])||b.type.is_variable(y.args[0].args[1])))w.throw_error(b.error.instantiation(y.indicator));else if(!b.type.is_term(y.args[0])||y.args[0].indicator!==\"//2\")w.throw_error(b.error.type(\"predicate_indicator\",y.args[0],y.indicator));else if(!b.type.is_atom(y.args[0].args[0]))w.throw_error(b.error.type(\"atom\",y.args[0].args[0],y.indicator));else if(!b.type.is_integer(y.args[0].args[1]))w.throw_error(b.error.type(\"integer\",y.args[0].args[1],y.indicator));else if(y.args[0].args[1].value<0)w.throw_error(b.error.domain(\"not_less_than_zero\",y.args[0].args[1],y.indicator));else if(b.type.is_number(w.get_flag(\"max_arity\"))&&y.args[0].args[1].value>w.get_flag(\"max_arity\").value)w.throw_error(b.error.representation(\"max_arity\",y.indicator));else{var F=y.args[0].args[0].id+\"/\"+y.args[0].args[1].value;w.is_public_predicate(F)?(delete w.session.rules[F],w.success(S)):w.throw_error(b.error.permission(\"modify\",\"static_procedure\",F,y.indicator))}},\"atom_length/2\":function(w,S,y){if(b.type.is_variable(y.args[0]))w.throw_error(b.error.instantiation(y.indicator));else if(!b.type.is_atom(y.args[0]))w.throw_error(b.error.type(\"atom\",y.args[0],y.indicator));else if(!b.type.is_variable(y.args[1])&&!b.type.is_integer(y.args[1]))w.throw_error(b.error.type(\"integer\",y.args[1],y.indicator));else if(b.type.is_integer(y.args[1])&&y.args[1].value<0)w.throw_error(b.error.domain(\"not_less_than_zero\",y.args[1],y.indicator));else{var F=new xe(y.args[0].id.length,!1);w.prepend([new be(S.goal.replace(new H(\"=\",[F,y.args[1]])),S.substitution,S)])}},\"atom_concat/3\":function(w,S,y){var F,J,X=y.args[0],Z=y.args[1],ie=y.args[2];if(b.type.is_variable(ie)&&(b.type.is_variable(X)||b.type.is_variable(Z)))w.throw_error(b.error.instantiation(y.indicator));else if(!b.type.is_variable(X)&&!b.type.is_atom(X))w.throw_error(b.error.type(\"atom\",X,y.indicator));else if(!b.type.is_variable(Z)&&!b.type.is_atom(Z))w.throw_error(b.error.type(\"atom\",Z,y.indicator));else if(!b.type.is_variable(ie)&&!b.type.is_atom(ie))w.throw_error(b.error.type(\"atom\",ie,y.indicator));else{var Pe=b.type.is_variable(X),Ne=b.type.is_variable(Z);if(!Pe&&!Ne)J=new H(\"=\",[ie,new H(X.id+Z.id)]),w.prepend([new be(S.goal.replace(J),S.substitution,S)]);else if(Pe&&!Ne)F=ie.id.substr(0,ie.id.length-Z.id.length),F+Z.id===ie.id&&(J=new H(\"=\",[X,new H(F)]),w.prepend([new be(S.goal.replace(J),S.substitution,S)]));else if(Ne&&!Pe)F=ie.id.substr(X.id.length),X.id+F===ie.id&&(J=new H(\"=\",[Z,new H(F)]),w.prepend([new be(S.goal.replace(J),S.substitution,S)]));else{for(var ot=[],dt=0;dt<=ie.id.length;dt++){var jt=new H(ie.id.substr(0,dt)),$t=new H(ie.id.substr(dt));J=new H(\",\",[new H(\"=\",[jt,X]),new H(\"=\",[$t,Z])]),ot.push(new be(S.goal.replace(J),S.substitution,S))}w.prepend(ot)}}},\"sub_atom/5\":function(w,S,y){var F,J=y.args[0],X=y.args[1],Z=y.args[2],ie=y.args[3],Pe=y.args[4];if(b.type.is_variable(J))w.throw_error(b.error.instantiation(y.indicator));else if(!b.type.is_variable(X)&&!b.type.is_integer(X))w.throw_error(b.error.type(\"integer\",X,y.indicator));else if(!b.type.is_variable(Z)&&!b.type.is_integer(Z))w.throw_error(b.error.type(\"integer\",Z,y.indicator));else if(!b.type.is_variable(ie)&&!b.type.is_integer(ie))w.throw_error(b.error.type(\"integer\",ie,y.indicator));else if(b.type.is_integer(X)&&X.value<0)w.throw_error(b.error.domain(\"not_less_than_zero\",X,y.indicator));else if(b.type.is_integer(Z)&&Z.value<0)w.throw_error(b.error.domain(\"not_less_than_zero\",Z,y.indicator));else if(b.type.is_integer(ie)&&ie.value<0)w.throw_error(b.error.domain(\"not_less_than_zero\",ie,y.indicator));else{var Ne=[],ot=[],dt=[];if(b.type.is_variable(X))for(F=0;F<=J.id.length;F++)Ne.push(F);else Ne.push(X.value);if(b.type.is_variable(Z))for(F=0;F<=J.id.length;F++)ot.push(F);else ot.push(Z.value);if(b.type.is_variable(ie))for(F=0;F<=J.id.length;F++)dt.push(F);else dt.push(ie.value);var jt=[];for(var $t in Ne)if(!!Ne.hasOwnProperty($t)){F=Ne[$t];for(var bt in ot)if(!!ot.hasOwnProperty(bt)){var an=ot[bt],Qr=J.id.length-F-an;if(e(dt,Qr)!==-1&&F+an+Qr===J.id.length){var mr=J.id.substr(F,an);if(J.id===J.id.substr(0,F)+mr+J.id.substr(F+an,Qr)){var br=new H(\"=\",[new H(mr),Pe]),Wr=new H(\"=\",[X,new xe(F)]),Kn=new H(\"=\",[Z,new xe(an)]),Ns=new H(\"=\",[ie,new xe(Qr)]),Ti=new H(\",\",[new H(\",\",[new H(\",\",[Wr,Kn]),Ns]),br]);jt.push(new be(S.goal.replace(Ti),S.substitution,S))}}}}w.prepend(jt)}},\"atom_chars/2\":function(w,S,y){var F=y.args[0],J=y.args[1];if(b.type.is_variable(F)&&b.type.is_variable(J))w.throw_error(b.error.instantiation(y.indicator));else if(!b.type.is_variable(F)&&!b.type.is_atom(F))w.throw_error(b.error.type(\"atom\",F,y.indicator));else if(b.type.is_variable(F)){for(var ie=J,Pe=b.type.is_variable(F),Ne=\"\";ie.indicator===\"./2\";){if(b.type.is_character(ie.args[0]))Ne+=ie.args[0].id;else if(b.type.is_variable(ie.args[0])&&Pe){w.throw_error(b.error.instantiation(y.indicator));return}else if(!b.type.is_variable(ie.args[0])){w.throw_error(b.error.type(\"character\",ie.args[0],y.indicator));return}ie=ie.args[1]}b.type.is_variable(ie)&&Pe?w.throw_error(b.error.instantiation(y.indicator)):!b.type.is_empty_list(ie)&&!b.type.is_variable(ie)?w.throw_error(b.error.type(\"list\",J,y.indicator)):w.prepend([new be(S.goal.replace(new H(\"=\",[new H(Ne),F])),S.substitution,S)])}else{for(var X=new H(\"[]\"),Z=F.id.length-1;Z>=0;Z--)X=new H(\".\",[new H(F.id.charAt(Z)),X]);w.prepend([new be(S.goal.replace(new H(\"=\",[J,X])),S.substitution,S)])}},\"atom_codes/2\":function(w,S,y){var F=y.args[0],J=y.args[1];if(b.type.is_variable(F)&&b.type.is_variable(J))w.throw_error(b.error.instantiation(y.indicator));else if(!b.type.is_variable(F)&&!b.type.is_atom(F))w.throw_error(b.error.type(\"atom\",F,y.indicator));else if(b.type.is_variable(F)){for(var ie=J,Pe=b.type.is_variable(F),Ne=\"\";ie.indicator===\"./2\";){if(b.type.is_character_code(ie.args[0]))Ne+=u(ie.args[0].value);else if(b.type.is_variable(ie.args[0])&&Pe){w.throw_error(b.error.instantiation(y.indicator));return}else if(!b.type.is_variable(ie.args[0])){w.throw_error(b.error.representation(\"character_code\",y.indicator));return}ie=ie.args[1]}b.type.is_variable(ie)&&Pe?w.throw_error(b.error.instantiation(y.indicator)):!b.type.is_empty_list(ie)&&!b.type.is_variable(ie)?w.throw_error(b.error.type(\"list\",J,y.indicator)):w.prepend([new be(S.goal.replace(new H(\"=\",[new H(Ne),F])),S.substitution,S)])}else{for(var X=new H(\"[]\"),Z=F.id.length-1;Z>=0;Z--)X=new H(\".\",[new xe(n(F.id,Z),!1),X]);w.prepend([new be(S.goal.replace(new H(\"=\",[J,X])),S.substitution,S)])}},\"char_code/2\":function(w,S,y){var F=y.args[0],J=y.args[1];if(b.type.is_variable(F)&&b.type.is_variable(J))w.throw_error(b.error.instantiation(y.indicator));else if(!b.type.is_variable(F)&&!b.type.is_character(F))w.throw_error(b.error.type(\"character\",F,y.indicator));else if(!b.type.is_variable(J)&&!b.type.is_integer(J))w.throw_error(b.error.type(\"integer\",J,y.indicator));else if(!b.type.is_variable(J)&&!b.type.is_character_code(J))w.throw_error(b.error.representation(\"character_code\",y.indicator));else if(b.type.is_variable(J)){var X=new xe(n(F.id,0),!1);w.prepend([new be(S.goal.replace(new H(\"=\",[X,J])),S.substitution,S)])}else{var Z=new H(u(J.value));w.prepend([new be(S.goal.replace(new H(\"=\",[Z,F])),S.substitution,S)])}},\"number_chars/2\":function(w,S,y){var F,J=y.args[0],X=y.args[1];if(b.type.is_variable(J)&&b.type.is_variable(X))w.throw_error(b.error.instantiation(y.indicator));else if(!b.type.is_variable(J)&&!b.type.is_number(J))w.throw_error(b.error.type(\"number\",J,y.indicator));else if(!b.type.is_variable(X)&&!b.type.is_list(X))w.throw_error(b.error.type(\"list\",X,y.indicator));else{var Z=b.type.is_variable(J);if(!b.type.is_variable(X)){var ie=X,Pe=!0;for(F=\"\";ie.indicator===\"./2\";){if(b.type.is_character(ie.args[0]))F+=ie.args[0].id;else if(b.type.is_variable(ie.args[0]))Pe=!1;else if(!b.type.is_variable(ie.args[0])){w.throw_error(b.error.type(\"character\",ie.args[0],y.indicator));return}ie=ie.args[1]}if(Pe=Pe&&b.type.is_empty_list(ie),!b.type.is_empty_list(ie)&&!b.type.is_variable(ie)){w.throw_error(b.error.type(\"list\",X,y.indicator));return}if(!Pe&&Z){w.throw_error(b.error.instantiation(y.indicator));return}else if(Pe)if(b.type.is_variable(ie)&&Z){w.throw_error(b.error.instantiation(y.indicator));return}else{var Ne=w.parse(F),ot=Ne.value;!b.type.is_number(ot)||Ne.tokens[Ne.tokens.length-1].space?w.throw_error(b.error.syntax_by_predicate(\"parseable_number\",y.indicator)):w.prepend([new be(S.goal.replace(new H(\"=\",[J,ot])),S.substitution,S)]);return}}if(!Z){F=J.toString();for(var dt=new H(\"[]\"),jt=F.length-1;jt>=0;jt--)dt=new H(\".\",[new H(F.charAt(jt)),dt]);w.prepend([new be(S.goal.replace(new H(\"=\",[X,dt])),S.substitution,S)])}}},\"number_codes/2\":function(w,S,y){var F,J=y.args[0],X=y.args[1];if(b.type.is_variable(J)&&b.type.is_variable(X))w.throw_error(b.error.instantiation(y.indicator));else if(!b.type.is_variable(J)&&!b.type.is_number(J))w.throw_error(b.error.type(\"number\",J,y.indicator));else if(!b.type.is_variable(X)&&!b.type.is_list(X))w.throw_error(b.error.type(\"list\",X,y.indicator));else{var Z=b.type.is_variable(J);if(!b.type.is_variable(X)){var ie=X,Pe=!0;for(F=\"\";ie.indicator===\"./2\";){if(b.type.is_character_code(ie.args[0]))F+=u(ie.args[0].value);else if(b.type.is_variable(ie.args[0]))Pe=!1;else if(!b.type.is_variable(ie.args[0])){w.throw_error(b.error.type(\"character_code\",ie.args[0],y.indicator));return}ie=ie.args[1]}if(Pe=Pe&&b.type.is_empty_list(ie),!b.type.is_empty_list(ie)&&!b.type.is_variable(ie)){w.throw_error(b.error.type(\"list\",X,y.indicator));return}if(!Pe&&Z){w.throw_error(b.error.instantiation(y.indicator));return}else if(Pe)if(b.type.is_variable(ie)&&Z){w.throw_error(b.error.instantiation(y.indicator));return}else{var Ne=w.parse(F),ot=Ne.value;!b.type.is_number(ot)||Ne.tokens[Ne.tokens.length-1].space?w.throw_error(b.error.syntax_by_predicate(\"parseable_number\",y.indicator)):w.prepend([new be(S.goal.replace(new H(\"=\",[J,ot])),S.substitution,S)]);return}}if(!Z){F=J.toString();for(var dt=new H(\"[]\"),jt=F.length-1;jt>=0;jt--)dt=new H(\".\",[new xe(n(F,jt),!1),dt]);w.prepend([new be(S.goal.replace(new H(\"=\",[X,dt])),S.substitution,S)])}}},\"upcase_atom/2\":function(w,S,y){var F=y.args[0],J=y.args[1];b.type.is_variable(F)?w.throw_error(b.error.instantiation(y.indicator)):b.type.is_atom(F)?!b.type.is_variable(J)&&!b.type.is_atom(J)?w.throw_error(b.error.type(\"atom\",J,y.indicator)):w.prepend([new be(S.goal.replace(new H(\"=\",[J,new H(F.id.toUpperCase(),[])])),S.substitution,S)]):w.throw_error(b.error.type(\"atom\",F,y.indicator))},\"downcase_atom/2\":function(w,S,y){var F=y.args[0],J=y.args[1];b.type.is_variable(F)?w.throw_error(b.error.instantiation(y.indicator)):b.type.is_atom(F)?!b.type.is_variable(J)&&!b.type.is_atom(J)?w.throw_error(b.error.type(\"atom\",J,y.indicator)):w.prepend([new be(S.goal.replace(new H(\"=\",[J,new H(F.id.toLowerCase(),[])])),S.substitution,S)]):w.throw_error(b.error.type(\"atom\",F,y.indicator))},\"atomic_list_concat/2\":function(w,S,y){var F=y.args[0],J=y.args[1];w.prepend([new be(S.goal.replace(new H(\"atomic_list_concat\",[F,new H(\"\",[]),J])),S.substitution,S)])},\"atomic_list_concat/3\":function(w,S,y){var F=y.args[0],J=y.args[1],X=y.args[2];if(b.type.is_variable(J)||b.type.is_variable(F)&&b.type.is_variable(X))w.throw_error(b.error.instantiation(y.indicator));else if(!b.type.is_variable(F)&&!b.type.is_list(F))w.throw_error(b.error.type(\"list\",F,y.indicator));else if(!b.type.is_variable(X)&&!b.type.is_atom(X))w.throw_error(b.error.type(\"atom\",X,y.indicator));else if(b.type.is_variable(X)){for(var ie=\"\",Pe=F;b.type.is_term(Pe)&&Pe.indicator===\"./2\";){if(!b.type.is_atom(Pe.args[0])&&!b.type.is_number(Pe.args[0])){w.throw_error(b.error.type(\"atomic\",Pe.args[0],y.indicator));return}ie!==\"\"&&(ie+=J.id),b.type.is_atom(Pe.args[0])?ie+=Pe.args[0].id:ie+=\"\"+Pe.args[0].value,Pe=Pe.args[1]}ie=new H(ie,[]),b.type.is_variable(Pe)?w.throw_error(b.error.instantiation(y.indicator)):!b.type.is_term(Pe)||Pe.indicator!==\"[]/0\"?w.throw_error(b.error.type(\"list\",F,y.indicator)):w.prepend([new be(S.goal.replace(new H(\"=\",[ie,X])),S.substitution,S)])}else{var Z=g(o(X.id.split(J.id),function(Ne){return new H(Ne,[])}));w.prepend([new be(S.goal.replace(new H(\"=\",[Z,F])),S.substitution,S)])}},\"@=</2\":function(w,S,y){b.compare(y.args[0],y.args[1])<=0&&w.success(S)},\"==/2\":function(w,S,y){b.compare(y.args[0],y.args[1])===0&&w.success(S)},\"\\\\==/2\":function(w,S,y){b.compare(y.args[0],y.args[1])!==0&&w.success(S)},\"@</2\":function(w,S,y){b.compare(y.args[0],y.args[1])<0&&w.success(S)},\"@>/2\":function(w,S,y){b.compare(y.args[0],y.args[1])>0&&w.success(S)},\"@>=/2\":function(w,S,y){b.compare(y.args[0],y.args[1])>=0&&w.success(S)},\"compare/3\":function(w,S,y){var F=y.args[0],J=y.args[1],X=y.args[2];if(!b.type.is_variable(F)&&!b.type.is_atom(F))w.throw_error(b.error.type(\"atom\",F,y.indicator));else if(b.type.is_atom(F)&&[\"<\",\">\",\"=\"].indexOf(F.id)===-1)w.throw_error(b.type.domain(\"order\",F,y.indicator));else{var Z=b.compare(J,X);Z=Z===0?\"=\":Z===-1?\"<\":\">\",w.prepend([new be(S.goal.replace(new H(\"=\",[F,new H(Z,[])])),S.substitution,S)])}},\"is/2\":function(w,S,y){var F=y.args[1].interpret(w);b.type.is_number(F)?w.prepend([new be(S.goal.replace(new H(\"=\",[y.args[0],F],w.level)),S.substitution,S)]):w.throw_error(F)},\"between/3\":function(w,S,y){var F=y.args[0],J=y.args[1],X=y.args[2];if(b.type.is_variable(F)||b.type.is_variable(J))w.throw_error(b.error.instantiation(y.indicator));else if(!b.type.is_integer(F))w.throw_error(b.error.type(\"integer\",F,y.indicator));else if(!b.type.is_integer(J))w.throw_error(b.error.type(\"integer\",J,y.indicator));else if(!b.type.is_variable(X)&&!b.type.is_integer(X))w.throw_error(b.error.type(\"integer\",X,y.indicator));else if(b.type.is_variable(X)){var Z=[new be(S.goal.replace(new H(\"=\",[X,F])),S.substitution,S)];F.value<J.value&&Z.push(new be(S.goal.replace(new H(\"between\",[new xe(F.value+1,!1),J,X])),S.substitution,S)),w.prepend(Z)}else F.value<=X.value&&J.value>=X.value&&w.success(S)},\"succ/2\":function(w,S,y){var F=y.args[0],J=y.args[1];b.type.is_variable(F)&&b.type.is_variable(J)?w.throw_error(b.error.instantiation(y.indicator)):!b.type.is_variable(F)&&!b.type.is_integer(F)?w.throw_error(b.error.type(\"integer\",F,y.indicator)):!b.type.is_variable(J)&&!b.type.is_integer(J)?w.throw_error(b.error.type(\"integer\",J,y.indicator)):!b.type.is_variable(F)&&F.value<0?w.throw_error(b.error.domain(\"not_less_than_zero\",F,y.indicator)):!b.type.is_variable(J)&&J.value<0?w.throw_error(b.error.domain(\"not_less_than_zero\",J,y.indicator)):(b.type.is_variable(J)||J.value>0)&&(b.type.is_variable(F)?w.prepend([new be(S.goal.replace(new H(\"=\",[F,new xe(J.value-1,!1)])),S.substitution,S)]):w.prepend([new be(S.goal.replace(new H(\"=\",[J,new xe(F.value+1,!1)])),S.substitution,S)]))},\"=:=/2\":function(w,S,y){var F=b.arithmetic_compare(w,y.args[0],y.args[1]);b.type.is_term(F)?w.throw_error(F):F===0&&w.success(S)},\"=\\\\=/2\":function(w,S,y){var F=b.arithmetic_compare(w,y.args[0],y.args[1]);b.type.is_term(F)?w.throw_error(F):F!==0&&w.success(S)},\"</2\":function(w,S,y){var F=b.arithmetic_compare(w,y.args[0],y.args[1]);b.type.is_term(F)?w.throw_error(F):F<0&&w.success(S)},\"=</2\":function(w,S,y){var F=b.arithmetic_compare(w,y.args[0],y.args[1]);b.type.is_term(F)?w.throw_error(F):F<=0&&w.success(S)},\">/2\":function(w,S,y){var F=b.arithmetic_compare(w,y.args[0],y.args[1]);b.type.is_term(F)?w.throw_error(F):F>0&&w.success(S)},\">=/2\":function(w,S,y){var F=b.arithmetic_compare(w,y.args[0],y.args[1]);b.type.is_term(F)?w.throw_error(F):F>=0&&w.success(S)},\"var/1\":function(w,S,y){b.type.is_variable(y.args[0])&&w.success(S)},\"atom/1\":function(w,S,y){b.type.is_atom(y.args[0])&&w.success(S)},\"atomic/1\":function(w,S,y){b.type.is_atomic(y.args[0])&&w.success(S)},\"compound/1\":function(w,S,y){b.type.is_compound(y.args[0])&&w.success(S)},\"integer/1\":function(w,S,y){b.type.is_integer(y.args[0])&&w.success(S)},\"float/1\":function(w,S,y){b.type.is_float(y.args[0])&&w.success(S)},\"number/1\":function(w,S,y){b.type.is_number(y.args[0])&&w.success(S)},\"nonvar/1\":function(w,S,y){b.type.is_variable(y.args[0])||w.success(S)},\"ground/1\":function(w,S,y){y.variables().length===0&&w.success(S)},\"acyclic_term/1\":function(w,S,y){for(var F=S.substitution.apply(S.substitution),J=y.args[0].variables(),X=0;X<J.length;X++)if(S.substitution.links[J[X]]!==void 0&&!S.substitution.links[J[X]].equals(F.links[J[X]]))return;w.success(S)},\"callable/1\":function(w,S,y){b.type.is_callable(y.args[0])&&w.success(S)},\"is_list/1\":function(w,S,y){for(var F=y.args[0];b.type.is_term(F)&&F.indicator===\"./2\";)F=F.args[1];b.type.is_term(F)&&F.indicator===\"[]/0\"&&w.success(S)},\"current_input/1\":function(w,S,y){var F=y.args[0];!b.type.is_variable(F)&&!b.type.is_stream(F)&&!b.type.is_atom(F)?w.throw_error(b.error.domain(\"stream\",F,y.indicator)):(b.type.is_atom(F)&&w.get_stream_by_alias(F.id)&&(F=w.get_stream_by_alias(F.id)),w.prepend([new be(S.goal.replace(new H(\"=\",[F,w.get_current_input()])),S.substitution,S)]))},\"current_output/1\":function(w,S,y){var F=y.args[0];!b.type.is_variable(F)&&!b.type.is_stream(F)&&!b.type.is_atom(F)?w.throw_error(b.error.domain(\"stream_or_alias\",F,y.indicator)):(b.type.is_atom(F)&&w.get_stream_by_alias(F.id)&&(F=w.get_stream_by_alias(F.id)),w.prepend([new be(S.goal.replace(new H(\"=\",[F,w.get_current_output()])),S.substitution,S)]))},\"set_input/1\":function(w,S,y){var F=y.args[0],J=b.type.is_stream(F)?F:w.get_stream_by_alias(F.id);b.type.is_variable(F)?w.throw_error(b.error.instantiation(y.indicator)):!b.type.is_variable(F)&&!b.type.is_stream(F)&&!b.type.is_atom(F)?w.throw_error(b.error.domain(\"stream_or_alias\",F,y.indicator)):b.type.is_stream(J)?J.output===!0?w.throw_error(b.error.permission(\"input\",\"stream\",F,y.indicator)):(w.set_current_input(J),w.success(S)):w.throw_error(b.error.existence(\"stream\",F,y.indicator))},\"set_output/1\":function(w,S,y){var F=y.args[0],J=b.type.is_stream(F)?F:w.get_stream_by_alias(F.id);b.type.is_variable(F)?w.throw_error(b.error.instantiation(y.indicator)):!b.type.is_variable(F)&&!b.type.is_stream(F)&&!b.type.is_atom(F)?w.throw_error(b.error.domain(\"stream_or_alias\",F,y.indicator)):b.type.is_stream(J)?J.input===!0?w.throw_error(b.error.permission(\"output\",\"stream\",F,y.indicator)):(w.set_current_output(J),w.success(S)):w.throw_error(b.error.existence(\"stream\",F,y.indicator))},\"open/3\":function(w,S,y){var F=y.args[0],J=y.args[1],X=y.args[2];w.prepend([new be(S.goal.replace(new H(\"open\",[F,J,X,new H(\"[]\",[])])),S.substitution,S)])},\"open/4\":function(w,S,y){var F=y.args[0],J=y.args[1],X=y.args[2],Z=y.args[3];if(b.type.is_variable(F)||b.type.is_variable(J))w.throw_error(b.error.instantiation(y.indicator));else if(!b.type.is_variable(J)&&!b.type.is_atom(J))w.throw_error(b.error.type(\"atom\",J,y.indicator));else if(!b.type.is_list(Z))w.throw_error(b.error.type(\"list\",Z,y.indicator));else if(!b.type.is_variable(X))w.throw_error(b.error.type(\"variable\",X,y.indicator));else if(!b.type.is_atom(F)&&!b.type.is_streamable(F))w.throw_error(b.error.domain(\"source_sink\",F,y.indicator));else if(!b.type.is_io_mode(J))w.throw_error(b.error.domain(\"io_mode\",J,y.indicator));else{for(var ie={},Pe=Z,Ne;b.type.is_term(Pe)&&Pe.indicator===\"./2\";){if(Ne=Pe.args[0],b.type.is_variable(Ne)){w.throw_error(b.error.instantiation(y.indicator));return}else if(!b.type.is_stream_option(Ne)){w.throw_error(b.error.domain(\"stream_option\",Ne,y.indicator));return}ie[Ne.id]=Ne.args[0].id,Pe=Pe.args[1]}if(Pe.indicator!==\"[]/0\"){b.type.is_variable(Pe)?w.throw_error(b.error.instantiation(y.indicator)):w.throw_error(b.error.type(\"list\",Z,y.indicator));return}else{var ot=ie.alias;if(ot&&w.get_stream_by_alias(ot)){w.throw_error(b.error.permission(\"open\",\"source_sink\",new H(\"alias\",[new H(ot,[])]),y.indicator));return}ie.type||(ie.type=\"text\");var dt;if(b.type.is_atom(F)?dt=w.file_system_open(F.id,ie.type,J.id):dt=F.stream(ie.type,J.id),dt===!1){w.throw_error(b.error.permission(\"open\",\"source_sink\",F,y.indicator));return}else if(dt===null){w.throw_error(b.error.existence(\"source_sink\",F,y.indicator));return}var jt=new Te(dt,J.id,ie.alias,ie.type,ie.reposition===\"true\",ie.eof_action);ot?w.session.streams[ot]=jt:w.session.streams[jt.id]=jt,w.prepend([new be(S.goal.replace(new H(\"=\",[X,jt])),S.substitution,S)])}}},\"close/1\":function(w,S,y){var F=y.args[0];w.prepend([new be(S.goal.replace(new H(\"close\",[F,new H(\"[]\",[])])),S.substitution,S)])},\"close/2\":function(w,S,y){var F=y.args[0],J=y.args[1],X=b.type.is_stream(F)?F:w.get_stream_by_alias(F.id);if(b.type.is_variable(F)||b.type.is_variable(J))w.throw_error(b.error.instantiation(y.indicator));else if(!b.type.is_list(J))w.throw_error(b.error.type(\"list\",J,y.indicator));else if(!b.type.is_stream(F)&&!b.type.is_atom(F))w.throw_error(b.error.domain(\"stream_or_alias\",F,y.indicator));else if(!b.type.is_stream(X)||X.stream===null)w.throw_error(b.error.existence(\"stream\",F,y.indicator));else{for(var Z={},ie=J,Pe;b.type.is_term(ie)&&ie.indicator===\"./2\";){if(Pe=ie.args[0],b.type.is_variable(Pe)){w.throw_error(b.error.instantiation(y.indicator));return}else if(!b.type.is_close_option(Pe)){w.throw_error(b.error.domain(\"close_option\",Pe,y.indicator));return}Z[Pe.id]=Pe.args[0].id===\"true\",ie=ie.args[1]}if(ie.indicator!==\"[]/0\"){b.type.is_variable(ie)?w.throw_error(b.error.instantiation(y.indicator)):w.throw_error(b.error.type(\"list\",J,y.indicator));return}else{if(X===w.session.standard_input||X===w.session.standard_output){w.success(S);return}else X===w.session.current_input?w.session.current_input=w.session.standard_input:X===w.session.current_output&&(w.session.current_output=w.session.current_output);X.alias!==null?delete w.session.streams[X.alias]:delete w.session.streams[X.id],X.output&&X.stream.flush();var Ne=X.stream.close();X.stream=null,(Z.force===!0||Ne===!0)&&w.success(S)}}},\"flush_output/0\":function(w,S,y){w.prepend([new be(S.goal.replace(new H(\",\",[new H(\"current_output\",[new we(\"S\")]),new H(\"flush_output\",[new we(\"S\")])])),S.substitution,S)])},\"flush_output/1\":function(w,S,y){var F=y.args[0],J=b.type.is_stream(F)?F:w.get_stream_by_alias(F.id);b.type.is_variable(F)?w.throw_error(b.error.instantiation(y.indicator)):!b.type.is_stream(F)&&!b.type.is_atom(F)?w.throw_error(b.error.domain(\"stream_or_alias\",F,y.indicator)):!b.type.is_stream(J)||J.stream===null?w.throw_error(b.error.existence(\"stream\",F,y.indicator)):F.input===!0?w.throw_error(b.error.permission(\"output\",\"stream\",output,y.indicator)):(J.stream.flush(),w.success(S))},\"stream_property/2\":function(w,S,y){var F=y.args[0],J=y.args[1],X=b.type.is_stream(F)?F:w.get_stream_by_alias(F.id);if(!b.type.is_variable(F)&&!b.type.is_stream(F)&&!b.type.is_atom(F))w.throw_error(b.error.domain(\"stream_or_alias\",F,y.indicator));else if(!b.type.is_variable(F)&&(!b.type.is_stream(X)||X.stream===null))w.throw_error(b.error.existence(\"stream\",F,y.indicator));else if(!b.type.is_variable(J)&&!b.type.is_stream_property(J))w.throw_error(b.error.domain(\"stream_property\",J,y.indicator));else{var Z=[],ie=[];if(!b.type.is_variable(F))Z.push(X);else for(var Pe in w.session.streams)Z.push(w.session.streams[Pe]);for(var Ne=0;Ne<Z.length;Ne++){var ot=[];Z[Ne].filename&&ot.push(new H(\"file_name\",[new H(Z[Ne].file_name,[])])),ot.push(new H(\"mode\",[new H(Z[Ne].mode,[])])),ot.push(new H(Z[Ne].input?\"input\":\"output\",[])),Z[Ne].alias&&ot.push(new H(\"alias\",[new H(Z[Ne].alias,[])])),ot.push(new H(\"position\",[typeof Z[Ne].position==\"number\"?new xe(Z[Ne].position,!1):new H(Z[Ne].position,[])])),ot.push(new H(\"end_of_stream\",[new H(Z[Ne].position===\"end_of_stream\"?\"at\":Z[Ne].position===\"past_end_of_stream\"?\"past\":\"not\",[])])),ot.push(new H(\"eof_action\",[new H(Z[Ne].eof_action,[])])),ot.push(new H(\"reposition\",[new H(Z[Ne].reposition?\"true\":\"false\",[])])),ot.push(new H(\"type\",[new H(Z[Ne].type,[])]));for(var dt=0;dt<ot.length;dt++)ie.push(new be(S.goal.replace(new H(\",\",[new H(\"=\",[b.type.is_variable(F)?F:X,Z[Ne]]),new H(\"=\",[J,ot[dt]])])),S.substitution,S))}w.prepend(ie)}},\"at_end_of_stream/0\":function(w,S,y){w.prepend([new be(S.goal.replace(new H(\",\",[new H(\"current_input\",[new we(\"S\")]),new H(\",\",[new H(\"stream_property\",[new we(\"S\"),new H(\"end_of_stream\",[new we(\"E\")])]),new H(\",\",[new H(\"!\",[]),new H(\";\",[new H(\"=\",[new we(\"E\"),new H(\"at\",[])]),new H(\"=\",[new we(\"E\"),new H(\"past\",[])])])])])])),S.substitution,S)])},\"at_end_of_stream/1\":function(w,S,y){var F=y.args[0];w.prepend([new be(S.goal.replace(new H(\",\",[new H(\"stream_property\",[F,new H(\"end_of_stream\",[new we(\"E\")])]),new H(\",\",[new H(\"!\",[]),new H(\";\",[new H(\"=\",[new we(\"E\"),new H(\"at\",[])]),new H(\"=\",[new we(\"E\"),new H(\"past\",[])])])])])),S.substitution,S)])},\"set_stream_position/2\":function(w,S,y){var F=y.args[0],J=y.args[1],X=b.type.is_stream(F)?F:w.get_stream_by_alias(F.id);b.type.is_variable(F)||b.type.is_variable(J)?w.throw_error(b.error.instantiation(y.indicator)):!b.type.is_stream(F)&&!b.type.is_atom(F)?w.throw_error(b.error.domain(\"stream_or_alias\",F,y.indicator)):!b.type.is_stream(X)||X.stream===null?w.throw_error(b.error.existence(\"stream\",F,y.indicator)):b.type.is_stream_position(J)?X.reposition===!1?w.throw_error(b.error.permission(\"reposition\",\"stream\",F,y.indicator)):(b.type.is_integer(J)?X.position=J.value:X.position=J.id,w.success(S)):w.throw_error(b.error.domain(\"stream_position\",J,y.indicator))},\"get_char/1\":function(w,S,y){var F=y.args[0];w.prepend([new be(S.goal.replace(new H(\",\",[new H(\"current_input\",[new we(\"S\")]),new H(\"get_char\",[new we(\"S\"),F])])),S.substitution,S)])},\"get_char/2\":function(w,S,y){var F=y.args[0],J=y.args[1],X=b.type.is_stream(F)?F:w.get_stream_by_alias(F.id);if(b.type.is_variable(F))w.throw_error(b.error.instantiation(y.indicator));else if(!b.type.is_variable(J)&&!b.type.is_character(J))w.throw_error(b.error.type(\"in_character\",J,y.indicator));else if(!b.type.is_stream(F)&&!b.type.is_atom(F))w.throw_error(b.error.domain(\"stream_or_alias\",F,y.indicator));else if(!b.type.is_stream(X)||X.stream===null)w.throw_error(b.error.existence(\"stream\",F,y.indicator));else if(X.output)w.throw_error(b.error.permission(\"input\",\"stream\",F,y.indicator));else if(X.type===\"binary\")w.throw_error(b.error.permission(\"input\",\"binary_stream\",F,y.indicator));else if(X.position===\"past_end_of_stream\"&&X.eof_action===\"error\")w.throw_error(b.error.permission(\"input\",\"past_end_of_stream\",F,y.indicator));else{var Z;if(X.position===\"end_of_stream\")Z=\"end_of_file\",X.position=\"past_end_of_stream\";else{if(Z=X.stream.get(1,X.position),Z===null){w.throw_error(b.error.representation(\"character\",y.indicator));return}X.position++}w.prepend([new be(S.goal.replace(new H(\"=\",[new H(Z,[]),J])),S.substitution,S)])}},\"get_code/1\":function(w,S,y){var F=y.args[0];w.prepend([new be(S.goal.replace(new H(\",\",[new H(\"current_input\",[new we(\"S\")]),new H(\"get_code\",[new we(\"S\"),F])])),S.substitution,S)])},\"get_code/2\":function(w,S,y){var F=y.args[0],J=y.args[1],X=b.type.is_stream(F)?F:w.get_stream_by_alias(F.id);if(b.type.is_variable(F))w.throw_error(b.error.instantiation(y.indicator));else if(!b.type.is_variable(J)&&!b.type.is_integer(J))w.throw_error(b.error.type(\"integer\",char,y.indicator));else if(!b.type.is_variable(F)&&!b.type.is_stream(F)&&!b.type.is_atom(F))w.throw_error(b.error.domain(\"stream_or_alias\",F,y.indicator));else if(!b.type.is_stream(X)||X.stream===null)w.throw_error(b.error.existence(\"stream\",F,y.indicator));else if(X.output)w.throw_error(b.error.permission(\"input\",\"stream\",F,y.indicator));else if(X.type===\"binary\")w.throw_error(b.error.permission(\"input\",\"binary_stream\",F,y.indicator));else if(X.position===\"past_end_of_stream\"&&X.eof_action===\"error\")w.throw_error(b.error.permission(\"input\",\"past_end_of_stream\",F,y.indicator));else{var Z;if(X.position===\"end_of_stream\")Z=-1,X.position=\"past_end_of_stream\";else{if(Z=X.stream.get(1,X.position),Z===null){w.throw_error(b.error.representation(\"character\",y.indicator));return}Z=n(Z,0),X.position++}w.prepend([new be(S.goal.replace(new H(\"=\",[new xe(Z,!1),J])),S.substitution,S)])}},\"peek_char/1\":function(w,S,y){var F=y.args[0];w.prepend([new be(S.goal.replace(new H(\",\",[new H(\"current_input\",[new we(\"S\")]),new H(\"peek_char\",[new we(\"S\"),F])])),S.substitution,S)])},\"peek_char/2\":function(w,S,y){var F=y.args[0],J=y.args[1],X=b.type.is_stream(F)?F:w.get_stream_by_alias(F.id);if(b.type.is_variable(F))w.throw_error(b.error.instantiation(y.indicator));else if(!b.type.is_variable(J)&&!b.type.is_character(J))w.throw_error(b.error.type(\"in_character\",J,y.indicator));else if(!b.type.is_stream(F)&&!b.type.is_atom(F))w.throw_error(b.error.domain(\"stream_or_alias\",F,y.indicator));else if(!b.type.is_stream(X)||X.stream===null)w.throw_error(b.error.existence(\"stream\",F,y.indicator));else if(X.output)w.throw_error(b.error.permission(\"input\",\"stream\",F,y.indicator));else if(X.type===\"binary\")w.throw_error(b.error.permission(\"input\",\"binary_stream\",F,y.indicator));else if(X.position===\"past_end_of_stream\"&&X.eof_action===\"error\")w.throw_error(b.error.permission(\"input\",\"past_end_of_stream\",F,y.indicator));else{var Z;if(X.position===\"end_of_stream\")Z=\"end_of_file\",X.position=\"past_end_of_stream\";else if(Z=X.stream.get(1,X.position),Z===null){w.throw_error(b.error.representation(\"character\",y.indicator));return}w.prepend([new be(S.goal.replace(new H(\"=\",[new H(Z,[]),J])),S.substitution,S)])}},\"peek_code/1\":function(w,S,y){var F=y.args[0];w.prepend([new be(S.goal.replace(new H(\",\",[new H(\"current_input\",[new we(\"S\")]),new H(\"peek_code\",[new we(\"S\"),F])])),S.substitution,S)])},\"peek_code/2\":function(w,S,y){var F=y.args[0],J=y.args[1],X=b.type.is_stream(F)?F:w.get_stream_by_alias(F.id);if(b.type.is_variable(F))w.throw_error(b.error.instantiation(y.indicator));else if(!b.type.is_variable(J)&&!b.type.is_integer(J))w.throw_error(b.error.type(\"integer\",char,y.indicator));else if(!b.type.is_variable(F)&&!b.type.is_stream(F)&&!b.type.is_atom(F))w.throw_error(b.error.domain(\"stream_or_alias\",F,y.indicator));else if(!b.type.is_stream(X)||X.stream===null)w.throw_error(b.error.existence(\"stream\",F,y.indicator));else if(X.output)w.throw_error(b.error.permission(\"input\",\"stream\",F,y.indicator));else if(X.type===\"binary\")w.throw_error(b.error.permission(\"input\",\"binary_stream\",F,y.indicator));else if(X.position===\"past_end_of_stream\"&&X.eof_action===\"error\")w.throw_error(b.error.permission(\"input\",\"past_end_of_stream\",F,y.indicator));else{var Z;if(X.position===\"end_of_stream\")Z=-1,X.position=\"past_end_of_stream\";else{if(Z=X.stream.get(1,X.position),Z===null){w.throw_error(b.error.representation(\"character\",y.indicator));return}Z=n(Z,0)}w.prepend([new be(S.goal.replace(new H(\"=\",[new xe(Z,!1),J])),S.substitution,S)])}},\"put_char/1\":function(w,S,y){var F=y.args[0];w.prepend([new be(S.goal.replace(new H(\",\",[new H(\"current_output\",[new we(\"S\")]),new H(\"put_char\",[new we(\"S\"),F])])),S.substitution,S)])},\"put_char/2\":function(w,S,y){var F=y.args[0],J=y.args[1],X=b.type.is_stream(F)?F:w.get_stream_by_alias(F.id);b.type.is_variable(F)||b.type.is_variable(J)?w.throw_error(b.error.instantiation(y.indicator)):b.type.is_character(J)?!b.type.is_variable(F)&&!b.type.is_stream(F)&&!b.type.is_atom(F)?w.throw_error(b.error.domain(\"stream_or_alias\",F,y.indicator)):!b.type.is_stream(X)||X.stream===null?w.throw_error(b.error.existence(\"stream\",F,y.indicator)):X.input?w.throw_error(b.error.permission(\"output\",\"stream\",F,y.indicator)):X.type===\"binary\"?w.throw_error(b.error.permission(\"output\",\"binary_stream\",F,y.indicator)):X.stream.put(J.id,X.position)&&(typeof X.position==\"number\"&&X.position++,w.success(S)):w.throw_error(b.error.type(\"character\",J,y.indicator))},\"put_code/1\":function(w,S,y){var F=y.args[0];w.prepend([new be(S.goal.replace(new H(\",\",[new H(\"current_output\",[new we(\"S\")]),new H(\"put_code\",[new we(\"S\"),F])])),S.substitution,S)])},\"put_code/2\":function(w,S,y){var F=y.args[0],J=y.args[1],X=b.type.is_stream(F)?F:w.get_stream_by_alias(F.id);b.type.is_variable(F)||b.type.is_variable(J)?w.throw_error(b.error.instantiation(y.indicator)):b.type.is_integer(J)?b.type.is_character_code(J)?!b.type.is_variable(F)&&!b.type.is_stream(F)&&!b.type.is_atom(F)?w.throw_error(b.error.domain(\"stream_or_alias\",F,y.indicator)):!b.type.is_stream(X)||X.stream===null?w.throw_error(b.error.existence(\"stream\",F,y.indicator)):X.input?w.throw_error(b.error.permission(\"output\",\"stream\",F,y.indicator)):X.type===\"binary\"?w.throw_error(b.error.permission(\"output\",\"binary_stream\",F,y.indicator)):X.stream.put_char(u(J.value),X.position)&&(typeof X.position==\"number\"&&X.position++,w.success(S)):w.throw_error(b.error.representation(\"character_code\",y.indicator)):w.throw_error(b.error.type(\"integer\",J,y.indicator))},\"nl/0\":function(w,S,y){w.prepend([new be(S.goal.replace(new H(\",\",[new H(\"current_output\",[new we(\"S\")]),new H(\"put_char\",[new we(\"S\"),new H(`\n`,[])])])),S.substitution,S)])},\"nl/1\":function(w,S,y){var F=y.args[0];w.prepend([new be(S.goal.replace(new H(\"put_char\",[F,new H(`\n`,[])])),S.substitution,S)])},\"get_byte/1\":function(w,S,y){var F=y.args[0];w.prepend([new be(S.goal.replace(new H(\",\",[new H(\"current_input\",[new we(\"S\")]),new H(\"get_byte\",[new we(\"S\"),F])])),S.substitution,S)])},\"get_byte/2\":function(w,S,y){var F=y.args[0],J=y.args[1],X=b.type.is_stream(F)?F:w.get_stream_by_alias(F.id);if(b.type.is_variable(F))w.throw_error(b.error.instantiation(y.indicator));else if(!b.type.is_variable(J)&&!b.type.is_byte(J))w.throw_error(b.error.type(\"in_byte\",char,y.indicator));else if(!b.type.is_stream(F)&&!b.type.is_atom(F))w.throw_error(b.error.domain(\"stream_or_alias\",F,y.indicator));else if(!b.type.is_stream(X)||X.stream===null)w.throw_error(b.error.existence(\"stream\",F,y.indicator));else if(X.output)w.throw_error(b.error.permission(\"input\",\"stream\",F,y.indicator));else if(X.type===\"text\")w.throw_error(b.error.permission(\"input\",\"text_stream\",F,y.indicator));else if(X.position===\"past_end_of_stream\"&&X.eof_action===\"error\")w.throw_error(b.error.permission(\"input\",\"past_end_of_stream\",F,y.indicator));else{var Z;if(X.position===\"end_of_stream\")Z=\"end_of_file\",X.position=\"past_end_of_stream\";else{if(Z=X.stream.get_byte(X.position),Z===null){w.throw_error(b.error.representation(\"byte\",y.indicator));return}X.position++}w.prepend([new be(S.goal.replace(new H(\"=\",[new xe(Z,!1),J])),S.substitution,S)])}},\"peek_byte/1\":function(w,S,y){var F=y.args[0];w.prepend([new be(S.goal.replace(new H(\",\",[new H(\"current_input\",[new we(\"S\")]),new H(\"peek_byte\",[new we(\"S\"),F])])),S.substitution,S)])},\"peek_byte/2\":function(w,S,y){var F=y.args[0],J=y.args[1],X=b.type.is_stream(F)?F:w.get_stream_by_alias(F.id);if(b.type.is_variable(F))w.throw_error(b.error.instantiation(y.indicator));else if(!b.type.is_variable(J)&&!b.type.is_byte(J))w.throw_error(b.error.type(\"in_byte\",char,y.indicator));else if(!b.type.is_stream(F)&&!b.type.is_atom(F))w.throw_error(b.error.domain(\"stream_or_alias\",F,y.indicator));else if(!b.type.is_stream(X)||X.stream===null)w.throw_error(b.error.existence(\"stream\",F,y.indicator));else if(X.output)w.throw_error(b.error.permission(\"input\",\"stream\",F,y.indicator));else if(X.type===\"text\")w.throw_error(b.error.permission(\"input\",\"text_stream\",F,y.indicator));else if(X.position===\"past_end_of_stream\"&&X.eof_action===\"error\")w.throw_error(b.error.permission(\"input\",\"past_end_of_stream\",F,y.indicator));else{var Z;if(X.position===\"end_of_stream\")Z=\"end_of_file\",X.position=\"past_end_of_stream\";else if(Z=X.stream.get_byte(X.position),Z===null){w.throw_error(b.error.representation(\"byte\",y.indicator));return}w.prepend([new be(S.goal.replace(new H(\"=\",[new xe(Z,!1),J])),S.substitution,S)])}},\"put_byte/1\":function(w,S,y){var F=y.args[0];w.prepend([new be(S.goal.replace(new H(\",\",[new H(\"current_output\",[new we(\"S\")]),new H(\"put_byte\",[new we(\"S\"),F])])),S.substitution,S)])},\"put_byte/2\":function(w,S,y){var F=y.args[0],J=y.args[1],X=b.type.is_stream(F)?F:w.get_stream_by_alias(F.id);b.type.is_variable(F)||b.type.is_variable(J)?w.throw_error(b.error.instantiation(y.indicator)):b.type.is_byte(J)?!b.type.is_variable(F)&&!b.type.is_stream(F)&&!b.type.is_atom(F)?w.throw_error(b.error.domain(\"stream_or_alias\",F,y.indicator)):!b.type.is_stream(X)||X.stream===null?w.throw_error(b.error.existence(\"stream\",F,y.indicator)):X.input?w.throw_error(b.error.permission(\"output\",\"stream\",F,y.indicator)):X.type===\"text\"?w.throw_error(b.error.permission(\"output\",\"text_stream\",F,y.indicator)):X.stream.put_byte(J.value,X.position)&&(typeof X.position==\"number\"&&X.position++,w.success(S)):w.throw_error(b.error.type(\"byte\",J,y.indicator))},\"read/1\":function(w,S,y){var F=y.args[0];w.prepend([new be(S.goal.replace(new H(\",\",[new H(\"current_input\",[new we(\"S\")]),new H(\"read_term\",[new we(\"S\"),F,new H(\"[]\",[])])])),S.substitution,S)])},\"read/2\":function(w,S,y){var F=y.args[0],J=y.args[1];w.prepend([new be(S.goal.replace(new H(\"read_term\",[F,J,new H(\"[]\",[])])),S.substitution,S)])},\"read_term/2\":function(w,S,y){var F=y.args[0],J=y.args[1];w.prepend([new be(S.goal.replace(new H(\",\",[new H(\"current_input\",[new we(\"S\")]),new H(\"read_term\",[new we(\"S\"),F,J])])),S.substitution,S)])},\"read_term/3\":function(w,S,y){var F=y.args[0],J=y.args[1],X=y.args[2],Z=b.type.is_stream(F)?F:w.get_stream_by_alias(F.id);if(b.type.is_variable(F)||b.type.is_variable(X))w.throw_error(b.error.instantiation(y.indicator));else if(!b.type.is_list(X))w.throw_error(b.error.type(\"list\",X,y.indicator));else if(!b.type.is_stream(F)&&!b.type.is_atom(F))w.throw_error(b.error.domain(\"stream_or_alias\",F,y.indicator));else if(!b.type.is_stream(Z)||Z.stream===null)w.throw_error(b.error.existence(\"stream\",F,y.indicator));else if(Z.output)w.throw_error(b.error.permission(\"input\",\"stream\",F,y.indicator));else if(Z.type===\"binary\")w.throw_error(b.error.permission(\"input\",\"binary_stream\",F,y.indicator));else if(Z.position===\"past_end_of_stream\"&&Z.eof_action===\"error\")w.throw_error(b.error.permission(\"input\",\"past_end_of_stream\",F,y.indicator));else{for(var ie={},Pe=X,Ne;b.type.is_term(Pe)&&Pe.indicator===\"./2\";){if(Ne=Pe.args[0],b.type.is_variable(Ne)){w.throw_error(b.error.instantiation(y.indicator));return}else if(!b.type.is_read_option(Ne)){w.throw_error(b.error.domain(\"read_option\",Ne,y.indicator));return}ie[Ne.id]=Ne.args[0],Pe=Pe.args[1]}if(Pe.indicator!==\"[]/0\"){b.type.is_variable(Pe)?w.throw_error(b.error.instantiation(y.indicator)):w.throw_error(b.error.type(\"list\",X,y.indicator));return}else{for(var ot,dt,jt,$t=\"\",bt=[],an=null;an===null||an.name!==\"atom\"||an.value!==\".\"||jt.type===A&&b.flatten_error(new H(\"throw\",[jt.value])).found===\"token_not_found\";){if(ot=Z.stream.get(1,Z.position),ot===null){w.throw_error(b.error.representation(\"character\",y.indicator));return}if(ot===\"end_of_file\"||ot===\"past_end_of_file\"){jt?w.throw_error(b.error.syntax(bt[jt.len-1],\". or expression expected\",!1)):w.throw_error(b.error.syntax(null,\"token not found\",!0));return}Z.position++,$t+=ot,dt=new U(w),dt.new_text($t),bt=dt.get_tokens(),an=bt!==null&&bt.length>0?bt[bt.length-1]:null,bt!==null&&(jt=z(w,bt,0,w.__get_max_priority(),!1))}if(jt.type===p&&jt.len===bt.length-1&&an.value===\".\"){jt=jt.value.rename(w);var Qr=new H(\"=\",[J,jt]);if(ie.variables){var mr=g(o(De(jt.variables()),function(br){return new we(br)}));Qr=new H(\",\",[Qr,new H(\"=\",[ie.variables,mr])])}if(ie.variable_names){var mr=g(o(De(jt.variables()),function(Wr){var Kn;for(Kn in w.session.renamed_variables)if(w.session.renamed_variables.hasOwnProperty(Kn)&&w.session.renamed_variables[Kn]===Wr)break;return new H(\"=\",[new H(Kn,[]),new we(Wr)])}));Qr=new H(\",\",[Qr,new H(\"=\",[ie.variable_names,mr])])}if(ie.singletons){var mr=g(o(new _e(jt,null).singleton_variables(),function(Wr){var Kn;for(Kn in w.session.renamed_variables)if(w.session.renamed_variables.hasOwnProperty(Kn)&&w.session.renamed_variables[Kn]===Wr)break;return new H(\"=\",[new H(Kn,[]),new we(Wr)])}));Qr=new H(\",\",[Qr,new H(\"=\",[ie.singletons,mr])])}w.prepend([new be(S.goal.replace(Qr),S.substitution,S)])}else jt.type===p?w.throw_error(b.error.syntax(bt[jt.len],\"unexpected token\",!1)):w.throw_error(jt.value)}}},\"write/1\":function(w,S,y){var F=y.args[0];w.prepend([new be(S.goal.replace(new H(\",\",[new H(\"current_output\",[new we(\"S\")]),new H(\"write\",[new we(\"S\"),F])])),S.substitution,S)])},\"write/2\":function(w,S,y){var F=y.args[0],J=y.args[1];w.prepend([new be(S.goal.replace(new H(\"write_term\",[F,J,new H(\".\",[new H(\"quoted\",[new H(\"false\",[])]),new H(\".\",[new H(\"ignore_ops\",[new H(\"false\")]),new H(\".\",[new H(\"numbervars\",[new H(\"true\")]),new H(\"[]\",[])])])])])),S.substitution,S)])},\"writeq/1\":function(w,S,y){var F=y.args[0];w.prepend([new be(S.goal.replace(new H(\",\",[new H(\"current_output\",[new we(\"S\")]),new H(\"writeq\",[new we(\"S\"),F])])),S.substitution,S)])},\"writeq/2\":function(w,S,y){var F=y.args[0],J=y.args[1];w.prepend([new be(S.goal.replace(new H(\"write_term\",[F,J,new H(\".\",[new H(\"quoted\",[new H(\"true\",[])]),new H(\".\",[new H(\"ignore_ops\",[new H(\"false\")]),new H(\".\",[new H(\"numbervars\",[new H(\"true\")]),new H(\"[]\",[])])])])])),S.substitution,S)])},\"write_canonical/1\":function(w,S,y){var F=y.args[0];w.prepend([new be(S.goal.replace(new H(\",\",[new H(\"current_output\",[new we(\"S\")]),new H(\"write_canonical\",[new we(\"S\"),F])])),S.substitution,S)])},\"write_canonical/2\":function(w,S,y){var F=y.args[0],J=y.args[1];w.prepend([new be(S.goal.replace(new H(\"write_term\",[F,J,new H(\".\",[new H(\"quoted\",[new H(\"true\",[])]),new H(\".\",[new H(\"ignore_ops\",[new H(\"true\")]),new H(\".\",[new H(\"numbervars\",[new H(\"false\")]),new H(\"[]\",[])])])])])),S.substitution,S)])},\"write_term/2\":function(w,S,y){var F=y.args[0],J=y.args[1];w.prepend([new be(S.goal.replace(new H(\",\",[new H(\"current_output\",[new we(\"S\")]),new H(\"write_term\",[new we(\"S\"),F,J])])),S.substitution,S)])},\"write_term/3\":function(w,S,y){var F=y.args[0],J=y.args[1],X=y.args[2],Z=b.type.is_stream(F)?F:w.get_stream_by_alias(F.id);if(b.type.is_variable(F)||b.type.is_variable(X))w.throw_error(b.error.instantiation(y.indicator));else if(!b.type.is_list(X))w.throw_error(b.error.type(\"list\",X,y.indicator));else if(!b.type.is_stream(F)&&!b.type.is_atom(F))w.throw_error(b.error.domain(\"stream_or_alias\",F,y.indicator));else if(!b.type.is_stream(Z)||Z.stream===null)w.throw_error(b.error.existence(\"stream\",F,y.indicator));else if(Z.input)w.throw_error(b.error.permission(\"output\",\"stream\",F,y.indicator));else if(Z.type===\"binary\")w.throw_error(b.error.permission(\"output\",\"binary_stream\",F,y.indicator));else if(Z.position===\"past_end_of_stream\"&&Z.eof_action===\"error\")w.throw_error(b.error.permission(\"output\",\"past_end_of_stream\",F,y.indicator));else{for(var ie={},Pe=X,Ne;b.type.is_term(Pe)&&Pe.indicator===\"./2\";){if(Ne=Pe.args[0],b.type.is_variable(Ne)){w.throw_error(b.error.instantiation(y.indicator));return}else if(!b.type.is_write_option(Ne)){w.throw_error(b.error.domain(\"write_option\",Ne,y.indicator));return}ie[Ne.id]=Ne.args[0].id===\"true\",Pe=Pe.args[1]}if(Pe.indicator!==\"[]/0\"){b.type.is_variable(Pe)?w.throw_error(b.error.instantiation(y.indicator)):w.throw_error(b.error.type(\"list\",X,y.indicator));return}else{ie.session=w.session;var ot=J.toString(ie);Z.stream.put(ot,Z.position),typeof Z.position==\"number\"&&(Z.position+=ot.length),w.success(S)}}},\"halt/0\":function(w,S,y){w.points=[]},\"halt/1\":function(w,S,y){var F=y.args[0];b.type.is_variable(F)?w.throw_error(b.error.instantiation(y.indicator)):b.type.is_integer(F)?w.points=[]:w.throw_error(b.error.type(\"integer\",F,y.indicator))},\"current_prolog_flag/2\":function(w,S,y){var F=y.args[0],J=y.args[1];if(!b.type.is_variable(F)&&!b.type.is_atom(F))w.throw_error(b.error.type(\"atom\",F,y.indicator));else if(!b.type.is_variable(F)&&!b.type.is_flag(F))w.throw_error(b.error.domain(\"prolog_flag\",F,y.indicator));else{var X=[];for(var Z in b.flag)if(!!b.flag.hasOwnProperty(Z)){var ie=new H(\",\",[new H(\"=\",[new H(Z),F]),new H(\"=\",[w.get_flag(Z),J])]);X.push(new be(S.goal.replace(ie),S.substitution,S))}w.prepend(X)}},\"set_prolog_flag/2\":function(w,S,y){var F=y.args[0],J=y.args[1];b.type.is_variable(F)||b.type.is_variable(J)?w.throw_error(b.error.instantiation(y.indicator)):b.type.is_atom(F)?b.type.is_flag(F)?b.type.is_value_flag(F,J)?b.type.is_modifiable_flag(F)?(w.session.flag[F.id]=J,w.success(S)):w.throw_error(b.error.permission(\"modify\",\"flag\",F)):w.throw_error(b.error.domain(\"flag_value\",new H(\"+\",[F,J]),y.indicator)):w.throw_error(b.error.domain(\"prolog_flag\",F,y.indicator)):w.throw_error(b.error.type(\"atom\",F,y.indicator))}},flag:{bounded:{allowed:[new H(\"true\"),new H(\"false\")],value:new H(\"true\"),changeable:!1},max_integer:{allowed:[new xe(Number.MAX_SAFE_INTEGER)],value:new xe(Number.MAX_SAFE_INTEGER),changeable:!1},min_integer:{allowed:[new xe(Number.MIN_SAFE_INTEGER)],value:new xe(Number.MIN_SAFE_INTEGER),changeable:!1},integer_rounding_function:{allowed:[new H(\"down\"),new H(\"toward_zero\")],value:new H(\"toward_zero\"),changeable:!1},char_conversion:{allowed:[new H(\"on\"),new H(\"off\")],value:new H(\"on\"),changeable:!0},debug:{allowed:[new H(\"on\"),new H(\"off\")],value:new H(\"off\"),changeable:!0},max_arity:{allowed:[new H(\"unbounded\")],value:new H(\"unbounded\"),changeable:!1},unknown:{allowed:[new H(\"error\"),new H(\"fail\"),new H(\"warning\")],value:new H(\"error\"),changeable:!0},double_quotes:{allowed:[new H(\"chars\"),new H(\"codes\"),new H(\"atom\")],value:new H(\"codes\"),changeable:!0},occurs_check:{allowed:[new H(\"false\"),new H(\"true\")],value:new H(\"false\"),changeable:!0},dialect:{allowed:[new H(\"tau\")],value:new H(\"tau\"),changeable:!1},version_data:{allowed:[new H(\"tau\",[new xe(t.major,!1),new xe(t.minor,!1),new xe(t.patch,!1),new H(t.status)])],value:new H(\"tau\",[new xe(t.major,!1),new xe(t.minor,!1),new xe(t.patch,!1),new H(t.status)]),changeable:!1},nodejs:{allowed:[new H(\"yes\"),new H(\"no\")],value:new H(typeof hl<\"u\"&&hl.exports?\"yes\":\"no\"),changeable:!1}},unify:function(w,S,y){y=y===void 0?!1:y;for(var F=[{left:w,right:S}],J={};F.length!==0;){var X=F.pop();if(w=X.left,S=X.right,b.type.is_term(w)&&b.type.is_term(S)){if(w.indicator!==S.indicator)return null;for(var Z=0;Z<w.args.length;Z++)F.push({left:w.args[Z],right:S.args[Z]})}else if(b.type.is_number(w)&&b.type.is_number(S)){if(w.value!==S.value||w.is_float!==S.is_float)return null}else if(b.type.is_variable(w)){if(b.type.is_variable(S)&&w.id===S.id)continue;if(y===!0&&S.variables().indexOf(w.id)!==-1)return null;if(w.id!==\"_\"){var ie=new ke;ie.add(w.id,S);for(var Z=0;Z<F.length;Z++)F[Z].left=F[Z].left.apply(ie),F[Z].right=F[Z].right.apply(ie);for(var Z in J)J[Z]=J[Z].apply(ie);J[w.id]=S}}else if(b.type.is_variable(S))F.push({left:S,right:w});else if(w.unify!==void 0){if(!w.unify(S))return null}else return null}return new ke(J)},compare:function(w,S){var y=b.type.compare(w,S);return y!==0?y:w.compare(S)},arithmetic_compare:function(w,S,y){var F=S.interpret(w);if(b.type.is_number(F)){var J=y.interpret(w);return b.type.is_number(J)?F.value<J.value?-1:F.value>J.value?1:0:J}else return F},operate:function(w,S){if(b.type.is_operator(S)){for(var y=b.type.is_operator(S),F=[],J,X=!1,Z=0;Z<S.args.length;Z++){if(J=S.args[Z].interpret(w),b.type.is_number(J)){if(y.type_args!==null&&J.is_float!==y.type_args)return b.error.type(y.type_args?\"float\":\"integer\",J,w.__call_indicator);F.push(J.value)}else return J;X=X||J.is_float}return F.push(w),J=b.arithmetic.evaluation[S.indicator].fn.apply(this,F),X=y.type_result===null?X:y.type_result,b.type.is_term(J)?J:J===Number.POSITIVE_INFINITY||J===Number.NEGATIVE_INFINITY?b.error.evaluation(\"overflow\",w.__call_indicator):X===!1&&w.get_flag(\"bounded\").id===\"true\"&&(J>w.get_flag(\"max_integer\").value||J<w.get_flag(\"min_integer\").value)?b.error.evaluation(\"int_overflow\",w.__call_indicator):new xe(J,X)}else return b.error.type(\"evaluable\",S.indicator,w.__call_indicator)},error:{existence:function(w,S,y){return typeof S==\"string\"&&(S=ee(S)),new H(\"error\",[new H(\"existence_error\",[new H(w),S]),ee(y)])},type:function(w,S,y){return new H(\"error\",[new H(\"type_error\",[new H(w),S]),ee(y)])},instantiation:function(w){return new H(\"error\",[new H(\"instantiation_error\"),ee(w)])},domain:function(w,S,y){return new H(\"error\",[new H(\"domain_error\",[new H(w),S]),ee(y)])},representation:function(w,S){return new H(\"error\",[new H(\"representation_error\",[new H(w)]),ee(S)])},permission:function(w,S,y,F){return new H(\"error\",[new H(\"permission_error\",[new H(w),new H(S),y]),ee(F)])},evaluation:function(w,S){return new H(\"error\",[new H(\"evaluation_error\",[new H(w)]),ee(S)])},syntax:function(w,S,y){w=w||{value:\"\",line:0,column:0,matches:[\"\"],start:0};var F=y&&w.matches.length>0?w.start+w.matches[0].length:w.start,J=y?new H(\"token_not_found\"):new H(\"found\",[new H(w.value.toString())]),X=new H(\".\",[new H(\"line\",[new xe(w.line+1)]),new H(\".\",[new H(\"column\",[new xe(F+1)]),new H(\".\",[J,new H(\"[]\",[])])])]);return new H(\"error\",[new H(\"syntax_error\",[new H(S)]),X])},syntax_by_predicate:function(w,S){return new H(\"error\",[new H(\"syntax_error\",[new H(w)]),ee(S)])}},warning:{singleton:function(w,S,y){for(var F=new H(\"[]\"),J=w.length-1;J>=0;J--)F=new H(\".\",[new we(w[J]),F]);return new H(\"warning\",[new H(\"singleton_variables\",[F,ee(S)]),new H(\".\",[new H(\"line\",[new xe(y,!1)]),new H(\"[]\")])])},failed_goal:function(w,S){return new H(\"warning\",[new H(\"failed_goal\",[w]),new H(\".\",[new H(\"line\",[new xe(S,!1)]),new H(\"[]\")])])}},format_variable:function(w){return\"_\"+w},format_answer:function(w,S,F){S instanceof Re&&(S=S.thread);var F=F||{};if(F.session=S?S.session:void 0,b.type.is_error(w))return\"uncaught exception: \"+w.args[0].toString();if(w===!1)return\"false.\";if(w===null)return\"limit exceeded ;\";var J=0,X=\"\";if(b.type.is_substitution(w)){var Z=w.domain(!0);w=w.filter(function(Ne,ot){return!b.type.is_variable(ot)||Z.indexOf(ot.id)!==-1&&Ne!==ot.id})}for(var ie in w.links)!w.links.hasOwnProperty(ie)||(J++,X!==\"\"&&(X+=\", \"),X+=ie.toString(F)+\" = \"+w.links[ie].toString(F));var Pe=typeof S>\"u\"||S.points.length>0?\" ;\":\".\";return J===0?\"true\"+Pe:X+Pe},flatten_error:function(w){if(!b.type.is_error(w))return null;w=w.args[0];var S={};return S.type=w.args[0].id,S.thrown=S.type===\"syntax_error\"?null:w.args[1].id,S.expected=null,S.found=null,S.representation=null,S.existence=null,S.existence_type=null,S.line=null,S.column=null,S.permission_operation=null,S.permission_type=null,S.evaluation_type=null,S.type===\"type_error\"||S.type===\"domain_error\"?(S.expected=w.args[0].args[0].id,S.found=w.args[0].args[1].toString()):S.type===\"syntax_error\"?w.args[1].indicator===\"./2\"?(S.expected=w.args[0].args[0].id,S.found=w.args[1].args[1].args[1].args[0],S.found=S.found.id===\"token_not_found\"?S.found.id:S.found.args[0].id,S.line=w.args[1].args[0].args[0].value,S.column=w.args[1].args[1].args[0].args[0].value):S.thrown=w.args[1].id:S.type===\"permission_error\"?(S.found=w.args[0].args[2].toString(),S.permission_operation=w.args[0].args[0].id,S.permission_type=w.args[0].args[1].id):S.type===\"evaluation_error\"?S.evaluation_type=w.args[0].args[0].id:S.type===\"representation_error\"?S.representation=w.args[0].args[0].id:S.type===\"existence_error\"&&(S.existence=w.args[0].args[1].toString(),S.existence_type=w.args[0].args[0].id),S},create:function(w){return new b.type.Session(w)}};typeof hl<\"u\"?hl.exports=b:window.pl=b})()});function lme(t,e,r){t.prepend(r.map(o=>new Ta.default.type.State(e.goal.replace(o),e.substitution,e)))}function CH(t){let e=ume.get(t.session);if(e==null)throw new Error(\"Assertion failed: A project should have been registered for the active session\");return e}function Ame(t,e){ume.set(t,e),t.consult(`:- use_module(library(${$gt.id})).`)}var wH,Ta,cme,c0,Xgt,Zgt,ume,$gt,fme=Et(()=>{Ye();wH=$e(h2()),Ta=$e(EH()),cme=$e(Be(\"vm\")),{is_atom:c0,is_variable:Xgt,is_instantiated_list:Zgt}=Ta.default.type;ume=new WeakMap;$gt=new Ta.default.type.Module(\"constraints\",{[\"project_workspaces_by_descriptor/3\"]:(t,e,r)=>{let[o,a,n]=r.args;if(!c0(o)||!c0(a)){t.throw_error(Ta.default.error.instantiation(r.indicator));return}let u=W.parseIdent(o.id),A=W.makeDescriptor(u,a.id),h=CH(t).tryWorkspaceByDescriptor(A);Xgt(n)&&h!==null&&lme(t,e,[new Ta.default.type.Term(\"=\",[n,new Ta.default.type.Term(String(h.relativeCwd))])]),c0(n)&&h!==null&&h.relativeCwd===n.id&&t.success(e)},[\"workspace_field/3\"]:(t,e,r)=>{let[o,a,n]=r.args;if(!c0(o)||!c0(a)){t.throw_error(Ta.default.error.instantiation(r.indicator));return}let A=CH(t).tryWorkspaceByCwd(o.id);if(A==null)return;let p=(0,wH.default)(A.manifest.raw,a.id);typeof p>\"u\"||lme(t,e,[new Ta.default.type.Term(\"=\",[n,new Ta.default.type.Term(typeof p==\"object\"?JSON.stringify(p):p)])])},[\"workspace_field_test/3\"]:(t,e,r)=>{let[o,a,n]=r.args;t.prepend([new Ta.default.type.State(e.goal.replace(new Ta.default.type.Term(\"workspace_field_test\",[o,a,n,new Ta.default.type.Term(\"[]\",[])])),e.substitution,e)])},[\"workspace_field_test/4\"]:(t,e,r)=>{let[o,a,n,u]=r.args;if(!c0(o)||!c0(a)||!c0(n)||!Zgt(u)){t.throw_error(Ta.default.error.instantiation(r.indicator));return}let p=CH(t).tryWorkspaceByCwd(o.id);if(p==null)return;let h=(0,wH.default)(p.manifest.raw,a.id);if(typeof h>\"u\")return;let C={$$:h};for(let[v,x]of u.toJavaScript().entries())C[`$${v}`]=x;cme.default.runInNewContext(n.id,C)&&t.success(e)}},[\"project_workspaces_by_descriptor/3\",\"workspace_field/3\",\"workspace_field_test/3\",\"workspace_field_test/4\"])});var P2={};Vt(P2,{Constraints:()=>D2,DependencyType:()=>dme});function to(t){if(t instanceof BC.default.type.Num)return t.value;if(t instanceof BC.default.type.Term)switch(t.indicator){case\"throw/1\":return to(t.args[0]);case\"error/1\":return to(t.args[0]);case\"error/2\":if(t.args[0]instanceof BC.default.type.Term&&t.args[0].indicator===\"syntax_error/1\")return Object.assign(to(t.args[0]),...to(t.args[1]));{let e=to(t.args[0]);return e.message+=` (in ${to(t.args[1])})`,e}case\"syntax_error/1\":return new Jt(43,`Syntax error: ${to(t.args[0])}`);case\"existence_error/2\":return new Jt(44,`Existence error: ${to(t.args[0])} ${to(t.args[1])} not found`);case\"instantiation_error/0\":return new Jt(75,\"Instantiation error: an argument is variable when an instantiated argument was expected\");case\"line/1\":return{line:to(t.args[0])};case\"column/1\":return{column:to(t.args[0])};case\"found/1\":return{found:to(t.args[0])};case\"./2\":return[to(t.args[0])].concat(to(t.args[1]));case\"//2\":return`${to(t.args[0])}/${to(t.args[1])}`;default:return t.id}throw`couldn't pretty print because of unsupported node ${t}`}function hme(t){let e;try{e=to(t)}catch(r){throw typeof r==\"string\"?new Jt(42,`Unknown error: ${t} (note: ${r})`):r}return typeof e.line<\"u\"&&typeof e.column<\"u\"&&(e.message+=` at line ${e.line}, column ${e.column}`),e}function Zd(t){return t.id===\"null\"?null:`${t.toJavaScript()}`}function edt(t){if(t.id===\"null\")return null;{let e=t.toJavaScript();if(typeof e!=\"string\")return JSON.stringify(e);try{return JSON.stringify(JSON.parse(e))}catch{return JSON.stringify(e)}}}function u0(t){return typeof t==\"string\"?`'${t}'`:\"[]\"}var gme,BC,dme,pme,IH,D2,S2=Et(()=>{Ye();Ye();Pt();gme=$e(Wde()),BC=$e(EH());I2();fme();(0,gme.default)(BC.default);dme=(o=>(o.Dependencies=\"dependencies\",o.DevDependencies=\"devDependencies\",o.PeerDependencies=\"peerDependencies\",o))(dme||{}),pme=[\"dependencies\",\"devDependencies\",\"peerDependencies\"];IH=class{constructor(e,r){let o=1e3*e.workspaces.length;this.session=BC.default.create(o),Ame(this.session,e),this.session.consult(\":- use_module(library(lists)).\"),this.session.consult(r)}fetchNextAnswer(){return new Promise(e=>{this.session.answer(r=>{e(r)})})}async*makeQuery(e){let r=this.session.query(e);if(r!==!0)throw hme(r);for(;;){let o=await this.fetchNextAnswer();if(o===null)throw new Jt(79,\"Resolution limit exceeded\");if(!o)break;if(o.id===\"throw\")throw hme(o);yield o}}};D2=class{constructor(e){this.source=\"\";this.project=e;let r=e.configuration.get(\"constraintsPath\");oe.existsSync(r)&&(this.source=oe.readFileSync(r,\"utf8\"))}static async find(e){return new D2(e)}getProjectDatabase(){let e=\"\";for(let r of pme)e+=`dependency_type(${r}).\n`;for(let r of this.project.workspacesByCwd.values()){let o=r.relativeCwd;e+=`workspace(${u0(o)}).\n`,e+=`workspace_ident(${u0(o)}, ${u0(W.stringifyIdent(r.anchoredLocator))}).\n`,e+=`workspace_version(${u0(o)}, ${u0(r.manifest.version)}).\n`;for(let a of pme)for(let n of r.manifest[a].values())e+=`workspace_has_dependency(${u0(o)}, ${u0(W.stringifyIdent(n))}, ${u0(n.range)}, ${a}).\n`}return e+=`workspace(_) :- false.\n`,e+=`workspace_ident(_, _) :- false.\n`,e+=`workspace_version(_, _) :- false.\n`,e+=`workspace_has_dependency(_, _, _, _) :- false.\n`,e}getDeclarations(){let e=\"\";return e+=`gen_enforced_dependency(_, _, _, _) :- false.\n`,e+=`gen_enforced_field(_, _, _) :- false.\n`,e}get fullSource(){return`${this.getProjectDatabase()}\n${this.source}\n${this.getDeclarations()}`}createSession(){return new IH(this.project,this.fullSource)}async processClassic(){let e=this.createSession();return{enforcedDependencies:await this.genEnforcedDependencies(e),enforcedFields:await this.genEnforcedFields(e)}}async process(){let{enforcedDependencies:e,enforcedFields:r}=await this.processClassic(),o=new Map;for(let{workspace:a,dependencyIdent:n,dependencyRange:u,dependencyType:A}of e){let p=w2([A,W.stringifyIdent(n)]),h=je.getMapWithDefault(o,a.cwd);je.getMapWithDefault(h,p).set(u??void 0,new Set)}for(let{workspace:a,fieldPath:n,fieldValue:u}of r){let A=w2(n),p=je.getMapWithDefault(o,a.cwd);je.getMapWithDefault(p,A).set(JSON.parse(u)??void 0,new Set)}return{manifestUpdates:o,reportedErrors:new Map}}async genEnforcedDependencies(e){let r=[];for await(let o of e.makeQuery(\"workspace(WorkspaceCwd), dependency_type(DependencyType), gen_enforced_dependency(WorkspaceCwd, DependencyIdent, DependencyRange, DependencyType).\")){let a=V.resolve(this.project.cwd,Zd(o.links.WorkspaceCwd)),n=Zd(o.links.DependencyIdent),u=Zd(o.links.DependencyRange),A=Zd(o.links.DependencyType);if(a===null||n===null)throw new Error(\"Invalid rule\");let p=this.project.getWorkspaceByCwd(a),h=W.parseIdent(n);r.push({workspace:p,dependencyIdent:h,dependencyRange:u,dependencyType:A})}return je.sortMap(r,[({dependencyRange:o})=>o!==null?\"0\":\"1\",({workspace:o})=>W.stringifyIdent(o.anchoredLocator),({dependencyIdent:o})=>W.stringifyIdent(o)])}async genEnforcedFields(e){let r=[];for await(let o of e.makeQuery(\"workspace(WorkspaceCwd), gen_enforced_field(WorkspaceCwd, FieldPath, FieldValue).\")){let a=V.resolve(this.project.cwd,Zd(o.links.WorkspaceCwd)),n=Zd(o.links.FieldPath),u=edt(o.links.FieldValue);if(a===null||n===null)throw new Error(\"Invalid rule\");let A=this.project.getWorkspaceByCwd(a);r.push({workspace:A,fieldPath:n,fieldValue:u})}return je.sortMap(r,[({workspace:o})=>W.stringifyIdent(o.anchoredLocator),({fieldPath:o})=>o])}async*query(e){let r=this.createSession();for await(let o of r.makeQuery(e)){let a={};for(let[n,u]of Object.entries(o.links))n!==\"_\"&&(a[n]=Zd(u));yield a}}}});var vme=_(vk=>{\"use strict\";Object.defineProperty(vk,\"__esModule\",{value:!0});function q2(t){let e=[...t.caches],r=e.shift();return r===void 0?Bme():{get(o,a,n={miss:()=>Promise.resolve()}){return r.get(o,a,n).catch(()=>q2({caches:e}).get(o,a,n))},set(o,a){return r.set(o,a).catch(()=>q2({caches:e}).set(o,a))},delete(o){return r.delete(o).catch(()=>q2({caches:e}).delete(o))},clear(){return r.clear().catch(()=>q2({caches:e}).clear())}}}function Bme(){return{get(t,e,r={miss:()=>Promise.resolve()}){return e().then(a=>Promise.all([a,r.miss(a)])).then(([a])=>a)},set(t,e){return Promise.resolve(e)},delete(t){return Promise.resolve()},clear(){return Promise.resolve()}}}vk.createFallbackableCache=q2;vk.createNullCache=Bme});var Pme=_((QWt,Dme)=>{Dme.exports=vme()});var Sme=_(LH=>{\"use strict\";Object.defineProperty(LH,\"__esModule\",{value:!0});function Edt(t={serializable:!0}){let e={};return{get(r,o,a={miss:()=>Promise.resolve()}){let n=JSON.stringify(r);if(n in e)return Promise.resolve(t.serializable?JSON.parse(e[n]):e[n]);let u=o(),A=a&&a.miss||(()=>Promise.resolve());return u.then(p=>A(p)).then(()=>u)},set(r,o){return e[JSON.stringify(r)]=t.serializable?JSON.stringify(o):o,Promise.resolve(o)},delete(r){return delete e[JSON.stringify(r)],Promise.resolve()},clear(){return e={},Promise.resolve()}}}LH.createInMemoryCache=Edt});var xme=_((RWt,bme)=>{bme.exports=Sme()});var Qme=_(Zc=>{\"use strict\";Object.defineProperty(Zc,\"__esModule\",{value:!0});function Cdt(t,e,r){let o={\"x-algolia-api-key\":r,\"x-algolia-application-id\":e};return{headers(){return t===OH.WithinHeaders?o:{}},queryParameters(){return t===OH.WithinQueryParameters?o:{}}}}function wdt(t){let e=0,r=()=>(e++,new Promise(o=>{setTimeout(()=>{o(t(r))},Math.min(100*e,1e3))}));return t(r)}function kme(t,e=(r,o)=>Promise.resolve()){return Object.assign(t,{wait(r){return kme(t.then(o=>Promise.all([e(o,r),o])).then(o=>o[1]))}})}function Idt(t){let e=t.length-1;for(e;e>0;e--){let r=Math.floor(Math.random()*(e+1)),o=t[e];t[e]=t[r],t[r]=o}return t}function Bdt(t,e){return e&&Object.keys(e).forEach(r=>{t[r]=e[r](t)}),t}function vdt(t,...e){let r=0;return t.replace(/%s/g,()=>encodeURIComponent(e[r++]))}var Ddt=\"4.14.2\",Pdt=t=>()=>t.transporter.requester.destroy(),OH={WithinQueryParameters:0,WithinHeaders:1};Zc.AuthMode=OH;Zc.addMethods=Bdt;Zc.createAuth=Cdt;Zc.createRetryablePromise=wdt;Zc.createWaitablePromise=kme;Zc.destroy=Pdt;Zc.encode=vdt;Zc.shuffle=Idt;Zc.version=Ddt});var G2=_((NWt,Fme)=>{Fme.exports=Qme()});var Rme=_(MH=>{\"use strict\";Object.defineProperty(MH,\"__esModule\",{value:!0});var Sdt={Delete:\"DELETE\",Get:\"GET\",Post:\"POST\",Put:\"PUT\"};MH.MethodEnum=Sdt});var Y2=_((OWt,Tme)=>{Tme.exports=Rme()});var zme=_(Fi=>{\"use strict\";Object.defineProperty(Fi,\"__esModule\",{value:!0});var Lme=Y2();function UH(t,e){let r=t||{},o=r.data||{};return Object.keys(r).forEach(a=>{[\"timeout\",\"headers\",\"queryParameters\",\"data\",\"cacheable\"].indexOf(a)===-1&&(o[a]=r[a])}),{data:Object.entries(o).length>0?o:void 0,timeout:r.timeout||e,headers:r.headers||{},queryParameters:r.queryParameters||{},cacheable:r.cacheable}}var W2={Read:1,Write:2,Any:3},SC={Up:1,Down:2,Timeouted:3},Ome=2*60*1e3;function HH(t,e=SC.Up){return{...t,status:e,lastUpdate:Date.now()}}function Mme(t){return t.status===SC.Up||Date.now()-t.lastUpdate>Ome}function Ume(t){return t.status===SC.Timeouted&&Date.now()-t.lastUpdate<=Ome}function jH(t){return typeof t==\"string\"?{protocol:\"https\",url:t,accept:W2.Any}:{protocol:t.protocol||\"https\",url:t.url,accept:t.accept||W2.Any}}function bdt(t,e){return Promise.all(e.map(r=>t.get(r,()=>Promise.resolve(HH(r))))).then(r=>{let o=r.filter(A=>Mme(A)),a=r.filter(A=>Ume(A)),n=[...o,...a],u=n.length>0?n.map(A=>jH(A)):e;return{getTimeout(A,p){return(a.length===0&&A===0?1:a.length+3+A)*p},statelessHosts:u}})}var xdt=({isTimedOut:t,status:e})=>!t&&~~e===0,kdt=t=>{let e=t.status;return t.isTimedOut||xdt(t)||~~(e/100)!==2&&~~(e/100)!==4},Qdt=({status:t})=>~~(t/100)===2,Fdt=(t,e)=>kdt(t)?e.onRetry(t):Qdt(t)?e.onSuccess(t):e.onFail(t);function Nme(t,e,r,o){let a=[],n=Gme(r,o),u=Yme(t,o),A=r.method,p=r.method!==Lme.MethodEnum.Get?{}:{...r.data,...o.data},h={\"x-algolia-agent\":t.userAgent.value,...t.queryParameters,...p,...o.queryParameters},C=0,I=(v,x)=>{let E=v.pop();if(E===void 0)throw Vme(_H(a));let R={data:n,headers:u,method:A,url:jme(E,r.path,h),connectTimeout:x(C,t.timeouts.connect),responseTimeout:x(C,o.timeout)},L=z=>{let te={request:R,response:z,host:E,triesLeft:v.length};return a.push(te),te},U={onSuccess:z=>_me(z),onRetry(z){let te=L(z);return z.isTimedOut&&C++,Promise.all([t.logger.info(\"Retryable failure\",qH(te)),t.hostsCache.set(E,HH(E,z.isTimedOut?SC.Timeouted:SC.Down))]).then(()=>I(v,x))},onFail(z){throw L(z),Hme(z,_H(a))}};return t.requester.send(R).then(z=>Fdt(z,U))};return bdt(t.hostsCache,e).then(v=>I([...v.statelessHosts].reverse(),v.getTimeout))}function Rdt(t){let{hostsCache:e,logger:r,requester:o,requestsCache:a,responsesCache:n,timeouts:u,userAgent:A,hosts:p,queryParameters:h,headers:C}=t,I={hostsCache:e,logger:r,requester:o,requestsCache:a,responsesCache:n,timeouts:u,userAgent:A,headers:C,queryParameters:h,hosts:p.map(v=>jH(v)),read(v,x){let E=UH(x,I.timeouts.read),R=()=>Nme(I,I.hosts.filter(z=>(z.accept&W2.Read)!==0),v,E);if((E.cacheable!==void 0?E.cacheable:v.cacheable)!==!0)return R();let U={request:v,mappedRequestOptions:E,transporter:{queryParameters:I.queryParameters,headers:I.headers}};return I.responsesCache.get(U,()=>I.requestsCache.get(U,()=>I.requestsCache.set(U,R()).then(z=>Promise.all([I.requestsCache.delete(U),z]),z=>Promise.all([I.requestsCache.delete(U),Promise.reject(z)])).then(([z,te])=>te)),{miss:z=>I.responsesCache.set(U,z)})},write(v,x){return Nme(I,I.hosts.filter(E=>(E.accept&W2.Write)!==0),v,UH(x,I.timeouts.write))}};return I}function Tdt(t){let e={value:`Algolia for JavaScript (${t})`,add(r){let o=`; ${r.segment}${r.version!==void 0?` (${r.version})`:\"\"}`;return e.value.indexOf(o)===-1&&(e.value=`${e.value}${o}`),e}};return e}function _me(t){try{return JSON.parse(t.content)}catch(e){throw Kme(e.message,t)}}function Hme({content:t,status:e},r){let o=t;try{o=JSON.parse(t).message}catch{}return Wme(o,e,r)}function Ndt(t,...e){let r=0;return t.replace(/%s/g,()=>encodeURIComponent(e[r++]))}function jme(t,e,r){let o=qme(r),a=`${t.protocol}://${t.url}/${e.charAt(0)===\"/\"?e.substr(1):e}`;return o.length&&(a+=`?${o}`),a}function qme(t){let e=r=>Object.prototype.toString.call(r)===\"[object Object]\"||Object.prototype.toString.call(r)===\"[object Array]\";return Object.keys(t).map(r=>Ndt(\"%s=%s\",r,e(t[r])?JSON.stringify(t[r]):t[r])).join(\"&\")}function Gme(t,e){if(t.method===Lme.MethodEnum.Get||t.data===void 0&&e.data===void 0)return;let r=Array.isArray(t.data)?t.data:{...t.data,...e.data};return JSON.stringify(r)}function Yme(t,e){let r={...t.headers,...e.headers},o={};return Object.keys(r).forEach(a=>{let n=r[a];o[a.toLowerCase()]=n}),o}function _H(t){return t.map(e=>qH(e))}function qH(t){let e=t.request.headers[\"x-algolia-api-key\"]?{\"x-algolia-api-key\":\"*****\"}:{};return{...t,request:{...t.request,headers:{...t.request.headers,...e}}}}function Wme(t,e,r){return{name:\"ApiError\",message:t,status:e,transporterStackTrace:r}}function Kme(t,e){return{name:\"DeserializationError\",message:t,response:e}}function Vme(t){return{name:\"RetryError\",message:\"Unreachable hosts - your application id may be incorrect. If the error persists, contact support@algolia.com.\",transporterStackTrace:t}}Fi.CallEnum=W2;Fi.HostStatusEnum=SC;Fi.createApiError=Wme;Fi.createDeserializationError=Kme;Fi.createMappedRequestOptions=UH;Fi.createRetryError=Vme;Fi.createStatefulHost=HH;Fi.createStatelessHost=jH;Fi.createTransporter=Rdt;Fi.createUserAgent=Tdt;Fi.deserializeFailure=Hme;Fi.deserializeSuccess=_me;Fi.isStatefulHostTimeouted=Ume;Fi.isStatefulHostUp=Mme;Fi.serializeData=Gme;Fi.serializeHeaders=Yme;Fi.serializeQueryParameters=qme;Fi.serializeUrl=jme;Fi.stackFrameWithoutCredentials=qH;Fi.stackTraceWithoutCredentials=_H});var K2=_((UWt,Jme)=>{Jme.exports=zme()});var Xme=_(d0=>{\"use strict\";Object.defineProperty(d0,\"__esModule\",{value:!0});var bC=G2(),Ldt=K2(),V2=Y2(),Odt=t=>{let e=t.region||\"us\",r=bC.createAuth(bC.AuthMode.WithinHeaders,t.appId,t.apiKey),o=Ldt.createTransporter({hosts:[{url:`analytics.${e}.algolia.com`}],...t,headers:{...r.headers(),\"content-type\":\"application/json\",...t.headers},queryParameters:{...r.queryParameters(),...t.queryParameters}}),a=t.appId;return bC.addMethods({appId:a,transporter:o},t.methods)},Mdt=t=>(e,r)=>t.transporter.write({method:V2.MethodEnum.Post,path:\"2/abtests\",data:e},r),Udt=t=>(e,r)=>t.transporter.write({method:V2.MethodEnum.Delete,path:bC.encode(\"2/abtests/%s\",e)},r),_dt=t=>(e,r)=>t.transporter.read({method:V2.MethodEnum.Get,path:bC.encode(\"2/abtests/%s\",e)},r),Hdt=t=>e=>t.transporter.read({method:V2.MethodEnum.Get,path:\"2/abtests\"},e),jdt=t=>(e,r)=>t.transporter.write({method:V2.MethodEnum.Post,path:bC.encode(\"2/abtests/%s/stop\",e)},r);d0.addABTest=Mdt;d0.createAnalyticsClient=Odt;d0.deleteABTest=Udt;d0.getABTest=_dt;d0.getABTests=Hdt;d0.stopABTest=jdt});var $me=_((HWt,Zme)=>{Zme.exports=Xme()});var tye=_(z2=>{\"use strict\";Object.defineProperty(z2,\"__esModule\",{value:!0});var GH=G2(),qdt=K2(),eye=Y2(),Gdt=t=>{let e=t.region||\"us\",r=GH.createAuth(GH.AuthMode.WithinHeaders,t.appId,t.apiKey),o=qdt.createTransporter({hosts:[{url:`personalization.${e}.algolia.com`}],...t,headers:{...r.headers(),\"content-type\":\"application/json\",...t.headers},queryParameters:{...r.queryParameters(),...t.queryParameters}});return GH.addMethods({appId:t.appId,transporter:o},t.methods)},Ydt=t=>e=>t.transporter.read({method:eye.MethodEnum.Get,path:\"1/strategies/personalization\"},e),Wdt=t=>(e,r)=>t.transporter.write({method:eye.MethodEnum.Post,path:\"1/strategies/personalization\",data:e},r);z2.createPersonalizationClient=Gdt;z2.getPersonalizationStrategy=Ydt;z2.setPersonalizationStrategy=Wdt});var nye=_((qWt,rye)=>{rye.exports=tye()});var mye=_(Ft=>{\"use strict\";Object.defineProperty(Ft,\"__esModule\",{value:!0});var Gt=G2(),Na=K2(),Ir=Y2(),Kdt=Be(\"crypto\");function Dk(t){let e=r=>t.request(r).then(o=>{if(t.batch!==void 0&&t.batch(o.hits),!t.shouldStop(o))return o.cursor?e({cursor:o.cursor}):e({page:(r.page||0)+1})});return e({})}var Vdt=t=>{let e=t.appId,r=Gt.createAuth(t.authMode!==void 0?t.authMode:Gt.AuthMode.WithinHeaders,e,t.apiKey),o=Na.createTransporter({hosts:[{url:`${e}-dsn.algolia.net`,accept:Na.CallEnum.Read},{url:`${e}.algolia.net`,accept:Na.CallEnum.Write}].concat(Gt.shuffle([{url:`${e}-1.algolianet.com`},{url:`${e}-2.algolianet.com`},{url:`${e}-3.algolianet.com`}])),...t,headers:{...r.headers(),\"content-type\":\"application/x-www-form-urlencoded\",...t.headers},queryParameters:{...r.queryParameters(),...t.queryParameters}}),a={transporter:o,appId:e,addAlgoliaAgent(n,u){o.userAgent.add({segment:n,version:u})},clearCache(){return Promise.all([o.requestsCache.clear(),o.responsesCache.clear()]).then(()=>{})}};return Gt.addMethods(a,t.methods)};function iye(){return{name:\"MissingObjectIDError\",message:\"All objects must have an unique objectID (like a primary key) to be valid. Algolia is also able to generate objectIDs automatically but *it's not recommended*. To do it, use the `{'autoGenerateObjectIDIfNotExist': true}` option.\"}}function sye(){return{name:\"ObjectNotFoundError\",message:\"Object not found.\"}}function oye(){return{name:\"ValidUntilNotFoundError\",message:\"ValidUntil not found in given secured api key.\"}}var zdt=t=>(e,r)=>{let{queryParameters:o,...a}=r||{},n={acl:e,...o!==void 0?{queryParameters:o}:{}},u=(A,p)=>Gt.createRetryablePromise(h=>J2(t)(A.key,p).catch(C=>{if(C.status!==404)throw C;return h()}));return Gt.createWaitablePromise(t.transporter.write({method:Ir.MethodEnum.Post,path:\"1/keys\",data:n},a),u)},Jdt=t=>(e,r,o)=>{let a=Na.createMappedRequestOptions(o);return a.queryParameters[\"X-Algolia-User-ID\"]=e,t.transporter.write({method:Ir.MethodEnum.Post,path:\"1/clusters/mapping\",data:{cluster:r}},a)},Xdt=t=>(e,r,o)=>t.transporter.write({method:Ir.MethodEnum.Post,path:\"1/clusters/mapping/batch\",data:{users:e,cluster:r}},o),Zdt=t=>(e,r)=>Gt.createWaitablePromise(t.transporter.write({method:Ir.MethodEnum.Post,path:Gt.encode(\"/1/dictionaries/%s/batch\",e),data:{clearExistingDictionaryEntries:!0,requests:{action:\"addEntry\",body:[]}}},r),(o,a)=>xC(t)(o.taskID,a)),Pk=t=>(e,r,o)=>{let a=(n,u)=>X2(t)(e,{methods:{waitTask:Zi}}).waitTask(n.taskID,u);return Gt.createWaitablePromise(t.transporter.write({method:Ir.MethodEnum.Post,path:Gt.encode(\"1/indexes/%s/operation\",e),data:{operation:\"copy\",destination:r}},o),a)},$dt=t=>(e,r,o)=>Pk(t)(e,r,{...o,scope:[bk.Rules]}),emt=t=>(e,r,o)=>Pk(t)(e,r,{...o,scope:[bk.Settings]}),tmt=t=>(e,r,o)=>Pk(t)(e,r,{...o,scope:[bk.Synonyms]}),rmt=t=>(e,r)=>e.method===Ir.MethodEnum.Get?t.transporter.read(e,r):t.transporter.write(e,r),nmt=t=>(e,r)=>{let o=(a,n)=>Gt.createRetryablePromise(u=>J2(t)(e,n).then(u).catch(A=>{if(A.status!==404)throw A}));return Gt.createWaitablePromise(t.transporter.write({method:Ir.MethodEnum.Delete,path:Gt.encode(\"1/keys/%s\",e)},r),o)},imt=t=>(e,r,o)=>{let a=r.map(n=>({action:\"deleteEntry\",body:{objectID:n}}));return Gt.createWaitablePromise(t.transporter.write({method:Ir.MethodEnum.Post,path:Gt.encode(\"/1/dictionaries/%s/batch\",e),data:{clearExistingDictionaryEntries:!1,requests:a}},o),(n,u)=>xC(t)(n.taskID,u))},smt=()=>(t,e)=>{let r=Na.serializeQueryParameters(e),o=Kdt.createHmac(\"sha256\",t).update(r).digest(\"hex\");return Buffer.from(o+r).toString(\"base64\")},J2=t=>(e,r)=>t.transporter.read({method:Ir.MethodEnum.Get,path:Gt.encode(\"1/keys/%s\",e)},r),aye=t=>(e,r)=>t.transporter.read({method:Ir.MethodEnum.Get,path:Gt.encode(\"1/task/%s\",e.toString())},r),omt=t=>e=>t.transporter.read({method:Ir.MethodEnum.Get,path:\"/1/dictionaries/*/settings\"},e),amt=t=>e=>t.transporter.read({method:Ir.MethodEnum.Get,path:\"1/logs\"},e),lmt=()=>t=>{let e=Buffer.from(t,\"base64\").toString(\"ascii\"),r=/validUntil=(\\d+)/,o=e.match(r);if(o===null)throw oye();return parseInt(o[1],10)-Math.round(new Date().getTime()/1e3)},cmt=t=>e=>t.transporter.read({method:Ir.MethodEnum.Get,path:\"1/clusters/mapping/top\"},e),umt=t=>(e,r)=>t.transporter.read({method:Ir.MethodEnum.Get,path:Gt.encode(\"1/clusters/mapping/%s\",e)},r),Amt=t=>e=>{let{retrieveMappings:r,...o}=e||{};return r===!0&&(o.getClusters=!0),t.transporter.read({method:Ir.MethodEnum.Get,path:\"1/clusters/mapping/pending\"},o)},X2=t=>(e,r={})=>{let o={transporter:t.transporter,appId:t.appId,indexName:e};return Gt.addMethods(o,r.methods)},fmt=t=>e=>t.transporter.read({method:Ir.MethodEnum.Get,path:\"1/keys\"},e),pmt=t=>e=>t.transporter.read({method:Ir.MethodEnum.Get,path:\"1/clusters\"},e),hmt=t=>e=>t.transporter.read({method:Ir.MethodEnum.Get,path:\"1/indexes\"},e),gmt=t=>e=>t.transporter.read({method:Ir.MethodEnum.Get,path:\"1/clusters/mapping\"},e),dmt=t=>(e,r,o)=>{let a=(n,u)=>X2(t)(e,{methods:{waitTask:Zi}}).waitTask(n.taskID,u);return Gt.createWaitablePromise(t.transporter.write({method:Ir.MethodEnum.Post,path:Gt.encode(\"1/indexes/%s/operation\",e),data:{operation:\"move\",destination:r}},o),a)},mmt=t=>(e,r)=>{let o=(a,n)=>Promise.all(Object.keys(a.taskID).map(u=>X2(t)(u,{methods:{waitTask:Zi}}).waitTask(a.taskID[u],n)));return Gt.createWaitablePromise(t.transporter.write({method:Ir.MethodEnum.Post,path:\"1/indexes/*/batch\",data:{requests:e}},r),o)},ymt=t=>(e,r)=>t.transporter.read({method:Ir.MethodEnum.Post,path:\"1/indexes/*/objects\",data:{requests:e}},r),Emt=t=>(e,r)=>{let o=e.map(a=>({...a,params:Na.serializeQueryParameters(a.params||{})}));return t.transporter.read({method:Ir.MethodEnum.Post,path:\"1/indexes/*/queries\",data:{requests:o},cacheable:!0},r)},Cmt=t=>(e,r)=>Promise.all(e.map(o=>{let{facetName:a,facetQuery:n,...u}=o.params;return X2(t)(o.indexName,{methods:{searchForFacetValues:hye}}).searchForFacetValues(a,n,{...r,...u})})),wmt=t=>(e,r)=>{let o=Na.createMappedRequestOptions(r);return o.queryParameters[\"X-Algolia-User-ID\"]=e,t.transporter.write({method:Ir.MethodEnum.Delete,path:\"1/clusters/mapping\"},o)},Imt=t=>(e,r,o)=>{let a=r.map(n=>({action:\"addEntry\",body:n}));return Gt.createWaitablePromise(t.transporter.write({method:Ir.MethodEnum.Post,path:Gt.encode(\"/1/dictionaries/%s/batch\",e),data:{clearExistingDictionaryEntries:!0,requests:a}},o),(n,u)=>xC(t)(n.taskID,u))},Bmt=t=>(e,r)=>{let o=(a,n)=>Gt.createRetryablePromise(u=>J2(t)(e,n).catch(A=>{if(A.status!==404)throw A;return u()}));return Gt.createWaitablePromise(t.transporter.write({method:Ir.MethodEnum.Post,path:Gt.encode(\"1/keys/%s/restore\",e)},r),o)},vmt=t=>(e,r,o)=>{let a=r.map(n=>({action:\"addEntry\",body:n}));return Gt.createWaitablePromise(t.transporter.write({method:Ir.MethodEnum.Post,path:Gt.encode(\"/1/dictionaries/%s/batch\",e),data:{clearExistingDictionaryEntries:!1,requests:a}},o),(n,u)=>xC(t)(n.taskID,u))},Dmt=t=>(e,r,o)=>t.transporter.read({method:Ir.MethodEnum.Post,path:Gt.encode(\"/1/dictionaries/%s/search\",e),data:{query:r},cacheable:!0},o),Pmt=t=>(e,r)=>t.transporter.read({method:Ir.MethodEnum.Post,path:\"1/clusters/mapping/search\",data:{query:e}},r),Smt=t=>(e,r)=>Gt.createWaitablePromise(t.transporter.write({method:Ir.MethodEnum.Put,path:\"/1/dictionaries/*/settings\",data:e},r),(o,a)=>xC(t)(o.taskID,a)),bmt=t=>(e,r)=>{let o=Object.assign({},r),{queryParameters:a,...n}=r||{},u=a?{queryParameters:a}:{},A=[\"acl\",\"indexes\",\"referers\",\"restrictSources\",\"queryParameters\",\"description\",\"maxQueriesPerIPPerHour\",\"maxHitsPerQuery\"],p=C=>Object.keys(o).filter(I=>A.indexOf(I)!==-1).every(I=>C[I]===o[I]),h=(C,I)=>Gt.createRetryablePromise(v=>J2(t)(e,I).then(x=>p(x)?Promise.resolve():v()));return Gt.createWaitablePromise(t.transporter.write({method:Ir.MethodEnum.Put,path:Gt.encode(\"1/keys/%s\",e),data:u},n),h)},xC=t=>(e,r)=>Gt.createRetryablePromise(o=>aye(t)(e,r).then(a=>a.status!==\"published\"?o():void 0)),lye=t=>(e,r)=>{let o=(a,n)=>Zi(t)(a.taskID,n);return Gt.createWaitablePromise(t.transporter.write({method:Ir.MethodEnum.Post,path:Gt.encode(\"1/indexes/%s/batch\",t.indexName),data:{requests:e}},r),o)},xmt=t=>e=>Dk({shouldStop:r=>r.cursor===void 0,...e,request:r=>t.transporter.read({method:Ir.MethodEnum.Post,path:Gt.encode(\"1/indexes/%s/browse\",t.indexName),data:r},e)}),kmt=t=>e=>{let r={hitsPerPage:1e3,...e};return Dk({shouldStop:o=>o.hits.length<r.hitsPerPage,...r,request(o){return gye(t)(\"\",{...r,...o}).then(a=>({...a,hits:a.hits.map(n=>(delete n._highlightResult,n))}))}})},Qmt=t=>e=>{let r={hitsPerPage:1e3,...e};return Dk({shouldStop:o=>o.hits.length<r.hitsPerPage,...r,request(o){return dye(t)(\"\",{...r,...o}).then(a=>({...a,hits:a.hits.map(n=>(delete n._highlightResult,n))}))}})},Sk=t=>(e,r,o)=>{let{batchSize:a,...n}=o||{},u={taskIDs:[],objectIDs:[]},A=(p=0)=>{let h=[],C;for(C=p;C<e.length&&(h.push(e[C]),h.length!==(a||1e3));C++);return h.length===0?Promise.resolve(u):lye(t)(h.map(I=>({action:r,body:I})),n).then(I=>(u.objectIDs=u.objectIDs.concat(I.objectIDs),u.taskIDs.push(I.taskID),C++,A(C)))};return Gt.createWaitablePromise(A(),(p,h)=>Promise.all(p.taskIDs.map(C=>Zi(t)(C,h))))},Fmt=t=>e=>Gt.createWaitablePromise(t.transporter.write({method:Ir.MethodEnum.Post,path:Gt.encode(\"1/indexes/%s/clear\",t.indexName)},e),(r,o)=>Zi(t)(r.taskID,o)),Rmt=t=>e=>{let{forwardToReplicas:r,...o}=e||{},a=Na.createMappedRequestOptions(o);return r&&(a.queryParameters.forwardToReplicas=1),Gt.createWaitablePromise(t.transporter.write({method:Ir.MethodEnum.Post,path:Gt.encode(\"1/indexes/%s/rules/clear\",t.indexName)},a),(n,u)=>Zi(t)(n.taskID,u))},Tmt=t=>e=>{let{forwardToReplicas:r,...o}=e||{},a=Na.createMappedRequestOptions(o);return r&&(a.queryParameters.forwardToReplicas=1),Gt.createWaitablePromise(t.transporter.write({method:Ir.MethodEnum.Post,path:Gt.encode(\"1/indexes/%s/synonyms/clear\",t.indexName)},a),(n,u)=>Zi(t)(n.taskID,u))},Nmt=t=>(e,r)=>Gt.createWaitablePromise(t.transporter.write({method:Ir.MethodEnum.Post,path:Gt.encode(\"1/indexes/%s/deleteByQuery\",t.indexName),data:e},r),(o,a)=>Zi(t)(o.taskID,a)),Lmt=t=>e=>Gt.createWaitablePromise(t.transporter.write({method:Ir.MethodEnum.Delete,path:Gt.encode(\"1/indexes/%s\",t.indexName)},e),(r,o)=>Zi(t)(r.taskID,o)),Omt=t=>(e,r)=>Gt.createWaitablePromise(cye(t)([e],r).then(o=>({taskID:o.taskIDs[0]})),(o,a)=>Zi(t)(o.taskID,a)),cye=t=>(e,r)=>{let o=e.map(a=>({objectID:a}));return Sk(t)(o,tm.DeleteObject,r)},Mmt=t=>(e,r)=>{let{forwardToReplicas:o,...a}=r||{},n=Na.createMappedRequestOptions(a);return o&&(n.queryParameters.forwardToReplicas=1),Gt.createWaitablePromise(t.transporter.write({method:Ir.MethodEnum.Delete,path:Gt.encode(\"1/indexes/%s/rules/%s\",t.indexName,e)},n),(u,A)=>Zi(t)(u.taskID,A))},Umt=t=>(e,r)=>{let{forwardToReplicas:o,...a}=r||{},n=Na.createMappedRequestOptions(a);return o&&(n.queryParameters.forwardToReplicas=1),Gt.createWaitablePromise(t.transporter.write({method:Ir.MethodEnum.Delete,path:Gt.encode(\"1/indexes/%s/synonyms/%s\",t.indexName,e)},n),(u,A)=>Zi(t)(u.taskID,A))},_mt=t=>e=>uye(t)(e).then(()=>!0).catch(r=>{if(r.status!==404)throw r;return!1}),Hmt=t=>(e,r,o)=>t.transporter.read({method:Ir.MethodEnum.Post,path:Gt.encode(\"1/answers/%s/prediction\",t.indexName),data:{query:e,queryLanguages:r},cacheable:!0},o),jmt=t=>(e,r)=>{let{query:o,paginate:a,...n}=r||{},u=0,A=()=>pye(t)(o||\"\",{...n,page:u}).then(p=>{for(let[h,C]of Object.entries(p.hits))if(e(C))return{object:C,position:parseInt(h,10),page:u};if(u++,a===!1||u>=p.nbPages)throw sye();return A()});return A()},qmt=t=>(e,r)=>t.transporter.read({method:Ir.MethodEnum.Get,path:Gt.encode(\"1/indexes/%s/%s\",t.indexName,e)},r),Gmt=()=>(t,e)=>{for(let[r,o]of Object.entries(t.hits))if(o.objectID===e)return parseInt(r,10);return-1},Ymt=t=>(e,r)=>{let{attributesToRetrieve:o,...a}=r||{},n=e.map(u=>({indexName:t.indexName,objectID:u,...o?{attributesToRetrieve:o}:{}}));return t.transporter.read({method:Ir.MethodEnum.Post,path:\"1/indexes/*/objects\",data:{requests:n}},a)},Wmt=t=>(e,r)=>t.transporter.read({method:Ir.MethodEnum.Get,path:Gt.encode(\"1/indexes/%s/rules/%s\",t.indexName,e)},r),uye=t=>e=>t.transporter.read({method:Ir.MethodEnum.Get,path:Gt.encode(\"1/indexes/%s/settings\",t.indexName),data:{getVersion:2}},e),Kmt=t=>(e,r)=>t.transporter.read({method:Ir.MethodEnum.Get,path:Gt.encode(\"1/indexes/%s/synonyms/%s\",t.indexName,e)},r),Aye=t=>(e,r)=>t.transporter.read({method:Ir.MethodEnum.Get,path:Gt.encode(\"1/indexes/%s/task/%s\",t.indexName,e.toString())},r),Vmt=t=>(e,r)=>Gt.createWaitablePromise(fye(t)([e],r).then(o=>({objectID:o.objectIDs[0],taskID:o.taskIDs[0]})),(o,a)=>Zi(t)(o.taskID,a)),fye=t=>(e,r)=>{let{createIfNotExists:o,...a}=r||{},n=o?tm.PartialUpdateObject:tm.PartialUpdateObjectNoCreate;return Sk(t)(e,n,a)},zmt=t=>(e,r)=>{let{safe:o,autoGenerateObjectIDIfNotExist:a,batchSize:n,...u}=r||{},A=(E,R,L,U)=>Gt.createWaitablePromise(t.transporter.write({method:Ir.MethodEnum.Post,path:Gt.encode(\"1/indexes/%s/operation\",E),data:{operation:L,destination:R}},U),(z,te)=>Zi(t)(z.taskID,te)),p=Math.random().toString(36).substring(7),h=`${t.indexName}_tmp_${p}`,C=YH({appId:t.appId,transporter:t.transporter,indexName:h}),I=[],v=A(t.indexName,h,\"copy\",{...u,scope:[\"settings\",\"synonyms\",\"rules\"]});I.push(v);let x=(o?v.wait(u):v).then(()=>{let E=C(e,{...u,autoGenerateObjectIDIfNotExist:a,batchSize:n});return I.push(E),o?E.wait(u):E}).then(()=>{let E=A(h,t.indexName,\"move\",u);return I.push(E),o?E.wait(u):E}).then(()=>Promise.all(I)).then(([E,R,L])=>({objectIDs:R.objectIDs,taskIDs:[E.taskID,...R.taskIDs,L.taskID]}));return Gt.createWaitablePromise(x,(E,R)=>Promise.all(I.map(L=>L.wait(R))))},Jmt=t=>(e,r)=>WH(t)(e,{...r,clearExistingRules:!0}),Xmt=t=>(e,r)=>KH(t)(e,{...r,clearExistingSynonyms:!0}),Zmt=t=>(e,r)=>Gt.createWaitablePromise(YH(t)([e],r).then(o=>({objectID:o.objectIDs[0],taskID:o.taskIDs[0]})),(o,a)=>Zi(t)(o.taskID,a)),YH=t=>(e,r)=>{let{autoGenerateObjectIDIfNotExist:o,...a}=r||{},n=o?tm.AddObject:tm.UpdateObject;if(n===tm.UpdateObject){for(let u of e)if(u.objectID===void 0)return Gt.createWaitablePromise(Promise.reject(iye()))}return Sk(t)(e,n,a)},$mt=t=>(e,r)=>WH(t)([e],r),WH=t=>(e,r)=>{let{forwardToReplicas:o,clearExistingRules:a,...n}=r||{},u=Na.createMappedRequestOptions(n);return o&&(u.queryParameters.forwardToReplicas=1),a&&(u.queryParameters.clearExistingRules=1),Gt.createWaitablePromise(t.transporter.write({method:Ir.MethodEnum.Post,path:Gt.encode(\"1/indexes/%s/rules/batch\",t.indexName),data:e},u),(A,p)=>Zi(t)(A.taskID,p))},eyt=t=>(e,r)=>KH(t)([e],r),KH=t=>(e,r)=>{let{forwardToReplicas:o,clearExistingSynonyms:a,replaceExistingSynonyms:n,...u}=r||{},A=Na.createMappedRequestOptions(u);return o&&(A.queryParameters.forwardToReplicas=1),(n||a)&&(A.queryParameters.replaceExistingSynonyms=1),Gt.createWaitablePromise(t.transporter.write({method:Ir.MethodEnum.Post,path:Gt.encode(\"1/indexes/%s/synonyms/batch\",t.indexName),data:e},A),(p,h)=>Zi(t)(p.taskID,h))},pye=t=>(e,r)=>t.transporter.read({method:Ir.MethodEnum.Post,path:Gt.encode(\"1/indexes/%s/query\",t.indexName),data:{query:e},cacheable:!0},r),hye=t=>(e,r,o)=>t.transporter.read({method:Ir.MethodEnum.Post,path:Gt.encode(\"1/indexes/%s/facets/%s/query\",t.indexName,e),data:{facetQuery:r},cacheable:!0},o),gye=t=>(e,r)=>t.transporter.read({method:Ir.MethodEnum.Post,path:Gt.encode(\"1/indexes/%s/rules/search\",t.indexName),data:{query:e}},r),dye=t=>(e,r)=>t.transporter.read({method:Ir.MethodEnum.Post,path:Gt.encode(\"1/indexes/%s/synonyms/search\",t.indexName),data:{query:e}},r),tyt=t=>(e,r)=>{let{forwardToReplicas:o,...a}=r||{},n=Na.createMappedRequestOptions(a);return o&&(n.queryParameters.forwardToReplicas=1),Gt.createWaitablePromise(t.transporter.write({method:Ir.MethodEnum.Put,path:Gt.encode(\"1/indexes/%s/settings\",t.indexName),data:e},n),(u,A)=>Zi(t)(u.taskID,A))},Zi=t=>(e,r)=>Gt.createRetryablePromise(o=>Aye(t)(e,r).then(a=>a.status!==\"published\"?o():void 0)),ryt={AddObject:\"addObject\",Analytics:\"analytics\",Browser:\"browse\",DeleteIndex:\"deleteIndex\",DeleteObject:\"deleteObject\",EditSettings:\"editSettings\",ListIndexes:\"listIndexes\",Logs:\"logs\",Personalization:\"personalization\",Recommendation:\"recommendation\",Search:\"search\",SeeUnretrievableAttributes:\"seeUnretrievableAttributes\",Settings:\"settings\",Usage:\"usage\"},tm={AddObject:\"addObject\",UpdateObject:\"updateObject\",PartialUpdateObject:\"partialUpdateObject\",PartialUpdateObjectNoCreate:\"partialUpdateObjectNoCreate\",DeleteObject:\"deleteObject\",DeleteIndex:\"delete\",ClearIndex:\"clear\"},bk={Settings:\"settings\",Synonyms:\"synonyms\",Rules:\"rules\"},nyt={None:\"none\",StopIfEnoughMatches:\"stopIfEnoughMatches\"},iyt={Synonym:\"synonym\",OneWaySynonym:\"oneWaySynonym\",AltCorrection1:\"altCorrection1\",AltCorrection2:\"altCorrection2\",Placeholder:\"placeholder\"};Ft.ApiKeyACLEnum=ryt;Ft.BatchActionEnum=tm;Ft.ScopeEnum=bk;Ft.StrategyEnum=nyt;Ft.SynonymEnum=iyt;Ft.addApiKey=zdt;Ft.assignUserID=Jdt;Ft.assignUserIDs=Xdt;Ft.batch=lye;Ft.browseObjects=xmt;Ft.browseRules=kmt;Ft.browseSynonyms=Qmt;Ft.chunkedBatch=Sk;Ft.clearDictionaryEntries=Zdt;Ft.clearObjects=Fmt;Ft.clearRules=Rmt;Ft.clearSynonyms=Tmt;Ft.copyIndex=Pk;Ft.copyRules=$dt;Ft.copySettings=emt;Ft.copySynonyms=tmt;Ft.createBrowsablePromise=Dk;Ft.createMissingObjectIDError=iye;Ft.createObjectNotFoundError=sye;Ft.createSearchClient=Vdt;Ft.createValidUntilNotFoundError=oye;Ft.customRequest=rmt;Ft.deleteApiKey=nmt;Ft.deleteBy=Nmt;Ft.deleteDictionaryEntries=imt;Ft.deleteIndex=Lmt;Ft.deleteObject=Omt;Ft.deleteObjects=cye;Ft.deleteRule=Mmt;Ft.deleteSynonym=Umt;Ft.exists=_mt;Ft.findAnswers=Hmt;Ft.findObject=jmt;Ft.generateSecuredApiKey=smt;Ft.getApiKey=J2;Ft.getAppTask=aye;Ft.getDictionarySettings=omt;Ft.getLogs=amt;Ft.getObject=qmt;Ft.getObjectPosition=Gmt;Ft.getObjects=Ymt;Ft.getRule=Wmt;Ft.getSecuredApiKeyRemainingValidity=lmt;Ft.getSettings=uye;Ft.getSynonym=Kmt;Ft.getTask=Aye;Ft.getTopUserIDs=cmt;Ft.getUserID=umt;Ft.hasPendingMappings=Amt;Ft.initIndex=X2;Ft.listApiKeys=fmt;Ft.listClusters=pmt;Ft.listIndices=hmt;Ft.listUserIDs=gmt;Ft.moveIndex=dmt;Ft.multipleBatch=mmt;Ft.multipleGetObjects=ymt;Ft.multipleQueries=Emt;Ft.multipleSearchForFacetValues=Cmt;Ft.partialUpdateObject=Vmt;Ft.partialUpdateObjects=fye;Ft.removeUserID=wmt;Ft.replaceAllObjects=zmt;Ft.replaceAllRules=Jmt;Ft.replaceAllSynonyms=Xmt;Ft.replaceDictionaryEntries=Imt;Ft.restoreApiKey=Bmt;Ft.saveDictionaryEntries=vmt;Ft.saveObject=Zmt;Ft.saveObjects=YH;Ft.saveRule=$mt;Ft.saveRules=WH;Ft.saveSynonym=eyt;Ft.saveSynonyms=KH;Ft.search=pye;Ft.searchDictionaryEntries=Dmt;Ft.searchForFacetValues=hye;Ft.searchRules=gye;Ft.searchSynonyms=dye;Ft.searchUserIDs=Pmt;Ft.setDictionarySettings=Smt;Ft.setSettings=tyt;Ft.updateApiKey=bmt;Ft.waitAppTask=xC;Ft.waitTask=Zi});var Eye=_((YWt,yye)=>{yye.exports=mye()});var Cye=_(xk=>{\"use strict\";Object.defineProperty(xk,\"__esModule\",{value:!0});function syt(){return{debug(t,e){return Promise.resolve()},info(t,e){return Promise.resolve()},error(t,e){return Promise.resolve()}}}var oyt={Debug:1,Info:2,Error:3};xk.LogLevelEnum=oyt;xk.createNullLogger=syt});var Iye=_((KWt,wye)=>{wye.exports=Cye()});var Pye=_(VH=>{\"use strict\";Object.defineProperty(VH,\"__esModule\",{value:!0});var Bye=Be(\"http\"),vye=Be(\"https\"),ayt=Be(\"url\"),Dye={keepAlive:!0},lyt=new Bye.Agent(Dye),cyt=new vye.Agent(Dye);function uyt({agent:t,httpAgent:e,httpsAgent:r,requesterOptions:o={}}={}){let a=e||t||lyt,n=r||t||cyt;return{send(u){return new Promise(A=>{let p=ayt.parse(u.url),h=p.query===null?p.pathname:`${p.pathname}?${p.query}`,C={...o,agent:p.protocol===\"https:\"?n:a,hostname:p.hostname,path:h,method:u.method,headers:{...o&&o.headers?o.headers:{},...u.headers},...p.port!==void 0?{port:p.port||\"\"}:{}},I=(p.protocol===\"https:\"?vye:Bye).request(C,R=>{let L=[];R.on(\"data\",U=>{L=L.concat(U)}),R.on(\"end\",()=>{clearTimeout(x),clearTimeout(E),A({status:R.statusCode||0,content:Buffer.concat(L).toString(),isTimedOut:!1})})}),v=(R,L)=>setTimeout(()=>{I.abort(),A({status:0,content:L,isTimedOut:!0})},R*1e3),x=v(u.connectTimeout,\"Connection timeout\"),E;I.on(\"error\",R=>{clearTimeout(x),clearTimeout(E),A({status:0,content:R.message,isTimedOut:!1})}),I.once(\"response\",()=>{clearTimeout(x),E=v(u.responseTimeout,\"Socket timeout\")}),u.data!==void 0&&I.write(u.data),I.end()})},destroy(){return a.destroy(),n.destroy(),Promise.resolve()}}}VH.createNodeHttpRequester=uyt});var bye=_((zWt,Sye)=>{Sye.exports=Pye()});var Fye=_((JWt,Qye)=>{\"use strict\";var xye=Pme(),Ayt=xme(),kC=$me(),JH=G2(),zH=nye(),Ut=Eye(),fyt=Iye(),pyt=bye(),hyt=K2();function kye(t,e,r){let o={appId:t,apiKey:e,timeouts:{connect:2,read:5,write:30},requester:pyt.createNodeHttpRequester(),logger:fyt.createNullLogger(),responsesCache:xye.createNullCache(),requestsCache:xye.createNullCache(),hostsCache:Ayt.createInMemoryCache(),userAgent:hyt.createUserAgent(JH.version).add({segment:\"Node.js\",version:process.versions.node})},a={...o,...r},n=()=>u=>zH.createPersonalizationClient({...o,...u,methods:{getPersonalizationStrategy:zH.getPersonalizationStrategy,setPersonalizationStrategy:zH.setPersonalizationStrategy}});return Ut.createSearchClient({...a,methods:{search:Ut.multipleQueries,searchForFacetValues:Ut.multipleSearchForFacetValues,multipleBatch:Ut.multipleBatch,multipleGetObjects:Ut.multipleGetObjects,multipleQueries:Ut.multipleQueries,copyIndex:Ut.copyIndex,copySettings:Ut.copySettings,copyRules:Ut.copyRules,copySynonyms:Ut.copySynonyms,moveIndex:Ut.moveIndex,listIndices:Ut.listIndices,getLogs:Ut.getLogs,listClusters:Ut.listClusters,multipleSearchForFacetValues:Ut.multipleSearchForFacetValues,getApiKey:Ut.getApiKey,addApiKey:Ut.addApiKey,listApiKeys:Ut.listApiKeys,updateApiKey:Ut.updateApiKey,deleteApiKey:Ut.deleteApiKey,restoreApiKey:Ut.restoreApiKey,assignUserID:Ut.assignUserID,assignUserIDs:Ut.assignUserIDs,getUserID:Ut.getUserID,searchUserIDs:Ut.searchUserIDs,listUserIDs:Ut.listUserIDs,getTopUserIDs:Ut.getTopUserIDs,removeUserID:Ut.removeUserID,hasPendingMappings:Ut.hasPendingMappings,generateSecuredApiKey:Ut.generateSecuredApiKey,getSecuredApiKeyRemainingValidity:Ut.getSecuredApiKeyRemainingValidity,destroy:JH.destroy,clearDictionaryEntries:Ut.clearDictionaryEntries,deleteDictionaryEntries:Ut.deleteDictionaryEntries,getDictionarySettings:Ut.getDictionarySettings,getAppTask:Ut.getAppTask,replaceDictionaryEntries:Ut.replaceDictionaryEntries,saveDictionaryEntries:Ut.saveDictionaryEntries,searchDictionaryEntries:Ut.searchDictionaryEntries,setDictionarySettings:Ut.setDictionarySettings,waitAppTask:Ut.waitAppTask,customRequest:Ut.customRequest,initIndex:u=>A=>Ut.initIndex(u)(A,{methods:{batch:Ut.batch,delete:Ut.deleteIndex,findAnswers:Ut.findAnswers,getObject:Ut.getObject,getObjects:Ut.getObjects,saveObject:Ut.saveObject,saveObjects:Ut.saveObjects,search:Ut.search,searchForFacetValues:Ut.searchForFacetValues,waitTask:Ut.waitTask,setSettings:Ut.setSettings,getSettings:Ut.getSettings,partialUpdateObject:Ut.partialUpdateObject,partialUpdateObjects:Ut.partialUpdateObjects,deleteObject:Ut.deleteObject,deleteObjects:Ut.deleteObjects,deleteBy:Ut.deleteBy,clearObjects:Ut.clearObjects,browseObjects:Ut.browseObjects,getObjectPosition:Ut.getObjectPosition,findObject:Ut.findObject,exists:Ut.exists,saveSynonym:Ut.saveSynonym,saveSynonyms:Ut.saveSynonyms,getSynonym:Ut.getSynonym,searchSynonyms:Ut.searchSynonyms,browseSynonyms:Ut.browseSynonyms,deleteSynonym:Ut.deleteSynonym,clearSynonyms:Ut.clearSynonyms,replaceAllObjects:Ut.replaceAllObjects,replaceAllSynonyms:Ut.replaceAllSynonyms,searchRules:Ut.searchRules,getRule:Ut.getRule,deleteRule:Ut.deleteRule,saveRule:Ut.saveRule,saveRules:Ut.saveRules,replaceAllRules:Ut.replaceAllRules,browseRules:Ut.browseRules,clearRules:Ut.clearRules}}),initAnalytics:()=>u=>kC.createAnalyticsClient({...o,...u,methods:{addABTest:kC.addABTest,getABTest:kC.getABTest,getABTests:kC.getABTests,stopABTest:kC.stopABTest,deleteABTest:kC.deleteABTest}}),initPersonalization:n,initRecommendation:()=>u=>(a.logger.info(\"The `initRecommendation` method is deprecated. Use `initPersonalization` instead.\"),n()(u))}})}kye.version=JH.version;Qye.exports=kye});var ZH=_((XWt,XH)=>{var Rye=Fye();XH.exports=Rye;XH.exports.default=Rye});var t6=_(($Wt,Lye)=>{\"use strict\";var Nye=Object.getOwnPropertySymbols,dyt=Object.prototype.hasOwnProperty,myt=Object.prototype.propertyIsEnumerable;function yyt(t){if(t==null)throw new TypeError(\"Object.assign cannot be called with null or undefined\");return Object(t)}function Eyt(){try{if(!Object.assign)return!1;var t=new String(\"abc\");if(t[5]=\"de\",Object.getOwnPropertyNames(t)[0]===\"5\")return!1;for(var e={},r=0;r<10;r++)e[\"_\"+String.fromCharCode(r)]=r;var o=Object.getOwnPropertyNames(e).map(function(n){return e[n]});if(o.join(\"\")!==\"0123456789\")return!1;var a={};return\"abcdefghijklmnopqrst\".split(\"\").forEach(function(n){a[n]=n}),Object.keys(Object.assign({},a)).join(\"\")===\"abcdefghijklmnopqrst\"}catch{return!1}}Lye.exports=Eyt()?Object.assign:function(t,e){for(var r,o=yyt(t),a,n=1;n<arguments.length;n++){r=Object(arguments[n]);for(var u in r)dyt.call(r,u)&&(o[u]=r[u]);if(Nye){a=Nye(r);for(var A=0;A<a.length;A++)myt.call(r,a[A])&&(o[a[A]]=r[a[A]])}}return o}});var Vye=_(Nn=>{\"use strict\";var o6=t6(),$c=typeof Symbol==\"function\"&&Symbol.for,Z2=$c?Symbol.for(\"react.element\"):60103,Cyt=$c?Symbol.for(\"react.portal\"):60106,wyt=$c?Symbol.for(\"react.fragment\"):60107,Iyt=$c?Symbol.for(\"react.strict_mode\"):60108,Byt=$c?Symbol.for(\"react.profiler\"):60114,vyt=$c?Symbol.for(\"react.provider\"):60109,Dyt=$c?Symbol.for(\"react.context\"):60110,Pyt=$c?Symbol.for(\"react.forward_ref\"):60112,Syt=$c?Symbol.for(\"react.suspense\"):60113,byt=$c?Symbol.for(\"react.memo\"):60115,xyt=$c?Symbol.for(\"react.lazy\"):60116,Oye=typeof Symbol==\"function\"&&Symbol.iterator;function $2(t){for(var e=\"https://reactjs.org/docs/error-decoder.html?invariant=\"+t,r=1;r<arguments.length;r++)e+=\"&args[]=\"+encodeURIComponent(arguments[r]);return\"Minified React error #\"+t+\"; visit \"+e+\" for the full message or use the non-minified dev environment for full errors and additional helpful warnings.\"}var Mye={isMounted:function(){return!1},enqueueForceUpdate:function(){},enqueueReplaceState:function(){},enqueueSetState:function(){}},Uye={};function QC(t,e,r){this.props=t,this.context=e,this.refs=Uye,this.updater=r||Mye}QC.prototype.isReactComponent={};QC.prototype.setState=function(t,e){if(typeof t!=\"object\"&&typeof t!=\"function\"&&t!=null)throw Error($2(85));this.updater.enqueueSetState(this,t,e,\"setState\")};QC.prototype.forceUpdate=function(t){this.updater.enqueueForceUpdate(this,t,\"forceUpdate\")};function _ye(){}_ye.prototype=QC.prototype;function a6(t,e,r){this.props=t,this.context=e,this.refs=Uye,this.updater=r||Mye}var l6=a6.prototype=new _ye;l6.constructor=a6;o6(l6,QC.prototype);l6.isPureReactComponent=!0;var c6={current:null},Hye=Object.prototype.hasOwnProperty,jye={key:!0,ref:!0,__self:!0,__source:!0};function qye(t,e,r){var o,a={},n=null,u=null;if(e!=null)for(o in e.ref!==void 0&&(u=e.ref),e.key!==void 0&&(n=\"\"+e.key),e)Hye.call(e,o)&&!jye.hasOwnProperty(o)&&(a[o]=e[o]);var A=arguments.length-2;if(A===1)a.children=r;else if(1<A){for(var p=Array(A),h=0;h<A;h++)p[h]=arguments[h+2];a.children=p}if(t&&t.defaultProps)for(o in A=t.defaultProps,A)a[o]===void 0&&(a[o]=A[o]);return{$$typeof:Z2,type:t,key:n,ref:u,props:a,_owner:c6.current}}function kyt(t,e){return{$$typeof:Z2,type:t.type,key:e,ref:t.ref,props:t.props,_owner:t._owner}}function u6(t){return typeof t==\"object\"&&t!==null&&t.$$typeof===Z2}function Qyt(t){var e={\"=\":\"=0\",\":\":\"=2\"};return\"$\"+(\"\"+t).replace(/[=:]/g,function(r){return e[r]})}var Gye=/\\/+/g,kk=[];function Yye(t,e,r,o){if(kk.length){var a=kk.pop();return a.result=t,a.keyPrefix=e,a.func=r,a.context=o,a.count=0,a}return{result:t,keyPrefix:e,func:r,context:o,count:0}}function Wye(t){t.result=null,t.keyPrefix=null,t.func=null,t.context=null,t.count=0,10>kk.length&&kk.push(t)}function n6(t,e,r,o){var a=typeof t;(a===\"undefined\"||a===\"boolean\")&&(t=null);var n=!1;if(t===null)n=!0;else switch(a){case\"string\":case\"number\":n=!0;break;case\"object\":switch(t.$$typeof){case Z2:case Cyt:n=!0}}if(n)return r(o,t,e===\"\"?\".\"+r6(t,0):e),1;if(n=0,e=e===\"\"?\".\":e+\":\",Array.isArray(t))for(var u=0;u<t.length;u++){a=t[u];var A=e+r6(a,u);n+=n6(a,A,r,o)}else if(t===null||typeof t!=\"object\"?A=null:(A=Oye&&t[Oye]||t[\"@@iterator\"],A=typeof A==\"function\"?A:null),typeof A==\"function\")for(t=A.call(t),u=0;!(a=t.next()).done;)a=a.value,A=e+r6(a,u++),n+=n6(a,A,r,o);else if(a===\"object\")throw r=\"\"+t,Error($2(31,r===\"[object Object]\"?\"object with keys {\"+Object.keys(t).join(\", \")+\"}\":r,\"\"));return n}function i6(t,e,r){return t==null?0:n6(t,\"\",e,r)}function r6(t,e){return typeof t==\"object\"&&t!==null&&t.key!=null?Qyt(t.key):e.toString(36)}function Fyt(t,e){t.func.call(t.context,e,t.count++)}function Ryt(t,e,r){var o=t.result,a=t.keyPrefix;t=t.func.call(t.context,e,t.count++),Array.isArray(t)?s6(t,o,r,function(n){return n}):t!=null&&(u6(t)&&(t=kyt(t,a+(!t.key||e&&e.key===t.key?\"\":(\"\"+t.key).replace(Gye,\"$&/\")+\"/\")+r)),o.push(t))}function s6(t,e,r,o,a){var n=\"\";r!=null&&(n=(\"\"+r).replace(Gye,\"$&/\")+\"/\"),e=Yye(e,n,o,a),i6(t,Ryt,e),Wye(e)}var Kye={current:null};function zf(){var t=Kye.current;if(t===null)throw Error($2(321));return t}var Tyt={ReactCurrentDispatcher:Kye,ReactCurrentBatchConfig:{suspense:null},ReactCurrentOwner:c6,IsSomeRendererActing:{current:!1},assign:o6};Nn.Children={map:function(t,e,r){if(t==null)return t;var o=[];return s6(t,o,null,e,r),o},forEach:function(t,e,r){if(t==null)return t;e=Yye(null,null,e,r),i6(t,Fyt,e),Wye(e)},count:function(t){return i6(t,function(){return null},null)},toArray:function(t){var e=[];return s6(t,e,null,function(r){return r}),e},only:function(t){if(!u6(t))throw Error($2(143));return t}};Nn.Component=QC;Nn.Fragment=wyt;Nn.Profiler=Byt;Nn.PureComponent=a6;Nn.StrictMode=Iyt;Nn.Suspense=Syt;Nn.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED=Tyt;Nn.cloneElement=function(t,e,r){if(t==null)throw Error($2(267,t));var o=o6({},t.props),a=t.key,n=t.ref,u=t._owner;if(e!=null){if(e.ref!==void 0&&(n=e.ref,u=c6.current),e.key!==void 0&&(a=\"\"+e.key),t.type&&t.type.defaultProps)var A=t.type.defaultProps;for(p in e)Hye.call(e,p)&&!jye.hasOwnProperty(p)&&(o[p]=e[p]===void 0&&A!==void 0?A[p]:e[p])}var p=arguments.length-2;if(p===1)o.children=r;else if(1<p){A=Array(p);for(var h=0;h<p;h++)A[h]=arguments[h+2];o.children=A}return{$$typeof:Z2,type:t.type,key:a,ref:n,props:o,_owner:u}};Nn.createContext=function(t,e){return e===void 0&&(e=null),t={$$typeof:Dyt,_calculateChangedBits:e,_currentValue:t,_currentValue2:t,_threadCount:0,Provider:null,Consumer:null},t.Provider={$$typeof:vyt,_context:t},t.Consumer=t};Nn.createElement=qye;Nn.createFactory=function(t){var e=qye.bind(null,t);return e.type=t,e};Nn.createRef=function(){return{current:null}};Nn.forwardRef=function(t){return{$$typeof:Pyt,render:t}};Nn.isValidElement=u6;Nn.lazy=function(t){return{$$typeof:xyt,_ctor:t,_status:-1,_result:null}};Nn.memo=function(t,e){return{$$typeof:byt,type:t,compare:e===void 0?null:e}};Nn.useCallback=function(t,e){return zf().useCallback(t,e)};Nn.useContext=function(t,e){return zf().useContext(t,e)};Nn.useDebugValue=function(){};Nn.useEffect=function(t,e){return zf().useEffect(t,e)};Nn.useImperativeHandle=function(t,e,r){return zf().useImperativeHandle(t,e,r)};Nn.useLayoutEffect=function(t,e){return zf().useLayoutEffect(t,e)};Nn.useMemo=function(t,e){return zf().useMemo(t,e)};Nn.useReducer=function(t,e,r){return zf().useReducer(t,e,r)};Nn.useRef=function(t){return zf().useRef(t)};Nn.useState=function(t){return zf().useState(t)};Nn.version=\"16.13.1\"});var sn=_((tKt,zye)=>{\"use strict\";zye.exports=Vye()});var f6=_((rKt,A6)=>{\"use strict\";var An=A6.exports;A6.exports.default=An;var Ln=\"\\x1B[\",eB=\"\\x1B]\",FC=\"\\x07\",Qk=\";\",Jye=process.env.TERM_PROGRAM===\"Apple_Terminal\";An.cursorTo=(t,e)=>{if(typeof t!=\"number\")throw new TypeError(\"The `x` argument is required\");return typeof e!=\"number\"?Ln+(t+1)+\"G\":Ln+(e+1)+\";\"+(t+1)+\"H\"};An.cursorMove=(t,e)=>{if(typeof t!=\"number\")throw new TypeError(\"The `x` argument is required\");let r=\"\";return t<0?r+=Ln+-t+\"D\":t>0&&(r+=Ln+t+\"C\"),e<0?r+=Ln+-e+\"A\":e>0&&(r+=Ln+e+\"B\"),r};An.cursorUp=(t=1)=>Ln+t+\"A\";An.cursorDown=(t=1)=>Ln+t+\"B\";An.cursorForward=(t=1)=>Ln+t+\"C\";An.cursorBackward=(t=1)=>Ln+t+\"D\";An.cursorLeft=Ln+\"G\";An.cursorSavePosition=Jye?\"\\x1B7\":Ln+\"s\";An.cursorRestorePosition=Jye?\"\\x1B8\":Ln+\"u\";An.cursorGetPosition=Ln+\"6n\";An.cursorNextLine=Ln+\"E\";An.cursorPrevLine=Ln+\"F\";An.cursorHide=Ln+\"?25l\";An.cursorShow=Ln+\"?25h\";An.eraseLines=t=>{let e=\"\";for(let r=0;r<t;r++)e+=An.eraseLine+(r<t-1?An.cursorUp():\"\");return t&&(e+=An.cursorLeft),e};An.eraseEndLine=Ln+\"K\";An.eraseStartLine=Ln+\"1K\";An.eraseLine=Ln+\"2K\";An.eraseDown=Ln+\"J\";An.eraseUp=Ln+\"1J\";An.eraseScreen=Ln+\"2J\";An.scrollUp=Ln+\"S\";An.scrollDown=Ln+\"T\";An.clearScreen=\"\\x1Bc\";An.clearTerminal=process.platform===\"win32\"?`${An.eraseScreen}${Ln}0f`:`${An.eraseScreen}${Ln}3J${Ln}H`;An.beep=FC;An.link=(t,e)=>[eB,\"8\",Qk,Qk,e,FC,t,eB,\"8\",Qk,Qk,FC].join(\"\");An.image=(t,e={})=>{let r=`${eB}1337;File=inline=1`;return e.width&&(r+=`;width=${e.width}`),e.height&&(r+=`;height=${e.height}`),e.preserveAspectRatio===!1&&(r+=\";preserveAspectRatio=0\"),r+\":\"+t.toString(\"base64\")+FC};An.iTerm={setCwd:(t=process.cwd())=>`${eB}50;CurrentDir=${t}${FC}`,annotation:(t,e={})=>{let r=`${eB}1337;`,o=typeof e.x<\"u\",a=typeof e.y<\"u\";if((o||a)&&!(o&&a&&typeof e.length<\"u\"))throw new Error(\"`x`, `y` and `length` must be defined when `x` or `y` is defined\");return t=t.replace(/\\|/g,\"\"),r+=e.isHidden?\"AddHiddenAnnotation=\":\"AddAnnotation=\",e.length>0?r+=(o?[t,e.length,e.x,e.y]:[e.length,t]).join(\"|\"):r+=t,r+FC}}});var Zye=_((nKt,p6)=>{\"use strict\";var Xye=(t,e)=>{for(let r of Reflect.ownKeys(e))Object.defineProperty(t,r,Object.getOwnPropertyDescriptor(e,r));return t};p6.exports=Xye;p6.exports.default=Xye});var eEe=_((iKt,Rk)=>{\"use strict\";var Nyt=Zye(),Fk=new WeakMap,$ye=(t,e={})=>{if(typeof t!=\"function\")throw new TypeError(\"Expected a function\");let r,o=0,a=t.displayName||t.name||\"<anonymous>\",n=function(...u){if(Fk.set(n,++o),o===1)r=t.apply(this,u),t=null;else if(e.throw===!0)throw new Error(`Function \\`${a}\\` can only be called once`);return r};return Nyt(n,t),Fk.set(n,o),n};Rk.exports=$ye;Rk.exports.default=$ye;Rk.exports.callCount=t=>{if(!Fk.has(t))throw new Error(`The given function \\`${t.name}\\` is not wrapped by the \\`onetime\\` package`);return Fk.get(t)}});var tEe=_((sKt,Tk)=>{Tk.exports=[\"SIGABRT\",\"SIGALRM\",\"SIGHUP\",\"SIGINT\",\"SIGTERM\"];process.platform!==\"win32\"&&Tk.exports.push(\"SIGVTALRM\",\"SIGXCPU\",\"SIGXFSZ\",\"SIGUSR2\",\"SIGTRAP\",\"SIGSYS\",\"SIGQUIT\",\"SIGIOT\");process.platform===\"linux\"&&Tk.exports.push(\"SIGIO\",\"SIGPOLL\",\"SIGPWR\",\"SIGSTKFLT\",\"SIGUNUSED\")});var d6=_((oKt,NC)=>{var Ei=global.process,rm=function(t){return t&&typeof t==\"object\"&&typeof t.removeListener==\"function\"&&typeof t.emit==\"function\"&&typeof t.reallyExit==\"function\"&&typeof t.listeners==\"function\"&&typeof t.kill==\"function\"&&typeof t.pid==\"number\"&&typeof t.on==\"function\"};rm(Ei)?(rEe=Be(\"assert\"),RC=tEe(),nEe=/^win/i.test(Ei.platform),tB=Be(\"events\"),typeof tB!=\"function\"&&(tB=tB.EventEmitter),Ei.__signal_exit_emitter__?Ts=Ei.__signal_exit_emitter__:(Ts=Ei.__signal_exit_emitter__=new tB,Ts.count=0,Ts.emitted={}),Ts.infinite||(Ts.setMaxListeners(1/0),Ts.infinite=!0),NC.exports=function(t,e){if(!rm(global.process))return function(){};rEe.equal(typeof t,\"function\",\"a callback must be provided for exit handler\"),TC===!1&&h6();var r=\"exit\";e&&e.alwaysLast&&(r=\"afterexit\");var o=function(){Ts.removeListener(r,t),Ts.listeners(\"exit\").length===0&&Ts.listeners(\"afterexit\").length===0&&Nk()};return Ts.on(r,t),o},Nk=function(){!TC||!rm(global.process)||(TC=!1,RC.forEach(function(e){try{Ei.removeListener(e,Lk[e])}catch{}}),Ei.emit=Ok,Ei.reallyExit=g6,Ts.count-=1)},NC.exports.unload=Nk,nm=function(e,r,o){Ts.emitted[e]||(Ts.emitted[e]=!0,Ts.emit(e,r,o))},Lk={},RC.forEach(function(t){Lk[t]=function(){if(!!rm(global.process)){var r=Ei.listeners(t);r.length===Ts.count&&(Nk(),nm(\"exit\",null,t),nm(\"afterexit\",null,t),nEe&&t===\"SIGHUP\"&&(t=\"SIGINT\"),Ei.kill(Ei.pid,t))}}}),NC.exports.signals=function(){return RC},TC=!1,h6=function(){TC||!rm(global.process)||(TC=!0,Ts.count+=1,RC=RC.filter(function(e){try{return Ei.on(e,Lk[e]),!0}catch{return!1}}),Ei.emit=sEe,Ei.reallyExit=iEe)},NC.exports.load=h6,g6=Ei.reallyExit,iEe=function(e){!rm(global.process)||(Ei.exitCode=e||0,nm(\"exit\",Ei.exitCode,null),nm(\"afterexit\",Ei.exitCode,null),g6.call(Ei,Ei.exitCode))},Ok=Ei.emit,sEe=function(e,r){if(e===\"exit\"&&rm(global.process)){r!==void 0&&(Ei.exitCode=r);var o=Ok.apply(this,arguments);return nm(\"exit\",Ei.exitCode,null),nm(\"afterexit\",Ei.exitCode,null),o}else return Ok.apply(this,arguments)}):NC.exports=function(){return function(){}};var rEe,RC,nEe,tB,Ts,Nk,nm,Lk,TC,h6,g6,iEe,Ok,sEe});var aEe=_((aKt,oEe)=>{\"use strict\";var Lyt=eEe(),Oyt=d6();oEe.exports=Lyt(()=>{Oyt(()=>{process.stderr.write(\"\\x1B[?25h\")},{alwaysLast:!0})})});var m6=_(LC=>{\"use strict\";var Myt=aEe(),Mk=!1;LC.show=(t=process.stderr)=>{!t.isTTY||(Mk=!1,t.write(\"\\x1B[?25h\"))};LC.hide=(t=process.stderr)=>{!t.isTTY||(Myt(),Mk=!0,t.write(\"\\x1B[?25l\"))};LC.toggle=(t,e)=>{t!==void 0&&(Mk=t),Mk?LC.show(e):LC.hide(e)}});var AEe=_(rB=>{\"use strict\";var uEe=rB&&rB.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};Object.defineProperty(rB,\"__esModule\",{value:!0});var lEe=uEe(f6()),cEe=uEe(m6()),Uyt=(t,{showCursor:e=!1}={})=>{let r=0,o=\"\",a=!1,n=u=>{!e&&!a&&(cEe.default.hide(),a=!0);let A=u+`\n`;A!==o&&(o=A,t.write(lEe.default.eraseLines(r)+A),r=A.split(`\n`).length)};return n.clear=()=>{t.write(lEe.default.eraseLines(r)),o=\"\",r=0},n.done=()=>{o=\"\",r=0,e||(cEe.default.show(),a=!1)},n};rB.default={create:Uyt}});var fEe=_((uKt,_yt)=>{_yt.exports=[{name:\"AppVeyor\",constant:\"APPVEYOR\",env:\"APPVEYOR\",pr:\"APPVEYOR_PULL_REQUEST_NUMBER\"},{name:\"Azure Pipelines\",constant:\"AZURE_PIPELINES\",env:\"SYSTEM_TEAMFOUNDATIONCOLLECTIONURI\",pr:\"SYSTEM_PULLREQUEST_PULLREQUESTID\"},{name:\"Bamboo\",constant:\"BAMBOO\",env:\"bamboo_planKey\"},{name:\"Bitbucket Pipelines\",constant:\"BITBUCKET\",env:\"BITBUCKET_COMMIT\",pr:\"BITBUCKET_PR_ID\"},{name:\"Bitrise\",constant:\"BITRISE\",env:\"BITRISE_IO\",pr:\"BITRISE_PULL_REQUEST\"},{name:\"Buddy\",constant:\"BUDDY\",env:\"BUDDY_WORKSPACE_ID\",pr:\"BUDDY_EXECUTION_PULL_REQUEST_ID\"},{name:\"Buildkite\",constant:\"BUILDKITE\",env:\"BUILDKITE\",pr:{env:\"BUILDKITE_PULL_REQUEST\",ne:\"false\"}},{name:\"CircleCI\",constant:\"CIRCLE\",env:\"CIRCLECI\",pr:\"CIRCLE_PULL_REQUEST\"},{name:\"Cirrus CI\",constant:\"CIRRUS\",env:\"CIRRUS_CI\",pr:\"CIRRUS_PR\"},{name:\"AWS CodeBuild\",constant:\"CODEBUILD\",env:\"CODEBUILD_BUILD_ARN\"},{name:\"Codeship\",constant:\"CODESHIP\",env:{CI_NAME:\"codeship\"}},{name:\"Drone\",constant:\"DRONE\",env:\"DRONE\",pr:{DRONE_BUILD_EVENT:\"pull_request\"}},{name:\"dsari\",constant:\"DSARI\",env:\"DSARI\"},{name:\"GitLab CI\",constant:\"GITLAB\",env:\"GITLAB_CI\"},{name:\"GoCD\",constant:\"GOCD\",env:\"GO_PIPELINE_LABEL\"},{name:\"Hudson\",constant:\"HUDSON\",env:\"HUDSON_URL\"},{name:\"Jenkins\",constant:\"JENKINS\",env:[\"JENKINS_URL\",\"BUILD_ID\"],pr:{any:[\"ghprbPullId\",\"CHANGE_ID\"]}},{name:\"Magnum CI\",constant:\"MAGNUM\",env:\"MAGNUM\"},{name:\"Netlify CI\",constant:\"NETLIFY\",env:\"NETLIFY_BUILD_BASE\",pr:{env:\"PULL_REQUEST\",ne:\"false\"}},{name:\"Sail CI\",constant:\"SAIL\",env:\"SAILCI\",pr:\"SAIL_PULL_REQUEST_NUMBER\"},{name:\"Semaphore\",constant:\"SEMAPHORE\",env:\"SEMAPHORE\",pr:\"PULL_REQUEST_NUMBER\"},{name:\"Shippable\",constant:\"SHIPPABLE\",env:\"SHIPPABLE\",pr:{IS_PULL_REQUEST:\"true\"}},{name:\"Solano CI\",constant:\"SOLANO\",env:\"TDDIUM\",pr:\"TDDIUM_PR_ID\"},{name:\"Strider CD\",constant:\"STRIDER\",env:\"STRIDER\"},{name:\"TaskCluster\",constant:\"TASKCLUSTER\",env:[\"TASK_ID\",\"RUN_ID\"]},{name:\"TeamCity\",constant:\"TEAMCITY\",env:\"TEAMCITY_VERSION\"},{name:\"Travis CI\",constant:\"TRAVIS\",env:\"TRAVIS\",pr:{env:\"TRAVIS_PULL_REQUEST\",ne:\"false\"}}]});var gEe=_(gl=>{\"use strict\";var hEe=fEe(),pA=process.env;Object.defineProperty(gl,\"_vendors\",{value:hEe.map(function(t){return t.constant})});gl.name=null;gl.isPR=null;hEe.forEach(function(t){var e=Array.isArray(t.env)?t.env:[t.env],r=e.every(function(o){return pEe(o)});if(gl[t.constant]=r,r)switch(gl.name=t.name,typeof t.pr){case\"string\":gl.isPR=!!pA[t.pr];break;case\"object\":\"env\"in t.pr?gl.isPR=t.pr.env in pA&&pA[t.pr.env]!==t.pr.ne:\"any\"in t.pr?gl.isPR=t.pr.any.some(function(o){return!!pA[o]}):gl.isPR=pEe(t.pr);break;default:gl.isPR=null}});gl.isCI=!!(pA.CI||pA.CONTINUOUS_INTEGRATION||pA.BUILD_NUMBER||pA.RUN_ID||gl.name);function pEe(t){return typeof t==\"string\"?!!pA[t]:Object.keys(t).every(function(e){return pA[e]===t[e]})}});var mEe=_((fKt,dEe)=>{\"use strict\";dEe.exports=gEe().isCI});var EEe=_((pKt,yEe)=>{\"use strict\";var Hyt=t=>{let e=new Set;do for(let r of Reflect.ownKeys(t))e.add([t,r]);while((t=Reflect.getPrototypeOf(t))&&t!==Object.prototype);return e};yEe.exports=(t,{include:e,exclude:r}={})=>{let o=a=>{let n=u=>typeof u==\"string\"?a===u:u.test(a);return e?e.some(n):r?!r.some(n):!0};for(let[a,n]of Hyt(t.constructor.prototype)){if(n===\"constructor\"||!o(n))continue;let u=Reflect.getOwnPropertyDescriptor(a,n);u&&typeof u.value==\"function\"&&(t[n]=t[n].bind(t))}return t}});var PEe=_(kn=>{\"use strict\";Object.defineProperty(kn,\"__esModule\",{value:!0});var MC,sB,qk,Gk,v6;typeof window>\"u\"||typeof MessageChannel!=\"function\"?(OC=null,y6=null,E6=function(){if(OC!==null)try{var t=kn.unstable_now();OC(!0,t),OC=null}catch(e){throw setTimeout(E6,0),e}},CEe=Date.now(),kn.unstable_now=function(){return Date.now()-CEe},MC=function(t){OC!==null?setTimeout(MC,0,t):(OC=t,setTimeout(E6,0))},sB=function(t,e){y6=setTimeout(t,e)},qk=function(){clearTimeout(y6)},Gk=function(){return!1},v6=kn.unstable_forceFrameRate=function(){}):(Uk=window.performance,C6=window.Date,wEe=window.setTimeout,IEe=window.clearTimeout,typeof console<\"u\"&&(BEe=window.cancelAnimationFrame,typeof window.requestAnimationFrame!=\"function\"&&console.error(\"This browser doesn't support requestAnimationFrame. Make sure that you load a polyfill in older browsers. https://fb.me/react-polyfills\"),typeof BEe!=\"function\"&&console.error(\"This browser doesn't support cancelAnimationFrame. Make sure that you load a polyfill in older browsers. https://fb.me/react-polyfills\")),typeof Uk==\"object\"&&typeof Uk.now==\"function\"?kn.unstable_now=function(){return Uk.now()}:(vEe=C6.now(),kn.unstable_now=function(){return C6.now()-vEe}),nB=!1,iB=null,_k=-1,w6=5,I6=0,Gk=function(){return kn.unstable_now()>=I6},v6=function(){},kn.unstable_forceFrameRate=function(t){0>t||125<t?console.error(\"forceFrameRate takes a positive int between 0 and 125, forcing framerates higher than 125 fps is not unsupported\"):w6=0<t?Math.floor(1e3/t):5},B6=new MessageChannel,Hk=B6.port2,B6.port1.onmessage=function(){if(iB!==null){var t=kn.unstable_now();I6=t+w6;try{iB(!0,t)?Hk.postMessage(null):(nB=!1,iB=null)}catch(e){throw Hk.postMessage(null),e}}else nB=!1},MC=function(t){iB=t,nB||(nB=!0,Hk.postMessage(null))},sB=function(t,e){_k=wEe(function(){t(kn.unstable_now())},e)},qk=function(){IEe(_k),_k=-1});var OC,y6,E6,CEe,Uk,C6,wEe,IEe,BEe,vEe,nB,iB,_k,w6,I6,B6,Hk;function D6(t,e){var r=t.length;t.push(e);e:for(;;){var o=Math.floor((r-1)/2),a=t[o];if(a!==void 0&&0<jk(a,e))t[o]=e,t[r]=a,r=o;else break e}}function nc(t){return t=t[0],t===void 0?null:t}function Yk(t){var e=t[0];if(e!==void 0){var r=t.pop();if(r!==e){t[0]=r;e:for(var o=0,a=t.length;o<a;){var n=2*(o+1)-1,u=t[n],A=n+1,p=t[A];if(u!==void 0&&0>jk(u,r))p!==void 0&&0>jk(p,u)?(t[o]=p,t[A]=r,o=A):(t[o]=u,t[n]=r,o=n);else if(p!==void 0&&0>jk(p,r))t[o]=p,t[A]=r,o=A;else break e}}return e}return null}function jk(t,e){var r=t.sortIndex-e.sortIndex;return r!==0?r:t.id-e.id}var eu=[],m0=[],jyt=1,na=null,Lo=3,Wk=!1,im=!1,oB=!1;function Kk(t){for(var e=nc(m0);e!==null;){if(e.callback===null)Yk(m0);else if(e.startTime<=t)Yk(m0),e.sortIndex=e.expirationTime,D6(eu,e);else break;e=nc(m0)}}function P6(t){if(oB=!1,Kk(t),!im)if(nc(eu)!==null)im=!0,MC(S6);else{var e=nc(m0);e!==null&&sB(P6,e.startTime-t)}}function S6(t,e){im=!1,oB&&(oB=!1,qk()),Wk=!0;var r=Lo;try{for(Kk(e),na=nc(eu);na!==null&&(!(na.expirationTime>e)||t&&!Gk());){var o=na.callback;if(o!==null){na.callback=null,Lo=na.priorityLevel;var a=o(na.expirationTime<=e);e=kn.unstable_now(),typeof a==\"function\"?na.callback=a:na===nc(eu)&&Yk(eu),Kk(e)}else Yk(eu);na=nc(eu)}if(na!==null)var n=!0;else{var u=nc(m0);u!==null&&sB(P6,u.startTime-e),n=!1}return n}finally{na=null,Lo=r,Wk=!1}}function DEe(t){switch(t){case 1:return-1;case 2:return 250;case 5:return 1073741823;case 4:return 1e4;default:return 5e3}}var qyt=v6;kn.unstable_ImmediatePriority=1;kn.unstable_UserBlockingPriority=2;kn.unstable_NormalPriority=3;kn.unstable_IdlePriority=5;kn.unstable_LowPriority=4;kn.unstable_runWithPriority=function(t,e){switch(t){case 1:case 2:case 3:case 4:case 5:break;default:t=3}var r=Lo;Lo=t;try{return e()}finally{Lo=r}};kn.unstable_next=function(t){switch(Lo){case 1:case 2:case 3:var e=3;break;default:e=Lo}var r=Lo;Lo=e;try{return t()}finally{Lo=r}};kn.unstable_scheduleCallback=function(t,e,r){var o=kn.unstable_now();if(typeof r==\"object\"&&r!==null){var a=r.delay;a=typeof a==\"number\"&&0<a?o+a:o,r=typeof r.timeout==\"number\"?r.timeout:DEe(t)}else r=DEe(t),a=o;return r=a+r,t={id:jyt++,callback:e,priorityLevel:t,startTime:a,expirationTime:r,sortIndex:-1},a>o?(t.sortIndex=a,D6(m0,t),nc(eu)===null&&t===nc(m0)&&(oB?qk():oB=!0,sB(P6,a-o))):(t.sortIndex=r,D6(eu,t),im||Wk||(im=!0,MC(S6))),t};kn.unstable_cancelCallback=function(t){t.callback=null};kn.unstable_wrapCallback=function(t){var e=Lo;return function(){var r=Lo;Lo=e;try{return t.apply(this,arguments)}finally{Lo=r}}};kn.unstable_getCurrentPriorityLevel=function(){return Lo};kn.unstable_shouldYield=function(){var t=kn.unstable_now();Kk(t);var e=nc(eu);return e!==na&&na!==null&&e!==null&&e.callback!==null&&e.startTime<=t&&e.expirationTime<na.expirationTime||Gk()};kn.unstable_requestPaint=qyt;kn.unstable_continueExecution=function(){im||Wk||(im=!0,MC(S6))};kn.unstable_pauseExecution=function(){};kn.unstable_getFirstCallbackNode=function(){return nc(eu)};kn.unstable_Profiling=null});var b6=_((gKt,SEe)=>{\"use strict\";SEe.exports=PEe()});var bEe=_((dKt,aB)=>{aB.exports=function t(e){\"use strict\";var r=t6(),o=sn(),a=b6();function n(P){for(var D=\"https://reactjs.org/docs/error-decoder.html?invariant=\"+P,T=1;T<arguments.length;T++)D+=\"&args[]=\"+encodeURIComponent(arguments[T]);return\"Minified React error #\"+P+\"; visit \"+D+\" for the full message or use the non-minified dev environment for full errors and additional helpful warnings.\"}var u=o.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED;u.hasOwnProperty(\"ReactCurrentDispatcher\")||(u.ReactCurrentDispatcher={current:null}),u.hasOwnProperty(\"ReactCurrentBatchConfig\")||(u.ReactCurrentBatchConfig={suspense:null});var A=typeof Symbol==\"function\"&&Symbol.for,p=A?Symbol.for(\"react.element\"):60103,h=A?Symbol.for(\"react.portal\"):60106,C=A?Symbol.for(\"react.fragment\"):60107,I=A?Symbol.for(\"react.strict_mode\"):60108,v=A?Symbol.for(\"react.profiler\"):60114,x=A?Symbol.for(\"react.provider\"):60109,E=A?Symbol.for(\"react.context\"):60110,R=A?Symbol.for(\"react.concurrent_mode\"):60111,L=A?Symbol.for(\"react.forward_ref\"):60112,U=A?Symbol.for(\"react.suspense\"):60113,z=A?Symbol.for(\"react.suspense_list\"):60120,te=A?Symbol.for(\"react.memo\"):60115,le=A?Symbol.for(\"react.lazy\"):60116;A&&Symbol.for(\"react.fundamental\"),A&&Symbol.for(\"react.responder\"),A&&Symbol.for(\"react.scope\");var he=typeof Symbol==\"function\"&&Symbol.iterator;function Ae(P){return P===null||typeof P!=\"object\"?null:(P=he&&P[he]||P[\"@@iterator\"],typeof P==\"function\"?P:null)}function ye(P){if(P._status===-1){P._status=0;var D=P._ctor;D=D(),P._result=D,D.then(function(T){P._status===0&&(T=T.default,P._status=1,P._result=T)},function(T){P._status===0&&(P._status=2,P._result=T)})}}function ae(P){if(P==null)return null;if(typeof P==\"function\")return P.displayName||P.name||null;if(typeof P==\"string\")return P;switch(P){case C:return\"Fragment\";case h:return\"Portal\";case v:return\"Profiler\";case I:return\"StrictMode\";case U:return\"Suspense\";case z:return\"SuspenseList\"}if(typeof P==\"object\")switch(P.$$typeof){case E:return\"Context.Consumer\";case x:return\"Context.Provider\";case L:var D=P.render;return D=D.displayName||D.name||\"\",P.displayName||(D!==\"\"?\"ForwardRef(\"+D+\")\":\"ForwardRef\");case te:return ae(P.type);case le:if(P=P._status===1?P._result:null)return ae(P)}return null}function Ie(P){var D=P,T=P;if(P.alternate)for(;D.return;)D=D.return;else{P=D;do D=P,(D.effectTag&1026)!==0&&(T=D.return),P=D.return;while(P)}return D.tag===3?T:null}function Fe(P){if(Ie(P)!==P)throw Error(n(188))}function g(P){var D=P.alternate;if(!D){if(D=Ie(P),D===null)throw Error(n(188));return D!==P?null:P}for(var T=P,j=D;;){var Y=T.return;if(Y===null)break;var fe=Y.alternate;if(fe===null){if(j=Y.return,j!==null){T=j;continue}break}if(Y.child===fe.child){for(fe=Y.child;fe;){if(fe===T)return Fe(Y),P;if(fe===j)return Fe(Y),D;fe=fe.sibling}throw Error(n(188))}if(T.return!==j.return)T=Y,j=fe;else{for(var ve=!1,vt=Y.child;vt;){if(vt===T){ve=!0,T=Y,j=fe;break}if(vt===j){ve=!0,j=Y,T=fe;break}vt=vt.sibling}if(!ve){for(vt=fe.child;vt;){if(vt===T){ve=!0,T=fe,j=Y;break}if(vt===j){ve=!0,j=fe,T=Y;break}vt=vt.sibling}if(!ve)throw Error(n(189))}}if(T.alternate!==j)throw Error(n(190))}if(T.tag!==3)throw Error(n(188));return T.stateNode.current===T?P:D}function Ee(P){if(P=g(P),!P)return null;for(var D=P;;){if(D.tag===5||D.tag===6)return D;if(D.child)D.child.return=D,D=D.child;else{if(D===P)break;for(;!D.sibling;){if(!D.return||D.return===P)return null;D=D.return}D.sibling.return=D.return,D=D.sibling}}return null}function De(P){if(P=g(P),!P)return null;for(var D=P;;){if(D.tag===5||D.tag===6)return D;if(D.child&&D.tag!==4)D.child.return=D,D=D.child;else{if(D===P)break;for(;!D.sibling;){if(!D.return||D.return===P)return null;D=D.return}D.sibling.return=D.return,D=D.sibling}}return null}var ce=e.getPublicInstance,ne=e.getRootHostContext,ee=e.getChildHostContext,we=e.prepareForCommit,xe=e.resetAfterCommit,ht=e.createInstance,H=e.appendInitialChild,lt=e.finalizeInitialChildren,Te=e.prepareUpdate,ke=e.shouldSetTextContent,be=e.shouldDeprioritizeSubtree,_e=e.createTextInstance,Re=e.setTimeout,ze=e.clearTimeout,He=e.noTimeout,b=e.isPrimaryRenderer,w=e.supportsMutation,S=e.supportsPersistence,y=e.supportsHydration,F=e.appendChild,J=e.appendChildToContainer,X=e.commitTextUpdate,Z=e.commitMount,ie=e.commitUpdate,Pe=e.insertBefore,Ne=e.insertInContainerBefore,ot=e.removeChild,dt=e.removeChildFromContainer,jt=e.resetTextContent,$t=e.hideInstance,bt=e.hideTextInstance,an=e.unhideInstance,Qr=e.unhideTextInstance,mr=e.cloneInstance,br=e.createContainerChildSet,Wr=e.appendChildToContainerChildSet,Kn=e.finalizeContainerChildren,Ns=e.replaceContainerChildren,Ti=e.cloneHiddenInstance,ps=e.cloneHiddenTextInstance,io=e.canHydrateInstance,Si=e.canHydrateTextInstance,Ls=e.isSuspenseInstancePending,so=e.isSuspenseInstanceFallback,cc=e.getNextHydratableSibling,cu=e.getFirstHydratableChild,op=e.hydrateInstance,ap=e.hydrateTextInstance,Os=e.getNextHydratableInstanceAfterSuspenseInstance,Dn=e.commitHydratedContainer,oo=e.commitHydratedSuspenseInstance,Ms=/^(.*)[\\\\\\/]/;function ml(P){var D=\"\";do{e:switch(P.tag){case 3:case 4:case 6:case 7:case 10:case 9:var T=\"\";break e;default:var j=P._debugOwner,Y=P._debugSource,fe=ae(P.type);T=null,j&&(T=ae(j.type)),j=fe,fe=\"\",Y?fe=\" (at \"+Y.fileName.replace(Ms,\"\")+\":\"+Y.lineNumber+\")\":T&&(fe=\" (created by \"+T+\")\"),T=`\n    in `+(j||\"Unknown\")+fe}D+=T,P=P.return}while(P);return D}var yl=[],ao=-1;function Vn(P){0>ao||(P.current=yl[ao],yl[ao]=null,ao--)}function On(P,D){ao++,yl[ao]=P.current,P.current=D}var Ni={},Mn={current:Ni},_i={current:!1},tr=Ni;function Oe(P,D){var T=P.type.contextTypes;if(!T)return Ni;var j=P.stateNode;if(j&&j.__reactInternalMemoizedUnmaskedChildContext===D)return j.__reactInternalMemoizedMaskedChildContext;var Y={},fe;for(fe in T)Y[fe]=D[fe];return j&&(P=P.stateNode,P.__reactInternalMemoizedUnmaskedChildContext=D,P.__reactInternalMemoizedMaskedChildContext=Y),Y}function ii(P){return P=P.childContextTypes,P!=null}function Ma(P){Vn(_i,P),Vn(Mn,P)}function hr(P){Vn(_i,P),Vn(Mn,P)}function uc(P,D,T){if(Mn.current!==Ni)throw Error(n(168));On(Mn,D,P),On(_i,T,P)}function uu(P,D,T){var j=P.stateNode;if(P=D.childContextTypes,typeof j.getChildContext!=\"function\")return T;j=j.getChildContext();for(var Y in j)if(!(Y in P))throw Error(n(108,ae(D)||\"Unknown\",Y));return r({},T,{},j)}function Ac(P){var D=P.stateNode;return D=D&&D.__reactInternalMemoizedMergedChildContext||Ni,tr=Mn.current,On(Mn,D,P),On(_i,_i.current,P),!0}function El(P,D,T){var j=P.stateNode;if(!j)throw Error(n(169));T?(D=uu(P,D,tr),j.__reactInternalMemoizedMergedChildContext=D,Vn(_i,P),Vn(Mn,P),On(Mn,D,P)):Vn(_i,P),On(_i,T,P)}var vA=a.unstable_runWithPriority,Au=a.unstable_scheduleCallback,Ce=a.unstable_cancelCallback,Rt=a.unstable_shouldYield,fc=a.unstable_requestPaint,Hi=a.unstable_now,fu=a.unstable_getCurrentPriorityLevel,Yt=a.unstable_ImmediatePriority,Cl=a.unstable_UserBlockingPriority,DA=a.unstable_NormalPriority,lp=a.unstable_LowPriority,pc=a.unstable_IdlePriority,PA={},Qn=fc!==void 0?fc:function(){},hi=null,hc=null,SA=!1,sa=Hi(),Li=1e4>sa?Hi:function(){return Hi()-sa};function _o(){switch(fu()){case Yt:return 99;case Cl:return 98;case DA:return 97;case lp:return 96;case pc:return 95;default:throw Error(n(332))}}function Ze(P){switch(P){case 99:return Yt;case 98:return Cl;case 97:return DA;case 96:return lp;case 95:return pc;default:throw Error(n(332))}}function lo(P,D){return P=Ze(P),vA(P,D)}function gc(P,D,T){return P=Ze(P),Au(P,D,T)}function pu(P){return hi===null?(hi=[P],hc=Au(Yt,hu)):hi.push(P),PA}function ji(){if(hc!==null){var P=hc;hc=null,Ce(P)}hu()}function hu(){if(!SA&&hi!==null){SA=!0;var P=0;try{var D=hi;lo(99,function(){for(;P<D.length;P++){var T=D[P];do T=T(!0);while(T!==null)}}),hi=null}catch(T){throw hi!==null&&(hi=hi.slice(P+1)),Au(Yt,ji),T}finally{SA=!1}}}var bA=3;function Ua(P,D,T){return T/=10,1073741821-(((1073741821-P+D/10)/T|0)+1)*T}function dc(P,D){return P===D&&(P!==0||1/P===1/D)||P!==P&&D!==D}var hs=typeof Object.is==\"function\"?Object.is:dc,_t=Object.prototype.hasOwnProperty;function Fn(P,D){if(hs(P,D))return!0;if(typeof P!=\"object\"||P===null||typeof D!=\"object\"||D===null)return!1;var T=Object.keys(P),j=Object.keys(D);if(T.length!==j.length)return!1;for(j=0;j<T.length;j++)if(!_t.call(D,T[j])||!hs(P[T[j]],D[T[j]]))return!1;return!0}function Ci(P,D){if(P&&P.defaultProps){D=r({},D),P=P.defaultProps;for(var T in P)D[T]===void 0&&(D[T]=P[T])}return D}var oa={current:null},co=null,Us=null,aa=null;function la(){aa=Us=co=null}function Ho(P,D){var T=P.type._context;b?(On(oa,T._currentValue,P),T._currentValue=D):(On(oa,T._currentValue2,P),T._currentValue2=D)}function wi(P){var D=oa.current;Vn(oa,P),P=P.type._context,b?P._currentValue=D:P._currentValue2=D}function gs(P,D){for(;P!==null;){var T=P.alternate;if(P.childExpirationTime<D)P.childExpirationTime=D,T!==null&&T.childExpirationTime<D&&(T.childExpirationTime=D);else if(T!==null&&T.childExpirationTime<D)T.childExpirationTime=D;else break;P=P.return}}function ds(P,D){co=P,aa=Us=null,P=P.dependencies,P!==null&&P.firstContext!==null&&(P.expirationTime>=D&&(qo=!0),P.firstContext=null)}function ms(P,D){if(aa!==P&&D!==!1&&D!==0)if((typeof D!=\"number\"||D===1073741823)&&(aa=P,D=1073741823),D={context:P,observedBits:D,next:null},Us===null){if(co===null)throw Error(n(308));Us=D,co.dependencies={expirationTime:0,firstContext:D,responders:null}}else Us=Us.next=D;return b?P._currentValue:P._currentValue2}var _s=!1;function Un(P){return{baseState:P,firstUpdate:null,lastUpdate:null,firstCapturedUpdate:null,lastCapturedUpdate:null,firstEffect:null,lastEffect:null,firstCapturedEffect:null,lastCapturedEffect:null}}function Pn(P){return{baseState:P.baseState,firstUpdate:P.firstUpdate,lastUpdate:P.lastUpdate,firstCapturedUpdate:null,lastCapturedUpdate:null,firstEffect:null,lastEffect:null,firstCapturedEffect:null,lastCapturedEffect:null}}function ys(P,D){return{expirationTime:P,suspenseConfig:D,tag:0,payload:null,callback:null,next:null,nextEffect:null}}function We(P,D){P.lastUpdate===null?P.firstUpdate=P.lastUpdate=D:(P.lastUpdate.next=D,P.lastUpdate=D)}function tt(P,D){var T=P.alternate;if(T===null){var j=P.updateQueue,Y=null;j===null&&(j=P.updateQueue=Un(P.memoizedState))}else j=P.updateQueue,Y=T.updateQueue,j===null?Y===null?(j=P.updateQueue=Un(P.memoizedState),Y=T.updateQueue=Un(T.memoizedState)):j=P.updateQueue=Pn(Y):Y===null&&(Y=T.updateQueue=Pn(j));Y===null||j===Y?We(j,D):j.lastUpdate===null||Y.lastUpdate===null?(We(j,D),We(Y,D)):(We(j,D),Y.lastUpdate=D)}function It(P,D){var T=P.updateQueue;T=T===null?P.updateQueue=Un(P.memoizedState):nr(P,T),T.lastCapturedUpdate===null?T.firstCapturedUpdate=T.lastCapturedUpdate=D:(T.lastCapturedUpdate.next=D,T.lastCapturedUpdate=D)}function nr(P,D){var T=P.alternate;return T!==null&&D===T.updateQueue&&(D=P.updateQueue=Pn(D)),D}function $(P,D,T,j,Y,fe){switch(T.tag){case 1:return P=T.payload,typeof P==\"function\"?P.call(fe,j,Y):P;case 3:P.effectTag=P.effectTag&-4097|64;case 0:if(P=T.payload,Y=typeof P==\"function\"?P.call(fe,j,Y):P,Y==null)break;return r({},j,Y);case 2:_s=!0}return j}function me(P,D,T,j,Y){_s=!1,D=nr(P,D);for(var fe=D.baseState,ve=null,vt=0,wt=D.firstUpdate,xt=fe;wt!==null;){var _r=wt.expirationTime;_r<Y?(ve===null&&(ve=wt,fe=xt),vt<_r&&(vt=_r)):(Dw(_r,wt.suspenseConfig),xt=$(P,D,wt,xt,T,j),wt.callback!==null&&(P.effectTag|=32,wt.nextEffect=null,D.lastEffect===null?D.firstEffect=D.lastEffect=wt:(D.lastEffect.nextEffect=wt,D.lastEffect=wt))),wt=wt.next}for(_r=null,wt=D.firstCapturedUpdate;wt!==null;){var is=wt.expirationTime;is<Y?(_r===null&&(_r=wt,ve===null&&(fe=xt)),vt<is&&(vt=is)):(xt=$(P,D,wt,xt,T,j),wt.callback!==null&&(P.effectTag|=32,wt.nextEffect=null,D.lastCapturedEffect===null?D.firstCapturedEffect=D.lastCapturedEffect=wt:(D.lastCapturedEffect.nextEffect=wt,D.lastCapturedEffect=wt))),wt=wt.next}ve===null&&(D.lastUpdate=null),_r===null?D.lastCapturedUpdate=null:P.effectTag|=32,ve===null&&_r===null&&(fe=xt),D.baseState=fe,D.firstUpdate=ve,D.firstCapturedUpdate=_r,Um(vt),P.expirationTime=vt,P.memoizedState=xt}function Le(P,D,T){D.firstCapturedUpdate!==null&&(D.lastUpdate!==null&&(D.lastUpdate.next=D.firstCapturedUpdate,D.lastUpdate=D.lastCapturedUpdate),D.firstCapturedUpdate=D.lastCapturedUpdate=null),ft(D.firstEffect,T),D.firstEffect=D.lastEffect=null,ft(D.firstCapturedEffect,T),D.firstCapturedEffect=D.lastCapturedEffect=null}function ft(P,D){for(;P!==null;){var T=P.callback;if(T!==null){P.callback=null;var j=D;if(typeof T!=\"function\")throw Error(n(191,T));T.call(j)}P=P.nextEffect}}var pt=u.ReactCurrentBatchConfig,Tt=new o.Component().refs;function er(P,D,T,j){D=P.memoizedState,T=T(j,D),T=T==null?D:r({},D,T),P.memoizedState=T,j=P.updateQueue,j!==null&&P.expirationTime===0&&(j.baseState=T)}var Zr={isMounted:function(P){return(P=P._reactInternalFiber)?Ie(P)===P:!1},enqueueSetState:function(P,D,T){P=P._reactInternalFiber;var j=ga(),Y=pt.suspense;j=HA(j,P,Y),Y=ys(j,Y),Y.payload=D,T!=null&&(Y.callback=T),tt(P,Y),Sc(P,j)},enqueueReplaceState:function(P,D,T){P=P._reactInternalFiber;var j=ga(),Y=pt.suspense;j=HA(j,P,Y),Y=ys(j,Y),Y.tag=1,Y.payload=D,T!=null&&(Y.callback=T),tt(P,Y),Sc(P,j)},enqueueForceUpdate:function(P,D){P=P._reactInternalFiber;var T=ga(),j=pt.suspense;T=HA(T,P,j),j=ys(T,j),j.tag=2,D!=null&&(j.callback=D),tt(P,j),Sc(P,T)}};function qi(P,D,T,j,Y,fe,ve){return P=P.stateNode,typeof P.shouldComponentUpdate==\"function\"?P.shouldComponentUpdate(j,fe,ve):D.prototype&&D.prototype.isPureReactComponent?!Fn(T,j)||!Fn(Y,fe):!0}function es(P,D,T){var j=!1,Y=Ni,fe=D.contextType;return typeof fe==\"object\"&&fe!==null?fe=ms(fe):(Y=ii(D)?tr:Mn.current,j=D.contextTypes,fe=(j=j!=null)?Oe(P,Y):Ni),D=new D(T,fe),P.memoizedState=D.state!==null&&D.state!==void 0?D.state:null,D.updater=Zr,P.stateNode=D,D._reactInternalFiber=P,j&&(P=P.stateNode,P.__reactInternalMemoizedUnmaskedChildContext=Y,P.__reactInternalMemoizedMaskedChildContext=fe),D}function bi(P,D,T,j){P=D.state,typeof D.componentWillReceiveProps==\"function\"&&D.componentWillReceiveProps(T,j),typeof D.UNSAFE_componentWillReceiveProps==\"function\"&&D.UNSAFE_componentWillReceiveProps(T,j),D.state!==P&&Zr.enqueueReplaceState(D,D.state,null)}function jo(P,D,T,j){var Y=P.stateNode;Y.props=T,Y.state=P.memoizedState,Y.refs=Tt;var fe=D.contextType;typeof fe==\"object\"&&fe!==null?Y.context=ms(fe):(fe=ii(D)?tr:Mn.current,Y.context=Oe(P,fe)),fe=P.updateQueue,fe!==null&&(me(P,fe,T,Y,j),Y.state=P.memoizedState),fe=D.getDerivedStateFromProps,typeof fe==\"function\"&&(er(P,D,fe,T),Y.state=P.memoizedState),typeof D.getDerivedStateFromProps==\"function\"||typeof Y.getSnapshotBeforeUpdate==\"function\"||typeof Y.UNSAFE_componentWillMount!=\"function\"&&typeof Y.componentWillMount!=\"function\"||(D=Y.state,typeof Y.componentWillMount==\"function\"&&Y.componentWillMount(),typeof Y.UNSAFE_componentWillMount==\"function\"&&Y.UNSAFE_componentWillMount(),D!==Y.state&&Zr.enqueueReplaceState(Y,Y.state,null),fe=P.updateQueue,fe!==null&&(me(P,fe,T,Y,j),Y.state=P.memoizedState)),typeof Y.componentDidMount==\"function\"&&(P.effectTag|=4)}var xA=Array.isArray;function kA(P,D,T){if(P=T.ref,P!==null&&typeof P!=\"function\"&&typeof P!=\"object\"){if(T._owner){if(T=T._owner,T){if(T.tag!==1)throw Error(n(309));var j=T.stateNode}if(!j)throw Error(n(147,P));var Y=\"\"+P;return D!==null&&D.ref!==null&&typeof D.ref==\"function\"&&D.ref._stringRef===Y?D.ref:(D=function(fe){var ve=j.refs;ve===Tt&&(ve=j.refs={}),fe===null?delete ve[Y]:ve[Y]=fe},D._stringRef=Y,D)}if(typeof P!=\"string\")throw Error(n(284));if(!T._owner)throw Error(n(290,P))}return P}function cp(P,D){if(P.type!==\"textarea\")throw Error(n(31,Object.prototype.toString.call(D)===\"[object Object]\"?\"object with keys {\"+Object.keys(D).join(\", \")+\"}\":D,\"\"))}function rg(P){function D(rt,Ve){if(P){var At=rt.lastEffect;At!==null?(At.nextEffect=Ve,rt.lastEffect=Ve):rt.firstEffect=rt.lastEffect=Ve,Ve.nextEffect=null,Ve.effectTag=8}}function T(rt,Ve){if(!P)return null;for(;Ve!==null;)D(rt,Ve),Ve=Ve.sibling;return null}function j(rt,Ve){for(rt=new Map;Ve!==null;)Ve.key!==null?rt.set(Ve.key,Ve):rt.set(Ve.index,Ve),Ve=Ve.sibling;return rt}function Y(rt,Ve,At){return rt=YA(rt,Ve,At),rt.index=0,rt.sibling=null,rt}function fe(rt,Ve,At){return rt.index=At,P?(At=rt.alternate,At!==null?(At=At.index,At<Ve?(rt.effectTag=2,Ve):At):(rt.effectTag=2,Ve)):Ve}function ve(rt){return P&&rt.alternate===null&&(rt.effectTag=2),rt}function vt(rt,Ve,At,Wt){return Ve===null||Ve.tag!==6?(Ve=kw(At,rt.mode,Wt),Ve.return=rt,Ve):(Ve=Y(Ve,At,Wt),Ve.return=rt,Ve)}function wt(rt,Ve,At,Wt){return Ve!==null&&Ve.elementType===At.type?(Wt=Y(Ve,At.props,Wt),Wt.ref=kA(rt,Ve,At),Wt.return=rt,Wt):(Wt=_m(At.type,At.key,At.props,null,rt.mode,Wt),Wt.ref=kA(rt,Ve,At),Wt.return=rt,Wt)}function xt(rt,Ve,At,Wt){return Ve===null||Ve.tag!==4||Ve.stateNode.containerInfo!==At.containerInfo||Ve.stateNode.implementation!==At.implementation?(Ve=Qw(At,rt.mode,Wt),Ve.return=rt,Ve):(Ve=Y(Ve,At.children||[],Wt),Ve.return=rt,Ve)}function _r(rt,Ve,At,Wt,vr){return Ve===null||Ve.tag!==7?(Ve=bu(At,rt.mode,Wt,vr),Ve.return=rt,Ve):(Ve=Y(Ve,At,Wt),Ve.return=rt,Ve)}function is(rt,Ve,At){if(typeof Ve==\"string\"||typeof Ve==\"number\")return Ve=kw(\"\"+Ve,rt.mode,At),Ve.return=rt,Ve;if(typeof Ve==\"object\"&&Ve!==null){switch(Ve.$$typeof){case p:return At=_m(Ve.type,Ve.key,Ve.props,null,rt.mode,At),At.ref=kA(rt,null,Ve),At.return=rt,At;case h:return Ve=Qw(Ve,rt.mode,At),Ve.return=rt,Ve}if(xA(Ve)||Ae(Ve))return Ve=bu(Ve,rt.mode,At,null),Ve.return=rt,Ve;cp(rt,Ve)}return null}function di(rt,Ve,At,Wt){var vr=Ve!==null?Ve.key:null;if(typeof At==\"string\"||typeof At==\"number\")return vr!==null?null:vt(rt,Ve,\"\"+At,Wt);if(typeof At==\"object\"&&At!==null){switch(At.$$typeof){case p:return At.key===vr?At.type===C?_r(rt,Ve,At.props.children,Wt,vr):wt(rt,Ve,At,Wt):null;case h:return At.key===vr?xt(rt,Ve,At,Wt):null}if(xA(At)||Ae(At))return vr!==null?null:_r(rt,Ve,At,Wt,null);cp(rt,At)}return null}function po(rt,Ve,At,Wt,vr){if(typeof Wt==\"string\"||typeof Wt==\"number\")return rt=rt.get(At)||null,vt(Ve,rt,\"\"+Wt,vr);if(typeof Wt==\"object\"&&Wt!==null){switch(Wt.$$typeof){case p:return rt=rt.get(Wt.key===null?At:Wt.key)||null,Wt.type===C?_r(Ve,rt,Wt.props.children,vr,Wt.key):wt(Ve,rt,Wt,vr);case h:return rt=rt.get(Wt.key===null?At:Wt.key)||null,xt(Ve,rt,Wt,vr)}if(xA(Wt)||Ae(Wt))return rt=rt.get(At)||null,_r(Ve,rt,Wt,vr,null);cp(Ve,Wt)}return null}function KA(rt,Ve,At,Wt){for(var vr=null,Sn=null,Fr=Ve,bn=Ve=0,ai=null;Fr!==null&&bn<At.length;bn++){Fr.index>bn?(ai=Fr,Fr=null):ai=Fr.sibling;var en=di(rt,Fr,At[bn],Wt);if(en===null){Fr===null&&(Fr=ai);break}P&&Fr&&en.alternate===null&&D(rt,Fr),Ve=fe(en,Ve,bn),Sn===null?vr=en:Sn.sibling=en,Sn=en,Fr=ai}if(bn===At.length)return T(rt,Fr),vr;if(Fr===null){for(;bn<At.length;bn++)Fr=is(rt,At[bn],Wt),Fr!==null&&(Ve=fe(Fr,Ve,bn),Sn===null?vr=Fr:Sn.sibling=Fr,Sn=Fr);return vr}for(Fr=j(rt,Fr);bn<At.length;bn++)ai=po(Fr,rt,bn,At[bn],Wt),ai!==null&&(P&&ai.alternate!==null&&Fr.delete(ai.key===null?bn:ai.key),Ve=fe(ai,Ve,bn),Sn===null?vr=ai:Sn.sibling=ai,Sn=ai);return P&&Fr.forEach(function(ho){return D(rt,ho)}),vr}function Yo(rt,Ve,At,Wt){var vr=Ae(At);if(typeof vr!=\"function\")throw Error(n(150));if(At=vr.call(At),At==null)throw Error(n(151));for(var Sn=vr=null,Fr=Ve,bn=Ve=0,ai=null,en=At.next();Fr!==null&&!en.done;bn++,en=At.next()){Fr.index>bn?(ai=Fr,Fr=null):ai=Fr.sibling;var ho=di(rt,Fr,en.value,Wt);if(ho===null){Fr===null&&(Fr=ai);break}P&&Fr&&ho.alternate===null&&D(rt,Fr),Ve=fe(ho,Ve,bn),Sn===null?vr=ho:Sn.sibling=ho,Sn=ho,Fr=ai}if(en.done)return T(rt,Fr),vr;if(Fr===null){for(;!en.done;bn++,en=At.next())en=is(rt,en.value,Wt),en!==null&&(Ve=fe(en,Ve,bn),Sn===null?vr=en:Sn.sibling=en,Sn=en);return vr}for(Fr=j(rt,Fr);!en.done;bn++,en=At.next())en=po(Fr,rt,bn,en.value,Wt),en!==null&&(P&&en.alternate!==null&&Fr.delete(en.key===null?bn:en.key),Ve=fe(en,Ve,bn),Sn===null?vr=en:Sn.sibling=en,Sn=en);return P&&Fr.forEach(function(PF){return D(rt,PF)}),vr}return function(rt,Ve,At,Wt){var vr=typeof At==\"object\"&&At!==null&&At.type===C&&At.key===null;vr&&(At=At.props.children);var Sn=typeof At==\"object\"&&At!==null;if(Sn)switch(At.$$typeof){case p:e:{for(Sn=At.key,vr=Ve;vr!==null;){if(vr.key===Sn)if(vr.tag===7?At.type===C:vr.elementType===At.type){T(rt,vr.sibling),Ve=Y(vr,At.type===C?At.props.children:At.props,Wt),Ve.ref=kA(rt,vr,At),Ve.return=rt,rt=Ve;break e}else{T(rt,vr);break}else D(rt,vr);vr=vr.sibling}At.type===C?(Ve=bu(At.props.children,rt.mode,Wt,At.key),Ve.return=rt,rt=Ve):(Wt=_m(At.type,At.key,At.props,null,rt.mode,Wt),Wt.ref=kA(rt,Ve,At),Wt.return=rt,rt=Wt)}return ve(rt);case h:e:{for(vr=At.key;Ve!==null;){if(Ve.key===vr)if(Ve.tag===4&&Ve.stateNode.containerInfo===At.containerInfo&&Ve.stateNode.implementation===At.implementation){T(rt,Ve.sibling),Ve=Y(Ve,At.children||[],Wt),Ve.return=rt,rt=Ve;break e}else{T(rt,Ve);break}else D(rt,Ve);Ve=Ve.sibling}Ve=Qw(At,rt.mode,Wt),Ve.return=rt,rt=Ve}return ve(rt)}if(typeof At==\"string\"||typeof At==\"number\")return At=\"\"+At,Ve!==null&&Ve.tag===6?(T(rt,Ve.sibling),Ve=Y(Ve,At,Wt),Ve.return=rt,rt=Ve):(T(rt,Ve),Ve=kw(At,rt.mode,Wt),Ve.return=rt,rt=Ve),ve(rt);if(xA(At))return KA(rt,Ve,At,Wt);if(Ae(At))return Yo(rt,Ve,At,Wt);if(Sn&&cp(rt,At),typeof At>\"u\"&&!vr)switch(rt.tag){case 1:case 0:throw rt=rt.type,Error(n(152,rt.displayName||rt.name||\"Component\"))}return T(rt,Ve)}}var gu=rg(!0),ng=rg(!1),du={},uo={current:du},QA={current:du},mc={current:du};function ca(P){if(P===du)throw Error(n(174));return P}function ig(P,D){On(mc,D,P),On(QA,P,P),On(uo,du,P),D=ne(D),Vn(uo,P),On(uo,D,P)}function yc(P){Vn(uo,P),Vn(QA,P),Vn(mc,P)}function Dm(P){var D=ca(mc.current),T=ca(uo.current);D=ee(T,P.type,D),T!==D&&(On(QA,P,P),On(uo,D,P))}function sg(P){QA.current===P&&(Vn(uo,P),Vn(QA,P))}var $n={current:0};function up(P){for(var D=P;D!==null;){if(D.tag===13){var T=D.memoizedState;if(T!==null&&(T=T.dehydrated,T===null||Ls(T)||so(T)))return D}else if(D.tag===19&&D.memoizedProps.revealOrder!==void 0){if((D.effectTag&64)!==0)return D}else if(D.child!==null){D.child.return=D,D=D.child;continue}if(D===P)break;for(;D.sibling===null;){if(D.return===null||D.return===P)return null;D=D.return}D.sibling.return=D.return,D=D.sibling}return null}function og(P,D){return{responder:P,props:D}}var FA=u.ReactCurrentDispatcher,Hs=u.ReactCurrentBatchConfig,mu=0,Ha=null,Gi=null,ua=null,yu=null,Es=null,Ec=null,Cc=0,G=null,Dt=0,wl=!1,xi=null,wc=0;function ct(){throw Error(n(321))}function Eu(P,D){if(D===null)return!1;for(var T=0;T<D.length&&T<P.length;T++)if(!hs(P[T],D[T]))return!1;return!0}function ag(P,D,T,j,Y,fe){if(mu=fe,Ha=D,ua=P!==null?P.memoizedState:null,FA.current=ua===null?mw:bm,D=T(j,Y),wl){do wl=!1,wc+=1,ua=P!==null?P.memoizedState:null,Ec=yu,G=Es=Gi=null,FA.current=bm,D=T(j,Y);while(wl);xi=null,wc=0}if(FA.current=wu,P=Ha,P.memoizedState=yu,P.expirationTime=Cc,P.updateQueue=G,P.effectTag|=Dt,P=Gi!==null&&Gi.next!==null,mu=0,Ec=Es=yu=ua=Gi=Ha=null,Cc=0,G=null,Dt=0,P)throw Error(n(300));return D}function dw(){FA.current=wu,mu=0,Ec=Es=yu=ua=Gi=Ha=null,Cc=0,G=null,Dt=0,wl=!1,xi=null,wc=0}function RA(){var P={memoizedState:null,baseState:null,queue:null,baseUpdate:null,next:null};return Es===null?yu=Es=P:Es=Es.next=P,Es}function Ap(){if(Ec!==null)Es=Ec,Ec=Es.next,Gi=ua,ua=Gi!==null?Gi.next:null;else{if(ua===null)throw Error(n(310));Gi=ua;var P={memoizedState:Gi.memoizedState,baseState:Gi.baseState,queue:Gi.queue,baseUpdate:Gi.baseUpdate,next:null};Es=Es===null?yu=P:Es.next=P,ua=Gi.next}return Es}function Br(P,D){return typeof D==\"function\"?D(P):D}function Cs(P){var D=Ap(),T=D.queue;if(T===null)throw Error(n(311));if(T.lastRenderedReducer=P,0<wc){var j=T.dispatch;if(xi!==null){var Y=xi.get(T);if(Y!==void 0){xi.delete(T);var fe=D.memoizedState;do fe=P(fe,Y.action),Y=Y.next;while(Y!==null);return hs(fe,D.memoizedState)||(qo=!0),D.memoizedState=fe,D.baseUpdate===T.last&&(D.baseState=fe),T.lastRenderedState=fe,[fe,j]}}return[D.memoizedState,j]}j=T.last;var ve=D.baseUpdate;if(fe=D.baseState,ve!==null?(j!==null&&(j.next=null),j=ve.next):j=j!==null?j.next:null,j!==null){var vt=Y=null,wt=j,xt=!1;do{var _r=wt.expirationTime;_r<mu?(xt||(xt=!0,vt=ve,Y=fe),_r>Cc&&(Cc=_r,Um(Cc))):(Dw(_r,wt.suspenseConfig),fe=wt.eagerReducer===P?wt.eagerState:P(fe,wt.action)),ve=wt,wt=wt.next}while(wt!==null&&wt!==j);xt||(vt=ve,Y=fe),hs(fe,D.memoizedState)||(qo=!0),D.memoizedState=fe,D.baseUpdate=vt,D.baseState=Y,T.lastRenderedState=fe}return[D.memoizedState,T.dispatch]}function lg(P){var D=RA();return typeof P==\"function\"&&(P=P()),D.memoizedState=D.baseState=P,P=D.queue={last:null,dispatch:null,lastRenderedReducer:Br,lastRenderedState:P},P=P.dispatch=pg.bind(null,Ha,P),[D.memoizedState,P]}function cg(P){return Cs(Br,P)}function ug(P,D,T,j){return P={tag:P,create:D,destroy:T,deps:j,next:null},G===null?(G={lastEffect:null},G.lastEffect=P.next=P):(D=G.lastEffect,D===null?G.lastEffect=P.next=P:(T=D.next,D.next=P,P.next=T,G.lastEffect=P)),P}function fp(P,D,T,j){var Y=RA();Dt|=P,Y.memoizedState=ug(D,T,void 0,j===void 0?null:j)}function Ic(P,D,T,j){var Y=Ap();j=j===void 0?null:j;var fe=void 0;if(Gi!==null){var ve=Gi.memoizedState;if(fe=ve.destroy,j!==null&&Eu(j,ve.deps)){ug(0,T,fe,j);return}}Dt|=P,Y.memoizedState=ug(D,T,fe,j)}function Ct(P,D){return fp(516,192,P,D)}function Pm(P,D){return Ic(516,192,P,D)}function Ag(P,D){if(typeof D==\"function\")return P=P(),D(P),function(){D(null)};if(D!=null)return P=P(),D.current=P,function(){D.current=null}}function fg(){}function Cu(P,D){return RA().memoizedState=[P,D===void 0?null:D],P}function Sm(P,D){var T=Ap();D=D===void 0?null:D;var j=T.memoizedState;return j!==null&&D!==null&&Eu(D,j[1])?j[0]:(T.memoizedState=[P,D],P)}function pg(P,D,T){if(!(25>wc))throw Error(n(301));var j=P.alternate;if(P===Ha||j!==null&&j===Ha)if(wl=!0,P={expirationTime:mu,suspenseConfig:null,action:T,eagerReducer:null,eagerState:null,next:null},xi===null&&(xi=new Map),T=xi.get(D),T===void 0)xi.set(D,P);else{for(D=T;D.next!==null;)D=D.next;D.next=P}else{var Y=ga(),fe=pt.suspense;Y=HA(Y,P,fe),fe={expirationTime:Y,suspenseConfig:fe,action:T,eagerReducer:null,eagerState:null,next:null};var ve=D.last;if(ve===null)fe.next=fe;else{var vt=ve.next;vt!==null&&(fe.next=vt),ve.next=fe}if(D.last=fe,P.expirationTime===0&&(j===null||j.expirationTime===0)&&(j=D.lastRenderedReducer,j!==null))try{var wt=D.lastRenderedState,xt=j(wt,T);if(fe.eagerReducer=j,fe.eagerState=xt,hs(xt,wt))return}catch{}finally{}Sc(P,Y)}}var wu={readContext:ms,useCallback:ct,useContext:ct,useEffect:ct,useImperativeHandle:ct,useLayoutEffect:ct,useMemo:ct,useReducer:ct,useRef:ct,useState:ct,useDebugValue:ct,useResponder:ct,useDeferredValue:ct,useTransition:ct},mw={readContext:ms,useCallback:Cu,useContext:ms,useEffect:Ct,useImperativeHandle:function(P,D,T){return T=T!=null?T.concat([P]):null,fp(4,36,Ag.bind(null,D,P),T)},useLayoutEffect:function(P,D){return fp(4,36,P,D)},useMemo:function(P,D){var T=RA();return D=D===void 0?null:D,P=P(),T.memoizedState=[P,D],P},useReducer:function(P,D,T){var j=RA();return D=T!==void 0?T(D):D,j.memoizedState=j.baseState=D,P=j.queue={last:null,dispatch:null,lastRenderedReducer:P,lastRenderedState:D},P=P.dispatch=pg.bind(null,Ha,P),[j.memoizedState,P]},useRef:function(P){var D=RA();return P={current:P},D.memoizedState=P},useState:lg,useDebugValue:fg,useResponder:og,useDeferredValue:function(P,D){var T=lg(P),j=T[0],Y=T[1];return Ct(function(){a.unstable_next(function(){var fe=Hs.suspense;Hs.suspense=D===void 0?null:D;try{Y(P)}finally{Hs.suspense=fe}})},[P,D]),j},useTransition:function(P){var D=lg(!1),T=D[0],j=D[1];return[Cu(function(Y){j(!0),a.unstable_next(function(){var fe=Hs.suspense;Hs.suspense=P===void 0?null:P;try{j(!1),Y()}finally{Hs.suspense=fe}})},[P,T]),T]}},bm={readContext:ms,useCallback:Sm,useContext:ms,useEffect:Pm,useImperativeHandle:function(P,D,T){return T=T!=null?T.concat([P]):null,Ic(4,36,Ag.bind(null,D,P),T)},useLayoutEffect:function(P,D){return Ic(4,36,P,D)},useMemo:function(P,D){var T=Ap();D=D===void 0?null:D;var j=T.memoizedState;return j!==null&&D!==null&&Eu(D,j[1])?j[0]:(P=P(),T.memoizedState=[P,D],P)},useReducer:Cs,useRef:function(){return Ap().memoizedState},useState:cg,useDebugValue:fg,useResponder:og,useDeferredValue:function(P,D){var T=cg(P),j=T[0],Y=T[1];return Pm(function(){a.unstable_next(function(){var fe=Hs.suspense;Hs.suspense=D===void 0?null:D;try{Y(P)}finally{Hs.suspense=fe}})},[P,D]),j},useTransition:function(P){var D=cg(!1),T=D[0],j=D[1];return[Sm(function(Y){j(!0),a.unstable_next(function(){var fe=Hs.suspense;Hs.suspense=P===void 0?null:P;try{j(!1),Y()}finally{Hs.suspense=fe}})},[P,T]),T]}},Aa=null,Bc=null,Il=!1;function Iu(P,D){var T=Dl(5,null,null,0);T.elementType=\"DELETED\",T.type=\"DELETED\",T.stateNode=D,T.return=P,T.effectTag=8,P.lastEffect!==null?(P.lastEffect.nextEffect=T,P.lastEffect=T):P.firstEffect=P.lastEffect=T}function hg(P,D){switch(P.tag){case 5:return D=io(D,P.type,P.pendingProps),D!==null?(P.stateNode=D,!0):!1;case 6:return D=Si(D,P.pendingProps),D!==null?(P.stateNode=D,!0):!1;case 13:return!1;default:return!1}}function TA(P){if(Il){var D=Bc;if(D){var T=D;if(!hg(P,D)){if(D=cc(T),!D||!hg(P,D)){P.effectTag=P.effectTag&-1025|2,Il=!1,Aa=P;return}Iu(Aa,T)}Aa=P,Bc=cu(D)}else P.effectTag=P.effectTag&-1025|2,Il=!1,Aa=P}}function pp(P){for(P=P.return;P!==null&&P.tag!==5&&P.tag!==3&&P.tag!==13;)P=P.return;Aa=P}function ja(P){if(!y||P!==Aa)return!1;if(!Il)return pp(P),Il=!0,!1;var D=P.type;if(P.tag!==5||D!==\"head\"&&D!==\"body\"&&!ke(D,P.memoizedProps))for(D=Bc;D;)Iu(P,D),D=cc(D);if(pp(P),P.tag===13){if(!y)throw Error(n(316));if(P=P.memoizedState,P=P!==null?P.dehydrated:null,!P)throw Error(n(317));Bc=Os(P)}else Bc=Aa?cc(P.stateNode):null;return!0}function gg(){y&&(Bc=Aa=null,Il=!1)}var hp=u.ReactCurrentOwner,qo=!1;function ws(P,D,T,j){D.child=P===null?ng(D,null,T,j):gu(D,P.child,T,j)}function Ii(P,D,T,j,Y){T=T.render;var fe=D.ref;return ds(D,Y),j=ag(P,D,T,j,fe,Y),P!==null&&!qo?(D.updateQueue=P.updateQueue,D.effectTag&=-517,P.expirationTime<=Y&&(P.expirationTime=0),si(P,D,Y)):(D.effectTag|=1,ws(P,D,j,Y),D.child)}function xm(P,D,T,j,Y,fe){if(P===null){var ve=T.type;return typeof ve==\"function\"&&!xw(ve)&&ve.defaultProps===void 0&&T.compare===null&&T.defaultProps===void 0?(D.tag=15,D.type=ve,km(P,D,ve,j,Y,fe)):(P=_m(T.type,null,j,null,D.mode,fe),P.ref=D.ref,P.return=D,D.child=P)}return ve=P.child,Y<fe&&(Y=ve.memoizedProps,T=T.compare,T=T!==null?T:Fn,T(Y,j)&&P.ref===D.ref)?si(P,D,fe):(D.effectTag|=1,P=YA(ve,j,fe),P.ref=D.ref,P.return=D,D.child=P)}function km(P,D,T,j,Y,fe){return P!==null&&Fn(P.memoizedProps,j)&&P.ref===D.ref&&(qo=!1,Y<fe)?si(P,D,fe):NA(P,D,T,j,fe)}function Go(P,D){var T=D.ref;(P===null&&T!==null||P!==null&&P.ref!==T)&&(D.effectTag|=128)}function NA(P,D,T,j,Y){var fe=ii(T)?tr:Mn.current;return fe=Oe(D,fe),ds(D,Y),T=ag(P,D,T,j,fe,Y),P!==null&&!qo?(D.updateQueue=P.updateQueue,D.effectTag&=-517,P.expirationTime<=Y&&(P.expirationTime=0),si(P,D,Y)):(D.effectTag|=1,ws(P,D,T,Y),D.child)}function gp(P,D,T,j,Y){if(ii(T)){var fe=!0;Ac(D)}else fe=!1;if(ds(D,Y),D.stateNode===null)P!==null&&(P.alternate=null,D.alternate=null,D.effectTag|=2),es(D,T,j,Y),jo(D,T,j,Y),j=!0;else if(P===null){var ve=D.stateNode,vt=D.memoizedProps;ve.props=vt;var wt=ve.context,xt=T.contextType;typeof xt==\"object\"&&xt!==null?xt=ms(xt):(xt=ii(T)?tr:Mn.current,xt=Oe(D,xt));var _r=T.getDerivedStateFromProps,is=typeof _r==\"function\"||typeof ve.getSnapshotBeforeUpdate==\"function\";is||typeof ve.UNSAFE_componentWillReceiveProps!=\"function\"&&typeof ve.componentWillReceiveProps!=\"function\"||(vt!==j||wt!==xt)&&bi(D,ve,j,xt),_s=!1;var di=D.memoizedState;wt=ve.state=di;var po=D.updateQueue;po!==null&&(me(D,po,j,ve,Y),wt=D.memoizedState),vt!==j||di!==wt||_i.current||_s?(typeof _r==\"function\"&&(er(D,T,_r,j),wt=D.memoizedState),(vt=_s||qi(D,T,vt,j,di,wt,xt))?(is||typeof ve.UNSAFE_componentWillMount!=\"function\"&&typeof ve.componentWillMount!=\"function\"||(typeof ve.componentWillMount==\"function\"&&ve.componentWillMount(),typeof ve.UNSAFE_componentWillMount==\"function\"&&ve.UNSAFE_componentWillMount()),typeof ve.componentDidMount==\"function\"&&(D.effectTag|=4)):(typeof ve.componentDidMount==\"function\"&&(D.effectTag|=4),D.memoizedProps=j,D.memoizedState=wt),ve.props=j,ve.state=wt,ve.context=xt,j=vt):(typeof ve.componentDidMount==\"function\"&&(D.effectTag|=4),j=!1)}else ve=D.stateNode,vt=D.memoizedProps,ve.props=D.type===D.elementType?vt:Ci(D.type,vt),wt=ve.context,xt=T.contextType,typeof xt==\"object\"&&xt!==null?xt=ms(xt):(xt=ii(T)?tr:Mn.current,xt=Oe(D,xt)),_r=T.getDerivedStateFromProps,(is=typeof _r==\"function\"||typeof ve.getSnapshotBeforeUpdate==\"function\")||typeof ve.UNSAFE_componentWillReceiveProps!=\"function\"&&typeof ve.componentWillReceiveProps!=\"function\"||(vt!==j||wt!==xt)&&bi(D,ve,j,xt),_s=!1,wt=D.memoizedState,di=ve.state=wt,po=D.updateQueue,po!==null&&(me(D,po,j,ve,Y),di=D.memoizedState),vt!==j||wt!==di||_i.current||_s?(typeof _r==\"function\"&&(er(D,T,_r,j),di=D.memoizedState),(_r=_s||qi(D,T,vt,j,wt,di,xt))?(is||typeof ve.UNSAFE_componentWillUpdate!=\"function\"&&typeof ve.componentWillUpdate!=\"function\"||(typeof ve.componentWillUpdate==\"function\"&&ve.componentWillUpdate(j,di,xt),typeof ve.UNSAFE_componentWillUpdate==\"function\"&&ve.UNSAFE_componentWillUpdate(j,di,xt)),typeof ve.componentDidUpdate==\"function\"&&(D.effectTag|=4),typeof ve.getSnapshotBeforeUpdate==\"function\"&&(D.effectTag|=256)):(typeof ve.componentDidUpdate!=\"function\"||vt===P.memoizedProps&&wt===P.memoizedState||(D.effectTag|=4),typeof ve.getSnapshotBeforeUpdate!=\"function\"||vt===P.memoizedProps&&wt===P.memoizedState||(D.effectTag|=256),D.memoizedProps=j,D.memoizedState=di),ve.props=j,ve.state=di,ve.context=xt,j=_r):(typeof ve.componentDidUpdate!=\"function\"||vt===P.memoizedProps&&wt===P.memoizedState||(D.effectTag|=4),typeof ve.getSnapshotBeforeUpdate!=\"function\"||vt===P.memoizedProps&&wt===P.memoizedState||(D.effectTag|=256),j=!1);return dp(P,D,T,j,fe,Y)}function dp(P,D,T,j,Y,fe){Go(P,D);var ve=(D.effectTag&64)!==0;if(!j&&!ve)return Y&&El(D,T,!1),si(P,D,fe);j=D.stateNode,hp.current=D;var vt=ve&&typeof T.getDerivedStateFromError!=\"function\"?null:j.render();return D.effectTag|=1,P!==null&&ve?(D.child=gu(D,P.child,null,fe),D.child=gu(D,null,vt,fe)):ws(P,D,vt,fe),D.memoizedState=j.state,Y&&El(D,T,!0),D.child}function dg(P){var D=P.stateNode;D.pendingContext?uc(P,D.pendingContext,D.pendingContext!==D.context):D.context&&uc(P,D.context,!1),ig(P,D.containerInfo)}var fa={dehydrated:null,retryTime:0};function ln(P,D,T){var j=D.mode,Y=D.pendingProps,fe=$n.current,ve=!1,vt;if((vt=(D.effectTag&64)!==0)||(vt=(fe&2)!==0&&(P===null||P.memoizedState!==null)),vt?(ve=!0,D.effectTag&=-65):P!==null&&P.memoizedState===null||Y.fallback===void 0||Y.unstable_avoidThisFallback===!0||(fe|=1),On($n,fe&1,D),P===null){if(Y.fallback!==void 0&&TA(D),ve){if(ve=Y.fallback,Y=bu(null,j,0,null),Y.return=D,(D.mode&2)===0)for(P=D.memoizedState!==null?D.child.child:D.child,Y.child=P;P!==null;)P.return=Y,P=P.sibling;return T=bu(ve,j,T,null),T.return=D,Y.sibling=T,D.memoizedState=fa,D.child=Y,T}return j=Y.children,D.memoizedState=null,D.child=ng(D,null,j,T)}if(P.memoizedState!==null){if(P=P.child,j=P.sibling,ve){if(Y=Y.fallback,T=YA(P,P.pendingProps,0),T.return=D,(D.mode&2)===0&&(ve=D.memoizedState!==null?D.child.child:D.child,ve!==P.child))for(T.child=ve;ve!==null;)ve.return=T,ve=ve.sibling;return j=YA(j,Y,j.expirationTime),j.return=D,T.sibling=j,T.childExpirationTime=0,D.memoizedState=fa,D.child=T,j}return T=gu(D,P.child,Y.children,T),D.memoizedState=null,D.child=T}if(P=P.child,ve){if(ve=Y.fallback,Y=bu(null,j,0,null),Y.return=D,Y.child=P,P!==null&&(P.return=Y),(D.mode&2)===0)for(P=D.memoizedState!==null?D.child.child:D.child,Y.child=P;P!==null;)P.return=Y,P=P.sibling;return T=bu(ve,j,T,null),T.return=D,Y.sibling=T,T.effectTag|=2,Y.childExpirationTime=0,D.memoizedState=fa,D.child=Y,T}return D.memoizedState=null,D.child=gu(D,P,Y.children,T)}function Ao(P,D){P.expirationTime<D&&(P.expirationTime=D);var T=P.alternate;T!==null&&T.expirationTime<D&&(T.expirationTime=D),gs(P.return,D)}function LA(P,D,T,j,Y,fe){var ve=P.memoizedState;ve===null?P.memoizedState={isBackwards:D,rendering:null,last:j,tail:T,tailExpiration:0,tailMode:Y,lastEffect:fe}:(ve.isBackwards=D,ve.rendering=null,ve.last=j,ve.tail=T,ve.tailExpiration=0,ve.tailMode=Y,ve.lastEffect=fe)}function qa(P,D,T){var j=D.pendingProps,Y=j.revealOrder,fe=j.tail;if(ws(P,D,j.children,T),j=$n.current,(j&2)!==0)j=j&1|2,D.effectTag|=64;else{if(P!==null&&(P.effectTag&64)!==0)e:for(P=D.child;P!==null;){if(P.tag===13)P.memoizedState!==null&&Ao(P,T);else if(P.tag===19)Ao(P,T);else if(P.child!==null){P.child.return=P,P=P.child;continue}if(P===D)break e;for(;P.sibling===null;){if(P.return===null||P.return===D)break e;P=P.return}P.sibling.return=P.return,P=P.sibling}j&=1}if(On($n,j,D),(D.mode&2)===0)D.memoizedState=null;else switch(Y){case\"forwards\":for(T=D.child,Y=null;T!==null;)P=T.alternate,P!==null&&up(P)===null&&(Y=T),T=T.sibling;T=Y,T===null?(Y=D.child,D.child=null):(Y=T.sibling,T.sibling=null),LA(D,!1,Y,T,fe,D.lastEffect);break;case\"backwards\":for(T=null,Y=D.child,D.child=null;Y!==null;){if(P=Y.alternate,P!==null&&up(P)===null){D.child=Y;break}P=Y.sibling,Y.sibling=T,T=Y,Y=P}LA(D,!0,T,null,fe,D.lastEffect);break;case\"together\":LA(D,!1,null,null,void 0,D.lastEffect);break;default:D.memoizedState=null}return D.child}function si(P,D,T){P!==null&&(D.dependencies=P.dependencies);var j=D.expirationTime;if(j!==0&&Um(j),D.childExpirationTime<T)return null;if(P!==null&&D.child!==P.child)throw Error(n(153));if(D.child!==null){for(P=D.child,T=YA(P,P.pendingProps,P.expirationTime),D.child=T,T.return=D;P.sibling!==null;)P=P.sibling,T=T.sibling=YA(P,P.pendingProps,P.expirationTime),T.return=D;T.sibling=null}return D.child}function pa(P){P.effectTag|=4}var vc,Bl,ts,Gr;if(w)vc=function(P,D){for(var T=D.child;T!==null;){if(T.tag===5||T.tag===6)H(P,T.stateNode);else if(T.tag!==4&&T.child!==null){T.child.return=T,T=T.child;continue}if(T===D)break;for(;T.sibling===null;){if(T.return===null||T.return===D)return;T=T.return}T.sibling.return=T.return,T=T.sibling}},Bl=function(){},ts=function(P,D,T,j,Y){if(P=P.memoizedProps,P!==j){var fe=D.stateNode,ve=ca(uo.current);T=Te(fe,T,P,j,Y,ve),(D.updateQueue=T)&&pa(D)}},Gr=function(P,D,T,j){T!==j&&pa(D)};else if(S){vc=function(P,D,T,j){for(var Y=D.child;Y!==null;){if(Y.tag===5){var fe=Y.stateNode;T&&j&&(fe=Ti(fe,Y.type,Y.memoizedProps,Y)),H(P,fe)}else if(Y.tag===6)fe=Y.stateNode,T&&j&&(fe=ps(fe,Y.memoizedProps,Y)),H(P,fe);else if(Y.tag!==4){if(Y.tag===13&&(Y.effectTag&4)!==0&&(fe=Y.memoizedState!==null)){var ve=Y.child;if(ve!==null&&(ve.child!==null&&(ve.child.return=ve,vc(P,ve,!0,fe)),fe=ve.sibling,fe!==null)){fe.return=Y,Y=fe;continue}}if(Y.child!==null){Y.child.return=Y,Y=Y.child;continue}}if(Y===D)break;for(;Y.sibling===null;){if(Y.return===null||Y.return===D)return;Y=Y.return}Y.sibling.return=Y.return,Y=Y.sibling}};var mp=function(P,D,T,j){for(var Y=D.child;Y!==null;){if(Y.tag===5){var fe=Y.stateNode;T&&j&&(fe=Ti(fe,Y.type,Y.memoizedProps,Y)),Wr(P,fe)}else if(Y.tag===6)fe=Y.stateNode,T&&j&&(fe=ps(fe,Y.memoizedProps,Y)),Wr(P,fe);else if(Y.tag!==4){if(Y.tag===13&&(Y.effectTag&4)!==0&&(fe=Y.memoizedState!==null)){var ve=Y.child;if(ve!==null&&(ve.child!==null&&(ve.child.return=ve,mp(P,ve,!0,fe)),fe=ve.sibling,fe!==null)){fe.return=Y,Y=fe;continue}}if(Y.child!==null){Y.child.return=Y,Y=Y.child;continue}}if(Y===D)break;for(;Y.sibling===null;){if(Y.return===null||Y.return===D)return;Y=Y.return}Y.sibling.return=Y.return,Y=Y.sibling}};Bl=function(P){var D=P.stateNode;if(P.firstEffect!==null){var T=D.containerInfo,j=br(T);mp(j,P,!1,!1),D.pendingChildren=j,pa(P),Kn(T,j)}},ts=function(P,D,T,j,Y){var fe=P.stateNode,ve=P.memoizedProps;if((P=D.firstEffect===null)&&ve===j)D.stateNode=fe;else{var vt=D.stateNode,wt=ca(uo.current),xt=null;ve!==j&&(xt=Te(vt,T,ve,j,Y,wt)),P&&xt===null?D.stateNode=fe:(fe=mr(fe,xt,T,ve,j,D,P,vt),lt(fe,T,j,Y,wt)&&pa(D),D.stateNode=fe,P?pa(D):vc(fe,D,!1,!1))}},Gr=function(P,D,T,j){T!==j&&(P=ca(mc.current),T=ca(uo.current),D.stateNode=_e(j,P,T,D),pa(D))}}else Bl=function(){},ts=function(){},Gr=function(){};function Dc(P,D){switch(P.tailMode){case\"hidden\":D=P.tail;for(var T=null;D!==null;)D.alternate!==null&&(T=D),D=D.sibling;T===null?P.tail=null:T.sibling=null;break;case\"collapsed\":T=P.tail;for(var j=null;T!==null;)T.alternate!==null&&(j=T),T=T.sibling;j===null?D||P.tail===null?P.tail=null:P.tail.sibling=null:j.sibling=null}}function yw(P){switch(P.tag){case 1:ii(P.type)&&Ma(P);var D=P.effectTag;return D&4096?(P.effectTag=D&-4097|64,P):null;case 3:if(yc(P),hr(P),D=P.effectTag,(D&64)!==0)throw Error(n(285));return P.effectTag=D&-4097|64,P;case 5:return sg(P),null;case 13:return Vn($n,P),D=P.effectTag,D&4096?(P.effectTag=D&-4097|64,P):null;case 19:return Vn($n,P),null;case 4:return yc(P),null;case 10:return wi(P),null;default:return null}}function mg(P,D){return{value:P,source:D,stack:ml(D)}}var yg=typeof WeakSet==\"function\"?WeakSet:Set;function Ga(P,D){var T=D.source,j=D.stack;j===null&&T!==null&&(j=ml(T)),T!==null&&ae(T.type),D=D.value,P!==null&&P.tag===1&&ae(P.type);try{console.error(D)}catch(Y){setTimeout(function(){throw Y})}}function Qm(P,D){try{D.props=P.memoizedProps,D.state=P.memoizedState,D.componentWillUnmount()}catch(T){GA(P,T)}}function Eg(P){var D=P.ref;if(D!==null)if(typeof D==\"function\")try{D(null)}catch(T){GA(P,T)}else D.current=null}function Qt(P,D){switch(D.tag){case 0:case 11:case 15:N(2,0,D);break;case 1:if(D.effectTag&256&&P!==null){var T=P.memoizedProps,j=P.memoizedState;P=D.stateNode,D=P.getSnapshotBeforeUpdate(D.elementType===D.type?T:Ci(D.type,T),j),P.__reactInternalSnapshotBeforeUpdate=D}break;case 3:case 5:case 6:case 4:case 17:break;default:throw Error(n(163))}}function N(P,D,T){if(T=T.updateQueue,T=T!==null?T.lastEffect:null,T!==null){var j=T=T.next;do{if((j.tag&P)!==0){var Y=j.destroy;j.destroy=void 0,Y!==void 0&&Y()}(j.tag&D)!==0&&(Y=j.create,j.destroy=Y()),j=j.next}while(j!==T)}}function K(P,D,T){switch(typeof bw==\"function\"&&bw(D),D.tag){case 0:case 11:case 14:case 15:if(P=D.updateQueue,P!==null&&(P=P.lastEffect,P!==null)){var j=P.next;lo(97<T?97:T,function(){var Y=j;do{var fe=Y.destroy;if(fe!==void 0){var ve=D;try{fe()}catch(vt){GA(ve,vt)}}Y=Y.next}while(Y!==j)})}break;case 1:Eg(D),T=D.stateNode,typeof T.componentWillUnmount==\"function\"&&Qm(D,T);break;case 5:Eg(D);break;case 4:w?Cr(P,D,T):S&&Je(D)}}function re(P,D,T){for(var j=D;;)if(K(P,j,T),j.child===null||w&&j.tag===4){if(j===D)break;for(;j.sibling===null;){if(j.return===null||j.return===D)return;j=j.return}j.sibling.return=j.return,j=j.sibling}else j.child.return=j,j=j.child}function pe(P){var D=P.alternate;P.return=null,P.child=null,P.memoizedState=null,P.updateQueue=null,P.dependencies=null,P.alternate=null,P.firstEffect=null,P.lastEffect=null,P.pendingProps=null,P.memoizedProps=null,D!==null&&pe(D)}function Je(P){if(S){P=P.stateNode.containerInfo;var D=br(P);Ns(P,D)}}function mt(P){return P.tag===5||P.tag===3||P.tag===4}function fr(P){if(w){e:{for(var D=P.return;D!==null;){if(mt(D)){var T=D;break e}D=D.return}throw Error(n(160))}switch(D=T.stateNode,T.tag){case 5:var j=!1;break;case 3:D=D.containerInfo,j=!0;break;case 4:D=D.containerInfo,j=!0;break;default:throw Error(n(161))}T.effectTag&16&&(jt(D),T.effectTag&=-17);e:t:for(T=P;;){for(;T.sibling===null;){if(T.return===null||mt(T.return)){T=null;break e}T=T.return}for(T.sibling.return=T.return,T=T.sibling;T.tag!==5&&T.tag!==6&&T.tag!==18;){if(T.effectTag&2||T.child===null||T.tag===4)continue t;T.child.return=T,T=T.child}if(!(T.effectTag&2)){T=T.stateNode;break e}}for(var Y=P;;){var fe=Y.tag===5||Y.tag===6;if(fe)fe=fe?Y.stateNode:Y.stateNode.instance,T?j?Ne(D,fe,T):Pe(D,fe,T):j?J(D,fe):F(D,fe);else if(Y.tag!==4&&Y.child!==null){Y.child.return=Y,Y=Y.child;continue}if(Y===P)break;for(;Y.sibling===null;){if(Y.return===null||Y.return===P)return;Y=Y.return}Y.sibling.return=Y.return,Y=Y.sibling}}}function Cr(P,D,T){for(var j=D,Y=!1,fe,ve;;){if(!Y){Y=j.return;e:for(;;){if(Y===null)throw Error(n(160));switch(fe=Y.stateNode,Y.tag){case 5:ve=!1;break e;case 3:fe=fe.containerInfo,ve=!0;break e;case 4:fe=fe.containerInfo,ve=!0;break e}Y=Y.return}Y=!0}if(j.tag===5||j.tag===6)re(P,j,T),ve?dt(fe,j.stateNode):ot(fe,j.stateNode);else if(j.tag===4){if(j.child!==null){fe=j.stateNode.containerInfo,ve=!0,j.child.return=j,j=j.child;continue}}else if(K(P,j,T),j.child!==null){j.child.return=j,j=j.child;continue}if(j===D)break;for(;j.sibling===null;){if(j.return===null||j.return===D)return;j=j.return,j.tag===4&&(Y=!1)}j.sibling.return=j.return,j=j.sibling}}function yn(P,D){if(w)switch(D.tag){case 0:case 11:case 14:case 15:N(4,8,D);break;case 1:break;case 5:var T=D.stateNode;if(T!=null){var j=D.memoizedProps;P=P!==null?P.memoizedProps:j;var Y=D.type,fe=D.updateQueue;D.updateQueue=null,fe!==null&&ie(T,fe,Y,P,j,D)}break;case 6:if(D.stateNode===null)throw Error(n(162));T=D.memoizedProps,X(D.stateNode,P!==null?P.memoizedProps:T,T);break;case 3:y&&(D=D.stateNode,D.hydrate&&(D.hydrate=!1,Dn(D.containerInfo)));break;case 12:break;case 13:oi(D),Oi(D);break;case 19:Oi(D);break;case 17:break;case 20:break;case 21:break;default:throw Error(n(163))}else{switch(D.tag){case 0:case 11:case 14:case 15:N(4,8,D);return;case 12:return;case 13:oi(D),Oi(D);return;case 19:Oi(D);return;case 3:y&&(T=D.stateNode,T.hydrate&&(T.hydrate=!1,Dn(T.containerInfo)))}e:if(S)switch(D.tag){case 1:case 5:case 6:case 20:break e;case 3:case 4:D=D.stateNode,Ns(D.containerInfo,D.pendingChildren);break e;default:throw Error(n(163))}}}function oi(P){var D=P;if(P.memoizedState===null)var T=!1;else T=!0,D=P.child,ww=Li();if(w&&D!==null){e:if(P=D,w)for(D=P;;){if(D.tag===5){var j=D.stateNode;T?$t(j):an(D.stateNode,D.memoizedProps)}else if(D.tag===6)j=D.stateNode,T?bt(j):Qr(j,D.memoizedProps);else if(D.tag===13&&D.memoizedState!==null&&D.memoizedState.dehydrated===null){j=D.child.sibling,j.return=D,D=j;continue}else if(D.child!==null){D.child.return=D,D=D.child;continue}if(D===P)break e;for(;D.sibling===null;){if(D.return===null||D.return===P)break e;D=D.return}D.sibling.return=D.return,D=D.sibling}}}function Oi(P){var D=P.updateQueue;if(D!==null){P.updateQueue=null;var T=P.stateNode;T===null&&(T=P.stateNode=new yg),D.forEach(function(j){var Y=CF.bind(null,P,j);T.has(j)||(T.add(j),j.then(Y,Y))})}}var Cg=typeof WeakMap==\"function\"?WeakMap:Map;function Gv(P,D,T){T=ys(T,null),T.tag=3,T.payload={element:null};var j=D.value;return T.callback=function(){vu||(vu=!0,Lm=j),Ga(P,D)},T}function Yv(P,D,T){T=ys(T,null),T.tag=3;var j=P.type.getDerivedStateFromError;if(typeof j==\"function\"){var Y=D.value;T.payload=function(){return Ga(P,D),j(Y)}}var fe=P.stateNode;return fe!==null&&typeof fe.componentDidCatch==\"function\"&&(T.callback=function(){typeof j!=\"function\"&&(Du===null?Du=new Set([this]):Du.add(this),Ga(P,D));var ve=D.stack;this.componentDidCatch(D.value,{componentStack:ve!==null?ve:\"\"})}),T}var Ew=Math.ceil,yp=u.ReactCurrentDispatcher,Cw=u.ReactCurrentOwner,En=0,Fm=8,rs=16,js=32,Bu=0,Rm=1,Bi=2,ha=3,vl=4,Pc=5,yr=En,gi=null,Or=null,ns=0,Yi=Bu,Tm=null,Ya=1073741823,OA=1073741823,Nm=null,Ep=0,MA=!1,ww=0,Iw=500,sr=null,vu=!1,Lm=null,Du=null,Cp=!1,wg=null,UA=90,_A=null,Ig=0,Bw=null,Om=0;function ga(){return(yr&(rs|js))!==En?1073741821-(Li()/10|0):Om!==0?Om:Om=1073741821-(Li()/10|0)}function HA(P,D,T){if(D=D.mode,(D&2)===0)return 1073741823;var j=_o();if((D&4)===0)return j===99?1073741823:1073741822;if((yr&rs)!==En)return ns;if(T!==null)P=Ua(P,T.timeoutMs|0||5e3,250);else switch(j){case 99:P=1073741823;break;case 98:P=Ua(P,150,100);break;case 97:case 96:P=Ua(P,5e3,250);break;case 95:P=2;break;default:throw Error(n(326))}return gi!==null&&P===ns&&--P,P}function Sc(P,D){if(50<Ig)throw Ig=0,Bw=null,Error(n(185));if(P=Bg(P,D),P!==null){var T=_o();D===1073741823?(yr&Fm)!==En&&(yr&(rs|js))===En?vw(P):(fo(P),yr===En&&ji()):fo(P),(yr&4)===En||T!==98&&T!==99||(_A===null?_A=new Map([[P,D]]):(T=_A.get(P),(T===void 0||T>D)&&_A.set(P,D)))}}function Bg(P,D){P.expirationTime<D&&(P.expirationTime=D);var T=P.alternate;T!==null&&T.expirationTime<D&&(T.expirationTime=D);var j=P.return,Y=null;if(j===null&&P.tag===3)Y=P.stateNode;else for(;j!==null;){if(T=j.alternate,j.childExpirationTime<D&&(j.childExpirationTime=D),T!==null&&T.childExpirationTime<D&&(T.childExpirationTime=D),j.return===null&&j.tag===3){Y=j.stateNode;break}j=j.return}return Y!==null&&(gi===Y&&(Um(D),Yi===vl&&WA(Y,ns)),eD(Y,D)),Y}function Mm(P){var D=P.lastExpiredTime;return D!==0||(D=P.firstPendingTime,!$v(P,D))?D:(D=P.lastPingedTime,P=P.nextKnownPendingLevel,D>P?D:P)}function fo(P){if(P.lastExpiredTime!==0)P.callbackExpirationTime=1073741823,P.callbackPriority=99,P.callbackNode=pu(vw.bind(null,P));else{var D=Mm(P),T=P.callbackNode;if(D===0)T!==null&&(P.callbackNode=null,P.callbackExpirationTime=0,P.callbackPriority=90);else{var j=ga();if(D===1073741823?j=99:D===1||D===2?j=95:(j=10*(1073741821-D)-10*(1073741821-j),j=0>=j?99:250>=j?98:5250>=j?97:95),T!==null){var Y=P.callbackPriority;if(P.callbackExpirationTime===D&&Y>=j)return;T!==PA&&Ce(T)}P.callbackExpirationTime=D,P.callbackPriority=j,D=D===1073741823?pu(vw.bind(null,P)):gc(j,Wv.bind(null,P),{timeout:10*(1073741821-D)-Li()}),P.callbackNode=D}}}function Wv(P,D){if(Om=0,D)return D=ga(),Hm(P,D),fo(P),null;var T=Mm(P);if(T!==0){if(D=P.callbackNode,(yr&(rs|js))!==En)throw Error(n(327));if(wp(),P===gi&&T===ns||Pu(P,T),Or!==null){var j=yr;yr|=rs;var Y=qA(P);do try{gF();break}catch(vt){jA(P,vt)}while(1);if(la(),yr=j,yp.current=Y,Yi===Rm)throw D=Tm,Pu(P,T),WA(P,T),fo(P),D;if(Or===null)switch(Y=P.finishedWork=P.current.alternate,P.finishedExpirationTime=T,j=Yi,gi=null,j){case Bu:case Rm:throw Error(n(345));case Bi:Hm(P,2<T?2:T);break;case ha:if(WA(P,T),j=P.lastSuspendedTime,T===j&&(P.nextKnownPendingLevel=Pw(Y)),Ya===1073741823&&(Y=ww+Iw-Li(),10<Y)){if(MA){var fe=P.lastPingedTime;if(fe===0||fe>=T){P.lastPingedTime=T,Pu(P,T);break}}if(fe=Mm(P),fe!==0&&fe!==T)break;if(j!==0&&j!==T){P.lastPingedTime=j;break}P.timeoutHandle=Re(Su.bind(null,P),Y);break}Su(P);break;case vl:if(WA(P,T),j=P.lastSuspendedTime,T===j&&(P.nextKnownPendingLevel=Pw(Y)),MA&&(Y=P.lastPingedTime,Y===0||Y>=T)){P.lastPingedTime=T,Pu(P,T);break}if(Y=Mm(P),Y!==0&&Y!==T)break;if(j!==0&&j!==T){P.lastPingedTime=j;break}if(OA!==1073741823?j=10*(1073741821-OA)-Li():Ya===1073741823?j=0:(j=10*(1073741821-Ya)-5e3,Y=Li(),T=10*(1073741821-T)-Y,j=Y-j,0>j&&(j=0),j=(120>j?120:480>j?480:1080>j?1080:1920>j?1920:3e3>j?3e3:4320>j?4320:1960*Ew(j/1960))-j,T<j&&(j=T)),10<j){P.timeoutHandle=Re(Su.bind(null,P),j);break}Su(P);break;case Pc:if(Ya!==1073741823&&Nm!==null){fe=Ya;var ve=Nm;if(j=ve.busyMinDurationMs|0,0>=j?j=0:(Y=ve.busyDelayMs|0,fe=Li()-(10*(1073741821-fe)-(ve.timeoutMs|0||5e3)),j=fe<=Y?0:Y+j-fe),10<j){WA(P,T),P.timeoutHandle=Re(Su.bind(null,P),j);break}}Su(P);break;default:throw Error(n(329))}if(fo(P),P.callbackNode===D)return Wv.bind(null,P)}}return null}function vw(P){var D=P.lastExpiredTime;if(D=D!==0?D:1073741823,P.finishedExpirationTime===D)Su(P);else{if((yr&(rs|js))!==En)throw Error(n(327));if(wp(),P===gi&&D===ns||Pu(P,D),Or!==null){var T=yr;yr|=rs;var j=qA(P);do try{hF();break}catch(Y){jA(P,Y)}while(1);if(la(),yr=T,yp.current=j,Yi===Rm)throw T=Tm,Pu(P,D),WA(P,D),fo(P),T;if(Or!==null)throw Error(n(261));P.finishedWork=P.current.alternate,P.finishedExpirationTime=D,gi=null,Su(P),fo(P)}}return null}function Kv(P,D){Hm(P,D),fo(P),(yr&(rs|js))===En&&ji()}function pF(){if(_A!==null){var P=_A;_A=null,P.forEach(function(D,T){Hm(T,D),fo(T)}),ji()}}function Vv(P,D){if((yr&(rs|js))!==En)throw Error(n(187));var T=yr;yr|=1;try{return lo(99,P.bind(null,D))}finally{yr=T,ji()}}function Pu(P,D){P.finishedWork=null,P.finishedExpirationTime=0;var T=P.timeoutHandle;if(T!==He&&(P.timeoutHandle=He,ze(T)),Or!==null)for(T=Or.return;T!==null;){var j=T;switch(j.tag){case 1:var Y=j.type.childContextTypes;Y!=null&&Ma(j);break;case 3:yc(j),hr(j);break;case 5:sg(j);break;case 4:yc(j);break;case 13:Vn($n,j);break;case 19:Vn($n,j);break;case 10:wi(j)}T=T.return}gi=P,Or=YA(P.current,null,D),ns=D,Yi=Bu,Tm=null,OA=Ya=1073741823,Nm=null,Ep=0,MA=!1}function jA(P,D){do{try{if(la(),dw(),Or===null||Or.return===null)return Yi=Rm,Tm=D,null;e:{var T=P,j=Or.return,Y=Or,fe=D;if(D=ns,Y.effectTag|=2048,Y.firstEffect=Y.lastEffect=null,fe!==null&&typeof fe==\"object\"&&typeof fe.then==\"function\"){var ve=fe,vt=($n.current&1)!==0,wt=j;do{var xt;if(xt=wt.tag===13){var _r=wt.memoizedState;if(_r!==null)xt=_r.dehydrated!==null;else{var is=wt.memoizedProps;xt=is.fallback===void 0?!1:is.unstable_avoidThisFallback!==!0?!0:!vt}}if(xt){var di=wt.updateQueue;if(di===null){var po=new Set;po.add(ve),wt.updateQueue=po}else di.add(ve);if((wt.mode&2)===0){if(wt.effectTag|=64,Y.effectTag&=-2981,Y.tag===1)if(Y.alternate===null)Y.tag=17;else{var KA=ys(1073741823,null);KA.tag=2,tt(Y,KA)}Y.expirationTime=1073741823;break e}fe=void 0,Y=D;var Yo=T.pingCache;if(Yo===null?(Yo=T.pingCache=new Cg,fe=new Set,Yo.set(ve,fe)):(fe=Yo.get(ve),fe===void 0&&(fe=new Set,Yo.set(ve,fe))),!fe.has(Y)){fe.add(Y);var rt=EF.bind(null,T,ve,Y);ve.then(rt,rt)}wt.effectTag|=4096,wt.expirationTime=D;break e}wt=wt.return}while(wt!==null);fe=Error((ae(Y.type)||\"A React component\")+` suspended while rendering, but no fallback UI was specified.\n\nAdd a <Suspense fallback=...> component higher in the tree to provide a loading indicator or placeholder to display.`+ml(Y))}Yi!==Pc&&(Yi=Bi),fe=mg(fe,Y),wt=j;do{switch(wt.tag){case 3:ve=fe,wt.effectTag|=4096,wt.expirationTime=D;var Ve=Gv(wt,ve,D);It(wt,Ve);break e;case 1:ve=fe;var At=wt.type,Wt=wt.stateNode;if((wt.effectTag&64)===0&&(typeof At.getDerivedStateFromError==\"function\"||Wt!==null&&typeof Wt.componentDidCatch==\"function\"&&(Du===null||!Du.has(Wt)))){wt.effectTag|=4096,wt.expirationTime=D;var vr=Yv(wt,ve,D);It(wt,vr);break e}}wt=wt.return}while(wt!==null)}Or=Jv(Or)}catch(Sn){D=Sn;continue}break}while(1)}function qA(){var P=yp.current;return yp.current=wu,P===null?wu:P}function Dw(P,D){P<Ya&&2<P&&(Ya=P),D!==null&&P<OA&&2<P&&(OA=P,Nm=D)}function Um(P){P>Ep&&(Ep=P)}function hF(){for(;Or!==null;)Or=zv(Or)}function gF(){for(;Or!==null&&!Rt();)Or=zv(Or)}function zv(P){var D=Zv(P.alternate,P,ns);return P.memoizedProps=P.pendingProps,D===null&&(D=Jv(P)),Cw.current=null,D}function Jv(P){Or=P;do{var D=Or.alternate;if(P=Or.return,(Or.effectTag&2048)===0){e:{var T=D;D=Or;var j=ns,Y=D.pendingProps;switch(D.tag){case 2:break;case 16:break;case 15:case 0:break;case 1:ii(D.type)&&Ma(D);break;case 3:yc(D),hr(D),Y=D.stateNode,Y.pendingContext&&(Y.context=Y.pendingContext,Y.pendingContext=null),(T===null||T.child===null)&&ja(D)&&pa(D),Bl(D);break;case 5:sg(D);var fe=ca(mc.current);if(j=D.type,T!==null&&D.stateNode!=null)ts(T,D,j,Y,fe),T.ref!==D.ref&&(D.effectTag|=128);else if(Y){if(T=ca(uo.current),ja(D)){if(Y=D,!y)throw Error(n(175));T=op(Y.stateNode,Y.type,Y.memoizedProps,fe,T,Y),Y.updateQueue=T,T=T!==null,T&&pa(D)}else{var ve=ht(j,Y,fe,T,D);vc(ve,D,!1,!1),D.stateNode=ve,lt(ve,j,Y,fe,T)&&pa(D)}D.ref!==null&&(D.effectTag|=128)}else if(D.stateNode===null)throw Error(n(166));break;case 6:if(T&&D.stateNode!=null)Gr(T,D,T.memoizedProps,Y);else{if(typeof Y!=\"string\"&&D.stateNode===null)throw Error(n(166));if(T=ca(mc.current),fe=ca(uo.current),ja(D)){if(T=D,!y)throw Error(n(176));(T=ap(T.stateNode,T.memoizedProps,T))&&pa(D)}else D.stateNode=_e(Y,T,fe,D)}break;case 11:break;case 13:if(Vn($n,D),Y=D.memoizedState,(D.effectTag&64)!==0){D.expirationTime=j;break e}Y=Y!==null,fe=!1,T===null?D.memoizedProps.fallback!==void 0&&ja(D):(j=T.memoizedState,fe=j!==null,Y||j===null||(j=T.child.sibling,j!==null&&(ve=D.firstEffect,ve!==null?(D.firstEffect=j,j.nextEffect=ve):(D.firstEffect=D.lastEffect=j,j.nextEffect=null),j.effectTag=8))),Y&&!fe&&(D.mode&2)!==0&&(T===null&&D.memoizedProps.unstable_avoidThisFallback!==!0||($n.current&1)!==0?Yi===Bu&&(Yi=ha):((Yi===Bu||Yi===ha)&&(Yi=vl),Ep!==0&&gi!==null&&(WA(gi,ns),eD(gi,Ep)))),S&&Y&&(D.effectTag|=4),w&&(Y||fe)&&(D.effectTag|=4);break;case 7:break;case 8:break;case 12:break;case 4:yc(D),Bl(D);break;case 10:wi(D);break;case 9:break;case 14:break;case 17:ii(D.type)&&Ma(D);break;case 19:if(Vn($n,D),Y=D.memoizedState,Y===null)break;if(fe=(D.effectTag&64)!==0,ve=Y.rendering,ve===null){if(fe)Dc(Y,!1);else if(Yi!==Bu||T!==null&&(T.effectTag&64)!==0)for(T=D.child;T!==null;){if(ve=up(T),ve!==null){for(D.effectTag|=64,Dc(Y,!1),T=ve.updateQueue,T!==null&&(D.updateQueue=T,D.effectTag|=4),Y.lastEffect===null&&(D.firstEffect=null),D.lastEffect=Y.lastEffect,T=j,Y=D.child;Y!==null;)fe=Y,j=T,fe.effectTag&=2,fe.nextEffect=null,fe.firstEffect=null,fe.lastEffect=null,ve=fe.alternate,ve===null?(fe.childExpirationTime=0,fe.expirationTime=j,fe.child=null,fe.memoizedProps=null,fe.memoizedState=null,fe.updateQueue=null,fe.dependencies=null):(fe.childExpirationTime=ve.childExpirationTime,fe.expirationTime=ve.expirationTime,fe.child=ve.child,fe.memoizedProps=ve.memoizedProps,fe.memoizedState=ve.memoizedState,fe.updateQueue=ve.updateQueue,j=ve.dependencies,fe.dependencies=j===null?null:{expirationTime:j.expirationTime,firstContext:j.firstContext,responders:j.responders}),Y=Y.sibling;On($n,$n.current&1|2,D),D=D.child;break e}T=T.sibling}}else{if(!fe)if(T=up(ve),T!==null){if(D.effectTag|=64,fe=!0,T=T.updateQueue,T!==null&&(D.updateQueue=T,D.effectTag|=4),Dc(Y,!0),Y.tail===null&&Y.tailMode===\"hidden\"&&!ve.alternate){D=D.lastEffect=Y.lastEffect,D!==null&&(D.nextEffect=null);break}}else Li()>Y.tailExpiration&&1<j&&(D.effectTag|=64,fe=!0,Dc(Y,!1),D.expirationTime=D.childExpirationTime=j-1);Y.isBackwards?(ve.sibling=D.child,D.child=ve):(T=Y.last,T!==null?T.sibling=ve:D.child=ve,Y.last=ve)}if(Y.tail!==null){Y.tailExpiration===0&&(Y.tailExpiration=Li()+500),T=Y.tail,Y.rendering=T,Y.tail=T.sibling,Y.lastEffect=D.lastEffect,T.sibling=null,Y=$n.current,Y=fe?Y&1|2:Y&1,On($n,Y,D),D=T;break e}break;case 20:break;case 21:break;default:throw Error(n(156,D.tag))}D=null}if(T=Or,ns===1||T.childExpirationTime!==1){for(Y=0,fe=T.child;fe!==null;)j=fe.expirationTime,ve=fe.childExpirationTime,j>Y&&(Y=j),ve>Y&&(Y=ve),fe=fe.sibling;T.childExpirationTime=Y}if(D!==null)return D;P!==null&&(P.effectTag&2048)===0&&(P.firstEffect===null&&(P.firstEffect=Or.firstEffect),Or.lastEffect!==null&&(P.lastEffect!==null&&(P.lastEffect.nextEffect=Or.firstEffect),P.lastEffect=Or.lastEffect),1<Or.effectTag&&(P.lastEffect!==null?P.lastEffect.nextEffect=Or:P.firstEffect=Or,P.lastEffect=Or))}else{if(D=yw(Or,ns),D!==null)return D.effectTag&=2047,D;P!==null&&(P.firstEffect=P.lastEffect=null,P.effectTag|=2048)}if(D=Or.sibling,D!==null)return D;Or=P}while(Or!==null);return Yi===Bu&&(Yi=Pc),null}function Pw(P){var D=P.expirationTime;return P=P.childExpirationTime,D>P?D:P}function Su(P){var D=_o();return lo(99,dF.bind(null,P,D)),null}function dF(P,D){do wp();while(wg!==null);if((yr&(rs|js))!==En)throw Error(n(327));var T=P.finishedWork,j=P.finishedExpirationTime;if(T===null)return null;if(P.finishedWork=null,P.finishedExpirationTime=0,T===P.current)throw Error(n(177));P.callbackNode=null,P.callbackExpirationTime=0,P.callbackPriority=90,P.nextKnownPendingLevel=0;var Y=Pw(T);if(P.firstPendingTime=Y,j<=P.lastSuspendedTime?P.firstSuspendedTime=P.lastSuspendedTime=P.nextKnownPendingLevel=0:j<=P.firstSuspendedTime&&(P.firstSuspendedTime=j-1),j<=P.lastPingedTime&&(P.lastPingedTime=0),j<=P.lastExpiredTime&&(P.lastExpiredTime=0),P===gi&&(Or=gi=null,ns=0),1<T.effectTag?T.lastEffect!==null?(T.lastEffect.nextEffect=T,Y=T.firstEffect):Y=T:Y=T.firstEffect,Y!==null){var fe=yr;yr|=js,Cw.current=null,we(P.containerInfo),sr=Y;do try{mF()}catch(ho){if(sr===null)throw Error(n(330));GA(sr,ho),sr=sr.nextEffect}while(sr!==null);sr=Y;do try{for(var ve=P,vt=D;sr!==null;){var wt=sr.effectTag;if(wt&16&&w&&jt(sr.stateNode),wt&128){var xt=sr.alternate;if(xt!==null){var _r=xt.ref;_r!==null&&(typeof _r==\"function\"?_r(null):_r.current=null)}}switch(wt&1038){case 2:fr(sr),sr.effectTag&=-3;break;case 6:fr(sr),sr.effectTag&=-3,yn(sr.alternate,sr);break;case 1024:sr.effectTag&=-1025;break;case 1028:sr.effectTag&=-1025,yn(sr.alternate,sr);break;case 4:yn(sr.alternate,sr);break;case 8:var is=ve,di=sr,po=vt;w?Cr(is,di,po):re(is,di,po),pe(di)}sr=sr.nextEffect}}catch(ho){if(sr===null)throw Error(n(330));GA(sr,ho),sr=sr.nextEffect}while(sr!==null);xe(P.containerInfo),P.current=T,sr=Y;do try{for(wt=j;sr!==null;){var KA=sr.effectTag;if(KA&36){var Yo=sr.alternate;switch(xt=sr,_r=wt,xt.tag){case 0:case 11:case 15:N(16,32,xt);break;case 1:var rt=xt.stateNode;if(xt.effectTag&4)if(Yo===null)rt.componentDidMount();else{var Ve=xt.elementType===xt.type?Yo.memoizedProps:Ci(xt.type,Yo.memoizedProps);rt.componentDidUpdate(Ve,Yo.memoizedState,rt.__reactInternalSnapshotBeforeUpdate)}var At=xt.updateQueue;At!==null&&Le(xt,At,rt,_r);break;case 3:var Wt=xt.updateQueue;if(Wt!==null){if(ve=null,xt.child!==null)switch(xt.child.tag){case 5:ve=ce(xt.child.stateNode);break;case 1:ve=xt.child.stateNode}Le(xt,Wt,ve,_r)}break;case 5:var vr=xt.stateNode;Yo===null&&xt.effectTag&4&&Z(vr,xt.type,xt.memoizedProps,xt);break;case 6:break;case 4:break;case 12:break;case 13:if(y&&xt.memoizedState===null){var Sn=xt.alternate;if(Sn!==null){var Fr=Sn.memoizedState;if(Fr!==null){var bn=Fr.dehydrated;bn!==null&&oo(bn)}}}break;case 19:case 17:case 20:case 21:break;default:throw Error(n(163))}}if(KA&128){xt=void 0;var ai=sr.ref;if(ai!==null){var en=sr.stateNode;switch(sr.tag){case 5:xt=ce(en);break;default:xt=en}typeof ai==\"function\"?ai(xt):ai.current=xt}}sr=sr.nextEffect}}catch(ho){if(sr===null)throw Error(n(330));GA(sr,ho),sr=sr.nextEffect}while(sr!==null);sr=null,Qn(),yr=fe}else P.current=T;if(Cp)Cp=!1,wg=P,UA=D;else for(sr=Y;sr!==null;)D=sr.nextEffect,sr.nextEffect=null,sr=D;if(D=P.firstPendingTime,D===0&&(Du=null),D===1073741823?P===Bw?Ig++:(Ig=0,Bw=P):Ig=0,typeof Sw==\"function\"&&Sw(T.stateNode,j),fo(P),vu)throw vu=!1,P=Lm,Lm=null,P;return(yr&Fm)!==En||ji(),null}function mF(){for(;sr!==null;){var P=sr.effectTag;(P&256)!==0&&Qt(sr.alternate,sr),(P&512)===0||Cp||(Cp=!0,gc(97,function(){return wp(),null})),sr=sr.nextEffect}}function wp(){if(UA!==90){var P=97<UA?97:UA;return UA=90,lo(P,yF)}}function yF(){if(wg===null)return!1;var P=wg;if(wg=null,(yr&(rs|js))!==En)throw Error(n(331));var D=yr;for(yr|=js,P=P.current.firstEffect;P!==null;){try{var T=P;if((T.effectTag&512)!==0)switch(T.tag){case 0:case 11:case 15:N(128,0,T),N(0,64,T)}}catch(j){if(P===null)throw Error(n(330));GA(P,j)}T=P.nextEffect,P.nextEffect=null,P=T}return yr=D,ji(),!0}function Xv(P,D,T){D=mg(T,D),D=Gv(P,D,1073741823),tt(P,D),P=Bg(P,1073741823),P!==null&&fo(P)}function GA(P,D){if(P.tag===3)Xv(P,P,D);else for(var T=P.return;T!==null;){if(T.tag===3){Xv(T,P,D);break}else if(T.tag===1){var j=T.stateNode;if(typeof T.type.getDerivedStateFromError==\"function\"||typeof j.componentDidCatch==\"function\"&&(Du===null||!Du.has(j))){P=mg(D,P),P=Yv(T,P,1073741823),tt(T,P),T=Bg(T,1073741823),T!==null&&fo(T);break}}T=T.return}}function EF(P,D,T){var j=P.pingCache;j!==null&&j.delete(D),gi===P&&ns===T?Yi===vl||Yi===ha&&Ya===1073741823&&Li()-ww<Iw?Pu(P,ns):MA=!0:$v(P,T)&&(D=P.lastPingedTime,D!==0&&D<T||(P.lastPingedTime=T,P.finishedExpirationTime===T&&(P.finishedExpirationTime=0,P.finishedWork=null),fo(P)))}function CF(P,D){var T=P.stateNode;T!==null&&T.delete(D),D=0,D===0&&(D=ga(),D=HA(D,P,null)),P=Bg(P,D),P!==null&&fo(P)}var Zv;Zv=function(P,D,T){var j=D.expirationTime;if(P!==null){var Y=D.pendingProps;if(P.memoizedProps!==Y||_i.current)qo=!0;else{if(j<T){switch(qo=!1,D.tag){case 3:dg(D),gg();break;case 5:if(Dm(D),D.mode&4&&T!==1&&be(D.type,Y))return D.expirationTime=D.childExpirationTime=1,null;break;case 1:ii(D.type)&&Ac(D);break;case 4:ig(D,D.stateNode.containerInfo);break;case 10:Ho(D,D.memoizedProps.value);break;case 13:if(D.memoizedState!==null)return j=D.child.childExpirationTime,j!==0&&j>=T?ln(P,D,T):(On($n,$n.current&1,D),D=si(P,D,T),D!==null?D.sibling:null);On($n,$n.current&1,D);break;case 19:if(j=D.childExpirationTime>=T,(P.effectTag&64)!==0){if(j)return qa(P,D,T);D.effectTag|=64}if(Y=D.memoizedState,Y!==null&&(Y.rendering=null,Y.tail=null),On($n,$n.current,D),!j)return null}return si(P,D,T)}qo=!1}}else qo=!1;switch(D.expirationTime=0,D.tag){case 2:if(j=D.type,P!==null&&(P.alternate=null,D.alternate=null,D.effectTag|=2),P=D.pendingProps,Y=Oe(D,Mn.current),ds(D,T),Y=ag(null,D,j,P,Y,T),D.effectTag|=1,typeof Y==\"object\"&&Y!==null&&typeof Y.render==\"function\"&&Y.$$typeof===void 0){if(D.tag=1,dw(),ii(j)){var fe=!0;Ac(D)}else fe=!1;D.memoizedState=Y.state!==null&&Y.state!==void 0?Y.state:null;var ve=j.getDerivedStateFromProps;typeof ve==\"function\"&&er(D,j,ve,P),Y.updater=Zr,D.stateNode=Y,Y._reactInternalFiber=D,jo(D,j,P,T),D=dp(null,D,j,!0,fe,T)}else D.tag=0,ws(null,D,Y,T),D=D.child;return D;case 16:if(Y=D.elementType,P!==null&&(P.alternate=null,D.alternate=null,D.effectTag|=2),P=D.pendingProps,ye(Y),Y._status!==1)throw Y._result;switch(Y=Y._result,D.type=Y,fe=D.tag=BF(Y),P=Ci(Y,P),fe){case 0:D=NA(null,D,Y,P,T);break;case 1:D=gp(null,D,Y,P,T);break;case 11:D=Ii(null,D,Y,P,T);break;case 14:D=xm(null,D,Y,Ci(Y.type,P),j,T);break;default:throw Error(n(306,Y,\"\"))}return D;case 0:return j=D.type,Y=D.pendingProps,Y=D.elementType===j?Y:Ci(j,Y),NA(P,D,j,Y,T);case 1:return j=D.type,Y=D.pendingProps,Y=D.elementType===j?Y:Ci(j,Y),gp(P,D,j,Y,T);case 3:if(dg(D),j=D.updateQueue,j===null)throw Error(n(282));if(Y=D.memoizedState,Y=Y!==null?Y.element:null,me(D,j,D.pendingProps,null,T),j=D.memoizedState.element,j===Y)gg(),D=si(P,D,T);else{if((Y=D.stateNode.hydrate)&&(y?(Bc=cu(D.stateNode.containerInfo),Aa=D,Y=Il=!0):Y=!1),Y)for(T=ng(D,null,j,T),D.child=T;T;)T.effectTag=T.effectTag&-3|1024,T=T.sibling;else ws(P,D,j,T),gg();D=D.child}return D;case 5:return Dm(D),P===null&&TA(D),j=D.type,Y=D.pendingProps,fe=P!==null?P.memoizedProps:null,ve=Y.children,ke(j,Y)?ve=null:fe!==null&&ke(j,fe)&&(D.effectTag|=16),Go(P,D),D.mode&4&&T!==1&&be(j,Y)?(D.expirationTime=D.childExpirationTime=1,D=null):(ws(P,D,ve,T),D=D.child),D;case 6:return P===null&&TA(D),null;case 13:return ln(P,D,T);case 4:return ig(D,D.stateNode.containerInfo),j=D.pendingProps,P===null?D.child=gu(D,null,j,T):ws(P,D,j,T),D.child;case 11:return j=D.type,Y=D.pendingProps,Y=D.elementType===j?Y:Ci(j,Y),Ii(P,D,j,Y,T);case 7:return ws(P,D,D.pendingProps,T),D.child;case 8:return ws(P,D,D.pendingProps.children,T),D.child;case 12:return ws(P,D,D.pendingProps.children,T),D.child;case 10:e:{if(j=D.type._context,Y=D.pendingProps,ve=D.memoizedProps,fe=Y.value,Ho(D,fe),ve!==null){var vt=ve.value;if(fe=hs(vt,fe)?0:(typeof j._calculateChangedBits==\"function\"?j._calculateChangedBits(vt,fe):1073741823)|0,fe===0){if(ve.children===Y.children&&!_i.current){D=si(P,D,T);break e}}else for(vt=D.child,vt!==null&&(vt.return=D);vt!==null;){var wt=vt.dependencies;if(wt!==null){ve=vt.child;for(var xt=wt.firstContext;xt!==null;){if(xt.context===j&&(xt.observedBits&fe)!==0){vt.tag===1&&(xt=ys(T,null),xt.tag=2,tt(vt,xt)),vt.expirationTime<T&&(vt.expirationTime=T),xt=vt.alternate,xt!==null&&xt.expirationTime<T&&(xt.expirationTime=T),gs(vt.return,T),wt.expirationTime<T&&(wt.expirationTime=T);break}xt=xt.next}}else ve=vt.tag===10&&vt.type===D.type?null:vt.child;if(ve!==null)ve.return=vt;else for(ve=vt;ve!==null;){if(ve===D){ve=null;break}if(vt=ve.sibling,vt!==null){vt.return=ve.return,ve=vt;break}ve=ve.return}vt=ve}}ws(P,D,Y.children,T),D=D.child}return D;case 9:return Y=D.type,fe=D.pendingProps,j=fe.children,ds(D,T),Y=ms(Y,fe.unstable_observedBits),j=j(Y),D.effectTag|=1,ws(P,D,j,T),D.child;case 14:return Y=D.type,fe=Ci(Y,D.pendingProps),fe=Ci(Y.type,fe),xm(P,D,Y,fe,j,T);case 15:return km(P,D,D.type,D.pendingProps,j,T);case 17:return j=D.type,Y=D.pendingProps,Y=D.elementType===j?Y:Ci(j,Y),P!==null&&(P.alternate=null,D.alternate=null,D.effectTag|=2),D.tag=1,ii(j)?(P=!0,Ac(D)):P=!1,ds(D,T),es(D,j,Y,T),jo(D,j,Y,T),dp(null,D,j,!0,P,T);case 19:return qa(P,D,T)}throw Error(n(156,D.tag))};var Sw=null,bw=null;function wF(P){if(typeof __REACT_DEVTOOLS_GLOBAL_HOOK__>\"u\")return!1;var D=__REACT_DEVTOOLS_GLOBAL_HOOK__;if(D.isDisabled||!D.supportsFiber)return!0;try{var T=D.inject(P);Sw=function(j){try{D.onCommitFiberRoot(T,j,void 0,(j.current.effectTag&64)===64)}catch{}},bw=function(j){try{D.onCommitFiberUnmount(T,j)}catch{}}}catch{}return!0}function IF(P,D,T,j){this.tag=P,this.key=T,this.sibling=this.child=this.return=this.stateNode=this.type=this.elementType=null,this.index=0,this.ref=null,this.pendingProps=D,this.dependencies=this.memoizedState=this.updateQueue=this.memoizedProps=null,this.mode=j,this.effectTag=0,this.lastEffect=this.firstEffect=this.nextEffect=null,this.childExpirationTime=this.expirationTime=0,this.alternate=null}function Dl(P,D,T,j){return new IF(P,D,T,j)}function xw(P){return P=P.prototype,!(!P||!P.isReactComponent)}function BF(P){if(typeof P==\"function\")return xw(P)?1:0;if(P!=null){if(P=P.$$typeof,P===L)return 11;if(P===te)return 14}return 2}function YA(P,D){var T=P.alternate;return T===null?(T=Dl(P.tag,D,P.key,P.mode),T.elementType=P.elementType,T.type=P.type,T.stateNode=P.stateNode,T.alternate=P,P.alternate=T):(T.pendingProps=D,T.effectTag=0,T.nextEffect=null,T.firstEffect=null,T.lastEffect=null),T.childExpirationTime=P.childExpirationTime,T.expirationTime=P.expirationTime,T.child=P.child,T.memoizedProps=P.memoizedProps,T.memoizedState=P.memoizedState,T.updateQueue=P.updateQueue,D=P.dependencies,T.dependencies=D===null?null:{expirationTime:D.expirationTime,firstContext:D.firstContext,responders:D.responders},T.sibling=P.sibling,T.index=P.index,T.ref=P.ref,T}function _m(P,D,T,j,Y,fe){var ve=2;if(j=P,typeof P==\"function\")xw(P)&&(ve=1);else if(typeof P==\"string\")ve=5;else e:switch(P){case C:return bu(T.children,Y,fe,D);case R:ve=8,Y|=7;break;case I:ve=8,Y|=1;break;case v:return P=Dl(12,T,D,Y|8),P.elementType=v,P.type=v,P.expirationTime=fe,P;case U:return P=Dl(13,T,D,Y),P.type=U,P.elementType=U,P.expirationTime=fe,P;case z:return P=Dl(19,T,D,Y),P.elementType=z,P.expirationTime=fe,P;default:if(typeof P==\"object\"&&P!==null)switch(P.$$typeof){case x:ve=10;break e;case E:ve=9;break e;case L:ve=11;break e;case te:ve=14;break e;case le:ve=16,j=null;break e}throw Error(n(130,P==null?P:typeof P,\"\"))}return D=Dl(ve,T,D,Y),D.elementType=P,D.type=j,D.expirationTime=fe,D}function bu(P,D,T,j){return P=Dl(7,P,j,D),P.expirationTime=T,P}function kw(P,D,T){return P=Dl(6,P,null,D),P.expirationTime=T,P}function Qw(P,D,T){return D=Dl(4,P.children!==null?P.children:[],P.key,D),D.expirationTime=T,D.stateNode={containerInfo:P.containerInfo,pendingChildren:null,implementation:P.implementation},D}function vF(P,D,T){this.tag=D,this.current=null,this.containerInfo=P,this.pingCache=this.pendingChildren=null,this.finishedExpirationTime=0,this.finishedWork=null,this.timeoutHandle=He,this.pendingContext=this.context=null,this.hydrate=T,this.callbackNode=null,this.callbackPriority=90,this.lastExpiredTime=this.lastPingedTime=this.nextKnownPendingLevel=this.lastSuspendedTime=this.firstSuspendedTime=this.firstPendingTime=0}function $v(P,D){var T=P.firstSuspendedTime;return P=P.lastSuspendedTime,T!==0&&T>=D&&P<=D}function WA(P,D){var T=P.firstSuspendedTime,j=P.lastSuspendedTime;T<D&&(P.firstSuspendedTime=D),(j>D||T===0)&&(P.lastSuspendedTime=D),D<=P.lastPingedTime&&(P.lastPingedTime=0),D<=P.lastExpiredTime&&(P.lastExpiredTime=0)}function eD(P,D){D>P.firstPendingTime&&(P.firstPendingTime=D);var T=P.firstSuspendedTime;T!==0&&(D>=T?P.firstSuspendedTime=P.lastSuspendedTime=P.nextKnownPendingLevel=0:D>=P.lastSuspendedTime&&(P.lastSuspendedTime=D+1),D>P.nextKnownPendingLevel&&(P.nextKnownPendingLevel=D))}function Hm(P,D){var T=P.lastExpiredTime;(T===0||T>D)&&(P.lastExpiredTime=D)}function tD(P){var D=P._reactInternalFiber;if(D===void 0)throw typeof P.render==\"function\"?Error(n(188)):Error(n(268,Object.keys(P)));return P=Ee(D),P===null?null:P.stateNode}function rD(P,D){P=P.memoizedState,P!==null&&P.dehydrated!==null&&P.retryTime<D&&(P.retryTime=D)}function jm(P,D){rD(P,D),(P=P.alternate)&&rD(P,D)}var nD={createContainer:function(P,D,T){return P=new vF(P,D,T),D=Dl(3,null,null,D===2?7:D===1?3:0),P.current=D,D.stateNode=P},updateContainer:function(P,D,T,j){var Y=D.current,fe=ga(),ve=pt.suspense;fe=HA(fe,Y,ve);e:if(T){T=T._reactInternalFiber;t:{if(Ie(T)!==T||T.tag!==1)throw Error(n(170));var vt=T;do{switch(vt.tag){case 3:vt=vt.stateNode.context;break t;case 1:if(ii(vt.type)){vt=vt.stateNode.__reactInternalMemoizedMergedChildContext;break t}}vt=vt.return}while(vt!==null);throw Error(n(171))}if(T.tag===1){var wt=T.type;if(ii(wt)){T=uu(T,wt,vt);break e}}T=vt}else T=Ni;return D.context===null?D.context=T:D.pendingContext=T,D=ys(fe,ve),D.payload={element:P},j=j===void 0?null:j,j!==null&&(D.callback=j),tt(Y,D),Sc(Y,fe),fe},batchedEventUpdates:function(P,D){var T=yr;yr|=2;try{return P(D)}finally{yr=T,yr===En&&ji()}},batchedUpdates:function(P,D){var T=yr;yr|=1;try{return P(D)}finally{yr=T,yr===En&&ji()}},unbatchedUpdates:function(P,D){var T=yr;yr&=-2,yr|=Fm;try{return P(D)}finally{yr=T,yr===En&&ji()}},deferredUpdates:function(P){return lo(97,P)},syncUpdates:function(P,D,T,j){return lo(99,P.bind(null,D,T,j))},discreteUpdates:function(P,D,T,j){var Y=yr;yr|=4;try{return lo(98,P.bind(null,D,T,j))}finally{yr=Y,yr===En&&ji()}},flushDiscreteUpdates:function(){(yr&(1|rs|js))===En&&(pF(),wp())},flushControlled:function(P){var D=yr;yr|=1;try{lo(99,P)}finally{yr=D,yr===En&&ji()}},flushSync:Vv,flushPassiveEffects:wp,IsThisRendererActing:{current:!1},getPublicRootInstance:function(P){if(P=P.current,!P.child)return null;switch(P.child.tag){case 5:return ce(P.child.stateNode);default:return P.child.stateNode}},attemptSynchronousHydration:function(P){switch(P.tag){case 3:var D=P.stateNode;D.hydrate&&Kv(D,D.firstPendingTime);break;case 13:Vv(function(){return Sc(P,1073741823)}),D=Ua(ga(),150,100),jm(P,D)}},attemptUserBlockingHydration:function(P){if(P.tag===13){var D=Ua(ga(),150,100);Sc(P,D),jm(P,D)}},attemptContinuousHydration:function(P){if(P.tag===13){ga();var D=bA++;Sc(P,D),jm(P,D)}},attemptHydrationAtCurrentPriority:function(P){if(P.tag===13){var D=ga();D=HA(D,P,null),Sc(P,D),jm(P,D)}},findHostInstance:tD,findHostInstanceWithWarning:function(P){return tD(P)},findHostInstanceWithNoPortals:function(P){return P=De(P),P===null?null:P.tag===20?P.stateNode.instance:P.stateNode},shouldSuspend:function(){return!1},injectIntoDevTools:function(P){var D=P.findFiberByHostInstance;return wF(r({},P,{overrideHookState:null,overrideProps:null,setSuspenseHandler:null,scheduleUpdate:null,currentDispatcherRef:u.ReactCurrentDispatcher,findHostInstanceByFiber:function(T){return T=Ee(T),T===null?null:T.stateNode},findFiberByHostInstance:function(T){return D?D(T):null},findHostInstancesForRefresh:null,scheduleRefresh:null,scheduleRoot:null,setRefreshHandler:null,getCurrentFiber:null}))}};aB.exports=nD.default||nD;var DF=aB.exports;return aB.exports=t,DF}});var kEe=_((mKt,xEe)=>{\"use strict\";xEe.exports=bEe()});var FEe=_((yKt,QEe)=>{\"use strict\";var Gyt={ALIGN_COUNT:8,ALIGN_AUTO:0,ALIGN_FLEX_START:1,ALIGN_CENTER:2,ALIGN_FLEX_END:3,ALIGN_STRETCH:4,ALIGN_BASELINE:5,ALIGN_SPACE_BETWEEN:6,ALIGN_SPACE_AROUND:7,DIMENSION_COUNT:2,DIMENSION_WIDTH:0,DIMENSION_HEIGHT:1,DIRECTION_COUNT:3,DIRECTION_INHERIT:0,DIRECTION_LTR:1,DIRECTION_RTL:2,DISPLAY_COUNT:2,DISPLAY_FLEX:0,DISPLAY_NONE:1,EDGE_COUNT:9,EDGE_LEFT:0,EDGE_TOP:1,EDGE_RIGHT:2,EDGE_BOTTOM:3,EDGE_START:4,EDGE_END:5,EDGE_HORIZONTAL:6,EDGE_VERTICAL:7,EDGE_ALL:8,EXPERIMENTAL_FEATURE_COUNT:1,EXPERIMENTAL_FEATURE_WEB_FLEX_BASIS:0,FLEX_DIRECTION_COUNT:4,FLEX_DIRECTION_COLUMN:0,FLEX_DIRECTION_COLUMN_REVERSE:1,FLEX_DIRECTION_ROW:2,FLEX_DIRECTION_ROW_REVERSE:3,JUSTIFY_COUNT:6,JUSTIFY_FLEX_START:0,JUSTIFY_CENTER:1,JUSTIFY_FLEX_END:2,JUSTIFY_SPACE_BETWEEN:3,JUSTIFY_SPACE_AROUND:4,JUSTIFY_SPACE_EVENLY:5,LOG_LEVEL_COUNT:6,LOG_LEVEL_ERROR:0,LOG_LEVEL_WARN:1,LOG_LEVEL_INFO:2,LOG_LEVEL_DEBUG:3,LOG_LEVEL_VERBOSE:4,LOG_LEVEL_FATAL:5,MEASURE_MODE_COUNT:3,MEASURE_MODE_UNDEFINED:0,MEASURE_MODE_EXACTLY:1,MEASURE_MODE_AT_MOST:2,NODE_TYPE_COUNT:2,NODE_TYPE_DEFAULT:0,NODE_TYPE_TEXT:1,OVERFLOW_COUNT:3,OVERFLOW_VISIBLE:0,OVERFLOW_HIDDEN:1,OVERFLOW_SCROLL:2,POSITION_TYPE_COUNT:2,POSITION_TYPE_RELATIVE:0,POSITION_TYPE_ABSOLUTE:1,PRINT_OPTIONS_COUNT:3,PRINT_OPTIONS_LAYOUT:1,PRINT_OPTIONS_STYLE:2,PRINT_OPTIONS_CHILDREN:4,UNIT_COUNT:4,UNIT_UNDEFINED:0,UNIT_POINT:1,UNIT_PERCENT:2,UNIT_AUTO:3,WRAP_COUNT:3,WRAP_NO_WRAP:0,WRAP_WRAP:1,WRAP_WRAP_REVERSE:2};QEe.exports=Gyt});var LEe=_((EKt,NEe)=>{\"use strict\";var Yyt=Object.assign||function(t){for(var e=1;e<arguments.length;e++){var r=arguments[e];for(var o in r)Object.prototype.hasOwnProperty.call(r,o)&&(t[o]=r[o])}return t},Vk=function(){function t(e,r){for(var o=0;o<r.length;o++){var a=r[o];a.enumerable=a.enumerable||!1,a.configurable=!0,\"value\"in a&&(a.writable=!0),Object.defineProperty(e,a.key,a)}}return function(e,r,o){return r&&t(e.prototype,r),o&&t(e,o),e}}();function x6(t,e,r){return e in t?Object.defineProperty(t,e,{value:r,enumerable:!0,configurable:!0,writable:!0}):t[e]=r,t}function k6(t,e){if(!(t instanceof e))throw new TypeError(\"Cannot call a class as a function\")}var tu=FEe(),Wyt=function(){function t(e,r,o,a,n,u){k6(this,t),this.left=e,this.right=r,this.top=o,this.bottom=a,this.width=n,this.height=u}return Vk(t,[{key:\"fromJS\",value:function(r){r(this.left,this.right,this.top,this.bottom,this.width,this.height)}},{key:\"toString\",value:function(){return\"<Layout#\"+this.left+\":\"+this.right+\";\"+this.top+\":\"+this.bottom+\";\"+this.width+\":\"+this.height+\">\"}}]),t}(),REe=function(){Vk(t,null,[{key:\"fromJS\",value:function(r){var o=r.width,a=r.height;return new t(o,a)}}]);function t(e,r){k6(this,t),this.width=e,this.height=r}return Vk(t,[{key:\"fromJS\",value:function(r){r(this.width,this.height)}},{key:\"toString\",value:function(){return\"<Size#\"+this.width+\"x\"+this.height+\">\"}}]),t}(),TEe=function(){function t(e,r){k6(this,t),this.unit=e,this.value=r}return Vk(t,[{key:\"fromJS\",value:function(r){r(this.unit,this.value)}},{key:\"toString\",value:function(){switch(this.unit){case tu.UNIT_POINT:return String(this.value);case tu.UNIT_PERCENT:return this.value+\"%\";case tu.UNIT_AUTO:return\"auto\";default:return this.value+\"?\"}}},{key:\"valueOf\",value:function(){return this.value}}]),t}();NEe.exports=function(t,e){function r(u,A,p){var h=u[A];u[A]=function(){for(var C=arguments.length,I=Array(C),v=0;v<C;v++)I[v]=arguments[v];return p.call.apply(p,[this,h].concat(I))}}for(var o=[\"setPosition\",\"setMargin\",\"setFlexBasis\",\"setWidth\",\"setHeight\",\"setMinWidth\",\"setMinHeight\",\"setMaxWidth\",\"setMaxHeight\",\"setPadding\"],a=function(){var A,p=o[n],h=(A={},x6(A,tu.UNIT_POINT,e.Node.prototype[p]),x6(A,tu.UNIT_PERCENT,e.Node.prototype[p+\"Percent\"]),x6(A,tu.UNIT_AUTO,e.Node.prototype[p+\"Auto\"]),A);r(e.Node.prototype,p,function(C){for(var I=arguments.length,v=Array(I>1?I-1:0),x=1;x<I;x++)v[x-1]=arguments[x];var E=v.pop(),R=void 0,L=void 0;if(E===\"auto\")R=tu.UNIT_AUTO,L=void 0;else if(E instanceof TEe)R=E.unit,L=E.valueOf();else if(R=typeof E==\"string\"&&E.endsWith(\"%\")?tu.UNIT_PERCENT:tu.UNIT_POINT,L=parseFloat(E),!Number.isNaN(E)&&Number.isNaN(L))throw new Error(\"Invalid value \"+E+\" for \"+p);if(!h[R])throw new Error('Failed to execute \"'+p+`\": Unsupported unit '`+E+\"'\");if(L!==void 0){var U;return(U=h[R]).call.apply(U,[this].concat(v,[L]))}else{var z;return(z=h[R]).call.apply(z,[this].concat(v))}})},n=0;n<o.length;n++)a();return r(e.Config.prototype,\"free\",function(){e.Config.destroy(this)}),r(e.Node,\"create\",function(u,A){return A?e.Node.createWithConfig(A):e.Node.createDefault()}),r(e.Node.prototype,\"free\",function(){e.Node.destroy(this)}),r(e.Node.prototype,\"freeRecursive\",function(){for(var u=0,A=this.getChildCount();u<A;++u)this.getChild(0).freeRecursive();this.free()}),r(e.Node.prototype,\"setMeasureFunc\",function(u,A){return A?u.call(this,function(){return REe.fromJS(A.apply(void 0,arguments))}):this.unsetMeasureFunc()}),r(e.Node.prototype,\"calculateLayout\",function(u){var A=arguments.length>1&&arguments[1]!==void 0?arguments[1]:NaN,p=arguments.length>2&&arguments[2]!==void 0?arguments[2]:NaN,h=arguments.length>3&&arguments[3]!==void 0?arguments[3]:tu.DIRECTION_LTR;return u.call(this,A,p,h)}),Yyt({Config:e.Config,Node:e.Node,Layout:t(\"Layout\",Wyt),Size:t(\"Size\",REe),Value:t(\"Value\",TEe),getInstanceCount:function(){return e.getInstanceCount.apply(e,arguments)}},tu)}});var OEe=_((exports,module)=>{(function(t,e){typeof define==\"function\"&&define.amd?define([],function(){return e}):typeof module==\"object\"&&module.exports?module.exports=e:(t.nbind=t.nbind||{}).init=e})(exports,function(Module,cb){typeof Module==\"function\"&&(cb=Module,Module={}),Module.onRuntimeInitialized=function(t,e){return function(){t&&t.apply(this,arguments);try{Module.ccall(\"nbind_init\")}catch(r){e(r);return}e(null,{bind:Module._nbind_value,reflect:Module.NBind.reflect,queryType:Module.NBind.queryType,toggleLightGC:Module.toggleLightGC,lib:Module})}}(Module.onRuntimeInitialized,cb);var Module;Module||(Module=(typeof Module<\"u\"?Module:null)||{});var moduleOverrides={};for(var key in Module)Module.hasOwnProperty(key)&&(moduleOverrides[key]=Module[key]);var ENVIRONMENT_IS_WEB=!1,ENVIRONMENT_IS_WORKER=!1,ENVIRONMENT_IS_NODE=!1,ENVIRONMENT_IS_SHELL=!1;if(Module.ENVIRONMENT)if(Module.ENVIRONMENT===\"WEB\")ENVIRONMENT_IS_WEB=!0;else if(Module.ENVIRONMENT===\"WORKER\")ENVIRONMENT_IS_WORKER=!0;else if(Module.ENVIRONMENT===\"NODE\")ENVIRONMENT_IS_NODE=!0;else if(Module.ENVIRONMENT===\"SHELL\")ENVIRONMENT_IS_SHELL=!0;else throw new Error(\"The provided Module['ENVIRONMENT'] value is not valid. It must be one of: WEB|WORKER|NODE|SHELL.\");else ENVIRONMENT_IS_WEB=typeof window==\"object\",ENVIRONMENT_IS_WORKER=typeof importScripts==\"function\",ENVIRONMENT_IS_NODE=typeof process==\"object\"&&typeof Be==\"function\"&&!ENVIRONMENT_IS_WEB&&!ENVIRONMENT_IS_WORKER,ENVIRONMENT_IS_SHELL=!ENVIRONMENT_IS_WEB&&!ENVIRONMENT_IS_NODE&&!ENVIRONMENT_IS_WORKER;if(ENVIRONMENT_IS_NODE){Module.print||(Module.print=console.log),Module.printErr||(Module.printErr=console.warn);var nodeFS,nodePath;Module.read=function(e,r){nodeFS||(nodeFS={}(\"\")),nodePath||(nodePath={}(\"\")),e=nodePath.normalize(e);var o=nodeFS.readFileSync(e);return r?o:o.toString()},Module.readBinary=function(e){var r=Module.read(e,!0);return r.buffer||(r=new Uint8Array(r)),assert(r.buffer),r},Module.load=function(e){globalEval(read(e))},Module.thisProgram||(process.argv.length>1?Module.thisProgram=process.argv[1].replace(/\\\\/g,\"/\"):Module.thisProgram=\"unknown-program\"),Module.arguments=process.argv.slice(2),typeof module<\"u\"&&(module.exports=Module),Module.inspect=function(){return\"[Emscripten Module object]\"}}else if(ENVIRONMENT_IS_SHELL)Module.print||(Module.print=print),typeof printErr<\"u\"&&(Module.printErr=printErr),typeof read<\"u\"?Module.read=read:Module.read=function(){throw\"no read() available\"},Module.readBinary=function(e){if(typeof readbuffer==\"function\")return new Uint8Array(readbuffer(e));var r=read(e,\"binary\");return assert(typeof r==\"object\"),r},typeof scriptArgs<\"u\"?Module.arguments=scriptArgs:typeof arguments<\"u\"&&(Module.arguments=arguments),typeof quit==\"function\"&&(Module.quit=function(t,e){quit(t)});else if(ENVIRONMENT_IS_WEB||ENVIRONMENT_IS_WORKER){if(Module.read=function(e){var r=new XMLHttpRequest;return r.open(\"GET\",e,!1),r.send(null),r.responseText},ENVIRONMENT_IS_WORKER&&(Module.readBinary=function(e){var r=new XMLHttpRequest;return r.open(\"GET\",e,!1),r.responseType=\"arraybuffer\",r.send(null),new Uint8Array(r.response)}),Module.readAsync=function(e,r,o){var a=new XMLHttpRequest;a.open(\"GET\",e,!0),a.responseType=\"arraybuffer\",a.onload=function(){a.status==200||a.status==0&&a.response?r(a.response):o()},a.onerror=o,a.send(null)},typeof arguments<\"u\"&&(Module.arguments=arguments),typeof console<\"u\")Module.print||(Module.print=function(e){console.log(e)}),Module.printErr||(Module.printErr=function(e){console.warn(e)});else{var TRY_USE_DUMP=!1;Module.print||(Module.print=TRY_USE_DUMP&&typeof dump<\"u\"?function(t){dump(t)}:function(t){})}ENVIRONMENT_IS_WORKER&&(Module.load=importScripts),typeof Module.setWindowTitle>\"u\"&&(Module.setWindowTitle=function(t){document.title=t})}else throw\"Unknown runtime environment. Where are we?\";function globalEval(t){eval.call(null,t)}!Module.load&&Module.read&&(Module.load=function(e){globalEval(Module.read(e))}),Module.print||(Module.print=function(){}),Module.printErr||(Module.printErr=Module.print),Module.arguments||(Module.arguments=[]),Module.thisProgram||(Module.thisProgram=\"./this.program\"),Module.quit||(Module.quit=function(t,e){throw e}),Module.print=Module.print,Module.printErr=Module.printErr,Module.preRun=[],Module.postRun=[];for(var key in moduleOverrides)moduleOverrides.hasOwnProperty(key)&&(Module[key]=moduleOverrides[key]);moduleOverrides=void 0;var Runtime={setTempRet0:function(t){return tempRet0=t,t},getTempRet0:function(){return tempRet0},stackSave:function(){return STACKTOP},stackRestore:function(t){STACKTOP=t},getNativeTypeSize:function(t){switch(t){case\"i1\":case\"i8\":return 1;case\"i16\":return 2;case\"i32\":return 4;case\"i64\":return 8;case\"float\":return 4;case\"double\":return 8;default:{if(t[t.length-1]===\"*\")return Runtime.QUANTUM_SIZE;if(t[0]===\"i\"){var e=parseInt(t.substr(1));return assert(e%8===0),e/8}else return 0}}},getNativeFieldSize:function(t){return Math.max(Runtime.getNativeTypeSize(t),Runtime.QUANTUM_SIZE)},STACK_ALIGN:16,prepVararg:function(t,e){return e===\"double\"||e===\"i64\"?t&7&&(assert((t&7)===4),t+=4):assert((t&3)===0),t},getAlignSize:function(t,e,r){return!r&&(t==\"i64\"||t==\"double\")?8:t?Math.min(e||(t?Runtime.getNativeFieldSize(t):0),Runtime.QUANTUM_SIZE):Math.min(e,8)},dynCall:function(t,e,r){return r&&r.length?Module[\"dynCall_\"+t].apply(null,[e].concat(r)):Module[\"dynCall_\"+t].call(null,e)},functionPointers:[],addFunction:function(t){for(var e=0;e<Runtime.functionPointers.length;e++)if(!Runtime.functionPointers[e])return Runtime.functionPointers[e]=t,2*(1+e);throw\"Finished up all reserved function pointers. Use a higher value for RESERVED_FUNCTION_POINTERS.\"},removeFunction:function(t){Runtime.functionPointers[(t-2)/2]=null},warnOnce:function(t){Runtime.warnOnce.shown||(Runtime.warnOnce.shown={}),Runtime.warnOnce.shown[t]||(Runtime.warnOnce.shown[t]=1,Module.printErr(t))},funcWrappers:{},getFuncWrapper:function(t,e){if(!!t){assert(e),Runtime.funcWrappers[e]||(Runtime.funcWrappers[e]={});var r=Runtime.funcWrappers[e];return r[t]||(e.length===1?r[t]=function(){return Runtime.dynCall(e,t)}:e.length===2?r[t]=function(a){return Runtime.dynCall(e,t,[a])}:r[t]=function(){return Runtime.dynCall(e,t,Array.prototype.slice.call(arguments))}),r[t]}},getCompilerSetting:function(t){throw\"You must build with -s RETAIN_COMPILER_SETTINGS=1 for Runtime.getCompilerSetting or emscripten_get_compiler_setting to work\"},stackAlloc:function(t){var e=STACKTOP;return STACKTOP=STACKTOP+t|0,STACKTOP=STACKTOP+15&-16,e},staticAlloc:function(t){var e=STATICTOP;return STATICTOP=STATICTOP+t|0,STATICTOP=STATICTOP+15&-16,e},dynamicAlloc:function(t){var e=HEAP32[DYNAMICTOP_PTR>>2],r=(e+t+15|0)&-16;if(HEAP32[DYNAMICTOP_PTR>>2]=r,r>=TOTAL_MEMORY){var o=enlargeMemory();if(!o)return HEAP32[DYNAMICTOP_PTR>>2]=e,0}return e},alignMemory:function(t,e){var r=t=Math.ceil(t/(e||16))*(e||16);return r},makeBigInt:function(t,e,r){var o=r?+(t>>>0)+ +(e>>>0)*4294967296:+(t>>>0)+ +(e|0)*4294967296;return o},GLOBAL_BASE:8,QUANTUM_SIZE:4,__dummy__:0};Module.Runtime=Runtime;var ABORT=0,EXITSTATUS=0;function assert(t,e){t||abort(\"Assertion failed: \"+e)}function getCFunc(ident){var func=Module[\"_\"+ident];if(!func)try{func=eval(\"_\"+ident)}catch(t){}return assert(func,\"Cannot call unknown function \"+ident+\" (perhaps LLVM optimizations or closure removed it?)\"),func}var cwrap,ccall;(function(){var JSfuncs={stackSave:function(){Runtime.stackSave()},stackRestore:function(){Runtime.stackRestore()},arrayToC:function(t){var e=Runtime.stackAlloc(t.length);return writeArrayToMemory(t,e),e},stringToC:function(t){var e=0;if(t!=null&&t!==0){var r=(t.length<<2)+1;e=Runtime.stackAlloc(r),stringToUTF8(t,e,r)}return e}},toC={string:JSfuncs.stringToC,array:JSfuncs.arrayToC};ccall=function(e,r,o,a,n){var u=getCFunc(e),A=[],p=0;if(a)for(var h=0;h<a.length;h++){var C=toC[o[h]];C?(p===0&&(p=Runtime.stackSave()),A[h]=C(a[h])):A[h]=a[h]}var I=u.apply(null,A);if(r===\"string\"&&(I=Pointer_stringify(I)),p!==0){if(n&&n.async){EmterpreterAsync.asyncFinalizers.push(function(){Runtime.stackRestore(p)});return}Runtime.stackRestore(p)}return I};var sourceRegex=/^function\\s*[a-zA-Z$_0-9]*\\s*\\(([^)]*)\\)\\s*{\\s*([^*]*?)[\\s;]*(?:return\\s*(.*?)[;\\s]*)?}$/;function parseJSFunc(t){var e=t.toString().match(sourceRegex).slice(1);return{arguments:e[0],body:e[1],returnValue:e[2]}}var JSsource=null;function ensureJSsource(){if(!JSsource){JSsource={};for(var t in JSfuncs)JSfuncs.hasOwnProperty(t)&&(JSsource[t]=parseJSFunc(JSfuncs[t]))}}cwrap=function cwrap(ident,returnType,argTypes){argTypes=argTypes||[];var cfunc=getCFunc(ident),numericArgs=argTypes.every(function(t){return t===\"number\"}),numericRet=returnType!==\"string\";if(numericRet&&numericArgs)return cfunc;var argNames=argTypes.map(function(t,e){return\"$\"+e}),funcstr=\"(function(\"+argNames.join(\",\")+\") {\",nargs=argTypes.length;if(!numericArgs){ensureJSsource(),funcstr+=\"var stack = \"+JSsource.stackSave.body+\";\";for(var i=0;i<nargs;i++){var arg=argNames[i],type=argTypes[i];if(type!==\"number\"){var convertCode=JSsource[type+\"ToC\"];funcstr+=\"var \"+convertCode.arguments+\" = \"+arg+\";\",funcstr+=convertCode.body+\";\",funcstr+=arg+\"=(\"+convertCode.returnValue+\");\"}}}var cfuncname=parseJSFunc(function(){return cfunc}).returnValue;if(funcstr+=\"var ret = \"+cfuncname+\"(\"+argNames.join(\",\")+\");\",!numericRet){var strgfy=parseJSFunc(function(){return Pointer_stringify}).returnValue;funcstr+=\"ret = \"+strgfy+\"(ret);\"}return numericArgs||(ensureJSsource(),funcstr+=JSsource.stackRestore.body.replace(\"()\",\"(stack)\")+\";\"),funcstr+=\"return ret})\",eval(funcstr)}})(),Module.ccall=ccall,Module.cwrap=cwrap;function setValue(t,e,r,o){switch(r=r||\"i8\",r.charAt(r.length-1)===\"*\"&&(r=\"i32\"),r){case\"i1\":HEAP8[t>>0]=e;break;case\"i8\":HEAP8[t>>0]=e;break;case\"i16\":HEAP16[t>>1]=e;break;case\"i32\":HEAP32[t>>2]=e;break;case\"i64\":tempI64=[e>>>0,(tempDouble=e,+Math_abs(tempDouble)>=1?tempDouble>0?(Math_min(+Math_floor(tempDouble/4294967296),4294967295)|0)>>>0:~~+Math_ceil((tempDouble-+(~~tempDouble>>>0))/4294967296)>>>0:0)],HEAP32[t>>2]=tempI64[0],HEAP32[t+4>>2]=tempI64[1];break;case\"float\":HEAPF32[t>>2]=e;break;case\"double\":HEAPF64[t>>3]=e;break;default:abort(\"invalid type for setValue: \"+r)}}Module.setValue=setValue;function getValue(t,e,r){switch(e=e||\"i8\",e.charAt(e.length-1)===\"*\"&&(e=\"i32\"),e){case\"i1\":return HEAP8[t>>0];case\"i8\":return HEAP8[t>>0];case\"i16\":return HEAP16[t>>1];case\"i32\":return HEAP32[t>>2];case\"i64\":return HEAP32[t>>2];case\"float\":return HEAPF32[t>>2];case\"double\":return HEAPF64[t>>3];default:abort(\"invalid type for setValue: \"+e)}return null}Module.getValue=getValue;var ALLOC_NORMAL=0,ALLOC_STACK=1,ALLOC_STATIC=2,ALLOC_DYNAMIC=3,ALLOC_NONE=4;Module.ALLOC_NORMAL=ALLOC_NORMAL,Module.ALLOC_STACK=ALLOC_STACK,Module.ALLOC_STATIC=ALLOC_STATIC,Module.ALLOC_DYNAMIC=ALLOC_DYNAMIC,Module.ALLOC_NONE=ALLOC_NONE;function allocate(t,e,r,o){var a,n;typeof t==\"number\"?(a=!0,n=t):(a=!1,n=t.length);var u=typeof e==\"string\"?e:null,A;if(r==ALLOC_NONE?A=o:A=[typeof _malloc==\"function\"?_malloc:Runtime.staticAlloc,Runtime.stackAlloc,Runtime.staticAlloc,Runtime.dynamicAlloc][r===void 0?ALLOC_STATIC:r](Math.max(n,u?1:e.length)),a){var o=A,p;for(assert((A&3)==0),p=A+(n&-4);o<p;o+=4)HEAP32[o>>2]=0;for(p=A+n;o<p;)HEAP8[o++>>0]=0;return A}if(u===\"i8\")return t.subarray||t.slice?HEAPU8.set(t,A):HEAPU8.set(new Uint8Array(t),A),A;for(var h=0,C,I,v;h<n;){var x=t[h];if(typeof x==\"function\"&&(x=Runtime.getFunctionIndex(x)),C=u||e[h],C===0){h++;continue}C==\"i64\"&&(C=\"i32\"),setValue(A+h,x,C),v!==C&&(I=Runtime.getNativeTypeSize(C),v=C),h+=I}return A}Module.allocate=allocate;function getMemory(t){return staticSealed?runtimeInitialized?_malloc(t):Runtime.dynamicAlloc(t):Runtime.staticAlloc(t)}Module.getMemory=getMemory;function Pointer_stringify(t,e){if(e===0||!t)return\"\";for(var r=0,o,a=0;o=HEAPU8[t+a>>0],r|=o,!(o==0&&!e||(a++,e&&a==e)););e||(e=a);var n=\"\";if(r<128){for(var u=1024,A;e>0;)A=String.fromCharCode.apply(String,HEAPU8.subarray(t,t+Math.min(e,u))),n=n?n+A:A,t+=u,e-=u;return n}return Module.UTF8ToString(t)}Module.Pointer_stringify=Pointer_stringify;function AsciiToString(t){for(var e=\"\";;){var r=HEAP8[t++>>0];if(!r)return e;e+=String.fromCharCode(r)}}Module.AsciiToString=AsciiToString;function stringToAscii(t,e){return writeAsciiToMemory(t,e,!1)}Module.stringToAscii=stringToAscii;var UTF8Decoder=typeof TextDecoder<\"u\"?new TextDecoder(\"utf8\"):void 0;function UTF8ArrayToString(t,e){for(var r=e;t[r];)++r;if(r-e>16&&t.subarray&&UTF8Decoder)return UTF8Decoder.decode(t.subarray(e,r));for(var o,a,n,u,A,p,h=\"\";;){if(o=t[e++],!o)return h;if(!(o&128)){h+=String.fromCharCode(o);continue}if(a=t[e++]&63,(o&224)==192){h+=String.fromCharCode((o&31)<<6|a);continue}if(n=t[e++]&63,(o&240)==224?o=(o&15)<<12|a<<6|n:(u=t[e++]&63,(o&248)==240?o=(o&7)<<18|a<<12|n<<6|u:(A=t[e++]&63,(o&252)==248?o=(o&3)<<24|a<<18|n<<12|u<<6|A:(p=t[e++]&63,o=(o&1)<<30|a<<24|n<<18|u<<12|A<<6|p))),o<65536)h+=String.fromCharCode(o);else{var C=o-65536;h+=String.fromCharCode(55296|C>>10,56320|C&1023)}}}Module.UTF8ArrayToString=UTF8ArrayToString;function UTF8ToString(t){return UTF8ArrayToString(HEAPU8,t)}Module.UTF8ToString=UTF8ToString;function stringToUTF8Array(t,e,r,o){if(!(o>0))return 0;for(var a=r,n=r+o-1,u=0;u<t.length;++u){var A=t.charCodeAt(u);if(A>=55296&&A<=57343&&(A=65536+((A&1023)<<10)|t.charCodeAt(++u)&1023),A<=127){if(r>=n)break;e[r++]=A}else if(A<=2047){if(r+1>=n)break;e[r++]=192|A>>6,e[r++]=128|A&63}else if(A<=65535){if(r+2>=n)break;e[r++]=224|A>>12,e[r++]=128|A>>6&63,e[r++]=128|A&63}else if(A<=2097151){if(r+3>=n)break;e[r++]=240|A>>18,e[r++]=128|A>>12&63,e[r++]=128|A>>6&63,e[r++]=128|A&63}else if(A<=67108863){if(r+4>=n)break;e[r++]=248|A>>24,e[r++]=128|A>>18&63,e[r++]=128|A>>12&63,e[r++]=128|A>>6&63,e[r++]=128|A&63}else{if(r+5>=n)break;e[r++]=252|A>>30,e[r++]=128|A>>24&63,e[r++]=128|A>>18&63,e[r++]=128|A>>12&63,e[r++]=128|A>>6&63,e[r++]=128|A&63}}return e[r]=0,r-a}Module.stringToUTF8Array=stringToUTF8Array;function stringToUTF8(t,e,r){return stringToUTF8Array(t,HEAPU8,e,r)}Module.stringToUTF8=stringToUTF8;function lengthBytesUTF8(t){for(var e=0,r=0;r<t.length;++r){var o=t.charCodeAt(r);o>=55296&&o<=57343&&(o=65536+((o&1023)<<10)|t.charCodeAt(++r)&1023),o<=127?++e:o<=2047?e+=2:o<=65535?e+=3:o<=2097151?e+=4:o<=67108863?e+=5:e+=6}return e}Module.lengthBytesUTF8=lengthBytesUTF8;var UTF16Decoder=typeof TextDecoder<\"u\"?new TextDecoder(\"utf-16le\"):void 0;function demangle(t){var e=Module.___cxa_demangle||Module.__cxa_demangle;if(e){try{var r=t.substr(1),o=lengthBytesUTF8(r)+1,a=_malloc(o);stringToUTF8(r,a,o);var n=_malloc(4),u=e(a,0,0,n);if(getValue(n,\"i32\")===0&&u)return Pointer_stringify(u)}catch{}finally{a&&_free(a),n&&_free(n),u&&_free(u)}return t}return Runtime.warnOnce(\"warning: build with  -s DEMANGLE_SUPPORT=1  to link in libcxxabi demangling\"),t}function demangleAll(t){var e=/__Z[\\w\\d_]+/g;return t.replace(e,function(r){var o=demangle(r);return r===o?r:r+\" [\"+o+\"]\"})}function jsStackTrace(){var t=new Error;if(!t.stack){try{throw new Error(0)}catch(e){t=e}if(!t.stack)return\"(no stack trace available)\"}return t.stack.toString()}function stackTrace(){var t=jsStackTrace();return Module.extraStackTrace&&(t+=`\n`+Module.extraStackTrace()),demangleAll(t)}Module.stackTrace=stackTrace;var HEAP,buffer,HEAP8,HEAPU8,HEAP16,HEAPU16,HEAP32,HEAPU32,HEAPF32,HEAPF64;function updateGlobalBufferViews(){Module.HEAP8=HEAP8=new Int8Array(buffer),Module.HEAP16=HEAP16=new Int16Array(buffer),Module.HEAP32=HEAP32=new Int32Array(buffer),Module.HEAPU8=HEAPU8=new Uint8Array(buffer),Module.HEAPU16=HEAPU16=new Uint16Array(buffer),Module.HEAPU32=HEAPU32=new Uint32Array(buffer),Module.HEAPF32=HEAPF32=new Float32Array(buffer),Module.HEAPF64=HEAPF64=new Float64Array(buffer)}var STATIC_BASE,STATICTOP,staticSealed,STACK_BASE,STACKTOP,STACK_MAX,DYNAMIC_BASE,DYNAMICTOP_PTR;STATIC_BASE=STATICTOP=STACK_BASE=STACKTOP=STACK_MAX=DYNAMIC_BASE=DYNAMICTOP_PTR=0,staticSealed=!1;function abortOnCannotGrowMemory(){abort(\"Cannot enlarge memory arrays. Either (1) compile with  -s TOTAL_MEMORY=X  with X higher than the current value \"+TOTAL_MEMORY+\", (2) compile with  -s ALLOW_MEMORY_GROWTH=1  which allows increasing the size at runtime but prevents some optimizations, (3) set Module.TOTAL_MEMORY to a higher value before the program runs, or (4) if you want malloc to return NULL (0) instead of this abort, compile with  -s ABORTING_MALLOC=0 \")}function enlargeMemory(){abortOnCannotGrowMemory()}var TOTAL_STACK=Module.TOTAL_STACK||5242880,TOTAL_MEMORY=Module.TOTAL_MEMORY||134217728;TOTAL_MEMORY<TOTAL_STACK&&Module.printErr(\"TOTAL_MEMORY should be larger than TOTAL_STACK, was \"+TOTAL_MEMORY+\"! (TOTAL_STACK=\"+TOTAL_STACK+\")\"),Module.buffer?buffer=Module.buffer:buffer=new ArrayBuffer(TOTAL_MEMORY),updateGlobalBufferViews();function getTotalMemory(){return TOTAL_MEMORY}if(HEAP32[0]=1668509029,HEAP16[1]=25459,HEAPU8[2]!==115||HEAPU8[3]!==99)throw\"Runtime error: expected the system to be little-endian!\";Module.HEAP=HEAP,Module.buffer=buffer,Module.HEAP8=HEAP8,Module.HEAP16=HEAP16,Module.HEAP32=HEAP32,Module.HEAPU8=HEAPU8,Module.HEAPU16=HEAPU16,Module.HEAPU32=HEAPU32,Module.HEAPF32=HEAPF32,Module.HEAPF64=HEAPF64;function callRuntimeCallbacks(t){for(;t.length>0;){var e=t.shift();if(typeof e==\"function\"){e();continue}var r=e.func;typeof r==\"number\"?e.arg===void 0?Module.dynCall_v(r):Module.dynCall_vi(r,e.arg):r(e.arg===void 0?null:e.arg)}}var __ATPRERUN__=[],__ATINIT__=[],__ATMAIN__=[],__ATEXIT__=[],__ATPOSTRUN__=[],runtimeInitialized=!1,runtimeExited=!1;function preRun(){if(Module.preRun)for(typeof Module.preRun==\"function\"&&(Module.preRun=[Module.preRun]);Module.preRun.length;)addOnPreRun(Module.preRun.shift());callRuntimeCallbacks(__ATPRERUN__)}function ensureInitRuntime(){runtimeInitialized||(runtimeInitialized=!0,callRuntimeCallbacks(__ATINIT__))}function preMain(){callRuntimeCallbacks(__ATMAIN__)}function exitRuntime(){callRuntimeCallbacks(__ATEXIT__),runtimeExited=!0}function postRun(){if(Module.postRun)for(typeof Module.postRun==\"function\"&&(Module.postRun=[Module.postRun]);Module.postRun.length;)addOnPostRun(Module.postRun.shift());callRuntimeCallbacks(__ATPOSTRUN__)}function addOnPreRun(t){__ATPRERUN__.unshift(t)}Module.addOnPreRun=addOnPreRun;function addOnInit(t){__ATINIT__.unshift(t)}Module.addOnInit=addOnInit;function addOnPreMain(t){__ATMAIN__.unshift(t)}Module.addOnPreMain=addOnPreMain;function addOnExit(t){__ATEXIT__.unshift(t)}Module.addOnExit=addOnExit;function addOnPostRun(t){__ATPOSTRUN__.unshift(t)}Module.addOnPostRun=addOnPostRun;function intArrayFromString(t,e,r){var o=r>0?r:lengthBytesUTF8(t)+1,a=new Array(o),n=stringToUTF8Array(t,a,0,a.length);return e&&(a.length=n),a}Module.intArrayFromString=intArrayFromString;function intArrayToString(t){for(var e=[],r=0;r<t.length;r++){var o=t[r];o>255&&(o&=255),e.push(String.fromCharCode(o))}return e.join(\"\")}Module.intArrayToString=intArrayToString;function writeStringToMemory(t,e,r){Runtime.warnOnce(\"writeStringToMemory is deprecated and should not be called! Use stringToUTF8() instead!\");var o,a;r&&(a=e+lengthBytesUTF8(t),o=HEAP8[a]),stringToUTF8(t,e,1/0),r&&(HEAP8[a]=o)}Module.writeStringToMemory=writeStringToMemory;function writeArrayToMemory(t,e){HEAP8.set(t,e)}Module.writeArrayToMemory=writeArrayToMemory;function writeAsciiToMemory(t,e,r){for(var o=0;o<t.length;++o)HEAP8[e++>>0]=t.charCodeAt(o);r||(HEAP8[e>>0]=0)}if(Module.writeAsciiToMemory=writeAsciiToMemory,(!Math.imul||Math.imul(4294967295,5)!==-5)&&(Math.imul=function t(e,r){var o=e>>>16,a=e&65535,n=r>>>16,u=r&65535;return a*u+(o*u+a*n<<16)|0}),Math.imul=Math.imul,!Math.fround){var froundBuffer=new Float32Array(1);Math.fround=function(t){return froundBuffer[0]=t,froundBuffer[0]}}Math.fround=Math.fround,Math.clz32||(Math.clz32=function(t){t=t>>>0;for(var e=0;e<32;e++)if(t&1<<31-e)return e;return 32}),Math.clz32=Math.clz32,Math.trunc||(Math.trunc=function(t){return t<0?Math.ceil(t):Math.floor(t)}),Math.trunc=Math.trunc;var Math_abs=Math.abs,Math_cos=Math.cos,Math_sin=Math.sin,Math_tan=Math.tan,Math_acos=Math.acos,Math_asin=Math.asin,Math_atan=Math.atan,Math_atan2=Math.atan2,Math_exp=Math.exp,Math_log=Math.log,Math_sqrt=Math.sqrt,Math_ceil=Math.ceil,Math_floor=Math.floor,Math_pow=Math.pow,Math_imul=Math.imul,Math_fround=Math.fround,Math_round=Math.round,Math_min=Math.min,Math_clz32=Math.clz32,Math_trunc=Math.trunc,runDependencies=0,runDependencyWatcher=null,dependenciesFulfilled=null;function getUniqueRunDependency(t){return t}function addRunDependency(t){runDependencies++,Module.monitorRunDependencies&&Module.monitorRunDependencies(runDependencies)}Module.addRunDependency=addRunDependency;function removeRunDependency(t){if(runDependencies--,Module.monitorRunDependencies&&Module.monitorRunDependencies(runDependencies),runDependencies==0&&(runDependencyWatcher!==null&&(clearInterval(runDependencyWatcher),runDependencyWatcher=null),dependenciesFulfilled)){var e=dependenciesFulfilled;dependenciesFulfilled=null,e()}}Module.removeRunDependency=removeRunDependency,Module.preloadedImages={},Module.preloadedAudios={};var ASM_CONSTS=[function(t,e,r,o,a,n,u,A){return _nbind.callbackSignatureList[t].apply(this,arguments)}];function _emscripten_asm_const_iiiiiiii(t,e,r,o,a,n,u,A){return ASM_CONSTS[t](e,r,o,a,n,u,A)}function _emscripten_asm_const_iiiii(t,e,r,o,a){return ASM_CONSTS[t](e,r,o,a)}function _emscripten_asm_const_iiidddddd(t,e,r,o,a,n,u,A,p){return ASM_CONSTS[t](e,r,o,a,n,u,A,p)}function _emscripten_asm_const_iiididi(t,e,r,o,a,n,u){return ASM_CONSTS[t](e,r,o,a,n,u)}function _emscripten_asm_const_iiii(t,e,r,o){return ASM_CONSTS[t](e,r,o)}function _emscripten_asm_const_iiiid(t,e,r,o,a){return ASM_CONSTS[t](e,r,o,a)}function _emscripten_asm_const_iiiiii(t,e,r,o,a,n){return ASM_CONSTS[t](e,r,o,a,n)}STATIC_BASE=Runtime.GLOBAL_BASE,STATICTOP=STATIC_BASE+12800,__ATINIT__.push({func:function(){__GLOBAL__sub_I_Yoga_cpp()}},{func:function(){__GLOBAL__sub_I_nbind_cc()}},{func:function(){__GLOBAL__sub_I_common_cc()}},{func:function(){__GLOBAL__sub_I_Binding_cc()}}),allocate([0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,4,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,192,127,0,0,192,127,0,0,192,127,0,0,192,127,3,0,0,0,0,0,192,127,0,0,0,0,0,0,192,127,0,0,0,0,0,0,192,127,0,0,0,0,0,0,192,127,0,0,0,0,0,0,192,127,0,0,0,0,0,0,192,127,0,0,0,0,0,0,192,127,0,0,0,0,0,0,192,127,0,0,0,0,0,0,192,127,0,0,0,0,0,0,192,127,0,0,0,0,0,0,192,127,0,0,0,0,0,0,192,127,0,0,0,0,0,0,192,127,0,0,0,0,0,0,192,127,0,0,0,0,0,0,192,127,0,0,0,0,0,0,192,127,0,0,0,0,0,0,192,127,0,0,0,0,0,0,192,127,0,0,0,0,0,0,192,127,0,0,0,0,0,0,192,127,0,0,0,0,0,0,192,127,0,0,0,0,0,0,192,127,0,0,0,0,0,0,192,127,0,0,0,0,0,0,192,127,0,0,0,0,0,0,192,127,0,0,0,0,0,0,192,127,0,0,0,0,0,0,192,127,0,0,0,0,0,0,192,127,0,0,0,0,0,0,192,127,0,0,0,0,0,0,192,127,0,0,0,0,0,0,192,127,0,0,0,0,0,0,192,127,0,0,0,0,0,0,192,127,0,0,0,0,0,0,192,127,0,0,0,0,0,0,192,127,0,0,0,0,0,0,192,127,0,0,0,0,0,0,192,127,3,0,0,0,0,0,192,127,3,0,0,0,0,0,192,127,0,0,0,0,0,0,192,127,0,0,0,0,0,0,192,127,0,0,0,0,0,0,192,127,0,0,0,0,0,0,192,127,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,192,127,0,0,192,127,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,192,127,0,0,0,0,0,0,0,0,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,192,127,0,0,192,127,0,0,0,0,0,0,0,0,255,255,255,255,255,255,255,255,0,0,128,191,0,0,128,191,0,0,192,127,0,0,0,0,0,0,0,0,0,0,128,63,1,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,3,0,0,0,1,0,0,0,2,0,0,0,0,0,0,0,190,12,0,0,200,12,0,0,208,12,0,0,216,12,0,0,230,12,0,0,242,12,0,0,1,0,0,0,3,0,0,0,0,0,0,0,2,0,0,0,0,0,192,127,3,0,0,0,180,45,0,0,181,45,0,0,182,45,0,0,181,45,0,0,182,45,0,0,0,0,0,0,0,0,0,0,1,0,0,0,2,0,0,0,3,0,0,0,1,0,0,0,4,0,0,0,183,45,0,0,181,45,0,0,181,45,0,0,181,45,0,0,181,45,0,0,181,45,0,0,181,45,0,0,184,45,0,0,185,45,0,0,181,45,0,0,181,45,0,0,182,45,0,0,186,45,0,0,185,45,0,0,148,4,0,0,3,0,0,0,187,45,0,0,164,4,0,0,188,45,0,0,2,0,0,0,189,45,0,0,164,4,0,0,188,45,0,0,185,45,0,0,164,4,0,0,185,45,0,0,164,4,0,0,188,45,0,0,181,45,0,0,182,45,0,0,181,45,0,0,0,0,0,0,0,0,0,0,1,0,0,0,5,0,0,0,6,0,0,0,1,0,0,0,7,0,0,0,183,45,0,0,182,45,0,0,181,45,0,0,190,45,0,0,190,45,0,0,182,45,0,0,182,45,0,0,185,45,0,0,181,45,0,0,185,45,0,0,182,45,0,0,181,45,0,0,185,45,0,0,182,45,0,0,185,45,0,0,48,5,0,0,3,0,0,0,56,5,0,0,1,0,0,0,189,45,0,0,185,45,0,0,164,4,0,0,76,5,0,0,2,0,0,0,191,45,0,0,186,45,0,0,182,45,0,0,185,45,0,0,192,45,0,0,185,45,0,0,182,45,0,0,186,45,0,0,185,45,0,0,76,5,0,0,76,5,0,0,136,5,0,0,182,45,0,0,181,45,0,0,2,0,0,0,190,45,0,0,136,5,0,0,56,19,0,0,156,5,0,0,2,0,0,0,184,45,0,0,0,0,0,0,0,0,0,0,1,0,0,0,8,0,0,0,9,0,0,0,1,0,0,0,10,0,0,0,204,5,0,0,181,45,0,0,181,45,0,0,2,0,0,0,180,45,0,0,204,5,0,0,2,0,0,0,195,45,0,0,236,5,0,0,97,19,0,0,198,45,0,0,211,45,0,0,212,45,0,0,213,45,0,0,214,45,0,0,215,45,0,0,188,45,0,0,182,45,0,0,216,45,0,0,217,45,0,0,218,45,0,0,219,45,0,0,192,45,0,0,181,45,0,0,0,0,0,0,185,45,0,0,110,19,0,0,186,45,0,0,115,19,0,0,221,45,0,0,120,19,0,0,148,4,0,0,132,19,0,0,96,6,0,0,145,19,0,0,222,45,0,0,164,19,0,0,223,45,0,0,173,19,0,0,0,0,0,0,3,0,0,0,104,6,0,0,1,0,0,0,187,45,0,0,0,0,0,0,0,0,0,0,1,0,0,0,11,0,0,0,12,0,0,0,1,0,0,0,13,0,0,0,185,45,0,0,224,45,0,0,164,6,0,0,188,45,0,0,172,6,0,0,180,6,0,0,2,0,0,0,188,6,0,0,7,0,0,0,224,45,0,0,7,0,0,0,164,6,0,0,1,0,0,0,213,45,0,0,185,45,0,0,224,45,0,0,172,6,0,0,185,45,0,0,224,45,0,0,164,6,0,0,185,45,0,0,224,45,0,0,211,45,0,0,211,45,0,0,222,45,0,0,211,45,0,0,224,45,0,0,222,45,0,0,211,45,0,0,224,45,0,0,172,6,0,0,222,45,0,0,211,45,0,0,224,45,0,0,188,45,0,0,222,45,0,0,211,45,0,0,40,7,0,0,188,45,0,0,2,0,0,0,224,45,0,0,185,45,0,0,188,45,0,0,188,45,0,0,188,45,0,0,188,45,0,0,222,45,0,0,224,45,0,0,148,4,0,0,185,45,0,0,148,4,0,0,148,4,0,0,148,4,0,0,148,4,0,0,148,4,0,0,185,45,0,0,164,6,0,0,148,4,0,0,0,0,0,0,0,0,0,0,1,0,0,0,14,0,0,0,15,0,0,0,1,0,0,0,16,0,0,0,148,7,0,0,2,0,0,0,225,45,0,0,183,45,0,0,188,45,0,0,168,7,0,0,5,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,2,0,0,0,234,45,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,148,45,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,9,0,0,5,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,0,0,0,2,0,0,0,242,45,0,0,0,4,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,10,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,67,111,117,108,100,32,110,111,116,32,97,108,108,111,99,97,116,101,32,109,101,109,111,114,121,32,102,111,114,32,110,111,100,101,0,67,97,110,110,111,116,32,114,101,115,101,116,32,97,32,110,111,100,101,32,119,104,105,99,104,32,115,116,105,108,108,32,104,97,115,32,99,104,105,108,100,114,101,110,32,97,116,116,97,99,104,101,100,0,67,97,110,110,111,116,32,114,101,115,101,116,32,97,32,110,111,100,101,32,115,116,105,108,108,32,97,116,116,97,99,104,101,100,32,116,111,32,97,32,112,97,114,101,110,116,0,67,111,117,108,100,32,110,111,116,32,97,108,108,111,99,97,116,101,32,109,101,109,111,114,121,32,102,111,114,32,99,111,110,102,105,103,0,67,97,110,110,111,116,32,115,101,116,32,109,101,97,115,117,114,101,32,102,117,110,99,116,105,111,110,58,32,78,111,100,101,115,32,119,105,116,104,32,109,101,97,115,117,114,101,32,102,117,110,99,116,105,111,110,115,32,99,97,110,110,111,116,32,104,97,118,101,32,99,104,105,108,100,114,101,110,46,0,67,104,105,108,100,32,97,108,114,101,97,100,121,32,104,97,115,32,97,32,112,97,114,101,110,116,44,32,105,116,32,109,117,115,116,32,98,101,32,114,101,109,111,118,101,100,32,102,105,114,115,116,46,0,67,97,110,110,111,116,32,97,100,100,32,99,104,105,108,100,58,32,78,111,100,101,115,32,119,105,116,104,32,109,101,97,115,117,114,101,32,102,117,110,99,116,105,111,110,115,32,99,97,110,110,111,116,32,104,97,118,101,32,99,104,105,108,100,114,101,110,46,0,79,110,108,121,32,108,101,97,102,32,110,111,100,101,115,32,119,105,116,104,32,99,117,115,116,111,109,32,109,101,97,115,117,114,101,32,102,117,110,99,116,105,111,110,115,115,104,111,117,108,100,32,109,97,110,117,97,108,108,121,32,109,97,114,107,32,116,104,101,109,115,101,108,118,101,115,32,97,115,32,100,105,114,116,121,0,67,97,110,110,111,116,32,103,101,116,32,108,97,121,111,117,116,32,112,114,111,112,101,114,116,105,101,115,32,111,102,32,109,117,108,116,105,45,101,100,103,101,32,115,104,111,114,116,104,97,110,100,115,0,37,115,37,100,46,123,91,115,107,105,112,112,101,100,93,32,0,119,109,58,32,37,115,44,32,104,109,58,32,37,115,44,32,97,119,58,32,37,102,32,97,104,58,32,37,102,32,61,62,32,100,58,32,40,37,102,44,32,37,102,41,32,37,115,10,0,37,115,37,100,46,123,37,115,0,42,0,119,109,58,32,37,115,44,32,104,109,58,32,37,115,44,32,97,119,58,32,37,102,32,97,104,58,32,37,102,32,37,115,10,0,37,115,37,100,46,125,37,115,0,119,109,58,32,37,115,44,32,104,109,58,32,37,115,44,32,100,58,32,40,37,102,44,32,37,102,41,32,37,115,10,0,79,117,116,32,111,102,32,99,97,99,104,101,32,101,110,116,114,105,101,115,33,10,0,83,99,97,108,101,32,102,97,99,116,111,114,32,115,104,111,117,108,100,32,110,111,116,32,98,101,32,108,101,115,115,32,116,104,97,110,32,122,101,114,111,0,105,110,105,116,105,97,108,0,37,115,10,0,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,0,85,78,68,69,70,73,78,69,68,0,69,88,65,67,84,76,89,0,65,84,95,77,79,83,84,0,76,65,89,95,85,78,68,69,70,73,78,69,68,0,76,65,89,95,69,88,65,67,84,76,89,0,76,65,89,95,65,84,95,77,79,83,84,0,97,118,97,105,108,97,98,108,101,87,105,100,116,104,32,105,115,32,105,110,100,101,102,105,110,105,116,101,32,115,111,32,119,105,100,116,104,77,101,97,115,117,114,101,77,111,100,101,32,109,117,115,116,32,98,101,32,89,71,77,101,97,115,117,114,101,77,111,100,101,85,110,100,101,102,105,110,101,100,0,97,118,97,105,108,97,98,108,101,72,101,105,103,104,116,32,105,115,32,105,110,100,101,102,105,110,105,116,101,32,115,111,32,104,101,105,103,104,116,77,101,97,115,117,114,101,77,111,100,101,32,109,117,115,116,32,98,101,32,89,71,77,101,97,115,117,114,101,77,111,100,101,85,110,100,101,102,105,110,101,100,0,102,108,101,120,0,115,116,114,101,116,99,104,0,109,117,108,116,105,108,105,110,101,45,115,116,114,101,116,99,104,0,69,120,112,101,99,116,101,100,32,110,111,100,101,32,116,111,32,104,97,118,101,32,99,117,115,116,111,109,32,109,101,97,115,117,114,101,32,102,117,110,99,116,105,111,110,0,109,101,97,115,117,114,101,0,69,120,112,101,99,116,32,99,117,115,116,111,109,32,98,97,115,101,108,105,110,101,32,102,117,110,99,116,105,111,110,32,116,111,32,110,111,116,32,114,101,116,117,114,110,32,78,97,78,0,97,98,115,45,109,101,97,115,117,114,101,0,97,98,115,45,108,97,121,111,117,116,0,78,111,100,101,0,99,114,101,97,116,101,68,101,102,97,117,108,116,0,99,114,101,97,116,101,87,105,116,104,67,111,110,102,105,103,0,100,101,115,116,114,111,121,0,114,101,115,101,116,0,99,111,112,121,83,116,121,108,101,0,115,101,116,80,111,115,105,116,105,111,110,84,121,112,101,0,115,101,116,80,111,115,105,116,105,111,110,0,115,101,116,80,111,115,105,116,105,111,110,80,101,114,99,101,110,116,0,115,101,116,65,108,105,103,110,67,111,110,116,101,110,116,0,115,101,116,65,108,105,103,110,73,116,101,109,115,0,115,101,116,65,108,105,103,110,83,101,108,102,0,115,101,116,70,108,101,120,68,105,114,101,99,116,105,111,110,0,115,101,116,70,108,101,120,87,114,97,112,0,115,101,116,74,117,115,116,105,102,121,67,111,110,116,101,110,116,0,115,101,116,77,97,114,103,105,110,0,115,101,116,77,97,114,103,105,110,80,101,114,99,101,110,116,0,115,101,116,77,97,114,103,105,110,65,117,116,111,0,115,101,116,79,118,101,114,102,108,111,119,0,115,101,116,68,105,115,112,108,97,121,0,115,101,116,70,108,101,120,0,115,101,116,70,108,101,120,66,97,115,105,115,0,115,101,116,70,108,101,120,66,97,115,105,115,80,101,114,99,101,110,116,0,115,101,116,70,108,101,120,71,114,111,119,0,115,101,116,70,108,101,120,83,104,114,105,110,107,0,115,101,116,87,105,100,116,104,0,115,101,116,87,105,100,116,104,80,101,114,99,101,110,116,0,115,101,116,87,105,100,116,104,65,117,116,111,0,115,101,116,72,101,105,103,104,116,0,115,101,116,72,101,105,103,104,116,80,101,114,99,101,110,116,0,115,101,116,72,101,105,103,104,116,65,117,116,111,0,115,101,116,77,105,110,87,105,100,116,104,0,115,101,116,77,105,110,87,105,100,116,104,80,101,114,99,101,110,116,0,115,101,116,77,105,110,72,101,105,103,104,116,0,115,101,116,77,105,110,72,101,105,103,104,116,80,101,114,99,101,110,116,0,115,101,116,77,97,120,87,105,100,116,104,0,115,101,116,77,97,120,87,105,100,116,104,80,101,114,99,101,110,116,0,115,101,116,77,97,120,72,101,105,103,104,116,0,115,101,116,77,97,120,72,101,105,103,104,116,80,101,114,99,101,110,116,0,115,101,116,65,115,112,101,99,116,82,97,116,105,111,0,115,101,116,66,111,114,100,101,114,0,115,101,116,80,97,100,100,105,110,103,0,115,101,116,80,97,100,100,105,110,103,80,101,114,99,101,110,116,0,103,101,116,80,111,115,105,116,105,111,110,84,121,112,101,0,103,101,116,80,111,115,105,116,105,111,110,0,103,101,116,65,108,105,103,110,67,111,110,116,101,110,116,0,103,101,116,65,108,105,103,110,73,116,101,109,115,0,103,101,116,65,108,105,103,110,83,101,108,102,0,103,101,116,70,108,101,120,68,105,114,101,99,116,105,111,110,0,103,101,116,70,108,101,120,87,114,97,112,0,103,101,116,74,117,115,116,105,102,121,67,111,110,116,101,110,116,0,103,101,116,77,97,114,103,105,110,0,103,101,116,70,108,101,120,66,97,115,105,115,0,103,101,116,70,108,101,120,71,114,111,119,0,103,101,116,70,108,101,120,83,104,114,105,110,107,0,103,101,116,87,105,100,116,104,0,103,101,116,72,101,105,103,104,116,0,103,101,116,77,105,110,87,105,100,116,104,0,103,101,116,77,105,110,72,101,105,103,104,116,0,103,101,116,77,97,120,87,105,100,116,104,0,103,101,116,77,97,120,72,101,105,103,104,116,0,103,101,116,65,115,112,101,99,116,82,97,116,105,111,0,103,101,116,66,111,114,100,101,114,0,103,101,116,79,118,101,114,102,108,111,119,0,103,101,116,68,105,115,112,108,97,121,0,103,101,116,80,97,100,100,105,110,103,0,105,110,115,101,114,116,67,104,105,108,100,0,114,101,109,111,118,101,67,104,105,108,100,0,103,101,116,67,104,105,108,100,67,111,117,110,116,0,103,101,116,80,97,114,101,110,116,0,103,101,116,67,104,105,108,100,0,115,101,116,77,101,97,115,117,114,101,70,117,110,99,0,117,110,115,101,116,77,101,97,115,117,114,101,70,117,110,99,0,109,97,114,107,68,105,114,116,121,0,105,115,68,105,114,116,121,0,99,97,108,99,117,108,97,116,101,76,97,121,111,117,116,0,103,101,116,67,111,109,112,117,116,101,100,76,101,102,116,0,103,101,116,67,111,109,112,117,116,101,100,82,105,103,104,116,0,103,101,116,67,111,109,112,117,116,101,100,84,111,112,0,103,101,116,67,111,109,112,117,116,101,100,66,111,116,116,111,109,0,103,101,116,67,111,109,112,117,116,101,100,87,105,100,116,104,0,103,101,116,67,111,109,112,117,116,101,100,72,101,105,103,104,116,0,103,101,116,67,111,109,112,117,116,101,100,76,97,121,111,117,116,0,103,101,116,67,111,109,112,117,116,101,100,77,97,114,103,105,110,0,103,101,116,67,111,109,112,117,116,101,100,66,111,114,100,101,114,0,103,101,116,67,111,109,112,117,116,101,100,80,97,100,100,105,110,103,0,67,111,110,102,105,103,0,99,114,101,97,116,101,0,115,101,116,69,120,112,101,114,105,109,101,110,116,97,108,70,101,97,116,117,114,101,69,110,97,98,108,101,100,0,115,101,116,80,111,105,110,116,83,99,97,108,101,70,97,99,116,111,114,0,105,115,69,120,112,101,114,105,109,101,110,116,97,108,70,101,97,116,117,114,101,69,110,97,98,108,101,100,0,86,97,108,117,101,0,76,97,121,111,117,116,0,83,105,122,101,0,103,101,116,73,110,115,116,97,110,99,101,67,111,117,110,116,0,73,110,116,54,52,0,1,1,1,2,2,4,4,4,4,8,8,4,8,118,111,105,100,0,98,111,111,108,0,115,116,100,58,58,115,116,114,105,110,103,0,99,98,70,117,110,99,116,105,111,110,32,38,0,99,111,110,115,116,32,99,98,70,117,110,99,116,105,111,110,32,38,0,69,120,116,101,114,110,97,108,0,66,117,102,102,101,114,0,78,66,105,110,100,73,68,0,78,66,105,110,100,0,98,105,110,100,95,118,97,108,117,101,0,114,101,102,108,101,99,116,0,113,117,101,114,121,84,121,112,101,0,108,97,108,108,111,99,0,108,114,101,115,101,116,0,123,114,101,116,117,114,110,40,95,110,98,105,110,100,46,99,97,108,108,98,97,99,107,83,105,103,110,97,116,117,114,101,76,105,115,116,91,36,48,93,46,97,112,112,108,121,40,116,104,105,115,44,97,114,103,117,109,101,110,116,115,41,41,59,125,0,95,110,98,105,110,100,95,110,101,119,0,17,0,10,0,17,17,17,0,0,0,0,5,0,0,0,0,0,0,9,0,0,0,0,11,0,0,0,0,0,0,0,0,17,0,15,10,17,17,17,3,10,7,0,1,19,9,11,11,0,0,9,6,11,0,0,11,0,6,17,0,0,0,17,17,17,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,11,0,0,0,0,0,0,0,0,17,0,10,10,17,17,17,0,10,0,0,2,0,9,11,0,0,0,9,0,11,0,0,11,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,12,0,0,0,0,0,0,0,0,0,0,0,12,0,0,0,0,12,0,0,0,0,9,12,0,0,0,0,0,12,0,0,12,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,14,0,0,0,0,0,0,0,0,0,0,0,13,0,0,0,4,13,0,0,0,0,9,14,0,0,0,0,0,14,0,0,14,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,16,0,0,0,0,0,0,0,0,0,0,0,15,0,0,0,0,15,0,0,0,0,9,16,0,0,0,0,0,16,0,0,16,0,0,18,0,0,0,18,18,18,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,18,0,0,0,18,18,18,0,0,0,0,0,0,9,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,11,0,0,0,0,0,0,0,0,0,0,0,10,0,0,0,0,10,0,0,0,0,9,11,0,0,0,0,0,11,0,0,11,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,12,0,0,0,0,0,0,0,0,0,0,0,12,0,0,0,0,12,0,0,0,0,9,12,0,0,0,0,0,12,0,0,12,0,0,45,43,32,32,32,48,88,48,120,0,40,110,117,108,108,41,0,45,48,88,43,48,88,32,48,88,45,48,120,43,48,120,32,48,120,0,105,110,102,0,73,78,70,0,110,97,110,0,78,65,78,0,48,49,50,51,52,53,54,55,56,57,65,66,67,68,69,70,46,0,84,33,34,25,13,1,2,3,17,75,28,12,16,4,11,29,18,30,39,104,110,111,112,113,98,32,5,6,15,19,20,21,26,8,22,7,40,36,23,24,9,10,14,27,31,37,35,131,130,125,38,42,43,60,61,62,63,67,71,74,77,88,89,90,91,92,93,94,95,96,97,99,100,101,102,103,105,106,107,108,114,115,116,121,122,123,124,0,73,108,108,101,103,97,108,32,98,121,116,101,32,115,101,113,117,101,110,99,101,0,68,111,109,97,105,110,32,101,114,114,111,114,0,82,101,115,117,108,116,32,110,111,116,32,114,101,112,114,101,115,101,110,116,97,98,108,101,0,78,111,116,32,97,32,116,116,121,0,80,101,114,109,105,115,115,105,111,110,32,100,101,110,105,101,100,0,79,112,101,114,97,116,105,111,110,32,110,111,116,32,112,101,114,109,105,116,116,101,100,0,78,111,32,115,117,99,104,32,102,105,108,101,32,111,114,32,100,105,114,101,99,116,111,114,121,0,78,111,32,115,117,99,104,32,112,114,111,99,101,115,115,0,70,105,108,101,32,101,120,105,115,116,115,0,86,97,108,117,101,32,116,111,111,32,108,97,114,103,101,32,102,111,114,32,100,97,116,97,32,116,121,112,101,0,78,111,32,115,112,97,99,101,32,108,101,102,116,32,111,110,32,100,101,118,105,99,101,0,79,117,116,32,111,102,32,109,101,109,111,114,121,0,82,101,115,111,117,114,99,101,32,98,117,115,121,0,73,110,116,101,114,114,117,112,116,101,100,32,115,121,115,116,101,109,32,99,97,108,108,0,82,101,115,111,117,114,99,101,32,116,101,109,112,111,114,97,114,105,108,121,32,117,110,97,118,97,105,108,97,98,108,101,0,73,110,118,97,108,105,100,32,115,101,101,107,0,67,114,111,115,115,45,100,101,118,105,99,101,32,108,105,110,107,0,82,101,97,100,45,111,110,108,121,32,102,105,108,101,32,115,121,115,116,101,109,0,68,105,114,101,99,116,111,114,121,32,110,111,116,32,101,109,112,116,121,0,67,111,110,110,101,99,116,105,111,110,32,114,101,115,101,116,32,98,121,32,112,101,101,114,0,79,112,101,114,97,116,105,111,110,32,116,105,109,101,100,32,111,117,116,0,67,111,110,110,101,99,116,105,111,110,32,114,101,102,117,115,101,100,0,72,111,115,116,32,105,115,32,100,111,119,110,0,72,111,115,116,32,105,115,32,117,110,114,101,97,99,104,97,98,108,101,0,65,100,100,114,101,115,115,32,105,110,32,117,115,101,0,66,114,111,107,101,110,32,112,105,112,101,0,73,47,79,32,101,114,114,111,114,0,78,111,32,115,117,99,104,32,100,101,118,105,99,101,32,111,114,32,97,100,100,114,101,115,115,0,66,108,111,99,107,32,100,101,118,105,99,101,32,114,101,113,117,105,114,101,100,0,78,111,32,115,117,99,104,32,100,101,118,105,99,101,0,78,111,116,32,97,32,100,105,114,101,99,116,111,114,121,0,73,115,32,97,32,100,105,114,101,99,116,111,114,121,0,84,101,120,116,32,102,105,108,101,32,98,117,115,121,0,69,120,101,99,32,102,111,114,109,97,116,32,101,114,114,111,114,0,73,110,118,97,108,105,100,32,97,114,103,117,109,101,110,116,0,65,114,103,117,109,101,110,116,32,108,105,115,116,32,116,111,111,32,108,111,110,103,0,83,121,109,98,111,108,105,99,32,108,105,110,107,32,108,111,111,112,0,70,105,108,101,110,97,109,101,32,116,111,111,32,108,111,110,103,0,84,111,111,32,109,97,110,121,32,111,112,101,110,32,102,105,108,101,115,32,105,110,32,115,121,115,116,101,109,0,78,111,32,102,105,108,101,32,100,101,115,99,114,105,112,116,111,114,115,32,97,118,97,105,108,97,98,108,101,0,66,97,100,32,102,105,108,101,32,100,101,115,99,114,105,112,116,111,114,0,78,111,32,99,104,105,108,100,32,112,114,111,99,101,115,115,0,66,97,100,32,97,100,100,114,101,115,115,0,70,105,108,101,32,116,111,111,32,108,97,114,103,101,0,84,111,111,32,109,97,110,121,32,108,105,110,107,115,0,78,111,32,108,111,99,107,115,32,97,118,97,105,108,97,98,108,101,0,82,101,115,111,117,114,99,101,32,100,101,97,100,108,111,99,107,32,119,111,117,108,100,32,111,99,99,117,114,0,83,116,97,116,101,32,110,111,116,32,114,101,99,111,118,101,114,97,98,108,101,0,80,114,101,118,105,111,117,115,32,111,119,110,101,114,32,100,105,101,100,0,79,112,101,114,97,116,105,111,110,32,99,97,110,99,101,108,101,100,0,70,117,110,99,116,105,111,110,32,110,111,116,32,105,109,112,108,101,109,101,110,116,101,100,0,78,111,32,109,101,115,115,97,103,101,32,111,102,32,100,101,115,105,114,101,100,32,116,121,112,101,0,73,100,101,110,116,105,102,105,101,114,32,114,101,109,111,118,101,100,0,68,101,118,105,99,101,32,110,111,116,32,97,32,115,116,114,101,97,109,0,78,111,32,100,97,116,97,32,97,118,97,105,108,97,98,108,101,0,68,101,118,105,99,101,32,116,105,109,101,111,117,116,0,79,117,116,32,111,102,32,115,116,114,101,97,109,115,32,114,101,115,111,117,114,99,101,115,0,76,105,110,107,32,104,97,115,32,98,101,101,110,32,115,101,118,101,114,101,100,0,80,114,111,116,111,99,111,108,32,101,114,114,111,114,0,66,97,100,32,109,101,115,115,97,103,101,0,70,105,108,101,32,100,101,115,99,114,105,112,116,111,114,32,105,110,32,98,97,100,32,115,116,97,116,101,0,78,111,116,32,97,32,115,111,99,107,101,116,0,68,101,115,116,105,110,97,116,105,111,110,32,97,100,100,114,101,115,115,32,114,101,113,117,105,114,101,100,0,77,101,115,115,97,103,101,32,116,111,111,32,108,97,114,103,101,0,80,114,111,116,111,99,111,108,32,119,114,111,110,103,32,116,121,112,101,32,102,111,114,32,115,111,99,107,101,116,0,80,114,111,116,111,99,111,108,32,110,111,116,32,97,118,97,105,108,97,98,108,101,0,80,114,111,116,111,99,111,108,32,110,111,116,32,115,117,112,112,111,114,116,101,100,0,83,111,99,107,101,116,32,116,121,112,101,32,110,111,116,32,115,117,112,112,111,114,116,101,100,0,78,111,116,32,115,117,112,112,111,114,116,101,100,0,80,114,111,116,111,99,111,108,32,102,97,109,105,108,121,32,110,111,116,32,115,117,112,112,111,114,116,101,100,0,65,100,100,114,101,115,115,32,102,97,109,105,108,121,32,110,111,116,32,115,117,112,112,111,114,116,101,100,32,98,121,32,112,114,111,116,111,99,111,108,0,65,100,100,114,101,115,115,32,110,111,116,32,97,118,97,105,108,97,98,108,101,0,78,101,116,119,111,114,107,32,105,115,32,100,111,119,110,0,78,101,116,119,111,114,107,32,117,110,114,101,97,99,104,97,98,108,101,0,67,111,110,110,101,99,116,105,111,110,32,114,101,115,101,116,32,98,121,32,110,101,116,119,111,114,107,0,67,111,110,110,101,99,116,105,111,110,32,97,98,111,114,116,101,100,0,78,111,32,98,117,102,102,101,114,32,115,112,97,99,101,32,97,118,97,105,108,97,98,108,101,0,83,111,99,107,101,116,32,105,115,32,99,111,110,110,101,99,116,101,100,0,83,111,99,107,101,116,32,110,111,116,32,99,111,110,110,101,99,116,101,100,0,67,97,110,110,111,116,32,115,101,110,100,32,97,102,116,101,114,32,115,111,99,107,101,116,32,115,104,117,116,100,111,119,110,0,79,112,101,114,97,116,105,111,110,32,97,108,114,101,97,100,121,32,105,110,32,112,114,111,103,114,101,115,115,0,79,112,101,114,97,116,105,111,110,32,105,110,32,112,114,111,103,114,101,115,115,0,83,116,97,108,101,32,102,105,108,101,32,104,97,110,100,108,101,0,82,101,109,111,116,101,32,73,47,79,32,101,114,114,111,114,0,81,117,111,116,97,32,101,120,99,101,101,100,101,100,0,78,111,32,109,101,100,105,117,109,32,102,111,117,110,100,0,87,114,111,110,103,32,109,101,100,105,117,109,32,116,121,112,101,0,78,111,32,101,114,114,111,114,32,105,110,102,111,114,109,97,116,105,111,110,0,0],\"i8\",ALLOC_NONE,Runtime.GLOBAL_BASE);var tempDoublePtr=STATICTOP;STATICTOP+=16;function _atexit(t,e){__ATEXIT__.unshift({func:t,arg:e})}function ___cxa_atexit(){return _atexit.apply(null,arguments)}function _abort(){Module.abort()}function __ZN8facebook4yoga14YGNodeToStringEPNSt3__212basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEEP6YGNode14YGPrintOptionsj(){Module.printErr(\"missing function: _ZN8facebook4yoga14YGNodeToStringEPNSt3__212basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEEP6YGNode14YGPrintOptionsj\"),abort(-1)}function __decorate(t,e,r,o){var a=arguments.length,n=a<3?e:o===null?o=Object.getOwnPropertyDescriptor(e,r):o,u;if(typeof Reflect==\"object\"&&typeof Reflect.decorate==\"function\")n=Reflect.decorate(t,e,r,o);else for(var A=t.length-1;A>=0;A--)(u=t[A])&&(n=(a<3?u(n):a>3?u(e,r,n):u(e,r))||n);return a>3&&n&&Object.defineProperty(e,r,n),n}function _defineHidden(t){return function(e,r){Object.defineProperty(e,r,{configurable:!1,enumerable:!1,value:t,writable:!0})}}var _nbind={};function __nbind_free_external(t){_nbind.externalList[t].dereference(t)}function __nbind_reference_external(t){_nbind.externalList[t].reference()}function _llvm_stackrestore(t){var e=_llvm_stacksave,r=e.LLVM_SAVEDSTACKS[t];e.LLVM_SAVEDSTACKS.splice(t,1),Runtime.stackRestore(r)}function __nbind_register_pool(t,e,r,o){_nbind.Pool.pageSize=t,_nbind.Pool.usedPtr=e/4,_nbind.Pool.rootPtr=r,_nbind.Pool.pagePtr=o/4,HEAP32[e/4]=16909060,HEAP8[e]==1&&(_nbind.bigEndian=!0),HEAP32[e/4]=0,_nbind.makeTypeKindTbl=(n={},n[1024]=_nbind.PrimitiveType,n[64]=_nbind.Int64Type,n[2048]=_nbind.BindClass,n[3072]=_nbind.BindClassPtr,n[4096]=_nbind.SharedClassPtr,n[5120]=_nbind.ArrayType,n[6144]=_nbind.ArrayType,n[7168]=_nbind.CStringType,n[9216]=_nbind.CallbackType,n[10240]=_nbind.BindType,n),_nbind.makeTypeNameTbl={Buffer:_nbind.BufferType,External:_nbind.ExternalType,Int64:_nbind.Int64Type,_nbind_new:_nbind.CreateValueType,bool:_nbind.BooleanType,\"cbFunction &\":_nbind.CallbackType,\"const cbFunction &\":_nbind.CallbackType,\"const std::string &\":_nbind.StringType,\"std::string\":_nbind.StringType},Module.toggleLightGC=_nbind.toggleLightGC,_nbind.callUpcast=Module.dynCall_ii;var a=_nbind.makeType(_nbind.constructType,{flags:2048,id:0,name:\"\"});a.proto=Module,_nbind.BindClass.list.push(a);var n}function _emscripten_set_main_loop_timing(t,e){if(Browser.mainLoop.timingMode=t,Browser.mainLoop.timingValue=e,!Browser.mainLoop.func)return 1;if(t==0)Browser.mainLoop.scheduler=function(){var u=Math.max(0,Browser.mainLoop.tickStartTime+e-_emscripten_get_now())|0;setTimeout(Browser.mainLoop.runner,u)},Browser.mainLoop.method=\"timeout\";else if(t==1)Browser.mainLoop.scheduler=function(){Browser.requestAnimationFrame(Browser.mainLoop.runner)},Browser.mainLoop.method=\"rAF\";else if(t==2){if(!window.setImmediate){let n=function(u){u.source===window&&u.data===o&&(u.stopPropagation(),r.shift()())};var a=n,r=[],o=\"setimmediate\";window.addEventListener(\"message\",n,!0),window.setImmediate=function(A){r.push(A),ENVIRONMENT_IS_WORKER?(Module.setImmediates===void 0&&(Module.setImmediates=[]),Module.setImmediates.push(A),window.postMessage({target:o})):window.postMessage(o,\"*\")}}Browser.mainLoop.scheduler=function(){window.setImmediate(Browser.mainLoop.runner)},Browser.mainLoop.method=\"immediate\"}return 0}function _emscripten_get_now(){abort()}function _emscripten_set_main_loop(t,e,r,o,a){Module.noExitRuntime=!0,assert(!Browser.mainLoop.func,\"emscripten_set_main_loop: there can only be one main loop function at once: call emscripten_cancel_main_loop to cancel the previous one before setting a new one with different parameters.\"),Browser.mainLoop.func=t,Browser.mainLoop.arg=o;var n;typeof o<\"u\"?n=function(){Module.dynCall_vi(t,o)}:n=function(){Module.dynCall_v(t)};var u=Browser.mainLoop.currentlyRunningMainloop;if(Browser.mainLoop.runner=function(){if(!ABORT){if(Browser.mainLoop.queue.length>0){var p=Date.now(),h=Browser.mainLoop.queue.shift();if(h.func(h.arg),Browser.mainLoop.remainingBlockers){var C=Browser.mainLoop.remainingBlockers,I=C%1==0?C-1:Math.floor(C);h.counted?Browser.mainLoop.remainingBlockers=I:(I=I+.5,Browser.mainLoop.remainingBlockers=(8*C+I)/9)}if(console.log('main loop blocker \"'+h.name+'\" took '+(Date.now()-p)+\" ms\"),Browser.mainLoop.updateStatus(),u<Browser.mainLoop.currentlyRunningMainloop)return;setTimeout(Browser.mainLoop.runner,0);return}if(!(u<Browser.mainLoop.currentlyRunningMainloop)){if(Browser.mainLoop.currentFrameNumber=Browser.mainLoop.currentFrameNumber+1|0,Browser.mainLoop.timingMode==1&&Browser.mainLoop.timingValue>1&&Browser.mainLoop.currentFrameNumber%Browser.mainLoop.timingValue!=0){Browser.mainLoop.scheduler();return}else Browser.mainLoop.timingMode==0&&(Browser.mainLoop.tickStartTime=_emscripten_get_now());Browser.mainLoop.method===\"timeout\"&&Module.ctx&&(Module.printErr(\"Looks like you are rendering without using requestAnimationFrame for the main loop. You should use 0 for the frame rate in emscripten_set_main_loop in order to use requestAnimationFrame, as that can greatly improve your frame rates!\"),Browser.mainLoop.method=\"\"),Browser.mainLoop.runIter(n),!(u<Browser.mainLoop.currentlyRunningMainloop)&&(typeof SDL==\"object\"&&SDL.audio&&SDL.audio.queueNewAudioData&&SDL.audio.queueNewAudioData(),Browser.mainLoop.scheduler())}}},a||(e&&e>0?_emscripten_set_main_loop_timing(0,1e3/e):_emscripten_set_main_loop_timing(1,1),Browser.mainLoop.scheduler()),r)throw\"SimulateInfiniteLoop\"}var Browser={mainLoop:{scheduler:null,method:\"\",currentlyRunningMainloop:0,func:null,arg:0,timingMode:0,timingValue:0,currentFrameNumber:0,queue:[],pause:function(){Browser.mainLoop.scheduler=null,Browser.mainLoop.currentlyRunningMainloop++},resume:function(){Browser.mainLoop.currentlyRunningMainloop++;var t=Browser.mainLoop.timingMode,e=Browser.mainLoop.timingValue,r=Browser.mainLoop.func;Browser.mainLoop.func=null,_emscripten_set_main_loop(r,0,!1,Browser.mainLoop.arg,!0),_emscripten_set_main_loop_timing(t,e),Browser.mainLoop.scheduler()},updateStatus:function(){if(Module.setStatus){var t=Module.statusMessage||\"Please wait...\",e=Browser.mainLoop.remainingBlockers,r=Browser.mainLoop.expectedBlockers;e?e<r?Module.setStatus(t+\" (\"+(r-e)+\"/\"+r+\")\"):Module.setStatus(t):Module.setStatus(\"\")}},runIter:function(t){if(!ABORT){if(Module.preMainLoop){var e=Module.preMainLoop();if(e===!1)return}try{t()}catch(r){if(r instanceof ExitStatus)return;throw r&&typeof r==\"object\"&&r.stack&&Module.printErr(\"exception thrown: \"+[r,r.stack]),r}Module.postMainLoop&&Module.postMainLoop()}}},isFullscreen:!1,pointerLock:!1,moduleContextCreatedCallbacks:[],workers:[],init:function(){if(Module.preloadPlugins||(Module.preloadPlugins=[]),Browser.initted)return;Browser.initted=!0;try{new Blob,Browser.hasBlobConstructor=!0}catch{Browser.hasBlobConstructor=!1,console.log(\"warning: no blob constructor, cannot create blobs with mimetypes\")}Browser.BlobBuilder=typeof MozBlobBuilder<\"u\"?MozBlobBuilder:typeof WebKitBlobBuilder<\"u\"?WebKitBlobBuilder:Browser.hasBlobConstructor?null:console.log(\"warning: no BlobBuilder\"),Browser.URLObject=typeof window<\"u\"?window.URL?window.URL:window.webkitURL:void 0,!Module.noImageDecoding&&typeof Browser.URLObject>\"u\"&&(console.log(\"warning: Browser does not support creating object URLs. Built-in browser image decoding will not be available.\"),Module.noImageDecoding=!0);var t={};t.canHandle=function(n){return!Module.noImageDecoding&&/\\.(jpg|jpeg|png|bmp)$/i.test(n)},t.handle=function(n,u,A,p){var h=null;if(Browser.hasBlobConstructor)try{h=new Blob([n],{type:Browser.getMimetype(u)}),h.size!==n.length&&(h=new Blob([new Uint8Array(n).buffer],{type:Browser.getMimetype(u)}))}catch(x){Runtime.warnOnce(\"Blob constructor present but fails: \"+x+\"; falling back to blob builder\")}if(!h){var C=new Browser.BlobBuilder;C.append(new Uint8Array(n).buffer),h=C.getBlob()}var I=Browser.URLObject.createObjectURL(h),v=new Image;v.onload=function(){assert(v.complete,\"Image \"+u+\" could not be decoded\");var E=document.createElement(\"canvas\");E.width=v.width,E.height=v.height;var R=E.getContext(\"2d\");R.drawImage(v,0,0),Module.preloadedImages[u]=E,Browser.URLObject.revokeObjectURL(I),A&&A(n)},v.onerror=function(E){console.log(\"Image \"+I+\" could not be decoded\"),p&&p()},v.src=I},Module.preloadPlugins.push(t);var e={};e.canHandle=function(n){return!Module.noAudioDecoding&&n.substr(-4)in{\".ogg\":1,\".wav\":1,\".mp3\":1}},e.handle=function(n,u,A,p){var h=!1;function C(R){h||(h=!0,Module.preloadedAudios[u]=R,A&&A(n))}function I(){h||(h=!0,Module.preloadedAudios[u]=new Audio,p&&p())}if(Browser.hasBlobConstructor){try{var v=new Blob([n],{type:Browser.getMimetype(u)})}catch{return I()}var x=Browser.URLObject.createObjectURL(v),E=new Audio;E.addEventListener(\"canplaythrough\",function(){C(E)},!1),E.onerror=function(L){if(h)return;console.log(\"warning: browser could not fully decode audio \"+u+\", trying slower base64 approach\");function U(z){for(var te=\"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/\",le=\"=\",he=\"\",Ae=0,ye=0,ae=0;ae<z.length;ae++)for(Ae=Ae<<8|z[ae],ye+=8;ye>=6;){var Ie=Ae>>ye-6&63;ye-=6,he+=te[Ie]}return ye==2?(he+=te[(Ae&3)<<4],he+=le+le):ye==4&&(he+=te[(Ae&15)<<2],he+=le),he}E.src=\"data:audio/x-\"+u.substr(-3)+\";base64,\"+U(n),C(E)},E.src=x,Browser.safeSetTimeout(function(){C(E)},1e4)}else return I()},Module.preloadPlugins.push(e);function r(){Browser.pointerLock=document.pointerLockElement===Module.canvas||document.mozPointerLockElement===Module.canvas||document.webkitPointerLockElement===Module.canvas||document.msPointerLockElement===Module.canvas}var o=Module.canvas;o&&(o.requestPointerLock=o.requestPointerLock||o.mozRequestPointerLock||o.webkitRequestPointerLock||o.msRequestPointerLock||function(){},o.exitPointerLock=document.exitPointerLock||document.mozExitPointerLock||document.webkitExitPointerLock||document.msExitPointerLock||function(){},o.exitPointerLock=o.exitPointerLock.bind(document),document.addEventListener(\"pointerlockchange\",r,!1),document.addEventListener(\"mozpointerlockchange\",r,!1),document.addEventListener(\"webkitpointerlockchange\",r,!1),document.addEventListener(\"mspointerlockchange\",r,!1),Module.elementPointerLock&&o.addEventListener(\"click\",function(a){!Browser.pointerLock&&Module.canvas.requestPointerLock&&(Module.canvas.requestPointerLock(),a.preventDefault())},!1))},createContext:function(t,e,r,o){if(e&&Module.ctx&&t==Module.canvas)return Module.ctx;var a,n;if(e){var u={antialias:!1,alpha:!1};if(o)for(var A in o)u[A]=o[A];n=GL.createContext(t,u),n&&(a=GL.getContext(n).GLctx)}else a=t.getContext(\"2d\");return a?(r&&(e||assert(typeof GLctx>\"u\",\"cannot set in module if GLctx is used, but we are a non-GL context that would replace it\"),Module.ctx=a,e&&GL.makeContextCurrent(n),Module.useWebGL=e,Browser.moduleContextCreatedCallbacks.forEach(function(p){p()}),Browser.init()),a):null},destroyContext:function(t,e,r){},fullscreenHandlersInstalled:!1,lockPointer:void 0,resizeCanvas:void 0,requestFullscreen:function(t,e,r){Browser.lockPointer=t,Browser.resizeCanvas=e,Browser.vrDevice=r,typeof Browser.lockPointer>\"u\"&&(Browser.lockPointer=!0),typeof Browser.resizeCanvas>\"u\"&&(Browser.resizeCanvas=!1),typeof Browser.vrDevice>\"u\"&&(Browser.vrDevice=null);var o=Module.canvas;function a(){Browser.isFullscreen=!1;var u=o.parentNode;(document.fullscreenElement||document.mozFullScreenElement||document.msFullscreenElement||document.webkitFullscreenElement||document.webkitCurrentFullScreenElement)===u?(o.exitFullscreen=document.exitFullscreen||document.cancelFullScreen||document.mozCancelFullScreen||document.msExitFullscreen||document.webkitCancelFullScreen||function(){},o.exitFullscreen=o.exitFullscreen.bind(document),Browser.lockPointer&&o.requestPointerLock(),Browser.isFullscreen=!0,Browser.resizeCanvas&&Browser.setFullscreenCanvasSize()):(u.parentNode.insertBefore(o,u),u.parentNode.removeChild(u),Browser.resizeCanvas&&Browser.setWindowedCanvasSize()),Module.onFullScreen&&Module.onFullScreen(Browser.isFullscreen),Module.onFullscreen&&Module.onFullscreen(Browser.isFullscreen),Browser.updateCanvasDimensions(o)}Browser.fullscreenHandlersInstalled||(Browser.fullscreenHandlersInstalled=!0,document.addEventListener(\"fullscreenchange\",a,!1),document.addEventListener(\"mozfullscreenchange\",a,!1),document.addEventListener(\"webkitfullscreenchange\",a,!1),document.addEventListener(\"MSFullscreenChange\",a,!1));var n=document.createElement(\"div\");o.parentNode.insertBefore(n,o),n.appendChild(o),n.requestFullscreen=n.requestFullscreen||n.mozRequestFullScreen||n.msRequestFullscreen||(n.webkitRequestFullscreen?function(){n.webkitRequestFullscreen(Element.ALLOW_KEYBOARD_INPUT)}:null)||(n.webkitRequestFullScreen?function(){n.webkitRequestFullScreen(Element.ALLOW_KEYBOARD_INPUT)}:null),r?n.requestFullscreen({vrDisplay:r}):n.requestFullscreen()},requestFullScreen:function(t,e,r){return Module.printErr(\"Browser.requestFullScreen() is deprecated. Please call Browser.requestFullscreen instead.\"),Browser.requestFullScreen=function(o,a,n){return Browser.requestFullscreen(o,a,n)},Browser.requestFullscreen(t,e,r)},nextRAF:0,fakeRequestAnimationFrame:function(t){var e=Date.now();if(Browser.nextRAF===0)Browser.nextRAF=e+1e3/60;else for(;e+2>=Browser.nextRAF;)Browser.nextRAF+=1e3/60;var r=Math.max(Browser.nextRAF-e,0);setTimeout(t,r)},requestAnimationFrame:function t(e){typeof window>\"u\"?Browser.fakeRequestAnimationFrame(e):(window.requestAnimationFrame||(window.requestAnimationFrame=window.requestAnimationFrame||window.mozRequestAnimationFrame||window.webkitRequestAnimationFrame||window.msRequestAnimationFrame||window.oRequestAnimationFrame||Browser.fakeRequestAnimationFrame),window.requestAnimationFrame(e))},safeCallback:function(t){return function(){if(!ABORT)return t.apply(null,arguments)}},allowAsyncCallbacks:!0,queuedAsyncCallbacks:[],pauseAsyncCallbacks:function(){Browser.allowAsyncCallbacks=!1},resumeAsyncCallbacks:function(){if(Browser.allowAsyncCallbacks=!0,Browser.queuedAsyncCallbacks.length>0){var t=Browser.queuedAsyncCallbacks;Browser.queuedAsyncCallbacks=[],t.forEach(function(e){e()})}},safeRequestAnimationFrame:function(t){return Browser.requestAnimationFrame(function(){ABORT||(Browser.allowAsyncCallbacks?t():Browser.queuedAsyncCallbacks.push(t))})},safeSetTimeout:function(t,e){return Module.noExitRuntime=!0,setTimeout(function(){ABORT||(Browser.allowAsyncCallbacks?t():Browser.queuedAsyncCallbacks.push(t))},e)},safeSetInterval:function(t,e){return Module.noExitRuntime=!0,setInterval(function(){ABORT||Browser.allowAsyncCallbacks&&t()},e)},getMimetype:function(t){return{jpg:\"image/jpeg\",jpeg:\"image/jpeg\",png:\"image/png\",bmp:\"image/bmp\",ogg:\"audio/ogg\",wav:\"audio/wav\",mp3:\"audio/mpeg\"}[t.substr(t.lastIndexOf(\".\")+1)]},getUserMedia:function(t){window.getUserMedia||(window.getUserMedia=navigator.getUserMedia||navigator.mozGetUserMedia),window.getUserMedia(t)},getMovementX:function(t){return t.movementX||t.mozMovementX||t.webkitMovementX||0},getMovementY:function(t){return t.movementY||t.mozMovementY||t.webkitMovementY||0},getMouseWheelDelta:function(t){var e=0;switch(t.type){case\"DOMMouseScroll\":e=t.detail;break;case\"mousewheel\":e=t.wheelDelta;break;case\"wheel\":e=t.deltaY;break;default:throw\"unrecognized mouse wheel event: \"+t.type}return e},mouseX:0,mouseY:0,mouseMovementX:0,mouseMovementY:0,touches:{},lastTouches:{},calculateMouseEvent:function(t){if(Browser.pointerLock)t.type!=\"mousemove\"&&\"mozMovementX\"in t?Browser.mouseMovementX=Browser.mouseMovementY=0:(Browser.mouseMovementX=Browser.getMovementX(t),Browser.mouseMovementY=Browser.getMovementY(t)),typeof SDL<\"u\"?(Browser.mouseX=SDL.mouseX+Browser.mouseMovementX,Browser.mouseY=SDL.mouseY+Browser.mouseMovementY):(Browser.mouseX+=Browser.mouseMovementX,Browser.mouseY+=Browser.mouseMovementY);else{var e=Module.canvas.getBoundingClientRect(),r=Module.canvas.width,o=Module.canvas.height,a=typeof window.scrollX<\"u\"?window.scrollX:window.pageXOffset,n=typeof window.scrollY<\"u\"?window.scrollY:window.pageYOffset;if(t.type===\"touchstart\"||t.type===\"touchend\"||t.type===\"touchmove\"){var u=t.touch;if(u===void 0)return;var A=u.pageX-(a+e.left),p=u.pageY-(n+e.top);A=A*(r/e.width),p=p*(o/e.height);var h={x:A,y:p};if(t.type===\"touchstart\")Browser.lastTouches[u.identifier]=h,Browser.touches[u.identifier]=h;else if(t.type===\"touchend\"||t.type===\"touchmove\"){var C=Browser.touches[u.identifier];C||(C=h),Browser.lastTouches[u.identifier]=C,Browser.touches[u.identifier]=h}return}var I=t.pageX-(a+e.left),v=t.pageY-(n+e.top);I=I*(r/e.width),v=v*(o/e.height),Browser.mouseMovementX=I-Browser.mouseX,Browser.mouseMovementY=v-Browser.mouseY,Browser.mouseX=I,Browser.mouseY=v}},asyncLoad:function(t,e,r,o){var a=o?\"\":\"al \"+t;Module.readAsync(t,function(n){assert(n,'Loading data file \"'+t+'\" failed (no arrayBuffer).'),e(new Uint8Array(n)),a&&removeRunDependency(a)},function(n){if(r)r();else throw'Loading data file \"'+t+'\" failed.'}),a&&addRunDependency(a)},resizeListeners:[],updateResizeListeners:function(){var t=Module.canvas;Browser.resizeListeners.forEach(function(e){e(t.width,t.height)})},setCanvasSize:function(t,e,r){var o=Module.canvas;Browser.updateCanvasDimensions(o,t,e),r||Browser.updateResizeListeners()},windowedWidth:0,windowedHeight:0,setFullscreenCanvasSize:function(){if(typeof SDL<\"u\"){var t=HEAPU32[SDL.screen+Runtime.QUANTUM_SIZE*0>>2];t=t|8388608,HEAP32[SDL.screen+Runtime.QUANTUM_SIZE*0>>2]=t}Browser.updateResizeListeners()},setWindowedCanvasSize:function(){if(typeof SDL<\"u\"){var t=HEAPU32[SDL.screen+Runtime.QUANTUM_SIZE*0>>2];t=t&-8388609,HEAP32[SDL.screen+Runtime.QUANTUM_SIZE*0>>2]=t}Browser.updateResizeListeners()},updateCanvasDimensions:function(t,e,r){e&&r?(t.widthNative=e,t.heightNative=r):(e=t.widthNative,r=t.heightNative);var o=e,a=r;if(Module.forcedAspectRatio&&Module.forcedAspectRatio>0&&(o/a<Module.forcedAspectRatio?o=Math.round(a*Module.forcedAspectRatio):a=Math.round(o/Module.forcedAspectRatio)),(document.fullscreenElement||document.mozFullScreenElement||document.msFullscreenElement||document.webkitFullscreenElement||document.webkitCurrentFullScreenElement)===t.parentNode&&typeof screen<\"u\"){var n=Math.min(screen.width/o,screen.height/a);o=Math.round(o*n),a=Math.round(a*n)}Browser.resizeCanvas?(t.width!=o&&(t.width=o),t.height!=a&&(t.height=a),typeof t.style<\"u\"&&(t.style.removeProperty(\"width\"),t.style.removeProperty(\"height\"))):(t.width!=e&&(t.width=e),t.height!=r&&(t.height=r),typeof t.style<\"u\"&&(o!=e||a!=r?(t.style.setProperty(\"width\",o+\"px\",\"important\"),t.style.setProperty(\"height\",a+\"px\",\"important\")):(t.style.removeProperty(\"width\"),t.style.removeProperty(\"height\"))))},wgetRequests:{},nextWgetRequestHandle:0,getNextWgetRequestHandle:function(){var t=Browser.nextWgetRequestHandle;return Browser.nextWgetRequestHandle++,t}},SYSCALLS={varargs:0,get:function(t){SYSCALLS.varargs+=4;var e=HEAP32[SYSCALLS.varargs-4>>2];return e},getStr:function(){var t=Pointer_stringify(SYSCALLS.get());return t},get64:function(){var t=SYSCALLS.get(),e=SYSCALLS.get();return t>=0?assert(e===0):assert(e===-1),t},getZero:function(){assert(SYSCALLS.get()===0)}};function ___syscall6(t,e){SYSCALLS.varargs=e;try{var r=SYSCALLS.getStreamFromFD();return FS.close(r),0}catch(o){return(typeof FS>\"u\"||!(o instanceof FS.ErrnoError))&&abort(o),-o.errno}}function ___syscall54(t,e){SYSCALLS.varargs=e;try{return 0}catch(r){return(typeof FS>\"u\"||!(r instanceof FS.ErrnoError))&&abort(r),-r.errno}}function _typeModule(t){var e=[[0,1,\"X\"],[1,1,\"const X\"],[128,1,\"X *\"],[256,1,\"X &\"],[384,1,\"X &&\"],[512,1,\"std::shared_ptr<X>\"],[640,1,\"std::unique_ptr<X>\"],[5120,1,\"std::vector<X>\"],[6144,2,\"std::array<X, Y>\"],[9216,-1,\"std::function<X (Y)>\"]];function r(p,h,C,I,v,x){if(h==1){var E=I&896;(E==128||E==256||E==384)&&(p=\"X const\")}var R;return x?R=C.replace(\"X\",p).replace(\"Y\",v):R=p.replace(\"X\",C).replace(\"Y\",v),R.replace(/([*&]) (?=[*&])/g,\"$1\")}function o(p,h,C,I,v){throw new Error(p+\" type \"+C.replace(\"X\",h+\"?\")+(I?\" with flag \"+I:\"\")+\" in \"+v)}function a(p,h,C,I,v,x,E,R){x===void 0&&(x=\"X\"),R===void 0&&(R=1);var L=C(p);if(L)return L;var U=I(p),z=U.placeholderFlag,te=e[z];E&&te&&(x=r(E[2],E[0],x,te[0],\"?\",!0));var le;z==0&&(le=\"Unbound\"),z>=10&&(le=\"Corrupt\"),R>20&&(le=\"Deeply nested\"),le&&o(le,p,x,z,v||\"?\");var he=U.paramList[0],Ae=a(he,h,C,I,v,x,te,R+1),ye,ae={flags:te[0],id:p,name:\"\",paramList:[Ae]},Ie=[],Fe=\"?\";switch(U.placeholderFlag){case 1:ye=Ae.spec;break;case 2:if((Ae.flags&15360)==1024&&Ae.spec.ptrSize==1){ae.flags=7168;break}case 3:case 6:case 5:ye=Ae.spec,Ae.flags&15360;break;case 8:Fe=\"\"+U.paramList[1],ae.paramList.push(U.paramList[1]);break;case 9:for(var g=0,Ee=U.paramList[1];g<Ee.length;g++){var De=Ee[g],ce=a(De,h,C,I,v,x,te,R+1);Ie.push(ce.name),ae.paramList.push(ce)}Fe=Ie.join(\", \");break;default:break}if(ae.name=r(te[2],te[0],Ae.name,Ae.flags,Fe),ye){for(var ne=0,ee=Object.keys(ye);ne<ee.length;ne++){var we=ee[ne];ae[we]=ae[we]||ye[we]}ae.flags|=ye.flags}return n(h,ae)}function n(p,h){var C=h.flags,I=C&896,v=C&15360;return!h.name&&v==1024&&(h.ptrSize==1?h.name=(C&16?\"\":(C&8?\"un\":\"\")+\"signed \")+\"char\":h.name=(C&8?\"u\":\"\")+(C&32?\"float\":\"int\")+(h.ptrSize*8+\"_t\")),h.ptrSize==8&&!(C&32)&&(v=64),v==2048&&(I==512||I==640?v=4096:I&&(v=3072)),p(v,h)}var u=function(){function p(h){this.id=h.id,this.name=h.name,this.flags=h.flags,this.spec=h}return p.prototype.toString=function(){return this.name},p}(),A={Type:u,getComplexType:a,makeType:n,structureList:e};return t.output=A,t.output||A}function __nbind_register_type(t,e){var r=_nbind.readAsciiString(e),o={flags:10240,id:t,name:r};_nbind.makeType(_nbind.constructType,o)}function __nbind_register_callback_signature(t,e){var r=_nbind.readTypeIdList(t,e),o=_nbind.callbackSignatureList.length;return _nbind.callbackSignatureList[o]=_nbind.makeJSCaller(r),o}function __extends(t,e){for(var r in e)e.hasOwnProperty(r)&&(t[r]=e[r]);function o(){this.constructor=t}o.prototype=e.prototype,t.prototype=new o}function __nbind_register_class(t,e,r,o,a,n,u){var A=_nbind.readAsciiString(u),p=_nbind.readPolicyList(e),h=HEAPU32.subarray(t/4,t/4+2),C={flags:2048|(p.Value?2:0),id:h[0],name:A},I=_nbind.makeType(_nbind.constructType,C);I.ptrType=_nbind.getComplexType(h[1],_nbind.constructType,_nbind.getType,_nbind.queryType),I.destroy=_nbind.makeMethodCaller(I.ptrType,{boundID:C.id,flags:0,name:\"destroy\",num:0,ptr:n,title:I.name+\".free\",typeList:[\"void\",\"uint32_t\",\"uint32_t\"]}),a&&(I.superIdList=Array.prototype.slice.call(HEAPU32.subarray(r/4,r/4+a)),I.upcastList=Array.prototype.slice.call(HEAPU32.subarray(o/4,o/4+a))),Module[I.name]=I.makeBound(p),_nbind.BindClass.list.push(I)}function _removeAccessorPrefix(t){var e=/^[Gg]et_?([A-Z]?([A-Z]?))/;return t.replace(e,function(r,o,a){return a?o:o.toLowerCase()})}function __nbind_register_function(t,e,r,o,a,n,u,A,p,h){var C=_nbind.getType(t),I=_nbind.readPolicyList(e),v=_nbind.readTypeIdList(r,o),x;if(u==5)x=[{direct:a,name:\"__nbindConstructor\",ptr:0,title:C.name+\" constructor\",typeList:[\"uint32_t\"].concat(v.slice(1))},{direct:n,name:\"__nbindValueConstructor\",ptr:0,title:C.name+\" value constructor\",typeList:[\"void\",\"uint32_t\"].concat(v.slice(1))}];else{var E=_nbind.readAsciiString(A),R=(C.name&&C.name+\".\")+E;(u==3||u==4)&&(E=_removeAccessorPrefix(E)),x=[{boundID:t,direct:n,name:E,ptr:a,title:R,typeList:v}]}for(var L=0,U=x;L<U.length;L++){var z=U[L];z.signatureType=u,z.policyTbl=I,z.num=p,z.flags=h,C.addMethod(z)}}function _nbind_value(t,e){_nbind.typeNameTbl[t]||_nbind.throwError(\"Unknown value type \"+t),Module.NBind.bind_value(t,e),_defineHidden(_nbind.typeNameTbl[t].proto.prototype.__nbindValueConstructor)(e.prototype,\"__nbindValueConstructor\")}Module._nbind_value=_nbind_value;function __nbind_get_value_object(t,e){var r=_nbind.popValue(t);if(!r.fromJS)throw new Error(\"Object \"+r+\" has no fromJS function\");r.fromJS(function(){r.__nbindValueConstructor.apply(this,Array.prototype.concat.apply([e],arguments))})}function _emscripten_memcpy_big(t,e,r){return HEAPU8.set(HEAPU8.subarray(e,e+r),t),t}function __nbind_register_primitive(t,e,r){var o={flags:1024|r,id:t,ptrSize:e};_nbind.makeType(_nbind.constructType,o)}var cttz_i8=allocate([8,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,5,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,6,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,5,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,7,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,5,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,6,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,5,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0],\"i8\",ALLOC_STATIC);function ___setErrNo(t){return Module.___errno_location&&(HEAP32[Module.___errno_location()>>2]=t),t}function _llvm_stacksave(){var t=_llvm_stacksave;return t.LLVM_SAVEDSTACKS||(t.LLVM_SAVEDSTACKS=[]),t.LLVM_SAVEDSTACKS.push(Runtime.stackSave()),t.LLVM_SAVEDSTACKS.length-1}function ___syscall140(t,e){SYSCALLS.varargs=e;try{var r=SYSCALLS.getStreamFromFD(),o=SYSCALLS.get(),a=SYSCALLS.get(),n=SYSCALLS.get(),u=SYSCALLS.get(),A=a;return FS.llseek(r,A,u),HEAP32[n>>2]=r.position,r.getdents&&A===0&&u===0&&(r.getdents=null),0}catch(p){return(typeof FS>\"u\"||!(p instanceof FS.ErrnoError))&&abort(p),-p.errno}}function ___syscall146(t,e){SYSCALLS.varargs=e;try{var r=SYSCALLS.get(),o=SYSCALLS.get(),a=SYSCALLS.get(),n=0;___syscall146.buffer||(___syscall146.buffers=[null,[],[]],___syscall146.printChar=function(C,I){var v=___syscall146.buffers[C];assert(v),I===0||I===10?((C===1?Module.print:Module.printErr)(UTF8ArrayToString(v,0)),v.length=0):v.push(I)});for(var u=0;u<a;u++){for(var A=HEAP32[o+u*8>>2],p=HEAP32[o+(u*8+4)>>2],h=0;h<p;h++)___syscall146.printChar(r,HEAPU8[A+h]);n+=p}return n}catch(C){return(typeof FS>\"u\"||!(C instanceof FS.ErrnoError))&&abort(C),-C.errno}}function __nbind_finish(){for(var t=0,e=_nbind.BindClass.list;t<e.length;t++){var r=e[t];r.finish()}}var ___dso_handle=STATICTOP;STATICTOP+=16,function(_nbind){var typeIdTbl={};_nbind.typeNameTbl={};var Pool=function(){function t(){}return t.lalloc=function(e){e=e+7&-8;var r=HEAPU32[t.usedPtr];if(e>t.pageSize/2||e>t.pageSize-r){var o=_nbind.typeNameTbl.NBind.proto;return o.lalloc(e)}else return HEAPU32[t.usedPtr]=r+e,t.rootPtr+r},t.lreset=function(e,r){var o=HEAPU32[t.pagePtr];if(o){var a=_nbind.typeNameTbl.NBind.proto;a.lreset(e,r)}else HEAPU32[t.usedPtr]=e},t}();_nbind.Pool=Pool;function constructType(t,e){var r=t==10240?_nbind.makeTypeNameTbl[e.name]||_nbind.BindType:_nbind.makeTypeKindTbl[t],o=new r(e);return typeIdTbl[e.id]=o,_nbind.typeNameTbl[e.name]=o,o}_nbind.constructType=constructType;function getType(t){return typeIdTbl[t]}_nbind.getType=getType;function queryType(t){var e=HEAPU8[t],r=_nbind.structureList[e][1];t/=4,r<0&&(++t,r=HEAPU32[t]+1);var o=Array.prototype.slice.call(HEAPU32.subarray(t+1,t+1+r));return e==9&&(o=[o[0],o.slice(1)]),{paramList:o,placeholderFlag:e}}_nbind.queryType=queryType;function getTypes(t,e){return t.map(function(r){return typeof r==\"number\"?_nbind.getComplexType(r,constructType,getType,queryType,e):_nbind.typeNameTbl[r]})}_nbind.getTypes=getTypes;function readTypeIdList(t,e){return Array.prototype.slice.call(HEAPU32,t/4,t/4+e)}_nbind.readTypeIdList=readTypeIdList;function readAsciiString(t){for(var e=t;HEAPU8[e++];);return String.fromCharCode.apply(\"\",HEAPU8.subarray(t,e-1))}_nbind.readAsciiString=readAsciiString;function readPolicyList(t){var e={};if(t)for(;;){var r=HEAPU32[t/4];if(!r)break;e[readAsciiString(r)]=!0,t+=4}return e}_nbind.readPolicyList=readPolicyList;function getDynCall(t,e){var r={float32_t:\"d\",float64_t:\"d\",int64_t:\"d\",uint64_t:\"d\",void:\"v\"},o=t.map(function(n){return r[n.name]||\"i\"}).join(\"\"),a=Module[\"dynCall_\"+o];if(!a)throw new Error(\"dynCall_\"+o+\" not found for \"+e+\"(\"+t.map(function(n){return n.name}).join(\", \")+\")\");return a}_nbind.getDynCall=getDynCall;function addMethod(t,e,r,o){var a=t[e];t.hasOwnProperty(e)&&a?((a.arity||a.arity===0)&&(a=_nbind.makeOverloader(a,a.arity),t[e]=a),a.addMethod(r,o)):(r.arity=o,t[e]=r)}_nbind.addMethod=addMethod;function throwError(t){throw new Error(t)}_nbind.throwError=throwError,_nbind.bigEndian=!1,_a=_typeModule(_typeModule),_nbind.Type=_a.Type,_nbind.makeType=_a.makeType,_nbind.getComplexType=_a.getComplexType,_nbind.structureList=_a.structureList;var BindType=function(t){__extends(e,t);function e(){var r=t!==null&&t.apply(this,arguments)||this;return r.heap=HEAPU32,r.ptrSize=4,r}return e.prototype.needsWireRead=function(r){return!!this.wireRead||!!this.makeWireRead},e.prototype.needsWireWrite=function(r){return!!this.wireWrite||!!this.makeWireWrite},e}(_nbind.Type);_nbind.BindType=BindType;var PrimitiveType=function(t){__extends(e,t);function e(r){var o=t.call(this,r)||this,a=r.flags&32?{32:HEAPF32,64:HEAPF64}:r.flags&8?{8:HEAPU8,16:HEAPU16,32:HEAPU32}:{8:HEAP8,16:HEAP16,32:HEAP32};return o.heap=a[r.ptrSize*8],o.ptrSize=r.ptrSize,o}return e.prototype.needsWireWrite=function(r){return!!r&&!!r.Strict},e.prototype.makeWireWrite=function(r,o){return o&&o.Strict&&function(a){if(typeof a==\"number\")return a;throw new Error(\"Type mismatch\")}},e}(BindType);_nbind.PrimitiveType=PrimitiveType;function pushCString(t,e){if(t==null){if(e&&e.Nullable)return 0;throw new Error(\"Type mismatch\")}if(e&&e.Strict){if(typeof t!=\"string\")throw new Error(\"Type mismatch\")}else t=t.toString();var r=Module.lengthBytesUTF8(t)+1,o=_nbind.Pool.lalloc(r);return Module.stringToUTF8Array(t,HEAPU8,o,r),o}_nbind.pushCString=pushCString;function popCString(t){return t===0?null:Module.Pointer_stringify(t)}_nbind.popCString=popCString;var CStringType=function(t){__extends(e,t);function e(){var r=t!==null&&t.apply(this,arguments)||this;return r.wireRead=popCString,r.wireWrite=pushCString,r.readResources=[_nbind.resources.pool],r.writeResources=[_nbind.resources.pool],r}return e.prototype.makeWireWrite=function(r,o){return function(a){return pushCString(a,o)}},e}(BindType);_nbind.CStringType=CStringType;var BooleanType=function(t){__extends(e,t);function e(){var r=t!==null&&t.apply(this,arguments)||this;return r.wireRead=function(o){return!!o},r}return e.prototype.needsWireWrite=function(r){return!!r&&!!r.Strict},e.prototype.makeWireRead=function(r){return\"!!(\"+r+\")\"},e.prototype.makeWireWrite=function(r,o){return o&&o.Strict&&function(a){if(typeof a==\"boolean\")return a;throw new Error(\"Type mismatch\")}||r},e}(BindType);_nbind.BooleanType=BooleanType;var Wrapper=function(){function t(){}return t.prototype.persist=function(){this.__nbindState|=1},t}();_nbind.Wrapper=Wrapper;function makeBound(t,e){var r=function(o){__extends(a,o);function a(n,u,A,p){var h=o.call(this)||this;if(!(h instanceof a))return new(Function.prototype.bind.apply(a,Array.prototype.concat.apply([null],arguments)));var C=u,I=A,v=p;if(n!==_nbind.ptrMarker){var x=h.__nbindConstructor.apply(h,arguments);C=4608,v=HEAPU32[x/4],I=HEAPU32[x/4+1]}var E={configurable:!0,enumerable:!1,value:null,writable:!1},R={__nbindFlags:C,__nbindPtr:I};v&&(R.__nbindShared=v,_nbind.mark(h));for(var L=0,U=Object.keys(R);L<U.length;L++){var z=U[L];E.value=R[z],Object.defineProperty(h,z,E)}return _defineHidden(0)(h,\"__nbindState\"),h}return a.prototype.free=function(){e.destroy.call(this,this.__nbindShared,this.__nbindFlags),this.__nbindState|=2,disableMember(this,\"__nbindShared\"),disableMember(this,\"__nbindPtr\")},a}(Wrapper);return __decorate([_defineHidden()],r.prototype,\"__nbindConstructor\",void 0),__decorate([_defineHidden()],r.prototype,\"__nbindValueConstructor\",void 0),__decorate([_defineHidden(t)],r.prototype,\"__nbindPolicies\",void 0),r}_nbind.makeBound=makeBound;function disableMember(t,e){function r(){throw new Error(\"Accessing deleted object\")}Object.defineProperty(t,e,{configurable:!1,enumerable:!1,get:r,set:r})}_nbind.ptrMarker={};var BindClass=function(t){__extends(e,t);function e(r){var o=t.call(this,r)||this;return o.wireRead=function(a){return _nbind.popValue(a,o.ptrType)},o.wireWrite=function(a){return pushPointer(a,o.ptrType,!0)},o.pendingSuperCount=0,o.ready=!1,o.methodTbl={},r.paramList?(o.classType=r.paramList[0].classType,o.proto=o.classType.proto):o.classType=o,o}return e.prototype.makeBound=function(r){var o=_nbind.makeBound(r,this);return this.proto=o,this.ptrType.proto=o,o},e.prototype.addMethod=function(r){var o=this.methodTbl[r.name]||[];o.push(r),this.methodTbl[r.name]=o},e.prototype.registerMethods=function(r,o){for(var a,n=0,u=Object.keys(r.methodTbl);n<u.length;n++)for(var A=u[n],p=r.methodTbl[A],h=0,C=p;h<C.length;h++){var I=C[h],v=void 0,x=void 0;if(v=this.proto.prototype,!(o&&I.signatureType!=1))switch(I.signatureType){case 1:v=this.proto;case 5:x=_nbind.makeCaller(I),_nbind.addMethod(v,I.name,x,I.typeList.length-1);break;case 4:a=_nbind.makeMethodCaller(r.ptrType,I);break;case 3:Object.defineProperty(v,I.name,{configurable:!0,enumerable:!1,get:_nbind.makeMethodCaller(r.ptrType,I),set:a});break;case 2:x=_nbind.makeMethodCaller(r.ptrType,I),_nbind.addMethod(v,I.name,x,I.typeList.length-1);break;default:break}}},e.prototype.registerSuperMethods=function(r,o,a){if(!a[r.name]){a[r.name]=!0;for(var n=0,u,A=0,p=r.superIdList||[];A<p.length;A++){var h=p[A],C=_nbind.getType(h);n++<o||o<0?u=-1:u=0,this.registerSuperMethods(C,u,a)}this.registerMethods(r,o<0)}},e.prototype.finish=function(){if(this.ready)return this;this.ready=!0,this.superList=(this.superIdList||[]).map(function(a){return _nbind.getType(a).finish()});var r=this.proto;if(this.superList.length){var o=function(){this.constructor=r};o.prototype=this.superList[0].proto.prototype,r.prototype=new o}return r!=Module&&(r.prototype.__nbindType=this),this.registerSuperMethods(this,1,{}),this},e.prototype.upcastStep=function(r,o){if(r==this)return o;for(var a=0;a<this.superList.length;++a){var n=this.superList[a].upcastStep(r,_nbind.callUpcast(this.upcastList[a],o));if(n)return n}return 0},e}(_nbind.BindType);BindClass.list=[],_nbind.BindClass=BindClass;function popPointer(t,e){return t?new e.proto(_nbind.ptrMarker,e.flags,t):null}_nbind.popPointer=popPointer;function pushPointer(t,e,r){if(!(t instanceof _nbind.Wrapper)){if(r)return _nbind.pushValue(t);throw new Error(\"Type mismatch\")}var o=t.__nbindPtr,a=t.__nbindType.classType,n=e.classType;if(t instanceof e.proto)for(;a!=n;)o=_nbind.callUpcast(a.upcastList[0],o),a=a.superList[0];else if(o=a.upcastStep(n,o),!o)throw new Error(\"Type mismatch\");return o}_nbind.pushPointer=pushPointer;function pushMutablePointer(t,e){var r=pushPointer(t,e);if(t.__nbindFlags&1)throw new Error(\"Passing a const value as a non-const argument\");return r}var BindClassPtr=function(t){__extends(e,t);function e(r){var o=t.call(this,r)||this;o.classType=r.paramList[0].classType,o.proto=o.classType.proto;var a=r.flags&1,n=(o.flags&896)==256&&r.flags&2,u=a?pushPointer:pushMutablePointer,A=n?_nbind.popValue:popPointer;return o.makeWireWrite=function(p,h){return h.Nullable?function(C){return C?u(C,o):0}:function(C){return u(C,o)}},o.wireRead=function(p){return A(p,o)},o.wireWrite=function(p){return u(p,o)},o}return e}(_nbind.BindType);_nbind.BindClassPtr=BindClassPtr;function popShared(t,e){var r=HEAPU32[t/4],o=HEAPU32[t/4+1];return o?new e.proto(_nbind.ptrMarker,e.flags,o,r):null}_nbind.popShared=popShared;function pushShared(t,e){if(!(t instanceof e.proto))throw new Error(\"Type mismatch\");return t.__nbindShared}function pushMutableShared(t,e){if(!(t instanceof e.proto))throw new Error(\"Type mismatch\");if(t.__nbindFlags&1)throw new Error(\"Passing a const value as a non-const argument\");return t.__nbindShared}var SharedClassPtr=function(t){__extends(e,t);function e(r){var o=t.call(this,r)||this;o.readResources=[_nbind.resources.pool],o.classType=r.paramList[0].classType,o.proto=o.classType.proto;var a=r.flags&1,n=a?pushShared:pushMutableShared;return o.wireRead=function(u){return popShared(u,o)},o.wireWrite=function(u){return n(u,o)},o}return e}(_nbind.BindType);_nbind.SharedClassPtr=SharedClassPtr,_nbind.externalList=[0];var firstFreeExternal=0,External=function(){function t(e){this.refCount=1,this.data=e}return t.prototype.register=function(){var e=firstFreeExternal;return e?firstFreeExternal=_nbind.externalList[e]:e=_nbind.externalList.length,_nbind.externalList[e]=this,e},t.prototype.reference=function(){++this.refCount},t.prototype.dereference=function(e){--this.refCount==0&&(this.free&&this.free(),_nbind.externalList[e]=firstFreeExternal,firstFreeExternal=e)},t}();_nbind.External=External;function popExternal(t){var e=_nbind.externalList[t];return e.dereference(t),e.data}function pushExternal(t){var e=new External(t);return e.reference(),e.register()}var ExternalType=function(t){__extends(e,t);function e(){var r=t!==null&&t.apply(this,arguments)||this;return r.wireRead=popExternal,r.wireWrite=pushExternal,r}return e}(_nbind.BindType);_nbind.ExternalType=ExternalType,_nbind.callbackSignatureList=[];var CallbackType=function(t){__extends(e,t);function e(){var r=t!==null&&t.apply(this,arguments)||this;return r.wireWrite=function(o){return typeof o!=\"function\"&&_nbind.throwError(\"Type mismatch\"),new _nbind.External(o).register()},r}return e}(_nbind.BindType);_nbind.CallbackType=CallbackType,_nbind.valueList=[0];var firstFreeValue=0;function pushValue(t){var e=firstFreeValue;return e?firstFreeValue=_nbind.valueList[e]:e=_nbind.valueList.length,_nbind.valueList[e]=t,e*2+1}_nbind.pushValue=pushValue;function popValue(t,e){if(t||_nbind.throwError(\"Value type JavaScript class is missing or not registered\"),t&1){t>>=1;var r=_nbind.valueList[t];return _nbind.valueList[t]=firstFreeValue,firstFreeValue=t,r}else{if(e)return _nbind.popShared(t,e);throw new Error(\"Invalid value slot \"+t)}}_nbind.popValue=popValue;var valueBase=18446744073709552e3;function push64(t){return typeof t==\"number\"?t:pushValue(t)*4096+valueBase}function pop64(t){return t<valueBase?t:popValue((t-valueBase)/4096)}var CreateValueType=function(t){__extends(e,t);function e(){return t!==null&&t.apply(this,arguments)||this}return e.prototype.makeWireWrite=function(r){return\"(_nbind.pushValue(new \"+r+\"))\"},e}(_nbind.BindType);_nbind.CreateValueType=CreateValueType;var Int64Type=function(t){__extends(e,t);function e(){var r=t!==null&&t.apply(this,arguments)||this;return r.wireWrite=push64,r.wireRead=pop64,r}return e}(_nbind.BindType);_nbind.Int64Type=Int64Type;function pushArray(t,e){if(!t)return 0;var r=t.length;if((e.size||e.size===0)&&r<e.size)throw new Error(\"Type mismatch\");var o=e.memberType.ptrSize,a=_nbind.Pool.lalloc(4+r*o);HEAPU32[a/4]=r;var n=e.memberType.heap,u=(a+4)/o,A=e.memberType.wireWrite,p=0;if(A)for(;p<r;)n[u++]=A(t[p++]);else for(;p<r;)n[u++]=t[p++];return a}_nbind.pushArray=pushArray;function popArray(t,e){if(t===0)return null;var r=HEAPU32[t/4],o=new Array(r),a=e.memberType.heap;t=(t+4)/e.memberType.ptrSize;var n=e.memberType.wireRead,u=0;if(n)for(;u<r;)o[u++]=n(a[t++]);else for(;u<r;)o[u++]=a[t++];return o}_nbind.popArray=popArray;var ArrayType=function(t){__extends(e,t);function e(r){var o=t.call(this,r)||this;return o.wireRead=function(a){return popArray(a,o)},o.wireWrite=function(a){return pushArray(a,o)},o.readResources=[_nbind.resources.pool],o.writeResources=[_nbind.resources.pool],o.memberType=r.paramList[0],r.paramList[1]&&(o.size=r.paramList[1]),o}return e}(_nbind.BindType);_nbind.ArrayType=ArrayType;function pushString(t,e){if(t==null)if(e&&e.Nullable)t=\"\";else throw new Error(\"Type mismatch\");if(e&&e.Strict){if(typeof t!=\"string\")throw new Error(\"Type mismatch\")}else t=t.toString();var r=Module.lengthBytesUTF8(t),o=_nbind.Pool.lalloc(4+r+1);return HEAPU32[o/4]=r,Module.stringToUTF8Array(t,HEAPU8,o+4,r+1),o}_nbind.pushString=pushString;function popString(t){if(t===0)return null;var e=HEAPU32[t/4];return Module.Pointer_stringify(t+4,e)}_nbind.popString=popString;var StringType=function(t){__extends(e,t);function e(){var r=t!==null&&t.apply(this,arguments)||this;return r.wireRead=popString,r.wireWrite=pushString,r.readResources=[_nbind.resources.pool],r.writeResources=[_nbind.resources.pool],r}return e.prototype.makeWireWrite=function(r,o){return function(a){return pushString(a,o)}},e}(_nbind.BindType);_nbind.StringType=StringType;function makeArgList(t){return Array.apply(null,Array(t)).map(function(e,r){return\"a\"+(r+1)})}function anyNeedsWireWrite(t,e){return t.reduce(function(r,o){return r||o.needsWireWrite(e)},!1)}function anyNeedsWireRead(t,e){return t.reduce(function(r,o){return r||!!o.needsWireRead(e)},!1)}function makeWireRead(t,e,r,o){var a=t.length;return r.makeWireRead?r.makeWireRead(o,t,a):r.wireRead?(t[a]=r.wireRead,\"(convertParamList[\"+a+\"](\"+o+\"))\"):o}function makeWireWrite(t,e,r,o){var a,n=t.length;return r.makeWireWrite?a=r.makeWireWrite(o,e,t,n):a=r.wireWrite,a?typeof a==\"string\"?a:(t[n]=a,\"(convertParamList[\"+n+\"](\"+o+\"))\"):o}function buildCallerFunction(dynCall,ptrType,ptr,num,policyTbl,needsWireWrite,prefix,returnType,argTypeList,mask,err){var argList=makeArgList(argTypeList.length),convertParamList=[],callExpression=makeWireRead(convertParamList,policyTbl,returnType,\"dynCall(\"+[prefix].concat(argList.map(function(t,e){return makeWireWrite(convertParamList,policyTbl,argTypeList[e],t)})).join(\",\")+\")\"),resourceSet=_nbind.listResources([returnType],argTypeList),sourceCode=\"function(\"+argList.join(\",\")+\"){\"+(mask?\"this.__nbindFlags&mask&&err();\":\"\")+resourceSet.makeOpen()+\"var r=\"+callExpression+\";\"+resourceSet.makeClose()+\"return r;}\";return eval(\"(\"+sourceCode+\")\")}function buildJSCallerFunction(returnType,argTypeList){var argList=makeArgList(argTypeList.length),convertParamList=[],callExpression=makeWireWrite(convertParamList,null,returnType,\"_nbind.externalList[num].data(\"+argList.map(function(t,e){return makeWireRead(convertParamList,null,argTypeList[e],t)}).join(\",\")+\")\"),resourceSet=_nbind.listResources(argTypeList,[returnType]);resourceSet.remove(_nbind.resources.pool);var sourceCode=\"function(\"+[\"dummy\",\"num\"].concat(argList).join(\",\")+\"){\"+resourceSet.makeOpen()+\"var r=\"+callExpression+\";\"+resourceSet.makeClose()+\"return r;}\";return eval(\"(\"+sourceCode+\")\")}_nbind.buildJSCallerFunction=buildJSCallerFunction;function makeJSCaller(t){var e=t.length-1,r=_nbind.getTypes(t,\"callback\"),o=r[0],a=r.slice(1),n=anyNeedsWireRead(a,null),u=o.needsWireWrite(null);if(!u&&!n)switch(e){case 0:return function(A,p){return _nbind.externalList[p].data()};case 1:return function(A,p,h){return _nbind.externalList[p].data(h)};case 2:return function(A,p,h,C){return _nbind.externalList[p].data(h,C)};case 3:return function(A,p,h,C,I){return _nbind.externalList[p].data(h,C,I)};default:break}return buildJSCallerFunction(o,a)}_nbind.makeJSCaller=makeJSCaller;function makeMethodCaller(t,e){var r=e.typeList.length-1,o=e.typeList.slice(0);o.splice(1,0,\"uint32_t\",e.boundID);var a=_nbind.getTypes(o,e.title),n=a[0],u=a.slice(3),A=n.needsWireRead(e.policyTbl),p=anyNeedsWireWrite(u,e.policyTbl),h=e.ptr,C=e.num,I=_nbind.getDynCall(a,e.title),v=~e.flags&1;function x(){throw new Error(\"Calling a non-const method on a const object\")}if(!A&&!p)switch(r){case 0:return function(){return this.__nbindFlags&v?x():I(h,C,_nbind.pushPointer(this,t))};case 1:return function(E){return this.__nbindFlags&v?x():I(h,C,_nbind.pushPointer(this,t),E)};case 2:return function(E,R){return this.__nbindFlags&v?x():I(h,C,_nbind.pushPointer(this,t),E,R)};case 3:return function(E,R,L){return this.__nbindFlags&v?x():I(h,C,_nbind.pushPointer(this,t),E,R,L)};default:break}return buildCallerFunction(I,t,h,C,e.policyTbl,p,\"ptr,num,pushPointer(this,ptrType)\",n,u,v,x)}_nbind.makeMethodCaller=makeMethodCaller;function makeCaller(t){var e=t.typeList.length-1,r=_nbind.getTypes(t.typeList,t.title),o=r[0],a=r.slice(1),n=o.needsWireRead(t.policyTbl),u=anyNeedsWireWrite(a,t.policyTbl),A=t.direct,p=t.ptr;if(t.direct&&!n&&!u){var h=_nbind.getDynCall(r,t.title);switch(e){case 0:return function(){return h(A)};case 1:return function(x){return h(A,x)};case 2:return function(x,E){return h(A,x,E)};case 3:return function(x,E,R){return h(A,x,E,R)};default:break}p=0}var C;if(p){var I=t.typeList.slice(0);I.splice(1,0,\"uint32_t\"),r=_nbind.getTypes(I,t.title),C=\"ptr,num\"}else p=A,C=\"ptr\";var v=_nbind.getDynCall(r,t.title);return buildCallerFunction(v,null,p,t.num,t.policyTbl,u,C,o,a)}_nbind.makeCaller=makeCaller;function makeOverloader(t,e){var r=[];function o(){return r[arguments.length].apply(this,arguments)}return o.addMethod=function(a,n){r[n]=a},o.addMethod(t,e),o}_nbind.makeOverloader=makeOverloader;var Resource=function(){function t(e,r){var o=this;this.makeOpen=function(){return Object.keys(o.openTbl).join(\"\")},this.makeClose=function(){return Object.keys(o.closeTbl).join(\"\")},this.openTbl={},this.closeTbl={},e&&(this.openTbl[e]=!0),r&&(this.closeTbl[r]=!0)}return t.prototype.add=function(e){for(var r=0,o=Object.keys(e.openTbl);r<o.length;r++){var a=o[r];this.openTbl[a]=!0}for(var n=0,u=Object.keys(e.closeTbl);n<u.length;n++){var a=u[n];this.closeTbl[a]=!0}},t.prototype.remove=function(e){for(var r=0,o=Object.keys(e.openTbl);r<o.length;r++){var a=o[r];delete this.openTbl[a]}for(var n=0,u=Object.keys(e.closeTbl);n<u.length;n++){var a=u[n];delete this.closeTbl[a]}},t}();_nbind.Resource=Resource;function listResources(t,e){for(var r=new Resource,o=0,a=t;o<a.length;o++)for(var n=a[o],u=0,A=n.readResources||[];u<A.length;u++){var p=A[u];r.add(p)}for(var h=0,C=e;h<C.length;h++)for(var n=C[h],I=0,v=n.writeResources||[];I<v.length;I++){var p=v[I];r.add(p)}return r}_nbind.listResources=listResources,_nbind.resources={pool:new Resource(\"var used=HEAPU32[_nbind.Pool.usedPtr],page=HEAPU32[_nbind.Pool.pagePtr];\",\"_nbind.Pool.lreset(used,page);\")};var ExternalBuffer=function(t){__extends(e,t);function e(r,o){var a=t.call(this,r)||this;return a.ptr=o,a}return e.prototype.free=function(){_free(this.ptr)},e}(_nbind.External);function getBuffer(t){return t instanceof ArrayBuffer?new Uint8Array(t):t instanceof DataView?new Uint8Array(t.buffer,t.byteOffset,t.byteLength):t}function pushBuffer(t,e){if(t==null&&e&&e.Nullable&&(t=[]),typeof t!=\"object\")throw new Error(\"Type mismatch\");var r=t,o=r.byteLength||r.length;if(!o&&o!==0&&r.byteLength!==0)throw new Error(\"Type mismatch\");var a=_nbind.Pool.lalloc(8),n=_malloc(o),u=a/4;return HEAPU32[u++]=o,HEAPU32[u++]=n,HEAPU32[u++]=new ExternalBuffer(t,n).register(),HEAPU8.set(getBuffer(t),n),a}var BufferType=function(t){__extends(e,t);function e(){var r=t!==null&&t.apply(this,arguments)||this;return r.wireWrite=pushBuffer,r.readResources=[_nbind.resources.pool],r.writeResources=[_nbind.resources.pool],r}return e.prototype.makeWireWrite=function(r,o){return function(a){return pushBuffer(a,o)}},e}(_nbind.BindType);_nbind.BufferType=BufferType;function commitBuffer(t,e,r){var o=_nbind.externalList[t].data,a=Buffer;if(typeof Buffer!=\"function\"&&(a=function(){}),!(o instanceof Array)){var n=HEAPU8.subarray(e,e+r);if(o instanceof a){var u=void 0;typeof Buffer.from==\"function\"&&Buffer.from.length>=3?u=Buffer.from(n):u=new Buffer(n),u.copy(o)}else getBuffer(o).set(n)}}_nbind.commitBuffer=commitBuffer;var dirtyList=[],gcTimer=0;function sweep(){for(var t=0,e=dirtyList;t<e.length;t++){var r=e[t];r.__nbindState&3||r.free()}dirtyList=[],gcTimer=0}_nbind.mark=function(t){};function toggleLightGC(t){t?_nbind.mark=function(e){dirtyList.push(e),gcTimer||(gcTimer=setTimeout(sweep,0))}:_nbind.mark=function(e){}}_nbind.toggleLightGC=toggleLightGC}(_nbind),Module.requestFullScreen=function t(e,r,o){Module.printErr(\"Module.requestFullScreen is deprecated. Please call Module.requestFullscreen instead.\"),Module.requestFullScreen=Module.requestFullscreen,Browser.requestFullScreen(e,r,o)},Module.requestFullscreen=function t(e,r,o){Browser.requestFullscreen(e,r,o)},Module.requestAnimationFrame=function t(e){Browser.requestAnimationFrame(e)},Module.setCanvasSize=function t(e,r,o){Browser.setCanvasSize(e,r,o)},Module.pauseMainLoop=function t(){Browser.mainLoop.pause()},Module.resumeMainLoop=function t(){Browser.mainLoop.resume()},Module.getUserMedia=function t(){Browser.getUserMedia()},Module.createContext=function t(e,r,o,a){return Browser.createContext(e,r,o,a)},ENVIRONMENT_IS_NODE?_emscripten_get_now=function(){var e=process.hrtime();return e[0]*1e3+e[1]/1e6}:typeof dateNow<\"u\"?_emscripten_get_now=dateNow:typeof self==\"object\"&&self.performance&&typeof self.performance.now==\"function\"?_emscripten_get_now=function(){return self.performance.now()}:typeof performance==\"object\"&&typeof performance.now==\"function\"?_emscripten_get_now=function(){return performance.now()}:_emscripten_get_now=Date.now,__ATEXIT__.push(function(){var t=Module._fflush;t&&t(0);var e=___syscall146.printChar;if(!!e){var r=___syscall146.buffers;r[1].length&&e(1,10),r[2].length&&e(2,10)}}),DYNAMICTOP_PTR=allocate(1,\"i32\",ALLOC_STATIC),STACK_BASE=STACKTOP=Runtime.alignMemory(STATICTOP),STACK_MAX=STACK_BASE+TOTAL_STACK,DYNAMIC_BASE=Runtime.alignMemory(STACK_MAX),HEAP32[DYNAMICTOP_PTR>>2]=DYNAMIC_BASE,staticSealed=!0;function invoke_viiiii(t,e,r,o,a,n){try{Module.dynCall_viiiii(t,e,r,o,a,n)}catch(u){if(typeof u!=\"number\"&&u!==\"longjmp\")throw u;Module.setThrew(1,0)}}function invoke_vif(t,e,r){try{Module.dynCall_vif(t,e,r)}catch(o){if(typeof o!=\"number\"&&o!==\"longjmp\")throw o;Module.setThrew(1,0)}}function invoke_vid(t,e,r){try{Module.dynCall_vid(t,e,r)}catch(o){if(typeof o!=\"number\"&&o!==\"longjmp\")throw o;Module.setThrew(1,0)}}function invoke_fiff(t,e,r,o){try{return Module.dynCall_fiff(t,e,r,o)}catch(a){if(typeof a!=\"number\"&&a!==\"longjmp\")throw a;Module.setThrew(1,0)}}function invoke_vi(t,e){try{Module.dynCall_vi(t,e)}catch(r){if(typeof r!=\"number\"&&r!==\"longjmp\")throw r;Module.setThrew(1,0)}}function invoke_vii(t,e,r){try{Module.dynCall_vii(t,e,r)}catch(o){if(typeof o!=\"number\"&&o!==\"longjmp\")throw o;Module.setThrew(1,0)}}function invoke_ii(t,e){try{return Module.dynCall_ii(t,e)}catch(r){if(typeof r!=\"number\"&&r!==\"longjmp\")throw r;Module.setThrew(1,0)}}function invoke_viddi(t,e,r,o,a){try{Module.dynCall_viddi(t,e,r,o,a)}catch(n){if(typeof n!=\"number\"&&n!==\"longjmp\")throw n;Module.setThrew(1,0)}}function invoke_vidd(t,e,r,o){try{Module.dynCall_vidd(t,e,r,o)}catch(a){if(typeof a!=\"number\"&&a!==\"longjmp\")throw a;Module.setThrew(1,0)}}function invoke_iiii(t,e,r,o){try{return Module.dynCall_iiii(t,e,r,o)}catch(a){if(typeof a!=\"number\"&&a!==\"longjmp\")throw a;Module.setThrew(1,0)}}function invoke_diii(t,e,r,o){try{return Module.dynCall_diii(t,e,r,o)}catch(a){if(typeof a!=\"number\"&&a!==\"longjmp\")throw a;Module.setThrew(1,0)}}function invoke_di(t,e){try{return Module.dynCall_di(t,e)}catch(r){if(typeof r!=\"number\"&&r!==\"longjmp\")throw r;Module.setThrew(1,0)}}function invoke_iid(t,e,r){try{return Module.dynCall_iid(t,e,r)}catch(o){if(typeof o!=\"number\"&&o!==\"longjmp\")throw o;Module.setThrew(1,0)}}function invoke_iii(t,e,r){try{return Module.dynCall_iii(t,e,r)}catch(o){if(typeof o!=\"number\"&&o!==\"longjmp\")throw o;Module.setThrew(1,0)}}function invoke_viiddi(t,e,r,o,a,n){try{Module.dynCall_viiddi(t,e,r,o,a,n)}catch(u){if(typeof u!=\"number\"&&u!==\"longjmp\")throw u;Module.setThrew(1,0)}}function invoke_viiiiii(t,e,r,o,a,n,u){try{Module.dynCall_viiiiii(t,e,r,o,a,n,u)}catch(A){if(typeof A!=\"number\"&&A!==\"longjmp\")throw A;Module.setThrew(1,0)}}function invoke_dii(t,e,r){try{return Module.dynCall_dii(t,e,r)}catch(o){if(typeof o!=\"number\"&&o!==\"longjmp\")throw o;Module.setThrew(1,0)}}function invoke_i(t){try{return Module.dynCall_i(t)}catch(e){if(typeof e!=\"number\"&&e!==\"longjmp\")throw e;Module.setThrew(1,0)}}function invoke_iiiiii(t,e,r,o,a,n){try{return Module.dynCall_iiiiii(t,e,r,o,a,n)}catch(u){if(typeof u!=\"number\"&&u!==\"longjmp\")throw u;Module.setThrew(1,0)}}function invoke_viiid(t,e,r,o,a){try{Module.dynCall_viiid(t,e,r,o,a)}catch(n){if(typeof n!=\"number\"&&n!==\"longjmp\")throw n;Module.setThrew(1,0)}}function invoke_viififi(t,e,r,o,a,n,u){try{Module.dynCall_viififi(t,e,r,o,a,n,u)}catch(A){if(typeof A!=\"number\"&&A!==\"longjmp\")throw A;Module.setThrew(1,0)}}function invoke_viii(t,e,r,o){try{Module.dynCall_viii(t,e,r,o)}catch(a){if(typeof a!=\"number\"&&a!==\"longjmp\")throw a;Module.setThrew(1,0)}}function invoke_v(t){try{Module.dynCall_v(t)}catch(e){if(typeof e!=\"number\"&&e!==\"longjmp\")throw e;Module.setThrew(1,0)}}function invoke_viid(t,e,r,o){try{Module.dynCall_viid(t,e,r,o)}catch(a){if(typeof a!=\"number\"&&a!==\"longjmp\")throw a;Module.setThrew(1,0)}}function invoke_idd(t,e,r){try{return Module.dynCall_idd(t,e,r)}catch(o){if(typeof o!=\"number\"&&o!==\"longjmp\")throw o;Module.setThrew(1,0)}}function invoke_viiii(t,e,r,o,a){try{Module.dynCall_viiii(t,e,r,o,a)}catch(n){if(typeof n!=\"number\"&&n!==\"longjmp\")throw n;Module.setThrew(1,0)}}Module.asmGlobalArg={Math,Int8Array,Int16Array,Int32Array,Uint8Array,Uint16Array,Uint32Array,Float32Array,Float64Array,NaN:NaN,Infinity:1/0},Module.asmLibraryArg={abort,assert,enlargeMemory,getTotalMemory,abortOnCannotGrowMemory,invoke_viiiii,invoke_vif,invoke_vid,invoke_fiff,invoke_vi,invoke_vii,invoke_ii,invoke_viddi,invoke_vidd,invoke_iiii,invoke_diii,invoke_di,invoke_iid,invoke_iii,invoke_viiddi,invoke_viiiiii,invoke_dii,invoke_i,invoke_iiiiii,invoke_viiid,invoke_viififi,invoke_viii,invoke_v,invoke_viid,invoke_idd,invoke_viiii,_emscripten_asm_const_iiiii,_emscripten_asm_const_iiidddddd,_emscripten_asm_const_iiiid,__nbind_reference_external,_emscripten_asm_const_iiiiiiii,_removeAccessorPrefix,_typeModule,__nbind_register_pool,__decorate,_llvm_stackrestore,___cxa_atexit,__extends,__nbind_get_value_object,__ZN8facebook4yoga14YGNodeToStringEPNSt3__212basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEEP6YGNode14YGPrintOptionsj,_emscripten_set_main_loop_timing,__nbind_register_primitive,__nbind_register_type,_emscripten_memcpy_big,__nbind_register_function,___setErrNo,__nbind_register_class,__nbind_finish,_abort,_nbind_value,_llvm_stacksave,___syscall54,_defineHidden,_emscripten_set_main_loop,_emscripten_get_now,__nbind_register_callback_signature,_emscripten_asm_const_iiiiii,__nbind_free_external,_emscripten_asm_const_iiii,_emscripten_asm_const_iiididi,___syscall6,_atexit,___syscall140,___syscall146,DYNAMICTOP_PTR,tempDoublePtr,ABORT,STACKTOP,STACK_MAX,cttz_i8,___dso_handle};var asm=function(t,e,r){var o=new t.Int8Array(r),a=new t.Int16Array(r),n=new t.Int32Array(r),u=new t.Uint8Array(r),A=new t.Uint16Array(r),p=new t.Uint32Array(r),h=new t.Float32Array(r),C=new t.Float64Array(r),I=e.DYNAMICTOP_PTR|0,v=e.tempDoublePtr|0,x=e.ABORT|0,E=e.STACKTOP|0,R=e.STACK_MAX|0,L=e.cttz_i8|0,U=e.___dso_handle|0,z=0,te=0,le=0,he=0,Ae=t.NaN,ye=t.Infinity,ae=0,Ie=0,Fe=0,g=0,Ee=0,De=0,ce=t.Math.floor,ne=t.Math.abs,ee=t.Math.sqrt,we=t.Math.pow,xe=t.Math.cos,ht=t.Math.sin,H=t.Math.tan,lt=t.Math.acos,Te=t.Math.asin,ke=t.Math.atan,be=t.Math.atan2,_e=t.Math.exp,Re=t.Math.log,ze=t.Math.ceil,He=t.Math.imul,b=t.Math.min,w=t.Math.max,S=t.Math.clz32,y=t.Math.fround,F=e.abort,J=e.assert,X=e.enlargeMemory,Z=e.getTotalMemory,ie=e.abortOnCannotGrowMemory,Pe=e.invoke_viiiii,Ne=e.invoke_vif,ot=e.invoke_vid,dt=e.invoke_fiff,jt=e.invoke_vi,$t=e.invoke_vii,bt=e.invoke_ii,an=e.invoke_viddi,Qr=e.invoke_vidd,mr=e.invoke_iiii,br=e.invoke_diii,Wr=e.invoke_di,Kn=e.invoke_iid,Ns=e.invoke_iii,Ti=e.invoke_viiddi,ps=e.invoke_viiiiii,io=e.invoke_dii,Si=e.invoke_i,Ls=e.invoke_iiiiii,so=e.invoke_viiid,cc=e.invoke_viififi,cu=e.invoke_viii,op=e.invoke_v,ap=e.invoke_viid,Os=e.invoke_idd,Dn=e.invoke_viiii,oo=e._emscripten_asm_const_iiiii,Ms=e._emscripten_asm_const_iiidddddd,ml=e._emscripten_asm_const_iiiid,yl=e.__nbind_reference_external,ao=e._emscripten_asm_const_iiiiiiii,Vn=e._removeAccessorPrefix,On=e._typeModule,Ni=e.__nbind_register_pool,Mn=e.__decorate,_i=e._llvm_stackrestore,tr=e.___cxa_atexit,Oe=e.__extends,ii=e.__nbind_get_value_object,Ma=e.__ZN8facebook4yoga14YGNodeToStringEPNSt3__212basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEEP6YGNode14YGPrintOptionsj,hr=e._emscripten_set_main_loop_timing,uc=e.__nbind_register_primitive,uu=e.__nbind_register_type,Ac=e._emscripten_memcpy_big,El=e.__nbind_register_function,vA=e.___setErrNo,Au=e.__nbind_register_class,Ce=e.__nbind_finish,Rt=e._abort,fc=e._nbind_value,Hi=e._llvm_stacksave,fu=e.___syscall54,Yt=e._defineHidden,Cl=e._emscripten_set_main_loop,DA=e._emscripten_get_now,lp=e.__nbind_register_callback_signature,pc=e._emscripten_asm_const_iiiiii,PA=e.__nbind_free_external,Qn=e._emscripten_asm_const_iiii,hi=e._emscripten_asm_const_iiididi,hc=e.___syscall6,SA=e._atexit,sa=e.___syscall140,Li=e.___syscall146,_o=y(0);let Ze=y(0);function lo(s){s=s|0;var l=0;return l=E,E=E+s|0,E=E+15&-16,l|0}function gc(){return E|0}function pu(s){s=s|0,E=s}function ji(s,l){s=s|0,l=l|0,E=s,R=l}function hu(s,l){s=s|0,l=l|0,z||(z=s,te=l)}function bA(s){s=s|0,De=s}function Ua(){return De|0}function dc(){var s=0,l=0;Dr(8104,8,400)|0,Dr(8504,408,540)|0,s=9044,l=s+44|0;do n[s>>2]=0,s=s+4|0;while((s|0)<(l|0));o[9088]=0,o[9089]=1,n[2273]=0,n[2274]=948,n[2275]=948,tr(17,8104,U|0)|0}function hs(s){s=s|0,ft(s+948|0)}function _t(s){return s=y(s),((Du(s)|0)&2147483647)>>>0>2139095040|0}function Fn(s,l,c){s=s|0,l=l|0,c=c|0;e:do if(n[s+(l<<3)+4>>2]|0)s=s+(l<<3)|0;else{if((l|2|0)==3&&n[s+60>>2]|0){s=s+56|0;break}switch(l|0){case 0:case 2:case 4:case 5:{if(n[s+52>>2]|0){s=s+48|0;break e}break}default:}if(n[s+68>>2]|0){s=s+64|0;break}else{s=(l|1|0)==5?948:c;break}}while(0);return s|0}function Ci(s){s=s|0;var l=0;return l=pD(1e3)|0,oa(s,(l|0)!=0,2456),n[2276]=(n[2276]|0)+1,Dr(l|0,8104,1e3)|0,o[s+2>>0]|0&&(n[l+4>>2]=2,n[l+12>>2]=4),n[l+976>>2]=s,l|0}function oa(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0;d=E,E=E+16|0,f=d,l||(n[f>>2]=c,mg(s,5,3197,f)),E=d}function co(){return Ci(956)|0}function Us(s){s=s|0;var l=0;return l=Kt(1e3)|0,aa(l,s),oa(n[s+976>>2]|0,1,2456),n[2276]=(n[2276]|0)+1,n[l+944>>2]=0,l|0}function aa(s,l){s=s|0,l=l|0;var c=0;Dr(s|0,l|0,948)|0,Qm(s+948|0,l+948|0),c=s+960|0,s=l+960|0,l=c+40|0;do n[c>>2]=n[s>>2],c=c+4|0,s=s+4|0;while((c|0)<(l|0))}function la(s){s=s|0;var l=0,c=0,f=0,d=0;if(l=s+944|0,c=n[l>>2]|0,c|0&&(Ho(c+948|0,s)|0,n[l>>2]=0),c=wi(s)|0,c|0){l=0;do n[(gs(s,l)|0)+944>>2]=0,l=l+1|0;while((l|0)!=(c|0))}c=s+948|0,f=n[c>>2]|0,d=s+952|0,l=n[d>>2]|0,(l|0)!=(f|0)&&(n[d>>2]=l+(~((l+-4-f|0)>>>2)<<2)),ds(c),hD(s),n[2276]=(n[2276]|0)+-1}function Ho(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0,B=0,k=0;f=n[s>>2]|0,k=s+4|0,c=n[k>>2]|0,m=c;e:do if((f|0)==(c|0))d=f,B=4;else for(s=f;;){if((n[s>>2]|0)==(l|0)){d=s,B=4;break e}if(s=s+4|0,(s|0)==(c|0)){s=0;break}}while(0);return(B|0)==4&&((d|0)!=(c|0)?(f=d+4|0,s=m-f|0,l=s>>2,l&&(Lw(d|0,f|0,s|0)|0,c=n[k>>2]|0),s=d+(l<<2)|0,(c|0)==(s|0)||(n[k>>2]=c+(~((c+-4-s|0)>>>2)<<2)),s=1):s=0),s|0}function wi(s){return s=s|0,(n[s+952>>2]|0)-(n[s+948>>2]|0)>>2|0}function gs(s,l){s=s|0,l=l|0;var c=0;return c=n[s+948>>2]|0,(n[s+952>>2]|0)-c>>2>>>0>l>>>0?s=n[c+(l<<2)>>2]|0:s=0,s|0}function ds(s){s=s|0;var l=0,c=0,f=0,d=0;f=E,E=E+32|0,l=f,d=n[s>>2]|0,c=(n[s+4>>2]|0)-d|0,((n[s+8>>2]|0)-d|0)>>>0>c>>>0&&(d=c>>2,Cp(l,d,d,s+8|0),wg(s,l),UA(l)),E=f}function ms(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0,B=0,k=0,Q=0,M=0;M=wi(s)|0;do if(M|0){if((n[(gs(s,0)|0)+944>>2]|0)==(s|0)){if(!(Ho(s+948|0,l)|0))break;Dr(l+400|0,8504,540)|0,n[l+944>>2]=0,Le(s);break}B=n[(n[s+976>>2]|0)+12>>2]|0,k=s+948|0,Q=(B|0)==0,c=0,m=0;do f=n[(n[k>>2]|0)+(m<<2)>>2]|0,(f|0)==(l|0)?Le(s):(d=Us(f)|0,n[(n[k>>2]|0)+(c<<2)>>2]=d,n[d+944>>2]=s,Q||LR[B&15](f,d,s,c),c=c+1|0),m=m+1|0;while((m|0)!=(M|0));if(c>>>0<M>>>0){Q=s+948|0,k=s+952|0,B=c,c=n[k>>2]|0;do m=(n[Q>>2]|0)+(B<<2)|0,f=m+4|0,d=c-f|0,l=d>>2,l&&(Lw(m|0,f|0,d|0)|0,c=n[k>>2]|0),d=c,f=m+(l<<2)|0,(d|0)!=(f|0)&&(c=d+(~((d+-4-f|0)>>>2)<<2)|0,n[k>>2]=c),B=B+1|0;while((B|0)!=(M|0))}}while(0)}function _s(s){s=s|0;var l=0,c=0,f=0,d=0;Un(s,(wi(s)|0)==0,2491),Un(s,(n[s+944>>2]|0)==0,2545),l=s+948|0,c=n[l>>2]|0,f=s+952|0,d=n[f>>2]|0,(d|0)!=(c|0)&&(n[f>>2]=d+(~((d+-4-c|0)>>>2)<<2)),ds(l),l=s+976|0,c=n[l>>2]|0,Dr(s|0,8104,1e3)|0,o[c+2>>0]|0&&(n[s+4>>2]=2,n[s+12>>2]=4),n[l>>2]=c}function Un(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0;d=E,E=E+16|0,f=d,l||(n[f>>2]=c,Ao(s,5,3197,f)),E=d}function Pn(){return n[2276]|0}function ys(){var s=0;return s=pD(20)|0,We((s|0)!=0,2592),n[2277]=(n[2277]|0)+1,n[s>>2]=n[239],n[s+4>>2]=n[240],n[s+8>>2]=n[241],n[s+12>>2]=n[242],n[s+16>>2]=n[243],s|0}function We(s,l){s=s|0,l=l|0;var c=0,f=0;f=E,E=E+16|0,c=f,s||(n[c>>2]=l,Ao(0,5,3197,c)),E=f}function tt(s){s=s|0,hD(s),n[2277]=(n[2277]|0)+-1}function It(s,l){s=s|0,l=l|0;var c=0;l?(Un(s,(wi(s)|0)==0,2629),c=1):(c=0,l=0),n[s+964>>2]=l,n[s+988>>2]=c}function nr(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0;f=E,E=E+16|0,m=f+8|0,d=f+4|0,B=f,n[d>>2]=l,Un(s,(n[l+944>>2]|0)==0,2709),Un(s,(n[s+964>>2]|0)==0,2763),$(s),l=s+948|0,n[B>>2]=(n[l>>2]|0)+(c<<2),n[m>>2]=n[B>>2],me(l,m,d)|0,n[(n[d>>2]|0)+944>>2]=s,Le(s),E=f}function $(s){s=s|0;var l=0,c=0,f=0,d=0,m=0,B=0,k=0;if(c=wi(s)|0,c|0&&(n[(gs(s,0)|0)+944>>2]|0)!=(s|0)){f=n[(n[s+976>>2]|0)+12>>2]|0,d=s+948|0,m=(f|0)==0,l=0;do B=n[(n[d>>2]|0)+(l<<2)>>2]|0,k=Us(B)|0,n[(n[d>>2]|0)+(l<<2)>>2]=k,n[k+944>>2]=s,m||LR[f&15](B,k,s,l),l=l+1|0;while((l|0)!=(c|0))}}function me(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0,k=0,Q=0,M=0,O=0,q=0,se=0,Ge=0,Me=0,Qe=0,et=0,Xe=0;et=E,E=E+64|0,q=et+52|0,k=et+48|0,se=et+28|0,Ge=et+24|0,Me=et+20|0,Qe=et,f=n[s>>2]|0,m=f,l=f+((n[l>>2]|0)-m>>2<<2)|0,f=s+4|0,d=n[f>>2]|0,B=s+8|0;do if(d>>>0<(n[B>>2]|0)>>>0){if((l|0)==(d|0)){n[l>>2]=n[c>>2],n[f>>2]=(n[f>>2]|0)+4;break}_A(s,l,d,l+4|0),l>>>0<=c>>>0&&(c=(n[f>>2]|0)>>>0>c>>>0?c+4|0:c),n[l>>2]=n[c>>2]}else{f=(d-m>>2)+1|0,d=N(s)|0,d>>>0<f>>>0&&Jr(s),O=n[s>>2]|0,M=(n[B>>2]|0)-O|0,m=M>>1,Cp(Qe,M>>2>>>0<d>>>1>>>0?m>>>0<f>>>0?f:m:d,l-O>>2,s+8|0),O=Qe+8|0,f=n[O>>2]|0,m=Qe+12|0,M=n[m>>2]|0,B=M,Q=f;do if((f|0)==(M|0)){if(M=Qe+4|0,f=n[M>>2]|0,Xe=n[Qe>>2]|0,d=Xe,f>>>0<=Xe>>>0){f=B-d>>1,f=(f|0)==0?1:f,Cp(se,f,f>>>2,n[Qe+16>>2]|0),n[Ge>>2]=n[M>>2],n[Me>>2]=n[O>>2],n[k>>2]=n[Ge>>2],n[q>>2]=n[Me>>2],Bw(se,k,q),f=n[Qe>>2]|0,n[Qe>>2]=n[se>>2],n[se>>2]=f,f=se+4|0,Xe=n[M>>2]|0,n[M>>2]=n[f>>2],n[f>>2]=Xe,f=se+8|0,Xe=n[O>>2]|0,n[O>>2]=n[f>>2],n[f>>2]=Xe,f=se+12|0,Xe=n[m>>2]|0,n[m>>2]=n[f>>2],n[f>>2]=Xe,UA(se),f=n[O>>2]|0;break}m=f,B=((m-d>>2)+1|0)/-2|0,k=f+(B<<2)|0,d=Q-m|0,m=d>>2,m&&(Lw(k|0,f|0,d|0)|0,f=n[M>>2]|0),Xe=k+(m<<2)|0,n[O>>2]=Xe,n[M>>2]=f+(B<<2),f=Xe}while(0);n[f>>2]=n[c>>2],n[O>>2]=(n[O>>2]|0)+4,l=Ig(s,Qe,l)|0,UA(Qe)}while(0);return E=et,l|0}function Le(s){s=s|0;var l=0;do{if(l=s+984|0,o[l>>0]|0)break;o[l>>0]=1,h[s+504>>2]=y(Ae),s=n[s+944>>2]|0}while((s|0)!=0)}function ft(s){s=s|0;var l=0,c=0,f=0;c=n[s>>2]|0,f=c,c|0&&(s=s+4|0,l=n[s>>2]|0,(l|0)!=(c|0)&&(n[s>>2]=l+(~((l+-4-f|0)>>>2)<<2)),gt(c))}function pt(s){return s=s|0,n[s+944>>2]|0}function Tt(s){s=s|0,Un(s,(n[s+964>>2]|0)!=0,2832),Le(s)}function er(s){return s=s|0,(o[s+984>>0]|0)!=0|0}function Zr(s,l){s=s|0,l=l|0,LUe(s,l,400)|0&&(Dr(s|0,l|0,400)|0,Le(s))}function qi(s){s=s|0;var l=Ze;return l=y(h[s+44>>2]),s=_t(l)|0,y(s?y(0):l)}function es(s){s=s|0;var l=Ze;return l=y(h[s+48>>2]),_t(l)|0&&(l=o[(n[s+976>>2]|0)+2>>0]|0?y(1):y(0)),y(l)}function bi(s,l){s=s|0,l=l|0,n[s+980>>2]=l}function jo(s){return s=s|0,n[s+980>>2]|0}function xA(s,l){s=s|0,l=l|0;var c=0;c=s+4|0,(n[c>>2]|0)!=(l|0)&&(n[c>>2]=l,Le(s))}function kA(s){return s=s|0,n[s+4>>2]|0}function cp(s,l){s=s|0,l=l|0;var c=0;c=s+8|0,(n[c>>2]|0)!=(l|0)&&(n[c>>2]=l,Le(s))}function rg(s){return s=s|0,n[s+8>>2]|0}function gu(s,l){s=s|0,l=l|0;var c=0;c=s+12|0,(n[c>>2]|0)!=(l|0)&&(n[c>>2]=l,Le(s))}function ng(s){return s=s|0,n[s+12>>2]|0}function du(s,l){s=s|0,l=l|0;var c=0;c=s+16|0,(n[c>>2]|0)!=(l|0)&&(n[c>>2]=l,Le(s))}function uo(s){return s=s|0,n[s+16>>2]|0}function QA(s,l){s=s|0,l=l|0;var c=0;c=s+20|0,(n[c>>2]|0)!=(l|0)&&(n[c>>2]=l,Le(s))}function mc(s){return s=s|0,n[s+20>>2]|0}function ca(s,l){s=s|0,l=l|0;var c=0;c=s+24|0,(n[c>>2]|0)!=(l|0)&&(n[c>>2]=l,Le(s))}function ig(s){return s=s|0,n[s+24>>2]|0}function yc(s,l){s=s|0,l=l|0;var c=0;c=s+28|0,(n[c>>2]|0)!=(l|0)&&(n[c>>2]=l,Le(s))}function Dm(s){return s=s|0,n[s+28>>2]|0}function sg(s,l){s=s|0,l=l|0;var c=0;c=s+32|0,(n[c>>2]|0)!=(l|0)&&(n[c>>2]=l,Le(s))}function $n(s){return s=s|0,n[s+32>>2]|0}function up(s,l){s=s|0,l=l|0;var c=0;c=s+36|0,(n[c>>2]|0)!=(l|0)&&(n[c>>2]=l,Le(s))}function og(s){return s=s|0,n[s+36>>2]|0}function FA(s,l){s=s|0,l=y(l);var c=0;c=s+40|0,y(h[c>>2])!=l&&(h[c>>2]=l,Le(s))}function Hs(s,l){s=s|0,l=y(l);var c=0;c=s+44|0,y(h[c>>2])!=l&&(h[c>>2]=l,Le(s))}function mu(s,l){s=s|0,l=y(l);var c=0;c=s+48|0,y(h[c>>2])!=l&&(h[c>>2]=l,Le(s))}function Ha(s,l){s=s|0,l=y(l);var c=0,f=0,d=0,m=0;m=_t(l)|0,c=(m^1)&1,f=s+52|0,d=s+56|0,m|y(h[f>>2])==l&&(n[d>>2]|0)==(c|0)||(h[f>>2]=l,n[d>>2]=c,Le(s))}function Gi(s,l){s=s|0,l=y(l);var c=0,f=0;f=s+52|0,c=s+56|0,y(h[f>>2])==l&&(n[c>>2]|0)==2||(h[f>>2]=l,f=_t(l)|0,n[c>>2]=f?3:2,Le(s))}function ua(s,l){s=s|0,l=l|0;var c=0,f=0;f=l+52|0,c=n[f+4>>2]|0,l=s,n[l>>2]=n[f>>2],n[l+4>>2]=c}function yu(s,l,c){s=s|0,l=l|0,c=y(c);var f=0,d=0,m=0;m=_t(c)|0,f=(m^1)&1,d=s+132+(l<<3)|0,l=s+132+(l<<3)+4|0,m|y(h[d>>2])==c&&(n[l>>2]|0)==(f|0)||(h[d>>2]=c,n[l>>2]=f,Le(s))}function Es(s,l,c){s=s|0,l=l|0,c=y(c);var f=0,d=0,m=0;m=_t(c)|0,f=m?0:2,d=s+132+(l<<3)|0,l=s+132+(l<<3)+4|0,m|y(h[d>>2])==c&&(n[l>>2]|0)==(f|0)||(h[d>>2]=c,n[l>>2]=f,Le(s))}function Ec(s,l,c){s=s|0,l=l|0,c=c|0;var f=0;f=l+132+(c<<3)|0,l=n[f+4>>2]|0,c=s,n[c>>2]=n[f>>2],n[c+4>>2]=l}function Cc(s,l,c){s=s|0,l=l|0,c=y(c);var f=0,d=0,m=0;m=_t(c)|0,f=(m^1)&1,d=s+60+(l<<3)|0,l=s+60+(l<<3)+4|0,m|y(h[d>>2])==c&&(n[l>>2]|0)==(f|0)||(h[d>>2]=c,n[l>>2]=f,Le(s))}function G(s,l,c){s=s|0,l=l|0,c=y(c);var f=0,d=0,m=0;m=_t(c)|0,f=m?0:2,d=s+60+(l<<3)|0,l=s+60+(l<<3)+4|0,m|y(h[d>>2])==c&&(n[l>>2]|0)==(f|0)||(h[d>>2]=c,n[l>>2]=f,Le(s))}function Dt(s,l,c){s=s|0,l=l|0,c=c|0;var f=0;f=l+60+(c<<3)|0,l=n[f+4>>2]|0,c=s,n[c>>2]=n[f>>2],n[c+4>>2]=l}function wl(s,l){s=s|0,l=l|0;var c=0;c=s+60+(l<<3)+4|0,(n[c>>2]|0)!=3&&(h[s+60+(l<<3)>>2]=y(Ae),n[c>>2]=3,Le(s))}function xi(s,l,c){s=s|0,l=l|0,c=y(c);var f=0,d=0,m=0;m=_t(c)|0,f=(m^1)&1,d=s+204+(l<<3)|0,l=s+204+(l<<3)+4|0,m|y(h[d>>2])==c&&(n[l>>2]|0)==(f|0)||(h[d>>2]=c,n[l>>2]=f,Le(s))}function wc(s,l,c){s=s|0,l=l|0,c=y(c);var f=0,d=0,m=0;m=_t(c)|0,f=m?0:2,d=s+204+(l<<3)|0,l=s+204+(l<<3)+4|0,m|y(h[d>>2])==c&&(n[l>>2]|0)==(f|0)||(h[d>>2]=c,n[l>>2]=f,Le(s))}function ct(s,l,c){s=s|0,l=l|0,c=c|0;var f=0;f=l+204+(c<<3)|0,l=n[f+4>>2]|0,c=s,n[c>>2]=n[f>>2],n[c+4>>2]=l}function Eu(s,l,c){s=s|0,l=l|0,c=y(c);var f=0,d=0,m=0;m=_t(c)|0,f=(m^1)&1,d=s+276+(l<<3)|0,l=s+276+(l<<3)+4|0,m|y(h[d>>2])==c&&(n[l>>2]|0)==(f|0)||(h[d>>2]=c,n[l>>2]=f,Le(s))}function ag(s,l){return s=s|0,l=l|0,y(h[s+276+(l<<3)>>2])}function dw(s,l){s=s|0,l=y(l);var c=0,f=0,d=0,m=0;m=_t(l)|0,c=(m^1)&1,f=s+348|0,d=s+352|0,m|y(h[f>>2])==l&&(n[d>>2]|0)==(c|0)||(h[f>>2]=l,n[d>>2]=c,Le(s))}function RA(s,l){s=s|0,l=y(l);var c=0,f=0;f=s+348|0,c=s+352|0,y(h[f>>2])==l&&(n[c>>2]|0)==2||(h[f>>2]=l,f=_t(l)|0,n[c>>2]=f?3:2,Le(s))}function Ap(s){s=s|0;var l=0;l=s+352|0,(n[l>>2]|0)!=3&&(h[s+348>>2]=y(Ae),n[l>>2]=3,Le(s))}function Br(s,l){s=s|0,l=l|0;var c=0,f=0;f=l+348|0,c=n[f+4>>2]|0,l=s,n[l>>2]=n[f>>2],n[l+4>>2]=c}function Cs(s,l){s=s|0,l=y(l);var c=0,f=0,d=0,m=0;m=_t(l)|0,c=(m^1)&1,f=s+356|0,d=s+360|0,m|y(h[f>>2])==l&&(n[d>>2]|0)==(c|0)||(h[f>>2]=l,n[d>>2]=c,Le(s))}function lg(s,l){s=s|0,l=y(l);var c=0,f=0;f=s+356|0,c=s+360|0,y(h[f>>2])==l&&(n[c>>2]|0)==2||(h[f>>2]=l,f=_t(l)|0,n[c>>2]=f?3:2,Le(s))}function cg(s){s=s|0;var l=0;l=s+360|0,(n[l>>2]|0)!=3&&(h[s+356>>2]=y(Ae),n[l>>2]=3,Le(s))}function ug(s,l){s=s|0,l=l|0;var c=0,f=0;f=l+356|0,c=n[f+4>>2]|0,l=s,n[l>>2]=n[f>>2],n[l+4>>2]=c}function fp(s,l){s=s|0,l=y(l);var c=0,f=0,d=0,m=0;m=_t(l)|0,c=(m^1)&1,f=s+364|0,d=s+368|0,m|y(h[f>>2])==l&&(n[d>>2]|0)==(c|0)||(h[f>>2]=l,n[d>>2]=c,Le(s))}function Ic(s,l){s=s|0,l=y(l);var c=0,f=0,d=0,m=0;m=_t(l)|0,c=m?0:2,f=s+364|0,d=s+368|0,m|y(h[f>>2])==l&&(n[d>>2]|0)==(c|0)||(h[f>>2]=l,n[d>>2]=c,Le(s))}function Ct(s,l){s=s|0,l=l|0;var c=0,f=0;f=l+364|0,c=n[f+4>>2]|0,l=s,n[l>>2]=n[f>>2],n[l+4>>2]=c}function Pm(s,l){s=s|0,l=y(l);var c=0,f=0,d=0,m=0;m=_t(l)|0,c=(m^1)&1,f=s+372|0,d=s+376|0,m|y(h[f>>2])==l&&(n[d>>2]|0)==(c|0)||(h[f>>2]=l,n[d>>2]=c,Le(s))}function Ag(s,l){s=s|0,l=y(l);var c=0,f=0,d=0,m=0;m=_t(l)|0,c=m?0:2,f=s+372|0,d=s+376|0,m|y(h[f>>2])==l&&(n[d>>2]|0)==(c|0)||(h[f>>2]=l,n[d>>2]=c,Le(s))}function fg(s,l){s=s|0,l=l|0;var c=0,f=0;f=l+372|0,c=n[f+4>>2]|0,l=s,n[l>>2]=n[f>>2],n[l+4>>2]=c}function Cu(s,l){s=s|0,l=y(l);var c=0,f=0,d=0,m=0;m=_t(l)|0,c=(m^1)&1,f=s+380|0,d=s+384|0,m|y(h[f>>2])==l&&(n[d>>2]|0)==(c|0)||(h[f>>2]=l,n[d>>2]=c,Le(s))}function Sm(s,l){s=s|0,l=y(l);var c=0,f=0,d=0,m=0;m=_t(l)|0,c=m?0:2,f=s+380|0,d=s+384|0,m|y(h[f>>2])==l&&(n[d>>2]|0)==(c|0)||(h[f>>2]=l,n[d>>2]=c,Le(s))}function pg(s,l){s=s|0,l=l|0;var c=0,f=0;f=l+380|0,c=n[f+4>>2]|0,l=s,n[l>>2]=n[f>>2],n[l+4>>2]=c}function wu(s,l){s=s|0,l=y(l);var c=0,f=0,d=0,m=0;m=_t(l)|0,c=(m^1)&1,f=s+388|0,d=s+392|0,m|y(h[f>>2])==l&&(n[d>>2]|0)==(c|0)||(h[f>>2]=l,n[d>>2]=c,Le(s))}function mw(s,l){s=s|0,l=y(l);var c=0,f=0,d=0,m=0;m=_t(l)|0,c=m?0:2,f=s+388|0,d=s+392|0,m|y(h[f>>2])==l&&(n[d>>2]|0)==(c|0)||(h[f>>2]=l,n[d>>2]=c,Le(s))}function bm(s,l){s=s|0,l=l|0;var c=0,f=0;f=l+388|0,c=n[f+4>>2]|0,l=s,n[l>>2]=n[f>>2],n[l+4>>2]=c}function Aa(s,l){s=s|0,l=y(l);var c=0;c=s+396|0,y(h[c>>2])!=l&&(h[c>>2]=l,Le(s))}function Bc(s){return s=s|0,y(h[s+396>>2])}function Il(s){return s=s|0,y(h[s+400>>2])}function Iu(s){return s=s|0,y(h[s+404>>2])}function hg(s){return s=s|0,y(h[s+408>>2])}function TA(s){return s=s|0,y(h[s+412>>2])}function pp(s){return s=s|0,y(h[s+416>>2])}function ja(s){return s=s|0,y(h[s+420>>2])}function gg(s,l){switch(s=s|0,l=l|0,Un(s,(l|0)<6,2918),l|0){case 0:{l=(n[s+496>>2]|0)==2?5:4;break}case 2:{l=(n[s+496>>2]|0)==2?4:5;break}default:}return y(h[s+424+(l<<2)>>2])}function hp(s,l){switch(s=s|0,l=l|0,Un(s,(l|0)<6,2918),l|0){case 0:{l=(n[s+496>>2]|0)==2?5:4;break}case 2:{l=(n[s+496>>2]|0)==2?4:5;break}default:}return y(h[s+448+(l<<2)>>2])}function qo(s,l){switch(s=s|0,l=l|0,Un(s,(l|0)<6,2918),l|0){case 0:{l=(n[s+496>>2]|0)==2?5:4;break}case 2:{l=(n[s+496>>2]|0)==2?4:5;break}default:}return y(h[s+472+(l<<2)>>2])}function ws(s,l){s=s|0,l=l|0;var c=0,f=Ze;return c=n[s+4>>2]|0,(c|0)==(n[l+4>>2]|0)?c?(f=y(h[s>>2]),s=y(ne(y(f-y(h[l>>2]))))<y(999999974e-13)):s=1:s=0,s|0}function Ii(s,l){s=y(s),l=y(l);var c=0;return _t(s)|0?c=_t(l)|0:c=y(ne(y(s-l)))<y(999999974e-13),c|0}function xm(s,l){s=s|0,l=l|0,km(s,l)}function km(s,l){s=s|0,l=l|0;var c=0,f=0;c=E,E=E+16|0,f=c+4|0,n[f>>2]=0,n[f+4>>2]=0,n[f+8>>2]=0,Ma(f|0,s|0,l|0,0),Ao(s,3,(o[f+11>>0]|0)<0?n[f>>2]|0:f,c),s3e(f),E=c}function Go(s,l,c,f){s=y(s),l=y(l),c=c|0,f=f|0;var d=Ze;s=y(s*l),d=y(kR(s,y(1)));do if(Ii(d,y(0))|0)s=y(s-d);else{if(s=y(s-d),Ii(d,y(1))|0){s=y(s+y(1));break}if(c){s=y(s+y(1));break}f||(d>y(.5)?d=y(1):(f=Ii(d,y(.5))|0,d=y(f?1:0)),s=y(s+d))}while(0);return y(s/l)}function NA(s,l,c,f,d,m,B,k,Q,M,O,q,se){s=s|0,l=y(l),c=c|0,f=y(f),d=d|0,m=y(m),B=B|0,k=y(k),Q=y(Q),M=y(M),O=y(O),q=y(q),se=se|0;var Ge=0,Me=Ze,Qe=Ze,et=Ze,Xe=Ze,at=Ze,Ue=Ze;return Q<y(0)|M<y(0)?se=0:((se|0)!=0&&(Me=y(h[se+4>>2]),Me!=y(0))?(et=y(Go(l,Me,0,0)),Xe=y(Go(f,Me,0,0)),Qe=y(Go(m,Me,0,0)),Me=y(Go(k,Me,0,0))):(Qe=m,et=l,Me=k,Xe=f),(d|0)==(s|0)?Ge=Ii(Qe,et)|0:Ge=0,(B|0)==(c|0)?se=Ii(Me,Xe)|0:se=0,!Ge&&(at=y(l-O),!(gp(s,at,Q)|0))&&!(dp(s,at,d,Q)|0)?Ge=dg(s,at,d,m,Q)|0:Ge=1,!se&&(Ue=y(f-q),!(gp(c,Ue,M)|0))&&!(dp(c,Ue,B,M)|0)?se=dg(c,Ue,B,k,M)|0:se=1,se=Ge&se),se|0}function gp(s,l,c){return s=s|0,l=y(l),c=y(c),(s|0)==1?s=Ii(l,c)|0:s=0,s|0}function dp(s,l,c,f){return s=s|0,l=y(l),c=c|0,f=y(f),(s|0)==2&(c|0)==0?l>=f?s=1:s=Ii(l,f)|0:s=0,s|0}function dg(s,l,c,f,d){return s=s|0,l=y(l),c=c|0,f=y(f),d=y(d),(s|0)==2&(c|0)==2&f>l?d<=l?s=1:s=Ii(l,d)|0:s=0,s|0}function fa(s,l,c,f,d,m,B,k,Q,M,O){s=s|0,l=y(l),c=y(c),f=f|0,d=d|0,m=m|0,B=y(B),k=y(k),Q=Q|0,M=M|0,O=O|0;var q=0,se=0,Ge=0,Me=0,Qe=Ze,et=Ze,Xe=0,at=0,Ue=0,qe=0,Lt=0,Mr=0,or=0,Xt=0,Pr=0,Nr=0,ir=0,xn=Ze,go=Ze,mo=Ze,yo=0,ya=0;ir=E,E=E+160|0,Xt=ir+152|0,or=ir+120|0,Mr=ir+104|0,Ue=ir+72|0,Me=ir+56|0,Lt=ir+8|0,at=ir,qe=(n[2279]|0)+1|0,n[2279]=qe,Pr=s+984|0,(o[Pr>>0]|0)!=0&&(n[s+512>>2]|0)!=(n[2278]|0)?Xe=4:(n[s+516>>2]|0)==(f|0)?Nr=0:Xe=4,(Xe|0)==4&&(n[s+520>>2]=0,n[s+924>>2]=-1,n[s+928>>2]=-1,h[s+932>>2]=y(-1),h[s+936>>2]=y(-1),Nr=1);e:do if(n[s+964>>2]|0)if(Qe=y(ln(s,2,B)),et=y(ln(s,0,B)),q=s+916|0,mo=y(h[q>>2]),go=y(h[s+920>>2]),xn=y(h[s+932>>2]),NA(d,l,m,c,n[s+924>>2]|0,mo,n[s+928>>2]|0,go,xn,y(h[s+936>>2]),Qe,et,O)|0)Xe=22;else if(Ge=n[s+520>>2]|0,!Ge)Xe=21;else for(se=0;;){if(q=s+524+(se*24|0)|0,xn=y(h[q>>2]),go=y(h[s+524+(se*24|0)+4>>2]),mo=y(h[s+524+(se*24|0)+16>>2]),NA(d,l,m,c,n[s+524+(se*24|0)+8>>2]|0,xn,n[s+524+(se*24|0)+12>>2]|0,go,mo,y(h[s+524+(se*24|0)+20>>2]),Qe,et,O)|0){Xe=22;break e}if(se=se+1|0,se>>>0>=Ge>>>0){Xe=21;break}}else{if(Q){if(q=s+916|0,!(Ii(y(h[q>>2]),l)|0)){Xe=21;break}if(!(Ii(y(h[s+920>>2]),c)|0)){Xe=21;break}if((n[s+924>>2]|0)!=(d|0)){Xe=21;break}q=(n[s+928>>2]|0)==(m|0)?q:0,Xe=22;break}if(Ge=n[s+520>>2]|0,!Ge)Xe=21;else for(se=0;;){if(q=s+524+(se*24|0)|0,Ii(y(h[q>>2]),l)|0&&Ii(y(h[s+524+(se*24|0)+4>>2]),c)|0&&(n[s+524+(se*24|0)+8>>2]|0)==(d|0)&&(n[s+524+(se*24|0)+12>>2]|0)==(m|0)){Xe=22;break e}if(se=se+1|0,se>>>0>=Ge>>>0){Xe=21;break}}}while(0);do if((Xe|0)==21)o[11697]|0?(q=0,Xe=28):(q=0,Xe=31);else if((Xe|0)==22){if(se=(o[11697]|0)!=0,!((q|0)!=0&(Nr^1)))if(se){Xe=28;break}else{Xe=31;break}Me=q+16|0,n[s+908>>2]=n[Me>>2],Ge=q+20|0,n[s+912>>2]=n[Ge>>2],(o[11698]|0)==0|se^1||(n[at>>2]=LA(qe)|0,n[at+4>>2]=qe,Ao(s,4,2972,at),se=n[s+972>>2]|0,se|0&&ef[se&127](s),d=qa(d,Q)|0,m=qa(m,Q)|0,ya=+y(h[Me>>2]),yo=+y(h[Ge>>2]),n[Lt>>2]=d,n[Lt+4>>2]=m,C[Lt+8>>3]=+l,C[Lt+16>>3]=+c,C[Lt+24>>3]=ya,C[Lt+32>>3]=yo,n[Lt+40>>2]=M,Ao(s,4,2989,Lt))}while(0);return(Xe|0)==28&&(se=LA(qe)|0,n[Me>>2]=se,n[Me+4>>2]=qe,n[Me+8>>2]=Nr?3047:11699,Ao(s,4,3038,Me),se=n[s+972>>2]|0,se|0&&ef[se&127](s),Lt=qa(d,Q)|0,Xe=qa(m,Q)|0,n[Ue>>2]=Lt,n[Ue+4>>2]=Xe,C[Ue+8>>3]=+l,C[Ue+16>>3]=+c,n[Ue+24>>2]=M,Ao(s,4,3049,Ue),Xe=31),(Xe|0)==31&&(si(s,l,c,f,d,m,B,k,Q,O),o[11697]|0&&(se=n[2279]|0,Lt=LA(se)|0,n[Mr>>2]=Lt,n[Mr+4>>2]=se,n[Mr+8>>2]=Nr?3047:11699,Ao(s,4,3083,Mr),se=n[s+972>>2]|0,se|0&&ef[se&127](s),Lt=qa(d,Q)|0,Mr=qa(m,Q)|0,yo=+y(h[s+908>>2]),ya=+y(h[s+912>>2]),n[or>>2]=Lt,n[or+4>>2]=Mr,C[or+8>>3]=yo,C[or+16>>3]=ya,n[or+24>>2]=M,Ao(s,4,3092,or)),n[s+516>>2]=f,q||(se=s+520|0,q=n[se>>2]|0,(q|0)==16&&(o[11697]|0&&Ao(s,4,3124,Xt),n[se>>2]=0,q=0),Q?q=s+916|0:(n[se>>2]=q+1,q=s+524+(q*24|0)|0),h[q>>2]=l,h[q+4>>2]=c,n[q+8>>2]=d,n[q+12>>2]=m,n[q+16>>2]=n[s+908>>2],n[q+20>>2]=n[s+912>>2],q=0)),Q&&(n[s+416>>2]=n[s+908>>2],n[s+420>>2]=n[s+912>>2],o[s+985>>0]=1,o[Pr>>0]=0),n[2279]=(n[2279]|0)+-1,n[s+512>>2]=n[2278],E=ir,Nr|(q|0)==0|0}function ln(s,l,c){s=s|0,l=l|0,c=y(c);var f=Ze;return f=y(K(s,l,c)),y(f+y(re(s,l,c)))}function Ao(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0,m=0;m=E,E=E+16|0,d=m,n[d>>2]=f,s?f=n[s+976>>2]|0:f=0,yg(f,s,l,c,d),E=m}function LA(s){return s=s|0,(s>>>0>60?3201:3201+(60-s)|0)|0}function qa(s,l){s=s|0,l=l|0;var c=0,f=0,d=0;return d=E,E=E+32|0,c=d+12|0,f=d,n[c>>2]=n[254],n[c+4>>2]=n[255],n[c+8>>2]=n[256],n[f>>2]=n[257],n[f+4>>2]=n[258],n[f+8>>2]=n[259],(s|0)>2?s=11699:s=n[(l?f:c)+(s<<2)>>2]|0,E=d,s|0}function si(s,l,c,f,d,m,B,k,Q,M){s=s|0,l=y(l),c=y(c),f=f|0,d=d|0,m=m|0,B=y(B),k=y(k),Q=Q|0,M=M|0;var O=0,q=0,se=0,Ge=0,Me=Ze,Qe=Ze,et=Ze,Xe=Ze,at=Ze,Ue=Ze,qe=Ze,Lt=0,Mr=0,or=0,Xt=Ze,Pr=Ze,Nr=0,ir=Ze,xn=0,go=0,mo=0,yo=0,ya=0,kp=0,Qp=0,bl=0,Fp=0,Fu=0,Ru=0,Rp=0,Tp=0,Np=0,Xr=0,xl=0,Lp=0,xc=0,Op=Ze,Mp=Ze,Tu=Ze,Nu=Ze,kc=Ze,qs=0,Ja=0,Wo=0,kl=0,rf=0,nf=Ze,Lu=Ze,sf=Ze,of=Ze,Gs=Ze,vs=Ze,Ql=0,Rn=Ze,af=Ze,Eo=Ze,Qc=Ze,Co=Ze,Fc=Ze,lf=0,cf=0,Rc=Ze,Ys=Ze,Fl=0,uf=0,Af=0,ff=0,xr=Ze,zn=0,Ds=0,wo=0,Ws=0,Rr=0,ur=0,Rl=0,zt=Ze,pf=0,li=0;Rl=E,E=E+16|0,qs=Rl+12|0,Ja=Rl+8|0,Wo=Rl+4|0,kl=Rl,Un(s,(d|0)==0|(_t(l)|0)^1,3326),Un(s,(m|0)==0|(_t(c)|0)^1,3406),Ds=mt(s,f)|0,n[s+496>>2]=Ds,Rr=fr(2,Ds)|0,ur=fr(0,Ds)|0,h[s+440>>2]=y(K(s,Rr,B)),h[s+444>>2]=y(re(s,Rr,B)),h[s+428>>2]=y(K(s,ur,B)),h[s+436>>2]=y(re(s,ur,B)),h[s+464>>2]=y(Cr(s,Rr)),h[s+468>>2]=y(yn(s,Rr)),h[s+452>>2]=y(Cr(s,ur)),h[s+460>>2]=y(yn(s,ur)),h[s+488>>2]=y(oi(s,Rr,B)),h[s+492>>2]=y(Oi(s,Rr,B)),h[s+476>>2]=y(oi(s,ur,B)),h[s+484>>2]=y(Oi(s,ur,B));do if(n[s+964>>2]|0)Cg(s,l,c,d,m,B,k);else{if(wo=s+948|0,Ws=(n[s+952>>2]|0)-(n[wo>>2]|0)>>2,!Ws){Gv(s,l,c,d,m,B,k);break}if(!Q&&Yv(s,l,c,d,m,B,k)|0)break;$(s),xl=s+508|0,o[xl>>0]=0,Rr=fr(n[s+4>>2]|0,Ds)|0,ur=Ew(Rr,Ds)|0,zn=pe(Rr)|0,Lp=n[s+8>>2]|0,uf=s+28|0,xc=(n[uf>>2]|0)!=0,Co=zn?B:k,Rc=zn?k:B,Op=y(yp(s,Rr,B)),Mp=y(Cw(s,Rr,B)),Me=y(yp(s,ur,B)),Fc=y(En(s,Rr,B)),Ys=y(En(s,ur,B)),or=zn?d:m,Fl=zn?m:d,xr=zn?Fc:Ys,at=zn?Ys:Fc,Qc=y(ln(s,2,B)),Xe=y(ln(s,0,B)),Qe=y(y(Gr(s+364|0,B))-xr),et=y(y(Gr(s+380|0,B))-xr),Ue=y(y(Gr(s+372|0,k))-at),qe=y(y(Gr(s+388|0,k))-at),Tu=zn?Qe:Ue,Nu=zn?et:qe,Qc=y(l-Qc),l=y(Qc-xr),_t(l)|0?xr=l:xr=y(_n(y(Fg(l,et)),Qe)),af=y(c-Xe),l=y(af-at),_t(l)|0?Eo=l:Eo=y(_n(y(Fg(l,qe)),Ue)),Qe=zn?xr:Eo,Rn=zn?Eo:xr;e:do if((or|0)==1)for(f=0,q=0;;){if(O=gs(s,q)|0,!f)y(rs(O))>y(0)&&y(js(O))>y(0)?f=O:f=0;else if(Fm(O)|0){Ge=0;break e}if(q=q+1|0,q>>>0>=Ws>>>0){Ge=f;break}}else Ge=0;while(0);Lt=Ge+500|0,Mr=Ge+504|0,f=0,O=0,l=y(0),se=0;do{if(q=n[(n[wo>>2]|0)+(se<<2)>>2]|0,(n[q+36>>2]|0)==1)Bu(q),o[q+985>>0]=1,o[q+984>>0]=0;else{Bl(q),Q&&mp(q,mt(q,Ds)|0,Qe,Rn,xr);do if((n[q+24>>2]|0)!=1)if((q|0)==(Ge|0)){n[Lt>>2]=n[2278],h[Mr>>2]=y(0);break}else{Rm(s,q,xr,d,Eo,xr,Eo,m,Ds,M);break}else O|0&&(n[O+960>>2]=q),n[q+960>>2]=0,O=q,f=(f|0)==0?q:f;while(0);vs=y(h[q+504>>2]),l=y(l+y(vs+y(ln(q,Rr,xr))))}se=se+1|0}while((se|0)!=(Ws|0));for(mo=l>Qe,Ql=xc&((or|0)==2&mo)?1:or,xn=(Fl|0)==1,ya=xn&(Q^1),kp=(Ql|0)==1,Qp=(Ql|0)==2,bl=976+(Rr<<2)|0,Fp=(Fl|2|0)==2,Np=xn&(xc^1),Fu=1040+(ur<<2)|0,Ru=1040+(Rr<<2)|0,Rp=976+(ur<<2)|0,Tp=(Fl|0)!=1,mo=xc&((or|0)!=0&mo),go=s+976|0,xn=xn^1,l=Qe,Nr=0,yo=0,vs=y(0),kc=y(0);;){e:do if(Nr>>>0<Ws>>>0)for(Mr=n[wo>>2]|0,se=0,qe=y(0),Ue=y(0),et=y(0),Qe=y(0),q=0,O=0,Ge=Nr;;){if(Lt=n[Mr+(Ge<<2)>>2]|0,(n[Lt+36>>2]|0)!=1&&(n[Lt+940>>2]=yo,(n[Lt+24>>2]|0)!=1)){if(Xe=y(ln(Lt,Rr,xr)),Xr=n[bl>>2]|0,c=y(Gr(Lt+380+(Xr<<3)|0,Co)),at=y(h[Lt+504>>2]),c=y(Fg(c,at)),c=y(_n(y(Gr(Lt+364+(Xr<<3)|0,Co)),c)),xc&(se|0)!=0&y(Xe+y(Ue+c))>l){m=se,Xe=qe,or=Ge;break e}Xe=y(Xe+c),c=y(Ue+Xe),Xe=y(qe+Xe),Fm(Lt)|0&&(et=y(et+y(rs(Lt))),Qe=y(Qe-y(at*y(js(Lt))))),O|0&&(n[O+960>>2]=Lt),n[Lt+960>>2]=0,se=se+1|0,O=Lt,q=(q|0)==0?Lt:q}else Xe=qe,c=Ue;if(Ge=Ge+1|0,Ge>>>0<Ws>>>0)qe=Xe,Ue=c;else{m=se,or=Ge;break}}else m=0,Xe=y(0),et=y(0),Qe=y(0),q=0,or=Nr;while(0);Xr=et>y(0)&et<y(1),Xt=Xr?y(1):et,Xr=Qe>y(0)&Qe<y(1),qe=Xr?y(1):Qe;do if(kp)Xr=51;else if(Xe<Tu&((_t(Tu)|0)^1))l=Tu,Xr=51;else if(Xe>Nu&((_t(Nu)|0)^1))l=Nu,Xr=51;else if(o[(n[go>>2]|0)+3>>0]|0)Xr=51;else{if(Xt!=y(0)&&y(rs(s))!=y(0)){Xr=53;break}l=Xe,Xr=53}while(0);if((Xr|0)==51&&(Xr=0,_t(l)|0?Xr=53:(Pr=y(l-Xe),ir=l)),(Xr|0)==53&&(Xr=0,Xe<y(0)?(Pr=y(-Xe),ir=l):(Pr=y(0),ir=l)),!ya&&(rf=(q|0)==0,!rf)){se=n[bl>>2]|0,Ge=Pr<y(0),at=y(Pr/qe),Lt=Pr>y(0),Ue=y(Pr/Xt),et=y(0),Xe=y(0),l=y(0),O=q;do c=y(Gr(O+380+(se<<3)|0,Co)),Qe=y(Gr(O+364+(se<<3)|0,Co)),Qe=y(Fg(c,y(_n(Qe,y(h[O+504>>2]))))),Ge?(c=y(Qe*y(js(O))),c!=y(-0)&&(zt=y(Qe-y(at*c)),nf=y(Bi(O,Rr,zt,ir,xr)),zt!=nf)&&(et=y(et-y(nf-Qe)),l=y(l+c))):Lt&&(Lu=y(rs(O)),Lu!=y(0))&&(zt=y(Qe+y(Ue*Lu)),sf=y(Bi(O,Rr,zt,ir,xr)),zt!=sf)&&(et=y(et-y(sf-Qe)),Xe=y(Xe-Lu)),O=n[O+960>>2]|0;while((O|0)!=0);if(l=y(qe+l),Qe=y(Pr+et),rf)l=y(0);else{at=y(Xt+Xe),Ge=n[bl>>2]|0,Lt=Qe<y(0),Mr=l==y(0),Ue=y(Qe/l),se=Qe>y(0),at=y(Qe/at),l=y(0);do{zt=y(Gr(q+380+(Ge<<3)|0,Co)),et=y(Gr(q+364+(Ge<<3)|0,Co)),et=y(Fg(zt,y(_n(et,y(h[q+504>>2]))))),Lt?(zt=y(et*y(js(q))),Qe=y(-zt),zt!=y(-0)?(zt=y(Ue*Qe),Qe=y(Bi(q,Rr,y(et+(Mr?Qe:zt)),ir,xr))):Qe=et):se&&(of=y(rs(q)),of!=y(0))?Qe=y(Bi(q,Rr,y(et+y(at*of)),ir,xr)):Qe=et,l=y(l-y(Qe-et)),Xe=y(ln(q,Rr,xr)),c=y(ln(q,ur,xr)),Qe=y(Qe+Xe),h[Ja>>2]=Qe,n[kl>>2]=1,et=y(h[q+396>>2]);e:do if(_t(et)|0){O=_t(Rn)|0;do if(!O){if(mo|(ts(q,ur,Rn)|0|xn)||(ha(s,q)|0)!=4||(n[(vl(q,ur)|0)+4>>2]|0)==3||(n[(Pc(q,ur)|0)+4>>2]|0)==3)break;h[qs>>2]=Rn,n[Wo>>2]=1;break e}while(0);if(ts(q,ur,Rn)|0){O=n[q+992+(n[Rp>>2]<<2)>>2]|0,zt=y(c+y(Gr(O,Rn))),h[qs>>2]=zt,O=Tp&(n[O+4>>2]|0)==2,n[Wo>>2]=((_t(zt)|0|O)^1)&1;break}else{h[qs>>2]=Rn,n[Wo>>2]=O?0:2;break}}else zt=y(Qe-Xe),Xt=y(zt/et),zt=y(et*zt),n[Wo>>2]=1,h[qs>>2]=y(c+(zn?Xt:zt));while(0);yr(q,Rr,ir,xr,kl,Ja),yr(q,ur,Rn,xr,Wo,qs);do if(!(ts(q,ur,Rn)|0)&&(ha(s,q)|0)==4){if((n[(vl(q,ur)|0)+4>>2]|0)==3){O=0;break}O=(n[(Pc(q,ur)|0)+4>>2]|0)!=3}else O=0;while(0);zt=y(h[Ja>>2]),Xt=y(h[qs>>2]),pf=n[kl>>2]|0,li=n[Wo>>2]|0,fa(q,zn?zt:Xt,zn?Xt:zt,Ds,zn?pf:li,zn?li:pf,xr,Eo,Q&(O^1),3488,M)|0,o[xl>>0]=o[xl>>0]|o[q+508>>0],q=n[q+960>>2]|0}while((q|0)!=0)}}else l=y(0);if(l=y(Pr+l),li=l<y(0)&1,o[xl>>0]=li|u[xl>>0],Qp&l>y(0)?(O=n[bl>>2]|0,(n[s+364+(O<<3)+4>>2]|0)!=0&&(Gs=y(Gr(s+364+(O<<3)|0,Co)),Gs>=y(0))?Qe=y(_n(y(0),y(Gs-y(ir-l)))):Qe=y(0)):Qe=l,Lt=Nr>>>0<or>>>0,Lt){Ge=n[wo>>2]|0,se=Nr,O=0;do q=n[Ge+(se<<2)>>2]|0,n[q+24>>2]|0||(O=((n[(vl(q,Rr)|0)+4>>2]|0)==3&1)+O|0,O=O+((n[(Pc(q,Rr)|0)+4>>2]|0)==3&1)|0),se=se+1|0;while((se|0)!=(or|0));O?(Xe=y(0),c=y(0)):Xr=101}else Xr=101;e:do if((Xr|0)==101)switch(Xr=0,Lp|0){case 1:{O=0,Xe=y(Qe*y(.5)),c=y(0);break e}case 2:{O=0,Xe=Qe,c=y(0);break e}case 3:{if(m>>>0<=1){O=0,Xe=y(0),c=y(0);break e}c=y((m+-1|0)>>>0),O=0,Xe=y(0),c=y(y(_n(Qe,y(0)))/c);break e}case 5:{c=y(Qe/y((m+1|0)>>>0)),O=0,Xe=c;break e}case 4:{c=y(Qe/y(m>>>0)),O=0,Xe=y(c*y(.5));break e}default:{O=0,Xe=y(0),c=y(0);break e}}while(0);if(l=y(Op+Xe),Lt){et=y(Qe/y(O|0)),se=n[wo>>2]|0,q=Nr,Qe=y(0);do{O=n[se+(q<<2)>>2]|0;e:do if((n[O+36>>2]|0)!=1){switch(n[O+24>>2]|0){case 1:{if(gi(O,Rr)|0){if(!Q)break e;zt=y(Or(O,Rr,ir)),zt=y(zt+y(Cr(s,Rr))),zt=y(zt+y(K(O,Rr,xr))),h[O+400+(n[Ru>>2]<<2)>>2]=zt;break e}break}case 0:if(li=(n[(vl(O,Rr)|0)+4>>2]|0)==3,zt=y(et+l),l=li?zt:l,Q&&(li=O+400+(n[Ru>>2]<<2)|0,h[li>>2]=y(l+y(h[li>>2]))),li=(n[(Pc(O,Rr)|0)+4>>2]|0)==3,zt=y(et+l),l=li?zt:l,ya){zt=y(c+y(ln(O,Rr,xr))),Qe=Rn,l=y(l+y(zt+y(h[O+504>>2])));break e}else{l=y(l+y(c+y(ns(O,Rr,xr)))),Qe=y(_n(Qe,y(ns(O,ur,xr))));break e}default:}Q&&(zt=y(Xe+y(Cr(s,Rr))),li=O+400+(n[Ru>>2]<<2)|0,h[li>>2]=y(zt+y(h[li>>2])))}while(0);q=q+1|0}while((q|0)!=(or|0))}else Qe=y(0);if(c=y(Mp+l),Fp?Xe=y(y(Bi(s,ur,y(Ys+Qe),Rc,B))-Ys):Xe=Rn,et=y(y(Bi(s,ur,y(Ys+(Np?Rn:Qe)),Rc,B))-Ys),Lt&Q){q=Nr;do{se=n[(n[wo>>2]|0)+(q<<2)>>2]|0;do if((n[se+36>>2]|0)!=1){if((n[se+24>>2]|0)==1){if(gi(se,ur)|0){if(zt=y(Or(se,ur,Rn)),zt=y(zt+y(Cr(s,ur))),zt=y(zt+y(K(se,ur,xr))),O=n[Fu>>2]|0,h[se+400+(O<<2)>>2]=zt,!(_t(zt)|0))break}else O=n[Fu>>2]|0;zt=y(Cr(s,ur)),h[se+400+(O<<2)>>2]=y(zt+y(K(se,ur,xr)));break}O=ha(s,se)|0;do if((O|0)==4){if((n[(vl(se,ur)|0)+4>>2]|0)==3){Xr=139;break}if((n[(Pc(se,ur)|0)+4>>2]|0)==3){Xr=139;break}if(ts(se,ur,Rn)|0){l=Me;break}pf=n[se+908+(n[bl>>2]<<2)>>2]|0,n[qs>>2]=pf,l=y(h[se+396>>2]),li=_t(l)|0,Qe=(n[v>>2]=pf,y(h[v>>2])),li?l=et:(Pr=y(ln(se,ur,xr)),zt=y(Qe/l),l=y(l*Qe),l=y(Pr+(zn?zt:l))),h[Ja>>2]=l,h[qs>>2]=y(y(ln(se,Rr,xr))+Qe),n[Wo>>2]=1,n[kl>>2]=1,yr(se,Rr,ir,xr,Wo,qs),yr(se,ur,Rn,xr,kl,Ja),l=y(h[qs>>2]),Pr=y(h[Ja>>2]),zt=zn?l:Pr,l=zn?Pr:l,li=((_t(zt)|0)^1)&1,fa(se,zt,l,Ds,li,((_t(l)|0)^1)&1,xr,Eo,1,3493,M)|0,l=Me}else Xr=139;while(0);e:do if((Xr|0)==139){Xr=0,l=y(Xe-y(ns(se,ur,xr)));do if((n[(vl(se,ur)|0)+4>>2]|0)==3){if((n[(Pc(se,ur)|0)+4>>2]|0)!=3)break;l=y(Me+y(_n(y(0),y(l*y(.5)))));break e}while(0);if((n[(Pc(se,ur)|0)+4>>2]|0)==3){l=Me;break}if((n[(vl(se,ur)|0)+4>>2]|0)==3){l=y(Me+y(_n(y(0),l)));break}switch(O|0){case 1:{l=Me;break e}case 2:{l=y(Me+y(l*y(.5)));break e}default:{l=y(Me+l);break e}}}while(0);zt=y(vs+l),li=se+400+(n[Fu>>2]<<2)|0,h[li>>2]=y(zt+y(h[li>>2]))}while(0);q=q+1|0}while((q|0)!=(or|0))}if(vs=y(vs+et),kc=y(_n(kc,c)),m=yo+1|0,or>>>0>=Ws>>>0)break;l=ir,Nr=or,yo=m}do if(Q){if(O=m>>>0>1,!O&&!(Yi(s)|0))break;if(!(_t(Rn)|0)){l=y(Rn-vs);e:do switch(n[s+12>>2]|0){case 3:{Me=y(Me+l),Ue=y(0);break}case 2:{Me=y(Me+y(l*y(.5))),Ue=y(0);break}case 4:{Rn>vs?Ue=y(l/y(m>>>0)):Ue=y(0);break}case 7:if(Rn>vs){Me=y(Me+y(l/y(m<<1>>>0))),Ue=y(l/y(m>>>0)),Ue=O?Ue:y(0);break e}else{Me=y(Me+y(l*y(.5))),Ue=y(0);break e}case 6:{Ue=y(l/y(yo>>>0)),Ue=Rn>vs&O?Ue:y(0);break}default:Ue=y(0)}while(0);if(m|0)for(Lt=1040+(ur<<2)|0,Mr=976+(ur<<2)|0,Ge=0,q=0;;){e:do if(q>>>0<Ws>>>0)for(Qe=y(0),et=y(0),l=y(0),se=q;;){O=n[(n[wo>>2]|0)+(se<<2)>>2]|0;do if((n[O+36>>2]|0)!=1&&(n[O+24>>2]|0)==0){if((n[O+940>>2]|0)!=(Ge|0))break e;if(Tm(O,ur)|0&&(zt=y(h[O+908+(n[Mr>>2]<<2)>>2]),l=y(_n(l,y(zt+y(ln(O,ur,xr)))))),(ha(s,O)|0)!=5)break;Gs=y(Ya(O)),Gs=y(Gs+y(K(O,0,xr))),zt=y(h[O+912>>2]),zt=y(y(zt+y(ln(O,0,xr)))-Gs),Gs=y(_n(et,Gs)),zt=y(_n(Qe,zt)),Qe=zt,et=Gs,l=y(_n(l,y(Gs+zt)))}while(0);if(O=se+1|0,O>>>0<Ws>>>0)se=O;else{se=O;break}}else et=y(0),l=y(0),se=q;while(0);if(at=y(Ue+l),c=Me,Me=y(Me+at),q>>>0<se>>>0){Xe=y(c+et),O=q;do{q=n[(n[wo>>2]|0)+(O<<2)>>2]|0;e:do if((n[q+36>>2]|0)!=1&&(n[q+24>>2]|0)==0)switch(ha(s,q)|0){case 1:{zt=y(c+y(K(q,ur,xr))),h[q+400+(n[Lt>>2]<<2)>>2]=zt;break e}case 3:{zt=y(y(Me-y(re(q,ur,xr)))-y(h[q+908+(n[Mr>>2]<<2)>>2])),h[q+400+(n[Lt>>2]<<2)>>2]=zt;break e}case 2:{zt=y(c+y(y(at-y(h[q+908+(n[Mr>>2]<<2)>>2]))*y(.5))),h[q+400+(n[Lt>>2]<<2)>>2]=zt;break e}case 4:{if(zt=y(c+y(K(q,ur,xr))),h[q+400+(n[Lt>>2]<<2)>>2]=zt,ts(q,ur,Rn)|0||(zn?(Qe=y(h[q+908>>2]),l=y(Qe+y(ln(q,Rr,xr))),et=at):(et=y(h[q+912>>2]),et=y(et+y(ln(q,ur,xr))),l=at,Qe=y(h[q+908>>2])),Ii(l,Qe)|0&&Ii(et,y(h[q+912>>2]))|0))break e;fa(q,l,et,Ds,1,1,xr,Eo,1,3501,M)|0;break e}case 5:{h[q+404>>2]=y(y(Xe-y(Ya(q)))+y(Or(q,0,Rn)));break e}default:break e}while(0);O=O+1|0}while((O|0)!=(se|0))}if(Ge=Ge+1|0,(Ge|0)==(m|0))break;q=se}}}while(0);if(h[s+908>>2]=y(Bi(s,2,Qc,B,B)),h[s+912>>2]=y(Bi(s,0,af,k,B)),(Ql|0)!=0&&(lf=n[s+32>>2]|0,cf=(Ql|0)==2,!(cf&(lf|0)!=2))?cf&(lf|0)==2&&(l=y(Fc+ir),l=y(_n(y(Fg(l,y(OA(s,Rr,kc,Co)))),Fc)),Xr=198):(l=y(Bi(s,Rr,kc,Co,B)),Xr=198),(Xr|0)==198&&(h[s+908+(n[976+(Rr<<2)>>2]<<2)>>2]=l),(Fl|0)!=0&&(Af=n[s+32>>2]|0,ff=(Fl|0)==2,!(ff&(Af|0)!=2))?ff&(Af|0)==2&&(l=y(Ys+Rn),l=y(_n(y(Fg(l,y(OA(s,ur,y(Ys+vs),Rc)))),Ys)),Xr=204):(l=y(Bi(s,ur,y(Ys+vs),Rc,B)),Xr=204),(Xr|0)==204&&(h[s+908+(n[976+(ur<<2)>>2]<<2)>>2]=l),Q){if((n[uf>>2]|0)==2){q=976+(ur<<2)|0,se=1040+(ur<<2)|0,O=0;do Ge=gs(s,O)|0,n[Ge+24>>2]|0||(pf=n[q>>2]|0,zt=y(h[s+908+(pf<<2)>>2]),li=Ge+400+(n[se>>2]<<2)|0,zt=y(zt-y(h[li>>2])),h[li>>2]=y(zt-y(h[Ge+908+(pf<<2)>>2]))),O=O+1|0;while((O|0)!=(Ws|0))}if(f|0){O=zn?Ql:d;do Nm(s,f,xr,O,Eo,Ds,M),f=n[f+960>>2]|0;while((f|0)!=0)}if(O=(Rr|2|0)==3,q=(ur|2|0)==3,O|q){f=0;do se=n[(n[wo>>2]|0)+(f<<2)>>2]|0,(n[se+36>>2]|0)!=1&&(O&&Ep(s,se,Rr),q&&Ep(s,se,ur)),f=f+1|0;while((f|0)!=(Ws|0))}}}while(0);E=Rl}function pa(s,l){s=s|0,l=y(l);var c=0;oa(s,l>=y(0),3147),c=l==y(0),h[s+4>>2]=c?y(0):l}function vc(s,l,c,f){s=s|0,l=y(l),c=y(c),f=f|0;var d=Ze,m=Ze,B=0,k=0,Q=0;n[2278]=(n[2278]|0)+1,Bl(s),ts(s,2,l)|0?(d=y(Gr(n[s+992>>2]|0,l)),Q=1,d=y(d+y(ln(s,2,l)))):(d=y(Gr(s+380|0,l)),d>=y(0)?Q=2:(Q=((_t(l)|0)^1)&1,d=l)),ts(s,0,c)|0?(m=y(Gr(n[s+996>>2]|0,c)),k=1,m=y(m+y(ln(s,0,l)))):(m=y(Gr(s+388|0,c)),m>=y(0)?k=2:(k=((_t(c)|0)^1)&1,m=c)),B=s+976|0,fa(s,d,m,f,Q,k,l,c,1,3189,n[B>>2]|0)|0&&(mp(s,n[s+496>>2]|0,l,c,l),Dc(s,y(h[(n[B>>2]|0)+4>>2]),y(0),y(0)),o[11696]|0)&&xm(s,7)}function Bl(s){s=s|0;var l=0,c=0,f=0,d=0,m=0,B=0,k=0,Q=0,M=0,O=0;k=E,E=E+32|0,B=k+24|0,m=k+16|0,f=k+8|0,d=k,c=0;do l=s+380+(c<<3)|0,(n[s+380+(c<<3)+4>>2]|0)!=0&&(Q=l,M=n[Q+4>>2]|0,O=f,n[O>>2]=n[Q>>2],n[O+4>>2]=M,O=s+364+(c<<3)|0,M=n[O+4>>2]|0,Q=d,n[Q>>2]=n[O>>2],n[Q+4>>2]=M,n[m>>2]=n[f>>2],n[m+4>>2]=n[f+4>>2],n[B>>2]=n[d>>2],n[B+4>>2]=n[d+4>>2],ws(m,B)|0)||(l=s+348+(c<<3)|0),n[s+992+(c<<2)>>2]=l,c=c+1|0;while((c|0)!=2);E=k}function ts(s,l,c){s=s|0,l=l|0,c=y(c);var f=0;switch(s=n[s+992+(n[976+(l<<2)>>2]<<2)>>2]|0,n[s+4>>2]|0){case 0:case 3:{s=0;break}case 1:{y(h[s>>2])<y(0)?s=0:f=5;break}case 2:{y(h[s>>2])<y(0)?s=0:s=(_t(c)|0)^1;break}default:f=5}return(f|0)==5&&(s=1),s|0}function Gr(s,l){switch(s=s|0,l=y(l),n[s+4>>2]|0){case 2:{l=y(y(y(h[s>>2])*l)/y(100));break}case 1:{l=y(h[s>>2]);break}default:l=y(Ae)}return y(l)}function mp(s,l,c,f,d){s=s|0,l=l|0,c=y(c),f=y(f),d=y(d);var m=0,B=Ze;l=n[s+944>>2]|0?l:1,m=fr(n[s+4>>2]|0,l)|0,l=Ew(m,l)|0,c=y(Lm(s,m,c)),f=y(Lm(s,l,f)),B=y(c+y(K(s,m,d))),h[s+400+(n[1040+(m<<2)>>2]<<2)>>2]=B,c=y(c+y(re(s,m,d))),h[s+400+(n[1e3+(m<<2)>>2]<<2)>>2]=c,c=y(f+y(K(s,l,d))),h[s+400+(n[1040+(l<<2)>>2]<<2)>>2]=c,d=y(f+y(re(s,l,d))),h[s+400+(n[1e3+(l<<2)>>2]<<2)>>2]=d}function Dc(s,l,c,f){s=s|0,l=y(l),c=y(c),f=y(f);var d=0,m=0,B=Ze,k=Ze,Q=0,M=0,O=Ze,q=0,se=Ze,Ge=Ze,Me=Ze,Qe=Ze;if(l!=y(0)&&(d=s+400|0,Qe=y(h[d>>2]),m=s+404|0,Me=y(h[m>>2]),q=s+416|0,Ge=y(h[q>>2]),M=s+420|0,B=y(h[M>>2]),se=y(Qe+c),O=y(Me+f),f=y(se+Ge),k=y(O+B),Q=(n[s+988>>2]|0)==1,h[d>>2]=y(Go(Qe,l,0,Q)),h[m>>2]=y(Go(Me,l,0,Q)),c=y(kR(y(Ge*l),y(1))),Ii(c,y(0))|0?m=0:m=(Ii(c,y(1))|0)^1,c=y(kR(y(B*l),y(1))),Ii(c,y(0))|0?d=0:d=(Ii(c,y(1))|0)^1,Qe=y(Go(f,l,Q&m,Q&(m^1))),h[q>>2]=y(Qe-y(Go(se,l,0,Q))),Qe=y(Go(k,l,Q&d,Q&(d^1))),h[M>>2]=y(Qe-y(Go(O,l,0,Q))),m=(n[s+952>>2]|0)-(n[s+948>>2]|0)>>2,m|0)){d=0;do Dc(gs(s,d)|0,l,se,O),d=d+1|0;while((d|0)!=(m|0))}}function yw(s,l,c,f,d){switch(s=s|0,l=l|0,c=c|0,f=f|0,d=d|0,c|0){case 5:case 0:{s=l7(n[489]|0,f,d)|0;break}default:s=t3e(f,d)|0}return s|0}function mg(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0,m=0;d=E,E=E+16|0,m=d,n[m>>2]=f,yg(s,0,l,c,m),E=d}function yg(s,l,c,f,d){if(s=s|0,l=l|0,c=c|0,f=f|0,d=d|0,s=s|0?s:956,x7[n[s+8>>2]&1](s,l,c,f,d)|0,(c|0)==5)Rt();else return}function Ga(s,l,c){s=s|0,l=l|0,c=c|0,o[s+l>>0]=c&1}function Qm(s,l){s=s|0,l=l|0;var c=0,f=0;n[s>>2]=0,n[s+4>>2]=0,n[s+8>>2]=0,c=l+4|0,f=(n[c>>2]|0)-(n[l>>2]|0)>>2,f|0&&(Eg(s,f),Qt(s,n[l>>2]|0,n[c>>2]|0,f))}function Eg(s,l){s=s|0,l=l|0;var c=0;if((N(s)|0)>>>0<l>>>0&&Jr(s),l>>>0>1073741823)Rt();else{c=Kt(l<<2)|0,n[s+4>>2]=c,n[s>>2]=c,n[s+8>>2]=c+(l<<2);return}}function Qt(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0,f=s+4|0,s=c-l|0,(s|0)>0&&(Dr(n[f>>2]|0,l|0,s|0)|0,n[f>>2]=(n[f>>2]|0)+(s>>>2<<2))}function N(s){return s=s|0,1073741823}function K(s,l,c){return s=s|0,l=l|0,c=y(c),pe(l)|0&&(n[s+96>>2]|0)!=0?s=s+92|0:s=Fn(s+60|0,n[1040+(l<<2)>>2]|0,992)|0,y(Je(s,c))}function re(s,l,c){return s=s|0,l=l|0,c=y(c),pe(l)|0&&(n[s+104>>2]|0)!=0?s=s+100|0:s=Fn(s+60|0,n[1e3+(l<<2)>>2]|0,992)|0,y(Je(s,c))}function pe(s){return s=s|0,(s|1|0)==3|0}function Je(s,l){return s=s|0,l=y(l),(n[s+4>>2]|0)==3?l=y(0):l=y(Gr(s,l)),y(l)}function mt(s,l){return s=s|0,l=l|0,s=n[s>>2]|0,((s|0)==0?(l|0)>1?l:1:s)|0}function fr(s,l){s=s|0,l=l|0;var c=0;e:do if((l|0)==2){switch(s|0){case 2:{s=3;break e}case 3:break;default:{c=4;break e}}s=2}else c=4;while(0);return s|0}function Cr(s,l){s=s|0,l=l|0;var c=Ze;return pe(l)|0&&(n[s+312>>2]|0)!=0&&(c=y(h[s+308>>2]),c>=y(0))||(c=y(_n(y(h[(Fn(s+276|0,n[1040+(l<<2)>>2]|0,992)|0)>>2]),y(0)))),y(c)}function yn(s,l){s=s|0,l=l|0;var c=Ze;return pe(l)|0&&(n[s+320>>2]|0)!=0&&(c=y(h[s+316>>2]),c>=y(0))||(c=y(_n(y(h[(Fn(s+276|0,n[1e3+(l<<2)>>2]|0,992)|0)>>2]),y(0)))),y(c)}function oi(s,l,c){s=s|0,l=l|0,c=y(c);var f=Ze;return pe(l)|0&&(n[s+240>>2]|0)!=0&&(f=y(Gr(s+236|0,c)),f>=y(0))||(f=y(_n(y(Gr(Fn(s+204|0,n[1040+(l<<2)>>2]|0,992)|0,c)),y(0)))),y(f)}function Oi(s,l,c){s=s|0,l=l|0,c=y(c);var f=Ze;return pe(l)|0&&(n[s+248>>2]|0)!=0&&(f=y(Gr(s+244|0,c)),f>=y(0))||(f=y(_n(y(Gr(Fn(s+204|0,n[1e3+(l<<2)>>2]|0,992)|0,c)),y(0)))),y(f)}function Cg(s,l,c,f,d,m,B){s=s|0,l=y(l),c=y(c),f=f|0,d=d|0,m=y(m),B=y(B);var k=Ze,Q=Ze,M=Ze,O=Ze,q=Ze,se=Ze,Ge=0,Me=0,Qe=0;Qe=E,E=E+16|0,Ge=Qe,Me=s+964|0,Un(s,(n[Me>>2]|0)!=0,3519),k=y(En(s,2,l)),Q=y(En(s,0,l)),M=y(ln(s,2,l)),O=y(ln(s,0,l)),_t(l)|0?q=l:q=y(_n(y(0),y(y(l-M)-k))),_t(c)|0?se=c:se=y(_n(y(0),y(y(c-O)-Q))),(f|0)==1&(d|0)==1?(h[s+908>>2]=y(Bi(s,2,y(l-M),m,m)),l=y(Bi(s,0,y(c-O),B,m))):(k7[n[Me>>2]&1](Ge,s,q,f,se,d),q=y(k+y(h[Ge>>2])),se=y(l-M),h[s+908>>2]=y(Bi(s,2,(f|2|0)==2?q:se,m,m)),se=y(Q+y(h[Ge+4>>2])),l=y(c-O),l=y(Bi(s,0,(d|2|0)==2?se:l,B,m))),h[s+912>>2]=l,E=Qe}function Gv(s,l,c,f,d,m,B){s=s|0,l=y(l),c=y(c),f=f|0,d=d|0,m=y(m),B=y(B);var k=Ze,Q=Ze,M=Ze,O=Ze;M=y(En(s,2,m)),k=y(En(s,0,m)),O=y(ln(s,2,m)),Q=y(ln(s,0,m)),l=y(l-O),h[s+908>>2]=y(Bi(s,2,(f|2|0)==2?M:l,m,m)),c=y(c-Q),h[s+912>>2]=y(Bi(s,0,(d|2|0)==2?k:c,B,m))}function Yv(s,l,c,f,d,m,B){s=s|0,l=y(l),c=y(c),f=f|0,d=d|0,m=y(m),B=y(B);var k=0,Q=Ze,M=Ze;return k=(f|0)==2,!(l<=y(0)&k)&&!(c<=y(0)&(d|0)==2)&&!((f|0)==1&(d|0)==1)?s=0:(Q=y(ln(s,0,m)),M=y(ln(s,2,m)),k=l<y(0)&k|(_t(l)|0),l=y(l-M),h[s+908>>2]=y(Bi(s,2,k?y(0):l,m,m)),l=y(c-Q),k=c<y(0)&(d|0)==2|(_t(c)|0),h[s+912>>2]=y(Bi(s,0,k?y(0):l,B,m)),s=1),s|0}function Ew(s,l){return s=s|0,l=l|0,MA(s)|0?s=fr(2,l)|0:s=0,s|0}function yp(s,l,c){return s=s|0,l=l|0,c=y(c),c=y(oi(s,l,c)),y(c+y(Cr(s,l)))}function Cw(s,l,c){return s=s|0,l=l|0,c=y(c),c=y(Oi(s,l,c)),y(c+y(yn(s,l)))}function En(s,l,c){s=s|0,l=l|0,c=y(c);var f=Ze;return f=y(yp(s,l,c)),y(f+y(Cw(s,l,c)))}function Fm(s){return s=s|0,n[s+24>>2]|0?s=0:y(rs(s))!=y(0)?s=1:s=y(js(s))!=y(0),s|0}function rs(s){s=s|0;var l=Ze;if(n[s+944>>2]|0){if(l=y(h[s+44>>2]),_t(l)|0)return l=y(h[s+40>>2]),s=l>y(0)&((_t(l)|0)^1),y(s?l:y(0))}else l=y(0);return y(l)}function js(s){s=s|0;var l=Ze,c=0,f=Ze;do if(n[s+944>>2]|0){if(l=y(h[s+48>>2]),_t(l)|0){if(c=o[(n[s+976>>2]|0)+2>>0]|0,c<<24>>24==0&&(f=y(h[s+40>>2]),f<y(0)&((_t(f)|0)^1))){l=y(-f);break}l=c<<24>>24?y(1):y(0)}}else l=y(0);while(0);return y(l)}function Bu(s){s=s|0;var l=0,c=0;if(zm(s+400|0,0,540)|0,o[s+985>>0]=1,$(s),c=wi(s)|0,c|0){l=s+948|0,s=0;do Bu(n[(n[l>>2]|0)+(s<<2)>>2]|0),s=s+1|0;while((s|0)!=(c|0))}}function Rm(s,l,c,f,d,m,B,k,Q,M){s=s|0,l=l|0,c=y(c),f=f|0,d=y(d),m=y(m),B=y(B),k=k|0,Q=Q|0,M=M|0;var O=0,q=Ze,se=0,Ge=0,Me=Ze,Qe=Ze,et=0,Xe=Ze,at=0,Ue=Ze,qe=0,Lt=0,Mr=0,or=0,Xt=0,Pr=0,Nr=0,ir=0,xn=0,go=0;xn=E,E=E+16|0,Mr=xn+12|0,or=xn+8|0,Xt=xn+4|0,Pr=xn,ir=fr(n[s+4>>2]|0,Q)|0,qe=pe(ir)|0,q=y(Gr(ww(l)|0,qe?m:B)),Lt=ts(l,2,m)|0,Nr=ts(l,0,B)|0;do if(!(_t(q)|0)&&!(_t(qe?c:d)|0)){if(O=l+504|0,!(_t(y(h[O>>2]))|0)&&(!(Iw(n[l+976>>2]|0,0)|0)||(n[l+500>>2]|0)==(n[2278]|0)))break;h[O>>2]=y(_n(q,y(En(l,ir,m))))}else se=7;while(0);do if((se|0)==7){if(at=qe^1,!(at|Lt^1)){B=y(Gr(n[l+992>>2]|0,m)),h[l+504>>2]=y(_n(B,y(En(l,2,m))));break}if(!(qe|Nr^1)){B=y(Gr(n[l+996>>2]|0,B)),h[l+504>>2]=y(_n(B,y(En(l,0,m))));break}h[Mr>>2]=y(Ae),h[or>>2]=y(Ae),n[Xt>>2]=0,n[Pr>>2]=0,Xe=y(ln(l,2,m)),Ue=y(ln(l,0,m)),Lt?(Me=y(Xe+y(Gr(n[l+992>>2]|0,m))),h[Mr>>2]=Me,n[Xt>>2]=1,Ge=1):(Ge=0,Me=y(Ae)),Nr?(q=y(Ue+y(Gr(n[l+996>>2]|0,B))),h[or>>2]=q,n[Pr>>2]=1,O=1):(O=0,q=y(Ae)),se=n[s+32>>2]|0,qe&(se|0)==2?se=2:_t(Me)|0&&!(_t(c)|0)&&(h[Mr>>2]=c,n[Xt>>2]=2,Ge=2,Me=c),!((se|0)==2&at)&&_t(q)|0&&!(_t(d)|0)&&(h[or>>2]=d,n[Pr>>2]=2,O=2,q=d),Qe=y(h[l+396>>2]),et=_t(Qe)|0;do if(et)se=Ge;else{if((Ge|0)==1&at){h[or>>2]=y(y(Me-Xe)/Qe),n[Pr>>2]=1,O=1,se=1;break}qe&(O|0)==1?(h[Mr>>2]=y(Qe*y(q-Ue)),n[Xt>>2]=1,O=1,se=1):se=Ge}while(0);go=_t(c)|0,Ge=(ha(s,l)|0)!=4,!(qe|Lt|((f|0)!=1|go)|(Ge|(se|0)==1))&&(h[Mr>>2]=c,n[Xt>>2]=1,!et)&&(h[or>>2]=y(y(c-Xe)/Qe),n[Pr>>2]=1,O=1),!(Nr|at|((k|0)!=1|(_t(d)|0))|(Ge|(O|0)==1))&&(h[or>>2]=d,n[Pr>>2]=1,!et)&&(h[Mr>>2]=y(Qe*y(d-Ue)),n[Xt>>2]=1),yr(l,2,m,m,Xt,Mr),yr(l,0,B,m,Pr,or),c=y(h[Mr>>2]),d=y(h[or>>2]),fa(l,c,d,Q,n[Xt>>2]|0,n[Pr>>2]|0,m,B,0,3565,M)|0,B=y(h[l+908+(n[976+(ir<<2)>>2]<<2)>>2]),h[l+504>>2]=y(_n(B,y(En(l,ir,m))))}while(0);n[l+500>>2]=n[2278],E=xn}function Bi(s,l,c,f,d){return s=s|0,l=l|0,c=y(c),f=y(f),d=y(d),f=y(OA(s,l,c,f)),y(_n(f,y(En(s,l,d))))}function ha(s,l){return s=s|0,l=l|0,l=l+20|0,l=n[((n[l>>2]|0)==0?s+16|0:l)>>2]|0,(l|0)==5&&MA(n[s+4>>2]|0)|0&&(l=1),l|0}function vl(s,l){return s=s|0,l=l|0,pe(l)|0&&(n[s+96>>2]|0)!=0?l=4:l=n[1040+(l<<2)>>2]|0,s+60+(l<<3)|0}function Pc(s,l){return s=s|0,l=l|0,pe(l)|0&&(n[s+104>>2]|0)!=0?l=5:l=n[1e3+(l<<2)>>2]|0,s+60+(l<<3)|0}function yr(s,l,c,f,d,m){switch(s=s|0,l=l|0,c=y(c),f=y(f),d=d|0,m=m|0,c=y(Gr(s+380+(n[976+(l<<2)>>2]<<3)|0,c)),c=y(c+y(ln(s,l,f))),n[d>>2]|0){case 2:case 1:{d=_t(c)|0,f=y(h[m>>2]),h[m>>2]=d|f<c?f:c;break}case 0:{_t(c)|0||(n[d>>2]=2,h[m>>2]=c);break}default:}}function gi(s,l){return s=s|0,l=l|0,s=s+132|0,pe(l)|0&&(n[(Fn(s,4,948)|0)+4>>2]|0)!=0?s=1:s=(n[(Fn(s,n[1040+(l<<2)>>2]|0,948)|0)+4>>2]|0)!=0,s|0}function Or(s,l,c){s=s|0,l=l|0,c=y(c);var f=0,d=0;return s=s+132|0,pe(l)|0&&(f=Fn(s,4,948)|0,(n[f+4>>2]|0)!=0)?d=4:(f=Fn(s,n[1040+(l<<2)>>2]|0,948)|0,n[f+4>>2]|0?d=4:c=y(0)),(d|0)==4&&(c=y(Gr(f,c))),y(c)}function ns(s,l,c){s=s|0,l=l|0,c=y(c);var f=Ze;return f=y(h[s+908+(n[976+(l<<2)>>2]<<2)>>2]),f=y(f+y(K(s,l,c))),y(f+y(re(s,l,c)))}function Yi(s){s=s|0;var l=0,c=0,f=0;e:do if(MA(n[s+4>>2]|0)|0)l=0;else if((n[s+16>>2]|0)!=5)if(c=wi(s)|0,!c)l=0;else for(l=0;;){if(f=gs(s,l)|0,(n[f+24>>2]|0)==0&&(n[f+20>>2]|0)==5){l=1;break e}if(l=l+1|0,l>>>0>=c>>>0){l=0;break}}else l=1;while(0);return l|0}function Tm(s,l){s=s|0,l=l|0;var c=Ze;return c=y(h[s+908+(n[976+(l<<2)>>2]<<2)>>2]),c>=y(0)&((_t(c)|0)^1)|0}function Ya(s){s=s|0;var l=Ze,c=0,f=0,d=0,m=0,B=0,k=0,Q=Ze;if(c=n[s+968>>2]|0,c)Q=y(h[s+908>>2]),l=y(h[s+912>>2]),l=y(D7[c&0](s,Q,l)),Un(s,(_t(l)|0)^1,3573);else{m=wi(s)|0;do if(m|0){for(c=0,d=0;;){if(f=gs(s,d)|0,n[f+940>>2]|0){B=8;break}if((n[f+24>>2]|0)!=1)if(k=(ha(s,f)|0)==5,k){c=f;break}else c=(c|0)==0?f:c;if(d=d+1|0,d>>>0>=m>>>0){B=8;break}}if((B|0)==8&&!c)break;return l=y(Ya(c)),y(l+y(h[c+404>>2]))}while(0);l=y(h[s+912>>2])}return y(l)}function OA(s,l,c,f){s=s|0,l=l|0,c=y(c),f=y(f);var d=Ze,m=0;return MA(l)|0?(l=1,m=3):pe(l)|0?(l=0,m=3):(f=y(Ae),d=y(Ae)),(m|0)==3&&(d=y(Gr(s+364+(l<<3)|0,f)),f=y(Gr(s+380+(l<<3)|0,f))),m=f<c&(f>=y(0)&((_t(f)|0)^1)),c=m?f:c,m=d>=y(0)&((_t(d)|0)^1)&c<d,y(m?d:c)}function Nm(s,l,c,f,d,m,B){s=s|0,l=l|0,c=y(c),f=f|0,d=y(d),m=m|0,B=B|0;var k=Ze,Q=Ze,M=0,O=0,q=Ze,se=Ze,Ge=Ze,Me=0,Qe=0,et=0,Xe=0,at=Ze,Ue=0;et=fr(n[s+4>>2]|0,m)|0,Me=Ew(et,m)|0,Qe=pe(et)|0,q=y(ln(l,2,c)),se=y(ln(l,0,c)),ts(l,2,c)|0?k=y(q+y(Gr(n[l+992>>2]|0,c))):gi(l,2)|0&&sr(l,2)|0?(k=y(h[s+908>>2]),Q=y(Cr(s,2)),Q=y(k-y(Q+y(yn(s,2)))),k=y(Or(l,2,c)),k=y(Bi(l,2,y(Q-y(k+y(vu(l,2,c)))),c,c))):k=y(Ae),ts(l,0,d)|0?Q=y(se+y(Gr(n[l+996>>2]|0,d))):gi(l,0)|0&&sr(l,0)|0?(Q=y(h[s+912>>2]),at=y(Cr(s,0)),at=y(Q-y(at+y(yn(s,0)))),Q=y(Or(l,0,d)),Q=y(Bi(l,0,y(at-y(Q+y(vu(l,0,d)))),d,c))):Q=y(Ae),M=_t(k)|0,O=_t(Q)|0;do if(M^O&&(Ge=y(h[l+396>>2]),!(_t(Ge)|0)))if(M){k=y(q+y(y(Q-se)*Ge));break}else{at=y(se+y(y(k-q)/Ge)),Q=O?at:Q;break}while(0);O=_t(k)|0,M=_t(Q)|0,O|M&&(Ue=(O^1)&1,f=c>y(0)&((f|0)!=0&O),k=Qe?k:f?c:k,fa(l,k,Q,m,Qe?Ue:f?2:Ue,O&(M^1)&1,k,Q,0,3623,B)|0,k=y(h[l+908>>2]),k=y(k+y(ln(l,2,c))),Q=y(h[l+912>>2]),Q=y(Q+y(ln(l,0,c)))),fa(l,k,Q,m,1,1,k,Q,1,3635,B)|0,sr(l,et)|0&&!(gi(l,et)|0)?(Ue=n[976+(et<<2)>>2]|0,at=y(h[s+908+(Ue<<2)>>2]),at=y(at-y(h[l+908+(Ue<<2)>>2])),at=y(at-y(yn(s,et))),at=y(at-y(re(l,et,c))),at=y(at-y(vu(l,et,Qe?c:d))),h[l+400+(n[1040+(et<<2)>>2]<<2)>>2]=at):Xe=21;do if((Xe|0)==21){if(!(gi(l,et)|0)&&(n[s+8>>2]|0)==1){Ue=n[976+(et<<2)>>2]|0,at=y(h[s+908+(Ue<<2)>>2]),at=y(y(at-y(h[l+908+(Ue<<2)>>2]))*y(.5)),h[l+400+(n[1040+(et<<2)>>2]<<2)>>2]=at;break}!(gi(l,et)|0)&&(n[s+8>>2]|0)==2&&(Ue=n[976+(et<<2)>>2]|0,at=y(h[s+908+(Ue<<2)>>2]),at=y(at-y(h[l+908+(Ue<<2)>>2])),h[l+400+(n[1040+(et<<2)>>2]<<2)>>2]=at)}while(0);sr(l,Me)|0&&!(gi(l,Me)|0)?(Ue=n[976+(Me<<2)>>2]|0,at=y(h[s+908+(Ue<<2)>>2]),at=y(at-y(h[l+908+(Ue<<2)>>2])),at=y(at-y(yn(s,Me))),at=y(at-y(re(l,Me,c))),at=y(at-y(vu(l,Me,Qe?d:c))),h[l+400+(n[1040+(Me<<2)>>2]<<2)>>2]=at):Xe=30;do if((Xe|0)==30&&!(gi(l,Me)|0)){if((ha(s,l)|0)==2){Ue=n[976+(Me<<2)>>2]|0,at=y(h[s+908+(Ue<<2)>>2]),at=y(y(at-y(h[l+908+(Ue<<2)>>2]))*y(.5)),h[l+400+(n[1040+(Me<<2)>>2]<<2)>>2]=at;break}Ue=(ha(s,l)|0)==3,Ue^(n[s+28>>2]|0)==2&&(Ue=n[976+(Me<<2)>>2]|0,at=y(h[s+908+(Ue<<2)>>2]),at=y(at-y(h[l+908+(Ue<<2)>>2])),h[l+400+(n[1040+(Me<<2)>>2]<<2)>>2]=at)}while(0)}function Ep(s,l,c){s=s|0,l=l|0,c=c|0;var f=Ze,d=0;d=n[976+(c<<2)>>2]|0,f=y(h[l+908+(d<<2)>>2]),f=y(y(h[s+908+(d<<2)>>2])-f),f=y(f-y(h[l+400+(n[1040+(c<<2)>>2]<<2)>>2])),h[l+400+(n[1e3+(c<<2)>>2]<<2)>>2]=f}function MA(s){return s=s|0,(s|1|0)==1|0}function ww(s){s=s|0;var l=Ze;switch(n[s+56>>2]|0){case 0:case 3:{l=y(h[s+40>>2]),l>y(0)&((_t(l)|0)^1)?s=o[(n[s+976>>2]|0)+2>>0]|0?1056:992:s=1056;break}default:s=s+52|0}return s|0}function Iw(s,l){return s=s|0,l=l|0,(o[s+l>>0]|0)!=0|0}function sr(s,l){return s=s|0,l=l|0,s=s+132|0,pe(l)|0&&(n[(Fn(s,5,948)|0)+4>>2]|0)!=0?s=1:s=(n[(Fn(s,n[1e3+(l<<2)>>2]|0,948)|0)+4>>2]|0)!=0,s|0}function vu(s,l,c){s=s|0,l=l|0,c=y(c);var f=0,d=0;return s=s+132|0,pe(l)|0&&(f=Fn(s,5,948)|0,(n[f+4>>2]|0)!=0)?d=4:(f=Fn(s,n[1e3+(l<<2)>>2]|0,948)|0,n[f+4>>2]|0?d=4:c=y(0)),(d|0)==4&&(c=y(Gr(f,c))),y(c)}function Lm(s,l,c){return s=s|0,l=l|0,c=y(c),gi(s,l)|0?c=y(Or(s,l,c)):c=y(-y(vu(s,l,c))),y(c)}function Du(s){return s=y(s),h[v>>2]=s,n[v>>2]|0|0}function Cp(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0;n[s+12>>2]=0,n[s+16>>2]=f;do if(l)if(l>>>0>1073741823)Rt();else{d=Kt(l<<2)|0;break}else d=0;while(0);n[s>>2]=d,f=d+(c<<2)|0,n[s+8>>2]=f,n[s+4>>2]=f,n[s+12>>2]=d+(l<<2)}function wg(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0,B=0;f=n[s>>2]|0,B=s+4|0,m=l+4|0,d=(n[B>>2]|0)-f|0,c=(n[m>>2]|0)+(0-(d>>2)<<2)|0,n[m>>2]=c,(d|0)>0?(Dr(c|0,f|0,d|0)|0,f=m,c=n[m>>2]|0):f=m,m=n[s>>2]|0,n[s>>2]=c,n[f>>2]=m,m=l+8|0,d=n[B>>2]|0,n[B>>2]=n[m>>2],n[m>>2]=d,m=s+8|0,B=l+12|0,s=n[m>>2]|0,n[m>>2]=n[B>>2],n[B>>2]=s,n[l>>2]=n[f>>2]}function UA(s){s=s|0;var l=0,c=0,f=0;l=n[s+4>>2]|0,c=s+8|0,f=n[c>>2]|0,(f|0)!=(l|0)&&(n[c>>2]=f+(~((f+-4-l|0)>>>2)<<2)),s=n[s>>2]|0,s|0&&gt(s)}function _A(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0,m=0,B=0,k=0;if(B=s+4|0,k=n[B>>2]|0,d=k-f|0,m=d>>2,s=l+(m<<2)|0,s>>>0<c>>>0){f=k;do n[f>>2]=n[s>>2],s=s+4|0,f=(n[B>>2]|0)+4|0,n[B>>2]=f;while(s>>>0<c>>>0)}m|0&&Lw(k+(0-m<<2)|0,l|0,d|0)|0}function Ig(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0,k=0,Q=0;return k=l+4|0,Q=n[k>>2]|0,d=n[s>>2]|0,B=c,m=B-d|0,f=Q+(0-(m>>2)<<2)|0,n[k>>2]=f,(m|0)>0&&Dr(f|0,d|0,m|0)|0,d=s+4|0,m=l+8|0,f=(n[d>>2]|0)-B|0,(f|0)>0&&(Dr(n[m>>2]|0,c|0,f|0)|0,n[m>>2]=(n[m>>2]|0)+(f>>>2<<2)),B=n[s>>2]|0,n[s>>2]=n[k>>2],n[k>>2]=B,B=n[d>>2]|0,n[d>>2]=n[m>>2],n[m>>2]=B,B=s+8|0,c=l+12|0,s=n[B>>2]|0,n[B>>2]=n[c>>2],n[c>>2]=s,n[l>>2]=n[k>>2],Q|0}function Bw(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0;if(B=n[l>>2]|0,m=n[c>>2]|0,(B|0)!=(m|0)){d=s+8|0,c=((m+-4-B|0)>>>2)+1|0,s=B,f=n[d>>2]|0;do n[f>>2]=n[s>>2],f=(n[d>>2]|0)+4|0,n[d>>2]=f,s=s+4|0;while((s|0)!=(m|0));n[l>>2]=B+(c<<2)}}function Om(){dc()}function ga(){var s=0;return s=Kt(4)|0,HA(s),s|0}function HA(s){s=s|0,n[s>>2]=ys()|0}function Sc(s){s=s|0,s|0&&(Bg(s),gt(s))}function Bg(s){s=s|0,tt(n[s>>2]|0)}function Mm(s,l,c){s=s|0,l=l|0,c=c|0,Ga(n[s>>2]|0,l,c)}function fo(s,l){s=s|0,l=y(l),pa(n[s>>2]|0,l)}function Wv(s,l){return s=s|0,l=l|0,Iw(n[s>>2]|0,l)|0}function vw(){var s=0;return s=Kt(8)|0,Kv(s,0),s|0}function Kv(s,l){s=s|0,l=l|0,l?l=Ci(n[l>>2]|0)|0:l=co()|0,n[s>>2]=l,n[s+4>>2]=0,bi(l,s)}function pF(s){s=s|0;var l=0;return l=Kt(8)|0,Kv(l,s),l|0}function Vv(s){s=s|0,s|0&&(Pu(s),gt(s))}function Pu(s){s=s|0;var l=0;la(n[s>>2]|0),l=s+4|0,s=n[l>>2]|0,n[l>>2]=0,s|0&&(jA(s),gt(s))}function jA(s){s=s|0,qA(s)}function qA(s){s=s|0,s=n[s>>2]|0,s|0&&PA(s|0)}function Dw(s){return s=s|0,jo(s)|0}function Um(s){s=s|0;var l=0,c=0;c=s+4|0,l=n[c>>2]|0,n[c>>2]=0,l|0&&(jA(l),gt(l)),_s(n[s>>2]|0)}function hF(s,l){s=s|0,l=l|0,Zr(n[s>>2]|0,n[l>>2]|0)}function gF(s,l){s=s|0,l=l|0,ca(n[s>>2]|0,l)}function zv(s,l,c){s=s|0,l=l|0,c=+c,yu(n[s>>2]|0,l,y(c))}function Jv(s,l,c){s=s|0,l=l|0,c=+c,Es(n[s>>2]|0,l,y(c))}function Pw(s,l){s=s|0,l=l|0,gu(n[s>>2]|0,l)}function Su(s,l){s=s|0,l=l|0,du(n[s>>2]|0,l)}function dF(s,l){s=s|0,l=l|0,QA(n[s>>2]|0,l)}function mF(s,l){s=s|0,l=l|0,xA(n[s>>2]|0,l)}function wp(s,l){s=s|0,l=l|0,yc(n[s>>2]|0,l)}function yF(s,l){s=s|0,l=l|0,cp(n[s>>2]|0,l)}function Xv(s,l,c){s=s|0,l=l|0,c=+c,Cc(n[s>>2]|0,l,y(c))}function GA(s,l,c){s=s|0,l=l|0,c=+c,G(n[s>>2]|0,l,y(c))}function EF(s,l){s=s|0,l=l|0,wl(n[s>>2]|0,l)}function CF(s,l){s=s|0,l=l|0,sg(n[s>>2]|0,l)}function Zv(s,l){s=s|0,l=l|0,up(n[s>>2]|0,l)}function Sw(s,l){s=s|0,l=+l,FA(n[s>>2]|0,y(l))}function bw(s,l){s=s|0,l=+l,Ha(n[s>>2]|0,y(l))}function wF(s,l){s=s|0,l=+l,Gi(n[s>>2]|0,y(l))}function IF(s,l){s=s|0,l=+l,Hs(n[s>>2]|0,y(l))}function Dl(s,l){s=s|0,l=+l,mu(n[s>>2]|0,y(l))}function xw(s,l){s=s|0,l=+l,dw(n[s>>2]|0,y(l))}function BF(s,l){s=s|0,l=+l,RA(n[s>>2]|0,y(l))}function YA(s){s=s|0,Ap(n[s>>2]|0)}function _m(s,l){s=s|0,l=+l,Cs(n[s>>2]|0,y(l))}function bu(s,l){s=s|0,l=+l,lg(n[s>>2]|0,y(l))}function kw(s){s=s|0,cg(n[s>>2]|0)}function Qw(s,l){s=s|0,l=+l,fp(n[s>>2]|0,y(l))}function vF(s,l){s=s|0,l=+l,Ic(n[s>>2]|0,y(l))}function $v(s,l){s=s|0,l=+l,Pm(n[s>>2]|0,y(l))}function WA(s,l){s=s|0,l=+l,Ag(n[s>>2]|0,y(l))}function eD(s,l){s=s|0,l=+l,Cu(n[s>>2]|0,y(l))}function Hm(s,l){s=s|0,l=+l,Sm(n[s>>2]|0,y(l))}function tD(s,l){s=s|0,l=+l,wu(n[s>>2]|0,y(l))}function rD(s,l){s=s|0,l=+l,mw(n[s>>2]|0,y(l))}function jm(s,l){s=s|0,l=+l,Aa(n[s>>2]|0,y(l))}function nD(s,l,c){s=s|0,l=l|0,c=+c,Eu(n[s>>2]|0,l,y(c))}function DF(s,l,c){s=s|0,l=l|0,c=+c,xi(n[s>>2]|0,l,y(c))}function P(s,l,c){s=s|0,l=l|0,c=+c,wc(n[s>>2]|0,l,y(c))}function D(s){return s=s|0,ig(n[s>>2]|0)|0}function T(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0;f=E,E=E+16|0,d=f,Ec(d,n[l>>2]|0,c),j(s,d),E=f}function j(s,l){s=s|0,l=l|0,Y(s,n[l+4>>2]|0,+y(h[l>>2]))}function Y(s,l,c){s=s|0,l=l|0,c=+c,n[s>>2]=l,C[s+8>>3]=c}function fe(s){return s=s|0,ng(n[s>>2]|0)|0}function ve(s){return s=s|0,uo(n[s>>2]|0)|0}function vt(s){return s=s|0,mc(n[s>>2]|0)|0}function wt(s){return s=s|0,kA(n[s>>2]|0)|0}function xt(s){return s=s|0,Dm(n[s>>2]|0)|0}function _r(s){return s=s|0,rg(n[s>>2]|0)|0}function is(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0;f=E,E=E+16|0,d=f,Dt(d,n[l>>2]|0,c),j(s,d),E=f}function di(s){return s=s|0,$n(n[s>>2]|0)|0}function po(s){return s=s|0,og(n[s>>2]|0)|0}function KA(s,l){s=s|0,l=l|0;var c=0,f=0;c=E,E=E+16|0,f=c,ua(f,n[l>>2]|0),j(s,f),E=c}function Yo(s){return s=s|0,+ +y(qi(n[s>>2]|0))}function rt(s){return s=s|0,+ +y(es(n[s>>2]|0))}function Ve(s,l){s=s|0,l=l|0;var c=0,f=0;c=E,E=E+16|0,f=c,Br(f,n[l>>2]|0),j(s,f),E=c}function At(s,l){s=s|0,l=l|0;var c=0,f=0;c=E,E=E+16|0,f=c,ug(f,n[l>>2]|0),j(s,f),E=c}function Wt(s,l){s=s|0,l=l|0;var c=0,f=0;c=E,E=E+16|0,f=c,Ct(f,n[l>>2]|0),j(s,f),E=c}function vr(s,l){s=s|0,l=l|0;var c=0,f=0;c=E,E=E+16|0,f=c,fg(f,n[l>>2]|0),j(s,f),E=c}function Sn(s,l){s=s|0,l=l|0;var c=0,f=0;c=E,E=E+16|0,f=c,pg(f,n[l>>2]|0),j(s,f),E=c}function Fr(s,l){s=s|0,l=l|0;var c=0,f=0;c=E,E=E+16|0,f=c,bm(f,n[l>>2]|0),j(s,f),E=c}function bn(s){return s=s|0,+ +y(Bc(n[s>>2]|0))}function ai(s,l){return s=s|0,l=l|0,+ +y(ag(n[s>>2]|0,l))}function en(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0;f=E,E=E+16|0,d=f,ct(d,n[l>>2]|0,c),j(s,d),E=f}function ho(s,l,c){s=s|0,l=l|0,c=c|0,nr(n[s>>2]|0,n[l>>2]|0,c)}function PF(s,l){s=s|0,l=l|0,ms(n[s>>2]|0,n[l>>2]|0)}function sve(s){return s=s|0,wi(n[s>>2]|0)|0}function ove(s){return s=s|0,s=pt(n[s>>2]|0)|0,s?s=Dw(s)|0:s=0,s|0}function ave(s,l){return s=s|0,l=l|0,s=gs(n[s>>2]|0,l)|0,s?s=Dw(s)|0:s=0,s|0}function lve(s,l){s=s|0,l=l|0;var c=0,f=0;f=Kt(4)|0,e5(f,l),c=s+4|0,l=n[c>>2]|0,n[c>>2]=f,l|0&&(jA(l),gt(l)),It(n[s>>2]|0,1)}function e5(s,l){s=s|0,l=l|0,Cve(s,l)}function cve(s,l,c,f,d,m){s=s|0,l=l|0,c=y(c),f=f|0,d=y(d),m=m|0;var B=0,k=0;B=E,E=E+16|0,k=B,uve(k,jo(l)|0,+c,f,+d,m),h[s>>2]=y(+C[k>>3]),h[s+4>>2]=y(+C[k+8>>3]),E=B}function uve(s,l,c,f,d,m){s=s|0,l=l|0,c=+c,f=f|0,d=+d,m=m|0;var B=0,k=0,Q=0,M=0,O=0;B=E,E=E+32|0,O=B+8|0,M=B+20|0,Q=B,k=B+16|0,C[O>>3]=c,n[M>>2]=f,C[Q>>3]=d,n[k>>2]=m,Ave(s,n[l+4>>2]|0,O,M,Q,k),E=B}function Ave(s,l,c,f,d,m){s=s|0,l=l|0,c=c|0,f=f|0,d=d|0,m=m|0;var B=0,k=0;B=E,E=E+16|0,k=B,Ka(k),l=da(l)|0,fve(s,l,+C[c>>3],n[f>>2]|0,+C[d>>3],n[m>>2]|0),Va(k),E=B}function da(s){return s=s|0,n[s>>2]|0}function fve(s,l,c,f,d,m){s=s|0,l=l|0,c=+c,f=f|0,d=+d,m=m|0;var B=0;B=Pl(pve()|0)|0,c=+VA(c),f=SF(f)|0,d=+VA(d),hve(s,hi(0,B|0,l|0,+c,f|0,+d,SF(m)|0)|0)}function pve(){var s=0;return o[7608]|0||(yve(9120),s=7608,n[s>>2]=1,n[s+4>>2]=0),9120}function Pl(s){return s=s|0,n[s+8>>2]|0}function VA(s){return s=+s,+ +bF(s)}function SF(s){return s=s|0,r5(s)|0}function hve(s,l){s=s|0,l=l|0;var c=0,f=0,d=0;d=E,E=E+32|0,c=d,f=l,f&1?(gve(c,0),ii(f|0,c|0)|0,dve(s,c),mve(c)):(n[s>>2]=n[l>>2],n[s+4>>2]=n[l+4>>2],n[s+8>>2]=n[l+8>>2],n[s+12>>2]=n[l+12>>2]),E=d}function gve(s,l){s=s|0,l=l|0,t5(s,l),n[s+8>>2]=0,o[s+24>>0]=0}function dve(s,l){s=s|0,l=l|0,l=l+8|0,n[s>>2]=n[l>>2],n[s+4>>2]=n[l+4>>2],n[s+8>>2]=n[l+8>>2],n[s+12>>2]=n[l+12>>2]}function mve(s){s=s|0,o[s+24>>0]=0}function t5(s,l){s=s|0,l=l|0,n[s>>2]=l}function r5(s){return s=s|0,s|0}function bF(s){return s=+s,+s}function yve(s){s=s|0,Sl(s,Eve()|0,4)}function Eve(){return 1064}function Sl(s,l,c){s=s|0,l=l|0,c=c|0,n[s>>2]=l,n[s+4>>2]=c,n[s+8>>2]=lp(l|0,c+1|0)|0}function Cve(s,l){s=s|0,l=l|0,l=n[l>>2]|0,n[s>>2]=l,yl(l|0)}function wve(s){s=s|0;var l=0,c=0;c=s+4|0,l=n[c>>2]|0,n[c>>2]=0,l|0&&(jA(l),gt(l)),It(n[s>>2]|0,0)}function Ive(s){s=s|0,Tt(n[s>>2]|0)}function Bve(s){return s=s|0,er(n[s>>2]|0)|0}function vve(s,l,c,f){s=s|0,l=+l,c=+c,f=f|0,vc(n[s>>2]|0,y(l),y(c),f)}function Dve(s){return s=s|0,+ +y(Il(n[s>>2]|0))}function Pve(s){return s=s|0,+ +y(hg(n[s>>2]|0))}function Sve(s){return s=s|0,+ +y(Iu(n[s>>2]|0))}function bve(s){return s=s|0,+ +y(TA(n[s>>2]|0))}function xve(s){return s=s|0,+ +y(pp(n[s>>2]|0))}function kve(s){return s=s|0,+ +y(ja(n[s>>2]|0))}function Qve(s,l){s=s|0,l=l|0,C[s>>3]=+y(Il(n[l>>2]|0)),C[s+8>>3]=+y(hg(n[l>>2]|0)),C[s+16>>3]=+y(Iu(n[l>>2]|0)),C[s+24>>3]=+y(TA(n[l>>2]|0)),C[s+32>>3]=+y(pp(n[l>>2]|0)),C[s+40>>3]=+y(ja(n[l>>2]|0))}function Fve(s,l){return s=s|0,l=l|0,+ +y(gg(n[s>>2]|0,l))}function Rve(s,l){return s=s|0,l=l|0,+ +y(hp(n[s>>2]|0,l))}function Tve(s,l){return s=s|0,l=l|0,+ +y(qo(n[s>>2]|0,l))}function Nve(){return Pn()|0}function Lve(){Ove(),Mve(),Uve(),_ve(),Hve(),jve()}function Ove(){HNe(11713,4938,1)}function Mve(){oNe(10448)}function Uve(){HTe(10408)}function _ve(){uTe(10324)}function Hve(){yFe(10096)}function jve(){qve(9132)}function qve(s){s=s|0;var l=0,c=0,f=0,d=0,m=0,B=0,k=0,Q=0,M=0,O=0,q=0,se=0,Ge=0,Me=0,Qe=0,et=0,Xe=0,at=0,Ue=0,qe=0,Lt=0,Mr=0,or=0,Xt=0,Pr=0,Nr=0,ir=0,xn=0,go=0,mo=0,yo=0,ya=0,kp=0,Qp=0,bl=0,Fp=0,Fu=0,Ru=0,Rp=0,Tp=0,Np=0,Xr=0,xl=0,Lp=0,xc=0,Op=0,Mp=0,Tu=0,Nu=0,kc=0,qs=0,Ja=0,Wo=0,kl=0,rf=0,nf=0,Lu=0,sf=0,of=0,Gs=0,vs=0,Ql=0,Rn=0,af=0,Eo=0,Qc=0,Co=0,Fc=0,lf=0,cf=0,Rc=0,Ys=0,Fl=0,uf=0,Af=0,ff=0,xr=0,zn=0,Ds=0,wo=0,Ws=0,Rr=0,ur=0,Rl=0;l=E,E=E+672|0,c=l+656|0,Rl=l+648|0,ur=l+640|0,Rr=l+632|0,Ws=l+624|0,wo=l+616|0,Ds=l+608|0,zn=l+600|0,xr=l+592|0,ff=l+584|0,Af=l+576|0,uf=l+568|0,Fl=l+560|0,Ys=l+552|0,Rc=l+544|0,cf=l+536|0,lf=l+528|0,Fc=l+520|0,Co=l+512|0,Qc=l+504|0,Eo=l+496|0,af=l+488|0,Rn=l+480|0,Ql=l+472|0,vs=l+464|0,Gs=l+456|0,of=l+448|0,sf=l+440|0,Lu=l+432|0,nf=l+424|0,rf=l+416|0,kl=l+408|0,Wo=l+400|0,Ja=l+392|0,qs=l+384|0,kc=l+376|0,Nu=l+368|0,Tu=l+360|0,Mp=l+352|0,Op=l+344|0,xc=l+336|0,Lp=l+328|0,xl=l+320|0,Xr=l+312|0,Np=l+304|0,Tp=l+296|0,Rp=l+288|0,Ru=l+280|0,Fu=l+272|0,Fp=l+264|0,bl=l+256|0,Qp=l+248|0,kp=l+240|0,ya=l+232|0,yo=l+224|0,mo=l+216|0,go=l+208|0,xn=l+200|0,ir=l+192|0,Nr=l+184|0,Pr=l+176|0,Xt=l+168|0,or=l+160|0,Mr=l+152|0,Lt=l+144|0,qe=l+136|0,Ue=l+128|0,at=l+120|0,Xe=l+112|0,et=l+104|0,Qe=l+96|0,Me=l+88|0,Ge=l+80|0,se=l+72|0,q=l+64|0,O=l+56|0,M=l+48|0,Q=l+40|0,k=l+32|0,B=l+24|0,m=l+16|0,d=l+8|0,f=l,Gve(s,3646),Yve(s,3651,2)|0,Wve(s,3665,2)|0,Kve(s,3682,18)|0,n[Rl>>2]=19,n[Rl+4>>2]=0,n[c>>2]=n[Rl>>2],n[c+4>>2]=n[Rl+4>>2],Fw(s,3690,c)|0,n[ur>>2]=1,n[ur+4>>2]=0,n[c>>2]=n[ur>>2],n[c+4>>2]=n[ur+4>>2],Vve(s,3696,c)|0,n[Rr>>2]=2,n[Rr+4>>2]=0,n[c>>2]=n[Rr>>2],n[c+4>>2]=n[Rr+4>>2],xu(s,3706,c)|0,n[Ws>>2]=1,n[Ws+4>>2]=0,n[c>>2]=n[Ws>>2],n[c+4>>2]=n[Ws+4>>2],vg(s,3722,c)|0,n[wo>>2]=2,n[wo+4>>2]=0,n[c>>2]=n[wo>>2],n[c+4>>2]=n[wo+4>>2],vg(s,3734,c)|0,n[Ds>>2]=3,n[Ds+4>>2]=0,n[c>>2]=n[Ds>>2],n[c+4>>2]=n[Ds+4>>2],xu(s,3753,c)|0,n[zn>>2]=4,n[zn+4>>2]=0,n[c>>2]=n[zn>>2],n[c+4>>2]=n[zn+4>>2],xu(s,3769,c)|0,n[xr>>2]=5,n[xr+4>>2]=0,n[c>>2]=n[xr>>2],n[c+4>>2]=n[xr+4>>2],xu(s,3783,c)|0,n[ff>>2]=6,n[ff+4>>2]=0,n[c>>2]=n[ff>>2],n[c+4>>2]=n[ff+4>>2],xu(s,3796,c)|0,n[Af>>2]=7,n[Af+4>>2]=0,n[c>>2]=n[Af>>2],n[c+4>>2]=n[Af+4>>2],xu(s,3813,c)|0,n[uf>>2]=8,n[uf+4>>2]=0,n[c>>2]=n[uf>>2],n[c+4>>2]=n[uf+4>>2],xu(s,3825,c)|0,n[Fl>>2]=3,n[Fl+4>>2]=0,n[c>>2]=n[Fl>>2],n[c+4>>2]=n[Fl+4>>2],vg(s,3843,c)|0,n[Ys>>2]=4,n[Ys+4>>2]=0,n[c>>2]=n[Ys>>2],n[c+4>>2]=n[Ys+4>>2],vg(s,3853,c)|0,n[Rc>>2]=9,n[Rc+4>>2]=0,n[c>>2]=n[Rc>>2],n[c+4>>2]=n[Rc+4>>2],xu(s,3870,c)|0,n[cf>>2]=10,n[cf+4>>2]=0,n[c>>2]=n[cf>>2],n[c+4>>2]=n[cf+4>>2],xu(s,3884,c)|0,n[lf>>2]=11,n[lf+4>>2]=0,n[c>>2]=n[lf>>2],n[c+4>>2]=n[lf+4>>2],xu(s,3896,c)|0,n[Fc>>2]=1,n[Fc+4>>2]=0,n[c>>2]=n[Fc>>2],n[c+4>>2]=n[Fc+4>>2],Is(s,3907,c)|0,n[Co>>2]=2,n[Co+4>>2]=0,n[c>>2]=n[Co>>2],n[c+4>>2]=n[Co+4>>2],Is(s,3915,c)|0,n[Qc>>2]=3,n[Qc+4>>2]=0,n[c>>2]=n[Qc>>2],n[c+4>>2]=n[Qc+4>>2],Is(s,3928,c)|0,n[Eo>>2]=4,n[Eo+4>>2]=0,n[c>>2]=n[Eo>>2],n[c+4>>2]=n[Eo+4>>2],Is(s,3948,c)|0,n[af>>2]=5,n[af+4>>2]=0,n[c>>2]=n[af>>2],n[c+4>>2]=n[af+4>>2],Is(s,3960,c)|0,n[Rn>>2]=6,n[Rn+4>>2]=0,n[c>>2]=n[Rn>>2],n[c+4>>2]=n[Rn+4>>2],Is(s,3974,c)|0,n[Ql>>2]=7,n[Ql+4>>2]=0,n[c>>2]=n[Ql>>2],n[c+4>>2]=n[Ql+4>>2],Is(s,3983,c)|0,n[vs>>2]=20,n[vs+4>>2]=0,n[c>>2]=n[vs>>2],n[c+4>>2]=n[vs+4>>2],Fw(s,3999,c)|0,n[Gs>>2]=8,n[Gs+4>>2]=0,n[c>>2]=n[Gs>>2],n[c+4>>2]=n[Gs+4>>2],Is(s,4012,c)|0,n[of>>2]=9,n[of+4>>2]=0,n[c>>2]=n[of>>2],n[c+4>>2]=n[of+4>>2],Is(s,4022,c)|0,n[sf>>2]=21,n[sf+4>>2]=0,n[c>>2]=n[sf>>2],n[c+4>>2]=n[sf+4>>2],Fw(s,4039,c)|0,n[Lu>>2]=10,n[Lu+4>>2]=0,n[c>>2]=n[Lu>>2],n[c+4>>2]=n[Lu+4>>2],Is(s,4053,c)|0,n[nf>>2]=11,n[nf+4>>2]=0,n[c>>2]=n[nf>>2],n[c+4>>2]=n[nf+4>>2],Is(s,4065,c)|0,n[rf>>2]=12,n[rf+4>>2]=0,n[c>>2]=n[rf>>2],n[c+4>>2]=n[rf+4>>2],Is(s,4084,c)|0,n[kl>>2]=13,n[kl+4>>2]=0,n[c>>2]=n[kl>>2],n[c+4>>2]=n[kl+4>>2],Is(s,4097,c)|0,n[Wo>>2]=14,n[Wo+4>>2]=0,n[c>>2]=n[Wo>>2],n[c+4>>2]=n[Wo+4>>2],Is(s,4117,c)|0,n[Ja>>2]=15,n[Ja+4>>2]=0,n[c>>2]=n[Ja>>2],n[c+4>>2]=n[Ja+4>>2],Is(s,4129,c)|0,n[qs>>2]=16,n[qs+4>>2]=0,n[c>>2]=n[qs>>2],n[c+4>>2]=n[qs+4>>2],Is(s,4148,c)|0,n[kc>>2]=17,n[kc+4>>2]=0,n[c>>2]=n[kc>>2],n[c+4>>2]=n[kc+4>>2],Is(s,4161,c)|0,n[Nu>>2]=18,n[Nu+4>>2]=0,n[c>>2]=n[Nu>>2],n[c+4>>2]=n[Nu+4>>2],Is(s,4181,c)|0,n[Tu>>2]=5,n[Tu+4>>2]=0,n[c>>2]=n[Tu>>2],n[c+4>>2]=n[Tu+4>>2],vg(s,4196,c)|0,n[Mp>>2]=6,n[Mp+4>>2]=0,n[c>>2]=n[Mp>>2],n[c+4>>2]=n[Mp+4>>2],vg(s,4206,c)|0,n[Op>>2]=7,n[Op+4>>2]=0,n[c>>2]=n[Op>>2],n[c+4>>2]=n[Op+4>>2],vg(s,4217,c)|0,n[xc>>2]=3,n[xc+4>>2]=0,n[c>>2]=n[xc>>2],n[c+4>>2]=n[xc+4>>2],zA(s,4235,c)|0,n[Lp>>2]=1,n[Lp+4>>2]=0,n[c>>2]=n[Lp>>2],n[c+4>>2]=n[Lp+4>>2],xF(s,4251,c)|0,n[xl>>2]=4,n[xl+4>>2]=0,n[c>>2]=n[xl>>2],n[c+4>>2]=n[xl+4>>2],zA(s,4263,c)|0,n[Xr>>2]=5,n[Xr+4>>2]=0,n[c>>2]=n[Xr>>2],n[c+4>>2]=n[Xr+4>>2],zA(s,4279,c)|0,n[Np>>2]=6,n[Np+4>>2]=0,n[c>>2]=n[Np>>2],n[c+4>>2]=n[Np+4>>2],zA(s,4293,c)|0,n[Tp>>2]=7,n[Tp+4>>2]=0,n[c>>2]=n[Tp>>2],n[c+4>>2]=n[Tp+4>>2],zA(s,4306,c)|0,n[Rp>>2]=8,n[Rp+4>>2]=0,n[c>>2]=n[Rp>>2],n[c+4>>2]=n[Rp+4>>2],zA(s,4323,c)|0,n[Ru>>2]=9,n[Ru+4>>2]=0,n[c>>2]=n[Ru>>2],n[c+4>>2]=n[Ru+4>>2],zA(s,4335,c)|0,n[Fu>>2]=2,n[Fu+4>>2]=0,n[c>>2]=n[Fu>>2],n[c+4>>2]=n[Fu+4>>2],xF(s,4353,c)|0,n[Fp>>2]=12,n[Fp+4>>2]=0,n[c>>2]=n[Fp>>2],n[c+4>>2]=n[Fp+4>>2],Dg(s,4363,c)|0,n[bl>>2]=1,n[bl+4>>2]=0,n[c>>2]=n[bl>>2],n[c+4>>2]=n[bl+4>>2],JA(s,4376,c)|0,n[Qp>>2]=2,n[Qp+4>>2]=0,n[c>>2]=n[Qp>>2],n[c+4>>2]=n[Qp+4>>2],JA(s,4388,c)|0,n[kp>>2]=13,n[kp+4>>2]=0,n[c>>2]=n[kp>>2],n[c+4>>2]=n[kp+4>>2],Dg(s,4402,c)|0,n[ya>>2]=14,n[ya+4>>2]=0,n[c>>2]=n[ya>>2],n[c+4>>2]=n[ya+4>>2],Dg(s,4411,c)|0,n[yo>>2]=15,n[yo+4>>2]=0,n[c>>2]=n[yo>>2],n[c+4>>2]=n[yo+4>>2],Dg(s,4421,c)|0,n[mo>>2]=16,n[mo+4>>2]=0,n[c>>2]=n[mo>>2],n[c+4>>2]=n[mo+4>>2],Dg(s,4433,c)|0,n[go>>2]=17,n[go+4>>2]=0,n[c>>2]=n[go>>2],n[c+4>>2]=n[go+4>>2],Dg(s,4446,c)|0,n[xn>>2]=18,n[xn+4>>2]=0,n[c>>2]=n[xn>>2],n[c+4>>2]=n[xn+4>>2],Dg(s,4458,c)|0,n[ir>>2]=3,n[ir+4>>2]=0,n[c>>2]=n[ir>>2],n[c+4>>2]=n[ir+4>>2],JA(s,4471,c)|0,n[Nr>>2]=1,n[Nr+4>>2]=0,n[c>>2]=n[Nr>>2],n[c+4>>2]=n[Nr+4>>2],iD(s,4486,c)|0,n[Pr>>2]=10,n[Pr+4>>2]=0,n[c>>2]=n[Pr>>2],n[c+4>>2]=n[Pr+4>>2],zA(s,4496,c)|0,n[Xt>>2]=11,n[Xt+4>>2]=0,n[c>>2]=n[Xt>>2],n[c+4>>2]=n[Xt+4>>2],zA(s,4508,c)|0,n[or>>2]=3,n[or+4>>2]=0,n[c>>2]=n[or>>2],n[c+4>>2]=n[or+4>>2],xF(s,4519,c)|0,n[Mr>>2]=4,n[Mr+4>>2]=0,n[c>>2]=n[Mr>>2],n[c+4>>2]=n[Mr+4>>2],zve(s,4530,c)|0,n[Lt>>2]=19,n[Lt+4>>2]=0,n[c>>2]=n[Lt>>2],n[c+4>>2]=n[Lt+4>>2],Jve(s,4542,c)|0,n[qe>>2]=12,n[qe+4>>2]=0,n[c>>2]=n[qe>>2],n[c+4>>2]=n[qe+4>>2],Xve(s,4554,c)|0,n[Ue>>2]=13,n[Ue+4>>2]=0,n[c>>2]=n[Ue>>2],n[c+4>>2]=n[Ue+4>>2],Zve(s,4568,c)|0,n[at>>2]=2,n[at+4>>2]=0,n[c>>2]=n[at>>2],n[c+4>>2]=n[at+4>>2],$ve(s,4578,c)|0,n[Xe>>2]=20,n[Xe+4>>2]=0,n[c>>2]=n[Xe>>2],n[c+4>>2]=n[Xe+4>>2],eDe(s,4587,c)|0,n[et>>2]=22,n[et+4>>2]=0,n[c>>2]=n[et>>2],n[c+4>>2]=n[et+4>>2],Fw(s,4602,c)|0,n[Qe>>2]=23,n[Qe+4>>2]=0,n[c>>2]=n[Qe>>2],n[c+4>>2]=n[Qe+4>>2],Fw(s,4619,c)|0,n[Me>>2]=14,n[Me+4>>2]=0,n[c>>2]=n[Me>>2],n[c+4>>2]=n[Me+4>>2],tDe(s,4629,c)|0,n[Ge>>2]=1,n[Ge+4>>2]=0,n[c>>2]=n[Ge>>2],n[c+4>>2]=n[Ge+4>>2],rDe(s,4637,c)|0,n[se>>2]=4,n[se+4>>2]=0,n[c>>2]=n[se>>2],n[c+4>>2]=n[se+4>>2],JA(s,4653,c)|0,n[q>>2]=5,n[q+4>>2]=0,n[c>>2]=n[q>>2],n[c+4>>2]=n[q+4>>2],JA(s,4669,c)|0,n[O>>2]=6,n[O+4>>2]=0,n[c>>2]=n[O>>2],n[c+4>>2]=n[O+4>>2],JA(s,4686,c)|0,n[M>>2]=7,n[M+4>>2]=0,n[c>>2]=n[M>>2],n[c+4>>2]=n[M+4>>2],JA(s,4701,c)|0,n[Q>>2]=8,n[Q+4>>2]=0,n[c>>2]=n[Q>>2],n[c+4>>2]=n[Q+4>>2],JA(s,4719,c)|0,n[k>>2]=9,n[k+4>>2]=0,n[c>>2]=n[k>>2],n[c+4>>2]=n[k+4>>2],JA(s,4736,c)|0,n[B>>2]=21,n[B+4>>2]=0,n[c>>2]=n[B>>2],n[c+4>>2]=n[B+4>>2],nDe(s,4754,c)|0,n[m>>2]=2,n[m+4>>2]=0,n[c>>2]=n[m>>2],n[c+4>>2]=n[m+4>>2],iD(s,4772,c)|0,n[d>>2]=3,n[d+4>>2]=0,n[c>>2]=n[d>>2],n[c+4>>2]=n[d+4>>2],iD(s,4790,c)|0,n[f>>2]=4,n[f+4>>2]=0,n[c>>2]=n[f>>2],n[c+4>>2]=n[f+4>>2],iD(s,4808,c)|0,E=l}function Gve(s,l){s=s|0,l=l|0;var c=0;c=cFe()|0,n[s>>2]=c,uFe(c,l),Sp(n[s>>2]|0)}function Yve(s,l,c){return s=s|0,l=l|0,c=c|0,zQe(s,pn(l)|0,c,0),s|0}function Wve(s,l,c){return s=s|0,l=l|0,c=c|0,RQe(s,pn(l)|0,c,0),s|0}function Kve(s,l,c){return s=s|0,l=l|0,c=c|0,EQe(s,pn(l)|0,c,0),s|0}function Fw(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0;return f=E,E=E+16|0,d=f+8|0,m=f,B=n[c+4>>2]|0,n[m>>2]=n[c>>2],n[m+4>>2]=B,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],nQe(s,l,d),E=f,s|0}function Vve(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0;return f=E,E=E+16|0,d=f+8|0,m=f,B=n[c+4>>2]|0,n[m>>2]=n[c>>2],n[m+4>>2]=B,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],Mke(s,l,d),E=f,s|0}function xu(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0;return f=E,E=E+16|0,d=f+8|0,m=f,B=n[c+4>>2]|0,n[m>>2]=n[c>>2],n[m+4>>2]=B,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],Ike(s,l,d),E=f,s|0}function vg(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0;return f=E,E=E+16|0,d=f+8|0,m=f,B=n[c+4>>2]|0,n[m>>2]=n[c>>2],n[m+4>>2]=B,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],oke(s,l,d),E=f,s|0}function Is(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0;return f=E,E=E+16|0,d=f+8|0,m=f,B=n[c+4>>2]|0,n[m>>2]=n[c>>2],n[m+4>>2]=B,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],Gxe(s,l,d),E=f,s|0}function zA(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0;return f=E,E=E+16|0,d=f+8|0,m=f,B=n[c+4>>2]|0,n[m>>2]=n[c>>2],n[m+4>>2]=B,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],bxe(s,l,d),E=f,s|0}function xF(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0;return f=E,E=E+16|0,d=f+8|0,m=f,B=n[c+4>>2]|0,n[m>>2]=n[c>>2],n[m+4>>2]=B,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],fxe(s,l,d),E=f,s|0}function Dg(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0;return f=E,E=E+16|0,d=f+8|0,m=f,B=n[c+4>>2]|0,n[m>>2]=n[c>>2],n[m+4>>2]=B,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],Mbe(s,l,d),E=f,s|0}function JA(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0;return f=E,E=E+16|0,d=f+8|0,m=f,B=n[c+4>>2]|0,n[m>>2]=n[c>>2],n[m+4>>2]=B,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],Ibe(s,l,d),E=f,s|0}function iD(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0;return f=E,E=E+16|0,d=f+8|0,m=f,B=n[c+4>>2]|0,n[m>>2]=n[c>>2],n[m+4>>2]=B,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],obe(s,l,d),E=f,s|0}function zve(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0;return f=E,E=E+16|0,d=f+8|0,m=f,B=n[c+4>>2]|0,n[m>>2]=n[c>>2],n[m+4>>2]=B,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],GSe(s,l,d),E=f,s|0}function Jve(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0;return f=E,E=E+16|0,d=f+8|0,m=f,B=n[c+4>>2]|0,n[m>>2]=n[c>>2],n[m+4>>2]=B,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],bSe(s,l,d),E=f,s|0}function Xve(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0;return f=E,E=E+16|0,d=f+8|0,m=f,B=n[c+4>>2]|0,n[m>>2]=n[c>>2],n[m+4>>2]=B,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],pSe(s,l,d),E=f,s|0}function Zve(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0;return f=E,E=E+16|0,d=f+8|0,m=f,B=n[c+4>>2]|0,n[m>>2]=n[c>>2],n[m+4>>2]=B,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],ZPe(s,l,d),E=f,s|0}function $ve(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0;return f=E,E=E+16|0,d=f+8|0,m=f,B=n[c+4>>2]|0,n[m>>2]=n[c>>2],n[m+4>>2]=B,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],NPe(s,l,d),E=f,s|0}function eDe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0;return f=E,E=E+16|0,d=f+8|0,m=f,B=n[c+4>>2]|0,n[m>>2]=n[c>>2],n[m+4>>2]=B,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],yPe(s,l,d),E=f,s|0}function tDe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0;return f=E,E=E+16|0,d=f+8|0,m=f,B=n[c+4>>2]|0,n[m>>2]=n[c>>2],n[m+4>>2]=B,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],rPe(s,l,d),E=f,s|0}function rDe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0;return f=E,E=E+16|0,d=f+8|0,m=f,B=n[c+4>>2]|0,n[m>>2]=n[c>>2],n[m+4>>2]=B,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],MDe(s,l,d),E=f,s|0}function nDe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0;return f=E,E=E+16|0,d=f+8|0,m=f,B=n[c+4>>2]|0,n[m>>2]=n[c>>2],n[m+4>>2]=B,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],iDe(s,l,d),E=f,s|0}function iDe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0,k=0;f=E,E=E+16|0,d=f+8|0,m=f,k=n[c>>2]|0,B=n[c+4>>2]|0,c=pn(l)|0,n[m>>2]=k,n[m+4>>2]=B,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],sDe(s,c,d,1),E=f}function pn(s){return s=s|0,s|0}function sDe(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0,m=0,B=0,k=0,Q=0,M=0,O=0;d=E,E=E+32|0,m=d+16|0,O=d+8|0,k=d,M=n[c>>2]|0,Q=n[c+4>>2]|0,B=n[s>>2]|0,s=kF()|0,n[O>>2]=M,n[O+4>>2]=Q,n[m>>2]=n[O>>2],n[m+4>>2]=n[O+4>>2],c=oDe(m)|0,n[k>>2]=M,n[k+4>>2]=Q,n[m>>2]=n[k>>2],n[m+4>>2]=n[k+4>>2],hn(B,l,s,c,aDe(m,f)|0,f),E=d}function kF(){var s=0,l=0;if(o[7616]|0||(s5(9136),tr(24,9136,U|0)|0,l=7616,n[l>>2]=1,n[l+4>>2]=0),!(Tr(9136)|0)){s=9136,l=s+36|0;do n[s>>2]=0,s=s+4|0;while((s|0)<(l|0));s5(9136)}return 9136}function oDe(s){return s=s|0,0}function aDe(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0,B=0,k=0,Q=0,M=0,O=0,q=0;return O=E,E=E+32|0,d=O+24|0,B=O+16|0,k=O,Q=O+8|0,m=n[s>>2]|0,f=n[s+4>>2]|0,n[k>>2]=m,n[k+4>>2]=f,q=kF()|0,M=q+24|0,s=gr(l,4)|0,n[Q>>2]=s,l=q+28|0,c=n[l>>2]|0,c>>>0<(n[q+32>>2]|0)>>>0?(n[B>>2]=m,n[B+4>>2]=f,n[d>>2]=n[B>>2],n[d+4>>2]=n[B+4>>2],i5(c,d,s),s=(n[l>>2]|0)+12|0,n[l>>2]=s):(uDe(M,k,Q),s=n[l>>2]|0),E=O,((s-(n[M>>2]|0)|0)/12|0)+-1|0}function hn(s,l,c,f,d,m){s=s|0,l=l|0,c=c|0,f=f|0,d=d|0,m=m|0;var B=0,k=0,Q=0,M=0,O=0,q=0,se=0,Ge=0;B=E,E=E+32|0,se=B+24|0,q=B+20|0,Q=B+16|0,O=B+12|0,M=B+8|0,k=B+4|0,Ge=B,n[q>>2]=l,n[Q>>2]=c,n[O>>2]=f,n[M>>2]=d,n[k>>2]=m,m=s+28|0,n[Ge>>2]=n[m>>2],n[se>>2]=n[Ge>>2],lDe(s+24|0,se,q,O,M,Q,k)|0,n[m>>2]=n[n[m>>2]>>2],E=B}function lDe(s,l,c,f,d,m,B){return s=s|0,l=l|0,c=c|0,f=f|0,d=d|0,m=m|0,B=B|0,s=cDe(l)|0,l=Kt(24)|0,n5(l+4|0,n[c>>2]|0,n[f>>2]|0,n[d>>2]|0,n[m>>2]|0,n[B>>2]|0),n[l>>2]=n[s>>2],n[s>>2]=l,l|0}function cDe(s){return s=s|0,n[s>>2]|0}function n5(s,l,c,f,d,m){s=s|0,l=l|0,c=c|0,f=f|0,d=d|0,m=m|0,n[s>>2]=l,n[s+4>>2]=c,n[s+8>>2]=f,n[s+12>>2]=d,n[s+16>>2]=m}function gr(s,l){return s=s|0,l=l|0,l|s|0}function i5(s,l,c){s=s|0,l=l|0,c=c|0;var f=0;f=n[l+4>>2]|0,n[s>>2]=n[l>>2],n[s+4>>2]=f,n[s+8>>2]=c}function uDe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0,k=0,Q=0,M=0,O=0,q=0,se=0;if(M=E,E=E+48|0,f=M+32|0,B=M+24|0,k=M,Q=s+4|0,d=(((n[Q>>2]|0)-(n[s>>2]|0)|0)/12|0)+1|0,m=ADe(s)|0,m>>>0<d>>>0)Jr(s);else{O=n[s>>2]|0,se=((n[s+8>>2]|0)-O|0)/12|0,q=se<<1,fDe(k,se>>>0<m>>>1>>>0?q>>>0<d>>>0?d:q:m,((n[Q>>2]|0)-O|0)/12|0,s+8|0),Q=k+8|0,m=n[Q>>2]|0,d=n[l+4>>2]|0,c=n[c>>2]|0,n[B>>2]=n[l>>2],n[B+4>>2]=d,n[f>>2]=n[B>>2],n[f+4>>2]=n[B+4>>2],i5(m,f,c),n[Q>>2]=(n[Q>>2]|0)+12,pDe(s,k),hDe(k),E=M;return}}function ADe(s){return s=s|0,357913941}function fDe(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0;n[s+12>>2]=0,n[s+16>>2]=f;do if(l)if(l>>>0>357913941)Rt();else{d=Kt(l*12|0)|0;break}else d=0;while(0);n[s>>2]=d,f=d+(c*12|0)|0,n[s+8>>2]=f,n[s+4>>2]=f,n[s+12>>2]=d+(l*12|0)}function pDe(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0,B=0;f=n[s>>2]|0,B=s+4|0,m=l+4|0,d=(n[B>>2]|0)-f|0,c=(n[m>>2]|0)+(((d|0)/-12|0)*12|0)|0,n[m>>2]=c,(d|0)>0?(Dr(c|0,f|0,d|0)|0,f=m,c=n[m>>2]|0):f=m,m=n[s>>2]|0,n[s>>2]=c,n[f>>2]=m,m=l+8|0,d=n[B>>2]|0,n[B>>2]=n[m>>2],n[m>>2]=d,m=s+8|0,B=l+12|0,s=n[m>>2]|0,n[m>>2]=n[B>>2],n[B>>2]=s,n[l>>2]=n[f>>2]}function hDe(s){s=s|0;var l=0,c=0,f=0;l=n[s+4>>2]|0,c=s+8|0,f=n[c>>2]|0,(f|0)!=(l|0)&&(n[c>>2]=f+(~(((f+-12-l|0)>>>0)/12|0)*12|0)),s=n[s>>2]|0,s|0&&gt(s)}function s5(s){s=s|0,mDe(s)}function gDe(s){s=s|0,dDe(s+24|0)}function Tr(s){return s=s|0,n[s>>2]|0}function dDe(s){s=s|0;var l=0,c=0,f=0;c=n[s>>2]|0,f=c,c|0&&(s=s+4|0,l=n[s>>2]|0,(l|0)!=(c|0)&&(n[s>>2]=l+(~(((l+-12-f|0)>>>0)/12|0)*12|0)),gt(c))}function mDe(s){s=s|0;var l=0;l=Kr()|0,Vr(s,2,3,l,yDe()|0,0),n[s+24>>2]=0,n[s+28>>2]=0,n[s+32>>2]=0}function Kr(){return 9228}function yDe(){return 1140}function EDe(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0;return c=E,E=E+16|0,f=c+8|0,d=c,m=CDe(s)|0,s=n[m+4>>2]|0,n[d>>2]=n[m>>2],n[d+4>>2]=s,n[f>>2]=n[d>>2],n[f+4>>2]=n[d+4>>2],l=wDe(l,f)|0,E=c,l|0}function Vr(s,l,c,f,d,m){s=s|0,l=l|0,c=c|0,f=f|0,d=d|0,m=m|0,n[s>>2]=l,n[s+4>>2]=c,n[s+8>>2]=f,n[s+12>>2]=d,n[s+16>>2]=m}function CDe(s){return s=s|0,(n[(kF()|0)+24>>2]|0)+(s*12|0)|0}function wDe(s,l){s=s|0,l=l|0;var c=0,f=0,d=0;return d=E,E=E+48|0,f=d,c=n[l>>2]|0,l=n[l+4>>2]|0,s=s+(l>>1)|0,l&1&&(c=n[(n[s>>2]|0)+c>>2]|0),tf[c&31](f,s),f=IDe(f)|0,E=d,f|0}function IDe(s){s=s|0;var l=0,c=0,f=0,d=0;return d=E,E=E+32|0,l=d+12|0,c=d,f=QF(o5()|0)|0,f?(FF(l,f),RF(c,l),BDe(s,c),s=TF(l)|0):s=vDe(s)|0,E=d,s|0}function o5(){var s=0;return o[7632]|0||(TDe(9184),tr(25,9184,U|0)|0,s=7632,n[s>>2]=1,n[s+4>>2]=0),9184}function QF(s){return s=s|0,n[s+36>>2]|0}function FF(s,l){s=s|0,l=l|0,n[s>>2]=l,n[s+4>>2]=s,n[s+8>>2]=0}function RF(s,l){s=s|0,l=l|0,n[s>>2]=n[l>>2],n[s+4>>2]=n[l+4>>2],n[s+8>>2]=0}function BDe(s,l){s=s|0,l=l|0,bDe(l,s,s+8|0,s+16|0,s+24|0,s+32|0,s+40|0)|0}function TF(s){return s=s|0,n[(n[s+4>>2]|0)+8>>2]|0}function vDe(s){s=s|0;var l=0,c=0,f=0,d=0,m=0,B=0,k=0,Q=0;Q=E,E=E+16|0,c=Q+4|0,f=Q,d=Wa(8)|0,m=d,B=Kt(48)|0,k=B,l=k+48|0;do n[k>>2]=n[s>>2],k=k+4|0,s=s+4|0;while((k|0)<(l|0));return l=m+4|0,n[l>>2]=B,k=Kt(8)|0,B=n[l>>2]|0,n[f>>2]=0,n[c>>2]=n[f>>2],a5(k,B,c),n[d>>2]=k,E=Q,m|0}function a5(s,l,c){s=s|0,l=l|0,c=c|0,n[s>>2]=l,c=Kt(16)|0,n[c+4>>2]=0,n[c+8>>2]=0,n[c>>2]=1092,n[c+12>>2]=l,n[s+4>>2]=c}function DDe(s){s=s|0,Vm(s),gt(s)}function PDe(s){s=s|0,s=n[s+12>>2]|0,s|0&&gt(s)}function SDe(s){s=s|0,gt(s)}function bDe(s,l,c,f,d,m,B){return s=s|0,l=l|0,c=c|0,f=f|0,d=d|0,m=m|0,B=B|0,m=xDe(n[s>>2]|0,l,c,f,d,m,B)|0,B=s+4|0,n[(n[B>>2]|0)+8>>2]=m,n[(n[B>>2]|0)+8>>2]|0}function xDe(s,l,c,f,d,m,B){s=s|0,l=l|0,c=c|0,f=f|0,d=d|0,m=m|0,B=B|0;var k=0,Q=0;return k=E,E=E+16|0,Q=k,Ka(Q),s=da(s)|0,B=kDe(s,+C[l>>3],+C[c>>3],+C[f>>3],+C[d>>3],+C[m>>3],+C[B>>3])|0,Va(Q),E=k,B|0}function kDe(s,l,c,f,d,m,B){s=s|0,l=+l,c=+c,f=+f,d=+d,m=+m,B=+B;var k=0;return k=Pl(QDe()|0)|0,l=+VA(l),c=+VA(c),f=+VA(f),d=+VA(d),m=+VA(m),Ms(0,k|0,s|0,+l,+c,+f,+d,+m,+ +VA(B))|0}function QDe(){var s=0;return o[7624]|0||(FDe(9172),s=7624,n[s>>2]=1,n[s+4>>2]=0),9172}function FDe(s){s=s|0,Sl(s,RDe()|0,6)}function RDe(){return 1112}function TDe(s){s=s|0,Ip(s)}function NDe(s){s=s|0,l5(s+24|0),c5(s+16|0)}function l5(s){s=s|0,ODe(s)}function c5(s){s=s|0,LDe(s)}function LDe(s){s=s|0;var l=0,c=0;if(l=n[s>>2]|0,l|0)do c=l,l=n[l>>2]|0,gt(c);while((l|0)!=0);n[s>>2]=0}function ODe(s){s=s|0;var l=0,c=0;if(l=n[s>>2]|0,l|0)do c=l,l=n[l>>2]|0,gt(c);while((l|0)!=0);n[s>>2]=0}function Ip(s){s=s|0;var l=0;n[s+16>>2]=0,n[s+20>>2]=0,l=s+24|0,n[l>>2]=0,n[s+28>>2]=l,n[s+36>>2]=0,o[s+40>>0]=0,o[s+41>>0]=0}function MDe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0,k=0;f=E,E=E+16|0,d=f+8|0,m=f,k=n[c>>2]|0,B=n[c+4>>2]|0,c=pn(l)|0,n[m>>2]=k,n[m+4>>2]=B,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],UDe(s,c,d,0),E=f}function UDe(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0,m=0,B=0,k=0,Q=0,M=0,O=0;d=E,E=E+32|0,m=d+16|0,O=d+8|0,k=d,M=n[c>>2]|0,Q=n[c+4>>2]|0,B=n[s>>2]|0,s=NF()|0,n[O>>2]=M,n[O+4>>2]=Q,n[m>>2]=n[O>>2],n[m+4>>2]=n[O+4>>2],c=_De(m)|0,n[k>>2]=M,n[k+4>>2]=Q,n[m>>2]=n[k>>2],n[m+4>>2]=n[k+4>>2],hn(B,l,s,c,HDe(m,f)|0,f),E=d}function NF(){var s=0,l=0;if(o[7640]|0||(A5(9232),tr(26,9232,U|0)|0,l=7640,n[l>>2]=1,n[l+4>>2]=0),!(Tr(9232)|0)){s=9232,l=s+36|0;do n[s>>2]=0,s=s+4|0;while((s|0)<(l|0));A5(9232)}return 9232}function _De(s){return s=s|0,0}function HDe(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0,B=0,k=0,Q=0,M=0,O=0,q=0;return O=E,E=E+32|0,d=O+24|0,B=O+16|0,k=O,Q=O+8|0,m=n[s>>2]|0,f=n[s+4>>2]|0,n[k>>2]=m,n[k+4>>2]=f,q=NF()|0,M=q+24|0,s=gr(l,4)|0,n[Q>>2]=s,l=q+28|0,c=n[l>>2]|0,c>>>0<(n[q+32>>2]|0)>>>0?(n[B>>2]=m,n[B+4>>2]=f,n[d>>2]=n[B>>2],n[d+4>>2]=n[B+4>>2],u5(c,d,s),s=(n[l>>2]|0)+12|0,n[l>>2]=s):(jDe(M,k,Q),s=n[l>>2]|0),E=O,((s-(n[M>>2]|0)|0)/12|0)+-1|0}function u5(s,l,c){s=s|0,l=l|0,c=c|0;var f=0;f=n[l+4>>2]|0,n[s>>2]=n[l>>2],n[s+4>>2]=f,n[s+8>>2]=c}function jDe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0,k=0,Q=0,M=0,O=0,q=0,se=0;if(M=E,E=E+48|0,f=M+32|0,B=M+24|0,k=M,Q=s+4|0,d=(((n[Q>>2]|0)-(n[s>>2]|0)|0)/12|0)+1|0,m=qDe(s)|0,m>>>0<d>>>0)Jr(s);else{O=n[s>>2]|0,se=((n[s+8>>2]|0)-O|0)/12|0,q=se<<1,GDe(k,se>>>0<m>>>1>>>0?q>>>0<d>>>0?d:q:m,((n[Q>>2]|0)-O|0)/12|0,s+8|0),Q=k+8|0,m=n[Q>>2]|0,d=n[l+4>>2]|0,c=n[c>>2]|0,n[B>>2]=n[l>>2],n[B+4>>2]=d,n[f>>2]=n[B>>2],n[f+4>>2]=n[B+4>>2],u5(m,f,c),n[Q>>2]=(n[Q>>2]|0)+12,YDe(s,k),WDe(k),E=M;return}}function qDe(s){return s=s|0,357913941}function GDe(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0;n[s+12>>2]=0,n[s+16>>2]=f;do if(l)if(l>>>0>357913941)Rt();else{d=Kt(l*12|0)|0;break}else d=0;while(0);n[s>>2]=d,f=d+(c*12|0)|0,n[s+8>>2]=f,n[s+4>>2]=f,n[s+12>>2]=d+(l*12|0)}function YDe(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0,B=0;f=n[s>>2]|0,B=s+4|0,m=l+4|0,d=(n[B>>2]|0)-f|0,c=(n[m>>2]|0)+(((d|0)/-12|0)*12|0)|0,n[m>>2]=c,(d|0)>0?(Dr(c|0,f|0,d|0)|0,f=m,c=n[m>>2]|0):f=m,m=n[s>>2]|0,n[s>>2]=c,n[f>>2]=m,m=l+8|0,d=n[B>>2]|0,n[B>>2]=n[m>>2],n[m>>2]=d,m=s+8|0,B=l+12|0,s=n[m>>2]|0,n[m>>2]=n[B>>2],n[B>>2]=s,n[l>>2]=n[f>>2]}function WDe(s){s=s|0;var l=0,c=0,f=0;l=n[s+4>>2]|0,c=s+8|0,f=n[c>>2]|0,(f|0)!=(l|0)&&(n[c>>2]=f+(~(((f+-12-l|0)>>>0)/12|0)*12|0)),s=n[s>>2]|0,s|0&&gt(s)}function A5(s){s=s|0,zDe(s)}function KDe(s){s=s|0,VDe(s+24|0)}function VDe(s){s=s|0;var l=0,c=0,f=0;c=n[s>>2]|0,f=c,c|0&&(s=s+4|0,l=n[s>>2]|0,(l|0)!=(c|0)&&(n[s>>2]=l+(~(((l+-12-f|0)>>>0)/12|0)*12|0)),gt(c))}function zDe(s){s=s|0;var l=0;l=Kr()|0,Vr(s,2,1,l,JDe()|0,3),n[s+24>>2]=0,n[s+28>>2]=0,n[s+32>>2]=0}function JDe(){return 1144}function XDe(s,l,c,f,d){s=s|0,l=l|0,c=+c,f=+f,d=d|0;var m=0,B=0,k=0,Q=0;m=E,E=E+16|0,B=m+8|0,k=m,Q=ZDe(s)|0,s=n[Q+4>>2]|0,n[k>>2]=n[Q>>2],n[k+4>>2]=s,n[B>>2]=n[k>>2],n[B+4>>2]=n[k+4>>2],$De(l,B,c,f,d),E=m}function ZDe(s){return s=s|0,(n[(NF()|0)+24>>2]|0)+(s*12|0)|0}function $De(s,l,c,f,d){s=s|0,l=l|0,c=+c,f=+f,d=d|0;var m=0,B=0,k=0,Q=0,M=0;M=E,E=E+16|0,B=M+2|0,k=M+1|0,Q=M,m=n[l>>2]|0,l=n[l+4>>2]|0,s=s+(l>>1)|0,l&1&&(m=n[(n[s>>2]|0)+m>>2]|0),ku(B,c),c=+Qu(B,c),ku(k,f),f=+Qu(k,f),XA(Q,d),Q=ZA(Q,d)|0,P7[m&1](s,c,f,Q),E=M}function ku(s,l){s=s|0,l=+l}function Qu(s,l){return s=s|0,l=+l,+ +tPe(l)}function XA(s,l){s=s|0,l=l|0}function ZA(s,l){return s=s|0,l=l|0,ePe(l)|0}function ePe(s){return s=s|0,s|0}function tPe(s){return s=+s,+s}function rPe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0,k=0;f=E,E=E+16|0,d=f+8|0,m=f,k=n[c>>2]|0,B=n[c+4>>2]|0,c=pn(l)|0,n[m>>2]=k,n[m+4>>2]=B,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],nPe(s,c,d,1),E=f}function nPe(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0,m=0,B=0,k=0,Q=0,M=0,O=0;d=E,E=E+32|0,m=d+16|0,O=d+8|0,k=d,M=n[c>>2]|0,Q=n[c+4>>2]|0,B=n[s>>2]|0,s=LF()|0,n[O>>2]=M,n[O+4>>2]=Q,n[m>>2]=n[O>>2],n[m+4>>2]=n[O+4>>2],c=iPe(m)|0,n[k>>2]=M,n[k+4>>2]=Q,n[m>>2]=n[k>>2],n[m+4>>2]=n[k+4>>2],hn(B,l,s,c,sPe(m,f)|0,f),E=d}function LF(){var s=0,l=0;if(o[7648]|0||(p5(9268),tr(27,9268,U|0)|0,l=7648,n[l>>2]=1,n[l+4>>2]=0),!(Tr(9268)|0)){s=9268,l=s+36|0;do n[s>>2]=0,s=s+4|0;while((s|0)<(l|0));p5(9268)}return 9268}function iPe(s){return s=s|0,0}function sPe(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0,B=0,k=0,Q=0,M=0,O=0,q=0;return O=E,E=E+32|0,d=O+24|0,B=O+16|0,k=O,Q=O+8|0,m=n[s>>2]|0,f=n[s+4>>2]|0,n[k>>2]=m,n[k+4>>2]=f,q=LF()|0,M=q+24|0,s=gr(l,4)|0,n[Q>>2]=s,l=q+28|0,c=n[l>>2]|0,c>>>0<(n[q+32>>2]|0)>>>0?(n[B>>2]=m,n[B+4>>2]=f,n[d>>2]=n[B>>2],n[d+4>>2]=n[B+4>>2],f5(c,d,s),s=(n[l>>2]|0)+12|0,n[l>>2]=s):(oPe(M,k,Q),s=n[l>>2]|0),E=O,((s-(n[M>>2]|0)|0)/12|0)+-1|0}function f5(s,l,c){s=s|0,l=l|0,c=c|0;var f=0;f=n[l+4>>2]|0,n[s>>2]=n[l>>2],n[s+4>>2]=f,n[s+8>>2]=c}function oPe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0,k=0,Q=0,M=0,O=0,q=0,se=0;if(M=E,E=E+48|0,f=M+32|0,B=M+24|0,k=M,Q=s+4|0,d=(((n[Q>>2]|0)-(n[s>>2]|0)|0)/12|0)+1|0,m=aPe(s)|0,m>>>0<d>>>0)Jr(s);else{O=n[s>>2]|0,se=((n[s+8>>2]|0)-O|0)/12|0,q=se<<1,lPe(k,se>>>0<m>>>1>>>0?q>>>0<d>>>0?d:q:m,((n[Q>>2]|0)-O|0)/12|0,s+8|0),Q=k+8|0,m=n[Q>>2]|0,d=n[l+4>>2]|0,c=n[c>>2]|0,n[B>>2]=n[l>>2],n[B+4>>2]=d,n[f>>2]=n[B>>2],n[f+4>>2]=n[B+4>>2],f5(m,f,c),n[Q>>2]=(n[Q>>2]|0)+12,cPe(s,k),uPe(k),E=M;return}}function aPe(s){return s=s|0,357913941}function lPe(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0;n[s+12>>2]=0,n[s+16>>2]=f;do if(l)if(l>>>0>357913941)Rt();else{d=Kt(l*12|0)|0;break}else d=0;while(0);n[s>>2]=d,f=d+(c*12|0)|0,n[s+8>>2]=f,n[s+4>>2]=f,n[s+12>>2]=d+(l*12|0)}function cPe(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0,B=0;f=n[s>>2]|0,B=s+4|0,m=l+4|0,d=(n[B>>2]|0)-f|0,c=(n[m>>2]|0)+(((d|0)/-12|0)*12|0)|0,n[m>>2]=c,(d|0)>0?(Dr(c|0,f|0,d|0)|0,f=m,c=n[m>>2]|0):f=m,m=n[s>>2]|0,n[s>>2]=c,n[f>>2]=m,m=l+8|0,d=n[B>>2]|0,n[B>>2]=n[m>>2],n[m>>2]=d,m=s+8|0,B=l+12|0,s=n[m>>2]|0,n[m>>2]=n[B>>2],n[B>>2]=s,n[l>>2]=n[f>>2]}function uPe(s){s=s|0;var l=0,c=0,f=0;l=n[s+4>>2]|0,c=s+8|0,f=n[c>>2]|0,(f|0)!=(l|0)&&(n[c>>2]=f+(~(((f+-12-l|0)>>>0)/12|0)*12|0)),s=n[s>>2]|0,s|0&&gt(s)}function p5(s){s=s|0,pPe(s)}function APe(s){s=s|0,fPe(s+24|0)}function fPe(s){s=s|0;var l=0,c=0,f=0;c=n[s>>2]|0,f=c,c|0&&(s=s+4|0,l=n[s>>2]|0,(l|0)!=(c|0)&&(n[s>>2]=l+(~(((l+-12-f|0)>>>0)/12|0)*12|0)),gt(c))}function pPe(s){s=s|0;var l=0;l=Kr()|0,Vr(s,2,4,l,hPe()|0,0),n[s+24>>2]=0,n[s+28>>2]=0,n[s+32>>2]=0}function hPe(){return 1160}function gPe(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0;return c=E,E=E+16|0,f=c+8|0,d=c,m=dPe(s)|0,s=n[m+4>>2]|0,n[d>>2]=n[m>>2],n[d+4>>2]=s,n[f>>2]=n[d>>2],n[f+4>>2]=n[d+4>>2],l=mPe(l,f)|0,E=c,l|0}function dPe(s){return s=s|0,(n[(LF()|0)+24>>2]|0)+(s*12|0)|0}function mPe(s,l){s=s|0,l=l|0;var c=0;return c=n[l>>2]|0,l=n[l+4>>2]|0,s=s+(l>>1)|0,l&1&&(c=n[(n[s>>2]|0)+c>>2]|0),h5(Tg[c&31](s)|0)|0}function h5(s){return s=s|0,s&1|0}function yPe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0,k=0;f=E,E=E+16|0,d=f+8|0,m=f,k=n[c>>2]|0,B=n[c+4>>2]|0,c=pn(l)|0,n[m>>2]=k,n[m+4>>2]=B,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],EPe(s,c,d,0),E=f}function EPe(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0,m=0,B=0,k=0,Q=0,M=0,O=0;d=E,E=E+32|0,m=d+16|0,O=d+8|0,k=d,M=n[c>>2]|0,Q=n[c+4>>2]|0,B=n[s>>2]|0,s=OF()|0,n[O>>2]=M,n[O+4>>2]=Q,n[m>>2]=n[O>>2],n[m+4>>2]=n[O+4>>2],c=CPe(m)|0,n[k>>2]=M,n[k+4>>2]=Q,n[m>>2]=n[k>>2],n[m+4>>2]=n[k+4>>2],hn(B,l,s,c,wPe(m,f)|0,f),E=d}function OF(){var s=0,l=0;if(o[7656]|0||(d5(9304),tr(28,9304,U|0)|0,l=7656,n[l>>2]=1,n[l+4>>2]=0),!(Tr(9304)|0)){s=9304,l=s+36|0;do n[s>>2]=0,s=s+4|0;while((s|0)<(l|0));d5(9304)}return 9304}function CPe(s){return s=s|0,0}function wPe(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0,B=0,k=0,Q=0,M=0,O=0,q=0;return O=E,E=E+32|0,d=O+24|0,B=O+16|0,k=O,Q=O+8|0,m=n[s>>2]|0,f=n[s+4>>2]|0,n[k>>2]=m,n[k+4>>2]=f,q=OF()|0,M=q+24|0,s=gr(l,4)|0,n[Q>>2]=s,l=q+28|0,c=n[l>>2]|0,c>>>0<(n[q+32>>2]|0)>>>0?(n[B>>2]=m,n[B+4>>2]=f,n[d>>2]=n[B>>2],n[d+4>>2]=n[B+4>>2],g5(c,d,s),s=(n[l>>2]|0)+12|0,n[l>>2]=s):(IPe(M,k,Q),s=n[l>>2]|0),E=O,((s-(n[M>>2]|0)|0)/12|0)+-1|0}function g5(s,l,c){s=s|0,l=l|0,c=c|0;var f=0;f=n[l+4>>2]|0,n[s>>2]=n[l>>2],n[s+4>>2]=f,n[s+8>>2]=c}function IPe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0,k=0,Q=0,M=0,O=0,q=0,se=0;if(M=E,E=E+48|0,f=M+32|0,B=M+24|0,k=M,Q=s+4|0,d=(((n[Q>>2]|0)-(n[s>>2]|0)|0)/12|0)+1|0,m=BPe(s)|0,m>>>0<d>>>0)Jr(s);else{O=n[s>>2]|0,se=((n[s+8>>2]|0)-O|0)/12|0,q=se<<1,vPe(k,se>>>0<m>>>1>>>0?q>>>0<d>>>0?d:q:m,((n[Q>>2]|0)-O|0)/12|0,s+8|0),Q=k+8|0,m=n[Q>>2]|0,d=n[l+4>>2]|0,c=n[c>>2]|0,n[B>>2]=n[l>>2],n[B+4>>2]=d,n[f>>2]=n[B>>2],n[f+4>>2]=n[B+4>>2],g5(m,f,c),n[Q>>2]=(n[Q>>2]|0)+12,DPe(s,k),PPe(k),E=M;return}}function BPe(s){return s=s|0,357913941}function vPe(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0;n[s+12>>2]=0,n[s+16>>2]=f;do if(l)if(l>>>0>357913941)Rt();else{d=Kt(l*12|0)|0;break}else d=0;while(0);n[s>>2]=d,f=d+(c*12|0)|0,n[s+8>>2]=f,n[s+4>>2]=f,n[s+12>>2]=d+(l*12|0)}function DPe(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0,B=0;f=n[s>>2]|0,B=s+4|0,m=l+4|0,d=(n[B>>2]|0)-f|0,c=(n[m>>2]|0)+(((d|0)/-12|0)*12|0)|0,n[m>>2]=c,(d|0)>0?(Dr(c|0,f|0,d|0)|0,f=m,c=n[m>>2]|0):f=m,m=n[s>>2]|0,n[s>>2]=c,n[f>>2]=m,m=l+8|0,d=n[B>>2]|0,n[B>>2]=n[m>>2],n[m>>2]=d,m=s+8|0,B=l+12|0,s=n[m>>2]|0,n[m>>2]=n[B>>2],n[B>>2]=s,n[l>>2]=n[f>>2]}function PPe(s){s=s|0;var l=0,c=0,f=0;l=n[s+4>>2]|0,c=s+8|0,f=n[c>>2]|0,(f|0)!=(l|0)&&(n[c>>2]=f+(~(((f+-12-l|0)>>>0)/12|0)*12|0)),s=n[s>>2]|0,s|0&&gt(s)}function d5(s){s=s|0,xPe(s)}function SPe(s){s=s|0,bPe(s+24|0)}function bPe(s){s=s|0;var l=0,c=0,f=0;c=n[s>>2]|0,f=c,c|0&&(s=s+4|0,l=n[s>>2]|0,(l|0)!=(c|0)&&(n[s>>2]=l+(~(((l+-12-f|0)>>>0)/12|0)*12|0)),gt(c))}function xPe(s){s=s|0;var l=0;l=Kr()|0,Vr(s,2,5,l,kPe()|0,1),n[s+24>>2]=0,n[s+28>>2]=0,n[s+32>>2]=0}function kPe(){return 1164}function QPe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0;f=E,E=E+16|0,d=f+8|0,m=f,B=FPe(s)|0,s=n[B+4>>2]|0,n[m>>2]=n[B>>2],n[m+4>>2]=s,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],RPe(l,d,c),E=f}function FPe(s){return s=s|0,(n[(OF()|0)+24>>2]|0)+(s*12|0)|0}function RPe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0;m=E,E=E+16|0,d=m,f=n[l>>2]|0,l=n[l+4>>2]|0,s=s+(l>>1)|0,l&1&&(f=n[(n[s>>2]|0)+f>>2]|0),Bp(d,c),c=vp(d,c)|0,tf[f&31](s,c),Dp(d),E=m}function Bp(s,l){s=s|0,l=l|0,TPe(s,l)}function vp(s,l){return s=s|0,l=l|0,s|0}function Dp(s){s=s|0,jA(s)}function TPe(s,l){s=s|0,l=l|0,MF(s,l)}function MF(s,l){s=s|0,l=l|0,n[s>>2]=l}function NPe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0,k=0;f=E,E=E+16|0,d=f+8|0,m=f,k=n[c>>2]|0,B=n[c+4>>2]|0,c=pn(l)|0,n[m>>2]=k,n[m+4>>2]=B,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],LPe(s,c,d,0),E=f}function LPe(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0,m=0,B=0,k=0,Q=0,M=0,O=0;d=E,E=E+32|0,m=d+16|0,O=d+8|0,k=d,M=n[c>>2]|0,Q=n[c+4>>2]|0,B=n[s>>2]|0,s=UF()|0,n[O>>2]=M,n[O+4>>2]=Q,n[m>>2]=n[O>>2],n[m+4>>2]=n[O+4>>2],c=OPe(m)|0,n[k>>2]=M,n[k+4>>2]=Q,n[m>>2]=n[k>>2],n[m+4>>2]=n[k+4>>2],hn(B,l,s,c,MPe(m,f)|0,f),E=d}function UF(){var s=0,l=0;if(o[7664]|0||(y5(9340),tr(29,9340,U|0)|0,l=7664,n[l>>2]=1,n[l+4>>2]=0),!(Tr(9340)|0)){s=9340,l=s+36|0;do n[s>>2]=0,s=s+4|0;while((s|0)<(l|0));y5(9340)}return 9340}function OPe(s){return s=s|0,0}function MPe(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0,B=0,k=0,Q=0,M=0,O=0,q=0;return O=E,E=E+32|0,d=O+24|0,B=O+16|0,k=O,Q=O+8|0,m=n[s>>2]|0,f=n[s+4>>2]|0,n[k>>2]=m,n[k+4>>2]=f,q=UF()|0,M=q+24|0,s=gr(l,4)|0,n[Q>>2]=s,l=q+28|0,c=n[l>>2]|0,c>>>0<(n[q+32>>2]|0)>>>0?(n[B>>2]=m,n[B+4>>2]=f,n[d>>2]=n[B>>2],n[d+4>>2]=n[B+4>>2],m5(c,d,s),s=(n[l>>2]|0)+12|0,n[l>>2]=s):(UPe(M,k,Q),s=n[l>>2]|0),E=O,((s-(n[M>>2]|0)|0)/12|0)+-1|0}function m5(s,l,c){s=s|0,l=l|0,c=c|0;var f=0;f=n[l+4>>2]|0,n[s>>2]=n[l>>2],n[s+4>>2]=f,n[s+8>>2]=c}function UPe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0,k=0,Q=0,M=0,O=0,q=0,se=0;if(M=E,E=E+48|0,f=M+32|0,B=M+24|0,k=M,Q=s+4|0,d=(((n[Q>>2]|0)-(n[s>>2]|0)|0)/12|0)+1|0,m=_Pe(s)|0,m>>>0<d>>>0)Jr(s);else{O=n[s>>2]|0,se=((n[s+8>>2]|0)-O|0)/12|0,q=se<<1,HPe(k,se>>>0<m>>>1>>>0?q>>>0<d>>>0?d:q:m,((n[Q>>2]|0)-O|0)/12|0,s+8|0),Q=k+8|0,m=n[Q>>2]|0,d=n[l+4>>2]|0,c=n[c>>2]|0,n[B>>2]=n[l>>2],n[B+4>>2]=d,n[f>>2]=n[B>>2],n[f+4>>2]=n[B+4>>2],m5(m,f,c),n[Q>>2]=(n[Q>>2]|0)+12,jPe(s,k),qPe(k),E=M;return}}function _Pe(s){return s=s|0,357913941}function HPe(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0;n[s+12>>2]=0,n[s+16>>2]=f;do if(l)if(l>>>0>357913941)Rt();else{d=Kt(l*12|0)|0;break}else d=0;while(0);n[s>>2]=d,f=d+(c*12|0)|0,n[s+8>>2]=f,n[s+4>>2]=f,n[s+12>>2]=d+(l*12|0)}function jPe(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0,B=0;f=n[s>>2]|0,B=s+4|0,m=l+4|0,d=(n[B>>2]|0)-f|0,c=(n[m>>2]|0)+(((d|0)/-12|0)*12|0)|0,n[m>>2]=c,(d|0)>0?(Dr(c|0,f|0,d|0)|0,f=m,c=n[m>>2]|0):f=m,m=n[s>>2]|0,n[s>>2]=c,n[f>>2]=m,m=l+8|0,d=n[B>>2]|0,n[B>>2]=n[m>>2],n[m>>2]=d,m=s+8|0,B=l+12|0,s=n[m>>2]|0,n[m>>2]=n[B>>2],n[B>>2]=s,n[l>>2]=n[f>>2]}function qPe(s){s=s|0;var l=0,c=0,f=0;l=n[s+4>>2]|0,c=s+8|0,f=n[c>>2]|0,(f|0)!=(l|0)&&(n[c>>2]=f+(~(((f+-12-l|0)>>>0)/12|0)*12|0)),s=n[s>>2]|0,s|0&&gt(s)}function y5(s){s=s|0,WPe(s)}function GPe(s){s=s|0,YPe(s+24|0)}function YPe(s){s=s|0;var l=0,c=0,f=0;c=n[s>>2]|0,f=c,c|0&&(s=s+4|0,l=n[s>>2]|0,(l|0)!=(c|0)&&(n[s>>2]=l+(~(((l+-12-f|0)>>>0)/12|0)*12|0)),gt(c))}function WPe(s){s=s|0;var l=0;l=Kr()|0,Vr(s,2,4,l,KPe()|0,1),n[s+24>>2]=0,n[s+28>>2]=0,n[s+32>>2]=0}function KPe(){return 1180}function VPe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0;return f=E,E=E+16|0,d=f+8|0,m=f,B=zPe(s)|0,s=n[B+4>>2]|0,n[m>>2]=n[B>>2],n[m+4>>2]=s,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],c=JPe(l,d,c)|0,E=f,c|0}function zPe(s){return s=s|0,(n[(UF()|0)+24>>2]|0)+(s*12|0)|0}function JPe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0;return m=E,E=E+16|0,d=m,f=n[l>>2]|0,l=n[l+4>>2]|0,s=s+(l>>1)|0,l&1&&(f=n[(n[s>>2]|0)+f>>2]|0),Pg(d,c),d=Sg(d,c)|0,d=sD(NR[f&15](s,d)|0)|0,E=m,d|0}function Pg(s,l){s=s|0,l=l|0}function Sg(s,l){return s=s|0,l=l|0,XPe(l)|0}function sD(s){return s=s|0,s|0}function XPe(s){return s=s|0,s|0}function ZPe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0,k=0;f=E,E=E+16|0,d=f+8|0,m=f,k=n[c>>2]|0,B=n[c+4>>2]|0,c=pn(l)|0,n[m>>2]=k,n[m+4>>2]=B,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],$Pe(s,c,d,0),E=f}function $Pe(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0,m=0,B=0,k=0,Q=0,M=0,O=0;d=E,E=E+32|0,m=d+16|0,O=d+8|0,k=d,M=n[c>>2]|0,Q=n[c+4>>2]|0,B=n[s>>2]|0,s=_F()|0,n[O>>2]=M,n[O+4>>2]=Q,n[m>>2]=n[O>>2],n[m+4>>2]=n[O+4>>2],c=eSe(m)|0,n[k>>2]=M,n[k+4>>2]=Q,n[m>>2]=n[k>>2],n[m+4>>2]=n[k+4>>2],hn(B,l,s,c,tSe(m,f)|0,f),E=d}function _F(){var s=0,l=0;if(o[7672]|0||(C5(9376),tr(30,9376,U|0)|0,l=7672,n[l>>2]=1,n[l+4>>2]=0),!(Tr(9376)|0)){s=9376,l=s+36|0;do n[s>>2]=0,s=s+4|0;while((s|0)<(l|0));C5(9376)}return 9376}function eSe(s){return s=s|0,0}function tSe(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0,B=0,k=0,Q=0,M=0,O=0,q=0;return O=E,E=E+32|0,d=O+24|0,B=O+16|0,k=O,Q=O+8|0,m=n[s>>2]|0,f=n[s+4>>2]|0,n[k>>2]=m,n[k+4>>2]=f,q=_F()|0,M=q+24|0,s=gr(l,4)|0,n[Q>>2]=s,l=q+28|0,c=n[l>>2]|0,c>>>0<(n[q+32>>2]|0)>>>0?(n[B>>2]=m,n[B+4>>2]=f,n[d>>2]=n[B>>2],n[d+4>>2]=n[B+4>>2],E5(c,d,s),s=(n[l>>2]|0)+12|0,n[l>>2]=s):(rSe(M,k,Q),s=n[l>>2]|0),E=O,((s-(n[M>>2]|0)|0)/12|0)+-1|0}function E5(s,l,c){s=s|0,l=l|0,c=c|0;var f=0;f=n[l+4>>2]|0,n[s>>2]=n[l>>2],n[s+4>>2]=f,n[s+8>>2]=c}function rSe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0,k=0,Q=0,M=0,O=0,q=0,se=0;if(M=E,E=E+48|0,f=M+32|0,B=M+24|0,k=M,Q=s+4|0,d=(((n[Q>>2]|0)-(n[s>>2]|0)|0)/12|0)+1|0,m=nSe(s)|0,m>>>0<d>>>0)Jr(s);else{O=n[s>>2]|0,se=((n[s+8>>2]|0)-O|0)/12|0,q=se<<1,iSe(k,se>>>0<m>>>1>>>0?q>>>0<d>>>0?d:q:m,((n[Q>>2]|0)-O|0)/12|0,s+8|0),Q=k+8|0,m=n[Q>>2]|0,d=n[l+4>>2]|0,c=n[c>>2]|0,n[B>>2]=n[l>>2],n[B+4>>2]=d,n[f>>2]=n[B>>2],n[f+4>>2]=n[B+4>>2],E5(m,f,c),n[Q>>2]=(n[Q>>2]|0)+12,sSe(s,k),oSe(k),E=M;return}}function nSe(s){return s=s|0,357913941}function iSe(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0;n[s+12>>2]=0,n[s+16>>2]=f;do if(l)if(l>>>0>357913941)Rt();else{d=Kt(l*12|0)|0;break}else d=0;while(0);n[s>>2]=d,f=d+(c*12|0)|0,n[s+8>>2]=f,n[s+4>>2]=f,n[s+12>>2]=d+(l*12|0)}function sSe(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0,B=0;f=n[s>>2]|0,B=s+4|0,m=l+4|0,d=(n[B>>2]|0)-f|0,c=(n[m>>2]|0)+(((d|0)/-12|0)*12|0)|0,n[m>>2]=c,(d|0)>0?(Dr(c|0,f|0,d|0)|0,f=m,c=n[m>>2]|0):f=m,m=n[s>>2]|0,n[s>>2]=c,n[f>>2]=m,m=l+8|0,d=n[B>>2]|0,n[B>>2]=n[m>>2],n[m>>2]=d,m=s+8|0,B=l+12|0,s=n[m>>2]|0,n[m>>2]=n[B>>2],n[B>>2]=s,n[l>>2]=n[f>>2]}function oSe(s){s=s|0;var l=0,c=0,f=0;l=n[s+4>>2]|0,c=s+8|0,f=n[c>>2]|0,(f|0)!=(l|0)&&(n[c>>2]=f+(~(((f+-12-l|0)>>>0)/12|0)*12|0)),s=n[s>>2]|0,s|0&&gt(s)}function C5(s){s=s|0,cSe(s)}function aSe(s){s=s|0,lSe(s+24|0)}function lSe(s){s=s|0;var l=0,c=0,f=0;c=n[s>>2]|0,f=c,c|0&&(s=s+4|0,l=n[s>>2]|0,(l|0)!=(c|0)&&(n[s>>2]=l+(~(((l+-12-f|0)>>>0)/12|0)*12|0)),gt(c))}function cSe(s){s=s|0;var l=0;l=Kr()|0,Vr(s,2,5,l,w5()|0,0),n[s+24>>2]=0,n[s+28>>2]=0,n[s+32>>2]=0}function w5(){return 1196}function uSe(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0;return c=E,E=E+16|0,f=c+8|0,d=c,m=ASe(s)|0,s=n[m+4>>2]|0,n[d>>2]=n[m>>2],n[d+4>>2]=s,n[f>>2]=n[d>>2],n[f+4>>2]=n[d+4>>2],l=fSe(l,f)|0,E=c,l|0}function ASe(s){return s=s|0,(n[(_F()|0)+24>>2]|0)+(s*12|0)|0}function fSe(s,l){s=s|0,l=l|0;var c=0;return c=n[l>>2]|0,l=n[l+4>>2]|0,s=s+(l>>1)|0,l&1&&(c=n[(n[s>>2]|0)+c>>2]|0),sD(Tg[c&31](s)|0)|0}function pSe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0,k=0;f=E,E=E+16|0,d=f+8|0,m=f,k=n[c>>2]|0,B=n[c+4>>2]|0,c=pn(l)|0,n[m>>2]=k,n[m+4>>2]=B,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],hSe(s,c,d,1),E=f}function hSe(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0,m=0,B=0,k=0,Q=0,M=0,O=0;d=E,E=E+32|0,m=d+16|0,O=d+8|0,k=d,M=n[c>>2]|0,Q=n[c+4>>2]|0,B=n[s>>2]|0,s=HF()|0,n[O>>2]=M,n[O+4>>2]=Q,n[m>>2]=n[O>>2],n[m+4>>2]=n[O+4>>2],c=gSe(m)|0,n[k>>2]=M,n[k+4>>2]=Q,n[m>>2]=n[k>>2],n[m+4>>2]=n[k+4>>2],hn(B,l,s,c,dSe(m,f)|0,f),E=d}function HF(){var s=0,l=0;if(o[7680]|0||(B5(9412),tr(31,9412,U|0)|0,l=7680,n[l>>2]=1,n[l+4>>2]=0),!(Tr(9412)|0)){s=9412,l=s+36|0;do n[s>>2]=0,s=s+4|0;while((s|0)<(l|0));B5(9412)}return 9412}function gSe(s){return s=s|0,0}function dSe(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0,B=0,k=0,Q=0,M=0,O=0,q=0;return O=E,E=E+32|0,d=O+24|0,B=O+16|0,k=O,Q=O+8|0,m=n[s>>2]|0,f=n[s+4>>2]|0,n[k>>2]=m,n[k+4>>2]=f,q=HF()|0,M=q+24|0,s=gr(l,4)|0,n[Q>>2]=s,l=q+28|0,c=n[l>>2]|0,c>>>0<(n[q+32>>2]|0)>>>0?(n[B>>2]=m,n[B+4>>2]=f,n[d>>2]=n[B>>2],n[d+4>>2]=n[B+4>>2],I5(c,d,s),s=(n[l>>2]|0)+12|0,n[l>>2]=s):(mSe(M,k,Q),s=n[l>>2]|0),E=O,((s-(n[M>>2]|0)|0)/12|0)+-1|0}function I5(s,l,c){s=s|0,l=l|0,c=c|0;var f=0;f=n[l+4>>2]|0,n[s>>2]=n[l>>2],n[s+4>>2]=f,n[s+8>>2]=c}function mSe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0,k=0,Q=0,M=0,O=0,q=0,se=0;if(M=E,E=E+48|0,f=M+32|0,B=M+24|0,k=M,Q=s+4|0,d=(((n[Q>>2]|0)-(n[s>>2]|0)|0)/12|0)+1|0,m=ySe(s)|0,m>>>0<d>>>0)Jr(s);else{O=n[s>>2]|0,se=((n[s+8>>2]|0)-O|0)/12|0,q=se<<1,ESe(k,se>>>0<m>>>1>>>0?q>>>0<d>>>0?d:q:m,((n[Q>>2]|0)-O|0)/12|0,s+8|0),Q=k+8|0,m=n[Q>>2]|0,d=n[l+4>>2]|0,c=n[c>>2]|0,n[B>>2]=n[l>>2],n[B+4>>2]=d,n[f>>2]=n[B>>2],n[f+4>>2]=n[B+4>>2],I5(m,f,c),n[Q>>2]=(n[Q>>2]|0)+12,CSe(s,k),wSe(k),E=M;return}}function ySe(s){return s=s|0,357913941}function ESe(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0;n[s+12>>2]=0,n[s+16>>2]=f;do if(l)if(l>>>0>357913941)Rt();else{d=Kt(l*12|0)|0;break}else d=0;while(0);n[s>>2]=d,f=d+(c*12|0)|0,n[s+8>>2]=f,n[s+4>>2]=f,n[s+12>>2]=d+(l*12|0)}function CSe(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0,B=0;f=n[s>>2]|0,B=s+4|0,m=l+4|0,d=(n[B>>2]|0)-f|0,c=(n[m>>2]|0)+(((d|0)/-12|0)*12|0)|0,n[m>>2]=c,(d|0)>0?(Dr(c|0,f|0,d|0)|0,f=m,c=n[m>>2]|0):f=m,m=n[s>>2]|0,n[s>>2]=c,n[f>>2]=m,m=l+8|0,d=n[B>>2]|0,n[B>>2]=n[m>>2],n[m>>2]=d,m=s+8|0,B=l+12|0,s=n[m>>2]|0,n[m>>2]=n[B>>2],n[B>>2]=s,n[l>>2]=n[f>>2]}function wSe(s){s=s|0;var l=0,c=0,f=0;l=n[s+4>>2]|0,c=s+8|0,f=n[c>>2]|0,(f|0)!=(l|0)&&(n[c>>2]=f+(~(((f+-12-l|0)>>>0)/12|0)*12|0)),s=n[s>>2]|0,s|0&&gt(s)}function B5(s){s=s|0,vSe(s)}function ISe(s){s=s|0,BSe(s+24|0)}function BSe(s){s=s|0;var l=0,c=0,f=0;c=n[s>>2]|0,f=c,c|0&&(s=s+4|0,l=n[s>>2]|0,(l|0)!=(c|0)&&(n[s>>2]=l+(~(((l+-12-f|0)>>>0)/12|0)*12|0)),gt(c))}function vSe(s){s=s|0;var l=0;l=Kr()|0,Vr(s,2,6,l,v5()|0,0),n[s+24>>2]=0,n[s+28>>2]=0,n[s+32>>2]=0}function v5(){return 1200}function DSe(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0;return c=E,E=E+16|0,f=c+8|0,d=c,m=PSe(s)|0,s=n[m+4>>2]|0,n[d>>2]=n[m>>2],n[d+4>>2]=s,n[f>>2]=n[d>>2],n[f+4>>2]=n[d+4>>2],l=SSe(l,f)|0,E=c,l|0}function PSe(s){return s=s|0,(n[(HF()|0)+24>>2]|0)+(s*12|0)|0}function SSe(s,l){s=s|0,l=l|0;var c=0;return c=n[l>>2]|0,l=n[l+4>>2]|0,s=s+(l>>1)|0,l&1&&(c=n[(n[s>>2]|0)+c>>2]|0),oD(Tg[c&31](s)|0)|0}function oD(s){return s=s|0,s|0}function bSe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0,k=0;f=E,E=E+16|0,d=f+8|0,m=f,k=n[c>>2]|0,B=n[c+4>>2]|0,c=pn(l)|0,n[m>>2]=k,n[m+4>>2]=B,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],xSe(s,c,d,0),E=f}function xSe(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0,m=0,B=0,k=0,Q=0,M=0,O=0;d=E,E=E+32|0,m=d+16|0,O=d+8|0,k=d,M=n[c>>2]|0,Q=n[c+4>>2]|0,B=n[s>>2]|0,s=jF()|0,n[O>>2]=M,n[O+4>>2]=Q,n[m>>2]=n[O>>2],n[m+4>>2]=n[O+4>>2],c=kSe(m)|0,n[k>>2]=M,n[k+4>>2]=Q,n[m>>2]=n[k>>2],n[m+4>>2]=n[k+4>>2],hn(B,l,s,c,QSe(m,f)|0,f),E=d}function jF(){var s=0,l=0;if(o[7688]|0||(P5(9448),tr(32,9448,U|0)|0,l=7688,n[l>>2]=1,n[l+4>>2]=0),!(Tr(9448)|0)){s=9448,l=s+36|0;do n[s>>2]=0,s=s+4|0;while((s|0)<(l|0));P5(9448)}return 9448}function kSe(s){return s=s|0,0}function QSe(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0,B=0,k=0,Q=0,M=0,O=0,q=0;return O=E,E=E+32|0,d=O+24|0,B=O+16|0,k=O,Q=O+8|0,m=n[s>>2]|0,f=n[s+4>>2]|0,n[k>>2]=m,n[k+4>>2]=f,q=jF()|0,M=q+24|0,s=gr(l,4)|0,n[Q>>2]=s,l=q+28|0,c=n[l>>2]|0,c>>>0<(n[q+32>>2]|0)>>>0?(n[B>>2]=m,n[B+4>>2]=f,n[d>>2]=n[B>>2],n[d+4>>2]=n[B+4>>2],D5(c,d,s),s=(n[l>>2]|0)+12|0,n[l>>2]=s):(FSe(M,k,Q),s=n[l>>2]|0),E=O,((s-(n[M>>2]|0)|0)/12|0)+-1|0}function D5(s,l,c){s=s|0,l=l|0,c=c|0;var f=0;f=n[l+4>>2]|0,n[s>>2]=n[l>>2],n[s+4>>2]=f,n[s+8>>2]=c}function FSe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0,k=0,Q=0,M=0,O=0,q=0,se=0;if(M=E,E=E+48|0,f=M+32|0,B=M+24|0,k=M,Q=s+4|0,d=(((n[Q>>2]|0)-(n[s>>2]|0)|0)/12|0)+1|0,m=RSe(s)|0,m>>>0<d>>>0)Jr(s);else{O=n[s>>2]|0,se=((n[s+8>>2]|0)-O|0)/12|0,q=se<<1,TSe(k,se>>>0<m>>>1>>>0?q>>>0<d>>>0?d:q:m,((n[Q>>2]|0)-O|0)/12|0,s+8|0),Q=k+8|0,m=n[Q>>2]|0,d=n[l+4>>2]|0,c=n[c>>2]|0,n[B>>2]=n[l>>2],n[B+4>>2]=d,n[f>>2]=n[B>>2],n[f+4>>2]=n[B+4>>2],D5(m,f,c),n[Q>>2]=(n[Q>>2]|0)+12,NSe(s,k),LSe(k),E=M;return}}function RSe(s){return s=s|0,357913941}function TSe(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0;n[s+12>>2]=0,n[s+16>>2]=f;do if(l)if(l>>>0>357913941)Rt();else{d=Kt(l*12|0)|0;break}else d=0;while(0);n[s>>2]=d,f=d+(c*12|0)|0,n[s+8>>2]=f,n[s+4>>2]=f,n[s+12>>2]=d+(l*12|0)}function NSe(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0,B=0;f=n[s>>2]|0,B=s+4|0,m=l+4|0,d=(n[B>>2]|0)-f|0,c=(n[m>>2]|0)+(((d|0)/-12|0)*12|0)|0,n[m>>2]=c,(d|0)>0?(Dr(c|0,f|0,d|0)|0,f=m,c=n[m>>2]|0):f=m,m=n[s>>2]|0,n[s>>2]=c,n[f>>2]=m,m=l+8|0,d=n[B>>2]|0,n[B>>2]=n[m>>2],n[m>>2]=d,m=s+8|0,B=l+12|0,s=n[m>>2]|0,n[m>>2]=n[B>>2],n[B>>2]=s,n[l>>2]=n[f>>2]}function LSe(s){s=s|0;var l=0,c=0,f=0;l=n[s+4>>2]|0,c=s+8|0,f=n[c>>2]|0,(f|0)!=(l|0)&&(n[c>>2]=f+(~(((f+-12-l|0)>>>0)/12|0)*12|0)),s=n[s>>2]|0,s|0&&gt(s)}function P5(s){s=s|0,USe(s)}function OSe(s){s=s|0,MSe(s+24|0)}function MSe(s){s=s|0;var l=0,c=0,f=0;c=n[s>>2]|0,f=c,c|0&&(s=s+4|0,l=n[s>>2]|0,(l|0)!=(c|0)&&(n[s>>2]=l+(~(((l+-12-f|0)>>>0)/12|0)*12|0)),gt(c))}function USe(s){s=s|0;var l=0;l=Kr()|0,Vr(s,2,6,l,S5()|0,1),n[s+24>>2]=0,n[s+28>>2]=0,n[s+32>>2]=0}function S5(){return 1204}function _Se(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0;f=E,E=E+16|0,d=f+8|0,m=f,B=HSe(s)|0,s=n[B+4>>2]|0,n[m>>2]=n[B>>2],n[m+4>>2]=s,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],jSe(l,d,c),E=f}function HSe(s){return s=s|0,(n[(jF()|0)+24>>2]|0)+(s*12|0)|0}function jSe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0;m=E,E=E+16|0,d=m,f=n[l>>2]|0,l=n[l+4>>2]|0,s=s+(l>>1)|0,l&1&&(f=n[(n[s>>2]|0)+f>>2]|0),qF(d,c),d=GF(d,c)|0,tf[f&31](s,d),E=m}function qF(s,l){s=s|0,l=l|0}function GF(s,l){return s=s|0,l=l|0,qSe(l)|0}function qSe(s){return s=s|0,s|0}function GSe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0,k=0;f=E,E=E+16|0,d=f+8|0,m=f,k=n[c>>2]|0,B=n[c+4>>2]|0,c=pn(l)|0,n[m>>2]=k,n[m+4>>2]=B,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],YSe(s,c,d,0),E=f}function YSe(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0,m=0,B=0,k=0,Q=0,M=0,O=0;d=E,E=E+32|0,m=d+16|0,O=d+8|0,k=d,M=n[c>>2]|0,Q=n[c+4>>2]|0,B=n[s>>2]|0,s=YF()|0,n[O>>2]=M,n[O+4>>2]=Q,n[m>>2]=n[O>>2],n[m+4>>2]=n[O+4>>2],c=WSe(m)|0,n[k>>2]=M,n[k+4>>2]=Q,n[m>>2]=n[k>>2],n[m+4>>2]=n[k+4>>2],hn(B,l,s,c,KSe(m,f)|0,f),E=d}function YF(){var s=0,l=0;if(o[7696]|0||(x5(9484),tr(33,9484,U|0)|0,l=7696,n[l>>2]=1,n[l+4>>2]=0),!(Tr(9484)|0)){s=9484,l=s+36|0;do n[s>>2]=0,s=s+4|0;while((s|0)<(l|0));x5(9484)}return 9484}function WSe(s){return s=s|0,0}function KSe(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0,B=0,k=0,Q=0,M=0,O=0,q=0;return O=E,E=E+32|0,d=O+24|0,B=O+16|0,k=O,Q=O+8|0,m=n[s>>2]|0,f=n[s+4>>2]|0,n[k>>2]=m,n[k+4>>2]=f,q=YF()|0,M=q+24|0,s=gr(l,4)|0,n[Q>>2]=s,l=q+28|0,c=n[l>>2]|0,c>>>0<(n[q+32>>2]|0)>>>0?(n[B>>2]=m,n[B+4>>2]=f,n[d>>2]=n[B>>2],n[d+4>>2]=n[B+4>>2],b5(c,d,s),s=(n[l>>2]|0)+12|0,n[l>>2]=s):(VSe(M,k,Q),s=n[l>>2]|0),E=O,((s-(n[M>>2]|0)|0)/12|0)+-1|0}function b5(s,l,c){s=s|0,l=l|0,c=c|0;var f=0;f=n[l+4>>2]|0,n[s>>2]=n[l>>2],n[s+4>>2]=f,n[s+8>>2]=c}function VSe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0,k=0,Q=0,M=0,O=0,q=0,se=0;if(M=E,E=E+48|0,f=M+32|0,B=M+24|0,k=M,Q=s+4|0,d=(((n[Q>>2]|0)-(n[s>>2]|0)|0)/12|0)+1|0,m=zSe(s)|0,m>>>0<d>>>0)Jr(s);else{O=n[s>>2]|0,se=((n[s+8>>2]|0)-O|0)/12|0,q=se<<1,JSe(k,se>>>0<m>>>1>>>0?q>>>0<d>>>0?d:q:m,((n[Q>>2]|0)-O|0)/12|0,s+8|0),Q=k+8|0,m=n[Q>>2]|0,d=n[l+4>>2]|0,c=n[c>>2]|0,n[B>>2]=n[l>>2],n[B+4>>2]=d,n[f>>2]=n[B>>2],n[f+4>>2]=n[B+4>>2],b5(m,f,c),n[Q>>2]=(n[Q>>2]|0)+12,XSe(s,k),ZSe(k),E=M;return}}function zSe(s){return s=s|0,357913941}function JSe(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0;n[s+12>>2]=0,n[s+16>>2]=f;do if(l)if(l>>>0>357913941)Rt();else{d=Kt(l*12|0)|0;break}else d=0;while(0);n[s>>2]=d,f=d+(c*12|0)|0,n[s+8>>2]=f,n[s+4>>2]=f,n[s+12>>2]=d+(l*12|0)}function XSe(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0,B=0;f=n[s>>2]|0,B=s+4|0,m=l+4|0,d=(n[B>>2]|0)-f|0,c=(n[m>>2]|0)+(((d|0)/-12|0)*12|0)|0,n[m>>2]=c,(d|0)>0?(Dr(c|0,f|0,d|0)|0,f=m,c=n[m>>2]|0):f=m,m=n[s>>2]|0,n[s>>2]=c,n[f>>2]=m,m=l+8|0,d=n[B>>2]|0,n[B>>2]=n[m>>2],n[m>>2]=d,m=s+8|0,B=l+12|0,s=n[m>>2]|0,n[m>>2]=n[B>>2],n[B>>2]=s,n[l>>2]=n[f>>2]}function ZSe(s){s=s|0;var l=0,c=0,f=0;l=n[s+4>>2]|0,c=s+8|0,f=n[c>>2]|0,(f|0)!=(l|0)&&(n[c>>2]=f+(~(((f+-12-l|0)>>>0)/12|0)*12|0)),s=n[s>>2]|0,s|0&&gt(s)}function x5(s){s=s|0,tbe(s)}function $Se(s){s=s|0,ebe(s+24|0)}function ebe(s){s=s|0;var l=0,c=0,f=0;c=n[s>>2]|0,f=c,c|0&&(s=s+4|0,l=n[s>>2]|0,(l|0)!=(c|0)&&(n[s>>2]=l+(~(((l+-12-f|0)>>>0)/12|0)*12|0)),gt(c))}function tbe(s){s=s|0;var l=0;l=Kr()|0,Vr(s,2,1,l,rbe()|0,2),n[s+24>>2]=0,n[s+28>>2]=0,n[s+32>>2]=0}function rbe(){return 1212}function nbe(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0,m=0,B=0,k=0;d=E,E=E+16|0,m=d+8|0,B=d,k=ibe(s)|0,s=n[k+4>>2]|0,n[B>>2]=n[k>>2],n[B+4>>2]=s,n[m>>2]=n[B>>2],n[m+4>>2]=n[B+4>>2],sbe(l,m,c,f),E=d}function ibe(s){return s=s|0,(n[(YF()|0)+24>>2]|0)+(s*12|0)|0}function sbe(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0,m=0,B=0,k=0;k=E,E=E+16|0,m=k+1|0,B=k,d=n[l>>2]|0,l=n[l+4>>2]|0,s=s+(l>>1)|0,l&1&&(d=n[(n[s>>2]|0)+d>>2]|0),qF(m,c),m=GF(m,c)|0,Pg(B,f),B=Sg(B,f)|0,Uw[d&15](s,m,B),E=k}function obe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0,k=0;f=E,E=E+16|0,d=f+8|0,m=f,k=n[c>>2]|0,B=n[c+4>>2]|0,c=pn(l)|0,n[m>>2]=k,n[m+4>>2]=B,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],abe(s,c,d,1),E=f}function abe(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0,m=0,B=0,k=0,Q=0,M=0,O=0;d=E,E=E+32|0,m=d+16|0,O=d+8|0,k=d,M=n[c>>2]|0,Q=n[c+4>>2]|0,B=n[s>>2]|0,s=WF()|0,n[O>>2]=M,n[O+4>>2]=Q,n[m>>2]=n[O>>2],n[m+4>>2]=n[O+4>>2],c=lbe(m)|0,n[k>>2]=M,n[k+4>>2]=Q,n[m>>2]=n[k>>2],n[m+4>>2]=n[k+4>>2],hn(B,l,s,c,cbe(m,f)|0,f),E=d}function WF(){var s=0,l=0;if(o[7704]|0||(Q5(9520),tr(34,9520,U|0)|0,l=7704,n[l>>2]=1,n[l+4>>2]=0),!(Tr(9520)|0)){s=9520,l=s+36|0;do n[s>>2]=0,s=s+4|0;while((s|0)<(l|0));Q5(9520)}return 9520}function lbe(s){return s=s|0,0}function cbe(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0,B=0,k=0,Q=0,M=0,O=0,q=0;return O=E,E=E+32|0,d=O+24|0,B=O+16|0,k=O,Q=O+8|0,m=n[s>>2]|0,f=n[s+4>>2]|0,n[k>>2]=m,n[k+4>>2]=f,q=WF()|0,M=q+24|0,s=gr(l,4)|0,n[Q>>2]=s,l=q+28|0,c=n[l>>2]|0,c>>>0<(n[q+32>>2]|0)>>>0?(n[B>>2]=m,n[B+4>>2]=f,n[d>>2]=n[B>>2],n[d+4>>2]=n[B+4>>2],k5(c,d,s),s=(n[l>>2]|0)+12|0,n[l>>2]=s):(ube(M,k,Q),s=n[l>>2]|0),E=O,((s-(n[M>>2]|0)|0)/12|0)+-1|0}function k5(s,l,c){s=s|0,l=l|0,c=c|0;var f=0;f=n[l+4>>2]|0,n[s>>2]=n[l>>2],n[s+4>>2]=f,n[s+8>>2]=c}function ube(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0,k=0,Q=0,M=0,O=0,q=0,se=0;if(M=E,E=E+48|0,f=M+32|0,B=M+24|0,k=M,Q=s+4|0,d=(((n[Q>>2]|0)-(n[s>>2]|0)|0)/12|0)+1|0,m=Abe(s)|0,m>>>0<d>>>0)Jr(s);else{O=n[s>>2]|0,se=((n[s+8>>2]|0)-O|0)/12|0,q=se<<1,fbe(k,se>>>0<m>>>1>>>0?q>>>0<d>>>0?d:q:m,((n[Q>>2]|0)-O|0)/12|0,s+8|0),Q=k+8|0,m=n[Q>>2]|0,d=n[l+4>>2]|0,c=n[c>>2]|0,n[B>>2]=n[l>>2],n[B+4>>2]=d,n[f>>2]=n[B>>2],n[f+4>>2]=n[B+4>>2],k5(m,f,c),n[Q>>2]=(n[Q>>2]|0)+12,pbe(s,k),hbe(k),E=M;return}}function Abe(s){return s=s|0,357913941}function fbe(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0;n[s+12>>2]=0,n[s+16>>2]=f;do if(l)if(l>>>0>357913941)Rt();else{d=Kt(l*12|0)|0;break}else d=0;while(0);n[s>>2]=d,f=d+(c*12|0)|0,n[s+8>>2]=f,n[s+4>>2]=f,n[s+12>>2]=d+(l*12|0)}function pbe(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0,B=0;f=n[s>>2]|0,B=s+4|0,m=l+4|0,d=(n[B>>2]|0)-f|0,c=(n[m>>2]|0)+(((d|0)/-12|0)*12|0)|0,n[m>>2]=c,(d|0)>0?(Dr(c|0,f|0,d|0)|0,f=m,c=n[m>>2]|0):f=m,m=n[s>>2]|0,n[s>>2]=c,n[f>>2]=m,m=l+8|0,d=n[B>>2]|0,n[B>>2]=n[m>>2],n[m>>2]=d,m=s+8|0,B=l+12|0,s=n[m>>2]|0,n[m>>2]=n[B>>2],n[B>>2]=s,n[l>>2]=n[f>>2]}function hbe(s){s=s|0;var l=0,c=0,f=0;l=n[s+4>>2]|0,c=s+8|0,f=n[c>>2]|0,(f|0)!=(l|0)&&(n[c>>2]=f+(~(((f+-12-l|0)>>>0)/12|0)*12|0)),s=n[s>>2]|0,s|0&&gt(s)}function Q5(s){s=s|0,mbe(s)}function gbe(s){s=s|0,dbe(s+24|0)}function dbe(s){s=s|0;var l=0,c=0,f=0;c=n[s>>2]|0,f=c,c|0&&(s=s+4|0,l=n[s>>2]|0,(l|0)!=(c|0)&&(n[s>>2]=l+(~(((l+-12-f|0)>>>0)/12|0)*12|0)),gt(c))}function mbe(s){s=s|0;var l=0;l=Kr()|0,Vr(s,2,1,l,ybe()|0,1),n[s+24>>2]=0,n[s+28>>2]=0,n[s+32>>2]=0}function ybe(){return 1224}function Ebe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0,k=0;return d=E,E=E+16|0,m=d+8|0,B=d,k=Cbe(s)|0,s=n[k+4>>2]|0,n[B>>2]=n[k>>2],n[B+4>>2]=s,n[m>>2]=n[B>>2],n[m+4>>2]=n[B+4>>2],f=+wbe(l,m,c),E=d,+f}function Cbe(s){return s=s|0,(n[(WF()|0)+24>>2]|0)+(s*12|0)|0}function wbe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0;return m=E,E=E+16|0,d=m,f=n[l>>2]|0,l=n[l+4>>2]|0,s=s+(l>>1)|0,l&1&&(f=n[(n[s>>2]|0)+f>>2]|0),XA(d,c),d=ZA(d,c)|0,B=+bF(+b7[f&7](s,d)),E=m,+B}function Ibe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0,k=0;f=E,E=E+16|0,d=f+8|0,m=f,k=n[c>>2]|0,B=n[c+4>>2]|0,c=pn(l)|0,n[m>>2]=k,n[m+4>>2]=B,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],Bbe(s,c,d,1),E=f}function Bbe(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0,m=0,B=0,k=0,Q=0,M=0,O=0;d=E,E=E+32|0,m=d+16|0,O=d+8|0,k=d,M=n[c>>2]|0,Q=n[c+4>>2]|0,B=n[s>>2]|0,s=KF()|0,n[O>>2]=M,n[O+4>>2]=Q,n[m>>2]=n[O>>2],n[m+4>>2]=n[O+4>>2],c=vbe(m)|0,n[k>>2]=M,n[k+4>>2]=Q,n[m>>2]=n[k>>2],n[m+4>>2]=n[k+4>>2],hn(B,l,s,c,Dbe(m,f)|0,f),E=d}function KF(){var s=0,l=0;if(o[7712]|0||(R5(9556),tr(35,9556,U|0)|0,l=7712,n[l>>2]=1,n[l+4>>2]=0),!(Tr(9556)|0)){s=9556,l=s+36|0;do n[s>>2]=0,s=s+4|0;while((s|0)<(l|0));R5(9556)}return 9556}function vbe(s){return s=s|0,0}function Dbe(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0,B=0,k=0,Q=0,M=0,O=0,q=0;return O=E,E=E+32|0,d=O+24|0,B=O+16|0,k=O,Q=O+8|0,m=n[s>>2]|0,f=n[s+4>>2]|0,n[k>>2]=m,n[k+4>>2]=f,q=KF()|0,M=q+24|0,s=gr(l,4)|0,n[Q>>2]=s,l=q+28|0,c=n[l>>2]|0,c>>>0<(n[q+32>>2]|0)>>>0?(n[B>>2]=m,n[B+4>>2]=f,n[d>>2]=n[B>>2],n[d+4>>2]=n[B+4>>2],F5(c,d,s),s=(n[l>>2]|0)+12|0,n[l>>2]=s):(Pbe(M,k,Q),s=n[l>>2]|0),E=O,((s-(n[M>>2]|0)|0)/12|0)+-1|0}function F5(s,l,c){s=s|0,l=l|0,c=c|0;var f=0;f=n[l+4>>2]|0,n[s>>2]=n[l>>2],n[s+4>>2]=f,n[s+8>>2]=c}function Pbe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0,k=0,Q=0,M=0,O=0,q=0,se=0;if(M=E,E=E+48|0,f=M+32|0,B=M+24|0,k=M,Q=s+4|0,d=(((n[Q>>2]|0)-(n[s>>2]|0)|0)/12|0)+1|0,m=Sbe(s)|0,m>>>0<d>>>0)Jr(s);else{O=n[s>>2]|0,se=((n[s+8>>2]|0)-O|0)/12|0,q=se<<1,bbe(k,se>>>0<m>>>1>>>0?q>>>0<d>>>0?d:q:m,((n[Q>>2]|0)-O|0)/12|0,s+8|0),Q=k+8|0,m=n[Q>>2]|0,d=n[l+4>>2]|0,c=n[c>>2]|0,n[B>>2]=n[l>>2],n[B+4>>2]=d,n[f>>2]=n[B>>2],n[f+4>>2]=n[B+4>>2],F5(m,f,c),n[Q>>2]=(n[Q>>2]|0)+12,xbe(s,k),kbe(k),E=M;return}}function Sbe(s){return s=s|0,357913941}function bbe(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0;n[s+12>>2]=0,n[s+16>>2]=f;do if(l)if(l>>>0>357913941)Rt();else{d=Kt(l*12|0)|0;break}else d=0;while(0);n[s>>2]=d,f=d+(c*12|0)|0,n[s+8>>2]=f,n[s+4>>2]=f,n[s+12>>2]=d+(l*12|0)}function xbe(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0,B=0;f=n[s>>2]|0,B=s+4|0,m=l+4|0,d=(n[B>>2]|0)-f|0,c=(n[m>>2]|0)+(((d|0)/-12|0)*12|0)|0,n[m>>2]=c,(d|0)>0?(Dr(c|0,f|0,d|0)|0,f=m,c=n[m>>2]|0):f=m,m=n[s>>2]|0,n[s>>2]=c,n[f>>2]=m,m=l+8|0,d=n[B>>2]|0,n[B>>2]=n[m>>2],n[m>>2]=d,m=s+8|0,B=l+12|0,s=n[m>>2]|0,n[m>>2]=n[B>>2],n[B>>2]=s,n[l>>2]=n[f>>2]}function kbe(s){s=s|0;var l=0,c=0,f=0;l=n[s+4>>2]|0,c=s+8|0,f=n[c>>2]|0,(f|0)!=(l|0)&&(n[c>>2]=f+(~(((f+-12-l|0)>>>0)/12|0)*12|0)),s=n[s>>2]|0,s|0&&gt(s)}function R5(s){s=s|0,Rbe(s)}function Qbe(s){s=s|0,Fbe(s+24|0)}function Fbe(s){s=s|0;var l=0,c=0,f=0;c=n[s>>2]|0,f=c,c|0&&(s=s+4|0,l=n[s>>2]|0,(l|0)!=(c|0)&&(n[s>>2]=l+(~(((l+-12-f|0)>>>0)/12|0)*12|0)),gt(c))}function Rbe(s){s=s|0;var l=0;l=Kr()|0,Vr(s,2,5,l,Tbe()|0,0),n[s+24>>2]=0,n[s+28>>2]=0,n[s+32>>2]=0}function Tbe(){return 1232}function Nbe(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0,B=0;return f=E,E=E+16|0,d=f+8|0,m=f,B=Lbe(s)|0,s=n[B+4>>2]|0,n[m>>2]=n[B>>2],n[m+4>>2]=s,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],c=+Obe(l,d),E=f,+c}function Lbe(s){return s=s|0,(n[(KF()|0)+24>>2]|0)+(s*12|0)|0}function Obe(s,l){s=s|0,l=l|0;var c=0;return c=n[l>>2]|0,l=n[l+4>>2]|0,s=s+(l>>1)|0,l&1&&(c=n[(n[s>>2]|0)+c>>2]|0),+ +bF(+S7[c&15](s))}function Mbe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0,k=0;f=E,E=E+16|0,d=f+8|0,m=f,k=n[c>>2]|0,B=n[c+4>>2]|0,c=pn(l)|0,n[m>>2]=k,n[m+4>>2]=B,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],Ube(s,c,d,1),E=f}function Ube(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0,m=0,B=0,k=0,Q=0,M=0,O=0;d=E,E=E+32|0,m=d+16|0,O=d+8|0,k=d,M=n[c>>2]|0,Q=n[c+4>>2]|0,B=n[s>>2]|0,s=VF()|0,n[O>>2]=M,n[O+4>>2]=Q,n[m>>2]=n[O>>2],n[m+4>>2]=n[O+4>>2],c=_be(m)|0,n[k>>2]=M,n[k+4>>2]=Q,n[m>>2]=n[k>>2],n[m+4>>2]=n[k+4>>2],hn(B,l,s,c,Hbe(m,f)|0,f),E=d}function VF(){var s=0,l=0;if(o[7720]|0||(N5(9592),tr(36,9592,U|0)|0,l=7720,n[l>>2]=1,n[l+4>>2]=0),!(Tr(9592)|0)){s=9592,l=s+36|0;do n[s>>2]=0,s=s+4|0;while((s|0)<(l|0));N5(9592)}return 9592}function _be(s){return s=s|0,0}function Hbe(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0,B=0,k=0,Q=0,M=0,O=0,q=0;return O=E,E=E+32|0,d=O+24|0,B=O+16|0,k=O,Q=O+8|0,m=n[s>>2]|0,f=n[s+4>>2]|0,n[k>>2]=m,n[k+4>>2]=f,q=VF()|0,M=q+24|0,s=gr(l,4)|0,n[Q>>2]=s,l=q+28|0,c=n[l>>2]|0,c>>>0<(n[q+32>>2]|0)>>>0?(n[B>>2]=m,n[B+4>>2]=f,n[d>>2]=n[B>>2],n[d+4>>2]=n[B+4>>2],T5(c,d,s),s=(n[l>>2]|0)+12|0,n[l>>2]=s):(jbe(M,k,Q),s=n[l>>2]|0),E=O,((s-(n[M>>2]|0)|0)/12|0)+-1|0}function T5(s,l,c){s=s|0,l=l|0,c=c|0;var f=0;f=n[l+4>>2]|0,n[s>>2]=n[l>>2],n[s+4>>2]=f,n[s+8>>2]=c}function jbe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0,k=0,Q=0,M=0,O=0,q=0,se=0;if(M=E,E=E+48|0,f=M+32|0,B=M+24|0,k=M,Q=s+4|0,d=(((n[Q>>2]|0)-(n[s>>2]|0)|0)/12|0)+1|0,m=qbe(s)|0,m>>>0<d>>>0)Jr(s);else{O=n[s>>2]|0,se=((n[s+8>>2]|0)-O|0)/12|0,q=se<<1,Gbe(k,se>>>0<m>>>1>>>0?q>>>0<d>>>0?d:q:m,((n[Q>>2]|0)-O|0)/12|0,s+8|0),Q=k+8|0,m=n[Q>>2]|0,d=n[l+4>>2]|0,c=n[c>>2]|0,n[B>>2]=n[l>>2],n[B+4>>2]=d,n[f>>2]=n[B>>2],n[f+4>>2]=n[B+4>>2],T5(m,f,c),n[Q>>2]=(n[Q>>2]|0)+12,Ybe(s,k),Wbe(k),E=M;return}}function qbe(s){return s=s|0,357913941}function Gbe(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0;n[s+12>>2]=0,n[s+16>>2]=f;do if(l)if(l>>>0>357913941)Rt();else{d=Kt(l*12|0)|0;break}else d=0;while(0);n[s>>2]=d,f=d+(c*12|0)|0,n[s+8>>2]=f,n[s+4>>2]=f,n[s+12>>2]=d+(l*12|0)}function Ybe(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0,B=0;f=n[s>>2]|0,B=s+4|0,m=l+4|0,d=(n[B>>2]|0)-f|0,c=(n[m>>2]|0)+(((d|0)/-12|0)*12|0)|0,n[m>>2]=c,(d|0)>0?(Dr(c|0,f|0,d|0)|0,f=m,c=n[m>>2]|0):f=m,m=n[s>>2]|0,n[s>>2]=c,n[f>>2]=m,m=l+8|0,d=n[B>>2]|0,n[B>>2]=n[m>>2],n[m>>2]=d,m=s+8|0,B=l+12|0,s=n[m>>2]|0,n[m>>2]=n[B>>2],n[B>>2]=s,n[l>>2]=n[f>>2]}function Wbe(s){s=s|0;var l=0,c=0,f=0;l=n[s+4>>2]|0,c=s+8|0,f=n[c>>2]|0,(f|0)!=(l|0)&&(n[c>>2]=f+(~(((f+-12-l|0)>>>0)/12|0)*12|0)),s=n[s>>2]|0,s|0&&gt(s)}function N5(s){s=s|0,zbe(s)}function Kbe(s){s=s|0,Vbe(s+24|0)}function Vbe(s){s=s|0;var l=0,c=0,f=0;c=n[s>>2]|0,f=c,c|0&&(s=s+4|0,l=n[s>>2]|0,(l|0)!=(c|0)&&(n[s>>2]=l+(~(((l+-12-f|0)>>>0)/12|0)*12|0)),gt(c))}function zbe(s){s=s|0;var l=0;l=Kr()|0,Vr(s,2,7,l,Jbe()|0,0),n[s+24>>2]=0,n[s+28>>2]=0,n[s+32>>2]=0}function Jbe(){return 1276}function Xbe(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0;return c=E,E=E+16|0,f=c+8|0,d=c,m=Zbe(s)|0,s=n[m+4>>2]|0,n[d>>2]=n[m>>2],n[d+4>>2]=s,n[f>>2]=n[d>>2],n[f+4>>2]=n[d+4>>2],l=$be(l,f)|0,E=c,l|0}function Zbe(s){return s=s|0,(n[(VF()|0)+24>>2]|0)+(s*12|0)|0}function $be(s,l){s=s|0,l=l|0;var c=0,f=0,d=0;return d=E,E=E+16|0,f=d,c=n[l>>2]|0,l=n[l+4>>2]|0,s=s+(l>>1)|0,l&1&&(c=n[(n[s>>2]|0)+c>>2]|0),tf[c&31](f,s),f=L5(f)|0,E=d,f|0}function L5(s){s=s|0;var l=0,c=0,f=0,d=0;return d=E,E=E+32|0,l=d+12|0,c=d,f=QF(O5()|0)|0,f?(FF(l,f),RF(c,l),exe(s,c),s=TF(l)|0):s=txe(s)|0,E=d,s|0}function O5(){var s=0;return o[7736]|0||(Axe(9640),tr(25,9640,U|0)|0,s=7736,n[s>>2]=1,n[s+4>>2]=0),9640}function exe(s,l){s=s|0,l=l|0,sxe(l,s,s+8|0)|0}function txe(s){s=s|0;var l=0,c=0,f=0,d=0,m=0,B=0,k=0;return c=E,E=E+16|0,d=c+4|0,B=c,f=Wa(8)|0,l=f,k=Kt(16)|0,n[k>>2]=n[s>>2],n[k+4>>2]=n[s+4>>2],n[k+8>>2]=n[s+8>>2],n[k+12>>2]=n[s+12>>2],m=l+4|0,n[m>>2]=k,s=Kt(8)|0,m=n[m>>2]|0,n[B>>2]=0,n[d>>2]=n[B>>2],zF(s,m,d),n[f>>2]=s,E=c,l|0}function zF(s,l,c){s=s|0,l=l|0,c=c|0,n[s>>2]=l,c=Kt(16)|0,n[c+4>>2]=0,n[c+8>>2]=0,n[c>>2]=1244,n[c+12>>2]=l,n[s+4>>2]=c}function rxe(s){s=s|0,Vm(s),gt(s)}function nxe(s){s=s|0,s=n[s+12>>2]|0,s|0&&gt(s)}function ixe(s){s=s|0,gt(s)}function sxe(s,l,c){return s=s|0,l=l|0,c=c|0,l=oxe(n[s>>2]|0,l,c)|0,c=s+4|0,n[(n[c>>2]|0)+8>>2]=l,n[(n[c>>2]|0)+8>>2]|0}function oxe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0;return f=E,E=E+16|0,d=f,Ka(d),s=da(s)|0,c=axe(s,n[l>>2]|0,+C[c>>3])|0,Va(d),E=f,c|0}function axe(s,l,c){s=s|0,l=l|0,c=+c;var f=0;return f=Pl(lxe()|0)|0,l=SF(l)|0,ml(0,f|0,s|0,l|0,+ +VA(c))|0}function lxe(){var s=0;return o[7728]|0||(cxe(9628),s=7728,n[s>>2]=1,n[s+4>>2]=0),9628}function cxe(s){s=s|0,Sl(s,uxe()|0,2)}function uxe(){return 1264}function Axe(s){s=s|0,Ip(s)}function fxe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0,k=0;f=E,E=E+16|0,d=f+8|0,m=f,k=n[c>>2]|0,B=n[c+4>>2]|0,c=pn(l)|0,n[m>>2]=k,n[m+4>>2]=B,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],pxe(s,c,d,1),E=f}function pxe(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0,m=0,B=0,k=0,Q=0,M=0,O=0;d=E,E=E+32|0,m=d+16|0,O=d+8|0,k=d,M=n[c>>2]|0,Q=n[c+4>>2]|0,B=n[s>>2]|0,s=JF()|0,n[O>>2]=M,n[O+4>>2]=Q,n[m>>2]=n[O>>2],n[m+4>>2]=n[O+4>>2],c=hxe(m)|0,n[k>>2]=M,n[k+4>>2]=Q,n[m>>2]=n[k>>2],n[m+4>>2]=n[k+4>>2],hn(B,l,s,c,gxe(m,f)|0,f),E=d}function JF(){var s=0,l=0;if(o[7744]|0||(U5(9684),tr(37,9684,U|0)|0,l=7744,n[l>>2]=1,n[l+4>>2]=0),!(Tr(9684)|0)){s=9684,l=s+36|0;do n[s>>2]=0,s=s+4|0;while((s|0)<(l|0));U5(9684)}return 9684}function hxe(s){return s=s|0,0}function gxe(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0,B=0,k=0,Q=0,M=0,O=0,q=0;return O=E,E=E+32|0,d=O+24|0,B=O+16|0,k=O,Q=O+8|0,m=n[s>>2]|0,f=n[s+4>>2]|0,n[k>>2]=m,n[k+4>>2]=f,q=JF()|0,M=q+24|0,s=gr(l,4)|0,n[Q>>2]=s,l=q+28|0,c=n[l>>2]|0,c>>>0<(n[q+32>>2]|0)>>>0?(n[B>>2]=m,n[B+4>>2]=f,n[d>>2]=n[B>>2],n[d+4>>2]=n[B+4>>2],M5(c,d,s),s=(n[l>>2]|0)+12|0,n[l>>2]=s):(dxe(M,k,Q),s=n[l>>2]|0),E=O,((s-(n[M>>2]|0)|0)/12|0)+-1|0}function M5(s,l,c){s=s|0,l=l|0,c=c|0;var f=0;f=n[l+4>>2]|0,n[s>>2]=n[l>>2],n[s+4>>2]=f,n[s+8>>2]=c}function dxe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0,k=0,Q=0,M=0,O=0,q=0,se=0;if(M=E,E=E+48|0,f=M+32|0,B=M+24|0,k=M,Q=s+4|0,d=(((n[Q>>2]|0)-(n[s>>2]|0)|0)/12|0)+1|0,m=mxe(s)|0,m>>>0<d>>>0)Jr(s);else{O=n[s>>2]|0,se=((n[s+8>>2]|0)-O|0)/12|0,q=se<<1,yxe(k,se>>>0<m>>>1>>>0?q>>>0<d>>>0?d:q:m,((n[Q>>2]|0)-O|0)/12|0,s+8|0),Q=k+8|0,m=n[Q>>2]|0,d=n[l+4>>2]|0,c=n[c>>2]|0,n[B>>2]=n[l>>2],n[B+4>>2]=d,n[f>>2]=n[B>>2],n[f+4>>2]=n[B+4>>2],M5(m,f,c),n[Q>>2]=(n[Q>>2]|0)+12,Exe(s,k),Cxe(k),E=M;return}}function mxe(s){return s=s|0,357913941}function yxe(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0;n[s+12>>2]=0,n[s+16>>2]=f;do if(l)if(l>>>0>357913941)Rt();else{d=Kt(l*12|0)|0;break}else d=0;while(0);n[s>>2]=d,f=d+(c*12|0)|0,n[s+8>>2]=f,n[s+4>>2]=f,n[s+12>>2]=d+(l*12|0)}function Exe(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0,B=0;f=n[s>>2]|0,B=s+4|0,m=l+4|0,d=(n[B>>2]|0)-f|0,c=(n[m>>2]|0)+(((d|0)/-12|0)*12|0)|0,n[m>>2]=c,(d|0)>0?(Dr(c|0,f|0,d|0)|0,f=m,c=n[m>>2]|0):f=m,m=n[s>>2]|0,n[s>>2]=c,n[f>>2]=m,m=l+8|0,d=n[B>>2]|0,n[B>>2]=n[m>>2],n[m>>2]=d,m=s+8|0,B=l+12|0,s=n[m>>2]|0,n[m>>2]=n[B>>2],n[B>>2]=s,n[l>>2]=n[f>>2]}function Cxe(s){s=s|0;var l=0,c=0,f=0;l=n[s+4>>2]|0,c=s+8|0,f=n[c>>2]|0,(f|0)!=(l|0)&&(n[c>>2]=f+(~(((f+-12-l|0)>>>0)/12|0)*12|0)),s=n[s>>2]|0,s|0&&gt(s)}function U5(s){s=s|0,Bxe(s)}function wxe(s){s=s|0,Ixe(s+24|0)}function Ixe(s){s=s|0;var l=0,c=0,f=0;c=n[s>>2]|0,f=c,c|0&&(s=s+4|0,l=n[s>>2]|0,(l|0)!=(c|0)&&(n[s>>2]=l+(~(((l+-12-f|0)>>>0)/12|0)*12|0)),gt(c))}function Bxe(s){s=s|0;var l=0;l=Kr()|0,Vr(s,2,5,l,vxe()|0,1),n[s+24>>2]=0,n[s+28>>2]=0,n[s+32>>2]=0}function vxe(){return 1280}function Dxe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0;return f=E,E=E+16|0,d=f+8|0,m=f,B=Pxe(s)|0,s=n[B+4>>2]|0,n[m>>2]=n[B>>2],n[m+4>>2]=s,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],c=Sxe(l,d,c)|0,E=f,c|0}function Pxe(s){return s=s|0,(n[(JF()|0)+24>>2]|0)+(s*12|0)|0}function Sxe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0;return B=E,E=E+32|0,d=B,m=B+16|0,f=n[l>>2]|0,l=n[l+4>>2]|0,s=s+(l>>1)|0,l&1&&(f=n[(n[s>>2]|0)+f>>2]|0),XA(m,c),m=ZA(m,c)|0,Uw[f&15](d,s,m),m=L5(d)|0,E=B,m|0}function bxe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0,k=0;f=E,E=E+16|0,d=f+8|0,m=f,k=n[c>>2]|0,B=n[c+4>>2]|0,c=pn(l)|0,n[m>>2]=k,n[m+4>>2]=B,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],xxe(s,c,d,1),E=f}function xxe(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0,m=0,B=0,k=0,Q=0,M=0,O=0;d=E,E=E+32|0,m=d+16|0,O=d+8|0,k=d,M=n[c>>2]|0,Q=n[c+4>>2]|0,B=n[s>>2]|0,s=XF()|0,n[O>>2]=M,n[O+4>>2]=Q,n[m>>2]=n[O>>2],n[m+4>>2]=n[O+4>>2],c=kxe(m)|0,n[k>>2]=M,n[k+4>>2]=Q,n[m>>2]=n[k>>2],n[m+4>>2]=n[k+4>>2],hn(B,l,s,c,Qxe(m,f)|0,f),E=d}function XF(){var s=0,l=0;if(o[7752]|0||(H5(9720),tr(38,9720,U|0)|0,l=7752,n[l>>2]=1,n[l+4>>2]=0),!(Tr(9720)|0)){s=9720,l=s+36|0;do n[s>>2]=0,s=s+4|0;while((s|0)<(l|0));H5(9720)}return 9720}function kxe(s){return s=s|0,0}function Qxe(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0,B=0,k=0,Q=0,M=0,O=0,q=0;return O=E,E=E+32|0,d=O+24|0,B=O+16|0,k=O,Q=O+8|0,m=n[s>>2]|0,f=n[s+4>>2]|0,n[k>>2]=m,n[k+4>>2]=f,q=XF()|0,M=q+24|0,s=gr(l,4)|0,n[Q>>2]=s,l=q+28|0,c=n[l>>2]|0,c>>>0<(n[q+32>>2]|0)>>>0?(n[B>>2]=m,n[B+4>>2]=f,n[d>>2]=n[B>>2],n[d+4>>2]=n[B+4>>2],_5(c,d,s),s=(n[l>>2]|0)+12|0,n[l>>2]=s):(Fxe(M,k,Q),s=n[l>>2]|0),E=O,((s-(n[M>>2]|0)|0)/12|0)+-1|0}function _5(s,l,c){s=s|0,l=l|0,c=c|0;var f=0;f=n[l+4>>2]|0,n[s>>2]=n[l>>2],n[s+4>>2]=f,n[s+8>>2]=c}function Fxe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0,k=0,Q=0,M=0,O=0,q=0,se=0;if(M=E,E=E+48|0,f=M+32|0,B=M+24|0,k=M,Q=s+4|0,d=(((n[Q>>2]|0)-(n[s>>2]|0)|0)/12|0)+1|0,m=Rxe(s)|0,m>>>0<d>>>0)Jr(s);else{O=n[s>>2]|0,se=((n[s+8>>2]|0)-O|0)/12|0,q=se<<1,Txe(k,se>>>0<m>>>1>>>0?q>>>0<d>>>0?d:q:m,((n[Q>>2]|0)-O|0)/12|0,s+8|0),Q=k+8|0,m=n[Q>>2]|0,d=n[l+4>>2]|0,c=n[c>>2]|0,n[B>>2]=n[l>>2],n[B+4>>2]=d,n[f>>2]=n[B>>2],n[f+4>>2]=n[B+4>>2],_5(m,f,c),n[Q>>2]=(n[Q>>2]|0)+12,Nxe(s,k),Lxe(k),E=M;return}}function Rxe(s){return s=s|0,357913941}function Txe(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0;n[s+12>>2]=0,n[s+16>>2]=f;do if(l)if(l>>>0>357913941)Rt();else{d=Kt(l*12|0)|0;break}else d=0;while(0);n[s>>2]=d,f=d+(c*12|0)|0,n[s+8>>2]=f,n[s+4>>2]=f,n[s+12>>2]=d+(l*12|0)}function Nxe(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0,B=0;f=n[s>>2]|0,B=s+4|0,m=l+4|0,d=(n[B>>2]|0)-f|0,c=(n[m>>2]|0)+(((d|0)/-12|0)*12|0)|0,n[m>>2]=c,(d|0)>0?(Dr(c|0,f|0,d|0)|0,f=m,c=n[m>>2]|0):f=m,m=n[s>>2]|0,n[s>>2]=c,n[f>>2]=m,m=l+8|0,d=n[B>>2]|0,n[B>>2]=n[m>>2],n[m>>2]=d,m=s+8|0,B=l+12|0,s=n[m>>2]|0,n[m>>2]=n[B>>2],n[B>>2]=s,n[l>>2]=n[f>>2]}function Lxe(s){s=s|0;var l=0,c=0,f=0;l=n[s+4>>2]|0,c=s+8|0,f=n[c>>2]|0,(f|0)!=(l|0)&&(n[c>>2]=f+(~(((f+-12-l|0)>>>0)/12|0)*12|0)),s=n[s>>2]|0,s|0&&gt(s)}function H5(s){s=s|0,Uxe(s)}function Oxe(s){s=s|0,Mxe(s+24|0)}function Mxe(s){s=s|0;var l=0,c=0,f=0;c=n[s>>2]|0,f=c,c|0&&(s=s+4|0,l=n[s>>2]|0,(l|0)!=(c|0)&&(n[s>>2]=l+(~(((l+-12-f|0)>>>0)/12|0)*12|0)),gt(c))}function Uxe(s){s=s|0;var l=0;l=Kr()|0,Vr(s,2,8,l,_xe()|0,0),n[s+24>>2]=0,n[s+28>>2]=0,n[s+32>>2]=0}function _xe(){return 1288}function Hxe(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0;return c=E,E=E+16|0,f=c+8|0,d=c,m=jxe(s)|0,s=n[m+4>>2]|0,n[d>>2]=n[m>>2],n[d+4>>2]=s,n[f>>2]=n[d>>2],n[f+4>>2]=n[d+4>>2],l=qxe(l,f)|0,E=c,l|0}function jxe(s){return s=s|0,(n[(XF()|0)+24>>2]|0)+(s*12|0)|0}function qxe(s,l){s=s|0,l=l|0;var c=0;return c=n[l>>2]|0,l=n[l+4>>2]|0,s=s+(l>>1)|0,l&1&&(c=n[(n[s>>2]|0)+c>>2]|0),r5(Tg[c&31](s)|0)|0}function Gxe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0,k=0;f=E,E=E+16|0,d=f+8|0,m=f,k=n[c>>2]|0,B=n[c+4>>2]|0,c=pn(l)|0,n[m>>2]=k,n[m+4>>2]=B,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],Yxe(s,c,d,0),E=f}function Yxe(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0,m=0,B=0,k=0,Q=0,M=0,O=0;d=E,E=E+32|0,m=d+16|0,O=d+8|0,k=d,M=n[c>>2]|0,Q=n[c+4>>2]|0,B=n[s>>2]|0,s=ZF()|0,n[O>>2]=M,n[O+4>>2]=Q,n[m>>2]=n[O>>2],n[m+4>>2]=n[O+4>>2],c=Wxe(m)|0,n[k>>2]=M,n[k+4>>2]=Q,n[m>>2]=n[k>>2],n[m+4>>2]=n[k+4>>2],hn(B,l,s,c,Kxe(m,f)|0,f),E=d}function ZF(){var s=0,l=0;if(o[7760]|0||(q5(9756),tr(39,9756,U|0)|0,l=7760,n[l>>2]=1,n[l+4>>2]=0),!(Tr(9756)|0)){s=9756,l=s+36|0;do n[s>>2]=0,s=s+4|0;while((s|0)<(l|0));q5(9756)}return 9756}function Wxe(s){return s=s|0,0}function Kxe(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0,B=0,k=0,Q=0,M=0,O=0,q=0;return O=E,E=E+32|0,d=O+24|0,B=O+16|0,k=O,Q=O+8|0,m=n[s>>2]|0,f=n[s+4>>2]|0,n[k>>2]=m,n[k+4>>2]=f,q=ZF()|0,M=q+24|0,s=gr(l,4)|0,n[Q>>2]=s,l=q+28|0,c=n[l>>2]|0,c>>>0<(n[q+32>>2]|0)>>>0?(n[B>>2]=m,n[B+4>>2]=f,n[d>>2]=n[B>>2],n[d+4>>2]=n[B+4>>2],j5(c,d,s),s=(n[l>>2]|0)+12|0,n[l>>2]=s):(Vxe(M,k,Q),s=n[l>>2]|0),E=O,((s-(n[M>>2]|0)|0)/12|0)+-1|0}function j5(s,l,c){s=s|0,l=l|0,c=c|0;var f=0;f=n[l+4>>2]|0,n[s>>2]=n[l>>2],n[s+4>>2]=f,n[s+8>>2]=c}function Vxe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0,k=0,Q=0,M=0,O=0,q=0,se=0;if(M=E,E=E+48|0,f=M+32|0,B=M+24|0,k=M,Q=s+4|0,d=(((n[Q>>2]|0)-(n[s>>2]|0)|0)/12|0)+1|0,m=zxe(s)|0,m>>>0<d>>>0)Jr(s);else{O=n[s>>2]|0,se=((n[s+8>>2]|0)-O|0)/12|0,q=se<<1,Jxe(k,se>>>0<m>>>1>>>0?q>>>0<d>>>0?d:q:m,((n[Q>>2]|0)-O|0)/12|0,s+8|0),Q=k+8|0,m=n[Q>>2]|0,d=n[l+4>>2]|0,c=n[c>>2]|0,n[B>>2]=n[l>>2],n[B+4>>2]=d,n[f>>2]=n[B>>2],n[f+4>>2]=n[B+4>>2],j5(m,f,c),n[Q>>2]=(n[Q>>2]|0)+12,Xxe(s,k),Zxe(k),E=M;return}}function zxe(s){return s=s|0,357913941}function Jxe(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0;n[s+12>>2]=0,n[s+16>>2]=f;do if(l)if(l>>>0>357913941)Rt();else{d=Kt(l*12|0)|0;break}else d=0;while(0);n[s>>2]=d,f=d+(c*12|0)|0,n[s+8>>2]=f,n[s+4>>2]=f,n[s+12>>2]=d+(l*12|0)}function Xxe(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0,B=0;f=n[s>>2]|0,B=s+4|0,m=l+4|0,d=(n[B>>2]|0)-f|0,c=(n[m>>2]|0)+(((d|0)/-12|0)*12|0)|0,n[m>>2]=c,(d|0)>0?(Dr(c|0,f|0,d|0)|0,f=m,c=n[m>>2]|0):f=m,m=n[s>>2]|0,n[s>>2]=c,n[f>>2]=m,m=l+8|0,d=n[B>>2]|0,n[B>>2]=n[m>>2],n[m>>2]=d,m=s+8|0,B=l+12|0,s=n[m>>2]|0,n[m>>2]=n[B>>2],n[B>>2]=s,n[l>>2]=n[f>>2]}function Zxe(s){s=s|0;var l=0,c=0,f=0;l=n[s+4>>2]|0,c=s+8|0,f=n[c>>2]|0,(f|0)!=(l|0)&&(n[c>>2]=f+(~(((f+-12-l|0)>>>0)/12|0)*12|0)),s=n[s>>2]|0,s|0&&gt(s)}function q5(s){s=s|0,tke(s)}function $xe(s){s=s|0,eke(s+24|0)}function eke(s){s=s|0;var l=0,c=0,f=0;c=n[s>>2]|0,f=c,c|0&&(s=s+4|0,l=n[s>>2]|0,(l|0)!=(c|0)&&(n[s>>2]=l+(~(((l+-12-f|0)>>>0)/12|0)*12|0)),gt(c))}function tke(s){s=s|0;var l=0;l=Kr()|0,Vr(s,2,8,l,rke()|0,1),n[s+24>>2]=0,n[s+28>>2]=0,n[s+32>>2]=0}function rke(){return 1292}function nke(s,l,c){s=s|0,l=l|0,c=+c;var f=0,d=0,m=0,B=0;f=E,E=E+16|0,d=f+8|0,m=f,B=ike(s)|0,s=n[B+4>>2]|0,n[m>>2]=n[B>>2],n[m+4>>2]=s,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],ske(l,d,c),E=f}function ike(s){return s=s|0,(n[(ZF()|0)+24>>2]|0)+(s*12|0)|0}function ske(s,l,c){s=s|0,l=l|0,c=+c;var f=0,d=0,m=0;m=E,E=E+16|0,d=m,f=n[l>>2]|0,l=n[l+4>>2]|0,s=s+(l>>1)|0,l&1&&(f=n[(n[s>>2]|0)+f>>2]|0),ku(d,c),c=+Qu(d,c),v7[f&31](s,c),E=m}function oke(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0,k=0;f=E,E=E+16|0,d=f+8|0,m=f,k=n[c>>2]|0,B=n[c+4>>2]|0,c=pn(l)|0,n[m>>2]=k,n[m+4>>2]=B,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],ake(s,c,d,0),E=f}function ake(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0,m=0,B=0,k=0,Q=0,M=0,O=0;d=E,E=E+32|0,m=d+16|0,O=d+8|0,k=d,M=n[c>>2]|0,Q=n[c+4>>2]|0,B=n[s>>2]|0,s=$F()|0,n[O>>2]=M,n[O+4>>2]=Q,n[m>>2]=n[O>>2],n[m+4>>2]=n[O+4>>2],c=lke(m)|0,n[k>>2]=M,n[k+4>>2]=Q,n[m>>2]=n[k>>2],n[m+4>>2]=n[k+4>>2],hn(B,l,s,c,cke(m,f)|0,f),E=d}function $F(){var s=0,l=0;if(o[7768]|0||(Y5(9792),tr(40,9792,U|0)|0,l=7768,n[l>>2]=1,n[l+4>>2]=0),!(Tr(9792)|0)){s=9792,l=s+36|0;do n[s>>2]=0,s=s+4|0;while((s|0)<(l|0));Y5(9792)}return 9792}function lke(s){return s=s|0,0}function cke(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0,B=0,k=0,Q=0,M=0,O=0,q=0;return O=E,E=E+32|0,d=O+24|0,B=O+16|0,k=O,Q=O+8|0,m=n[s>>2]|0,f=n[s+4>>2]|0,n[k>>2]=m,n[k+4>>2]=f,q=$F()|0,M=q+24|0,s=gr(l,4)|0,n[Q>>2]=s,l=q+28|0,c=n[l>>2]|0,c>>>0<(n[q+32>>2]|0)>>>0?(n[B>>2]=m,n[B+4>>2]=f,n[d>>2]=n[B>>2],n[d+4>>2]=n[B+4>>2],G5(c,d,s),s=(n[l>>2]|0)+12|0,n[l>>2]=s):(uke(M,k,Q),s=n[l>>2]|0),E=O,((s-(n[M>>2]|0)|0)/12|0)+-1|0}function G5(s,l,c){s=s|0,l=l|0,c=c|0;var f=0;f=n[l+4>>2]|0,n[s>>2]=n[l>>2],n[s+4>>2]=f,n[s+8>>2]=c}function uke(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0,k=0,Q=0,M=0,O=0,q=0,se=0;if(M=E,E=E+48|0,f=M+32|0,B=M+24|0,k=M,Q=s+4|0,d=(((n[Q>>2]|0)-(n[s>>2]|0)|0)/12|0)+1|0,m=Ake(s)|0,m>>>0<d>>>0)Jr(s);else{O=n[s>>2]|0,se=((n[s+8>>2]|0)-O|0)/12|0,q=se<<1,fke(k,se>>>0<m>>>1>>>0?q>>>0<d>>>0?d:q:m,((n[Q>>2]|0)-O|0)/12|0,s+8|0),Q=k+8|0,m=n[Q>>2]|0,d=n[l+4>>2]|0,c=n[c>>2]|0,n[B>>2]=n[l>>2],n[B+4>>2]=d,n[f>>2]=n[B>>2],n[f+4>>2]=n[B+4>>2],G5(m,f,c),n[Q>>2]=(n[Q>>2]|0)+12,pke(s,k),hke(k),E=M;return}}function Ake(s){return s=s|0,357913941}function fke(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0;n[s+12>>2]=0,n[s+16>>2]=f;do if(l)if(l>>>0>357913941)Rt();else{d=Kt(l*12|0)|0;break}else d=0;while(0);n[s>>2]=d,f=d+(c*12|0)|0,n[s+8>>2]=f,n[s+4>>2]=f,n[s+12>>2]=d+(l*12|0)}function pke(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0,B=0;f=n[s>>2]|0,B=s+4|0,m=l+4|0,d=(n[B>>2]|0)-f|0,c=(n[m>>2]|0)+(((d|0)/-12|0)*12|0)|0,n[m>>2]=c,(d|0)>0?(Dr(c|0,f|0,d|0)|0,f=m,c=n[m>>2]|0):f=m,m=n[s>>2]|0,n[s>>2]=c,n[f>>2]=m,m=l+8|0,d=n[B>>2]|0,n[B>>2]=n[m>>2],n[m>>2]=d,m=s+8|0,B=l+12|0,s=n[m>>2]|0,n[m>>2]=n[B>>2],n[B>>2]=s,n[l>>2]=n[f>>2]}function hke(s){s=s|0;var l=0,c=0,f=0;l=n[s+4>>2]|0,c=s+8|0,f=n[c>>2]|0,(f|0)!=(l|0)&&(n[c>>2]=f+(~(((f+-12-l|0)>>>0)/12|0)*12|0)),s=n[s>>2]|0,s|0&&gt(s)}function Y5(s){s=s|0,mke(s)}function gke(s){s=s|0,dke(s+24|0)}function dke(s){s=s|0;var l=0,c=0,f=0;c=n[s>>2]|0,f=c,c|0&&(s=s+4|0,l=n[s>>2]|0,(l|0)!=(c|0)&&(n[s>>2]=l+(~(((l+-12-f|0)>>>0)/12|0)*12|0)),gt(c))}function mke(s){s=s|0;var l=0;l=Kr()|0,Vr(s,2,1,l,yke()|0,2),n[s+24>>2]=0,n[s+28>>2]=0,n[s+32>>2]=0}function yke(){return 1300}function Eke(s,l,c,f){s=s|0,l=l|0,c=c|0,f=+f;var d=0,m=0,B=0,k=0;d=E,E=E+16|0,m=d+8|0,B=d,k=Cke(s)|0,s=n[k+4>>2]|0,n[B>>2]=n[k>>2],n[B+4>>2]=s,n[m>>2]=n[B>>2],n[m+4>>2]=n[B+4>>2],wke(l,m,c,f),E=d}function Cke(s){return s=s|0,(n[($F()|0)+24>>2]|0)+(s*12|0)|0}function wke(s,l,c,f){s=s|0,l=l|0,c=c|0,f=+f;var d=0,m=0,B=0,k=0;k=E,E=E+16|0,m=k+1|0,B=k,d=n[l>>2]|0,l=n[l+4>>2]|0,s=s+(l>>1)|0,l&1&&(d=n[(n[s>>2]|0)+d>>2]|0),XA(m,c),m=ZA(m,c)|0,ku(B,f),f=+Qu(B,f),F7[d&15](s,m,f),E=k}function Ike(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0,k=0;f=E,E=E+16|0,d=f+8|0,m=f,k=n[c>>2]|0,B=n[c+4>>2]|0,c=pn(l)|0,n[m>>2]=k,n[m+4>>2]=B,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],Bke(s,c,d,0),E=f}function Bke(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0,m=0,B=0,k=0,Q=0,M=0,O=0;d=E,E=E+32|0,m=d+16|0,O=d+8|0,k=d,M=n[c>>2]|0,Q=n[c+4>>2]|0,B=n[s>>2]|0,s=eR()|0,n[O>>2]=M,n[O+4>>2]=Q,n[m>>2]=n[O>>2],n[m+4>>2]=n[O+4>>2],c=vke(m)|0,n[k>>2]=M,n[k+4>>2]=Q,n[m>>2]=n[k>>2],n[m+4>>2]=n[k+4>>2],hn(B,l,s,c,Dke(m,f)|0,f),E=d}function eR(){var s=0,l=0;if(o[7776]|0||(K5(9828),tr(41,9828,U|0)|0,l=7776,n[l>>2]=1,n[l+4>>2]=0),!(Tr(9828)|0)){s=9828,l=s+36|0;do n[s>>2]=0,s=s+4|0;while((s|0)<(l|0));K5(9828)}return 9828}function vke(s){return s=s|0,0}function Dke(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0,B=0,k=0,Q=0,M=0,O=0,q=0;return O=E,E=E+32|0,d=O+24|0,B=O+16|0,k=O,Q=O+8|0,m=n[s>>2]|0,f=n[s+4>>2]|0,n[k>>2]=m,n[k+4>>2]=f,q=eR()|0,M=q+24|0,s=gr(l,4)|0,n[Q>>2]=s,l=q+28|0,c=n[l>>2]|0,c>>>0<(n[q+32>>2]|0)>>>0?(n[B>>2]=m,n[B+4>>2]=f,n[d>>2]=n[B>>2],n[d+4>>2]=n[B+4>>2],W5(c,d,s),s=(n[l>>2]|0)+12|0,n[l>>2]=s):(Pke(M,k,Q),s=n[l>>2]|0),E=O,((s-(n[M>>2]|0)|0)/12|0)+-1|0}function W5(s,l,c){s=s|0,l=l|0,c=c|0;var f=0;f=n[l+4>>2]|0,n[s>>2]=n[l>>2],n[s+4>>2]=f,n[s+8>>2]=c}function Pke(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0,k=0,Q=0,M=0,O=0,q=0,se=0;if(M=E,E=E+48|0,f=M+32|0,B=M+24|0,k=M,Q=s+4|0,d=(((n[Q>>2]|0)-(n[s>>2]|0)|0)/12|0)+1|0,m=Ske(s)|0,m>>>0<d>>>0)Jr(s);else{O=n[s>>2]|0,se=((n[s+8>>2]|0)-O|0)/12|0,q=se<<1,bke(k,se>>>0<m>>>1>>>0?q>>>0<d>>>0?d:q:m,((n[Q>>2]|0)-O|0)/12|0,s+8|0),Q=k+8|0,m=n[Q>>2]|0,d=n[l+4>>2]|0,c=n[c>>2]|0,n[B>>2]=n[l>>2],n[B+4>>2]=d,n[f>>2]=n[B>>2],n[f+4>>2]=n[B+4>>2],W5(m,f,c),n[Q>>2]=(n[Q>>2]|0)+12,xke(s,k),kke(k),E=M;return}}function Ske(s){return s=s|0,357913941}function bke(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0;n[s+12>>2]=0,n[s+16>>2]=f;do if(l)if(l>>>0>357913941)Rt();else{d=Kt(l*12|0)|0;break}else d=0;while(0);n[s>>2]=d,f=d+(c*12|0)|0,n[s+8>>2]=f,n[s+4>>2]=f,n[s+12>>2]=d+(l*12|0)}function xke(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0,B=0;f=n[s>>2]|0,B=s+4|0,m=l+4|0,d=(n[B>>2]|0)-f|0,c=(n[m>>2]|0)+(((d|0)/-12|0)*12|0)|0,n[m>>2]=c,(d|0)>0?(Dr(c|0,f|0,d|0)|0,f=m,c=n[m>>2]|0):f=m,m=n[s>>2]|0,n[s>>2]=c,n[f>>2]=m,m=l+8|0,d=n[B>>2]|0,n[B>>2]=n[m>>2],n[m>>2]=d,m=s+8|0,B=l+12|0,s=n[m>>2]|0,n[m>>2]=n[B>>2],n[B>>2]=s,n[l>>2]=n[f>>2]}function kke(s){s=s|0;var l=0,c=0,f=0;l=n[s+4>>2]|0,c=s+8|0,f=n[c>>2]|0,(f|0)!=(l|0)&&(n[c>>2]=f+(~(((f+-12-l|0)>>>0)/12|0)*12|0)),s=n[s>>2]|0,s|0&&gt(s)}function K5(s){s=s|0,Rke(s)}function Qke(s){s=s|0,Fke(s+24|0)}function Fke(s){s=s|0;var l=0,c=0,f=0;c=n[s>>2]|0,f=c,c|0&&(s=s+4|0,l=n[s>>2]|0,(l|0)!=(c|0)&&(n[s>>2]=l+(~(((l+-12-f|0)>>>0)/12|0)*12|0)),gt(c))}function Rke(s){s=s|0;var l=0;l=Kr()|0,Vr(s,2,7,l,Tke()|0,1),n[s+24>>2]=0,n[s+28>>2]=0,n[s+32>>2]=0}function Tke(){return 1312}function Nke(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0;f=E,E=E+16|0,d=f+8|0,m=f,B=Lke(s)|0,s=n[B+4>>2]|0,n[m>>2]=n[B>>2],n[m+4>>2]=s,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],Oke(l,d,c),E=f}function Lke(s){return s=s|0,(n[(eR()|0)+24>>2]|0)+(s*12|0)|0}function Oke(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0;m=E,E=E+16|0,d=m,f=n[l>>2]|0,l=n[l+4>>2]|0,s=s+(l>>1)|0,l&1&&(f=n[(n[s>>2]|0)+f>>2]|0),XA(d,c),d=ZA(d,c)|0,tf[f&31](s,d),E=m}function Mke(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0,k=0;f=E,E=E+16|0,d=f+8|0,m=f,k=n[c>>2]|0,B=n[c+4>>2]|0,c=pn(l)|0,n[m>>2]=k,n[m+4>>2]=B,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],Uke(s,c,d,0),E=f}function Uke(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0,m=0,B=0,k=0,Q=0,M=0,O=0;d=E,E=E+32|0,m=d+16|0,O=d+8|0,k=d,M=n[c>>2]|0,Q=n[c+4>>2]|0,B=n[s>>2]|0,s=tR()|0,n[O>>2]=M,n[O+4>>2]=Q,n[m>>2]=n[O>>2],n[m+4>>2]=n[O+4>>2],c=_ke(m)|0,n[k>>2]=M,n[k+4>>2]=Q,n[m>>2]=n[k>>2],n[m+4>>2]=n[k+4>>2],hn(B,l,s,c,Hke(m,f)|0,f),E=d}function tR(){var s=0,l=0;if(o[7784]|0||(z5(9864),tr(42,9864,U|0)|0,l=7784,n[l>>2]=1,n[l+4>>2]=0),!(Tr(9864)|0)){s=9864,l=s+36|0;do n[s>>2]=0,s=s+4|0;while((s|0)<(l|0));z5(9864)}return 9864}function _ke(s){return s=s|0,0}function Hke(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0,B=0,k=0,Q=0,M=0,O=0,q=0;return O=E,E=E+32|0,d=O+24|0,B=O+16|0,k=O,Q=O+8|0,m=n[s>>2]|0,f=n[s+4>>2]|0,n[k>>2]=m,n[k+4>>2]=f,q=tR()|0,M=q+24|0,s=gr(l,4)|0,n[Q>>2]=s,l=q+28|0,c=n[l>>2]|0,c>>>0<(n[q+32>>2]|0)>>>0?(n[B>>2]=m,n[B+4>>2]=f,n[d>>2]=n[B>>2],n[d+4>>2]=n[B+4>>2],V5(c,d,s),s=(n[l>>2]|0)+12|0,n[l>>2]=s):(jke(M,k,Q),s=n[l>>2]|0),E=O,((s-(n[M>>2]|0)|0)/12|0)+-1|0}function V5(s,l,c){s=s|0,l=l|0,c=c|0;var f=0;f=n[l+4>>2]|0,n[s>>2]=n[l>>2],n[s+4>>2]=f,n[s+8>>2]=c}function jke(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0,k=0,Q=0,M=0,O=0,q=0,se=0;if(M=E,E=E+48|0,f=M+32|0,B=M+24|0,k=M,Q=s+4|0,d=(((n[Q>>2]|0)-(n[s>>2]|0)|0)/12|0)+1|0,m=qke(s)|0,m>>>0<d>>>0)Jr(s);else{O=n[s>>2]|0,se=((n[s+8>>2]|0)-O|0)/12|0,q=se<<1,Gke(k,se>>>0<m>>>1>>>0?q>>>0<d>>>0?d:q:m,((n[Q>>2]|0)-O|0)/12|0,s+8|0),Q=k+8|0,m=n[Q>>2]|0,d=n[l+4>>2]|0,c=n[c>>2]|0,n[B>>2]=n[l>>2],n[B+4>>2]=d,n[f>>2]=n[B>>2],n[f+4>>2]=n[B+4>>2],V5(m,f,c),n[Q>>2]=(n[Q>>2]|0)+12,Yke(s,k),Wke(k),E=M;return}}function qke(s){return s=s|0,357913941}function Gke(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0;n[s+12>>2]=0,n[s+16>>2]=f;do if(l)if(l>>>0>357913941)Rt();else{d=Kt(l*12|0)|0;break}else d=0;while(0);n[s>>2]=d,f=d+(c*12|0)|0,n[s+8>>2]=f,n[s+4>>2]=f,n[s+12>>2]=d+(l*12|0)}function Yke(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0,B=0;f=n[s>>2]|0,B=s+4|0,m=l+4|0,d=(n[B>>2]|0)-f|0,c=(n[m>>2]|0)+(((d|0)/-12|0)*12|0)|0,n[m>>2]=c,(d|0)>0?(Dr(c|0,f|0,d|0)|0,f=m,c=n[m>>2]|0):f=m,m=n[s>>2]|0,n[s>>2]=c,n[f>>2]=m,m=l+8|0,d=n[B>>2]|0,n[B>>2]=n[m>>2],n[m>>2]=d,m=s+8|0,B=l+12|0,s=n[m>>2]|0,n[m>>2]=n[B>>2],n[B>>2]=s,n[l>>2]=n[f>>2]}function Wke(s){s=s|0;var l=0,c=0,f=0;l=n[s+4>>2]|0,c=s+8|0,f=n[c>>2]|0,(f|0)!=(l|0)&&(n[c>>2]=f+(~(((f+-12-l|0)>>>0)/12|0)*12|0)),s=n[s>>2]|0,s|0&&gt(s)}function z5(s){s=s|0,zke(s)}function Kke(s){s=s|0,Vke(s+24|0)}function Vke(s){s=s|0;var l=0,c=0,f=0;c=n[s>>2]|0,f=c,c|0&&(s=s+4|0,l=n[s>>2]|0,(l|0)!=(c|0)&&(n[s>>2]=l+(~(((l+-12-f|0)>>>0)/12|0)*12|0)),gt(c))}function zke(s){s=s|0;var l=0;l=Kr()|0,Vr(s,2,8,l,Jke()|0,1),n[s+24>>2]=0,n[s+28>>2]=0,n[s+32>>2]=0}function Jke(){return 1320}function Xke(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0;f=E,E=E+16|0,d=f+8|0,m=f,B=Zke(s)|0,s=n[B+4>>2]|0,n[m>>2]=n[B>>2],n[m+4>>2]=s,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],$ke(l,d,c),E=f}function Zke(s){return s=s|0,(n[(tR()|0)+24>>2]|0)+(s*12|0)|0}function $ke(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0;m=E,E=E+16|0,d=m,f=n[l>>2]|0,l=n[l+4>>2]|0,s=s+(l>>1)|0,l&1&&(f=n[(n[s>>2]|0)+f>>2]|0),eQe(d,c),d=tQe(d,c)|0,tf[f&31](s,d),E=m}function eQe(s,l){s=s|0,l=l|0}function tQe(s,l){return s=s|0,l=l|0,rQe(l)|0}function rQe(s){return s=s|0,s|0}function nQe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0,k=0;f=E,E=E+16|0,d=f+8|0,m=f,k=n[c>>2]|0,B=n[c+4>>2]|0,c=pn(l)|0,n[m>>2]=k,n[m+4>>2]=B,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],iQe(s,c,d,0),E=f}function iQe(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0,m=0,B=0,k=0,Q=0,M=0,O=0;d=E,E=E+32|0,m=d+16|0,O=d+8|0,k=d,M=n[c>>2]|0,Q=n[c+4>>2]|0,B=n[s>>2]|0,s=rR()|0,n[O>>2]=M,n[O+4>>2]=Q,n[m>>2]=n[O>>2],n[m+4>>2]=n[O+4>>2],c=sQe(m)|0,n[k>>2]=M,n[k+4>>2]=Q,n[m>>2]=n[k>>2],n[m+4>>2]=n[k+4>>2],hn(B,l,s,c,oQe(m,f)|0,f),E=d}function rR(){var s=0,l=0;if(o[7792]|0||(X5(9900),tr(43,9900,U|0)|0,l=7792,n[l>>2]=1,n[l+4>>2]=0),!(Tr(9900)|0)){s=9900,l=s+36|0;do n[s>>2]=0,s=s+4|0;while((s|0)<(l|0));X5(9900)}return 9900}function sQe(s){return s=s|0,0}function oQe(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0,B=0,k=0,Q=0,M=0,O=0,q=0;return O=E,E=E+32|0,d=O+24|0,B=O+16|0,k=O,Q=O+8|0,m=n[s>>2]|0,f=n[s+4>>2]|0,n[k>>2]=m,n[k+4>>2]=f,q=rR()|0,M=q+24|0,s=gr(l,4)|0,n[Q>>2]=s,l=q+28|0,c=n[l>>2]|0,c>>>0<(n[q+32>>2]|0)>>>0?(n[B>>2]=m,n[B+4>>2]=f,n[d>>2]=n[B>>2],n[d+4>>2]=n[B+4>>2],J5(c,d,s),s=(n[l>>2]|0)+12|0,n[l>>2]=s):(aQe(M,k,Q),s=n[l>>2]|0),E=O,((s-(n[M>>2]|0)|0)/12|0)+-1|0}function J5(s,l,c){s=s|0,l=l|0,c=c|0;var f=0;f=n[l+4>>2]|0,n[s>>2]=n[l>>2],n[s+4>>2]=f,n[s+8>>2]=c}function aQe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0,k=0,Q=0,M=0,O=0,q=0,se=0;if(M=E,E=E+48|0,f=M+32|0,B=M+24|0,k=M,Q=s+4|0,d=(((n[Q>>2]|0)-(n[s>>2]|0)|0)/12|0)+1|0,m=lQe(s)|0,m>>>0<d>>>0)Jr(s);else{O=n[s>>2]|0,se=((n[s+8>>2]|0)-O|0)/12|0,q=se<<1,cQe(k,se>>>0<m>>>1>>>0?q>>>0<d>>>0?d:q:m,((n[Q>>2]|0)-O|0)/12|0,s+8|0),Q=k+8|0,m=n[Q>>2]|0,d=n[l+4>>2]|0,c=n[c>>2]|0,n[B>>2]=n[l>>2],n[B+4>>2]=d,n[f>>2]=n[B>>2],n[f+4>>2]=n[B+4>>2],J5(m,f,c),n[Q>>2]=(n[Q>>2]|0)+12,uQe(s,k),AQe(k),E=M;return}}function lQe(s){return s=s|0,357913941}function cQe(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0;n[s+12>>2]=0,n[s+16>>2]=f;do if(l)if(l>>>0>357913941)Rt();else{d=Kt(l*12|0)|0;break}else d=0;while(0);n[s>>2]=d,f=d+(c*12|0)|0,n[s+8>>2]=f,n[s+4>>2]=f,n[s+12>>2]=d+(l*12|0)}function uQe(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0,B=0;f=n[s>>2]|0,B=s+4|0,m=l+4|0,d=(n[B>>2]|0)-f|0,c=(n[m>>2]|0)+(((d|0)/-12|0)*12|0)|0,n[m>>2]=c,(d|0)>0?(Dr(c|0,f|0,d|0)|0,f=m,c=n[m>>2]|0):f=m,m=n[s>>2]|0,n[s>>2]=c,n[f>>2]=m,m=l+8|0,d=n[B>>2]|0,n[B>>2]=n[m>>2],n[m>>2]=d,m=s+8|0,B=l+12|0,s=n[m>>2]|0,n[m>>2]=n[B>>2],n[B>>2]=s,n[l>>2]=n[f>>2]}function AQe(s){s=s|0;var l=0,c=0,f=0;l=n[s+4>>2]|0,c=s+8|0,f=n[c>>2]|0,(f|0)!=(l|0)&&(n[c>>2]=f+(~(((f+-12-l|0)>>>0)/12|0)*12|0)),s=n[s>>2]|0,s|0&&gt(s)}function X5(s){s=s|0,hQe(s)}function fQe(s){s=s|0,pQe(s+24|0)}function pQe(s){s=s|0;var l=0,c=0,f=0;c=n[s>>2]|0,f=c,c|0&&(s=s+4|0,l=n[s>>2]|0,(l|0)!=(c|0)&&(n[s>>2]=l+(~(((l+-12-f|0)>>>0)/12|0)*12|0)),gt(c))}function hQe(s){s=s|0;var l=0;l=Kr()|0,Vr(s,2,22,l,gQe()|0,0),n[s+24>>2]=0,n[s+28>>2]=0,n[s+32>>2]=0}function gQe(){return 1344}function dQe(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0;c=E,E=E+16|0,f=c+8|0,d=c,m=mQe(s)|0,s=n[m+4>>2]|0,n[d>>2]=n[m>>2],n[d+4>>2]=s,n[f>>2]=n[d>>2],n[f+4>>2]=n[d+4>>2],yQe(l,f),E=c}function mQe(s){return s=s|0,(n[(rR()|0)+24>>2]|0)+(s*12|0)|0}function yQe(s,l){s=s|0,l=l|0;var c=0;c=n[l>>2]|0,l=n[l+4>>2]|0,s=s+(l>>1)|0,l&1&&(c=n[(n[s>>2]|0)+c>>2]|0),ef[c&127](s)}function EQe(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0,m=0;m=n[s>>2]|0,d=nR()|0,s=CQe(c)|0,hn(m,l,d,s,wQe(c,f)|0,f)}function nR(){var s=0,l=0;if(o[7800]|0||($5(9936),tr(44,9936,U|0)|0,l=7800,n[l>>2]=1,n[l+4>>2]=0),!(Tr(9936)|0)){s=9936,l=s+36|0;do n[s>>2]=0,s=s+4|0;while((s|0)<(l|0));$5(9936)}return 9936}function CQe(s){return s=s|0,s|0}function wQe(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0,B=0,k=0,Q=0;return k=E,E=E+16|0,d=k,m=k+4|0,n[d>>2]=s,Q=nR()|0,B=Q+24|0,l=gr(l,4)|0,n[m>>2]=l,c=Q+28|0,f=n[c>>2]|0,f>>>0<(n[Q+32>>2]|0)>>>0?(Z5(f,s,l),l=(n[c>>2]|0)+8|0,n[c>>2]=l):(IQe(B,d,m),l=n[c>>2]|0),E=k,(l-(n[B>>2]|0)>>3)+-1|0}function Z5(s,l,c){s=s|0,l=l|0,c=c|0,n[s>>2]=l,n[s+4>>2]=c}function IQe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0,k=0,Q=0,M=0,O=0;if(k=E,E=E+32|0,d=k,m=s+4|0,B=((n[m>>2]|0)-(n[s>>2]|0)>>3)+1|0,f=BQe(s)|0,f>>>0<B>>>0)Jr(s);else{Q=n[s>>2]|0,O=(n[s+8>>2]|0)-Q|0,M=O>>2,vQe(d,O>>3>>>0<f>>>1>>>0?M>>>0<B>>>0?B:M:f,(n[m>>2]|0)-Q>>3,s+8|0),B=d+8|0,Z5(n[B>>2]|0,n[l>>2]|0,n[c>>2]|0),n[B>>2]=(n[B>>2]|0)+8,DQe(s,d),PQe(d),E=k;return}}function BQe(s){return s=s|0,536870911}function vQe(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0;n[s+12>>2]=0,n[s+16>>2]=f;do if(l)if(l>>>0>536870911)Rt();else{d=Kt(l<<3)|0;break}else d=0;while(0);n[s>>2]=d,f=d+(c<<3)|0,n[s+8>>2]=f,n[s+4>>2]=f,n[s+12>>2]=d+(l<<3)}function DQe(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0,B=0;f=n[s>>2]|0,B=s+4|0,m=l+4|0,d=(n[B>>2]|0)-f|0,c=(n[m>>2]|0)+(0-(d>>3)<<3)|0,n[m>>2]=c,(d|0)>0?(Dr(c|0,f|0,d|0)|0,f=m,c=n[m>>2]|0):f=m,m=n[s>>2]|0,n[s>>2]=c,n[f>>2]=m,m=l+8|0,d=n[B>>2]|0,n[B>>2]=n[m>>2],n[m>>2]=d,m=s+8|0,B=l+12|0,s=n[m>>2]|0,n[m>>2]=n[B>>2],n[B>>2]=s,n[l>>2]=n[f>>2]}function PQe(s){s=s|0;var l=0,c=0,f=0;l=n[s+4>>2]|0,c=s+8|0,f=n[c>>2]|0,(f|0)!=(l|0)&&(n[c>>2]=f+(~((f+-8-l|0)>>>3)<<3)),s=n[s>>2]|0,s|0&&gt(s)}function $5(s){s=s|0,xQe(s)}function SQe(s){s=s|0,bQe(s+24|0)}function bQe(s){s=s|0;var l=0,c=0,f=0;c=n[s>>2]|0,f=c,c|0&&(s=s+4|0,l=n[s>>2]|0,(l|0)!=(c|0)&&(n[s>>2]=l+(~((l+-8-f|0)>>>3)<<3)),gt(c))}function xQe(s){s=s|0;var l=0;l=Kr()|0,Vr(s,1,23,l,S5()|0,1),n[s+24>>2]=0,n[s+28>>2]=0,n[s+32>>2]=0}function kQe(s,l){s=s|0,l=l|0,FQe(n[(QQe(s)|0)>>2]|0,l)}function QQe(s){return s=s|0,(n[(nR()|0)+24>>2]|0)+(s<<3)|0}function FQe(s,l){s=s|0,l=l|0;var c=0,f=0;c=E,E=E+16|0,f=c,qF(f,l),l=GF(f,l)|0,ef[s&127](l),E=c}function RQe(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0,m=0;m=n[s>>2]|0,d=iR()|0,s=TQe(c)|0,hn(m,l,d,s,NQe(c,f)|0,f)}function iR(){var s=0,l=0;if(o[7808]|0||(t9(9972),tr(45,9972,U|0)|0,l=7808,n[l>>2]=1,n[l+4>>2]=0),!(Tr(9972)|0)){s=9972,l=s+36|0;do n[s>>2]=0,s=s+4|0;while((s|0)<(l|0));t9(9972)}return 9972}function TQe(s){return s=s|0,s|0}function NQe(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0,B=0,k=0,Q=0;return k=E,E=E+16|0,d=k,m=k+4|0,n[d>>2]=s,Q=iR()|0,B=Q+24|0,l=gr(l,4)|0,n[m>>2]=l,c=Q+28|0,f=n[c>>2]|0,f>>>0<(n[Q+32>>2]|0)>>>0?(e9(f,s,l),l=(n[c>>2]|0)+8|0,n[c>>2]=l):(LQe(B,d,m),l=n[c>>2]|0),E=k,(l-(n[B>>2]|0)>>3)+-1|0}function e9(s,l,c){s=s|0,l=l|0,c=c|0,n[s>>2]=l,n[s+4>>2]=c}function LQe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0,k=0,Q=0,M=0,O=0;if(k=E,E=E+32|0,d=k,m=s+4|0,B=((n[m>>2]|0)-(n[s>>2]|0)>>3)+1|0,f=OQe(s)|0,f>>>0<B>>>0)Jr(s);else{Q=n[s>>2]|0,O=(n[s+8>>2]|0)-Q|0,M=O>>2,MQe(d,O>>3>>>0<f>>>1>>>0?M>>>0<B>>>0?B:M:f,(n[m>>2]|0)-Q>>3,s+8|0),B=d+8|0,e9(n[B>>2]|0,n[l>>2]|0,n[c>>2]|0),n[B>>2]=(n[B>>2]|0)+8,UQe(s,d),_Qe(d),E=k;return}}function OQe(s){return s=s|0,536870911}function MQe(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0;n[s+12>>2]=0,n[s+16>>2]=f;do if(l)if(l>>>0>536870911)Rt();else{d=Kt(l<<3)|0;break}else d=0;while(0);n[s>>2]=d,f=d+(c<<3)|0,n[s+8>>2]=f,n[s+4>>2]=f,n[s+12>>2]=d+(l<<3)}function UQe(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0,B=0;f=n[s>>2]|0,B=s+4|0,m=l+4|0,d=(n[B>>2]|0)-f|0,c=(n[m>>2]|0)+(0-(d>>3)<<3)|0,n[m>>2]=c,(d|0)>0?(Dr(c|0,f|0,d|0)|0,f=m,c=n[m>>2]|0):f=m,m=n[s>>2]|0,n[s>>2]=c,n[f>>2]=m,m=l+8|0,d=n[B>>2]|0,n[B>>2]=n[m>>2],n[m>>2]=d,m=s+8|0,B=l+12|0,s=n[m>>2]|0,n[m>>2]=n[B>>2],n[B>>2]=s,n[l>>2]=n[f>>2]}function _Qe(s){s=s|0;var l=0,c=0,f=0;l=n[s+4>>2]|0,c=s+8|0,f=n[c>>2]|0,(f|0)!=(l|0)&&(n[c>>2]=f+(~((f+-8-l|0)>>>3)<<3)),s=n[s>>2]|0,s|0&&gt(s)}function t9(s){s=s|0,qQe(s)}function HQe(s){s=s|0,jQe(s+24|0)}function jQe(s){s=s|0;var l=0,c=0,f=0;c=n[s>>2]|0,f=c,c|0&&(s=s+4|0,l=n[s>>2]|0,(l|0)!=(c|0)&&(n[s>>2]=l+(~((l+-8-f|0)>>>3)<<3)),gt(c))}function qQe(s){s=s|0;var l=0;l=Kr()|0,Vr(s,1,9,l,GQe()|0,1),n[s+24>>2]=0,n[s+28>>2]=0,n[s+32>>2]=0}function GQe(){return 1348}function YQe(s,l){return s=s|0,l=l|0,KQe(n[(WQe(s)|0)>>2]|0,l)|0}function WQe(s){return s=s|0,(n[(iR()|0)+24>>2]|0)+(s<<3)|0}function KQe(s,l){s=s|0,l=l|0;var c=0,f=0;return c=E,E=E+16|0,f=c,r9(f,l),l=n9(f,l)|0,l=sD(Tg[s&31](l)|0)|0,E=c,l|0}function r9(s,l){s=s|0,l=l|0}function n9(s,l){return s=s|0,l=l|0,VQe(l)|0}function VQe(s){return s=s|0,s|0}function zQe(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0,m=0;m=n[s>>2]|0,d=sR()|0,s=JQe(c)|0,hn(m,l,d,s,XQe(c,f)|0,f)}function sR(){var s=0,l=0;if(o[7816]|0||(s9(10008),tr(46,10008,U|0)|0,l=7816,n[l>>2]=1,n[l+4>>2]=0),!(Tr(10008)|0)){s=10008,l=s+36|0;do n[s>>2]=0,s=s+4|0;while((s|0)<(l|0));s9(10008)}return 10008}function JQe(s){return s=s|0,s|0}function XQe(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0,B=0,k=0,Q=0;return k=E,E=E+16|0,d=k,m=k+4|0,n[d>>2]=s,Q=sR()|0,B=Q+24|0,l=gr(l,4)|0,n[m>>2]=l,c=Q+28|0,f=n[c>>2]|0,f>>>0<(n[Q+32>>2]|0)>>>0?(i9(f,s,l),l=(n[c>>2]|0)+8|0,n[c>>2]=l):(ZQe(B,d,m),l=n[c>>2]|0),E=k,(l-(n[B>>2]|0)>>3)+-1|0}function i9(s,l,c){s=s|0,l=l|0,c=c|0,n[s>>2]=l,n[s+4>>2]=c}function ZQe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0,k=0,Q=0,M=0,O=0;if(k=E,E=E+32|0,d=k,m=s+4|0,B=((n[m>>2]|0)-(n[s>>2]|0)>>3)+1|0,f=$Qe(s)|0,f>>>0<B>>>0)Jr(s);else{Q=n[s>>2]|0,O=(n[s+8>>2]|0)-Q|0,M=O>>2,eFe(d,O>>3>>>0<f>>>1>>>0?M>>>0<B>>>0?B:M:f,(n[m>>2]|0)-Q>>3,s+8|0),B=d+8|0,i9(n[B>>2]|0,n[l>>2]|0,n[c>>2]|0),n[B>>2]=(n[B>>2]|0)+8,tFe(s,d),rFe(d),E=k;return}}function $Qe(s){return s=s|0,536870911}function eFe(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0;n[s+12>>2]=0,n[s+16>>2]=f;do if(l)if(l>>>0>536870911)Rt();else{d=Kt(l<<3)|0;break}else d=0;while(0);n[s>>2]=d,f=d+(c<<3)|0,n[s+8>>2]=f,n[s+4>>2]=f,n[s+12>>2]=d+(l<<3)}function tFe(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0,B=0;f=n[s>>2]|0,B=s+4|0,m=l+4|0,d=(n[B>>2]|0)-f|0,c=(n[m>>2]|0)+(0-(d>>3)<<3)|0,n[m>>2]=c,(d|0)>0?(Dr(c|0,f|0,d|0)|0,f=m,c=n[m>>2]|0):f=m,m=n[s>>2]|0,n[s>>2]=c,n[f>>2]=m,m=l+8|0,d=n[B>>2]|0,n[B>>2]=n[m>>2],n[m>>2]=d,m=s+8|0,B=l+12|0,s=n[m>>2]|0,n[m>>2]=n[B>>2],n[B>>2]=s,n[l>>2]=n[f>>2]}function rFe(s){s=s|0;var l=0,c=0,f=0;l=n[s+4>>2]|0,c=s+8|0,f=n[c>>2]|0,(f|0)!=(l|0)&&(n[c>>2]=f+(~((f+-8-l|0)>>>3)<<3)),s=n[s>>2]|0,s|0&&gt(s)}function s9(s){s=s|0,sFe(s)}function nFe(s){s=s|0,iFe(s+24|0)}function iFe(s){s=s|0;var l=0,c=0,f=0;c=n[s>>2]|0,f=c,c|0&&(s=s+4|0,l=n[s>>2]|0,(l|0)!=(c|0)&&(n[s>>2]=l+(~((l+-8-f|0)>>>3)<<3)),gt(c))}function sFe(s){s=s|0;var l=0;l=Kr()|0,Vr(s,1,15,l,w5()|0,0),n[s+24>>2]=0,n[s+28>>2]=0,n[s+32>>2]=0}function oFe(s){return s=s|0,lFe(n[(aFe(s)|0)>>2]|0)|0}function aFe(s){return s=s|0,(n[(sR()|0)+24>>2]|0)+(s<<3)|0}function lFe(s){return s=s|0,sD(CD[s&7]()|0)|0}function cFe(){var s=0;return o[7832]|0||(mFe(10052),tr(25,10052,U|0)|0,s=7832,n[s>>2]=1,n[s+4>>2]=0),10052}function uFe(s,l){s=s|0,l=l|0,n[s>>2]=AFe()|0,n[s+4>>2]=fFe()|0,n[s+12>>2]=l,n[s+8>>2]=pFe()|0,n[s+32>>2]=2}function AFe(){return 11709}function fFe(){return 1188}function pFe(){return aD()|0}function hFe(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0,(Pp(f,896)|0)==512?c|0&&(gFe(c),gt(c)):l|0&&(Pu(l),gt(l))}function Pp(s,l){return s=s|0,l=l|0,l&s|0}function gFe(s){s=s|0,s=n[s+4>>2]|0,s|0&&bp(s)}function aD(){var s=0;return o[7824]|0||(n[2511]=dFe()|0,n[2512]=0,s=7824,n[s>>2]=1,n[s+4>>2]=0),10044}function dFe(){return 0}function mFe(s){s=s|0,Ip(s)}function yFe(s){s=s|0;var l=0,c=0,f=0,d=0,m=0;l=E,E=E+32|0,c=l+24|0,m=l+16|0,d=l+8|0,f=l,EFe(s,4827),CFe(s,4834,3)|0,wFe(s,3682,47)|0,n[m>>2]=9,n[m+4>>2]=0,n[c>>2]=n[m>>2],n[c+4>>2]=n[m+4>>2],IFe(s,4841,c)|0,n[d>>2]=1,n[d+4>>2]=0,n[c>>2]=n[d>>2],n[c+4>>2]=n[d+4>>2],BFe(s,4871,c)|0,n[f>>2]=10,n[f+4>>2]=0,n[c>>2]=n[f>>2],n[c+4>>2]=n[f+4>>2],vFe(s,4891,c)|0,E=l}function EFe(s,l){s=s|0,l=l|0;var c=0;c=rTe()|0,n[s>>2]=c,nTe(c,l),Sp(n[s>>2]|0)}function CFe(s,l,c){return s=s|0,l=l|0,c=c|0,_Re(s,pn(l)|0,c,0),s|0}function wFe(s,l,c){return s=s|0,l=l|0,c=c|0,DRe(s,pn(l)|0,c,0),s|0}function IFe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0;return f=E,E=E+16|0,d=f+8|0,m=f,B=n[c+4>>2]|0,n[m>>2]=n[c>>2],n[m+4>>2]=B,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],oRe(s,l,d),E=f,s|0}function BFe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0;return f=E,E=E+16|0,d=f+8|0,m=f,B=n[c+4>>2]|0,n[m>>2]=n[c>>2],n[m+4>>2]=B,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],HFe(s,l,d),E=f,s|0}function vFe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0;return f=E,E=E+16|0,d=f+8|0,m=f,B=n[c+4>>2]|0,n[m>>2]=n[c>>2],n[m+4>>2]=B,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],DFe(s,l,d),E=f,s|0}function DFe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0,k=0;f=E,E=E+16|0,d=f+8|0,m=f,k=n[c>>2]|0,B=n[c+4>>2]|0,c=pn(l)|0,n[m>>2]=k,n[m+4>>2]=B,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],PFe(s,c,d,1),E=f}function PFe(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0,m=0,B=0,k=0,Q=0,M=0,O=0;d=E,E=E+32|0,m=d+16|0,O=d+8|0,k=d,M=n[c>>2]|0,Q=n[c+4>>2]|0,B=n[s>>2]|0,s=oR()|0,n[O>>2]=M,n[O+4>>2]=Q,n[m>>2]=n[O>>2],n[m+4>>2]=n[O+4>>2],c=SFe(m)|0,n[k>>2]=M,n[k+4>>2]=Q,n[m>>2]=n[k>>2],n[m+4>>2]=n[k+4>>2],hn(B,l,s,c,bFe(m,f)|0,f),E=d}function oR(){var s=0,l=0;if(o[7840]|0||(a9(10100),tr(48,10100,U|0)|0,l=7840,n[l>>2]=1,n[l+4>>2]=0),!(Tr(10100)|0)){s=10100,l=s+36|0;do n[s>>2]=0,s=s+4|0;while((s|0)<(l|0));a9(10100)}return 10100}function SFe(s){return s=s|0,0}function bFe(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0,B=0,k=0,Q=0,M=0,O=0,q=0;return O=E,E=E+32|0,d=O+24|0,B=O+16|0,k=O,Q=O+8|0,m=n[s>>2]|0,f=n[s+4>>2]|0,n[k>>2]=m,n[k+4>>2]=f,q=oR()|0,M=q+24|0,s=gr(l,4)|0,n[Q>>2]=s,l=q+28|0,c=n[l>>2]|0,c>>>0<(n[q+32>>2]|0)>>>0?(n[B>>2]=m,n[B+4>>2]=f,n[d>>2]=n[B>>2],n[d+4>>2]=n[B+4>>2],o9(c,d,s),s=(n[l>>2]|0)+12|0,n[l>>2]=s):(xFe(M,k,Q),s=n[l>>2]|0),E=O,((s-(n[M>>2]|0)|0)/12|0)+-1|0}function o9(s,l,c){s=s|0,l=l|0,c=c|0;var f=0;f=n[l+4>>2]|0,n[s>>2]=n[l>>2],n[s+4>>2]=f,n[s+8>>2]=c}function xFe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0,k=0,Q=0,M=0,O=0,q=0,se=0;if(M=E,E=E+48|0,f=M+32|0,B=M+24|0,k=M,Q=s+4|0,d=(((n[Q>>2]|0)-(n[s>>2]|0)|0)/12|0)+1|0,m=kFe(s)|0,m>>>0<d>>>0)Jr(s);else{O=n[s>>2]|0,se=((n[s+8>>2]|0)-O|0)/12|0,q=se<<1,QFe(k,se>>>0<m>>>1>>>0?q>>>0<d>>>0?d:q:m,((n[Q>>2]|0)-O|0)/12|0,s+8|0),Q=k+8|0,m=n[Q>>2]|0,d=n[l+4>>2]|0,c=n[c>>2]|0,n[B>>2]=n[l>>2],n[B+4>>2]=d,n[f>>2]=n[B>>2],n[f+4>>2]=n[B+4>>2],o9(m,f,c),n[Q>>2]=(n[Q>>2]|0)+12,FFe(s,k),RFe(k),E=M;return}}function kFe(s){return s=s|0,357913941}function QFe(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0;n[s+12>>2]=0,n[s+16>>2]=f;do if(l)if(l>>>0>357913941)Rt();else{d=Kt(l*12|0)|0;break}else d=0;while(0);n[s>>2]=d,f=d+(c*12|0)|0,n[s+8>>2]=f,n[s+4>>2]=f,n[s+12>>2]=d+(l*12|0)}function FFe(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0,B=0;f=n[s>>2]|0,B=s+4|0,m=l+4|0,d=(n[B>>2]|0)-f|0,c=(n[m>>2]|0)+(((d|0)/-12|0)*12|0)|0,n[m>>2]=c,(d|0)>0?(Dr(c|0,f|0,d|0)|0,f=m,c=n[m>>2]|0):f=m,m=n[s>>2]|0,n[s>>2]=c,n[f>>2]=m,m=l+8|0,d=n[B>>2]|0,n[B>>2]=n[m>>2],n[m>>2]=d,m=s+8|0,B=l+12|0,s=n[m>>2]|0,n[m>>2]=n[B>>2],n[B>>2]=s,n[l>>2]=n[f>>2]}function RFe(s){s=s|0;var l=0,c=0,f=0;l=n[s+4>>2]|0,c=s+8|0,f=n[c>>2]|0,(f|0)!=(l|0)&&(n[c>>2]=f+(~(((f+-12-l|0)>>>0)/12|0)*12|0)),s=n[s>>2]|0,s|0&&gt(s)}function a9(s){s=s|0,LFe(s)}function TFe(s){s=s|0,NFe(s+24|0)}function NFe(s){s=s|0;var l=0,c=0,f=0;c=n[s>>2]|0,f=c,c|0&&(s=s+4|0,l=n[s>>2]|0,(l|0)!=(c|0)&&(n[s>>2]=l+(~(((l+-12-f|0)>>>0)/12|0)*12|0)),gt(c))}function LFe(s){s=s|0;var l=0;l=Kr()|0,Vr(s,2,6,l,OFe()|0,1),n[s+24>>2]=0,n[s+28>>2]=0,n[s+32>>2]=0}function OFe(){return 1364}function MFe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0;return f=E,E=E+16|0,d=f+8|0,m=f,B=UFe(s)|0,s=n[B+4>>2]|0,n[m>>2]=n[B>>2],n[m+4>>2]=s,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],c=_Fe(l,d,c)|0,E=f,c|0}function UFe(s){return s=s|0,(n[(oR()|0)+24>>2]|0)+(s*12|0)|0}function _Fe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0;return m=E,E=E+16|0,d=m,f=n[l>>2]|0,l=n[l+4>>2]|0,s=s+(l>>1)|0,l&1&&(f=n[(n[s>>2]|0)+f>>2]|0),XA(d,c),d=ZA(d,c)|0,d=h5(NR[f&15](s,d)|0)|0,E=m,d|0}function HFe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0,k=0;f=E,E=E+16|0,d=f+8|0,m=f,k=n[c>>2]|0,B=n[c+4>>2]|0,c=pn(l)|0,n[m>>2]=k,n[m+4>>2]=B,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],jFe(s,c,d,0),E=f}function jFe(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0,m=0,B=0,k=0,Q=0,M=0,O=0;d=E,E=E+32|0,m=d+16|0,O=d+8|0,k=d,M=n[c>>2]|0,Q=n[c+4>>2]|0,B=n[s>>2]|0,s=aR()|0,n[O>>2]=M,n[O+4>>2]=Q,n[m>>2]=n[O>>2],n[m+4>>2]=n[O+4>>2],c=qFe(m)|0,n[k>>2]=M,n[k+4>>2]=Q,n[m>>2]=n[k>>2],n[m+4>>2]=n[k+4>>2],hn(B,l,s,c,GFe(m,f)|0,f),E=d}function aR(){var s=0,l=0;if(o[7848]|0||(c9(10136),tr(49,10136,U|0)|0,l=7848,n[l>>2]=1,n[l+4>>2]=0),!(Tr(10136)|0)){s=10136,l=s+36|0;do n[s>>2]=0,s=s+4|0;while((s|0)<(l|0));c9(10136)}return 10136}function qFe(s){return s=s|0,0}function GFe(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0,B=0,k=0,Q=0,M=0,O=0,q=0;return O=E,E=E+32|0,d=O+24|0,B=O+16|0,k=O,Q=O+8|0,m=n[s>>2]|0,f=n[s+4>>2]|0,n[k>>2]=m,n[k+4>>2]=f,q=aR()|0,M=q+24|0,s=gr(l,4)|0,n[Q>>2]=s,l=q+28|0,c=n[l>>2]|0,c>>>0<(n[q+32>>2]|0)>>>0?(n[B>>2]=m,n[B+4>>2]=f,n[d>>2]=n[B>>2],n[d+4>>2]=n[B+4>>2],l9(c,d,s),s=(n[l>>2]|0)+12|0,n[l>>2]=s):(YFe(M,k,Q),s=n[l>>2]|0),E=O,((s-(n[M>>2]|0)|0)/12|0)+-1|0}function l9(s,l,c){s=s|0,l=l|0,c=c|0;var f=0;f=n[l+4>>2]|0,n[s>>2]=n[l>>2],n[s+4>>2]=f,n[s+8>>2]=c}function YFe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0,k=0,Q=0,M=0,O=0,q=0,se=0;if(M=E,E=E+48|0,f=M+32|0,B=M+24|0,k=M,Q=s+4|0,d=(((n[Q>>2]|0)-(n[s>>2]|0)|0)/12|0)+1|0,m=WFe(s)|0,m>>>0<d>>>0)Jr(s);else{O=n[s>>2]|0,se=((n[s+8>>2]|0)-O|0)/12|0,q=se<<1,KFe(k,se>>>0<m>>>1>>>0?q>>>0<d>>>0?d:q:m,((n[Q>>2]|0)-O|0)/12|0,s+8|0),Q=k+8|0,m=n[Q>>2]|0,d=n[l+4>>2]|0,c=n[c>>2]|0,n[B>>2]=n[l>>2],n[B+4>>2]=d,n[f>>2]=n[B>>2],n[f+4>>2]=n[B+4>>2],l9(m,f,c),n[Q>>2]=(n[Q>>2]|0)+12,VFe(s,k),zFe(k),E=M;return}}function WFe(s){return s=s|0,357913941}function KFe(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0;n[s+12>>2]=0,n[s+16>>2]=f;do if(l)if(l>>>0>357913941)Rt();else{d=Kt(l*12|0)|0;break}else d=0;while(0);n[s>>2]=d,f=d+(c*12|0)|0,n[s+8>>2]=f,n[s+4>>2]=f,n[s+12>>2]=d+(l*12|0)}function VFe(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0,B=0;f=n[s>>2]|0,B=s+4|0,m=l+4|0,d=(n[B>>2]|0)-f|0,c=(n[m>>2]|0)+(((d|0)/-12|0)*12|0)|0,n[m>>2]=c,(d|0)>0?(Dr(c|0,f|0,d|0)|0,f=m,c=n[m>>2]|0):f=m,m=n[s>>2]|0,n[s>>2]=c,n[f>>2]=m,m=l+8|0,d=n[B>>2]|0,n[B>>2]=n[m>>2],n[m>>2]=d,m=s+8|0,B=l+12|0,s=n[m>>2]|0,n[m>>2]=n[B>>2],n[B>>2]=s,n[l>>2]=n[f>>2]}function zFe(s){s=s|0;var l=0,c=0,f=0;l=n[s+4>>2]|0,c=s+8|0,f=n[c>>2]|0,(f|0)!=(l|0)&&(n[c>>2]=f+(~(((f+-12-l|0)>>>0)/12|0)*12|0)),s=n[s>>2]|0,s|0&&gt(s)}function c9(s){s=s|0,ZFe(s)}function JFe(s){s=s|0,XFe(s+24|0)}function XFe(s){s=s|0;var l=0,c=0,f=0;c=n[s>>2]|0,f=c,c|0&&(s=s+4|0,l=n[s>>2]|0,(l|0)!=(c|0)&&(n[s>>2]=l+(~(((l+-12-f|0)>>>0)/12|0)*12|0)),gt(c))}function ZFe(s){s=s|0;var l=0;l=Kr()|0,Vr(s,2,9,l,$Fe()|0,1),n[s+24>>2]=0,n[s+28>>2]=0,n[s+32>>2]=0}function $Fe(){return 1372}function eRe(s,l,c){s=s|0,l=l|0,c=+c;var f=0,d=0,m=0,B=0;f=E,E=E+16|0,d=f+8|0,m=f,B=tRe(s)|0,s=n[B+4>>2]|0,n[m>>2]=n[B>>2],n[m+4>>2]=s,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],rRe(l,d,c),E=f}function tRe(s){return s=s|0,(n[(aR()|0)+24>>2]|0)+(s*12|0)|0}function rRe(s,l,c){s=s|0,l=l|0,c=+c;var f=0,d=0,m=0,B=Ze;m=E,E=E+16|0,d=m,f=n[l>>2]|0,l=n[l+4>>2]|0,s=s+(l>>1)|0,l&1&&(f=n[(n[s>>2]|0)+f>>2]|0),nRe(d,c),B=y(iRe(d,c)),B7[f&1](s,B),E=m}function nRe(s,l){s=s|0,l=+l}function iRe(s,l){return s=s|0,l=+l,y(sRe(l))}function sRe(s){return s=+s,y(s)}function oRe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0,k=0;f=E,E=E+16|0,d=f+8|0,m=f,k=n[c>>2]|0,B=n[c+4>>2]|0,c=pn(l)|0,n[m>>2]=k,n[m+4>>2]=B,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],aRe(s,c,d,0),E=f}function aRe(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0,m=0,B=0,k=0,Q=0,M=0,O=0;d=E,E=E+32|0,m=d+16|0,O=d+8|0,k=d,M=n[c>>2]|0,Q=n[c+4>>2]|0,B=n[s>>2]|0,s=lR()|0,n[O>>2]=M,n[O+4>>2]=Q,n[m>>2]=n[O>>2],n[m+4>>2]=n[O+4>>2],c=lRe(m)|0,n[k>>2]=M,n[k+4>>2]=Q,n[m>>2]=n[k>>2],n[m+4>>2]=n[k+4>>2],hn(B,l,s,c,cRe(m,f)|0,f),E=d}function lR(){var s=0,l=0;if(o[7856]|0||(A9(10172),tr(50,10172,U|0)|0,l=7856,n[l>>2]=1,n[l+4>>2]=0),!(Tr(10172)|0)){s=10172,l=s+36|0;do n[s>>2]=0,s=s+4|0;while((s|0)<(l|0));A9(10172)}return 10172}function lRe(s){return s=s|0,0}function cRe(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0,B=0,k=0,Q=0,M=0,O=0,q=0;return O=E,E=E+32|0,d=O+24|0,B=O+16|0,k=O,Q=O+8|0,m=n[s>>2]|0,f=n[s+4>>2]|0,n[k>>2]=m,n[k+4>>2]=f,q=lR()|0,M=q+24|0,s=gr(l,4)|0,n[Q>>2]=s,l=q+28|0,c=n[l>>2]|0,c>>>0<(n[q+32>>2]|0)>>>0?(n[B>>2]=m,n[B+4>>2]=f,n[d>>2]=n[B>>2],n[d+4>>2]=n[B+4>>2],u9(c,d,s),s=(n[l>>2]|0)+12|0,n[l>>2]=s):(uRe(M,k,Q),s=n[l>>2]|0),E=O,((s-(n[M>>2]|0)|0)/12|0)+-1|0}function u9(s,l,c){s=s|0,l=l|0,c=c|0;var f=0;f=n[l+4>>2]|0,n[s>>2]=n[l>>2],n[s+4>>2]=f,n[s+8>>2]=c}function uRe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0,k=0,Q=0,M=0,O=0,q=0,se=0;if(M=E,E=E+48|0,f=M+32|0,B=M+24|0,k=M,Q=s+4|0,d=(((n[Q>>2]|0)-(n[s>>2]|0)|0)/12|0)+1|0,m=ARe(s)|0,m>>>0<d>>>0)Jr(s);else{O=n[s>>2]|0,se=((n[s+8>>2]|0)-O|0)/12|0,q=se<<1,fRe(k,se>>>0<m>>>1>>>0?q>>>0<d>>>0?d:q:m,((n[Q>>2]|0)-O|0)/12|0,s+8|0),Q=k+8|0,m=n[Q>>2]|0,d=n[l+4>>2]|0,c=n[c>>2]|0,n[B>>2]=n[l>>2],n[B+4>>2]=d,n[f>>2]=n[B>>2],n[f+4>>2]=n[B+4>>2],u9(m,f,c),n[Q>>2]=(n[Q>>2]|0)+12,pRe(s,k),hRe(k),E=M;return}}function ARe(s){return s=s|0,357913941}function fRe(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0;n[s+12>>2]=0,n[s+16>>2]=f;do if(l)if(l>>>0>357913941)Rt();else{d=Kt(l*12|0)|0;break}else d=0;while(0);n[s>>2]=d,f=d+(c*12|0)|0,n[s+8>>2]=f,n[s+4>>2]=f,n[s+12>>2]=d+(l*12|0)}function pRe(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0,B=0;f=n[s>>2]|0,B=s+4|0,m=l+4|0,d=(n[B>>2]|0)-f|0,c=(n[m>>2]|0)+(((d|0)/-12|0)*12|0)|0,n[m>>2]=c,(d|0)>0?(Dr(c|0,f|0,d|0)|0,f=m,c=n[m>>2]|0):f=m,m=n[s>>2]|0,n[s>>2]=c,n[f>>2]=m,m=l+8|0,d=n[B>>2]|0,n[B>>2]=n[m>>2],n[m>>2]=d,m=s+8|0,B=l+12|0,s=n[m>>2]|0,n[m>>2]=n[B>>2],n[B>>2]=s,n[l>>2]=n[f>>2]}function hRe(s){s=s|0;var l=0,c=0,f=0;l=n[s+4>>2]|0,c=s+8|0,f=n[c>>2]|0,(f|0)!=(l|0)&&(n[c>>2]=f+(~(((f+-12-l|0)>>>0)/12|0)*12|0)),s=n[s>>2]|0,s|0&&gt(s)}function A9(s){s=s|0,mRe(s)}function gRe(s){s=s|0,dRe(s+24|0)}function dRe(s){s=s|0;var l=0,c=0,f=0;c=n[s>>2]|0,f=c,c|0&&(s=s+4|0,l=n[s>>2]|0,(l|0)!=(c|0)&&(n[s>>2]=l+(~(((l+-12-f|0)>>>0)/12|0)*12|0)),gt(c))}function mRe(s){s=s|0;var l=0;l=Kr()|0,Vr(s,2,3,l,yRe()|0,2),n[s+24>>2]=0,n[s+28>>2]=0,n[s+32>>2]=0}function yRe(){return 1380}function ERe(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0,m=0,B=0,k=0;d=E,E=E+16|0,m=d+8|0,B=d,k=CRe(s)|0,s=n[k+4>>2]|0,n[B>>2]=n[k>>2],n[B+4>>2]=s,n[m>>2]=n[B>>2],n[m+4>>2]=n[B+4>>2],wRe(l,m,c,f),E=d}function CRe(s){return s=s|0,(n[(lR()|0)+24>>2]|0)+(s*12|0)|0}function wRe(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0,m=0,B=0,k=0;k=E,E=E+16|0,m=k+1|0,B=k,d=n[l>>2]|0,l=n[l+4>>2]|0,s=s+(l>>1)|0,l&1&&(d=n[(n[s>>2]|0)+d>>2]|0),XA(m,c),m=ZA(m,c)|0,IRe(B,f),B=BRe(B,f)|0,Uw[d&15](s,m,B),E=k}function IRe(s,l){s=s|0,l=l|0}function BRe(s,l){return s=s|0,l=l|0,vRe(l)|0}function vRe(s){return s=s|0,(s|0)!=0|0}function DRe(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0,m=0;m=n[s>>2]|0,d=cR()|0,s=PRe(c)|0,hn(m,l,d,s,SRe(c,f)|0,f)}function cR(){var s=0,l=0;if(o[7864]|0||(p9(10208),tr(51,10208,U|0)|0,l=7864,n[l>>2]=1,n[l+4>>2]=0),!(Tr(10208)|0)){s=10208,l=s+36|0;do n[s>>2]=0,s=s+4|0;while((s|0)<(l|0));p9(10208)}return 10208}function PRe(s){return s=s|0,s|0}function SRe(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0,B=0,k=0,Q=0;return k=E,E=E+16|0,d=k,m=k+4|0,n[d>>2]=s,Q=cR()|0,B=Q+24|0,l=gr(l,4)|0,n[m>>2]=l,c=Q+28|0,f=n[c>>2]|0,f>>>0<(n[Q+32>>2]|0)>>>0?(f9(f,s,l),l=(n[c>>2]|0)+8|0,n[c>>2]=l):(bRe(B,d,m),l=n[c>>2]|0),E=k,(l-(n[B>>2]|0)>>3)+-1|0}function f9(s,l,c){s=s|0,l=l|0,c=c|0,n[s>>2]=l,n[s+4>>2]=c}function bRe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0,k=0,Q=0,M=0,O=0;if(k=E,E=E+32|0,d=k,m=s+4|0,B=((n[m>>2]|0)-(n[s>>2]|0)>>3)+1|0,f=xRe(s)|0,f>>>0<B>>>0)Jr(s);else{Q=n[s>>2]|0,O=(n[s+8>>2]|0)-Q|0,M=O>>2,kRe(d,O>>3>>>0<f>>>1>>>0?M>>>0<B>>>0?B:M:f,(n[m>>2]|0)-Q>>3,s+8|0),B=d+8|0,f9(n[B>>2]|0,n[l>>2]|0,n[c>>2]|0),n[B>>2]=(n[B>>2]|0)+8,QRe(s,d),FRe(d),E=k;return}}function xRe(s){return s=s|0,536870911}function kRe(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0;n[s+12>>2]=0,n[s+16>>2]=f;do if(l)if(l>>>0>536870911)Rt();else{d=Kt(l<<3)|0;break}else d=0;while(0);n[s>>2]=d,f=d+(c<<3)|0,n[s+8>>2]=f,n[s+4>>2]=f,n[s+12>>2]=d+(l<<3)}function QRe(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0,B=0;f=n[s>>2]|0,B=s+4|0,m=l+4|0,d=(n[B>>2]|0)-f|0,c=(n[m>>2]|0)+(0-(d>>3)<<3)|0,n[m>>2]=c,(d|0)>0?(Dr(c|0,f|0,d|0)|0,f=m,c=n[m>>2]|0):f=m,m=n[s>>2]|0,n[s>>2]=c,n[f>>2]=m,m=l+8|0,d=n[B>>2]|0,n[B>>2]=n[m>>2],n[m>>2]=d,m=s+8|0,B=l+12|0,s=n[m>>2]|0,n[m>>2]=n[B>>2],n[B>>2]=s,n[l>>2]=n[f>>2]}function FRe(s){s=s|0;var l=0,c=0,f=0;l=n[s+4>>2]|0,c=s+8|0,f=n[c>>2]|0,(f|0)!=(l|0)&&(n[c>>2]=f+(~((f+-8-l|0)>>>3)<<3)),s=n[s>>2]|0,s|0&&gt(s)}function p9(s){s=s|0,NRe(s)}function RRe(s){s=s|0,TRe(s+24|0)}function TRe(s){s=s|0;var l=0,c=0,f=0;c=n[s>>2]|0,f=c,c|0&&(s=s+4|0,l=n[s>>2]|0,(l|0)!=(c|0)&&(n[s>>2]=l+(~((l+-8-f|0)>>>3)<<3)),gt(c))}function NRe(s){s=s|0;var l=0;l=Kr()|0,Vr(s,1,24,l,LRe()|0,1),n[s+24>>2]=0,n[s+28>>2]=0,n[s+32>>2]=0}function LRe(){return 1392}function ORe(s,l){s=s|0,l=l|0,URe(n[(MRe(s)|0)>>2]|0,l)}function MRe(s){return s=s|0,(n[(cR()|0)+24>>2]|0)+(s<<3)|0}function URe(s,l){s=s|0,l=l|0;var c=0,f=0;c=E,E=E+16|0,f=c,r9(f,l),l=n9(f,l)|0,ef[s&127](l),E=c}function _Re(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0,m=0;m=n[s>>2]|0,d=uR()|0,s=HRe(c)|0,hn(m,l,d,s,jRe(c,f)|0,f)}function uR(){var s=0,l=0;if(o[7872]|0||(g9(10244),tr(52,10244,U|0)|0,l=7872,n[l>>2]=1,n[l+4>>2]=0),!(Tr(10244)|0)){s=10244,l=s+36|0;do n[s>>2]=0,s=s+4|0;while((s|0)<(l|0));g9(10244)}return 10244}function HRe(s){return s=s|0,s|0}function jRe(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0,B=0,k=0,Q=0;return k=E,E=E+16|0,d=k,m=k+4|0,n[d>>2]=s,Q=uR()|0,B=Q+24|0,l=gr(l,4)|0,n[m>>2]=l,c=Q+28|0,f=n[c>>2]|0,f>>>0<(n[Q+32>>2]|0)>>>0?(h9(f,s,l),l=(n[c>>2]|0)+8|0,n[c>>2]=l):(qRe(B,d,m),l=n[c>>2]|0),E=k,(l-(n[B>>2]|0)>>3)+-1|0}function h9(s,l,c){s=s|0,l=l|0,c=c|0,n[s>>2]=l,n[s+4>>2]=c}function qRe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0,k=0,Q=0,M=0,O=0;if(k=E,E=E+32|0,d=k,m=s+4|0,B=((n[m>>2]|0)-(n[s>>2]|0)>>3)+1|0,f=GRe(s)|0,f>>>0<B>>>0)Jr(s);else{Q=n[s>>2]|0,O=(n[s+8>>2]|0)-Q|0,M=O>>2,YRe(d,O>>3>>>0<f>>>1>>>0?M>>>0<B>>>0?B:M:f,(n[m>>2]|0)-Q>>3,s+8|0),B=d+8|0,h9(n[B>>2]|0,n[l>>2]|0,n[c>>2]|0),n[B>>2]=(n[B>>2]|0)+8,WRe(s,d),KRe(d),E=k;return}}function GRe(s){return s=s|0,536870911}function YRe(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0;n[s+12>>2]=0,n[s+16>>2]=f;do if(l)if(l>>>0>536870911)Rt();else{d=Kt(l<<3)|0;break}else d=0;while(0);n[s>>2]=d,f=d+(c<<3)|0,n[s+8>>2]=f,n[s+4>>2]=f,n[s+12>>2]=d+(l<<3)}function WRe(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0,B=0;f=n[s>>2]|0,B=s+4|0,m=l+4|0,d=(n[B>>2]|0)-f|0,c=(n[m>>2]|0)+(0-(d>>3)<<3)|0,n[m>>2]=c,(d|0)>0?(Dr(c|0,f|0,d|0)|0,f=m,c=n[m>>2]|0):f=m,m=n[s>>2]|0,n[s>>2]=c,n[f>>2]=m,m=l+8|0,d=n[B>>2]|0,n[B>>2]=n[m>>2],n[m>>2]=d,m=s+8|0,B=l+12|0,s=n[m>>2]|0,n[m>>2]=n[B>>2],n[B>>2]=s,n[l>>2]=n[f>>2]}function KRe(s){s=s|0;var l=0,c=0,f=0;l=n[s+4>>2]|0,c=s+8|0,f=n[c>>2]|0,(f|0)!=(l|0)&&(n[c>>2]=f+(~((f+-8-l|0)>>>3)<<3)),s=n[s>>2]|0,s|0&&gt(s)}function g9(s){s=s|0,JRe(s)}function VRe(s){s=s|0,zRe(s+24|0)}function zRe(s){s=s|0;var l=0,c=0,f=0;c=n[s>>2]|0,f=c,c|0&&(s=s+4|0,l=n[s>>2]|0,(l|0)!=(c|0)&&(n[s>>2]=l+(~((l+-8-f|0)>>>3)<<3)),gt(c))}function JRe(s){s=s|0;var l=0;l=Kr()|0,Vr(s,1,16,l,XRe()|0,0),n[s+24>>2]=0,n[s+28>>2]=0,n[s+32>>2]=0}function XRe(){return 1400}function ZRe(s){return s=s|0,eTe(n[($Re(s)|0)>>2]|0)|0}function $Re(s){return s=s|0,(n[(uR()|0)+24>>2]|0)+(s<<3)|0}function eTe(s){return s=s|0,tTe(CD[s&7]()|0)|0}function tTe(s){return s=s|0,s|0}function rTe(){var s=0;return o[7880]|0||(cTe(10280),tr(25,10280,U|0)|0,s=7880,n[s>>2]=1,n[s+4>>2]=0),10280}function nTe(s,l){s=s|0,l=l|0,n[s>>2]=iTe()|0,n[s+4>>2]=sTe()|0,n[s+12>>2]=l,n[s+8>>2]=oTe()|0,n[s+32>>2]=4}function iTe(){return 11711}function sTe(){return 1356}function oTe(){return aD()|0}function aTe(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0,(Pp(f,896)|0)==512?c|0&&(lTe(c),gt(c)):l|0&&(Bg(l),gt(l))}function lTe(s){s=s|0,s=n[s+4>>2]|0,s|0&&bp(s)}function cTe(s){s=s|0,Ip(s)}function uTe(s){s=s|0,ATe(s,4920),fTe(s)|0,pTe(s)|0}function ATe(s,l){s=s|0,l=l|0;var c=0;c=O5()|0,n[s>>2]=c,TTe(c,l),Sp(n[s>>2]|0)}function fTe(s){s=s|0;var l=0;return l=n[s>>2]|0,bg(l,vTe()|0),s|0}function pTe(s){s=s|0;var l=0;return l=n[s>>2]|0,bg(l,hTe()|0),s|0}function hTe(){var s=0;return o[7888]|0||(d9(10328),tr(53,10328,U|0)|0,s=7888,n[s>>2]=1,n[s+4>>2]=0),Tr(10328)|0||d9(10328),10328}function bg(s,l){s=s|0,l=l|0,hn(s,0,l,0,0,0)}function d9(s){s=s|0,mTe(s),xg(s,10)}function gTe(s){s=s|0,dTe(s+24|0)}function dTe(s){s=s|0;var l=0,c=0,f=0;c=n[s>>2]|0,f=c,c|0&&(s=s+4|0,l=n[s>>2]|0,(l|0)!=(c|0)&&(n[s>>2]=l+(~((l+-8-f|0)>>>3)<<3)),gt(c))}function mTe(s){s=s|0;var l=0;l=Kr()|0,Vr(s,5,1,l,wTe()|0,2),n[s+24>>2]=0,n[s+28>>2]=0,n[s+32>>2]=0}function yTe(s,l,c){s=s|0,l=l|0,c=+c,ETe(s,l,c)}function xg(s,l){s=s|0,l=l|0,n[s+20>>2]=l}function ETe(s,l,c){s=s|0,l=l|0,c=+c;var f=0,d=0,m=0,B=0,k=0;f=E,E=E+16|0,m=f+8|0,k=f+13|0,d=f,B=f+12|0,XA(k,l),n[m>>2]=ZA(k,l)|0,ku(B,c),C[d>>3]=+Qu(B,c),CTe(s,m,d),E=f}function CTe(s,l,c){s=s|0,l=l|0,c=c|0,Y(s+8|0,n[l>>2]|0,+C[c>>3]),o[s+24>>0]=1}function wTe(){return 1404}function ITe(s,l){return s=s|0,l=+l,BTe(s,l)|0}function BTe(s,l){s=s|0,l=+l;var c=0,f=0,d=0,m=0,B=0,k=0,Q=0;return f=E,E=E+16|0,m=f+4|0,B=f+8|0,k=f,d=Wa(8)|0,c=d,Q=Kt(16)|0,XA(m,s),s=ZA(m,s)|0,ku(B,l),Y(Q,s,+Qu(B,l)),B=c+4|0,n[B>>2]=Q,s=Kt(8)|0,B=n[B>>2]|0,n[k>>2]=0,n[m>>2]=n[k>>2],zF(s,B,m),n[d>>2]=s,E=f,c|0}function vTe(){var s=0;return o[7896]|0||(m9(10364),tr(54,10364,U|0)|0,s=7896,n[s>>2]=1,n[s+4>>2]=0),Tr(10364)|0||m9(10364),10364}function m9(s){s=s|0,STe(s),xg(s,55)}function DTe(s){s=s|0,PTe(s+24|0)}function PTe(s){s=s|0;var l=0,c=0,f=0;c=n[s>>2]|0,f=c,c|0&&(s=s+4|0,l=n[s>>2]|0,(l|0)!=(c|0)&&(n[s>>2]=l+(~((l+-8-f|0)>>>3)<<3)),gt(c))}function STe(s){s=s|0;var l=0;l=Kr()|0,Vr(s,5,4,l,QTe()|0,0),n[s+24>>2]=0,n[s+28>>2]=0,n[s+32>>2]=0}function bTe(s){s=s|0,xTe(s)}function xTe(s){s=s|0,kTe(s)}function kTe(s){s=s|0,y9(s+8|0),o[s+24>>0]=1}function y9(s){s=s|0,n[s>>2]=0,C[s+8>>3]=0}function QTe(){return 1424}function FTe(){return RTe()|0}function RTe(){var s=0,l=0,c=0,f=0,d=0,m=0,B=0;return l=E,E=E+16|0,d=l+4|0,B=l,c=Wa(8)|0,s=c,f=Kt(16)|0,y9(f),m=s+4|0,n[m>>2]=f,f=Kt(8)|0,m=n[m>>2]|0,n[B>>2]=0,n[d>>2]=n[B>>2],zF(f,m,d),n[c>>2]=f,E=l,s|0}function TTe(s,l){s=s|0,l=l|0,n[s>>2]=NTe()|0,n[s+4>>2]=LTe()|0,n[s+12>>2]=l,n[s+8>>2]=OTe()|0,n[s+32>>2]=5}function NTe(){return 11710}function LTe(){return 1416}function OTe(){return lD()|0}function MTe(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0,(Pp(f,896)|0)==512?c|0&&(UTe(c),gt(c)):l|0&&gt(l)}function UTe(s){s=s|0,s=n[s+4>>2]|0,s|0&&bp(s)}function lD(){var s=0;return o[7904]|0||(n[2600]=_Te()|0,n[2601]=0,s=7904,n[s>>2]=1,n[s+4>>2]=0),10400}function _Te(){return n[357]|0}function HTe(s){s=s|0,jTe(s,4926),qTe(s)|0}function jTe(s,l){s=s|0,l=l|0;var c=0;c=o5()|0,n[s>>2]=c,eNe(c,l),Sp(n[s>>2]|0)}function qTe(s){s=s|0;var l=0;return l=n[s>>2]|0,bg(l,GTe()|0),s|0}function GTe(){var s=0;return o[7912]|0||(E9(10412),tr(56,10412,U|0)|0,s=7912,n[s>>2]=1,n[s+4>>2]=0),Tr(10412)|0||E9(10412),10412}function E9(s){s=s|0,KTe(s),xg(s,57)}function YTe(s){s=s|0,WTe(s+24|0)}function WTe(s){s=s|0;var l=0,c=0,f=0;c=n[s>>2]|0,f=c,c|0&&(s=s+4|0,l=n[s>>2]|0,(l|0)!=(c|0)&&(n[s>>2]=l+(~((l+-8-f|0)>>>3)<<3)),gt(c))}function KTe(s){s=s|0;var l=0;l=Kr()|0,Vr(s,5,5,l,XTe()|0,0),n[s+24>>2]=0,n[s+28>>2]=0,n[s+32>>2]=0}function VTe(s){s=s|0,zTe(s)}function zTe(s){s=s|0,JTe(s)}function JTe(s){s=s|0;var l=0,c=0;l=s+8|0,c=l+48|0;do n[l>>2]=0,l=l+4|0;while((l|0)<(c|0));o[s+56>>0]=1}function XTe(){return 1432}function ZTe(){return $Te()|0}function $Te(){var s=0,l=0,c=0,f=0,d=0,m=0,B=0,k=0;B=E,E=E+16|0,s=B+4|0,l=B,c=Wa(8)|0,f=c,d=Kt(48)|0,m=d,k=m+48|0;do n[m>>2]=0,m=m+4|0;while((m|0)<(k|0));return m=f+4|0,n[m>>2]=d,k=Kt(8)|0,m=n[m>>2]|0,n[l>>2]=0,n[s>>2]=n[l>>2],a5(k,m,s),n[c>>2]=k,E=B,f|0}function eNe(s,l){s=s|0,l=l|0,n[s>>2]=tNe()|0,n[s+4>>2]=rNe()|0,n[s+12>>2]=l,n[s+8>>2]=nNe()|0,n[s+32>>2]=6}function tNe(){return 11704}function rNe(){return 1436}function nNe(){return lD()|0}function iNe(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0,(Pp(f,896)|0)==512?c|0&&(sNe(c),gt(c)):l|0&&gt(l)}function sNe(s){s=s|0,s=n[s+4>>2]|0,s|0&&bp(s)}function oNe(s){s=s|0,aNe(s,4933),lNe(s)|0,cNe(s)|0}function aNe(s,l){s=s|0,l=l|0;var c=0;c=RNe()|0,n[s>>2]=c,TNe(c,l),Sp(n[s>>2]|0)}function lNe(s){s=s|0;var l=0;return l=n[s>>2]|0,bg(l,BNe()|0),s|0}function cNe(s){s=s|0;var l=0;return l=n[s>>2]|0,bg(l,uNe()|0),s|0}function uNe(){var s=0;return o[7920]|0||(C9(10452),tr(58,10452,U|0)|0,s=7920,n[s>>2]=1,n[s+4>>2]=0),Tr(10452)|0||C9(10452),10452}function C9(s){s=s|0,pNe(s),xg(s,1)}function ANe(s){s=s|0,fNe(s+24|0)}function fNe(s){s=s|0;var l=0,c=0,f=0;c=n[s>>2]|0,f=c,c|0&&(s=s+4|0,l=n[s>>2]|0,(l|0)!=(c|0)&&(n[s>>2]=l+(~((l+-8-f|0)>>>3)<<3)),gt(c))}function pNe(s){s=s|0;var l=0;l=Kr()|0,Vr(s,5,1,l,mNe()|0,2),n[s+24>>2]=0,n[s+28>>2]=0,n[s+32>>2]=0}function hNe(s,l,c){s=s|0,l=+l,c=+c,gNe(s,l,c)}function gNe(s,l,c){s=s|0,l=+l,c=+c;var f=0,d=0,m=0,B=0,k=0;f=E,E=E+32|0,m=f+8|0,k=f+17|0,d=f,B=f+16|0,ku(k,l),C[m>>3]=+Qu(k,l),ku(B,c),C[d>>3]=+Qu(B,c),dNe(s,m,d),E=f}function dNe(s,l,c){s=s|0,l=l|0,c=c|0,w9(s+8|0,+C[l>>3],+C[c>>3]),o[s+24>>0]=1}function w9(s,l,c){s=s|0,l=+l,c=+c,C[s>>3]=l,C[s+8>>3]=c}function mNe(){return 1472}function yNe(s,l){return s=+s,l=+l,ENe(s,l)|0}function ENe(s,l){s=+s,l=+l;var c=0,f=0,d=0,m=0,B=0,k=0,Q=0;return f=E,E=E+16|0,B=f+4|0,k=f+8|0,Q=f,d=Wa(8)|0,c=d,m=Kt(16)|0,ku(B,s),s=+Qu(B,s),ku(k,l),w9(m,s,+Qu(k,l)),k=c+4|0,n[k>>2]=m,m=Kt(8)|0,k=n[k>>2]|0,n[Q>>2]=0,n[B>>2]=n[Q>>2],I9(m,k,B),n[d>>2]=m,E=f,c|0}function I9(s,l,c){s=s|0,l=l|0,c=c|0,n[s>>2]=l,c=Kt(16)|0,n[c+4>>2]=0,n[c+8>>2]=0,n[c>>2]=1452,n[c+12>>2]=l,n[s+4>>2]=c}function CNe(s){s=s|0,Vm(s),gt(s)}function wNe(s){s=s|0,s=n[s+12>>2]|0,s|0&&gt(s)}function INe(s){s=s|0,gt(s)}function BNe(){var s=0;return o[7928]|0||(B9(10488),tr(59,10488,U|0)|0,s=7928,n[s>>2]=1,n[s+4>>2]=0),Tr(10488)|0||B9(10488),10488}function B9(s){s=s|0,PNe(s),xg(s,60)}function vNe(s){s=s|0,DNe(s+24|0)}function DNe(s){s=s|0;var l=0,c=0,f=0;c=n[s>>2]|0,f=c,c|0&&(s=s+4|0,l=n[s>>2]|0,(l|0)!=(c|0)&&(n[s>>2]=l+(~((l+-8-f|0)>>>3)<<3)),gt(c))}function PNe(s){s=s|0;var l=0;l=Kr()|0,Vr(s,5,6,l,kNe()|0,0),n[s+24>>2]=0,n[s+28>>2]=0,n[s+32>>2]=0}function SNe(s){s=s|0,bNe(s)}function bNe(s){s=s|0,xNe(s)}function xNe(s){s=s|0,v9(s+8|0),o[s+24>>0]=1}function v9(s){s=s|0,n[s>>2]=0,n[s+4>>2]=0,n[s+8>>2]=0,n[s+12>>2]=0}function kNe(){return 1492}function QNe(){return FNe()|0}function FNe(){var s=0,l=0,c=0,f=0,d=0,m=0,B=0;return l=E,E=E+16|0,d=l+4|0,B=l,c=Wa(8)|0,s=c,f=Kt(16)|0,v9(f),m=s+4|0,n[m>>2]=f,f=Kt(8)|0,m=n[m>>2]|0,n[B>>2]=0,n[d>>2]=n[B>>2],I9(f,m,d),n[c>>2]=f,E=l,s|0}function RNe(){var s=0;return o[7936]|0||(_Ne(10524),tr(25,10524,U|0)|0,s=7936,n[s>>2]=1,n[s+4>>2]=0),10524}function TNe(s,l){s=s|0,l=l|0,n[s>>2]=NNe()|0,n[s+4>>2]=LNe()|0,n[s+12>>2]=l,n[s+8>>2]=ONe()|0,n[s+32>>2]=7}function NNe(){return 11700}function LNe(){return 1484}function ONe(){return lD()|0}function MNe(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0,(Pp(f,896)|0)==512?c|0&&(UNe(c),gt(c)):l|0&&gt(l)}function UNe(s){s=s|0,s=n[s+4>>2]|0,s|0&&bp(s)}function _Ne(s){s=s|0,Ip(s)}function HNe(s,l,c){s=s|0,l=l|0,c=c|0,s=pn(l)|0,l=jNe(c)|0,c=qNe(c,0)|0,ELe(s,l,c,AR()|0,0)}function jNe(s){return s=s|0,s|0}function qNe(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0,B=0,k=0,Q=0;return k=E,E=E+16|0,d=k,m=k+4|0,n[d>>2]=s,Q=AR()|0,B=Q+24|0,l=gr(l,4)|0,n[m>>2]=l,c=Q+28|0,f=n[c>>2]|0,f>>>0<(n[Q+32>>2]|0)>>>0?(P9(f,s,l),l=(n[c>>2]|0)+8|0,n[c>>2]=l):(JNe(B,d,m),l=n[c>>2]|0),E=k,(l-(n[B>>2]|0)>>3)+-1|0}function AR(){var s=0,l=0;if(o[7944]|0||(D9(10568),tr(61,10568,U|0)|0,l=7944,n[l>>2]=1,n[l+4>>2]=0),!(Tr(10568)|0)){s=10568,l=s+36|0;do n[s>>2]=0,s=s+4|0;while((s|0)<(l|0));D9(10568)}return 10568}function D9(s){s=s|0,WNe(s)}function GNe(s){s=s|0,YNe(s+24|0)}function YNe(s){s=s|0;var l=0,c=0,f=0;c=n[s>>2]|0,f=c,c|0&&(s=s+4|0,l=n[s>>2]|0,(l|0)!=(c|0)&&(n[s>>2]=l+(~((l+-8-f|0)>>>3)<<3)),gt(c))}function WNe(s){s=s|0;var l=0;l=Kr()|0,Vr(s,1,17,l,v5()|0,0),n[s+24>>2]=0,n[s+28>>2]=0,n[s+32>>2]=0}function KNe(s){return s=s|0,zNe(n[(VNe(s)|0)>>2]|0)|0}function VNe(s){return s=s|0,(n[(AR()|0)+24>>2]|0)+(s<<3)|0}function zNe(s){return s=s|0,oD(CD[s&7]()|0)|0}function P9(s,l,c){s=s|0,l=l|0,c=c|0,n[s>>2]=l,n[s+4>>2]=c}function JNe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0,k=0,Q=0,M=0,O=0;if(k=E,E=E+32|0,d=k,m=s+4|0,B=((n[m>>2]|0)-(n[s>>2]|0)>>3)+1|0,f=XNe(s)|0,f>>>0<B>>>0)Jr(s);else{Q=n[s>>2]|0,O=(n[s+8>>2]|0)-Q|0,M=O>>2,ZNe(d,O>>3>>>0<f>>>1>>>0?M>>>0<B>>>0?B:M:f,(n[m>>2]|0)-Q>>3,s+8|0),B=d+8|0,P9(n[B>>2]|0,n[l>>2]|0,n[c>>2]|0),n[B>>2]=(n[B>>2]|0)+8,$Ne(s,d),eLe(d),E=k;return}}function XNe(s){return s=s|0,536870911}function ZNe(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0;n[s+12>>2]=0,n[s+16>>2]=f;do if(l)if(l>>>0>536870911)Rt();else{d=Kt(l<<3)|0;break}else d=0;while(0);n[s>>2]=d,f=d+(c<<3)|0,n[s+8>>2]=f,n[s+4>>2]=f,n[s+12>>2]=d+(l<<3)}function $Ne(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0,B=0;f=n[s>>2]|0,B=s+4|0,m=l+4|0,d=(n[B>>2]|0)-f|0,c=(n[m>>2]|0)+(0-(d>>3)<<3)|0,n[m>>2]=c,(d|0)>0?(Dr(c|0,f|0,d|0)|0,f=m,c=n[m>>2]|0):f=m,m=n[s>>2]|0,n[s>>2]=c,n[f>>2]=m,m=l+8|0,d=n[B>>2]|0,n[B>>2]=n[m>>2],n[m>>2]=d,m=s+8|0,B=l+12|0,s=n[m>>2]|0,n[m>>2]=n[B>>2],n[B>>2]=s,n[l>>2]=n[f>>2]}function eLe(s){s=s|0;var l=0,c=0,f=0;l=n[s+4>>2]|0,c=s+8|0,f=n[c>>2]|0,(f|0)!=(l|0)&&(n[c>>2]=f+(~((f+-8-l|0)>>>3)<<3)),s=n[s>>2]|0,s|0&&gt(s)}function tLe(){rLe()}function rLe(){nLe(10604)}function nLe(s){s=s|0,iLe(s,4955)}function iLe(s,l){s=s|0,l=l|0;var c=0;c=sLe()|0,n[s>>2]=c,oLe(c,l),Sp(n[s>>2]|0)}function sLe(){var s=0;return o[7952]|0||(gLe(10612),tr(25,10612,U|0)|0,s=7952,n[s>>2]=1,n[s+4>>2]=0),10612}function oLe(s,l){s=s|0,l=l|0,n[s>>2]=uLe()|0,n[s+4>>2]=ALe()|0,n[s+12>>2]=l,n[s+8>>2]=fLe()|0,n[s+32>>2]=8}function Sp(s){s=s|0;var l=0,c=0;l=E,E=E+16|0,c=l,qm()|0,n[c>>2]=s,aLe(10608,c),E=l}function qm(){return o[11714]|0||(n[2652]=0,tr(62,10608,U|0)|0,o[11714]=1),10608}function aLe(s,l){s=s|0,l=l|0;var c=0;c=Kt(8)|0,n[c+4>>2]=n[l>>2],n[c>>2]=n[s>>2],n[s>>2]=c}function lLe(s){s=s|0,cLe(s)}function cLe(s){s=s|0;var l=0,c=0;if(l=n[s>>2]|0,l|0)do c=l,l=n[l>>2]|0,gt(c);while((l|0)!=0);n[s>>2]=0}function uLe(){return 11715}function ALe(){return 1496}function fLe(){return aD()|0}function pLe(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0,(Pp(f,896)|0)==512?c|0&&(hLe(c),gt(c)):l|0&&gt(l)}function hLe(s){s=s|0,s=n[s+4>>2]|0,s|0&&bp(s)}function gLe(s){s=s|0,Ip(s)}function dLe(s,l){s=s|0,l=l|0;var c=0,f=0;qm()|0,c=n[2652]|0;e:do if(c|0){for(;f=n[c+4>>2]|0,!(f|0&&(a7(fR(f)|0,s)|0)==0);)if(c=n[c>>2]|0,!c)break e;mLe(f,l)}while(0)}function fR(s){return s=s|0,n[s+12>>2]|0}function mLe(s,l){s=s|0,l=l|0;var c=0;s=s+36|0,c=n[s>>2]|0,c|0&&(jA(c),gt(c)),c=Kt(4)|0,e5(c,l),n[s>>2]=c}function pR(){return o[11716]|0||(n[2664]=0,tr(63,10656,U|0)|0,o[11716]=1),10656}function S9(){var s=0;return o[11717]|0?s=n[2665]|0:(yLe(),n[2665]=1504,o[11717]=1,s=1504),s|0}function yLe(){o[11740]|0||(o[11718]=gr(gr(8,0)|0,0)|0,o[11719]=gr(gr(0,0)|0,0)|0,o[11720]=gr(gr(0,16)|0,0)|0,o[11721]=gr(gr(8,0)|0,0)|0,o[11722]=gr(gr(0,0)|0,0)|0,o[11723]=gr(gr(8,0)|0,0)|0,o[11724]=gr(gr(0,0)|0,0)|0,o[11725]=gr(gr(8,0)|0,0)|0,o[11726]=gr(gr(0,0)|0,0)|0,o[11727]=gr(gr(8,0)|0,0)|0,o[11728]=gr(gr(0,0)|0,0)|0,o[11729]=gr(gr(0,0)|0,32)|0,o[11730]=gr(gr(0,0)|0,32)|0,o[11740]=1)}function b9(){return 1572}function ELe(s,l,c,f,d){s=s|0,l=l|0,c=c|0,f=f|0,d=d|0;var m=0,B=0,k=0,Q=0,M=0,O=0;m=E,E=E+32|0,O=m+16|0,M=m+12|0,Q=m+8|0,k=m+4|0,B=m,n[O>>2]=s,n[M>>2]=l,n[Q>>2]=c,n[k>>2]=f,n[B>>2]=d,pR()|0,CLe(10656,O,M,Q,k,B),E=m}function CLe(s,l,c,f,d,m){s=s|0,l=l|0,c=c|0,f=f|0,d=d|0,m=m|0;var B=0;B=Kt(24)|0,n5(B+4|0,n[l>>2]|0,n[c>>2]|0,n[f>>2]|0,n[d>>2]|0,n[m>>2]|0),n[B>>2]=n[s>>2],n[s>>2]=B}function x9(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0,k=0,Q=0,M=0,O=0,q=0,se=0,Ge=0,Me=0,Qe=0,et=0,Xe=0,at=0;if(at=E,E=E+32|0,Me=at+20|0,Qe=at+8|0,et=at+4|0,Xe=at,l=n[l>>2]|0,l|0){Ge=Me+4|0,Q=Me+8|0,M=Qe+4|0,O=Qe+8|0,q=Qe+8|0,se=Me+8|0;do{if(B=l+4|0,k=hR(B)|0,k|0){if(d=Rw(k)|0,n[Me>>2]=0,n[Ge>>2]=0,n[Q>>2]=0,f=(Tw(k)|0)+1|0,wLe(Me,f),f|0)for(;f=f+-1|0,bc(Qe,n[d>>2]|0),m=n[Ge>>2]|0,m>>>0<(n[se>>2]|0)>>>0?(n[m>>2]=n[Qe>>2],n[Ge>>2]=(n[Ge>>2]|0)+4):gR(Me,Qe),f;)d=d+4|0;f=Nw(k)|0,n[Qe>>2]=0,n[M>>2]=0,n[O>>2]=0;e:do if(n[f>>2]|0)for(d=0,m=0;;){if((d|0)==(m|0)?ILe(Qe,f):(n[d>>2]=n[f>>2],n[M>>2]=(n[M>>2]|0)+4),f=f+4|0,!(n[f>>2]|0))break e;d=n[M>>2]|0,m=n[q>>2]|0}while(0);n[et>>2]=cD(B)|0,n[Xe>>2]=Tr(k)|0,BLe(c,s,et,Xe,Me,Qe),dR(Qe),$A(Me)}l=n[l>>2]|0}while((l|0)!=0)}E=at}function hR(s){return s=s|0,n[s+12>>2]|0}function Rw(s){return s=s|0,n[s+12>>2]|0}function Tw(s){return s=s|0,n[s+16>>2]|0}function wLe(s,l){s=s|0,l=l|0;var c=0,f=0,d=0;d=E,E=E+32|0,c=d,f=n[s>>2]|0,(n[s+8>>2]|0)-f>>2>>>0<l>>>0&&(O9(c,l,(n[s+4>>2]|0)-f>>2,s+8|0),M9(s,c),U9(c)),E=d}function gR(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0,B=0,k=0,Q=0,M=0;if(B=E,E=E+32|0,c=B,f=s+4|0,d=((n[f>>2]|0)-(n[s>>2]|0)>>2)+1|0,m=L9(s)|0,m>>>0<d>>>0)Jr(s);else{k=n[s>>2]|0,M=(n[s+8>>2]|0)-k|0,Q=M>>1,O9(c,M>>2>>>0<m>>>1>>>0?Q>>>0<d>>>0?d:Q:m,(n[f>>2]|0)-k>>2,s+8|0),m=c+8|0,n[n[m>>2]>>2]=n[l>>2],n[m>>2]=(n[m>>2]|0)+4,M9(s,c),U9(c),E=B;return}}function Nw(s){return s=s|0,n[s+8>>2]|0}function ILe(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0,B=0,k=0,Q=0,M=0;if(B=E,E=E+32|0,c=B,f=s+4|0,d=((n[f>>2]|0)-(n[s>>2]|0)>>2)+1|0,m=N9(s)|0,m>>>0<d>>>0)Jr(s);else{k=n[s>>2]|0,M=(n[s+8>>2]|0)-k|0,Q=M>>1,jLe(c,M>>2>>>0<m>>>1>>>0?Q>>>0<d>>>0?d:Q:m,(n[f>>2]|0)-k>>2,s+8|0),m=c+8|0,n[n[m>>2]>>2]=n[l>>2],n[m>>2]=(n[m>>2]|0)+4,qLe(s,c),GLe(c),E=B;return}}function cD(s){return s=s|0,n[s>>2]|0}function BLe(s,l,c,f,d,m){s=s|0,l=l|0,c=c|0,f=f|0,d=d|0,m=m|0,vLe(s,l,c,f,d,m)}function dR(s){s=s|0;var l=0,c=0,f=0;c=n[s>>2]|0,f=c,c|0&&(s=s+4|0,l=n[s>>2]|0,(l|0)!=(c|0)&&(n[s>>2]=l+(~((l+-4-f|0)>>>2)<<2)),gt(c))}function $A(s){s=s|0;var l=0,c=0,f=0;c=n[s>>2]|0,f=c,c|0&&(s=s+4|0,l=n[s>>2]|0,(l|0)!=(c|0)&&(n[s>>2]=l+(~((l+-4-f|0)>>>2)<<2)),gt(c))}function vLe(s,l,c,f,d,m){s=s|0,l=l|0,c=c|0,f=f|0,d=d|0,m=m|0;var B=0,k=0,Q=0,M=0,O=0,q=0;B=E,E=E+48|0,O=B+40|0,k=B+32|0,q=B+24|0,Q=B+12|0,M=B,Ka(k),s=da(s)|0,n[q>>2]=n[l>>2],c=n[c>>2]|0,f=n[f>>2]|0,mR(Q,d),DLe(M,m),n[O>>2]=n[q>>2],PLe(s,O,c,f,Q,M),dR(M),$A(Q),Va(k),E=B}function mR(s,l){s=s|0,l=l|0;var c=0,f=0;n[s>>2]=0,n[s+4>>2]=0,n[s+8>>2]=0,c=l+4|0,f=(n[c>>2]|0)-(n[l>>2]|0)>>2,f|0&&(_Le(s,f),HLe(s,n[l>>2]|0,n[c>>2]|0,f))}function DLe(s,l){s=s|0,l=l|0;var c=0,f=0;n[s>>2]=0,n[s+4>>2]=0,n[s+8>>2]=0,c=l+4|0,f=(n[c>>2]|0)-(n[l>>2]|0)>>2,f|0&&(MLe(s,f),ULe(s,n[l>>2]|0,n[c>>2]|0,f))}function PLe(s,l,c,f,d,m){s=s|0,l=l|0,c=c|0,f=f|0,d=d|0,m=m|0;var B=0,k=0,Q=0,M=0,O=0,q=0;B=E,E=E+32|0,O=B+28|0,q=B+24|0,k=B+12|0,Q=B,M=Pl(SLe()|0)|0,n[q>>2]=n[l>>2],n[O>>2]=n[q>>2],l=kg(O)|0,c=k9(c)|0,f=yR(f)|0,n[k>>2]=n[d>>2],O=d+4|0,n[k+4>>2]=n[O>>2],q=d+8|0,n[k+8>>2]=n[q>>2],n[q>>2]=0,n[O>>2]=0,n[d>>2]=0,d=ER(k)|0,n[Q>>2]=n[m>>2],O=m+4|0,n[Q+4>>2]=n[O>>2],q=m+8|0,n[Q+8>>2]=n[q>>2],n[q>>2]=0,n[O>>2]=0,n[m>>2]=0,ao(0,M|0,s|0,l|0,c|0,f|0,d|0,bLe(Q)|0)|0,dR(Q),$A(k),E=B}function SLe(){var s=0;return o[7968]|0||(LLe(10708),s=7968,n[s>>2]=1,n[s+4>>2]=0),10708}function kg(s){return s=s|0,F9(s)|0}function k9(s){return s=s|0,Q9(s)|0}function yR(s){return s=s|0,oD(s)|0}function ER(s){return s=s|0,kLe(s)|0}function bLe(s){return s=s|0,xLe(s)|0}function xLe(s){s=s|0;var l=0,c=0,f=0;if(f=(n[s+4>>2]|0)-(n[s>>2]|0)|0,c=f>>2,f=Wa(f+4|0)|0,n[f>>2]=c,c|0){l=0;do n[f+4+(l<<2)>>2]=Q9(n[(n[s>>2]|0)+(l<<2)>>2]|0)|0,l=l+1|0;while((l|0)!=(c|0))}return f|0}function Q9(s){return s=s|0,s|0}function kLe(s){s=s|0;var l=0,c=0,f=0;if(f=(n[s+4>>2]|0)-(n[s>>2]|0)|0,c=f>>2,f=Wa(f+4|0)|0,n[f>>2]=c,c|0){l=0;do n[f+4+(l<<2)>>2]=F9((n[s>>2]|0)+(l<<2)|0)|0,l=l+1|0;while((l|0)!=(c|0))}return f|0}function F9(s){s=s|0;var l=0,c=0,f=0,d=0;return d=E,E=E+32|0,l=d+12|0,c=d,f=QF(R9()|0)|0,f?(FF(l,f),RF(c,l),fUe(s,c),s=TF(l)|0):s=QLe(s)|0,E=d,s|0}function R9(){var s=0;return o[7960]|0||(NLe(10664),tr(25,10664,U|0)|0,s=7960,n[s>>2]=1,n[s+4>>2]=0),10664}function QLe(s){s=s|0;var l=0,c=0,f=0,d=0,m=0,B=0,k=0;return c=E,E=E+16|0,d=c+4|0,B=c,f=Wa(8)|0,l=f,k=Kt(4)|0,n[k>>2]=n[s>>2],m=l+4|0,n[m>>2]=k,s=Kt(8)|0,m=n[m>>2]|0,n[B>>2]=0,n[d>>2]=n[B>>2],T9(s,m,d),n[f>>2]=s,E=c,l|0}function T9(s,l,c){s=s|0,l=l|0,c=c|0,n[s>>2]=l,c=Kt(16)|0,n[c+4>>2]=0,n[c+8>>2]=0,n[c>>2]=1656,n[c+12>>2]=l,n[s+4>>2]=c}function FLe(s){s=s|0,Vm(s),gt(s)}function RLe(s){s=s|0,s=n[s+12>>2]|0,s|0&&gt(s)}function TLe(s){s=s|0,gt(s)}function NLe(s){s=s|0,Ip(s)}function LLe(s){s=s|0,Sl(s,OLe()|0,5)}function OLe(){return 1676}function MLe(s,l){s=s|0,l=l|0;var c=0;if((N9(s)|0)>>>0<l>>>0&&Jr(s),l>>>0>1073741823)Rt();else{c=Kt(l<<2)|0,n[s+4>>2]=c,n[s>>2]=c,n[s+8>>2]=c+(l<<2);return}}function ULe(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0,f=s+4|0,s=c-l|0,(s|0)>0&&(Dr(n[f>>2]|0,l|0,s|0)|0,n[f>>2]=(n[f>>2]|0)+(s>>>2<<2))}function N9(s){return s=s|0,1073741823}function _Le(s,l){s=s|0,l=l|0;var c=0;if((L9(s)|0)>>>0<l>>>0&&Jr(s),l>>>0>1073741823)Rt();else{c=Kt(l<<2)|0,n[s+4>>2]=c,n[s>>2]=c,n[s+8>>2]=c+(l<<2);return}}function HLe(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0,f=s+4|0,s=c-l|0,(s|0)>0&&(Dr(n[f>>2]|0,l|0,s|0)|0,n[f>>2]=(n[f>>2]|0)+(s>>>2<<2))}function L9(s){return s=s|0,1073741823}function jLe(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0;n[s+12>>2]=0,n[s+16>>2]=f;do if(l)if(l>>>0>1073741823)Rt();else{d=Kt(l<<2)|0;break}else d=0;while(0);n[s>>2]=d,f=d+(c<<2)|0,n[s+8>>2]=f,n[s+4>>2]=f,n[s+12>>2]=d+(l<<2)}function qLe(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0,B=0;f=n[s>>2]|0,B=s+4|0,m=l+4|0,d=(n[B>>2]|0)-f|0,c=(n[m>>2]|0)+(0-(d>>2)<<2)|0,n[m>>2]=c,(d|0)>0?(Dr(c|0,f|0,d|0)|0,f=m,c=n[m>>2]|0):f=m,m=n[s>>2]|0,n[s>>2]=c,n[f>>2]=m,m=l+8|0,d=n[B>>2]|0,n[B>>2]=n[m>>2],n[m>>2]=d,m=s+8|0,B=l+12|0,s=n[m>>2]|0,n[m>>2]=n[B>>2],n[B>>2]=s,n[l>>2]=n[f>>2]}function GLe(s){s=s|0;var l=0,c=0,f=0;l=n[s+4>>2]|0,c=s+8|0,f=n[c>>2]|0,(f|0)!=(l|0)&&(n[c>>2]=f+(~((f+-4-l|0)>>>2)<<2)),s=n[s>>2]|0,s|0&&gt(s)}function O9(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0;n[s+12>>2]=0,n[s+16>>2]=f;do if(l)if(l>>>0>1073741823)Rt();else{d=Kt(l<<2)|0;break}else d=0;while(0);n[s>>2]=d,f=d+(c<<2)|0,n[s+8>>2]=f,n[s+4>>2]=f,n[s+12>>2]=d+(l<<2)}function M9(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0,B=0;f=n[s>>2]|0,B=s+4|0,m=l+4|0,d=(n[B>>2]|0)-f|0,c=(n[m>>2]|0)+(0-(d>>2)<<2)|0,n[m>>2]=c,(d|0)>0?(Dr(c|0,f|0,d|0)|0,f=m,c=n[m>>2]|0):f=m,m=n[s>>2]|0,n[s>>2]=c,n[f>>2]=m,m=l+8|0,d=n[B>>2]|0,n[B>>2]=n[m>>2],n[m>>2]=d,m=s+8|0,B=l+12|0,s=n[m>>2]|0,n[m>>2]=n[B>>2],n[B>>2]=s,n[l>>2]=n[f>>2]}function U9(s){s=s|0;var l=0,c=0,f=0;l=n[s+4>>2]|0,c=s+8|0,f=n[c>>2]|0,(f|0)!=(l|0)&&(n[c>>2]=f+(~((f+-4-l|0)>>>2)<<2)),s=n[s>>2]|0,s|0&&gt(s)}function YLe(s,l,c,f,d){s=s|0,l=l|0,c=c|0,f=f|0,d=d|0;var m=0,B=0,k=0,Q=0,M=0,O=0,q=0,se=0,Ge=0,Me=0,Qe=0;if(Qe=E,E=E+32|0,O=Qe+20|0,q=Qe+12|0,M=Qe+16|0,se=Qe+4|0,Ge=Qe,Me=Qe+8|0,k=S9()|0,m=n[k>>2]|0,B=n[m>>2]|0,B|0)for(Q=n[k+8>>2]|0,k=n[k+4>>2]|0;bc(O,B),WLe(s,O,k,Q),m=m+4|0,B=n[m>>2]|0,B;)Q=Q+1|0,k=k+1|0;if(m=b9()|0,B=n[m>>2]|0,B|0)do bc(O,B),n[q>>2]=n[m+4>>2],KLe(l,O,q),m=m+8|0,B=n[m>>2]|0;while((B|0)!=0);if(m=n[(qm()|0)>>2]|0,m|0)do l=n[m+4>>2]|0,bc(O,n[(Gm(l)|0)>>2]|0),n[q>>2]=fR(l)|0,VLe(c,O,q),m=n[m>>2]|0;while((m|0)!=0);if(bc(M,0),m=pR()|0,n[O>>2]=n[M>>2],x9(O,m,d),m=n[(qm()|0)>>2]|0,m|0){s=O+4|0,l=O+8|0,c=O+8|0;do{if(Q=n[m+4>>2]|0,bc(q,n[(Gm(Q)|0)>>2]|0),zLe(se,_9(Q)|0),B=n[se>>2]|0,B|0){n[O>>2]=0,n[s>>2]=0,n[l>>2]=0;do bc(Ge,n[(Gm(n[B+4>>2]|0)|0)>>2]|0),k=n[s>>2]|0,k>>>0<(n[c>>2]|0)>>>0?(n[k>>2]=n[Ge>>2],n[s>>2]=(n[s>>2]|0)+4):gR(O,Ge),B=n[B>>2]|0;while((B|0)!=0);JLe(f,q,O),$A(O)}n[Me>>2]=n[q>>2],M=H9(Q)|0,n[O>>2]=n[Me>>2],x9(O,M,d),c5(se),m=n[m>>2]|0}while((m|0)!=0)}E=Qe}function WLe(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0,lOe(s,l,c,f)}function KLe(s,l,c){s=s|0,l=l|0,c=c|0,aOe(s,l,c)}function Gm(s){return s=s|0,s|0}function VLe(s,l,c){s=s|0,l=l|0,c=c|0,nOe(s,l,c)}function _9(s){return s=s|0,s+16|0}function zLe(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0,B=0,k=0,Q=0;if(m=E,E=E+16|0,d=m+8|0,c=m,n[s>>2]=0,f=n[l>>2]|0,n[d>>2]=f,n[c>>2]=s,c=rOe(c)|0,f|0){if(f=Kt(12)|0,B=(j9(d)|0)+4|0,s=n[B+4>>2]|0,l=f+4|0,n[l>>2]=n[B>>2],n[l+4>>2]=s,l=n[n[d>>2]>>2]|0,n[d>>2]=l,!l)s=f;else for(l=f;s=Kt(12)|0,Q=(j9(d)|0)+4|0,k=n[Q+4>>2]|0,B=s+4|0,n[B>>2]=n[Q>>2],n[B+4>>2]=k,n[l>>2]=s,B=n[n[d>>2]>>2]|0,n[d>>2]=B,B;)l=s;n[s>>2]=n[c>>2],n[c>>2]=f}E=m}function JLe(s,l,c){s=s|0,l=l|0,c=c|0,XLe(s,l,c)}function H9(s){return s=s|0,s+24|0}function XLe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0,k=0;f=E,E=E+32|0,B=f+24|0,d=f+16|0,k=f+12|0,m=f,Ka(d),s=da(s)|0,n[k>>2]=n[l>>2],mR(m,c),n[B>>2]=n[k>>2],ZLe(s,B,m),$A(m),Va(d),E=f}function ZLe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0,k=0;f=E,E=E+32|0,B=f+16|0,k=f+12|0,d=f,m=Pl($Le()|0)|0,n[k>>2]=n[l>>2],n[B>>2]=n[k>>2],l=kg(B)|0,n[d>>2]=n[c>>2],B=c+4|0,n[d+4>>2]=n[B>>2],k=c+8|0,n[d+8>>2]=n[k>>2],n[k>>2]=0,n[B>>2]=0,n[c>>2]=0,oo(0,m|0,s|0,l|0,ER(d)|0)|0,$A(d),E=f}function $Le(){var s=0;return o[7976]|0||(eOe(10720),s=7976,n[s>>2]=1,n[s+4>>2]=0),10720}function eOe(s){s=s|0,Sl(s,tOe()|0,2)}function tOe(){return 1732}function rOe(s){return s=s|0,n[s>>2]|0}function j9(s){return s=s|0,n[s>>2]|0}function nOe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0;f=E,E=E+32|0,m=f+16|0,d=f+8|0,B=f,Ka(d),s=da(s)|0,n[B>>2]=n[l>>2],c=n[c>>2]|0,n[m>>2]=n[B>>2],q9(s,m,c),Va(d),E=f}function q9(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0;f=E,E=E+16|0,m=f+4|0,B=f,d=Pl(iOe()|0)|0,n[B>>2]=n[l>>2],n[m>>2]=n[B>>2],l=kg(m)|0,oo(0,d|0,s|0,l|0,k9(c)|0)|0,E=f}function iOe(){var s=0;return o[7984]|0||(sOe(10732),s=7984,n[s>>2]=1,n[s+4>>2]=0),10732}function sOe(s){s=s|0,Sl(s,oOe()|0,2)}function oOe(){return 1744}function aOe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0;f=E,E=E+32|0,m=f+16|0,d=f+8|0,B=f,Ka(d),s=da(s)|0,n[B>>2]=n[l>>2],c=n[c>>2]|0,n[m>>2]=n[B>>2],q9(s,m,c),Va(d),E=f}function lOe(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0,m=0,B=0,k=0;d=E,E=E+32|0,B=d+16|0,m=d+8|0,k=d,Ka(m),s=da(s)|0,n[k>>2]=n[l>>2],c=o[c>>0]|0,f=o[f>>0]|0,n[B>>2]=n[k>>2],cOe(s,B,c,f),Va(m),E=d}function cOe(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0,m=0,B=0,k=0;d=E,E=E+16|0,B=d+4|0,k=d,m=Pl(uOe()|0)|0,n[k>>2]=n[l>>2],n[B>>2]=n[k>>2],l=kg(B)|0,c=Ym(c)|0,pc(0,m|0,s|0,l|0,c|0,Ym(f)|0)|0,E=d}function uOe(){var s=0;return o[7992]|0||(fOe(10744),s=7992,n[s>>2]=1,n[s+4>>2]=0),10744}function Ym(s){return s=s|0,AOe(s)|0}function AOe(s){return s=s|0,s&255|0}function fOe(s){s=s|0,Sl(s,pOe()|0,3)}function pOe(){return 1756}function hOe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0,k=0,Q=0,M=0,O=0,q=0,se=0;switch(se=E,E=E+32|0,k=se+8|0,Q=se+4|0,M=se+20|0,O=se,MF(s,0),f=AUe(l)|0,n[k>>2]=0,q=k+4|0,n[q>>2]=0,n[k+8>>2]=0,f<<24>>24){case 0:{o[M>>0]=0,gOe(Q,c,M),uD(s,Q)|0,qA(Q);break}case 8:{q=DR(l)|0,o[M>>0]=8,bc(O,n[q+4>>2]|0),dOe(Q,c,M,O,q+8|0),uD(s,Q)|0,qA(Q);break}case 9:{if(m=DR(l)|0,l=n[m+4>>2]|0,l|0)for(B=k+8|0,d=m+12|0;l=l+-1|0,bc(Q,n[d>>2]|0),f=n[q>>2]|0,f>>>0<(n[B>>2]|0)>>>0?(n[f>>2]=n[Q>>2],n[q>>2]=(n[q>>2]|0)+4):gR(k,Q),l;)d=d+4|0;o[M>>0]=9,bc(O,n[m+8>>2]|0),mOe(Q,c,M,O,k),uD(s,Q)|0,qA(Q);break}default:q=DR(l)|0,o[M>>0]=f,bc(O,n[q+4>>2]|0),yOe(Q,c,M,O),uD(s,Q)|0,qA(Q)}$A(k),E=se}function gOe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0;f=E,E=E+16|0,d=f,Ka(d),l=da(l)|0,QOe(s,l,o[c>>0]|0),Va(d),E=f}function uD(s,l){s=s|0,l=l|0;var c=0;return c=n[s>>2]|0,c|0&&PA(c|0),n[s>>2]=n[l>>2],n[l>>2]=0,s|0}function dOe(s,l,c,f,d){s=s|0,l=l|0,c=c|0,f=f|0,d=d|0;var m=0,B=0,k=0,Q=0;m=E,E=E+32|0,k=m+16|0,B=m+8|0,Q=m,Ka(B),l=da(l)|0,c=o[c>>0]|0,n[Q>>2]=n[f>>2],d=n[d>>2]|0,n[k>>2]=n[Q>>2],SOe(s,l,c,k,d),Va(B),E=m}function mOe(s,l,c,f,d){s=s|0,l=l|0,c=c|0,f=f|0,d=d|0;var m=0,B=0,k=0,Q=0,M=0;m=E,E=E+32|0,Q=m+24|0,B=m+16|0,M=m+12|0,k=m,Ka(B),l=da(l)|0,c=o[c>>0]|0,n[M>>2]=n[f>>2],mR(k,d),n[Q>>2]=n[M>>2],BOe(s,l,c,Q,k),$A(k),Va(B),E=m}function yOe(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0,m=0,B=0,k=0;d=E,E=E+32|0,B=d+16|0,m=d+8|0,k=d,Ka(m),l=da(l)|0,c=o[c>>0]|0,n[k>>2]=n[f>>2],n[B>>2]=n[k>>2],EOe(s,l,c,B),Va(m),E=d}function EOe(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0,m=0,B=0,k=0;d=E,E=E+16|0,m=d+4|0,k=d,B=Pl(COe()|0)|0,c=Ym(c)|0,n[k>>2]=n[f>>2],n[m>>2]=n[k>>2],AD(s,oo(0,B|0,l|0,c|0,kg(m)|0)|0),E=d}function COe(){var s=0;return o[8e3]|0||(wOe(10756),s=8e3,n[s>>2]=1,n[s+4>>2]=0),10756}function AD(s,l){s=s|0,l=l|0,MF(s,l)}function wOe(s){s=s|0,Sl(s,IOe()|0,2)}function IOe(){return 1772}function BOe(s,l,c,f,d){s=s|0,l=l|0,c=c|0,f=f|0,d=d|0;var m=0,B=0,k=0,Q=0,M=0;m=E,E=E+32|0,Q=m+16|0,M=m+12|0,B=m,k=Pl(vOe()|0)|0,c=Ym(c)|0,n[M>>2]=n[f>>2],n[Q>>2]=n[M>>2],f=kg(Q)|0,n[B>>2]=n[d>>2],Q=d+4|0,n[B+4>>2]=n[Q>>2],M=d+8|0,n[B+8>>2]=n[M>>2],n[M>>2]=0,n[Q>>2]=0,n[d>>2]=0,AD(s,pc(0,k|0,l|0,c|0,f|0,ER(B)|0)|0),$A(B),E=m}function vOe(){var s=0;return o[8008]|0||(DOe(10768),s=8008,n[s>>2]=1,n[s+4>>2]=0),10768}function DOe(s){s=s|0,Sl(s,POe()|0,3)}function POe(){return 1784}function SOe(s,l,c,f,d){s=s|0,l=l|0,c=c|0,f=f|0,d=d|0;var m=0,B=0,k=0,Q=0;m=E,E=E+16|0,k=m+4|0,Q=m,B=Pl(bOe()|0)|0,c=Ym(c)|0,n[Q>>2]=n[f>>2],n[k>>2]=n[Q>>2],f=kg(k)|0,AD(s,pc(0,B|0,l|0,c|0,f|0,yR(d)|0)|0),E=m}function bOe(){var s=0;return o[8016]|0||(xOe(10780),s=8016,n[s>>2]=1,n[s+4>>2]=0),10780}function xOe(s){s=s|0,Sl(s,kOe()|0,3)}function kOe(){return 1800}function QOe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0;f=Pl(FOe()|0)|0,AD(s,Qn(0,f|0,l|0,Ym(c)|0)|0)}function FOe(){var s=0;return o[8024]|0||(ROe(10792),s=8024,n[s>>2]=1,n[s+4>>2]=0),10792}function ROe(s){s=s|0,Sl(s,TOe()|0,1)}function TOe(){return 1816}function NOe(){LOe(),OOe(),MOe()}function LOe(){n[2702]=m7(65536)|0}function OOe(){iMe(10856)}function MOe(){UOe(10816)}function UOe(s){s=s|0,_Oe(s,5044),HOe(s)|0}function _Oe(s,l){s=s|0,l=l|0;var c=0;c=R9()|0,n[s>>2]=c,ZOe(c,l),Sp(n[s>>2]|0)}function HOe(s){s=s|0;var l=0;return l=n[s>>2]|0,bg(l,jOe()|0),s|0}function jOe(){var s=0;return o[8032]|0||(G9(10820),tr(64,10820,U|0)|0,s=8032,n[s>>2]=1,n[s+4>>2]=0),Tr(10820)|0||G9(10820),10820}function G9(s){s=s|0,YOe(s),xg(s,25)}function qOe(s){s=s|0,GOe(s+24|0)}function GOe(s){s=s|0;var l=0,c=0,f=0;c=n[s>>2]|0,f=c,c|0&&(s=s+4|0,l=n[s>>2]|0,(l|0)!=(c|0)&&(n[s>>2]=l+(~((l+-8-f|0)>>>3)<<3)),gt(c))}function YOe(s){s=s|0;var l=0;l=Kr()|0,Vr(s,5,18,l,zOe()|0,1),n[s+24>>2]=0,n[s+28>>2]=0,n[s+32>>2]=0}function WOe(s,l){s=s|0,l=l|0,KOe(s,l)}function KOe(s,l){s=s|0,l=l|0;var c=0,f=0,d=0;c=E,E=E+16|0,f=c,d=c+4|0,Pg(d,l),n[f>>2]=Sg(d,l)|0,VOe(s,f),E=c}function VOe(s,l){s=s|0,l=l|0,Y9(s+4|0,n[l>>2]|0),o[s+8>>0]=1}function Y9(s,l){s=s|0,l=l|0,n[s>>2]=l}function zOe(){return 1824}function JOe(s){return s=s|0,XOe(s)|0}function XOe(s){s=s|0;var l=0,c=0,f=0,d=0,m=0,B=0,k=0;return c=E,E=E+16|0,d=c+4|0,B=c,f=Wa(8)|0,l=f,k=Kt(4)|0,Pg(d,s),Y9(k,Sg(d,s)|0),m=l+4|0,n[m>>2]=k,s=Kt(8)|0,m=n[m>>2]|0,n[B>>2]=0,n[d>>2]=n[B>>2],T9(s,m,d),n[f>>2]=s,E=c,l|0}function Wa(s){s=s|0;var l=0,c=0;return s=s+7&-8,s>>>0<=32768&&(l=n[2701]|0,s>>>0<=(65536-l|0)>>>0)?(c=(n[2702]|0)+l|0,n[2701]=l+s,s=c):(s=m7(s+8|0)|0,n[s>>2]=n[2703],n[2703]=s,s=s+8|0),s|0}function ZOe(s,l){s=s|0,l=l|0,n[s>>2]=$Oe()|0,n[s+4>>2]=eMe()|0,n[s+12>>2]=l,n[s+8>>2]=tMe()|0,n[s+32>>2]=9}function $Oe(){return 11744}function eMe(){return 1832}function tMe(){return lD()|0}function rMe(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0,(Pp(f,896)|0)==512?c|0&&(nMe(c),gt(c)):l|0&&gt(l)}function nMe(s){s=s|0,s=n[s+4>>2]|0,s|0&&bp(s)}function iMe(s){s=s|0,sMe(s,5052),oMe(s)|0,aMe(s,5058,26)|0,lMe(s,5069,1)|0,cMe(s,5077,10)|0,uMe(s,5087,19)|0,AMe(s,5094,27)|0}function sMe(s,l){s=s|0,l=l|0;var c=0;c=nUe()|0,n[s>>2]=c,iUe(c,l),Sp(n[s>>2]|0)}function oMe(s){s=s|0;var l=0;return l=n[s>>2]|0,bg(l,q4e()|0),s|0}function aMe(s,l,c){return s=s|0,l=l|0,c=c|0,D4e(s,pn(l)|0,c,0),s|0}function lMe(s,l,c){return s=s|0,l=l|0,c=c|0,u4e(s,pn(l)|0,c,0),s|0}function cMe(s,l,c){return s=s|0,l=l|0,c=c|0,jMe(s,pn(l)|0,c,0),s|0}function uMe(s,l,c){return s=s|0,l=l|0,c=c|0,SMe(s,pn(l)|0,c,0),s|0}function W9(s,l){s=s|0,l=l|0;var c=0,f=0;e:for(;;){for(c=n[2703]|0;;){if((c|0)==(l|0))break e;if(f=n[c>>2]|0,n[2703]=f,!c)c=f;else break}gt(c)}n[2701]=s}function AMe(s,l,c){return s=s|0,l=l|0,c=c|0,fMe(s,pn(l)|0,c,0),s|0}function fMe(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0,m=0;m=n[s>>2]|0,d=CR()|0,s=pMe(c)|0,hn(m,l,d,s,hMe(c,f)|0,f)}function CR(){var s=0,l=0;if(o[8040]|0||(V9(10860),tr(65,10860,U|0)|0,l=8040,n[l>>2]=1,n[l+4>>2]=0),!(Tr(10860)|0)){s=10860,l=s+36|0;do n[s>>2]=0,s=s+4|0;while((s|0)<(l|0));V9(10860)}return 10860}function pMe(s){return s=s|0,s|0}function hMe(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0,B=0,k=0,Q=0;return k=E,E=E+16|0,d=k,m=k+4|0,n[d>>2]=s,Q=CR()|0,B=Q+24|0,l=gr(l,4)|0,n[m>>2]=l,c=Q+28|0,f=n[c>>2]|0,f>>>0<(n[Q+32>>2]|0)>>>0?(K9(f,s,l),l=(n[c>>2]|0)+8|0,n[c>>2]=l):(gMe(B,d,m),l=n[c>>2]|0),E=k,(l-(n[B>>2]|0)>>3)+-1|0}function K9(s,l,c){s=s|0,l=l|0,c=c|0,n[s>>2]=l,n[s+4>>2]=c}function gMe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0,k=0,Q=0,M=0,O=0;if(k=E,E=E+32|0,d=k,m=s+4|0,B=((n[m>>2]|0)-(n[s>>2]|0)>>3)+1|0,f=dMe(s)|0,f>>>0<B>>>0)Jr(s);else{Q=n[s>>2]|0,O=(n[s+8>>2]|0)-Q|0,M=O>>2,mMe(d,O>>3>>>0<f>>>1>>>0?M>>>0<B>>>0?B:M:f,(n[m>>2]|0)-Q>>3,s+8|0),B=d+8|0,K9(n[B>>2]|0,n[l>>2]|0,n[c>>2]|0),n[B>>2]=(n[B>>2]|0)+8,yMe(s,d),EMe(d),E=k;return}}function dMe(s){return s=s|0,536870911}function mMe(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0;n[s+12>>2]=0,n[s+16>>2]=f;do if(l)if(l>>>0>536870911)Rt();else{d=Kt(l<<3)|0;break}else d=0;while(0);n[s>>2]=d,f=d+(c<<3)|0,n[s+8>>2]=f,n[s+4>>2]=f,n[s+12>>2]=d+(l<<3)}function yMe(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0,B=0;f=n[s>>2]|0,B=s+4|0,m=l+4|0,d=(n[B>>2]|0)-f|0,c=(n[m>>2]|0)+(0-(d>>3)<<3)|0,n[m>>2]=c,(d|0)>0?(Dr(c|0,f|0,d|0)|0,f=m,c=n[m>>2]|0):f=m,m=n[s>>2]|0,n[s>>2]=c,n[f>>2]=m,m=l+8|0,d=n[B>>2]|0,n[B>>2]=n[m>>2],n[m>>2]=d,m=s+8|0,B=l+12|0,s=n[m>>2]|0,n[m>>2]=n[B>>2],n[B>>2]=s,n[l>>2]=n[f>>2]}function EMe(s){s=s|0;var l=0,c=0,f=0;l=n[s+4>>2]|0,c=s+8|0,f=n[c>>2]|0,(f|0)!=(l|0)&&(n[c>>2]=f+(~((f+-8-l|0)>>>3)<<3)),s=n[s>>2]|0,s|0&&gt(s)}function V9(s){s=s|0,IMe(s)}function CMe(s){s=s|0,wMe(s+24|0)}function wMe(s){s=s|0;var l=0,c=0,f=0;c=n[s>>2]|0,f=c,c|0&&(s=s+4|0,l=n[s>>2]|0,(l|0)!=(c|0)&&(n[s>>2]=l+(~((l+-8-f|0)>>>3)<<3)),gt(c))}function IMe(s){s=s|0;var l=0;l=Kr()|0,Vr(s,1,11,l,BMe()|0,2),n[s+24>>2]=0,n[s+28>>2]=0,n[s+32>>2]=0}function BMe(){return 1840}function vMe(s,l,c){s=s|0,l=l|0,c=c|0,PMe(n[(DMe(s)|0)>>2]|0,l,c)}function DMe(s){return s=s|0,(n[(CR()|0)+24>>2]|0)+(s<<3)|0}function PMe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0;f=E,E=E+16|0,m=f+1|0,d=f,Pg(m,l),l=Sg(m,l)|0,Pg(d,c),c=Sg(d,c)|0,tf[s&31](l,c),E=f}function SMe(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0,m=0;m=n[s>>2]|0,d=wR()|0,s=bMe(c)|0,hn(m,l,d,s,xMe(c,f)|0,f)}function wR(){var s=0,l=0;if(o[8048]|0||(J9(10896),tr(66,10896,U|0)|0,l=8048,n[l>>2]=1,n[l+4>>2]=0),!(Tr(10896)|0)){s=10896,l=s+36|0;do n[s>>2]=0,s=s+4|0;while((s|0)<(l|0));J9(10896)}return 10896}function bMe(s){return s=s|0,s|0}function xMe(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0,B=0,k=0,Q=0;return k=E,E=E+16|0,d=k,m=k+4|0,n[d>>2]=s,Q=wR()|0,B=Q+24|0,l=gr(l,4)|0,n[m>>2]=l,c=Q+28|0,f=n[c>>2]|0,f>>>0<(n[Q+32>>2]|0)>>>0?(z9(f,s,l),l=(n[c>>2]|0)+8|0,n[c>>2]=l):(kMe(B,d,m),l=n[c>>2]|0),E=k,(l-(n[B>>2]|0)>>3)+-1|0}function z9(s,l,c){s=s|0,l=l|0,c=c|0,n[s>>2]=l,n[s+4>>2]=c}function kMe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0,k=0,Q=0,M=0,O=0;if(k=E,E=E+32|0,d=k,m=s+4|0,B=((n[m>>2]|0)-(n[s>>2]|0)>>3)+1|0,f=QMe(s)|0,f>>>0<B>>>0)Jr(s);else{Q=n[s>>2]|0,O=(n[s+8>>2]|0)-Q|0,M=O>>2,FMe(d,O>>3>>>0<f>>>1>>>0?M>>>0<B>>>0?B:M:f,(n[m>>2]|0)-Q>>3,s+8|0),B=d+8|0,z9(n[B>>2]|0,n[l>>2]|0,n[c>>2]|0),n[B>>2]=(n[B>>2]|0)+8,RMe(s,d),TMe(d),E=k;return}}function QMe(s){return s=s|0,536870911}function FMe(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0;n[s+12>>2]=0,n[s+16>>2]=f;do if(l)if(l>>>0>536870911)Rt();else{d=Kt(l<<3)|0;break}else d=0;while(0);n[s>>2]=d,f=d+(c<<3)|0,n[s+8>>2]=f,n[s+4>>2]=f,n[s+12>>2]=d+(l<<3)}function RMe(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0,B=0;f=n[s>>2]|0,B=s+4|0,m=l+4|0,d=(n[B>>2]|0)-f|0,c=(n[m>>2]|0)+(0-(d>>3)<<3)|0,n[m>>2]=c,(d|0)>0?(Dr(c|0,f|0,d|0)|0,f=m,c=n[m>>2]|0):f=m,m=n[s>>2]|0,n[s>>2]=c,n[f>>2]=m,m=l+8|0,d=n[B>>2]|0,n[B>>2]=n[m>>2],n[m>>2]=d,m=s+8|0,B=l+12|0,s=n[m>>2]|0,n[m>>2]=n[B>>2],n[B>>2]=s,n[l>>2]=n[f>>2]}function TMe(s){s=s|0;var l=0,c=0,f=0;l=n[s+4>>2]|0,c=s+8|0,f=n[c>>2]|0,(f|0)!=(l|0)&&(n[c>>2]=f+(~((f+-8-l|0)>>>3)<<3)),s=n[s>>2]|0,s|0&&gt(s)}function J9(s){s=s|0,OMe(s)}function NMe(s){s=s|0,LMe(s+24|0)}function LMe(s){s=s|0;var l=0,c=0,f=0;c=n[s>>2]|0,f=c,c|0&&(s=s+4|0,l=n[s>>2]|0,(l|0)!=(c|0)&&(n[s>>2]=l+(~((l+-8-f|0)>>>3)<<3)),gt(c))}function OMe(s){s=s|0;var l=0;l=Kr()|0,Vr(s,1,11,l,MMe()|0,1),n[s+24>>2]=0,n[s+28>>2]=0,n[s+32>>2]=0}function MMe(){return 1852}function UMe(s,l){return s=s|0,l=l|0,HMe(n[(_Me(s)|0)>>2]|0,l)|0}function _Me(s){return s=s|0,(n[(wR()|0)+24>>2]|0)+(s<<3)|0}function HMe(s,l){s=s|0,l=l|0;var c=0,f=0;return c=E,E=E+16|0,f=c,Pg(f,l),l=Sg(f,l)|0,l=oD(Tg[s&31](l)|0)|0,E=c,l|0}function jMe(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0,m=0;m=n[s>>2]|0,d=IR()|0,s=qMe(c)|0,hn(m,l,d,s,GMe(c,f)|0,f)}function IR(){var s=0,l=0;if(o[8056]|0||(Z9(10932),tr(67,10932,U|0)|0,l=8056,n[l>>2]=1,n[l+4>>2]=0),!(Tr(10932)|0)){s=10932,l=s+36|0;do n[s>>2]=0,s=s+4|0;while((s|0)<(l|0));Z9(10932)}return 10932}function qMe(s){return s=s|0,s|0}function GMe(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0,B=0,k=0,Q=0;return k=E,E=E+16|0,d=k,m=k+4|0,n[d>>2]=s,Q=IR()|0,B=Q+24|0,l=gr(l,4)|0,n[m>>2]=l,c=Q+28|0,f=n[c>>2]|0,f>>>0<(n[Q+32>>2]|0)>>>0?(X9(f,s,l),l=(n[c>>2]|0)+8|0,n[c>>2]=l):(YMe(B,d,m),l=n[c>>2]|0),E=k,(l-(n[B>>2]|0)>>3)+-1|0}function X9(s,l,c){s=s|0,l=l|0,c=c|0,n[s>>2]=l,n[s+4>>2]=c}function YMe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0,k=0,Q=0,M=0,O=0;if(k=E,E=E+32|0,d=k,m=s+4|0,B=((n[m>>2]|0)-(n[s>>2]|0)>>3)+1|0,f=WMe(s)|0,f>>>0<B>>>0)Jr(s);else{Q=n[s>>2]|0,O=(n[s+8>>2]|0)-Q|0,M=O>>2,KMe(d,O>>3>>>0<f>>>1>>>0?M>>>0<B>>>0?B:M:f,(n[m>>2]|0)-Q>>3,s+8|0),B=d+8|0,X9(n[B>>2]|0,n[l>>2]|0,n[c>>2]|0),n[B>>2]=(n[B>>2]|0)+8,VMe(s,d),zMe(d),E=k;return}}function WMe(s){return s=s|0,536870911}function KMe(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0;n[s+12>>2]=0,n[s+16>>2]=f;do if(l)if(l>>>0>536870911)Rt();else{d=Kt(l<<3)|0;break}else d=0;while(0);n[s>>2]=d,f=d+(c<<3)|0,n[s+8>>2]=f,n[s+4>>2]=f,n[s+12>>2]=d+(l<<3)}function VMe(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0,B=0;f=n[s>>2]|0,B=s+4|0,m=l+4|0,d=(n[B>>2]|0)-f|0,c=(n[m>>2]|0)+(0-(d>>3)<<3)|0,n[m>>2]=c,(d|0)>0?(Dr(c|0,f|0,d|0)|0,f=m,c=n[m>>2]|0):f=m,m=n[s>>2]|0,n[s>>2]=c,n[f>>2]=m,m=l+8|0,d=n[B>>2]|0,n[B>>2]=n[m>>2],n[m>>2]=d,m=s+8|0,B=l+12|0,s=n[m>>2]|0,n[m>>2]=n[B>>2],n[B>>2]=s,n[l>>2]=n[f>>2]}function zMe(s){s=s|0;var l=0,c=0,f=0;l=n[s+4>>2]|0,c=s+8|0,f=n[c>>2]|0,(f|0)!=(l|0)&&(n[c>>2]=f+(~((f+-8-l|0)>>>3)<<3)),s=n[s>>2]|0,s|0&&gt(s)}function Z9(s){s=s|0,ZMe(s)}function JMe(s){s=s|0,XMe(s+24|0)}function XMe(s){s=s|0;var l=0,c=0,f=0;c=n[s>>2]|0,f=c,c|0&&(s=s+4|0,l=n[s>>2]|0,(l|0)!=(c|0)&&(n[s>>2]=l+(~((l+-8-f|0)>>>3)<<3)),gt(c))}function ZMe(s){s=s|0;var l=0;l=Kr()|0,Vr(s,1,7,l,$Me()|0,2),n[s+24>>2]=0,n[s+28>>2]=0,n[s+32>>2]=0}function $Me(){return 1860}function e4e(s,l,c){return s=s|0,l=l|0,c=c|0,r4e(n[(t4e(s)|0)>>2]|0,l,c)|0}function t4e(s){return s=s|0,(n[(IR()|0)+24>>2]|0)+(s<<3)|0}function r4e(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0,k=0,Q=0;return f=E,E=E+32|0,B=f+12|0,m=f+8|0,k=f,Q=f+16|0,d=f+4|0,n4e(Q,l),i4e(k,Q,l),Bp(d,c),c=vp(d,c)|0,n[B>>2]=n[k>>2],Uw[s&15](m,B,c),c=s4e(m)|0,qA(m),Dp(d),E=f,c|0}function n4e(s,l){s=s|0,l=l|0}function i4e(s,l,c){s=s|0,l=l|0,c=c|0,o4e(s,c)}function s4e(s){return s=s|0,da(s)|0}function o4e(s,l){s=s|0,l=l|0;var c=0,f=0,d=0;d=E,E=E+16|0,c=d,f=l,f&1?(a4e(c,0),ii(f|0,c|0)|0,l4e(s,c),c4e(c)):n[s>>2]=n[l>>2],E=d}function a4e(s,l){s=s|0,l=l|0,t5(s,l),n[s+4>>2]=0,o[s+8>>0]=0}function l4e(s,l){s=s|0,l=l|0,n[s>>2]=n[l+4>>2]}function c4e(s){s=s|0,o[s+8>>0]=0}function u4e(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0,m=0;m=n[s>>2]|0,d=BR()|0,s=A4e(c)|0,hn(m,l,d,s,f4e(c,f)|0,f)}function BR(){var s=0,l=0;if(o[8064]|0||(e7(10968),tr(68,10968,U|0)|0,l=8064,n[l>>2]=1,n[l+4>>2]=0),!(Tr(10968)|0)){s=10968,l=s+36|0;do n[s>>2]=0,s=s+4|0;while((s|0)<(l|0));e7(10968)}return 10968}function A4e(s){return s=s|0,s|0}function f4e(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0,B=0,k=0,Q=0;return k=E,E=E+16|0,d=k,m=k+4|0,n[d>>2]=s,Q=BR()|0,B=Q+24|0,l=gr(l,4)|0,n[m>>2]=l,c=Q+28|0,f=n[c>>2]|0,f>>>0<(n[Q+32>>2]|0)>>>0?($9(f,s,l),l=(n[c>>2]|0)+8|0,n[c>>2]=l):(p4e(B,d,m),l=n[c>>2]|0),E=k,(l-(n[B>>2]|0)>>3)+-1|0}function $9(s,l,c){s=s|0,l=l|0,c=c|0,n[s>>2]=l,n[s+4>>2]=c}function p4e(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0,k=0,Q=0,M=0,O=0;if(k=E,E=E+32|0,d=k,m=s+4|0,B=((n[m>>2]|0)-(n[s>>2]|0)>>3)+1|0,f=h4e(s)|0,f>>>0<B>>>0)Jr(s);else{Q=n[s>>2]|0,O=(n[s+8>>2]|0)-Q|0,M=O>>2,g4e(d,O>>3>>>0<f>>>1>>>0?M>>>0<B>>>0?B:M:f,(n[m>>2]|0)-Q>>3,s+8|0),B=d+8|0,$9(n[B>>2]|0,n[l>>2]|0,n[c>>2]|0),n[B>>2]=(n[B>>2]|0)+8,d4e(s,d),m4e(d),E=k;return}}function h4e(s){return s=s|0,536870911}function g4e(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0;n[s+12>>2]=0,n[s+16>>2]=f;do if(l)if(l>>>0>536870911)Rt();else{d=Kt(l<<3)|0;break}else d=0;while(0);n[s>>2]=d,f=d+(c<<3)|0,n[s+8>>2]=f,n[s+4>>2]=f,n[s+12>>2]=d+(l<<3)}function d4e(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0,B=0;f=n[s>>2]|0,B=s+4|0,m=l+4|0,d=(n[B>>2]|0)-f|0,c=(n[m>>2]|0)+(0-(d>>3)<<3)|0,n[m>>2]=c,(d|0)>0?(Dr(c|0,f|0,d|0)|0,f=m,c=n[m>>2]|0):f=m,m=n[s>>2]|0,n[s>>2]=c,n[f>>2]=m,m=l+8|0,d=n[B>>2]|0,n[B>>2]=n[m>>2],n[m>>2]=d,m=s+8|0,B=l+12|0,s=n[m>>2]|0,n[m>>2]=n[B>>2],n[B>>2]=s,n[l>>2]=n[f>>2]}function m4e(s){s=s|0;var l=0,c=0,f=0;l=n[s+4>>2]|0,c=s+8|0,f=n[c>>2]|0,(f|0)!=(l|0)&&(n[c>>2]=f+(~((f+-8-l|0)>>>3)<<3)),s=n[s>>2]|0,s|0&&gt(s)}function e7(s){s=s|0,C4e(s)}function y4e(s){s=s|0,E4e(s+24|0)}function E4e(s){s=s|0;var l=0,c=0,f=0;c=n[s>>2]|0,f=c,c|0&&(s=s+4|0,l=n[s>>2]|0,(l|0)!=(c|0)&&(n[s>>2]=l+(~((l+-8-f|0)>>>3)<<3)),gt(c))}function C4e(s){s=s|0;var l=0;l=Kr()|0,Vr(s,1,1,l,w4e()|0,5),n[s+24>>2]=0,n[s+28>>2]=0,n[s+32>>2]=0}function w4e(){return 1872}function I4e(s,l,c,f,d,m){s=s|0,l=l|0,c=c|0,f=f|0,d=d|0,m=m|0,v4e(n[(B4e(s)|0)>>2]|0,l,c,f,d,m)}function B4e(s){return s=s|0,(n[(BR()|0)+24>>2]|0)+(s<<3)|0}function v4e(s,l,c,f,d,m){s=s|0,l=l|0,c=c|0,f=f|0,d=d|0,m=m|0;var B=0,k=0,Q=0,M=0,O=0,q=0;B=E,E=E+32|0,k=B+16|0,Q=B+12|0,M=B+8|0,O=B+4|0,q=B,Bp(k,l),l=vp(k,l)|0,Bp(Q,c),c=vp(Q,c)|0,Bp(M,f),f=vp(M,f)|0,Bp(O,d),d=vp(O,d)|0,Bp(q,m),m=vp(q,m)|0,I7[s&1](l,c,f,d,m),Dp(q),Dp(O),Dp(M),Dp(Q),Dp(k),E=B}function D4e(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0,m=0;m=n[s>>2]|0,d=vR()|0,s=P4e(c)|0,hn(m,l,d,s,S4e(c,f)|0,f)}function vR(){var s=0,l=0;if(o[8072]|0||(r7(11004),tr(69,11004,U|0)|0,l=8072,n[l>>2]=1,n[l+4>>2]=0),!(Tr(11004)|0)){s=11004,l=s+36|0;do n[s>>2]=0,s=s+4|0;while((s|0)<(l|0));r7(11004)}return 11004}function P4e(s){return s=s|0,s|0}function S4e(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0,B=0,k=0,Q=0;return k=E,E=E+16|0,d=k,m=k+4|0,n[d>>2]=s,Q=vR()|0,B=Q+24|0,l=gr(l,4)|0,n[m>>2]=l,c=Q+28|0,f=n[c>>2]|0,f>>>0<(n[Q+32>>2]|0)>>>0?(t7(f,s,l),l=(n[c>>2]|0)+8|0,n[c>>2]=l):(b4e(B,d,m),l=n[c>>2]|0),E=k,(l-(n[B>>2]|0)>>3)+-1|0}function t7(s,l,c){s=s|0,l=l|0,c=c|0,n[s>>2]=l,n[s+4>>2]=c}function b4e(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0,k=0,Q=0,M=0,O=0;if(k=E,E=E+32|0,d=k,m=s+4|0,B=((n[m>>2]|0)-(n[s>>2]|0)>>3)+1|0,f=x4e(s)|0,f>>>0<B>>>0)Jr(s);else{Q=n[s>>2]|0,O=(n[s+8>>2]|0)-Q|0,M=O>>2,k4e(d,O>>3>>>0<f>>>1>>>0?M>>>0<B>>>0?B:M:f,(n[m>>2]|0)-Q>>3,s+8|0),B=d+8|0,t7(n[B>>2]|0,n[l>>2]|0,n[c>>2]|0),n[B>>2]=(n[B>>2]|0)+8,Q4e(s,d),F4e(d),E=k;return}}function x4e(s){return s=s|0,536870911}function k4e(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0;n[s+12>>2]=0,n[s+16>>2]=f;do if(l)if(l>>>0>536870911)Rt();else{d=Kt(l<<3)|0;break}else d=0;while(0);n[s>>2]=d,f=d+(c<<3)|0,n[s+8>>2]=f,n[s+4>>2]=f,n[s+12>>2]=d+(l<<3)}function Q4e(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0,B=0;f=n[s>>2]|0,B=s+4|0,m=l+4|0,d=(n[B>>2]|0)-f|0,c=(n[m>>2]|0)+(0-(d>>3)<<3)|0,n[m>>2]=c,(d|0)>0?(Dr(c|0,f|0,d|0)|0,f=m,c=n[m>>2]|0):f=m,m=n[s>>2]|0,n[s>>2]=c,n[f>>2]=m,m=l+8|0,d=n[B>>2]|0,n[B>>2]=n[m>>2],n[m>>2]=d,m=s+8|0,B=l+12|0,s=n[m>>2]|0,n[m>>2]=n[B>>2],n[B>>2]=s,n[l>>2]=n[f>>2]}function F4e(s){s=s|0;var l=0,c=0,f=0;l=n[s+4>>2]|0,c=s+8|0,f=n[c>>2]|0,(f|0)!=(l|0)&&(n[c>>2]=f+(~((f+-8-l|0)>>>3)<<3)),s=n[s>>2]|0,s|0&&gt(s)}function r7(s){s=s|0,N4e(s)}function R4e(s){s=s|0,T4e(s+24|0)}function T4e(s){s=s|0;var l=0,c=0,f=0;c=n[s>>2]|0,f=c,c|0&&(s=s+4|0,l=n[s>>2]|0,(l|0)!=(c|0)&&(n[s>>2]=l+(~((l+-8-f|0)>>>3)<<3)),gt(c))}function N4e(s){s=s|0;var l=0;l=Kr()|0,Vr(s,1,12,l,L4e()|0,2),n[s+24>>2]=0,n[s+28>>2]=0,n[s+32>>2]=0}function L4e(){return 1896}function O4e(s,l,c){s=s|0,l=l|0,c=c|0,U4e(n[(M4e(s)|0)>>2]|0,l,c)}function M4e(s){return s=s|0,(n[(vR()|0)+24>>2]|0)+(s<<3)|0}function U4e(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0;f=E,E=E+16|0,m=f+4|0,d=f,_4e(m,l),l=H4e(m,l)|0,Bp(d,c),c=vp(d,c)|0,tf[s&31](l,c),Dp(d),E=f}function _4e(s,l){s=s|0,l=l|0}function H4e(s,l){return s=s|0,l=l|0,j4e(l)|0}function j4e(s){return s=s|0,s|0}function q4e(){var s=0;return o[8080]|0||(n7(11040),tr(70,11040,U|0)|0,s=8080,n[s>>2]=1,n[s+4>>2]=0),Tr(11040)|0||n7(11040),11040}function n7(s){s=s|0,W4e(s),xg(s,71)}function G4e(s){s=s|0,Y4e(s+24|0)}function Y4e(s){s=s|0;var l=0,c=0,f=0;c=n[s>>2]|0,f=c,c|0&&(s=s+4|0,l=n[s>>2]|0,(l|0)!=(c|0)&&(n[s>>2]=l+(~((l+-8-f|0)>>>3)<<3)),gt(c))}function W4e(s){s=s|0;var l=0;l=Kr()|0,Vr(s,5,7,l,J4e()|0,0),n[s+24>>2]=0,n[s+28>>2]=0,n[s+32>>2]=0}function K4e(s){s=s|0,V4e(s)}function V4e(s){s=s|0,z4e(s)}function z4e(s){s=s|0,o[s+8>>0]=1}function J4e(){return 1936}function X4e(){return Z4e()|0}function Z4e(){var s=0,l=0,c=0,f=0,d=0,m=0,B=0;return l=E,E=E+16|0,d=l+4|0,B=l,c=Wa(8)|0,s=c,m=s+4|0,n[m>>2]=Kt(1)|0,f=Kt(8)|0,m=n[m>>2]|0,n[B>>2]=0,n[d>>2]=n[B>>2],$4e(f,m,d),n[c>>2]=f,E=l,s|0}function $4e(s,l,c){s=s|0,l=l|0,c=c|0,n[s>>2]=l,c=Kt(16)|0,n[c+4>>2]=0,n[c+8>>2]=0,n[c>>2]=1916,n[c+12>>2]=l,n[s+4>>2]=c}function eUe(s){s=s|0,Vm(s),gt(s)}function tUe(s){s=s|0,s=n[s+12>>2]|0,s|0&&gt(s)}function rUe(s){s=s|0,gt(s)}function nUe(){var s=0;return o[8088]|0||(uUe(11076),tr(25,11076,U|0)|0,s=8088,n[s>>2]=1,n[s+4>>2]=0),11076}function iUe(s,l){s=s|0,l=l|0,n[s>>2]=sUe()|0,n[s+4>>2]=oUe()|0,n[s+12>>2]=l,n[s+8>>2]=aUe()|0,n[s+32>>2]=10}function sUe(){return 11745}function oUe(){return 1940}function aUe(){return aD()|0}function lUe(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0,(Pp(f,896)|0)==512?c|0&&(cUe(c),gt(c)):l|0&&gt(l)}function cUe(s){s=s|0,s=n[s+4>>2]|0,s|0&&bp(s)}function uUe(s){s=s|0,Ip(s)}function bc(s,l){s=s|0,l=l|0,n[s>>2]=l}function DR(s){return s=s|0,n[s>>2]|0}function AUe(s){return s=s|0,o[n[s>>2]>>0]|0}function fUe(s,l){s=s|0,l=l|0;var c=0,f=0;c=E,E=E+16|0,f=c,n[f>>2]=n[s>>2],pUe(l,f)|0,E=c}function pUe(s,l){s=s|0,l=l|0;var c=0;return c=hUe(n[s>>2]|0,l)|0,l=s+4|0,n[(n[l>>2]|0)+8>>2]=c,n[(n[l>>2]|0)+8>>2]|0}function hUe(s,l){s=s|0,l=l|0;var c=0,f=0;return c=E,E=E+16|0,f=c,Ka(f),s=da(s)|0,l=gUe(s,n[l>>2]|0)|0,Va(f),E=c,l|0}function Ka(s){s=s|0,n[s>>2]=n[2701],n[s+4>>2]=n[2703]}function gUe(s,l){s=s|0,l=l|0;var c=0;return c=Pl(dUe()|0)|0,Qn(0,c|0,s|0,yR(l)|0)|0}function Va(s){s=s|0,W9(n[s>>2]|0,n[s+4>>2]|0)}function dUe(){var s=0;return o[8096]|0||(mUe(11120),s=8096,n[s>>2]=1,n[s+4>>2]=0),11120}function mUe(s){s=s|0,Sl(s,yUe()|0,1)}function yUe(){return 1948}function EUe(){CUe()}function CUe(){var s=0,l=0,c=0,f=0,d=0,m=0,B=0,k=0,Q=0,M=0,O=0,q=0,se=0,Ge=0,Me=0,Qe=0;if(Me=E,E=E+16|0,O=Me+4|0,q=Me,Ni(65536,10804,n[2702]|0,10812),c=S9()|0,l=n[c>>2]|0,s=n[l>>2]|0,s|0)for(f=n[c+8>>2]|0,c=n[c+4>>2]|0;uc(s|0,u[c>>0]|0|0,o[f>>0]|0),l=l+4|0,s=n[l>>2]|0,s;)f=f+1|0,c=c+1|0;if(s=b9()|0,l=n[s>>2]|0,l|0)do uu(l|0,n[s+4>>2]|0),s=s+8|0,l=n[s>>2]|0;while((l|0)!=0);uu(wUe()|0,5167),M=qm()|0,s=n[M>>2]|0;e:do if(s|0){do IUe(n[s+4>>2]|0),s=n[s>>2]|0;while((s|0)!=0);if(s=n[M>>2]|0,s|0){Q=M;do{for(;d=s,s=n[s>>2]|0,d=n[d+4>>2]|0,!!(BUe(d)|0);)if(n[q>>2]=Q,n[O>>2]=n[q>>2],vUe(M,O)|0,!s)break e;if(DUe(d),Q=n[Q>>2]|0,l=i7(d)|0,m=Hi()|0,B=E,E=E+((1*(l<<2)|0)+15&-16)|0,k=E,E=E+((1*(l<<2)|0)+15&-16)|0,l=n[(_9(d)|0)>>2]|0,l|0)for(c=B,f=k;n[c>>2]=n[(Gm(n[l+4>>2]|0)|0)>>2],n[f>>2]=n[l+8>>2],l=n[l>>2]|0,l;)c=c+4|0,f=f+4|0;Qe=Gm(d)|0,l=PUe(d)|0,c=i7(d)|0,f=SUe(d)|0,Au(Qe|0,l|0,B|0,k|0,c|0,f|0,fR(d)|0),_i(m|0)}while((s|0)!=0)}}while(0);if(s=n[(pR()|0)>>2]|0,s|0)do Qe=s+4|0,M=hR(Qe)|0,d=Nw(M)|0,m=Rw(M)|0,B=(Tw(M)|0)+1|0,k=fD(M)|0,Q=s7(Qe)|0,M=Tr(M)|0,O=cD(Qe)|0,q=PR(Qe)|0,El(0,d|0,m|0,B|0,k|0,Q|0,M|0,O|0,q|0,SR(Qe)|0),s=n[s>>2]|0;while((s|0)!=0);s=n[(qm()|0)>>2]|0;e:do if(s|0){t:for(;;){if(l=n[s+4>>2]|0,l|0&&(se=n[(Gm(l)|0)>>2]|0,Ge=n[(H9(l)|0)>>2]|0,Ge|0)){c=Ge;do{l=c+4|0,f=hR(l)|0;r:do if(f|0)switch(Tr(f)|0){case 0:break t;case 4:case 3:case 2:{k=Nw(f)|0,Q=Rw(f)|0,M=(Tw(f)|0)+1|0,O=fD(f)|0,q=Tr(f)|0,Qe=cD(l)|0,El(se|0,k|0,Q|0,M|0,O|0,0,q|0,Qe|0,PR(l)|0,SR(l)|0);break r}case 1:{B=Nw(f)|0,k=Rw(f)|0,Q=(Tw(f)|0)+1|0,M=fD(f)|0,O=s7(l)|0,q=Tr(f)|0,Qe=cD(l)|0,El(se|0,B|0,k|0,Q|0,M|0,O|0,q|0,Qe|0,PR(l)|0,SR(l)|0);break r}case 5:{M=Nw(f)|0,O=Rw(f)|0,q=(Tw(f)|0)+1|0,Qe=fD(f)|0,El(se|0,M|0,O|0,q|0,Qe|0,bUe(f)|0,Tr(f)|0,0,0,0);break r}default:break r}while(0);c=n[c>>2]|0}while((c|0)!=0)}if(s=n[s>>2]|0,!s)break e}Rt()}while(0);Ce(),E=Me}function wUe(){return 11703}function IUe(s){s=s|0,o[s+40>>0]=0}function BUe(s){return s=s|0,(o[s+40>>0]|0)!=0|0}function vUe(s,l){return s=s|0,l=l|0,l=xUe(l)|0,s=n[l>>2]|0,n[l>>2]=n[s>>2],gt(s),n[l>>2]|0}function DUe(s){s=s|0,o[s+40>>0]=1}function i7(s){return s=s|0,n[s+20>>2]|0}function PUe(s){return s=s|0,n[s+8>>2]|0}function SUe(s){return s=s|0,n[s+32>>2]|0}function fD(s){return s=s|0,n[s+4>>2]|0}function s7(s){return s=s|0,n[s+4>>2]|0}function PR(s){return s=s|0,n[s+8>>2]|0}function SR(s){return s=s|0,n[s+16>>2]|0}function bUe(s){return s=s|0,n[s+20>>2]|0}function xUe(s){return s=s|0,n[s>>2]|0}function pD(s){s=s|0;var l=0,c=0,f=0,d=0,m=0,B=0,k=0,Q=0,M=0,O=0,q=0,se=0,Ge=0,Me=0,Qe=0,et=0,Xe=0,at=0,Ue=0,qe=0,Lt=0;Lt=E,E=E+16|0,se=Lt;do if(s>>>0<245){if(M=s>>>0<11?16:s+11&-8,s=M>>>3,q=n[2783]|0,c=q>>>s,c&3|0)return l=(c&1^1)+s|0,s=11172+(l<<1<<2)|0,c=s+8|0,f=n[c>>2]|0,d=f+8|0,m=n[d>>2]|0,(s|0)==(m|0)?n[2783]=q&~(1<<l):(n[m+12>>2]=s,n[c>>2]=m),qe=l<<3,n[f+4>>2]=qe|3,qe=f+qe+4|0,n[qe>>2]=n[qe>>2]|1,qe=d,E=Lt,qe|0;if(O=n[2785]|0,M>>>0>O>>>0){if(c|0)return l=2<<s,l=c<<s&(l|0-l),l=(l&0-l)+-1|0,B=l>>>12&16,l=l>>>B,c=l>>>5&8,l=l>>>c,d=l>>>2&4,l=l>>>d,s=l>>>1&2,l=l>>>s,f=l>>>1&1,f=(c|B|d|s|f)+(l>>>f)|0,l=11172+(f<<1<<2)|0,s=l+8|0,d=n[s>>2]|0,B=d+8|0,c=n[B>>2]|0,(l|0)==(c|0)?(s=q&~(1<<f),n[2783]=s):(n[c+12>>2]=l,n[s>>2]=c,s=q),m=(f<<3)-M|0,n[d+4>>2]=M|3,f=d+M|0,n[f+4>>2]=m|1,n[f+m>>2]=m,O|0&&(d=n[2788]|0,l=O>>>3,c=11172+(l<<1<<2)|0,l=1<<l,s&l?(s=c+8|0,l=n[s>>2]|0):(n[2783]=s|l,l=c,s=c+8|0),n[s>>2]=d,n[l+12>>2]=d,n[d+8>>2]=l,n[d+12>>2]=c),n[2785]=m,n[2788]=f,qe=B,E=Lt,qe|0;if(k=n[2784]|0,k){if(c=(k&0-k)+-1|0,B=c>>>12&16,c=c>>>B,m=c>>>5&8,c=c>>>m,Q=c>>>2&4,c=c>>>Q,f=c>>>1&2,c=c>>>f,s=c>>>1&1,s=n[11436+((m|B|Q|f|s)+(c>>>s)<<2)>>2]|0,c=(n[s+4>>2]&-8)-M|0,f=n[s+16+(((n[s+16>>2]|0)==0&1)<<2)>>2]|0,!f)Q=s,m=c;else{do B=(n[f+4>>2]&-8)-M|0,Q=B>>>0<c>>>0,c=Q?B:c,s=Q?f:s,f=n[f+16+(((n[f+16>>2]|0)==0&1)<<2)>>2]|0;while((f|0)!=0);Q=s,m=c}if(B=Q+M|0,Q>>>0<B>>>0){d=n[Q+24>>2]|0,l=n[Q+12>>2]|0;do if((l|0)==(Q|0)){if(s=Q+20|0,l=n[s>>2]|0,!l&&(s=Q+16|0,l=n[s>>2]|0,!l)){c=0;break}for(;;){if(c=l+20|0,f=n[c>>2]|0,f|0){l=f,s=c;continue}if(c=l+16|0,f=n[c>>2]|0,f)l=f,s=c;else break}n[s>>2]=0,c=l}else c=n[Q+8>>2]|0,n[c+12>>2]=l,n[l+8>>2]=c,c=l;while(0);do if(d|0){if(l=n[Q+28>>2]|0,s=11436+(l<<2)|0,(Q|0)==(n[s>>2]|0)){if(n[s>>2]=c,!c){n[2784]=k&~(1<<l);break}}else if(n[d+16+(((n[d+16>>2]|0)!=(Q|0)&1)<<2)>>2]=c,!c)break;n[c+24>>2]=d,l=n[Q+16>>2]|0,l|0&&(n[c+16>>2]=l,n[l+24>>2]=c),l=n[Q+20>>2]|0,l|0&&(n[c+20>>2]=l,n[l+24>>2]=c)}while(0);return m>>>0<16?(qe=m+M|0,n[Q+4>>2]=qe|3,qe=Q+qe+4|0,n[qe>>2]=n[qe>>2]|1):(n[Q+4>>2]=M|3,n[B+4>>2]=m|1,n[B+m>>2]=m,O|0&&(f=n[2788]|0,l=O>>>3,c=11172+(l<<1<<2)|0,l=1<<l,q&l?(s=c+8|0,l=n[s>>2]|0):(n[2783]=q|l,l=c,s=c+8|0),n[s>>2]=f,n[l+12>>2]=f,n[f+8>>2]=l,n[f+12>>2]=c),n[2785]=m,n[2788]=B),qe=Q+8|0,E=Lt,qe|0}else q=M}else q=M}else q=M}else if(s>>>0<=4294967231)if(s=s+11|0,M=s&-8,Q=n[2784]|0,Q){f=0-M|0,s=s>>>8,s?M>>>0>16777215?k=31:(q=(s+1048320|0)>>>16&8,Ue=s<<q,O=(Ue+520192|0)>>>16&4,Ue=Ue<<O,k=(Ue+245760|0)>>>16&2,k=14-(O|q|k)+(Ue<<k>>>15)|0,k=M>>>(k+7|0)&1|k<<1):k=0,c=n[11436+(k<<2)>>2]|0;e:do if(!c)c=0,s=0,Ue=57;else for(s=0,B=M<<((k|0)==31?0:25-(k>>>1)|0),m=0;;){if(d=(n[c+4>>2]&-8)-M|0,d>>>0<f>>>0)if(d)s=c,f=d;else{s=c,f=0,d=c,Ue=61;break e}if(d=n[c+20>>2]|0,c=n[c+16+(B>>>31<<2)>>2]|0,m=(d|0)==0|(d|0)==(c|0)?m:d,d=(c|0)==0,d){c=m,Ue=57;break}else B=B<<((d^1)&1)}while(0);if((Ue|0)==57){if((c|0)==0&(s|0)==0){if(s=2<<k,s=Q&(s|0-s),!s){q=M;break}q=(s&0-s)+-1|0,B=q>>>12&16,q=q>>>B,m=q>>>5&8,q=q>>>m,k=q>>>2&4,q=q>>>k,O=q>>>1&2,q=q>>>O,c=q>>>1&1,s=0,c=n[11436+((m|B|k|O|c)+(q>>>c)<<2)>>2]|0}c?(d=c,Ue=61):(k=s,B=f)}if((Ue|0)==61)for(;;)if(Ue=0,c=(n[d+4>>2]&-8)-M|0,q=c>>>0<f>>>0,c=q?c:f,s=q?d:s,d=n[d+16+(((n[d+16>>2]|0)==0&1)<<2)>>2]|0,d)f=c,Ue=61;else{k=s,B=c;break}if((k|0)!=0&&B>>>0<((n[2785]|0)-M|0)>>>0){if(m=k+M|0,k>>>0>=m>>>0)return qe=0,E=Lt,qe|0;d=n[k+24>>2]|0,l=n[k+12>>2]|0;do if((l|0)==(k|0)){if(s=k+20|0,l=n[s>>2]|0,!l&&(s=k+16|0,l=n[s>>2]|0,!l)){l=0;break}for(;;){if(c=l+20|0,f=n[c>>2]|0,f|0){l=f,s=c;continue}if(c=l+16|0,f=n[c>>2]|0,f)l=f,s=c;else break}n[s>>2]=0}else qe=n[k+8>>2]|0,n[qe+12>>2]=l,n[l+8>>2]=qe;while(0);do if(d){if(s=n[k+28>>2]|0,c=11436+(s<<2)|0,(k|0)==(n[c>>2]|0)){if(n[c>>2]=l,!l){f=Q&~(1<<s),n[2784]=f;break}}else if(n[d+16+(((n[d+16>>2]|0)!=(k|0)&1)<<2)>>2]=l,!l){f=Q;break}n[l+24>>2]=d,s=n[k+16>>2]|0,s|0&&(n[l+16>>2]=s,n[s+24>>2]=l),s=n[k+20>>2]|0,s&&(n[l+20>>2]=s,n[s+24>>2]=l),f=Q}else f=Q;while(0);do if(B>>>0>=16){if(n[k+4>>2]=M|3,n[m+4>>2]=B|1,n[m+B>>2]=B,l=B>>>3,B>>>0<256){c=11172+(l<<1<<2)|0,s=n[2783]|0,l=1<<l,s&l?(s=c+8|0,l=n[s>>2]|0):(n[2783]=s|l,l=c,s=c+8|0),n[s>>2]=m,n[l+12>>2]=m,n[m+8>>2]=l,n[m+12>>2]=c;break}if(l=B>>>8,l?B>>>0>16777215?l=31:(Ue=(l+1048320|0)>>>16&8,qe=l<<Ue,at=(qe+520192|0)>>>16&4,qe=qe<<at,l=(qe+245760|0)>>>16&2,l=14-(at|Ue|l)+(qe<<l>>>15)|0,l=B>>>(l+7|0)&1|l<<1):l=0,c=11436+(l<<2)|0,n[m+28>>2]=l,s=m+16|0,n[s+4>>2]=0,n[s>>2]=0,s=1<<l,!(f&s)){n[2784]=f|s,n[c>>2]=m,n[m+24>>2]=c,n[m+12>>2]=m,n[m+8>>2]=m;break}for(s=B<<((l|0)==31?0:25-(l>>>1)|0),c=n[c>>2]|0;;){if((n[c+4>>2]&-8|0)==(B|0)){Ue=97;break}if(f=c+16+(s>>>31<<2)|0,l=n[f>>2]|0,l)s=s<<1,c=l;else{Ue=96;break}}if((Ue|0)==96){n[f>>2]=m,n[m+24>>2]=c,n[m+12>>2]=m,n[m+8>>2]=m;break}else if((Ue|0)==97){Ue=c+8|0,qe=n[Ue>>2]|0,n[qe+12>>2]=m,n[Ue>>2]=m,n[m+8>>2]=qe,n[m+12>>2]=c,n[m+24>>2]=0;break}}else qe=B+M|0,n[k+4>>2]=qe|3,qe=k+qe+4|0,n[qe>>2]=n[qe>>2]|1;while(0);return qe=k+8|0,E=Lt,qe|0}else q=M}else q=M;else q=-1;while(0);if(c=n[2785]|0,c>>>0>=q>>>0)return l=c-q|0,s=n[2788]|0,l>>>0>15?(qe=s+q|0,n[2788]=qe,n[2785]=l,n[qe+4>>2]=l|1,n[qe+l>>2]=l,n[s+4>>2]=q|3):(n[2785]=0,n[2788]=0,n[s+4>>2]=c|3,qe=s+c+4|0,n[qe>>2]=n[qe>>2]|1),qe=s+8|0,E=Lt,qe|0;if(B=n[2786]|0,B>>>0>q>>>0)return at=B-q|0,n[2786]=at,qe=n[2789]|0,Ue=qe+q|0,n[2789]=Ue,n[Ue+4>>2]=at|1,n[qe+4>>2]=q|3,qe=qe+8|0,E=Lt,qe|0;if(n[2901]|0?s=n[2903]|0:(n[2903]=4096,n[2902]=4096,n[2904]=-1,n[2905]=-1,n[2906]=0,n[2894]=0,s=se&-16^1431655768,n[se>>2]=s,n[2901]=s,s=4096),k=q+48|0,Q=q+47|0,m=s+Q|0,d=0-s|0,M=m&d,M>>>0<=q>>>0||(s=n[2893]|0,s|0&&(O=n[2891]|0,se=O+M|0,se>>>0<=O>>>0|se>>>0>s>>>0)))return qe=0,E=Lt,qe|0;e:do if(n[2894]&4)l=0,Ue=133;else{c=n[2789]|0;t:do if(c){for(f=11580;s=n[f>>2]|0,!(s>>>0<=c>>>0&&(Qe=f+4|0,(s+(n[Qe>>2]|0)|0)>>>0>c>>>0));)if(s=n[f+8>>2]|0,s)f=s;else{Ue=118;break t}if(l=m-B&d,l>>>0<2147483647)if(s=xp(l|0)|0,(s|0)==((n[f>>2]|0)+(n[Qe>>2]|0)|0)){if((s|0)!=-1){B=l,m=s,Ue=135;break e}}else f=s,Ue=126;else l=0}else Ue=118;while(0);do if((Ue|0)==118)if(c=xp(0)|0,(c|0)!=-1&&(l=c,Ge=n[2902]|0,Me=Ge+-1|0,l=((Me&l|0)==0?0:(Me+l&0-Ge)-l|0)+M|0,Ge=n[2891]|0,Me=l+Ge|0,l>>>0>q>>>0&l>>>0<2147483647)){if(Qe=n[2893]|0,Qe|0&&Me>>>0<=Ge>>>0|Me>>>0>Qe>>>0){l=0;break}if(s=xp(l|0)|0,(s|0)==(c|0)){B=l,m=c,Ue=135;break e}else f=s,Ue=126}else l=0;while(0);do if((Ue|0)==126){if(c=0-l|0,!(k>>>0>l>>>0&(l>>>0<2147483647&(f|0)!=-1)))if((f|0)==-1){l=0;break}else{B=l,m=f,Ue=135;break e}if(s=n[2903]|0,s=Q-l+s&0-s,s>>>0>=2147483647){B=l,m=f,Ue=135;break e}if((xp(s|0)|0)==-1){xp(c|0)|0,l=0;break}else{B=s+l|0,m=f,Ue=135;break e}}while(0);n[2894]=n[2894]|4,Ue=133}while(0);if((Ue|0)==133&&M>>>0<2147483647&&(at=xp(M|0)|0,Qe=xp(0)|0,et=Qe-at|0,Xe=et>>>0>(q+40|0)>>>0,!((at|0)==-1|Xe^1|at>>>0<Qe>>>0&((at|0)!=-1&(Qe|0)!=-1)^1))&&(B=Xe?et:l,m=at,Ue=135),(Ue|0)==135){l=(n[2891]|0)+B|0,n[2891]=l,l>>>0>(n[2892]|0)>>>0&&(n[2892]=l),Q=n[2789]|0;do if(Q){for(l=11580;;){if(s=n[l>>2]|0,c=l+4|0,f=n[c>>2]|0,(m|0)==(s+f|0)){Ue=145;break}if(d=n[l+8>>2]|0,d)l=d;else break}if((Ue|0)==145&&(n[l+12>>2]&8|0)==0&&Q>>>0<m>>>0&Q>>>0>=s>>>0){n[c>>2]=f+B,qe=Q+8|0,qe=(qe&7|0)==0?0:0-qe&7,Ue=Q+qe|0,qe=(n[2786]|0)+(B-qe)|0,n[2789]=Ue,n[2786]=qe,n[Ue+4>>2]=qe|1,n[Ue+qe+4>>2]=40,n[2790]=n[2905];break}for(m>>>0<(n[2787]|0)>>>0&&(n[2787]=m),c=m+B|0,l=11580;;){if((n[l>>2]|0)==(c|0)){Ue=153;break}if(s=n[l+8>>2]|0,s)l=s;else break}if((Ue|0)==153&&(n[l+12>>2]&8|0)==0){n[l>>2]=m,O=l+4|0,n[O>>2]=(n[O>>2]|0)+B,O=m+8|0,O=m+((O&7|0)==0?0:0-O&7)|0,l=c+8|0,l=c+((l&7|0)==0?0:0-l&7)|0,M=O+q|0,k=l-O-q|0,n[O+4>>2]=q|3;do if((l|0)!=(Q|0)){if((l|0)==(n[2788]|0)){qe=(n[2785]|0)+k|0,n[2785]=qe,n[2788]=M,n[M+4>>2]=qe|1,n[M+qe>>2]=qe;break}if(s=n[l+4>>2]|0,(s&3|0)==1){B=s&-8,f=s>>>3;e:do if(s>>>0<256)if(s=n[l+8>>2]|0,c=n[l+12>>2]|0,(c|0)==(s|0)){n[2783]=n[2783]&~(1<<f);break}else{n[s+12>>2]=c,n[c+8>>2]=s;break}else{m=n[l+24>>2]|0,s=n[l+12>>2]|0;do if((s|0)==(l|0)){if(f=l+16|0,c=f+4|0,s=n[c>>2]|0,!s)if(s=n[f>>2]|0,s)c=f;else{s=0;break}for(;;){if(f=s+20|0,d=n[f>>2]|0,d|0){s=d,c=f;continue}if(f=s+16|0,d=n[f>>2]|0,d)s=d,c=f;else break}n[c>>2]=0}else qe=n[l+8>>2]|0,n[qe+12>>2]=s,n[s+8>>2]=qe;while(0);if(!m)break;c=n[l+28>>2]|0,f=11436+(c<<2)|0;do if((l|0)!=(n[f>>2]|0)){if(n[m+16+(((n[m+16>>2]|0)!=(l|0)&1)<<2)>>2]=s,!s)break e}else{if(n[f>>2]=s,s|0)break;n[2784]=n[2784]&~(1<<c);break e}while(0);if(n[s+24>>2]=m,c=l+16|0,f=n[c>>2]|0,f|0&&(n[s+16>>2]=f,n[f+24>>2]=s),c=n[c+4>>2]|0,!c)break;n[s+20>>2]=c,n[c+24>>2]=s}while(0);l=l+B|0,d=B+k|0}else d=k;if(l=l+4|0,n[l>>2]=n[l>>2]&-2,n[M+4>>2]=d|1,n[M+d>>2]=d,l=d>>>3,d>>>0<256){c=11172+(l<<1<<2)|0,s=n[2783]|0,l=1<<l,s&l?(s=c+8|0,l=n[s>>2]|0):(n[2783]=s|l,l=c,s=c+8|0),n[s>>2]=M,n[l+12>>2]=M,n[M+8>>2]=l,n[M+12>>2]=c;break}l=d>>>8;do if(!l)l=0;else{if(d>>>0>16777215){l=31;break}Ue=(l+1048320|0)>>>16&8,qe=l<<Ue,at=(qe+520192|0)>>>16&4,qe=qe<<at,l=(qe+245760|0)>>>16&2,l=14-(at|Ue|l)+(qe<<l>>>15)|0,l=d>>>(l+7|0)&1|l<<1}while(0);if(f=11436+(l<<2)|0,n[M+28>>2]=l,s=M+16|0,n[s+4>>2]=0,n[s>>2]=0,s=n[2784]|0,c=1<<l,!(s&c)){n[2784]=s|c,n[f>>2]=M,n[M+24>>2]=f,n[M+12>>2]=M,n[M+8>>2]=M;break}for(s=d<<((l|0)==31?0:25-(l>>>1)|0),c=n[f>>2]|0;;){if((n[c+4>>2]&-8|0)==(d|0)){Ue=194;break}if(f=c+16+(s>>>31<<2)|0,l=n[f>>2]|0,l)s=s<<1,c=l;else{Ue=193;break}}if((Ue|0)==193){n[f>>2]=M,n[M+24>>2]=c,n[M+12>>2]=M,n[M+8>>2]=M;break}else if((Ue|0)==194){Ue=c+8|0,qe=n[Ue>>2]|0,n[qe+12>>2]=M,n[Ue>>2]=M,n[M+8>>2]=qe,n[M+12>>2]=c,n[M+24>>2]=0;break}}else qe=(n[2786]|0)+k|0,n[2786]=qe,n[2789]=M,n[M+4>>2]=qe|1;while(0);return qe=O+8|0,E=Lt,qe|0}for(l=11580;s=n[l>>2]|0,!(s>>>0<=Q>>>0&&(qe=s+(n[l+4>>2]|0)|0,qe>>>0>Q>>>0));)l=n[l+8>>2]|0;d=qe+-47|0,s=d+8|0,s=d+((s&7|0)==0?0:0-s&7)|0,d=Q+16|0,s=s>>>0<d>>>0?Q:s,l=s+8|0,c=m+8|0,c=(c&7|0)==0?0:0-c&7,Ue=m+c|0,c=B+-40-c|0,n[2789]=Ue,n[2786]=c,n[Ue+4>>2]=c|1,n[Ue+c+4>>2]=40,n[2790]=n[2905],c=s+4|0,n[c>>2]=27,n[l>>2]=n[2895],n[l+4>>2]=n[2896],n[l+8>>2]=n[2897],n[l+12>>2]=n[2898],n[2895]=m,n[2896]=B,n[2898]=0,n[2897]=l,l=s+24|0;do Ue=l,l=l+4|0,n[l>>2]=7;while((Ue+8|0)>>>0<qe>>>0);if((s|0)!=(Q|0)){if(m=s-Q|0,n[c>>2]=n[c>>2]&-2,n[Q+4>>2]=m|1,n[s>>2]=m,l=m>>>3,m>>>0<256){c=11172+(l<<1<<2)|0,s=n[2783]|0,l=1<<l,s&l?(s=c+8|0,l=n[s>>2]|0):(n[2783]=s|l,l=c,s=c+8|0),n[s>>2]=Q,n[l+12>>2]=Q,n[Q+8>>2]=l,n[Q+12>>2]=c;break}if(l=m>>>8,l?m>>>0>16777215?c=31:(Ue=(l+1048320|0)>>>16&8,qe=l<<Ue,at=(qe+520192|0)>>>16&4,qe=qe<<at,c=(qe+245760|0)>>>16&2,c=14-(at|Ue|c)+(qe<<c>>>15)|0,c=m>>>(c+7|0)&1|c<<1):c=0,f=11436+(c<<2)|0,n[Q+28>>2]=c,n[Q+20>>2]=0,n[d>>2]=0,l=n[2784]|0,s=1<<c,!(l&s)){n[2784]=l|s,n[f>>2]=Q,n[Q+24>>2]=f,n[Q+12>>2]=Q,n[Q+8>>2]=Q;break}for(s=m<<((c|0)==31?0:25-(c>>>1)|0),c=n[f>>2]|0;;){if((n[c+4>>2]&-8|0)==(m|0)){Ue=216;break}if(f=c+16+(s>>>31<<2)|0,l=n[f>>2]|0,l)s=s<<1,c=l;else{Ue=215;break}}if((Ue|0)==215){n[f>>2]=Q,n[Q+24>>2]=c,n[Q+12>>2]=Q,n[Q+8>>2]=Q;break}else if((Ue|0)==216){Ue=c+8|0,qe=n[Ue>>2]|0,n[qe+12>>2]=Q,n[Ue>>2]=Q,n[Q+8>>2]=qe,n[Q+12>>2]=c,n[Q+24>>2]=0;break}}}else{qe=n[2787]|0,(qe|0)==0|m>>>0<qe>>>0&&(n[2787]=m),n[2895]=m,n[2896]=B,n[2898]=0,n[2792]=n[2901],n[2791]=-1,l=0;do qe=11172+(l<<1<<2)|0,n[qe+12>>2]=qe,n[qe+8>>2]=qe,l=l+1|0;while((l|0)!=32);qe=m+8|0,qe=(qe&7|0)==0?0:0-qe&7,Ue=m+qe|0,qe=B+-40-qe|0,n[2789]=Ue,n[2786]=qe,n[Ue+4>>2]=qe|1,n[Ue+qe+4>>2]=40,n[2790]=n[2905]}while(0);if(l=n[2786]|0,l>>>0>q>>>0)return at=l-q|0,n[2786]=at,qe=n[2789]|0,Ue=qe+q|0,n[2789]=Ue,n[Ue+4>>2]=at|1,n[qe+4>>2]=q|3,qe=qe+8|0,E=Lt,qe|0}return n[(Wm()|0)>>2]=12,qe=0,E=Lt,qe|0}function hD(s){s=s|0;var l=0,c=0,f=0,d=0,m=0,B=0,k=0,Q=0;if(!!s){c=s+-8|0,d=n[2787]|0,s=n[s+-4>>2]|0,l=s&-8,Q=c+l|0;do if(s&1)k=c,B=c;else{if(f=n[c>>2]|0,!(s&3)||(B=c+(0-f)|0,m=f+l|0,B>>>0<d>>>0))return;if((B|0)==(n[2788]|0)){if(s=Q+4|0,l=n[s>>2]|0,(l&3|0)!=3){k=B,l=m;break}n[2785]=m,n[s>>2]=l&-2,n[B+4>>2]=m|1,n[B+m>>2]=m;return}if(c=f>>>3,f>>>0<256)if(s=n[B+8>>2]|0,l=n[B+12>>2]|0,(l|0)==(s|0)){n[2783]=n[2783]&~(1<<c),k=B,l=m;break}else{n[s+12>>2]=l,n[l+8>>2]=s,k=B,l=m;break}d=n[B+24>>2]|0,s=n[B+12>>2]|0;do if((s|0)==(B|0)){if(c=B+16|0,l=c+4|0,s=n[l>>2]|0,!s)if(s=n[c>>2]|0,s)l=c;else{s=0;break}for(;;){if(c=s+20|0,f=n[c>>2]|0,f|0){s=f,l=c;continue}if(c=s+16|0,f=n[c>>2]|0,f)s=f,l=c;else break}n[l>>2]=0}else k=n[B+8>>2]|0,n[k+12>>2]=s,n[s+8>>2]=k;while(0);if(d){if(l=n[B+28>>2]|0,c=11436+(l<<2)|0,(B|0)==(n[c>>2]|0)){if(n[c>>2]=s,!s){n[2784]=n[2784]&~(1<<l),k=B,l=m;break}}else if(n[d+16+(((n[d+16>>2]|0)!=(B|0)&1)<<2)>>2]=s,!s){k=B,l=m;break}n[s+24>>2]=d,l=B+16|0,c=n[l>>2]|0,c|0&&(n[s+16>>2]=c,n[c+24>>2]=s),l=n[l+4>>2]|0,l?(n[s+20>>2]=l,n[l+24>>2]=s,k=B,l=m):(k=B,l=m)}else k=B,l=m}while(0);if(!(B>>>0>=Q>>>0)&&(s=Q+4|0,f=n[s>>2]|0,!!(f&1))){if(f&2)n[s>>2]=f&-2,n[k+4>>2]=l|1,n[B+l>>2]=l,d=l;else{if(s=n[2788]|0,(Q|0)==(n[2789]|0)){if(Q=(n[2786]|0)+l|0,n[2786]=Q,n[2789]=k,n[k+4>>2]=Q|1,(k|0)!=(s|0))return;n[2788]=0,n[2785]=0;return}if((Q|0)==(s|0)){Q=(n[2785]|0)+l|0,n[2785]=Q,n[2788]=B,n[k+4>>2]=Q|1,n[B+Q>>2]=Q;return}d=(f&-8)+l|0,c=f>>>3;do if(f>>>0<256)if(l=n[Q+8>>2]|0,s=n[Q+12>>2]|0,(s|0)==(l|0)){n[2783]=n[2783]&~(1<<c);break}else{n[l+12>>2]=s,n[s+8>>2]=l;break}else{m=n[Q+24>>2]|0,s=n[Q+12>>2]|0;do if((s|0)==(Q|0)){if(c=Q+16|0,l=c+4|0,s=n[l>>2]|0,!s)if(s=n[c>>2]|0,s)l=c;else{c=0;break}for(;;){if(c=s+20|0,f=n[c>>2]|0,f|0){s=f,l=c;continue}if(c=s+16|0,f=n[c>>2]|0,f)s=f,l=c;else break}n[l>>2]=0,c=s}else c=n[Q+8>>2]|0,n[c+12>>2]=s,n[s+8>>2]=c,c=s;while(0);if(m|0){if(s=n[Q+28>>2]|0,l=11436+(s<<2)|0,(Q|0)==(n[l>>2]|0)){if(n[l>>2]=c,!c){n[2784]=n[2784]&~(1<<s);break}}else if(n[m+16+(((n[m+16>>2]|0)!=(Q|0)&1)<<2)>>2]=c,!c)break;n[c+24>>2]=m,s=Q+16|0,l=n[s>>2]|0,l|0&&(n[c+16>>2]=l,n[l+24>>2]=c),s=n[s+4>>2]|0,s|0&&(n[c+20>>2]=s,n[s+24>>2]=c)}}while(0);if(n[k+4>>2]=d|1,n[B+d>>2]=d,(k|0)==(n[2788]|0)){n[2785]=d;return}}if(s=d>>>3,d>>>0<256){c=11172+(s<<1<<2)|0,l=n[2783]|0,s=1<<s,l&s?(l=c+8|0,s=n[l>>2]|0):(n[2783]=l|s,s=c,l=c+8|0),n[l>>2]=k,n[s+12>>2]=k,n[k+8>>2]=s,n[k+12>>2]=c;return}s=d>>>8,s?d>>>0>16777215?s=31:(B=(s+1048320|0)>>>16&8,Q=s<<B,m=(Q+520192|0)>>>16&4,Q=Q<<m,s=(Q+245760|0)>>>16&2,s=14-(m|B|s)+(Q<<s>>>15)|0,s=d>>>(s+7|0)&1|s<<1):s=0,f=11436+(s<<2)|0,n[k+28>>2]=s,n[k+20>>2]=0,n[k+16>>2]=0,l=n[2784]|0,c=1<<s;do if(l&c){for(l=d<<((s|0)==31?0:25-(s>>>1)|0),c=n[f>>2]|0;;){if((n[c+4>>2]&-8|0)==(d|0)){s=73;break}if(f=c+16+(l>>>31<<2)|0,s=n[f>>2]|0,s)l=l<<1,c=s;else{s=72;break}}if((s|0)==72){n[f>>2]=k,n[k+24>>2]=c,n[k+12>>2]=k,n[k+8>>2]=k;break}else if((s|0)==73){B=c+8|0,Q=n[B>>2]|0,n[Q+12>>2]=k,n[B>>2]=k,n[k+8>>2]=Q,n[k+12>>2]=c,n[k+24>>2]=0;break}}else n[2784]=l|c,n[f>>2]=k,n[k+24>>2]=f,n[k+12>>2]=k,n[k+8>>2]=k;while(0);if(Q=(n[2791]|0)+-1|0,n[2791]=Q,!Q)s=11588;else return;for(;s=n[s>>2]|0,s;)s=s+8|0;n[2791]=-1}}}function kUe(){return 11628}function QUe(s){s=s|0;var l=0,c=0;return l=E,E=E+16|0,c=l,n[c>>2]=TUe(n[s+60>>2]|0)|0,s=gD(hc(6,c|0)|0)|0,E=l,s|0}function o7(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0,k=0,Q=0,M=0,O=0,q=0,se=0,Ge=0;q=E,E=E+48|0,M=q+16|0,m=q,d=q+32|0,k=s+28|0,f=n[k>>2]|0,n[d>>2]=f,Q=s+20|0,f=(n[Q>>2]|0)-f|0,n[d+4>>2]=f,n[d+8>>2]=l,n[d+12>>2]=c,f=f+c|0,B=s+60|0,n[m>>2]=n[B>>2],n[m+4>>2]=d,n[m+8>>2]=2,m=gD(Li(146,m|0)|0)|0;e:do if((f|0)!=(m|0)){for(l=2;!((m|0)<0);)if(f=f-m|0,Ge=n[d+4>>2]|0,se=m>>>0>Ge>>>0,d=se?d+8|0:d,l=(se<<31>>31)+l|0,Ge=m-(se?Ge:0)|0,n[d>>2]=(n[d>>2]|0)+Ge,se=d+4|0,n[se>>2]=(n[se>>2]|0)-Ge,n[M>>2]=n[B>>2],n[M+4>>2]=d,n[M+8>>2]=l,m=gD(Li(146,M|0)|0)|0,(f|0)==(m|0)){O=3;break e}n[s+16>>2]=0,n[k>>2]=0,n[Q>>2]=0,n[s>>2]=n[s>>2]|32,(l|0)==2?c=0:c=c-(n[d+4>>2]|0)|0}else O=3;while(0);return(O|0)==3&&(Ge=n[s+44>>2]|0,n[s+16>>2]=Ge+(n[s+48>>2]|0),n[k>>2]=Ge,n[Q>>2]=Ge),E=q,c|0}function FUe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0;return d=E,E=E+32|0,m=d,f=d+20|0,n[m>>2]=n[s+60>>2],n[m+4>>2]=0,n[m+8>>2]=l,n[m+12>>2]=f,n[m+16>>2]=c,(gD(sa(140,m|0)|0)|0)<0?(n[f>>2]=-1,s=-1):s=n[f>>2]|0,E=d,s|0}function gD(s){return s=s|0,s>>>0>4294963200&&(n[(Wm()|0)>>2]=0-s,s=-1),s|0}function Wm(){return(RUe()|0)+64|0}function RUe(){return bR()|0}function bR(){return 2084}function TUe(s){return s=s|0,s|0}function NUe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0;return d=E,E=E+32|0,f=d,n[s+36>>2]=1,(n[s>>2]&64|0)==0&&(n[f>>2]=n[s+60>>2],n[f+4>>2]=21523,n[f+8>>2]=d+16,fu(54,f|0)|0)&&(o[s+75>>0]=-1),f=o7(s,l,c)|0,E=d,f|0}function a7(s,l){s=s|0,l=l|0;var c=0,f=0;if(c=o[s>>0]|0,f=o[l>>0]|0,c<<24>>24==0||c<<24>>24!=f<<24>>24)s=f;else{do s=s+1|0,l=l+1|0,c=o[s>>0]|0,f=o[l>>0]|0;while(!(c<<24>>24==0||c<<24>>24!=f<<24>>24));s=f}return(c&255)-(s&255)|0}function LUe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0;e:do if(!c)s=0;else{for(;f=o[s>>0]|0,d=o[l>>0]|0,f<<24>>24==d<<24>>24;)if(c=c+-1|0,c)s=s+1|0,l=l+1|0;else{s=0;break e}s=(f&255)-(d&255)|0}while(0);return s|0}function l7(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0,k=0,Q=0,M=0,O=0,q=0,se=0,Ge=0,Me=0,Qe=0;Qe=E,E=E+224|0,O=Qe+120|0,q=Qe+80|0,Ge=Qe,Me=Qe+136|0,f=q,d=f+40|0;do n[f>>2]=0,f=f+4|0;while((f|0)<(d|0));return n[O>>2]=n[c>>2],(xR(0,l,O,Ge,q)|0)<0?c=-1:((n[s+76>>2]|0)>-1?se=OUe(s)|0:se=0,c=n[s>>2]|0,M=c&32,(o[s+74>>0]|0)<1&&(n[s>>2]=c&-33),f=s+48|0,n[f>>2]|0?c=xR(s,l,O,Ge,q)|0:(d=s+44|0,m=n[d>>2]|0,n[d>>2]=Me,B=s+28|0,n[B>>2]=Me,k=s+20|0,n[k>>2]=Me,n[f>>2]=80,Q=s+16|0,n[Q>>2]=Me+80,c=xR(s,l,O,Ge,q)|0,m&&(ED[n[s+36>>2]&7](s,0,0)|0,c=(n[k>>2]|0)==0?-1:c,n[d>>2]=m,n[f>>2]=0,n[Q>>2]=0,n[B>>2]=0,n[k>>2]=0)),f=n[s>>2]|0,n[s>>2]=f|M,se|0&&MUe(s),c=(f&32|0)==0?c:-1),E=Qe,c|0}function xR(s,l,c,f,d){s=s|0,l=l|0,c=c|0,f=f|0,d=d|0;var m=0,B=0,k=0,Q=0,M=0,O=0,q=0,se=0,Ge=0,Me=0,Qe=0,et=0,Xe=0,at=0,Ue=0,qe=0,Lt=0,Mr=0,or=0,Xt=0,Pr=0,Nr=0,ir=0;ir=E,E=E+64|0,or=ir+16|0,Xt=ir,Lt=ir+24|0,Pr=ir+8|0,Nr=ir+20|0,n[or>>2]=l,at=(s|0)!=0,Ue=Lt+40|0,qe=Ue,Lt=Lt+39|0,Mr=Pr+4|0,B=0,m=0,O=0;e:for(;;){do if((m|0)>-1)if((B|0)>(2147483647-m|0)){n[(Wm()|0)>>2]=75,m=-1;break}else{m=B+m|0;break}while(0);if(B=o[l>>0]|0,B<<24>>24)k=l;else{Xe=87;break}t:for(;;){switch(B<<24>>24){case 37:{B=k,Xe=9;break t}case 0:{B=k;break t}default:}et=k+1|0,n[or>>2]=et,B=o[et>>0]|0,k=et}t:do if((Xe|0)==9)for(;;){if(Xe=0,(o[k+1>>0]|0)!=37)break t;if(B=B+1|0,k=k+2|0,n[or>>2]=k,(o[k>>0]|0)==37)Xe=9;else break}while(0);if(B=B-l|0,at&&ss(s,l,B),B|0){l=k;continue}Q=k+1|0,B=(o[Q>>0]|0)+-48|0,B>>>0<10?(et=(o[k+2>>0]|0)==36,Qe=et?B:-1,O=et?1:O,Q=et?k+3|0:Q):Qe=-1,n[or>>2]=Q,B=o[Q>>0]|0,k=(B<<24>>24)+-32|0;t:do if(k>>>0<32)for(M=0,q=B;;){if(B=1<<k,!(B&75913)){B=q;break t}if(M=B|M,Q=Q+1|0,n[or>>2]=Q,B=o[Q>>0]|0,k=(B<<24>>24)+-32|0,k>>>0>=32)break;q=B}else M=0;while(0);if(B<<24>>24==42){if(k=Q+1|0,B=(o[k>>0]|0)+-48|0,B>>>0<10&&(o[Q+2>>0]|0)==36)n[d+(B<<2)>>2]=10,B=n[f+((o[k>>0]|0)+-48<<3)>>2]|0,O=1,Q=Q+3|0;else{if(O|0){m=-1;break}at?(O=(n[c>>2]|0)+(4-1)&~(4-1),B=n[O>>2]|0,n[c>>2]=O+4,O=0,Q=k):(B=0,O=0,Q=k)}n[or>>2]=Q,et=(B|0)<0,B=et?0-B|0:B,M=et?M|8192:M}else{if(B=c7(or)|0,(B|0)<0){m=-1;break}Q=n[or>>2]|0}do if((o[Q>>0]|0)==46){if((o[Q+1>>0]|0)!=42){n[or>>2]=Q+1,k=c7(or)|0,Q=n[or>>2]|0;break}if(q=Q+2|0,k=(o[q>>0]|0)+-48|0,k>>>0<10&&(o[Q+3>>0]|0)==36){n[d+(k<<2)>>2]=10,k=n[f+((o[q>>0]|0)+-48<<3)>>2]|0,Q=Q+4|0,n[or>>2]=Q;break}if(O|0){m=-1;break e}at?(et=(n[c>>2]|0)+(4-1)&~(4-1),k=n[et>>2]|0,n[c>>2]=et+4):k=0,n[or>>2]=q,Q=q}else k=-1;while(0);for(Me=0;;){if(((o[Q>>0]|0)+-65|0)>>>0>57){m=-1;break e}if(et=Q+1|0,n[or>>2]=et,q=o[(o[Q>>0]|0)+-65+(5178+(Me*58|0))>>0]|0,se=q&255,(se+-1|0)>>>0<8)Me=se,Q=et;else break}if(!(q<<24>>24)){m=-1;break}Ge=(Qe|0)>-1;do if(q<<24>>24==19)if(Ge){m=-1;break e}else Xe=49;else{if(Ge){n[d+(Qe<<2)>>2]=se,Ge=f+(Qe<<3)|0,Qe=n[Ge+4>>2]|0,Xe=Xt,n[Xe>>2]=n[Ge>>2],n[Xe+4>>2]=Qe,Xe=49;break}if(!at){m=0;break e}u7(Xt,se,c)}while(0);if((Xe|0)==49&&(Xe=0,!at)){B=0,l=et;continue}Q=o[Q>>0]|0,Q=(Me|0)!=0&(Q&15|0)==3?Q&-33:Q,Ge=M&-65537,Qe=(M&8192|0)==0?M:Ge;t:do switch(Q|0){case 110:switch((Me&255)<<24>>24){case 0:{n[n[Xt>>2]>>2]=m,B=0,l=et;continue e}case 1:{n[n[Xt>>2]>>2]=m,B=0,l=et;continue e}case 2:{B=n[Xt>>2]|0,n[B>>2]=m,n[B+4>>2]=((m|0)<0)<<31>>31,B=0,l=et;continue e}case 3:{a[n[Xt>>2]>>1]=m,B=0,l=et;continue e}case 4:{o[n[Xt>>2]>>0]=m,B=0,l=et;continue e}case 6:{n[n[Xt>>2]>>2]=m,B=0,l=et;continue e}case 7:{B=n[Xt>>2]|0,n[B>>2]=m,n[B+4>>2]=((m|0)<0)<<31>>31,B=0,l=et;continue e}default:{B=0,l=et;continue e}}case 112:{Q=120,k=k>>>0>8?k:8,l=Qe|8,Xe=61;break}case 88:case 120:{l=Qe,Xe=61;break}case 111:{Q=Xt,l=n[Q>>2]|0,Q=n[Q+4>>2]|0,se=_Ue(l,Q,Ue)|0,Ge=qe-se|0,M=0,q=5642,k=(Qe&8|0)==0|(k|0)>(Ge|0)?k:Ge+1|0,Ge=Qe,Xe=67;break}case 105:case 100:if(Q=Xt,l=n[Q>>2]|0,Q=n[Q+4>>2]|0,(Q|0)<0){l=dD(0,0,l|0,Q|0)|0,Q=De,M=Xt,n[M>>2]=l,n[M+4>>2]=Q,M=1,q=5642,Xe=66;break t}else{M=(Qe&2049|0)!=0&1,q=(Qe&2048|0)==0?(Qe&1|0)==0?5642:5644:5643,Xe=66;break t}case 117:{Q=Xt,M=0,q=5642,l=n[Q>>2]|0,Q=n[Q+4>>2]|0,Xe=66;break}case 99:{o[Lt>>0]=n[Xt>>2],l=Lt,M=0,q=5642,se=Ue,Q=1,k=Ge;break}case 109:{Q=HUe(n[(Wm()|0)>>2]|0)|0,Xe=71;break}case 115:{Q=n[Xt>>2]|0,Q=Q|0?Q:5652,Xe=71;break}case 67:{n[Pr>>2]=n[Xt>>2],n[Mr>>2]=0,n[Xt>>2]=Pr,se=-1,Q=Pr,Xe=75;break}case 83:{l=n[Xt>>2]|0,k?(se=k,Q=l,Xe=75):(Bs(s,32,B,0,Qe),l=0,Xe=84);break}case 65:case 71:case 70:case 69:case 97:case 103:case 102:case 101:{B=qUe(s,+C[Xt>>3],B,k,Qe,Q)|0,l=et;continue e}default:M=0,q=5642,se=Ue,Q=k,k=Qe}while(0);t:do if((Xe|0)==61)Qe=Xt,Me=n[Qe>>2]|0,Qe=n[Qe+4>>2]|0,se=UUe(Me,Qe,Ue,Q&32)|0,q=(l&8|0)==0|(Me|0)==0&(Qe|0)==0,M=q?0:2,q=q?5642:5642+(Q>>4)|0,Ge=l,l=Me,Q=Qe,Xe=67;else if((Xe|0)==66)se=Km(l,Q,Ue)|0,Ge=Qe,Xe=67;else if((Xe|0)==71)Xe=0,Qe=jUe(Q,0,k)|0,Me=(Qe|0)==0,l=Q,M=0,q=5642,se=Me?Q+k|0:Qe,Q=Me?k:Qe-Q|0,k=Ge;else if((Xe|0)==75){for(Xe=0,q=Q,l=0,k=0;M=n[q>>2]|0,!(!M||(k=A7(Nr,M)|0,(k|0)<0|k>>>0>(se-l|0)>>>0));)if(l=k+l|0,se>>>0>l>>>0)q=q+4|0;else break;if((k|0)<0){m=-1;break e}if(Bs(s,32,B,l,Qe),!l)l=0,Xe=84;else for(M=0;;){if(k=n[Q>>2]|0,!k){Xe=84;break t}if(k=A7(Nr,k)|0,M=k+M|0,(M|0)>(l|0)){Xe=84;break t}if(ss(s,Nr,k),M>>>0>=l>>>0){Xe=84;break}else Q=Q+4|0}}while(0);if((Xe|0)==67)Xe=0,Q=(l|0)!=0|(Q|0)!=0,Qe=(k|0)!=0|Q,Q=((Q^1)&1)+(qe-se)|0,l=Qe?se:Ue,se=Ue,Q=Qe?(k|0)>(Q|0)?k:Q:k,k=(k|0)>-1?Ge&-65537:Ge;else if((Xe|0)==84){Xe=0,Bs(s,32,B,l,Qe^8192),B=(B|0)>(l|0)?B:l,l=et;continue}Me=se-l|0,Ge=(Q|0)<(Me|0)?Me:Q,Qe=Ge+M|0,B=(B|0)<(Qe|0)?Qe:B,Bs(s,32,B,Qe,k),ss(s,q,M),Bs(s,48,B,Qe,k^65536),Bs(s,48,Ge,Me,0),ss(s,l,Me),Bs(s,32,B,Qe,k^8192),l=et}e:do if((Xe|0)==87&&!s)if(!O)m=0;else{for(m=1;l=n[d+(m<<2)>>2]|0,!!l;)if(u7(f+(m<<3)|0,l,c),m=m+1|0,(m|0)>=10){m=1;break e}for(;;){if(n[d+(m<<2)>>2]|0){m=-1;break e}if(m=m+1|0,(m|0)>=10){m=1;break}}}while(0);return E=ir,m|0}function OUe(s){return s=s|0,0}function MUe(s){s=s|0}function ss(s,l,c){s=s|0,l=l|0,c=c|0,n[s>>2]&32||ZUe(l,c,s)|0}function c7(s){s=s|0;var l=0,c=0,f=0;if(c=n[s>>2]|0,f=(o[c>>0]|0)+-48|0,f>>>0<10){l=0;do l=f+(l*10|0)|0,c=c+1|0,n[s>>2]=c,f=(o[c>>0]|0)+-48|0;while(f>>>0<10)}else l=0;return l|0}function u7(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0;e:do if(l>>>0<=20)do switch(l|0){case 9:{f=(n[c>>2]|0)+(4-1)&~(4-1),l=n[f>>2]|0,n[c>>2]=f+4,n[s>>2]=l;break e}case 10:{f=(n[c>>2]|0)+(4-1)&~(4-1),l=n[f>>2]|0,n[c>>2]=f+4,f=s,n[f>>2]=l,n[f+4>>2]=((l|0)<0)<<31>>31;break e}case 11:{f=(n[c>>2]|0)+(4-1)&~(4-1),l=n[f>>2]|0,n[c>>2]=f+4,f=s,n[f>>2]=l,n[f+4>>2]=0;break e}case 12:{f=(n[c>>2]|0)+(8-1)&~(8-1),l=f,d=n[l>>2]|0,l=n[l+4>>2]|0,n[c>>2]=f+8,f=s,n[f>>2]=d,n[f+4>>2]=l;break e}case 13:{d=(n[c>>2]|0)+(4-1)&~(4-1),f=n[d>>2]|0,n[c>>2]=d+4,f=(f&65535)<<16>>16,d=s,n[d>>2]=f,n[d+4>>2]=((f|0)<0)<<31>>31;break e}case 14:{d=(n[c>>2]|0)+(4-1)&~(4-1),f=n[d>>2]|0,n[c>>2]=d+4,d=s,n[d>>2]=f&65535,n[d+4>>2]=0;break e}case 15:{d=(n[c>>2]|0)+(4-1)&~(4-1),f=n[d>>2]|0,n[c>>2]=d+4,f=(f&255)<<24>>24,d=s,n[d>>2]=f,n[d+4>>2]=((f|0)<0)<<31>>31;break e}case 16:{d=(n[c>>2]|0)+(4-1)&~(4-1),f=n[d>>2]|0,n[c>>2]=d+4,d=s,n[d>>2]=f&255,n[d+4>>2]=0;break e}case 17:{d=(n[c>>2]|0)+(8-1)&~(8-1),m=+C[d>>3],n[c>>2]=d+8,C[s>>3]=m;break e}case 18:{d=(n[c>>2]|0)+(8-1)&~(8-1),m=+C[d>>3],n[c>>2]=d+8,C[s>>3]=m;break e}default:break e}while(0);while(0)}function UUe(s,l,c,f){if(s=s|0,l=l|0,c=c|0,f=f|0,!((s|0)==0&(l|0)==0))do c=c+-1|0,o[c>>0]=u[5694+(s&15)>>0]|0|f,s=mD(s|0,l|0,4)|0,l=De;while(!((s|0)==0&(l|0)==0));return c|0}function _Ue(s,l,c){if(s=s|0,l=l|0,c=c|0,!((s|0)==0&(l|0)==0))do c=c+-1|0,o[c>>0]=s&7|48,s=mD(s|0,l|0,3)|0,l=De;while(!((s|0)==0&(l|0)==0));return c|0}function Km(s,l,c){s=s|0,l=l|0,c=c|0;var f=0;if(l>>>0>0|(l|0)==0&s>>>0>4294967295){for(;f=RR(s|0,l|0,10,0)|0,c=c+-1|0,o[c>>0]=f&255|48,f=s,s=FR(s|0,l|0,10,0)|0,l>>>0>9|(l|0)==9&f>>>0>4294967295;)l=De;l=s}else l=s;if(l)for(;c=c+-1|0,o[c>>0]=(l>>>0)%10|0|48,!(l>>>0<10);)l=(l>>>0)/10|0;return c|0}function HUe(s){return s=s|0,VUe(s,n[(KUe()|0)+188>>2]|0)|0}function jUe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0;m=l&255,f=(c|0)!=0;e:do if(f&(s&3|0)!=0)for(d=l&255;;){if((o[s>>0]|0)==d<<24>>24){B=6;break e}if(s=s+1|0,c=c+-1|0,f=(c|0)!=0,!(f&(s&3|0)!=0)){B=5;break}}else B=5;while(0);(B|0)==5&&(f?B=6:c=0);e:do if((B|0)==6&&(d=l&255,(o[s>>0]|0)!=d<<24>>24)){f=He(m,16843009)|0;t:do if(c>>>0>3){for(;m=n[s>>2]^f,!((m&-2139062144^-2139062144)&m+-16843009|0);)if(s=s+4|0,c=c+-4|0,c>>>0<=3){B=11;break t}}else B=11;while(0);if((B|0)==11&&!c){c=0;break}for(;;){if((o[s>>0]|0)==d<<24>>24)break e;if(s=s+1|0,c=c+-1|0,!c){c=0;break}}}while(0);return(c|0?s:0)|0}function Bs(s,l,c,f,d){s=s|0,l=l|0,c=c|0,f=f|0,d=d|0;var m=0,B=0;if(B=E,E=E+256|0,m=B,(c|0)>(f|0)&(d&73728|0)==0){if(d=c-f|0,zm(m|0,l|0,(d>>>0<256?d:256)|0)|0,d>>>0>255){l=c-f|0;do ss(s,m,256),d=d+-256|0;while(d>>>0>255);d=l&255}ss(s,m,d)}E=B}function A7(s,l){return s=s|0,l=l|0,s?s=YUe(s,l,0)|0:s=0,s|0}function qUe(s,l,c,f,d,m){s=s|0,l=+l,c=c|0,f=f|0,d=d|0,m=m|0;var B=0,k=0,Q=0,M=0,O=0,q=0,se=0,Ge=0,Me=0,Qe=0,et=0,Xe=0,at=0,Ue=0,qe=0,Lt=0,Mr=0,or=0,Xt=0,Pr=0,Nr=0,ir=0,xn=0;xn=E,E=E+560|0,Q=xn+8|0,et=xn,ir=xn+524|0,Nr=ir,M=xn+512|0,n[et>>2]=0,Pr=M+12|0,f7(l)|0,(De|0)<0?(l=-l,or=1,Mr=5659):(or=(d&2049|0)!=0&1,Mr=(d&2048|0)==0?(d&1|0)==0?5660:5665:5662),f7(l)|0,Xt=De&2146435072;do if(Xt>>>0<2146435072|(Xt|0)==2146435072&0<0){if(Ge=+GUe(l,et)*2,B=Ge!=0,B&&(n[et>>2]=(n[et>>2]|0)+-1),at=m|32,(at|0)==97){Me=m&32,se=(Me|0)==0?Mr:Mr+9|0,q=or|2,B=12-f|0;do if(f>>>0>11|(B|0)==0)l=Ge;else{l=8;do B=B+-1|0,l=l*16;while((B|0)!=0);if((o[se>>0]|0)==45){l=-(l+(-Ge-l));break}else{l=Ge+l-l;break}}while(0);k=n[et>>2]|0,B=(k|0)<0?0-k|0:k,B=Km(B,((B|0)<0)<<31>>31,Pr)|0,(B|0)==(Pr|0)&&(B=M+11|0,o[B>>0]=48),o[B+-1>>0]=(k>>31&2)+43,O=B+-2|0,o[O>>0]=m+15,M=(f|0)<1,Q=(d&8|0)==0,B=ir;do Xt=~~l,k=B+1|0,o[B>>0]=u[5694+Xt>>0]|Me,l=(l-+(Xt|0))*16,(k-Nr|0)==1&&!(Q&(M&l==0))?(o[k>>0]=46,B=B+2|0):B=k;while(l!=0);Xt=B-Nr|0,Nr=Pr-O|0,Pr=(f|0)!=0&(Xt+-2|0)<(f|0)?f+2|0:Xt,B=Nr+q+Pr|0,Bs(s,32,c,B,d),ss(s,se,q),Bs(s,48,c,B,d^65536),ss(s,ir,Xt),Bs(s,48,Pr-Xt|0,0,0),ss(s,O,Nr),Bs(s,32,c,B,d^8192);break}k=(f|0)<0?6:f,B?(B=(n[et>>2]|0)+-28|0,n[et>>2]=B,l=Ge*268435456):(l=Ge,B=n[et>>2]|0),Xt=(B|0)<0?Q:Q+288|0,Q=Xt;do qe=~~l>>>0,n[Q>>2]=qe,Q=Q+4|0,l=(l-+(qe>>>0))*1e9;while(l!=0);if((B|0)>0)for(M=Xt,q=Q;;){if(O=(B|0)<29?B:29,B=q+-4|0,B>>>0>=M>>>0){Q=0;do Ue=y7(n[B>>2]|0,0,O|0)|0,Ue=QR(Ue|0,De|0,Q|0,0)|0,qe=De,Xe=RR(Ue|0,qe|0,1e9,0)|0,n[B>>2]=Xe,Q=FR(Ue|0,qe|0,1e9,0)|0,B=B+-4|0;while(B>>>0>=M>>>0);Q&&(M=M+-4|0,n[M>>2]=Q)}for(Q=q;!(Q>>>0<=M>>>0);)if(B=Q+-4|0,!(n[B>>2]|0))Q=B;else break;if(B=(n[et>>2]|0)-O|0,n[et>>2]=B,(B|0)>0)q=Q;else break}else M=Xt;if((B|0)<0){f=((k+25|0)/9|0)+1|0,Qe=(at|0)==102;do{if(Me=0-B|0,Me=(Me|0)<9?Me:9,M>>>0<Q>>>0){O=(1<<Me)+-1|0,q=1e9>>>Me,se=0,B=M;do qe=n[B>>2]|0,n[B>>2]=(qe>>>Me)+se,se=He(qe&O,q)|0,B=B+4|0;while(B>>>0<Q>>>0);B=(n[M>>2]|0)==0?M+4|0:M,se?(n[Q>>2]=se,M=B,B=Q+4|0):(M=B,B=Q)}else M=(n[M>>2]|0)==0?M+4|0:M,B=Q;Q=Qe?Xt:M,Q=(B-Q>>2|0)>(f|0)?Q+(f<<2)|0:B,B=(n[et>>2]|0)+Me|0,n[et>>2]=B}while((B|0)<0);B=M,f=Q}else B=M,f=Q;if(qe=Xt,B>>>0<f>>>0){if(Q=(qe-B>>2)*9|0,O=n[B>>2]|0,O>>>0>=10){M=10;do M=M*10|0,Q=Q+1|0;while(O>>>0>=M>>>0)}}else Q=0;if(Qe=(at|0)==103,Xe=(k|0)!=0,M=k-((at|0)!=102?Q:0)+((Xe&Qe)<<31>>31)|0,(M|0)<(((f-qe>>2)*9|0)+-9|0)){if(M=M+9216|0,Me=Xt+4+(((M|0)/9|0)+-1024<<2)|0,M=((M|0)%9|0)+1|0,(M|0)<9){O=10;do O=O*10|0,M=M+1|0;while((M|0)!=9)}else O=10;if(q=n[Me>>2]|0,se=(q>>>0)%(O>>>0)|0,M=(Me+4|0)==(f|0),M&(se|0)==0)M=Me;else if(Ge=(((q>>>0)/(O>>>0)|0)&1|0)==0?9007199254740992:9007199254740994,Ue=(O|0)/2|0,l=se>>>0<Ue>>>0?.5:M&(se|0)==(Ue|0)?1:1.5,or&&(Ue=(o[Mr>>0]|0)==45,l=Ue?-l:l,Ge=Ue?-Ge:Ge),M=q-se|0,n[Me>>2]=M,Ge+l!=Ge){if(Ue=M+O|0,n[Me>>2]=Ue,Ue>>>0>999999999)for(Q=Me;M=Q+-4|0,n[Q>>2]=0,M>>>0<B>>>0&&(B=B+-4|0,n[B>>2]=0),Ue=(n[M>>2]|0)+1|0,n[M>>2]=Ue,Ue>>>0>999999999;)Q=M;else M=Me;if(Q=(qe-B>>2)*9|0,q=n[B>>2]|0,q>>>0>=10){O=10;do O=O*10|0,Q=Q+1|0;while(q>>>0>=O>>>0)}}else M=Me;M=M+4|0,M=f>>>0>M>>>0?M:f,Ue=B}else M=f,Ue=B;for(at=M;;){if(at>>>0<=Ue>>>0){et=0;break}if(B=at+-4|0,!(n[B>>2]|0))at=B;else{et=1;break}}f=0-Q|0;do if(Qe)if(B=((Xe^1)&1)+k|0,(B|0)>(Q|0)&(Q|0)>-5?(O=m+-1|0,k=B+-1-Q|0):(O=m+-2|0,k=B+-1|0),B=d&8,B)Me=B;else{if(et&&(Lt=n[at+-4>>2]|0,(Lt|0)!=0))if((Lt>>>0)%10|0)M=0;else{M=0,B=10;do B=B*10|0,M=M+1|0;while(!((Lt>>>0)%(B>>>0)|0|0))}else M=9;if(B=((at-qe>>2)*9|0)+-9|0,(O|32|0)==102){Me=B-M|0,Me=(Me|0)>0?Me:0,k=(k|0)<(Me|0)?k:Me,Me=0;break}else{Me=B+Q-M|0,Me=(Me|0)>0?Me:0,k=(k|0)<(Me|0)?k:Me,Me=0;break}}else O=m,Me=d&8;while(0);if(Qe=k|Me,q=(Qe|0)!=0&1,se=(O|32|0)==102,se)Xe=0,B=(Q|0)>0?Q:0;else{if(B=(Q|0)<0?f:Q,B=Km(B,((B|0)<0)<<31>>31,Pr)|0,M=Pr,(M-B|0)<2)do B=B+-1|0,o[B>>0]=48;while((M-B|0)<2);o[B+-1>>0]=(Q>>31&2)+43,B=B+-2|0,o[B>>0]=O,Xe=B,B=M-B|0}if(B=or+1+k+q+B|0,Bs(s,32,c,B,d),ss(s,Mr,or),Bs(s,48,c,B,d^65536),se){O=Ue>>>0>Xt>>>0?Xt:Ue,Me=ir+9|0,q=Me,se=ir+8|0,M=O;do{if(Q=Km(n[M>>2]|0,0,Me)|0,(M|0)==(O|0))(Q|0)==(Me|0)&&(o[se>>0]=48,Q=se);else if(Q>>>0>ir>>>0){zm(ir|0,48,Q-Nr|0)|0;do Q=Q+-1|0;while(Q>>>0>ir>>>0)}ss(s,Q,q-Q|0),M=M+4|0}while(M>>>0<=Xt>>>0);if(Qe|0&&ss(s,5710,1),M>>>0<at>>>0&(k|0)>0)for(;;){if(Q=Km(n[M>>2]|0,0,Me)|0,Q>>>0>ir>>>0){zm(ir|0,48,Q-Nr|0)|0;do Q=Q+-1|0;while(Q>>>0>ir>>>0)}if(ss(s,Q,(k|0)<9?k:9),M=M+4|0,Q=k+-9|0,M>>>0<at>>>0&(k|0)>9)k=Q;else{k=Q;break}}Bs(s,48,k+9|0,9,0)}else{if(Qe=et?at:Ue+4|0,(k|0)>-1){et=ir+9|0,Me=(Me|0)==0,f=et,q=0-Nr|0,se=ir+8|0,O=Ue;do{Q=Km(n[O>>2]|0,0,et)|0,(Q|0)==(et|0)&&(o[se>>0]=48,Q=se);do if((O|0)==(Ue|0)){if(M=Q+1|0,ss(s,Q,1),Me&(k|0)<1){Q=M;break}ss(s,5710,1),Q=M}else{if(Q>>>0<=ir>>>0)break;zm(ir|0,48,Q+q|0)|0;do Q=Q+-1|0;while(Q>>>0>ir>>>0)}while(0);Nr=f-Q|0,ss(s,Q,(k|0)>(Nr|0)?Nr:k),k=k-Nr|0,O=O+4|0}while(O>>>0<Qe>>>0&(k|0)>-1)}Bs(s,48,k+18|0,18,0),ss(s,Xe,Pr-Xe|0)}Bs(s,32,c,B,d^8192)}else ir=(m&32|0)!=0,B=or+3|0,Bs(s,32,c,B,d&-65537),ss(s,Mr,or),ss(s,l!=l|!1?ir?5686:5690:ir?5678:5682,3),Bs(s,32,c,B,d^8192);while(0);return E=xn,((B|0)<(c|0)?c:B)|0}function f7(s){s=+s;var l=0;return C[v>>3]=s,l=n[v>>2]|0,De=n[v+4>>2]|0,l|0}function GUe(s,l){return s=+s,l=l|0,+ +p7(s,l)}function p7(s,l){s=+s,l=l|0;var c=0,f=0,d=0;switch(C[v>>3]=s,c=n[v>>2]|0,f=n[v+4>>2]|0,d=mD(c|0,f|0,52)|0,d&2047){case 0:{s!=0?(s=+p7(s*18446744073709552e3,l),c=(n[l>>2]|0)+-64|0):c=0,n[l>>2]=c;break}case 2047:break;default:n[l>>2]=(d&2047)+-1022,n[v>>2]=c,n[v+4>>2]=f&-2146435073|1071644672,s=+C[v>>3]}return+s}function YUe(s,l,c){s=s|0,l=l|0,c=c|0;do if(s){if(l>>>0<128){o[s>>0]=l,s=1;break}if(!(n[n[(WUe()|0)+188>>2]>>2]|0))if((l&-128|0)==57216){o[s>>0]=l,s=1;break}else{n[(Wm()|0)>>2]=84,s=-1;break}if(l>>>0<2048){o[s>>0]=l>>>6|192,o[s+1>>0]=l&63|128,s=2;break}if(l>>>0<55296|(l&-8192|0)==57344){o[s>>0]=l>>>12|224,o[s+1>>0]=l>>>6&63|128,o[s+2>>0]=l&63|128,s=3;break}if((l+-65536|0)>>>0<1048576){o[s>>0]=l>>>18|240,o[s+1>>0]=l>>>12&63|128,o[s+2>>0]=l>>>6&63|128,o[s+3>>0]=l&63|128,s=4;break}else{n[(Wm()|0)>>2]=84,s=-1;break}}else s=1;while(0);return s|0}function WUe(){return bR()|0}function KUe(){return bR()|0}function VUe(s,l){s=s|0,l=l|0;var c=0,f=0;for(f=0;;){if((u[5712+f>>0]|0)==(s|0)){s=2;break}if(c=f+1|0,(c|0)==87){c=5800,f=87,s=5;break}else f=c}if((s|0)==2&&(f?(c=5800,s=5):c=5800),(s|0)==5)for(;;){do s=c,c=c+1|0;while((o[s>>0]|0)!=0);if(f=f+-1|0,f)s=5;else break}return zUe(c,n[l+20>>2]|0)|0}function zUe(s,l){return s=s|0,l=l|0,JUe(s,l)|0}function JUe(s,l){return s=s|0,l=l|0,l?l=XUe(n[l>>2]|0,n[l+4>>2]|0,s)|0:l=0,(l|0?l:s)|0}function XUe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0,k=0,Q=0,M=0,O=0,q=0,se=0;se=(n[s>>2]|0)+1794895138|0,m=Qg(n[s+8>>2]|0,se)|0,f=Qg(n[s+12>>2]|0,se)|0,d=Qg(n[s+16>>2]|0,se)|0;e:do if(m>>>0<l>>>2>>>0&&(q=l-(m<<2)|0,f>>>0<q>>>0&d>>>0<q>>>0)&&((d|f)&3|0)==0){for(q=f>>>2,O=d>>>2,M=0;;){if(k=m>>>1,Q=M+k|0,B=Q<<1,d=B+q|0,f=Qg(n[s+(d<<2)>>2]|0,se)|0,d=Qg(n[s+(d+1<<2)>>2]|0,se)|0,!(d>>>0<l>>>0&f>>>0<(l-d|0)>>>0)){f=0;break e}if(o[s+(d+f)>>0]|0){f=0;break e}if(f=a7(c,s+d|0)|0,!f)break;if(f=(f|0)<0,(m|0)==1){f=0;break e}else M=f?M:Q,m=f?k:m-k|0}f=B+O|0,d=Qg(n[s+(f<<2)>>2]|0,se)|0,f=Qg(n[s+(f+1<<2)>>2]|0,se)|0,f>>>0<l>>>0&d>>>0<(l-f|0)>>>0?f=(o[s+(f+d)>>0]|0)==0?s+f|0:0:f=0}else f=0;while(0);return f|0}function Qg(s,l){s=s|0,l=l|0;var c=0;return c=w7(s|0)|0,((l|0)==0?s:c)|0}function ZUe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0,k=0;f=c+16|0,d=n[f>>2]|0,d?m=5:$Ue(c)|0?f=0:(d=n[f>>2]|0,m=5);e:do if((m|0)==5){if(k=c+20|0,B=n[k>>2]|0,f=B,(d-B|0)>>>0<l>>>0){f=ED[n[c+36>>2]&7](c,s,l)|0;break}t:do if((o[c+75>>0]|0)>-1){for(B=l;;){if(!B){m=0,d=s;break t}if(d=B+-1|0,(o[s+d>>0]|0)==10)break;B=d}if(f=ED[n[c+36>>2]&7](c,s,B)|0,f>>>0<B>>>0)break e;m=B,d=s+B|0,l=l-B|0,f=n[k>>2]|0}else m=0,d=s;while(0);Dr(f|0,d|0,l|0)|0,n[k>>2]=(n[k>>2]|0)+l,f=m+l|0}while(0);return f|0}function $Ue(s){s=s|0;var l=0,c=0;return l=s+74|0,c=o[l>>0]|0,o[l>>0]=c+255|c,l=n[s>>2]|0,l&8?(n[s>>2]=l|32,s=-1):(n[s+8>>2]=0,n[s+4>>2]=0,c=n[s+44>>2]|0,n[s+28>>2]=c,n[s+20>>2]=c,n[s+16>>2]=c+(n[s+48>>2]|0),s=0),s|0}function _n(s,l){s=y(s),l=y(l);var c=0,f=0;c=h7(s)|0;do if((c&2147483647)>>>0<=2139095040){if(f=h7(l)|0,(f&2147483647)>>>0<=2139095040)if((f^c|0)<0){s=(c|0)<0?l:s;break}else{s=s<l?l:s;break}}else s=l;while(0);return y(s)}function h7(s){return s=y(s),h[v>>2]=s,n[v>>2]|0|0}function Fg(s,l){s=y(s),l=y(l);var c=0,f=0;c=g7(s)|0;do if((c&2147483647)>>>0<=2139095040){if(f=g7(l)|0,(f&2147483647)>>>0<=2139095040)if((f^c|0)<0){s=(c|0)<0?s:l;break}else{s=s<l?s:l;break}}else s=l;while(0);return y(s)}function g7(s){return s=y(s),h[v>>2]=s,n[v>>2]|0|0}function kR(s,l){s=y(s),l=y(l);var c=0,f=0,d=0,m=0,B=0,k=0,Q=0,M=0;m=(h[v>>2]=s,n[v>>2]|0),k=(h[v>>2]=l,n[v>>2]|0),c=m>>>23&255,B=k>>>23&255,Q=m&-2147483648,d=k<<1;e:do if((d|0)!=0&&!((c|0)==255|((e3e(l)|0)&2147483647)>>>0>2139095040)){if(f=m<<1,f>>>0<=d>>>0)return l=y(s*y(0)),y((f|0)==(d|0)?l:s);if(c)f=m&8388607|8388608;else{if(c=m<<9,(c|0)>-1){f=c,c=0;do c=c+-1|0,f=f<<1;while((f|0)>-1)}else c=0;f=m<<1-c}if(B)k=k&8388607|8388608;else{if(m=k<<9,(m|0)>-1){d=0;do d=d+-1|0,m=m<<1;while((m|0)>-1)}else d=0;B=d,k=k<<1-d}d=f-k|0,m=(d|0)>-1;t:do if((c|0)>(B|0)){for(;;){if(m)if(d)f=d;else break;if(f=f<<1,c=c+-1|0,d=f-k|0,m=(d|0)>-1,(c|0)<=(B|0))break t}l=y(s*y(0));break e}while(0);if(m)if(d)f=d;else{l=y(s*y(0));break}if(f>>>0<8388608)do f=f<<1,c=c+-1|0;while(f>>>0<8388608);(c|0)>0?c=f+-8388608|c<<23:c=f>>>(1-c|0),l=(n[v>>2]=c|Q,y(h[v>>2]))}else M=3;while(0);return(M|0)==3&&(l=y(s*l),l=y(l/l)),y(l)}function e3e(s){return s=y(s),h[v>>2]=s,n[v>>2]|0|0}function t3e(s,l){return s=s|0,l=l|0,l7(n[582]|0,s,l)|0}function Jr(s){s=s|0,Rt()}function Vm(s){s=s|0}function r3e(s,l){return s=s|0,l=l|0,0}function n3e(s){return s=s|0,(d7(s+4|0)|0)==-1?(ef[n[(n[s>>2]|0)+8>>2]&127](s),s=1):s=0,s|0}function d7(s){s=s|0;var l=0;return l=n[s>>2]|0,n[s>>2]=l+-1,l+-1|0}function bp(s){s=s|0,n3e(s)|0&&i3e(s)}function i3e(s){s=s|0;var l=0;l=s+8|0,(n[l>>2]|0)!=0&&(d7(l)|0)!=-1||ef[n[(n[s>>2]|0)+16>>2]&127](s)}function Kt(s){s=s|0;var l=0;for(l=(s|0)==0?1:s;s=pD(l)|0,!(s|0);){if(s=o3e()|0,!s){s=0;break}Q7[s&0]()}return s|0}function m7(s){return s=s|0,Kt(s)|0}function gt(s){s=s|0,hD(s)}function s3e(s){s=s|0,(o[s+11>>0]|0)<0&&gt(n[s>>2]|0)}function o3e(){var s=0;return s=n[2923]|0,n[2923]=s+0,s|0}function a3e(){}function dD(s,l,c,f){return s=s|0,l=l|0,c=c|0,f=f|0,f=l-f-(c>>>0>s>>>0|0)>>>0,De=f,s-c>>>0|0|0}function QR(s,l,c,f){return s=s|0,l=l|0,c=c|0,f=f|0,c=s+c>>>0,De=l+f+(c>>>0<s>>>0|0)>>>0,c|0|0}function zm(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0;if(m=s+c|0,l=l&255,(c|0)>=67){for(;s&3;)o[s>>0]=l,s=s+1|0;for(f=m&-4|0,d=f-64|0,B=l|l<<8|l<<16|l<<24;(s|0)<=(d|0);)n[s>>2]=B,n[s+4>>2]=B,n[s+8>>2]=B,n[s+12>>2]=B,n[s+16>>2]=B,n[s+20>>2]=B,n[s+24>>2]=B,n[s+28>>2]=B,n[s+32>>2]=B,n[s+36>>2]=B,n[s+40>>2]=B,n[s+44>>2]=B,n[s+48>>2]=B,n[s+52>>2]=B,n[s+56>>2]=B,n[s+60>>2]=B,s=s+64|0;for(;(s|0)<(f|0);)n[s>>2]=B,s=s+4|0}for(;(s|0)<(m|0);)o[s>>0]=l,s=s+1|0;return m-c|0}function y7(s,l,c){return s=s|0,l=l|0,c=c|0,(c|0)<32?(De=l<<c|(s&(1<<c)-1<<32-c)>>>32-c,s<<c):(De=s<<c-32,0)}function mD(s,l,c){return s=s|0,l=l|0,c=c|0,(c|0)<32?(De=l>>>c,s>>>c|(l&(1<<c)-1)<<32-c):(De=0,l>>>c-32|0)}function Dr(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0;if((c|0)>=8192)return Ac(s|0,l|0,c|0)|0;if(m=s|0,d=s+c|0,(s&3)==(l&3)){for(;s&3;){if(!c)return m|0;o[s>>0]=o[l>>0]|0,s=s+1|0,l=l+1|0,c=c-1|0}for(c=d&-4|0,f=c-64|0;(s|0)<=(f|0);)n[s>>2]=n[l>>2],n[s+4>>2]=n[l+4>>2],n[s+8>>2]=n[l+8>>2],n[s+12>>2]=n[l+12>>2],n[s+16>>2]=n[l+16>>2],n[s+20>>2]=n[l+20>>2],n[s+24>>2]=n[l+24>>2],n[s+28>>2]=n[l+28>>2],n[s+32>>2]=n[l+32>>2],n[s+36>>2]=n[l+36>>2],n[s+40>>2]=n[l+40>>2],n[s+44>>2]=n[l+44>>2],n[s+48>>2]=n[l+48>>2],n[s+52>>2]=n[l+52>>2],n[s+56>>2]=n[l+56>>2],n[s+60>>2]=n[l+60>>2],s=s+64|0,l=l+64|0;for(;(s|0)<(c|0);)n[s>>2]=n[l>>2],s=s+4|0,l=l+4|0}else for(c=d-4|0;(s|0)<(c|0);)o[s>>0]=o[l>>0]|0,o[s+1>>0]=o[l+1>>0]|0,o[s+2>>0]=o[l+2>>0]|0,o[s+3>>0]=o[l+3>>0]|0,s=s+4|0,l=l+4|0;for(;(s|0)<(d|0);)o[s>>0]=o[l>>0]|0,s=s+1|0,l=l+1|0;return m|0}function E7(s){s=s|0;var l=0;return l=o[L+(s&255)>>0]|0,(l|0)<8?l|0:(l=o[L+(s>>8&255)>>0]|0,(l|0)<8?l+8|0:(l=o[L+(s>>16&255)>>0]|0,(l|0)<8?l+16|0:(o[L+(s>>>24)>>0]|0)+24|0))}function C7(s,l,c,f,d){s=s|0,l=l|0,c=c|0,f=f|0,d=d|0;var m=0,B=0,k=0,Q=0,M=0,O=0,q=0,se=0,Ge=0,Me=0;if(O=s,Q=l,M=Q,B=c,se=f,k=se,!M)return m=(d|0)!=0,k?m?(n[d>>2]=s|0,n[d+4>>2]=l&0,se=0,d=0,De=se,d|0):(se=0,d=0,De=se,d|0):(m&&(n[d>>2]=(O>>>0)%(B>>>0),n[d+4>>2]=0),se=0,d=(O>>>0)/(B>>>0)>>>0,De=se,d|0);m=(k|0)==0;do if(B){if(!m){if(m=(S(k|0)|0)-(S(M|0)|0)|0,m>>>0<=31){q=m+1|0,k=31-m|0,l=m-31>>31,B=q,s=O>>>(q>>>0)&l|M<<k,l=M>>>(q>>>0)&l,m=0,k=O<<k;break}return d?(n[d>>2]=s|0,n[d+4>>2]=Q|l&0,se=0,d=0,De=se,d|0):(se=0,d=0,De=se,d|0)}if(m=B-1|0,m&B|0){k=(S(B|0)|0)+33-(S(M|0)|0)|0,Me=64-k|0,q=32-k|0,Q=q>>31,Ge=k-32|0,l=Ge>>31,B=k,s=q-1>>31&M>>>(Ge>>>0)|(M<<q|O>>>(k>>>0))&l,l=l&M>>>(k>>>0),m=O<<Me&Q,k=(M<<Me|O>>>(Ge>>>0))&Q|O<<q&k-33>>31;break}return d|0&&(n[d>>2]=m&O,n[d+4>>2]=0),(B|0)==1?(Ge=Q|l&0,Me=s|0|0,De=Ge,Me|0):(Me=E7(B|0)|0,Ge=M>>>(Me>>>0)|0,Me=M<<32-Me|O>>>(Me>>>0)|0,De=Ge,Me|0)}else{if(m)return d|0&&(n[d>>2]=(M>>>0)%(B>>>0),n[d+4>>2]=0),Ge=0,Me=(M>>>0)/(B>>>0)>>>0,De=Ge,Me|0;if(!O)return d|0&&(n[d>>2]=0,n[d+4>>2]=(M>>>0)%(k>>>0)),Ge=0,Me=(M>>>0)/(k>>>0)>>>0,De=Ge,Me|0;if(m=k-1|0,!(m&k))return d|0&&(n[d>>2]=s|0,n[d+4>>2]=m&M|l&0),Ge=0,Me=M>>>((E7(k|0)|0)>>>0),De=Ge,Me|0;if(m=(S(k|0)|0)-(S(M|0)|0)|0,m>>>0<=30){l=m+1|0,k=31-m|0,B=l,s=M<<k|O>>>(l>>>0),l=M>>>(l>>>0),m=0,k=O<<k;break}return d?(n[d>>2]=s|0,n[d+4>>2]=Q|l&0,Ge=0,Me=0,De=Ge,Me|0):(Ge=0,Me=0,De=Ge,Me|0)}while(0);if(!B)M=k,Q=0,k=0;else{q=c|0|0,O=se|f&0,M=QR(q|0,O|0,-1,-1)|0,c=De,Q=k,k=0;do f=Q,Q=m>>>31|Q<<1,m=k|m<<1,f=s<<1|f>>>31|0,se=s>>>31|l<<1|0,dD(M|0,c|0,f|0,se|0)|0,Me=De,Ge=Me>>31|((Me|0)<0?-1:0)<<1,k=Ge&1,s=dD(f|0,se|0,Ge&q|0,(((Me|0)<0?-1:0)>>31|((Me|0)<0?-1:0)<<1)&O|0)|0,l=De,B=B-1|0;while((B|0)!=0);M=Q,Q=0}return B=0,d|0&&(n[d>>2]=s,n[d+4>>2]=l),Ge=(m|0)>>>31|(M|B)<<1|(B<<1|m>>>31)&0|Q,Me=(m<<1|0>>>31)&-2|k,De=Ge,Me|0}function FR(s,l,c,f){return s=s|0,l=l|0,c=c|0,f=f|0,C7(s,l,c,f,0)|0}function xp(s){s=s|0;var l=0,c=0;return c=s+15&-16|0,l=n[I>>2]|0,s=l+c|0,(c|0)>0&(s|0)<(l|0)|(s|0)<0?(ie()|0,vA(12),-1):(n[I>>2]=s,(s|0)>(Z()|0)&&(X()|0)==0?(n[I>>2]=l,vA(12),-1):l|0)}function Lw(s,l,c){s=s|0,l=l|0,c=c|0;var f=0;if((l|0)<(s|0)&(s|0)<(l+c|0)){for(f=s,l=l+c|0,s=s+c|0;(c|0)>0;)s=s-1|0,l=l-1|0,c=c-1|0,o[s>>0]=o[l>>0]|0;s=f}else Dr(s,l,c)|0;return s|0}function RR(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0,m=0;return m=E,E=E+16|0,d=m|0,C7(s,l,c,f,d)|0,E=m,De=n[d+4>>2]|0,n[d>>2]|0|0}function w7(s){return s=s|0,(s&255)<<24|(s>>8&255)<<16|(s>>16&255)<<8|s>>>24|0}function l3e(s,l,c,f,d,m){s=s|0,l=l|0,c=c|0,f=f|0,d=d|0,m=m|0,I7[s&1](l|0,c|0,f|0,d|0,m|0)}function c3e(s,l,c){s=s|0,l=l|0,c=y(c),B7[s&1](l|0,y(c))}function u3e(s,l,c){s=s|0,l=l|0,c=+c,v7[s&31](l|0,+c)}function A3e(s,l,c,f){return s=s|0,l=l|0,c=y(c),f=y(f),y(D7[s&0](l|0,y(c),y(f)))}function f3e(s,l){s=s|0,l=l|0,ef[s&127](l|0)}function p3e(s,l,c){s=s|0,l=l|0,c=c|0,tf[s&31](l|0,c|0)}function h3e(s,l){return s=s|0,l=l|0,Tg[s&31](l|0)|0}function g3e(s,l,c,f,d){s=s|0,l=l|0,c=+c,f=+f,d=d|0,P7[s&1](l|0,+c,+f,d|0)}function d3e(s,l,c,f){s=s|0,l=l|0,c=+c,f=+f,J3e[s&1](l|0,+c,+f)}function m3e(s,l,c,f){return s=s|0,l=l|0,c=c|0,f=f|0,ED[s&7](l|0,c|0,f|0)|0}function y3e(s,l,c,f){return s=s|0,l=l|0,c=c|0,f=f|0,+X3e[s&1](l|0,c|0,f|0)}function E3e(s,l){return s=s|0,l=l|0,+S7[s&15](l|0)}function C3e(s,l,c){return s=s|0,l=l|0,c=+c,Z3e[s&1](l|0,+c)|0}function w3e(s,l,c){return s=s|0,l=l|0,c=c|0,NR[s&15](l|0,c|0)|0}function I3e(s,l,c,f,d,m){s=s|0,l=l|0,c=c|0,f=+f,d=+d,m=m|0,$3e[s&1](l|0,c|0,+f,+d,m|0)}function B3e(s,l,c,f,d,m,B){s=s|0,l=l|0,c=c|0,f=f|0,d=d|0,m=m|0,B=B|0,e_e[s&1](l|0,c|0,f|0,d|0,m|0,B|0)}function v3e(s,l,c){return s=s|0,l=l|0,c=c|0,+b7[s&7](l|0,c|0)}function D3e(s){return s=s|0,CD[s&7]()|0}function P3e(s,l,c,f,d,m){return s=s|0,l=l|0,c=c|0,f=f|0,d=d|0,m=m|0,x7[s&1](l|0,c|0,f|0,d|0,m|0)|0}function S3e(s,l,c,f,d){s=s|0,l=l|0,c=c|0,f=f|0,d=+d,t_e[s&1](l|0,c|0,f|0,+d)}function b3e(s,l,c,f,d,m,B){s=s|0,l=l|0,c=c|0,f=y(f),d=d|0,m=y(m),B=B|0,k7[s&1](l|0,c|0,y(f),d|0,y(m),B|0)}function x3e(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0,Uw[s&15](l|0,c|0,f|0)}function k3e(s){s=s|0,Q7[s&0]()}function Q3e(s,l,c,f){s=s|0,l=l|0,c=c|0,f=+f,F7[s&15](l|0,c|0,+f)}function F3e(s,l,c){return s=s|0,l=+l,c=+c,r_e[s&1](+l,+c)|0}function R3e(s,l,c,f,d){s=s|0,l=l|0,c=c|0,f=f|0,d=d|0,LR[s&15](l|0,c|0,f|0,d|0)}function T3e(s,l,c,f,d){s=s|0,l=l|0,c=c|0,f=f|0,d=d|0,F(0)}function N3e(s,l){s=s|0,l=y(l),F(1)}function ma(s,l){s=s|0,l=+l,F(2)}function L3e(s,l,c){return s=s|0,l=y(l),c=y(c),F(3),Ze}function Er(s){s=s|0,F(4)}function Ow(s,l){s=s|0,l=l|0,F(5)}function za(s){return s=s|0,F(6),0}function O3e(s,l,c,f){s=s|0,l=+l,c=+c,f=f|0,F(7)}function M3e(s,l,c){s=s|0,l=+l,c=+c,F(8)}function U3e(s,l,c){return s=s|0,l=l|0,c=c|0,F(9),0}function _3e(s,l,c){return s=s|0,l=l|0,c=c|0,F(10),0}function Rg(s){return s=s|0,F(11),0}function H3e(s,l){return s=s|0,l=+l,F(12),0}function Mw(s,l){return s=s|0,l=l|0,F(13),0}function j3e(s,l,c,f,d){s=s|0,l=l|0,c=+c,f=+f,d=d|0,F(14)}function q3e(s,l,c,f,d,m){s=s|0,l=l|0,c=c|0,f=f|0,d=d|0,m=m|0,F(15)}function TR(s,l){return s=s|0,l=l|0,F(16),0}function G3e(){return F(17),0}function Y3e(s,l,c,f,d){return s=s|0,l=l|0,c=c|0,f=f|0,d=d|0,F(18),0}function W3e(s,l,c,f){s=s|0,l=l|0,c=c|0,f=+f,F(19)}function K3e(s,l,c,f,d,m){s=s|0,l=l|0,c=y(c),f=f|0,d=y(d),m=m|0,F(20)}function yD(s,l,c){s=s|0,l=l|0,c=c|0,F(21)}function V3e(){F(22)}function Jm(s,l,c){s=s|0,l=l|0,c=+c,F(23)}function z3e(s,l){return s=+s,l=+l,F(24),0}function Xm(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0,F(25)}var I7=[T3e,YLe],B7=[N3e,fo],v7=[ma,Sw,bw,wF,IF,Dl,xw,BF,_m,bu,Qw,vF,$v,WA,eD,Hm,tD,rD,jm,ma,ma,ma,ma,ma,ma,ma,ma,ma,ma,ma,ma,ma],D7=[L3e],ef=[Er,Vm,DDe,PDe,SDe,rxe,nxe,ixe,CNe,wNe,INe,FLe,RLe,TLe,eUe,tUe,rUe,hs,Vv,Um,YA,kw,wve,Ive,gDe,NDe,KDe,APe,SPe,GPe,aSe,ISe,OSe,$Se,gbe,Qbe,Kbe,wxe,Oxe,$xe,gke,Qke,Kke,fQe,SQe,HQe,nFe,Sc,TFe,JFe,gRe,RRe,VRe,gTe,DTe,bTe,YTe,VTe,ANe,vNe,SNe,GNe,lLe,l5,qOe,CMe,NMe,JMe,y4e,R4e,G4e,K4e,Er,Er,Er,Er,Er,Er,Er,Er,Er,Er,Er,Er,Er,Er,Er,Er,Er,Er,Er,Er,Er,Er,Er,Er,Er,Er,Er,Er,Er,Er,Er,Er,Er,Er,Er,Er,Er,Er,Er,Er,Er,Er,Er,Er,Er,Er,Er,Er,Er,Er,Er,Er,Er,Er,Er,Er],tf=[Ow,hF,gF,Pw,Su,dF,mF,wp,yF,EF,CF,Zv,KA,Ve,At,Wt,vr,Sn,Fr,PF,lve,Qve,dQe,kQe,ORe,WOe,dLe,W9,Ow,Ow,Ow,Ow],Tg=[za,QUe,pF,D,fe,ve,vt,wt,xt,_r,di,po,sve,ove,Bve,oFe,ZRe,KNe,JOe,Wa,za,za,za,za,za,za,za,za,za,za,za,za],P7=[O3e,vve],J3e=[M3e,hNe],ED=[U3e,o7,FUe,NUe,VPe,Dxe,MFe,e4e],X3e=[_3e,Ebe],S7=[Rg,Yo,rt,bn,Dve,Pve,Sve,bve,xve,kve,Rg,Rg,Rg,Rg,Rg,Rg],Z3e=[H3e,ITe],NR=[Mw,r3e,ave,EDe,gPe,uSe,DSe,Xbe,Hxe,YQe,Wv,UMe,Mw,Mw,Mw,Mw],$3e=[j3e,XDe],e_e=[q3e,I4e],b7=[TR,ai,Fve,Rve,Tve,Nbe,TR,TR],CD=[G3e,Nve,vw,ga,FTe,ZTe,QNe,X4e],x7=[Y3e,yw],t_e=[W3e,Eke],k7=[K3e,cve],Uw=[yD,T,is,en,ho,QPe,_Se,Nke,Xke,Mm,hOe,vMe,O4e,yD,yD,yD],Q7=[V3e],F7=[Jm,zv,Jv,Xv,GA,nD,DF,P,nke,eRe,yTe,Jm,Jm,Jm,Jm,Jm],r_e=[z3e,yNe],LR=[Xm,nbe,hFe,ERe,aTe,MTe,iNe,MNe,pLe,rMe,lUe,Xm,Xm,Xm,Xm,Xm];return{_llvm_bswap_i32:w7,dynCall_idd:F3e,dynCall_i:D3e,_i64Subtract:dD,___udivdi3:FR,dynCall_vif:c3e,setThrew:hu,dynCall_viii:x3e,_bitshift64Lshr:mD,_bitshift64Shl:y7,dynCall_vi:f3e,dynCall_viiddi:I3e,dynCall_diii:y3e,dynCall_iii:w3e,_memset:zm,_sbrk:xp,_memcpy:Dr,__GLOBAL__sub_I_Yoga_cpp:Om,dynCall_vii:p3e,___uremdi3:RR,dynCall_vid:u3e,stackAlloc:lo,_nbind_init:EUe,getTempRet0:Ua,dynCall_di:E3e,dynCall_iid:C3e,setTempRet0:bA,_i64Add:QR,dynCall_fiff:A3e,dynCall_iiii:m3e,_emscripten_get_global_libc:kUe,dynCall_viid:Q3e,dynCall_viiid:S3e,dynCall_viififi:b3e,dynCall_ii:h3e,__GLOBAL__sub_I_Binding_cc:NOe,dynCall_viiii:R3e,dynCall_iiiiii:P3e,stackSave:gc,dynCall_viiiii:l3e,__GLOBAL__sub_I_nbind_cc:Lve,dynCall_vidd:d3e,_free:hD,runPostSets:a3e,dynCall_viiiiii:B3e,establishStackSpace:ji,_memmove:Lw,stackRestore:pu,_malloc:pD,__GLOBAL__sub_I_common_cc:tLe,dynCall_viddi:g3e,dynCall_dii:v3e,dynCall_v:k3e}}(Module.asmGlobalArg,Module.asmLibraryArg,buffer),_llvm_bswap_i32=Module._llvm_bswap_i32=asm._llvm_bswap_i32,getTempRet0=Module.getTempRet0=asm.getTempRet0,___udivdi3=Module.___udivdi3=asm.___udivdi3,setThrew=Module.setThrew=asm.setThrew,_bitshift64Lshr=Module._bitshift64Lshr=asm._bitshift64Lshr,_bitshift64Shl=Module._bitshift64Shl=asm._bitshift64Shl,_memset=Module._memset=asm._memset,_sbrk=Module._sbrk=asm._sbrk,_memcpy=Module._memcpy=asm._memcpy,stackAlloc=Module.stackAlloc=asm.stackAlloc,___uremdi3=Module.___uremdi3=asm.___uremdi3,_nbind_init=Module._nbind_init=asm._nbind_init,_i64Subtract=Module._i64Subtract=asm._i64Subtract,setTempRet0=Module.setTempRet0=asm.setTempRet0,_i64Add=Module._i64Add=asm._i64Add,_emscripten_get_global_libc=Module._emscripten_get_global_libc=asm._emscripten_get_global_libc,__GLOBAL__sub_I_Yoga_cpp=Module.__GLOBAL__sub_I_Yoga_cpp=asm.__GLOBAL__sub_I_Yoga_cpp,__GLOBAL__sub_I_Binding_cc=Module.__GLOBAL__sub_I_Binding_cc=asm.__GLOBAL__sub_I_Binding_cc,stackSave=Module.stackSave=asm.stackSave,__GLOBAL__sub_I_nbind_cc=Module.__GLOBAL__sub_I_nbind_cc=asm.__GLOBAL__sub_I_nbind_cc,_free=Module._free=asm._free,runPostSets=Module.runPostSets=asm.runPostSets,establishStackSpace=Module.establishStackSpace=asm.establishStackSpace,_memmove=Module._memmove=asm._memmove,stackRestore=Module.stackRestore=asm.stackRestore,_malloc=Module._malloc=asm._malloc,__GLOBAL__sub_I_common_cc=Module.__GLOBAL__sub_I_common_cc=asm.__GLOBAL__sub_I_common_cc,dynCall_viiiii=Module.dynCall_viiiii=asm.dynCall_viiiii,dynCall_vif=Module.dynCall_vif=asm.dynCall_vif,dynCall_vid=Module.dynCall_vid=asm.dynCall_vid,dynCall_fiff=Module.dynCall_fiff=asm.dynCall_fiff,dynCall_vi=Module.dynCall_vi=asm.dynCall_vi,dynCall_vii=Module.dynCall_vii=asm.dynCall_vii,dynCall_ii=Module.dynCall_ii=asm.dynCall_ii,dynCall_viddi=Module.dynCall_viddi=asm.dynCall_viddi,dynCall_vidd=Module.dynCall_vidd=asm.dynCall_vidd,dynCall_iiii=Module.dynCall_iiii=asm.dynCall_iiii,dynCall_diii=Module.dynCall_diii=asm.dynCall_diii,dynCall_di=Module.dynCall_di=asm.dynCall_di,dynCall_iid=Module.dynCall_iid=asm.dynCall_iid,dynCall_iii=Module.dynCall_iii=asm.dynCall_iii,dynCall_viiddi=Module.dynCall_viiddi=asm.dynCall_viiddi,dynCall_viiiiii=Module.dynCall_viiiiii=asm.dynCall_viiiiii,dynCall_dii=Module.dynCall_dii=asm.dynCall_dii,dynCall_i=Module.dynCall_i=asm.dynCall_i,dynCall_iiiiii=Module.dynCall_iiiiii=asm.dynCall_iiiiii,dynCall_viiid=Module.dynCall_viiid=asm.dynCall_viiid,dynCall_viififi=Module.dynCall_viififi=asm.dynCall_viififi,dynCall_viii=Module.dynCall_viii=asm.dynCall_viii,dynCall_v=Module.dynCall_v=asm.dynCall_v,dynCall_viid=Module.dynCall_viid=asm.dynCall_viid,dynCall_idd=Module.dynCall_idd=asm.dynCall_idd,dynCall_viiii=Module.dynCall_viiii=asm.dynCall_viiii;Runtime.stackAlloc=Module.stackAlloc,Runtime.stackSave=Module.stackSave,Runtime.stackRestore=Module.stackRestore,Runtime.establishStackSpace=Module.establishStackSpace,Runtime.setTempRet0=Module.setTempRet0,Runtime.getTempRet0=Module.getTempRet0,Module.asm=asm;function ExitStatus(t){this.name=\"ExitStatus\",this.message=\"Program terminated with exit(\"+t+\")\",this.status=t}ExitStatus.prototype=new Error,ExitStatus.prototype.constructor=ExitStatus;var initialStackTop,preloadStartTime=null,calledMain=!1;dependenciesFulfilled=function t(){Module.calledRun||run(),Module.calledRun||(dependenciesFulfilled=t)},Module.callMain=Module.callMain=function t(e){e=e||[],ensureInitRuntime();var r=e.length+1;function o(){for(var p=0;p<4-1;p++)a.push(0)}var a=[allocate(intArrayFromString(Module.thisProgram),\"i8\",ALLOC_NORMAL)];o();for(var n=0;n<r-1;n=n+1)a.push(allocate(intArrayFromString(e[n]),\"i8\",ALLOC_NORMAL)),o();a.push(0),a=allocate(a,\"i32\",ALLOC_NORMAL);try{var u=Module._main(r,a,0);exit(u,!0)}catch(p){if(p instanceof ExitStatus)return;if(p==\"SimulateInfiniteLoop\"){Module.noExitRuntime=!0;return}else{var A=p;p&&typeof p==\"object\"&&p.stack&&(A=[p,p.stack]),Module.printErr(\"exception thrown: \"+A),Module.quit(1,p)}}finally{calledMain=!0}};function run(t){if(t=t||Module.arguments,preloadStartTime===null&&(preloadStartTime=Date.now()),runDependencies>0||(preRun(),runDependencies>0)||Module.calledRun)return;function e(){Module.calledRun||(Module.calledRun=!0,!ABORT&&(ensureInitRuntime(),preMain(),Module.onRuntimeInitialized&&Module.onRuntimeInitialized(),Module._main&&shouldRunNow&&Module.callMain(t),postRun()))}Module.setStatus?(Module.setStatus(\"Running...\"),setTimeout(function(){setTimeout(function(){Module.setStatus(\"\")},1),e()},1)):e()}Module.run=Module.run=run;function exit(t,e){e&&Module.noExitRuntime||(Module.noExitRuntime||(ABORT=!0,EXITSTATUS=t,STACKTOP=initialStackTop,exitRuntime(),Module.onExit&&Module.onExit(t)),ENVIRONMENT_IS_NODE&&process.exit(t),Module.quit(t,new ExitStatus(t)))}Module.exit=Module.exit=exit;var abortDecorators=[];function abort(t){Module.onAbort&&Module.onAbort(t),t!==void 0?(Module.print(t),Module.printErr(t),t=JSON.stringify(t)):t=\"\",ABORT=!0,EXITSTATUS=1;var e=`\nIf this abort() is unexpected, build with -s ASSERTIONS=1 which can give more information.`,r=\"abort(\"+t+\") at \"+stackTrace()+e;throw abortDecorators&&abortDecorators.forEach(function(o){r=o(r,t)}),r}if(Module.abort=Module.abort=abort,Module.preInit)for(typeof Module.preInit==\"function\"&&(Module.preInit=[Module.preInit]);Module.preInit.length>0;)Module.preInit.pop()();var shouldRunNow=!0;Module.noInitialRun&&(shouldRunNow=!1),run()})});var sm=_((wKt,MEe)=>{\"use strict\";var Kyt=LEe(),Vyt=OEe(),Q6=!1,F6=null;Vyt({},function(t,e){if(!Q6){if(Q6=!0,t)throw t;F6=e}});if(!Q6)throw new Error(\"Failed to load the yoga module - it needed to be loaded synchronously, but didn't\");MEe.exports=Kyt(F6.bind,F6.lib)});var T6=_((IKt,R6)=>{\"use strict\";var UEe=t=>Number.isNaN(t)?!1:t>=4352&&(t<=4447||t===9001||t===9002||11904<=t&&t<=12871&&t!==12351||12880<=t&&t<=19903||19968<=t&&t<=42182||43360<=t&&t<=43388||44032<=t&&t<=55203||63744<=t&&t<=64255||65040<=t&&t<=65049||65072<=t&&t<=65131||65281<=t&&t<=65376||65504<=t&&t<=65510||110592<=t&&t<=110593||127488<=t&&t<=127569||131072<=t&&t<=262141);R6.exports=UEe;R6.exports.default=UEe});var HEe=_((BKt,_Ee)=>{\"use strict\";_Ee.exports=function(){return/\\uD83C\\uDFF4\\uDB40\\uDC67\\uDB40\\uDC62(?:\\uDB40\\uDC65\\uDB40\\uDC6E\\uDB40\\uDC67|\\uDB40\\uDC73\\uDB40\\uDC63\\uDB40\\uDC74|\\uDB40\\uDC77\\uDB40\\uDC6C\\uDB40\\uDC73)\\uDB40\\uDC7F|\\uD83D\\uDC68(?:\\uD83C\\uDFFC\\u200D(?:\\uD83E\\uDD1D\\u200D\\uD83D\\uDC68\\uD83C\\uDFFB|\\uD83C[\\uDF3E\\uDF73\\uDF93\\uDFA4\\uDFA8\\uDFEB\\uDFED]|\\uD83D[\\uDCBB\\uDCBC\\uDD27\\uDD2C\\uDE80\\uDE92]|\\uD83E[\\uDDAF-\\uDDB3\\uDDBC\\uDDBD])|\\uD83C\\uDFFF\\u200D(?:\\uD83E\\uDD1D\\u200D\\uD83D\\uDC68(?:\\uD83C[\\uDFFB-\\uDFFE])|\\uD83C[\\uDF3E\\uDF73\\uDF93\\uDFA4\\uDFA8\\uDFEB\\uDFED]|\\uD83D[\\uDCBB\\uDCBC\\uDD27\\uDD2C\\uDE80\\uDE92]|\\uD83E[\\uDDAF-\\uDDB3\\uDDBC\\uDDBD])|\\uD83C\\uDFFE\\u200D(?:\\uD83E\\uDD1D\\u200D\\uD83D\\uDC68(?:\\uD83C[\\uDFFB-\\uDFFD])|\\uD83C[\\uDF3E\\uDF73\\uDF93\\uDFA4\\uDFA8\\uDFEB\\uDFED]|\\uD83D[\\uDCBB\\uDCBC\\uDD27\\uDD2C\\uDE80\\uDE92]|\\uD83E[\\uDDAF-\\uDDB3\\uDDBC\\uDDBD])|\\uD83C\\uDFFD\\u200D(?:\\uD83E\\uDD1D\\u200D\\uD83D\\uDC68(?:\\uD83C[\\uDFFB\\uDFFC])|\\uD83C[\\uDF3E\\uDF73\\uDF93\\uDFA4\\uDFA8\\uDFEB\\uDFED]|\\uD83D[\\uDCBB\\uDCBC\\uDD27\\uDD2C\\uDE80\\uDE92]|\\uD83E[\\uDDAF-\\uDDB3\\uDDBC\\uDDBD])|\\u200D(?:\\u2764\\uFE0F\\u200D(?:\\uD83D\\uDC8B\\u200D)?\\uD83D\\uDC68|(?:\\uD83D[\\uDC68\\uDC69])\\u200D(?:\\uD83D\\uDC66\\u200D\\uD83D\\uDC66|\\uD83D\\uDC67\\u200D(?:\\uD83D[\\uDC66\\uDC67]))|\\uD83D\\uDC66\\u200D\\uD83D\\uDC66|\\uD83D\\uDC67\\u200D(?:\\uD83D[\\uDC66\\uDC67])|(?:\\uD83D[\\uDC68\\uDC69])\\u200D(?:\\uD83D[\\uDC66\\uDC67])|[\\u2695\\u2696\\u2708]\\uFE0F|\\uD83D[\\uDC66\\uDC67]|\\uD83C[\\uDF3E\\uDF73\\uDF93\\uDFA4\\uDFA8\\uDFEB\\uDFED]|\\uD83D[\\uDCBB\\uDCBC\\uDD27\\uDD2C\\uDE80\\uDE92]|\\uD83E[\\uDDAF-\\uDDB3\\uDDBC\\uDDBD])|(?:\\uD83C\\uDFFB\\u200D[\\u2695\\u2696\\u2708]|\\uD83C\\uDFFF\\u200D[\\u2695\\u2696\\u2708]|\\uD83C\\uDFFE\\u200D[\\u2695\\u2696\\u2708]|\\uD83C\\uDFFD\\u200D[\\u2695\\u2696\\u2708]|\\uD83C\\uDFFC\\u200D[\\u2695\\u2696\\u2708])\\uFE0F|\\uD83C\\uDFFB\\u200D(?:\\uD83C[\\uDF3E\\uDF73\\uDF93\\uDFA4\\uDFA8\\uDFEB\\uDFED]|\\uD83D[\\uDCBB\\uDCBC\\uDD27\\uDD2C\\uDE80\\uDE92]|\\uD83E[\\uDDAF-\\uDDB3\\uDDBC\\uDDBD])|\\uD83C[\\uDFFB-\\uDFFF])|(?:\\uD83E\\uDDD1\\uD83C\\uDFFB\\u200D\\uD83E\\uDD1D\\u200D\\uD83E\\uDDD1|\\uD83D\\uDC69\\uD83C\\uDFFC\\u200D\\uD83E\\uDD1D\\u200D\\uD83D\\uDC69)\\uD83C\\uDFFB|\\uD83E\\uDDD1(?:\\uD83C\\uDFFF\\u200D\\uD83E\\uDD1D\\u200D\\uD83E\\uDDD1(?:\\uD83C[\\uDFFB-\\uDFFF])|\\u200D\\uD83E\\uDD1D\\u200D\\uD83E\\uDDD1)|(?:\\uD83E\\uDDD1\\uD83C\\uDFFE\\u200D\\uD83E\\uDD1D\\u200D\\uD83E\\uDDD1|\\uD83D\\uDC69\\uD83C\\uDFFF\\u200D\\uD83E\\uDD1D\\u200D(?:\\uD83D[\\uDC68\\uDC69]))(?:\\uD83C[\\uDFFB-\\uDFFE])|(?:\\uD83E\\uDDD1\\uD83C\\uDFFC\\u200D\\uD83E\\uDD1D\\u200D\\uD83E\\uDDD1|\\uD83D\\uDC69\\uD83C\\uDFFD\\u200D\\uD83E\\uDD1D\\u200D\\uD83D\\uDC69)(?:\\uD83C[\\uDFFB\\uDFFC])|\\uD83D\\uDC69(?:\\uD83C\\uDFFE\\u200D(?:\\uD83E\\uDD1D\\u200D\\uD83D\\uDC68(?:\\uD83C[\\uDFFB-\\uDFFD\\uDFFF])|\\uD83C[\\uDF3E\\uDF73\\uDF93\\uDFA4\\uDFA8\\uDFEB\\uDFED]|\\uD83D[\\uDCBB\\uDCBC\\uDD27\\uDD2C\\uDE80\\uDE92]|\\uD83E[\\uDDAF-\\uDDB3\\uDDBC\\uDDBD])|\\uD83C\\uDFFC\\u200D(?:\\uD83E\\uDD1D\\u200D\\uD83D\\uDC68(?:\\uD83C[\\uDFFB\\uDFFD-\\uDFFF])|\\uD83C[\\uDF3E\\uDF73\\uDF93\\uDFA4\\uDFA8\\uDFEB\\uDFED]|\\uD83D[\\uDCBB\\uDCBC\\uDD27\\uDD2C\\uDE80\\uDE92]|\\uD83E[\\uDDAF-\\uDDB3\\uDDBC\\uDDBD])|\\uD83C\\uDFFB\\u200D(?:\\uD83E\\uDD1D\\u200D\\uD83D\\uDC68(?:\\uD83C[\\uDFFC-\\uDFFF])|\\uD83C[\\uDF3E\\uDF73\\uDF93\\uDFA4\\uDFA8\\uDFEB\\uDFED]|\\uD83D[\\uDCBB\\uDCBC\\uDD27\\uDD2C\\uDE80\\uDE92]|\\uD83E[\\uDDAF-\\uDDB3\\uDDBC\\uDDBD])|\\uD83C\\uDFFD\\u200D(?:\\uD83E\\uDD1D\\u200D\\uD83D\\uDC68(?:\\uD83C[\\uDFFB\\uDFFC\\uDFFE\\uDFFF])|\\uD83C[\\uDF3E\\uDF73\\uDF93\\uDFA4\\uDFA8\\uDFEB\\uDFED]|\\uD83D[\\uDCBB\\uDCBC\\uDD27\\uDD2C\\uDE80\\uDE92]|\\uD83E[\\uDDAF-\\uDDB3\\uDDBC\\uDDBD])|\\u200D(?:\\u2764\\uFE0F\\u200D(?:\\uD83D\\uDC8B\\u200D(?:\\uD83D[\\uDC68\\uDC69])|\\uD83D[\\uDC68\\uDC69])|\\uD83C[\\uDF3E\\uDF73\\uDF93\\uDFA4\\uDFA8\\uDFEB\\uDFED]|\\uD83D[\\uDCBB\\uDCBC\\uDD27\\uDD2C\\uDE80\\uDE92]|\\uD83E[\\uDDAF-\\uDDB3\\uDDBC\\uDDBD])|\\uD83C\\uDFFF\\u200D(?:\\uD83C[\\uDF3E\\uDF73\\uDF93\\uDFA4\\uDFA8\\uDFEB\\uDFED]|\\uD83D[\\uDCBB\\uDCBC\\uDD27\\uDD2C\\uDE80\\uDE92]|\\uD83E[\\uDDAF-\\uDDB3\\uDDBC\\uDDBD]))|\\uD83D\\uDC69\\u200D\\uD83D\\uDC69\\u200D(?:\\uD83D\\uDC66\\u200D\\uD83D\\uDC66|\\uD83D\\uDC67\\u200D(?:\\uD83D[\\uDC66\\uDC67]))|(?:\\uD83E\\uDDD1\\uD83C\\uDFFD\\u200D\\uD83E\\uDD1D\\u200D\\uD83E\\uDDD1|\\uD83D\\uDC69\\uD83C\\uDFFE\\u200D\\uD83E\\uDD1D\\u200D\\uD83D\\uDC69)(?:\\uD83C[\\uDFFB-\\uDFFD])|\\uD83D\\uDC69\\u200D\\uD83D\\uDC66\\u200D\\uD83D\\uDC66|\\uD83D\\uDC69\\u200D\\uD83D\\uDC69\\u200D(?:\\uD83D[\\uDC66\\uDC67])|(?:\\uD83D\\uDC41\\uFE0F\\u200D\\uD83D\\uDDE8|\\uD83D\\uDC69(?:\\uD83C\\uDFFF\\u200D[\\u2695\\u2696\\u2708]|\\uD83C\\uDFFE\\u200D[\\u2695\\u2696\\u2708]|\\uD83C\\uDFFC\\u200D[\\u2695\\u2696\\u2708]|\\uD83C\\uDFFB\\u200D[\\u2695\\u2696\\u2708]|\\uD83C\\uDFFD\\u200D[\\u2695\\u2696\\u2708]|\\u200D[\\u2695\\u2696\\u2708])|(?:(?:\\u26F9|\\uD83C[\\uDFCB\\uDFCC]|\\uD83D\\uDD75)\\uFE0F|\\uD83D\\uDC6F|\\uD83E[\\uDD3C\\uDDDE\\uDDDF])\\u200D[\\u2640\\u2642]|(?:\\u26F9|\\uD83C[\\uDFCB\\uDFCC]|\\uD83D\\uDD75)(?:\\uD83C[\\uDFFB-\\uDFFF])\\u200D[\\u2640\\u2642]|(?:\\uD83C[\\uDFC3\\uDFC4\\uDFCA]|\\uD83D[\\uDC6E\\uDC71\\uDC73\\uDC77\\uDC81\\uDC82\\uDC86\\uDC87\\uDE45-\\uDE47\\uDE4B\\uDE4D\\uDE4E\\uDEA3\\uDEB4-\\uDEB6]|\\uD83E[\\uDD26\\uDD37-\\uDD39\\uDD3D\\uDD3E\\uDDB8\\uDDB9\\uDDCD-\\uDDCF\\uDDD6-\\uDDDD])(?:(?:\\uD83C[\\uDFFB-\\uDFFF])\\u200D[\\u2640\\u2642]|\\u200D[\\u2640\\u2642])|\\uD83C\\uDFF4\\u200D\\u2620)\\uFE0F|\\uD83D\\uDC69\\u200D\\uD83D\\uDC67\\u200D(?:\\uD83D[\\uDC66\\uDC67])|\\uD83C\\uDFF3\\uFE0F\\u200D\\uD83C\\uDF08|\\uD83D\\uDC15\\u200D\\uD83E\\uDDBA|\\uD83D\\uDC69\\u200D\\uD83D\\uDC66|\\uD83D\\uDC69\\u200D\\uD83D\\uDC67|\\uD83C\\uDDFD\\uD83C\\uDDF0|\\uD83C\\uDDF4\\uD83C\\uDDF2|\\uD83C\\uDDF6\\uD83C\\uDDE6|[#\\*0-9]\\uFE0F\\u20E3|\\uD83C\\uDDE7(?:\\uD83C[\\uDDE6\\uDDE7\\uDDE9-\\uDDEF\\uDDF1-\\uDDF4\\uDDF6-\\uDDF9\\uDDFB\\uDDFC\\uDDFE\\uDDFF])|\\uD83C\\uDDF9(?:\\uD83C[\\uDDE6\\uDDE8\\uDDE9\\uDDEB-\\uDDED\\uDDEF-\\uDDF4\\uDDF7\\uDDF9\\uDDFB\\uDDFC\\uDDFF])|\\uD83C\\uDDEA(?:\\uD83C[\\uDDE6\\uDDE8\\uDDEA\\uDDEC\\uDDED\\uDDF7-\\uDDFA])|\\uD83E\\uDDD1(?:\\uD83C[\\uDFFB-\\uDFFF])|\\uD83C\\uDDF7(?:\\uD83C[\\uDDEA\\uDDF4\\uDDF8\\uDDFA\\uDDFC])|\\uD83D\\uDC69(?:\\uD83C[\\uDFFB-\\uDFFF])|\\uD83C\\uDDF2(?:\\uD83C[\\uDDE6\\uDDE8-\\uDDED\\uDDF0-\\uDDFF])|\\uD83C\\uDDE6(?:\\uD83C[\\uDDE8-\\uDDEC\\uDDEE\\uDDF1\\uDDF2\\uDDF4\\uDDF6-\\uDDFA\\uDDFC\\uDDFD\\uDDFF])|\\uD83C\\uDDF0(?:\\uD83C[\\uDDEA\\uDDEC-\\uDDEE\\uDDF2\\uDDF3\\uDDF5\\uDDF7\\uDDFC\\uDDFE\\uDDFF])|\\uD83C\\uDDED(?:\\uD83C[\\uDDF0\\uDDF2\\uDDF3\\uDDF7\\uDDF9\\uDDFA])|\\uD83C\\uDDE9(?:\\uD83C[\\uDDEA\\uDDEC\\uDDEF\\uDDF0\\uDDF2\\uDDF4\\uDDFF])|\\uD83C\\uDDFE(?:\\uD83C[\\uDDEA\\uDDF9])|\\uD83C\\uDDEC(?:\\uD83C[\\uDDE6\\uDDE7\\uDDE9-\\uDDEE\\uDDF1-\\uDDF3\\uDDF5-\\uDDFA\\uDDFC\\uDDFE])|\\uD83C\\uDDF8(?:\\uD83C[\\uDDE6-\\uDDEA\\uDDEC-\\uDDF4\\uDDF7-\\uDDF9\\uDDFB\\uDDFD-\\uDDFF])|\\uD83C\\uDDEB(?:\\uD83C[\\uDDEE-\\uDDF0\\uDDF2\\uDDF4\\uDDF7])|\\uD83C\\uDDF5(?:\\uD83C[\\uDDE6\\uDDEA-\\uDDED\\uDDF0-\\uDDF3\\uDDF7-\\uDDF9\\uDDFC\\uDDFE])|\\uD83C\\uDDFB(?:\\uD83C[\\uDDE6\\uDDE8\\uDDEA\\uDDEC\\uDDEE\\uDDF3\\uDDFA])|\\uD83C\\uDDF3(?:\\uD83C[\\uDDE6\\uDDE8\\uDDEA-\\uDDEC\\uDDEE\\uDDF1\\uDDF4\\uDDF5\\uDDF7\\uDDFA\\uDDFF])|\\uD83C\\uDDE8(?:\\uD83C[\\uDDE6\\uDDE8\\uDDE9\\uDDEB-\\uDDEE\\uDDF0-\\uDDF5\\uDDF7\\uDDFA-\\uDDFF])|\\uD83C\\uDDF1(?:\\uD83C[\\uDDE6-\\uDDE8\\uDDEE\\uDDF0\\uDDF7-\\uDDFB\\uDDFE])|\\uD83C\\uDDFF(?:\\uD83C[\\uDDE6\\uDDF2\\uDDFC])|\\uD83C\\uDDFC(?:\\uD83C[\\uDDEB\\uDDF8])|\\uD83C\\uDDFA(?:\\uD83C[\\uDDE6\\uDDEC\\uDDF2\\uDDF3\\uDDF8\\uDDFE\\uDDFF])|\\uD83C\\uDDEE(?:\\uD83C[\\uDDE8-\\uDDEA\\uDDF1-\\uDDF4\\uDDF6-\\uDDF9])|\\uD83C\\uDDEF(?:\\uD83C[\\uDDEA\\uDDF2\\uDDF4\\uDDF5])|(?:\\uD83C[\\uDFC3\\uDFC4\\uDFCA]|\\uD83D[\\uDC6E\\uDC71\\uDC73\\uDC77\\uDC81\\uDC82\\uDC86\\uDC87\\uDE45-\\uDE47\\uDE4B\\uDE4D\\uDE4E\\uDEA3\\uDEB4-\\uDEB6]|\\uD83E[\\uDD26\\uDD37-\\uDD39\\uDD3D\\uDD3E\\uDDB8\\uDDB9\\uDDCD-\\uDDCF\\uDDD6-\\uDDDD])(?:\\uD83C[\\uDFFB-\\uDFFF])|(?:\\u26F9|\\uD83C[\\uDFCB\\uDFCC]|\\uD83D\\uDD75)(?:\\uD83C[\\uDFFB-\\uDFFF])|(?:[\\u261D\\u270A-\\u270D]|\\uD83C[\\uDF85\\uDFC2\\uDFC7]|\\uD83D[\\uDC42\\uDC43\\uDC46-\\uDC50\\uDC66\\uDC67\\uDC6B-\\uDC6D\\uDC70\\uDC72\\uDC74-\\uDC76\\uDC78\\uDC7C\\uDC83\\uDC85\\uDCAA\\uDD74\\uDD7A\\uDD90\\uDD95\\uDD96\\uDE4C\\uDE4F\\uDEC0\\uDECC]|\\uD83E[\\uDD0F\\uDD18-\\uDD1C\\uDD1E\\uDD1F\\uDD30-\\uDD36\\uDDB5\\uDDB6\\uDDBB\\uDDD2-\\uDDD5])(?:\\uD83C[\\uDFFB-\\uDFFF])|(?:[\\u231A\\u231B\\u23E9-\\u23EC\\u23F0\\u23F3\\u25FD\\u25FE\\u2614\\u2615\\u2648-\\u2653\\u267F\\u2693\\u26A1\\u26AA\\u26AB\\u26BD\\u26BE\\u26C4\\u26C5\\u26CE\\u26D4\\u26EA\\u26F2\\u26F3\\u26F5\\u26FA\\u26FD\\u2705\\u270A\\u270B\\u2728\\u274C\\u274E\\u2753-\\u2755\\u2757\\u2795-\\u2797\\u27B0\\u27BF\\u2B1B\\u2B1C\\u2B50\\u2B55]|\\uD83C[\\uDC04\\uDCCF\\uDD8E\\uDD91-\\uDD9A\\uDDE6-\\uDDFF\\uDE01\\uDE1A\\uDE2F\\uDE32-\\uDE36\\uDE38-\\uDE3A\\uDE50\\uDE51\\uDF00-\\uDF20\\uDF2D-\\uDF35\\uDF37-\\uDF7C\\uDF7E-\\uDF93\\uDFA0-\\uDFCA\\uDFCF-\\uDFD3\\uDFE0-\\uDFF0\\uDFF4\\uDFF8-\\uDFFF]|\\uD83D[\\uDC00-\\uDC3E\\uDC40\\uDC42-\\uDCFC\\uDCFF-\\uDD3D\\uDD4B-\\uDD4E\\uDD50-\\uDD67\\uDD7A\\uDD95\\uDD96\\uDDA4\\uDDFB-\\uDE4F\\uDE80-\\uDEC5\\uDECC\\uDED0-\\uDED2\\uDED5\\uDEEB\\uDEEC\\uDEF4-\\uDEFA\\uDFE0-\\uDFEB]|\\uD83E[\\uDD0D-\\uDD3A\\uDD3C-\\uDD45\\uDD47-\\uDD71\\uDD73-\\uDD76\\uDD7A-\\uDDA2\\uDDA5-\\uDDAA\\uDDAE-\\uDDCA\\uDDCD-\\uDDFF\\uDE70-\\uDE73\\uDE78-\\uDE7A\\uDE80-\\uDE82\\uDE90-\\uDE95])|(?:[#\\*0-9\\xA9\\xAE\\u203C\\u2049\\u2122\\u2139\\u2194-\\u2199\\u21A9\\u21AA\\u231A\\u231B\\u2328\\u23CF\\u23E9-\\u23F3\\u23F8-\\u23FA\\u24C2\\u25AA\\u25AB\\u25B6\\u25C0\\u25FB-\\u25FE\\u2600-\\u2604\\u260E\\u2611\\u2614\\u2615\\u2618\\u261D\\u2620\\u2622\\u2623\\u2626\\u262A\\u262E\\u262F\\u2638-\\u263A\\u2640\\u2642\\u2648-\\u2653\\u265F\\u2660\\u2663\\u2665\\u2666\\u2668\\u267B\\u267E\\u267F\\u2692-\\u2697\\u2699\\u269B\\u269C\\u26A0\\u26A1\\u26AA\\u26AB\\u26B0\\u26B1\\u26BD\\u26BE\\u26C4\\u26C5\\u26C8\\u26CE\\u26CF\\u26D1\\u26D3\\u26D4\\u26E9\\u26EA\\u26F0-\\u26F5\\u26F7-\\u26FA\\u26FD\\u2702\\u2705\\u2708-\\u270D\\u270F\\u2712\\u2714\\u2716\\u271D\\u2721\\u2728\\u2733\\u2734\\u2744\\u2747\\u274C\\u274E\\u2753-\\u2755\\u2757\\u2763\\u2764\\u2795-\\u2797\\u27A1\\u27B0\\u27BF\\u2934\\u2935\\u2B05-\\u2B07\\u2B1B\\u2B1C\\u2B50\\u2B55\\u3030\\u303D\\u3297\\u3299]|\\uD83C[\\uDC04\\uDCCF\\uDD70\\uDD71\\uDD7E\\uDD7F\\uDD8E\\uDD91-\\uDD9A\\uDDE6-\\uDDFF\\uDE01\\uDE02\\uDE1A\\uDE2F\\uDE32-\\uDE3A\\uDE50\\uDE51\\uDF00-\\uDF21\\uDF24-\\uDF93\\uDF96\\uDF97\\uDF99-\\uDF9B\\uDF9E-\\uDFF0\\uDFF3-\\uDFF5\\uDFF7-\\uDFFF]|\\uD83D[\\uDC00-\\uDCFD\\uDCFF-\\uDD3D\\uDD49-\\uDD4E\\uDD50-\\uDD67\\uDD6F\\uDD70\\uDD73-\\uDD7A\\uDD87\\uDD8A-\\uDD8D\\uDD90\\uDD95\\uDD96\\uDDA4\\uDDA5\\uDDA8\\uDDB1\\uDDB2\\uDDBC\\uDDC2-\\uDDC4\\uDDD1-\\uDDD3\\uDDDC-\\uDDDE\\uDDE1\\uDDE3\\uDDE8\\uDDEF\\uDDF3\\uDDFA-\\uDE4F\\uDE80-\\uDEC5\\uDECB-\\uDED2\\uDED5\\uDEE0-\\uDEE5\\uDEE9\\uDEEB\\uDEEC\\uDEF0\\uDEF3-\\uDEFA\\uDFE0-\\uDFEB]|\\uD83E[\\uDD0D-\\uDD3A\\uDD3C-\\uDD45\\uDD47-\\uDD71\\uDD73-\\uDD76\\uDD7A-\\uDDA2\\uDDA5-\\uDDAA\\uDDAE-\\uDDCA\\uDDCD-\\uDDFF\\uDE70-\\uDE73\\uDE78-\\uDE7A\\uDE80-\\uDE82\\uDE90-\\uDE95])\\uFE0F|(?:[\\u261D\\u26F9\\u270A-\\u270D]|\\uD83C[\\uDF85\\uDFC2-\\uDFC4\\uDFC7\\uDFCA-\\uDFCC]|\\uD83D[\\uDC42\\uDC43\\uDC46-\\uDC50\\uDC66-\\uDC78\\uDC7C\\uDC81-\\uDC83\\uDC85-\\uDC87\\uDC8F\\uDC91\\uDCAA\\uDD74\\uDD75\\uDD7A\\uDD90\\uDD95\\uDD96\\uDE45-\\uDE47\\uDE4B-\\uDE4F\\uDEA3\\uDEB4-\\uDEB6\\uDEC0\\uDECC]|\\uD83E[\\uDD0F\\uDD18-\\uDD1F\\uDD26\\uDD30-\\uDD39\\uDD3C-\\uDD3E\\uDDB5\\uDDB6\\uDDB8\\uDDB9\\uDDBB\\uDDCD-\\uDDCF\\uDDD1-\\uDDDD])/g}});var zk=_((vKt,N6)=>{\"use strict\";var zyt=OP(),Jyt=T6(),Xyt=HEe(),jEe=t=>{if(typeof t!=\"string\"||t.length===0||(t=zyt(t),t.length===0))return 0;t=t.replace(Xyt(),\"  \");let e=0;for(let r=0;r<t.length;r++){let o=t.codePointAt(r);o<=31||o>=127&&o<=159||o>=768&&o<=879||(o>65535&&r++,e+=Jyt(o)?2:1)}return e};N6.exports=jEe;N6.exports.default=jEe});var O6=_((DKt,L6)=>{\"use strict\";var Zyt=zk(),qEe=t=>{let e=0;for(let r of t.split(`\n`))e=Math.max(e,Zyt(r));return e};L6.exports=qEe;L6.exports.default=qEe});var GEe=_(lB=>{\"use strict\";var $yt=lB&&lB.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};Object.defineProperty(lB,\"__esModule\",{value:!0});var eEt=$yt(O6()),M6={};lB.default=t=>{if(t.length===0)return{width:0,height:0};if(M6[t])return M6[t];let e=eEt.default(t),r=t.split(`\n`).length;return M6[t]={width:e,height:r},{width:e,height:r}}});var YEe=_(cB=>{\"use strict\";var tEt=cB&&cB.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};Object.defineProperty(cB,\"__esModule\",{value:!0});var dn=tEt(sm()),rEt=(t,e)=>{\"position\"in e&&t.setPositionType(e.position===\"absolute\"?dn.default.POSITION_TYPE_ABSOLUTE:dn.default.POSITION_TYPE_RELATIVE)},nEt=(t,e)=>{\"marginLeft\"in e&&t.setMargin(dn.default.EDGE_START,e.marginLeft||0),\"marginRight\"in e&&t.setMargin(dn.default.EDGE_END,e.marginRight||0),\"marginTop\"in e&&t.setMargin(dn.default.EDGE_TOP,e.marginTop||0),\"marginBottom\"in e&&t.setMargin(dn.default.EDGE_BOTTOM,e.marginBottom||0)},iEt=(t,e)=>{\"paddingLeft\"in e&&t.setPadding(dn.default.EDGE_LEFT,e.paddingLeft||0),\"paddingRight\"in e&&t.setPadding(dn.default.EDGE_RIGHT,e.paddingRight||0),\"paddingTop\"in e&&t.setPadding(dn.default.EDGE_TOP,e.paddingTop||0),\"paddingBottom\"in e&&t.setPadding(dn.default.EDGE_BOTTOM,e.paddingBottom||0)},sEt=(t,e)=>{var r;\"flexGrow\"in e&&t.setFlexGrow((r=e.flexGrow)!==null&&r!==void 0?r:0),\"flexShrink\"in e&&t.setFlexShrink(typeof e.flexShrink==\"number\"?e.flexShrink:1),\"flexDirection\"in e&&(e.flexDirection===\"row\"&&t.setFlexDirection(dn.default.FLEX_DIRECTION_ROW),e.flexDirection===\"row-reverse\"&&t.setFlexDirection(dn.default.FLEX_DIRECTION_ROW_REVERSE),e.flexDirection===\"column\"&&t.setFlexDirection(dn.default.FLEX_DIRECTION_COLUMN),e.flexDirection===\"column-reverse\"&&t.setFlexDirection(dn.default.FLEX_DIRECTION_COLUMN_REVERSE)),\"flexBasis\"in e&&(typeof e.flexBasis==\"number\"?t.setFlexBasis(e.flexBasis):typeof e.flexBasis==\"string\"?t.setFlexBasisPercent(Number.parseInt(e.flexBasis,10)):t.setFlexBasis(NaN)),\"alignItems\"in e&&((e.alignItems===\"stretch\"||!e.alignItems)&&t.setAlignItems(dn.default.ALIGN_STRETCH),e.alignItems===\"flex-start\"&&t.setAlignItems(dn.default.ALIGN_FLEX_START),e.alignItems===\"center\"&&t.setAlignItems(dn.default.ALIGN_CENTER),e.alignItems===\"flex-end\"&&t.setAlignItems(dn.default.ALIGN_FLEX_END)),\"alignSelf\"in e&&((e.alignSelf===\"auto\"||!e.alignSelf)&&t.setAlignSelf(dn.default.ALIGN_AUTO),e.alignSelf===\"flex-start\"&&t.setAlignSelf(dn.default.ALIGN_FLEX_START),e.alignSelf===\"center\"&&t.setAlignSelf(dn.default.ALIGN_CENTER),e.alignSelf===\"flex-end\"&&t.setAlignSelf(dn.default.ALIGN_FLEX_END)),\"justifyContent\"in e&&((e.justifyContent===\"flex-start\"||!e.justifyContent)&&t.setJustifyContent(dn.default.JUSTIFY_FLEX_START),e.justifyContent===\"center\"&&t.setJustifyContent(dn.default.JUSTIFY_CENTER),e.justifyContent===\"flex-end\"&&t.setJustifyContent(dn.default.JUSTIFY_FLEX_END),e.justifyContent===\"space-between\"&&t.setJustifyContent(dn.default.JUSTIFY_SPACE_BETWEEN),e.justifyContent===\"space-around\"&&t.setJustifyContent(dn.default.JUSTIFY_SPACE_AROUND))},oEt=(t,e)=>{var r,o;\"width\"in e&&(typeof e.width==\"number\"?t.setWidth(e.width):typeof e.width==\"string\"?t.setWidthPercent(Number.parseInt(e.width,10)):t.setWidthAuto()),\"height\"in e&&(typeof e.height==\"number\"?t.setHeight(e.height):typeof e.height==\"string\"?t.setHeightPercent(Number.parseInt(e.height,10)):t.setHeightAuto()),\"minWidth\"in e&&(typeof e.minWidth==\"string\"?t.setMinWidthPercent(Number.parseInt(e.minWidth,10)):t.setMinWidth((r=e.minWidth)!==null&&r!==void 0?r:0)),\"minHeight\"in e&&(typeof e.minHeight==\"string\"?t.setMinHeightPercent(Number.parseInt(e.minHeight,10)):t.setMinHeight((o=e.minHeight)!==null&&o!==void 0?o:0))},aEt=(t,e)=>{\"display\"in e&&t.setDisplay(e.display===\"flex\"?dn.default.DISPLAY_FLEX:dn.default.DISPLAY_NONE)},lEt=(t,e)=>{if(\"borderStyle\"in e){let r=typeof e.borderStyle==\"string\"?1:0;t.setBorder(dn.default.EDGE_TOP,r),t.setBorder(dn.default.EDGE_BOTTOM,r),t.setBorder(dn.default.EDGE_LEFT,r),t.setBorder(dn.default.EDGE_RIGHT,r)}};cB.default=(t,e={})=>{rEt(t,e),nEt(t,e),iEt(t,e),sEt(t,e),oEt(t,e),aEt(t,e),lEt(t,e)}});var VEe=_((bKt,KEe)=>{\"use strict\";var uB=zk(),cEt=OP(),uEt=BI(),_6=new Set([\"\\x1B\",\"\\x9B\"]),AEt=39,WEe=t=>`${_6.values().next().value}[${t}m`,fEt=t=>t.split(\" \").map(e=>uB(e)),U6=(t,e,r)=>{let o=[...e],a=!1,n=uB(cEt(t[t.length-1]));for(let[u,A]of o.entries()){let p=uB(A);if(n+p<=r?t[t.length-1]+=A:(t.push(A),n=0),_6.has(A))a=!0;else if(a&&A===\"m\"){a=!1;continue}a||(n+=p,n===r&&u<o.length-1&&(t.push(\"\"),n=0))}!n&&t[t.length-1].length>0&&t.length>1&&(t[t.length-2]+=t.pop())},pEt=t=>{let e=t.split(\" \"),r=e.length;for(;r>0&&!(uB(e[r-1])>0);)r--;return r===e.length?t:e.slice(0,r).join(\" \")+e.slice(r).join(\"\")},hEt=(t,e,r={})=>{if(r.trim!==!1&&t.trim()===\"\")return\"\";let o=\"\",a=\"\",n,u=fEt(t),A=[\"\"];for(let[p,h]of t.split(\" \").entries()){r.trim!==!1&&(A[A.length-1]=A[A.length-1].trimLeft());let C=uB(A[A.length-1]);if(p!==0&&(C>=e&&(r.wordWrap===!1||r.trim===!1)&&(A.push(\"\"),C=0),(C>0||r.trim===!1)&&(A[A.length-1]+=\" \",C++)),r.hard&&u[p]>e){let I=e-C,v=1+Math.floor((u[p]-I-1)/e);Math.floor((u[p]-1)/e)<v&&A.push(\"\"),U6(A,h,e);continue}if(C+u[p]>e&&C>0&&u[p]>0){if(r.wordWrap===!1&&C<e){U6(A,h,e);continue}A.push(\"\")}if(C+u[p]>e&&r.wordWrap===!1){U6(A,h,e);continue}A[A.length-1]+=h}r.trim!==!1&&(A=A.map(pEt)),o=A.join(`\n`);for(let[p,h]of[...o].entries()){if(a+=h,_6.has(h)){let I=parseFloat(/\\d[^m]*/.exec(o.slice(p,p+4)));n=I===AEt?null:I}let C=uEt.codes.get(Number(n));n&&C&&(o[p+1]===`\n`?a+=WEe(C):h===`\n`&&(a+=WEe(n)))}return a};KEe.exports=(t,e,r)=>String(t).normalize().replace(/\\r\\n/g,`\n`).split(`\n`).map(o=>hEt(o,e,r)).join(`\n`)});var XEe=_((xKt,JEe)=>{\"use strict\";var zEe=\"[\\uD800-\\uDBFF][\\uDC00-\\uDFFF]\",gEt=t=>t&&t.exact?new RegExp(`^${zEe}$`):new RegExp(zEe,\"g\");JEe.exports=gEt});var H6=_((kKt,tCe)=>{\"use strict\";var dEt=T6(),mEt=XEe(),ZEe=BI(),eCe=[\"\\x1B\",\"\\x9B\"],Jk=t=>`${eCe[0]}[${t}m`,$Ee=(t,e,r)=>{let o=[];t=[...t];for(let a of t){let n=a;a.match(\";\")&&(a=a.split(\";\")[0][0]+\"0\");let u=ZEe.codes.get(parseInt(a,10));if(u){let A=t.indexOf(u.toString());A>=0?t.splice(A,1):o.push(Jk(e?u:n))}else if(e){o.push(Jk(0));break}else o.push(Jk(n))}if(e&&(o=o.filter((a,n)=>o.indexOf(a)===n),r!==void 0)){let a=Jk(ZEe.codes.get(parseInt(r,10)));o=o.reduce((n,u)=>u===a?[u,...n]:[...n,u],[])}return o.join(\"\")};tCe.exports=(t,e,r)=>{let o=[...t.normalize()],a=[];r=typeof r==\"number\"?r:o.length;let n=!1,u,A=0,p=\"\";for(let[h,C]of o.entries()){let I=!1;if(eCe.includes(C)){let v=/\\d[^m]*/.exec(t.slice(h,h+18));u=v&&v.length>0?v[0]:void 0,A<r&&(n=!0,u!==void 0&&a.push(u))}else n&&C===\"m\"&&(n=!1,I=!0);if(!n&&!I&&++A,!mEt({exact:!0}).test(C)&&dEt(C.codePointAt())&&++A,A>e&&A<=r)p+=C;else if(A===e&&!n&&u!==void 0)p=$Ee(a);else if(A>=r){p+=$Ee(a,!0,u);break}}return p}});var nCe=_((QKt,rCe)=>{\"use strict\";var y0=H6(),yEt=zk();function Xk(t,e,r){if(t.charAt(e)===\" \")return e;for(let o=1;o<=3;o++)if(r){if(t.charAt(e+o)===\" \")return e+o}else if(t.charAt(e-o)===\" \")return e-o;return e}rCe.exports=(t,e,r)=>{r={position:\"end\",preferTruncationOnSpace:!1,...r};let{position:o,space:a,preferTruncationOnSpace:n}=r,u=\"\\u2026\",A=1;if(typeof t!=\"string\")throw new TypeError(`Expected \\`input\\` to be a string, got ${typeof t}`);if(typeof e!=\"number\")throw new TypeError(`Expected \\`columns\\` to be a number, got ${typeof e}`);if(e<1)return\"\";if(e===1)return u;let p=yEt(t);if(p<=e)return t;if(o===\"start\"){if(n){let h=Xk(t,p-e+1,!0);return u+y0(t,h,p).trim()}return a===!0&&(u+=\" \",A=2),u+y0(t,p-e+A,p)}if(o===\"middle\"){a===!0&&(u=\" \"+u+\" \",A=3);let h=Math.floor(e/2);if(n){let C=Xk(t,h),I=Xk(t,p-(e-h)+1,!0);return y0(t,0,C)+u+y0(t,I,p).trim()}return y0(t,0,h)+u+y0(t,p-(e-h)+A,p)}if(o===\"end\"){if(n){let h=Xk(t,e-1);return y0(t,0,h)+u}return a===!0&&(u=\" \"+u,A=2),y0(t,0,e-A)+u}throw new Error(`Expected \\`options.position\\` to be either \\`start\\`, \\`middle\\` or \\`end\\`, got ${o}`)}});var q6=_(AB=>{\"use strict\";var iCe=AB&&AB.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};Object.defineProperty(AB,\"__esModule\",{value:!0});var EEt=iCe(VEe()),CEt=iCe(nCe()),j6={};AB.default=(t,e,r)=>{let o=t+String(e)+String(r);if(j6[o])return j6[o];let a=t;if(r===\"wrap\"&&(a=EEt.default(t,e,{trim:!1,hard:!0})),r.startsWith(\"truncate\")){let n=\"end\";r===\"truncate-middle\"&&(n=\"middle\"),r===\"truncate-start\"&&(n=\"start\"),a=CEt.default(t,e,{position:n})}return j6[o]=a,a}});var Y6=_(G6=>{\"use strict\";Object.defineProperty(G6,\"__esModule\",{value:!0});var sCe=t=>{let e=\"\";if(t.childNodes.length>0)for(let r of t.childNodes){let o=\"\";r.nodeName===\"#text\"?o=r.nodeValue:((r.nodeName===\"ink-text\"||r.nodeName===\"ink-virtual-text\")&&(o=sCe(r)),o.length>0&&typeof r.internal_transform==\"function\"&&(o=r.internal_transform(o))),e+=o}return e};G6.default=sCe});var W6=_(pi=>{\"use strict\";var fB=pi&&pi.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};Object.defineProperty(pi,\"__esModule\",{value:!0});pi.setTextNodeValue=pi.createTextNode=pi.setStyle=pi.setAttribute=pi.removeChildNode=pi.insertBeforeNode=pi.appendChildNode=pi.createNode=pi.TEXT_NAME=void 0;var wEt=fB(sm()),oCe=fB(GEe()),IEt=fB(YEe()),BEt=fB(q6()),vEt=fB(Y6());pi.TEXT_NAME=\"#text\";pi.createNode=t=>{var e;let r={nodeName:t,style:{},attributes:{},childNodes:[],parentNode:null,yogaNode:t===\"ink-virtual-text\"?void 0:wEt.default.Node.create()};return t===\"ink-text\"&&((e=r.yogaNode)===null||e===void 0||e.setMeasureFunc(DEt.bind(null,r))),r};pi.appendChildNode=(t,e)=>{var r;e.parentNode&&pi.removeChildNode(e.parentNode,e),e.parentNode=t,t.childNodes.push(e),e.yogaNode&&((r=t.yogaNode)===null||r===void 0||r.insertChild(e.yogaNode,t.yogaNode.getChildCount())),(t.nodeName===\"ink-text\"||t.nodeName===\"ink-virtual-text\")&&Zk(t)};pi.insertBeforeNode=(t,e,r)=>{var o,a;e.parentNode&&pi.removeChildNode(e.parentNode,e),e.parentNode=t;let n=t.childNodes.indexOf(r);if(n>=0){t.childNodes.splice(n,0,e),e.yogaNode&&((o=t.yogaNode)===null||o===void 0||o.insertChild(e.yogaNode,n));return}t.childNodes.push(e),e.yogaNode&&((a=t.yogaNode)===null||a===void 0||a.insertChild(e.yogaNode,t.yogaNode.getChildCount())),(t.nodeName===\"ink-text\"||t.nodeName===\"ink-virtual-text\")&&Zk(t)};pi.removeChildNode=(t,e)=>{var r,o;e.yogaNode&&((o=(r=e.parentNode)===null||r===void 0?void 0:r.yogaNode)===null||o===void 0||o.removeChild(e.yogaNode)),e.parentNode=null;let a=t.childNodes.indexOf(e);a>=0&&t.childNodes.splice(a,1),(t.nodeName===\"ink-text\"||t.nodeName===\"ink-virtual-text\")&&Zk(t)};pi.setAttribute=(t,e,r)=>{t.attributes[e]=r};pi.setStyle=(t,e)=>{t.style=e,t.yogaNode&&IEt.default(t.yogaNode,e)};pi.createTextNode=t=>{let e={nodeName:\"#text\",nodeValue:t,yogaNode:void 0,parentNode:null,style:{}};return pi.setTextNodeValue(e,t),e};var DEt=function(t,e){var r,o;let a=t.nodeName===\"#text\"?t.nodeValue:vEt.default(t),n=oCe.default(a);if(n.width<=e||n.width>=1&&e>0&&e<1)return n;let u=(o=(r=t.style)===null||r===void 0?void 0:r.textWrap)!==null&&o!==void 0?o:\"wrap\",A=BEt.default(a,e,u);return oCe.default(A)},aCe=t=>{var e;if(!(!t||!t.parentNode))return(e=t.yogaNode)!==null&&e!==void 0?e:aCe(t.parentNode)},Zk=t=>{let e=aCe(t);e?.markDirty()};pi.setTextNodeValue=(t,e)=>{typeof e!=\"string\"&&(e=String(e)),t.nodeValue=e,Zk(t)}});var fCe=_(pB=>{\"use strict\";var ACe=pB&&pB.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};Object.defineProperty(pB,\"__esModule\",{value:!0});var lCe=b6(),PEt=ACe(kEe()),cCe=ACe(sm()),Oo=W6(),uCe=t=>{t?.unsetMeasureFunc(),t?.freeRecursive()};pB.default=PEt.default({schedulePassiveEffects:lCe.unstable_scheduleCallback,cancelPassiveEffects:lCe.unstable_cancelCallback,now:Date.now,getRootHostContext:()=>({isInsideText:!1}),prepareForCommit:()=>{},resetAfterCommit:t=>{if(t.isStaticDirty){t.isStaticDirty=!1,typeof t.onImmediateRender==\"function\"&&t.onImmediateRender();return}typeof t.onRender==\"function\"&&t.onRender()},getChildHostContext:(t,e)=>{let r=t.isInsideText,o=e===\"ink-text\"||e===\"ink-virtual-text\";return r===o?t:{isInsideText:o}},shouldSetTextContent:()=>!1,createInstance:(t,e,r,o)=>{if(o.isInsideText&&t===\"ink-box\")throw new Error(\"<Box> can\\u2019t be nested inside <Text> component\");let a=t===\"ink-text\"&&o.isInsideText?\"ink-virtual-text\":t,n=Oo.createNode(a);for(let[u,A]of Object.entries(e))u!==\"children\"&&(u===\"style\"?Oo.setStyle(n,A):u===\"internal_transform\"?n.internal_transform=A:u===\"internal_static\"?n.internal_static=!0:Oo.setAttribute(n,u,A));return n},createTextInstance:(t,e,r)=>{if(!r.isInsideText)throw new Error(`Text string \"${t}\" must be rendered inside <Text> component`);return Oo.createTextNode(t)},resetTextContent:()=>{},hideTextInstance:t=>{Oo.setTextNodeValue(t,\"\")},unhideTextInstance:(t,e)=>{Oo.setTextNodeValue(t,e)},getPublicInstance:t=>t,hideInstance:t=>{var e;(e=t.yogaNode)===null||e===void 0||e.setDisplay(cCe.default.DISPLAY_NONE)},unhideInstance:t=>{var e;(e=t.yogaNode)===null||e===void 0||e.setDisplay(cCe.default.DISPLAY_FLEX)},appendInitialChild:Oo.appendChildNode,appendChild:Oo.appendChildNode,insertBefore:Oo.insertBeforeNode,finalizeInitialChildren:(t,e,r,o)=>(t.internal_static&&(o.isStaticDirty=!0,o.staticNode=t),!1),supportsMutation:!0,appendChildToContainer:Oo.appendChildNode,insertInContainerBefore:Oo.insertBeforeNode,removeChildFromContainer:(t,e)=>{Oo.removeChildNode(t,e),uCe(e.yogaNode)},prepareUpdate:(t,e,r,o,a)=>{t.internal_static&&(a.isStaticDirty=!0);let n={},u=Object.keys(o);for(let A of u)if(o[A]!==r[A]){if(A===\"style\"&&typeof o.style==\"object\"&&typeof r.style==\"object\"){let h=o.style,C=r.style,I=Object.keys(h);for(let v of I){if(v===\"borderStyle\"||v===\"borderColor\"){if(typeof n.style!=\"object\"){let x={};n.style=x}n.style.borderStyle=h.borderStyle,n.style.borderColor=h.borderColor}if(h[v]!==C[v]){if(typeof n.style!=\"object\"){let x={};n.style=x}n.style[v]=h[v]}}continue}n[A]=o[A]}return n},commitUpdate:(t,e)=>{for(let[r,o]of Object.entries(e))r!==\"children\"&&(r===\"style\"?Oo.setStyle(t,o):r===\"internal_transform\"?t.internal_transform=o:r===\"internal_static\"?t.internal_static=!0:Oo.setAttribute(t,r,o))},commitTextUpdate:(t,e,r)=>{Oo.setTextNodeValue(t,r)},removeChild:(t,e)=>{Oo.removeChildNode(t,e),uCe(e.yogaNode)}})});var hCe=_((LKt,pCe)=>{\"use strict\";pCe.exports=(t,e=1,r)=>{if(r={indent:\" \",includeEmptyLines:!1,...r},typeof t!=\"string\")throw new TypeError(`Expected \\`input\\` to be a \\`string\\`, got \\`${typeof t}\\``);if(typeof e!=\"number\")throw new TypeError(`Expected \\`count\\` to be a \\`number\\`, got \\`${typeof e}\\``);if(typeof r.indent!=\"string\")throw new TypeError(`Expected \\`options.indent\\` to be a \\`string\\`, got \\`${typeof r.indent}\\``);if(e===0)return t;let o=r.includeEmptyLines?/^/gm:/^(?!\\s*$)/gm;return t.replace(o,r.indent.repeat(e))}});var gCe=_(hB=>{\"use strict\";var SEt=hB&&hB.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};Object.defineProperty(hB,\"__esModule\",{value:!0});var $k=SEt(sm());hB.default=t=>t.getComputedWidth()-t.getComputedPadding($k.default.EDGE_LEFT)-t.getComputedPadding($k.default.EDGE_RIGHT)-t.getComputedBorder($k.default.EDGE_LEFT)-t.getComputedBorder($k.default.EDGE_RIGHT)});var dCe=_((MKt,bEt)=>{bEt.exports={single:{topLeft:\"\\u250C\",topRight:\"\\u2510\",bottomRight:\"\\u2518\",bottomLeft:\"\\u2514\",vertical:\"\\u2502\",horizontal:\"\\u2500\"},double:{topLeft:\"\\u2554\",topRight:\"\\u2557\",bottomRight:\"\\u255D\",bottomLeft:\"\\u255A\",vertical:\"\\u2551\",horizontal:\"\\u2550\"},round:{topLeft:\"\\u256D\",topRight:\"\\u256E\",bottomRight:\"\\u256F\",bottomLeft:\"\\u2570\",vertical:\"\\u2502\",horizontal:\"\\u2500\"},bold:{topLeft:\"\\u250F\",topRight:\"\\u2513\",bottomRight:\"\\u251B\",bottomLeft:\"\\u2517\",vertical:\"\\u2503\",horizontal:\"\\u2501\"},singleDouble:{topLeft:\"\\u2553\",topRight:\"\\u2556\",bottomRight:\"\\u255C\",bottomLeft:\"\\u2559\",vertical:\"\\u2551\",horizontal:\"\\u2500\"},doubleSingle:{topLeft:\"\\u2552\",topRight:\"\\u2555\",bottomRight:\"\\u255B\",bottomLeft:\"\\u2558\",vertical:\"\\u2502\",horizontal:\"\\u2550\"},classic:{topLeft:\"+\",topRight:\"+\",bottomRight:\"+\",bottomLeft:\"+\",vertical:\"|\",horizontal:\"-\"}}});var yCe=_((UKt,K6)=>{\"use strict\";var mCe=dCe();K6.exports=mCe;K6.exports.default=mCe});var CCe=_((_Kt,ECe)=>{\"use strict\";var xEt=(t,e,r)=>{let o=t.indexOf(e);if(o===-1)return t;let a=e.length,n=0,u=\"\";do u+=t.substr(n,o-n)+e+r,n=o+a,o=t.indexOf(e,n);while(o!==-1);return u+=t.substr(n),u},kEt=(t,e,r,o)=>{let a=0,n=\"\";do{let u=t[o-1]===\"\\r\";n+=t.substr(a,(u?o-1:o)-a)+e+(u?`\\r\n`:`\n`)+r,a=o+1,o=t.indexOf(`\n`,a)}while(o!==-1);return n+=t.substr(a),n};ECe.exports={stringReplaceAll:xEt,stringEncaseCRLFWithFirstIndex:kEt}});var DCe=_((HKt,vCe)=>{\"use strict\";var QEt=/(?:\\\\(u(?:[a-f\\d]{4}|\\{[a-f\\d]{1,6}\\})|x[a-f\\d]{2}|.))|(?:\\{(~)?(\\w+(?:\\([^)]*\\))?(?:\\.\\w+(?:\\([^)]*\\))?)*)(?:[ \\t]|(?=\\r?\\n)))|(\\})|((?:.|[\\r\\n\\f])+?)/gi,wCe=/(?:^|\\.)(\\w+)(?:\\(([^)]*)\\))?/g,FEt=/^(['\"])((?:\\\\.|(?!\\1)[^\\\\])*)\\1$/,REt=/\\\\(u(?:[a-f\\d]{4}|{[a-f\\d]{1,6}})|x[a-f\\d]{2}|.)|([^\\\\])/gi,TEt=new Map([[\"n\",`\n`],[\"r\",\"\\r\"],[\"t\",\"\t\"],[\"b\",\"\\b\"],[\"f\",\"\\f\"],[\"v\",\"\\v\"],[\"0\",\"\\0\"],[\"\\\\\",\"\\\\\"],[\"e\",\"\\x1B\"],[\"a\",\"\\x07\"]]);function BCe(t){let e=t[0]===\"u\",r=t[1]===\"{\";return e&&!r&&t.length===5||t[0]===\"x\"&&t.length===3?String.fromCharCode(parseInt(t.slice(1),16)):e&&r?String.fromCodePoint(parseInt(t.slice(2,-1),16)):TEt.get(t)||t}function NEt(t,e){let r=[],o=e.trim().split(/\\s*,\\s*/g),a;for(let n of o){let u=Number(n);if(!Number.isNaN(u))r.push(u);else if(a=n.match(FEt))r.push(a[2].replace(REt,(A,p,h)=>p?BCe(p):h));else throw new Error(`Invalid Chalk template style argument: ${n} (in style '${t}')`)}return r}function LEt(t){wCe.lastIndex=0;let e=[],r;for(;(r=wCe.exec(t))!==null;){let o=r[1];if(r[2]){let a=NEt(o,r[2]);e.push([o].concat(a))}else e.push([o])}return e}function ICe(t,e){let r={};for(let a of e)for(let n of a.styles)r[n[0]]=a.inverse?null:n.slice(1);let o=t;for(let[a,n]of Object.entries(r))if(!!Array.isArray(n)){if(!(a in o))throw new Error(`Unknown Chalk style: ${a}`);o=n.length>0?o[a](...n):o[a]}return o}vCe.exports=(t,e)=>{let r=[],o=[],a=[];if(e.replace(QEt,(n,u,A,p,h,C)=>{if(u)a.push(BCe(u));else if(p){let I=a.join(\"\");a=[],o.push(r.length===0?I:ICe(t,r)(I)),r.push({inverse:A,styles:LEt(p)})}else if(h){if(r.length===0)throw new Error(\"Found extraneous } in Chalk template literal\");o.push(ICe(t,r)(a.join(\"\"))),a=[],r.pop()}else a.push(C)}),o.push(a.join(\"\")),r.length>0){let n=`Chalk template literal is missing ${r.length} closing bracket${r.length===1?\"\":\"s\"} (\\`}\\`)`;throw new Error(n)}return o.join(\"\")}});var iQ=_((jKt,QCe)=>{\"use strict\";var gB=BI(),{stdout:z6,stderr:J6}=yN(),{stringReplaceAll:OEt,stringEncaseCRLFWithFirstIndex:MEt}=CCe(),{isArray:eQ}=Array,SCe=[\"ansi\",\"ansi\",\"ansi256\",\"ansi16m\"],UC=Object.create(null),UEt=(t,e={})=>{if(e.level&&!(Number.isInteger(e.level)&&e.level>=0&&e.level<=3))throw new Error(\"The `level` option should be an integer from 0 to 3\");let r=z6?z6.level:0;t.level=e.level===void 0?r:e.level},X6=class{constructor(e){return bCe(e)}},bCe=t=>{let e={};return UEt(e,t),e.template=(...r)=>kCe(e.template,...r),Object.setPrototypeOf(e,tQ.prototype),Object.setPrototypeOf(e.template,e),e.template.constructor=()=>{throw new Error(\"`chalk.constructor()` is deprecated. Use `new chalk.Instance()` instead.\")},e.template.Instance=X6,e.template};function tQ(t){return bCe(t)}for(let[t,e]of Object.entries(gB))UC[t]={get(){let r=rQ(this,Z6(e.open,e.close,this._styler),this._isEmpty);return Object.defineProperty(this,t,{value:r}),r}};UC.visible={get(){let t=rQ(this,this._styler,!0);return Object.defineProperty(this,\"visible\",{value:t}),t}};var xCe=[\"rgb\",\"hex\",\"keyword\",\"hsl\",\"hsv\",\"hwb\",\"ansi\",\"ansi256\"];for(let t of xCe)UC[t]={get(){let{level:e}=this;return function(...r){let o=Z6(gB.color[SCe[e]][t](...r),gB.color.close,this._styler);return rQ(this,o,this._isEmpty)}}};for(let t of xCe){let e=\"bg\"+t[0].toUpperCase()+t.slice(1);UC[e]={get(){let{level:r}=this;return function(...o){let a=Z6(gB.bgColor[SCe[r]][t](...o),gB.bgColor.close,this._styler);return rQ(this,a,this._isEmpty)}}}}var _Et=Object.defineProperties(()=>{},{...UC,level:{enumerable:!0,get(){return this._generator.level},set(t){this._generator.level=t}}}),Z6=(t,e,r)=>{let o,a;return r===void 0?(o=t,a=e):(o=r.openAll+t,a=e+r.closeAll),{open:t,close:e,openAll:o,closeAll:a,parent:r}},rQ=(t,e,r)=>{let o=(...a)=>eQ(a[0])&&eQ(a[0].raw)?PCe(o,kCe(o,...a)):PCe(o,a.length===1?\"\"+a[0]:a.join(\" \"));return Object.setPrototypeOf(o,_Et),o._generator=t,o._styler=e,o._isEmpty=r,o},PCe=(t,e)=>{if(t.level<=0||!e)return t._isEmpty?\"\":e;let r=t._styler;if(r===void 0)return e;let{openAll:o,closeAll:a}=r;if(e.indexOf(\"\\x1B\")!==-1)for(;r!==void 0;)e=OEt(e,r.close,r.open),r=r.parent;let n=e.indexOf(`\n`);return n!==-1&&(e=MEt(e,a,o,n)),o+e+a},V6,kCe=(t,...e)=>{let[r]=e;if(!eQ(r)||!eQ(r.raw))return e.join(\" \");let o=e.slice(1),a=[r.raw[0]];for(let n=1;n<r.length;n++)a.push(String(o[n-1]).replace(/[{}\\\\]/g,\"\\\\$&\"),String(r.raw[n]));return V6===void 0&&(V6=DCe()),V6(t,a.join(\"\"))};Object.defineProperties(tQ.prototype,UC);var nQ=tQ();nQ.supportsColor=z6;nQ.stderr=tQ({level:J6?J6.level:0});nQ.stderr.supportsColor=J6;QCe.exports=nQ});var $6=_(mB=>{\"use strict\";var HEt=mB&&mB.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};Object.defineProperty(mB,\"__esModule\",{value:!0});var dB=HEt(iQ()),jEt=/^(rgb|hsl|hsv|hwb)\\(\\s?(\\d+),\\s?(\\d+),\\s?(\\d+)\\s?\\)$/,qEt=/^(ansi|ansi256)\\(\\s?(\\d+)\\s?\\)$/,sQ=(t,e)=>e===\"foreground\"?t:\"bg\"+t[0].toUpperCase()+t.slice(1);mB.default=(t,e,r)=>{if(!e)return t;if(e in dB.default){let a=sQ(e,r);return dB.default[a](t)}if(e.startsWith(\"#\")){let a=sQ(\"hex\",r);return dB.default[a](e)(t)}if(e.startsWith(\"ansi\")){let a=qEt.exec(e);if(!a)return t;let n=sQ(a[1],r),u=Number(a[2]);return dB.default[n](u)(t)}if(e.startsWith(\"rgb\")||e.startsWith(\"hsl\")||e.startsWith(\"hsv\")||e.startsWith(\"hwb\")){let a=jEt.exec(e);if(!a)return t;let n=sQ(a[1],r),u=Number(a[2]),A=Number(a[3]),p=Number(a[4]);return dB.default[n](u,A,p)(t)}return t}});var RCe=_(yB=>{\"use strict\";var FCe=yB&&yB.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};Object.defineProperty(yB,\"__esModule\",{value:!0});var GEt=FCe(yCe()),ej=FCe($6());yB.default=(t,e,r,o)=>{if(typeof r.style.borderStyle==\"string\"){let a=r.yogaNode.getComputedWidth(),n=r.yogaNode.getComputedHeight(),u=r.style.borderColor,A=GEt.default[r.style.borderStyle],p=ej.default(A.topLeft+A.horizontal.repeat(a-2)+A.topRight,u,\"foreground\"),h=(ej.default(A.vertical,u,\"foreground\")+`\n`).repeat(n-2),C=ej.default(A.bottomLeft+A.horizontal.repeat(a-2)+A.bottomRight,u,\"foreground\");o.write(t,e,p,{transformers:[]}),o.write(t,e+1,h,{transformers:[]}),o.write(t+a-1,e+1,h,{transformers:[]}),o.write(t,e+n-1,C,{transformers:[]})}}});var NCe=_(EB=>{\"use strict\";var om=EB&&EB.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};Object.defineProperty(EB,\"__esModule\",{value:!0});var YEt=om(sm()),WEt=om(O6()),KEt=om(hCe()),VEt=om(q6()),zEt=om(gCe()),JEt=om(Y6()),XEt=om(RCe()),ZEt=(t,e)=>{var r;let o=(r=t.childNodes[0])===null||r===void 0?void 0:r.yogaNode;if(o){let a=o.getComputedLeft(),n=o.getComputedTop();e=`\n`.repeat(n)+KEt.default(e,a)}return e},TCe=(t,e,r)=>{var o;let{offsetX:a=0,offsetY:n=0,transformers:u=[],skipStaticElements:A}=r;if(A&&t.internal_static)return;let{yogaNode:p}=t;if(p){if(p.getDisplay()===YEt.default.DISPLAY_NONE)return;let h=a+p.getComputedLeft(),C=n+p.getComputedTop(),I=u;if(typeof t.internal_transform==\"function\"&&(I=[t.internal_transform,...u]),t.nodeName===\"ink-text\"){let v=JEt.default(t);if(v.length>0){let x=WEt.default(v),E=zEt.default(p);if(x>E){let R=(o=t.style.textWrap)!==null&&o!==void 0?o:\"wrap\";v=VEt.default(v,E,R)}v=ZEt(t,v),e.write(h,C,v,{transformers:I})}return}if(t.nodeName===\"ink-box\"&&XEt.default(h,C,t,e),t.nodeName===\"ink-root\"||t.nodeName===\"ink-box\")for(let v of t.childNodes)TCe(v,e,{offsetX:h,offsetY:C,transformers:I,skipStaticElements:A})}};EB.default=TCe});var OCe=_((WKt,LCe)=>{\"use strict\";LCe.exports=t=>{t=Object.assign({onlyFirst:!1},t);let e=[\"[\\\\u001B\\\\u009B][[\\\\]()#;?]*(?:(?:(?:[a-zA-Z\\\\d]*(?:;[-a-zA-Z\\\\d\\\\/#&.:=?%@~_]*)*)?\\\\u0007)\",\"(?:(?:\\\\d{1,4}(?:;\\\\d{0,4})*)?[\\\\dA-PR-TZcf-ntqry=><~]))\"].join(\"|\");return new RegExp(e,t.onlyFirst?void 0:\"g\")}});var UCe=_((KKt,tj)=>{\"use strict\";var $Et=OCe(),MCe=t=>typeof t==\"string\"?t.replace($Et(),\"\"):t;tj.exports=MCe;tj.exports.default=MCe});var jCe=_((VKt,HCe)=>{\"use strict\";var _Ce=\"[\\uD800-\\uDBFF][\\uDC00-\\uDFFF]\";HCe.exports=t=>t&&t.exact?new RegExp(`^${_Ce}$`):new RegExp(_Ce,\"g\")});var GCe=_((zKt,rj)=>{\"use strict\";var eCt=UCe(),tCt=jCe(),qCe=t=>eCt(t).replace(tCt(),\" \").length;rj.exports=qCe;rj.exports.default=qCe});var KCe=_(CB=>{\"use strict\";var WCe=CB&&CB.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};Object.defineProperty(CB,\"__esModule\",{value:!0});var YCe=WCe(H6()),rCt=WCe(GCe()),nj=class{constructor(e){this.writes=[];let{width:r,height:o}=e;this.width=r,this.height=o}write(e,r,o,a){let{transformers:n}=a;!o||this.writes.push({x:e,y:r,text:o,transformers:n})}get(){let e=[];for(let o=0;o<this.height;o++)e.push(\" \".repeat(this.width));for(let o of this.writes){let{x:a,y:n,text:u,transformers:A}=o,p=u.split(`\n`),h=0;for(let C of p){let I=e[n+h];if(!I)continue;let v=rCt.default(C);for(let x of A)C=x(C);e[n+h]=YCe.default(I,0,a)+C+YCe.default(I,a+v),h++}}return{output:e.map(o=>o.trimRight()).join(`\n`),height:e.length}}};CB.default=nj});var JCe=_(wB=>{\"use strict\";var ij=wB&&wB.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};Object.defineProperty(wB,\"__esModule\",{value:!0});var nCt=ij(sm()),VCe=ij(NCe()),zCe=ij(KCe());wB.default=(t,e)=>{var r;if(t.yogaNode.setWidth(e),t.yogaNode){t.yogaNode.calculateLayout(void 0,void 0,nCt.default.DIRECTION_LTR);let o=new zCe.default({width:t.yogaNode.getComputedWidth(),height:t.yogaNode.getComputedHeight()});VCe.default(t,o,{skipStaticElements:!0});let a;!((r=t.staticNode)===null||r===void 0)&&r.yogaNode&&(a=new zCe.default({width:t.staticNode.yogaNode.getComputedWidth(),height:t.staticNode.yogaNode.getComputedHeight()}),VCe.default(t.staticNode,a,{skipStaticElements:!1}));let{output:n,height:u}=o.get();return{output:n,outputHeight:u,staticOutput:a?`${a.get().output}\n`:\"\"}}return{output:\"\",outputHeight:0,staticOutput:\"\"}}});var ewe=_((ZKt,$Ce)=>{\"use strict\";var XCe=Be(\"stream\"),ZCe=[\"assert\",\"count\",\"countReset\",\"debug\",\"dir\",\"dirxml\",\"error\",\"group\",\"groupCollapsed\",\"groupEnd\",\"info\",\"log\",\"table\",\"time\",\"timeEnd\",\"timeLog\",\"trace\",\"warn\"],sj={},iCt=t=>{let e=new XCe.PassThrough,r=new XCe.PassThrough;e.write=a=>t(\"stdout\",a),r.write=a=>t(\"stderr\",a);let o=new console.Console(e,r);for(let a of ZCe)sj[a]=console[a],console[a]=o[a];return()=>{for(let a of ZCe)console[a]=sj[a];sj={}}};$Ce.exports=iCt});var aj=_(oj=>{\"use strict\";Object.defineProperty(oj,\"__esModule\",{value:!0});oj.default=new WeakMap});var cj=_(lj=>{\"use strict\";Object.defineProperty(lj,\"__esModule\",{value:!0});var sCt=sn(),twe=sCt.createContext({exit:()=>{}});twe.displayName=\"InternalAppContext\";lj.default=twe});var Aj=_(uj=>{\"use strict\";Object.defineProperty(uj,\"__esModule\",{value:!0});var oCt=sn(),rwe=oCt.createContext({stdin:void 0,setRawMode:()=>{},isRawModeSupported:!1,internal_exitOnCtrlC:!0});rwe.displayName=\"InternalStdinContext\";uj.default=rwe});var pj=_(fj=>{\"use strict\";Object.defineProperty(fj,\"__esModule\",{value:!0});var aCt=sn(),nwe=aCt.createContext({stdout:void 0,write:()=>{}});nwe.displayName=\"InternalStdoutContext\";fj.default=nwe});var gj=_(hj=>{\"use strict\";Object.defineProperty(hj,\"__esModule\",{value:!0});var lCt=sn(),iwe=lCt.createContext({stderr:void 0,write:()=>{}});iwe.displayName=\"InternalStderrContext\";hj.default=iwe});var oQ=_(dj=>{\"use strict\";Object.defineProperty(dj,\"__esModule\",{value:!0});var cCt=sn(),swe=cCt.createContext({activeId:void 0,add:()=>{},remove:()=>{},activate:()=>{},deactivate:()=>{},enableFocus:()=>{},disableFocus:()=>{},focusNext:()=>{},focusPrevious:()=>{}});swe.displayName=\"InternalFocusContext\";dj.default=swe});var awe=_((sVt,owe)=>{\"use strict\";var uCt=/[|\\\\{}()[\\]^$+*?.-]/g;owe.exports=t=>{if(typeof t!=\"string\")throw new TypeError(\"Expected a string\");return t.replace(uCt,\"\\\\$&\")}});var Awe=_((oVt,uwe)=>{\"use strict\";var ACt=awe(),fCt=typeof process==\"object\"&&process&&typeof process.cwd==\"function\"?process.cwd():\".\",cwe=[].concat(Be(\"module\").builtinModules,\"bootstrap_node\",\"node\").map(t=>new RegExp(`(?:\\\\((?:node:)?${t}(?:\\\\.js)?:\\\\d+:\\\\d+\\\\)$|^\\\\s*at (?:node:)?${t}(?:\\\\.js)?:\\\\d+:\\\\d+$)`));cwe.push(/\\((?:node:)?internal\\/[^:]+:\\d+:\\d+\\)$/,/\\s*at (?:node:)?internal\\/[^:]+:\\d+:\\d+$/,/\\/\\.node-spawn-wrap-\\w+-\\w+\\/node:\\d+:\\d+\\)?$/);var IB=class{constructor(e){e={ignoredPackages:[],...e},\"internals\"in e||(e.internals=IB.nodeInternals()),\"cwd\"in e||(e.cwd=fCt),this._cwd=e.cwd.replace(/\\\\/g,\"/\"),this._internals=[].concat(e.internals,pCt(e.ignoredPackages)),this._wrapCallSite=e.wrapCallSite||!1}static nodeInternals(){return[...cwe]}clean(e,r=0){r=\" \".repeat(r),Array.isArray(e)||(e=e.split(`\n`)),!/^\\s*at /.test(e[0])&&/^\\s*at /.test(e[1])&&(e=e.slice(1));let o=!1,a=null,n=[];return e.forEach(u=>{if(u=u.replace(/\\\\/g,\"/\"),this._internals.some(p=>p.test(u)))return;let A=/^\\s*at /.test(u);o?u=u.trimEnd().replace(/^(\\s+)at /,\"$1\"):(u=u.trim(),A&&(u=u.slice(3))),u=u.replace(`${this._cwd}/`,\"\"),u&&(A?(a&&(n.push(a),a=null),n.push(u)):(o=!0,a=u))}),n.map(u=>`${r}${u}\n`).join(\"\")}captureString(e,r=this.captureString){typeof e==\"function\"&&(r=e,e=1/0);let{stackTraceLimit:o}=Error;e&&(Error.stackTraceLimit=e);let a={};Error.captureStackTrace(a,r);let{stack:n}=a;return Error.stackTraceLimit=o,this.clean(n)}capture(e,r=this.capture){typeof e==\"function\"&&(r=e,e=1/0);let{prepareStackTrace:o,stackTraceLimit:a}=Error;Error.prepareStackTrace=(A,p)=>this._wrapCallSite?p.map(this._wrapCallSite):p,e&&(Error.stackTraceLimit=e);let n={};Error.captureStackTrace(n,r);let{stack:u}=n;return Object.assign(Error,{prepareStackTrace:o,stackTraceLimit:a}),u}at(e=this.at){let[r]=this.capture(1,e);if(!r)return{};let o={line:r.getLineNumber(),column:r.getColumnNumber()};lwe(o,r.getFileName(),this._cwd),r.isConstructor()&&(o.constructor=!0),r.isEval()&&(o.evalOrigin=r.getEvalOrigin()),r.isNative()&&(o.native=!0);let a;try{a=r.getTypeName()}catch{}a&&a!==\"Object\"&&a!==\"[object Object]\"&&(o.type=a);let n=r.getFunctionName();n&&(o.function=n);let u=r.getMethodName();return u&&n!==u&&(o.method=u),o}parseLine(e){let r=e&&e.match(hCt);if(!r)return null;let o=r[1]===\"new\",a=r[2],n=r[3],u=r[4],A=Number(r[5]),p=Number(r[6]),h=r[7],C=r[8],I=r[9],v=r[10]===\"native\",x=r[11]===\")\",E,R={};if(C&&(R.line=Number(C)),I&&(R.column=Number(I)),x&&h){let L=0;for(let U=h.length-1;U>0;U--)if(h.charAt(U)===\")\")L++;else if(h.charAt(U)===\"(\"&&h.charAt(U-1)===\" \"&&(L--,L===-1&&h.charAt(U-1)===\" \")){let z=h.slice(0,U-1);h=h.slice(U+1),a+=` (${z}`;break}}if(a){let L=a.match(gCt);L&&(a=L[1],E=L[2])}return lwe(R,h,this._cwd),o&&(R.constructor=!0),n&&(R.evalOrigin=n,R.evalLine=A,R.evalColumn=p,R.evalFile=u&&u.replace(/\\\\/g,\"/\")),v&&(R.native=!0),a&&(R.function=a),E&&a!==E&&(R.method=E),R}};function lwe(t,e,r){e&&(e=e.replace(/\\\\/g,\"/\"),e.startsWith(`${r}/`)&&(e=e.slice(r.length+1)),t.file=e)}function pCt(t){if(t.length===0)return[];let e=t.map(r=>ACt(r));return new RegExp(`[/\\\\\\\\]node_modules[/\\\\\\\\](?:${e.join(\"|\")})[/\\\\\\\\][^:]+:\\\\d+:\\\\d+`)}var hCt=new RegExp(\"^(?:\\\\s*at )?(?:(new) )?(?:(.*?) \\\\()?(?:eval at ([^ ]+) \\\\((.+?):(\\\\d+):(\\\\d+)\\\\), )?(?:(.+?):(\\\\d+):(\\\\d+)|(native))(\\\\)?)$\"),gCt=/^(.*?) \\[as (.*?)\\]$/;uwe.exports=IB});var pwe=_((aVt,fwe)=>{\"use strict\";fwe.exports=(t,e)=>t.replace(/^\\t+/gm,r=>\" \".repeat(r.length*(e||2)))});var gwe=_((lVt,hwe)=>{\"use strict\";var dCt=pwe(),mCt=(t,e)=>{let r=[],o=t-e,a=t+e;for(let n=o;n<=a;n++)r.push(n);return r};hwe.exports=(t,e,r)=>{if(typeof t!=\"string\")throw new TypeError(\"Source code is missing.\");if(!e||e<1)throw new TypeError(\"Line number must start from `1`.\");if(t=dCt(t).split(/\\r?\\n/),!(e>t.length))return r={around:3,...r},mCt(e,r.around).filter(o=>t[o-1]!==void 0).map(o=>({line:o,value:t[o-1]}))}});var aQ=_(ru=>{\"use strict\";var yCt=ru&&ru.__createBinding||(Object.create?function(t,e,r,o){o===void 0&&(o=r),Object.defineProperty(t,o,{enumerable:!0,get:function(){return e[r]}})}:function(t,e,r,o){o===void 0&&(o=r),t[o]=e[r]}),ECt=ru&&ru.__setModuleDefault||(Object.create?function(t,e){Object.defineProperty(t,\"default\",{enumerable:!0,value:e})}:function(t,e){t.default=e}),CCt=ru&&ru.__importStar||function(t){if(t&&t.__esModule)return t;var e={};if(t!=null)for(var r in t)r!==\"default\"&&Object.hasOwnProperty.call(t,r)&&yCt(e,t,r);return ECt(e,t),e},wCt=ru&&ru.__rest||function(t,e){var r={};for(var o in t)Object.prototype.hasOwnProperty.call(t,o)&&e.indexOf(o)<0&&(r[o]=t[o]);if(t!=null&&typeof Object.getOwnPropertySymbols==\"function\")for(var a=0,o=Object.getOwnPropertySymbols(t);a<o.length;a++)e.indexOf(o[a])<0&&Object.prototype.propertyIsEnumerable.call(t,o[a])&&(r[o[a]]=t[o[a]]);return r};Object.defineProperty(ru,\"__esModule\",{value:!0});var dwe=CCt(sn()),mj=dwe.forwardRef((t,e)=>{var{children:r}=t,o=wCt(t,[\"children\"]);let a=Object.assign(Object.assign({},o),{marginLeft:o.marginLeft||o.marginX||o.margin||0,marginRight:o.marginRight||o.marginX||o.margin||0,marginTop:o.marginTop||o.marginY||o.margin||0,marginBottom:o.marginBottom||o.marginY||o.margin||0,paddingLeft:o.paddingLeft||o.paddingX||o.padding||0,paddingRight:o.paddingRight||o.paddingX||o.padding||0,paddingTop:o.paddingTop||o.paddingY||o.padding||0,paddingBottom:o.paddingBottom||o.paddingY||o.padding||0});return dwe.default.createElement(\"ink-box\",{ref:e,style:a},r)});mj.displayName=\"Box\";mj.defaultProps={flexDirection:\"row\",flexGrow:0,flexShrink:1};ru.default=mj});var Cj=_(BB=>{\"use strict\";var yj=BB&&BB.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};Object.defineProperty(BB,\"__esModule\",{value:!0});var ICt=yj(sn()),_C=yj(iQ()),mwe=yj($6()),Ej=({color:t,backgroundColor:e,dimColor:r,bold:o,italic:a,underline:n,strikethrough:u,inverse:A,wrap:p,children:h})=>{if(h==null)return null;let C=I=>(r&&(I=_C.default.dim(I)),t&&(I=mwe.default(I,t,\"foreground\")),e&&(I=mwe.default(I,e,\"background\")),o&&(I=_C.default.bold(I)),a&&(I=_C.default.italic(I)),n&&(I=_C.default.underline(I)),u&&(I=_C.default.strikethrough(I)),A&&(I=_C.default.inverse(I)),I);return ICt.default.createElement(\"ink-text\",{style:{flexGrow:0,flexShrink:1,flexDirection:\"row\",textWrap:p},internal_transform:C},h)};Ej.displayName=\"Text\";Ej.defaultProps={dimColor:!1,bold:!1,italic:!1,underline:!1,strikethrough:!1,wrap:\"wrap\"};BB.default=Ej});var wwe=_(nu=>{\"use strict\";var BCt=nu&&nu.__createBinding||(Object.create?function(t,e,r,o){o===void 0&&(o=r),Object.defineProperty(t,o,{enumerable:!0,get:function(){return e[r]}})}:function(t,e,r,o){o===void 0&&(o=r),t[o]=e[r]}),vCt=nu&&nu.__setModuleDefault||(Object.create?function(t,e){Object.defineProperty(t,\"default\",{enumerable:!0,value:e})}:function(t,e){t.default=e}),DCt=nu&&nu.__importStar||function(t){if(t&&t.__esModule)return t;var e={};if(t!=null)for(var r in t)r!==\"default\"&&Object.hasOwnProperty.call(t,r)&&BCt(e,t,r);return vCt(e,t),e},vB=nu&&nu.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};Object.defineProperty(nu,\"__esModule\",{value:!0});var ywe=DCt(Be(\"fs\")),fs=vB(sn()),Ewe=vB(Awe()),PCt=vB(gwe()),Jf=vB(aQ()),hA=vB(Cj()),Cwe=new Ewe.default({cwd:process.cwd(),internals:Ewe.default.nodeInternals()}),SCt=({error:t})=>{let e=t.stack?t.stack.split(`\n`).slice(1):void 0,r=e?Cwe.parseLine(e[0]):void 0,o,a=0;if(r?.file&&r?.line&&ywe.existsSync(r.file)){let n=ywe.readFileSync(r.file,\"utf8\");if(o=PCt.default(n,r.line),o)for(let{line:u}of o)a=Math.max(a,String(u).length)}return fs.default.createElement(Jf.default,{flexDirection:\"column\",padding:1},fs.default.createElement(Jf.default,null,fs.default.createElement(hA.default,{backgroundColor:\"red\",color:\"white\"},\" \",\"ERROR\",\" \"),fs.default.createElement(hA.default,null,\" \",t.message)),r&&fs.default.createElement(Jf.default,{marginTop:1},fs.default.createElement(hA.default,{dimColor:!0},r.file,\":\",r.line,\":\",r.column)),r&&o&&fs.default.createElement(Jf.default,{marginTop:1,flexDirection:\"column\"},o.map(({line:n,value:u})=>fs.default.createElement(Jf.default,{key:n},fs.default.createElement(Jf.default,{width:a+1},fs.default.createElement(hA.default,{dimColor:n!==r.line,backgroundColor:n===r.line?\"red\":void 0,color:n===r.line?\"white\":void 0},String(n).padStart(a,\" \"),\":\")),fs.default.createElement(hA.default,{key:n,backgroundColor:n===r.line?\"red\":void 0,color:n===r.line?\"white\":void 0},\" \"+u)))),t.stack&&fs.default.createElement(Jf.default,{marginTop:1,flexDirection:\"column\"},t.stack.split(`\n`).slice(1).map(n=>{let u=Cwe.parseLine(n);return u?fs.default.createElement(Jf.default,{key:n},fs.default.createElement(hA.default,{dimColor:!0},\"- \"),fs.default.createElement(hA.default,{dimColor:!0,bold:!0},u.function),fs.default.createElement(hA.default,{dimColor:!0,color:\"gray\"},\" \",\"(\",u.file,\":\",u.line,\":\",u.column,\")\")):fs.default.createElement(Jf.default,{key:n},fs.default.createElement(hA.default,{dimColor:!0},\"- \"),fs.default.createElement(hA.default,{dimColor:!0,bold:!0},n))})))};nu.default=SCt});var Bwe=_(iu=>{\"use strict\";var bCt=iu&&iu.__createBinding||(Object.create?function(t,e,r,o){o===void 0&&(o=r),Object.defineProperty(t,o,{enumerable:!0,get:function(){return e[r]}})}:function(t,e,r,o){o===void 0&&(o=r),t[o]=e[r]}),xCt=iu&&iu.__setModuleDefault||(Object.create?function(t,e){Object.defineProperty(t,\"default\",{enumerable:!0,value:e})}:function(t,e){t.default=e}),kCt=iu&&iu.__importStar||function(t){if(t&&t.__esModule)return t;var e={};if(t!=null)for(var r in t)r!==\"default\"&&Object.hasOwnProperty.call(t,r)&&bCt(e,t,r);return xCt(e,t),e},lm=iu&&iu.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};Object.defineProperty(iu,\"__esModule\",{value:!0});var am=kCt(sn()),Iwe=lm(m6()),QCt=lm(cj()),FCt=lm(Aj()),RCt=lm(pj()),TCt=lm(gj()),NCt=lm(oQ()),LCt=lm(wwe()),OCt=\"\t\",MCt=\"\\x1B[Z\",UCt=\"\\x1B\",lQ=class extends am.PureComponent{constructor(){super(...arguments),this.state={isFocusEnabled:!0,activeFocusId:void 0,focusables:[],error:void 0},this.rawModeEnabledCount=0,this.handleSetRawMode=e=>{let{stdin:r}=this.props;if(!this.isRawModeSupported())throw r===process.stdin?new Error(`Raw mode is not supported on the current process.stdin, which Ink uses as input stream by default.\nRead about how to prevent this error on https://github.com/vadimdemedes/ink/#israwmodesupported`):new Error(`Raw mode is not supported on the stdin provided to Ink.\nRead about how to prevent this error on https://github.com/vadimdemedes/ink/#israwmodesupported`);if(r.setEncoding(\"utf8\"),e){this.rawModeEnabledCount===0&&(r.addListener(\"data\",this.handleInput),r.resume(),r.setRawMode(!0)),this.rawModeEnabledCount++;return}--this.rawModeEnabledCount===0&&(r.setRawMode(!1),r.removeListener(\"data\",this.handleInput),r.pause())},this.handleInput=e=>{e===\"\u0003\"&&this.props.exitOnCtrlC&&this.handleExit(),e===UCt&&this.state.activeFocusId&&this.setState({activeFocusId:void 0}),this.state.isFocusEnabled&&this.state.focusables.length>0&&(e===OCt&&this.focusNext(),e===MCt&&this.focusPrevious())},this.handleExit=e=>{this.isRawModeSupported()&&this.handleSetRawMode(!1),this.props.onExit(e)},this.enableFocus=()=>{this.setState({isFocusEnabled:!0})},this.disableFocus=()=>{this.setState({isFocusEnabled:!1})},this.focusNext=()=>{this.setState(e=>{let r=e.focusables[0].id;return{activeFocusId:this.findNextFocusable(e)||r}})},this.focusPrevious=()=>{this.setState(e=>{let r=e.focusables[e.focusables.length-1].id;return{activeFocusId:this.findPreviousFocusable(e)||r}})},this.addFocusable=(e,{autoFocus:r})=>{this.setState(o=>{let a=o.activeFocusId;return!a&&r&&(a=e),{activeFocusId:a,focusables:[...o.focusables,{id:e,isActive:!0}]}})},this.removeFocusable=e=>{this.setState(r=>({activeFocusId:r.activeFocusId===e?void 0:r.activeFocusId,focusables:r.focusables.filter(o=>o.id!==e)}))},this.activateFocusable=e=>{this.setState(r=>({focusables:r.focusables.map(o=>o.id!==e?o:{id:e,isActive:!0})}))},this.deactivateFocusable=e=>{this.setState(r=>({activeFocusId:r.activeFocusId===e?void 0:r.activeFocusId,focusables:r.focusables.map(o=>o.id!==e?o:{id:e,isActive:!1})}))},this.findNextFocusable=e=>{let r=e.focusables.findIndex(o=>o.id===e.activeFocusId);for(let o=r+1;o<e.focusables.length;o++)if(e.focusables[o].isActive)return e.focusables[o].id},this.findPreviousFocusable=e=>{let r=e.focusables.findIndex(o=>o.id===e.activeFocusId);for(let o=r-1;o>=0;o--)if(e.focusables[o].isActive)return e.focusables[o].id}}static getDerivedStateFromError(e){return{error:e}}isRawModeSupported(){return this.props.stdin.isTTY}render(){return am.default.createElement(QCt.default.Provider,{value:{exit:this.handleExit}},am.default.createElement(FCt.default.Provider,{value:{stdin:this.props.stdin,setRawMode:this.handleSetRawMode,isRawModeSupported:this.isRawModeSupported(),internal_exitOnCtrlC:this.props.exitOnCtrlC}},am.default.createElement(RCt.default.Provider,{value:{stdout:this.props.stdout,write:this.props.writeToStdout}},am.default.createElement(TCt.default.Provider,{value:{stderr:this.props.stderr,write:this.props.writeToStderr}},am.default.createElement(NCt.default.Provider,{value:{activeId:this.state.activeFocusId,add:this.addFocusable,remove:this.removeFocusable,activate:this.activateFocusable,deactivate:this.deactivateFocusable,enableFocus:this.enableFocus,disableFocus:this.disableFocus,focusNext:this.focusNext,focusPrevious:this.focusPrevious}},this.state.error?am.default.createElement(LCt.default,{error:this.state.error}):this.props.children)))))}componentDidMount(){Iwe.default.hide(this.props.stdout)}componentWillUnmount(){Iwe.default.show(this.props.stdout),this.isRawModeSupported()&&this.handleSetRawMode(!1)}componentDidCatch(e){this.handleExit(e)}};iu.default=lQ;lQ.displayName=\"InternalApp\"});var Pwe=_(su=>{\"use strict\";var _Ct=su&&su.__createBinding||(Object.create?function(t,e,r,o){o===void 0&&(o=r),Object.defineProperty(t,o,{enumerable:!0,get:function(){return e[r]}})}:function(t,e,r,o){o===void 0&&(o=r),t[o]=e[r]}),HCt=su&&su.__setModuleDefault||(Object.create?function(t,e){Object.defineProperty(t,\"default\",{enumerable:!0,value:e})}:function(t,e){t.default=e}),jCt=su&&su.__importStar||function(t){if(t&&t.__esModule)return t;var e={};if(t!=null)for(var r in t)r!==\"default\"&&Object.hasOwnProperty.call(t,r)&&_Ct(e,t,r);return HCt(e,t),e},ou=su&&su.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};Object.defineProperty(su,\"__esModule\",{value:!0});var qCt=ou(sn()),vwe=uM(),GCt=ou(AEe()),YCt=ou(f6()),WCt=ou(mEe()),KCt=ou(EEe()),wj=ou(fCe()),VCt=ou(JCe()),zCt=ou(d6()),JCt=ou(ewe()),XCt=jCt(W6()),ZCt=ou(aj()),$Ct=ou(Bwe()),HC=process.env.CI===\"false\"?!1:WCt.default,Dwe=()=>{},Ij=class{constructor(e){this.resolveExitPromise=()=>{},this.rejectExitPromise=()=>{},this.unsubscribeExit=()=>{},this.onRender=()=>{if(this.isUnmounted)return;let{output:r,outputHeight:o,staticOutput:a}=VCt.default(this.rootNode,this.options.stdout.columns||80),n=a&&a!==`\n`;if(this.options.debug){n&&(this.fullStaticOutput+=a),this.options.stdout.write(this.fullStaticOutput+r);return}if(HC){n&&this.options.stdout.write(a),this.lastOutput=r;return}if(n&&(this.fullStaticOutput+=a),o>=this.options.stdout.rows){this.options.stdout.write(YCt.default.clearTerminal+this.fullStaticOutput+r),this.lastOutput=r;return}n&&(this.log.clear(),this.options.stdout.write(a),this.log(r)),!n&&r!==this.lastOutput&&this.throttledLog(r),this.lastOutput=r},KCt.default(this),this.options=e,this.rootNode=XCt.createNode(\"ink-root\"),this.rootNode.onRender=e.debug?this.onRender:vwe(this.onRender,32,{leading:!0,trailing:!0}),this.rootNode.onImmediateRender=this.onRender,this.log=GCt.default.create(e.stdout),this.throttledLog=e.debug?this.log:vwe(this.log,void 0,{leading:!0,trailing:!0}),this.isUnmounted=!1,this.lastOutput=\"\",this.fullStaticOutput=\"\",this.container=wj.default.createContainer(this.rootNode,!1,!1),this.unsubscribeExit=zCt.default(this.unmount,{alwaysLast:!1}),e.patchConsole&&this.patchConsole(),HC||(e.stdout.on(\"resize\",this.onRender),this.unsubscribeResize=()=>{e.stdout.off(\"resize\",this.onRender)})}render(e){let r=qCt.default.createElement($Ct.default,{stdin:this.options.stdin,stdout:this.options.stdout,stderr:this.options.stderr,writeToStdout:this.writeToStdout,writeToStderr:this.writeToStderr,exitOnCtrlC:this.options.exitOnCtrlC,onExit:this.unmount},e);wj.default.updateContainer(r,this.container,null,Dwe)}writeToStdout(e){if(!this.isUnmounted){if(this.options.debug){this.options.stdout.write(e+this.fullStaticOutput+this.lastOutput);return}if(HC){this.options.stdout.write(e);return}this.log.clear(),this.options.stdout.write(e),this.log(this.lastOutput)}}writeToStderr(e){if(!this.isUnmounted){if(this.options.debug){this.options.stderr.write(e),this.options.stdout.write(this.fullStaticOutput+this.lastOutput);return}if(HC){this.options.stderr.write(e);return}this.log.clear(),this.options.stderr.write(e),this.log(this.lastOutput)}}unmount(e){this.isUnmounted||(this.onRender(),this.unsubscribeExit(),typeof this.restoreConsole==\"function\"&&this.restoreConsole(),typeof this.unsubscribeResize==\"function\"&&this.unsubscribeResize(),HC?this.options.stdout.write(this.lastOutput+`\n`):this.options.debug||this.log.done(),this.isUnmounted=!0,wj.default.updateContainer(null,this.container,null,Dwe),ZCt.default.delete(this.options.stdout),e instanceof Error?this.rejectExitPromise(e):this.resolveExitPromise())}waitUntilExit(){return this.exitPromise||(this.exitPromise=new Promise((e,r)=>{this.resolveExitPromise=e,this.rejectExitPromise=r})),this.exitPromise}clear(){!HC&&!this.options.debug&&this.log.clear()}patchConsole(){this.options.debug||(this.restoreConsole=JCt.default((e,r)=>{e===\"stdout\"&&this.writeToStdout(r),e===\"stderr\"&&(r.startsWith(\"The above error occurred\")||this.writeToStderr(r))}))}};su.default=Ij});var bwe=_(DB=>{\"use strict\";var Swe=DB&&DB.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};Object.defineProperty(DB,\"__esModule\",{value:!0});var ewt=Swe(Pwe()),cQ=Swe(aj()),twt=Be(\"stream\"),rwt=(t,e)=>{let r=Object.assign({stdout:process.stdout,stdin:process.stdin,stderr:process.stderr,debug:!1,exitOnCtrlC:!0,patchConsole:!0},nwt(e)),o=iwt(r.stdout,()=>new ewt.default(r));return o.render(t),{rerender:o.render,unmount:()=>o.unmount(),waitUntilExit:o.waitUntilExit,cleanup:()=>cQ.default.delete(r.stdout),clear:o.clear}};DB.default=rwt;var nwt=(t={})=>t instanceof twt.Stream?{stdout:t,stdin:process.stdin}:t,iwt=(t,e)=>{let r;return cQ.default.has(t)?r=cQ.default.get(t):(r=e(),cQ.default.set(t,r)),r}});var kwe=_(Xf=>{\"use strict\";var swt=Xf&&Xf.__createBinding||(Object.create?function(t,e,r,o){o===void 0&&(o=r),Object.defineProperty(t,o,{enumerable:!0,get:function(){return e[r]}})}:function(t,e,r,o){o===void 0&&(o=r),t[o]=e[r]}),owt=Xf&&Xf.__setModuleDefault||(Object.create?function(t,e){Object.defineProperty(t,\"default\",{enumerable:!0,value:e})}:function(t,e){t.default=e}),awt=Xf&&Xf.__importStar||function(t){if(t&&t.__esModule)return t;var e={};if(t!=null)for(var r in t)r!==\"default\"&&Object.hasOwnProperty.call(t,r)&&swt(e,t,r);return owt(e,t),e};Object.defineProperty(Xf,\"__esModule\",{value:!0});var PB=awt(sn()),xwe=t=>{let{items:e,children:r,style:o}=t,[a,n]=PB.useState(0),u=PB.useMemo(()=>e.slice(a),[e,a]);PB.useLayoutEffect(()=>{n(e.length)},[e.length]);let A=u.map((h,C)=>r(h,a+C)),p=PB.useMemo(()=>Object.assign({position:\"absolute\",flexDirection:\"column\"},o),[o]);return PB.default.createElement(\"ink-box\",{internal_static:!0,style:p},A)};xwe.displayName=\"Static\";Xf.default=xwe});var Fwe=_(SB=>{\"use strict\";var lwt=SB&&SB.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};Object.defineProperty(SB,\"__esModule\",{value:!0});var cwt=lwt(sn()),Qwe=({children:t,transform:e})=>t==null?null:cwt.default.createElement(\"ink-text\",{style:{flexGrow:0,flexShrink:1,flexDirection:\"row\"},internal_transform:e},t);Qwe.displayName=\"Transform\";SB.default=Qwe});var Twe=_(bB=>{\"use strict\";var uwt=bB&&bB.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};Object.defineProperty(bB,\"__esModule\",{value:!0});var Awt=uwt(sn()),Rwe=({count:t=1})=>Awt.default.createElement(\"ink-text\",null,`\n`.repeat(t));Rwe.displayName=\"Newline\";bB.default=Rwe});var Owe=_(xB=>{\"use strict\";var Nwe=xB&&xB.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};Object.defineProperty(xB,\"__esModule\",{value:!0});var fwt=Nwe(sn()),pwt=Nwe(aQ()),Lwe=()=>fwt.default.createElement(pwt.default,{flexGrow:1});Lwe.displayName=\"Spacer\";xB.default=Lwe});var uQ=_(kB=>{\"use strict\";var hwt=kB&&kB.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};Object.defineProperty(kB,\"__esModule\",{value:!0});var gwt=sn(),dwt=hwt(Aj()),mwt=()=>gwt.useContext(dwt.default);kB.default=mwt});var Uwe=_(QB=>{\"use strict\";var ywt=QB&&QB.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};Object.defineProperty(QB,\"__esModule\",{value:!0});var Mwe=sn(),Ewt=ywt(uQ()),Cwt=(t,e={})=>{let{stdin:r,setRawMode:o,internal_exitOnCtrlC:a}=Ewt.default();Mwe.useEffect(()=>{if(e.isActive!==!1)return o(!0),()=>{o(!1)}},[e.isActive,o]),Mwe.useEffect(()=>{if(e.isActive===!1)return;let n=u=>{let A=String(u),p={upArrow:A===\"\\x1B[A\",downArrow:A===\"\\x1B[B\",leftArrow:A===\"\\x1B[D\",rightArrow:A===\"\\x1B[C\",pageDown:A===\"\\x1B[6~\",pageUp:A===\"\\x1B[5~\",return:A===\"\\r\",escape:A===\"\\x1B\",ctrl:!1,shift:!1,tab:A===\"\t\"||A===\"\\x1B[Z\",backspace:A===\"\\b\",delete:A===\"\\x7F\"||A===\"\\x1B[3~\",meta:!1};A<=\"\u001a\"&&!p.return&&(A=String.fromCharCode(A.charCodeAt(0)+\"a\".charCodeAt(0)-1),p.ctrl=!0),A.startsWith(\"\\x1B\")&&(A=A.slice(1),p.meta=!0);let h=A>=\"A\"&&A<=\"Z\",C=A>=\"\\u0410\"&&A<=\"\\u042F\";A.length===1&&(h||C)&&(p.shift=!0),p.tab&&A===\"[Z\"&&(p.shift=!0),(p.tab||p.backspace||p.delete)&&(A=\"\"),(!(A===\"c\"&&p.ctrl)||!a)&&t(A,p)};return r?.on(\"data\",n),()=>{r?.off(\"data\",n)}},[e.isActive,r,a,t])};QB.default=Cwt});var _we=_(FB=>{\"use strict\";var wwt=FB&&FB.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};Object.defineProperty(FB,\"__esModule\",{value:!0});var Iwt=sn(),Bwt=wwt(cj()),vwt=()=>Iwt.useContext(Bwt.default);FB.default=vwt});var Hwe=_(RB=>{\"use strict\";var Dwt=RB&&RB.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};Object.defineProperty(RB,\"__esModule\",{value:!0});var Pwt=sn(),Swt=Dwt(pj()),bwt=()=>Pwt.useContext(Swt.default);RB.default=bwt});var jwe=_(TB=>{\"use strict\";var xwt=TB&&TB.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};Object.defineProperty(TB,\"__esModule\",{value:!0});var kwt=sn(),Qwt=xwt(gj()),Fwt=()=>kwt.useContext(Qwt.default);TB.default=Fwt});var Gwe=_(LB=>{\"use strict\";var qwe=LB&&LB.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};Object.defineProperty(LB,\"__esModule\",{value:!0});var NB=sn(),Rwt=qwe(oQ()),Twt=qwe(uQ()),Nwt=({isActive:t=!0,autoFocus:e=!1}={})=>{let{isRawModeSupported:r,setRawMode:o}=Twt.default(),{activeId:a,add:n,remove:u,activate:A,deactivate:p}=NB.useContext(Rwt.default),h=NB.useMemo(()=>Math.random().toString().slice(2,7),[]);return NB.useEffect(()=>(n(h,{autoFocus:e}),()=>{u(h)}),[h,e]),NB.useEffect(()=>{t?A(h):p(h)},[t,h]),NB.useEffect(()=>{if(!(!r||!t))return o(!0),()=>{o(!1)}},[t]),{isFocused:Boolean(h)&&a===h}};LB.default=Nwt});var Ywe=_(OB=>{\"use strict\";var Lwt=OB&&OB.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};Object.defineProperty(OB,\"__esModule\",{value:!0});var Owt=sn(),Mwt=Lwt(oQ()),Uwt=()=>{let t=Owt.useContext(Mwt.default);return{enableFocus:t.enableFocus,disableFocus:t.disableFocus,focusNext:t.focusNext,focusPrevious:t.focusPrevious}};OB.default=Uwt});var Wwe=_(Bj=>{\"use strict\";Object.defineProperty(Bj,\"__esModule\",{value:!0});Bj.default=t=>{var e,r,o,a;return{width:(r=(e=t.yogaNode)===null||e===void 0?void 0:e.getComputedWidth())!==null&&r!==void 0?r:0,height:(a=(o=t.yogaNode)===null||o===void 0?void 0:o.getComputedHeight())!==null&&a!==void 0?a:0}}});var ic=_(ro=>{\"use strict\";Object.defineProperty(ro,\"__esModule\",{value:!0});var _wt=bwe();Object.defineProperty(ro,\"render\",{enumerable:!0,get:function(){return _wt.default}});var Hwt=aQ();Object.defineProperty(ro,\"Box\",{enumerable:!0,get:function(){return Hwt.default}});var jwt=Cj();Object.defineProperty(ro,\"Text\",{enumerable:!0,get:function(){return jwt.default}});var qwt=kwe();Object.defineProperty(ro,\"Static\",{enumerable:!0,get:function(){return qwt.default}});var Gwt=Fwe();Object.defineProperty(ro,\"Transform\",{enumerable:!0,get:function(){return Gwt.default}});var Ywt=Twe();Object.defineProperty(ro,\"Newline\",{enumerable:!0,get:function(){return Ywt.default}});var Wwt=Owe();Object.defineProperty(ro,\"Spacer\",{enumerable:!0,get:function(){return Wwt.default}});var Kwt=Uwe();Object.defineProperty(ro,\"useInput\",{enumerable:!0,get:function(){return Kwt.default}});var Vwt=_we();Object.defineProperty(ro,\"useApp\",{enumerable:!0,get:function(){return Vwt.default}});var zwt=uQ();Object.defineProperty(ro,\"useStdin\",{enumerable:!0,get:function(){return zwt.default}});var Jwt=Hwe();Object.defineProperty(ro,\"useStdout\",{enumerable:!0,get:function(){return Jwt.default}});var Xwt=jwe();Object.defineProperty(ro,\"useStderr\",{enumerable:!0,get:function(){return Xwt.default}});var Zwt=Gwe();Object.defineProperty(ro,\"useFocus\",{enumerable:!0,get:function(){return Zwt.default}});var $wt=Ywe();Object.defineProperty(ro,\"useFocusManager\",{enumerable:!0,get:function(){return $wt.default}});var eIt=Wwe();Object.defineProperty(ro,\"measureElement\",{enumerable:!0,get:function(){return eIt.default}})});var Dj={};Vt(Dj,{Gem:()=>vj});var Kwe,cm,vj,AQ=Et(()=>{Kwe=$e(ic()),cm=$e(sn()),vj=(0,cm.memo)(({active:t})=>{let e=(0,cm.useMemo)(()=>t?\"\\u25C9\":\"\\u25EF\",[t]),r=(0,cm.useMemo)(()=>t?\"green\":\"yellow\",[t]);return cm.default.createElement(Kwe.Text,{color:r},e)})});var zwe={};Vt(zwe,{useKeypress:()=>um});function um({active:t},e,r){let{stdin:o}=(0,Vwe.useStdin)(),a=(0,fQ.useCallback)((n,u)=>e(n,u),r);(0,fQ.useEffect)(()=>{if(!(!t||!o))return o.on(\"keypress\",a),()=>{o.off(\"keypress\",a)}},[t,a,o])}var Vwe,fQ,MB=Et(()=>{Vwe=$e(ic()),fQ=$e(sn())});var Xwe={};Vt(Xwe,{FocusRequest:()=>Jwe,useFocusRequest:()=>Pj});var Jwe,Pj,Sj=Et(()=>{MB();Jwe=(r=>(r.BEFORE=\"before\",r.AFTER=\"after\",r))(Jwe||{}),Pj=function({active:t},e,r){um({active:t},(o,a)=>{a.name===\"tab\"&&(a.shift?e(\"before\"):e(\"after\"))},r)}});var Zwe={};Vt(Zwe,{useListInput:()=>UB});var UB,pQ=Et(()=>{MB();UB=function(t,e,{active:r,minus:o,plus:a,set:n,loop:u=!0}){um({active:r},(A,p)=>{let h=e.indexOf(t);switch(p.name){case o:{let C=h-1;if(u){n(e[(e.length+C)%e.length]);return}if(C<0)return;n(e[C])}break;case a:{let C=h+1;if(u){n(e[C%e.length]);return}if(C>=e.length)return;n(e[C])}break}},[e,t,a,n,u])}});var hQ={};Vt(hQ,{ScrollableItems:()=>tIt});var E0,La,tIt,gQ=Et(()=>{E0=$e(ic()),La=$e(sn());Sj();pQ();tIt=({active:t=!0,children:e=[],radius:r=10,size:o=1,loop:a=!0,onFocusRequest:n,willReachEnd:u})=>{let A=L=>{if(L.key===null)throw new Error(\"Expected all children to have a key\");return L.key},p=La.default.Children.map(e,L=>A(L)),h=p[0],[C,I]=(0,La.useState)(h),v=p.indexOf(C);(0,La.useEffect)(()=>{p.includes(C)||I(h)},[e]),(0,La.useEffect)(()=>{u&&v>=p.length-2&&u()},[v]),Pj({active:t&&!!n},L=>{n?.(L)},[n]),UB(C,p,{active:t,minus:\"up\",plus:\"down\",set:I,loop:a});let x=v-r,E=v+r;E>p.length&&(x-=E-p.length,E=p.length),x<0&&(E+=-x,x=0),E>=p.length&&(E=p.length-1);let R=[];for(let L=x;L<=E;++L){let U=p[L],z=t&&U===C;R.push(La.default.createElement(E0.Box,{key:U,height:o},La.default.createElement(E0.Box,{marginLeft:1,marginRight:1},La.default.createElement(E0.Text,null,z?La.default.createElement(E0.Text,{color:\"cyan\",bold:!0},\">\"):\" \")),La.default.createElement(E0.Box,null,La.default.cloneElement(e[L],{active:z}))))}return La.default.createElement(E0.Box,{flexDirection:\"column\",width:\"100%\"},R)}});var $we,Zf,eIe,bj,tIe,xj=Et(()=>{$we=$e(ic()),Zf=$e(sn()),eIe=Be(\"readline\"),bj=Zf.default.createContext(null),tIe=({children:t})=>{let{stdin:e,setRawMode:r}=(0,$we.useStdin)();(0,Zf.useEffect)(()=>{r&&r(!0),e&&(0,eIe.emitKeypressEvents)(e)},[e,r]);let[o,a]=(0,Zf.useState)(new Map),n=(0,Zf.useMemo)(()=>({getAll:()=>o,get:u=>o.get(u),set:(u,A)=>a(new Map([...o,[u,A]]))}),[o,a]);return Zf.default.createElement(bj.Provider,{value:n,children:t})}});var kj={};Vt(kj,{useMinistore:()=>rIt});function rIt(t,e){let r=(0,dQ.useContext)(bj);if(r===null)throw new Error(\"Expected this hook to run with a ministore context attached\");if(typeof t>\"u\")return r.getAll();let o=(0,dQ.useCallback)(n=>{r.set(t,n)},[t,r.set]),a=r.get(t);return typeof a>\"u\"&&(a=e),[a,o]}var dQ,Qj=Et(()=>{dQ=$e(sn());xj()});var yQ={};Vt(yQ,{renderForm:()=>nIt});async function nIt(t,e,{stdin:r,stdout:o,stderr:a}){let n,u=p=>{let{exit:h}=(0,mQ.useApp)();um({active:!0},(C,I)=>{I.name===\"return\"&&(n=p,h())},[h,p])},{waitUntilExit:A}=(0,mQ.render)(Fj.default.createElement(tIe,null,Fj.default.createElement(t,{...e,useSubmit:u})),{stdin:r,stdout:o,stderr:a});return await A(),n}var mQ,Fj,EQ=Et(()=>{mQ=$e(ic()),Fj=$e(sn());xj();MB()});var sIe=_(_B=>{\"use strict\";Object.defineProperty(_B,\"__esModule\",{value:!0});_B.UncontrolledTextInput=void 0;var nIe=sn(),Rj=sn(),rIe=ic(),Am=iQ(),iIe=({value:t,placeholder:e=\"\",focus:r=!0,mask:o,highlightPastedText:a=!1,showCursor:n=!0,onChange:u,onSubmit:A})=>{let[{cursorOffset:p,cursorWidth:h},C]=Rj.useState({cursorOffset:(t||\"\").length,cursorWidth:0});Rj.useEffect(()=>{C(R=>{if(!r||!n)return R;let L=t||\"\";return R.cursorOffset>L.length-1?{cursorOffset:L.length,cursorWidth:0}:R})},[t,r,n]);let I=a?h:0,v=o?o.repeat(t.length):t,x=v,E=e?Am.grey(e):void 0;if(n&&r){E=e.length>0?Am.inverse(e[0])+Am.grey(e.slice(1)):Am.inverse(\" \"),x=v.length>0?\"\":Am.inverse(\" \");let R=0;for(let L of v)R>=p-I&&R<=p?x+=Am.inverse(L):x+=L,R++;v.length>0&&p===v.length&&(x+=Am.inverse(\" \"))}return rIe.useInput((R,L)=>{if(L.upArrow||L.downArrow||L.ctrl&&R===\"c\"||L.tab||L.shift&&L.tab)return;if(L.return){A&&A(t);return}let U=p,z=t,te=0;L.leftArrow?n&&U--:L.rightArrow?n&&U++:L.backspace||L.delete?p>0&&(z=t.slice(0,p-1)+t.slice(p,t.length),U--):(z=t.slice(0,p)+R+t.slice(p,t.length),U+=R.length,R.length>1&&(te=R.length)),p<0&&(U=0),p>t.length&&(U=t.length),C({cursorOffset:U,cursorWidth:te}),z!==t&&u(z)},{isActive:r}),nIe.createElement(rIe.Text,null,e?v.length>0?x:E:x)};_B.default=iIe;_B.UncontrolledTextInput=t=>{let[e,r]=Rj.useState(\"\");return nIe.createElement(iIe,Object.assign({},t,{value:e,onChange:r}))}});var lIe={};Vt(lIe,{Pad:()=>Tj});var oIe,aIe,Tj,Nj=Et(()=>{oIe=$e(ic()),aIe=$e(sn()),Tj=({length:t,active:e})=>{if(t===0)return null;let r=t>1?` ${\"-\".repeat(t-1)}`:\" \";return aIe.default.createElement(oIe.Text,{dimColor:!e},r)}});var cIe={};Vt(cIe,{ItemOptions:()=>iIt});var jB,w0,iIt,uIe=Et(()=>{jB=$e(ic()),w0=$e(sn());pQ();AQ();Nj();iIt=function({active:t,skewer:e,options:r,value:o,onChange:a,sizes:n=[]}){let u=r.filter(({label:p})=>!!p).map(({value:p})=>p),A=r.findIndex(p=>p.value===o&&p.label!=\"\");return UB(o,u,{active:t,minus:\"left\",plus:\"right\",set:a}),w0.default.createElement(w0.default.Fragment,null,r.map(({label:p},h)=>{let C=h===A,I=n[h]-1||0,v=p.replace(/[\\u001b\\u009b][[()#;?]*(?:[0-9]{1,4}(?:;[0-9]{0,4})*)?[0-9A-ORZcf-nqry=><]/g,\"\"),x=Math.max(0,I-v.length-2);return p?w0.default.createElement(jB.Box,{key:p,width:I,marginLeft:1},w0.default.createElement(jB.Text,{wrap:\"truncate\"},w0.default.createElement(vj,{active:C}),\" \",p),e?w0.default.createElement(Tj,{active:t,length:x}):null):w0.default.createElement(jB.Box,{key:`spacer-${h}`,width:I,marginLeft:1})}))}});var PIe=_((Jzt,DIe)=>{var Gj;DIe.exports=()=>(typeof Gj>\"u\"&&(Gj=Be(\"zlib\").brotliDecompressSync(Buffer.from(\"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\",\"base64\")).toString()),Gj)});var KIe=_((wJt,WIe)=>{var $j=Symbol(\"arg flag\"),Oa=class extends Error{constructor(e,r){super(e),this.name=\"ArgError\",this.code=r,Object.setPrototypeOf(this,Oa.prototype)}};function iv(t,{argv:e=process.argv.slice(2),permissive:r=!1,stopAtPositional:o=!1}={}){if(!t)throw new Oa(\"argument specification object is required\",\"ARG_CONFIG_NO_SPEC\");let a={_:[]},n={},u={};for(let A of Object.keys(t)){if(!A)throw new Oa(\"argument key cannot be an empty string\",\"ARG_CONFIG_EMPTY_KEY\");if(A[0]!==\"-\")throw new Oa(`argument key must start with '-' but found: '${A}'`,\"ARG_CONFIG_NONOPT_KEY\");if(A.length===1)throw new Oa(`argument key must have a name; singular '-' keys are not allowed: ${A}`,\"ARG_CONFIG_NONAME_KEY\");if(typeof t[A]==\"string\"){n[A]=t[A];continue}let p=t[A],h=!1;if(Array.isArray(p)&&p.length===1&&typeof p[0]==\"function\"){let[C]=p;p=(I,v,x=[])=>(x.push(C(I,v,x[x.length-1])),x),h=C===Boolean||C[$j]===!0}else if(typeof p==\"function\")h=p===Boolean||p[$j]===!0;else throw new Oa(`type missing or not a function or valid array type: ${A}`,\"ARG_CONFIG_VAD_TYPE\");if(A[1]!==\"-\"&&A.length>2)throw new Oa(`short argument keys (with a single hyphen) must have only one character: ${A}`,\"ARG_CONFIG_SHORTOPT_TOOLONG\");u[A]=[p,h]}for(let A=0,p=e.length;A<p;A++){let h=e[A];if(o&&a._.length>0){a._=a._.concat(e.slice(A));break}if(h===\"--\"){a._=a._.concat(e.slice(A+1));break}if(h.length>1&&h[0]===\"-\"){let C=h[1]===\"-\"||h.length===2?[h]:h.slice(1).split(\"\").map(I=>`-${I}`);for(let I=0;I<C.length;I++){let v=C[I],[x,E]=v[1]===\"-\"?v.split(/=(.*)/,2):[v,void 0],R=x;for(;R in n;)R=n[R];if(!(R in u))if(r){a._.push(v);continue}else throw new Oa(`unknown or unexpected option: ${x}`,\"ARG_UNKNOWN_OPTION\");let[L,U]=u[R];if(!U&&I+1<C.length)throw new Oa(`option requires argument (but was followed by another short argument): ${x}`,\"ARG_MISSING_REQUIRED_SHORTARG\");if(U)a[R]=L(!0,R,a[R]);else if(E===void 0){if(e.length<A+2||e[A+1].length>1&&e[A+1][0]===\"-\"&&!(e[A+1].match(/^-?\\d*(\\.(?=\\d))?\\d*$/)&&(L===Number||typeof BigInt<\"u\"&&L===BigInt))){let z=x===R?\"\":` (alias for ${R})`;throw new Oa(`option requires argument: ${x}${z}`,\"ARG_MISSING_REQUIRED_LONGARG\")}a[R]=L(e[A+1],R,a[R]),++A}else a[R]=L(E,R,a[R])}}else a._.push(h)}return a}iv.flag=t=>(t[$j]=!0,t);iv.COUNT=iv.flag((t,e,r)=>(r||0)+1);iv.ArgError=Oa;WIe.exports=iv});var t1e=_((KJt,e1e)=>{var iq;e1e.exports=()=>(typeof iq>\"u\"&&(iq=Be(\"zlib\").brotliDecompressSync(Buffer.from(\"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\",\"base64\")).toString()),iq)});var o1e=_((uq,Aq)=>{(function(t){uq&&typeof uq==\"object\"&&typeof Aq<\"u\"?Aq.exports=t():typeof define==\"function\"&&define.amd?define([],t):typeof window<\"u\"?window.isWindows=t():typeof global<\"u\"?global.isWindows=t():typeof self<\"u\"?self.isWindows=t():this.isWindows=t()})(function(){\"use strict\";return function(){return process&&(process.platform===\"win32\"||/^(msys|cygwin)$/.test(process.env.OSTYPE))}})});var u1e=_((YXt,c1e)=>{\"use strict\";fq.ifExists=t1t;var qC=Be(\"util\"),sc=Be(\"path\"),a1e=o1e(),ZIt=/^#!\\s*(?:\\/usr\\/bin\\/env)?\\s*([^ \\t]+)(.*)$/,$It={createPwshFile:!0,createCmdFile:a1e(),fs:Be(\"fs\")},e1t=new Map([[\".js\",\"node\"],[\".cjs\",\"node\"],[\".mjs\",\"node\"],[\".cmd\",\"cmd\"],[\".bat\",\"cmd\"],[\".ps1\",\"pwsh\"],[\".sh\",\"sh\"]]);function l1e(t){let e={...$It,...t},r=e.fs;return e.fs_={chmod:r.chmod?qC.promisify(r.chmod):async()=>{},mkdir:qC.promisify(r.mkdir),readFile:qC.promisify(r.readFile),stat:qC.promisify(r.stat),unlink:qC.promisify(r.unlink),writeFile:qC.promisify(r.writeFile)},e}async function fq(t,e,r){let o=l1e(r);await o.fs_.stat(t),await n1t(t,e,o)}function t1t(t,e,r){return fq(t,e,r).catch(()=>{})}function r1t(t,e){return e.fs_.unlink(t).catch(()=>{})}async function n1t(t,e,r){let o=await l1t(t,r);return await i1t(e,r),s1t(t,e,o,r)}function i1t(t,e){return e.fs_.mkdir(sc.dirname(t),{recursive:!0})}function s1t(t,e,r,o){let a=l1e(o),n=[{generator:A1t,extension:\"\"}];return a.createCmdFile&&n.push({generator:u1t,extension:\".cmd\"}),a.createPwshFile&&n.push({generator:f1t,extension:\".ps1\"}),Promise.all(n.map(u=>c1t(t,e+u.extension,r,u.generator,a)))}function o1t(t,e){return r1t(t,e)}function a1t(t,e){return p1t(t,e)}async function l1t(t,e){let a=(await e.fs_.readFile(t,\"utf8\")).trim().split(/\\r*\\n/)[0].match(ZIt);if(!a){let n=sc.extname(t).toLowerCase();return{program:e1t.get(n)||null,additionalArgs:\"\"}}return{program:a[1],additionalArgs:a[2]}}async function c1t(t,e,r,o,a){let n=a.preserveSymlinks?\"--preserve-symlinks\":\"\",u=[r.additionalArgs,n].filter(A=>A).join(\" \");return a=Object.assign({},a,{prog:r.program,args:u}),await o1t(e,a),await a.fs_.writeFile(e,o(t,e,a),\"utf8\"),a1t(e,a)}function u1t(t,e,r){let a=sc.relative(sc.dirname(e),t).split(\"/\").join(\"\\\\\"),n=sc.isAbsolute(a)?`\"${a}\"`:`\"%~dp0\\\\${a}\"`,u,A=r.prog,p=r.args||\"\",h=pq(r.nodePath).win32;A?(u=`\"%~dp0\\\\${A}.exe\"`,a=n):(A=n,p=\"\",a=\"\");let C=r.progArgs?`${r.progArgs.join(\" \")} `:\"\",I=h?`@SET NODE_PATH=${h}\\r\n`:\"\";return u?I+=`@IF EXIST ${u} (\\r\n  ${u} ${p} ${a} ${C}%*\\r\n) ELSE (\\r\n  @SETLOCAL\\r\n  @SET PATHEXT=%PATHEXT:;.JS;=;%\\r\n  ${A} ${p} ${a} ${C}%*\\r\n)\\r\n`:I+=`@${A} ${p} ${a} ${C}%*\\r\n`,I}function A1t(t,e,r){let o=sc.relative(sc.dirname(e),t),a=r.prog&&r.prog.split(\"\\\\\").join(\"/\"),n;o=o.split(\"\\\\\").join(\"/\");let u=sc.isAbsolute(o)?`\"${o}\"`:`\"$basedir/${o}\"`,A=r.args||\"\",p=pq(r.nodePath).posix;a?(n=`\"$basedir/${r.prog}\"`,o=u):(a=u,A=\"\",o=\"\");let h=r.progArgs?`${r.progArgs.join(\" \")} `:\"\",C=`#!/bin/sh\nbasedir=$(dirname \"$(echo \"$0\" | sed -e 's,\\\\\\\\,/,g')\")\n\ncase \\`uname\\` in\n    *CYGWIN*) basedir=\\`cygpath -w \"$basedir\"\\`;;\nesac\n\n`,I=r.nodePath?`export NODE_PATH=\"${p}\"\n`:\"\";return n?C+=`${I}if [ -x ${n} ]; then\n  exec ${n} ${A} ${o} ${h}\"$@\"\nelse\n  exec ${a} ${A} ${o} ${h}\"$@\"\nfi\n`:C+=`${I}${a} ${A} ${o} ${h}\"$@\"\nexit $?\n`,C}function f1t(t,e,r){let o=sc.relative(sc.dirname(e),t),a=r.prog&&r.prog.split(\"\\\\\").join(\"/\"),n=a&&`\"${a}$exe\"`,u;o=o.split(\"\\\\\").join(\"/\");let A=sc.isAbsolute(o)?`\"${o}\"`:`\"$basedir/${o}\"`,p=r.args||\"\",h=pq(r.nodePath),C=h.win32,I=h.posix;n?(u=`\"$basedir/${r.prog}$exe\"`,o=A):(n=A,p=\"\",o=\"\");let v=r.progArgs?`${r.progArgs.join(\" \")} `:\"\",x=`#!/usr/bin/env pwsh\n$basedir=Split-Path $MyInvocation.MyCommand.Definition -Parent\n\n$exe=\"\"\n${r.nodePath?`$env_node_path=$env:NODE_PATH\n$env:NODE_PATH=\"${C}\"\n`:\"\"}if ($PSVersionTable.PSVersion -lt \"6.0\" -or $IsWindows) {\n  # Fix case when both the Windows and Linux builds of Node\n  # are installed in the same directory\n  $exe=\".exe\"\n}`;return r.nodePath&&(x+=` else {\n  $env:NODE_PATH=\"${I}\"\n}`),u?x+=`\n$ret=0\nif (Test-Path ${u}) {\n  # Support pipeline input\n  if ($MyInvocation.ExpectingInput) {\n    $input | & ${u} ${p} ${o} ${v}$args\n  } else {\n    & ${u} ${p} ${o} ${v}$args\n  }\n  $ret=$LASTEXITCODE\n} else {\n  # Support pipeline input\n  if ($MyInvocation.ExpectingInput) {\n    $input | & ${n} ${p} ${o} ${v}$args\n  } else {\n    & ${n} ${p} ${o} ${v}$args\n  }\n  $ret=$LASTEXITCODE\n}\n${r.nodePath?`$env:NODE_PATH=$env_node_path\n`:\"\"}exit $ret\n`:x+=`\n# Support pipeline input\nif ($MyInvocation.ExpectingInput) {\n  $input | & ${n} ${p} ${o} ${v}$args\n} else {\n  & ${n} ${p} ${o} ${v}$args\n}\n${r.nodePath?`$env:NODE_PATH=$env_node_path\n`:\"\"}exit $LASTEXITCODE\n`,x}function p1t(t,e){return e.fs_.chmod(t,493)}function pq(t){if(!t)return{win32:\"\",posix:\"\"};let e=typeof t==\"string\"?t.split(sc.delimiter):Array.from(t),r={};for(let o=0;o<e.length;o++){let a=e[o].split(\"/\").join(\"\\\\\"),n=a1e()?e[o].split(\"\\\\\").join(\"/\").replace(/^([^:\\\\/]*):/,(u,A)=>`/mnt/${A.toLowerCase()}`):e[o];r.win32=r.win32?`${r.win32};${a}`:a,r.posix=r.posix?`${r.posix}:${n}`:n,r[o]={win32:a,posix:n}}return r}c1e.exports=fq});var bq=_((p$t,F1e)=>{F1e.exports=Be(\"stream\")});var L1e=_((h$t,N1e)=>{\"use strict\";function R1e(t,e){var r=Object.keys(t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(t);e&&(o=o.filter(function(a){return Object.getOwnPropertyDescriptor(t,a).enumerable})),r.push.apply(r,o)}return r}function O1t(t){for(var e=1;e<arguments.length;e++){var r=arguments[e]!=null?arguments[e]:{};e%2?R1e(Object(r),!0).forEach(function(o){M1t(t,o,r[o])}):Object.getOwnPropertyDescriptors?Object.defineProperties(t,Object.getOwnPropertyDescriptors(r)):R1e(Object(r)).forEach(function(o){Object.defineProperty(t,o,Object.getOwnPropertyDescriptor(r,o))})}return t}function M1t(t,e,r){return e in t?Object.defineProperty(t,e,{value:r,enumerable:!0,configurable:!0,writable:!0}):t[e]=r,t}function U1t(t,e){if(!(t instanceof e))throw new TypeError(\"Cannot call a class as a function\")}function T1e(t,e){for(var r=0;r<e.length;r++){var o=e[r];o.enumerable=o.enumerable||!1,o.configurable=!0,\"value\"in o&&(o.writable=!0),Object.defineProperty(t,o.key,o)}}function _1t(t,e,r){return e&&T1e(t.prototype,e),r&&T1e(t,r),t}var H1t=Be(\"buffer\"),QQ=H1t.Buffer,j1t=Be(\"util\"),xq=j1t.inspect,q1t=xq&&xq.custom||\"inspect\";function G1t(t,e,r){QQ.prototype.copy.call(t,e,r)}N1e.exports=function(){function t(){U1t(this,t),this.head=null,this.tail=null,this.length=0}return _1t(t,[{key:\"push\",value:function(r){var o={data:r,next:null};this.length>0?this.tail.next=o:this.head=o,this.tail=o,++this.length}},{key:\"unshift\",value:function(r){var o={data:r,next:this.head};this.length===0&&(this.tail=o),this.head=o,++this.length}},{key:\"shift\",value:function(){if(this.length!==0){var r=this.head.data;return this.length===1?this.head=this.tail=null:this.head=this.head.next,--this.length,r}}},{key:\"clear\",value:function(){this.head=this.tail=null,this.length=0}},{key:\"join\",value:function(r){if(this.length===0)return\"\";for(var o=this.head,a=\"\"+o.data;o=o.next;)a+=r+o.data;return a}},{key:\"concat\",value:function(r){if(this.length===0)return QQ.alloc(0);for(var o=QQ.allocUnsafe(r>>>0),a=this.head,n=0;a;)G1t(a.data,o,n),n+=a.data.length,a=a.next;return o}},{key:\"consume\",value:function(r,o){var a;return r<this.head.data.length?(a=this.head.data.slice(0,r),this.head.data=this.head.data.slice(r)):r===this.head.data.length?a=this.shift():a=o?this._getString(r):this._getBuffer(r),a}},{key:\"first\",value:function(){return this.head.data}},{key:\"_getString\",value:function(r){var o=this.head,a=1,n=o.data;for(r-=n.length;o=o.next;){var u=o.data,A=r>u.length?u.length:r;if(A===u.length?n+=u:n+=u.slice(0,r),r-=A,r===0){A===u.length?(++a,o.next?this.head=o.next:this.head=this.tail=null):(this.head=o,o.data=u.slice(A));break}++a}return this.length-=a,n}},{key:\"_getBuffer\",value:function(r){var o=QQ.allocUnsafe(r),a=this.head,n=1;for(a.data.copy(o),r-=a.data.length;a=a.next;){var u=a.data,A=r>u.length?u.length:r;if(u.copy(o,o.length-r,0,A),r-=A,r===0){A===u.length?(++n,a.next?this.head=a.next:this.head=this.tail=null):(this.head=a,a.data=u.slice(A));break}++n}return this.length-=n,o}},{key:q1t,value:function(r,o){return xq(this,O1t({},o,{depth:0,customInspect:!1}))}}]),t}()});var Qq=_((g$t,M1e)=>{\"use strict\";function Y1t(t,e){var r=this,o=this._readableState&&this._readableState.destroyed,a=this._writableState&&this._writableState.destroyed;return o||a?(e?e(t):t&&(this._writableState?this._writableState.errorEmitted||(this._writableState.errorEmitted=!0,process.nextTick(kq,this,t)):process.nextTick(kq,this,t)),this):(this._readableState&&(this._readableState.destroyed=!0),this._writableState&&(this._writableState.destroyed=!0),this._destroy(t||null,function(n){!e&&n?r._writableState?r._writableState.errorEmitted?process.nextTick(FQ,r):(r._writableState.errorEmitted=!0,process.nextTick(O1e,r,n)):process.nextTick(O1e,r,n):e?(process.nextTick(FQ,r),e(n)):process.nextTick(FQ,r)}),this)}function O1e(t,e){kq(t,e),FQ(t)}function FQ(t){t._writableState&&!t._writableState.emitClose||t._readableState&&!t._readableState.emitClose||t.emit(\"close\")}function W1t(){this._readableState&&(this._readableState.destroyed=!1,this._readableState.reading=!1,this._readableState.ended=!1,this._readableState.endEmitted=!1),this._writableState&&(this._writableState.destroyed=!1,this._writableState.ended=!1,this._writableState.ending=!1,this._writableState.finalCalled=!1,this._writableState.prefinished=!1,this._writableState.finished=!1,this._writableState.errorEmitted=!1)}function kq(t,e){t.emit(\"error\",e)}function K1t(t,e){var r=t._readableState,o=t._writableState;r&&r.autoDestroy||o&&o.autoDestroy?t.destroy(e):t.emit(\"error\",e)}M1e.exports={destroy:Y1t,undestroy:W1t,errorOrDestroy:K1t}});var x0=_((d$t,H1e)=>{\"use strict\";var _1e={};function ac(t,e,r){r||(r=Error);function o(n,u,A){return typeof e==\"string\"?e:e(n,u,A)}class a extends r{constructor(u,A,p){super(o(u,A,p))}}a.prototype.name=r.name,a.prototype.code=t,_1e[t]=a}function U1e(t,e){if(Array.isArray(t)){let r=t.length;return t=t.map(o=>String(o)),r>2?`one of ${e} ${t.slice(0,r-1).join(\", \")}, or `+t[r-1]:r===2?`one of ${e} ${t[0]} or ${t[1]}`:`of ${e} ${t[0]}`}else return`of ${e} ${String(t)}`}function V1t(t,e,r){return t.substr(!r||r<0?0:+r,e.length)===e}function z1t(t,e,r){return(r===void 0||r>t.length)&&(r=t.length),t.substring(r-e.length,r)===e}function J1t(t,e,r){return typeof r!=\"number\"&&(r=0),r+e.length>t.length?!1:t.indexOf(e,r)!==-1}ac(\"ERR_INVALID_OPT_VALUE\",function(t,e){return'The value \"'+e+'\" is invalid for option \"'+t+'\"'},TypeError);ac(\"ERR_INVALID_ARG_TYPE\",function(t,e,r){let o;typeof e==\"string\"&&V1t(e,\"not \")?(o=\"must not be\",e=e.replace(/^not /,\"\")):o=\"must be\";let a;if(z1t(t,\" argument\"))a=`The ${t} ${o} ${U1e(e,\"type\")}`;else{let n=J1t(t,\".\")?\"property\":\"argument\";a=`The \"${t}\" ${n} ${o} ${U1e(e,\"type\")}`}return a+=`. Received type ${typeof r}`,a},TypeError);ac(\"ERR_STREAM_PUSH_AFTER_EOF\",\"stream.push() after EOF\");ac(\"ERR_METHOD_NOT_IMPLEMENTED\",function(t){return\"The \"+t+\" method is not implemented\"});ac(\"ERR_STREAM_PREMATURE_CLOSE\",\"Premature close\");ac(\"ERR_STREAM_DESTROYED\",function(t){return\"Cannot call \"+t+\" after a stream was destroyed\"});ac(\"ERR_MULTIPLE_CALLBACK\",\"Callback called multiple times\");ac(\"ERR_STREAM_CANNOT_PIPE\",\"Cannot pipe, not readable\");ac(\"ERR_STREAM_WRITE_AFTER_END\",\"write after end\");ac(\"ERR_STREAM_NULL_VALUES\",\"May not write null values to stream\",TypeError);ac(\"ERR_UNKNOWN_ENCODING\",function(t){return\"Unknown encoding: \"+t},TypeError);ac(\"ERR_STREAM_UNSHIFT_AFTER_END_EVENT\",\"stream.unshift() after end event\");H1e.exports.codes=_1e});var Fq=_((m$t,j1e)=>{\"use strict\";var X1t=x0().codes.ERR_INVALID_OPT_VALUE;function Z1t(t,e,r){return t.highWaterMark!=null?t.highWaterMark:e?t[r]:null}function $1t(t,e,r,o){var a=Z1t(e,o,r);if(a!=null){if(!(isFinite(a)&&Math.floor(a)===a)||a<0){var n=o?r:\"highWaterMark\";throw new X1t(n,a)}return Math.floor(a)}return t.objectMode?16:16*1024}j1e.exports={getHighWaterMark:$1t}});var q1e=_((y$t,Rq)=>{typeof Object.create==\"function\"?Rq.exports=function(e,r){r&&(e.super_=r,e.prototype=Object.create(r.prototype,{constructor:{value:e,enumerable:!1,writable:!0,configurable:!0}}))}:Rq.exports=function(e,r){if(r){e.super_=r;var o=function(){};o.prototype=r.prototype,e.prototype=new o,e.prototype.constructor=e}}});var k0=_((E$t,Nq)=>{try{if(Tq=Be(\"util\"),typeof Tq.inherits!=\"function\")throw\"\";Nq.exports=Tq.inherits}catch{Nq.exports=q1e()}var Tq});var Y1e=_((C$t,G1e)=>{G1e.exports=Be(\"util\").deprecate});var Mq=_((w$t,X1e)=>{\"use strict\";X1e.exports=Ri;function K1e(t){var e=this;this.next=null,this.entry=null,this.finish=function(){P2t(e,t)}}var VC;Ri.WritableState=mv;var e2t={deprecate:Y1e()},V1e=bq(),TQ=Be(\"buffer\").Buffer,t2t=global.Uint8Array||function(){};function r2t(t){return TQ.from(t)}function n2t(t){return TQ.isBuffer(t)||t instanceof t2t}var Oq=Qq(),i2t=Fq(),s2t=i2t.getHighWaterMark,Q0=x0().codes,o2t=Q0.ERR_INVALID_ARG_TYPE,a2t=Q0.ERR_METHOD_NOT_IMPLEMENTED,l2t=Q0.ERR_MULTIPLE_CALLBACK,c2t=Q0.ERR_STREAM_CANNOT_PIPE,u2t=Q0.ERR_STREAM_DESTROYED,A2t=Q0.ERR_STREAM_NULL_VALUES,f2t=Q0.ERR_STREAM_WRITE_AFTER_END,p2t=Q0.ERR_UNKNOWN_ENCODING,zC=Oq.errorOrDestroy;k0()(Ri,V1e);function h2t(){}function mv(t,e,r){VC=VC||ym(),t=t||{},typeof r!=\"boolean\"&&(r=e instanceof VC),this.objectMode=!!t.objectMode,r&&(this.objectMode=this.objectMode||!!t.writableObjectMode),this.highWaterMark=s2t(this,t,\"writableHighWaterMark\",r),this.finalCalled=!1,this.needDrain=!1,this.ending=!1,this.ended=!1,this.finished=!1,this.destroyed=!1;var o=t.decodeStrings===!1;this.decodeStrings=!o,this.defaultEncoding=t.defaultEncoding||\"utf8\",this.length=0,this.writing=!1,this.corked=0,this.sync=!0,this.bufferProcessing=!1,this.onwrite=function(a){w2t(e,a)},this.writecb=null,this.writelen=0,this.bufferedRequest=null,this.lastBufferedRequest=null,this.pendingcb=0,this.prefinished=!1,this.errorEmitted=!1,this.emitClose=t.emitClose!==!1,this.autoDestroy=!!t.autoDestroy,this.bufferedRequestCount=0,this.corkedRequestsFree=new K1e(this)}mv.prototype.getBuffer=function(){for(var e=this.bufferedRequest,r=[];e;)r.push(e),e=e.next;return r};(function(){try{Object.defineProperty(mv.prototype,\"buffer\",{get:e2t.deprecate(function(){return this.getBuffer()},\"_writableState.buffer is deprecated. Use _writableState.getBuffer instead.\",\"DEP0003\")})}catch{}})();var RQ;typeof Symbol==\"function\"&&Symbol.hasInstance&&typeof Function.prototype[Symbol.hasInstance]==\"function\"?(RQ=Function.prototype[Symbol.hasInstance],Object.defineProperty(Ri,Symbol.hasInstance,{value:function(e){return RQ.call(this,e)?!0:this!==Ri?!1:e&&e._writableState instanceof mv}})):RQ=function(e){return e instanceof this};function Ri(t){VC=VC||ym();var e=this instanceof VC;if(!e&&!RQ.call(Ri,this))return new Ri(t);this._writableState=new mv(t,this,e),this.writable=!0,t&&(typeof t.write==\"function\"&&(this._write=t.write),typeof t.writev==\"function\"&&(this._writev=t.writev),typeof t.destroy==\"function\"&&(this._destroy=t.destroy),typeof t.final==\"function\"&&(this._final=t.final)),V1e.call(this)}Ri.prototype.pipe=function(){zC(this,new c2t)};function g2t(t,e){var r=new f2t;zC(t,r),process.nextTick(e,r)}function d2t(t,e,r,o){var a;return r===null?a=new A2t:typeof r!=\"string\"&&!e.objectMode&&(a=new o2t(\"chunk\",[\"string\",\"Buffer\"],r)),a?(zC(t,a),process.nextTick(o,a),!1):!0}Ri.prototype.write=function(t,e,r){var o=this._writableState,a=!1,n=!o.objectMode&&n2t(t);return n&&!TQ.isBuffer(t)&&(t=r2t(t)),typeof e==\"function\"&&(r=e,e=null),n?e=\"buffer\":e||(e=o.defaultEncoding),typeof r!=\"function\"&&(r=h2t),o.ending?g2t(this,r):(n||d2t(this,o,t,r))&&(o.pendingcb++,a=y2t(this,o,n,t,e,r)),a};Ri.prototype.cork=function(){this._writableState.corked++};Ri.prototype.uncork=function(){var t=this._writableState;t.corked&&(t.corked--,!t.writing&&!t.corked&&!t.bufferProcessing&&t.bufferedRequest&&z1e(this,t))};Ri.prototype.setDefaultEncoding=function(e){if(typeof e==\"string\"&&(e=e.toLowerCase()),!([\"hex\",\"utf8\",\"utf-8\",\"ascii\",\"binary\",\"base64\",\"ucs2\",\"ucs-2\",\"utf16le\",\"utf-16le\",\"raw\"].indexOf((e+\"\").toLowerCase())>-1))throw new p2t(e);return this._writableState.defaultEncoding=e,this};Object.defineProperty(Ri.prototype,\"writableBuffer\",{enumerable:!1,get:function(){return this._writableState&&this._writableState.getBuffer()}});function m2t(t,e,r){return!t.objectMode&&t.decodeStrings!==!1&&typeof e==\"string\"&&(e=TQ.from(e,r)),e}Object.defineProperty(Ri.prototype,\"writableHighWaterMark\",{enumerable:!1,get:function(){return this._writableState.highWaterMark}});function y2t(t,e,r,o,a,n){if(!r){var u=m2t(e,o,a);o!==u&&(r=!0,a=\"buffer\",o=u)}var A=e.objectMode?1:o.length;e.length+=A;var p=e.length<e.highWaterMark;if(p||(e.needDrain=!0),e.writing||e.corked){var h=e.lastBufferedRequest;e.lastBufferedRequest={chunk:o,encoding:a,isBuf:r,callback:n,next:null},h?h.next=e.lastBufferedRequest:e.bufferedRequest=e.lastBufferedRequest,e.bufferedRequestCount+=1}else Lq(t,e,!1,A,o,a,n);return p}function Lq(t,e,r,o,a,n,u){e.writelen=o,e.writecb=u,e.writing=!0,e.sync=!0,e.destroyed?e.onwrite(new u2t(\"write\")):r?t._writev(a,e.onwrite):t._write(a,n,e.onwrite),e.sync=!1}function E2t(t,e,r,o,a){--e.pendingcb,r?(process.nextTick(a,o),process.nextTick(dv,t,e),t._writableState.errorEmitted=!0,zC(t,o)):(a(o),t._writableState.errorEmitted=!0,zC(t,o),dv(t,e))}function C2t(t){t.writing=!1,t.writecb=null,t.length-=t.writelen,t.writelen=0}function w2t(t,e){var r=t._writableState,o=r.sync,a=r.writecb;if(typeof a!=\"function\")throw new l2t;if(C2t(r),e)E2t(t,r,o,e,a);else{var n=J1e(r)||t.destroyed;!n&&!r.corked&&!r.bufferProcessing&&r.bufferedRequest&&z1e(t,r),o?process.nextTick(W1e,t,r,n,a):W1e(t,r,n,a)}}function W1e(t,e,r,o){r||I2t(t,e),e.pendingcb--,o(),dv(t,e)}function I2t(t,e){e.length===0&&e.needDrain&&(e.needDrain=!1,t.emit(\"drain\"))}function z1e(t,e){e.bufferProcessing=!0;var r=e.bufferedRequest;if(t._writev&&r&&r.next){var o=e.bufferedRequestCount,a=new Array(o),n=e.corkedRequestsFree;n.entry=r;for(var u=0,A=!0;r;)a[u]=r,r.isBuf||(A=!1),r=r.next,u+=1;a.allBuffers=A,Lq(t,e,!0,e.length,a,\"\",n.finish),e.pendingcb++,e.lastBufferedRequest=null,n.next?(e.corkedRequestsFree=n.next,n.next=null):e.corkedRequestsFree=new K1e(e),e.bufferedRequestCount=0}else{for(;r;){var p=r.chunk,h=r.encoding,C=r.callback,I=e.objectMode?1:p.length;if(Lq(t,e,!1,I,p,h,C),r=r.next,e.bufferedRequestCount--,e.writing)break}r===null&&(e.lastBufferedRequest=null)}e.bufferedRequest=r,e.bufferProcessing=!1}Ri.prototype._write=function(t,e,r){r(new a2t(\"_write()\"))};Ri.prototype._writev=null;Ri.prototype.end=function(t,e,r){var o=this._writableState;return typeof t==\"function\"?(r=t,t=null,e=null):typeof e==\"function\"&&(r=e,e=null),t!=null&&this.write(t,e),o.corked&&(o.corked=1,this.uncork()),o.ending||D2t(this,o,r),this};Object.defineProperty(Ri.prototype,\"writableLength\",{enumerable:!1,get:function(){return this._writableState.length}});function J1e(t){return t.ending&&t.length===0&&t.bufferedRequest===null&&!t.finished&&!t.writing}function B2t(t,e){t._final(function(r){e.pendingcb--,r&&zC(t,r),e.prefinished=!0,t.emit(\"prefinish\"),dv(t,e)})}function v2t(t,e){!e.prefinished&&!e.finalCalled&&(typeof t._final==\"function\"&&!e.destroyed?(e.pendingcb++,e.finalCalled=!0,process.nextTick(B2t,t,e)):(e.prefinished=!0,t.emit(\"prefinish\")))}function dv(t,e){var r=J1e(e);if(r&&(v2t(t,e),e.pendingcb===0&&(e.finished=!0,t.emit(\"finish\"),e.autoDestroy))){var o=t._readableState;(!o||o.autoDestroy&&o.endEmitted)&&t.destroy()}return r}function D2t(t,e,r){e.ending=!0,dv(t,e),r&&(e.finished?process.nextTick(r):t.once(\"finish\",r)),e.ended=!0,t.writable=!1}function P2t(t,e,r){var o=t.entry;for(t.entry=null;o;){var a=o.callback;e.pendingcb--,a(r),o=o.next}e.corkedRequestsFree.next=t}Object.defineProperty(Ri.prototype,\"destroyed\",{enumerable:!1,get:function(){return this._writableState===void 0?!1:this._writableState.destroyed},set:function(e){!this._writableState||(this._writableState.destroyed=e)}});Ri.prototype.destroy=Oq.destroy;Ri.prototype._undestroy=Oq.undestroy;Ri.prototype._destroy=function(t,e){e(t)}});var ym=_((I$t,$1e)=>{\"use strict\";var S2t=Object.keys||function(t){var e=[];for(var r in t)e.push(r);return e};$1e.exports=yA;var Z1e=Hq(),_q=Mq();k0()(yA,Z1e);for(Uq=S2t(_q.prototype),NQ=0;NQ<Uq.length;NQ++)LQ=Uq[NQ],yA.prototype[LQ]||(yA.prototype[LQ]=_q.prototype[LQ]);var Uq,LQ,NQ;function yA(t){if(!(this instanceof yA))return new yA(t);Z1e.call(this,t),_q.call(this,t),this.allowHalfOpen=!0,t&&(t.readable===!1&&(this.readable=!1),t.writable===!1&&(this.writable=!1),t.allowHalfOpen===!1&&(this.allowHalfOpen=!1,this.once(\"end\",b2t)))}Object.defineProperty(yA.prototype,\"writableHighWaterMark\",{enumerable:!1,get:function(){return this._writableState.highWaterMark}});Object.defineProperty(yA.prototype,\"writableBuffer\",{enumerable:!1,get:function(){return this._writableState&&this._writableState.getBuffer()}});Object.defineProperty(yA.prototype,\"writableLength\",{enumerable:!1,get:function(){return this._writableState.length}});function b2t(){this._writableState.ended||process.nextTick(x2t,this)}function x2t(t){t.end()}Object.defineProperty(yA.prototype,\"destroyed\",{enumerable:!1,get:function(){return this._readableState===void 0||this._writableState===void 0?!1:this._readableState.destroyed&&this._writableState.destroyed},set:function(e){this._readableState===void 0||this._writableState===void 0||(this._readableState.destroyed=e,this._writableState.destroyed=e)}})});var r2e=_((jq,t2e)=>{var OQ=Be(\"buffer\"),rp=OQ.Buffer;function e2e(t,e){for(var r in t)e[r]=t[r]}rp.from&&rp.alloc&&rp.allocUnsafe&&rp.allocUnsafeSlow?t2e.exports=OQ:(e2e(OQ,jq),jq.Buffer=JC);function JC(t,e,r){return rp(t,e,r)}e2e(rp,JC);JC.from=function(t,e,r){if(typeof t==\"number\")throw new TypeError(\"Argument must not be a number\");return rp(t,e,r)};JC.alloc=function(t,e,r){if(typeof t!=\"number\")throw new TypeError(\"Argument must be a number\");var o=rp(t);return e!==void 0?typeof r==\"string\"?o.fill(e,r):o.fill(e):o.fill(0),o};JC.allocUnsafe=function(t){if(typeof t!=\"number\")throw new TypeError(\"Argument must be a number\");return rp(t)};JC.allocUnsafeSlow=function(t){if(typeof t!=\"number\")throw new TypeError(\"Argument must be a number\");return OQ.SlowBuffer(t)}});var Yq=_(i2e=>{\"use strict\";var Gq=r2e().Buffer,n2e=Gq.isEncoding||function(t){switch(t=\"\"+t,t&&t.toLowerCase()){case\"hex\":case\"utf8\":case\"utf-8\":case\"ascii\":case\"binary\":case\"base64\":case\"ucs2\":case\"ucs-2\":case\"utf16le\":case\"utf-16le\":case\"raw\":return!0;default:return!1}};function k2t(t){if(!t)return\"utf8\";for(var e;;)switch(t){case\"utf8\":case\"utf-8\":return\"utf8\";case\"ucs2\":case\"ucs-2\":case\"utf16le\":case\"utf-16le\":return\"utf16le\";case\"latin1\":case\"binary\":return\"latin1\";case\"base64\":case\"ascii\":case\"hex\":return t;default:if(e)return;t=(\"\"+t).toLowerCase(),e=!0}}function Q2t(t){var e=k2t(t);if(typeof e!=\"string\"&&(Gq.isEncoding===n2e||!n2e(t)))throw new Error(\"Unknown encoding: \"+t);return e||t}i2e.StringDecoder=yv;function yv(t){this.encoding=Q2t(t);var e;switch(this.encoding){case\"utf16le\":this.text=O2t,this.end=M2t,e=4;break;case\"utf8\":this.fillLast=T2t,e=4;break;case\"base64\":this.text=U2t,this.end=_2t,e=3;break;default:this.write=H2t,this.end=j2t;return}this.lastNeed=0,this.lastTotal=0,this.lastChar=Gq.allocUnsafe(e)}yv.prototype.write=function(t){if(t.length===0)return\"\";var e,r;if(this.lastNeed){if(e=this.fillLast(t),e===void 0)return\"\";r=this.lastNeed,this.lastNeed=0}else r=0;return r<t.length?e?e+this.text(t,r):this.text(t,r):e||\"\"};yv.prototype.end=L2t;yv.prototype.text=N2t;yv.prototype.fillLast=function(t){if(this.lastNeed<=t.length)return t.copy(this.lastChar,this.lastTotal-this.lastNeed,0,this.lastNeed),this.lastChar.toString(this.encoding,0,this.lastTotal);t.copy(this.lastChar,this.lastTotal-this.lastNeed,0,t.length),this.lastNeed-=t.length};function qq(t){return t<=127?0:t>>5===6?2:t>>4===14?3:t>>3===30?4:t>>6===2?-1:-2}function F2t(t,e,r){var o=e.length-1;if(o<r)return 0;var a=qq(e[o]);return a>=0?(a>0&&(t.lastNeed=a-1),a):--o<r||a===-2?0:(a=qq(e[o]),a>=0?(a>0&&(t.lastNeed=a-2),a):--o<r||a===-2?0:(a=qq(e[o]),a>=0?(a>0&&(a===2?a=0:t.lastNeed=a-3),a):0))}function R2t(t,e,r){if((e[0]&192)!==128)return t.lastNeed=0,\"\\uFFFD\";if(t.lastNeed>1&&e.length>1){if((e[1]&192)!==128)return t.lastNeed=1,\"\\uFFFD\";if(t.lastNeed>2&&e.length>2&&(e[2]&192)!==128)return t.lastNeed=2,\"\\uFFFD\"}}function T2t(t){var e=this.lastTotal-this.lastNeed,r=R2t(this,t,e);if(r!==void 0)return r;if(this.lastNeed<=t.length)return t.copy(this.lastChar,e,0,this.lastNeed),this.lastChar.toString(this.encoding,0,this.lastTotal);t.copy(this.lastChar,e,0,t.length),this.lastNeed-=t.length}function N2t(t,e){var r=F2t(this,t,e);if(!this.lastNeed)return t.toString(\"utf8\",e);this.lastTotal=r;var o=t.length-(r-this.lastNeed);return t.copy(this.lastChar,0,o),t.toString(\"utf8\",e,o)}function L2t(t){var e=t&&t.length?this.write(t):\"\";return this.lastNeed?e+\"\\uFFFD\":e}function O2t(t,e){if((t.length-e)%2===0){var r=t.toString(\"utf16le\",e);if(r){var o=r.charCodeAt(r.length-1);if(o>=55296&&o<=56319)return this.lastNeed=2,this.lastTotal=4,this.lastChar[0]=t[t.length-2],this.lastChar[1]=t[t.length-1],r.slice(0,-1)}return r}return this.lastNeed=1,this.lastTotal=2,this.lastChar[0]=t[t.length-1],t.toString(\"utf16le\",e,t.length-1)}function M2t(t){var e=t&&t.length?this.write(t):\"\";if(this.lastNeed){var r=this.lastTotal-this.lastNeed;return e+this.lastChar.toString(\"utf16le\",0,r)}return e}function U2t(t,e){var r=(t.length-e)%3;return r===0?t.toString(\"base64\",e):(this.lastNeed=3-r,this.lastTotal=3,r===1?this.lastChar[0]=t[t.length-1]:(this.lastChar[0]=t[t.length-2],this.lastChar[1]=t[t.length-1]),t.toString(\"base64\",e,t.length-r))}function _2t(t){var e=t&&t.length?this.write(t):\"\";return this.lastNeed?e+this.lastChar.toString(\"base64\",0,3-this.lastNeed):e}function H2t(t){return t.toString(this.encoding)}function j2t(t){return t&&t.length?this.write(t):\"\"}});var MQ=_((v$t,a2e)=>{\"use strict\";var s2e=x0().codes.ERR_STREAM_PREMATURE_CLOSE;function q2t(t){var e=!1;return function(){if(!e){e=!0;for(var r=arguments.length,o=new Array(r),a=0;a<r;a++)o[a]=arguments[a];t.apply(this,o)}}}function G2t(){}function Y2t(t){return t.setHeader&&typeof t.abort==\"function\"}function o2e(t,e,r){if(typeof e==\"function\")return o2e(t,null,e);e||(e={}),r=q2t(r||G2t);var o=e.readable||e.readable!==!1&&t.readable,a=e.writable||e.writable!==!1&&t.writable,n=function(){t.writable||A()},u=t._writableState&&t._writableState.finished,A=function(){a=!1,u=!0,o||r.call(t)},p=t._readableState&&t._readableState.endEmitted,h=function(){o=!1,p=!0,a||r.call(t)},C=function(E){r.call(t,E)},I=function(){var E;if(o&&!p)return(!t._readableState||!t._readableState.ended)&&(E=new s2e),r.call(t,E);if(a&&!u)return(!t._writableState||!t._writableState.ended)&&(E=new s2e),r.call(t,E)},v=function(){t.req.on(\"finish\",A)};return Y2t(t)?(t.on(\"complete\",A),t.on(\"abort\",I),t.req?v():t.on(\"request\",v)):a&&!t._writableState&&(t.on(\"end\",n),t.on(\"close\",n)),t.on(\"end\",h),t.on(\"finish\",A),e.error!==!1&&t.on(\"error\",C),t.on(\"close\",I),function(){t.removeListener(\"complete\",A),t.removeListener(\"abort\",I),t.removeListener(\"request\",v),t.req&&t.req.removeListener(\"finish\",A),t.removeListener(\"end\",n),t.removeListener(\"close\",n),t.removeListener(\"finish\",A),t.removeListener(\"end\",h),t.removeListener(\"error\",C),t.removeListener(\"close\",I)}}a2e.exports=o2e});var c2e=_((D$t,l2e)=>{\"use strict\";var UQ;function F0(t,e,r){return e in t?Object.defineProperty(t,e,{value:r,enumerable:!0,configurable:!0,writable:!0}):t[e]=r,t}var W2t=MQ(),R0=Symbol(\"lastResolve\"),Em=Symbol(\"lastReject\"),Ev=Symbol(\"error\"),_Q=Symbol(\"ended\"),Cm=Symbol(\"lastPromise\"),Wq=Symbol(\"handlePromise\"),wm=Symbol(\"stream\");function T0(t,e){return{value:t,done:e}}function K2t(t){var e=t[R0];if(e!==null){var r=t[wm].read();r!==null&&(t[Cm]=null,t[R0]=null,t[Em]=null,e(T0(r,!1)))}}function V2t(t){process.nextTick(K2t,t)}function z2t(t,e){return function(r,o){t.then(function(){if(e[_Q]){r(T0(void 0,!0));return}e[Wq](r,o)},o)}}var J2t=Object.getPrototypeOf(function(){}),X2t=Object.setPrototypeOf((UQ={get stream(){return this[wm]},next:function(){var e=this,r=this[Ev];if(r!==null)return Promise.reject(r);if(this[_Q])return Promise.resolve(T0(void 0,!0));if(this[wm].destroyed)return new Promise(function(u,A){process.nextTick(function(){e[Ev]?A(e[Ev]):u(T0(void 0,!0))})});var o=this[Cm],a;if(o)a=new Promise(z2t(o,this));else{var n=this[wm].read();if(n!==null)return Promise.resolve(T0(n,!1));a=new Promise(this[Wq])}return this[Cm]=a,a}},F0(UQ,Symbol.asyncIterator,function(){return this}),F0(UQ,\"return\",function(){var e=this;return new Promise(function(r,o){e[wm].destroy(null,function(a){if(a){o(a);return}r(T0(void 0,!0))})})}),UQ),J2t),Z2t=function(e){var r,o=Object.create(X2t,(r={},F0(r,wm,{value:e,writable:!0}),F0(r,R0,{value:null,writable:!0}),F0(r,Em,{value:null,writable:!0}),F0(r,Ev,{value:null,writable:!0}),F0(r,_Q,{value:e._readableState.endEmitted,writable:!0}),F0(r,Wq,{value:function(n,u){var A=o[wm].read();A?(o[Cm]=null,o[R0]=null,o[Em]=null,n(T0(A,!1))):(o[R0]=n,o[Em]=u)},writable:!0}),r));return o[Cm]=null,W2t(e,function(a){if(a&&a.code!==\"ERR_STREAM_PREMATURE_CLOSE\"){var n=o[Em];n!==null&&(o[Cm]=null,o[R0]=null,o[Em]=null,n(a)),o[Ev]=a;return}var u=o[R0];u!==null&&(o[Cm]=null,o[R0]=null,o[Em]=null,u(T0(void 0,!0))),o[_Q]=!0}),e.on(\"readable\",V2t.bind(null,o)),o};l2e.exports=Z2t});var p2e=_((P$t,f2e)=>{\"use strict\";function u2e(t,e,r,o,a,n,u){try{var A=t[n](u),p=A.value}catch(h){r(h);return}A.done?e(p):Promise.resolve(p).then(o,a)}function $2t(t){return function(){var e=this,r=arguments;return new Promise(function(o,a){var n=t.apply(e,r);function u(p){u2e(n,o,a,u,A,\"next\",p)}function A(p){u2e(n,o,a,u,A,\"throw\",p)}u(void 0)})}}function A2e(t,e){var r=Object.keys(t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(t);e&&(o=o.filter(function(a){return Object.getOwnPropertyDescriptor(t,a).enumerable})),r.push.apply(r,o)}return r}function eBt(t){for(var e=1;e<arguments.length;e++){var r=arguments[e]!=null?arguments[e]:{};e%2?A2e(Object(r),!0).forEach(function(o){tBt(t,o,r[o])}):Object.getOwnPropertyDescriptors?Object.defineProperties(t,Object.getOwnPropertyDescriptors(r)):A2e(Object(r)).forEach(function(o){Object.defineProperty(t,o,Object.getOwnPropertyDescriptor(r,o))})}return t}function tBt(t,e,r){return e in t?Object.defineProperty(t,e,{value:r,enumerable:!0,configurable:!0,writable:!0}):t[e]=r,t}var rBt=x0().codes.ERR_INVALID_ARG_TYPE;function nBt(t,e,r){var o;if(e&&typeof e.next==\"function\")o=e;else if(e&&e[Symbol.asyncIterator])o=e[Symbol.asyncIterator]();else if(e&&e[Symbol.iterator])o=e[Symbol.iterator]();else throw new rBt(\"iterable\",[\"Iterable\"],e);var a=new t(eBt({objectMode:!0},r)),n=!1;a._read=function(){n||(n=!0,u())};function u(){return A.apply(this,arguments)}function A(){return A=$2t(function*(){try{var p=yield o.next(),h=p.value,C=p.done;C?a.push(null):a.push(yield h)?u():n=!1}catch(I){a.destroy(I)}}),A.apply(this,arguments)}return a}f2e.exports=nBt});var Hq=_((b$t,B2e)=>{\"use strict\";B2e.exports=mn;var XC;mn.ReadableState=m2e;var S$t=Be(\"events\").EventEmitter,d2e=function(e,r){return e.listeners(r).length},wv=bq(),HQ=Be(\"buffer\").Buffer,iBt=global.Uint8Array||function(){};function sBt(t){return HQ.from(t)}function oBt(t){return HQ.isBuffer(t)||t instanceof iBt}var Kq=Be(\"util\"),$r;Kq&&Kq.debuglog?$r=Kq.debuglog(\"stream\"):$r=function(){};var aBt=L1e(),eG=Qq(),lBt=Fq(),cBt=lBt.getHighWaterMark,jQ=x0().codes,uBt=jQ.ERR_INVALID_ARG_TYPE,ABt=jQ.ERR_STREAM_PUSH_AFTER_EOF,fBt=jQ.ERR_METHOD_NOT_IMPLEMENTED,pBt=jQ.ERR_STREAM_UNSHIFT_AFTER_END_EVENT,ZC,Vq,zq;k0()(mn,wv);var Cv=eG.errorOrDestroy,Jq=[\"error\",\"close\",\"destroy\",\"pause\",\"resume\"];function hBt(t,e,r){if(typeof t.prependListener==\"function\")return t.prependListener(e,r);!t._events||!t._events[e]?t.on(e,r):Array.isArray(t._events[e])?t._events[e].unshift(r):t._events[e]=[r,t._events[e]]}function m2e(t,e,r){XC=XC||ym(),t=t||{},typeof r!=\"boolean\"&&(r=e instanceof XC),this.objectMode=!!t.objectMode,r&&(this.objectMode=this.objectMode||!!t.readableObjectMode),this.highWaterMark=cBt(this,t,\"readableHighWaterMark\",r),this.buffer=new aBt,this.length=0,this.pipes=null,this.pipesCount=0,this.flowing=null,this.ended=!1,this.endEmitted=!1,this.reading=!1,this.sync=!0,this.needReadable=!1,this.emittedReadable=!1,this.readableListening=!1,this.resumeScheduled=!1,this.paused=!0,this.emitClose=t.emitClose!==!1,this.autoDestroy=!!t.autoDestroy,this.destroyed=!1,this.defaultEncoding=t.defaultEncoding||\"utf8\",this.awaitDrain=0,this.readingMore=!1,this.decoder=null,this.encoding=null,t.encoding&&(ZC||(ZC=Yq().StringDecoder),this.decoder=new ZC(t.encoding),this.encoding=t.encoding)}function mn(t){if(XC=XC||ym(),!(this instanceof mn))return new mn(t);var e=this instanceof XC;this._readableState=new m2e(t,this,e),this.readable=!0,t&&(typeof t.read==\"function\"&&(this._read=t.read),typeof t.destroy==\"function\"&&(this._destroy=t.destroy)),wv.call(this)}Object.defineProperty(mn.prototype,\"destroyed\",{enumerable:!1,get:function(){return this._readableState===void 0?!1:this._readableState.destroyed},set:function(e){!this._readableState||(this._readableState.destroyed=e)}});mn.prototype.destroy=eG.destroy;mn.prototype._undestroy=eG.undestroy;mn.prototype._destroy=function(t,e){e(t)};mn.prototype.push=function(t,e){var r=this._readableState,o;return r.objectMode?o=!0:typeof t==\"string\"&&(e=e||r.defaultEncoding,e!==r.encoding&&(t=HQ.from(t,e),e=\"\"),o=!0),y2e(this,t,e,!1,o)};mn.prototype.unshift=function(t){return y2e(this,t,null,!0,!1)};function y2e(t,e,r,o,a){$r(\"readableAddChunk\",e);var n=t._readableState;if(e===null)n.reading=!1,mBt(t,n);else{var u;if(a||(u=gBt(n,e)),u)Cv(t,u);else if(n.objectMode||e&&e.length>0)if(typeof e!=\"string\"&&!n.objectMode&&Object.getPrototypeOf(e)!==HQ.prototype&&(e=sBt(e)),o)n.endEmitted?Cv(t,new pBt):Xq(t,n,e,!0);else if(n.ended)Cv(t,new ABt);else{if(n.destroyed)return!1;n.reading=!1,n.decoder&&!r?(e=n.decoder.write(e),n.objectMode||e.length!==0?Xq(t,n,e,!1):$q(t,n)):Xq(t,n,e,!1)}else o||(n.reading=!1,$q(t,n))}return!n.ended&&(n.length<n.highWaterMark||n.length===0)}function Xq(t,e,r,o){e.flowing&&e.length===0&&!e.sync?(e.awaitDrain=0,t.emit(\"data\",r)):(e.length+=e.objectMode?1:r.length,o?e.buffer.unshift(r):e.buffer.push(r),e.needReadable&&qQ(t)),$q(t,e)}function gBt(t,e){var r;return!oBt(e)&&typeof e!=\"string\"&&e!==void 0&&!t.objectMode&&(r=new uBt(\"chunk\",[\"string\",\"Buffer\",\"Uint8Array\"],e)),r}mn.prototype.isPaused=function(){return this._readableState.flowing===!1};mn.prototype.setEncoding=function(t){ZC||(ZC=Yq().StringDecoder);var e=new ZC(t);this._readableState.decoder=e,this._readableState.encoding=this._readableState.decoder.encoding;for(var r=this._readableState.buffer.head,o=\"\";r!==null;)o+=e.write(r.data),r=r.next;return this._readableState.buffer.clear(),o!==\"\"&&this._readableState.buffer.push(o),this._readableState.length=o.length,this};var h2e=1073741824;function dBt(t){return t>=h2e?t=h2e:(t--,t|=t>>>1,t|=t>>>2,t|=t>>>4,t|=t>>>8,t|=t>>>16,t++),t}function g2e(t,e){return t<=0||e.length===0&&e.ended?0:e.objectMode?1:t!==t?e.flowing&&e.length?e.buffer.head.data.length:e.length:(t>e.highWaterMark&&(e.highWaterMark=dBt(t)),t<=e.length?t:e.ended?e.length:(e.needReadable=!0,0))}mn.prototype.read=function(t){$r(\"read\",t),t=parseInt(t,10);var e=this._readableState,r=t;if(t!==0&&(e.emittedReadable=!1),t===0&&e.needReadable&&((e.highWaterMark!==0?e.length>=e.highWaterMark:e.length>0)||e.ended))return $r(\"read: emitReadable\",e.length,e.ended),e.length===0&&e.ended?Zq(this):qQ(this),null;if(t=g2e(t,e),t===0&&e.ended)return e.length===0&&Zq(this),null;var o=e.needReadable;$r(\"need readable\",o),(e.length===0||e.length-t<e.highWaterMark)&&(o=!0,$r(\"length less than watermark\",o)),e.ended||e.reading?(o=!1,$r(\"reading or ended\",o)):o&&($r(\"do read\"),e.reading=!0,e.sync=!0,e.length===0&&(e.needReadable=!0),this._read(e.highWaterMark),e.sync=!1,e.reading||(t=g2e(r,e)));var a;return t>0?a=w2e(t,e):a=null,a===null?(e.needReadable=e.length<=e.highWaterMark,t=0):(e.length-=t,e.awaitDrain=0),e.length===0&&(e.ended||(e.needReadable=!0),r!==t&&e.ended&&Zq(this)),a!==null&&this.emit(\"data\",a),a};function mBt(t,e){if($r(\"onEofChunk\"),!e.ended){if(e.decoder){var r=e.decoder.end();r&&r.length&&(e.buffer.push(r),e.length+=e.objectMode?1:r.length)}e.ended=!0,e.sync?qQ(t):(e.needReadable=!1,e.emittedReadable||(e.emittedReadable=!0,E2e(t)))}}function qQ(t){var e=t._readableState;$r(\"emitReadable\",e.needReadable,e.emittedReadable),e.needReadable=!1,e.emittedReadable||($r(\"emitReadable\",e.flowing),e.emittedReadable=!0,process.nextTick(E2e,t))}function E2e(t){var e=t._readableState;$r(\"emitReadable_\",e.destroyed,e.length,e.ended),!e.destroyed&&(e.length||e.ended)&&(t.emit(\"readable\"),e.emittedReadable=!1),e.needReadable=!e.flowing&&!e.ended&&e.length<=e.highWaterMark,tG(t)}function $q(t,e){e.readingMore||(e.readingMore=!0,process.nextTick(yBt,t,e))}function yBt(t,e){for(;!e.reading&&!e.ended&&(e.length<e.highWaterMark||e.flowing&&e.length===0);){var r=e.length;if($r(\"maybeReadMore read 0\"),t.read(0),r===e.length)break}e.readingMore=!1}mn.prototype._read=function(t){Cv(this,new fBt(\"_read()\"))};mn.prototype.pipe=function(t,e){var r=this,o=this._readableState;switch(o.pipesCount){case 0:o.pipes=t;break;case 1:o.pipes=[o.pipes,t];break;default:o.pipes.push(t);break}o.pipesCount+=1,$r(\"pipe count=%d opts=%j\",o.pipesCount,e);var a=(!e||e.end!==!1)&&t!==process.stdout&&t!==process.stderr,n=a?A:R;o.endEmitted?process.nextTick(n):r.once(\"end\",n),t.on(\"unpipe\",u);function u(L,U){$r(\"onunpipe\"),L===r&&U&&U.hasUnpiped===!1&&(U.hasUnpiped=!0,C())}function A(){$r(\"onend\"),t.end()}var p=EBt(r);t.on(\"drain\",p);var h=!1;function C(){$r(\"cleanup\"),t.removeListener(\"close\",x),t.removeListener(\"finish\",E),t.removeListener(\"drain\",p),t.removeListener(\"error\",v),t.removeListener(\"unpipe\",u),r.removeListener(\"end\",A),r.removeListener(\"end\",R),r.removeListener(\"data\",I),h=!0,o.awaitDrain&&(!t._writableState||t._writableState.needDrain)&&p()}r.on(\"data\",I);function I(L){$r(\"ondata\");var U=t.write(L);$r(\"dest.write\",U),U===!1&&((o.pipesCount===1&&o.pipes===t||o.pipesCount>1&&I2e(o.pipes,t)!==-1)&&!h&&($r(\"false write response, pause\",o.awaitDrain),o.awaitDrain++),r.pause())}function v(L){$r(\"onerror\",L),R(),t.removeListener(\"error\",v),d2e(t,\"error\")===0&&Cv(t,L)}hBt(t,\"error\",v);function x(){t.removeListener(\"finish\",E),R()}t.once(\"close\",x);function E(){$r(\"onfinish\"),t.removeListener(\"close\",x),R()}t.once(\"finish\",E);function R(){$r(\"unpipe\"),r.unpipe(t)}return t.emit(\"pipe\",r),o.flowing||($r(\"pipe resume\"),r.resume()),t};function EBt(t){return function(){var r=t._readableState;$r(\"pipeOnDrain\",r.awaitDrain),r.awaitDrain&&r.awaitDrain--,r.awaitDrain===0&&d2e(t,\"data\")&&(r.flowing=!0,tG(t))}}mn.prototype.unpipe=function(t){var e=this._readableState,r={hasUnpiped:!1};if(e.pipesCount===0)return this;if(e.pipesCount===1)return t&&t!==e.pipes?this:(t||(t=e.pipes),e.pipes=null,e.pipesCount=0,e.flowing=!1,t&&t.emit(\"unpipe\",this,r),this);if(!t){var o=e.pipes,a=e.pipesCount;e.pipes=null,e.pipesCount=0,e.flowing=!1;for(var n=0;n<a;n++)o[n].emit(\"unpipe\",this,{hasUnpiped:!1});return this}var u=I2e(e.pipes,t);return u===-1?this:(e.pipes.splice(u,1),e.pipesCount-=1,e.pipesCount===1&&(e.pipes=e.pipes[0]),t.emit(\"unpipe\",this,r),this)};mn.prototype.on=function(t,e){var r=wv.prototype.on.call(this,t,e),o=this._readableState;return t===\"data\"?(o.readableListening=this.listenerCount(\"readable\")>0,o.flowing!==!1&&this.resume()):t===\"readable\"&&!o.endEmitted&&!o.readableListening&&(o.readableListening=o.needReadable=!0,o.flowing=!1,o.emittedReadable=!1,$r(\"on readable\",o.length,o.reading),o.length?qQ(this):o.reading||process.nextTick(CBt,this)),r};mn.prototype.addListener=mn.prototype.on;mn.prototype.removeListener=function(t,e){var r=wv.prototype.removeListener.call(this,t,e);return t===\"readable\"&&process.nextTick(C2e,this),r};mn.prototype.removeAllListeners=function(t){var e=wv.prototype.removeAllListeners.apply(this,arguments);return(t===\"readable\"||t===void 0)&&process.nextTick(C2e,this),e};function C2e(t){var e=t._readableState;e.readableListening=t.listenerCount(\"readable\")>0,e.resumeScheduled&&!e.paused?e.flowing=!0:t.listenerCount(\"data\")>0&&t.resume()}function CBt(t){$r(\"readable nexttick read 0\"),t.read(0)}mn.prototype.resume=function(){var t=this._readableState;return t.flowing||($r(\"resume\"),t.flowing=!t.readableListening,wBt(this,t)),t.paused=!1,this};function wBt(t,e){e.resumeScheduled||(e.resumeScheduled=!0,process.nextTick(IBt,t,e))}function IBt(t,e){$r(\"resume\",e.reading),e.reading||t.read(0),e.resumeScheduled=!1,t.emit(\"resume\"),tG(t),e.flowing&&!e.reading&&t.read(0)}mn.prototype.pause=function(){return $r(\"call pause flowing=%j\",this._readableState.flowing),this._readableState.flowing!==!1&&($r(\"pause\"),this._readableState.flowing=!1,this.emit(\"pause\")),this._readableState.paused=!0,this};function tG(t){var e=t._readableState;for($r(\"flow\",e.flowing);e.flowing&&t.read()!==null;);}mn.prototype.wrap=function(t){var e=this,r=this._readableState,o=!1;t.on(\"end\",function(){if($r(\"wrapped end\"),r.decoder&&!r.ended){var u=r.decoder.end();u&&u.length&&e.push(u)}e.push(null)}),t.on(\"data\",function(u){if($r(\"wrapped data\"),r.decoder&&(u=r.decoder.write(u)),!(r.objectMode&&u==null)&&!(!r.objectMode&&(!u||!u.length))){var A=e.push(u);A||(o=!0,t.pause())}});for(var a in t)this[a]===void 0&&typeof t[a]==\"function\"&&(this[a]=function(A){return function(){return t[A].apply(t,arguments)}}(a));for(var n=0;n<Jq.length;n++)t.on(Jq[n],this.emit.bind(this,Jq[n]));return this._read=function(u){$r(\"wrapped _read\",u),o&&(o=!1,t.resume())},this};typeof Symbol==\"function\"&&(mn.prototype[Symbol.asyncIterator]=function(){return Vq===void 0&&(Vq=c2e()),Vq(this)});Object.defineProperty(mn.prototype,\"readableHighWaterMark\",{enumerable:!1,get:function(){return this._readableState.highWaterMark}});Object.defineProperty(mn.prototype,\"readableBuffer\",{enumerable:!1,get:function(){return this._readableState&&this._readableState.buffer}});Object.defineProperty(mn.prototype,\"readableFlowing\",{enumerable:!1,get:function(){return this._readableState.flowing},set:function(e){this._readableState&&(this._readableState.flowing=e)}});mn._fromList=w2e;Object.defineProperty(mn.prototype,\"readableLength\",{enumerable:!1,get:function(){return this._readableState.length}});function w2e(t,e){if(e.length===0)return null;var r;return e.objectMode?r=e.buffer.shift():!t||t>=e.length?(e.decoder?r=e.buffer.join(\"\"):e.buffer.length===1?r=e.buffer.first():r=e.buffer.concat(e.length),e.buffer.clear()):r=e.buffer.consume(t,e.decoder),r}function Zq(t){var e=t._readableState;$r(\"endReadable\",e.endEmitted),e.endEmitted||(e.ended=!0,process.nextTick(BBt,e,t))}function BBt(t,e){if($r(\"endReadableNT\",t.endEmitted,t.length),!t.endEmitted&&t.length===0&&(t.endEmitted=!0,e.readable=!1,e.emit(\"end\"),t.autoDestroy)){var r=e._writableState;(!r||r.autoDestroy&&r.finished)&&e.destroy()}}typeof Symbol==\"function\"&&(mn.from=function(t,e){return zq===void 0&&(zq=p2e()),zq(mn,t,e)});function I2e(t,e){for(var r=0,o=t.length;r<o;r++)if(t[r]===e)return r;return-1}});var rG=_((x$t,D2e)=>{\"use strict\";D2e.exports=np;var GQ=x0().codes,vBt=GQ.ERR_METHOD_NOT_IMPLEMENTED,DBt=GQ.ERR_MULTIPLE_CALLBACK,PBt=GQ.ERR_TRANSFORM_ALREADY_TRANSFORMING,SBt=GQ.ERR_TRANSFORM_WITH_LENGTH_0,YQ=ym();k0()(np,YQ);function bBt(t,e){var r=this._transformState;r.transforming=!1;var o=r.writecb;if(o===null)return this.emit(\"error\",new DBt);r.writechunk=null,r.writecb=null,e!=null&&this.push(e),o(t);var a=this._readableState;a.reading=!1,(a.needReadable||a.length<a.highWaterMark)&&this._read(a.highWaterMark)}function np(t){if(!(this instanceof np))return new np(t);YQ.call(this,t),this._transformState={afterTransform:bBt.bind(this),needTransform:!1,transforming:!1,writecb:null,writechunk:null,writeencoding:null},this._readableState.needReadable=!0,this._readableState.sync=!1,t&&(typeof t.transform==\"function\"&&(this._transform=t.transform),typeof t.flush==\"function\"&&(this._flush=t.flush)),this.on(\"prefinish\",xBt)}function xBt(){var t=this;typeof this._flush==\"function\"&&!this._readableState.destroyed?this._flush(function(e,r){v2e(t,e,r)}):v2e(this,null,null)}np.prototype.push=function(t,e){return this._transformState.needTransform=!1,YQ.prototype.push.call(this,t,e)};np.prototype._transform=function(t,e,r){r(new vBt(\"_transform()\"))};np.prototype._write=function(t,e,r){var o=this._transformState;if(o.writecb=r,o.writechunk=t,o.writeencoding=e,!o.transforming){var a=this._readableState;(o.needTransform||a.needReadable||a.length<a.highWaterMark)&&this._read(a.highWaterMark)}};np.prototype._read=function(t){var e=this._transformState;e.writechunk!==null&&!e.transforming?(e.transforming=!0,this._transform(e.writechunk,e.writeencoding,e.afterTransform)):e.needTransform=!0};np.prototype._destroy=function(t,e){YQ.prototype._destroy.call(this,t,function(r){e(r)})};function v2e(t,e,r){if(e)return t.emit(\"error\",e);if(r!=null&&t.push(r),t._writableState.length)throw new SBt;if(t._transformState.transforming)throw new PBt;return t.push(null)}});var b2e=_((k$t,S2e)=>{\"use strict\";S2e.exports=Iv;var P2e=rG();k0()(Iv,P2e);function Iv(t){if(!(this instanceof Iv))return new Iv(t);P2e.call(this,t)}Iv.prototype._transform=function(t,e,r){r(null,t)}});var R2e=_((Q$t,F2e)=>{\"use strict\";var nG;function kBt(t){var e=!1;return function(){e||(e=!0,t.apply(void 0,arguments))}}var Q2e=x0().codes,QBt=Q2e.ERR_MISSING_ARGS,FBt=Q2e.ERR_STREAM_DESTROYED;function x2e(t){if(t)throw t}function RBt(t){return t.setHeader&&typeof t.abort==\"function\"}function TBt(t,e,r,o){o=kBt(o);var a=!1;t.on(\"close\",function(){a=!0}),nG===void 0&&(nG=MQ()),nG(t,{readable:e,writable:r},function(u){if(u)return o(u);a=!0,o()});var n=!1;return function(u){if(!a&&!n){if(n=!0,RBt(t))return t.abort();if(typeof t.destroy==\"function\")return t.destroy();o(u||new FBt(\"pipe\"))}}}function k2e(t){t()}function NBt(t,e){return t.pipe(e)}function LBt(t){return!t.length||typeof t[t.length-1]!=\"function\"?x2e:t.pop()}function OBt(){for(var t=arguments.length,e=new Array(t),r=0;r<t;r++)e[r]=arguments[r];var o=LBt(e);if(Array.isArray(e[0])&&(e=e[0]),e.length<2)throw new QBt(\"streams\");var a,n=e.map(function(u,A){var p=A<e.length-1,h=A>0;return TBt(u,p,h,function(C){a||(a=C),C&&n.forEach(k2e),!p&&(n.forEach(k2e),o(a))})});return e.reduce(NBt)}F2e.exports=OBt});var $C=_((lc,vv)=>{var Bv=Be(\"stream\");process.env.READABLE_STREAM===\"disable\"&&Bv?(vv.exports=Bv.Readable,Object.assign(vv.exports,Bv),vv.exports.Stream=Bv):(lc=vv.exports=Hq(),lc.Stream=Bv||lc,lc.Readable=lc,lc.Writable=Mq(),lc.Duplex=ym(),lc.Transform=rG(),lc.PassThrough=b2e(),lc.finished=MQ(),lc.pipeline=R2e())});var L2e=_((F$t,N2e)=>{\"use strict\";var{Buffer:lu}=Be(\"buffer\"),T2e=Symbol.for(\"BufferList\");function ni(t){if(!(this instanceof ni))return new ni(t);ni._init.call(this,t)}ni._init=function(e){Object.defineProperty(this,T2e,{value:!0}),this._bufs=[],this.length=0,e&&this.append(e)};ni.prototype._new=function(e){return new ni(e)};ni.prototype._offset=function(e){if(e===0)return[0,0];let r=0;for(let o=0;o<this._bufs.length;o++){let a=r+this._bufs[o].length;if(e<a||o===this._bufs.length-1)return[o,e-r];r=a}};ni.prototype._reverseOffset=function(t){let e=t[0],r=t[1];for(let o=0;o<e;o++)r+=this._bufs[o].length;return r};ni.prototype.get=function(e){if(e>this.length||e<0)return;let r=this._offset(e);return this._bufs[r[0]][r[1]]};ni.prototype.slice=function(e,r){return typeof e==\"number\"&&e<0&&(e+=this.length),typeof r==\"number\"&&r<0&&(r+=this.length),this.copy(null,0,e,r)};ni.prototype.copy=function(e,r,o,a){if((typeof o!=\"number\"||o<0)&&(o=0),(typeof a!=\"number\"||a>this.length)&&(a=this.length),o>=this.length||a<=0)return e||lu.alloc(0);let n=!!e,u=this._offset(o),A=a-o,p=A,h=n&&r||0,C=u[1];if(o===0&&a===this.length){if(!n)return this._bufs.length===1?this._bufs[0]:lu.concat(this._bufs,this.length);for(let I=0;I<this._bufs.length;I++)this._bufs[I].copy(e,h),h+=this._bufs[I].length;return e}if(p<=this._bufs[u[0]].length-C)return n?this._bufs[u[0]].copy(e,r,C,C+p):this._bufs[u[0]].slice(C,C+p);n||(e=lu.allocUnsafe(A));for(let I=u[0];I<this._bufs.length;I++){let v=this._bufs[I].length-C;if(p>v)this._bufs[I].copy(e,h,C),h+=v;else{this._bufs[I].copy(e,h,C,C+p),h+=v;break}p-=v,C&&(C=0)}return e.length>h?e.slice(0,h):e};ni.prototype.shallowSlice=function(e,r){if(e=e||0,r=typeof r!=\"number\"?this.length:r,e<0&&(e+=this.length),r<0&&(r+=this.length),e===r)return this._new();let o=this._offset(e),a=this._offset(r),n=this._bufs.slice(o[0],a[0]+1);return a[1]===0?n.pop():n[n.length-1]=n[n.length-1].slice(0,a[1]),o[1]!==0&&(n[0]=n[0].slice(o[1])),this._new(n)};ni.prototype.toString=function(e,r,o){return this.slice(r,o).toString(e)};ni.prototype.consume=function(e){if(e=Math.trunc(e),Number.isNaN(e)||e<=0)return this;for(;this._bufs.length;)if(e>=this._bufs[0].length)e-=this._bufs[0].length,this.length-=this._bufs[0].length,this._bufs.shift();else{this._bufs[0]=this._bufs[0].slice(e),this.length-=e;break}return this};ni.prototype.duplicate=function(){let e=this._new();for(let r=0;r<this._bufs.length;r++)e.append(this._bufs[r]);return e};ni.prototype.append=function(e){if(e==null)return this;if(e.buffer)this._appendBuffer(lu.from(e.buffer,e.byteOffset,e.byteLength));else if(Array.isArray(e))for(let r=0;r<e.length;r++)this.append(e[r]);else if(this._isBufferList(e))for(let r=0;r<e._bufs.length;r++)this.append(e._bufs[r]);else typeof e==\"number\"&&(e=e.toString()),this._appendBuffer(lu.from(e));return this};ni.prototype._appendBuffer=function(e){this._bufs.push(e),this.length+=e.length};ni.prototype.indexOf=function(t,e,r){if(r===void 0&&typeof e==\"string\"&&(r=e,e=void 0),typeof t==\"function\"||Array.isArray(t))throw new TypeError('The \"value\" argument must be one of type string, Buffer, BufferList, or Uint8Array.');if(typeof t==\"number\"?t=lu.from([t]):typeof t==\"string\"?t=lu.from(t,r):this._isBufferList(t)?t=t.slice():Array.isArray(t.buffer)?t=lu.from(t.buffer,t.byteOffset,t.byteLength):lu.isBuffer(t)||(t=lu.from(t)),e=Number(e||0),isNaN(e)&&(e=0),e<0&&(e=this.length+e),e<0&&(e=0),t.length===0)return e>this.length?this.length:e;let o=this._offset(e),a=o[0],n=o[1];for(;a<this._bufs.length;a++){let u=this._bufs[a];for(;n<u.length;)if(u.length-n>=t.length){let p=u.indexOf(t,n);if(p!==-1)return this._reverseOffset([a,p]);n=u.length-t.length+1}else{let p=this._reverseOffset([a,n]);if(this._match(p,t))return p;n++}n=0}return-1};ni.prototype._match=function(t,e){if(this.length-t<e.length)return!1;for(let r=0;r<e.length;r++)if(this.get(t+r)!==e[r])return!1;return!0};(function(){let t={readDoubleBE:8,readDoubleLE:8,readFloatBE:4,readFloatLE:4,readInt32BE:4,readInt32LE:4,readUInt32BE:4,readUInt32LE:4,readInt16BE:2,readInt16LE:2,readUInt16BE:2,readUInt16LE:2,readInt8:1,readUInt8:1,readIntBE:null,readIntLE:null,readUIntBE:null,readUIntLE:null};for(let e in t)(function(r){t[r]===null?ni.prototype[r]=function(o,a){return this.slice(o,o+a)[r](0,a)}:ni.prototype[r]=function(o=0){return this.slice(o,o+t[r])[r](0)}})(e)})();ni.prototype._isBufferList=function(e){return e instanceof ni||ni.isBufferList(e)};ni.isBufferList=function(e){return e!=null&&e[T2e]};N2e.exports=ni});var O2e=_((R$t,WQ)=>{\"use strict\";var iG=$C().Duplex,MBt=k0(),Dv=L2e();function Uo(t){if(!(this instanceof Uo))return new Uo(t);if(typeof t==\"function\"){this._callback=t;let e=function(o){this._callback&&(this._callback(o),this._callback=null)}.bind(this);this.on(\"pipe\",function(o){o.on(\"error\",e)}),this.on(\"unpipe\",function(o){o.removeListener(\"error\",e)}),t=null}Dv._init.call(this,t),iG.call(this)}MBt(Uo,iG);Object.assign(Uo.prototype,Dv.prototype);Uo.prototype._new=function(e){return new Uo(e)};Uo.prototype._write=function(e,r,o){this._appendBuffer(e),typeof o==\"function\"&&o()};Uo.prototype._read=function(e){if(!this.length)return this.push(null);e=Math.min(e,this.length),this.push(this.slice(0,e)),this.consume(e)};Uo.prototype.end=function(e){iG.prototype.end.call(this,e),this._callback&&(this._callback(null,this.slice()),this._callback=null)};Uo.prototype._destroy=function(e,r){this._bufs.length=0,this.length=0,r(e)};Uo.prototype._isBufferList=function(e){return e instanceof Uo||e instanceof Dv||Uo.isBufferList(e)};Uo.isBufferList=Dv.isBufferList;WQ.exports=Uo;WQ.exports.BufferListStream=Uo;WQ.exports.BufferList=Dv});var aG=_(tw=>{var UBt=Buffer.alloc,_Bt=\"0000000000000000000\",HBt=\"7777777777777777777\",M2e=\"0\".charCodeAt(0),U2e=Buffer.from(\"ustar\\0\",\"binary\"),jBt=Buffer.from(\"00\",\"binary\"),qBt=Buffer.from(\"ustar \",\"binary\"),GBt=Buffer.from(\" \\0\",\"binary\"),YBt=parseInt(\"7777\",8),Pv=257,oG=263,WBt=function(t,e,r){return typeof t!=\"number\"?r:(t=~~t,t>=e?e:t>=0||(t+=e,t>=0)?t:0)},KBt=function(t){switch(t){case 0:return\"file\";case 1:return\"link\";case 2:return\"symlink\";case 3:return\"character-device\";case 4:return\"block-device\";case 5:return\"directory\";case 6:return\"fifo\";case 7:return\"contiguous-file\";case 72:return\"pax-header\";case 55:return\"pax-global-header\";case 27:return\"gnu-long-link-path\";case 28:case 30:return\"gnu-long-path\"}return null},VBt=function(t){switch(t){case\"file\":return 0;case\"link\":return 1;case\"symlink\":return 2;case\"character-device\":return 3;case\"block-device\":return 4;case\"directory\":return 5;case\"fifo\":return 6;case\"contiguous-file\":return 7;case\"pax-header\":return 72}return 0},_2e=function(t,e,r,o){for(;r<o;r++)if(t[r]===e)return r;return o},H2e=function(t){for(var e=256,r=0;r<148;r++)e+=t[r];for(var o=156;o<512;o++)e+=t[o];return e},N0=function(t,e){return t=t.toString(8),t.length>e?HBt.slice(0,e)+\" \":_Bt.slice(0,e-t.length)+t+\" \"};function zBt(t){var e;if(t[0]===128)e=!0;else if(t[0]===255)e=!1;else return null;for(var r=[],o=t.length-1;o>0;o--){var a=t[o];e?r.push(a):r.push(255-a)}var n=0,u=r.length;for(o=0;o<u;o++)n+=r[o]*Math.pow(256,o);return e?n:-1*n}var L0=function(t,e,r){if(t=t.slice(e,e+r),e=0,t[e]&128)return zBt(t);for(;e<t.length&&t[e]===32;)e++;for(var o=WBt(_2e(t,32,e,t.length),t.length,t.length);e<o&&t[e]===0;)e++;return o===e?0:parseInt(t.slice(e,o).toString(),8)},ew=function(t,e,r,o){return t.slice(e,_2e(t,0,e,e+r)).toString(o)},sG=function(t){var e=Buffer.byteLength(t),r=Math.floor(Math.log(e)/Math.log(10))+1;return e+r>=Math.pow(10,r)&&r++,e+r+t};tw.decodeLongPath=function(t,e){return ew(t,0,t.length,e)};tw.encodePax=function(t){var e=\"\";t.name&&(e+=sG(\" path=\"+t.name+`\n`)),t.linkname&&(e+=sG(\" linkpath=\"+t.linkname+`\n`));var r=t.pax;if(r)for(var o in r)e+=sG(\" \"+o+\"=\"+r[o]+`\n`);return Buffer.from(e)};tw.decodePax=function(t){for(var e={};t.length;){for(var r=0;r<t.length&&t[r]!==32;)r++;var o=parseInt(t.slice(0,r).toString(),10);if(!o)return e;var a=t.slice(r+1,o-1).toString(),n=a.indexOf(\"=\");if(n===-1)return e;e[a.slice(0,n)]=a.slice(n+1),t=t.slice(o)}return e};tw.encode=function(t){var e=UBt(512),r=t.name,o=\"\";if(t.typeflag===5&&r[r.length-1]!==\"/\"&&(r+=\"/\"),Buffer.byteLength(r)!==r.length)return null;for(;Buffer.byteLength(r)>100;){var a=r.indexOf(\"/\");if(a===-1)return null;o+=o?\"/\"+r.slice(0,a):r.slice(0,a),r=r.slice(a+1)}return Buffer.byteLength(r)>100||Buffer.byteLength(o)>155||t.linkname&&Buffer.byteLength(t.linkname)>100?null:(e.write(r),e.write(N0(t.mode&YBt,6),100),e.write(N0(t.uid,6),108),e.write(N0(t.gid,6),116),e.write(N0(t.size,11),124),e.write(N0(t.mtime.getTime()/1e3|0,11),136),e[156]=M2e+VBt(t.type),t.linkname&&e.write(t.linkname,157),U2e.copy(e,Pv),jBt.copy(e,oG),t.uname&&e.write(t.uname,265),t.gname&&e.write(t.gname,297),e.write(N0(t.devmajor||0,6),329),e.write(N0(t.devminor||0,6),337),o&&e.write(o,345),e.write(N0(H2e(e),6),148),e)};tw.decode=function(t,e,r){var o=t[156]===0?0:t[156]-M2e,a=ew(t,0,100,e),n=L0(t,100,8),u=L0(t,108,8),A=L0(t,116,8),p=L0(t,124,12),h=L0(t,136,12),C=KBt(o),I=t[157]===0?null:ew(t,157,100,e),v=ew(t,265,32),x=ew(t,297,32),E=L0(t,329,8),R=L0(t,337,8),L=H2e(t);if(L===8*32)return null;if(L!==L0(t,148,8))throw new Error(\"Invalid tar header. Maybe the tar is corrupted or it needs to be gunzipped?\");if(U2e.compare(t,Pv,Pv+6)===0)t[345]&&(a=ew(t,345,155,e)+\"/\"+a);else if(!(qBt.compare(t,Pv,Pv+6)===0&&GBt.compare(t,oG,oG+2)===0)){if(!r)throw new Error(\"Invalid tar header: unknown format.\")}return o===0&&a&&a[a.length-1]===\"/\"&&(o=5),{name:a,mode:n,uid:u,gid:A,size:p,mtime:new Date(1e3*h),type:C,linkname:I,uname:v,gname:x,devmajor:E,devminor:R}}});var V2e=_((N$t,K2e)=>{var q2e=Be(\"util\"),JBt=O2e(),Sv=aG(),G2e=$C().Writable,Y2e=$C().PassThrough,W2e=function(){},j2e=function(t){return t&=511,t&&512-t},XBt=function(t,e){var r=new KQ(t,e);return r.end(),r},ZBt=function(t,e){return e.path&&(t.name=e.path),e.linkpath&&(t.linkname=e.linkpath),e.size&&(t.size=parseInt(e.size,10)),t.pax=e,t},KQ=function(t,e){this._parent=t,this.offset=e,Y2e.call(this,{autoDestroy:!1})};q2e.inherits(KQ,Y2e);KQ.prototype.destroy=function(t){this._parent.destroy(t)};var ip=function(t){if(!(this instanceof ip))return new ip(t);G2e.call(this,t),t=t||{},this._offset=0,this._buffer=JBt(),this._missing=0,this._partial=!1,this._onparse=W2e,this._header=null,this._stream=null,this._overflow=null,this._cb=null,this._locked=!1,this._destroyed=!1,this._pax=null,this._paxGlobal=null,this._gnuLongPath=null,this._gnuLongLinkPath=null;var e=this,r=e._buffer,o=function(){e._continue()},a=function(v){if(e._locked=!1,v)return e.destroy(v);e._stream||o()},n=function(){e._stream=null;var v=j2e(e._header.size);v?e._parse(v,u):e._parse(512,I),e._locked||o()},u=function(){e._buffer.consume(j2e(e._header.size)),e._parse(512,I),o()},A=function(){var v=e._header.size;e._paxGlobal=Sv.decodePax(r.slice(0,v)),r.consume(v),n()},p=function(){var v=e._header.size;e._pax=Sv.decodePax(r.slice(0,v)),e._paxGlobal&&(e._pax=Object.assign({},e._paxGlobal,e._pax)),r.consume(v),n()},h=function(){var v=e._header.size;this._gnuLongPath=Sv.decodeLongPath(r.slice(0,v),t.filenameEncoding),r.consume(v),n()},C=function(){var v=e._header.size;this._gnuLongLinkPath=Sv.decodeLongPath(r.slice(0,v),t.filenameEncoding),r.consume(v),n()},I=function(){var v=e._offset,x;try{x=e._header=Sv.decode(r.slice(0,512),t.filenameEncoding,t.allowUnknownFormat)}catch(E){e.emit(\"error\",E)}if(r.consume(512),!x){e._parse(512,I),o();return}if(x.type===\"gnu-long-path\"){e._parse(x.size,h),o();return}if(x.type===\"gnu-long-link-path\"){e._parse(x.size,C),o();return}if(x.type===\"pax-global-header\"){e._parse(x.size,A),o();return}if(x.type===\"pax-header\"){e._parse(x.size,p),o();return}if(e._gnuLongPath&&(x.name=e._gnuLongPath,e._gnuLongPath=null),e._gnuLongLinkPath&&(x.linkname=e._gnuLongLinkPath,e._gnuLongLinkPath=null),e._pax&&(e._header=x=ZBt(x,e._pax),e._pax=null),e._locked=!0,!x.size||x.type===\"directory\"){e._parse(512,I),e.emit(\"entry\",x,XBt(e,v),a);return}e._stream=new KQ(e,v),e.emit(\"entry\",x,e._stream,a),e._parse(x.size,n),o()};this._onheader=I,this._parse(512,I)};q2e.inherits(ip,G2e);ip.prototype.destroy=function(t){this._destroyed||(this._destroyed=!0,t&&this.emit(\"error\",t),this.emit(\"close\"),this._stream&&this._stream.emit(\"close\"))};ip.prototype._parse=function(t,e){this._destroyed||(this._offset+=t,this._missing=t,e===this._onheader&&(this._partial=!1),this._onparse=e)};ip.prototype._continue=function(){if(!this._destroyed){var t=this._cb;this._cb=W2e,this._overflow?this._write(this._overflow,void 0,t):t()}};ip.prototype._write=function(t,e,r){if(!this._destroyed){var o=this._stream,a=this._buffer,n=this._missing;if(t.length&&(this._partial=!0),t.length<n)return this._missing-=t.length,this._overflow=null,o?o.write(t,r):(a.append(t),r());this._cb=r,this._missing=0;var u=null;t.length>n&&(u=t.slice(n),t=t.slice(0,n)),o?o.end(t):a.append(t),this._overflow=u,this._onparse()}};ip.prototype._final=function(t){if(this._partial)return this.destroy(new Error(\"Unexpected end of data\"));t()};K2e.exports=ip});var J2e=_((L$t,z2e)=>{z2e.exports=Be(\"fs\").constants||Be(\"constants\")});var tBe=_((O$t,eBe)=>{var rw=J2e(),X2e=MM(),zQ=k0(),$Bt=Buffer.alloc,Z2e=$C().Readable,nw=$C().Writable,evt=Be(\"string_decoder\").StringDecoder,VQ=aG(),tvt=parseInt(\"755\",8),rvt=parseInt(\"644\",8),$2e=$Bt(1024),cG=function(){},lG=function(t,e){e&=511,e&&t.push($2e.slice(0,512-e))};function nvt(t){switch(t&rw.S_IFMT){case rw.S_IFBLK:return\"block-device\";case rw.S_IFCHR:return\"character-device\";case rw.S_IFDIR:return\"directory\";case rw.S_IFIFO:return\"fifo\";case rw.S_IFLNK:return\"symlink\"}return\"file\"}var JQ=function(t){nw.call(this),this.written=0,this._to=t,this._destroyed=!1};zQ(JQ,nw);JQ.prototype._write=function(t,e,r){if(this.written+=t.length,this._to.push(t))return r();this._to._drain=r};JQ.prototype.destroy=function(){this._destroyed||(this._destroyed=!0,this.emit(\"close\"))};var XQ=function(){nw.call(this),this.linkname=\"\",this._decoder=new evt(\"utf-8\"),this._destroyed=!1};zQ(XQ,nw);XQ.prototype._write=function(t,e,r){this.linkname+=this._decoder.write(t),r()};XQ.prototype.destroy=function(){this._destroyed||(this._destroyed=!0,this.emit(\"close\"))};var bv=function(){nw.call(this),this._destroyed=!1};zQ(bv,nw);bv.prototype._write=function(t,e,r){r(new Error(\"No body allowed for this entry\"))};bv.prototype.destroy=function(){this._destroyed||(this._destroyed=!0,this.emit(\"close\"))};var EA=function(t){if(!(this instanceof EA))return new EA(t);Z2e.call(this,t),this._drain=cG,this._finalized=!1,this._finalizing=!1,this._destroyed=!1,this._stream=null};zQ(EA,Z2e);EA.prototype.entry=function(t,e,r){if(this._stream)throw new Error(\"already piping an entry\");if(!(this._finalized||this._destroyed)){typeof e==\"function\"&&(r=e,e=null),r||(r=cG);var o=this;if((!t.size||t.type===\"symlink\")&&(t.size=0),t.type||(t.type=nvt(t.mode)),t.mode||(t.mode=t.type===\"directory\"?tvt:rvt),t.uid||(t.uid=0),t.gid||(t.gid=0),t.mtime||(t.mtime=new Date),typeof e==\"string\"&&(e=Buffer.from(e)),Buffer.isBuffer(e)){t.size=e.length,this._encode(t);var a=this.push(e);return lG(o,t.size),a?process.nextTick(r):this._drain=r,new bv}if(t.type===\"symlink\"&&!t.linkname){var n=new XQ;return X2e(n,function(A){if(A)return o.destroy(),r(A);t.linkname=n.linkname,o._encode(t),r()}),n}if(this._encode(t),t.type!==\"file\"&&t.type!==\"contiguous-file\")return process.nextTick(r),new bv;var u=new JQ(this);return this._stream=u,X2e(u,function(A){if(o._stream=null,A)return o.destroy(),r(A);if(u.written!==t.size)return o.destroy(),r(new Error(\"size mismatch\"));lG(o,t.size),o._finalizing&&o.finalize(),r()}),u}};EA.prototype.finalize=function(){if(this._stream){this._finalizing=!0;return}this._finalized||(this._finalized=!0,this.push($2e),this.push(null))};EA.prototype.destroy=function(t){this._destroyed||(this._destroyed=!0,t&&this.emit(\"error\",t),this.emit(\"close\"),this._stream&&this._stream.destroy&&this._stream.destroy())};EA.prototype._encode=function(t){if(!t.pax){var e=VQ.encode(t);if(e){this.push(e);return}}this._encodePax(t)};EA.prototype._encodePax=function(t){var e=VQ.encodePax({name:t.name,linkname:t.linkname,pax:t.pax}),r={name:\"PaxHeader\",mode:t.mode,uid:t.uid,gid:t.gid,size:e.length,mtime:t.mtime,type:\"pax-header\",linkname:t.linkname&&\"PaxHeader\",uname:t.uname,gname:t.gname,devmajor:t.devmajor,devminor:t.devminor};this.push(VQ.encode(r)),this.push(e),lG(this,e.length),r.size=t.size,r.type=t.type,this.push(VQ.encode(r))};EA.prototype._read=function(t){var e=this._drain;this._drain=cG,e()};eBe.exports=EA});var rBe=_(uG=>{uG.extract=V2e();uG.pack=tBe()});var hBe=_((ner,pBe)=>{\"use strict\";var Im=class{constructor(e,r,o){this.__specs=e||{},Object.keys(this.__specs).forEach(a=>{if(typeof this.__specs[a]==\"string\"){let n=this.__specs[a],u=this.__specs[n];if(u){let A=u.aliases||[];A.push(a,n),u.aliases=[...new Set(A)],this.__specs[a]=u}else throw new Error(`Alias refers to invalid key: ${n} -> ${a}`)}}),this.__opts=r||{},this.__providers=ABe(o.filter(a=>a!=null&&typeof a==\"object\")),this.__isFiggyPudding=!0}get(e){return dG(this,e,!0)}get[Symbol.toStringTag](){return\"FiggyPudding\"}forEach(e,r=this){for(let[o,a]of this.entries())e.call(r,a,o,this)}toJSON(){let e={};return this.forEach((r,o)=>{e[o]=r}),e}*entries(e){for(let o of Object.keys(this.__specs))yield[o,this.get(o)];let r=e||this.__opts.other;if(r){let o=new Set;for(let a of this.__providers){let n=a.entries?a.entries(r):yvt(a);for(let[u,A]of n)r(u)&&!o.has(u)&&(o.add(u),yield[u,A])}}}*[Symbol.iterator](){for(let[e,r]of this.entries())yield[e,r]}*keys(){for(let[e]of this.entries())yield e}*values(){for(let[,e]of this.entries())yield e}concat(...e){return new Proxy(new Im(this.__specs,this.__opts,ABe(this.__providers).concat(e)),fBe)}};try{let t=Be(\"util\");Im.prototype[t.inspect.custom]=function(e,r){return this[Symbol.toStringTag]+\" \"+t.inspect(this.toJSON(),r)}}catch{}function dvt(t){throw Object.assign(new Error(`invalid config key requested: ${t}`),{code:\"EBADKEY\"})}function dG(t,e,r){let o=t.__specs[e];if(r&&!o&&(!t.__opts.other||!t.__opts.other(e)))dvt(e);else{o||(o={});let a;for(let n of t.__providers){if(a=uBe(e,n),a===void 0&&o.aliases&&o.aliases.length){for(let u of o.aliases)if(u!==e&&(a=uBe(u,n),a!==void 0))break}if(a!==void 0)break}return a===void 0&&o.default!==void 0?typeof o.default==\"function\"?o.default(t):o.default:a}}function uBe(t,e){let r;return e.__isFiggyPudding?r=dG(e,t,!1):typeof e.get==\"function\"?r=e.get(t):r=e[t],r}var fBe={has(t,e){return e in t.__specs&&dG(t,e,!1)!==void 0},ownKeys(t){return Object.keys(t.__specs)},get(t,e){return typeof e==\"symbol\"||e.slice(0,2)===\"__\"||e in Im.prototype?t[e]:t.get(e)},set(t,e,r){if(typeof e==\"symbol\"||e.slice(0,2)===\"__\")return t[e]=r,!0;throw new Error(\"figgyPudding options cannot be modified. Use .concat() instead.\")},deleteProperty(){throw new Error(\"figgyPudding options cannot be deleted. Use .concat() and shadow them instead.\")}};pBe.exports=mvt;function mvt(t,e){function r(...o){return new Proxy(new Im(t,e,o),fBe)}return r}function ABe(t){let e=[];return t.forEach(r=>e.unshift(r)),e}function yvt(t){return Object.keys(t).map(e=>[e,t[e]])}});var mBe=_((ier,IA)=>{\"use strict\";var kv=Be(\"crypto\"),Evt=hBe(),Cvt=Be(\"stream\").Transform,gBe=[\"sha256\",\"sha384\",\"sha512\"],wvt=/^[a-z0-9+/]+(?:=?=?)$/i,Ivt=/^([^-]+)-([^?]+)([?\\S*]*)$/,Bvt=/^([^-]+)-([A-Za-z0-9+/=]{44,88})(\\?[\\x21-\\x7E]*)*$/,vvt=/^[\\x21-\\x7E]+$/,ia=Evt({algorithms:{default:[\"sha512\"]},error:{default:!1},integrity:{},options:{default:[]},pickAlgorithm:{default:()=>Fvt},Promise:{default:()=>Promise},sep:{default:\" \"},single:{default:!1},size:{},strict:{default:!1}}),M0=class{get isHash(){return!0}constructor(e,r){r=ia(r);let o=!!r.strict;this.source=e.trim();let a=this.source.match(o?Bvt:Ivt);if(!a||o&&!gBe.some(u=>u===a[1]))return;this.algorithm=a[1],this.digest=a[2];let n=a[3];this.options=n?n.slice(1).split(\"?\"):[]}hexDigest(){return this.digest&&Buffer.from(this.digest,\"base64\").toString(\"hex\")}toJSON(){return this.toString()}toString(e){if(e=ia(e),e.strict&&!(gBe.some(o=>o===this.algorithm)&&this.digest.match(wvt)&&(this.options||[]).every(o=>o.match(vvt))))return\"\";let r=this.options&&this.options.length?`?${this.options.join(\"?\")}`:\"\";return`${this.algorithm}-${this.digest}${r}`}},Bm=class{get isIntegrity(){return!0}toJSON(){return this.toString()}toString(e){e=ia(e);let r=e.sep||\" \";return e.strict&&(r=r.replace(/\\S+/g,\" \")),Object.keys(this).map(o=>this[o].map(a=>M0.prototype.toString.call(a,e)).filter(a=>a.length).join(r)).filter(o=>o.length).join(r)}concat(e,r){r=ia(r);let o=typeof e==\"string\"?e:xv(e,r);return wA(`${this.toString(r)} ${o}`,r)}hexDigest(){return wA(this,{single:!0}).hexDigest()}match(e,r){r=ia(r);let o=wA(e,r),a=o.pickAlgorithm(r);return this[a]&&o[a]&&this[a].find(n=>o[a].find(u=>n.digest===u.digest))||!1}pickAlgorithm(e){e=ia(e);let r=e.pickAlgorithm,o=Object.keys(this);if(!o.length)throw new Error(`No algorithms available for ${JSON.stringify(this.toString())}`);return o.reduce((a,n)=>r(a,n)||a)}};IA.exports.parse=wA;function wA(t,e){if(e=ia(e),typeof t==\"string\")return mG(t,e);if(t.algorithm&&t.digest){let r=new Bm;return r[t.algorithm]=[t],mG(xv(r,e),e)}else return mG(xv(t,e),e)}function mG(t,e){return e.single?new M0(t,e):t.trim().split(/\\s+/).reduce((r,o)=>{let a=new M0(o,e);if(a.algorithm&&a.digest){let n=a.algorithm;r[n]||(r[n]=[]),r[n].push(a)}return r},new Bm)}IA.exports.stringify=xv;function xv(t,e){return e=ia(e),t.algorithm&&t.digest?M0.prototype.toString.call(t,e):typeof t==\"string\"?xv(wA(t,e),e):Bm.prototype.toString.call(t,e)}IA.exports.fromHex=Dvt;function Dvt(t,e,r){r=ia(r);let o=r.options&&r.options.length?`?${r.options.join(\"?\")}`:\"\";return wA(`${e}-${Buffer.from(t,\"hex\").toString(\"base64\")}${o}`,r)}IA.exports.fromData=Pvt;function Pvt(t,e){e=ia(e);let r=e.algorithms,o=e.options&&e.options.length?`?${e.options.join(\"?\")}`:\"\";return r.reduce((a,n)=>{let u=kv.createHash(n).update(t).digest(\"base64\"),A=new M0(`${n}-${u}${o}`,e);if(A.algorithm&&A.digest){let p=A.algorithm;a[p]||(a[p]=[]),a[p].push(A)}return a},new Bm)}IA.exports.fromStream=Svt;function Svt(t,e){e=ia(e);let r=e.Promise||Promise,o=yG(e);return new r((a,n)=>{t.pipe(o),t.on(\"error\",n),o.on(\"error\",n);let u;o.on(\"integrity\",A=>{u=A}),o.on(\"end\",()=>a(u)),o.on(\"data\",()=>{})})}IA.exports.checkData=bvt;function bvt(t,e,r){if(r=ia(r),e=wA(e,r),!Object.keys(e).length){if(r.error)throw Object.assign(new Error(\"No valid integrity hashes to check against\"),{code:\"EINTEGRITY\"});return!1}let o=e.pickAlgorithm(r),a=kv.createHash(o).update(t).digest(\"base64\"),n=wA({algorithm:o,digest:a}),u=n.match(e,r);if(u||!r.error)return u;if(typeof r.size==\"number\"&&t.length!==r.size){let A=new Error(`data size mismatch when checking ${e}.\n  Wanted: ${r.size}\n  Found: ${t.length}`);throw A.code=\"EBADSIZE\",A.found=t.length,A.expected=r.size,A.sri=e,A}else{let A=new Error(`Integrity checksum failed when using ${o}: Wanted ${e}, but got ${n}. (${t.length} bytes)`);throw A.code=\"EINTEGRITY\",A.found=n,A.expected=e,A.algorithm=o,A.sri=e,A}}IA.exports.checkStream=xvt;function xvt(t,e,r){r=ia(r);let o=r.Promise||Promise,a=yG(r.concat({integrity:e}));return new o((n,u)=>{t.pipe(a),t.on(\"error\",u),a.on(\"error\",u);let A;a.on(\"verified\",p=>{A=p}),a.on(\"end\",()=>n(A)),a.on(\"data\",()=>{})})}IA.exports.integrityStream=yG;function yG(t){t=ia(t);let e=t.integrity&&wA(t.integrity,t),r=e&&Object.keys(e).length,o=r&&e.pickAlgorithm(t),a=r&&e[o],n=Array.from(new Set(t.algorithms.concat(o?[o]:[]))),u=n.map(kv.createHash),A=0,p=new Cvt({transform(h,C,I){A+=h.length,u.forEach(v=>v.update(h,C)),I(null,h,C)}}).on(\"end\",()=>{let h=t.options&&t.options.length?`?${t.options.join(\"?\")}`:\"\",C=wA(u.map((v,x)=>`${n[x]}-${v.digest(\"base64\")}${h}`).join(\" \"),t),I=r&&C.match(e,t);if(typeof t.size==\"number\"&&A!==t.size){let v=new Error(`stream size mismatch when checking ${e}.\n  Wanted: ${t.size}\n  Found: ${A}`);v.code=\"EBADSIZE\",v.found=A,v.expected=t.size,v.sri=e,p.emit(\"error\",v)}else if(t.integrity&&!I){let v=new Error(`${e} integrity checksum failed when using ${o}: wanted ${a} but got ${C}. (${A} bytes)`);v.code=\"EINTEGRITY\",v.found=C,v.expected=a,v.algorithm=o,v.sri=e,p.emit(\"error\",v)}else p.emit(\"size\",A),p.emit(\"integrity\",C),I&&p.emit(\"verified\",I)});return p}IA.exports.create=kvt;function kvt(t){t=ia(t);let e=t.algorithms,r=t.options.length?`?${t.options.join(\"?\")}`:\"\",o=e.map(kv.createHash);return{update:function(a,n){return o.forEach(u=>u.update(a,n)),this},digest:function(a){return e.reduce((u,A)=>{let p=o.shift().digest(\"base64\"),h=new M0(`${A}-${p}${r}`,t);if(h.algorithm&&h.digest){let C=h.algorithm;u[C]||(u[C]=[]),u[C].push(h)}return u},new Bm)}}}var Qvt=new Set(kv.getHashes()),dBe=[\"md5\",\"whirlpool\",\"sha1\",\"sha224\",\"sha256\",\"sha384\",\"sha512\",\"sha3\",\"sha3-256\",\"sha3-384\",\"sha3-512\",\"sha3_256\",\"sha3_384\",\"sha3_512\"].filter(t=>Qvt.has(t));function Fvt(t,e){return dBe.indexOf(t.toLowerCase())>=dBe.indexOf(e.toLowerCase())?t:e}});var KBe=_((air,WBe)=>{var QDt=uL();function FDt(t){return QDt(t)?void 0:t}WBe.exports=FDt});var zBe=_((lir,VBe)=>{var RDt=qb(),TDt=Q8(),NDt=N8(),LDt=Hd(),ODt=hd(),MDt=KBe(),UDt=P_(),_Dt=k8(),HDt=1,jDt=2,qDt=4,GDt=UDt(function(t,e){var r={};if(t==null)return r;var o=!1;e=RDt(e,function(n){return n=LDt(n,t),o||(o=n.length>1),n}),ODt(t,_Dt(t),r),o&&(r=TDt(r,HDt|jDt|qDt,MDt));for(var a=e.length;a--;)NDt(r,e[a]);return r});VBe.exports=GDt});Pt();Ye();Pt();var eve=Be(\"child_process\"),tve=$e($g());qt();var cC=new Map([]);var s2={};Vt(s2,{BaseCommand:()=>ut,WorkspaceRequiredError:()=>rr,getCli:()=>rhe,getDynamicLibs:()=>the,getPluginConfiguration:()=>AC,openWorkspace:()=>uC,pluginCommands:()=>cC,runExit:()=>sk});qt();var ut=class extends nt{constructor(){super(...arguments);this.cwd=ge.String(\"--cwd\",{hidden:!0})}validateAndExecute(){if(typeof this.cwd<\"u\")throw new it(\"The --cwd option is ambiguous when used anywhere else than the very first parameter provided in the command line, before even the command path\");return super.validateAndExecute()}};Ye();Pt();qt();var rr=class extends it{constructor(e,r){let o=V.relative(e,r),a=V.join(e,Ot.fileName);super(`This command can only be run from within a workspace of your project (${o} isn't a workspace of ${a}).`)}};Ye();Pt();nA();Nl();b1();qt();var OAt=$e(Jn());Za();var the=()=>new Map([[\"@yarnpkg/cli\",s2],[\"@yarnpkg/core\",i2],[\"@yarnpkg/fslib\",Ww],[\"@yarnpkg/libzip\",S1],[\"@yarnpkg/parsers\",eI],[\"@yarnpkg/shell\",F1],[\"clipanion\",fI],[\"semver\",OAt],[\"typanion\",Vo]]);Ye();async function uC(t,e){let{project:r,workspace:o}=await St.find(t,e);if(!o)throw new rr(r.cwd,e);return o}Ye();Pt();nA();Nl();b1();qt();var $Dt=$e(Jn());Za();var tH={};Vt(tH,{AddCommand:()=>xh,BinCommand:()=>kh,CacheCleanCommand:()=>Qh,ClipanionCommand:()=>Yd,ConfigCommand:()=>Nh,ConfigGetCommand:()=>Fh,ConfigSetCommand:()=>Rh,ConfigUnsetCommand:()=>Th,DedupeCommand:()=>Lh,EntryCommand:()=>gC,ExecCommand:()=>Oh,ExplainCommand:()=>_h,ExplainPeerRequirementsCommand:()=>Mh,HelpCommand:()=>Wd,InfoCommand:()=>Hh,LinkCommand:()=>qh,NodeCommand:()=>Gh,PluginCheckCommand:()=>Yh,PluginImportCommand:()=>Vh,PluginImportSourcesCommand:()=>zh,PluginListCommand:()=>Wh,PluginRemoveCommand:()=>Jh,PluginRuntimeCommand:()=>Xh,RebuildCommand:()=>Zh,RemoveCommand:()=>$h,RunCommand:()=>e0,RunIndexCommand:()=>zd,SetResolutionCommand:()=>t0,SetVersionCommand:()=>Uh,SetVersionSourcesCommand:()=>Kh,UnlinkCommand:()=>r0,UpCommand:()=>Kf,VersionCommand:()=>Kd,WhyCommand:()=>n0,WorkspaceCommand:()=>o0,WorkspacesListCommand:()=>s0,YarnCommand:()=>jh,dedupeUtils:()=>gk,default:()=>xgt,suggestUtils:()=>Jc});var Tde=$e($g());Ye();Ye();Ye();qt();var q0e=$e(u2());Za();var Jc={};Vt(Jc,{Modifier:()=>D8,Strategy:()=>fk,Target:()=>A2,WorkspaceModifier:()=>M0e,applyModifier:()=>npt,extractDescriptorFromPath:()=>P8,extractRangeModifier:()=>U0e,fetchDescriptorFrom:()=>S8,findProjectDescriptors:()=>j0e,getModifier:()=>f2,getSuggestedDescriptors:()=>p2,makeWorkspaceDescriptor:()=>H0e,toWorkspaceModifier:()=>_0e});Ye();Ye();Pt();var v8=$e(Jn()),tpt=\"workspace:\",A2=(o=>(o.REGULAR=\"dependencies\",o.DEVELOPMENT=\"devDependencies\",o.PEER=\"peerDependencies\",o))(A2||{}),D8=(o=>(o.CARET=\"^\",o.TILDE=\"~\",o.EXACT=\"\",o))(D8||{}),M0e=(o=>(o.CARET=\"^\",o.TILDE=\"~\",o.EXACT=\"*\",o))(M0e||{}),fk=(n=>(n.KEEP=\"keep\",n.REUSE=\"reuse\",n.PROJECT=\"project\",n.LATEST=\"latest\",n.CACHE=\"cache\",n))(fk||{});function f2(t,e){return t.exact?\"\":t.caret?\"^\":t.tilde?\"~\":e.configuration.get(\"defaultSemverRangePrefix\")}var rpt=/^([\\^~]?)[0-9]+(?:\\.[0-9]+){0,2}(?:-\\S+)?$/;function U0e(t,{project:e}){let r=t.match(rpt);return r?r[1]:e.configuration.get(\"defaultSemverRangePrefix\")}function npt(t,e){let{protocol:r,source:o,params:a,selector:n}=W.parseRange(t.range);return v8.default.valid(n)&&(n=`${e}${t.range}`),W.makeDescriptor(t,W.makeRange({protocol:r,source:o,params:a,selector:n}))}function _0e(t){switch(t){case\"^\":return\"^\";case\"~\":return\"~\";case\"\":return\"*\";default:throw new Error(`Assertion failed: Unknown modifier: \"${t}\"`)}}function H0e(t,e){return W.makeDescriptor(t.anchoredDescriptor,`${tpt}${_0e(e)}`)}async function j0e(t,{project:e,target:r}){let o=new Map,a=n=>{let u=o.get(n.descriptorHash);return u||o.set(n.descriptorHash,u={descriptor:n,locators:[]}),u};for(let n of e.workspaces)if(r===\"peerDependencies\"){let u=n.manifest.peerDependencies.get(t.identHash);u!==void 0&&a(u).locators.push(n.anchoredLocator)}else{let u=n.manifest.dependencies.get(t.identHash),A=n.manifest.devDependencies.get(t.identHash);r===\"devDependencies\"?A!==void 0?a(A).locators.push(n.anchoredLocator):u!==void 0&&a(u).locators.push(n.anchoredLocator):u!==void 0?a(u).locators.push(n.anchoredLocator):A!==void 0&&a(A).locators.push(n.anchoredLocator)}return o}async function P8(t,{cwd:e,workspace:r}){return await ipt(async o=>{V.isAbsolute(t)||(t=V.relative(r.cwd,V.resolve(e,t)),t.match(/^\\.{0,2}\\//)||(t=`./${t}`));let{project:a}=r,n=await S8(W.makeIdent(null,\"archive\"),t,{project:r.project,cache:o,workspace:r});if(!n)throw new Error(\"Assertion failed: The descriptor should have been found\");let u=new Qi,A=a.configuration.makeResolver(),p=a.configuration.makeFetcher(),h={checksums:a.storedChecksums,project:a,cache:o,fetcher:p,report:u,resolver:A},C=A.bindDescriptor(n,r.anchoredLocator,h),I=W.convertDescriptorToLocator(C),v=await p.fetch(I,h),x=await Ot.find(v.prefixPath,{baseFs:v.packageFs});if(!x.name)throw new Error(\"Target path doesn't have a name\");return W.makeDescriptor(x.name,t)})}async function p2(t,{project:e,workspace:r,cache:o,target:a,fixed:n,modifier:u,strategies:A,maxResults:p=1/0}){if(!(p>=0))throw new Error(`Invalid maxResults (${p})`);let[h,C]=t.range!==\"unknown\"?n||kr.validRange(t.range)||!t.range.match(/^[a-z0-9._-]+$/i)?[t.range,\"latest\"]:[\"unknown\",t.range]:[\"unknown\",\"latest\"];if(h!==\"unknown\")return{suggestions:[{descriptor:t,name:`Use ${W.prettyDescriptor(e.configuration,t)}`,reason:\"(unambiguous explicit request)\"}],rejections:[]};let I=typeof r<\"u\"&&r!==null&&r.manifest[a].get(t.identHash)||null,v=[],x=[],E=async R=>{try{await R()}catch(L){x.push(L)}};for(let R of A){if(v.length>=p)break;switch(R){case\"keep\":await E(async()=>{I&&v.push({descriptor:I,name:`Keep ${W.prettyDescriptor(e.configuration,I)}`,reason:\"(no changes)\"})});break;case\"reuse\":await E(async()=>{for(let{descriptor:L,locators:U}of(await j0e(t,{project:e,target:a})).values()){if(U.length===1&&U[0].locatorHash===r.anchoredLocator.locatorHash&&A.includes(\"keep\"))continue;let z=`(originally used by ${W.prettyLocator(e.configuration,U[0])}`;z+=U.length>1?` and ${U.length-1} other${U.length>2?\"s\":\"\"})`:\")\",v.push({descriptor:L,name:`Reuse ${W.prettyDescriptor(e.configuration,L)}`,reason:z})}});break;case\"cache\":await E(async()=>{for(let L of e.storedDescriptors.values())L.identHash===t.identHash&&v.push({descriptor:L,name:`Reuse ${W.prettyDescriptor(e.configuration,L)}`,reason:\"(already used somewhere in the lockfile)\"})});break;case\"project\":await E(async()=>{if(r.manifest.name!==null&&t.identHash===r.manifest.name.identHash)return;let L=e.tryWorkspaceByIdent(t);if(L===null)return;let U=H0e(L,u);v.push({descriptor:U,name:`Attach ${W.prettyDescriptor(e.configuration,U)}`,reason:`(local workspace at ${de.pretty(e.configuration,L.relativeCwd,de.Type.PATH)})`})});break;case\"latest\":{let L=e.configuration.get(\"enableNetwork\"),U=e.configuration.get(\"enableOfflineMode\");await E(async()=>{if(a===\"peerDependencies\")v.push({descriptor:W.makeDescriptor(t,\"*\"),name:\"Use *\",reason:\"(catch-all peer dependency pattern)\"});else if(!L&&!U)v.push({descriptor:null,name:\"Resolve from latest\",reason:de.pretty(e.configuration,\"(unavailable because enableNetwork is toggled off)\",\"grey\")});else{let z=await S8(t,C,{project:e,cache:o,workspace:r,modifier:u});z&&v.push({descriptor:z,name:`Use ${W.prettyDescriptor(e.configuration,z)}`,reason:`(resolved from ${U?\"the cache\":\"latest\"})`})}})}break}}return{suggestions:v.slice(0,p),rejections:x.slice(0,p)}}async function S8(t,e,{project:r,cache:o,workspace:a,preserveModifier:n=!0,modifier:u}){let A=r.configuration.normalizeDependency(W.makeDescriptor(t,e)),p=new Qi,h=r.configuration.makeFetcher(),C=r.configuration.makeResolver(),I={project:r,fetcher:h,cache:o,checksums:r.storedChecksums,report:p,cacheOptions:{skipIntegrityCheck:!0}},v={...I,resolver:C,fetchOptions:I},x=C.bindDescriptor(A,a.anchoredLocator,v),E=await C.getCandidates(x,{},v);if(E.length===0)return null;let R=E[0],{protocol:L,source:U,params:z,selector:te}=W.parseRange(W.convertToManifestRange(R.reference));if(L===r.configuration.get(\"defaultProtocol\")&&(L=null),v8.default.valid(te)){let le=te;if(typeof u<\"u\")te=u+te;else if(n!==!1){let ye=typeof n==\"string\"?n:A.range;te=U0e(ye,{project:r})+te}let he=W.makeDescriptor(R,W.makeRange({protocol:L,source:U,params:z,selector:te}));(await C.getCandidates(r.configuration.normalizeDependency(he),{},v)).length!==1&&(te=le)}return W.makeDescriptor(R,W.makeRange({protocol:L,source:U,params:z,selector:te}))}async function ipt(t){return await oe.mktempPromise(async e=>{let r=Ke.create(e);return r.useWithSource(e,{enableMirror:!1,compressionLevel:0},e,{overwrite:!0}),await t(new Lr(e,{configuration:r,check:!1,immutable:!1}))})}var xh=class extends ut{constructor(){super(...arguments);this.json=ge.Boolean(\"--json\",!1,{description:\"Format the output as an NDJSON stream\"});this.fixed=ge.Boolean(\"-F,--fixed\",!1,{description:\"Store dependency tags as-is instead of resolving them\"});this.exact=ge.Boolean(\"-E,--exact\",!1,{description:\"Don't use any semver modifier on the resolved range\"});this.tilde=ge.Boolean(\"-T,--tilde\",!1,{description:\"Use the `~` semver modifier on the resolved range\"});this.caret=ge.Boolean(\"-C,--caret\",!1,{description:\"Use the `^` semver modifier on the resolved range\"});this.dev=ge.Boolean(\"-D,--dev\",!1,{description:\"Add a package as a dev dependency\"});this.peer=ge.Boolean(\"-P,--peer\",!1,{description:\"Add a package as a peer dependency\"});this.optional=ge.Boolean(\"-O,--optional\",!1,{description:\"Add / upgrade a package to an optional regular / peer dependency\"});this.preferDev=ge.Boolean(\"--prefer-dev\",!1,{description:\"Add / upgrade a package to a dev dependency\"});this.interactive=ge.Boolean(\"-i,--interactive\",{description:\"Reuse the specified package from other workspaces in the project\"});this.cached=ge.Boolean(\"--cached\",!1,{description:\"Reuse the highest version already used somewhere within the project\"});this.mode=ge.String(\"--mode\",{description:\"Change what artifacts installs generate\",validator:Ks(pl)});this.silent=ge.Boolean(\"--silent\",{hidden:!0});this.packages=ge.Rest()}async execute(){let r=await Ke.find(this.context.cwd,this.context.plugins),{project:o,workspace:a}=await St.find(r,this.context.cwd),n=await Lr.find(r);if(!a)throw new rr(o.cwd,this.context.cwd);await o.restoreInstallState({restoreResolutions:!1});let u=this.fixed,A=this.interactive??r.get(\"preferInteractive\"),p=A||r.get(\"preferReuse\"),h=f2(this,o),C=[p?\"reuse\":void 0,\"project\",this.cached?\"cache\":void 0,\"latest\"].filter(U=>typeof U<\"u\"),I=A?1/0:1,v=await Promise.all(this.packages.map(async U=>{let z=U.match(/^\\.{0,2}\\//)?await P8(U,{cwd:this.context.cwd,workspace:a}):W.tryParseDescriptor(U),te=U.match(/^(https?:|git@github)/);if(te)throw new it(`It seems you are trying to add a package using a ${de.pretty(r,`${te[0]}...`,de.Type.RANGE)} url; we now require package names to be explicitly specified.\nTry running the command again with the package name prefixed: ${de.pretty(r,\"yarn add\",de.Type.CODE)} ${de.pretty(r,W.makeDescriptor(W.makeIdent(null,\"my-package\"),`${te[0]}...`),de.Type.DESCRIPTOR)}`);if(!z)throw new it(`The ${de.pretty(r,U,de.Type.CODE)} string didn't match the required format (package-name@range). Did you perhaps forget to explicitly reference the package name?`);let le=spt(a,z,{dev:this.dev,peer:this.peer,preferDev:this.preferDev,optional:this.optional});return await Promise.all(le.map(async Ae=>{let ye=await p2(z,{project:o,workspace:a,cache:n,fixed:u,target:Ae,modifier:h,strategies:C,maxResults:I});return{request:z,suggestedDescriptors:ye,target:Ae}}))})).then(U=>U.flat()),x=await AA.start({configuration:r,stdout:this.context.stdout,suggestInstall:!1},async U=>{for(let{request:z,suggestedDescriptors:{suggestions:te,rejections:le}}of v)if(te.filter(Ae=>Ae.descriptor!==null).length===0){let[Ae]=le;if(typeof Ae>\"u\")throw new Error(\"Assertion failed: Expected an error to have been set\");o.configuration.get(\"enableNetwork\")?U.reportError(27,`${W.prettyDescriptor(r,z)} can't be resolved to a satisfying range`):U.reportError(27,`${W.prettyDescriptor(r,z)} can't be resolved to a satisfying range (note: network resolution has been disabled)`),U.reportSeparator(),U.reportExceptionOnce(Ae)}});if(x.hasErrors())return x.exitCode();let E=!1,R=[],L=[];for(let{suggestedDescriptors:{suggestions:U},target:z}of v){let te,le=U.filter(ae=>ae.descriptor!==null),he=le[0].descriptor,Ae=le.every(ae=>W.areDescriptorsEqual(ae.descriptor,he));le.length===1||Ae?te=he:(E=!0,{answer:te}=await(0,q0e.prompt)({type:\"select\",name:\"answer\",message:\"Which range do you want to use?\",choices:U.map(({descriptor:ae,name:Ie,reason:Fe})=>ae?{name:Ie,hint:Fe,descriptor:ae}:{name:Ie,hint:Fe,disabled:!0}),onCancel:()=>process.exit(130),result(ae){return this.find(ae,\"descriptor\")},stdin:this.context.stdin,stdout:this.context.stdout}));let ye=a.manifest[z].get(te.identHash);(typeof ye>\"u\"||ye.descriptorHash!==te.descriptorHash)&&(a.manifest[z].set(te.identHash,te),this.optional&&(z===\"dependencies\"?a.manifest.ensureDependencyMeta({...te,range:\"unknown\"}).optional=!0:z===\"peerDependencies\"&&(a.manifest.ensurePeerDependencyMeta({...te,range:\"unknown\"}).optional=!0)),typeof ye>\"u\"?R.push([a,z,te,C]):L.push([a,z,ye,te]))}return await r.triggerMultipleHooks(U=>U.afterWorkspaceDependencyAddition,R),await r.triggerMultipleHooks(U=>U.afterWorkspaceDependencyReplacement,L),E&&this.context.stdout.write(`\n`),await o.installWithNewReport({json:this.json,stdout:this.context.stdout,quiet:this.context.quiet},{cache:n,mode:this.mode})}};xh.paths=[[\"add\"]],xh.usage=nt.Usage({description:\"add dependencies to the project\",details:\"\\n      This command adds a package to the package.json for the nearest workspace.\\n\\n      - If it didn't exist before, the package will by default be added to the regular `dependencies` field, but this behavior can be overriden thanks to the `-D,--dev` flag (which will cause the dependency to be added to the `devDependencies` field instead) and the `-P,--peer` flag (which will do the same but for `peerDependencies`).\\n\\n      - If the package was already listed in your dependencies, it will by default be upgraded whether it's part of your `dependencies` or `devDependencies` (it won't ever update `peerDependencies`, though).\\n\\n      - If set, the `--prefer-dev` flag will operate as a more flexible `-D,--dev` in that it will add the package to your `devDependencies` if it isn't already listed in either `dependencies` or `devDependencies`, but it will also happily upgrade your `dependencies` if that's what you already use (whereas `-D,--dev` would throw an exception).\\n\\n      - If set, the `-O,--optional` flag will add the package to the `optionalDependencies` field and, in combination with the `-P,--peer` flag, it will add the package as an optional peer dependency. If the package was already listed in your `dependencies`, it will be upgraded to `optionalDependencies`. If the package was already listed in your `peerDependencies`, in combination with the `-P,--peer` flag, it will be upgraded to an optional peer dependency: `\\\"peerDependenciesMeta\\\": { \\\"<package>\\\": { \\\"optional\\\": true } }`\\n\\n      - If the added package doesn't specify a range at all its `latest` tag will be resolved and the returned version will be used to generate a new semver range (using the `^` modifier by default unless otherwise configured via the `defaultSemverRangePrefix` configuration, or the `~` modifier if `-T,--tilde` is specified, or no modifier at all if `-E,--exact` is specified). Two exceptions to this rule: the first one is that if the package is a workspace then its local version will be used, and the second one is that if you use `-P,--peer` the default range will be `*` and won't be resolved at all.\\n\\n      - If the added package specifies a range (such as `^1.0.0`, `latest`, or `rc`), Yarn will add this range as-is in the resulting package.json entry (in particular, tags such as `rc` will be encoded as-is rather than being converted into a semver range).\\n\\n      If the `--cached` option is used, Yarn will preferably reuse the highest version already used somewhere within the project, even if through a transitive dependency.\\n\\n      If the `-i,--interactive` option is used (or if the `preferInteractive` settings is toggled on) the command will first try to check whether other workspaces in the project use the specified package and, if so, will offer to reuse them.\\n\\n      If the `--mode=<mode>` option is set, Yarn will change which artifacts are generated. The modes currently supported are:\\n\\n      - `skip-build` will not run the build scripts at all. Note that this is different from setting `enableScripts` to false because the latter will disable build scripts, and thus affect the content of the artifacts generated on disk, whereas the former will just disable the build step - but not the scripts themselves, which just won't run.\\n\\n      - `update-lockfile` will skip the link step altogether, and only fetch packages that are missing from the lockfile (or that have no associated checksums). This mode is typically used by tools like Renovate or Dependabot to keep a lockfile up-to-date without incurring the full install cost.\\n\\n      For a compilation of all the supported protocols, please consult the dedicated page from our website: https://yarnpkg.com/features/protocols.\\n    \",examples:[[\"Add a regular package to the current workspace\",\"$0 add lodash\"],[\"Add a specific version for a package to the current workspace\",\"$0 add lodash@1.2.3\"],[\"Add a package from a GitHub repository (the master branch) to the current workspace using a URL\",\"$0 add lodash@https://github.com/lodash/lodash\"],[\"Add a package from a GitHub repository (the master branch) to the current workspace using the GitHub protocol\",\"$0 add lodash@github:lodash/lodash\"],[\"Add a package from a GitHub repository (the master branch) to the current workspace using the GitHub protocol (shorthand)\",\"$0 add lodash@lodash/lodash\"],[\"Add a package from a specific branch of a GitHub repository to the current workspace using the GitHub protocol (shorthand)\",\"$0 add lodash-es@lodash/lodash#es\"]]});function spt(t,e,{dev:r,peer:o,preferDev:a,optional:n}){let u=t.manifest[\"dependencies\"].has(e.identHash),A=t.manifest[\"devDependencies\"].has(e.identHash),p=t.manifest[\"peerDependencies\"].has(e.identHash);if((r||o)&&u)throw new it(`Package \"${W.prettyIdent(t.project.configuration,e)}\" is already listed as a regular dependency - remove the -D,-P flags or remove it from your dependencies first`);if(!r&&!o&&p)throw new it(`Package \"${W.prettyIdent(t.project.configuration,e)}\" is already listed as a peer dependency - use either of -D or -P, or remove it from your peer dependencies first`);if(n&&A)throw new it(`Package \"${W.prettyIdent(t.project.configuration,e)}\" is already listed as a dev dependency - remove the -O flag or remove it from your dev dependencies first`);if(n&&!o&&p)throw new it(`Package \"${W.prettyIdent(t.project.configuration,e)}\" is already listed as a peer dependency - remove the -O flag or add the -P flag or remove it from your peer dependencies first`);if((r||a)&&n)throw new it(`Package \"${W.prettyIdent(t.project.configuration,e)}\" cannot simultaneously be a dev dependency and an optional dependency`);let h=[];return o&&h.push(\"peerDependencies\"),(r||a)&&h.push(\"devDependencies\"),n&&h.push(\"dependencies\"),h.length>0?h:A?[\"devDependencies\"]:p?[\"peerDependencies\"]:[\"dependencies\"]}Ye();Ye();qt();var kh=class extends ut{constructor(){super(...arguments);this.verbose=ge.Boolean(\"-v,--verbose\",!1,{description:\"Print both the binary name and the locator of the package that provides the binary\"});this.json=ge.Boolean(\"--json\",!1,{description:\"Format the output as an NDJSON stream\"});this.name=ge.String({required:!1})}async execute(){let r=await Ke.find(this.context.cwd,this.context.plugins),{project:o,locator:a}=await St.find(r,this.context.cwd);if(await o.restoreInstallState(),this.name){let A=(await un.getPackageAccessibleBinaries(a,{project:o})).get(this.name);if(!A)throw new it(`Couldn't find a binary named \"${this.name}\" for package \"${W.prettyLocator(r,a)}\"`);let[,p]=A;return this.context.stdout.write(`${p}\n`),0}return(await Nt.start({configuration:r,json:this.json,stdout:this.context.stdout},async u=>{let A=await un.getPackageAccessibleBinaries(a,{project:o}),h=Array.from(A.keys()).reduce((C,I)=>Math.max(C,I.length),0);for(let[C,[I,v]]of A)u.reportJson({name:C,source:W.stringifyIdent(I),path:v});if(this.verbose)for(let[C,[I]]of A)u.reportInfo(null,`${C.padEnd(h,\" \")}   ${W.prettyLocator(r,I)}`);else for(let C of A.keys())u.reportInfo(null,C)})).exitCode()}};kh.paths=[[\"bin\"]],kh.usage=nt.Usage({description:\"get the path to a binary script\",details:`\n      When used without arguments, this command will print the list of all the binaries available in the current workspace. Adding the \\`-v,--verbose\\` flag will cause the output to contain both the binary name and the locator of the package that provides the binary.\n\n      When an argument is specified, this command will just print the path to the binary on the standard output and exit. Note that the reported path may be stored within a zip archive.\n    `,examples:[[\"List all the available binaries\",\"$0 bin\"],[\"Print the path to a specific binary\",\"$0 bin eslint\"]]});Ye();Pt();qt();var Qh=class extends ut{constructor(){super(...arguments);this.mirror=ge.Boolean(\"--mirror\",!1,{description:\"Remove the global cache files instead of the local cache files\"});this.all=ge.Boolean(\"--all\",!1,{description:\"Remove both the global cache files and the local cache files of the current project\"})}async execute(){let r=await Ke.find(this.context.cwd,this.context.plugins),o=await Lr.find(r);return(await Nt.start({configuration:r,stdout:this.context.stdout},async()=>{let n=(this.all||this.mirror)&&o.mirrorCwd!==null,u=!this.mirror;n&&(await oe.removePromise(o.mirrorCwd),await r.triggerHook(A=>A.cleanGlobalArtifacts,r)),u&&await oe.removePromise(o.cwd)})).exitCode()}};Qh.paths=[[\"cache\",\"clean\"],[\"cache\",\"clear\"]],Qh.usage=nt.Usage({description:\"remove the shared cache files\",details:`\n      This command will remove all the files from the cache.\n    `,examples:[[\"Remove all the local archives\",\"$0 cache clean\"],[\"Remove all the archives stored in the ~/.yarn directory\",\"$0 cache clean --mirror\"]]});Ye();qt();var Y0e=$e(h2()),b8=Be(\"util\"),Fh=class extends ut{constructor(){super(...arguments);this.why=ge.Boolean(\"--why\",!1,{description:\"Print the explanation for why a setting has its value\"});this.json=ge.Boolean(\"--json\",!1,{description:\"Format the output as an NDJSON stream\"});this.unsafe=ge.Boolean(\"--no-redacted\",!1,{description:\"Don't redact secrets (such as tokens) from the output\"});this.name=ge.String()}async execute(){let r=await Ke.find(this.context.cwd,this.context.plugins),o=this.name.replace(/[.[].*$/,\"\"),a=this.name.replace(/^[^.[]*/,\"\");if(typeof r.settings.get(o)>\"u\")throw new it(`Couldn't find a configuration settings named \"${o}\"`);let u=r.getSpecial(o,{hideSecrets:!this.unsafe,getNativePaths:!0}),A=je.convertMapsToIndexableObjects(u),p=a?(0,Y0e.default)(A,a):A,h=await Nt.start({configuration:r,includeFooter:!1,json:this.json,stdout:this.context.stdout},async C=>{C.reportJson(p)});if(!this.json){if(typeof p==\"string\")return this.context.stdout.write(`${p}\n`),h.exitCode();b8.inspect.styles.name=\"cyan\",this.context.stdout.write(`${(0,b8.inspect)(p,{depth:1/0,colors:r.get(\"enableColors\"),compact:!1})}\n`)}return h.exitCode()}};Fh.paths=[[\"config\",\"get\"]],Fh.usage=nt.Usage({description:\"read a configuration settings\",details:`\n      This command will print a configuration setting.\n\n      Secrets (such as tokens) will be redacted from the output by default. If this behavior isn't desired, set the \\`--no-redacted\\` to get the untransformed value.\n    `,examples:[[\"Print a simple configuration setting\",\"yarn config get yarnPath\"],[\"Print a complex configuration setting\",\"yarn config get packageExtensions\"],[\"Print a nested field from the configuration\",`yarn config get 'npmScopes[\"my-company\"].npmRegistryServer'`],[\"Print a token from the configuration\",\"yarn config get npmAuthToken --no-redacted\"],[\"Print a configuration setting as JSON\",\"yarn config get packageExtensions --json\"]]});Ye();qt();var Nge=$e(F8()),Lge=$e(h2()),Oge=$e(R8()),T8=Be(\"util\"),Rh=class extends ut{constructor(){super(...arguments);this.json=ge.Boolean(\"--json\",!1,{description:\"Set complex configuration settings to JSON values\"});this.home=ge.Boolean(\"-H,--home\",!1,{description:\"Update the home configuration instead of the project configuration\"});this.name=ge.String();this.value=ge.String()}async execute(){let r=await Ke.find(this.context.cwd,this.context.plugins),o=()=>{if(!r.projectCwd)throw new it(\"This command must be run from within a project folder\");return r.projectCwd},a=this.name.replace(/[.[].*$/,\"\"),n=this.name.replace(/^[^.[]*\\.?/,\"\");if(typeof r.settings.get(a)>\"u\")throw new it(`Couldn't find a configuration settings named \"${a}\"`);if(a===\"enableStrictSettings\")throw new it(\"This setting only affects the file it's in, and thus cannot be set from the CLI\");let A=this.json?JSON.parse(this.value):this.value;await(this.home?E=>Ke.updateHomeConfiguration(E):E=>Ke.updateConfiguration(o(),E))(E=>{if(n){let R=(0,Nge.default)(E);return(0,Oge.default)(R,this.name,A),R}else return{...E,[a]:A}});let C=(await Ke.find(this.context.cwd,this.context.plugins)).getSpecial(a,{hideSecrets:!0,getNativePaths:!0}),I=je.convertMapsToIndexableObjects(C),v=n?(0,Lge.default)(I,n):I;return(await Nt.start({configuration:r,includeFooter:!1,stdout:this.context.stdout},async E=>{T8.inspect.styles.name=\"cyan\",E.reportInfo(0,`Successfully set ${this.name} to ${(0,T8.inspect)(v,{depth:1/0,colors:r.get(\"enableColors\"),compact:!1})}`)})).exitCode()}};Rh.paths=[[\"config\",\"set\"]],Rh.usage=nt.Usage({description:\"change a configuration settings\",details:`\n      This command will set a configuration setting.\n\n      When used without the \\`--json\\` flag, it can only set a simple configuration setting (a string, a number, or a boolean).\n\n      When used with the \\`--json\\` flag, it can set both simple and complex configuration settings, including Arrays and Objects.\n    `,examples:[[\"Set a simple configuration setting (a string, a number, or a boolean)\",\"yarn config set initScope myScope\"],[\"Set a simple configuration setting (a string, a number, or a boolean) using the `--json` flag\",'yarn config set initScope --json \\\\\"myScope\\\\\"'],[\"Set a complex configuration setting (an Array) using the `--json` flag\",`yarn config set unsafeHttpWhitelist --json '[\"*.example.com\", \"example.com\"]'`],[\"Set a complex configuration setting (an Object) using the `--json` flag\",`yarn config set packageExtensions --json '{ \"@babel/parser@*\": { \"dependencies\": { \"@babel/types\": \"*\" } } }'`],[\"Set a nested configuration setting\",'yarn config set npmScopes.company.npmRegistryServer \"https://npm.example.com\"'],[\"Set a nested configuration setting using indexed access for non-simple keys\",`yarn config set 'npmRegistries[\"//npm.example.com\"].npmAuthToken' \"ffffffff-ffff-ffff-ffff-ffffffffffff\"`]]});Ye();qt();var Vge=$e(F8()),zge=$e(Hge()),Jge=$e(L8()),Th=class extends ut{constructor(){super(...arguments);this.home=ge.Boolean(\"-H,--home\",!1,{description:\"Update the home configuration instead of the project configuration\"});this.name=ge.String()}async execute(){let r=await Ke.find(this.context.cwd,this.context.plugins),o=()=>{if(!r.projectCwd)throw new it(\"This command must be run from within a project folder\");return r.projectCwd},a=this.name.replace(/[.[].*$/,\"\"),n=this.name.replace(/^[^.[]*\\.?/,\"\");if(typeof r.settings.get(a)>\"u\")throw new it(`Couldn't find a configuration settings named \"${a}\"`);let A=this.home?h=>Ke.updateHomeConfiguration(h):h=>Ke.updateConfiguration(o(),h);return(await Nt.start({configuration:r,includeFooter:!1,stdout:this.context.stdout},async h=>{let C=!1;await A(I=>{if(!(0,zge.default)(I,this.name))return h.reportWarning(0,`Configuration doesn't contain setting ${this.name}; there is nothing to unset`),C=!0,I;let v=n?(0,Vge.default)(I):{...I};return(0,Jge.default)(v,this.name),v}),C||h.reportInfo(0,`Successfully unset ${this.name}`)})).exitCode()}};Th.paths=[[\"config\",\"unset\"]],Th.usage=nt.Usage({description:\"unset a configuration setting\",details:`\n      This command will unset a configuration setting.\n    `,examples:[[\"Unset a simple configuration setting\",\"yarn config unset initScope\"],[\"Unset a complex configuration setting\",\"yarn config unset packageExtensions\"],[\"Unset a nested configuration setting\",\"yarn config unset npmScopes.company.npmRegistryServer\"]]});Ye();Pt();qt();var hk=Be(\"util\"),Nh=class extends ut{constructor(){super(...arguments);this.noDefaults=ge.Boolean(\"--no-defaults\",!1,{description:\"Omit the default values from the display\"});this.json=ge.Boolean(\"--json\",!1,{description:\"Format the output as an NDJSON stream\"});this.verbose=ge.Boolean(\"-v,--verbose\",{hidden:!0});this.why=ge.Boolean(\"--why\",{hidden:!0});this.names=ge.Rest()}async execute(){let r=await Ke.find(this.context.cwd,this.context.plugins,{strict:!1}),o=await TE({configuration:r,stdout:this.context.stdout,forceError:this.json},[{option:this.verbose,message:\"The --verbose option is deprecated, the settings' descriptions are now always displayed\"},{option:this.why,message:\"The --why option is deprecated, the settings' sources are now always displayed\"}]);if(o!==null)return o;let a=this.names.length>0?[...new Set(this.names)].sort():[...r.settings.keys()].sort(),n,u=await Nt.start({configuration:r,json:this.json,stdout:this.context.stdout,includeFooter:!1},async A=>{if(r.invalid.size>0&&!this.json){for(let[p,h]of r.invalid)A.reportError(34,`Invalid configuration key \"${p}\" in ${h}`);A.reportSeparator()}if(this.json)for(let p of a){let h=r.settings.get(p);typeof h>\"u\"&&A.reportError(34,`No configuration key named \"${p}\"`);let C=r.getSpecial(p,{hideSecrets:!0,getNativePaths:!0}),I=r.sources.get(p)??\"<default>\",v=I&&I[0]!==\"<\"?ue.fromPortablePath(I):I;A.reportJson({key:p,effective:C,source:v,...h})}else{let p={breakLength:1/0,colors:r.get(\"enableColors\"),maxArrayLength:2},h={},C={children:h};for(let I of a){if(this.noDefaults&&!r.sources.has(I))continue;let v=r.settings.get(I),x=r.sources.get(I)??\"<default>\",E=r.getSpecial(I,{hideSecrets:!0,getNativePaths:!0}),R={Description:{label:\"Description\",value:de.tuple(de.Type.MARKDOWN,{text:v.description,format:this.cli.format(),paragraphs:!1})},Source:{label:\"Source\",value:de.tuple(x[0]===\"<\"?de.Type.CODE:de.Type.PATH,x)}};h[I]={value:de.tuple(de.Type.CODE,I),children:R};let L=(U,z)=>{for(let[te,le]of z)if(le instanceof Map){let he={};U[te]={children:he},L(he,le)}else U[te]={label:te,value:de.tuple(de.Type.NO_HINT,(0,hk.inspect)(le,p))}};E instanceof Map?L(R,E):R.Value={label:\"Value\",value:de.tuple(de.Type.NO_HINT,(0,hk.inspect)(E,p))}}a.length!==1&&(n=void 0),$s.emitTree(C,{configuration:r,json:this.json,stdout:this.context.stdout,separators:2})}});if(!this.json&&typeof n<\"u\"){let A=a[0],p=(0,hk.inspect)(r.getSpecial(A,{hideSecrets:!0,getNativePaths:!0}),{colors:r.get(\"enableColors\")});this.context.stdout.write(`\n`),this.context.stdout.write(`${p}\n`)}return u.exitCode()}};Nh.paths=[[\"config\"]],Nh.usage=nt.Usage({description:\"display the current configuration\",details:`\n      This command prints the current active configuration settings.\n    `,examples:[[\"Print the active configuration settings\",\"$0 config\"]]});Ye();qt();Za();var gk={};Vt(gk,{Strategy:()=>g2,acceptedStrategies:()=>H0t,dedupe:()=>O8});Ye();Ye();var Xge=$e(Zo()),g2=(e=>(e.HIGHEST=\"highest\",e))(g2||{}),H0t=new Set(Object.values(g2)),j0t={highest:async(t,e,{resolver:r,fetcher:o,resolveOptions:a,fetchOptions:n})=>{let u=new Map;for(let[p,h]of t.storedResolutions){let C=t.storedDescriptors.get(p);if(typeof C>\"u\")throw new Error(`Assertion failed: The descriptor (${p}) should have been registered`);je.getSetWithDefault(u,C.identHash).add(h)}let A=new Map(je.mapAndFilter(t.storedDescriptors.values(),p=>W.isVirtualDescriptor(p)?je.mapAndFilter.skip:[p.descriptorHash,je.makeDeferred()]));for(let p of t.storedDescriptors.values()){let h=A.get(p.descriptorHash);if(typeof h>\"u\")throw new Error(`Assertion failed: The descriptor (${p.descriptorHash}) should have been registered`);let C=t.storedResolutions.get(p.descriptorHash);if(typeof C>\"u\")throw new Error(`Assertion failed: The resolution (${p.descriptorHash}) should have been registered`);let I=t.originalPackages.get(C);if(typeof I>\"u\")throw new Error(`Assertion failed: The package (${C}) should have been registered`);Promise.resolve().then(async()=>{let v=r.getResolutionDependencies(p,a),x=Object.fromEntries(await je.allSettledSafe(Object.entries(v).map(async([te,le])=>{let he=A.get(le.descriptorHash);if(typeof he>\"u\")throw new Error(`Assertion failed: The descriptor (${le.descriptorHash}) should have been registered`);let Ae=await he.promise;if(!Ae)throw new Error(\"Assertion failed: Expected the dependency to have been through the dedupe process itself\");return[te,Ae.updatedPackage]})));if(e.length&&!Xge.default.isMatch(W.stringifyIdent(p),e)||!r.shouldPersistResolution(I,a))return I;let E=u.get(p.identHash);if(typeof E>\"u\")throw new Error(`Assertion failed: The resolutions (${p.identHash}) should have been registered`);if(E.size===1)return I;let R=[...E].map(te=>{let le=t.originalPackages.get(te);if(typeof le>\"u\")throw new Error(`Assertion failed: The package (${te}) should have been registered`);return le}),L=await r.getSatisfying(p,x,R,a),U=L.locators?.[0];if(typeof U>\"u\"||!L.sorted)return I;let z=t.originalPackages.get(U.locatorHash);if(typeof z>\"u\")throw new Error(`Assertion failed: The package (${U.locatorHash}) should have been registered`);return z}).then(async v=>{let x=await t.preparePackage(v,{resolver:r,resolveOptions:a});h.resolve({descriptor:p,currentPackage:I,updatedPackage:v,resolvedPackage:x})}).catch(v=>{h.reject(v)})}return[...A.values()].map(p=>p.promise)}};async function O8(t,{strategy:e,patterns:r,cache:o,report:a}){let{configuration:n}=t,u=new Qi,A=n.makeResolver(),p=n.makeFetcher(),h={cache:o,checksums:t.storedChecksums,fetcher:p,project:t,report:u,cacheOptions:{skipIntegrityCheck:!0}},C={project:t,resolver:A,report:u,fetchOptions:h};return await a.startTimerPromise(\"Deduplication step\",async()=>{let I=j0t[e],v=await I(t,r,{resolver:A,resolveOptions:C,fetcher:p,fetchOptions:h}),x=Xs.progressViaCounter(v.length);await a.reportProgress(x);let E=0;await Promise.all(v.map(U=>U.then(z=>{if(z===null||z.currentPackage.locatorHash===z.updatedPackage.locatorHash)return;E++;let{descriptor:te,currentPackage:le,updatedPackage:he}=z;a.reportInfo(0,`${W.prettyDescriptor(n,te)} can be deduped from ${W.prettyLocator(n,le)} to ${W.prettyLocator(n,he)}`),a.reportJson({descriptor:W.stringifyDescriptor(te),currentResolution:W.stringifyLocator(le),updatedResolution:W.stringifyLocator(he)}),t.storedResolutions.set(te.descriptorHash,he.locatorHash)}).finally(()=>x.tick())));let R;switch(E){case 0:R=\"No packages\";break;case 1:R=\"One package\";break;default:R=`${E} packages`}let L=de.pretty(n,e,de.Type.CODE);return a.reportInfo(0,`${R} can be deduped using the ${L} strategy`),E})}var Lh=class extends ut{constructor(){super(...arguments);this.strategy=ge.String(\"-s,--strategy\",\"highest\",{description:\"The strategy to use when deduping dependencies\",validator:Ks(g2)});this.check=ge.Boolean(\"-c,--check\",!1,{description:\"Exit with exit code 1 when duplicates are found, without persisting the dependency tree\"});this.json=ge.Boolean(\"--json\",!1,{description:\"Format the output as an NDJSON stream\"});this.mode=ge.String(\"--mode\",{description:\"Change what artifacts installs generate\",validator:Ks(pl)});this.patterns=ge.Rest()}async execute(){let r=await Ke.find(this.context.cwd,this.context.plugins),{project:o}=await St.find(r,this.context.cwd),a=await Lr.find(r);await o.restoreInstallState({restoreResolutions:!1});let n=0,u=await Nt.start({configuration:r,includeFooter:!1,stdout:this.context.stdout,json:this.json},async A=>{n=await O8(o,{strategy:this.strategy,patterns:this.patterns,cache:a,report:A})});return u.hasErrors()?u.exitCode():this.check?n?1:0:await o.installWithNewReport({json:this.json,stdout:this.context.stdout},{cache:a,mode:this.mode})}};Lh.paths=[[\"dedupe\"]],Lh.usage=nt.Usage({description:\"deduplicate dependencies with overlapping ranges\",details:\"\\n      Duplicates are defined as descriptors with overlapping ranges being resolved and locked to different locators. They are a natural consequence of Yarn's deterministic installs, but they can sometimes pile up and unnecessarily increase the size of your project.\\n\\n      This command dedupes dependencies in the current project using different strategies (only one is implemented at the moment):\\n\\n      - `highest`: Reuses (where possible) the locators with the highest versions. This means that dependencies can only be upgraded, never downgraded. It's also guaranteed that it never takes more than a single pass to dedupe the entire dependency tree.\\n\\n      **Note:** Even though it never produces a wrong dependency tree, this command should be used with caution, as it modifies the dependency tree, which can sometimes cause problems when packages don't strictly follow semver recommendations. Because of this, it is recommended to also review the changes manually.\\n\\n      If set, the `-c,--check` flag will only report the found duplicates, without persisting the modified dependency tree. If changes are found, the command will exit with a non-zero exit code, making it suitable for CI purposes.\\n\\n      If the `--mode=<mode>` option is set, Yarn will change which artifacts are generated. The modes currently supported are:\\n\\n      - `skip-build` will not run the build scripts at all. Note that this is different from setting `enableScripts` to false because the latter will disable build scripts, and thus affect the content of the artifacts generated on disk, whereas the former will just disable the build step - but not the scripts themselves, which just won't run.\\n\\n      - `update-lockfile` will skip the link step altogether, and only fetch packages that are missing from the lockfile (or that have no associated checksums). This mode is typically used by tools like Renovate or Dependabot to keep a lockfile up-to-date without incurring the full install cost.\\n\\n      This command accepts glob patterns as arguments (if valid Idents and supported by [micromatch](https://github.com/micromatch/micromatch)). Make sure to escape the patterns, to prevent your own shell from trying to expand them.\\n\\n      ### In-depth explanation:\\n\\n      Yarn doesn't deduplicate dependencies by default, otherwise installs wouldn't be deterministic and the lockfile would be useless. What it actually does is that it tries to not duplicate dependencies in the first place.\\n\\n      **Example:** If `foo@^2.3.4` (a dependency of a dependency) has already been resolved to `foo@2.3.4`, running `yarn add foo@*`will cause Yarn to reuse `foo@2.3.4`, even if the latest `foo` is actually `foo@2.10.14`, thus preventing unnecessary duplication.\\n\\n      Duplication happens when Yarn can't unlock dependencies that have already been locked inside the lockfile.\\n\\n      **Example:** If `foo@^2.3.4` (a dependency of a dependency) has already been resolved to `foo@2.3.4`, running `yarn add foo@2.10.14` will cause Yarn to install `foo@2.10.14` because the existing resolution doesn't satisfy the range `2.10.14`. This behavior can lead to (sometimes) unwanted duplication, since now the lockfile contains 2 separate resolutions for the 2 `foo` descriptors, even though they have overlapping ranges, which means that the lockfile can be simplified so that both descriptors resolve to `foo@2.10.14`.\\n    \",examples:[[\"Dedupe all packages\",\"$0 dedupe\"],[\"Dedupe all packages using a specific strategy\",\"$0 dedupe --strategy highest\"],[\"Dedupe a specific package\",\"$0 dedupe lodash\"],[\"Dedupe all packages with the `@babel/*` scope\",\"$0 dedupe '@babel/*'\"],[\"Check for duplicates (can be used as a CI step)\",\"$0 dedupe --check\"]]});Ye();qt();var Yd=class extends ut{async execute(){let{plugins:e}=await Ke.find(this.context.cwd,this.context.plugins),r=[];for(let u of e){let{commands:A}=u[1];if(A){let h=as.from(A).definitions();r.push([u[0],h])}}let o=this.cli.definitions(),a=(u,A)=>u.split(\" \").slice(1).join()===A.split(\" \").slice(1).join(),n=Zge()[\"@yarnpkg/builder\"].bundles.standard;for(let u of r){let A=u[1];for(let p of A)o.find(h=>a(h.path,p.path)).plugin={name:u[0],isDefault:n.includes(u[0])}}this.context.stdout.write(`${JSON.stringify(o,null,2)}\n`)}};Yd.paths=[[\"--clipanion=definitions\"]];var Wd=class extends ut{async execute(){this.context.stdout.write(this.cli.usage(null))}};Wd.paths=[[\"help\"],[\"--help\"],[\"-h\"]];Ye();Pt();qt();var gC=class extends ut{constructor(){super(...arguments);this.leadingArgument=ge.String();this.args=ge.Proxy()}async execute(){if(this.leadingArgument.match(/[\\\\/]/)&&!W.tryParseIdent(this.leadingArgument)){let r=V.resolve(this.context.cwd,ue.toPortablePath(this.leadingArgument));return await this.cli.run(this.args,{cwd:r})}else return await this.cli.run([\"run\",this.leadingArgument,...this.args])}};Ye();var Kd=class extends ut{async execute(){this.context.stdout.write(`${tn||\"<unknown>\"}\n`)}};Kd.paths=[[\"-v\"],[\"--version\"]];Ye();Ye();qt();var Oh=class extends ut{constructor(){super(...arguments);this.commandName=ge.String();this.args=ge.Proxy()}async execute(){let r=await Ke.find(this.context.cwd,this.context.plugins),{project:o,locator:a}=await St.find(r,this.context.cwd);return await o.restoreInstallState(),await un.executePackageShellcode(a,this.commandName,this.args,{cwd:this.context.cwd,stdin:this.context.stdin,stdout:this.context.stdout,stderr:this.context.stderr,project:o})}};Oh.paths=[[\"exec\"]],Oh.usage=nt.Usage({description:\"execute a shell script\",details:`\n      This command simply executes a shell script within the context of the root directory of the active workspace using the portable shell.\n\n      It also makes sure to call it in a way that's compatible with the current project (for example, on PnP projects the environment will be setup in such a way that PnP will be correctly injected into the environment).\n    `,examples:[[\"Execute a single shell command\",\"$0 exec echo Hello World\"],[\"Execute a shell script\",'$0 exec \"tsc & babel src --out-dir lib\"']]});Ye();qt();Za();var Mh=class extends ut{constructor(){super(...arguments);this.hash=ge.String({validator:aP(yy(),[iI(/^p[0-9a-f]{5}$/)])})}async execute(){let r=await Ke.find(this.context.cwd,this.context.plugins),{project:o}=await St.find(r,this.context.cwd);return await o.restoreInstallState({restoreResolutions:!1}),await o.applyLightResolution(),await G0t(this.hash,o,{stdout:this.context.stdout})}};Mh.paths=[[\"explain\",\"peer-requirements\"]],Mh.usage=nt.Usage({description:\"explain a set of peer requirements\",details:`\n      A set of peer requirements represents all peer requirements that a dependent must satisfy when providing a given peer request to a requester and its descendants.\n\n      When the hash argument is specified, this command prints a detailed explanation of all requirements of the set corresponding to the hash and whether they're satisfied or not.\n\n      When used without arguments, this command lists all sets of peer requirements and the corresponding hash that can be used to get detailed information about a given set.\n\n      **Note:** A hash is a six-letter p-prefixed code that can be obtained from peer dependency warnings or from the list of all peer requirements (\\`yarn explain peer-requirements\\`).\n    `,examples:[[\"Explain the corresponding set of peer requirements for a hash\",\"$0 explain peer-requirements p1a4ed\"],[\"List all sets of peer requirements\",\"$0 explain peer-requirements\"]]});async function G0t(t,e,r){let o=e.peerWarnings.find(n=>n.hash===t);if(typeof o>\"u\")throw new Error(`No peerDependency requirements found for hash: \"${t}\"`);return(await Nt.start({configuration:e.configuration,stdout:r.stdout,includeFooter:!1,includePrefix:!1},async n=>{let u=de.mark(e.configuration);switch(o.type){case 2:{n.reportInfo(0,`We have a problem with ${de.pretty(e.configuration,o.requested,de.Type.IDENT)}, which is provided with version ${W.prettyReference(e.configuration,o.version)}.`),n.reportInfo(0,\"It is needed by the following direct dependencies of workspaces in your project:\"),n.reportSeparator();for(let h of o.requesters.values()){let C=e.storedPackages.get(h.locatorHash);if(!C)throw new Error(\"Assertion failed: Expected the package to be registered\");let I=C?.peerDependencies.get(o.requested.identHash);if(!I)throw new Error(\"Assertion failed: Expected the package to list the peer dependency\");let v=kr.satisfiesWithPrereleases(o.version,I.range)?u.Check:u.Cross;n.reportInfo(null,`  ${v} ${W.prettyLocator(e.configuration,h)} (via ${W.prettyRange(e.configuration,I.range)})`)}let A=[...o.links.values()].filter(h=>!o.requesters.has(h.locatorHash));if(A.length>0){n.reportSeparator(),n.reportInfo(0,`However, those packages themselves have more dependencies listing ${W.prettyIdent(e.configuration,o.requested)} as peer dependency:`),n.reportSeparator();for(let h of A){let C=e.storedPackages.get(h.locatorHash);if(!C)throw new Error(\"Assertion failed: Expected the package to be registered\");let I=C?.peerDependencies.get(o.requested.identHash);if(!I)throw new Error(\"Assertion failed: Expected the package to list the peer dependency\");let v=kr.satisfiesWithPrereleases(o.version,I.range)?u.Check:u.Cross;n.reportInfo(null,`  ${v} ${W.prettyLocator(e.configuration,h)} (via ${W.prettyRange(e.configuration,I.range)})`)}}let p=Array.from(o.links.values(),h=>{let C=e.storedPackages.get(h.locatorHash);if(typeof C>\"u\")throw new Error(\"Assertion failed: Expected the package to be registered\");let I=C.peerDependencies.get(o.requested.identHash);if(typeof I>\"u\")throw new Error(\"Assertion failed: Expected the ident to be registered\");return I.range});if(p.length>1){let h=kr.simplifyRanges(p);n.reportSeparator(),h===null?(n.reportInfo(0,\"Unfortunately, put together, we found no single range that can satisfy all those peer requirements.\"),n.reportInfo(0,`Your best option may be to try to upgrade some dependencies with ${de.pretty(e.configuration,\"yarn up\",de.Type.CODE)}, or silence the warning via ${de.pretty(e.configuration,\"logFilters\",de.Type.CODE)}.`)):n.reportInfo(0,`Put together, the final range we computed is ${de.pretty(e.configuration,h,de.Type.RANGE)}`)}}break;default:n.reportInfo(0,`The ${de.pretty(e.configuration,\"yarn explain peer-requirements\",de.Type.CODE)} command doesn't support this warning type yet.`);break}})).exitCode()}Ye();qt();Za();Ye();Ye();Pt();qt();var $ge=$e(Jn()),Uh=class extends ut{constructor(){super(...arguments);this.useYarnPath=ge.Boolean(\"--yarn-path\",{description:\"Set the yarnPath setting even if the version can be accessed by Corepack\"});this.onlyIfNeeded=ge.Boolean(\"--only-if-needed\",!1,{description:\"Only lock the Yarn version if it isn't already locked\"});this.version=ge.String()}async execute(){let r=await Ke.find(this.context.cwd,this.context.plugins);if(this.onlyIfNeeded&&r.get(\"yarnPath\")){let A=r.sources.get(\"yarnPath\");if(!A)throw new Error(\"Assertion failed: Expected 'yarnPath' to have a source\");let p=r.projectCwd??r.startingCwd;if(V.contains(p,A))return 0}let o=()=>{if(typeof tn>\"u\")throw new it(\"The --install flag can only be used without explicit version specifier from the Yarn CLI\");return`file://${process.argv[1]}`},a,n=(A,p)=>({version:p,url:A.replace(/\\{\\}/g,p)});if(this.version===\"self\")a={url:o(),version:tn??\"self\"};else if(this.version===\"latest\"||this.version===\"berry\"||this.version===\"stable\")a=n(\"https://repo.yarnpkg.com/{}/packages/yarnpkg-cli/bin/yarn.js\",await d2(r,\"stable\"));else if(this.version===\"canary\")a=n(\"https://repo.yarnpkg.com/{}/packages/yarnpkg-cli/bin/yarn.js\",await d2(r,\"canary\"));else if(this.version===\"classic\")a={url:\"https://classic.yarnpkg.com/latest.js\",version:\"classic\"};else if(this.version.match(/^https?:/))a={url:this.version,version:\"remote\"};else if(this.version.match(/^\\.{0,2}[\\\\/]/)||ue.isAbsolute(this.version))a={url:`file://${V.resolve(ue.toPortablePath(this.version))}`,version:\"file\"};else if(kr.satisfiesWithPrereleases(this.version,\">=2.0.0\"))a=n(\"https://repo.yarnpkg.com/{}/packages/yarnpkg-cli/bin/yarn.js\",this.version);else if(kr.satisfiesWithPrereleases(this.version,\"^0.x || ^1.x\"))a=n(\"https://github.com/yarnpkg/yarn/releases/download/v{}/yarn-{}.js\",this.version);else if(kr.validRange(this.version))a=n(\"https://repo.yarnpkg.com/{}/packages/yarnpkg-cli/bin/yarn.js\",await Y0t(r,this.version));else throw new it(`Invalid version descriptor \"${this.version}\"`);return(await Nt.start({configuration:r,stdout:this.context.stdout,includeLogs:!this.context.quiet},async A=>{let p=async()=>{let h=\"file://\";return a.url.startsWith(h)?(A.reportInfo(0,`Retrieving ${de.pretty(r,a.url,de.Type.PATH)}`),await oe.readFilePromise(a.url.slice(h.length))):(A.reportInfo(0,`Downloading ${de.pretty(r,a.url,de.Type.URL)}`),await rn.get(a.url,{configuration:r}))};await M8(r,a.version,p,{report:A,useYarnPath:this.useYarnPath})})).exitCode()}};Uh.paths=[[\"set\",\"version\"]],Uh.usage=nt.Usage({description:\"lock the Yarn version used by the project\",details:\"\\n      This command will set a specific release of Yarn to be used by Corepack: https://nodejs.org/api/corepack.html.\\n\\n      By default it only will set the `packageManager` field at the root of your project, but if the referenced release cannot be represented this way, if you already have `yarnPath` configured, or if you set the `--yarn-path` command line flag, then the release will also be downloaded from the Yarn GitHub repository, stored inside your project, and referenced via the `yarnPath` settings from your project `.yarnrc.yml` file.\\n\\n      A very good use case for this command is to enforce the version of Yarn used by any single member of your team inside the same project - by doing this you ensure that you have control over Yarn upgrades and downgrades (including on your deployment servers), and get rid of most of the headaches related to someone using a slightly different version and getting different behavior.\\n\\n      The version specifier can be:\\n\\n      - a tag:\\n        - `latest` / `berry` / `stable` -> the most recent stable berry (`>=2.0.0`) release\\n        - `canary` -> the most recent canary (release candidate) berry (`>=2.0.0`) release\\n        - `classic` -> the most recent classic (`^0.x || ^1.x`) release\\n\\n      - a semver range (e.g. `2.x`) -> the most recent version satisfying the range (limited to berry releases)\\n\\n      - a semver version (e.g. `2.4.1`, `1.22.1`)\\n\\n      - a local file referenced through either a relative or absolute path\\n\\n      - `self` -> the version used to invoke the command\\n    \",examples:[[\"Download the latest release from the Yarn repository\",\"$0 set version latest\"],[\"Download the latest canary release from the Yarn repository\",\"$0 set version canary\"],[\"Download the latest classic release from the Yarn repository\",\"$0 set version classic\"],[\"Download the most recent Yarn 3 build\",\"$0 set version 3.x\"],[\"Download a specific Yarn 2 build\",\"$0 set version 2.0.0-rc.30\"],[\"Switch back to a specific Yarn 1 release\",\"$0 set version 1.22.1\"],[\"Use a release from the local filesystem\",\"$0 set version ./yarn.cjs\"],[\"Use a release from a URL\",\"$0 set version https://repo.yarnpkg.com/3.1.0/packages/yarnpkg-cli/bin/yarn.js\"],[\"Download the version used to invoke the command\",\"$0 set version self\"]]});async function Y0t(t,e){let o=(await rn.get(\"https://repo.yarnpkg.com/tags\",{configuration:t,jsonResponse:!0})).tags.filter(a=>kr.satisfiesWithPrereleases(a,e));if(o.length===0)throw new it(`No matching release found for range ${de.pretty(t,e,de.Type.RANGE)}.`);return o[0]}async function d2(t,e){let r=await rn.get(\"https://repo.yarnpkg.com/tags\",{configuration:t,jsonResponse:!0});if(!r.latest[e])throw new it(`Tag ${de.pretty(t,e,de.Type.RANGE)} not found`);return r.latest[e]}async function M8(t,e,r,{report:o,useYarnPath:a}){let n,u=async()=>(typeof n>\"u\"&&(n=await r()),n);if(e===null){let te=await u();await oe.mktempPromise(async le=>{let he=V.join(le,\"yarn.cjs\");await oe.writeFilePromise(he,te);let{stdout:Ae}=await Ur.execvp(process.execPath,[ue.fromPortablePath(he),\"--version\"],{cwd:le,env:{...t.env,YARN_IGNORE_PATH:\"1\"}});if(e=Ae.trim(),!$ge.default.valid(e))throw new Error(`Invalid semver version. ${de.pretty(t,\"yarn --version\",de.Type.CODE)} returned:\n${e}`)})}let A=t.projectCwd??t.startingCwd,p=V.resolve(A,\".yarn/releases\"),h=V.resolve(p,`yarn-${e}.cjs`),C=V.relative(t.startingCwd,h),I=je.isTaggedYarnVersion(e),v=t.get(\"yarnPath\"),x=!I,E=x||!!v||!!a;if(a===!1){if(x)throw new Jt(0,\"You explicitly opted out of yarnPath usage in your command line, but the version you specified cannot be represented by Corepack\");E=!1}else!E&&!process.env.COREPACK_ROOT&&(o.reportWarning(0,`You don't seem to have ${de.applyHyperlink(t,\"Corepack\",\"https://nodejs.org/api/corepack.html\")} enabled; we'll have to rely on ${de.applyHyperlink(t,\"yarnPath\",\"https://yarnpkg.com/configuration/yarnrc#yarnPath\")} instead`),E=!0);if(E){let te=await u();o.reportInfo(0,`Saving the new release in ${de.pretty(t,C,\"magenta\")}`),await oe.removePromise(V.dirname(h)),await oe.mkdirPromise(V.dirname(h),{recursive:!0}),await oe.writeFilePromise(h,te,{mode:493}),await Ke.updateConfiguration(A,{yarnPath:V.relative(A,h)})}else await oe.removePromise(V.dirname(h)),await Ke.updateConfiguration(A,{yarnPath:Ke.deleteProperty});let R=await Ot.tryFind(A)||new Ot;R.packageManager=`yarn@${I?e:await d2(t,\"stable\")}`;let L={};R.exportTo(L);let U=V.join(A,Ot.fileName),z=`${JSON.stringify(L,null,R.indent)}\n`;return await oe.changeFilePromise(U,z,{automaticNewlines:!0}),{bundleVersion:e}}function ede(t){return wr[fP(t)]}var W0t=/## (?<code>YN[0-9]{4}) - `(?<name>[A-Z_]+)`\\n\\n(?<details>(?:.(?!##))+)/gs;async function K0t(t){let r=`https://repo.yarnpkg.com/${je.isTaggedYarnVersion(tn)?tn:await d2(t,\"canary\")}/packages/gatsby/content/advanced/error-codes.md`,o=await rn.get(r,{configuration:t});return new Map(Array.from(o.toString().matchAll(W0t),({groups:a})=>{if(!a)throw new Error(\"Assertion failed: Expected the match to have been successful\");let n=ede(a.code);if(a.name!==n)throw new Error(`Assertion failed: Invalid error code data: Expected \"${a.name}\" to be named \"${n}\"`);return[a.code,a.details]}))}var _h=class extends ut{constructor(){super(...arguments);this.code=ge.String({required:!1,validator:sI(yy(),[iI(/^YN[0-9]{4}$/)])});this.json=ge.Boolean(\"--json\",!1,{description:\"Format the output as an NDJSON stream\"})}async execute(){let r=await Ke.find(this.context.cwd,this.context.plugins);if(typeof this.code<\"u\"){let o=ede(this.code),a=de.pretty(r,o,de.Type.CODE),n=this.cli.format().header(`${this.code} - ${a}`),A=(await K0t(r)).get(this.code),p=typeof A<\"u\"?de.jsonOrPretty(this.json,r,de.tuple(de.Type.MARKDOWN,{text:A,format:this.cli.format(),paragraphs:!0})):`This error code does not have a description.\n\nYou can help us by editing this page on GitHub \\u{1F642}:\n${de.jsonOrPretty(this.json,r,de.tuple(de.Type.URL,\"https://github.com/yarnpkg/berry/blob/master/packages/gatsby/content/advanced/error-codes.md\"))}\n`;this.json?this.context.stdout.write(`${JSON.stringify({code:this.code,name:o,details:p})}\n`):this.context.stdout.write(`${n}\n\n${p}\n`)}else{let o={children:je.mapAndFilter(Object.entries(wr),([a,n])=>Number.isNaN(Number(a))?je.mapAndFilter.skip:{label:Wu(Number(a)),value:de.tuple(de.Type.CODE,n)})};$s.emitTree(o,{configuration:r,stdout:this.context.stdout,json:this.json})}}};_h.paths=[[\"explain\"]],_h.usage=nt.Usage({description:\"explain an error code\",details:`\n      When the code argument is specified, this command prints its name and its details.\n\n      When used without arguments, this command lists all error codes and their names.\n    `,examples:[[\"Explain an error code\",\"$0 explain YN0006\"],[\"List all error codes\",\"$0 explain\"]]});Ye();Pt();qt();var tde=$e(Zo()),Hh=class extends ut{constructor(){super(...arguments);this.all=ge.Boolean(\"-A,--all\",!1,{description:\"Print versions of a package from the whole project\"});this.recursive=ge.Boolean(\"-R,--recursive\",!1,{description:\"Print information for all packages, including transitive dependencies\"});this.extra=ge.Array(\"-X,--extra\",[],{description:\"An array of requests of extra data provided by plugins\"});this.cache=ge.Boolean(\"--cache\",!1,{description:\"Print information about the cache entry of a package (path, size, checksum)\"});this.dependents=ge.Boolean(\"--dependents\",!1,{description:\"Print all dependents for each matching package\"});this.manifest=ge.Boolean(\"--manifest\",!1,{description:\"Print data obtained by looking at the package archive (license, homepage, ...)\"});this.nameOnly=ge.Boolean(\"--name-only\",!1,{description:\"Only print the name for the matching packages\"});this.virtuals=ge.Boolean(\"--virtuals\",!1,{description:\"Print each instance of the virtual packages\"});this.json=ge.Boolean(\"--json\",!1,{description:\"Format the output as an NDJSON stream\"});this.patterns=ge.Rest()}async execute(){let r=await Ke.find(this.context.cwd,this.context.plugins),{project:o,workspace:a}=await St.find(r,this.context.cwd),n=await Lr.find(r);if(!a&&!this.all)throw new rr(o.cwd,this.context.cwd);await o.restoreInstallState();let u=new Set(this.extra);this.cache&&u.add(\"cache\"),this.dependents&&u.add(\"dependents\"),this.manifest&&u.add(\"manifest\");let A=(le,{recursive:he})=>{let Ae=le.anchoredLocator.locatorHash,ye=new Map,ae=[Ae];for(;ae.length>0;){let Ie=ae.shift();if(ye.has(Ie))continue;let Fe=o.storedPackages.get(Ie);if(typeof Fe>\"u\")throw new Error(\"Assertion failed: Expected the package to be registered\");if(ye.set(Ie,Fe),W.isVirtualLocator(Fe)&&ae.push(W.devirtualizeLocator(Fe).locatorHash),!(!he&&Ie!==Ae))for(let g of Fe.dependencies.values()){let Ee=o.storedResolutions.get(g.descriptorHash);if(typeof Ee>\"u\")throw new Error(\"Assertion failed: Expected the resolution to be registered\");ae.push(Ee)}}return ye.values()},p=({recursive:le})=>{let he=new Map;for(let Ae of o.workspaces)for(let ye of A(Ae,{recursive:le}))he.set(ye.locatorHash,ye);return he.values()},h=({all:le,recursive:he})=>le&&he?o.storedPackages.values():le?p({recursive:he}):A(a,{recursive:he}),C=({all:le,recursive:he})=>{let Ae=h({all:le,recursive:he}),ye=this.patterns.map(Fe=>{let g=W.parseLocator(Fe),Ee=tde.default.makeRe(W.stringifyIdent(g)),De=W.isVirtualLocator(g),ce=De?W.devirtualizeLocator(g):g;return ne=>{let ee=W.stringifyIdent(ne);if(!Ee.test(ee))return!1;if(g.reference===\"unknown\")return!0;let we=W.isVirtualLocator(ne),xe=we?W.devirtualizeLocator(ne):ne;return!(De&&we&&g.reference!==ne.reference||ce.reference!==xe.reference)}}),ae=je.sortMap([...Ae],Fe=>W.stringifyLocator(Fe));return{selection:ae.filter(Fe=>ye.length===0||ye.some(g=>g(Fe))),sortedLookup:ae}},{selection:I,sortedLookup:v}=C({all:this.all,recursive:this.recursive});if(I.length===0)throw new it(\"No package matched your request\");let x=new Map;if(this.dependents)for(let le of v)for(let he of le.dependencies.values()){let Ae=o.storedResolutions.get(he.descriptorHash);if(typeof Ae>\"u\")throw new Error(\"Assertion failed: Expected the resolution to be registered\");je.getArrayWithDefault(x,Ae).push(le)}let E=new Map;for(let le of v){if(!W.isVirtualLocator(le))continue;let he=W.devirtualizeLocator(le);je.getArrayWithDefault(E,he.locatorHash).push(le)}let R={},L={children:R},U=r.makeFetcher(),z={project:o,fetcher:U,cache:n,checksums:o.storedChecksums,report:new Qi,cacheOptions:{skipIntegrityCheck:!0}},te=[async(le,he,Ae)=>{if(!he.has(\"manifest\"))return;let ye=await U.fetch(le,z),ae;try{ae=await Ot.find(ye.prefixPath,{baseFs:ye.packageFs})}finally{ye.releaseFs?.()}Ae(\"Manifest\",{License:de.tuple(de.Type.NO_HINT,ae.license),Homepage:de.tuple(de.Type.URL,ae.raw.homepage??null)})},async(le,he,Ae)=>{if(!he.has(\"cache\"))return;let ye=o.storedChecksums.get(le.locatorHash)??null,ae=n.getLocatorPath(le,ye),Ie;if(ae!==null)try{Ie=await oe.statPromise(ae)}catch{}let Fe=typeof Ie<\"u\"?[Ie.size,de.Type.SIZE]:void 0;Ae(\"Cache\",{Checksum:de.tuple(de.Type.NO_HINT,ye),Path:de.tuple(de.Type.PATH,ae),Size:Fe})}];for(let le of I){let he=W.isVirtualLocator(le);if(!this.virtuals&&he)continue;let Ae={},ye={value:[le,de.Type.LOCATOR],children:Ae};if(R[W.stringifyLocator(le)]=ye,this.nameOnly){delete ye.children;continue}let ae=E.get(le.locatorHash);typeof ae<\"u\"&&(Ae.Instances={label:\"Instances\",value:de.tuple(de.Type.NUMBER,ae.length)}),Ae.Version={label:\"Version\",value:de.tuple(de.Type.NO_HINT,le.version)};let Ie=(g,Ee)=>{let De={};if(Ae[g]=De,Array.isArray(Ee))De.children=Ee.map(ce=>({value:ce}));else{let ce={};De.children=ce;for(let[ne,ee]of Object.entries(Ee))typeof ee>\"u\"||(ce[ne]={label:ne,value:ee})}};if(!he){for(let g of te)await g(le,u,Ie);await r.triggerHook(g=>g.fetchPackageInfo,le,u,Ie)}le.bin.size>0&&!he&&Ie(\"Exported Binaries\",[...le.bin.keys()].map(g=>de.tuple(de.Type.PATH,g)));let Fe=x.get(le.locatorHash);typeof Fe<\"u\"&&Fe.length>0&&Ie(\"Dependents\",Fe.map(g=>de.tuple(de.Type.LOCATOR,g))),le.dependencies.size>0&&!he&&Ie(\"Dependencies\",[...le.dependencies.values()].map(g=>{let Ee=o.storedResolutions.get(g.descriptorHash),De=typeof Ee<\"u\"?o.storedPackages.get(Ee)??null:null;return de.tuple(de.Type.RESOLUTION,{descriptor:g,locator:De})})),le.peerDependencies.size>0&&he&&Ie(\"Peer dependencies\",[...le.peerDependencies.values()].map(g=>{let Ee=le.dependencies.get(g.identHash),De=typeof Ee<\"u\"?o.storedResolutions.get(Ee.descriptorHash)??null:null,ce=De!==null?o.storedPackages.get(De)??null:null;return de.tuple(de.Type.RESOLUTION,{descriptor:g,locator:ce})}))}$s.emitTree(L,{configuration:r,json:this.json,stdout:this.context.stdout,separators:this.nameOnly?0:2})}};Hh.paths=[[\"info\"]],Hh.usage=nt.Usage({description:\"see information related to packages\",details:\"\\n      This command prints various information related to the specified packages, accepting glob patterns.\\n\\n      By default, if the locator reference is missing, Yarn will default to print the information about all the matching direct dependencies of the package for the active workspace. To instead print all versions of the package that are direct dependencies of any of your workspaces, use the `-A,--all` flag. Adding the `-R,--recursive` flag will also report transitive dependencies.\\n\\n      Some fields will be hidden by default in order to keep the output readable, but can be selectively displayed by using additional options (`--dependents`, `--manifest`, `--virtuals`, ...) described in the option descriptions.\\n\\n      Note that this command will only print the information directly related to the selected packages - if you wish to know why the package is there in the first place, use `yarn why` which will do just that (it also provides a `-R,--recursive` flag that may be of some help).\\n    \",examples:[[\"Show information about Lodash\",\"$0 info lodash\"]]});Ye();Pt();Nl();var dk=$e($g());qt();var U8=$e(Jn());Za();var V0t=[{selector:t=>t===-1,name:\"nodeLinker\",value:\"node-modules\"},{selector:t=>t!==-1&&t<8,name:\"enableGlobalCache\",value:!1},{selector:t=>t!==-1&&t<8,name:\"compressionLevel\",value:\"mixed\"}],jh=class extends ut{constructor(){super(...arguments);this.json=ge.Boolean(\"--json\",!1,{description:\"Format the output as an NDJSON stream\"});this.immutable=ge.Boolean(\"--immutable\",{description:\"Abort with an error exit code if the lockfile was to be modified\"});this.immutableCache=ge.Boolean(\"--immutable-cache\",{description:\"Abort with an error exit code if the cache folder was to be modified\"});this.refreshLockfile=ge.Boolean(\"--refresh-lockfile\",{description:\"Refresh the package metadata stored in the lockfile\"});this.checkCache=ge.Boolean(\"--check-cache\",{description:\"Always refetch the packages and ensure that their checksums are consistent\"});this.checkResolutions=ge.Boolean(\"--check-resolutions\",{description:\"Validates that the package resolutions are coherent\"});this.inlineBuilds=ge.Boolean(\"--inline-builds\",{description:\"Verbosely print the output of the build steps of dependencies\"});this.mode=ge.String(\"--mode\",{description:\"Change what artifacts installs generate\",validator:Ks(pl)});this.cacheFolder=ge.String(\"--cache-folder\",{hidden:!0});this.frozenLockfile=ge.Boolean(\"--frozen-lockfile\",{hidden:!0});this.ignoreEngines=ge.Boolean(\"--ignore-engines\",{hidden:!0});this.nonInteractive=ge.Boolean(\"--non-interactive\",{hidden:!0});this.preferOffline=ge.Boolean(\"--prefer-offline\",{hidden:!0});this.production=ge.Boolean(\"--production\",{hidden:!0});this.registry=ge.String(\"--registry\",{hidden:!0});this.silent=ge.Boolean(\"--silent\",{hidden:!0});this.networkTimeout=ge.String(\"--network-timeout\",{hidden:!0})}async execute(){let r=await Ke.find(this.context.cwd,this.context.plugins);typeof this.inlineBuilds<\"u\"&&r.useWithSource(\"<cli>\",{enableInlineBuilds:this.inlineBuilds},r.startingCwd,{overwrite:!0});let o=!!process.env.FUNCTION_TARGET||!!process.env.GOOGLE_RUNTIME,a=await TE({configuration:r,stdout:this.context.stdout},[{option:this.ignoreEngines,message:\"The --ignore-engines option is deprecated; engine checking isn't a core feature anymore\",error:!dk.default.VERCEL},{option:this.registry,message:\"The --registry option is deprecated; prefer setting npmRegistryServer in your .yarnrc.yml file\"},{option:this.preferOffline,message:\"The --prefer-offline flag is deprecated; use the --cached flag with 'yarn add' instead\",error:!dk.default.VERCEL},{option:this.production,message:\"The --production option is deprecated on 'install'; use 'yarn workspaces focus' instead\",error:!0},{option:this.nonInteractive,message:\"The --non-interactive option is deprecated\",error:!o},{option:this.frozenLockfile,message:\"The --frozen-lockfile option is deprecated; use --immutable and/or --immutable-cache instead\",callback:()=>this.immutable=this.frozenLockfile},{option:this.cacheFolder,message:\"The cache-folder option has been deprecated; use rc settings instead\",error:!dk.default.NETLIFY}]);if(a!==null)return a;let n=this.mode===\"update-lockfile\";if(n&&(this.immutable||this.immutableCache))throw new it(`${de.pretty(r,\"--immutable\",de.Type.CODE)} and ${de.pretty(r,\"--immutable-cache\",de.Type.CODE)} cannot be used with ${de.pretty(r,\"--mode=update-lockfile\",de.Type.CODE)}`);let u=(this.immutable??r.get(\"enableImmutableInstalls\"))&&!n,A=this.immutableCache&&!n;if(r.projectCwd!==null){let E=await Nt.start({configuration:r,json:this.json,stdout:this.context.stdout,includeFooter:!1},async R=>{let L=!1;await X0t(r,u)&&(R.reportInfo(48,\"Automatically removed core plugins that are now builtins \\u{1F44D}\"),L=!0),await J0t(r,u)&&(R.reportInfo(48,\"Automatically fixed merge conflicts \\u{1F44D}\"),L=!0),L&&R.reportSeparator()});if(E.hasErrors())return E.exitCode()}if(r.projectCwd!==null){let E=await Nt.start({configuration:r,json:this.json,stdout:this.context.stdout,includeFooter:!1},async R=>{if(Ke.telemetry?.isNew)Ke.telemetry.commitTips(),R.reportInfo(65,\"Yarn will periodically gather anonymous telemetry: https://yarnpkg.com/advanced/telemetry\"),R.reportInfo(65,`Run ${de.pretty(r,\"yarn config set --home enableTelemetry 0\",de.Type.CODE)} to disable`),R.reportSeparator();else if(Ke.telemetry?.shouldShowTips){let L=await rn.get(\"https://repo.yarnpkg.com/tags\",{configuration:r,jsonResponse:!0}).catch(()=>null);if(L!==null){let U=null;if(tn!==null){let te=U8.default.prerelease(tn)?\"canary\":\"stable\",le=L.latest[te];U8.default.gt(le,tn)&&(U=[te,le])}if(U)Ke.telemetry.commitTips(),R.reportInfo(88,`${de.applyStyle(r,`A new ${U[0]} version of Yarn is available:`,de.Style.BOLD)} ${W.prettyReference(r,U[1])}!`),R.reportInfo(88,`Upgrade now by running ${de.pretty(r,`yarn set version ${U[1]}`,de.Type.CODE)}`),R.reportSeparator();else{let z=Ke.telemetry.selectTip(L.tips);z&&(R.reportInfo(89,de.pretty(r,z.message,de.Type.MARKDOWN_INLINE)),z.url&&R.reportInfo(89,`Learn more at ${z.url}`),R.reportSeparator())}}}});if(E.hasErrors())return E.exitCode()}let{project:p,workspace:h}=await St.find(r,this.context.cwd),C=p.lockfileLastVersion;if(C!==null){let E=await Nt.start({configuration:r,json:this.json,stdout:this.context.stdout,includeFooter:!1},async R=>{let L={};for(let U of V0t)U.selector(C)&&typeof r.sources.get(U.name)>\"u\"&&(r.use(\"<compat>\",{[U.name]:U.value},p.cwd,{overwrite:!0}),L[U.name]=U.value);Object.keys(L).length>0&&(await Ke.updateConfiguration(p.cwd,L),R.reportInfo(87,\"Migrated your project to the latest Yarn version \\u{1F680}\"),R.reportSeparator())});if(E.hasErrors())return E.exitCode()}let I=await Lr.find(r,{immutable:A,check:this.checkCache});if(!h)throw new rr(p.cwd,this.context.cwd);await p.restoreInstallState({restoreResolutions:!1});let v=r.get(\"enableHardenedMode\");(this.refreshLockfile??v)&&(p.lockfileNeedsRefresh=!0);let x=this.checkResolutions??v;return await p.installWithNewReport({json:this.json,stdout:this.context.stdout},{cache:I,immutable:u,checkResolutions:x,mode:this.mode})}};jh.paths=[[\"install\"],nt.Default],jh.usage=nt.Usage({description:\"install the project dependencies\",details:\"\\n      This command sets up your project if needed. The installation is split into four different steps that each have their own characteristics:\\n\\n      - **Resolution:** First the package manager will resolve your dependencies. The exact way a dependency version is privileged over another isn't standardized outside of the regular semver guarantees. If a package doesn't resolve to what you would expect, check that all dependencies are correctly declared (also check our website for more information: ).\\n\\n      - **Fetch:** Then we download all the dependencies if needed, and make sure that they're all stored within our cache (check the value of `cacheFolder` in `yarn config` to see where the cache files are stored).\\n\\n      - **Link:** Then we send the dependency tree information to internal plugins tasked with writing them on the disk in some form (for example by generating the .pnp.cjs file you might know).\\n\\n      - **Build:** Once the dependency tree has been written on the disk, the package manager will now be free to run the build scripts for all packages that might need it, in a topological order compatible with the way they depend on one another. See https://yarnpkg.com/advanced/lifecycle-scripts for detail.\\n\\n      Note that running this command is not part of the recommended workflow. Yarn supports zero-installs, which means that as long as you store your cache and your .pnp.cjs file inside your repository, everything will work without requiring any install right after cloning your repository or switching branches.\\n\\n      If the `--immutable` option is set (defaults to true on CI), Yarn will abort with an error exit code if the lockfile was to be modified (other paths can be added using the `immutablePatterns` configuration setting). For backward compatibility we offer an alias under the name of `--frozen-lockfile`, but it will be removed in a later release.\\n\\n      If the `--immutable-cache` option is set, Yarn will abort with an error exit code if the cache folder was to be modified (either because files would be added, or because they'd be removed).\\n\\n      If the `--refresh-lockfile` option is set, Yarn will keep the same resolution for the packages currently in the lockfile but will refresh their metadata. If used together with `--immutable`, it can validate that the lockfile information are consistent. This flag is enabled by default when Yarn detects it runs within a pull request context.\\n\\n      If the `--check-cache` option is set, Yarn will always refetch the packages and will ensure that their checksum matches what's 1/ described in the lockfile 2/ inside the existing cache files (if present). This is recommended as part of your CI workflow if you're both following the Zero-Installs model and accepting PRs from third-parties, as they'd otherwise have the ability to alter the checked-in packages before submitting them.\\n\\n      If the `--inline-builds` option is set, Yarn will verbosely print the output of the build steps of your dependencies (instead of writing them into individual files). This is likely useful mostly for debug purposes only when using Docker-like environments.\\n\\n      If the `--mode=<mode>` option is set, Yarn will change which artifacts are generated. The modes currently supported are:\\n\\n      - `skip-build` will not run the build scripts at all. Note that this is different from setting `enableScripts` to false because the latter will disable build scripts, and thus affect the content of the artifacts generated on disk, whereas the former will just disable the build step - but not the scripts themselves, which just won't run.\\n\\n      - `update-lockfile` will skip the link step altogether, and only fetch packages that are missing from the lockfile (or that have no associated checksums). This mode is typically used by tools like Renovate or Dependabot to keep a lockfile up-to-date without incurring the full install cost.\\n    \",examples:[[\"Install the project\",\"$0 install\"],[\"Validate a project when using Zero-Installs\",\"$0 install --immutable --immutable-cache\"],[\"Validate a project when using Zero-Installs (slightly safer if you accept external PRs)\",\"$0 install --immutable --immutable-cache --check-cache\"]]});var z0t=\"<<<<<<<\";async function J0t(t,e){if(!t.projectCwd)return!1;let r=V.join(t.projectCwd,dr.lockfile);if(!await oe.existsPromise(r)||!(await oe.readFilePromise(r,\"utf8\")).includes(z0t))return!1;if(e)throw new Jt(47,\"Cannot autofix a lockfile when running an immutable install\");let a=await Ur.execvp(\"git\",[\"rev-parse\",\"MERGE_HEAD\",\"HEAD\"],{cwd:t.projectCwd});if(a.code!==0&&(a=await Ur.execvp(\"git\",[\"rev-parse\",\"REBASE_HEAD\",\"HEAD\"],{cwd:t.projectCwd})),a.code!==0&&(a=await Ur.execvp(\"git\",[\"rev-parse\",\"CHERRY_PICK_HEAD\",\"HEAD\"],{cwd:t.projectCwd})),a.code!==0)throw new Jt(83,\"Git returned an error when trying to find the commits pertaining to the conflict\");let n=await Promise.all(a.stdout.trim().split(/\\n/).map(async A=>{let p=await Ur.execvp(\"git\",[\"show\",`${A}:./${dr.lockfile}`],{cwd:t.projectCwd});if(p.code!==0)throw new Jt(83,`Git returned an error when trying to access the lockfile content in ${A}`);try{return Ki(p.stdout)}catch{throw new Jt(46,\"A variant of the conflicting lockfile failed to parse\")}}));n=n.filter(A=>!!A.__metadata);for(let A of n){if(A.__metadata.version<7)for(let p of Object.keys(A)){if(p===\"__metadata\")continue;let h=W.parseDescriptor(p,!0),C=t.normalizeDependency(h),I=W.stringifyDescriptor(C);I!==p&&(A[I]=A[p],delete A[p])}for(let p of Object.keys(A)){if(p===\"__metadata\")continue;let h=A[p].checksum;typeof h==\"string\"&&h.includes(\"/\")||(A[p].checksum=`${A.__metadata.cacheKey}/${h}`)}}let u=Object.assign({},...n);u.__metadata.version=`${Math.min(...n.map(A=>parseInt(A.__metadata.version??0)))}`,u.__metadata.cacheKey=\"merged\";for(let[A,p]of Object.entries(u))typeof p==\"string\"&&delete u[A];return await oe.changeFilePromise(r,Ba(u),{automaticNewlines:!0}),!0}async function X0t(t,e){if(!t.projectCwd)return!1;let r=[],o=V.join(t.projectCwd,\".yarn/plugins/@yarnpkg\");return await Ke.updateConfiguration(t.projectCwd,{plugins:n=>{if(!Array.isArray(n))return n;let u=n.filter(A=>{if(!A.path)return!0;let p=V.resolve(t.projectCwd,A.path),h=I1.has(A.spec)&&V.contains(o,p);return h&&r.push(p),!h});return u.length===0?Ke.deleteProperty:u.length===n.length?n:u}},{immutable:e})?(await Promise.all(r.map(async n=>{await oe.removePromise(n)})),!0):!1}Ye();Pt();qt();var qh=class extends ut{constructor(){super(...arguments);this.all=ge.Boolean(\"-A,--all\",!1,{description:\"Link all workspaces belonging to the target projects to the current one\"});this.private=ge.Boolean(\"-p,--private\",!1,{description:\"Also link private workspaces belonging to the target projects to the current one\"});this.relative=ge.Boolean(\"-r,--relative\",!1,{description:\"Link workspaces using relative paths instead of absolute paths\"});this.destinations=ge.Rest()}async execute(){let r=await Ke.find(this.context.cwd,this.context.plugins),{project:o,workspace:a}=await St.find(r,this.context.cwd),n=await Lr.find(r);if(!a)throw new rr(o.cwd,this.context.cwd);await o.restoreInstallState({restoreResolutions:!1});let u=o.topLevelWorkspace,A=[];for(let p of this.destinations){let h=V.resolve(this.context.cwd,ue.toPortablePath(p)),C=await Ke.find(h,this.context.plugins,{useRc:!1,strict:!1}),{project:I,workspace:v}=await St.find(C,h);if(o.cwd===I.cwd)throw new it(`Invalid destination '${p}'; Can't link the project to itself`);if(!v)throw new rr(I.cwd,h);if(this.all){let x=!1;for(let E of I.workspaces)E.manifest.name&&(!E.manifest.private||this.private)&&(A.push(E),x=!0);if(!x)throw new it(`No workspace found to be linked in the target project: ${p}`)}else{if(!v.manifest.name)throw new it(`The target workspace at '${p}' doesn't have a name and thus cannot be linked`);if(v.manifest.private&&!this.private)throw new it(`The target workspace at '${p}' is marked private - use the --private flag to link it anyway`);A.push(v)}}for(let p of A){let h=W.stringifyIdent(p.anchoredLocator),C=this.relative?V.relative(o.cwd,p.cwd):p.cwd;u.manifest.resolutions.push({pattern:{descriptor:{fullName:h}},reference:`portal:${C}`})}return await o.installWithNewReport({stdout:this.context.stdout},{cache:n})}};qh.paths=[[\"link\"]],qh.usage=nt.Usage({description:\"connect the local project to another one\",details:\"\\n      This command will set a new `resolutions` field in the project-level manifest and point it to the workspace at the specified location (even if part of another project).\\n    \",examples:[[\"Register one or more remote workspaces for use in the current project\",\"$0 link ~/ts-loader ~/jest\"],[\"Register all workspaces from a remote project for use in the current project\",\"$0 link ~/jest --all\"]]});qt();var Gh=class extends ut{constructor(){super(...arguments);this.args=ge.Proxy()}async execute(){return this.cli.run([\"exec\",\"node\",...this.args])}};Gh.paths=[[\"node\"]],Gh.usage=nt.Usage({description:\"run node with the hook already setup\",details:`\n      This command simply runs Node. It also makes sure to call it in a way that's compatible with the current project (for example, on PnP projects the environment will be setup in such a way that PnP will be correctly injected into the environment).\n\n      The Node process will use the exact same version of Node as the one used to run Yarn itself, which might be a good way to ensure that your commands always use a consistent Node version.\n    `,examples:[[\"Run a Node script\",\"$0 node ./my-script.js\"]]});Ye();qt();var Yh=class extends ut{constructor(){super(...arguments);this.json=ge.Boolean(\"--json\",!1,{description:\"Format the output as an NDJSON stream\"})}async execute(){let r=await Ke.find(this.context.cwd,this.context.plugins),o=await Ke.findRcFiles(this.context.cwd);return(await Nt.start({configuration:r,json:this.json,stdout:this.context.stdout},async n=>{for(let u of o)if(!!u.data?.plugins)for(let A of u.data.plugins){if(!A.checksum||!A.spec.match(/^https?:/))continue;let p=await rn.get(A.spec,{configuration:r}),h=wn.makeHash(p);if(A.checksum===h)continue;let C=de.pretty(r,A.path,de.Type.PATH),I=de.pretty(r,A.spec,de.Type.URL),v=`${C} is different from the file provided by ${I}`;n.reportJson({...A,newChecksum:h}),n.reportError(0,v)}})).exitCode()}};Yh.paths=[[\"plugin\",\"check\"]],Yh.usage=nt.Usage({category:\"Plugin-related commands\",description:\"find all third-party plugins that differ from their own spec\",details:`\n      Check only the plugins from https.\n\n      If this command detects any plugin differences in the CI environment, it will throw an error.\n    `,examples:[[\"find all third-party plugins that differ from their own spec\",\"$0 plugin check\"]]});Ye();Ye();Pt();qt();var ade=Be(\"os\");Ye();Pt();qt();var rde=Be(\"os\");Ye();Nl();qt();var Z0t=\"https://raw.githubusercontent.com/yarnpkg/berry/master/plugins.yml\";async function Vd(t,e){let r=await rn.get(Z0t,{configuration:t}),o=Ki(r.toString());return Object.fromEntries(Object.entries(o).filter(([a,n])=>!e||kr.satisfiesWithPrereleases(e,n.range??\"<4.0.0-rc.1\")))}var Wh=class extends ut{constructor(){super(...arguments);this.json=ge.Boolean(\"--json\",!1,{description:\"Format the output as an NDJSON stream\"})}async execute(){let r=await Ke.find(this.context.cwd,this.context.plugins);return(await Nt.start({configuration:r,json:this.json,stdout:this.context.stdout},async a=>{let n=await Vd(r,tn);for(let[u,{experimental:A,...p}]of Object.entries(n)){let h=u;A&&(h+=\" [experimental]\"),a.reportJson({name:u,experimental:A,...p}),a.reportInfo(null,h)}})).exitCode()}};Wh.paths=[[\"plugin\",\"list\"]],Wh.usage=nt.Usage({category:\"Plugin-related commands\",description:\"list the available official plugins\",details:\"\\n      This command prints the plugins available directly from the Yarn repository. Only those plugins can be referenced by name in `yarn plugin import`.\\n    \",examples:[[\"List the official plugins\",\"$0 plugin list\"]]});var $0t=/^[0-9]+$/;function nde(t){return $0t.test(t)?`pull/${t}/head`:t}var egt=({repository:t,branch:e},r)=>[[\"git\",\"init\",ue.fromPortablePath(r)],[\"git\",\"remote\",\"add\",\"origin\",t],[\"git\",\"fetch\",\"origin\",\"--depth=1\",nde(e)],[\"git\",\"reset\",\"--hard\",\"FETCH_HEAD\"]],tgt=({branch:t})=>[[\"git\",\"fetch\",\"origin\",\"--depth=1\",nde(t),\"--force\"],[\"git\",\"reset\",\"--hard\",\"FETCH_HEAD\"],[\"git\",\"clean\",\"-dfx\",\"-e\",\"packages/yarnpkg-cli/bundles\"]],rgt=({plugins:t,noMinify:e},r,o)=>[[\"yarn\",\"build:cli\",...new Array().concat(...t.map(a=>[\"--plugin\",V.resolve(o,a)])),...e?[\"--no-minify\"]:[],\"|\"],[\"mv\",\"packages/yarnpkg-cli/bundles/yarn.js\",ue.fromPortablePath(r),\"|\"]],Kh=class extends ut{constructor(){super(...arguments);this.installPath=ge.String(\"--path\",{description:\"The path where the repository should be cloned to\"});this.repository=ge.String(\"--repository\",\"https://github.com/yarnpkg/berry.git\",{description:\"The repository that should be cloned\"});this.branch=ge.String(\"--branch\",\"master\",{description:\"The branch of the repository that should be cloned\"});this.plugins=ge.Array(\"--plugin\",[],{description:\"An array of additional plugins that should be included in the bundle\"});this.dryRun=ge.Boolean(\"-n,--dry-run\",!1,{description:\"If set, the bundle will be built but not added to the project\"});this.noMinify=ge.Boolean(\"--no-minify\",!1,{description:\"Build a bundle for development (debugging) - non-minified and non-mangled\"});this.force=ge.Boolean(\"-f,--force\",!1,{description:\"Always clone the repository instead of trying to fetch the latest commits\"});this.skipPlugins=ge.Boolean(\"--skip-plugins\",!1,{description:\"Skip updating the contrib plugins\"})}async execute(){let r=await Ke.find(this.context.cwd,this.context.plugins),{project:o}=await St.find(r,this.context.cwd),a=typeof this.installPath<\"u\"?V.resolve(this.context.cwd,ue.toPortablePath(this.installPath)):V.resolve(ue.toPortablePath((0,rde.tmpdir)()),\"yarnpkg-sources\",wn.makeHash(this.repository).slice(0,6));return(await Nt.start({configuration:r,stdout:this.context.stdout},async u=>{await _8(this,{configuration:r,report:u,target:a}),u.reportSeparator(),u.reportInfo(0,\"Building a fresh bundle\"),u.reportSeparator();let A=await Ur.execvp(\"git\",[\"rev-parse\",\"--short\",\"HEAD\"],{cwd:a,strict:!0}),p=V.join(a,`packages/yarnpkg-cli/bundles/yarn-${A.stdout.trim()}.js`);oe.existsSync(p)||(await m2(rgt(this,p,a),{configuration:r,context:this.context,target:a}),u.reportSeparator());let h=await oe.readFilePromise(p);if(!this.dryRun){let{bundleVersion:C}=await M8(r,null,async()=>h,{report:u});this.skipPlugins||await ngt(this,C,{project:o,report:u,target:a})}})).exitCode()}};Kh.paths=[[\"set\",\"version\",\"from\",\"sources\"]],Kh.usage=nt.Usage({description:\"build Yarn from master\",details:`\n      This command will clone the Yarn repository into a temporary folder, then build it. The resulting bundle will then be copied into the local project.\n\n      By default, it also updates all contrib plugins to the same commit the bundle is built from. This behavior can be disabled by using the \\`--skip-plugins\\` flag.\n    `,examples:[[\"Build Yarn from master\",\"$0 set version from sources\"]]});async function m2(t,{configuration:e,context:r,target:o}){for(let[a,...n]of t){let u=n[n.length-1]===\"|\";if(u&&n.pop(),u)await Ur.pipevp(a,n,{cwd:o,stdin:r.stdin,stdout:r.stdout,stderr:r.stderr,strict:!0});else{r.stdout.write(`${de.pretty(e,`  $ ${[a,...n].join(\" \")}`,\"grey\")}\n`);try{await Ur.execvp(a,n,{cwd:o,strict:!0})}catch(A){throw r.stdout.write(A.stdout||A.stack),A}}}}async function _8(t,{configuration:e,report:r,target:o}){let a=!1;if(!t.force&&oe.existsSync(V.join(o,\".git\"))){r.reportInfo(0,\"Fetching the latest commits\"),r.reportSeparator();try{await m2(tgt(t),{configuration:e,context:t.context,target:o}),a=!0}catch{r.reportSeparator(),r.reportWarning(0,\"Repository update failed; we'll try to regenerate it\")}}a||(r.reportInfo(0,\"Cloning the remote repository\"),r.reportSeparator(),await oe.removePromise(o),await oe.mkdirPromise(o,{recursive:!0}),await m2(egt(t,o),{configuration:e,context:t.context,target:o}))}async function ngt(t,e,{project:r,report:o,target:a}){let n=await Vd(r.configuration,e),u=new Set(Object.keys(n));for(let A of r.configuration.plugins.keys())!u.has(A)||await H8(A,t,{project:r,report:o,target:a})}Ye();Ye();Pt();qt();var ide=$e(Jn()),sde=Be(\"url\"),ode=Be(\"vm\");var Vh=class extends ut{constructor(){super(...arguments);this.name=ge.String();this.checksum=ge.Boolean(\"--checksum\",!0,{description:\"Whether to care if this plugin is modified\"})}async execute(){let r=await Ke.find(this.context.cwd,this.context.plugins);return(await Nt.start({configuration:r,stdout:this.context.stdout},async a=>{let{project:n}=await St.find(r,this.context.cwd),u,A;if(this.name.match(/^\\.{0,2}[\\\\/]/)||ue.isAbsolute(this.name)){let p=V.resolve(this.context.cwd,ue.toPortablePath(this.name));a.reportInfo(0,`Reading ${de.pretty(r,p,de.Type.PATH)}`),u=V.relative(n.cwd,p),A=await oe.readFilePromise(p)}else{let p;if(this.name.match(/^https?:/)){try{new sde.URL(this.name)}catch{throw new Jt(52,`Plugin specifier \"${this.name}\" is neither a plugin name nor a valid url`)}u=this.name,p=this.name}else{let h=W.parseLocator(this.name.replace(/^((@yarnpkg\\/)?plugin-)?/,\"@yarnpkg/plugin-\"));if(h.reference!==\"unknown\"&&!ide.default.valid(h.reference))throw new Jt(0,\"Official plugins only accept strict version references. Use an explicit URL if you wish to download them from another location.\");let C=W.stringifyIdent(h),I=await Vd(r,tn);if(!Object.hasOwn(I,C)){let v=`Couldn't find a plugin named ${W.prettyIdent(r,h)} on the remote registry.\n`;throw r.plugins.has(C)?v+=`A plugin named ${W.prettyIdent(r,h)} is already installed; possibly attempting to import a built-in plugin.`:v+=`Note that only the plugins referenced on our website (${de.pretty(r,\"https://github.com/yarnpkg/berry/blob/master/plugins.yml\",de.Type.URL)}) can be referenced by their name; any other plugin will have to be referenced through its public url (for example ${de.pretty(r,\"https://github.com/yarnpkg/berry/raw/master/packages/plugin-typescript/bin/%40yarnpkg/plugin-typescript.js\",de.Type.URL)}).`,new Jt(51,v)}u=C,p=I[C].url,h.reference!==\"unknown\"?p=p.replace(/\\/master\\//,`/${C}/${h.reference}/`):tn!==null&&(p=p.replace(/\\/master\\//,`/@yarnpkg/cli/${tn}/`))}a.reportInfo(0,`Downloading ${de.pretty(r,p,\"green\")}`),A=await rn.get(p,{configuration:r})}await j8(u,A,{checksum:this.checksum,project:n,report:a})})).exitCode()}};Vh.paths=[[\"plugin\",\"import\"]],Vh.usage=nt.Usage({category:\"Plugin-related commands\",description:\"download a plugin\",details:`\n      This command downloads the specified plugin from its remote location and updates the configuration to reference it in further CLI invocations.\n\n      Three types of plugin references are accepted:\n\n      - If the plugin is stored within the Yarn repository, it can be referenced by name.\n      - Third-party plugins can be referenced directly through their public urls.\n      - Local plugins can be referenced by their path on the disk.\n\n      If the \\`--no-checksum\\` option is set, Yarn will no longer care if the plugin is modified.\n\n      Plugins cannot be downloaded from the npm registry, and aren't allowed to have dependencies (they need to be bundled into a single file, possibly thanks to the \\`@yarnpkg/builder\\` package).\n    `,examples:[['Download and activate the \"@yarnpkg/plugin-exec\" plugin',\"$0 plugin import @yarnpkg/plugin-exec\"],['Download and activate the \"@yarnpkg/plugin-exec\" plugin (shorthand)',\"$0 plugin import exec\"],[\"Download and activate a community plugin\",\"$0 plugin import https://example.org/path/to/plugin.js\"],[\"Activate a local plugin\",\"$0 plugin import ./path/to/plugin.js\"]]});async function j8(t,e,{checksum:r=!0,project:o,report:a}){let{configuration:n}=o,u={},A={exports:u};(0,ode.runInNewContext)(e.toString(),{module:A,exports:u});let h=`.yarn/plugins/${A.exports.name}.cjs`,C=V.resolve(o.cwd,h);a.reportInfo(0,`Saving the new plugin in ${de.pretty(n,h,\"magenta\")}`),await oe.mkdirPromise(V.dirname(C),{recursive:!0}),await oe.writeFilePromise(C,e);let I={path:h,spec:t};r&&(I.checksum=wn.makeHash(e)),await Ke.addPlugin(o.cwd,[I])}var igt=({pluginName:t,noMinify:e},r)=>[[\"yarn\",`build:${t}`,...e?[\"--no-minify\"]:[],\"|\"]],zh=class extends ut{constructor(){super(...arguments);this.installPath=ge.String(\"--path\",{description:\"The path where the repository should be cloned to\"});this.repository=ge.String(\"--repository\",\"https://github.com/yarnpkg/berry.git\",{description:\"The repository that should be cloned\"});this.branch=ge.String(\"--branch\",\"master\",{description:\"The branch of the repository that should be cloned\"});this.noMinify=ge.Boolean(\"--no-minify\",!1,{description:\"Build a plugin for development (debugging) - non-minified and non-mangled\"});this.force=ge.Boolean(\"-f,--force\",!1,{description:\"Always clone the repository instead of trying to fetch the latest commits\"});this.name=ge.String()}async execute(){let r=await Ke.find(this.context.cwd,this.context.plugins),o=typeof this.installPath<\"u\"?V.resolve(this.context.cwd,ue.toPortablePath(this.installPath)):V.resolve(ue.toPortablePath((0,ade.tmpdir)()),\"yarnpkg-sources\",wn.makeHash(this.repository).slice(0,6));return(await Nt.start({configuration:r,stdout:this.context.stdout},async n=>{let{project:u}=await St.find(r,this.context.cwd),A=W.parseIdent(this.name.replace(/^((@yarnpkg\\/)?plugin-)?/,\"@yarnpkg/plugin-\")),p=W.stringifyIdent(A),h=await Vd(r,tn);if(!Object.hasOwn(h,p))throw new Jt(51,`Couldn't find a plugin named \"${p}\" on the remote registry. Note that only the plugins referenced on our website (https://github.com/yarnpkg/berry/blob/master/plugins.yml) can be built and imported from sources.`);let C=p;await _8(this,{configuration:r,report:n,target:o}),await H8(C,this,{project:u,report:n,target:o})})).exitCode()}};zh.paths=[[\"plugin\",\"import\",\"from\",\"sources\"]],zh.usage=nt.Usage({category:\"Plugin-related commands\",description:\"build a plugin from sources\",details:`\n      This command clones the Yarn repository into a temporary folder, builds the specified contrib plugin and updates the configuration to reference it in further CLI invocations.\n\n      The plugins can be referenced by their short name if sourced from the official Yarn repository.\n    `,examples:[['Build and activate the \"@yarnpkg/plugin-exec\" plugin',\"$0 plugin import from sources @yarnpkg/plugin-exec\"],['Build and activate the \"@yarnpkg/plugin-exec\" plugin (shorthand)',\"$0 plugin import from sources exec\"]]});async function H8(t,{context:e,noMinify:r},{project:o,report:a,target:n}){let u=t.replace(/@yarnpkg\\//,\"\"),{configuration:A}=o;a.reportSeparator(),a.reportInfo(0,`Building a fresh ${u}`),a.reportSeparator(),await m2(igt({pluginName:u,noMinify:r},n),{configuration:A,context:e,target:n}),a.reportSeparator();let p=V.resolve(n,`packages/${u}/bundles/${t}.js`),h=await oe.readFilePromise(p);await j8(t,h,{project:o,report:a})}Ye();Pt();qt();var Jh=class extends ut{constructor(){super(...arguments);this.name=ge.String()}async execute(){let r=await Ke.find(this.context.cwd,this.context.plugins),{project:o}=await St.find(r,this.context.cwd);return(await Nt.start({configuration:r,stdout:this.context.stdout},async n=>{let u=this.name,A=W.parseIdent(u);if(!r.plugins.has(u))throw new it(`${W.prettyIdent(r,A)} isn't referenced by the current configuration`);let p=`.yarn/plugins/${u}.cjs`,h=V.resolve(o.cwd,p);oe.existsSync(h)&&(n.reportInfo(0,`Removing ${de.pretty(r,p,de.Type.PATH)}...`),await oe.removePromise(h)),n.reportInfo(0,\"Updating the configuration...\"),await Ke.updateConfiguration(o.cwd,{plugins:C=>{if(!Array.isArray(C))return C;let I=C.filter(v=>v.path!==p);return I.length===0?Ke.deleteProperty:I.length===C.length?C:I}})})).exitCode()}};Jh.paths=[[\"plugin\",\"remove\"]],Jh.usage=nt.Usage({category:\"Plugin-related commands\",description:\"remove a plugin\",details:`\n      This command deletes the specified plugin from the .yarn/plugins folder and removes it from the configuration.\n\n      **Note:** The plugins have to be referenced by their name property, which can be obtained using the \\`yarn plugin runtime\\` command. Shorthands are not allowed.\n   `,examples:[[\"Remove a plugin imported from the Yarn repository\",\"$0 plugin remove @yarnpkg/plugin-typescript\"],[\"Remove a plugin imported from a local file\",\"$0 plugin remove my-local-plugin\"]]});Ye();qt();var Xh=class extends ut{constructor(){super(...arguments);this.json=ge.Boolean(\"--json\",!1,{description:\"Format the output as an NDJSON stream\"})}async execute(){let r=await Ke.find(this.context.cwd,this.context.plugins);return(await Nt.start({configuration:r,json:this.json,stdout:this.context.stdout},async a=>{for(let n of r.plugins.keys()){let u=this.context.plugins.plugins.has(n),A=n;u&&(A+=\" [builtin]\"),a.reportJson({name:n,builtin:u}),a.reportInfo(null,`${A}`)}})).exitCode()}};Xh.paths=[[\"plugin\",\"runtime\"]],Xh.usage=nt.Usage({category:\"Plugin-related commands\",description:\"list the active plugins\",details:`\n      This command prints the currently active plugins. Will be displayed both builtin plugins and external plugins.\n    `,examples:[[\"List the currently active plugins\",\"$0 plugin runtime\"]]});Ye();Ye();qt();var Zh=class extends ut{constructor(){super(...arguments);this.idents=ge.Rest()}async execute(){let r=await Ke.find(this.context.cwd,this.context.plugins),{project:o,workspace:a}=await St.find(r,this.context.cwd),n=await Lr.find(r);if(!a)throw new rr(o.cwd,this.context.cwd);let u=new Set;for(let A of this.idents)u.add(W.parseIdent(A).identHash);if(await o.restoreInstallState({restoreResolutions:!1}),await o.resolveEverything({cache:n,report:new Qi}),u.size>0)for(let A of o.storedPackages.values())u.has(A.identHash)&&(o.storedBuildState.delete(A.locatorHash),o.skippedBuilds.delete(A.locatorHash));else o.storedBuildState.clear(),o.skippedBuilds.clear();return await o.installWithNewReport({stdout:this.context.stdout,quiet:this.context.quiet},{cache:n})}};Zh.paths=[[\"rebuild\"]],Zh.usage=nt.Usage({description:\"rebuild the project's native packages\",details:`\n      This command will automatically cause Yarn to forget about previous compilations of the given packages and to run them again.\n\n      Note that while Yarn forgets the compilation, the previous artifacts aren't erased from the filesystem and may affect the next builds (in good or bad). To avoid this, you may remove the .yarn/unplugged folder, or any other relevant location where packages might have been stored (Yarn may offer a way to do that automatically in the future).\n\n      By default all packages will be rebuilt, but you can filter the list by specifying the names of the packages you want to clear from memory.\n    `,examples:[[\"Rebuild all packages\",\"$0 rebuild\"],[\"Rebuild fsevents only\",\"$0 rebuild fsevents\"]]});Ye();Ye();Ye();qt();var q8=$e(Zo());Za();var $h=class extends ut{constructor(){super(...arguments);this.all=ge.Boolean(\"-A,--all\",!1,{description:\"Apply the operation to all workspaces from the current project\"});this.mode=ge.String(\"--mode\",{description:\"Change what artifacts installs generate\",validator:Ks(pl)});this.patterns=ge.Rest()}async execute(){let r=await Ke.find(this.context.cwd,this.context.plugins),{project:o,workspace:a}=await St.find(r,this.context.cwd),n=await Lr.find(r);if(!a)throw new rr(o.cwd,this.context.cwd);await o.restoreInstallState({restoreResolutions:!1});let u=this.all?o.workspaces:[a],A=[\"dependencies\",\"devDependencies\",\"peerDependencies\"],p=[],h=!1,C=[];for(let E of this.patterns){let R=!1,L=W.parseIdent(E);for(let U of u){let z=[...U.manifest.peerDependenciesMeta.keys()];for(let te of(0,q8.default)(z,E))U.manifest.peerDependenciesMeta.delete(te),h=!0,R=!0;for(let te of A){let le=U.manifest.getForScope(te),he=[...le.values()].map(Ae=>W.stringifyIdent(Ae));for(let Ae of(0,q8.default)(he,W.stringifyIdent(L))){let{identHash:ye}=W.parseIdent(Ae),ae=le.get(ye);if(typeof ae>\"u\")throw new Error(\"Assertion failed: Expected the descriptor to be registered\");U.manifest[te].delete(ye),C.push([U,te,ae]),h=!0,R=!0}}}R||p.push(E)}let I=p.length>1?\"Patterns\":\"Pattern\",v=p.length>1?\"don't\":\"doesn't\",x=this.all?\"any\":\"this\";if(p.length>0)throw new it(`${I} ${de.prettyList(r,p,de.Type.CODE)} ${v} match any packages referenced by ${x} workspace`);return h?(await r.triggerMultipleHooks(E=>E.afterWorkspaceDependencyRemoval,C),await o.installWithNewReport({stdout:this.context.stdout},{cache:n,mode:this.mode})):0}};$h.paths=[[\"remove\"]],$h.usage=nt.Usage({description:\"remove dependencies from the project\",details:`\n      This command will remove the packages matching the specified patterns from the current workspace.\n\n      If the \\`--mode=<mode>\\` option is set, Yarn will change which artifacts are generated. The modes currently supported are:\n\n      - \\`skip-build\\` will not run the build scripts at all. Note that this is different from setting \\`enableScripts\\` to false because the latter will disable build scripts, and thus affect the content of the artifacts generated on disk, whereas the former will just disable the build step - but not the scripts themselves, which just won't run.\n\n      - \\`update-lockfile\\` will skip the link step altogether, and only fetch packages that are missing from the lockfile (or that have no associated checksums). This mode is typically used by tools like Renovate or Dependabot to keep a lockfile up-to-date without incurring the full install cost.\n\n      This command accepts glob patterns as arguments (if valid Idents and supported by [micromatch](https://github.com/micromatch/micromatch)). Make sure to escape the patterns, to prevent your own shell from trying to expand them.\n    `,examples:[[\"Remove a dependency from the current project\",\"$0 remove lodash\"],[\"Remove a dependency from all workspaces at once\",\"$0 remove lodash --all\"],[\"Remove all dependencies starting with `eslint-`\",\"$0 remove 'eslint-*'\"],[\"Remove all dependencies with the `@babel` scope\",\"$0 remove '@babel/*'\"],[\"Remove all dependencies matching `react-dom` or `react-helmet`\",\"$0 remove 'react-{dom,helmet}'\"]]});Ye();Ye();var lde=Be(\"util\"),zd=class extends ut{async execute(){let e=await Ke.find(this.context.cwd,this.context.plugins),{project:r,workspace:o}=await St.find(e,this.context.cwd);if(!o)throw new rr(r.cwd,this.context.cwd);return(await Nt.start({configuration:e,stdout:this.context.stdout},async n=>{let u=o.manifest.scripts,A=je.sortMap(u.keys(),C=>C),p={breakLength:1/0,colors:e.get(\"enableColors\"),maxArrayLength:2},h=A.reduce((C,I)=>Math.max(C,I.length),0);for(let[C,I]of u.entries())n.reportInfo(null,`${C.padEnd(h,\" \")}   ${(0,lde.inspect)(I,p)}`)})).exitCode()}};zd.paths=[[\"run\"]];Ye();Ye();qt();var e0=class extends ut{constructor(){super(...arguments);this.inspect=ge.String(\"--inspect\",!1,{tolerateBoolean:!0,description:\"Forwarded to the underlying Node process when executing a binary\"});this.inspectBrk=ge.String(\"--inspect-brk\",!1,{tolerateBoolean:!0,description:\"Forwarded to the underlying Node process when executing a binary\"});this.topLevel=ge.Boolean(\"-T,--top-level\",!1,{description:\"Check the root workspace for scripts and/or binaries instead of the current one\"});this.binariesOnly=ge.Boolean(\"-B,--binaries-only\",!1,{description:\"Ignore any user defined scripts and only check for binaries\"});this.require=ge.String(\"--require\",{description:\"Forwarded to the underlying Node process when executing a binary\"});this.silent=ge.Boolean(\"--silent\",{hidden:!0});this.scriptName=ge.String();this.args=ge.Proxy()}async execute(){let r=await Ke.find(this.context.cwd,this.context.plugins),{project:o,workspace:a,locator:n}=await St.find(r,this.context.cwd);await o.restoreInstallState();let u=this.topLevel?o.topLevelWorkspace.anchoredLocator:n;if(!this.binariesOnly&&await un.hasPackageScript(u,this.scriptName,{project:o}))return await un.executePackageScript(u,this.scriptName,this.args,{project:o,stdin:this.context.stdin,stdout:this.context.stdout,stderr:this.context.stderr});let A=await un.getPackageAccessibleBinaries(u,{project:o});if(A.get(this.scriptName)){let h=[];return this.inspect&&(typeof this.inspect==\"string\"?h.push(`--inspect=${this.inspect}`):h.push(\"--inspect\")),this.inspectBrk&&(typeof this.inspectBrk==\"string\"?h.push(`--inspect-brk=${this.inspectBrk}`):h.push(\"--inspect-brk\")),this.require&&h.push(`--require=${this.require}`),await un.executePackageAccessibleBinary(u,this.scriptName,this.args,{cwd:this.context.cwd,project:o,stdin:this.context.stdin,stdout:this.context.stdout,stderr:this.context.stderr,nodeArgs:h,packageAccessibleBinaries:A})}if(!this.topLevel&&!this.binariesOnly&&a&&this.scriptName.includes(\":\")){let C=(await Promise.all(o.workspaces.map(async I=>I.manifest.scripts.has(this.scriptName)?I:null))).filter(I=>I!==null);if(C.length===1)return await un.executeWorkspaceScript(C[0],this.scriptName,this.args,{stdin:this.context.stdin,stdout:this.context.stdout,stderr:this.context.stderr})}if(this.topLevel)throw this.scriptName===\"node-gyp\"?new it(`Couldn't find a script name \"${this.scriptName}\" in the top-level (used by ${W.prettyLocator(r,n)}). This typically happens because some package depends on \"node-gyp\" to build itself, but didn't list it in their dependencies. To fix that, please run \"yarn add node-gyp\" into your top-level workspace. You also can open an issue on the repository of the specified package to suggest them to use an optional peer dependency.`):new it(`Couldn't find a script name \"${this.scriptName}\" in the top-level (used by ${W.prettyLocator(r,n)}).`);{if(this.scriptName===\"global\")throw new it(\"The 'yarn global' commands have been removed in 2.x - consider using 'yarn dlx' or a third-party plugin instead\");let h=[this.scriptName].concat(this.args);for(let[C,I]of cC)for(let v of I)if(h.length>=v.length&&JSON.stringify(h.slice(0,v.length))===JSON.stringify(v))throw new it(`Couldn't find a script named \"${this.scriptName}\", but a matching command can be found in the ${C} plugin. You can install it with \"yarn plugin import ${C}\".`);throw new it(`Couldn't find a script named \"${this.scriptName}\".`)}}};e0.paths=[[\"run\"]],e0.usage=nt.Usage({description:\"run a script defined in the package.json\",details:`\n      This command will run a tool. The exact tool that will be executed will depend on the current state of your workspace:\n\n      - If the \\`scripts\\` field from your local package.json contains a matching script name, its definition will get executed.\n\n      - Otherwise, if one of the local workspace's dependencies exposes a binary with a matching name, this binary will get executed.\n\n      - Otherwise, if the specified name contains a colon character and if one of the workspaces in the project contains exactly one script with a matching name, then this script will get executed.\n\n      Whatever happens, the cwd of the spawned process will be the workspace that declares the script (which makes it possible to call commands cross-workspaces using the third syntax).\n    `,examples:[[\"Run the tests from the local workspace\",\"$0 run test\"],['Same thing, but without the \"run\" keyword',\"$0 test\"],[\"Inspect Webpack while running\",\"$0 run --inspect-brk webpack\"]]});Ye();Ye();qt();var t0=class extends ut{constructor(){super(...arguments);this.save=ge.Boolean(\"-s,--save\",!1,{description:\"Persist the resolution inside the top-level manifest\"});this.descriptor=ge.String();this.resolution=ge.String()}async execute(){let r=await Ke.find(this.context.cwd,this.context.plugins),{project:o,workspace:a}=await St.find(r,this.context.cwd),n=await Lr.find(r);if(await o.restoreInstallState({restoreResolutions:!1}),!a)throw new rr(o.cwd,this.context.cwd);let u=W.parseDescriptor(this.descriptor,!0),A=W.makeDescriptor(u,this.resolution);return o.storedDescriptors.set(u.descriptorHash,u),o.storedDescriptors.set(A.descriptorHash,A),o.resolutionAliases.set(u.descriptorHash,A.descriptorHash),await o.installWithNewReport({stdout:this.context.stdout},{cache:n})}};t0.paths=[[\"set\",\"resolution\"]],t0.usage=nt.Usage({description:\"enforce a package resolution\",details:'\\n      This command updates the resolution table so that `descriptor` is resolved by `resolution`.\\n\\n      Note that by default this command only affect the current resolution table - meaning that this \"manual override\" will disappear if you remove the lockfile, or if the package disappear from the table. If you wish to make the enforced resolution persist whatever happens, add the `-s,--save` flag which will also edit the `resolutions` field from your top-level manifest.\\n\\n      Note that no attempt is made at validating that `resolution` is a valid resolution entry for `descriptor`.\\n    ',examples:[[\"Force all instances of lodash@npm:^1.2.3 to resolve to 1.5.0\",\"$0 set resolution lodash@npm:^1.2.3 1.5.0\"]]});Ye();Pt();qt();var cde=$e(Zo()),r0=class extends ut{constructor(){super(...arguments);this.all=ge.Boolean(\"-A,--all\",!1,{description:\"Unlink all workspaces belonging to the target project from the current one\"});this.leadingArguments=ge.Rest()}async execute(){let r=await Ke.find(this.context.cwd,this.context.plugins),{project:o,workspace:a}=await St.find(r,this.context.cwd),n=await Lr.find(r);if(!a)throw new rr(o.cwd,this.context.cwd);let u=o.topLevelWorkspace,A=new Set;if(this.leadingArguments.length===0&&this.all)for(let{pattern:p,reference:h}of u.manifest.resolutions)h.startsWith(\"portal:\")&&A.add(p.descriptor.fullName);if(this.leadingArguments.length>0)for(let p of this.leadingArguments){let h=V.resolve(this.context.cwd,ue.toPortablePath(p));if(je.isPathLike(p)){let C=await Ke.find(h,this.context.plugins,{useRc:!1,strict:!1}),{project:I,workspace:v}=await St.find(C,h);if(!v)throw new rr(I.cwd,h);if(this.all){for(let x of I.workspaces)x.manifest.name&&A.add(W.stringifyIdent(x.anchoredLocator));if(A.size===0)throw new it(\"No workspace found to be unlinked in the target project\")}else{if(!v.manifest.name)throw new it(\"The target workspace doesn't have a name and thus cannot be unlinked\");A.add(W.stringifyIdent(v.anchoredLocator))}}else{let C=[...u.manifest.resolutions.map(({pattern:I})=>I.descriptor.fullName)];for(let I of(0,cde.default)(C,p))A.add(I)}}return u.manifest.resolutions=u.manifest.resolutions.filter(({pattern:p})=>!A.has(p.descriptor.fullName)),await o.installWithNewReport({stdout:this.context.stdout,quiet:this.context.quiet},{cache:n})}};r0.paths=[[\"unlink\"]],r0.usage=nt.Usage({description:\"disconnect the local project from another one\",details:`\n      This command will remove any resolutions in the project-level manifest that would have been added via a yarn link with similar arguments.\n    `,examples:[[\"Unregister a remote workspace in the current project\",\"$0 unlink ~/ts-loader\"],[\"Unregister all workspaces from a remote project in the current project\",\"$0 unlink ~/jest --all\"],[\"Unregister all previously linked workspaces\",\"$0 unlink --all\"],[\"Unregister all workspaces matching a glob\",\"$0 unlink '@babel/*' 'pkg-{a,b}'\"]]});Ye();Ye();Ye();qt();var ude=$e(u2()),G8=$e(Zo());Za();var Kf=class extends ut{constructor(){super(...arguments);this.interactive=ge.Boolean(\"-i,--interactive\",{description:\"Offer various choices, depending on the detected upgrade paths\"});this.fixed=ge.Boolean(\"-F,--fixed\",!1,{description:\"Store dependency tags as-is instead of resolving them\"});this.exact=ge.Boolean(\"-E,--exact\",!1,{description:\"Don't use any semver modifier on the resolved range\"});this.tilde=ge.Boolean(\"-T,--tilde\",!1,{description:\"Use the `~` semver modifier on the resolved range\"});this.caret=ge.Boolean(\"-C,--caret\",!1,{description:\"Use the `^` semver modifier on the resolved range\"});this.recursive=ge.Boolean(\"-R,--recursive\",!1,{description:\"Resolve again ALL resolutions for those packages\"});this.mode=ge.String(\"--mode\",{description:\"Change what artifacts installs generate\",validator:Ks(pl)});this.patterns=ge.Rest()}async execute(){return this.recursive?await this.executeUpRecursive():await this.executeUpClassic()}async executeUpRecursive(){let r=await Ke.find(this.context.cwd,this.context.plugins),{project:o,workspace:a}=await St.find(r,this.context.cwd),n=await Lr.find(r);if(!a)throw new rr(o.cwd,this.context.cwd);await o.restoreInstallState({restoreResolutions:!1});let u=[...o.storedDescriptors.values()],A=u.map(C=>W.stringifyIdent(C)),p=new Set;for(let C of this.patterns){if(W.parseDescriptor(C).range!==\"unknown\")throw new it(\"Ranges aren't allowed when using --recursive\");for(let I of(0,G8.default)(A,C)){let v=W.parseIdent(I);p.add(v.identHash)}}let h=u.filter(C=>p.has(C.identHash));for(let C of h)o.storedDescriptors.delete(C.descriptorHash),o.storedResolutions.delete(C.descriptorHash);return await o.installWithNewReport({stdout:this.context.stdout},{cache:n,mode:this.mode})}async executeUpClassic(){let r=await Ke.find(this.context.cwd,this.context.plugins),{project:o,workspace:a}=await St.find(r,this.context.cwd),n=await Lr.find(r);if(!a)throw new rr(o.cwd,this.context.cwd);await o.restoreInstallState({restoreResolutions:!1});let u=this.fixed,A=this.interactive??r.get(\"preferInteractive\"),p=f2(this,o),h=A?[\"keep\",\"reuse\",\"project\",\"latest\"]:[\"project\",\"latest\"],C=[],I=[];for(let L of this.patterns){let U=!1,z=W.parseDescriptor(L),te=W.stringifyIdent(z);for(let le of o.workspaces)for(let he of[\"dependencies\",\"devDependencies\"]){let ye=[...le.manifest.getForScope(he).values()].map(Ie=>W.stringifyIdent(Ie)),ae=te===\"*\"?ye:(0,G8.default)(ye,te);for(let Ie of ae){let Fe=W.parseIdent(Ie),g=le.manifest[he].get(Fe.identHash);if(typeof g>\"u\")throw new Error(\"Assertion failed: Expected the descriptor to be registered\");let Ee=W.makeDescriptor(Fe,z.range);C.push(Promise.resolve().then(async()=>[le,he,g,await p2(Ee,{project:o,workspace:le,cache:n,target:he,fixed:u,modifier:p,strategies:h})])),U=!0}}U||I.push(L)}if(I.length>1)throw new it(`Patterns ${de.prettyList(r,I,de.Type.CODE)} don't match any packages referenced by any workspace`);if(I.length>0)throw new it(`Pattern ${de.prettyList(r,I,de.Type.CODE)} doesn't match any packages referenced by any workspace`);let v=await Promise.all(C),x=await AA.start({configuration:r,stdout:this.context.stdout,suggestInstall:!1},async L=>{for(let[,,U,{suggestions:z,rejections:te}]of v){let le=z.filter(he=>he.descriptor!==null);if(le.length===0){let[he]=te;if(typeof he>\"u\")throw new Error(\"Assertion failed: Expected an error to have been set\");let Ae=this.cli.error(he);o.configuration.get(\"enableNetwork\")?L.reportError(27,`${W.prettyDescriptor(r,U)} can't be resolved to a satisfying range\n\n${Ae}`):L.reportError(27,`${W.prettyDescriptor(r,U)} can't be resolved to a satisfying range (note: network resolution has been disabled)\n\n${Ae}`)}else le.length>1&&!A&&L.reportError(27,`${W.prettyDescriptor(r,U)} has multiple possible upgrade strategies; use -i to disambiguate manually`)}});if(x.hasErrors())return x.exitCode();let E=!1,R=[];for(let[L,U,,{suggestions:z}]of v){let te,le=z.filter(ae=>ae.descriptor!==null),he=le[0].descriptor,Ae=le.every(ae=>W.areDescriptorsEqual(ae.descriptor,he));le.length===1||Ae?te=he:(E=!0,{answer:te}=await(0,ude.prompt)({type:\"select\",name:\"answer\",message:`Which range do you want to use in ${W.prettyWorkspace(r,L)} \\u276F ${U}?`,choices:z.map(({descriptor:ae,name:Ie,reason:Fe})=>ae?{name:Ie,hint:Fe,descriptor:ae}:{name:Ie,hint:Fe,disabled:!0}),onCancel:()=>process.exit(130),result(ae){return this.find(ae,\"descriptor\")},stdin:this.context.stdin,stdout:this.context.stdout}));let ye=L.manifest[U].get(te.identHash);if(typeof ye>\"u\")throw new Error(\"Assertion failed: This descriptor should have a matching entry\");if(ye.descriptorHash!==te.descriptorHash)L.manifest[U].set(te.identHash,te),R.push([L,U,ye,te]);else{let ae=r.makeResolver(),Ie={project:o,resolver:ae},Fe=r.normalizeDependency(ye),g=ae.bindDescriptor(Fe,L.anchoredLocator,Ie);o.forgetResolution(g)}}return await r.triggerMultipleHooks(L=>L.afterWorkspaceDependencyReplacement,R),E&&this.context.stdout.write(`\n`),await o.installWithNewReport({stdout:this.context.stdout},{cache:n,mode:this.mode})}};Kf.paths=[[\"up\"]],Kf.usage=nt.Usage({description:\"upgrade dependencies across the project\",details:\"\\n      This command upgrades the packages matching the list of specified patterns to their latest available version across the whole project (regardless of whether they're part of `dependencies` or `devDependencies` - `peerDependencies` won't be affected). This is a project-wide command: all workspaces will be upgraded in the process.\\n\\n      If `-R,--recursive` is set the command will change behavior and no other switch will be allowed. When operating under this mode `yarn up` will force all ranges matching the selected packages to be resolved again (often to the highest available versions) before being stored in the lockfile. It however won't touch your manifests anymore, so depending on your needs you might want to run both `yarn up` and `yarn up -R` to cover all bases.\\n\\n      If `-i,--interactive` is set (or if the `preferInteractive` settings is toggled on) the command will offer various choices, depending on the detected upgrade paths. Some upgrades require this flag in order to resolve ambiguities.\\n\\n      The, `-C,--caret`, `-E,--exact` and  `-T,--tilde` options have the same meaning as in the `add` command (they change the modifier used when the range is missing or a tag, and are ignored when the range is explicitly set).\\n\\n      If the `--mode=<mode>` option is set, Yarn will change which artifacts are generated. The modes currently supported are:\\n\\n      - `skip-build` will not run the build scripts at all. Note that this is different from setting `enableScripts` to false because the latter will disable build scripts, and thus affect the content of the artifacts generated on disk, whereas the former will just disable the build step - but not the scripts themselves, which just won't run.\\n\\n      - `update-lockfile` will skip the link step altogether, and only fetch packages that are missing from the lockfile (or that have no associated checksums). This mode is typically used by tools like Renovate or Dependabot to keep a lockfile up-to-date without incurring the full install cost.\\n\\n      Generally you can see `yarn up` as a counterpart to what was `yarn upgrade --latest` in Yarn 1 (ie it ignores the ranges previously listed in your manifests), but unlike `yarn upgrade` which only upgraded dependencies in the current workspace, `yarn up` will upgrade all workspaces at the same time.\\n\\n      This command accepts glob patterns as arguments (if valid Descriptors and supported by [micromatch](https://github.com/micromatch/micromatch)). Make sure to escape the patterns, to prevent your own shell from trying to expand them.\\n\\n      **Note:** The ranges have to be static, only the package scopes and names can contain glob patterns.\\n    \",examples:[[\"Upgrade all instances of lodash to the latest release\",\"$0 up lodash\"],[\"Upgrade all instances of lodash to the latest release, but ask confirmation for each\",\"$0 up lodash -i\"],[\"Upgrade all instances of lodash to 1.2.3\",\"$0 up lodash@1.2.3\"],[\"Upgrade all instances of packages with the `@babel` scope to the latest release\",\"$0 up '@babel/*'\"],[\"Upgrade all instances of packages containing the word `jest` to the latest release\",\"$0 up '*jest*'\"],[\"Upgrade all instances of packages with the `@babel` scope to 7.0.0\",\"$0 up '@babel/*@7.0.0'\"]]}),Kf.schema=[aI(\"recursive\",Gu.Forbids,[\"interactive\",\"exact\",\"tilde\",\"caret\"],{ignore:[void 0,!1]})];Ye();Ye();Ye();qt();var n0=class extends ut{constructor(){super(...arguments);this.recursive=ge.Boolean(\"-R,--recursive\",!1,{description:\"List, for each workspace, what are all the paths that lead to the dependency\"});this.json=ge.Boolean(\"--json\",!1,{description:\"Format the output as an NDJSON stream\"});this.peers=ge.Boolean(\"--peers\",!1,{description:\"Also print the peer dependencies that match the specified name\"});this.package=ge.String()}async execute(){let r=await Ke.find(this.context.cwd,this.context.plugins),{project:o,workspace:a}=await St.find(r,this.context.cwd);if(!a)throw new rr(o.cwd,this.context.cwd);await o.restoreInstallState();let n=W.parseIdent(this.package).identHash,u=this.recursive?ogt(o,n,{configuration:r,peers:this.peers}):sgt(o,n,{configuration:r,peers:this.peers});$s.emitTree(u,{configuration:r,stdout:this.context.stdout,json:this.json,separators:1})}};n0.paths=[[\"why\"]],n0.usage=nt.Usage({description:\"display the reason why a package is needed\",details:`\n      This command prints the exact reasons why a package appears in the dependency tree.\n\n      If \\`-R,--recursive\\` is set, the listing will go in depth and will list, for each workspaces, what are all the paths that lead to the dependency. Note that the display is somewhat optimized in that it will not print the package listing twice for a single package, so if you see a leaf named \"Foo\" when looking for \"Bar\", it means that \"Foo\" already got printed higher in the tree.\n    `,examples:[[\"Explain why lodash is used in your project\",\"$0 why lodash\"]]});function sgt(t,e,{configuration:r,peers:o}){let a=je.sortMap(t.storedPackages.values(),A=>W.stringifyLocator(A)),n={},u={children:n};for(let A of a){let p={};for(let C of A.dependencies.values()){if(!o&&A.peerDependencies.has(C.identHash))continue;let I=t.storedResolutions.get(C.descriptorHash);if(!I)throw new Error(\"Assertion failed: The resolution should have been registered\");let v=t.storedPackages.get(I);if(!v)throw new Error(\"Assertion failed: The package should have been registered\");if(v.identHash!==e)continue;{let E=W.stringifyLocator(A);n[E]={value:[A,de.Type.LOCATOR],children:p}}let x=W.stringifyLocator(v);p[x]={value:[{descriptor:C,locator:v},de.Type.DEPENDENT]}}}return u}function ogt(t,e,{configuration:r,peers:o}){let a=je.sortMap(t.workspaces,v=>W.stringifyLocator(v.anchoredLocator)),n=new Set,u=new Set,A=v=>{if(n.has(v.locatorHash))return u.has(v.locatorHash);if(n.add(v.locatorHash),v.identHash===e)return u.add(v.locatorHash),!0;let x=!1;v.identHash===e&&(x=!0);for(let E of v.dependencies.values()){if(!o&&v.peerDependencies.has(E.identHash))continue;let R=t.storedResolutions.get(E.descriptorHash);if(!R)throw new Error(\"Assertion failed: The resolution should have been registered\");let L=t.storedPackages.get(R);if(!L)throw new Error(\"Assertion failed: The package should have been registered\");A(L)&&(x=!0)}return x&&u.add(v.locatorHash),x};for(let v of a)A(v.anchoredPackage);let p=new Set,h={},C={children:h},I=(v,x,E)=>{if(!u.has(v.locatorHash))return;let R=E!==null?de.tuple(de.Type.DEPENDENT,{locator:v,descriptor:E}):de.tuple(de.Type.LOCATOR,v),L={},U={value:R,children:L},z=W.stringifyLocator(v);if(x[z]=U,!p.has(v.locatorHash)&&(p.add(v.locatorHash),!(E!==null&&t.tryWorkspaceByLocator(v))))for(let te of v.dependencies.values()){if(!o&&v.peerDependencies.has(te.identHash))continue;let le=t.storedResolutions.get(te.descriptorHash);if(!le)throw new Error(\"Assertion failed: The resolution should have been registered\");let he=t.storedPackages.get(le);if(!he)throw new Error(\"Assertion failed: The package should have been registered\");I(he,L,te)}};for(let v of a)I(v.anchoredPackage,h,null);return C}Ye();var eH={};Vt(eH,{GitFetcher:()=>E2,GitResolver:()=>C2,default:()=>Sgt,gitUtils:()=>ra});Ye();Pt();var ra={};Vt(ra,{TreeishProtocols:()=>y2,clone:()=>$8,fetchBase:()=>Fde,fetchChangedFiles:()=>Rde,fetchChangedWorkspaces:()=>Dgt,fetchRoot:()=>Qde,isGitUrl:()=>yC,lsRemote:()=>kde,normalizeLocator:()=>vgt,normalizeRepoUrl:()=>dC,resolveUrl:()=>Z8,splitRepoUrl:()=>i0,validateRepoUrl:()=>X8});Ye();Pt();qt();var Sde=$e(vde()),bde=$e(EU()),mC=$e(Be(\"querystring\")),z8=$e(Jn());function V8(t,e,r){let o=t.indexOf(r);return t.lastIndexOf(e,o>-1?o:1/0)}function Dde(t){try{return new URL(t)}catch{return}}function Igt(t){let e=V8(t,\"@\",\"#\"),r=V8(t,\":\",\"#\");return r>e&&(t=`${t.slice(0,r)}/${t.slice(r+1)}`),V8(t,\":\",\"#\")===-1&&t.indexOf(\"//\")===-1&&(t=`ssh://${t}`),t}function Pde(t){return Dde(t)||Dde(Igt(t))}function dC(t,{git:e=!1}={}){if(t=t.replace(/^git\\+https:/,\"https:\"),t=t.replace(/^(?:github:|https:\\/\\/github\\.com\\/|git:\\/\\/github\\.com\\/)?(?!\\.{1,2}\\/)([a-zA-Z0-9._-]+)\\/(?!\\.{1,2}(?:#|$))([a-zA-Z0-9._-]+?)(?:\\.git)?(#.*)?$/,\"https://github.com/$1/$2.git$3\"),t=t.replace(/^https:\\/\\/github\\.com\\/(?!\\.{1,2}\\/)([a-zA-Z0-9._-]+)\\/(?!\\.{1,2}(?:#|$))([a-zA-Z0-9._-]+?)\\/tarball\\/(.+)?$/,\"https://github.com/$1/$2.git#$3\"),e){let r=Pde(t);r&&(t=r.href),t=t.replace(/^git\\+([^:]+):/,\"$1:\")}return t}function xde(){return{...process.env,GIT_SSH_COMMAND:process.env.GIT_SSH_COMMAND||`${process.env.GIT_SSH||\"ssh\"} -o BatchMode=yes`}}var Bgt=[/^ssh:/,/^git(?:\\+[^:]+)?:/,/^(?:git\\+)?https?:[^#]+\\/[^#]+(?:\\.git)(?:#.*)?$/,/^git@[^#]+\\/[^#]+\\.git(?:#.*)?$/,/^(?:github:|https:\\/\\/github\\.com\\/)?(?!\\.{1,2}\\/)([a-zA-Z._0-9-]+)\\/(?!\\.{1,2}(?:#|$))([a-zA-Z._0-9-]+?)(?:\\.git)?(?:#.*)?$/,/^https:\\/\\/github\\.com\\/(?!\\.{1,2}\\/)([a-zA-Z0-9._-]+)\\/(?!\\.{1,2}(?:#|$))([a-zA-Z0-9._-]+?)\\/tarball\\/(.+)?$/],y2=(a=>(a.Commit=\"commit\",a.Head=\"head\",a.Tag=\"tag\",a.Semver=\"semver\",a))(y2||{});function yC(t){return t?Bgt.some(e=>!!t.match(e)):!1}function i0(t){t=dC(t);let e=t.indexOf(\"#\");if(e===-1)return{repo:t,treeish:{protocol:\"head\",request:\"HEAD\"},extra:{}};let r=t.slice(0,e),o=t.slice(e+1);if(o.match(/^[a-z]+=/)){let a=mC.default.parse(o);for(let[p,h]of Object.entries(a))if(typeof h!=\"string\")throw new Error(`Assertion failed: The ${p} parameter must be a literal string`);let n=Object.values(y2).find(p=>Object.hasOwn(a,p)),[u,A]=typeof n<\"u\"?[n,a[n]]:[\"head\",\"HEAD\"];for(let p of Object.values(y2))delete a[p];return{repo:r,treeish:{protocol:u,request:A},extra:a}}else{let a=o.indexOf(\":\"),[n,u]=a===-1?[null,o]:[o.slice(0,a),o.slice(a+1)];return{repo:r,treeish:{protocol:n,request:u},extra:{}}}}function vgt(t){return W.makeLocator(t,dC(t.reference))}function X8(t,{configuration:e}){let r=dC(t,{git:!0});if(!rn.getNetworkSettings(`https://${(0,Sde.default)(r).resource}`,{configuration:e}).enableNetwork)throw new Jt(80,`Request to '${r}' has been blocked because of your configuration settings`);return r}async function kde(t,e){let r=X8(t,{configuration:e}),o=await J8(\"listing refs\",[\"ls-remote\",r],{cwd:e.startingCwd,env:xde()},{configuration:e,normalizedRepoUrl:r}),a=new Map,n=/^([a-f0-9]{40})\\t([^\\n]+)/gm,u;for(;(u=n.exec(o.stdout))!==null;)a.set(u[2],u[1]);return a}async function Z8(t,e){let{repo:r,treeish:{protocol:o,request:a},extra:n}=i0(t),u=await kde(r,e),A=(h,C)=>{switch(h){case\"commit\":{if(!C.match(/^[a-f0-9]{40}$/))throw new Error(\"Invalid commit hash\");return mC.default.stringify({...n,commit:C})}case\"head\":{let I=u.get(C===\"HEAD\"?C:`refs/heads/${C}`);if(typeof I>\"u\")throw new Error(`Unknown head (\"${C}\")`);return mC.default.stringify({...n,commit:I})}case\"tag\":{let I=u.get(`refs/tags/${C}`);if(typeof I>\"u\")throw new Error(`Unknown tag (\"${C}\")`);return mC.default.stringify({...n,commit:I})}case\"semver\":{let I=kr.validRange(C);if(!I)throw new Error(`Invalid range (\"${C}\")`);let v=new Map([...u.entries()].filter(([E])=>E.startsWith(\"refs/tags/\")).map(([E,R])=>[z8.default.parse(E.slice(10)),R]).filter(E=>E[0]!==null)),x=z8.default.maxSatisfying([...v.keys()],I);if(x===null)throw new Error(`No matching range (\"${C}\")`);return mC.default.stringify({...n,commit:v.get(x)})}case null:{let I;if((I=p(\"commit\",C))!==null||(I=p(\"tag\",C))!==null||(I=p(\"head\",C))!==null)return I;throw C.match(/^[a-f0-9]+$/)?new Error(`Couldn't resolve \"${C}\" as either a commit, a tag, or a head - if a commit, use the 40-characters commit hash`):new Error(`Couldn't resolve \"${C}\" as either a commit, a tag, or a head`)}default:throw new Error(`Invalid Git resolution protocol (\"${h}\")`)}},p=(h,C)=>{try{return A(h,C)}catch{return null}};return dC(`${r}#${A(o,a)}`)}async function $8(t,e){return await e.getLimit(\"cloneConcurrency\")(async()=>{let{repo:r,treeish:{protocol:o,request:a}}=i0(t);if(o!==\"commit\")throw new Error(\"Invalid treeish protocol when cloning\");let n=X8(r,{configuration:e}),u=await oe.mktempPromise(),A={cwd:u,env:xde()};return await J8(\"cloning the repository\",[\"clone\",\"-c core.autocrlf=false\",n,ue.fromPortablePath(u)],A,{configuration:e,normalizedRepoUrl:n}),await J8(\"switching branch\",[\"checkout\",`${a}`],A,{configuration:e,normalizedRepoUrl:n}),u})}async function Qde(t){let e,r=t;do{if(e=r,await oe.existsPromise(V.join(e,\".git\")))return e;r=V.dirname(e)}while(r!==e);return null}async function Fde(t,{baseRefs:e}){if(e.length===0)throw new it(\"Can't run this command with zero base refs specified.\");let r=[];for(let A of e){let{code:p}=await Ur.execvp(\"git\",[\"merge-base\",A,\"HEAD\"],{cwd:t});p===0&&r.push(A)}if(r.length===0)throw new it(`No ancestor could be found between any of HEAD and ${e.join(\", \")}`);let{stdout:o}=await Ur.execvp(\"git\",[\"merge-base\",\"HEAD\",...r],{cwd:t,strict:!0}),a=o.trim(),{stdout:n}=await Ur.execvp(\"git\",[\"show\",\"--quiet\",\"--pretty=format:%s\",a],{cwd:t,strict:!0}),u=n.trim();return{hash:a,title:u}}async function Rde(t,{base:e,project:r}){let o=je.buildIgnorePattern(r.configuration.get(\"changesetIgnorePatterns\")),{stdout:a}=await Ur.execvp(\"git\",[\"diff\",\"--name-only\",`${e}`],{cwd:t,strict:!0}),n=a.split(/\\r\\n|\\r|\\n/).filter(h=>h.length>0).map(h=>V.resolve(t,ue.toPortablePath(h))),{stdout:u}=await Ur.execvp(\"git\",[\"ls-files\",\"--others\",\"--exclude-standard\"],{cwd:t,strict:!0}),A=u.split(/\\r\\n|\\r|\\n/).filter(h=>h.length>0).map(h=>V.resolve(t,ue.toPortablePath(h))),p=[...new Set([...n,...A].sort())];return o?p.filter(h=>!V.relative(r.cwd,h).match(o)):p}async function Dgt({ref:t,project:e}){if(e.configuration.projectCwd===null)throw new it(\"This command can only be run from within a Yarn project\");let r=[V.resolve(e.cwd,dr.lockfile),V.resolve(e.cwd,e.configuration.get(\"cacheFolder\")),V.resolve(e.cwd,e.configuration.get(\"installStatePath\")),V.resolve(e.cwd,e.configuration.get(\"virtualFolder\"))];await e.configuration.triggerHook(u=>u.populateYarnPaths,e,u=>{u!=null&&r.push(u)});let o=await Qde(e.configuration.projectCwd);if(o==null)throw new it(\"This command can only be run on Git repositories\");let a=await Fde(o,{baseRefs:typeof t==\"string\"?[t]:e.configuration.get(\"changesetBaseRefs\")}),n=await Rde(o,{base:a.hash,project:e});return new Set(je.mapAndFilter(n,u=>{let A=e.tryWorkspaceByFilePath(u);return A===null?je.mapAndFilter.skip:r.some(p=>u.startsWith(p))?je.mapAndFilter.skip:A}))}async function J8(t,e,r,{configuration:o,normalizedRepoUrl:a}){try{return await Ur.execvp(\"git\",e,{...r,strict:!0})}catch(n){if(!(n instanceof Ur.ExecError))throw n;let u=n.reportExtra,A=n.stderr.toString();throw new Jt(1,`Failed ${t}`,p=>{p.reportError(1,`  ${de.prettyField(o,{label:\"Repository URL\",value:de.tuple(de.Type.URL,a)})}`);for(let h of A.matchAll(/^(.+?): (.*)$/gm)){let[,C,I]=h;C=C.toLowerCase();let v=C===\"error\"?\"Error\":`${(0,bde.default)(C)} Error`;p.reportError(1,`  ${de.prettyField(o,{label:v,value:de.tuple(de.Type.NO_HINT,I)})}`)}u?.(p)})}}var E2=class{supports(e,r){return yC(e.reference)}getLocalPath(e,r){return null}async fetch(e,r){let o=r.checksums.get(e.locatorHash)||null,a=new Map(r.checksums);a.set(e.locatorHash,o);let n={...r,checksums:a},u=await this.downloadHosted(e,n);if(u!==null)return u;let[A,p,h]=await r.cache.fetchPackageFromCache(e,o,{onHit:()=>r.report.reportCacheHit(e),onMiss:()=>r.report.reportCacheMiss(e,`${W.prettyLocator(r.project.configuration,e)} can't be found in the cache and will be fetched from the remote repository`),loader:()=>this.cloneFromRemote(e,n),...r.cacheOptions});return{packageFs:A,releaseFs:p,prefixPath:W.getIdentVendorPath(e),checksum:h}}async downloadHosted(e,r){return r.project.configuration.reduceHook(o=>o.fetchHostedRepository,null,e,r)}async cloneFromRemote(e,r){let o=await $8(e.reference,r.project.configuration),a=i0(e.reference),n=V.join(o,\"package.tgz\");await un.prepareExternalProject(o,n,{configuration:r.project.configuration,report:r.report,workspace:a.extra.workspace,locator:e});let u=await oe.readFilePromise(n);return await je.releaseAfterUseAsync(async()=>await Xi.convertToZip(u,{configuration:r.project.configuration,prefixPath:W.getIdentVendorPath(e),stripComponents:1}))}};Ye();Ye();var C2=class{supportsDescriptor(e,r){return yC(e.range)}supportsLocator(e,r){return yC(e.reference)}shouldPersistResolution(e,r){return!0}bindDescriptor(e,r,o){return e}getResolutionDependencies(e,r){return{}}async getCandidates(e,r,o){let a=await Z8(e.range,o.project.configuration);return[W.makeLocator(e,a)]}async getSatisfying(e,r,o,a){let n=i0(e.range);return{locators:o.filter(A=>{if(A.identHash!==e.identHash)return!1;let p=i0(A.reference);return!(n.repo!==p.repo||n.treeish.protocol===\"commit\"&&n.treeish.request!==p.treeish.request)}),sorted:!1}}async resolve(e,r){if(!r.fetchOptions)throw new Error(\"Assertion failed: This resolver cannot be used unless a fetcher is configured\");let o=await r.fetchOptions.fetcher.fetch(e,r.fetchOptions),a=await je.releaseAfterUseAsync(async()=>await Ot.find(o.prefixPath,{baseFs:o.packageFs}),o.releaseFs);return{...e,version:a.version||\"0.0.0\",languageName:a.languageName||r.project.configuration.get(\"defaultLanguageName\"),linkType:\"HARD\",conditions:a.getConditions(),dependencies:r.project.configuration.normalizeDependencyMap(a.dependencies),peerDependencies:a.peerDependencies,dependenciesMeta:a.dependenciesMeta,peerDependenciesMeta:a.peerDependenciesMeta,bin:a.bin}}};var Pgt={configuration:{changesetBaseRefs:{description:\"The base git refs that the current HEAD is compared against when detecting changes. Supports git branches, tags, and commits.\",type:\"STRING\",isArray:!0,isNullable:!1,default:[\"master\",\"origin/master\",\"upstream/master\",\"main\",\"origin/main\",\"upstream/main\"]},changesetIgnorePatterns:{description:\"Array of glob patterns; files matching them will be ignored when fetching the changed files\",type:\"STRING\",default:[],isArray:!0},cloneConcurrency:{description:\"Maximal number of concurrent clones\",type:\"NUMBER\",default:2}},fetchers:[E2],resolvers:[C2]};var Sgt=Pgt;qt();var s0=class extends ut{constructor(){super(...arguments);this.since=ge.String(\"--since\",{description:\"Only include workspaces that have been changed since the specified ref.\",tolerateBoolean:!0});this.recursive=ge.Boolean(\"-R,--recursive\",!1,{description:\"Find packages via dependencies/devDependencies instead of using the workspaces field\"});this.noPrivate=ge.Boolean(\"--no-private\",{description:\"Exclude workspaces that have the private field set to true\"});this.verbose=ge.Boolean(\"-v,--verbose\",!1,{description:\"Also return the cross-dependencies between workspaces\"});this.json=ge.Boolean(\"--json\",!1,{description:\"Format the output as an NDJSON stream\"})}async execute(){let r=await Ke.find(this.context.cwd,this.context.plugins),{project:o}=await St.find(r,this.context.cwd);return(await Nt.start({configuration:r,json:this.json,stdout:this.context.stdout},async n=>{let u=this.since?await ra.fetchChangedWorkspaces({ref:this.since,project:o}):o.workspaces,A=new Set(u);if(this.recursive)for(let p of[...u].map(h=>h.getRecursiveWorkspaceDependents()))for(let h of p)A.add(h);for(let p of A){let{manifest:h}=p;if(h.private&&this.noPrivate)continue;let C;if(this.verbose){let I=new Set,v=new Set;for(let x of Ot.hardDependencies)for(let[E,R]of h.getForScope(x)){let L=o.tryWorkspaceByDescriptor(R);L===null?o.workspacesByIdent.has(E)&&v.add(R):I.add(L)}C={workspaceDependencies:Array.from(I).map(x=>x.relativeCwd),mismatchedWorkspaceDependencies:Array.from(v).map(x=>W.stringifyDescriptor(x))}}n.reportInfo(null,`${p.relativeCwd}`),n.reportJson({location:p.relativeCwd,name:h.name?W.stringifyIdent(h.name):null,...C})}})).exitCode()}};s0.paths=[[\"workspaces\",\"list\"]],s0.usage=nt.Usage({category:\"Workspace-related commands\",description:\"list all available workspaces\",details:\"\\n      This command will print the list of all workspaces in the project.\\n\\n      - If `--since` is set, Yarn will only list workspaces that have been modified since the specified ref. By default Yarn will use the refs specified by the `changesetBaseRefs` configuration option.\\n\\n      - If `-R,--recursive` is set, Yarn will find workspaces to run the command on by recursively evaluating `dependencies` and `devDependencies` fields, instead of looking at the `workspaces` fields.\\n\\n      - If `--no-private` is set, Yarn will not list any workspaces that have the `private` field set to `true`.\\n\\n      - If both the `-v,--verbose` and `--json` options are set, Yarn will also return the cross-dependencies between each workspaces (useful when you wish to automatically generate Buck / Bazel rules).\\n    \"});Ye();Ye();qt();var o0=class extends ut{constructor(){super(...arguments);this.workspaceName=ge.String();this.commandName=ge.String();this.args=ge.Proxy()}async execute(){let r=await Ke.find(this.context.cwd,this.context.plugins),{project:o,workspace:a}=await St.find(r,this.context.cwd);if(!a)throw new rr(o.cwd,this.context.cwd);let n=o.workspaces,u=new Map(n.map(p=>[W.stringifyIdent(p.anchoredLocator),p])),A=u.get(this.workspaceName);if(A===void 0){let p=Array.from(u.keys()).sort();throw new it(`Workspace '${this.workspaceName}' not found. Did you mean any of the following:\n  - ${p.join(`\n  - `)}?`)}return this.cli.run([this.commandName,...this.args],{cwd:A.cwd})}};o0.paths=[[\"workspace\"]],o0.usage=nt.Usage({category:\"Workspace-related commands\",description:\"run a command within the specified workspace\",details:`\n      This command will run a given sub-command on a single workspace.\n    `,examples:[[\"Add a package to a single workspace\",\"yarn workspace components add -D react\"],[\"Run build script on a single workspace\",\"yarn workspace components run build\"]]});var bgt={configuration:{enableImmutableInstalls:{description:\"If true (the default on CI), prevents the install command from modifying the lockfile\",type:\"BOOLEAN\",default:Tde.isCI},defaultSemverRangePrefix:{description:\"The default save prefix: '^', '~' or ''\",type:\"STRING\",values:[\"^\",\"~\",\"\"],default:\"^\"},preferReuse:{description:\"If true, `yarn add` will attempt to reuse the most common dependency range in other workspaces.\",type:\"BOOLEAN\",default:!1}},commands:[Qh,Fh,Rh,Th,t0,Kh,Uh,s0,Yd,Wd,gC,Kd,xh,kh,Nh,Lh,Oh,Mh,_h,Hh,jh,qh,r0,Gh,Yh,zh,Vh,Jh,Wh,Xh,Zh,$h,zd,e0,Kf,n0,o0]},xgt=bgt;var oH={};Vt(oH,{default:()=>Qgt});Ye();var kt={optional:!0},rH=[[\"@tailwindcss/aspect-ratio@<0.2.1\",{peerDependencies:{tailwindcss:\"^2.0.2\"}}],[\"@tailwindcss/line-clamp@<0.2.1\",{peerDependencies:{tailwindcss:\"^2.0.2\"}}],[\"@fullhuman/postcss-purgecss@3.1.3 || 3.1.3-alpha.0\",{peerDependencies:{postcss:\"^8.0.0\"}}],[\"@samverschueren/stream-to-observable@<0.3.1\",{peerDependenciesMeta:{rxjs:kt,zenObservable:kt}}],[\"any-observable@<0.5.1\",{peerDependenciesMeta:{rxjs:kt,zenObservable:kt}}],[\"@pm2/agent@<1.0.4\",{dependencies:{debug:\"*\"}}],[\"debug@<4.2.0\",{peerDependenciesMeta:{[\"supports-color\"]:kt}}],[\"got@<11\",{dependencies:{[\"@types/responselike\"]:\"^1.0.0\",[\"@types/keyv\"]:\"^3.1.1\"}}],[\"cacheable-lookup@<4.1.2\",{dependencies:{[\"@types/keyv\"]:\"^3.1.1\"}}],[\"http-link-dataloader@*\",{peerDependencies:{graphql:\"^0.13.1 || ^14.0.0\"}}],[\"typescript-language-server@*\",{dependencies:{[\"vscode-jsonrpc\"]:\"^5.0.1\",[\"vscode-languageserver-protocol\"]:\"^3.15.0\"}}],[\"postcss-syntax@*\",{peerDependenciesMeta:{[\"postcss-html\"]:kt,[\"postcss-jsx\"]:kt,[\"postcss-less\"]:kt,[\"postcss-markdown\"]:kt,[\"postcss-scss\"]:kt}}],[\"jss-plugin-rule-value-function@<=10.1.1\",{dependencies:{[\"tiny-warning\"]:\"^1.0.2\"}}],[\"ink-select-input@<4.1.0\",{peerDependencies:{react:\"^16.8.2\"}}],[\"license-webpack-plugin@<2.3.18\",{peerDependenciesMeta:{webpack:kt}}],[\"snowpack@>=3.3.0\",{dependencies:{[\"node-gyp\"]:\"^7.1.0\"}}],[\"promise-inflight@*\",{peerDependenciesMeta:{bluebird:kt}}],[\"reactcss@*\",{peerDependencies:{react:\"*\"}}],[\"react-color@<=2.19.0\",{peerDependencies:{react:\"*\"}}],[\"gatsby-plugin-i18n@*\",{dependencies:{ramda:\"^0.24.1\"}}],[\"useragent@^2.0.0\",{dependencies:{request:\"^2.88.0\",yamlparser:\"0.0.x\",semver:\"5.5.x\"}}],[\"@apollographql/apollo-tools@<=0.5.2\",{peerDependencies:{graphql:\"^14.2.1 || ^15.0.0\"}}],[\"material-table@^2.0.0\",{dependencies:{\"@babel/runtime\":\"^7.11.2\"}}],[\"@babel/parser@*\",{dependencies:{\"@babel/types\":\"^7.8.3\"}}],[\"fork-ts-checker-webpack-plugin@<=6.3.4\",{peerDependencies:{eslint:\">= 6\",typescript:\">= 2.7\",webpack:\">= 4\",\"vue-template-compiler\":\"*\"},peerDependenciesMeta:{eslint:kt,\"vue-template-compiler\":kt}}],[\"rc-animate@<=3.1.1\",{peerDependencies:{react:\">=16.9.0\",\"react-dom\":\">=16.9.0\"}}],[\"react-bootstrap-table2-paginator@*\",{dependencies:{classnames:\"^2.2.6\"}}],[\"react-draggable@<=4.4.3\",{peerDependencies:{react:\">= 16.3.0\",\"react-dom\":\">= 16.3.0\"}}],[\"apollo-upload-client@<14\",{peerDependencies:{graphql:\"14 - 15\"}}],[\"react-instantsearch-core@<=6.7.0\",{peerDependencies:{algoliasearch:\">= 3.1 < 5\"}}],[\"react-instantsearch-dom@<=6.7.0\",{dependencies:{\"react-fast-compare\":\"^3.0.0\"}}],[\"ws@<7.2.1\",{peerDependencies:{bufferutil:\"^4.0.1\",\"utf-8-validate\":\"^5.0.2\"},peerDependenciesMeta:{bufferutil:kt,\"utf-8-validate\":kt}}],[\"react-portal@<4.2.2\",{peerDependencies:{\"react-dom\":\"^15.0.0-0 || ^16.0.0-0 || ^17.0.0-0\"}}],[\"react-scripts@<=4.0.1\",{peerDependencies:{react:\"*\"}}],[\"testcafe@<=1.10.1\",{dependencies:{\"@babel/plugin-transform-for-of\":\"^7.12.1\",\"@babel/runtime\":\"^7.12.5\"}}],[\"testcafe-legacy-api@<=4.2.0\",{dependencies:{\"testcafe-hammerhead\":\"^17.0.1\",\"read-file-relative\":\"^1.2.0\"}}],[\"@google-cloud/firestore@<=4.9.3\",{dependencies:{protobufjs:\"^6.8.6\"}}],[\"gatsby-source-apiserver@*\",{dependencies:{[\"babel-polyfill\"]:\"^6.26.0\"}}],[\"@webpack-cli/package-utils@<=1.0.1-alpha.4\",{dependencies:{[\"cross-spawn\"]:\"^7.0.3\"}}],[\"gatsby-remark-prismjs@<3.3.28\",{dependencies:{lodash:\"^4\"}}],[\"gatsby-plugin-favicon@*\",{peerDependencies:{webpack:\"*\"}}],[\"gatsby-plugin-sharp@<=4.6.0-next.3\",{dependencies:{debug:\"^4.3.1\"}}],[\"gatsby-react-router-scroll@<=5.6.0-next.0\",{dependencies:{[\"prop-types\"]:\"^15.7.2\"}}],[\"@rebass/forms@*\",{dependencies:{[\"@styled-system/should-forward-prop\"]:\"^5.0.0\"},peerDependencies:{react:\"^16.8.6\"}}],[\"rebass@*\",{peerDependencies:{react:\"^16.8.6\"}}],[\"@ant-design/react-slick@<=0.28.3\",{peerDependencies:{react:\">=16.0.0\"}}],[\"mqtt@<4.2.7\",{dependencies:{duplexify:\"^4.1.1\"}}],[\"vue-cli-plugin-vuetify@<=2.0.3\",{dependencies:{semver:\"^6.3.0\"},peerDependenciesMeta:{\"sass-loader\":kt,\"vuetify-loader\":kt}}],[\"vue-cli-plugin-vuetify@<=2.0.4\",{dependencies:{\"null-loader\":\"^3.0.0\"}}],[\"vue-cli-plugin-vuetify@>=2.4.3\",{peerDependencies:{vue:\"*\"}}],[\"@vuetify/cli-plugin-utils@<=0.0.4\",{dependencies:{semver:\"^6.3.0\"},peerDependenciesMeta:{\"sass-loader\":kt}}],[\"@vue/cli-plugin-typescript@<=5.0.0-alpha.0\",{dependencies:{\"babel-loader\":\"^8.1.0\"}}],[\"@vue/cli-plugin-typescript@<=5.0.0-beta.0\",{dependencies:{\"@babel/core\":\"^7.12.16\"},peerDependencies:{\"vue-template-compiler\":\"^2.0.0\"},peerDependenciesMeta:{\"vue-template-compiler\":kt}}],[\"cordova-ios@<=6.3.0\",{dependencies:{underscore:\"^1.9.2\"}}],[\"cordova-lib@<=10.0.1\",{dependencies:{underscore:\"^1.9.2\"}}],[\"git-node-fs@*\",{peerDependencies:{\"js-git\":\"^0.7.8\"},peerDependenciesMeta:{\"js-git\":kt}}],[\"consolidate@<0.16.0\",{peerDependencies:{mustache:\"^3.0.0\"},peerDependenciesMeta:{mustache:kt}}],[\"consolidate@<=0.16.0\",{peerDependencies:{velocityjs:\"^2.0.1\",tinyliquid:\"^0.2.34\",\"liquid-node\":\"^3.0.1\",jade:\"^1.11.0\",\"then-jade\":\"*\",dust:\"^0.3.0\",\"dustjs-helpers\":\"^1.7.4\",\"dustjs-linkedin\":\"^2.7.5\",swig:\"^1.4.2\",\"swig-templates\":\"^2.0.3\",\"razor-tmpl\":\"^1.3.1\",atpl:\">=0.7.6\",liquor:\"^0.0.5\",twig:\"^1.15.2\",ejs:\"^3.1.5\",eco:\"^1.1.0-rc-3\",jazz:\"^0.0.18\",jqtpl:\"~1.1.0\",hamljs:\"^0.6.2\",hamlet:\"^0.3.3\",whiskers:\"^0.4.0\",\"haml-coffee\":\"^1.14.1\",\"hogan.js\":\"^3.0.2\",templayed:\">=0.2.3\",handlebars:\"^4.7.6\",underscore:\"^1.11.0\",lodash:\"^4.17.20\",pug:\"^3.0.0\",\"then-pug\":\"*\",qejs:\"^3.0.5\",walrus:\"^0.10.1\",mustache:\"^4.0.1\",just:\"^0.1.8\",ect:\"^0.5.9\",mote:\"^0.2.0\",toffee:\"^0.3.6\",dot:\"^1.1.3\",\"bracket-template\":\"^1.1.5\",ractive:\"^1.3.12\",nunjucks:\"^3.2.2\",htmling:\"^0.0.8\",\"babel-core\":\"^6.26.3\",plates:\"~0.4.11\",\"react-dom\":\"^16.13.1\",react:\"^16.13.1\",\"arc-templates\":\"^0.5.3\",vash:\"^0.13.0\",slm:\"^2.0.0\",marko:\"^3.14.4\",teacup:\"^2.0.0\",\"coffee-script\":\"^1.12.7\",squirrelly:\"^5.1.0\",twing:\"^5.0.2\"},peerDependenciesMeta:{velocityjs:kt,tinyliquid:kt,\"liquid-node\":kt,jade:kt,\"then-jade\":kt,dust:kt,\"dustjs-helpers\":kt,\"dustjs-linkedin\":kt,swig:kt,\"swig-templates\":kt,\"razor-tmpl\":kt,atpl:kt,liquor:kt,twig:kt,ejs:kt,eco:kt,jazz:kt,jqtpl:kt,hamljs:kt,hamlet:kt,whiskers:kt,\"haml-coffee\":kt,\"hogan.js\":kt,templayed:kt,handlebars:kt,underscore:kt,lodash:kt,pug:kt,\"then-pug\":kt,qejs:kt,walrus:kt,mustache:kt,just:kt,ect:kt,mote:kt,toffee:kt,dot:kt,\"bracket-template\":kt,ractive:kt,nunjucks:kt,htmling:kt,\"babel-core\":kt,plates:kt,\"react-dom\":kt,react:kt,\"arc-templates\":kt,vash:kt,slm:kt,marko:kt,teacup:kt,\"coffee-script\":kt,squirrelly:kt,twing:kt}}],[\"vue-loader@<=16.3.3\",{peerDependencies:{\"@vue/compiler-sfc\":\"^3.0.8\",webpack:\"^4.1.0 || ^5.0.0-0\"},peerDependenciesMeta:{\"@vue/compiler-sfc\":kt}}],[\"vue-loader@^16.7.0\",{peerDependencies:{\"@vue/compiler-sfc\":\"^3.0.8\",vue:\"^3.2.13\"},peerDependenciesMeta:{\"@vue/compiler-sfc\":kt,vue:kt}}],[\"scss-parser@<=1.0.5\",{dependencies:{lodash:\"^4.17.21\"}}],[\"query-ast@<1.0.5\",{dependencies:{lodash:\"^4.17.21\"}}],[\"redux-thunk@<=2.3.0\",{peerDependencies:{redux:\"^4.0.0\"}}],[\"skypack@<=0.3.2\",{dependencies:{tar:\"^6.1.0\"}}],[\"@npmcli/metavuln-calculator@<2.0.0\",{dependencies:{\"json-parse-even-better-errors\":\"^2.3.1\"}}],[\"bin-links@<2.3.0\",{dependencies:{\"mkdirp-infer-owner\":\"^1.0.2\"}}],[\"rollup-plugin-polyfill-node@<=0.8.0\",{peerDependencies:{rollup:\"^1.20.0 || ^2.0.0\"}}],[\"snowpack@<3.8.6\",{dependencies:{\"magic-string\":\"^0.25.7\"}}],[\"elm-webpack-loader@*\",{dependencies:{temp:\"^0.9.4\"}}],[\"winston-transport@<=4.4.0\",{dependencies:{logform:\"^2.2.0\"}}],[\"jest-vue-preprocessor@*\",{dependencies:{\"@babel/core\":\"7.8.7\",\"@babel/template\":\"7.8.6\"},peerDependencies:{pug:\"^2.0.4\"},peerDependenciesMeta:{pug:kt}}],[\"redux-persist@*\",{peerDependencies:{react:\">=16\"},peerDependenciesMeta:{react:kt}}],[\"sodium@>=3\",{dependencies:{\"node-gyp\":\"^3.8.0\"}}],[\"babel-plugin-graphql-tag@<=3.1.0\",{peerDependencies:{graphql:\"^14.0.0 || ^15.0.0\"}}],[\"@playwright/test@<=1.14.1\",{dependencies:{\"jest-matcher-utils\":\"^26.4.2\"}}],...[\"babel-plugin-remove-graphql-queries@<3.14.0-next.1\",\"babel-preset-gatsby-package@<1.14.0-next.1\",\"create-gatsby@<1.14.0-next.1\",\"gatsby-admin@<0.24.0-next.1\",\"gatsby-cli@<3.14.0-next.1\",\"gatsby-core-utils@<2.14.0-next.1\",\"gatsby-design-tokens@<3.14.0-next.1\",\"gatsby-legacy-polyfills@<1.14.0-next.1\",\"gatsby-plugin-benchmark-reporting@<1.14.0-next.1\",\"gatsby-plugin-graphql-config@<0.23.0-next.1\",\"gatsby-plugin-image@<1.14.0-next.1\",\"gatsby-plugin-mdx@<2.14.0-next.1\",\"gatsby-plugin-netlify-cms@<5.14.0-next.1\",\"gatsby-plugin-no-sourcemaps@<3.14.0-next.1\",\"gatsby-plugin-page-creator@<3.14.0-next.1\",\"gatsby-plugin-preact@<5.14.0-next.1\",\"gatsby-plugin-preload-fonts@<2.14.0-next.1\",\"gatsby-plugin-schema-snapshot@<2.14.0-next.1\",\"gatsby-plugin-styletron@<6.14.0-next.1\",\"gatsby-plugin-subfont@<3.14.0-next.1\",\"gatsby-plugin-utils@<1.14.0-next.1\",\"gatsby-recipes@<0.25.0-next.1\",\"gatsby-source-shopify@<5.6.0-next.1\",\"gatsby-source-wikipedia@<3.14.0-next.1\",\"gatsby-transformer-screenshot@<3.14.0-next.1\",\"gatsby-worker@<0.5.0-next.1\"].map(t=>[t,{dependencies:{\"@babel/runtime\":\"^7.14.8\"}}]),[\"gatsby-core-utils@<2.14.0-next.1\",{dependencies:{got:\"8.3.2\"}}],[\"gatsby-plugin-gatsby-cloud@<=3.1.0-next.0\",{dependencies:{\"gatsby-core-utils\":\"^2.13.0-next.0\"}}],[\"gatsby-plugin-gatsby-cloud@<=3.2.0-next.1\",{peerDependencies:{webpack:\"*\"}}],[\"babel-plugin-remove-graphql-queries@<=3.14.0-next.1\",{dependencies:{\"gatsby-core-utils\":\"^2.8.0-next.1\"}}],[\"gatsby-plugin-netlify@3.13.0-next.1\",{dependencies:{\"gatsby-core-utils\":\"^2.13.0-next.0\"}}],[\"clipanion-v3-codemod@<=0.2.0\",{peerDependencies:{jscodeshift:\"^0.11.0\"}}],[\"react-live@*\",{peerDependencies:{\"react-dom\":\"*\",react:\"*\"}}],[\"webpack@<4.44.1\",{peerDependenciesMeta:{\"webpack-cli\":kt,\"webpack-command\":kt}}],[\"webpack@<5.0.0-beta.23\",{peerDependenciesMeta:{\"webpack-cli\":kt}}],[\"webpack-dev-server@<3.10.2\",{peerDependenciesMeta:{\"webpack-cli\":kt}}],[\"@docusaurus/responsive-loader@<1.5.0\",{peerDependenciesMeta:{sharp:kt,jimp:kt}}],[\"eslint-module-utils@*\",{peerDependenciesMeta:{\"eslint-import-resolver-node\":kt,\"eslint-import-resolver-typescript\":kt,\"eslint-import-resolver-webpack\":kt,\"@typescript-eslint/parser\":kt}}],[\"eslint-plugin-import@*\",{peerDependenciesMeta:{\"@typescript-eslint/parser\":kt}}],[\"critters-webpack-plugin@<3.0.2\",{peerDependenciesMeta:{\"html-webpack-plugin\":kt}}],[\"terser@<=5.10.0\",{dependencies:{acorn:\"^8.5.0\"}}],[\"babel-preset-react-app@10.0.x\",{dependencies:{\"@babel/plugin-proposal-private-property-in-object\":\"^7.16.0\"}}],[\"eslint-config-react-app@*\",{peerDependenciesMeta:{typescript:kt}}],[\"@vue/eslint-config-typescript@<11.0.0\",{peerDependenciesMeta:{typescript:kt}}],[\"unplugin-vue2-script-setup@<0.9.1\",{peerDependencies:{\"@vue/composition-api\":\"^1.4.3\",\"@vue/runtime-dom\":\"^3.2.26\"}}],[\"@cypress/snapshot@*\",{dependencies:{debug:\"^3.2.7\"}}],[\"auto-relay@<=0.14.0\",{peerDependencies:{\"reflect-metadata\":\"^0.1.13\"}}],[\"vue-template-babel-compiler@<1.2.0\",{peerDependencies:{[\"vue-template-compiler\"]:\"^2.6.0\"}}],[\"@parcel/transformer-image@<2.5.0\",{peerDependencies:{[\"@parcel/core\"]:\"*\"}}],[\"@parcel/transformer-js@<2.5.0\",{peerDependencies:{[\"@parcel/core\"]:\"*\"}}],[\"parcel@*\",{peerDependenciesMeta:{[\"@parcel/core\"]:kt}}],[\"react-scripts@*\",{peerDependencies:{eslint:\"*\"}}],[\"focus-trap-react@^8.0.0\",{dependencies:{tabbable:\"^5.3.2\"}}],[\"react-rnd@<10.3.7\",{peerDependencies:{react:\">=16.3.0\",\"react-dom\":\">=16.3.0\"}}],[\"connect-mongo@*\",{peerDependencies:{\"express-session\":\"^1.17.1\"}}],[\"vue-i18n@<9\",{peerDependencies:{vue:\"^2\"}}],[\"vue-router@<4\",{peerDependencies:{vue:\"^2\"}}],[\"unified@<10\",{dependencies:{\"@types/unist\":\"^2.0.0\"}}],[\"react-github-btn@<=1.3.0\",{peerDependencies:{react:\">=16.3.0\"}}],[\"react-dev-utils@*\",{peerDependencies:{typescript:\">=2.7\",webpack:\">=4\"},peerDependenciesMeta:{typescript:kt}}],[\"@asyncapi/react-component@<=1.0.0-next.39\",{peerDependencies:{react:\">=16.8.0\",\"react-dom\":\">=16.8.0\"}}],[\"xo@*\",{peerDependencies:{webpack:\">=1.11.0\"},peerDependenciesMeta:{webpack:kt}}],[\"babel-plugin-remove-graphql-queries@<=4.20.0-next.0\",{dependencies:{\"@babel/types\":\"^7.15.4\"}}],[\"gatsby-plugin-page-creator@<=4.20.0-next.1\",{dependencies:{\"fs-extra\":\"^10.1.0\"}}],[\"gatsby-plugin-utils@<=3.14.0-next.1\",{dependencies:{fastq:\"^1.13.0\"},peerDependencies:{graphql:\"^15.0.0\"}}],[\"gatsby-plugin-mdx@<3.1.0-next.1\",{dependencies:{mkdirp:\"^1.0.4\"}}],[\"gatsby-plugin-mdx@^2\",{peerDependencies:{gatsby:\"^3.0.0-next\"}}],[\"fdir@<=5.2.0\",{peerDependencies:{picomatch:\"2.x\"},peerDependenciesMeta:{picomatch:kt}}],[\"babel-plugin-transform-typescript-metadata@<=0.3.2\",{peerDependencies:{\"@babel/core\":\"^7\",\"@babel/traverse\":\"^7\"},peerDependenciesMeta:{\"@babel/traverse\":kt}}],[\"graphql-compose@>=9.0.10\",{peerDependencies:{graphql:\"^14.2.0 || ^15.0.0 || ^16.0.0\"}}]];var nH;function Nde(){return typeof nH>\"u\"&&(nH=Be(\"zlib\").brotliDecompressSync(Buffer.from(\"G7weAByFTVk3Vs7UfHhq4yykgEM7pbW7TI43SG2S5tvGrwHBAzdz+s/npQ6tgEvobvxisrPIadkXeUAJotBn5bDZ5kAhcRqsIHe3F75Walet5hNalwgFDtxb0BiDUjiUQkjG0yW2hto9HPgiCkm316d6bC0kST72YN7D7rfkhCE9x4J0XwB0yavalxpUu2t9xszHrmtwalOxT7VslsxWcB1qpqZwERUra4psWhTV8BgwWeizurec82Caf1ABL11YMfbf8FJ9JBceZOkgmvrQPbC9DUldX/yMbmX06UQluCEjSwUoyO+EZPIjofr+/oAZUck2enraRD+oWLlnlYnj8xB+gwSo9lmmks4fXv574qSqcWA6z21uYkzMu3EWj+K23RxeQlLqiE35/rC8GcS4CGkKHKKq+zAIQwD9iRDNfiAqueLLpicFFrNsAI4zeTD/eO9MHcnRa5m8UT+M2+V+AkFST4BlKneiAQRSdST8KEAIyFlULt6wa9EBd0Ds28VmpaxquJdVt+nwdEs5xUskI13OVtFyY0UrQIRAlCuvvWivvlSKQfTO+2Q8OyUR1W5RvetaPz4jD27hdtwHFFA1Ptx6Ee/t2cY2rg2G46M1pNDRf2pWhvpy8pqMnuI3++4OF3+7OFIWXGjh+o7Nr2jNvbiYcQdQS1h903/jVFgOpA0yJ78z+x759bFA0rq+6aY5qPB4FzS3oYoLupDUhD9nDz6F6H7hpnlMf18KNKDu4IKjTWwrAnY6MFQw1W6ymOALHlFyCZmQhldg1MQHaMVVQTVgDC60TfaBqG++Y8PEoFhN/PBTZT175KNP/BlHDYGOOBmnBdzqJKplZ/ljiVG0ZBzfqeBRrrUkn6rA54462SgiliKoYVnbeptMdXNfAuaupIEi0bApF10TlgHfmEJAPUVidRVFyDupSem5po5vErPqWKhKbUIp0LozpYsIKK57dM/HKr+nguF+7924IIWMICkQ8JUigs9D+W+c4LnNoRtPPKNRUiCYmP+Jfo2lfKCKw8qpraEeWU3uiNRO6zcyKQoXPR5htmzzLznke7b4YbXW3I1lIRzmgG02Udb58U+7TpwyN7XymCgH+wuPDthZVQvRZuEP+SnLtMicz9m5zASWOBiAcLmkuFlTKuHspSIhCBD0yUPKcxu81A+4YD78rA2vtwsUEday9WNyrShyrl60rWmA+SmbYZkQOwFJWArxRYYc5jGhA5ikxYw1rx3ei4NmeX/lKiwpZ9Ln1tV2Ae7sArvxuVLbJjqJRjW1vFXAyHpvLG+8MJ6T2Ubx5M2KDa2SN6vuIGxJ9WQM9Mk3Q7aCNiZONXllhqq24DmoLbQfW2rYWsOgHWjtOmIQMyMKdiHZDjoyIq5+U700nZ6odJAoYXPQBvFNiQ78d5jaXliBqLTJEqUCwi+LiH2mx92EmNKDsJL74Z613+3lf20pxkV1+erOrjj8pW00vsPaahKUM+05ssd5uwM7K482KWEf3TCwlg/o3e5ngto7qSMz7YteIgCsF1UOcsLk7F7MxWbvrPMY473ew0G+noVL8EPbkmEMftMSeL6HFub/zy+2JQ==\",\"base64\")).toString()),nH}var iH;function Lde(){return typeof iH>\"u\"&&(iH=Be(\"zlib\").brotliDecompressSync(Buffer.from(\"G8MSIIzURnVBnObTcvb3XE6v2S9Qgc2K801Oa5otNKEtK8BINZNcaQHy+9/vf/WXBimwutXC33P2DPc64pps5rz7NGGWaOKNSPL4Y2KRE8twut2lFOIN+OXPtRmPMRhMTILib2bEQx43az2I5d3YS8Roa5UZpF/ujHb3Djd3GDvYUfvFYSUQ39vb2cmifp/rgB4J/65JK3wRBTvMBoNBmn3mbXC63/gbBkW/2IRPri0O8bcsRBsmarF328pAln04nyJFkwUAvNu934supAqLtyerZZpJ8I8suJHhf/ocMV+scKwa8NOiDKIPXw6Ex/EEZD6TEGaW8N5zvNHYF10l6Lfooj7D5W2k3dgvQSbp2Wv8TGOayS978gxlOLVjTGXs66ozewbrjwElLtyrYNnWTfzzdEutgROUFPVMhnMoy8EjJLLlWwIEoySxliim9kYW30JUHiPVyjt0iAw/ZpPmCbUCltYPnq6ZNblIKhTNhqS/oqC9iya5sGKZTOVsTEg34n92uZTf2iPpcZih8rPW8CzA+adIGmyCPcKdLMsBLShd+zuEbTrqpwuh+DLmracZcjPC5Sdf5odDAhKpFuOsQS67RT+1VgWWygSv3YwxDnylc04/PYuaMeIzhBkLrvs7e/OUzRTF56MmfY6rI63QtEjEQzq637zQqJ39nNhu3NmoRRhW/086bHGBUtx0PE0j3aEGvkdh9WJC8y8j8mqqke9/dQ5la+Q3ba4RlhvTbnfQhPDDab3tUifkjKuOsp13mXEmO00Mu88F/M67R7LXfoFDFLNtgCSWjWX+3Jn1371pJTK9xPBiMJafvDjtFyAzu8rxeQ0TKMQXNPs5xxiBOd+BRJP8KP88XPtJIbZKh/cdW8KvBUkpqKpGoiIaA32c3/JnQr4efXt85mXvidOvn/eU3Pase1typLYBalJ14mCso9h79nuMOuCa/kZAOkJHmTjP5RM2WNoPasZUAnT1TAE/NH25hUxcQv6hQWR/m1PKk4ooXMcM4SR1iYU3fUohvqk4RY2hbmTVVIXv6TvqO+0doOjgeVFAcom+RlwJQmOVH7pr1Q9LoJT6n1DeQEB+NHygsATbIwTcOKZlJsY8G4+suX1uQLjUWwLjjs0mvSvZcLTpIGAekeR7GCgl8eo3ndAqEe2XCav4huliHjdbIPBsGJuPX7lrO9HX1UbXRH5opOe1x6JsOSgHZR+EaxuXVhpLLxm6jk1LJtZfHSc6BKPun3CpYYVMJGwEUyk8MTGG0XL5MfEwaXpnc9TKnBmlGn6nHiGREc3ysn47XIBDzA+YvFdjZzVIEDcKGpS6PbUJehFRjEne8D0lVU1XuRtlgszq6pTNlQ/3MzNOEgCWPyTct22V2mEi2krizn5VDo9B19/X2DB3hCGRMM7ONbtnAcIx/OWB1u5uPbW1gsH8irXxT/IzG0PoXWYjhbMsH3KTuoOl5o17PulcgvsfTSnKFM354GWI8luqZnrswWjiXy3G+Vbyo1KMopFmmvBwNELgaS8z8dNZchx/Cl/xjddxhMcyqtzFyONb2Zdu90NkI8pAeufe7YlXrp53v8Dj/l8vWeVspRKBGXScBBPI/HinSTGmLDOGGOCIyH0JFdOZx0gWsacNlQLJMIrBhqRxXxHF/5pseWwejlAAvZ3klZSDSYY8mkToaWejXhgNomeGtx1DTLEUFMRkgF5yFB22WYdJnaWN14r1YJj81hGi45+jrADS5nYRhCiSlCJJ1nL8pYX+HDSMhdTEWyRcgHVp/IsUIZYMfT+YYncUQPgcxNGCHfZ88vDdrcUuaGIl6zhAsiaq7R5dfqrqXH/JcBhfjT8D0azayIyEz75Nxp6YkcyDxlJq3EXnJUpqDohJJOysL1t1uNiHESlvsxPb5cpbW0+ICZqJmUZus1BMW0F5IVBODLIo2zHHjA0=\",\"base64\")).toString()),iH}var sH;function Ode(){return typeof sH>\"u\"&&(sH=Be(\"zlib\").brotliDecompressSync(Buffer.from(\"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\",\"base64\")).toString()),sH}var Mde=new Map([[W.makeIdent(null,\"fsevents\").identHash,Nde],[W.makeIdent(null,\"resolve\").identHash,Lde],[W.makeIdent(null,\"typescript\").identHash,Ode]]),kgt={hooks:{registerPackageExtensions:async(t,e)=>{for(let[r,o]of rH)e(W.parseDescriptor(r,!0),o)},getBuiltinPatch:async(t,e)=>{let r=\"compat/\";if(!e.startsWith(r))return;let o=W.parseIdent(e.slice(r.length)),a=Mde.get(o.identHash)?.();return typeof a<\"u\"?a:null},reduceDependency:async(t,e,r,o)=>typeof Mde.get(t.identHash)>\"u\"?t:W.makeDescriptor(t,W.makeRange({protocol:\"patch:\",source:W.stringifyDescriptor(t),selector:`optional!builtin<compat/${W.stringifyIdent(t)}>`,params:null}))}},Qgt=kgt;var BH={};Vt(BH,{ConstraintsCheckCommand:()=>p0,ConstraintsQueryCommand:()=>A0,ConstraintsSourceCommand:()=>f0,default:()=>idt});Ye();Ye();I2();var CC=class{constructor(e){this.project=e}createEnvironment(){let e=new EC([\"cwd\",\"ident\"]),r=new EC([\"workspace\",\"type\",\"ident\"]),o=new EC([\"ident\"]),a={manifestUpdates:new Map,reportedErrors:new Map},n=new Map,u=new Map;for(let A of this.project.storedPackages.values()){let p=Array.from(A.peerDependencies.values(),h=>[W.stringifyIdent(h),h.range]);n.set(A.locatorHash,{workspace:null,ident:W.stringifyIdent(A),version:A.version,dependencies:new Map,peerDependencies:new Map(p.filter(([h])=>A.peerDependenciesMeta.get(h)?.optional!==!0)),optionalPeerDependencies:new Map(p.filter(([h])=>A.peerDependenciesMeta.get(h)?.optional===!0))})}for(let A of this.project.storedPackages.values()){let p=n.get(A.locatorHash);p.dependencies=new Map(Array.from(A.dependencies.values(),h=>{let C=this.project.storedResolutions.get(h.descriptorHash);if(typeof C>\"u\")throw new Error(\"Assertion failed: The resolution should have been registered\");let I=n.get(C);if(typeof I>\"u\")throw new Error(\"Assertion failed: The package should have been registered\");return[W.stringifyIdent(h),I]})),p.dependencies.delete(p.ident)}for(let A of this.project.workspaces){let p=W.stringifyIdent(A.anchoredLocator),h=A.manifest.exportTo({}),C=n.get(A.anchoredLocator.locatorHash);if(typeof C>\"u\")throw new Error(\"Assertion failed: The package should have been registered\");let I=(R,L,{caller:U=zi.getCaller()}={})=>{let z=w2(R),te=je.getMapWithDefault(a.manifestUpdates,A.cwd),le=je.getMapWithDefault(te,z),he=je.getSetWithDefault(le,L);U!==null&&he.add(U)},v=R=>I(R,void 0,{caller:zi.getCaller()}),x=R=>{je.getArrayWithDefault(a.reportedErrors,A.cwd).push(R)},E=e.insert({cwd:A.relativeCwd,ident:p,manifest:h,pkg:C,set:I,unset:v,error:x});u.set(A,E);for(let R of Ot.allDependencies)for(let L of A.manifest[R].values()){let U=W.stringifyIdent(L),z=()=>{I([R,U],void 0,{caller:zi.getCaller()})},te=he=>{I([R,U],he,{caller:zi.getCaller()})},le=null;if(R!==\"peerDependencies\"&&(R!==\"dependencies\"||!A.manifest.devDependencies.has(L.identHash))){let he=A.anchoredPackage.dependencies.get(L.identHash);if(he){if(typeof he>\"u\")throw new Error(\"Assertion failed: The dependency should have been registered\");let Ae=this.project.storedResolutions.get(he.descriptorHash);if(typeof Ae>\"u\")throw new Error(\"Assertion failed: The resolution should have been registered\");let ye=n.get(Ae);if(typeof ye>\"u\")throw new Error(\"Assertion failed: The package should have been registered\");le=ye}}r.insert({workspace:E,ident:U,range:L.range,type:R,resolution:le,update:te,delete:z,error:x})}}for(let A of this.project.storedPackages.values()){let p=this.project.tryWorkspaceByLocator(A);if(!p)continue;let h=u.get(p);if(typeof h>\"u\")throw new Error(\"Assertion failed: The workspace should have been registered\");let C=n.get(A.locatorHash);if(typeof C>\"u\")throw new Error(\"Assertion failed: The package should have been registered\");C.workspace=h}return{workspaces:e,dependencies:r,packages:o,result:a}}async process(){let e=this.createEnvironment(),r={Yarn:{workspace:a=>e.workspaces.find(a)[0]??null,workspaces:a=>e.workspaces.find(a),dependency:a=>e.dependencies.find(a)[0]??null,dependencies:a=>e.dependencies.find(a),package:a=>e.packages.find(a)[0]??null,packages:a=>e.packages.find(a)}},o=await this.project.loadUserConfig();return o?.constraints?(await o.constraints(r),e.result):null}};Ye();Ye();qt();var A0=class extends ut{constructor(){super(...arguments);this.json=ge.Boolean(\"--json\",!1,{description:\"Format the output as an NDJSON stream\"});this.query=ge.String()}async execute(){let{Constraints:r}=await Promise.resolve().then(()=>(S2(),P2)),o=await Ke.find(this.context.cwd,this.context.plugins),{project:a}=await St.find(o,this.context.cwd),n=await r.find(a),u=this.query;return u.endsWith(\".\")||(u=`${u}.`),(await Nt.start({configuration:o,json:this.json,stdout:this.context.stdout},async p=>{for await(let h of n.query(u)){let C=Array.from(Object.entries(h)),I=C.length,v=C.reduce((x,[E])=>Math.max(x,E.length),0);for(let x=0;x<I;x++){let[E,R]=C[x];p.reportInfo(null,`${rdt(x,I)}${E.padEnd(v,\" \")} = ${tdt(R)}`)}p.reportJson(h)}})).exitCode()}};A0.paths=[[\"constraints\",\"query\"]],A0.usage=nt.Usage({category:\"Constraints-related commands\",description:\"query the constraints fact database\",details:`\n      This command will output all matches to the given prolog query.\n    `,examples:[[\"List all dependencies throughout the workspace\",\"yarn constraints query 'workspace_has_dependency(_, DependencyName, _, _).'\"]]});function tdt(t){return typeof t!=\"string\"?`${t}`:t.match(/^[a-zA-Z][a-zA-Z0-9_]+$/)?t:`'${t}'`}function rdt(t,e){let r=t===0,o=t===e-1;return r&&o?\"\":r?\"\\u250C \":o?\"\\u2514 \":\"\\u2502 \"}Ye();qt();var f0=class extends ut{constructor(){super(...arguments);this.verbose=ge.Boolean(\"-v,--verbose\",!1,{description:\"Also print the fact database automatically compiled from the workspace manifests\"})}async execute(){let{Constraints:r}=await Promise.resolve().then(()=>(S2(),P2)),o=await Ke.find(this.context.cwd,this.context.plugins),{project:a}=await St.find(o,this.context.cwd),n=await r.find(a);this.context.stdout.write(this.verbose?n.fullSource:n.source)}};f0.paths=[[\"constraints\",\"source\"]],f0.usage=nt.Usage({category:\"Constraints-related commands\",description:\"print the source code for the constraints\",details:\"\\n      This command will print the Prolog source code used by the constraints engine. Adding the `-v,--verbose` flag will print the *full* source code, including the fact database automatically compiled from the workspace manifests.\\n    \",examples:[[\"Prints the source code\",\"yarn constraints source\"],[\"Print the source code and the fact database\",\"yarn constraints source -v\"]]});Ye();Ye();qt();I2();var p0=class extends ut{constructor(){super(...arguments);this.fix=ge.Boolean(\"--fix\",!1,{description:\"Attempt to automatically fix unambiguous issues, following a multi-pass process\"});this.json=ge.Boolean(\"--json\",!1,{description:\"Format the output as an NDJSON stream\"})}async execute(){let r=await Ke.find(this.context.cwd,this.context.plugins),{project:o}=await St.find(r,this.context.cwd);await o.restoreInstallState();let a=await o.loadUserConfig(),n;if(a?.constraints)n=new CC(o);else{let{Constraints:h}=await Promise.resolve().then(()=>(S2(),P2));n=await h.find(o)}let u,A=!1,p=!1;for(let h=this.fix?10:1;h>0;--h){let C=await n.process();if(!C)break;let{changedWorkspaces:I,remainingErrors:v}=mk(o,C,{fix:this.fix}),x=[];for(let[E,R]of I){let L=E.manifest.indent;E.manifest=new Ot,E.manifest.indent=L,E.manifest.load(R),x.push(E.persistManifest())}if(await Promise.all(x),!(I.size>0&&h>1)){u=Yde(v,{configuration:r}),A=!1,p=!0;for(let[,E]of v)for(let R of E)R.fixable?A=!0:p=!1}}if(u.children.length===0)return 0;if(A){let h=p?`Those errors can all be fixed by running ${de.pretty(r,\"yarn constraints --fix\",de.Type.CODE)}`:`Errors prefixed by '\\u2699' can be fixed by running ${de.pretty(r,\"yarn constraints --fix\",de.Type.CODE)}`;await Nt.start({configuration:r,stdout:this.context.stdout,includeNames:!1,includeFooter:!1},async C=>{C.reportInfo(0,h),C.reportSeparator()})}return u.children=je.sortMap(u.children,h=>h.value[1]),$s.emitTree(u,{configuration:r,stdout:this.context.stdout,json:this.json,separators:1}),1}};p0.paths=[[\"constraints\"]],p0.usage=nt.Usage({category:\"Constraints-related commands\",description:\"check that the project constraints are met\",details:`\n      This command will run constraints on your project and emit errors for each one that is found but isn't met. If any error is emitted the process will exit with a non-zero exit code.\n\n      If the \\`--fix\\` flag is used, Yarn will attempt to automatically fix the issues the best it can, following a multi-pass process (with a maximum of 10 iterations). Some ambiguous patterns cannot be autofixed, in which case you'll have to manually specify the right resolution.\n\n      For more information as to how to write constraints, please consult our dedicated page on our website: https://yarnpkg.com/features/constraints.\n    `,examples:[[\"Check that all constraints are satisfied\",\"yarn constraints\"],[\"Autofix all unmet constraints\",\"yarn constraints --fix\"]]});I2();var ndt={configuration:{enableConstraintsChecks:{description:\"If true, constraints will run during installs\",type:\"BOOLEAN\",default:!1},constraintsPath:{description:\"The path of the constraints file.\",type:\"ABSOLUTE_PATH\",default:\"./constraints.pro\"}},commands:[A0,f0,p0],hooks:{async validateProjectAfterInstall(t,{reportError:e}){if(!t.configuration.get(\"enableConstraintsChecks\"))return;let r=await t.loadUserConfig(),o;if(r?.constraints)o=new CC(t);else{let{Constraints:u}=await Promise.resolve().then(()=>(S2(),P2));o=await u.find(t)}let a=await o.process();if(!a)return;let{remainingErrors:n}=mk(t,a);if(n.size!==0)if(t.configuration.isCI)for(let[u,A]of n)for(let p of A)e(84,`${de.pretty(t.configuration,u.anchoredLocator,de.Type.IDENT)}: ${p.text}`);else e(84,`Constraint check failed; run ${de.pretty(t.configuration,\"yarn constraints\",de.Type.CODE)} for more details`)}}},idt=ndt;var vH={};Vt(vH,{CreateCommand:()=>$d,DlxCommand:()=>h0,default:()=>odt});Ye();qt();var $d=class extends ut{constructor(){super(...arguments);this.pkg=ge.String(\"-p,--package\",{description:\"The package to run the provided command from\"});this.quiet=ge.Boolean(\"-q,--quiet\",!1,{description:\"Only report critical errors instead of printing the full install logs\"});this.command=ge.String();this.args=ge.Proxy()}async execute(){let r=[];this.pkg&&r.push(\"--package\",this.pkg),this.quiet&&r.push(\"--quiet\");let o=this.command.replace(/^(@[^@/]+)(@|$)/,\"$1/create$2\"),a=W.parseDescriptor(o),n=a.name.match(/^create(-|$)/)?a:a.scope?W.makeIdent(a.scope,`create-${a.name}`):W.makeIdent(null,`create-${a.name}`),u=W.stringifyIdent(n);return a.range!==\"unknown\"&&(u+=`@${a.range}`),this.cli.run([\"dlx\",...r,u,...this.args])}};$d.paths=[[\"create\"]];Ye();Ye();Pt();qt();var h0=class extends ut{constructor(){super(...arguments);this.packages=ge.Array(\"-p,--package\",{description:\"The package(s) to install before running the command\"});this.quiet=ge.Boolean(\"-q,--quiet\",!1,{description:\"Only report critical errors instead of printing the full install logs\"});this.command=ge.String();this.args=ge.Proxy()}async execute(){return Ke.telemetry=null,await oe.mktempPromise(async r=>{let o=V.join(r,`dlx-${process.pid}`);await oe.mkdirPromise(o),await oe.writeFilePromise(V.join(o,\"package.json\"),`{}\n`),await oe.writeFilePromise(V.join(o,\"yarn.lock\"),\"\");let a=V.join(o,\".yarnrc.yml\"),n=await Ke.findProjectCwd(this.context.cwd),A={enableGlobalCache:!(await Ke.find(this.context.cwd,null,{strict:!1})).get(\"enableGlobalCache\"),enableTelemetry:!1,logFilters:[{code:Wu(68),level:de.LogLevel.Discard}]},p=n!==null?V.join(n,\".yarnrc.yml\"):null;p!==null&&oe.existsSync(p)?(await oe.copyFilePromise(p,a),await Ke.updateConfiguration(o,L=>{let U=je.toMerged(L,A);return Array.isArray(L.plugins)&&(U.plugins=L.plugins.map(z=>{let te=typeof z==\"string\"?z:z.path,le=ue.isAbsolute(te)?te:ue.resolve(ue.fromPortablePath(n),te);return typeof z==\"string\"?le:{path:le,spec:z.spec}})),U})):await oe.writeJsonPromise(a,A);let h=this.packages??[this.command],C=W.parseDescriptor(this.command).name,I=await this.cli.run([\"add\",\"--fixed\",\"--\",...h],{cwd:o,quiet:this.quiet});if(I!==0)return I;this.quiet||this.context.stdout.write(`\n`);let v=await Ke.find(o,this.context.plugins),{project:x,workspace:E}=await St.find(v,o);if(E===null)throw new rr(x.cwd,o);await x.restoreInstallState();let R=await un.getWorkspaceAccessibleBinaries(E);return R.has(C)===!1&&R.size===1&&typeof this.packages>\"u\"&&(C=Array.from(R)[0][0]),await un.executeWorkspaceAccessibleBinary(E,C,this.args,{packageAccessibleBinaries:R,cwd:this.context.cwd,stdin:this.context.stdin,stdout:this.context.stdout,stderr:this.context.stderr})})}};h0.paths=[[\"dlx\"]],h0.usage=nt.Usage({description:\"run a package in a temporary environment\",details:\"\\n      This command will install a package within a temporary environment, and run its binary script if it contains any. The binary will run within the current cwd.\\n\\n      By default Yarn will download the package named `command`, but this can be changed through the use of the `-p,--package` flag which will instruct Yarn to still run the same command but from a different package.\\n\\n      Using `yarn dlx` as a replacement of `yarn add` isn't recommended, as it makes your project non-deterministic (Yarn doesn't keep track of the packages installed through `dlx` - neither their name, nor their version).\\n    \",examples:[[\"Use create-react-app to create a new React app\",\"yarn dlx create-react-app ./my-app\"],[\"Install multiple packages for a single command\",`yarn dlx -p typescript -p ts-node ts-node --transpile-only -e \"console.log('hello!')\"`]]});var sdt={commands:[$d,h0]},odt=sdt;var SH={};Vt(SH,{ExecFetcher:()=>x2,ExecResolver:()=>k2,default:()=>cdt,execUtils:()=>wk});Ye();Ye();Pt();var fA=\"exec:\";var wk={};Vt(wk,{loadGeneratorFile:()=>b2,makeLocator:()=>PH,makeSpec:()=>mme,parseSpec:()=>DH});Ye();Pt();function DH(t){let{params:e,selector:r}=W.parseRange(t),o=ue.toPortablePath(r);return{parentLocator:e&&typeof e.locator==\"string\"?W.parseLocator(e.locator):null,path:o}}function mme({parentLocator:t,path:e,generatorHash:r,protocol:o}){let a=t!==null?{locator:W.stringifyLocator(t)}:{},n=typeof r<\"u\"?{hash:r}:{};return W.makeRange({protocol:o,source:e,selector:e,params:{...n,...a}})}function PH(t,{parentLocator:e,path:r,generatorHash:o,protocol:a}){return W.makeLocator(t,mme({parentLocator:e,path:r,generatorHash:o,protocol:a}))}async function b2(t,e,r){let{parentLocator:o,path:a}=W.parseFileStyleRange(t,{protocol:e}),n=V.isAbsolute(a)?{packageFs:new gn(Bt.root),prefixPath:Bt.dot,localPath:Bt.root}:await r.fetcher.fetch(o,r),u=n.localPath?{packageFs:new gn(Bt.root),prefixPath:V.relative(Bt.root,n.localPath)}:n;n!==u&&n.releaseFs&&n.releaseFs();let A=u.packageFs,p=V.join(u.prefixPath,a);return await A.readFilePromise(p,\"utf8\")}var x2=class{supports(e,r){return!!e.reference.startsWith(fA)}getLocalPath(e,r){let{parentLocator:o,path:a}=W.parseFileStyleRange(e.reference,{protocol:fA});if(V.isAbsolute(a))return a;let n=r.fetcher.getLocalPath(o,r);return n===null?null:V.resolve(n,a)}async fetch(e,r){let o=r.checksums.get(e.locatorHash)||null,[a,n,u]=await r.cache.fetchPackageFromCache(e,o,{onHit:()=>r.report.reportCacheHit(e),onMiss:()=>r.report.reportCacheMiss(e),loader:()=>this.fetchFromDisk(e,r),...r.cacheOptions});return{packageFs:a,releaseFs:n,prefixPath:W.getIdentVendorPath(e),localPath:this.getLocalPath(e,r),checksum:u}}async fetchFromDisk(e,r){let o=await b2(e.reference,fA,r);return oe.mktempPromise(async a=>{let n=V.join(a,\"generator.js\");return await oe.writeFilePromise(n,o),oe.mktempPromise(async u=>{if(await this.generatePackage(u,e,n,r),!oe.existsSync(V.join(u,\"build\")))throw new Error(\"The script should have generated a build directory\");return await Xi.makeArchiveFromDirectory(V.join(u,\"build\"),{prefixPath:W.getIdentVendorPath(e),compressionLevel:r.project.configuration.get(\"compressionLevel\")})})})}async generatePackage(e,r,o,a){return await oe.mktempPromise(async n=>{let u=await un.makeScriptEnv({project:a.project,binFolder:n}),A=V.join(e,\"runtime.js\");return await oe.mktempPromise(async p=>{let h=V.join(p,\"buildfile.log\"),C=V.join(e,\"generator\"),I=V.join(e,\"build\");await oe.mkdirPromise(C),await oe.mkdirPromise(I);let v={tempDir:ue.fromPortablePath(C),buildDir:ue.fromPortablePath(I),locator:W.stringifyLocator(r)};await oe.writeFilePromise(A,`\n          // Expose 'Module' as a global variable\n          Object.defineProperty(global, 'Module', {\n            get: () => require('module'),\n            configurable: true,\n            enumerable: false,\n          });\n\n          // Expose non-hidden built-in modules as global variables\n          for (const name of Module.builtinModules.filter((name) => name !== 'module' && !name.startsWith('_'))) {\n            Object.defineProperty(global, name, {\n              get: () => require(name),\n              configurable: true,\n              enumerable: false,\n            });\n          }\n\n          // Expose the 'execEnv' global variable\n          Object.defineProperty(global, 'execEnv', {\n            value: {\n              ...${JSON.stringify(v)},\n            },\n            enumerable: true,\n          });\n        `);let x=u.NODE_OPTIONS||\"\",E=/\\s*--require\\s+\\S*\\.pnp\\.c?js\\s*/g;x=x.replace(E,\" \").trim(),u.NODE_OPTIONS=x;let{stdout:R,stderr:L}=a.project.configuration.getSubprocessStreams(h,{header:`# This file contains the result of Yarn generating a package (${W.stringifyLocator(r)})\n`,prefix:W.prettyLocator(a.project.configuration,r),report:a.report}),{code:U}=await Ur.pipevp(process.execPath,[\"--require\",ue.fromPortablePath(A),ue.fromPortablePath(o),W.stringifyIdent(r)],{cwd:e,env:u,stdin:null,stdout:R,stderr:L});if(U!==0)throw oe.detachTemp(p),new Error(`Package generation failed (exit code ${U}, logs can be found here: ${de.pretty(a.project.configuration,h,de.Type.PATH)})`)})})}};Ye();Ye();var adt=2,k2=class{supportsDescriptor(e,r){return!!e.range.startsWith(fA)}supportsLocator(e,r){return!!e.reference.startsWith(fA)}shouldPersistResolution(e,r){return!1}bindDescriptor(e,r,o){return W.bindDescriptor(e,{locator:W.stringifyLocator(r)})}getResolutionDependencies(e,r){return{}}async getCandidates(e,r,o){if(!o.fetchOptions)throw new Error(\"Assertion failed: This resolver cannot be used unless a fetcher is configured\");let{path:a,parentLocator:n}=DH(e.range);if(n===null)throw new Error(\"Assertion failed: The descriptor should have been bound\");let u=await b2(W.makeRange({protocol:fA,source:a,selector:a,params:{locator:W.stringifyLocator(n)}}),fA,o.fetchOptions),A=wn.makeHash(`${adt}`,u).slice(0,6);return[PH(e,{parentLocator:n,path:a,generatorHash:A,protocol:fA})]}async getSatisfying(e,r,o,a){let[n]=await this.getCandidates(e,r,a);return{locators:o.filter(u=>u.locatorHash===n.locatorHash),sorted:!1}}async resolve(e,r){if(!r.fetchOptions)throw new Error(\"Assertion failed: This resolver cannot be used unless a fetcher is configured\");let o=await r.fetchOptions.fetcher.fetch(e,r.fetchOptions),a=await je.releaseAfterUseAsync(async()=>await Ot.find(o.prefixPath,{baseFs:o.packageFs}),o.releaseFs);return{...e,version:a.version||\"0.0.0\",languageName:a.languageName||r.project.configuration.get(\"defaultLanguageName\"),linkType:\"HARD\",conditions:a.getConditions(),dependencies:r.project.configuration.normalizeDependencyMap(a.dependencies),peerDependencies:a.peerDependencies,dependenciesMeta:a.dependenciesMeta,peerDependenciesMeta:a.peerDependenciesMeta,bin:a.bin}}};var ldt={fetchers:[x2],resolvers:[k2]},cdt=ldt;var xH={};Vt(xH,{FileFetcher:()=>T2,FileResolver:()=>N2,TarballFileFetcher:()=>L2,TarballFileResolver:()=>O2,default:()=>fdt,fileUtils:()=>em});Ye();Pt();var vC=/^(?:[a-zA-Z]:[\\\\/]|\\.{0,2}\\/)/,Q2=/^[^?]*\\.(?:tar\\.gz|tgz)(?:::.*)?$/,Ui=\"file:\";var em={};Vt(em,{fetchArchiveFromLocator:()=>R2,makeArchiveFromLocator:()=>Ik,makeBufferFromLocator:()=>bH,makeLocator:()=>DC,makeSpec:()=>yme,parseSpec:()=>F2});Ye();Pt();function F2(t){let{params:e,selector:r}=W.parseRange(t),o=ue.toPortablePath(r);return{parentLocator:e&&typeof e.locator==\"string\"?W.parseLocator(e.locator):null,path:o}}function yme({parentLocator:t,path:e,hash:r,protocol:o}){let a=t!==null?{locator:W.stringifyLocator(t)}:{},n=typeof r<\"u\"?{hash:r}:{};return W.makeRange({protocol:o,source:e,selector:e,params:{...n,...a}})}function DC(t,{parentLocator:e,path:r,hash:o,protocol:a}){return W.makeLocator(t,yme({parentLocator:e,path:r,hash:o,protocol:a}))}async function R2(t,e){let{parentLocator:r,path:o}=W.parseFileStyleRange(t.reference,{protocol:Ui}),a=V.isAbsolute(o)?{packageFs:new gn(Bt.root),prefixPath:Bt.dot,localPath:Bt.root}:await e.fetcher.fetch(r,e),n=a.localPath?{packageFs:new gn(Bt.root),prefixPath:V.relative(Bt.root,a.localPath)}:a;a!==n&&a.releaseFs&&a.releaseFs();let u=n.packageFs,A=V.join(n.prefixPath,o);return await je.releaseAfterUseAsync(async()=>await u.readFilePromise(A),n.releaseFs)}async function Ik(t,{protocol:e,fetchOptions:r,inMemory:o=!1}){let{parentLocator:a,path:n}=W.parseFileStyleRange(t.reference,{protocol:e}),u=V.isAbsolute(n)?{packageFs:new gn(Bt.root),prefixPath:Bt.dot,localPath:Bt.root}:await r.fetcher.fetch(a,r),A=u.localPath?{packageFs:new gn(Bt.root),prefixPath:V.relative(Bt.root,u.localPath)}:u;u!==A&&u.releaseFs&&u.releaseFs();let p=A.packageFs,h=V.join(A.prefixPath,n);return await je.releaseAfterUseAsync(async()=>await Xi.makeArchiveFromDirectory(h,{baseFs:p,prefixPath:W.getIdentVendorPath(t),compressionLevel:r.project.configuration.get(\"compressionLevel\"),inMemory:o}),A.releaseFs)}async function bH(t,{protocol:e,fetchOptions:r}){return(await Ik(t,{protocol:e,fetchOptions:r,inMemory:!0})).getBufferAndClose()}var T2=class{supports(e,r){return!!e.reference.startsWith(Ui)}getLocalPath(e,r){let{parentLocator:o,path:a}=W.parseFileStyleRange(e.reference,{protocol:Ui});if(V.isAbsolute(a))return a;let n=r.fetcher.getLocalPath(o,r);return n===null?null:V.resolve(n,a)}async fetch(e,r){let o=r.checksums.get(e.locatorHash)||null,[a,n,u]=await r.cache.fetchPackageFromCache(e,o,{onHit:()=>r.report.reportCacheHit(e),onMiss:()=>r.report.reportCacheMiss(e,`${W.prettyLocator(r.project.configuration,e)} can't be found in the cache and will be fetched from the disk`),loader:()=>this.fetchFromDisk(e,r),...r.cacheOptions});return{packageFs:a,releaseFs:n,prefixPath:W.getIdentVendorPath(e),localPath:this.getLocalPath(e,r),checksum:u}}async fetchFromDisk(e,r){return Ik(e,{protocol:Ui,fetchOptions:r})}};Ye();Ye();var udt=2,N2=class{supportsDescriptor(e,r){return e.range.match(vC)?!0:!!e.range.startsWith(Ui)}supportsLocator(e,r){return!!e.reference.startsWith(Ui)}shouldPersistResolution(e,r){return!1}bindDescriptor(e,r,o){return vC.test(e.range)&&(e=W.makeDescriptor(e,`${Ui}${e.range}`)),W.bindDescriptor(e,{locator:W.stringifyLocator(r)})}getResolutionDependencies(e,r){return{}}async getCandidates(e,r,o){if(!o.fetchOptions)throw new Error(\"Assertion failed: This resolver cannot be used unless a fetcher is configured\");let{path:a,parentLocator:n}=F2(e.range);if(n===null)throw new Error(\"Assertion failed: The descriptor should have been bound\");let u=await bH(W.makeLocator(e,W.makeRange({protocol:Ui,source:a,selector:a,params:{locator:W.stringifyLocator(n)}})),{protocol:Ui,fetchOptions:o.fetchOptions}),A=wn.makeHash(`${udt}`,u).slice(0,6);return[DC(e,{parentLocator:n,path:a,hash:A,protocol:Ui})]}async getSatisfying(e,r,o,a){let[n]=await this.getCandidates(e,r,a);return{locators:o.filter(u=>u.locatorHash===n.locatorHash),sorted:!1}}async resolve(e,r){if(!r.fetchOptions)throw new Error(\"Assertion failed: This resolver cannot be used unless a fetcher is configured\");let o=await r.fetchOptions.fetcher.fetch(e,r.fetchOptions),a=await je.releaseAfterUseAsync(async()=>await Ot.find(o.prefixPath,{baseFs:o.packageFs}),o.releaseFs);return{...e,version:a.version||\"0.0.0\",languageName:a.languageName||r.project.configuration.get(\"defaultLanguageName\"),linkType:\"HARD\",conditions:a.getConditions(),dependencies:r.project.configuration.normalizeDependencyMap(a.dependencies),peerDependencies:a.peerDependencies,dependenciesMeta:a.dependenciesMeta,peerDependenciesMeta:a.peerDependenciesMeta,bin:a.bin}}};Ye();var L2=class{supports(e,r){return Q2.test(e.reference)?!!e.reference.startsWith(Ui):!1}getLocalPath(e,r){return null}async fetch(e,r){let o=r.checksums.get(e.locatorHash)||null,[a,n,u]=await r.cache.fetchPackageFromCache(e,o,{onHit:()=>r.report.reportCacheHit(e),onMiss:()=>r.report.reportCacheMiss(e,`${W.prettyLocator(r.project.configuration,e)} can't be found in the cache and will be fetched from the disk`),loader:()=>this.fetchFromDisk(e,r),...r.cacheOptions});return{packageFs:a,releaseFs:n,prefixPath:W.getIdentVendorPath(e),checksum:u}}async fetchFromDisk(e,r){let o=await R2(e,r);return await Xi.convertToZip(o,{configuration:r.project.configuration,prefixPath:W.getIdentVendorPath(e),stripComponents:1})}};Ye();Ye();Ye();var O2=class{supportsDescriptor(e,r){return Q2.test(e.range)?!!(e.range.startsWith(Ui)||vC.test(e.range)):!1}supportsLocator(e,r){return Q2.test(e.reference)?!!e.reference.startsWith(Ui):!1}shouldPersistResolution(e,r){return!1}bindDescriptor(e,r,o){return vC.test(e.range)&&(e=W.makeDescriptor(e,`${Ui}${e.range}`)),W.bindDescriptor(e,{locator:W.stringifyLocator(r)})}getResolutionDependencies(e,r){return{}}async getCandidates(e,r,o){if(!o.fetchOptions)throw new Error(\"Assertion failed: This resolver cannot be used unless a fetcher is configured\");let{path:a,parentLocator:n}=F2(e.range);if(n===null)throw new Error(\"Assertion failed: The descriptor should have been bound\");let u=DC(e,{parentLocator:n,path:a,hash:\"\",protocol:Ui}),A=await R2(u,o.fetchOptions),p=wn.makeHash(A).slice(0,6);return[DC(e,{parentLocator:n,path:a,hash:p,protocol:Ui})]}async getSatisfying(e,r,o,a){let[n]=await this.getCandidates(e,r,a);return{locators:o.filter(u=>u.locatorHash===n.locatorHash),sorted:!1}}async resolve(e,r){if(!r.fetchOptions)throw new Error(\"Assertion failed: This resolver cannot be used unless a fetcher is configured\");let o=await r.fetchOptions.fetcher.fetch(e,r.fetchOptions),a=await je.releaseAfterUseAsync(async()=>await Ot.find(o.prefixPath,{baseFs:o.packageFs}),o.releaseFs);return{...e,version:a.version||\"0.0.0\",languageName:a.languageName||r.project.configuration.get(\"defaultLanguageName\"),linkType:\"HARD\",conditions:a.getConditions(),dependencies:r.project.configuration.normalizeDependencyMap(a.dependencies),peerDependencies:a.peerDependencies,dependenciesMeta:a.dependenciesMeta,peerDependenciesMeta:a.peerDependenciesMeta,bin:a.bin}}};var Adt={fetchers:[L2,T2],resolvers:[O2,N2]},fdt=Adt;var FH={};Vt(FH,{GithubFetcher:()=>M2,default:()=>hdt,githubUtils:()=>Bk});Ye();Pt();var Bk={};Vt(Bk,{invalidGithubUrlMessage:()=>wme,isGithubUrl:()=>kH,parseGithubUrl:()=>QH});var Eme=$e(Be(\"querystring\")),Cme=[/^https?:\\/\\/(?:([^/]+?)@)?github.com\\/([^/#]+)\\/([^/#]+)\\/tarball\\/([^/#]+)(?:#(.*))?$/,/^https?:\\/\\/(?:([^/]+?)@)?github.com\\/([^/#]+)\\/([^/#]+?)(?:\\.git)?(?:#(.*))?$/];function kH(t){return t?Cme.some(e=>!!t.match(e)):!1}function QH(t){let e;for(let A of Cme)if(e=t.match(A),e)break;if(!e)throw new Error(wme(t));let[,r,o,a,n=\"master\"]=e,{commit:u}=Eme.default.parse(n);return n=u||n.replace(/[^:]*:/,\"\"),{auth:r,username:o,reponame:a,treeish:n}}function wme(t){return`Input cannot be parsed as a valid GitHub URL ('${t}').`}var M2=class{supports(e,r){return!!kH(e.reference)}getLocalPath(e,r){return null}async fetch(e,r){let o=r.checksums.get(e.locatorHash)||null,[a,n,u]=await r.cache.fetchPackageFromCache(e,o,{onHit:()=>r.report.reportCacheHit(e),onMiss:()=>r.report.reportCacheMiss(e,`${W.prettyLocator(r.project.configuration,e)} can't be found in the cache and will be fetched from GitHub`),loader:()=>this.fetchFromNetwork(e,r),...r.cacheOptions});return{packageFs:a,releaseFs:n,prefixPath:W.getIdentVendorPath(e),checksum:u}}async fetchFromNetwork(e,r){let o=await rn.get(this.getLocatorUrl(e,r),{configuration:r.project.configuration});return await oe.mktempPromise(async a=>{let n=new gn(a);await Xi.extractArchiveTo(o,n,{stripComponents:1});let u=ra.splitRepoUrl(e.reference),A=V.join(a,\"package.tgz\");await un.prepareExternalProject(a,A,{configuration:r.project.configuration,report:r.report,workspace:u.extra.workspace,locator:e});let p=await oe.readFilePromise(A);return await Xi.convertToZip(p,{configuration:r.project.configuration,prefixPath:W.getIdentVendorPath(e),stripComponents:1})})}getLocatorUrl(e,r){let{auth:o,username:a,reponame:n,treeish:u}=QH(e.reference);return`https://${o?`${o}@`:\"\"}github.com/${a}/${n}/archive/${u}.tar.gz`}};var pdt={hooks:{async fetchHostedRepository(t,e,r){if(t!==null)return t;let o=new M2;if(!o.supports(e,r))return null;try{return await o.fetch(e,r)}catch{return null}}}},hdt=pdt;var RH={};Vt(RH,{TarballHttpFetcher:()=>H2,TarballHttpResolver:()=>j2,default:()=>ddt});Ye();var U2=/^[^?]*\\.(?:tar\\.gz|tgz)(?:\\?.*)?(?:#.*)?$/,_2=/^https?:/;var H2=class{supports(e,r){return U2.test(e.reference)?!!_2.test(e.reference):!1}getLocalPath(e,r){return null}async fetch(e,r){let o=r.checksums.get(e.locatorHash)||null,[a,n,u]=await r.cache.fetchPackageFromCache(e,o,{onHit:()=>r.report.reportCacheHit(e),onMiss:()=>r.report.reportCacheMiss(e,`${W.prettyLocator(r.project.configuration,e)} can't be found in the cache and will be fetched from the remote server`),loader:()=>this.fetchFromNetwork(e,r),...r.cacheOptions});return{packageFs:a,releaseFs:n,prefixPath:W.getIdentVendorPath(e),checksum:u}}async fetchFromNetwork(e,r){let o=await rn.get(e.reference,{configuration:r.project.configuration});return await Xi.convertToZip(o,{configuration:r.project.configuration,prefixPath:W.getIdentVendorPath(e),stripComponents:1})}};Ye();Ye();var j2=class{supportsDescriptor(e,r){return U2.test(e.range)?!!_2.test(e.range):!1}supportsLocator(e,r){return U2.test(e.reference)?!!_2.test(e.reference):!1}shouldPersistResolution(e,r){return!0}bindDescriptor(e,r,o){return e}getResolutionDependencies(e,r){return{}}async getCandidates(e,r,o){return[W.convertDescriptorToLocator(e)]}async getSatisfying(e,r,o,a){let[n]=await this.getCandidates(e,r,a);return{locators:o.filter(u=>u.locatorHash===n.locatorHash),sorted:!1}}async resolve(e,r){if(!r.fetchOptions)throw new Error(\"Assertion failed: This resolver cannot be used unless a fetcher is configured\");let o=await r.fetchOptions.fetcher.fetch(e,r.fetchOptions),a=await je.releaseAfterUseAsync(async()=>await Ot.find(o.prefixPath,{baseFs:o.packageFs}),o.releaseFs);return{...e,version:a.version||\"0.0.0\",languageName:a.languageName||r.project.configuration.get(\"defaultLanguageName\"),linkType:\"HARD\",conditions:a.getConditions(),dependencies:r.project.configuration.normalizeDependencyMap(a.dependencies),peerDependencies:a.peerDependencies,dependenciesMeta:a.dependenciesMeta,peerDependenciesMeta:a.peerDependenciesMeta,bin:a.bin}}};var gdt={fetchers:[H2],resolvers:[j2]},ddt=gdt;var TH={};Vt(TH,{InitCommand:()=>g0,default:()=>ydt});Ye();Ye();Pt();qt();var g0=class extends ut{constructor(){super(...arguments);this.private=ge.Boolean(\"-p,--private\",!1,{description:\"Initialize a private package\"});this.workspace=ge.Boolean(\"-w,--workspace\",!1,{description:\"Initialize a workspace root with a `packages/` directory\"});this.install=ge.String(\"-i,--install\",!1,{tolerateBoolean:!0,description:\"Initialize a package with a specific bundle that will be locked in the project\"});this.name=ge.String(\"-n,--name\",{description:\"Initialize a package with the given name\"});this.usev2=ge.Boolean(\"-2\",!1,{hidden:!0});this.yes=ge.Boolean(\"-y,--yes\",{hidden:!0})}async execute(){let r=await Ke.find(this.context.cwd,this.context.plugins),o=typeof this.install==\"string\"?this.install:this.usev2||this.install===!0?\"latest\":null;return o!==null?await this.executeProxy(r,o):await this.executeRegular(r)}async executeProxy(r,o){if(r.projectCwd!==null&&r.projectCwd!==this.context.cwd)throw new it(\"Cannot use the --install flag from within a project subdirectory\");oe.existsSync(this.context.cwd)||await oe.mkdirPromise(this.context.cwd,{recursive:!0});let a=V.join(this.context.cwd,dr.lockfile);oe.existsSync(a)||await oe.writeFilePromise(a,\"\");let n=await this.cli.run([\"set\",\"version\",o],{quiet:!0});if(n!==0)return n;let u=[];return this.private&&u.push(\"-p\"),this.workspace&&u.push(\"-w\"),this.name&&u.push(`-n=${this.name}`),this.yes&&u.push(\"-y\"),await oe.mktempPromise(async A=>{let{code:p}=await Ur.pipevp(\"yarn\",[\"init\",...u],{cwd:this.context.cwd,stdin:this.context.stdin,stdout:this.context.stdout,stderr:this.context.stderr,env:await un.makeScriptEnv({binFolder:A})});return p})}async executeRegular(r){let o=null;try{o=(await St.find(r,this.context.cwd)).project}catch{o=null}oe.existsSync(this.context.cwd)||await oe.mkdirPromise(this.context.cwd,{recursive:!0});let a=await Ot.tryFind(this.context.cwd),n=a??new Ot,u=Object.fromEntries(r.get(\"initFields\").entries());n.load(u),n.name=n.name??W.makeIdent(r.get(\"initScope\"),this.name??V.basename(this.context.cwd)),n.packageManager=tn&&je.isTaggedYarnVersion(tn)?`yarn@${tn}`:null,(!a&&this.workspace||this.private)&&(n.private=!0),this.workspace&&n.workspaceDefinitions.length===0&&(await oe.mkdirPromise(V.join(this.context.cwd,\"packages\"),{recursive:!0}),n.workspaceDefinitions=[{pattern:\"packages/*\"}]);let A={};n.exportTo(A);let p=V.join(this.context.cwd,Ot.fileName);await oe.changeFilePromise(p,`${JSON.stringify(A,null,2)}\n`,{automaticNewlines:!0});let h=[p],C=V.join(this.context.cwd,\"README.md\");if(oe.existsSync(C)||(await oe.writeFilePromise(C,`# ${W.stringifyIdent(n.name)}\n`),h.push(C)),!o||o.cwd===this.context.cwd){let I=V.join(this.context.cwd,dr.lockfile);oe.existsSync(I)||(await oe.writeFilePromise(I,\"\"),h.push(I));let x=[\".yarn/*\",\"!.yarn/patches\",\"!.yarn/plugins\",\"!.yarn/releases\",\"!.yarn/sdks\",\"!.yarn/versions\",\"\",\"# Swap the comments on the following lines if you wish to use zero-installs\",\"# In that case, don't forget to run `yarn config set enableGlobalCache false`!\",\"# Documentation here: https://yarnpkg.com/features/zero-installs\",\"\",\"#!.yarn/cache\",\".pnp.*\"].map(he=>`${he}\n`).join(\"\"),E=V.join(this.context.cwd,\".gitignore\");oe.existsSync(E)||(await oe.writeFilePromise(E,x),h.push(E));let L=[\"/.yarn/**            linguist-vendored\",\"/.yarn/releases/*    binary\",\"/.yarn/plugins/**/*  binary\",\"/.pnp.*              binary linguist-generated\"].map(he=>`${he}\n`).join(\"\"),U=V.join(this.context.cwd,\".gitattributes\");oe.existsSync(U)||(await oe.writeFilePromise(U,L),h.push(U));let z={[\"*\"]:{endOfLine:\"lf\",insertFinalNewline:!0},[\"*.{js,json,yml}\"]:{charset:\"utf-8\",indentStyle:\"space\",indentSize:2}};je.mergeIntoTarget(z,r.get(\"initEditorConfig\"));let te=`root = true\n`;for(let[he,Ae]of Object.entries(z)){te+=`\n[${he}]\n`;for(let[ye,ae]of Object.entries(Ae)){let Ie=ye.replace(/[A-Z]/g,Fe=>`_${Fe.toLowerCase()}`);te+=`${Ie} = ${ae}\n`}}let le=V.join(this.context.cwd,\".editorconfig\");oe.existsSync(le)||(await oe.writeFilePromise(le,te),h.push(le)),await this.cli.run([\"install\"],{quiet:!0}),oe.existsSync(V.join(this.context.cwd,\".git\"))||(await Ur.execvp(\"git\",[\"init\"],{cwd:this.context.cwd}),await Ur.execvp(\"git\",[\"add\",\"--\",...h],{cwd:this.context.cwd}),await Ur.execvp(\"git\",[\"commit\",\"--allow-empty\",\"-m\",\"First commit\"],{cwd:this.context.cwd}))}}};g0.paths=[[\"init\"]],g0.usage=nt.Usage({description:\"create a new package\",details:\"\\n      This command will setup a new package in your local directory.\\n\\n      If the `-p,--private` or `-w,--workspace` options are set, the package will be private by default.\\n\\n      If the `-w,--workspace` option is set, the package will be configured to accept a set of workspaces in the `packages/` directory.\\n\\n      If the `-i,--install` option is given a value, Yarn will first download it using `yarn set version` and only then forward the init call to the newly downloaded bundle. Without arguments, the downloaded bundle will be `latest`.\\n\\n      The initial settings of the manifest can be changed by using the `initScope` and `initFields` configuration values. Additionally, Yarn will generate an EditorConfig file whose rules can be altered via `initEditorConfig`, and will initialize a Git repository in the current directory.\\n    \",examples:[[\"Create a new package in the local directory\",\"yarn init\"],[\"Create a new private package in the local directory\",\"yarn init -p\"],[\"Create a new package and store the Yarn release inside\",\"yarn init -i=latest\"],[\"Create a new private package and defines it as a workspace root\",\"yarn init -w\"]]});var mdt={configuration:{initScope:{description:\"Scope used when creating packages via the init command\",type:\"STRING\",default:null},initFields:{description:\"Additional fields to set when creating packages via the init command\",type:\"MAP\",valueDefinition:{description:\"\",type:\"ANY\"}},initEditorConfig:{description:\"Extra rules to define in the generator editorconfig\",type:\"MAP\",valueDefinition:{description:\"\",type:\"ANY\"}}},commands:[g0]},ydt=mdt;var Lj={};Vt(Lj,{SearchCommand:()=>C0,UpgradeInteractiveCommand:()=>I0,default:()=>oIt});Ye();var Ime=$e(Be(\"os\"));function PC({stdout:t}){if(Ime.default.endianness()===\"BE\")throw new Error(\"Interactive commands cannot be used on big-endian systems because ink depends on yoga-layout-prebuilt which only supports little-endian architectures\");if(!t.isTTY)throw new Error(\"Interactive commands can only be used inside a TTY environment\")}qt();var Tye=$e(ZH()),$H={appId:\"OFCNCOG2CU\",apiKey:\"6fe4476ee5a1832882e326b506d14126\",indexName:\"npm-search\"},gyt=(0,Tye.default)($H.appId,$H.apiKey).initIndex($H.indexName),e6=async(t,e=0)=>await gyt.search(t,{analyticsTags:[\"yarn-plugin-interactive-tools\"],attributesToRetrieve:[\"name\",\"version\",\"owner\",\"repository\",\"humanDownloadsLast30Days\"],page:e,hitsPerPage:10});var HB=[\"regular\",\"dev\",\"peer\"],C0=class extends ut{async execute(){PC(this.context);let{Gem:e}=await Promise.resolve().then(()=>(AQ(),Dj)),{ScrollableItems:r}=await Promise.resolve().then(()=>(gQ(),hQ)),{useKeypress:o}=await Promise.resolve().then(()=>(MB(),zwe)),{useMinistore:a}=await Promise.resolve().then(()=>(Qj(),kj)),{renderForm:n}=await Promise.resolve().then(()=>(EQ(),yQ)),{default:u}=await Promise.resolve().then(()=>$e(sIe())),{Box:A,Text:p}=await Promise.resolve().then(()=>$e(ic())),{default:h,useEffect:C,useState:I}=await Promise.resolve().then(()=>$e(sn())),v=await Ke.find(this.context.cwd,this.context.plugins),x=()=>h.createElement(A,{flexDirection:\"row\"},h.createElement(A,{flexDirection:\"column\",width:48},h.createElement(A,null,h.createElement(p,null,\"Press \",h.createElement(p,{bold:!0,color:\"cyanBright\"},\"<up>\"),\"/\",h.createElement(p,{bold:!0,color:\"cyanBright\"},\"<down>\"),\" to move between packages.\")),h.createElement(A,null,h.createElement(p,null,\"Press \",h.createElement(p,{bold:!0,color:\"cyanBright\"},\"<space>\"),\" to select a package.\")),h.createElement(A,null,h.createElement(p,null,\"Press \",h.createElement(p,{bold:!0,color:\"cyanBright\"},\"<space>\"),\" again to change the target.\"))),h.createElement(A,{flexDirection:\"column\"},h.createElement(A,{marginLeft:1},h.createElement(p,null,\"Press \",h.createElement(p,{bold:!0,color:\"cyanBright\"},\"<enter>\"),\" to install the selected packages.\")),h.createElement(A,{marginLeft:1},h.createElement(p,null,\"Press \",h.createElement(p,{bold:!0,color:\"cyanBright\"},\"<ctrl+c>\"),\" to abort.\")))),E=()=>h.createElement(h.Fragment,null,h.createElement(A,{width:15},h.createElement(p,{bold:!0,underline:!0,color:\"gray\"},\"Owner\")),h.createElement(A,{width:11},h.createElement(p,{bold:!0,underline:!0,color:\"gray\"},\"Version\")),h.createElement(A,{width:10},h.createElement(p,{bold:!0,underline:!0,color:\"gray\"},\"Downloads\"))),R=()=>h.createElement(A,{width:17},h.createElement(p,{bold:!0,underline:!0,color:\"gray\"},\"Target\")),L=({hit:ae,active:Ie})=>{let[Fe,g]=a(ae.name,null);o({active:Ie},(ce,ne)=>{if(ne.name!==\"space\")return;if(!Fe){g(HB[0]);return}let ee=HB.indexOf(Fe)+1;ee===HB.length?g(null):g(HB[ee])},[Fe,g]);let Ee=W.parseIdent(ae.name),De=W.prettyIdent(v,Ee);return h.createElement(A,null,h.createElement(A,{width:45},h.createElement(p,{bold:!0,wrap:\"wrap\"},De)),h.createElement(A,{width:14,marginLeft:1},h.createElement(p,{bold:!0,wrap:\"truncate\"},ae.owner.name)),h.createElement(A,{width:10,marginLeft:1},h.createElement(p,{italic:!0,wrap:\"truncate\"},ae.version)),h.createElement(A,{width:16,marginLeft:1},h.createElement(p,null,ae.humanDownloadsLast30Days)))},U=({name:ae,active:Ie})=>{let[Fe]=a(ae,null),g=W.parseIdent(ae);return h.createElement(A,null,h.createElement(A,{width:47},h.createElement(p,{bold:!0},\" - \",W.prettyIdent(v,g))),HB.map(Ee=>h.createElement(A,{key:Ee,width:14,marginLeft:1},h.createElement(p,null,\" \",h.createElement(e,{active:Fe===Ee}),\" \",h.createElement(p,{bold:!0},Ee)))))},z=()=>h.createElement(A,{marginTop:1},h.createElement(p,null,\"Powered by Algolia.\")),le=await n(({useSubmit:ae})=>{let Ie=a();ae(Ie);let Fe=Array.from(Ie.keys()).filter(H=>Ie.get(H)!==null),[g,Ee]=I(\"\"),[De,ce]=I(0),[ne,ee]=I([]),we=H=>{H.match(/\\t| /)||Ee(H)},xe=async()=>{ce(0);let H=await e6(g);H.query===g&&ee(H.hits)},ht=async()=>{let H=await e6(g,De+1);H.query===g&&H.page-1===De&&(ce(H.page),ee([...ne,...H.hits]))};return C(()=>{g?xe():ee([])},[g]),h.createElement(A,{flexDirection:\"column\"},h.createElement(x,null),h.createElement(A,{flexDirection:\"row\",marginTop:1},h.createElement(p,{bold:!0},\"Search: \"),h.createElement(A,{width:41},h.createElement(u,{value:g,onChange:we,placeholder:\"i.e. babel, webpack, react...\",showCursor:!1})),h.createElement(E,null)),ne.length?h.createElement(r,{radius:2,loop:!1,children:ne.map(H=>h.createElement(L,{key:H.name,hit:H,active:!1})),willReachEnd:ht}):h.createElement(p,{color:\"gray\"},\"Start typing...\"),h.createElement(A,{flexDirection:\"row\",marginTop:1},h.createElement(A,{width:49},h.createElement(p,{bold:!0},\"Selected:\")),h.createElement(R,null)),Fe.length?Fe.map(H=>h.createElement(U,{key:H,name:H,active:!1})):h.createElement(p,{color:\"gray\"},\"No selected packages...\"),h.createElement(z,null))},{},{stdin:this.context.stdin,stdout:this.context.stdout,stderr:this.context.stderr});if(typeof le>\"u\")return 1;let he=Array.from(le.keys()).filter(ae=>le.get(ae)===\"regular\"),Ae=Array.from(le.keys()).filter(ae=>le.get(ae)===\"dev\"),ye=Array.from(le.keys()).filter(ae=>le.get(ae)===\"peer\");return he.length&&await this.cli.run([\"add\",...he]),Ae.length&&await this.cli.run([\"add\",\"--dev\",...Ae]),ye&&await this.cli.run([\"add\",\"--peer\",...ye]),0}};C0.paths=[[\"search\"]],C0.usage=nt.Usage({category:\"Interactive commands\",description:\"open the search interface\",details:`\n    This command opens a fullscreen terminal interface where you can search for and install packages from the npm registry.\n    `,examples:[[\"Open the search window\",\"yarn search\"]]});Ye();qt();w_();var fIe=$e(Jn()),AIe=/^((?:[\\^~]|>=?)?)([0-9]+)(\\.[0-9]+)(\\.[0-9]+)((?:-\\S+)?)$/,pIe=(t,e)=>t.length>0?[t.slice(0,e)].concat(pIe(t.slice(e),e)):[],I0=class extends ut{async execute(){PC(this.context);let{ItemOptions:e}=await Promise.resolve().then(()=>(uIe(),cIe)),{Pad:r}=await Promise.resolve().then(()=>(Nj(),lIe)),{ScrollableItems:o}=await Promise.resolve().then(()=>(gQ(),hQ)),{useMinistore:a}=await Promise.resolve().then(()=>(Qj(),kj)),{renderForm:n}=await Promise.resolve().then(()=>(EQ(),yQ)),{Box:u,Text:A}=await Promise.resolve().then(()=>$e(ic())),{default:p,useEffect:h,useRef:C,useState:I}=await Promise.resolve().then(()=>$e(sn())),v=await Ke.find(this.context.cwd,this.context.plugins),{project:x,workspace:E}=await St.find(v,this.context.cwd),R=await Lr.find(v);if(!E)throw new rr(x.cwd,this.context.cwd);await x.restoreInstallState({restoreResolutions:!1});let L=this.context.stdout.rows-7,U=(Ee,De)=>{let ce=ppe(Ee,De),ne=\"\";for(let ee of ce)ee.added?ne+=de.pretty(v,ee.value,\"green\"):ee.removed||(ne+=ee.value);return ne},z=(Ee,De)=>{if(Ee===De)return De;let ce=W.parseRange(Ee),ne=W.parseRange(De),ee=ce.selector.match(AIe),we=ne.selector.match(AIe);if(!ee||!we)return U(Ee,De);let xe=[\"gray\",\"red\",\"yellow\",\"green\",\"magenta\"],ht=null,H=\"\";for(let lt=1;lt<xe.length;++lt)ht!==null||ee[lt]!==we[lt]?(ht===null&&(ht=xe[lt-1]),H+=de.pretty(v,we[lt],ht)):H+=we[lt];return H},te=async(Ee,De,ce)=>{let ne=await Jc.fetchDescriptorFrom(Ee,ce,{project:x,cache:R,preserveModifier:De,workspace:E});return ne!==null?ne.range:Ee.range},le=async Ee=>{let De=fIe.default.valid(Ee.range)?`^${Ee.range}`:Ee.range,[ce,ne]=await Promise.all([te(Ee,Ee.range,De).catch(()=>null),te(Ee,Ee.range,\"latest\").catch(()=>null)]),ee=[{value:null,label:Ee.range}];return ce&&ce!==Ee.range?ee.push({value:ce,label:z(Ee.range,ce)}):ee.push({value:null,label:\"\"}),ne&&ne!==ce&&ne!==Ee.range?ee.push({value:ne,label:z(Ee.range,ne)}):ee.push({value:null,label:\"\"}),ee},he=()=>p.createElement(u,{flexDirection:\"row\"},p.createElement(u,{flexDirection:\"column\",width:49},p.createElement(u,{marginLeft:1},p.createElement(A,null,\"Press \",p.createElement(A,{bold:!0,color:\"cyanBright\"},\"<up>\"),\"/\",p.createElement(A,{bold:!0,color:\"cyanBright\"},\"<down>\"),\" to select packages.\")),p.createElement(u,{marginLeft:1},p.createElement(A,null,\"Press \",p.createElement(A,{bold:!0,color:\"cyanBright\"},\"<left>\"),\"/\",p.createElement(A,{bold:!0,color:\"cyanBright\"},\"<right>\"),\" to select versions.\"))),p.createElement(u,{flexDirection:\"column\"},p.createElement(u,{marginLeft:1},p.createElement(A,null,\"Press \",p.createElement(A,{bold:!0,color:\"cyanBright\"},\"<enter>\"),\" to install.\")),p.createElement(u,{marginLeft:1},p.createElement(A,null,\"Press \",p.createElement(A,{bold:!0,color:\"cyanBright\"},\"<ctrl+c>\"),\" to abort.\")))),Ae=()=>p.createElement(u,{flexDirection:\"row\",paddingTop:1,paddingBottom:1},p.createElement(u,{width:50},p.createElement(A,{bold:!0},p.createElement(A,{color:\"greenBright\"},\"?\"),\" Pick the packages you want to upgrade.\")),p.createElement(u,{width:17},p.createElement(A,{bold:!0,underline:!0,color:\"gray\"},\"Current\")),p.createElement(u,{width:17},p.createElement(A,{bold:!0,underline:!0,color:\"gray\"},\"Range\")),p.createElement(u,{width:17},p.createElement(A,{bold:!0,underline:!0,color:\"gray\"},\"Latest\"))),ye=({active:Ee,descriptor:De,suggestions:ce})=>{let[ne,ee]=a(De.descriptorHash,null),we=W.stringifyIdent(De),xe=Math.max(0,45-we.length);return p.createElement(p.Fragment,null,p.createElement(u,null,p.createElement(u,{width:45},p.createElement(A,{bold:!0},W.prettyIdent(v,De)),p.createElement(r,{active:Ee,length:xe})),p.createElement(e,{active:Ee,options:ce,value:ne,skewer:!0,onChange:ee,sizes:[17,17,17]})))},ae=({dependencies:Ee})=>{let[De,ce]=I(Ee.map(()=>null)),ne=C(!0),ee=async we=>{let xe=await le(we);return xe.filter(ht=>ht.label!==\"\").length<=1?null:{descriptor:we,suggestions:xe}};return h(()=>()=>{ne.current=!1},[]),h(()=>{let we=Math.trunc(L*1.75),xe=Ee.slice(0,we),ht=Ee.slice(we),H=pIe(ht,L),lt=xe.map(ee).reduce(async(Te,ke)=>{await Te;let be=await ke;be!==null&&(!ne.current||ce(_e=>{let Re=_e.findIndex(He=>He===null),ze=[..._e];return ze[Re]=be,ze}))},Promise.resolve());H.reduce((Te,ke)=>Promise.all(ke.map(be=>Promise.resolve().then(()=>ee(be)))).then(async be=>{be=be.filter(_e=>_e!==null),await Te,ne.current&&ce(_e=>{let Re=_e.findIndex(ze=>ze===null);return _e.slice(0,Re).concat(be).concat(_e.slice(Re+be.length))})}),lt).then(()=>{ne.current&&ce(Te=>Te.filter(ke=>ke!==null))})},[]),De.length?p.createElement(o,{radius:L>>1,children:De.map((we,xe)=>we!==null?p.createElement(ye,{key:xe,active:!1,descriptor:we.descriptor,suggestions:we.suggestions}):p.createElement(A,{key:xe},\"Loading...\"))}):p.createElement(A,null,\"No upgrades found\")},Fe=await n(({useSubmit:Ee})=>{Ee(a());let De=new Map;for(let ne of x.workspaces)for(let ee of[\"dependencies\",\"devDependencies\"])for(let we of ne.manifest[ee].values())x.tryWorkspaceByDescriptor(we)===null&&(we.range.startsWith(\"link:\")||De.set(we.descriptorHash,we));let ce=je.sortMap(De.values(),ne=>W.stringifyDescriptor(ne));return p.createElement(u,{flexDirection:\"column\"},p.createElement(he,null),p.createElement(Ae,null),p.createElement(ae,{dependencies:ce}))},{},{stdin:this.context.stdin,stdout:this.context.stdout,stderr:this.context.stderr});if(typeof Fe>\"u\")return 1;let g=!1;for(let Ee of x.workspaces)for(let De of[\"dependencies\",\"devDependencies\"]){let ce=Ee.manifest[De];for(let ne of ce.values()){let ee=Fe.get(ne.descriptorHash);typeof ee<\"u\"&&ee!==null&&(ce.set(ne.identHash,W.makeDescriptor(ne,ee)),g=!0)}}return g?await x.installWithNewReport({quiet:this.context.quiet,stdout:this.context.stdout},{cache:R}):0}};I0.paths=[[\"upgrade-interactive\"]],I0.usage=nt.Usage({category:\"Interactive commands\",description:\"open the upgrade interface\",details:`\n      This command opens a fullscreen terminal interface where you can see any out of date packages used by your application, their status compared to the latest versions available on the remote registry, and select packages to upgrade.\n    `,examples:[[\"Open the upgrade window\",\"yarn upgrade-interactive\"]]});var sIt={commands:[C0,I0]},oIt=sIt;var Oj={};Vt(Oj,{LinkFetcher:()=>qB,LinkResolver:()=>GB,PortalFetcher:()=>YB,PortalResolver:()=>WB,default:()=>lIt});Ye();Pt();var $f=\"portal:\",ep=\"link:\";var qB=class{supports(e,r){return!!e.reference.startsWith(ep)}getLocalPath(e,r){let{parentLocator:o,path:a}=W.parseFileStyleRange(e.reference,{protocol:ep});if(V.isAbsolute(a))return a;let n=r.fetcher.getLocalPath(o,r);return n===null?null:V.resolve(n,a)}async fetch(e,r){let{parentLocator:o,path:a}=W.parseFileStyleRange(e.reference,{protocol:ep}),n=V.isAbsolute(a)?{packageFs:new gn(Bt.root),prefixPath:Bt.dot,localPath:Bt.root}:await r.fetcher.fetch(o,r),u=n.localPath?{packageFs:new gn(Bt.root),prefixPath:V.relative(Bt.root,n.localPath),localPath:Bt.root}:n;n!==u&&n.releaseFs&&n.releaseFs();let A=u.packageFs,p=V.resolve(u.localPath??u.packageFs.getRealPath(),u.prefixPath,a);return n.localPath?{packageFs:new gn(p,{baseFs:A}),releaseFs:u.releaseFs,prefixPath:Bt.dot,discardFromLookup:!0,localPath:p}:{packageFs:new _u(p,{baseFs:A}),releaseFs:u.releaseFs,prefixPath:Bt.dot,discardFromLookup:!0}}};Ye();Pt();var GB=class{supportsDescriptor(e,r){return!!e.range.startsWith(ep)}supportsLocator(e,r){return!!e.reference.startsWith(ep)}shouldPersistResolution(e,r){return!1}bindDescriptor(e,r,o){return W.bindDescriptor(e,{locator:W.stringifyLocator(r)})}getResolutionDependencies(e,r){return{}}async getCandidates(e,r,o){let a=e.range.slice(ep.length);return[W.makeLocator(e,`${ep}${ue.toPortablePath(a)}`)]}async getSatisfying(e,r,o,a){let[n]=await this.getCandidates(e,r,a);return{locators:o.filter(u=>u.locatorHash===n.locatorHash),sorted:!1}}async resolve(e,r){return{...e,version:\"0.0.0\",languageName:r.project.configuration.get(\"defaultLanguageName\"),linkType:\"SOFT\",conditions:null,dependencies:new Map,peerDependencies:new Map,dependenciesMeta:new Map,peerDependenciesMeta:new Map,bin:new Map}}};Ye();Pt();var YB=class{supports(e,r){return!!e.reference.startsWith($f)}getLocalPath(e,r){let{parentLocator:o,path:a}=W.parseFileStyleRange(e.reference,{protocol:$f});if(V.isAbsolute(a))return a;let n=r.fetcher.getLocalPath(o,r);return n===null?null:V.resolve(n,a)}async fetch(e,r){let{parentLocator:o,path:a}=W.parseFileStyleRange(e.reference,{protocol:$f}),n=V.isAbsolute(a)?{packageFs:new gn(Bt.root),prefixPath:Bt.dot,localPath:Bt.root}:await r.fetcher.fetch(o,r),u=n.localPath?{packageFs:new gn(Bt.root),prefixPath:V.relative(Bt.root,n.localPath),localPath:Bt.root}:n;n!==u&&n.releaseFs&&n.releaseFs();let A=u.packageFs,p=V.resolve(u.localPath??u.packageFs.getRealPath(),u.prefixPath,a);return n.localPath?{packageFs:new gn(p,{baseFs:A}),releaseFs:u.releaseFs,prefixPath:Bt.dot,localPath:p}:{packageFs:new _u(p,{baseFs:A}),releaseFs:u.releaseFs,prefixPath:Bt.dot}}};Ye();Ye();Pt();var WB=class{supportsDescriptor(e,r){return!!e.range.startsWith($f)}supportsLocator(e,r){return!!e.reference.startsWith($f)}shouldPersistResolution(e,r){return!1}bindDescriptor(e,r,o){return W.bindDescriptor(e,{locator:W.stringifyLocator(r)})}getResolutionDependencies(e,r){return{}}async getCandidates(e,r,o){let a=e.range.slice($f.length);return[W.makeLocator(e,`${$f}${ue.toPortablePath(a)}`)]}async getSatisfying(e,r,o,a){let[n]=await this.getCandidates(e,r,a);return{locators:o.filter(u=>u.locatorHash===n.locatorHash),sorted:!1}}async resolve(e,r){if(!r.fetchOptions)throw new Error(\"Assertion failed: This resolver cannot be used unless a fetcher is configured\");let o=await r.fetchOptions.fetcher.fetch(e,r.fetchOptions),a=await je.releaseAfterUseAsync(async()=>await Ot.find(o.prefixPath,{baseFs:o.packageFs}),o.releaseFs);return{...e,version:a.version||\"0.0.0\",languageName:a.languageName||r.project.configuration.get(\"defaultLanguageName\"),linkType:\"SOFT\",conditions:a.getConditions(),dependencies:r.project.configuration.normalizeDependencyMap(a.dependencies),peerDependencies:a.peerDependencies,dependenciesMeta:a.dependenciesMeta,peerDependenciesMeta:a.peerDependenciesMeta,bin:a.bin}}};var aIt={fetchers:[qB,YB],resolvers:[GB,WB]},lIt=aIt;var wq={};Vt(wq,{NodeModulesLinker:()=>lv,NodeModulesMode:()=>mq,PnpLooseLinker:()=>cv,default:()=>v1t});Pt();Ye();Pt();Pt();var Uj=(t,e)=>`${t}@${e}`,hIe=(t,e)=>{let r=e.indexOf(\"#\"),o=r>=0?e.substring(r+1):e;return Uj(t,o)};var mIe=(t,e={})=>{let r=e.debugLevel||Number(process.env.NM_DEBUG_LEVEL||-1),o=e.check||r>=9,a=e.hoistingLimits||new Map,n={check:o,debugLevel:r,hoistingLimits:a,fastLookupPossible:!0},u;n.debugLevel>=0&&(u=Date.now());let A=gIt(t,n),p=!1,h=0;do p=_j(A,[A],new Set([A.locator]),new Map,n).anotherRoundNeeded,n.fastLookupPossible=!1,h++;while(p);if(n.debugLevel>=0&&console.log(`hoist time: ${Date.now()-u}ms, rounds: ${h}`),n.debugLevel>=1){let C=KB(A);if(_j(A,[A],new Set([A.locator]),new Map,n).isGraphChanged)throw new Error(`The hoisting result is not terminal, prev tree:\n${C}, next tree:\n${KB(A)}`);let v=yIe(A);if(v)throw new Error(`${v}, after hoisting finished:\n${KB(A)}`)}return n.debugLevel>=2&&console.log(KB(A)),dIt(A)},cIt=t=>{let e=t[t.length-1],r=new Map,o=new Set,a=n=>{if(!o.has(n)){o.add(n);for(let u of n.hoistedDependencies.values())r.set(u.name,u);for(let u of n.dependencies.values())n.peerNames.has(u.name)||a(u)}};return a(e),r},uIt=t=>{let e=t[t.length-1],r=new Map,o=new Set,a=new Set,n=(u,A)=>{if(o.has(u))return;o.add(u);for(let h of u.hoistedDependencies.values())if(!A.has(h.name)){let C;for(let I of t)C=I.dependencies.get(h.name),C&&r.set(C.name,C)}let p=new Set;for(let h of u.dependencies.values())p.add(h.name);for(let h of u.dependencies.values())u.peerNames.has(h.name)||n(h,p)};return n(e,a),r},gIe=(t,e)=>{if(e.decoupled)return e;let{name:r,references:o,ident:a,locator:n,dependencies:u,originalDependencies:A,hoistedDependencies:p,peerNames:h,reasons:C,isHoistBorder:I,hoistPriority:v,dependencyKind:x,hoistedFrom:E,hoistedTo:R}=e,L={name:r,references:new Set(o),ident:a,locator:n,dependencies:new Map(u),originalDependencies:new Map(A),hoistedDependencies:new Map(p),peerNames:new Set(h),reasons:new Map(C),decoupled:!0,isHoistBorder:I,hoistPriority:v,dependencyKind:x,hoistedFrom:new Map(E),hoistedTo:new Map(R)},U=L.dependencies.get(r);return U&&U.ident==L.ident&&L.dependencies.set(r,L),t.dependencies.set(L.name,L),L},AIt=(t,e)=>{let r=new Map([[t.name,[t.ident]]]);for(let a of t.dependencies.values())t.peerNames.has(a.name)||r.set(a.name,[a.ident]);let o=Array.from(e.keys());o.sort((a,n)=>{let u=e.get(a),A=e.get(n);return A.hoistPriority!==u.hoistPriority?A.hoistPriority-u.hoistPriority:A.peerDependents.size!==u.peerDependents.size?A.peerDependents.size-u.peerDependents.size:A.dependents.size-u.dependents.size});for(let a of o){let n=a.substring(0,a.indexOf(\"@\",1)),u=a.substring(n.length+1);if(!t.peerNames.has(n)){let A=r.get(n);A||(A=[],r.set(n,A)),A.indexOf(u)<0&&A.push(u)}}return r},Mj=t=>{let e=new Set,r=(o,a=new Set)=>{if(!a.has(o)){a.add(o);for(let n of o.peerNames)if(!t.peerNames.has(n)){let u=t.dependencies.get(n);u&&!e.has(u)&&r(u,a)}e.add(o)}};for(let o of t.dependencies.values())t.peerNames.has(o.name)||r(o);return e},_j=(t,e,r,o,a,n=new Set)=>{let u=e[e.length-1];if(n.has(u))return{anotherRoundNeeded:!1,isGraphChanged:!1};n.add(u);let A=mIt(u),p=AIt(u,A),h=t==u?new Map:a.fastLookupPossible?cIt(e):uIt(e),C,I=!1,v=!1,x=new Map(Array.from(p.entries()).map(([R,L])=>[R,L[0]])),E=new Map;do{let R=hIt(t,e,r,h,x,p,o,E,a);R.isGraphChanged&&(v=!0),R.anotherRoundNeeded&&(I=!0),C=!1;for(let[L,U]of p)U.length>1&&!u.dependencies.has(L)&&(x.delete(L),U.shift(),x.set(L,U[0]),C=!0)}while(C);for(let R of u.dependencies.values())if(!u.peerNames.has(R.name)&&!r.has(R.locator)){r.add(R.locator);let L=_j(t,[...e,R],r,E,a);L.isGraphChanged&&(v=!0),L.anotherRoundNeeded&&(I=!0),r.delete(R.locator)}return{anotherRoundNeeded:I,isGraphChanged:v}},fIt=t=>{for(let[e,r]of t.dependencies)if(!t.peerNames.has(e)&&r.ident!==t.ident)return!0;return!1},pIt=(t,e,r,o,a,n,u,A,{outputReason:p,fastLookupPossible:h})=>{let C,I=null,v=new Set;p&&(C=`${Array.from(e).map(L=>no(L)).join(\"\\u2192\")}`);let x=r[r.length-1],R=!(o.ident===x.ident);if(p&&!R&&(I=\"- self-reference\"),R&&(R=o.dependencyKind!==1,p&&!R&&(I=\"- workspace\")),R&&o.dependencyKind===2&&(R=!fIt(o),p&&!R&&(I=\"- external soft link with unhoisted dependencies\")),R&&(R=x.dependencyKind!==1||x.hoistedFrom.has(o.name)||e.size===1,p&&!R&&(I=x.reasons.get(o.name))),R&&(R=!t.peerNames.has(o.name),p&&!R&&(I=`- cannot shadow peer: ${no(t.originalDependencies.get(o.name).locator)} at ${C}`)),R){let L=!1,U=a.get(o.name);if(L=!U||U.ident===o.ident,p&&!L&&(I=`- filled by: ${no(U.locator)} at ${C}`),L)for(let z=r.length-1;z>=1;z--){let le=r[z].dependencies.get(o.name);if(le&&le.ident!==o.ident){L=!1;let he=A.get(x);he||(he=new Set,A.set(x,he)),he.add(o.name),p&&(I=`- filled by ${no(le.locator)} at ${r.slice(0,z).map(Ae=>no(Ae.locator)).join(\"\\u2192\")}`);break}}R=L}if(R&&(R=n.get(o.name)===o.ident,p&&!R&&(I=`- filled by: ${no(u.get(o.name)[0])} at ${C}`)),R){let L=!0,U=new Set(o.peerNames);for(let z=r.length-1;z>=1;z--){let te=r[z];for(let le of U){if(te.peerNames.has(le)&&te.originalDependencies.has(le))continue;let he=te.dependencies.get(le);he&&t.dependencies.get(le)!==he&&(z===r.length-1?v.add(he):(v=null,L=!1,p&&(I=`- peer dependency ${no(he.locator)} from parent ${no(te.locator)} was not hoisted to ${C}`))),U.delete(le)}if(!L)break}R=L}if(R&&!h)for(let L of o.hoistedDependencies.values()){let U=a.get(L.name)||t.dependencies.get(L.name);if(!U||L.ident!==U.ident){R=!1,p&&(I=`- previously hoisted dependency mismatch, needed: ${no(L.locator)}, available: ${no(U?.locator)}`);break}}return v!==null&&v.size>0?{isHoistable:2,dependsOn:v,reason:I}:{isHoistable:R?0:1,reason:I}},CQ=t=>`${t.name}@${t.locator}`,hIt=(t,e,r,o,a,n,u,A,p)=>{let h=e[e.length-1],C=new Set,I=!1,v=!1,x=(U,z,te,le,he)=>{if(C.has(le))return;let Ae=[...z,CQ(le)],ye=[...te,CQ(le)],ae=new Map,Ie=new Map;for(let ce of Mj(le)){let ne=pIt(h,r,[h,...U,le],ce,o,a,n,A,{outputReason:p.debugLevel>=2,fastLookupPossible:p.fastLookupPossible});if(Ie.set(ce,ne),ne.isHoistable===2)for(let ee of ne.dependsOn){let we=ae.get(ee.name)||new Set;we.add(ce.name),ae.set(ee.name,we)}}let Fe=new Set,g=(ce,ne,ee)=>{if(!Fe.has(ce)){Fe.add(ce),Ie.set(ce,{isHoistable:1,reason:ee});for(let we of ae.get(ce.name)||[])g(le.dependencies.get(we),ne,p.debugLevel>=2?`- peer dependency ${no(ce.locator)} from parent ${no(le.locator)} was not hoisted`:\"\")}};for(let[ce,ne]of Ie)ne.isHoistable===1&&g(ce,ne,ne.reason);let Ee=!1;for(let ce of Ie.keys())if(!Fe.has(ce)){v=!0;let ne=u.get(le);ne&&ne.has(ce.name)&&(I=!0),Ee=!0,le.dependencies.delete(ce.name),le.hoistedDependencies.set(ce.name,ce),le.reasons.delete(ce.name);let ee=h.dependencies.get(ce.name);if(p.debugLevel>=2){let we=Array.from(z).concat([le.locator]).map(ht=>no(ht)).join(\"\\u2192\"),xe=h.hoistedFrom.get(ce.name);xe||(xe=[],h.hoistedFrom.set(ce.name,xe)),xe.push(we),le.hoistedTo.set(ce.name,Array.from(e).map(ht=>no(ht.locator)).join(\"\\u2192\"))}if(!ee)h.ident!==ce.ident&&(h.dependencies.set(ce.name,ce),he.add(ce));else for(let we of ce.references)ee.references.add(we)}if(le.dependencyKind===2&&Ee&&(I=!0),p.check){let ce=yIe(t);if(ce)throw new Error(`${ce}, after hoisting dependencies of ${[h,...U,le].map(ne=>no(ne.locator)).join(\"\\u2192\")}:\n${KB(t)}`)}let De=Mj(le);for(let ce of De)if(Fe.has(ce)){let ne=Ie.get(ce);if((a.get(ce.name)===ce.ident||!le.reasons.has(ce.name))&&ne.isHoistable!==0&&le.reasons.set(ce.name,ne.reason),!ce.isHoistBorder&&ye.indexOf(CQ(ce))<0){C.add(le);let we=gIe(le,ce);x([...U,le],Ae,ye,we,R),C.delete(le)}}},E,R=new Set(Mj(h)),L=Array.from(e).map(U=>CQ(U));do{E=R,R=new Set;for(let U of E){if(U.locator===h.locator||U.isHoistBorder)continue;let z=gIe(h,U);x([],Array.from(r),L,z,R)}}while(R.size>0);return{anotherRoundNeeded:I,isGraphChanged:v}},yIe=t=>{let e=[],r=new Set,o=new Set,a=(n,u,A)=>{if(r.has(n)||(r.add(n),o.has(n)))return;let p=new Map(u);for(let h of n.dependencies.values())n.peerNames.has(h.name)||p.set(h.name,h);for(let h of n.originalDependencies.values()){let C=p.get(h.name),I=()=>`${Array.from(o).concat([n]).map(v=>no(v.locator)).join(\"\\u2192\")}`;if(n.peerNames.has(h.name)){let v=u.get(h.name);(v!==C||!v||v.ident!==h.ident)&&e.push(`${I()} - broken peer promise: expected ${h.ident} but found ${v&&v.ident}`)}else{let v=A.hoistedFrom.get(n.name),x=n.hoistedTo.get(h.name),E=`${v?` hoisted from ${v.join(\", \")}`:\"\"}`,R=`${x?` hoisted to ${x}`:\"\"}`,L=`${I()}${E}`;C?C.ident!==h.ident&&e.push(`${L} - broken require promise for ${h.name}${R}: expected ${h.ident}, but found: ${C.ident}`):e.push(`${L} - broken require promise: no required dependency ${h.name}${R} found`)}}o.add(n);for(let h of n.dependencies.values())n.peerNames.has(h.name)||a(h,p,n);o.delete(n)};return a(t,t.dependencies,t),e.join(`\n`)},gIt=(t,e)=>{let{identName:r,name:o,reference:a,peerNames:n}=t,u={name:o,references:new Set([a]),locator:Uj(r,a),ident:hIe(r,a),dependencies:new Map,originalDependencies:new Map,hoistedDependencies:new Map,peerNames:new Set(n),reasons:new Map,decoupled:!0,isHoistBorder:!0,hoistPriority:0,dependencyKind:1,hoistedFrom:new Map,hoistedTo:new Map},A=new Map([[t,u]]),p=(h,C)=>{let I=A.get(h),v=!!I;if(!I){let{name:x,identName:E,reference:R,peerNames:L,hoistPriority:U,dependencyKind:z}=h,te=e.hoistingLimits.get(C.locator);I={name:x,references:new Set([R]),locator:Uj(E,R),ident:hIe(E,R),dependencies:new Map,originalDependencies:new Map,hoistedDependencies:new Map,peerNames:new Set(L),reasons:new Map,decoupled:!0,isHoistBorder:te?te.has(x):!1,hoistPriority:U||0,dependencyKind:z||0,hoistedFrom:new Map,hoistedTo:new Map},A.set(h,I)}if(C.dependencies.set(h.name,I),C.originalDependencies.set(h.name,I),v){let x=new Set,E=R=>{if(!x.has(R)){x.add(R),R.decoupled=!1;for(let L of R.dependencies.values())R.peerNames.has(L.name)||E(L)}};E(I)}else for(let x of h.dependencies)p(x,I)};for(let h of t.dependencies)p(h,u);return u},Hj=t=>t.substring(0,t.indexOf(\"@\",1)),dIt=t=>{let e={name:t.name,identName:Hj(t.locator),references:new Set(t.references),dependencies:new Set},r=new Set([t]),o=(a,n,u)=>{let A=r.has(a),p;if(n===a)p=u;else{let{name:h,references:C,locator:I}=a;p={name:h,identName:Hj(I),references:C,dependencies:new Set}}if(u.dependencies.add(p),!A){r.add(a);for(let h of a.dependencies.values())a.peerNames.has(h.name)||o(h,a,p);r.delete(a)}};for(let a of t.dependencies.values())o(a,t,e);return e},mIt=t=>{let e=new Map,r=new Set([t]),o=u=>`${u.name}@${u.ident}`,a=u=>{let A=o(u),p=e.get(A);return p||(p={dependents:new Set,peerDependents:new Set,hoistPriority:0},e.set(A,p)),p},n=(u,A)=>{let p=!!r.has(A);if(a(A).dependents.add(u.ident),!p){r.add(A);for(let C of A.dependencies.values()){let I=a(C);I.hoistPriority=Math.max(I.hoistPriority,C.hoistPriority),A.peerNames.has(C.name)?I.peerDependents.add(A.ident):n(A,C)}}};for(let u of t.dependencies.values())t.peerNames.has(u.name)||n(t,u);return e},no=t=>{if(!t)return\"none\";let e=t.indexOf(\"@\",1),r=t.substring(0,e);r.endsWith(\"$wsroot$\")&&(r=`wh:${r.replace(\"$wsroot$\",\"\")}`);let o=t.substring(e+1);if(o===\"workspace:.\")return\".\";if(o){let a=(o.indexOf(\"#\")>0?o.split(\"#\")[1]:o).replace(\"npm:\",\"\");return o.startsWith(\"virtual\")&&(r=`v:${r}`),a.startsWith(\"workspace\")&&(r=`w:${r}`,a=\"\"),`${r}${a?`@${a}`:\"\"}`}else return`${r}`},dIe=5e4,KB=t=>{let e=0,r=(a,n,u=\"\")=>{if(e>dIe||n.has(a))return\"\";e++;let A=Array.from(a.dependencies.values()).sort((h,C)=>h.name===C.name?0:h.name>C.name?1:-1),p=\"\";n.add(a);for(let h=0;h<A.length;h++){let C=A[h];if(!a.peerNames.has(C.name)&&C!==a){let I=a.reasons.get(C.name),v=Hj(C.locator);p+=`${u}${h<A.length-1?\"\\u251C\\u2500\":\"\\u2514\\u2500\"}${(n.has(C)?\">\":\"\")+(v!==C.name?`a:${C.name}:`:\"\")+no(C.locator)+(I?` ${I}`:\"\")}\n`,p+=r(C,n,`${u}${h<A.length-1?\"\\u2502 \":\"  \"}`)}}return n.delete(a),p};return r(t,new Set)+(e>dIe?`\nTree is too large, part of the tree has been dunped\n`:\"\")};var VB=(o=>(o.WORKSPACES=\"workspaces\",o.DEPENDENCIES=\"dependencies\",o.NONE=\"none\",o))(VB||{}),EIe=\"node_modules\",fm=\"$wsroot$\";var zB=(t,e)=>{let{packageTree:r,hoistingLimits:o,errors:a,preserveSymlinksRequired:n}=EIt(t,e),u=null;if(a.length===0){let A=mIe(r,{hoistingLimits:o});u=wIt(t,A,e)}return{tree:u,errors:a,preserveSymlinksRequired:n}},gA=t=>`${t.name}@${t.reference}`,qj=t=>{let e=new Map;for(let[r,o]of t.entries())if(!o.dirList){let a=e.get(o.locator);a||(a={target:o.target,linkType:o.linkType,locations:[],aliases:o.aliases},e.set(o.locator,a)),a.locations.push(r)}for(let r of e.values())r.locations=r.locations.sort((o,a)=>{let n=o.split(V.delimiter).length,u=a.split(V.delimiter).length;return a===o?0:n!==u?u-n:a>o?1:-1});return e},CIe=(t,e)=>{let r=W.isVirtualLocator(t)?W.devirtualizeLocator(t):t,o=W.isVirtualLocator(e)?W.devirtualizeLocator(e):e;return W.areLocatorsEqual(r,o)},jj=(t,e,r,o)=>{if(t.linkType!==\"SOFT\")return!1;let a=ue.toPortablePath(r.resolveVirtual&&e.reference&&e.reference.startsWith(\"virtual:\")?r.resolveVirtual(t.packageLocation):t.packageLocation);return V.contains(o,a)===null},yIt=t=>{let e=t.getPackageInformation(t.topLevel);if(e===null)throw new Error(\"Assertion failed: Expected the top-level package to have been registered\");if(t.findPackageLocator(e.packageLocation)===null)throw new Error(\"Assertion failed: Expected the top-level package to have a physical locator\");let o=ue.toPortablePath(e.packageLocation.slice(0,-1)),a=new Map,n={children:new Map},u=t.getDependencyTreeRoots(),A=new Map,p=new Set,h=(v,x)=>{let E=gA(v);if(p.has(E))return;p.add(E);let R=t.getPackageInformation(v);if(R){let L=x?gA(x):\"\";if(gA(v)!==L&&R.linkType===\"SOFT\"&&!jj(R,v,t,o)){let U=wIe(R,v,t);(!A.get(U)||v.reference.startsWith(\"workspace:\"))&&A.set(U,v)}for(let[U,z]of R.packageDependencies)z!==null&&(R.packagePeers.has(U)||h(t.getLocator(U,z),v))}};for(let v of u)h(v,null);let C=o.split(V.sep);for(let v of A.values()){let x=t.getPackageInformation(v),R=ue.toPortablePath(x.packageLocation.slice(0,-1)).split(V.sep).slice(C.length),L=n;for(let U of R){let z=L.children.get(U);z||(z={children:new Map},L.children.set(U,z)),L=z}L.workspaceLocator=v}let I=(v,x)=>{if(v.workspaceLocator){let E=gA(x),R=a.get(E);R||(R=new Set,a.set(E,R)),R.add(v.workspaceLocator)}for(let E of v.children.values())I(E,v.workspaceLocator||x)};for(let v of n.children.values())I(v,n.workspaceLocator);return a},EIt=(t,e)=>{let r=[],o=!1,a=new Map,n=yIt(t),u=t.getPackageInformation(t.topLevel);if(u===null)throw new Error(\"Assertion failed: Expected the top-level package to have been registered\");let A=t.findPackageLocator(u.packageLocation);if(A===null)throw new Error(\"Assertion failed: Expected the top-level package to have a physical locator\");let p=ue.toPortablePath(u.packageLocation.slice(0,-1)),h={name:A.name,identName:A.name,reference:A.reference,peerNames:u.packagePeers,dependencies:new Set,dependencyKind:1},C=new Map,I=(x,E)=>`${gA(E)}:${x}`,v=(x,E,R,L,U,z,te,le)=>{let he=I(x,R),Ae=C.get(he),ye=!!Ae;!ye&&R.name===A.name&&R.reference===A.reference&&(Ae=h,C.set(he,h));let ae=jj(E,R,t,p);if(!Ae){let ce=0;ae?ce=2:E.linkType===\"SOFT\"&&R.name.endsWith(fm)&&(ce=1),Ae={name:x,identName:R.name,reference:R.reference,dependencies:new Set,peerNames:ce===1?new Set:E.packagePeers,dependencyKind:ce},C.set(he,Ae)}let Ie;if(ae?Ie=2:U.linkType===\"SOFT\"?Ie=1:Ie=0,Ae.hoistPriority=Math.max(Ae.hoistPriority||0,Ie),le&&!ae){let ce=gA({name:L.identName,reference:L.reference}),ne=a.get(ce)||new Set;a.set(ce,ne),ne.add(Ae.name)}let Fe=new Map(E.packageDependencies);if(e.project){let ce=e.project.workspacesByCwd.get(ue.toPortablePath(E.packageLocation.slice(0,-1)));if(ce){let ne=new Set([...Array.from(ce.manifest.peerDependencies.values(),ee=>W.stringifyIdent(ee)),...Array.from(ce.manifest.peerDependenciesMeta.keys())]);for(let ee of ne)Fe.has(ee)||(Fe.set(ee,z.get(ee)||null),Ae.peerNames.add(ee))}}let g=gA({name:R.name.replace(fm,\"\"),reference:R.reference}),Ee=n.get(g);if(Ee)for(let ce of Ee)Fe.set(`${ce.name}${fm}`,ce.reference);(E!==U||E.linkType!==\"SOFT\"||!ae&&(!e.selfReferencesByCwd||e.selfReferencesByCwd.get(te)))&&L.dependencies.add(Ae);let De=R!==A&&E.linkType===\"SOFT\"&&!R.name.endsWith(fm)&&!ae;if(!ye&&!De){let ce=new Map;for(let[ne,ee]of Fe)if(ee!==null){let we=t.getLocator(ne,ee),xe=t.getLocator(ne.replace(fm,\"\"),ee),ht=t.getPackageInformation(xe);if(ht===null)throw new Error(\"Assertion failed: Expected the package to have been registered\");let H=jj(ht,we,t,p);if(e.validateExternalSoftLinks&&e.project&&H){ht.packageDependencies.size>0&&(o=!0);for(let[_e,Re]of ht.packageDependencies)if(Re!==null){let ze=W.parseLocator(Array.isArray(Re)?`${Re[0]}@${Re[1]}`:`${_e}@${Re}`);if(gA(ze)!==gA(we)){let He=Fe.get(_e);if(He){let b=W.parseLocator(Array.isArray(He)?`${He[0]}@${He[1]}`:`${_e}@${He}`);CIe(b,ze)||r.push({messageName:71,text:`Cannot link ${W.prettyIdent(e.project.configuration,W.parseIdent(we.name))} into ${W.prettyLocator(e.project.configuration,W.parseLocator(`${R.name}@${R.reference}`))} dependency ${W.prettyLocator(e.project.configuration,ze)} conflicts with parent dependency ${W.prettyLocator(e.project.configuration,b)}`})}else{let b=ce.get(_e);if(b){let w=b.target,S=W.parseLocator(Array.isArray(w)?`${w[0]}@${w[1]}`:`${_e}@${w}`);CIe(S,ze)||r.push({messageName:71,text:`Cannot link ${W.prettyIdent(e.project.configuration,W.parseIdent(we.name))} into ${W.prettyLocator(e.project.configuration,W.parseLocator(`${R.name}@${R.reference}`))} dependency ${W.prettyLocator(e.project.configuration,ze)} conflicts with dependency ${W.prettyLocator(e.project.configuration,S)} from sibling portal ${W.prettyIdent(e.project.configuration,W.parseIdent(b.portal.name))}`})}else ce.set(_e,{target:ze.reference,portal:we})}}}}let lt=e.hoistingLimitsByCwd?.get(te),Te=H?te:V.relative(p,ue.toPortablePath(ht.packageLocation))||Bt.dot,ke=e.hoistingLimitsByCwd?.get(Te);v(ne,ht,we,Ae,E,Fe,Te,lt===\"dependencies\"||ke===\"dependencies\"||ke===\"workspaces\")}}};return v(A.name,u,A,h,u,u.packageDependencies,Bt.dot,!1),{packageTree:h,hoistingLimits:a,errors:r,preserveSymlinksRequired:o}};function wIe(t,e,r){let o=r.resolveVirtual&&e.reference&&e.reference.startsWith(\"virtual:\")?r.resolveVirtual(t.packageLocation):t.packageLocation;return ue.toPortablePath(o||t.packageLocation)}function CIt(t,e,r){let o=e.getLocator(t.name.replace(fm,\"\"),t.reference),a=e.getPackageInformation(o);if(a===null)throw new Error(\"Assertion failed: Expected the package to be registered\");return r.pnpifyFs?{linkType:\"SOFT\",target:ue.toPortablePath(a.packageLocation)}:{linkType:a.linkType,target:wIe(a,t,e)}}var wIt=(t,e,r)=>{let o=new Map,a=(C,I,v)=>{let{linkType:x,target:E}=CIt(C,t,r);return{locator:gA(C),nodePath:I,target:E,linkType:x,aliases:v}},n=C=>{let[I,v]=C.split(\"/\");return v?{scope:I,name:v}:{scope:null,name:I}},u=new Set,A=(C,I,v)=>{if(u.has(C))return;u.add(C);let x=Array.from(C.references).sort().join(\"#\");for(let E of C.dependencies){let R=Array.from(E.references).sort().join(\"#\");if(E.identName===C.identName&&R===x)continue;let L=Array.from(E.references).sort(),U={name:E.identName,reference:L[0]},{name:z,scope:te}=n(E.name),le=te?[te,z]:[z],he=V.join(I,EIe),Ae=V.join(he,...le),ye=`${v}/${U.name}`,ae=a(U,v,L.slice(1)),Ie=!1;if(ae.linkType===\"SOFT\"&&r.project){let g=r.project.workspacesByCwd.get(ae.target.slice(0,-1));Ie=!!(g&&!g.manifest.name)}let Fe=ae.linkType===\"SOFT\"&&Ae.startsWith(ae.target);if(!E.name.endsWith(fm)&&!Ie&&!Fe){let g=o.get(Ae);if(g){if(g.dirList)throw new Error(`Assertion failed: ${Ae} cannot merge dir node with leaf node`);{let ce=W.parseLocator(g.locator),ne=W.parseLocator(ae.locator);if(g.linkType!==ae.linkType)throw new Error(`Assertion failed: ${Ae} cannot merge nodes with different link types ${g.nodePath}/${W.stringifyLocator(ce)} and ${v}/${W.stringifyLocator(ne)}`);if(ce.identHash!==ne.identHash)throw new Error(`Assertion failed: ${Ae} cannot merge nodes with different idents ${g.nodePath}/${W.stringifyLocator(ce)} and ${v}/s${W.stringifyLocator(ne)}`);ae.aliases=[...ae.aliases,...g.aliases,W.parseLocator(g.locator).reference]}}o.set(Ae,ae);let Ee=Ae.split(\"/\"),De=Ee.indexOf(EIe);for(let ce=Ee.length-1;De>=0&&ce>De;ce--){let ne=ue.toPortablePath(Ee.slice(0,ce).join(V.sep)),ee=Ee[ce],we=o.get(ne);if(!we)o.set(ne,{dirList:new Set([ee])});else if(we.dirList){if(we.dirList.has(ee))break;we.dirList.add(ee)}}}A(E,ae.linkType===\"SOFT\"?ae.target:Ae,ye)}},p=a({name:e.name,reference:Array.from(e.references)[0]},\"\",[]),h=p.target;return o.set(h,p),A(e,h,\"\"),o};Ye();Ye();Pt();Pt();nA();Nl();var cq={};Vt(cq,{PnpInstaller:()=>gm,PnpLinker:()=>D0,UnplugCommand:()=>S0,default:()=>XIt,getPnpPath:()=>P0,jsInstallUtils:()=>mA,pnpUtils:()=>av,quotePathIfNeeded:()=>s1e});Pt();var i1e=Be(\"url\");Ye();Ye();Pt();Pt();var IIe={[\"DEFAULT\"]:{collapsed:!1,next:{[\"*\"]:\"DEFAULT\"}},[\"TOP_LEVEL\"]:{collapsed:!1,next:{fallbackExclusionList:\"FALLBACK_EXCLUSION_LIST\",packageRegistryData:\"PACKAGE_REGISTRY_DATA\",[\"*\"]:\"DEFAULT\"}},[\"FALLBACK_EXCLUSION_LIST\"]:{collapsed:!1,next:{[\"*\"]:\"FALLBACK_EXCLUSION_ENTRIES\"}},[\"FALLBACK_EXCLUSION_ENTRIES\"]:{collapsed:!0,next:{[\"*\"]:\"FALLBACK_EXCLUSION_DATA\"}},[\"FALLBACK_EXCLUSION_DATA\"]:{collapsed:!0,next:{[\"*\"]:\"DEFAULT\"}},[\"PACKAGE_REGISTRY_DATA\"]:{collapsed:!1,next:{[\"*\"]:\"PACKAGE_REGISTRY_ENTRIES\"}},[\"PACKAGE_REGISTRY_ENTRIES\"]:{collapsed:!0,next:{[\"*\"]:\"PACKAGE_STORE_DATA\"}},[\"PACKAGE_STORE_DATA\"]:{collapsed:!1,next:{[\"*\"]:\"PACKAGE_STORE_ENTRIES\"}},[\"PACKAGE_STORE_ENTRIES\"]:{collapsed:!0,next:{[\"*\"]:\"PACKAGE_INFORMATION_DATA\"}},[\"PACKAGE_INFORMATION_DATA\"]:{collapsed:!1,next:{packageDependencies:\"PACKAGE_DEPENDENCIES\",[\"*\"]:\"DEFAULT\"}},[\"PACKAGE_DEPENDENCIES\"]:{collapsed:!1,next:{[\"*\"]:\"PACKAGE_DEPENDENCY\"}},[\"PACKAGE_DEPENDENCY\"]:{collapsed:!0,next:{[\"*\"]:\"DEFAULT\"}}};function IIt(t,e,r){let o=\"\";o+=\"[\";for(let a=0,n=t.length;a<n;++a)o+=wQ(String(a),t[a],e,r).replace(/^ +/g,\"\"),a+1<n&&(o+=\", \");return o+=\"]\",o}function BIt(t,e,r){let o=`${r}  `,a=\"\";a+=r,a+=`[\n`;for(let n=0,u=t.length;n<u;++n)a+=o+wQ(String(n),t[n],e,o).replace(/^ +/,\"\"),n+1<u&&(a+=\",\"),a+=`\n`;return a+=r,a+=\"]\",a}function vIt(t,e,r){let o=Object.keys(t),a=\"\";a+=\"{\";for(let n=0,u=o.length,A=0;n<u;++n){let p=o[n],h=t[p];typeof h>\"u\"||(A!==0&&(a+=\", \"),a+=JSON.stringify(p),a+=\": \",a+=wQ(p,h,e,r).replace(/^ +/g,\"\"),A+=1)}return a+=\"}\",a}function DIt(t,e,r){let o=Object.keys(t),a=`${r}  `,n=\"\";n+=r,n+=`{\n`;let u=0;for(let A=0,p=o.length;A<p;++A){let h=o[A],C=t[h];typeof C>\"u\"||(u!==0&&(n+=\",\",n+=`\n`),n+=a,n+=JSON.stringify(h),n+=\": \",n+=wQ(h,C,e,a).replace(/^ +/g,\"\"),u+=1)}return u!==0&&(n+=`\n`),n+=r,n+=\"}\",n}function wQ(t,e,r,o){let{next:a}=IIe[r],n=a[t]||a[\"*\"];return BIe(e,n,o)}function BIe(t,e,r){let{collapsed:o}=IIe[e];return Array.isArray(t)?o?IIt(t,e,r):BIt(t,e,r):typeof t==\"object\"&&t!==null?o?vIt(t,e,r):DIt(t,e,r):JSON.stringify(t)}function vIe(t){return BIe(t,\"TOP_LEVEL\",\"\")}function JB(t,e){let r=Array.from(t);Array.isArray(e)||(e=[e]);let o=[];for(let n of e)o.push(r.map(u=>n(u)));let a=r.map((n,u)=>u);return a.sort((n,u)=>{for(let A of o){let p=A[n]<A[u]?-1:A[n]>A[u]?1:0;if(p!==0)return p}return 0}),a.map(n=>r[n])}function PIt(t){let e=new Map,r=JB(t.fallbackExclusionList||[],[({name:o,reference:a})=>o,({name:o,reference:a})=>a]);for(let{name:o,reference:a}of r){let n=e.get(o);typeof n>\"u\"&&e.set(o,n=new Set),n.add(a)}return Array.from(e).map(([o,a])=>[o,Array.from(a)])}function SIt(t){return JB(t.fallbackPool||[],([e])=>e)}function bIt(t){let e=[];for(let[r,o]of JB(t.packageRegistry,([a])=>a===null?\"0\":`1${a}`)){let a=[];e.push([r,a]);for(let[n,{packageLocation:u,packageDependencies:A,packagePeers:p,linkType:h,discardFromLookup:C}]of JB(o,([I])=>I===null?\"0\":`1${I}`)){let I=[];r!==null&&n!==null&&!A.has(r)&&I.push([r,n]);for(let[E,R]of JB(A.entries(),([L])=>L))I.push([E,R]);let v=p&&p.size>0?Array.from(p):void 0,x=C||void 0;a.push([n,{packageLocation:u,packageDependencies:I,packagePeers:v,linkType:h,discardFromLookup:x}])}}return e}function XB(t){return{__info:[\"This file is automatically generated. Do not touch it, or risk\",\"your modifications being lost.\"],dependencyTreeRoots:t.dependencyTreeRoots,enableTopLevelFallback:t.enableTopLevelFallback||!1,ignorePatternData:t.ignorePattern||null,fallbackExclusionList:PIt(t),fallbackPool:SIt(t),packageRegistryData:bIt(t)}}var SIe=$e(PIe());function bIe(t,e){return[t?`${t}\n`:\"\",`/* eslint-disable */\n`,`\"use strict\";\n`,`\n`,e,`\n`,(0,SIe.default)()].join(\"\")}function xIt(t){return JSON.stringify(t,null,2)}function kIt(t){return`'${t.replace(/\\\\/g,\"\\\\\\\\\").replace(/'/g,\"\\\\'\").replace(/\\n/g,`\\\\\n`)}'`}function QIt(t){return[`const RAW_RUNTIME_STATE =\n`,`${kIt(vIe(t))};\n\n`,`function $$SETUP_STATE(hydrateRuntimeState, basePath) {\n`,`  return hydrateRuntimeState(JSON.parse(RAW_RUNTIME_STATE), {basePath: basePath || __dirname});\n`,`}\n`].join(\"\")}function FIt(){return[`function $$SETUP_STATE(hydrateRuntimeState, basePath) {\n`,`  const fs = require('fs');\n`,`  const path = require('path');\n`,`  const pnpDataFilepath = path.resolve(__dirname, ${JSON.stringify(dr.pnpData)});\n`,`  return hydrateRuntimeState(JSON.parse(fs.readFileSync(pnpDataFilepath, 'utf8')), {basePath: basePath || __dirname});\n`,`}\n`].join(\"\")}function xIe(t){let e=XB(t),r=QIt(e);return bIe(t.shebang,r)}function kIe(t){let e=XB(t),r=FIt(),o=bIe(t.shebang,r);return{dataFile:xIt(e),loaderFile:o}}Pt();function Yj(t,{basePath:e}){let r=ue.toPortablePath(e),o=V.resolve(r),a=t.ignorePatternData!==null?new RegExp(t.ignorePatternData):null,n=new Map,u=new Map(t.packageRegistryData.map(([I,v])=>[I,new Map(v.map(([x,E])=>{if(I===null!=(x===null))throw new Error(\"Assertion failed: The name and reference should be null, or neither should\");let R=E.discardFromLookup??!1,L={name:I,reference:x},U=n.get(E.packageLocation);U?(U.discardFromLookup=U.discardFromLookup&&R,R||(U.locator=L)):n.set(E.packageLocation,{locator:L,discardFromLookup:R});let z=null;return[x,{packageDependencies:new Map(E.packageDependencies),packagePeers:new Set(E.packagePeers),linkType:E.linkType,discardFromLookup:R,get packageLocation(){return z||(z=V.join(o,E.packageLocation))}}]}))])),A=new Map(t.fallbackExclusionList.map(([I,v])=>[I,new Set(v)])),p=new Map(t.fallbackPool),h=t.dependencyTreeRoots,C=t.enableTopLevelFallback;return{basePath:r,dependencyTreeRoots:h,enableTopLevelFallback:C,fallbackExclusionList:A,fallbackPool:p,ignorePattern:a,packageLocatorsByLocations:n,packageRegistry:u}}Pt();Pt();var tp=Be(\"module\"),hm=Be(\"url\"),rq=Be(\"util\");var Mo=Be(\"url\");var TIe=$e(Be(\"assert\"));var Wj=Array.isArray,ZB=JSON.stringify,$B=Object.getOwnPropertyNames,pm=(t,e)=>Object.prototype.hasOwnProperty.call(t,e),Kj=(t,e)=>RegExp.prototype.exec.call(t,e),Vj=(t,...e)=>RegExp.prototype[Symbol.replace].apply(t,e),B0=(t,...e)=>String.prototype.endsWith.apply(t,e),zj=(t,...e)=>String.prototype.includes.apply(t,e),Jj=(t,...e)=>String.prototype.lastIndexOf.apply(t,e),ev=(t,...e)=>String.prototype.indexOf.apply(t,e),QIe=(t,...e)=>String.prototype.replace.apply(t,e),v0=(t,...e)=>String.prototype.slice.apply(t,e),dA=(t,...e)=>String.prototype.startsWith.apply(t,e),FIe=Map,RIe=JSON.parse;function tv(t,e,r){return class extends r{constructor(...o){super(e(...o)),this.code=t,this.name=`${r.name} [${t}]`}}}var NIe=tv(\"ERR_PACKAGE_IMPORT_NOT_DEFINED\",(t,e,r)=>`Package import specifier \"${t}\" is not defined${e?` in package ${e}package.json`:\"\"} imported from ${r}`,TypeError),Xj=tv(\"ERR_INVALID_MODULE_SPECIFIER\",(t,e,r=void 0)=>`Invalid module \"${t}\" ${e}${r?` imported from ${r}`:\"\"}`,TypeError),LIe=tv(\"ERR_INVALID_PACKAGE_TARGET\",(t,e,r,o=!1,a=void 0)=>{let n=typeof r==\"string\"&&!o&&r.length&&!dA(r,\"./\");return e===\".\"?((0,TIe.default)(o===!1),`Invalid \"exports\" main target ${ZB(r)} defined in the package config ${t}package.json${a?` imported from ${a}`:\"\"}${n?'; targets must start with \"./\"':\"\"}`):`Invalid \"${o?\"imports\":\"exports\"}\" target ${ZB(r)} defined for '${e}' in the package config ${t}package.json${a?` imported from ${a}`:\"\"}${n?'; targets must start with \"./\"':\"\"}`},Error),rv=tv(\"ERR_INVALID_PACKAGE_CONFIG\",(t,e,r)=>`Invalid package config ${t}${e?` while importing ${e}`:\"\"}${r?`. ${r}`:\"\"}`,Error),OIe=tv(\"ERR_PACKAGE_PATH_NOT_EXPORTED\",(t,e,r=void 0)=>e===\".\"?`No \"exports\" main defined in ${t}package.json${r?` imported from ${r}`:\"\"}`:`Package subpath '${e}' is not defined by \"exports\" in ${t}package.json${r?` imported from ${r}`:\"\"}`,Error);var BQ=Be(\"url\");function MIe(t,e){let r=Object.create(null);for(let o=0;o<e.length;o++){let a=e[o];pm(t,a)&&(r[a]=t[a])}return r}var IQ=new FIe;function RIt(t,e,r,o){let a=IQ.get(t);if(a!==void 0)return a;let n=o(t);if(n===void 0){let x={pjsonPath:t,exists:!1,main:void 0,name:void 0,type:\"none\",exports:void 0,imports:void 0};return IQ.set(t,x),x}let u;try{u=RIe(n)}catch(x){throw new rv(t,(r?`\"${e}\" from `:\"\")+(0,BQ.fileURLToPath)(r||e),x.message)}let{imports:A,main:p,name:h,type:C}=MIe(u,[\"imports\",\"main\",\"name\",\"type\"]),I=pm(u,\"exports\")?u.exports:void 0;(typeof A!=\"object\"||A===null)&&(A=void 0),typeof p!=\"string\"&&(p=void 0),typeof h!=\"string\"&&(h=void 0),C!==\"module\"&&C!==\"commonjs\"&&(C=\"none\");let v={pjsonPath:t,exists:!0,main:p,name:h,type:C,exports:I,imports:A};return IQ.set(t,v),v}function UIe(t,e){let r=new URL(\"./package.json\",t);for(;;){let n=r.pathname;if(B0(n,\"node_modules/package.json\"))break;let u=RIt((0,BQ.fileURLToPath)(r),t,void 0,e);if(u.exists)return u;let A=r;if(r=new URL(\"../package.json\",r),r.pathname===A.pathname)break}let o=(0,BQ.fileURLToPath)(r),a={pjsonPath:o,exists:!1,main:void 0,name:void 0,type:\"none\",exports:void 0,imports:void 0};return IQ.set(o,a),a}function TIt(t,e,r){throw new NIe(t,e&&(0,Mo.fileURLToPath)(new URL(\".\",e)),(0,Mo.fileURLToPath)(r))}function NIt(t,e,r,o){let a=`request is not a valid subpath for the \"${r?\"imports\":\"exports\"}\" resolution of ${(0,Mo.fileURLToPath)(e)}`;throw new Xj(t,a,o&&(0,Mo.fileURLToPath)(o))}function nv(t,e,r,o,a){throw typeof e==\"object\"&&e!==null?e=ZB(e,null,\"\"):e=`${e}`,new LIe((0,Mo.fileURLToPath)(new URL(\".\",r)),t,e,o,a&&(0,Mo.fileURLToPath)(a))}var _Ie=/(^|\\\\|\\/)((\\.|%2e)(\\.|%2e)?|(n|%6e|%4e)(o|%6f|%4f)(d|%64|%44)(e|%65|%45)(_|%5f)(m|%6d|%4d)(o|%6f|%4f)(d|%64|%44)(u|%75|%55)(l|%6c|%4c)(e|%65|%45)(s|%73|%53))(\\\\|\\/|$)/i,HIe=/\\*/g;function LIt(t,e,r,o,a,n,u,A){if(e!==\"\"&&!n&&t[t.length-1]!==\"/\"&&nv(r,t,o,u,a),!dA(t,\"./\")){if(u&&!dA(t,\"../\")&&!dA(t,\"/\")){let I=!1;try{new URL(t),I=!0}catch{}if(!I)return n?Vj(HIe,t,()=>e):t+e}nv(r,t,o,u,a)}Kj(_Ie,v0(t,2))!==null&&nv(r,t,o,u,a);let p=new URL(t,o),h=p.pathname,C=new URL(\".\",o).pathname;if(dA(h,C)||nv(r,t,o,u,a),e===\"\")return p;if(Kj(_Ie,e)!==null){let I=n?QIe(r,\"*\",()=>e):r+e;NIt(I,o,u,a)}return n?new URL(Vj(HIe,p.href,()=>e)):new URL(e,p)}function OIt(t){let e=+t;return`${e}`!==t?!1:e>=0&&e<4294967295}function jC(t,e,r,o,a,n,u,A){if(typeof e==\"string\")return LIt(e,r,o,t,a,n,u,A);if(Wj(e)){if(e.length===0)return null;let p;for(let h=0;h<e.length;h++){let C=e[h],I;try{I=jC(t,C,r,o,a,n,u,A)}catch(v){if(p=v,v.code===\"ERR_INVALID_PACKAGE_TARGET\")continue;throw v}if(I!==void 0){if(I===null){p=null;continue}return I}}if(p==null)return p;throw p}else if(typeof e==\"object\"&&e!==null){let p=$B(e);for(let h=0;h<p.length;h++){let C=p[h];if(OIt(C))throw new rv((0,Mo.fileURLToPath)(t),a,'\"exports\" cannot contain numeric property keys.')}for(let h=0;h<p.length;h++){let C=p[h];if(C===\"default\"||A.has(C)){let I=e[C],v=jC(t,I,r,o,a,n,u,A);if(v===void 0)continue;return v}}return}else if(e===null)return null;nv(o,e,t,u,a)}function qIe(t,e){let r=ev(t,\"*\"),o=ev(e,\"*\"),a=r===-1?t.length:r+1,n=o===-1?e.length:o+1;return a>n?-1:n>a||r===-1?1:o===-1||t.length>e.length?-1:e.length>t.length?1:0}function MIt(t,e,r){if(typeof t==\"string\"||Wj(t))return!0;if(typeof t!=\"object\"||t===null)return!1;let o=$B(t),a=!1,n=0;for(let u=0;u<o.length;u++){let A=o[u],p=A===\"\"||A[0]!==\".\";if(n++===0)a=p;else if(a!==p)throw new rv((0,Mo.fileURLToPath)(e),r,`\"exports\" cannot contain some keys starting with '.' and some not. The exports object must either be an object of package subpath keys or an object of main entry condition name keys only.`)}return a}function Zj(t,e,r){throw new OIe((0,Mo.fileURLToPath)(new URL(\".\",e)),t,r&&(0,Mo.fileURLToPath)(r))}var jIe=new Set;function UIt(t,e,r){let o=(0,Mo.fileURLToPath)(e);jIe.has(o+\"|\"+t)||(jIe.add(o+\"|\"+t),process.emitWarning(`Use of deprecated trailing slash pattern mapping \"${t}\" in the \"exports\" field module resolution of the package at ${o}${r?` imported from ${(0,Mo.fileURLToPath)(r)}`:\"\"}. Mapping specifiers ending in \"/\" is no longer supported.`,\"DeprecationWarning\",\"DEP0155\"))}function GIe({packageJSONUrl:t,packageSubpath:e,exports:r,base:o,conditions:a}){if(MIt(r,t,o)&&(r={\".\":r}),pm(r,e)&&!zj(e,\"*\")&&!B0(e,\"/\")){let p=r[e],h=jC(t,p,\"\",e,o,!1,!1,a);return h==null&&Zj(e,t,o),h}let n=\"\",u,A=$B(r);for(let p=0;p<A.length;p++){let h=A[p],C=ev(h,\"*\");if(C!==-1&&dA(e,v0(h,0,C))){B0(e,\"/\")&&UIt(e,t,o);let I=v0(h,C+1);e.length>=h.length&&B0(e,I)&&qIe(n,h)===1&&Jj(h,\"*\")===C&&(n=h,u=v0(e,C,e.length-I.length))}}if(n){let p=r[n],h=jC(t,p,u,n,o,!0,!1,a);return h==null&&Zj(e,t,o),h}Zj(e,t,o)}function YIe({name:t,base:e,conditions:r,readFileSyncFn:o}){if(t===\"#\"||dA(t,\"#/\")||B0(t,\"/\")){let u=\"is not a valid internal imports specifier name\";throw new Xj(t,u,(0,Mo.fileURLToPath)(e))}let a,n=UIe(e,o);if(n.exists){a=(0,Mo.pathToFileURL)(n.pjsonPath);let u=n.imports;if(u)if(pm(u,t)&&!zj(t,\"*\")){let A=jC(a,u[t],\"\",t,e,!1,!0,r);if(A!=null)return A}else{let A=\"\",p,h=$B(u);for(let C=0;C<h.length;C++){let I=h[C],v=ev(I,\"*\");if(v!==-1&&dA(t,v0(I,0,v))){let x=v0(I,v+1);t.length>=I.length&&B0(t,x)&&qIe(A,I)===1&&Jj(I,\"*\")===v&&(A=I,p=v0(t,v,t.length-x.length))}}if(A){let C=u[A],I=jC(a,C,p,A,e,!0,!0,r);if(I!=null)return I}}}TIt(t,a,e)}Pt();var _It=new Set([\"BUILTIN_NODE_RESOLUTION_FAILED\",\"MISSING_DEPENDENCY\",\"MISSING_PEER_DEPENDENCY\",\"QUALIFIED_PATH_RESOLUTION_FAILED\",\"UNDECLARED_DEPENDENCY\"]);function $i(t,e,r={},o){o??=_It.has(t)?\"MODULE_NOT_FOUND\":t;let a={configurable:!0,writable:!0,enumerable:!1};return Object.defineProperties(new Error(e),{code:{...a,value:o},pnpCode:{...a,value:t},data:{...a,value:r}})}function au(t){return ue.normalize(ue.fromPortablePath(t))}var zIe=$e(KIe());function JIe(t){return HIt(),eq[t]}var eq;function HIt(){eq||(eq={\"--conditions\":[],...VIe(jIt()),...VIe(process.execArgv)})}function VIe(t){return(0,zIe.default)({\"--conditions\":[String],\"-C\":\"--conditions\"},{argv:t,permissive:!0})}function jIt(){let t=[],e=qIt(process.env.NODE_OPTIONS||\"\",t);return t.length,e}function qIt(t,e){let r=[],o=!1,a=!0;for(let n=0;n<t.length;++n){let u=t[n];if(u===\"\\\\\"&&o){if(n+1===t.length)return e.push(`invalid value for NODE_OPTIONS (invalid escape)\n`),r;u=t[++n]}else if(u===\" \"&&!o){a=!0;continue}else if(u==='\"'){o=!o;continue}a?(r.push(u),a=!1):r[r.length-1]+=u}return o&&e.push(`invalid value for NODE_OPTIONS (unterminated string)\n`),r}Pt();var[sv,tq]=process.versions.node.split(\".\").map(t=>parseInt(t,10)),XIe=sv>19||sv===19&&tq>=2||sv===18&&tq>=13,BJt=sv>19||sv===19&&tq>=3;function ZIe(t){if(process.env.WATCH_REPORT_DEPENDENCIES&&process.send)if(t=t.map(e=>ue.fromPortablePath(mi.resolveVirtual(ue.toPortablePath(e)))),XIe)process.send({\"watch:require\":t});else for(let e of t)process.send({\"watch:require\":e})}function nq(t,e){let r=Number(process.env.PNP_ALWAYS_WARN_ON_FALLBACK)>0,o=Number(process.env.PNP_DEBUG_LEVEL),a=/^(?![a-zA-Z]:[\\\\/]|\\\\\\\\|\\.{0,2}(?:\\/|$))((?:node:)?(?:@[^/]+\\/)?[^/]+)\\/*(.*|)$/,n=/^(\\/|\\.{1,2}(\\/|$))/,u=/\\/$/,A=/^\\.{0,2}\\//,p={name:null,reference:null},h=[],C=new Set;if(t.enableTopLevelFallback===!0&&h.push(p),e.compatibilityMode!==!1)for(let Te of[\"react-scripts\",\"gatsby\"]){let ke=t.packageRegistry.get(Te);if(ke)for(let be of ke.keys()){if(be===null)throw new Error(\"Assertion failed: This reference shouldn't be null\");h.push({name:Te,reference:be})}}let{ignorePattern:I,packageRegistry:v,packageLocatorsByLocations:x}=t;function E(Te,ke){return{fn:Te,args:ke,error:null,result:null}}function R(Te){let ke=process.stderr?.hasColors?.()??process.stdout.isTTY,be=(ze,He)=>`\\x1B[${ze}m${He}\\x1B[0m`,_e=Te.error;console.error(_e?be(\"31;1\",`\\u2716 ${Te.error?.message.replace(/\\n.*/s,\"\")}`):be(\"33;1\",\"\\u203C Resolution\")),Te.args.length>0&&console.error();for(let ze of Te.args)console.error(`  ${be(\"37;1\",\"In \\u2190\")} ${(0,rq.inspect)(ze,{colors:ke,compact:!0})}`);Te.result&&(console.error(),console.error(`  ${be(\"37;1\",\"Out \\u2192\")} ${(0,rq.inspect)(Te.result,{colors:ke,compact:!0})}`));let Re=new Error().stack.match(/(?<=^ +)at.*/gm)?.slice(2)??[];if(Re.length>0){console.error();for(let ze of Re)console.error(`  ${be(\"38;5;244\",ze)}`)}console.error()}function L(Te,ke){if(e.allowDebug===!1)return ke;if(Number.isFinite(o)){if(o>=2)return(...be)=>{let _e=E(Te,be);try{return _e.result=ke(...be)}catch(Re){throw _e.error=Re}finally{R(_e)}};if(o>=1)return(...be)=>{try{return ke(...be)}catch(_e){let Re=E(Te,be);throw Re.error=_e,R(Re),_e}}}return ke}function U(Te){let ke=g(Te);if(!ke)throw $i(\"INTERNAL\",\"Couldn't find a matching entry in the dependency tree for the specified parent (this is probably an internal error)\");return ke}function z(Te){if(Te.name===null)return!0;for(let ke of t.dependencyTreeRoots)if(ke.name===Te.name&&ke.reference===Te.reference)return!0;return!1}let te=new Set([\"node\",\"require\",...JIe(\"--conditions\")]);function le(Te,ke=te,be){let _e=ce(V.join(Te,\"internal.js\"),{resolveIgnored:!0,includeDiscardFromLookup:!0});if(_e===null)throw $i(\"INTERNAL\",`The locator that owns the \"${Te}\" path can't be found inside the dependency tree (this is probably an internal error)`);let{packageLocation:Re}=U(_e),ze=V.join(Re,dr.manifest);if(!e.fakeFs.existsSync(ze))return null;let He=JSON.parse(e.fakeFs.readFileSync(ze,\"utf8\"));if(He.exports==null)return null;let b=V.contains(Re,Te);if(b===null)throw $i(\"INTERNAL\",\"unqualifiedPath doesn't contain the packageLocation (this is probably an internal error)\");b!==\".\"&&!A.test(b)&&(b=`./${b}`);try{let w=GIe({packageJSONUrl:(0,hm.pathToFileURL)(ue.fromPortablePath(ze)),packageSubpath:b,exports:He.exports,base:be?(0,hm.pathToFileURL)(ue.fromPortablePath(be)):null,conditions:ke});return ue.toPortablePath((0,hm.fileURLToPath)(w))}catch(w){throw $i(\"EXPORTS_RESOLUTION_FAILED\",w.message,{unqualifiedPath:au(Te),locator:_e,pkgJson:He,subpath:au(b),conditions:ke},w.code)}}function he(Te,ke,{extensions:be}){let _e;try{ke.push(Te),_e=e.fakeFs.statSync(Te)}catch{}if(_e&&!_e.isDirectory())return e.fakeFs.realpathSync(Te);if(_e&&_e.isDirectory()){let Re;try{Re=JSON.parse(e.fakeFs.readFileSync(V.join(Te,dr.manifest),\"utf8\"))}catch{}let ze;if(Re&&Re.main&&(ze=V.resolve(Te,Re.main)),ze&&ze!==Te){let He=he(ze,ke,{extensions:be});if(He!==null)return He}}for(let Re=0,ze=be.length;Re<ze;Re++){let He=`${Te}${be[Re]}`;if(ke.push(He),e.fakeFs.existsSync(He))return He}if(_e&&_e.isDirectory())for(let Re=0,ze=be.length;Re<ze;Re++){let He=V.format({dir:Te,name:\"index\",ext:be[Re]});if(ke.push(He),e.fakeFs.existsSync(He))return He}return null}function Ae(Te){let ke=new tp.Module(Te,null);return ke.filename=Te,ke.paths=tp.Module._nodeModulePaths(Te),ke}function ye(Te,ke){return ke.endsWith(\"/\")&&(ke=V.join(ke,\"internal.js\")),tp.Module._resolveFilename(ue.fromPortablePath(Te),Ae(ue.fromPortablePath(ke)),!1,{plugnplay:!1})}function ae(Te){if(I===null)return!1;let ke=V.contains(t.basePath,Te);return ke===null?!1:!!I.test(ke.replace(/\\/$/,\"\"))}let Ie={std:3,resolveVirtual:1,getAllLocators:1},Fe=p;function g({name:Te,reference:ke}){let be=v.get(Te);if(!be)return null;let _e=be.get(ke);return _e||null}function Ee({name:Te,reference:ke}){let be=[];for(let[_e,Re]of v)if(_e!==null)for(let[ze,He]of Re)ze===null||He.packageDependencies.get(Te)!==ke||_e===Te&&ze===ke||be.push({name:_e,reference:ze});return be}function De(Te,ke){let be=new Map,_e=new Set,Re=He=>{let b=JSON.stringify(He.name);if(_e.has(b))return;_e.add(b);let w=Ee(He);for(let S of w)if(U(S).packagePeers.has(Te))Re(S);else{let F=be.get(S.name);typeof F>\"u\"&&be.set(S.name,F=new Set),F.add(S.reference)}};Re(ke);let ze=[];for(let He of[...be.keys()].sort())for(let b of[...be.get(He)].sort())ze.push({name:He,reference:b});return ze}function ce(Te,{resolveIgnored:ke=!1,includeDiscardFromLookup:be=!1}={}){if(ae(Te)&&!ke)return null;let _e=V.relative(t.basePath,Te);_e.match(n)||(_e=`./${_e}`),_e.endsWith(\"/\")||(_e=`${_e}/`);do{let Re=x.get(_e);if(typeof Re>\"u\"||Re.discardFromLookup&&!be){_e=_e.substring(0,_e.lastIndexOf(\"/\",_e.length-2)+1);continue}return Re.locator}while(_e!==\"\");return null}function ne(Te){try{return e.fakeFs.readFileSync(ue.toPortablePath(Te),\"utf8\")}catch(ke){if(ke.code===\"ENOENT\")return;throw ke}}function ee(Te,ke,{considerBuiltins:be=!0}={}){if(Te.startsWith(\"#\"))throw new Error(\"resolveToUnqualified can not handle private import mappings\");if(Te===\"pnpapi\")return ue.toPortablePath(e.pnpapiResolution);if(be&&(0,tp.isBuiltin)(Te))return null;let _e=au(Te),Re=ke&&au(ke);if(ke&&ae(ke)&&(!V.isAbsolute(Te)||ce(Te)===null)){let b=ye(Te,ke);if(b===!1)throw $i(\"BUILTIN_NODE_RESOLUTION_FAILED\",`The builtin node resolution algorithm was unable to resolve the requested module (it didn't go through the pnp resolver because the issuer was explicitely ignored by the regexp)\n\nRequire request: \"${_e}\"\nRequired by: ${Re}\n`,{request:_e,issuer:Re});return ue.toPortablePath(b)}let ze,He=Te.match(a);if(He){if(!ke)throw $i(\"API_ERROR\",\"The resolveToUnqualified function must be called with a valid issuer when the path isn't a builtin nor absolute\",{request:_e,issuer:Re});let[,b,w]=He,S=ce(ke);if(!S){let Ne=ye(Te,ke);if(Ne===!1)throw $i(\"BUILTIN_NODE_RESOLUTION_FAILED\",`The builtin node resolution algorithm was unable to resolve the requested module (it didn't go through the pnp resolver because the issuer doesn't seem to be part of the Yarn-managed dependency tree).\n\nRequire path: \"${_e}\"\nRequired by: ${Re}\n`,{request:_e,issuer:Re});return ue.toPortablePath(Ne)}let F=U(S).packageDependencies.get(b),J=null;if(F==null&&S.name!==null){let Ne=t.fallbackExclusionList.get(S.name);if(!Ne||!Ne.has(S.reference)){for(let dt=0,jt=h.length;dt<jt;++dt){let bt=U(h[dt]).packageDependencies.get(b);if(bt!=null){r?J=bt:F=bt;break}}if(t.enableTopLevelFallback&&F==null&&J===null){let dt=t.fallbackPool.get(b);dt!=null&&(J=dt)}}}let X=null;if(F===null)if(z(S))X=$i(\"MISSING_PEER_DEPENDENCY\",`Your application tried to access ${b} (a peer dependency); this isn't allowed as there is no ancestor to satisfy the requirement. Use a devDependency if needed.\n\nRequired package: ${b}${b!==_e?` (via \"${_e}\")`:\"\"}\nRequired by: ${Re}\n`,{request:_e,issuer:Re,dependencyName:b});else{let Ne=De(b,S);Ne.every(ot=>z(ot))?X=$i(\"MISSING_PEER_DEPENDENCY\",`${S.name} tried to access ${b} (a peer dependency) but it isn't provided by your application; this makes the require call ambiguous and unsound.\n\nRequired package: ${b}${b!==_e?` (via \"${_e}\")`:\"\"}\nRequired by: ${S.name}@${S.reference} (via ${Re})\n${Ne.map(ot=>`Ancestor breaking the chain: ${ot.name}@${ot.reference}\n`).join(\"\")}\n`,{request:_e,issuer:Re,issuerLocator:Object.assign({},S),dependencyName:b,brokenAncestors:Ne}):X=$i(\"MISSING_PEER_DEPENDENCY\",`${S.name} tried to access ${b} (a peer dependency) but it isn't provided by its ancestors; this makes the require call ambiguous and unsound.\n\nRequired package: ${b}${b!==_e?` (via \"${_e}\")`:\"\"}\nRequired by: ${S.name}@${S.reference} (via ${Re})\n\n${Ne.map(ot=>`Ancestor breaking the chain: ${ot.name}@${ot.reference}\n`).join(\"\")}\n`,{request:_e,issuer:Re,issuerLocator:Object.assign({},S),dependencyName:b,brokenAncestors:Ne})}else F===void 0&&(!be&&(0,tp.isBuiltin)(Te)?z(S)?X=$i(\"UNDECLARED_DEPENDENCY\",`Your application tried to access ${b}. While this module is usually interpreted as a Node builtin, your resolver is running inside a non-Node resolution context where such builtins are ignored. Since ${b} isn't otherwise declared in your dependencies, this makes the require call ambiguous and unsound.\n\nRequired package: ${b}${b!==_e?` (via \"${_e}\")`:\"\"}\nRequired by: ${Re}\n`,{request:_e,issuer:Re,dependencyName:b}):X=$i(\"UNDECLARED_DEPENDENCY\",`${S.name} tried to access ${b}. While this module is usually interpreted as a Node builtin, your resolver is running inside a non-Node resolution context where such builtins are ignored. Since ${b} isn't otherwise declared in ${S.name}'s dependencies, this makes the require call ambiguous and unsound.\n\nRequired package: ${b}${b!==_e?` (via \"${_e}\")`:\"\"}\nRequired by: ${Re}\n`,{request:_e,issuer:Re,issuerLocator:Object.assign({},S),dependencyName:b}):z(S)?X=$i(\"UNDECLARED_DEPENDENCY\",`Your application tried to access ${b}, but it isn't declared in your dependencies; this makes the require call ambiguous and unsound.\n\nRequired package: ${b}${b!==_e?` (via \"${_e}\")`:\"\"}\nRequired by: ${Re}\n`,{request:_e,issuer:Re,dependencyName:b}):X=$i(\"UNDECLARED_DEPENDENCY\",`${S.name} tried to access ${b}, but it isn't declared in its dependencies; this makes the require call ambiguous and unsound.\n\nRequired package: ${b}${b!==_e?` (via \"${_e}\")`:\"\"}\nRequired by: ${S.name}@${S.reference} (via ${Re})\n`,{request:_e,issuer:Re,issuerLocator:Object.assign({},S),dependencyName:b}));if(F==null){if(J===null||X===null)throw X||new Error(\"Assertion failed: Expected an error to have been set\");F=J;let Ne=X.message.replace(/\\n.*/g,\"\");X.message=Ne,!C.has(Ne)&&o!==0&&(C.add(Ne),process.emitWarning(X))}let Z=Array.isArray(F)?{name:F[0],reference:F[1]}:{name:b,reference:F},ie=U(Z);if(!ie.packageLocation)throw $i(\"MISSING_DEPENDENCY\",`A dependency seems valid but didn't get installed for some reason. This might be caused by a partial install, such as dev vs prod.\n\nRequired package: ${Z.name}@${Z.reference}${Z.name!==_e?` (via \"${_e}\")`:\"\"}\nRequired by: ${S.name}@${S.reference} (via ${Re})\n`,{request:_e,issuer:Re,dependencyLocator:Object.assign({},Z)});let Pe=ie.packageLocation;w?ze=V.join(Pe,w):ze=Pe}else if(V.isAbsolute(Te))ze=V.normalize(Te);else{if(!ke)throw $i(\"API_ERROR\",\"The resolveToUnqualified function must be called with a valid issuer when the path isn't a builtin nor absolute\",{request:_e,issuer:Re});let b=V.resolve(ke);ke.match(u)?ze=V.normalize(V.join(b,Te)):ze=V.normalize(V.join(V.dirname(b),Te))}return V.normalize(ze)}function we(Te,ke,be=te,_e){if(n.test(Te))return ke;let Re=le(ke,be,_e);return Re?V.normalize(Re):ke}function xe(Te,{extensions:ke=Object.keys(tp.Module._extensions)}={}){let be=[],_e=he(Te,be,{extensions:ke});if(_e)return V.normalize(_e);{ZIe(be.map(He=>ue.fromPortablePath(He)));let Re=au(Te),ze=ce(Te);if(ze){let{packageLocation:He}=U(ze),b=!0;try{e.fakeFs.accessSync(He)}catch(w){if(w?.code===\"ENOENT\")b=!1;else{let S=(w?.message??w??\"empty exception thrown\").replace(/^[A-Z]/,y=>y.toLowerCase());throw $i(\"QUALIFIED_PATH_RESOLUTION_FAILED\",`Required package exists but could not be accessed (${S}).\n\nMissing package: ${ze.name}@${ze.reference}\nExpected package location: ${au(He)}\n`,{unqualifiedPath:Re,extensions:ke})}}if(!b){let w=He.includes(\"/unplugged/\")?\"Required unplugged package missing from disk. This may happen when switching branches without running installs (unplugged packages must be fully materialized on disk to work).\":\"Required package missing from disk. If you keep your packages inside your repository then restarting the Node process may be enough. Otherwise, try to run an install first.\";throw $i(\"QUALIFIED_PATH_RESOLUTION_FAILED\",`${w}\n\nMissing package: ${ze.name}@${ze.reference}\nExpected package location: ${au(He)}\n`,{unqualifiedPath:Re,extensions:ke})}}throw $i(\"QUALIFIED_PATH_RESOLUTION_FAILED\",`Qualified path resolution failed: we looked for the following paths, but none could be accessed.\n\nSource path: ${Re}\n${be.map(He=>`Not found: ${au(He)}\n`).join(\"\")}`,{unqualifiedPath:Re,extensions:ke})}}function ht(Te,ke,be){if(!ke)throw new Error(\"Assertion failed: An issuer is required to resolve private import mappings\");let _e=YIe({name:Te,base:(0,hm.pathToFileURL)(ue.fromPortablePath(ke)),conditions:be.conditions??te,readFileSyncFn:ne});if(_e instanceof URL)return xe(ue.toPortablePath((0,hm.fileURLToPath)(_e)),{extensions:be.extensions});if(_e.startsWith(\"#\"))throw new Error(\"Mapping from one private import to another isn't allowed\");return H(_e,ke,be)}function H(Te,ke,be={}){try{if(Te.startsWith(\"#\"))return ht(Te,ke,be);let{considerBuiltins:_e,extensions:Re,conditions:ze}=be,He=ee(Te,ke,{considerBuiltins:_e});if(Te===\"pnpapi\")return He;if(He===null)return null;let b=()=>ke!==null?ae(ke):!1,w=(!_e||!(0,tp.isBuiltin)(Te))&&!b()?we(Te,He,ze,ke):He;return xe(w,{extensions:Re})}catch(_e){throw Object.hasOwn(_e,\"pnpCode\")&&Object.assign(_e.data,{request:au(Te),issuer:ke&&au(ke)}),_e}}function lt(Te){let ke=V.normalize(Te),be=mi.resolveVirtual(ke);return be!==ke?be:null}return{VERSIONS:Ie,topLevel:Fe,getLocator:(Te,ke)=>Array.isArray(ke)?{name:ke[0],reference:ke[1]}:{name:Te,reference:ke},getDependencyTreeRoots:()=>[...t.dependencyTreeRoots],getAllLocators(){let Te=[];for(let[ke,be]of v)for(let _e of be.keys())ke!==null&&_e!==null&&Te.push({name:ke,reference:_e});return Te},getPackageInformation:Te=>{let ke=g(Te);if(ke===null)return null;let be=ue.fromPortablePath(ke.packageLocation);return{...ke,packageLocation:be}},findPackageLocator:Te=>ce(ue.toPortablePath(Te)),resolveToUnqualified:L(\"resolveToUnqualified\",(Te,ke,be)=>{let _e=ke!==null?ue.toPortablePath(ke):null,Re=ee(ue.toPortablePath(Te),_e,be);return Re===null?null:ue.fromPortablePath(Re)}),resolveUnqualified:L(\"resolveUnqualified\",(Te,ke)=>ue.fromPortablePath(xe(ue.toPortablePath(Te),ke))),resolveRequest:L(\"resolveRequest\",(Te,ke,be)=>{let _e=ke!==null?ue.toPortablePath(ke):null,Re=H(ue.toPortablePath(Te),_e,be);return Re===null?null:ue.fromPortablePath(Re)}),resolveVirtual:L(\"resolveVirtual\",Te=>{let ke=lt(ue.toPortablePath(Te));return ke!==null?ue.fromPortablePath(ke):null})}}Pt();var $Ie=(t,e,r)=>{let o=XB(t),a=Yj(o,{basePath:e}),n=ue.join(e,dr.pnpCjs);return nq(a,{fakeFs:r,pnpapiResolution:n})};var sq=$e(t1e());qt();var mA={};Vt(mA,{checkManifestCompatibility:()=>r1e,extractBuildRequest:()=>vQ,getExtractHint:()=>oq,hasBindingGyp:()=>aq});Ye();Pt();function r1e(t){return W.isPackageCompatible(t,zi.getArchitectureSet())}function vQ(t,e,r,{configuration:o}){let a=[];for(let n of[\"preinstall\",\"install\",\"postinstall\"])e.manifest.scripts.has(n)&&a.push({type:0,script:n});return!e.manifest.scripts.has(\"install\")&&e.misc.hasBindingGyp&&a.push({type:1,script:\"node-gyp rebuild\"}),a.length===0?null:t.linkType!==\"HARD\"?{skipped:!0,explain:n=>n.reportWarningOnce(6,`${W.prettyLocator(o,t)} lists build scripts, but is referenced through a soft link. Soft links don't support build scripts, so they'll be ignored.`)}:r&&r.built===!1?{skipped:!0,explain:n=>n.reportInfoOnce(5,`${W.prettyLocator(o,t)} lists build scripts, but its build has been explicitly disabled through configuration.`)}:!o.get(\"enableScripts\")&&!r.built?{skipped:!0,explain:n=>n.reportWarningOnce(4,`${W.prettyLocator(o,t)} lists build scripts, but all build scripts have been disabled.`)}:r1e(t)?{skipped:!1,directives:a}:{skipped:!0,explain:n=>n.reportWarningOnce(76,`${W.prettyLocator(o,t)} The ${zi.getArchitectureName()} architecture is incompatible with this package, build skipped.`)}}var YIt=new Set([\".exe\",\".bin\",\".h\",\".hh\",\".hpp\",\".c\",\".cc\",\".cpp\",\".java\",\".jar\",\".node\"]);function oq(t){return t.packageFs.getExtractHint({relevantExtensions:YIt})}function aq(t){let e=V.join(t.prefixPath,\"binding.gyp\");return t.packageFs.existsSync(e)}var av={};Vt(av,{getUnpluggedPath:()=>ov});Ye();Pt();function ov(t,{configuration:e}){return V.resolve(e.get(\"pnpUnpluggedFolder\"),W.slugifyLocator(t))}var WIt=new Set([W.makeIdent(null,\"open\").identHash,W.makeIdent(null,\"opn\").identHash]),D0=class{constructor(){this.mode=\"strict\";this.pnpCache=new Map}getCustomDataKey(){return JSON.stringify({name:\"PnpLinker\",version:2})}supportsPackage(e,r){return this.isEnabled(r)}async findPackageLocation(e,r){if(!this.isEnabled(r))throw new Error(\"Assertion failed: Expected the PnP linker to be enabled\");let o=P0(r.project).cjs;if(!oe.existsSync(o))throw new it(`The project in ${de.pretty(r.project.configuration,`${r.project.cwd}/package.json`,de.Type.PATH)} doesn't seem to have been installed - running an install there might help`);let a=je.getFactoryWithDefault(this.pnpCache,o,()=>je.dynamicRequire(o,{cachingStrategy:je.CachingStrategy.FsTime})),n={name:W.stringifyIdent(e),reference:e.reference},u=a.getPackageInformation(n);if(!u)throw new it(`Couldn't find ${W.prettyLocator(r.project.configuration,e)} in the currently installed PnP map - running an install might help`);return ue.toPortablePath(u.packageLocation)}async findPackageLocator(e,r){if(!this.isEnabled(r))return null;let o=P0(r.project).cjs;if(!oe.existsSync(o))return null;let n=je.getFactoryWithDefault(this.pnpCache,o,()=>je.dynamicRequire(o,{cachingStrategy:je.CachingStrategy.FsTime})).findPackageLocator(ue.fromPortablePath(e));return n?W.makeLocator(W.parseIdent(n.name),n.reference):null}makeInstaller(e){return new gm(e)}isEnabled(e){return!(e.project.configuration.get(\"nodeLinker\")!==\"pnp\"||e.project.configuration.get(\"pnpMode\")!==this.mode)}},gm=class{constructor(e){this.opts=e;this.mode=\"strict\";this.asyncActions=new je.AsyncActions(10);this.packageRegistry=new Map;this.virtualTemplates=new Map;this.isESMLoaderRequired=!1;this.customData={store:new Map};this.unpluggedPaths=new Set;this.opts=e}attachCustomData(e){this.customData=e}async installPackage(e,r,o){let a=W.stringifyIdent(e),n=e.reference,u=!!this.opts.project.tryWorkspaceByLocator(e),A=W.isVirtualLocator(e),p=e.peerDependencies.size>0&&!A,h=!p&&!u,C=!p&&e.linkType!==\"SOFT\",I,v;if(h||C){let te=A?W.devirtualizeLocator(e):e;I=this.customData.store.get(te.locatorHash),typeof I>\"u\"&&(I=await KIt(r),e.linkType===\"HARD\"&&this.customData.store.set(te.locatorHash,I)),I.manifest.type===\"module\"&&(this.isESMLoaderRequired=!0),v=this.opts.project.getDependencyMeta(te,e.version)}let x=h?vQ(e,I,v,{configuration:this.opts.project.configuration}):null,E=C?await this.unplugPackageIfNeeded(e,I,r,v,o):r.packageFs;if(V.isAbsolute(r.prefixPath))throw new Error(`Assertion failed: Expected the prefix path (${r.prefixPath}) to be relative to the parent`);let R=V.resolve(E.getRealPath(),r.prefixPath),L=lq(this.opts.project.cwd,R),U=new Map,z=new Set;if(A){for(let te of e.peerDependencies.values())U.set(W.stringifyIdent(te),null),z.add(W.stringifyIdent(te));if(!u){let te=W.devirtualizeLocator(e);this.virtualTemplates.set(te.locatorHash,{location:lq(this.opts.project.cwd,mi.resolveVirtual(R)),locator:te})}}return je.getMapWithDefault(this.packageRegistry,a).set(n,{packageLocation:L,packageDependencies:U,packagePeers:z,linkType:e.linkType,discardFromLookup:r.discardFromLookup||!1}),{packageLocation:R,buildRequest:x}}async attachInternalDependencies(e,r){let o=this.getPackageInformation(e);for(let[a,n]of r){let u=W.areIdentsEqual(a,n)?n.reference:[W.stringifyIdent(n),n.reference];o.packageDependencies.set(W.stringifyIdent(a),u)}}async attachExternalDependents(e,r){for(let o of r)this.getDiskInformation(o).packageDependencies.set(W.stringifyIdent(e),e.reference)}async finalizeInstall(){if(this.opts.project.configuration.get(\"pnpMode\")!==this.mode)return;let e=P0(this.opts.project);if(this.isEsmEnabled()||await oe.removePromise(e.esmLoader),this.opts.project.configuration.get(\"nodeLinker\")!==\"pnp\"){await oe.removePromise(e.cjs),await oe.removePromise(e.data),await oe.removePromise(e.esmLoader),await oe.removePromise(this.opts.project.configuration.get(\"pnpUnpluggedFolder\"));return}for(let{locator:C,location:I}of this.virtualTemplates.values())je.getMapWithDefault(this.packageRegistry,W.stringifyIdent(C)).set(C.reference,{packageLocation:I,packageDependencies:new Map,packagePeers:new Set,linkType:\"SOFT\",discardFromLookup:!1});this.packageRegistry.set(null,new Map([[null,this.getPackageInformation(this.opts.project.topLevelWorkspace.anchoredLocator)]]));let r=this.opts.project.configuration.get(\"pnpFallbackMode\"),o=this.opts.project.workspaces.map(({anchoredLocator:C})=>({name:W.stringifyIdent(C),reference:C.reference})),a=r!==\"none\",n=[],u=new Map,A=je.buildIgnorePattern([\".yarn/sdks/**\",...this.opts.project.configuration.get(\"pnpIgnorePatterns\")]),p=this.packageRegistry,h=this.opts.project.configuration.get(\"pnpShebang\");if(r===\"dependencies-only\")for(let C of this.opts.project.storedPackages.values())this.opts.project.tryWorkspaceByLocator(C)&&n.push({name:W.stringifyIdent(C),reference:C.reference});return await this.asyncActions.wait(),await this.finalizeInstallWithPnp({dependencyTreeRoots:o,enableTopLevelFallback:a,fallbackExclusionList:n,fallbackPool:u,ignorePattern:A,packageRegistry:p,shebang:h}),{customData:this.customData}}async transformPnpSettings(e){}isEsmEnabled(){if(this.opts.project.configuration.sources.has(\"pnpEnableEsmLoader\"))return this.opts.project.configuration.get(\"pnpEnableEsmLoader\");if(this.isESMLoaderRequired)return!0;for(let e of this.opts.project.workspaces)if(e.manifest.type===\"module\")return!0;return!1}async finalizeInstallWithPnp(e){let r=P0(this.opts.project),o=await this.locateNodeModules(e.ignorePattern);if(o.length>0){this.opts.report.reportWarning(31,\"One or more node_modules have been detected and will be removed. This operation may take some time.\");for(let n of o)await oe.removePromise(n)}if(await this.transformPnpSettings(e),this.opts.project.configuration.get(\"pnpEnableInlining\")){let n=xIe(e);await oe.changeFilePromise(r.cjs,n,{automaticNewlines:!0,mode:493}),await oe.removePromise(r.data)}else{let{dataFile:n,loaderFile:u}=kIe(e);await oe.changeFilePromise(r.cjs,u,{automaticNewlines:!0,mode:493}),await oe.changeFilePromise(r.data,n,{automaticNewlines:!0,mode:420})}this.isEsmEnabled()&&(this.opts.report.reportWarning(0,\"ESM support for PnP uses the experimental loader API and is therefore experimental\"),await oe.changeFilePromise(r.esmLoader,(0,sq.default)(),{automaticNewlines:!0,mode:420}));let a=this.opts.project.configuration.get(\"pnpUnpluggedFolder\");if(this.unpluggedPaths.size===0)await oe.removePromise(a);else for(let n of await oe.readdirPromise(a)){let u=V.resolve(a,n);this.unpluggedPaths.has(u)||await oe.removePromise(u)}}async locateNodeModules(e){let r=[],o=e?new RegExp(e):null;for(let a of this.opts.project.workspaces){let n=V.join(a.cwd,\"node_modules\");if(o&&o.test(V.relative(this.opts.project.cwd,a.cwd))||!oe.existsSync(n))continue;let u=await oe.readdirPromise(n,{withFileTypes:!0}),A=u.filter(p=>!p.isDirectory()||p.name===\".bin\"||!p.name.startsWith(\".\"));if(A.length===u.length)r.push(n);else for(let p of A)r.push(V.join(n,p.name))}return r}async unplugPackageIfNeeded(e,r,o,a,n){return this.shouldBeUnplugged(e,r,a)?this.unplugPackage(e,o,n):o.packageFs}shouldBeUnplugged(e,r,o){return typeof o.unplugged<\"u\"?o.unplugged:WIt.has(e.identHash)||e.conditions!=null?!0:r.manifest.preferUnplugged!==null?r.manifest.preferUnplugged:!!(vQ(e,r,o,{configuration:this.opts.project.configuration})?.skipped===!1||r.misc.extractHint)}async unplugPackage(e,r,o){let a=ov(e,{configuration:this.opts.project.configuration});return this.opts.project.disabledLocators.has(e.locatorHash)?new Uu(a,{baseFs:r.packageFs,pathUtils:V}):(this.unpluggedPaths.add(a),o.holdFetchResult(this.asyncActions.set(e.locatorHash,async()=>{let n=V.join(a,r.prefixPath,\".ready\");await oe.existsPromise(n)||(this.opts.project.storedBuildState.delete(e.locatorHash),await oe.mkdirPromise(a,{recursive:!0}),await oe.copyPromise(a,Bt.dot,{baseFs:r.packageFs,overwrite:!1}),await oe.writeFilePromise(n,\"\"))})),new gn(a))}getPackageInformation(e){let r=W.stringifyIdent(e),o=e.reference,a=this.packageRegistry.get(r);if(!a)throw new Error(`Assertion failed: The package information store should have been available (for ${W.prettyIdent(this.opts.project.configuration,e)})`);let n=a.get(o);if(!n)throw new Error(`Assertion failed: The package information should have been available (for ${W.prettyLocator(this.opts.project.configuration,e)})`);return n}getDiskInformation(e){let r=je.getMapWithDefault(this.packageRegistry,\"@@disk\"),o=lq(this.opts.project.cwd,e);return je.getFactoryWithDefault(r,o,()=>({packageLocation:o,packageDependencies:new Map,packagePeers:new Set,linkType:\"SOFT\",discardFromLookup:!1}))}};function lq(t,e){let r=V.relative(t,e);return r.match(/^\\.{0,2}\\//)||(r=`./${r}`),r.replace(/\\/?$/,\"/\")}async function KIt(t){let e=await Ot.tryFind(t.prefixPath,{baseFs:t.packageFs})??new Ot,r=new Set([\"preinstall\",\"install\",\"postinstall\"]);for(let o of e.scripts.keys())r.has(o)||e.scripts.delete(o);return{manifest:{scripts:e.scripts,preferUnplugged:e.preferUnplugged,type:e.type},misc:{extractHint:oq(t),hasBindingGyp:aq(t)}}}Ye();Ye();qt();var n1e=$e(Zo());var S0=class extends ut{constructor(){super(...arguments);this.all=ge.Boolean(\"-A,--all\",!1,{description:\"Unplug direct dependencies from the entire project\"});this.recursive=ge.Boolean(\"-R,--recursive\",!1,{description:\"Unplug both direct and transitive dependencies\"});this.json=ge.Boolean(\"--json\",!1,{description:\"Format the output as an NDJSON stream\"});this.patterns=ge.Rest()}async execute(){let r=await Ke.find(this.context.cwd,this.context.plugins),{project:o,workspace:a}=await St.find(r,this.context.cwd),n=await Lr.find(r);if(!a)throw new rr(o.cwd,this.context.cwd);if(r.get(\"nodeLinker\")!==\"pnp\")throw new it(\"This command can only be used if the `nodeLinker` option is set to `pnp`\");await o.restoreInstallState();let u=new Set(this.patterns),A=this.patterns.map(x=>{let E=W.parseDescriptor(x),R=E.range!==\"unknown\"?E:W.makeDescriptor(E,\"*\");if(!kr.validRange(R.range))throw new it(`The range of the descriptor patterns must be a valid semver range (${W.prettyDescriptor(r,R)})`);return L=>{let U=W.stringifyIdent(L);return!n1e.default.isMatch(U,W.stringifyIdent(R))||L.version&&!kr.satisfiesWithPrereleases(L.version,R.range)?!1:(u.delete(x),!0)}}),p=()=>{let x=[];for(let E of o.storedPackages.values())!o.tryWorkspaceByLocator(E)&&!W.isVirtualLocator(E)&&A.some(R=>R(E))&&x.push(E);return x},h=x=>{let E=new Set,R=[],L=(U,z)=>{if(E.has(U.locatorHash))return;let te=!!o.tryWorkspaceByLocator(U);if(!(z>0&&!this.recursive&&te)&&(E.add(U.locatorHash),!o.tryWorkspaceByLocator(U)&&A.some(le=>le(U))&&R.push(U),!(z>0&&!this.recursive)))for(let le of U.dependencies.values()){let he=o.storedResolutions.get(le.descriptorHash);if(!he)throw new Error(\"Assertion failed: The resolution should have been registered\");let Ae=o.storedPackages.get(he);if(!Ae)throw new Error(\"Assertion failed: The package should have been registered\");L(Ae,z+1)}};for(let U of x)L(U.anchoredPackage,0);return R},C,I;if(this.all&&this.recursive?(C=p(),I=\"the project\"):this.all?(C=h(o.workspaces),I=\"any workspace\"):(C=h([a]),I=\"this workspace\"),u.size>1)throw new it(`Patterns ${de.prettyList(r,u,de.Type.CODE)} don't match any packages referenced by ${I}`);if(u.size>0)throw new it(`Pattern ${de.prettyList(r,u,de.Type.CODE)} doesn't match any packages referenced by ${I}`);C=je.sortMap(C,x=>W.stringifyLocator(x));let v=await Nt.start({configuration:r,stdout:this.context.stdout,json:this.json},async x=>{for(let E of C){let R=E.version??\"unknown\",L=o.topLevelWorkspace.manifest.ensureDependencyMeta(W.makeDescriptor(E,R));L.unplugged=!0,x.reportInfo(0,`Will unpack ${W.prettyLocator(r,E)} to ${de.pretty(r,ov(E,{configuration:r}),de.Type.PATH)}`),x.reportJson({locator:W.stringifyLocator(E),version:R})}await o.topLevelWorkspace.persistManifest(),this.json||x.reportSeparator()});return v.hasErrors()?v.exitCode():await o.installWithNewReport({json:this.json,stdout:this.context.stdout},{cache:n})}};S0.paths=[[\"unplug\"]],S0.usage=nt.Usage({description:\"force the unpacking of a list of packages\",details:\"\\n      This command will add the selectors matching the specified patterns to the list of packages that must be unplugged when installed.\\n\\n      A package being unplugged means that instead of being referenced directly through its archive, it will be unpacked at install time in the directory configured via `pnpUnpluggedFolder`. Note that unpacking packages this way is generally not recommended because it'll make it harder to store your packages within the repository. However, it's a good approach to quickly and safely debug some packages, and can even sometimes be required depending on the context (for example when the package contains shellscripts).\\n\\n      Running the command will set a persistent flag inside your top-level `package.json`, in the `dependenciesMeta` field. As such, to undo its effects, you'll need to revert the changes made to the manifest and run `yarn install` to apply the modification.\\n\\n      By default, only direct dependencies from the current workspace are affected. If `-A,--all` is set, direct dependencies from the entire project are affected. Using the `-R,--recursive` flag will affect transitive dependencies as well as direct ones.\\n\\n      This command accepts glob patterns inside the scope and name components (not the range). Make sure to escape the patterns to prevent your own shell from trying to expand them.\\n    \",examples:[[\"Unplug the lodash dependency from the active workspace\",\"yarn unplug lodash\"],[\"Unplug all instances of lodash referenced by any workspace\",\"yarn unplug lodash -A\"],[\"Unplug all instances of lodash referenced by the active workspace and its dependencies\",\"yarn unplug lodash -R\"],[\"Unplug all instances of lodash, anywhere\",\"yarn unplug lodash -AR\"],[\"Unplug one specific version of lodash\",\"yarn unplug lodash@1.2.3\"],[\"Unplug all packages with the `@babel` scope\",\"yarn unplug '@babel/*'\"],[\"Unplug all packages (only for testing, not recommended)\",\"yarn unplug -R '*'\"]]});var P0=t=>({cjs:V.join(t.cwd,dr.pnpCjs),data:V.join(t.cwd,dr.pnpData),esmLoader:V.join(t.cwd,dr.pnpEsmLoader)}),s1e=t=>/\\s/.test(t)?JSON.stringify(t):t;async function VIt(t,e,r){let o=/\\s*--require\\s+\\S*\\.pnp\\.c?js\\s*/g,a=/\\s*--experimental-loader\\s+\\S*\\.pnp\\.loader\\.mjs\\s*/,n=(e.NODE_OPTIONS??\"\").replace(o,\" \").replace(a,\" \").trim();if(t.configuration.get(\"nodeLinker\")!==\"pnp\"){e.NODE_OPTIONS=n;return}let u=P0(t),A=`--require ${s1e(ue.fromPortablePath(u.cjs))}`;oe.existsSync(u.esmLoader)&&(A=`${A} --experimental-loader ${(0,i1e.pathToFileURL)(ue.fromPortablePath(u.esmLoader)).href}`),oe.existsSync(u.cjs)&&(e.NODE_OPTIONS=n?`${A} ${n}`:A)}async function zIt(t,e){let r=P0(t);e(r.cjs),e(r.data),e(r.esmLoader),e(t.configuration.get(\"pnpUnpluggedFolder\"))}var JIt={hooks:{populateYarnPaths:zIt,setupScriptEnvironment:VIt},configuration:{nodeLinker:{description:'The linker used for installing Node packages, one of: \"pnp\", \"pnpm\", or \"node-modules\"',type:\"STRING\",default:\"pnp\"},winLinkType:{description:\"Whether Yarn should use Windows Junctions or symlinks when creating links on Windows.\",type:\"STRING\",values:[\"junctions\",\"symlinks\"],default:\"junctions\"},pnpMode:{description:\"If 'strict', generates standard PnP maps. If 'loose', merges them with the n_m resolution.\",type:\"STRING\",default:\"strict\"},pnpShebang:{description:\"String to prepend to the generated PnP script\",type:\"STRING\",default:\"#!/usr/bin/env node\"},pnpIgnorePatterns:{description:\"Array of glob patterns; files matching them will use the classic resolution\",type:\"STRING\",default:[],isArray:!0},pnpEnableEsmLoader:{description:\"If true, Yarn will generate an ESM loader (`.pnp.loader.mjs`). If this is not explicitly set Yarn tries to automatically detect whether ESM support is required.\",type:\"BOOLEAN\",default:!1},pnpEnableInlining:{description:\"If true, the PnP data will be inlined along with the generated loader\",type:\"BOOLEAN\",default:!0},pnpFallbackMode:{description:\"If true, the generated PnP loader will follow the top-level fallback rule\",type:\"STRING\",default:\"dependencies-only\"},pnpUnpluggedFolder:{description:\"Folder where the unplugged packages must be stored\",type:\"ABSOLUTE_PATH\",default:\"./.yarn/unplugged\"}},linkers:[D0],commands:[S0]},XIt=JIt;var p1e=$e(u1e());qt();var dq=$e(Be(\"crypto\")),h1e=$e(Be(\"fs\")),g1e=1,Pi=\"node_modules\",DQ=\".bin\",d1e=\".yarn-state.yml\",h1t=1e3,mq=(o=>(o.CLASSIC=\"classic\",o.HARDLINKS_LOCAL=\"hardlinks-local\",o.HARDLINKS_GLOBAL=\"hardlinks-global\",o))(mq||{}),lv=class{constructor(){this.installStateCache=new Map}getCustomDataKey(){return JSON.stringify({name:\"NodeModulesLinker\",version:3})}supportsPackage(e,r){return this.isEnabled(r)}async findPackageLocation(e,r){if(!this.isEnabled(r))throw new Error(\"Assertion failed: Expected the node-modules linker to be enabled\");let o=r.project.tryWorkspaceByLocator(e);if(o)return o.cwd;let a=await je.getFactoryWithDefault(this.installStateCache,r.project.cwd,async()=>await gq(r.project,{unrollAliases:!0}));if(a===null)throw new it(\"Couldn't find the node_modules state file - running an install might help (findPackageLocation)\");let n=a.locatorMap.get(W.stringifyLocator(e));if(!n){let p=new it(`Couldn't find ${W.prettyLocator(r.project.configuration,e)} in the currently installed node_modules map - running an install might help`);throw p.code=\"LOCATOR_NOT_INSTALLED\",p}let u=n.locations.sort((p,h)=>p.split(V.sep).length-h.split(V.sep).length),A=V.join(r.project.configuration.startingCwd,Pi);return u.find(p=>V.contains(A,p))||n.locations[0]}async findPackageLocator(e,r){if(!this.isEnabled(r))return null;let o=await je.getFactoryWithDefault(this.installStateCache,r.project.cwd,async()=>await gq(r.project,{unrollAliases:!0}));if(o===null)return null;let{locationRoot:a,segments:n}=PQ(V.resolve(e),{skipPrefix:r.project.cwd}),u=o.locationTree.get(a);if(!u)return null;let A=u.locator;for(let p of n){if(u=u.children.get(p),!u)break;A=u.locator||A}return W.parseLocator(A)}makeInstaller(e){return new hq(e)}isEnabled(e){return e.project.configuration.get(\"nodeLinker\")===\"node-modules\"}},hq=class{constructor(e){this.opts=e;this.localStore=new Map;this.realLocatorChecksums=new Map;this.customData={store:new Map}}attachCustomData(e){this.customData=e}async installPackage(e,r){let o=V.resolve(r.packageFs.getRealPath(),r.prefixPath),a=this.customData.store.get(e.locatorHash);if(typeof a>\"u\"&&(a=await g1t(e,r),e.linkType===\"HARD\"&&this.customData.store.set(e.locatorHash,a)),!W.isPackageCompatible(e,this.opts.project.configuration.getSupportedArchitectures()))return{packageLocation:null,buildRequest:null};let n=new Map,u=new Set;n.has(W.stringifyIdent(e))||n.set(W.stringifyIdent(e),e.reference);let A=e;if(W.isVirtualLocator(e)){A=W.devirtualizeLocator(e);for(let C of e.peerDependencies.values())n.set(W.stringifyIdent(C),null),u.add(W.stringifyIdent(C))}let p={packageLocation:`${ue.fromPortablePath(o)}/`,packageDependencies:n,packagePeers:u,linkType:e.linkType,discardFromLookup:r.discardFromLookup??!1};this.localStore.set(e.locatorHash,{pkg:e,customPackageData:a,dependencyMeta:this.opts.project.getDependencyMeta(e,e.version),pnpNode:p});let h=r.checksum?r.checksum.substring(r.checksum.indexOf(\"/\")+1):null;return this.realLocatorChecksums.set(A.locatorHash,h),{packageLocation:o,buildRequest:null}}async attachInternalDependencies(e,r){let o=this.localStore.get(e.locatorHash);if(typeof o>\"u\")throw new Error(\"Assertion failed: Expected information object to have been registered\");for(let[a,n]of r){let u=W.areIdentsEqual(a,n)?n.reference:[W.stringifyIdent(n),n.reference];o.pnpNode.packageDependencies.set(W.stringifyIdent(a),u)}}async attachExternalDependents(e,r){throw new Error(\"External dependencies haven't been implemented for the node-modules linker\")}async finalizeInstall(){if(this.opts.project.configuration.get(\"nodeLinker\")!==\"node-modules\")return;let e=new mi({baseFs:new zl({maxOpenFiles:80,readOnlyArchives:!0})}),r=await gq(this.opts.project),o=this.opts.project.configuration.get(\"nmMode\");(r===null||o!==r.nmMode)&&(this.opts.project.storedBuildState.clear(),r={locatorMap:new Map,binSymlinks:new Map,locationTree:new Map,nmMode:o,mtimeMs:0});let a=new Map(this.opts.project.workspaces.map(v=>{let x=this.opts.project.configuration.get(\"nmHoistingLimits\");try{x=je.validateEnum(VB,v.manifest.installConfig?.hoistingLimits??x)}catch{let R=W.prettyWorkspace(this.opts.project.configuration,v);this.opts.report.reportWarning(57,`${R}: Invalid 'installConfig.hoistingLimits' value. Expected one of ${Object.values(VB).join(\", \")}, using default: \"${x}\"`)}return[v.relativeCwd,x]})),n=new Map(this.opts.project.workspaces.map(v=>{let x=this.opts.project.configuration.get(\"nmSelfReferences\");return x=v.manifest.installConfig?.selfReferences??x,[v.relativeCwd,x]})),u={VERSIONS:{std:1},topLevel:{name:null,reference:null},getLocator:(v,x)=>Array.isArray(x)?{name:x[0],reference:x[1]}:{name:v,reference:x},getDependencyTreeRoots:()=>this.opts.project.workspaces.map(v=>{let x=v.anchoredLocator;return{name:W.stringifyIdent(x),reference:x.reference}}),getPackageInformation:v=>{let x=v.reference===null?this.opts.project.topLevelWorkspace.anchoredLocator:W.makeLocator(W.parseIdent(v.name),v.reference),E=this.localStore.get(x.locatorHash);if(typeof E>\"u\")throw new Error(\"Assertion failed: Expected the package reference to have been registered\");return E.pnpNode},findPackageLocator:v=>{let x=this.opts.project.tryWorkspaceByCwd(ue.toPortablePath(v));if(x!==null){let E=x.anchoredLocator;return{name:W.stringifyIdent(E),reference:E.reference}}throw new Error(\"Assertion failed: Unimplemented\")},resolveToUnqualified:()=>{throw new Error(\"Assertion failed: Unimplemented\")},resolveUnqualified:()=>{throw new Error(\"Assertion failed: Unimplemented\")},resolveRequest:()=>{throw new Error(\"Assertion failed: Unimplemented\")},resolveVirtual:v=>ue.fromPortablePath(mi.resolveVirtual(ue.toPortablePath(v)))},{tree:A,errors:p,preserveSymlinksRequired:h}=zB(u,{pnpifyFs:!1,validateExternalSoftLinks:!0,hoistingLimitsByCwd:a,project:this.opts.project,selfReferencesByCwd:n});if(!A){for(let{messageName:v,text:x}of p)this.opts.report.reportError(v,x);return}let C=qj(A);await w1t(r,C,{baseFs:e,project:this.opts.project,report:this.opts.report,realLocatorChecksums:this.realLocatorChecksums,loadManifest:async v=>{let x=W.parseLocator(v),E=this.localStore.get(x.locatorHash);if(typeof E>\"u\")throw new Error(\"Assertion failed: Expected the slot to exist\");return E.customPackageData.manifest}});let I=[];for(let[v,x]of C.entries()){if(C1e(v))continue;let E=W.parseLocator(v),R=this.localStore.get(E.locatorHash);if(typeof R>\"u\")throw new Error(\"Assertion failed: Expected the slot to exist\");if(this.opts.project.tryWorkspaceByLocator(R.pkg))continue;let L=mA.extractBuildRequest(R.pkg,R.customPackageData,R.dependencyMeta,{configuration:this.opts.project.configuration});!L||I.push({buildLocations:x.locations,locator:E,buildRequest:L})}return h&&this.opts.report.reportWarning(72,`The application uses portals and that's why ${de.pretty(this.opts.project.configuration,\"--preserve-symlinks\",de.Type.CODE)} Node option is required for launching it`),{customData:this.customData,records:I}}};async function g1t(t,e){let r=await Ot.tryFind(e.prefixPath,{baseFs:e.packageFs})??new Ot,o=new Set([\"preinstall\",\"install\",\"postinstall\"]);for(let a of r.scripts.keys())o.has(a)||r.scripts.delete(a);return{manifest:{bin:r.bin,scripts:r.scripts},misc:{hasBindingGyp:mA.hasBindingGyp(e)}}}async function d1t(t,e,r,o,{installChangedByUser:a}){let n=\"\";n+=`# Warning: This file is automatically generated. Removing it is fine, but will\n`,n+=`# cause your node_modules installation to become invalidated.\n`,n+=`\n`,n+=`__metadata:\n`,n+=`  version: ${g1e}\n`,n+=`  nmMode: ${o.value}\n`;let u=Array.from(e.keys()).sort(),A=W.stringifyLocator(t.topLevelWorkspace.anchoredLocator);for(let C of u){let I=e.get(C);n+=`\n`,n+=`${JSON.stringify(C)}:\n`,n+=`  locations:\n`;for(let v of I.locations){let x=V.contains(t.cwd,v);if(x===null)throw new Error(`Assertion failed: Expected the path to be within the project (${v})`);n+=`    - ${JSON.stringify(x)}\n`}if(I.aliases.length>0){n+=`  aliases:\n`;for(let v of I.aliases)n+=`    - ${JSON.stringify(v)}\n`}if(C===A&&r.size>0){n+=`  bin:\n`;for(let[v,x]of r){let E=V.contains(t.cwd,v);if(E===null)throw new Error(`Assertion failed: Expected the path to be within the project (${v})`);n+=`    ${JSON.stringify(E)}:\n`;for(let[R,L]of x){let U=V.relative(V.join(v,Pi),L);n+=`      ${JSON.stringify(R)}: ${JSON.stringify(U)}\n`}}}}let p=t.cwd,h=V.join(p,Pi,d1e);a&&await oe.removePromise(h),await oe.changeFilePromise(h,n,{automaticNewlines:!0})}async function gq(t,{unrollAliases:e=!1}={}){let r=t.cwd,o=V.join(r,Pi,d1e),a;try{a=await oe.statPromise(o)}catch{}if(!a)return null;let n=Ki(await oe.readFilePromise(o,\"utf8\"));if(n.__metadata.version>g1e)return null;let u=n.__metadata.nmMode||\"classic\",A=new Map,p=new Map;delete n.__metadata;for(let[h,C]of Object.entries(n)){let I=C.locations.map(x=>V.join(r,x)),v=C.bin;if(v)for(let[x,E]of Object.entries(v)){let R=V.join(r,ue.toPortablePath(x)),L=je.getMapWithDefault(p,R);for(let[U,z]of Object.entries(E))L.set(U,ue.toPortablePath([R,Pi,z].join(V.sep)))}if(A.set(h,{target:Bt.dot,linkType:\"HARD\",locations:I,aliases:C.aliases||[]}),e&&C.aliases)for(let x of C.aliases){let{scope:E,name:R}=W.parseLocator(h),L=W.makeLocator(W.makeIdent(E,R),x),U=W.stringifyLocator(L);A.set(U,{target:Bt.dot,linkType:\"HARD\",locations:I,aliases:[]})}}return{locatorMap:A,binSymlinks:p,locationTree:m1e(A,{skipPrefix:t.cwd}),nmMode:u,mtimeMs:a.mtimeMs}}var GC=async(t,e)=>{if(t.split(V.sep).indexOf(Pi)<0)throw new Error(`Assertion failed: trying to remove dir that doesn't contain node_modules: ${t}`);try{if(!e.innerLoop){let o=e.allowSymlink?await oe.statPromise(t):await oe.lstatPromise(t);if(e.allowSymlink&&!o.isDirectory()||!e.allowSymlink&&o.isSymbolicLink()){await oe.unlinkPromise(t);return}}let r=await oe.readdirPromise(t,{withFileTypes:!0});for(let o of r){let a=V.join(t,o.name);o.isDirectory()?(o.name!==Pi||e&&e.innerLoop)&&await GC(a,{innerLoop:!0,contentsOnly:!1}):await oe.unlinkPromise(a)}e.contentsOnly||await oe.rmdirPromise(t)}catch(r){if(r.code!==\"ENOENT\"&&r.code!==\"ENOTEMPTY\")throw r}},A1e=4,PQ=(t,{skipPrefix:e})=>{let r=V.contains(e,t);if(r===null)throw new Error(`Assertion failed: Writing attempt prevented to ${t} which is outside project root: ${e}`);let o=r.split(V.sep).filter(p=>p!==\"\"),a=o.indexOf(Pi),n=o.slice(0,a).join(V.sep),u=V.join(e,n),A=o.slice(a);return{locationRoot:u,segments:A}},m1e=(t,{skipPrefix:e})=>{let r=new Map;if(t===null)return r;let o=()=>({children:new Map,linkType:\"HARD\"});for(let[a,n]of t.entries()){if(n.linkType===\"SOFT\"&&V.contains(e,n.target)!==null){let A=je.getFactoryWithDefault(r,n.target,o);A.locator=a,A.linkType=n.linkType}for(let u of n.locations){let{locationRoot:A,segments:p}=PQ(u,{skipPrefix:e}),h=je.getFactoryWithDefault(r,A,o);for(let C=0;C<p.length;++C){let I=p[C];if(I!==\".\"){let v=je.getFactoryWithDefault(h.children,I,o);h.children.set(I,v),h=v}C===p.length-1&&(h.locator=a,h.linkType=n.linkType)}}}return r},yq=async(t,e,r)=>{if(process.platform===\"win32\"&&r===\"junctions\"){let o;try{o=await oe.lstatPromise(t)}catch{}if(!o||o.isDirectory()){await oe.symlinkPromise(t,e,\"junction\");return}}await oe.symlinkPromise(V.relative(V.dirname(e),t),e)};async function y1e(t,e,r){let o=V.join(t,`${dq.default.randomBytes(16).toString(\"hex\")}.tmp`);try{await oe.writeFilePromise(o,r);try{await oe.linkPromise(o,e)}catch{}}finally{await oe.unlinkPromise(o)}}async function m1t({srcPath:t,dstPath:e,entry:r,globalHardlinksStore:o,baseFs:a,nmMode:n}){if(r.kind===E1e.FILE){if(n.value===\"hardlinks-global\"&&o&&r.digest){let A=V.join(o,r.digest.substring(0,2),`${r.digest.substring(2)}.dat`),p;try{let h=await oe.statPromise(A);if(h&&(!r.mtimeMs||h.mtimeMs>r.mtimeMs||h.mtimeMs<r.mtimeMs-h1t))if(await wn.checksumFile(A,{baseFs:oe,algorithm:\"sha1\"})!==r.digest){let I=V.join(o,`${dq.default.randomBytes(16).toString(\"hex\")}.tmp`);await oe.renamePromise(A,I);let v=await a.readFilePromise(t);await oe.writeFilePromise(I,v);try{await oe.linkPromise(I,A),r.mtimeMs=new Date().getTime(),await oe.unlinkPromise(I)}catch{}}else r.mtimeMs||(r.mtimeMs=Math.ceil(h.mtimeMs));await oe.linkPromise(A,e),p=!0}catch{p=!1}if(!p){let h=await a.readFilePromise(t);await y1e(o,A,h),r.mtimeMs=new Date().getTime();try{await oe.linkPromise(A,e)}catch(C){C&&C.code&&C.code==\"EXDEV\"&&(n.value=\"hardlinks-local\",await a.copyFilePromise(t,e))}}}else await a.copyFilePromise(t,e);let u=r.mode&511;u!==420&&await oe.chmodPromise(e,u)}}var E1e=(o=>(o.FILE=\"file\",o.DIRECTORY=\"directory\",o.SYMLINK=\"symlink\",o))(E1e||{}),y1t=async(t,e,{baseFs:r,globalHardlinksStore:o,nmMode:a,windowsLinkType:n,packageChecksum:u})=>{await oe.mkdirPromise(t,{recursive:!0});let A=async(C=Bt.dot)=>{let I=V.join(e,C),v=await r.readdirPromise(I,{withFileTypes:!0}),x=new Map;for(let E of v){let R=V.join(C,E.name),L,U=V.join(I,E.name);if(E.isFile()){if(L={kind:\"file\",mode:(await r.lstatPromise(U)).mode},a.value===\"hardlinks-global\"){let z=await wn.checksumFile(U,{baseFs:r,algorithm:\"sha1\"});L.digest=z}}else if(E.isDirectory())L={kind:\"directory\"};else if(E.isSymbolicLink())L={kind:\"symlink\",symlinkTo:await r.readlinkPromise(U)};else throw new Error(`Unsupported file type (file: ${U}, mode: 0o${await r.statSync(U).mode.toString(8).padStart(6,\"0\")})`);if(x.set(R,L),E.isDirectory()&&R!==Pi){let z=await A(R);for(let[te,le]of z)x.set(te,le)}}return x},p;if(a.value===\"hardlinks-global\"&&o&&u){let C=V.join(o,u.substring(0,2),`${u.substring(2)}.json`);try{p=new Map(Object.entries(JSON.parse(await oe.readFilePromise(C,\"utf8\"))))}catch{p=await A()}}else p=await A();let h=!1;for(let[C,I]of p){let v=V.join(e,C),x=V.join(t,C);if(I.kind===\"directory\")await oe.mkdirPromise(x,{recursive:!0});else if(I.kind===\"file\"){let E=I.mtimeMs;await m1t({srcPath:v,dstPath:x,entry:I,nmMode:a,baseFs:r,globalHardlinksStore:o}),I.mtimeMs!==E&&(h=!0)}else I.kind===\"symlink\"&&await yq(V.resolve(V.dirname(x),I.symlinkTo),x,n)}if(a.value===\"hardlinks-global\"&&o&&h&&u){let C=V.join(o,u.substring(0,2),`${u.substring(2)}.json`);await oe.removePromise(C),await y1e(o,C,Buffer.from(JSON.stringify(Object.fromEntries(p))))}};function E1t(t,e,r,o){let a=new Map,n=new Map,u=new Map,A=!1,p=(h,C,I,v,x)=>{let E=!0,R=V.join(h,C),L=new Set;if(C===Pi||C.startsWith(\"@\")){let z;try{z=oe.statSync(R)}catch{}E=!!z,z?z.mtimeMs>r?(A=!0,L=new Set(oe.readdirSync(R))):L=new Set(I.children.get(C).children.keys()):A=!0;let te=e.get(h);if(te){let le=V.join(h,Pi,DQ),he;try{he=oe.statSync(le)}catch{}if(!he)A=!0;else if(he.mtimeMs>r){A=!0;let Ae=new Set(oe.readdirSync(le)),ye=new Map;n.set(h,ye);for(let[ae,Ie]of te)Ae.has(ae)&&ye.set(ae,Ie)}else n.set(h,te)}}else E=x.has(C);let U=I.children.get(C);if(E){let{linkType:z,locator:te}=U,le={children:new Map,linkType:z,locator:te};if(v.children.set(C,le),te){let he=je.getSetWithDefault(u,te);he.add(R),u.set(te,he)}for(let he of U.children.keys())p(R,he,U,le,L)}else U.locator&&o.storedBuildState.delete(W.parseLocator(U.locator).locatorHash)};for(let[h,C]of t){let{linkType:I,locator:v}=C,x={children:new Map,linkType:I,locator:v};if(a.set(h,x),v){let E=je.getSetWithDefault(u,C.locator);E.add(h),u.set(C.locator,E)}C.children.has(Pi)&&p(h,Pi,C,x,new Set)}return{locationTree:a,binSymlinks:n,locatorLocations:u,installChangedByUser:A}}function C1e(t){let e=W.parseDescriptor(t);return W.isVirtualDescriptor(e)&&(e=W.devirtualizeDescriptor(e)),e.range.startsWith(\"link:\")}async function C1t(t,e,r,{loadManifest:o}){let a=new Map;for(let[A,{locations:p}]of t){let h=C1e(A)?null:await o(A,p[0]),C=new Map;if(h)for(let[I,v]of h.bin){let x=V.join(p[0],v);v!==\"\"&&oe.existsSync(x)&&C.set(I,v)}a.set(A,C)}let n=new Map,u=(A,p,h)=>{let C=new Map,I=V.contains(r,A);if(h.locator&&I!==null){let v=a.get(h.locator);for(let[x,E]of v){let R=V.join(A,ue.toPortablePath(E));C.set(x,R)}for(let[x,E]of h.children){let R=V.join(A,x),L=u(R,R,E);L.size>0&&n.set(A,new Map([...n.get(A)||new Map,...L]))}}else for(let[v,x]of h.children){let E=u(V.join(A,v),p,x);for(let[R,L]of E)C.set(R,L)}return C};for(let[A,p]of e){let h=u(A,A,p);h.size>0&&n.set(A,new Map([...n.get(A)||new Map,...h]))}return n}var f1e=(t,e)=>{if(!t||!e)return t===e;let r=W.parseLocator(t);W.isVirtualLocator(r)&&(r=W.devirtualizeLocator(r));let o=W.parseLocator(e);return W.isVirtualLocator(o)&&(o=W.devirtualizeLocator(o)),W.areLocatorsEqual(r,o)};function Eq(t){return V.join(t.get(\"globalFolder\"),\"store\")}async function w1t(t,e,{baseFs:r,project:o,report:a,loadManifest:n,realLocatorChecksums:u}){let A=V.join(o.cwd,Pi),{locationTree:p,binSymlinks:h,locatorLocations:C,installChangedByUser:I}=E1t(t.locationTree,t.binSymlinks,t.mtimeMs,o),v=m1e(e,{skipPrefix:o.cwd}),x=[],E=async({srcDir:Ie,dstDir:Fe,linkType:g,globalHardlinksStore:Ee,nmMode:De,windowsLinkType:ce,packageChecksum:ne})=>{let ee=(async()=>{try{g===\"SOFT\"?(await oe.mkdirPromise(V.dirname(Fe),{recursive:!0}),await yq(V.resolve(Ie),Fe,ce)):await y1t(Fe,Ie,{baseFs:r,globalHardlinksStore:Ee,nmMode:De,windowsLinkType:ce,packageChecksum:ne})}catch(we){throw we.message=`While persisting ${Ie} -> ${Fe} ${we.message}`,we}finally{le.tick()}})().then(()=>x.splice(x.indexOf(ee),1));x.push(ee),x.length>A1e&&await Promise.race(x)},R=async(Ie,Fe,g)=>{let Ee=(async()=>{let De=async(ce,ne,ee)=>{try{ee.innerLoop||await oe.mkdirPromise(ne,{recursive:!0});let we=await oe.readdirPromise(ce,{withFileTypes:!0});for(let xe of we){if(!ee.innerLoop&&xe.name===DQ)continue;let ht=V.join(ce,xe.name),H=V.join(ne,xe.name);xe.isDirectory()?(xe.name!==Pi||ee&&ee.innerLoop)&&(await oe.mkdirPromise(H,{recursive:!0}),await De(ht,H,{...ee,innerLoop:!0})):ye.value===\"hardlinks-local\"||ye.value===\"hardlinks-global\"?await oe.linkPromise(ht,H):await oe.copyFilePromise(ht,H,h1e.default.constants.COPYFILE_FICLONE)}}catch(we){throw ee.innerLoop||(we.message=`While cloning ${ce} -> ${ne} ${we.message}`),we}finally{ee.innerLoop||le.tick()}};await De(Ie,Fe,g)})().then(()=>x.splice(x.indexOf(Ee),1));x.push(Ee),x.length>A1e&&await Promise.race(x)},L=async(Ie,Fe,g)=>{if(g)for(let[Ee,De]of Fe.children){let ce=g.children.get(Ee);await L(V.join(Ie,Ee),De,ce)}else{Fe.children.has(Pi)&&await GC(V.join(Ie,Pi),{contentsOnly:!1});let Ee=V.basename(Ie)===Pi&&v.has(V.join(V.dirname(Ie),V.sep));await GC(Ie,{contentsOnly:Ie===A,allowSymlink:Ee})}};for(let[Ie,Fe]of p){let g=v.get(Ie);for(let[Ee,De]of Fe.children){if(Ee===\".\")continue;let ce=g&&g.children.get(Ee),ne=V.join(Ie,Ee);await L(ne,De,ce)}}let U=async(Ie,Fe,g)=>{if(g){f1e(Fe.locator,g.locator)||await GC(Ie,{contentsOnly:Fe.linkType===\"HARD\"});for(let[Ee,De]of Fe.children){let ce=g.children.get(Ee);await U(V.join(Ie,Ee),De,ce)}}else{Fe.children.has(Pi)&&await GC(V.join(Ie,Pi),{contentsOnly:!0});let Ee=V.basename(Ie)===Pi&&v.has(V.join(V.dirname(Ie),V.sep));await GC(Ie,{contentsOnly:Fe.linkType===\"HARD\",allowSymlink:Ee})}};for(let[Ie,Fe]of v){let g=p.get(Ie);for(let[Ee,De]of Fe.children){if(Ee===\".\")continue;let ce=g&&g.children.get(Ee);await U(V.join(Ie,Ee),De,ce)}}let z=new Map,te=[];for(let[Ie,Fe]of C)for(let g of Fe){let{locationRoot:Ee,segments:De}=PQ(g,{skipPrefix:o.cwd}),ce=v.get(Ee),ne=Ee;if(ce){for(let ee of De)if(ne=V.join(ne,ee),ce=ce.children.get(ee),!ce)break;if(ce){let ee=f1e(ce.locator,Ie),we=e.get(ce.locator),xe=we.target,ht=ne,H=we.linkType;if(ee)z.has(xe)||z.set(xe,ht);else if(xe!==ht){let lt=W.parseLocator(ce.locator);W.isVirtualLocator(lt)&&(lt=W.devirtualizeLocator(lt)),te.push({srcDir:xe,dstDir:ht,linkType:H,realLocatorHash:lt.locatorHash})}}}}for(let[Ie,{locations:Fe}]of e.entries())for(let g of Fe){let{locationRoot:Ee,segments:De}=PQ(g,{skipPrefix:o.cwd}),ce=p.get(Ee),ne=v.get(Ee),ee=Ee,we=e.get(Ie),xe=W.parseLocator(Ie);W.isVirtualLocator(xe)&&(xe=W.devirtualizeLocator(xe));let ht=xe.locatorHash,H=we.target,lt=g;if(H===lt)continue;let Te=we.linkType;for(let ke of De)ne=ne.children.get(ke);if(!ce)te.push({srcDir:H,dstDir:lt,linkType:Te,realLocatorHash:ht});else for(let ke of De)if(ee=V.join(ee,ke),ce=ce.children.get(ke),!ce){te.push({srcDir:H,dstDir:lt,linkType:Te,realLocatorHash:ht});break}}let le=Xs.progressViaCounter(te.length),he=a.reportProgress(le),Ae=o.configuration.get(\"nmMode\"),ye={value:Ae},ae=o.configuration.get(\"winLinkType\");try{let Ie=ye.value===\"hardlinks-global\"?`${Eq(o.configuration)}/v1`:null;if(Ie&&!await oe.existsPromise(Ie)){await oe.mkdirpPromise(Ie);for(let g=0;g<256;g++)await oe.mkdirPromise(V.join(Ie,g.toString(16).padStart(2,\"0\")))}for(let g of te)(g.linkType===\"SOFT\"||!z.has(g.srcDir))&&(z.set(g.srcDir,g.dstDir),await E({...g,globalHardlinksStore:Ie,nmMode:ye,windowsLinkType:ae,packageChecksum:u.get(g.realLocatorHash)||null}));await Promise.all(x),x.length=0;for(let g of te){let Ee=z.get(g.srcDir);g.linkType!==\"SOFT\"&&g.dstDir!==Ee&&await R(Ee,g.dstDir,{nmMode:ye})}await Promise.all(x),await oe.mkdirPromise(A,{recursive:!0});let Fe=await C1t(e,v,o.cwd,{loadManifest:n});await I1t(h,Fe,o.cwd,ae),await d1t(o,e,Fe,ye,{installChangedByUser:I}),Ae==\"hardlinks-global\"&&ye.value==\"hardlinks-local\"&&a.reportWarningOnce(74,\"'nmMode' has been downgraded to 'hardlinks-local' due to global cache and install folder being on different devices\")}finally{he.stop()}}async function I1t(t,e,r,o){for(let a of t.keys()){if(V.contains(r,a)===null)throw new Error(`Assertion failed. Excepted bin symlink location to be inside project dir, instead it was at ${a}`);if(!e.has(a)){let n=V.join(a,Pi,DQ);await oe.removePromise(n)}}for(let[a,n]of e){if(V.contains(r,a)===null)throw new Error(`Assertion failed. Excepted bin symlink location to be inside project dir, instead it was at ${a}`);let u=V.join(a,Pi,DQ),A=t.get(a)||new Map;await oe.mkdirPromise(u,{recursive:!0});for(let p of A.keys())n.has(p)||(await oe.removePromise(V.join(u,p)),process.platform===\"win32\"&&await oe.removePromise(V.join(u,`${p}.cmd`)));for(let[p,h]of n){let C=A.get(p),I=V.join(u,p);C!==h&&(process.platform===\"win32\"?await(0,p1e.default)(ue.fromPortablePath(h),ue.fromPortablePath(I),{createPwshFile:!1}):(await oe.removePromise(I),await yq(h,I,o),V.contains(r,await oe.realpathPromise(h))!==null&&await oe.chmodPromise(h,493)))}}}Ye();Pt();nA();var cv=class extends D0{constructor(){super(...arguments);this.mode=\"loose\"}makeInstaller(r){return new Cq(r)}},Cq=class extends gm{constructor(){super(...arguments);this.mode=\"loose\"}async transformPnpSettings(r){let o=new mi({baseFs:new zl({maxOpenFiles:80,readOnlyArchives:!0})}),a=$Ie(r,this.opts.project.cwd,o),{tree:n,errors:u}=zB(a,{pnpifyFs:!1,project:this.opts.project});if(!n){for(let{messageName:I,text:v}of u)this.opts.report.reportError(I,v);return}let A=new Map;r.fallbackPool=A;let p=(I,v)=>{let x=W.parseLocator(v.locator),E=W.stringifyIdent(x);E===I?A.set(I,x.reference):A.set(I,[E,x.reference])},h=V.join(this.opts.project.cwd,dr.nodeModules),C=n.get(h);if(!(typeof C>\"u\")){if(\"target\"in C)throw new Error(\"Assertion failed: Expected the root junction point to be a directory\");for(let I of C.dirList){let v=V.join(h,I),x=n.get(v);if(typeof x>\"u\")throw new Error(\"Assertion failed: Expected the child to have been registered\");if(\"target\"in x)p(I,x);else for(let E of x.dirList){let R=V.join(v,E),L=n.get(R);if(typeof L>\"u\")throw new Error(\"Assertion failed: Expected the subchild to have been registered\");if(\"target\"in L)p(`${I}/${E}`,L);else throw new Error(\"Assertion failed: Expected the leaf junction to be a package\")}}}}};var B1t={hooks:{cleanGlobalArtifacts:async t=>{let e=Eq(t);await oe.removePromise(e)}},configuration:{nmHoistingLimits:{description:\"Prevents packages to be hoisted past specific levels\",type:\"STRING\",values:[\"workspaces\",\"dependencies\",\"none\"],default:\"none\"},nmMode:{description:\"Defines in which measure Yarn must use hardlinks and symlinks when generated `node_modules` directories.\",type:\"STRING\",values:[\"classic\",\"hardlinks-local\",\"hardlinks-global\"],default:\"classic\"},nmSelfReferences:{description:\"Defines whether the linker should generate self-referencing symlinks for workspaces.\",type:\"BOOLEAN\",default:!0}},linkers:[lv,cv]},v1t=B1t;var CG={};Vt(CG,{NpmHttpFetcher:()=>fv,NpmRemapResolver:()=>pv,NpmSemverFetcher:()=>dl,NpmSemverResolver:()=>hv,NpmTagResolver:()=>gv,default:()=>Lvt,npmConfigUtils:()=>Zn,npmHttpUtils:()=>on,npmPublishUtils:()=>iw});Ye();var b1e=$e(Jn());var Wn=\"npm:\";var on={};Vt(on,{AuthType:()=>P1e,customPackageError:()=>dm,del:()=>R1t,get:()=>mm,getIdentUrl:()=>SQ,getPackageMetadata:()=>KC,handleInvalidAuthenticationError:()=>b0,post:()=>Q1t,put:()=>F1t});Ye();Ye();Pt();var vq=$e(u2()),v1e=$e(S_()),D1e=$e(Jn()),Dq=Be(\"url\");var Zn={};Vt(Zn,{RegistryType:()=>w1e,getAuditRegistry:()=>D1t,getAuthConfiguration:()=>Bq,getDefaultRegistry:()=>uv,getPublishRegistry:()=>P1t,getRegistryConfiguration:()=>I1e,getScopeConfiguration:()=>Iq,getScopeRegistry:()=>YC,normalizeRegistry:()=>oc});var w1e=(o=>(o.AUDIT_REGISTRY=\"npmAuditRegistry\",o.FETCH_REGISTRY=\"npmRegistryServer\",o.PUBLISH_REGISTRY=\"npmPublishRegistry\",o))(w1e||{});function oc(t){return t.replace(/\\/$/,\"\")}function D1t({configuration:t}){return uv({configuration:t,type:\"npmAuditRegistry\"})}function P1t(t,{configuration:e}){return t.publishConfig?.registry?oc(t.publishConfig.registry):t.name?YC(t.name.scope,{configuration:e,type:\"npmPublishRegistry\"}):uv({configuration:e,type:\"npmPublishRegistry\"})}function YC(t,{configuration:e,type:r=\"npmRegistryServer\"}){let o=Iq(t,{configuration:e});if(o===null)return uv({configuration:e,type:r});let a=o.get(r);return a===null?uv({configuration:e,type:r}):oc(a)}function uv({configuration:t,type:e=\"npmRegistryServer\"}){let r=t.get(e);return oc(r!==null?r:t.get(\"npmRegistryServer\"))}function I1e(t,{configuration:e}){let r=e.get(\"npmRegistries\"),o=oc(t),a=r.get(o);if(typeof a<\"u\")return a;let n=r.get(o.replace(/^[a-z]+:/,\"\"));return typeof n<\"u\"?n:null}function Iq(t,{configuration:e}){if(t===null)return null;let o=e.get(\"npmScopes\").get(t);return o||null}function Bq(t,{configuration:e,ident:r}){let o=r&&Iq(r.scope,{configuration:e});return o?.get(\"npmAuthIdent\")||o?.get(\"npmAuthToken\")?o:I1e(t,{configuration:e})||e}var P1e=(a=>(a[a.NO_AUTH=0]=\"NO_AUTH\",a[a.BEST_EFFORT=1]=\"BEST_EFFORT\",a[a.CONFIGURATION=2]=\"CONFIGURATION\",a[a.ALWAYS_AUTH=3]=\"ALWAYS_AUTH\",a))(P1e||{});async function b0(t,{attemptedAs:e,registry:r,headers:o,configuration:a}){if(xQ(t))throw new Jt(41,\"Invalid OTP token\");if(t.originalError?.name===\"HTTPError\"&&t.originalError?.response.statusCode===401)throw new Jt(41,`Invalid authentication (${typeof e!=\"string\"?`as ${await N1t(r,o,{configuration:a})}`:`attempted as ${e}`})`)}function dm(t,e){let r=t.response?.statusCode;return r?r===404?\"Package not found\":r>=500&&r<600?`The registry appears to be down (using a ${de.applyHyperlink(e,\"local cache\",\"https://yarnpkg.com/advanced/lexicon#local-cache\")} might have protected you against such outages)`:null:null}function SQ(t){return t.scope?`/@${t.scope}%2f${t.name}`:`/${t.name}`}var B1e=new Map;async function KC(t,{cache:e,project:r,registry:o,headers:a,version:n,...u}){return await je.getFactoryWithDefault(B1e,t.identHash,async()=>{let{configuration:A}=r;o=Av(A,{ident:t,registry:o});let p=x1t(A,o),h=V.join(p,`${W.slugifyIdent(t)}.json`),C=null;if(!r.lockfileNeedsRefresh){try{C=await oe.readJsonPromise(h)}catch{}if(C){if(typeof n<\"u\"&&typeof C.metadata.versions[n]<\"u\")return C.metadata;if(A.get(\"enableOfflineMode\")){let I=structuredClone(C.metadata),v=new Set;if(e){for(let E of Object.keys(I.versions)){let R=W.makeLocator(t,`npm:${E}`),L=e.getLocatorMirrorPath(R);(!L||!oe.existsSync(L))&&(delete I.versions[E],v.add(E))}let x=I[\"dist-tags\"].latest;if(v.has(x)){let E=Object.keys(C.metadata.versions).sort(D1e.default.compare),R=E.indexOf(x);for(;v.has(E[R])&&R>=0;)R-=1;R>=0?I[\"dist-tags\"].latest=E[R]:delete I[\"dist-tags\"].latest}}return I}}}return await mm(SQ(t),{...u,customErrorMessage:dm,configuration:A,registry:o,ident:t,headers:{...a,[\"If-None-Match\"]:C?.etag,[\"If-Modified-Since\"]:C?.lastModified},wrapNetworkRequest:async I=>async()=>{let v=await I();if(v.statusCode===304){if(C===null)throw new Error(\"Assertion failed: cachedMetadata should not be null\");return{...v,body:C.metadata}}let x=S1t(JSON.parse(v.body.toString()));B1e.set(t.identHash,x);let E={metadata:x,etag:v.headers.etag,lastModified:v.headers[\"last-modified\"]},R=`${h}-${process.pid}.tmp`;return await oe.mkdirPromise(p,{recursive:!0}),await oe.writeJsonPromise(R,E,{compact:!0}),await oe.renamePromise(R,h),{...v,body:x}}})})}var S1e=[\"name\",\"dist.tarball\",\"bin\",\"scripts\",\"os\",\"cpu\",\"libc\",\"dependencies\",\"dependenciesMeta\",\"optionalDependencies\",\"peerDependencies\",\"peerDependenciesMeta\",\"deprecated\"];function S1t(t){return{\"dist-tags\":t[\"dist-tags\"],versions:Object.fromEntries(Object.entries(t.versions).map(([e,r])=>[e,(0,v1e.default)(r,S1e)]))}}var b1t=wn.makeHash(...S1e).slice(0,6);function x1t(t,e){let r=k1t(t),o=new Dq.URL(e);return V.join(r,b1t,o.hostname)}function k1t(t){return V.join(t.get(\"globalFolder\"),\"metadata/npm\")}async function mm(t,{configuration:e,headers:r,ident:o,authType:a,registry:n,...u}){n=Av(e,{ident:o,registry:n}),o&&o.scope&&typeof a>\"u\"&&(a=1);let A=await bQ(n,{authType:a,configuration:e,ident:o});A&&(r={...r,authorization:A});try{return await rn.get(t.charAt(0)===\"/\"?`${n}${t}`:t,{configuration:e,headers:r,...u})}catch(p){throw await b0(p,{registry:n,configuration:e,headers:r}),p}}async function Q1t(t,e,{attemptedAs:r,configuration:o,headers:a,ident:n,authType:u=3,registry:A,otp:p,...h}){A=Av(o,{ident:n,registry:A});let C=await bQ(A,{authType:u,configuration:o,ident:n});C&&(a={...a,authorization:C}),p&&(a={...a,...WC(p)});try{return await rn.post(A+t,e,{configuration:o,headers:a,...h})}catch(I){if(!xQ(I)||p)throw await b0(I,{attemptedAs:r,registry:A,configuration:o,headers:a}),I;p=await Pq(I,{configuration:o});let v={...a,...WC(p)};try{return await rn.post(`${A}${t}`,e,{configuration:o,headers:v,...h})}catch(x){throw await b0(x,{attemptedAs:r,registry:A,configuration:o,headers:a}),x}}}async function F1t(t,e,{attemptedAs:r,configuration:o,headers:a,ident:n,authType:u=3,registry:A,otp:p,...h}){A=Av(o,{ident:n,registry:A});let C=await bQ(A,{authType:u,configuration:o,ident:n});C&&(a={...a,authorization:C}),p&&(a={...a,...WC(p)});try{return await rn.put(A+t,e,{configuration:o,headers:a,...h})}catch(I){if(!xQ(I))throw await b0(I,{attemptedAs:r,registry:A,configuration:o,headers:a}),I;p=await Pq(I,{configuration:o});let v={...a,...WC(p)};try{return await rn.put(`${A}${t}`,e,{configuration:o,headers:v,...h})}catch(x){throw await b0(x,{attemptedAs:r,registry:A,configuration:o,headers:a}),x}}}async function R1t(t,{attemptedAs:e,configuration:r,headers:o,ident:a,authType:n=3,registry:u,otp:A,...p}){u=Av(r,{ident:a,registry:u});let h=await bQ(u,{authType:n,configuration:r,ident:a});h&&(o={...o,authorization:h}),A&&(o={...o,...WC(A)});try{return await rn.del(u+t,{configuration:r,headers:o,...p})}catch(C){if(!xQ(C)||A)throw await b0(C,{attemptedAs:e,registry:u,configuration:r,headers:o}),C;A=await Pq(C,{configuration:r});let I={...o,...WC(A)};try{return await rn.del(`${u}${t}`,{configuration:r,headers:I,...p})}catch(v){throw await b0(v,{attemptedAs:e,registry:u,configuration:r,headers:o}),v}}}function Av(t,{ident:e,registry:r}){if(typeof r>\"u\"&&e)return YC(e.scope,{configuration:t});if(typeof r!=\"string\")throw new Error(\"Assertion failed: The registry should be a string\");return oc(r)}async function bQ(t,{authType:e=2,configuration:r,ident:o}){let a=Bq(t,{configuration:r,ident:o}),n=T1t(a,e);if(!n)return null;let u=await r.reduceHook(A=>A.getNpmAuthenticationHeader,void 0,t,{configuration:r,ident:o});if(u)return u;if(a.get(\"npmAuthToken\"))return`Bearer ${a.get(\"npmAuthToken\")}`;if(a.get(\"npmAuthIdent\")){let A=a.get(\"npmAuthIdent\");return A.includes(\":\")?`Basic ${Buffer.from(A).toString(\"base64\")}`:`Basic ${A}`}if(n&&e!==1)throw new Jt(33,\"No authentication configured for request\");return null}function T1t(t,e){switch(e){case 2:return t.get(\"npmAlwaysAuth\");case 1:case 3:return!0;case 0:return!1;default:throw new Error(\"Unreachable\")}}async function N1t(t,e,{configuration:r}){if(typeof e>\"u\"||typeof e.authorization>\"u\")return\"an anonymous user\";try{return(await rn.get(new Dq.URL(`${t}/-/whoami`).href,{configuration:r,headers:e,jsonResponse:!0})).username??\"an unknown user\"}catch{return\"an unknown user\"}}async function Pq(t,{configuration:e}){let r=t.originalError?.response.headers[\"npm-notice\"];if(r&&(await Nt.start({configuration:e,stdout:process.stdout,includeFooter:!1},async a=>{if(a.reportInfo(0,r.replace(/(https?:\\/\\/\\S+)/g,de.pretty(e,\"$1\",de.Type.URL))),!process.env.YARN_IS_TEST_ENV){let n=r.match(/open (https?:\\/\\/\\S+)/i);if(n&&zi.openUrl){let{openNow:u}=await(0,vq.prompt)({type:\"confirm\",name:\"openNow\",message:\"Do you want to try to open this url now?\",required:!0,initial:!0,onCancel:()=>process.exit(130)});u&&(await zi.openUrl(n[1])||(a.reportSeparator(),a.reportWarning(0,\"We failed to automatically open the url; you'll have to open it yourself in your browser of choice.\")))}}}),process.stdout.write(`\n`)),process.env.YARN_IS_TEST_ENV)return process.env.YARN_INJECT_NPM_2FA_TOKEN||\"\";let{otp:o}=await(0,vq.prompt)({type:\"password\",name:\"otp\",message:\"One-time password:\",required:!0,onCancel:()=>process.exit(130)});return process.stdout.write(`\n`),o}function xQ(t){if(t.originalError?.name!==\"HTTPError\")return!1;try{return(t.originalError?.response.headers[\"www-authenticate\"].split(/,\\s*/).map(r=>r.toLowerCase())).includes(\"otp\")}catch{return!1}}function WC(t){return{[\"npm-otp\"]:t}}var fv=class{supports(e,r){if(!e.reference.startsWith(Wn))return!1;let{selector:o,params:a}=W.parseRange(e.reference);return!(!b1e.default.valid(o)||a===null||typeof a.__archiveUrl!=\"string\")}getLocalPath(e,r){return null}async fetch(e,r){let o=r.checksums.get(e.locatorHash)||null,[a,n,u]=await r.cache.fetchPackageFromCache(e,o,{onHit:()=>r.report.reportCacheHit(e),onMiss:()=>r.report.reportCacheMiss(e,`${W.prettyLocator(r.project.configuration,e)} can't be found in the cache and will be fetched from the remote server`),loader:()=>this.fetchFromNetwork(e,r),...r.cacheOptions});return{packageFs:a,releaseFs:n,prefixPath:W.getIdentVendorPath(e),checksum:u}}async fetchFromNetwork(e,r){let{params:o}=W.parseRange(e.reference);if(o===null||typeof o.__archiveUrl!=\"string\")throw new Error(\"Assertion failed: The archiveUrl querystring parameter should have been available\");let a=await mm(o.__archiveUrl,{customErrorMessage:dm,configuration:r.project.configuration,ident:e});return await Xi.convertToZip(a,{configuration:r.project.configuration,prefixPath:W.getIdentVendorPath(e),stripComponents:1})}};Ye();var pv=class{supportsDescriptor(e,r){return!(!e.range.startsWith(Wn)||!W.tryParseDescriptor(e.range.slice(Wn.length),!0))}supportsLocator(e,r){return!1}shouldPersistResolution(e,r){throw new Error(\"Unreachable\")}bindDescriptor(e,r,o){return e}getResolutionDependencies(e,r){let o=r.project.configuration.normalizeDependency(W.parseDescriptor(e.range.slice(Wn.length),!0));return r.resolver.getResolutionDependencies(o,r)}async getCandidates(e,r,o){let a=o.project.configuration.normalizeDependency(W.parseDescriptor(e.range.slice(Wn.length),!0));return await o.resolver.getCandidates(a,r,o)}async getSatisfying(e,r,o,a){let n=a.project.configuration.normalizeDependency(W.parseDescriptor(e.range.slice(Wn.length),!0));return a.resolver.getSatisfying(n,r,o,a)}resolve(e,r){throw new Error(\"Unreachable\")}};Ye();Ye();var x1e=$e(Jn()),k1e=Be(\"url\");var dl=class{supports(e,r){if(!e.reference.startsWith(Wn))return!1;let o=new k1e.URL(e.reference);return!(!x1e.default.valid(o.pathname)||o.searchParams.has(\"__archiveUrl\"))}getLocalPath(e,r){return null}async fetch(e,r){let o=r.checksums.get(e.locatorHash)||null,[a,n,u]=await r.cache.fetchPackageFromCache(e,o,{onHit:()=>r.report.reportCacheHit(e),onMiss:()=>r.report.reportCacheMiss(e,`${W.prettyLocator(r.project.configuration,e)} can't be found in the cache and will be fetched from the remote registry`),loader:()=>this.fetchFromNetwork(e,r),...r.cacheOptions});return{packageFs:a,releaseFs:n,prefixPath:W.getIdentVendorPath(e),checksum:u}}async fetchFromNetwork(e,r){let o;try{o=await mm(dl.getLocatorUrl(e),{customErrorMessage:dm,configuration:r.project.configuration,ident:e})}catch{o=await mm(dl.getLocatorUrl(e).replace(/%2f/g,\"/\"),{customErrorMessage:dm,configuration:r.project.configuration,ident:e})}return await Xi.convertToZip(o,{configuration:r.project.configuration,prefixPath:W.getIdentVendorPath(e),stripComponents:1})}static isConventionalTarballUrl(e,r,{configuration:o}){let a=YC(e.scope,{configuration:o}),n=dl.getLocatorUrl(e);return r=r.replace(/^https?:(\\/\\/(?:[^/]+\\.)?npmjs.org(?:$|\\/))/,\"https:$1\"),a=a.replace(/^https:\\/\\/registry\\.npmjs\\.org($|\\/)/,\"https://registry.yarnpkg.com$1\"),r=r.replace(/^https:\\/\\/registry\\.npmjs\\.org($|\\/)/,\"https://registry.yarnpkg.com$1\"),r===a+n||r===a+n.replace(/%2f/g,\"/\")}static getLocatorUrl(e){let r=kr.clean(e.reference.slice(Wn.length));if(r===null)throw new Jt(10,\"The npm semver resolver got selected, but the version isn't semver\");return`${SQ(e)}/-/${e.name}-${r}.tgz`}};Ye();Ye();Ye();var Sq=$e(Jn());var kQ=W.makeIdent(null,\"node-gyp\"),L1t=/\\b(node-gyp|prebuild-install)\\b/,hv=class{supportsDescriptor(e,r){return e.range.startsWith(Wn)?!!kr.validRange(e.range.slice(Wn.length)):!1}supportsLocator(e,r){if(!e.reference.startsWith(Wn))return!1;let{selector:o}=W.parseRange(e.reference);return!!Sq.default.valid(o)}shouldPersistResolution(e,r){return!0}bindDescriptor(e,r,o){return e}getResolutionDependencies(e,r){return{}}async getCandidates(e,r,o){let a=kr.validRange(e.range.slice(Wn.length));if(a===null)throw new Error(`Expected a valid range, got ${e.range.slice(Wn.length)}`);let n=await KC(e,{cache:o.fetchOptions?.cache,project:o.project,version:Sq.default.valid(a.raw)?a.raw:void 0}),u=je.mapAndFilter(Object.keys(n.versions),h=>{try{let C=new kr.SemVer(h);if(a.test(C))return C}catch{}return je.mapAndFilter.skip}),A=u.filter(h=>!n.versions[h.raw].deprecated),p=A.length>0?A:u;return p.sort((h,C)=>-h.compare(C)),p.map(h=>{let C=W.makeLocator(e,`${Wn}${h.raw}`),I=n.versions[h.raw].dist.tarball;return dl.isConventionalTarballUrl(C,I,{configuration:o.project.configuration})?C:W.bindLocator(C,{__archiveUrl:I})})}async getSatisfying(e,r,o,a){let n=kr.validRange(e.range.slice(Wn.length));if(n===null)throw new Error(`Expected a valid range, got ${e.range.slice(Wn.length)}`);return{locators:je.mapAndFilter(o,p=>{if(p.identHash!==e.identHash)return je.mapAndFilter.skip;let h=W.tryParseRange(p.reference,{requireProtocol:Wn});if(!h)return je.mapAndFilter.skip;let C=new kr.SemVer(h.selector);return n.test(C)?{locator:p,version:C}:je.mapAndFilter.skip}).sort((p,h)=>-p.version.compare(h.version)).map(({locator:p})=>p),sorted:!0}}async resolve(e,r){let{selector:o}=W.parseRange(e.reference),a=kr.clean(o);if(a===null)throw new Jt(10,\"The npm semver resolver got selected, but the version isn't semver\");let n=await KC(e,{cache:r.fetchOptions?.cache,project:r.project,version:a});if(!Object.hasOwn(n,\"versions\"))throw new Jt(15,'Registry returned invalid data for - missing \"versions\" field');if(!Object.hasOwn(n.versions,a))throw new Jt(16,`Registry failed to return reference \"${a}\"`);let u=new Ot;if(u.load(n.versions[a]),!u.dependencies.has(kQ.identHash)&&!u.peerDependencies.has(kQ.identHash)){for(let A of u.scripts.values())if(A.match(L1t)){u.dependencies.set(kQ.identHash,W.makeDescriptor(kQ,\"latest\"));break}}return{...e,version:a,languageName:\"node\",linkType:\"HARD\",conditions:u.getConditions(),dependencies:r.project.configuration.normalizeDependencyMap(u.dependencies),peerDependencies:u.peerDependencies,dependenciesMeta:u.dependenciesMeta,peerDependenciesMeta:u.peerDependenciesMeta,bin:u.bin}}};Ye();Ye();var Q1e=$e(Jn());var gv=class{supportsDescriptor(e,r){return!(!e.range.startsWith(Wn)||!kE.test(e.range.slice(Wn.length)))}supportsLocator(e,r){return!1}shouldPersistResolution(e,r){throw new Error(\"Unreachable\")}bindDescriptor(e,r,o){return e}getResolutionDependencies(e,r){return{}}async getCandidates(e,r,o){let a=e.range.slice(Wn.length),n=await KC(e,{cache:o.fetchOptions?.cache,project:o.project});if(!Object.hasOwn(n,\"dist-tags\"))throw new Jt(15,'Registry returned invalid data - missing \"dist-tags\" field');let u=n[\"dist-tags\"];if(!Object.hasOwn(u,a))throw new Jt(16,`Registry failed to return tag \"${a}\"`);let A=u[a],p=W.makeLocator(e,`${Wn}${A}`),h=n.versions[A].dist.tarball;return dl.isConventionalTarballUrl(p,h,{configuration:o.project.configuration})?[p]:[W.bindLocator(p,{__archiveUrl:h})]}async getSatisfying(e,r,o,a){let n=[];for(let u of o){if(u.identHash!==e.identHash)continue;let A=W.tryParseRange(u.reference,{requireProtocol:Wn});if(!(!A||!Q1e.default.valid(A.selector))){if(A.params?.__archiveUrl){let p=W.makeRange({protocol:Wn,selector:A.selector,source:null,params:null}),[h]=await a.resolver.getCandidates(W.makeDescriptor(e,p),r,a);if(u.reference!==h.reference)continue}n.push(u)}}return{locators:n,sorted:!1}}async resolve(e,r){throw new Error(\"Unreachable\")}};var iw={};Vt(iw,{getGitHead:()=>Tvt,getPublishAccess:()=>wBe,getReadmeContent:()=>IBe,makePublishBody:()=>Rvt});Ye();Ye();Pt();var gG={};Vt(gG,{PackCommand:()=>O0,default:()=>gvt,packUtils:()=>CA});Ye();Ye();Ye();Pt();qt();var CA={};Vt(CA,{genPackList:()=>$Q,genPackStream:()=>hG,genPackageManifest:()=>lBe,hasPackScripts:()=>fG,prepareForPack:()=>pG});Ye();Pt();var AG=$e(Zo()),oBe=$e(rBe()),aBe=Be(\"zlib\"),ivt=[\"/package.json\",\"/readme\",\"/readme.*\",\"/license\",\"/license.*\",\"/licence\",\"/licence.*\",\"/changelog\",\"/changelog.*\"],svt=[\"/package.tgz\",\".github\",\".git\",\".hg\",\"node_modules\",\".npmignore\",\".gitignore\",\".#*\",\".DS_Store\"];async function fG(t){return!!(un.hasWorkspaceScript(t,\"prepack\")||un.hasWorkspaceScript(t,\"postpack\"))}async function pG(t,{report:e},r){await un.maybeExecuteWorkspaceLifecycleScript(t,\"prepack\",{report:e});try{let o=V.join(t.cwd,Ot.fileName);await oe.existsPromise(o)&&await t.manifest.loadFile(o,{baseFs:oe}),await r()}finally{await un.maybeExecuteWorkspaceLifecycleScript(t,\"postpack\",{report:e})}}async function hG(t,e){typeof e>\"u\"&&(e=await $Q(t));let r=new Set;for(let n of t.manifest.publishConfig?.executableFiles??new Set)r.add(V.normalize(n));for(let n of t.manifest.bin.values())r.add(V.normalize(n));let o=oBe.default.pack();process.nextTick(async()=>{for(let n of e){let u=V.normalize(n),A=V.resolve(t.cwd,u),p=V.join(\"package\",u),h=await oe.lstatPromise(A),C={name:p,mtime:new Date(vi.SAFE_TIME*1e3)},I=r.has(u)?493:420,v,x,E=new Promise((L,U)=>{v=L,x=U}),R=L=>{L?x(L):v()};if(h.isFile()){let L;u===\"package.json\"?L=Buffer.from(JSON.stringify(await lBe(t),null,2)):L=await oe.readFilePromise(A),o.entry({...C,mode:I,type:\"file\"},L,R)}else h.isSymbolicLink()?o.entry({...C,mode:I,type:\"symlink\",linkname:await oe.readlinkPromise(A)},R):R(new Error(`Unsupported file type ${h.mode} for ${ue.fromPortablePath(u)}`));await E}o.finalize()});let a=(0,aBe.createGzip)();return o.pipe(a),a}async function lBe(t){let e=JSON.parse(JSON.stringify(t.manifest.raw));return await t.project.configuration.triggerHook(r=>r.beforeWorkspacePacking,t,e),e}async function $Q(t){let e=t.project,r=e.configuration,o={accept:[],reject:[]};for(let I of svt)o.reject.push(I);for(let I of ivt)o.accept.push(I);o.reject.push(r.get(\"rcFilename\"));let a=I=>{if(I===null||!I.startsWith(`${t.cwd}/`))return;let v=V.relative(t.cwd,I),x=V.resolve(Bt.root,v);o.reject.push(x)};a(V.resolve(e.cwd,dr.lockfile)),a(r.get(\"cacheFolder\")),a(r.get(\"globalFolder\")),a(r.get(\"installStatePath\")),a(r.get(\"virtualFolder\")),a(r.get(\"yarnPath\")),await r.triggerHook(I=>I.populateYarnPaths,e,I=>{a(I)});for(let I of e.workspaces){let v=V.relative(t.cwd,I.cwd);v!==\"\"&&!v.match(/^(\\.\\.)?\\//)&&o.reject.push(`/${v}`)}let n={accept:[],reject:[]},u=t.manifest.publishConfig?.main??t.manifest.main,A=t.manifest.publishConfig?.module??t.manifest.module,p=t.manifest.publishConfig?.browser??t.manifest.browser,h=t.manifest.publishConfig?.bin??t.manifest.bin;u!=null&&n.accept.push(V.resolve(Bt.root,u)),A!=null&&n.accept.push(V.resolve(Bt.root,A)),typeof p==\"string\"&&n.accept.push(V.resolve(Bt.root,p));for(let I of h.values())n.accept.push(V.resolve(Bt.root,I));if(p instanceof Map)for(let[I,v]of p.entries())n.accept.push(V.resolve(Bt.root,I)),typeof v==\"string\"&&n.accept.push(V.resolve(Bt.root,v));let C=t.manifest.files!==null;if(C){n.reject.push(\"/*\");for(let I of t.manifest.files)cBe(n.accept,I,{cwd:Bt.root})}return await ovt(t.cwd,{hasExplicitFileList:C,globalList:o,ignoreList:n})}async function ovt(t,{hasExplicitFileList:e,globalList:r,ignoreList:o}){let a=[],n=new _u(t),u=[[Bt.root,[o]]];for(;u.length>0;){let[A,p]=u.pop(),h=await n.lstatPromise(A);if(!iBe(A,{globalList:r,ignoreLists:h.isDirectory()?null:p}))if(h.isDirectory()){let C=await n.readdirPromise(A),I=!1,v=!1;if(!e||A!==Bt.root)for(let R of C)I=I||R===\".gitignore\",v=v||R===\".npmignore\";let x=v?await nBe(n,A,\".npmignore\"):I?await nBe(n,A,\".gitignore\"):null,E=x!==null?[x].concat(p):p;iBe(A,{globalList:r,ignoreLists:p})&&(E=[...p,{accept:[],reject:[\"**/*\"]}]);for(let R of C)u.push([V.resolve(A,R),E])}else(h.isFile()||h.isSymbolicLink())&&a.push(V.relative(Bt.root,A))}return a.sort()}async function nBe(t,e,r){let o={accept:[],reject:[]},a=await t.readFilePromise(V.join(e,r),\"utf8\");for(let n of a.split(/\\n/g))cBe(o.reject,n,{cwd:e});return o}function avt(t,{cwd:e}){let r=t[0]===\"!\";return r&&(t=t.slice(1)),t.match(/\\.{0,1}\\//)&&(t=V.resolve(e,t)),r&&(t=`!${t}`),t}function cBe(t,e,{cwd:r}){let o=e.trim();o===\"\"||o[0]===\"#\"||t.push(avt(o,{cwd:r}))}function iBe(t,{globalList:e,ignoreLists:r}){let o=ZQ(t,e.accept);if(o!==0)return o===2;let a=ZQ(t,e.reject);if(a!==0)return a===1;if(r!==null)for(let n of r){let u=ZQ(t,n.accept);if(u!==0)return u===2;let A=ZQ(t,n.reject);if(A!==0)return A===1}return!1}function ZQ(t,e){let r=e,o=[];for(let a=0;a<e.length;++a)e[a][0]!==\"!\"?r!==e&&r.push(e[a]):(r===e&&(r=e.slice(0,a)),o.push(e[a].slice(1)));return sBe(t,o)?2:sBe(t,r)?1:0}function sBe(t,e){let r=e,o=[];for(let a=0;a<e.length;++a)e[a].includes(\"/\")?r!==e&&r.push(e[a]):(r===e&&(r=e.slice(0,a)),o.push(e[a]));return!!(AG.default.isMatch(t,r,{dot:!0,nocase:!0})||AG.default.isMatch(t,o,{dot:!0,basename:!0,nocase:!0}))}var O0=class extends ut{constructor(){super(...arguments);this.installIfNeeded=ge.Boolean(\"--install-if-needed\",!1,{description:\"Run a preliminary `yarn install` if the package contains build scripts\"});this.dryRun=ge.Boolean(\"-n,--dry-run\",!1,{description:\"Print the file paths without actually generating the package archive\"});this.json=ge.Boolean(\"--json\",!1,{description:\"Format the output as an NDJSON stream\"});this.out=ge.String(\"-o,--out\",{description:\"Create the archive at the specified path\"});this.filename=ge.String(\"--filename\",{hidden:!0})}async execute(){let r=await Ke.find(this.context.cwd,this.context.plugins),{project:o,workspace:a}=await St.find(r,this.context.cwd);if(!a)throw new rr(o.cwd,this.context.cwd);await fG(a)&&(this.installIfNeeded?await o.install({cache:await Lr.find(r),report:new Qi}):await o.restoreInstallState());let n=this.out??this.filename,u=typeof n<\"u\"?V.resolve(this.context.cwd,lvt(n,{workspace:a})):V.resolve(a.cwd,\"package.tgz\");return(await Nt.start({configuration:r,stdout:this.context.stdout,json:this.json},async p=>{await pG(a,{report:p},async()=>{p.reportJson({base:ue.fromPortablePath(a.cwd)});let h=await $Q(a);for(let C of h)p.reportInfo(null,ue.fromPortablePath(C)),p.reportJson({location:ue.fromPortablePath(C)});if(!this.dryRun){let C=await hG(a,h),I=oe.createWriteStream(u);C.pipe(I),await new Promise(v=>{I.on(\"finish\",v)})}}),this.dryRun||(p.reportInfo(0,`Package archive generated in ${de.pretty(r,u,de.Type.PATH)}`),p.reportJson({output:ue.fromPortablePath(u)}))})).exitCode()}};O0.paths=[[\"pack\"]],O0.usage=nt.Usage({description:\"generate a tarball from the active workspace\",details:\"\\n      This command will turn the active workspace into a compressed archive suitable for publishing. The archive will by default be stored at the root of the workspace (`package.tgz`).\\n\\n      If the `-o,---out` is set the archive will be created at the specified path. The `%s` and `%v` variables can be used within the path and will be respectively replaced by the package name and version.\\n    \",examples:[[\"Create an archive from the active workspace\",\"yarn pack\"],[\"List the files that would be made part of the workspace's archive\",\"yarn pack --dry-run\"],[\"Name and output the archive in a dedicated folder\",\"yarn pack --out /artifacts/%s-%v.tgz\"]]});function lvt(t,{workspace:e}){let r=t.replace(\"%s\",cvt(e)).replace(\"%v\",uvt(e));return ue.toPortablePath(r)}function cvt(t){return t.manifest.name!==null?W.slugifyIdent(t.manifest.name):\"package\"}function uvt(t){return t.manifest.version!==null?t.manifest.version:\"unknown\"}var Avt=[\"dependencies\",\"devDependencies\",\"peerDependencies\"],fvt=\"workspace:\",pvt=(t,e)=>{e.publishConfig&&(e.publishConfig.type&&(e.type=e.publishConfig.type),e.publishConfig.main&&(e.main=e.publishConfig.main),e.publishConfig.browser&&(e.browser=e.publishConfig.browser),e.publishConfig.module&&(e.module=e.publishConfig.module),e.publishConfig.exports&&(e.exports=e.publishConfig.exports),e.publishConfig.imports&&(e.imports=e.publishConfig.imports),e.publishConfig.bin&&(e.bin=e.publishConfig.bin));let r=t.project;for(let o of Avt)for(let a of t.manifest.getForScope(o).values()){let n=r.tryWorkspaceByDescriptor(a),u=W.parseRange(a.range);if(u.protocol===fvt)if(n===null){if(r.tryWorkspaceByIdent(a)===null)throw new Jt(21,`${W.prettyDescriptor(r.configuration,a)}: No local workspace found for this range`)}else{let A;W.areDescriptorsEqual(a,n.anchoredDescriptor)||u.selector===\"*\"?A=n.manifest.version??\"0.0.0\":u.selector===\"~\"||u.selector===\"^\"?A=`${u.selector}${n.manifest.version??\"0.0.0\"}`:A=u.selector;let p=o===\"dependencies\"?W.makeDescriptor(a,\"unknown\"):null,h=p!==null&&t.manifest.ensureDependencyMeta(p).optional?\"optionalDependencies\":o;e[h][W.stringifyIdent(a)]=A}}},hvt={hooks:{beforeWorkspacePacking:pvt},commands:[O0]},gvt=hvt;var yBe=Be(\"crypto\"),EBe=$e(mBe()),CBe=Be(\"url\");async function Rvt(t,e,{access:r,tag:o,registry:a,gitHead:n}){let u=t.manifest.name,A=t.manifest.version,p=W.stringifyIdent(u),h=(0,yBe.createHash)(\"sha1\").update(e).digest(\"hex\"),C=EBe.default.fromData(e).toString(),I=r??wBe(t,u),v=await IBe(t),x=await CA.genPackageManifest(t),E=`${p}-${A}.tgz`,R=new CBe.URL(`${oc(a)}/${p}/-/${E}`);return{_id:p,_attachments:{[E]:{content_type:\"application/octet-stream\",data:e.toString(\"base64\"),length:e.length}},name:p,access:I,[\"dist-tags\"]:{[o]:A},versions:{[A]:{...x,_id:`${p}@${A}`,name:p,version:A,gitHead:n,dist:{shasum:h,integrity:C,tarball:R.toString()}}},readme:v}}async function Tvt(t){try{let{stdout:e}=await Ur.execvp(\"git\",[\"rev-parse\",\"--revs-only\",\"HEAD\"],{cwd:t});return e.trim()===\"\"?void 0:e.trim()}catch{return}}function wBe(t,e){let r=t.project.configuration;return t.manifest.publishConfig&&typeof t.manifest.publishConfig.access==\"string\"?t.manifest.publishConfig.access:r.get(\"npmPublishAccess\")!==null?r.get(\"npmPublishAccess\"):e.scope?\"restricted\":\"public\"}async function IBe(t){let e=ue.toPortablePath(`${t.cwd}/README.md`),r=t.manifest.name,a=`# ${W.stringifyIdent(r)}\n`;try{a=await oe.readFilePromise(e,\"utf8\")}catch(n){if(n.code===\"ENOENT\")return a;throw n}return a}var EG={npmAlwaysAuth:{description:\"URL of the selected npm registry (note: npm enterprise isn't supported)\",type:\"BOOLEAN\",default:!1},npmAuthIdent:{description:\"Authentication identity for the npm registry (_auth in npm and yarn v1)\",type:\"SECRET\",default:null},npmAuthToken:{description:\"Authentication token for the npm registry (_authToken in npm and yarn v1)\",type:\"SECRET\",default:null}},BBe={npmAuditRegistry:{description:\"Registry to query for audit reports\",type:\"STRING\",default:null},npmPublishRegistry:{description:\"Registry to push packages to\",type:\"STRING\",default:null},npmRegistryServer:{description:\"URL of the selected npm registry (note: npm enterprise isn't supported)\",type:\"STRING\",default:\"https://registry.yarnpkg.com\"}},Nvt={configuration:{...EG,...BBe,npmScopes:{description:\"Settings per package scope\",type:\"MAP\",valueDefinition:{description:\"\",type:\"SHAPE\",properties:{...EG,...BBe}}},npmRegistries:{description:\"Settings per registry\",type:\"MAP\",normalizeKeys:oc,valueDefinition:{description:\"\",type:\"SHAPE\",properties:{...EG}}}},fetchers:[fv,dl],resolvers:[pv,hv,gv]},Lvt=Nvt;var xG={};Vt(xG,{NpmAuditCommand:()=>U0,NpmInfoCommand:()=>_0,NpmLoginCommand:()=>H0,NpmLogoutCommand:()=>j0,NpmPublishCommand:()=>q0,NpmTagAddCommand:()=>Y0,NpmTagListCommand:()=>G0,NpmTagRemoveCommand:()=>W0,NpmWhoamiCommand:()=>K0,default:()=>jvt,npmAuditTypes:()=>Rv,npmAuditUtils:()=>eF});Ye();Ye();qt();var DG=$e(Zo());Za();var Rv={};Vt(Rv,{Environment:()=>Qv,Severity:()=>Fv});var Qv=(o=>(o.All=\"all\",o.Production=\"production\",o.Development=\"development\",o))(Qv||{}),Fv=(n=>(n.Info=\"info\",n.Low=\"low\",n.Moderate=\"moderate\",n.High=\"high\",n.Critical=\"critical\",n))(Fv||{});var eF={};Vt(eF,{allSeverities:()=>sw,getPackages:()=>vG,getReportTree:()=>IG,getSeverityInclusions:()=>wG,getTopLevelDependencies:()=>BG});Ye();var vBe=$e(Jn());var sw=[\"info\",\"low\",\"moderate\",\"high\",\"critical\"];function wG(t){if(typeof t>\"u\")return new Set(sw);let e=sw.indexOf(t),r=sw.slice(e);return new Set(r)}function IG(t){let e={},r={children:e};for(let[o,a]of je.sortMap(Object.entries(t),n=>n[0]))for(let n of je.sortMap(a,u=>`${u.id}`))e[`${o}/${n.id}`]={value:de.tuple(de.Type.IDENT,W.parseIdent(o)),children:{ID:typeof n.id<\"u\"&&{label:\"ID\",value:de.tuple(de.Type.ID,n.id)},Issue:{label:\"Issue\",value:de.tuple(de.Type.NO_HINT,n.title)},URL:typeof n.url<\"u\"&&{label:\"URL\",value:de.tuple(de.Type.URL,n.url)},Severity:{label:\"Severity\",value:de.tuple(de.Type.NO_HINT,n.severity)},[\"Vulnerable Versions\"]:{label:\"Vulnerable Versions\",value:de.tuple(de.Type.RANGE,n.vulnerable_versions)},[\"Tree Versions\"]:{label:\"Tree Versions\",children:[...n.versions].sort(vBe.default.compare).map(u=>({value:de.tuple(de.Type.REFERENCE,u)}))},Dependents:{label:\"Dependents\",children:je.sortMap(n.dependents,u=>W.stringifyLocator(u)).map(u=>({value:de.tuple(de.Type.LOCATOR,u)}))}}};return r}function BG(t,e,{all:r,environment:o}){let a=[],n=r?t.workspaces:[e],u=[\"all\",\"production\"].includes(o),A=[\"all\",\"development\"].includes(o);for(let p of n)for(let h of p.anchoredPackage.dependencies.values())(p.manifest.devDependencies.has(h.identHash)?!A:!u)||a.push({workspace:p,dependency:h});return a}function vG(t,e,{recursive:r}){let o=new Map,a=new Set,n=[],u=(A,p)=>{let h=t.storedResolutions.get(p.descriptorHash);if(typeof h>\"u\")throw new Error(\"Assertion failed: The resolution should have been registered\");if(!a.has(h))a.add(h);else return;let C=t.storedPackages.get(h);if(typeof C>\"u\")throw new Error(\"Assertion failed: The package should have been registered\");if(W.ensureDevirtualizedLocator(C).reference.startsWith(\"npm:\")&&C.version!==null){let v=W.stringifyIdent(C),x=je.getMapWithDefault(o,v);je.getArrayWithDefault(x,C.version).push(A)}if(r)for(let v of C.dependencies.values())n.push([C,v])};for(let{workspace:A,dependency:p}of e)n.push([A.anchoredLocator,p]);for(;n.length>0;){let[A,p]=n.shift();u(A,p)}return o}var U0=class extends ut{constructor(){super(...arguments);this.all=ge.Boolean(\"-A,--all\",!1,{description:\"Audit dependencies from all workspaces\"});this.recursive=ge.Boolean(\"-R,--recursive\",!1,{description:\"Audit transitive dependencies as well\"});this.environment=ge.String(\"--environment\",\"all\",{description:\"Which environments to cover\",validator:Ks(Qv)});this.json=ge.Boolean(\"--json\",!1,{description:\"Format the output as an NDJSON stream\"});this.noDeprecations=ge.Boolean(\"--no-deprecations\",!1,{description:\"Don't warn about deprecated packages\"});this.severity=ge.String(\"--severity\",\"info\",{description:\"Minimal severity requested for packages to be displayed\",validator:Ks(Fv)});this.excludes=ge.Array(\"--exclude\",[],{description:\"Array of glob patterns of packages to exclude from audit\"});this.ignores=ge.Array(\"--ignore\",[],{description:\"Array of glob patterns of advisory ID's to ignore in the audit report\"})}async execute(){let r=await Ke.find(this.context.cwd,this.context.plugins),{project:o,workspace:a}=await St.find(r,this.context.cwd);if(!a)throw new rr(o.cwd,this.context.cwd);await o.restoreInstallState();let n=BG(o,a,{all:this.all,environment:this.environment}),u=vG(o,n,{recursive:this.recursive}),A=Array.from(new Set([...r.get(\"npmAuditExcludePackages\"),...this.excludes])),p=Object.create(null);for(let[L,U]of u)A.some(z=>DG.default.isMatch(L,z))||(p[L]=[...U.keys()]);let h=Zn.getAuditRegistry({configuration:r}),C,I=await AA.start({configuration:r,stdout:this.context.stdout},async()=>{let L=on.post(\"/-/npm/v1/security/advisories/bulk\",p,{authType:on.AuthType.BEST_EFFORT,configuration:r,jsonResponse:!0,registry:h}),U=this.noDeprecations?[]:await Promise.all(Array.from(Object.entries(p),async([te,le])=>{let he=await on.getPackageMetadata(W.parseIdent(te),{project:o});return je.mapAndFilter(le,Ae=>{let{deprecated:ye}=he.versions[Ae];return ye?[te,Ae,ye]:je.mapAndFilter.skip})})),z=await L;for(let[te,le,he]of U.flat(1))Object.hasOwn(z,te)&&z[te].some(Ae=>kr.satisfiesWithPrereleases(le,Ae.vulnerable_versions))||(z[te]??=[],z[te].push({id:`${te} (deprecation)`,title:he.trim()||\"This package has been deprecated.\",severity:\"moderate\",vulnerable_versions:le}));C=z});if(I.hasErrors())return I.exitCode();let v=wG(this.severity),x=Array.from(new Set([...r.get(\"npmAuditIgnoreAdvisories\"),...this.ignores])),E=Object.create(null);for(let[L,U]of Object.entries(C)){let z=U.filter(te=>!DG.default.isMatch(`${te.id}`,x)&&v.has(te.severity));z.length>0&&(E[L]=z.map(te=>{let le=u.get(L);if(typeof le>\"u\")throw new Error(\"Assertion failed: Expected the registry to only return packages that were requested\");let he=[...le.keys()].filter(ye=>kr.satisfiesWithPrereleases(ye,te.vulnerable_versions)),Ae=new Map;for(let ye of he)for(let ae of le.get(ye))Ae.set(ae.locatorHash,ae);return{...te,versions:he,dependents:[...Ae.values()]}}))}let R=Object.keys(E).length>0;return R?($s.emitTree(IG(E),{configuration:r,json:this.json,stdout:this.context.stdout,separators:2}),1):(await Nt.start({configuration:r,includeFooter:!1,json:this.json,stdout:this.context.stdout},async L=>{L.reportInfo(1,\"No audit suggestions\")}),R?1:0)}};U0.paths=[[\"npm\",\"audit\"]],U0.usage=nt.Usage({description:\"perform a vulnerability audit against the installed packages\",details:`\n      This command checks for known security reports on the packages you use. The reports are by default extracted from the npm registry, and may or may not be relevant to your actual program (not all vulnerabilities affect all code paths).\n\n      For consistency with our other commands the default is to only check the direct dependencies for the active workspace. To extend this search to all workspaces, use \\`-A,--all\\`. To extend this search to both direct and transitive dependencies, use \\`-R,--recursive\\`.\n\n      Applying the \\`--severity\\` flag will limit the audit table to vulnerabilities of the corresponding severity and above. Valid values are ${sw.map(r=>`\\`${r}\\``).join(\", \")}.\n\n      If the \\`--json\\` flag is set, Yarn will print the output exactly as received from the registry. Regardless of this flag, the process will exit with a non-zero exit code if a report is found for the selected packages.\n\n      If certain packages produce false positives for a particular environment, the \\`--exclude\\` flag can be used to exclude any number of packages from the audit. This can also be set in the configuration file with the \\`npmAuditExcludePackages\\` option.\n\n      If particular advisories are needed to be ignored, the \\`--ignore\\` flag can be used with Advisory ID's to ignore any number of advisories in the audit report. This can also be set in the configuration file with the \\`npmAuditIgnoreAdvisories\\` option.\n\n      To understand the dependency tree requiring vulnerable packages, check the raw report with the \\`--json\\` flag or use \\`yarn why package\\` to get more information as to who depends on them.\n    `,examples:[[\"Checks for known security issues with the installed packages. The output is a list of known issues.\",\"yarn npm audit\"],[\"Audit dependencies in all workspaces\",\"yarn npm audit --all\"],[\"Limit auditing to `dependencies` (excludes `devDependencies`)\",\"yarn npm audit --environment production\"],[\"Show audit report as valid JSON\",\"yarn npm audit --json\"],[\"Audit all direct and transitive dependencies\",\"yarn npm audit --recursive\"],[\"Output moderate (or more severe) vulnerabilities\",\"yarn npm audit --severity moderate\"],[\"Exclude certain packages\",\"yarn npm audit --exclude package1 --exclude package2\"],[\"Ignore specific advisories\",\"yarn npm audit --ignore 1234567 --ignore 7654321\"]]});Ye();Ye();Pt();qt();var PG=$e(Jn()),SG=Be(\"util\"),_0=class extends ut{constructor(){super(...arguments);this.fields=ge.String(\"-f,--fields\",{description:\"A comma-separated list of manifest fields that should be displayed\"});this.json=ge.Boolean(\"--json\",!1,{description:\"Format the output as an NDJSON stream\"});this.packages=ge.Rest()}async execute(){let r=await Ke.find(this.context.cwd,this.context.plugins),{project:o}=await St.find(r,this.context.cwd),a=typeof this.fields<\"u\"?new Set([\"name\",...this.fields.split(/\\s*,\\s*/)]):null,n=[],u=!1,A=await Nt.start({configuration:r,includeFooter:!1,json:this.json,stdout:this.context.stdout},async p=>{for(let h of this.packages){let C;if(h===\".\"){let le=o.topLevelWorkspace;if(!le.manifest.name)throw new it(`Missing ${de.pretty(r,\"name\",de.Type.CODE)} field in ${ue.fromPortablePath(V.join(le.cwd,dr.manifest))}`);C=W.makeDescriptor(le.manifest.name,\"unknown\")}else C=W.parseDescriptor(h);let I=on.getIdentUrl(C),v=bG(await on.get(I,{configuration:r,ident:C,jsonResponse:!0,customErrorMessage:on.customPackageError})),x=Object.keys(v.versions).sort(PG.default.compareLoose),R=v[\"dist-tags\"].latest||x[x.length-1],L=kr.validRange(C.range);if(L){let le=PG.default.maxSatisfying(x,L);le!==null?R=le:(p.reportWarning(0,`Unmet range ${W.prettyRange(r,C.range)}; falling back to the latest version`),u=!0)}else Object.hasOwn(v[\"dist-tags\"],C.range)?R=v[\"dist-tags\"][C.range]:C.range!==\"unknown\"&&(p.reportWarning(0,`Unknown tag ${W.prettyRange(r,C.range)}; falling back to the latest version`),u=!0);let U=v.versions[R],z={...v,...U,version:R,versions:x},te;if(a!==null){te={};for(let le of a){let he=z[le];if(typeof he<\"u\")te[le]=he;else{p.reportWarning(1,`The ${de.pretty(r,le,de.Type.CODE)} field doesn't exist inside ${W.prettyIdent(r,C)}'s information`),u=!0;continue}}}else this.json||(delete z.dist,delete z.readme,delete z.users),te=z;p.reportJson(te),this.json||n.push(te)}});SG.inspect.styles.name=\"cyan\";for(let p of n)(p!==n[0]||u)&&this.context.stdout.write(`\n`),this.context.stdout.write(`${(0,SG.inspect)(p,{depth:1/0,colors:!0,compact:!1})}\n`);return A.exitCode()}};_0.paths=[[\"npm\",\"info\"]],_0.usage=nt.Usage({category:\"Npm-related commands\",description:\"show information about a package\",details:\"\\n      This command fetches information about a package from the npm registry and prints it in a tree format.\\n\\n      The package does not have to be installed locally, but needs to have been published (in particular, local changes will be ignored even for workspaces).\\n\\n      Append `@<range>` to the package argument to provide information specific to the latest version that satisfies the range or to the corresponding tagged version. If the range is invalid or if there is no version satisfying the range, the command will print a warning and fall back to the latest version.\\n\\n      If the `-f,--fields` option is set, it's a comma-separated list of fields which will be used to only display part of the package information.\\n\\n      By default, this command won't return the `dist`, `readme`, and `users` fields, since they are often very long. To explicitly request those fields, explicitly list them with the `--fields` flag or request the output in JSON mode.\\n    \",examples:[[\"Show all available information about react (except the `dist`, `readme`, and `users` fields)\",\"yarn npm info react\"],[\"Show all available information about react as valid JSON (including the `dist`, `readme`, and `users` fields)\",\"yarn npm info react --json\"],[\"Show all available information about react@16.12.0\",\"yarn npm info react@16.12.0\"],[\"Show all available information about react@next\",\"yarn npm info react@next\"],[\"Show the description of react\",\"yarn npm info react --fields description\"],[\"Show all available versions of react\",\"yarn npm info react --fields versions\"],[\"Show the readme of react\",\"yarn npm info react --fields readme\"],[\"Show a few fields of react\",\"yarn npm info react --fields homepage,repository\"]]});function bG(t){if(Array.isArray(t)){let e=[];for(let r of t)r=bG(r),r&&e.push(r);return e}else if(typeof t==\"object\"&&t!==null){let e={};for(let r of Object.keys(t)){if(r.startsWith(\"_\"))continue;let o=bG(t[r]);o&&(e[r]=o)}return e}else return t||null}Ye();Ye();qt();var DBe=$e(u2()),H0=class extends ut{constructor(){super(...arguments);this.scope=ge.String(\"-s,--scope\",{description:\"Login to the registry configured for a given scope\"});this.publish=ge.Boolean(\"--publish\",!1,{description:\"Login to the publish registry\"});this.alwaysAuth=ge.Boolean(\"--always-auth\",{description:\"Set the npmAlwaysAuth configuration\"})}async execute(){let r=await Ke.find(this.context.cwd,this.context.plugins),o=await tF({configuration:r,cwd:this.context.cwd,publish:this.publish,scope:this.scope});return(await Nt.start({configuration:r,stdout:this.context.stdout,includeFooter:!1},async n=>{let u=await Mvt({configuration:r,registry:o,report:n,stdin:this.context.stdin,stdout:this.context.stdout}),A=`/-/user/org.couchdb.user:${encodeURIComponent(u.name)}`,p=await on.put(A,u,{attemptedAs:u.name,configuration:r,registry:o,jsonResponse:!0,authType:on.AuthType.NO_AUTH});return await Ovt(o,p.token,{alwaysAuth:this.alwaysAuth,scope:this.scope}),n.reportInfo(0,\"Successfully logged in\")})).exitCode()}};H0.paths=[[\"npm\",\"login\"]],H0.usage=nt.Usage({category:\"Npm-related commands\",description:\"store new login info to access the npm registry\",details:\"\\n      This command will ask you for your username, password, and 2FA One-Time-Password (when it applies). It will then modify your local configuration (in your home folder, never in the project itself) to reference the new tokens thus generated.\\n\\n      Adding the `-s,--scope` flag will cause the authentication to be done against whatever registry is configured for the associated scope (see also `npmScopes`).\\n\\n      Adding the `--publish` flag will cause the authentication to be done against the registry used when publishing the package (see also `publishConfig.registry` and `npmPublishRegistry`).\\n    \",examples:[[\"Login to the default registry\",\"yarn npm login\"],[\"Login to the registry linked to the @my-scope registry\",\"yarn npm login --scope my-scope\"],[\"Login to the publish registry for the current package\",\"yarn npm login --publish\"]]});async function tF({scope:t,publish:e,configuration:r,cwd:o}){return t&&e?Zn.getScopeRegistry(t,{configuration:r,type:Zn.RegistryType.PUBLISH_REGISTRY}):t?Zn.getScopeRegistry(t,{configuration:r}):e?Zn.getPublishRegistry((await uC(r,o)).manifest,{configuration:r}):Zn.getDefaultRegistry({configuration:r})}async function Ovt(t,e,{alwaysAuth:r,scope:o}){let a=u=>A=>{let p=je.isIndexableObject(A)?A:{},h=p[u],C=je.isIndexableObject(h)?h:{};return{...p,[u]:{...C,...r!==void 0?{npmAlwaysAuth:r}:{},npmAuthToken:e}}},n=o?{npmScopes:a(o)}:{npmRegistries:a(t)};return await Ke.updateHomeConfiguration(n)}async function Mvt({configuration:t,registry:e,report:r,stdin:o,stdout:a}){r.reportInfo(0,`Logging in to ${de.pretty(t,e,de.Type.URL)}`);let n=!1;if(e.match(/^https:\\/\\/npm\\.pkg\\.github\\.com(\\/|$)/)&&(r.reportInfo(0,\"You seem to be using the GitHub Package Registry. Tokens must be generated with the 'repo', 'write:packages', and 'read:packages' permissions.\"),n=!0),r.reportSeparator(),t.env.YARN_IS_TEST_ENV)return{name:t.env.YARN_INJECT_NPM_USER||\"\",password:t.env.YARN_INJECT_NPM_PASSWORD||\"\"};let{username:u,password:A}=await(0,DBe.prompt)([{type:\"input\",name:\"username\",message:\"Username:\",required:!0,onCancel:()=>process.exit(130),stdin:o,stdout:a},{type:\"password\",name:\"password\",message:n?\"Token:\":\"Password:\",required:!0,onCancel:()=>process.exit(130),stdin:o,stdout:a}]);return r.reportSeparator(),{name:u,password:A}}Ye();Ye();qt();var ow=new Set([\"npmAuthIdent\",\"npmAuthToken\"]),j0=class extends ut{constructor(){super(...arguments);this.scope=ge.String(\"-s,--scope\",{description:\"Logout of the registry configured for a given scope\"});this.publish=ge.Boolean(\"--publish\",!1,{description:\"Logout of the publish registry\"});this.all=ge.Boolean(\"-A,--all\",!1,{description:\"Logout of all registries\"})}async execute(){let r=await Ke.find(this.context.cwd,this.context.plugins),o=async()=>{let n=await tF({configuration:r,cwd:this.context.cwd,publish:this.publish,scope:this.scope}),u=await Ke.find(this.context.cwd,this.context.plugins),A=W.makeIdent(this.scope??null,\"pkg\");return!Zn.getAuthConfiguration(n,{configuration:u,ident:A}).get(\"npmAuthToken\")};return(await Nt.start({configuration:r,stdout:this.context.stdout},async n=>{if(this.all&&(await _vt(),n.reportInfo(0,\"Successfully logged out from everything\")),this.scope){await PBe(\"npmScopes\",this.scope),await o()?n.reportInfo(0,`Successfully logged out from ${this.scope}`):n.reportWarning(0,\"Scope authentication settings removed, but some other ones settings still apply to it\");return}let u=await tF({configuration:r,cwd:this.context.cwd,publish:this.publish});await PBe(\"npmRegistries\",u),await o()?n.reportInfo(0,`Successfully logged out from ${u}`):n.reportWarning(0,\"Registry authentication settings removed, but some other ones settings still apply to it\")})).exitCode()}};j0.paths=[[\"npm\",\"logout\"]],j0.usage=nt.Usage({category:\"Npm-related commands\",description:\"logout of the npm registry\",details:\"\\n      This command will log you out by modifying your local configuration (in your home folder, never in the project itself) to delete all credentials linked to a registry.\\n\\n      Adding the `-s,--scope` flag will cause the deletion to be done against whatever registry is configured for the associated scope (see also `npmScopes`).\\n\\n      Adding the `--publish` flag will cause the deletion to be done against the registry used when publishing the package (see also `publishConfig.registry` and `npmPublishRegistry`).\\n\\n      Adding the `-A,--all` flag will cause the deletion to be done against all registries and scopes.\\n    \",examples:[[\"Logout of the default registry\",\"yarn npm logout\"],[\"Logout of the @my-scope scope\",\"yarn npm logout --scope my-scope\"],[\"Logout of the publish registry for the current package\",\"yarn npm logout --publish\"],[\"Logout of all registries\",\"yarn npm logout --all\"]]});function Uvt(t,e){let r=t[e];if(!je.isIndexableObject(r))return!1;let o=new Set(Object.keys(r));if([...ow].every(n=>!o.has(n)))return!1;for(let n of ow)o.delete(n);if(o.size===0)return t[e]=void 0,!0;let a={...r};for(let n of ow)delete a[n];return t[e]=a,!0}async function _vt(){let t=e=>{let r=!1,o=je.isIndexableObject(e)?{...e}:{};o.npmAuthToken&&(delete o.npmAuthToken,r=!0);for(let a of Object.keys(o))Uvt(o,a)&&(r=!0);if(Object.keys(o).length!==0)return r?o:e};return await Ke.updateHomeConfiguration({npmRegistries:t,npmScopes:t})}async function PBe(t,e){return await Ke.updateHomeConfiguration({[t]:r=>{let o=je.isIndexableObject(r)?r:{};if(!Object.hasOwn(o,e))return r;let a=o[e],n=je.isIndexableObject(a)?a:{},u=new Set(Object.keys(n));if([...ow].every(p=>!u.has(p)))return r;for(let p of ow)u.delete(p);if(u.size===0)return Object.keys(o).length===1?void 0:{...o,[e]:void 0};let A={};for(let p of ow)A[p]=void 0;return{...o,[e]:{...n,...A}}}})}Ye();qt();var q0=class extends ut{constructor(){super(...arguments);this.access=ge.String(\"--access\",{description:\"The access for the published package (public or restricted)\"});this.tag=ge.String(\"--tag\",\"latest\",{description:\"The tag on the registry that the package should be attached to\"});this.tolerateRepublish=ge.Boolean(\"--tolerate-republish\",!1,{description:\"Warn and exit when republishing an already existing version of a package\"});this.otp=ge.String(\"--otp\",{description:\"The OTP token to use with the command\"})}async execute(){let r=await Ke.find(this.context.cwd,this.context.plugins),{project:o,workspace:a}=await St.find(r,this.context.cwd);if(!a)throw new rr(o.cwd,this.context.cwd);if(a.manifest.private)throw new it(\"Private workspaces cannot be published\");if(a.manifest.name===null||a.manifest.version===null)throw new it(\"Workspaces must have valid names and versions to be published on an external registry\");await o.restoreInstallState();let n=a.manifest.name,u=a.manifest.version,A=Zn.getPublishRegistry(a.manifest,{configuration:r});return(await Nt.start({configuration:r,stdout:this.context.stdout},async h=>{if(this.tolerateRepublish)try{let C=await on.get(on.getIdentUrl(n),{configuration:r,registry:A,ident:n,jsonResponse:!0});if(!Object.hasOwn(C,\"versions\"))throw new Jt(15,'Registry returned invalid data for - missing \"versions\" field');if(Object.hasOwn(C.versions,u)){h.reportWarning(0,`Registry already knows about version ${u}; skipping.`);return}}catch(C){if(C.originalError?.response?.statusCode!==404)throw C}await un.maybeExecuteWorkspaceLifecycleScript(a,\"prepublish\",{report:h}),await CA.prepareForPack(a,{report:h},async()=>{let C=await CA.genPackList(a);for(let R of C)h.reportInfo(null,R);let I=await CA.genPackStream(a,C),v=await je.bufferStream(I),x=await iw.getGitHead(a.cwd),E=await iw.makePublishBody(a,v,{access:this.access,tag:this.tag,registry:A,gitHead:x});await on.put(on.getIdentUrl(n),E,{configuration:r,registry:A,ident:n,otp:this.otp,jsonResponse:!0})}),h.reportInfo(0,\"Package archive published\")})).exitCode()}};q0.paths=[[\"npm\",\"publish\"]],q0.usage=nt.Usage({category:\"Npm-related commands\",description:\"publish the active workspace to the npm registry\",details:'\\n      This command will pack the active workspace into a fresh archive and upload it to the npm registry.\\n\\n      The package will by default be attached to the `latest` tag on the registry, but this behavior can be overriden by using the `--tag` option.\\n\\n      Note that for legacy reasons scoped packages are by default published with an access set to `restricted` (aka \"private packages\"). This requires you to register for a paid npm plan. In case you simply wish to publish a public scoped package to the registry (for free), just add the `--access public` flag. This behavior can be enabled by default through the `npmPublishAccess` settings.\\n    ',examples:[[\"Publish the active workspace\",\"yarn npm publish\"]]});Ye();qt();var SBe=$e(Jn());Ye();Pt();qt();var G0=class extends ut{constructor(){super(...arguments);this.json=ge.Boolean(\"--json\",!1,{description:\"Format the output as an NDJSON stream\"});this.package=ge.String({required:!1})}async execute(){let r=await Ke.find(this.context.cwd,this.context.plugins),{project:o,workspace:a}=await St.find(r,this.context.cwd),n;if(typeof this.package<\"u\")n=W.parseIdent(this.package);else{if(!a)throw new rr(o.cwd,this.context.cwd);if(!a.manifest.name)throw new it(`Missing 'name' field in ${ue.fromPortablePath(V.join(a.cwd,dr.manifest))}`);n=a.manifest.name}let u=await Tv(n,r),p={children:je.sortMap(Object.entries(u),([h])=>h).map(([h,C])=>({value:de.tuple(de.Type.RESOLUTION,{descriptor:W.makeDescriptor(n,h),locator:W.makeLocator(n,C)})}))};return $s.emitTree(p,{configuration:r,json:this.json,stdout:this.context.stdout})}};G0.paths=[[\"npm\",\"tag\",\"list\"]],G0.usage=nt.Usage({category:\"Npm-related commands\",description:\"list all dist-tags of a package\",details:`\n      This command will list all tags of a package from the npm registry.\n\n      If the package is not specified, Yarn will default to the current workspace.\n    `,examples:[[\"List all tags of package `my-pkg`\",\"yarn npm tag list my-pkg\"]]});async function Tv(t,e){let r=`/-/package${on.getIdentUrl(t)}/dist-tags`;return on.get(r,{configuration:e,ident:t,jsonResponse:!0,customErrorMessage:on.customPackageError})}var Y0=class extends ut{constructor(){super(...arguments);this.package=ge.String();this.tag=ge.String()}async execute(){let r=await Ke.find(this.context.cwd,this.context.plugins),{project:o,workspace:a}=await St.find(r,this.context.cwd);if(!a)throw new rr(o.cwd,this.context.cwd);let n=W.parseDescriptor(this.package,!0),u=n.range;if(!SBe.default.valid(u))throw new it(`The range ${de.pretty(r,n.range,de.Type.RANGE)} must be a valid semver version`);let A=Zn.getPublishRegistry(a.manifest,{configuration:r}),p=de.pretty(r,n,de.Type.IDENT),h=de.pretty(r,u,de.Type.RANGE),C=de.pretty(r,this.tag,de.Type.CODE);return(await Nt.start({configuration:r,stdout:this.context.stdout},async v=>{let x=await Tv(n,r);Object.hasOwn(x,this.tag)&&x[this.tag]===u&&v.reportWarning(0,`Tag ${C} is already set to version ${h}`);let E=`/-/package${on.getIdentUrl(n)}/dist-tags/${encodeURIComponent(this.tag)}`;await on.put(E,u,{configuration:r,registry:A,ident:n,jsonRequest:!0,jsonResponse:!0}),v.reportInfo(0,`Tag ${C} added to version ${h} of package ${p}`)})).exitCode()}};Y0.paths=[[\"npm\",\"tag\",\"add\"]],Y0.usage=nt.Usage({category:\"Npm-related commands\",description:\"add a tag for a specific version of a package\",details:`\n      This command will add a tag to the npm registry for a specific version of a package. If the tag already exists, it will be overwritten.\n    `,examples:[[\"Add a `beta` tag for version `2.3.4-beta.4` of package `my-pkg`\",\"yarn npm tag add my-pkg@2.3.4-beta.4 beta\"]]});Ye();qt();var W0=class extends ut{constructor(){super(...arguments);this.package=ge.String();this.tag=ge.String()}async execute(){if(this.tag===\"latest\")throw new it(\"The 'latest' tag cannot be removed.\");let r=await Ke.find(this.context.cwd,this.context.plugins),{project:o,workspace:a}=await St.find(r,this.context.cwd);if(!a)throw new rr(o.cwd,this.context.cwd);let n=W.parseIdent(this.package),u=Zn.getPublishRegistry(a.manifest,{configuration:r}),A=de.pretty(r,this.tag,de.Type.CODE),p=de.pretty(r,n,de.Type.IDENT),h=await Tv(n,r);if(!Object.hasOwn(h,this.tag))throw new it(`${A} is not a tag of package ${p}`);return(await Nt.start({configuration:r,stdout:this.context.stdout},async I=>{let v=`/-/package${on.getIdentUrl(n)}/dist-tags/${encodeURIComponent(this.tag)}`;await on.del(v,{configuration:r,registry:u,ident:n,jsonResponse:!0}),I.reportInfo(0,`Tag ${A} removed from package ${p}`)})).exitCode()}};W0.paths=[[\"npm\",\"tag\",\"remove\"]],W0.usage=nt.Usage({category:\"Npm-related commands\",description:\"remove a tag from a package\",details:`\n      This command will remove a tag from a package from the npm registry.\n    `,examples:[[\"Remove the `beta` tag from package `my-pkg`\",\"yarn npm tag remove my-pkg beta\"]]});Ye();Ye();qt();var K0=class extends ut{constructor(){super(...arguments);this.scope=ge.String(\"-s,--scope\",{description:\"Print username for the registry configured for a given scope\"});this.publish=ge.Boolean(\"--publish\",!1,{description:\"Print username for the publish registry\"})}async execute(){let r=await Ke.find(this.context.cwd,this.context.plugins),o;return this.scope&&this.publish?o=Zn.getScopeRegistry(this.scope,{configuration:r,type:Zn.RegistryType.PUBLISH_REGISTRY}):this.scope?o=Zn.getScopeRegistry(this.scope,{configuration:r}):this.publish?o=Zn.getPublishRegistry((await uC(r,this.context.cwd)).manifest,{configuration:r}):o=Zn.getDefaultRegistry({configuration:r}),(await Nt.start({configuration:r,stdout:this.context.stdout},async n=>{let u;try{u=await on.get(\"/-/whoami\",{configuration:r,registry:o,authType:on.AuthType.ALWAYS_AUTH,jsonResponse:!0,ident:this.scope?W.makeIdent(this.scope,\"\"):void 0})}catch(A){if(A.response?.statusCode===401||A.response?.statusCode===403){n.reportError(41,\"Authentication failed - your credentials may have expired\");return}else throw A}n.reportInfo(0,u.username)})).exitCode()}};K0.paths=[[\"npm\",\"whoami\"]],K0.usage=nt.Usage({category:\"Npm-related commands\",description:\"display the name of the authenticated user\",details:\"\\n      Print the username associated with the current authentication settings to the standard output.\\n\\n      When using `-s,--scope`, the username printed will be the one that matches the authentication settings of the registry associated with the given scope (those settings can be overriden using the `npmRegistries` map, and the registry associated with the scope is configured via the `npmScopes` map).\\n\\n      When using `--publish`, the registry we'll select will by default be the one used when publishing packages (`publishConfig.registry` or `npmPublishRegistry` if available, otherwise we'll fallback to the regular `npmRegistryServer`).\\n    \",examples:[[\"Print username for the default registry\",\"yarn npm whoami\"],[\"Print username for the registry on a given scope\",\"yarn npm whoami --scope company\"]]});var Hvt={configuration:{npmPublishAccess:{description:\"Default access of the published packages\",type:\"STRING\",default:null},npmAuditExcludePackages:{description:\"Array of glob patterns of packages to exclude from npm audit\",type:\"STRING\",default:[],isArray:!0},npmAuditIgnoreAdvisories:{description:\"Array of glob patterns of advisory IDs to exclude from npm audit\",type:\"STRING\",default:[],isArray:!0}},commands:[U0,_0,H0,j0,q0,Y0,G0,W0,K0]},jvt=Hvt;var LG={};Vt(LG,{PatchCommand:()=>J0,PatchCommitCommand:()=>z0,PatchFetcher:()=>Uv,PatchResolver:()=>_v,default:()=>oDt,patchUtils:()=>vm});Ye();Ye();Pt();nA();var vm={};Vt(vm,{applyPatchFile:()=>nF,diffFolders:()=>TG,ensureUnpatchedDescriptor:()=>kG,ensureUnpatchedLocator:()=>sF,extractPackageToDisk:()=>RG,extractPatchFlags:()=>TBe,isParentRequired:()=>FG,isPatchDescriptor:()=>iF,isPatchLocator:()=>V0,loadPatchFiles:()=>Mv,makeDescriptor:()=>oF,makeLocator:()=>QG,makePatchHash:()=>NG,parseDescriptor:()=>Lv,parseLocator:()=>Ov,parsePatchFile:()=>Nv,unpatchDescriptor:()=>nDt,unpatchLocator:()=>iDt});Ye();Pt();Ye();Pt();var qvt=/^@@ -(\\d+)(,(\\d+))? \\+(\\d+)(,(\\d+))? @@.*/;function aw(t){return V.relative(Bt.root,V.resolve(Bt.root,ue.toPortablePath(t)))}function Gvt(t){let e=t.trim().match(qvt);if(!e)throw new Error(`Bad header line: '${t}'`);return{original:{start:Math.max(Number(e[1]),1),length:Number(e[3]||1)},patched:{start:Math.max(Number(e[4]),1),length:Number(e[6]||1)}}}var Yvt=420,Wvt=493;var bBe=()=>({semverExclusivity:null,diffLineFromPath:null,diffLineToPath:null,oldMode:null,newMode:null,deletedFileMode:null,newFileMode:null,renameFrom:null,renameTo:null,beforeHash:null,afterHash:null,fromPath:null,toPath:null,hunks:null}),Kvt=t=>({header:Gvt(t),parts:[]}),Vvt={[\"@\"]:\"header\",[\"-\"]:\"deletion\",[\"+\"]:\"insertion\",[\" \"]:\"context\",[\"\\\\\"]:\"pragma\",undefined:\"context\"};function zvt(t){let e=[],r=bBe(),o=\"parsing header\",a=null,n=null;function u(){a&&(n&&(a.parts.push(n),n=null),r.hunks.push(a),a=null)}function A(){u(),e.push(r),r=bBe()}for(let p=0;p<t.length;p++){let h=t[p];if(o===\"parsing header\")if(h.startsWith(\"@@\"))o=\"parsing hunks\",r.hunks=[],p-=1;else if(h.startsWith(\"diff --git \")){r&&r.diffLineFromPath&&A();let C=h.match(/^diff --git a\\/(.*?) b\\/(.*?)\\s*$/);if(!C)throw new Error(`Bad diff line: ${h}`);r.diffLineFromPath=C[1],r.diffLineToPath=C[2]}else if(h.startsWith(\"old mode \"))r.oldMode=h.slice(9).trim();else if(h.startsWith(\"new mode \"))r.newMode=h.slice(9).trim();else if(h.startsWith(\"deleted file mode \"))r.deletedFileMode=h.slice(18).trim();else if(h.startsWith(\"new file mode \"))r.newFileMode=h.slice(14).trim();else if(h.startsWith(\"rename from \"))r.renameFrom=h.slice(12).trim();else if(h.startsWith(\"rename to \"))r.renameTo=h.slice(10).trim();else if(h.startsWith(\"index \")){let C=h.match(/(\\w+)\\.\\.(\\w+)/);if(!C)continue;r.beforeHash=C[1],r.afterHash=C[2]}else h.startsWith(\"semver exclusivity \")?r.semverExclusivity=h.slice(19).trim():h.startsWith(\"--- \")?r.fromPath=h.slice(6).trim():h.startsWith(\"+++ \")&&(r.toPath=h.slice(6).trim());else{let C=Vvt[h[0]]||null;switch(C){case\"header\":u(),a=Kvt(h);break;case null:o=\"parsing header\",A(),p-=1;break;case\"pragma\":{if(!h.startsWith(\"\\\\ No newline at end of file\"))throw new Error(`Unrecognized pragma in patch file: ${h}`);if(!n)throw new Error(\"Bad parser state: No newline at EOF pragma encountered without context\");n.noNewlineAtEndOfFile=!0}break;case\"context\":case\"deletion\":case\"insertion\":{if(!a)throw new Error(\"Bad parser state: Hunk lines encountered before hunk header\");n&&n.type!==C&&(a.parts.push(n),n=null),n||(n={type:C,lines:[],noNewlineAtEndOfFile:!1}),n.lines.push(h.slice(1))}break;default:je.assertNever(C);break}}}A();for(let{hunks:p}of e)if(p)for(let h of p)Xvt(h);return e}function Jvt(t){let e=[];for(let r of t){let{semverExclusivity:o,diffLineFromPath:a,diffLineToPath:n,oldMode:u,newMode:A,deletedFileMode:p,newFileMode:h,renameFrom:C,renameTo:I,beforeHash:v,afterHash:x,fromPath:E,toPath:R,hunks:L}=r,U=C?\"rename\":p?\"file deletion\":h?\"file creation\":L&&L.length>0?\"patch\":\"mode change\",z=null;switch(U){case\"rename\":{if(!C||!I)throw new Error(\"Bad parser state: rename from & to not given\");e.push({type:\"rename\",semverExclusivity:o,fromPath:aw(C),toPath:aw(I)}),z=I}break;case\"file deletion\":{let te=a||E;if(!te)throw new Error(\"Bad parse state: no path given for file deletion\");e.push({type:\"file deletion\",semverExclusivity:o,hunk:L&&L[0]||null,path:aw(te),mode:rF(p),hash:v})}break;case\"file creation\":{let te=n||R;if(!te)throw new Error(\"Bad parse state: no path given for file creation\");e.push({type:\"file creation\",semverExclusivity:o,hunk:L&&L[0]||null,path:aw(te),mode:rF(h),hash:x})}break;case\"patch\":case\"mode change\":z=R||n;break;default:je.assertNever(U);break}z&&u&&A&&u!==A&&e.push({type:\"mode change\",semverExclusivity:o,path:aw(z),oldMode:rF(u),newMode:rF(A)}),z&&L&&L.length&&e.push({type:\"patch\",semverExclusivity:o,path:aw(z),hunks:L,beforeHash:v,afterHash:x})}if(e.length===0)throw new Error(\"Unable to parse patch file: No changes found. Make sure the patch is a valid UTF8 encoded string\");return e}function rF(t){let e=parseInt(t,8)&511;if(e!==Yvt&&e!==Wvt)throw new Error(`Unexpected file mode string: ${t}`);return e}function Nv(t){let e=t.split(/\\n/g);return e[e.length-1]===\"\"&&e.pop(),Jvt(zvt(e))}function Xvt(t){let e=0,r=0;for(let{type:o,lines:a}of t.parts)switch(o){case\"context\":r+=a.length,e+=a.length;break;case\"deletion\":e+=a.length;break;case\"insertion\":r+=a.length;break;default:je.assertNever(o);break}if(e!==t.header.original.length||r!==t.header.patched.length){let o=a=>a<0?a:`+${a}`;throw new Error(`hunk header integrity check failed (expected @@ ${o(t.header.original.length)} ${o(t.header.patched.length)} @@, got @@ ${o(e)} ${o(r)} @@)`)}}Ye();Pt();var lw=class extends Error{constructor(r,o){super(`Cannot apply hunk #${r+1}`);this.hunk=o}};async function cw(t,e,r){let o=await t.lstatPromise(e),a=await r();typeof a<\"u\"&&(e=a),await t.lutimesPromise(e,o.atime,o.mtime)}async function nF(t,{baseFs:e=new Tn,dryRun:r=!1,version:o=null}={}){for(let a of t)if(!(a.semverExclusivity!==null&&o!==null&&!kr.satisfiesWithPrereleases(o,a.semverExclusivity)))switch(a.type){case\"file deletion\":if(r){if(!e.existsSync(a.path))throw new Error(`Trying to delete a file that doesn't exist: ${a.path}`)}else await cw(e,V.dirname(a.path),async()=>{await e.unlinkPromise(a.path)});break;case\"rename\":if(r){if(!e.existsSync(a.fromPath))throw new Error(`Trying to move a file that doesn't exist: ${a.fromPath}`)}else await cw(e,V.dirname(a.fromPath),async()=>{await cw(e,V.dirname(a.toPath),async()=>{await cw(e,a.fromPath,async()=>(await e.movePromise(a.fromPath,a.toPath),a.toPath))})});break;case\"file creation\":if(r){if(e.existsSync(a.path))throw new Error(`Trying to create a file that already exists: ${a.path}`)}else{let n=a.hunk?a.hunk.parts[0].lines.join(`\n`)+(a.hunk.parts[0].noNewlineAtEndOfFile?\"\":`\n`):\"\";await e.mkdirpPromise(V.dirname(a.path),{chmod:493,utimes:[vi.SAFE_TIME,vi.SAFE_TIME]}),await e.writeFilePromise(a.path,n,{mode:a.mode}),await e.utimesPromise(a.path,vi.SAFE_TIME,vi.SAFE_TIME)}break;case\"patch\":await cw(e,a.path,async()=>{await eDt(a,{baseFs:e,dryRun:r})});break;case\"mode change\":{let u=(await e.statPromise(a.path)).mode;if(xBe(a.newMode)!==xBe(u))continue;await cw(e,a.path,async()=>{await e.chmodPromise(a.path,a.newMode)})}break;default:je.assertNever(a);break}}function xBe(t){return(t&64)>0}function kBe(t){return t.replace(/\\s+$/,\"\")}function $vt(t,e){return kBe(t)===kBe(e)}async function eDt({hunks:t,path:e},{baseFs:r,dryRun:o=!1}){let a=await r.statSync(e).mode,u=(await r.readFileSync(e,\"utf8\")).split(/\\n/),A=[],p=0,h=0;for(let I of t){let v=Math.max(h,I.header.patched.start+p),x=Math.max(0,v-h),E=Math.max(0,u.length-v-I.header.original.length),R=Math.max(x,E),L=0,U=0,z=null;for(;L<=R;){if(L<=x&&(U=v-L,z=QBe(I,u,U),z!==null)){L=-L;break}if(L<=E&&(U=v+L,z=QBe(I,u,U),z!==null))break;L+=1}if(z===null)throw new lw(t.indexOf(I),I);A.push(z),p+=L,h=U+I.header.original.length}if(o)return;let C=0;for(let I of A)for(let v of I)switch(v.type){case\"splice\":{let x=v.index+C;u.splice(x,v.numToDelete,...v.linesToInsert),C+=v.linesToInsert.length-v.numToDelete}break;case\"pop\":u.pop();break;case\"push\":u.push(v.line);break;default:je.assertNever(v);break}await r.writeFilePromise(e,u.join(`\n`),{mode:a})}function QBe(t,e,r){let o=[];for(let a of t.parts)switch(a.type){case\"context\":case\"deletion\":{for(let n of a.lines){let u=e[r];if(u==null||!$vt(u,n))return null;r+=1}a.type===\"deletion\"&&(o.push({type:\"splice\",index:r-a.lines.length,numToDelete:a.lines.length,linesToInsert:[]}),a.noNewlineAtEndOfFile&&o.push({type:\"push\",line:\"\"}))}break;case\"insertion\":o.push({type:\"splice\",index:r,numToDelete:0,linesToInsert:a.lines}),a.noNewlineAtEndOfFile&&o.push({type:\"pop\"});break;default:je.assertNever(a.type);break}return o}var rDt=/^builtin<([^>]+)>$/;function uw(t,e){let{protocol:r,source:o,selector:a,params:n}=W.parseRange(t);if(r!==\"patch:\")throw new Error(\"Invalid patch range\");if(o===null)throw new Error(\"Patch locators must explicitly define their source\");let u=a?a.split(/&/).map(C=>ue.toPortablePath(C)):[],A=n&&typeof n.locator==\"string\"?W.parseLocator(n.locator):null,p=n&&typeof n.version==\"string\"?n.version:null,h=e(o);return{parentLocator:A,sourceItem:h,patchPaths:u,sourceVersion:p}}function iF(t){return t.range.startsWith(\"patch:\")}function V0(t){return t.reference.startsWith(\"patch:\")}function Lv(t){let{sourceItem:e,...r}=uw(t.range,W.parseDescriptor);return{...r,sourceDescriptor:e}}function Ov(t){let{sourceItem:e,...r}=uw(t.reference,W.parseLocator);return{...r,sourceLocator:e}}function nDt(t){let{sourceItem:e}=uw(t.range,W.parseDescriptor);return e}function iDt(t){let{sourceItem:e}=uw(t.reference,W.parseLocator);return e}function kG(t){if(!iF(t))return t;let{sourceItem:e}=uw(t.range,W.parseDescriptor);return e}function sF(t){if(!V0(t))return t;let{sourceItem:e}=uw(t.reference,W.parseLocator);return e}function FBe({parentLocator:t,sourceItem:e,patchPaths:r,sourceVersion:o,patchHash:a},n){let u=t!==null?{locator:W.stringifyLocator(t)}:{},A=typeof o<\"u\"?{version:o}:{},p=typeof a<\"u\"?{hash:a}:{};return W.makeRange({protocol:\"patch:\",source:n(e),selector:r.join(\"&\"),params:{...A,...p,...u}})}function oF(t,{parentLocator:e,sourceDescriptor:r,patchPaths:o}){return W.makeDescriptor(t,FBe({parentLocator:e,sourceItem:r,patchPaths:o},W.stringifyDescriptor))}function QG(t,{parentLocator:e,sourcePackage:r,patchPaths:o,patchHash:a}){return W.makeLocator(t,FBe({parentLocator:e,sourceItem:r,sourceVersion:r.version,patchPaths:o,patchHash:a},W.stringifyLocator))}function RBe({onAbsolute:t,onRelative:e,onProject:r,onBuiltin:o},a){let n=a.lastIndexOf(\"!\");n!==-1&&(a=a.slice(n+1));let u=a.match(rDt);return u!==null?o(u[1]):a.startsWith(\"~/\")?r(a.slice(2)):V.isAbsolute(a)?t(a):e(a)}function TBe(t){let e=t.lastIndexOf(\"!\");return{optional:(e!==-1?new Set(t.slice(0,e).split(/!/)):new Set).has(\"optional\")}}function FG(t){return RBe({onAbsolute:()=>!1,onRelative:()=>!0,onProject:()=>!1,onBuiltin:()=>!1},t)}async function Mv(t,e,r){let o=t!==null?await r.fetcher.fetch(t,r):null,a=o&&o.localPath?{packageFs:new gn(Bt.root),prefixPath:V.relative(Bt.root,o.localPath)}:o;o&&o!==a&&o.releaseFs&&o.releaseFs();let n=await je.releaseAfterUseAsync(async()=>await Promise.all(e.map(async u=>{let A=TBe(u),p=await RBe({onAbsolute:async h=>await oe.readFilePromise(h,\"utf8\"),onRelative:async h=>{if(a===null)throw new Error(\"Assertion failed: The parent locator should have been fetched\");return await a.packageFs.readFilePromise(V.join(a.prefixPath,h),\"utf8\")},onProject:async h=>await oe.readFilePromise(V.join(r.project.cwd,h),\"utf8\"),onBuiltin:async h=>await r.project.configuration.firstHook(C=>C.getBuiltinPatch,r.project,h)},u);return{...A,source:p}})));for(let u of n)typeof u.source==\"string\"&&(u.source=u.source.replace(/\\r\\n?/g,`\n`));return n}async function RG(t,{cache:e,project:r}){let o=r.storedPackages.get(t.locatorHash);if(typeof o>\"u\")throw new Error(\"Assertion failed: Expected the package to be registered\");let a=sF(t),n=r.storedChecksums,u=new Qi,A=await oe.mktempPromise(),p=V.join(A,\"source\"),h=V.join(A,\"user\"),C=V.join(A,\".yarn-patch.json\"),I=r.configuration.makeFetcher(),v=[];try{let x,E;if(t.locatorHash===a.locatorHash){let R=await I.fetch(t,{cache:e,project:r,fetcher:I,checksums:n,report:u});v.push(()=>R.releaseFs?.()),x=R,E=R}else x=await I.fetch(t,{cache:e,project:r,fetcher:I,checksums:n,report:u}),v.push(()=>x.releaseFs?.()),E=await I.fetch(t,{cache:e,project:r,fetcher:I,checksums:n,report:u}),v.push(()=>E.releaseFs?.());await Promise.all([oe.copyPromise(p,x.prefixPath,{baseFs:x.packageFs}),oe.copyPromise(h,E.prefixPath,{baseFs:E.packageFs}),oe.writeJsonPromise(C,{locator:W.stringifyLocator(t),version:o.version})])}finally{for(let x of v)x()}return oe.detachTemp(A),h}async function TG(t,e){let r=ue.fromPortablePath(t).replace(/\\\\/g,\"/\"),o=ue.fromPortablePath(e).replace(/\\\\/g,\"/\"),{stdout:a,stderr:n}=await Ur.execvp(\"git\",[\"-c\",\"core.safecrlf=false\",\"diff\",\"--src-prefix=a/\",\"--dst-prefix=b/\",\"--ignore-cr-at-eol\",\"--full-index\",\"--no-index\",\"--no-renames\",\"--text\",r,o],{cwd:ue.toPortablePath(process.cwd()),env:{...process.env,GIT_CONFIG_NOSYSTEM:\"1\",HOME:\"\",XDG_CONFIG_HOME:\"\",USERPROFILE:\"\"}});if(n.length>0)throw new Error(`Unable to diff directories. Make sure you have a recent version of 'git' available in PATH.\nThe following error was reported by 'git':\n${n}`);let u=r.startsWith(\"/\")?A=>A.slice(1):A=>A;return a.replace(new RegExp(`(a|b)(${je.escapeRegExp(`/${u(r)}/`)})`,\"g\"),\"$1/\").replace(new RegExp(`(a|b)${je.escapeRegExp(`/${u(o)}/`)}`,\"g\"),\"$1/\").replace(new RegExp(je.escapeRegExp(`${r}/`),\"g\"),\"\").replace(new RegExp(je.escapeRegExp(`${o}/`),\"g\"),\"\")}function NG(t,e){let r=[];for(let{source:o}of t){if(o===null)continue;let a=Nv(o);for(let n of a){let{semverExclusivity:u,...A}=n;u!==null&&e!==null&&!kr.satisfiesWithPrereleases(e,u)||r.push(JSON.stringify(A))}}return wn.makeHash(`${3}`,...r).slice(0,6)}Ye();function NBe(t,{configuration:e,report:r}){for(let o of t.parts)for(let a of o.lines)switch(o.type){case\"context\":r.reportInfo(null,`  ${de.pretty(e,a,\"grey\")}`);break;case\"deletion\":r.reportError(28,`- ${de.pretty(e,a,de.Type.REMOVED)}`);break;case\"insertion\":r.reportError(28,`+ ${de.pretty(e,a,de.Type.ADDED)}`);break;default:je.assertNever(o.type)}}var Uv=class{supports(e,r){return!!V0(e)}getLocalPath(e,r){return null}async fetch(e,r){let o=r.checksums.get(e.locatorHash)||null,[a,n,u]=await r.cache.fetchPackageFromCache(e,o,{onHit:()=>r.report.reportCacheHit(e),onMiss:()=>r.report.reportCacheMiss(e,`${W.prettyLocator(r.project.configuration,e)} can't be found in the cache and will be fetched from the disk`),loader:()=>this.patchPackage(e,r),...r.cacheOptions});return{packageFs:a,releaseFs:n,prefixPath:W.getIdentVendorPath(e),localPath:this.getLocalPath(e,r),checksum:u}}async patchPackage(e,r){let{parentLocator:o,sourceLocator:a,sourceVersion:n,patchPaths:u}=Ov(e),A=await Mv(o,u,r),p=await oe.mktempPromise(),h=V.join(p,\"current.zip\"),C=await r.fetcher.fetch(a,r),I=W.getIdentVendorPath(e),v=new Ji(h,{create:!0,level:r.project.configuration.get(\"compressionLevel\")});await je.releaseAfterUseAsync(async()=>{await v.copyPromise(I,C.prefixPath,{baseFs:C.packageFs,stableSort:!0})},C.releaseFs),v.saveAndClose();for(let{source:x,optional:E}of A){if(x===null)continue;let R=new Ji(h,{level:r.project.configuration.get(\"compressionLevel\")}),L=new gn(V.resolve(Bt.root,I),{baseFs:R});try{await nF(Nv(x),{baseFs:L,version:n})}catch(U){if(!(U instanceof lw))throw U;let z=r.project.configuration.get(\"enableInlineHunks\"),te=!z&&!E?\" (set enableInlineHunks for details)\":\"\",le=`${W.prettyLocator(r.project.configuration,e)}: ${U.message}${te}`,he=Ae=>{!z||NBe(U.hunk,{configuration:r.project.configuration,report:Ae})};if(R.discardAndClose(),E){r.report.reportWarningOnce(66,le,{reportExtra:he});continue}else throw new Jt(66,le,he)}R.saveAndClose()}return new Ji(h,{level:r.project.configuration.get(\"compressionLevel\")})}};Ye();var _v=class{supportsDescriptor(e,r){return!!iF(e)}supportsLocator(e,r){return!!V0(e)}shouldPersistResolution(e,r){return!1}bindDescriptor(e,r,o){let{patchPaths:a}=Lv(e);return a.every(n=>!FG(n))?e:W.bindDescriptor(e,{locator:W.stringifyLocator(r)})}getResolutionDependencies(e,r){let{sourceDescriptor:o}=Lv(e);return{sourceDescriptor:r.project.configuration.normalizeDependency(o)}}async getCandidates(e,r,o){if(!o.fetchOptions)throw new Error(\"Assertion failed: This resolver cannot be used unless a fetcher is configured\");let{parentLocator:a,patchPaths:n}=Lv(e),u=await Mv(a,n,o.fetchOptions),A=r.sourceDescriptor;if(typeof A>\"u\")throw new Error(\"Assertion failed: The dependency should have been resolved\");let p=NG(u,A.version);return[QG(e,{parentLocator:a,sourcePackage:A,patchPaths:n,patchHash:p})]}async getSatisfying(e,r,o,a){let[n]=await this.getCandidates(e,r,a);return{locators:o.filter(u=>u.locatorHash===n.locatorHash),sorted:!1}}async resolve(e,r){let{sourceLocator:o}=Ov(e);return{...await r.resolver.resolve(o,r),...e}}};Ye();Pt();qt();var z0=class extends ut{constructor(){super(...arguments);this.save=ge.Boolean(\"-s,--save\",!1,{description:\"Add the patch to your resolution entries\"});this.patchFolder=ge.String()}async execute(){let r=await Ke.find(this.context.cwd,this.context.plugins),{project:o,workspace:a}=await St.find(r,this.context.cwd);if(!a)throw new rr(o.cwd,this.context.cwd);await o.restoreInstallState();let n=V.resolve(this.context.cwd,ue.toPortablePath(this.patchFolder)),u=V.join(n,\"../source\"),A=V.join(n,\"../.yarn-patch.json\");if(!oe.existsSync(u))throw new it(\"The argument folder didn't get created by 'yarn patch'\");let p=await TG(u,n),h=await oe.readJsonPromise(A),C=W.parseLocator(h.locator,!0);if(!o.storedPackages.has(C.locatorHash))throw new it(\"No package found in the project for the given locator\");if(!this.save){this.context.stdout.write(p);return}let I=r.get(\"patchFolder\"),v=V.join(I,`${W.slugifyLocator(C)}.patch`);await oe.mkdirPromise(I,{recursive:!0}),await oe.writeFilePromise(v,p);let x=[],E=new Map;for(let R of o.storedPackages.values()){if(W.isVirtualLocator(R))continue;let L=R.dependencies.get(C.identHash);if(!L)continue;let U=W.ensureDevirtualizedDescriptor(L),z=kG(U),te=o.storedResolutions.get(z.descriptorHash);if(!te)throw new Error(\"Assertion failed: Expected the resolution to have been registered\");if(!o.storedPackages.get(te))throw new Error(\"Assertion failed: Expected the package to have been registered\");let he=o.tryWorkspaceByLocator(R);if(he)x.push(he);else{let Ae=o.originalPackages.get(R.locatorHash);if(!Ae)throw new Error(\"Assertion failed: Expected the original package to have been registered\");let ye=Ae.dependencies.get(L.identHash);if(!ye)throw new Error(\"Assertion failed: Expected the original dependency to have been registered\");E.set(ye.descriptorHash,ye)}}for(let R of x)for(let L of Ot.hardDependencies){let U=R.manifest[L].get(C.identHash);if(!U)continue;let z=oF(U,{parentLocator:null,sourceDescriptor:W.convertLocatorToDescriptor(C),patchPaths:[V.join(dr.home,V.relative(o.cwd,v))]});R.manifest[L].set(U.identHash,z)}for(let R of E.values()){let L=oF(R,{parentLocator:null,sourceDescriptor:W.convertLocatorToDescriptor(C),patchPaths:[V.join(dr.home,V.relative(o.cwd,v))]});o.topLevelWorkspace.manifest.resolutions.push({pattern:{descriptor:{fullName:W.stringifyIdent(L),description:R.range}},reference:L.range})}await o.persist()}};z0.paths=[[\"patch-commit\"]],z0.usage=nt.Usage({description:\"generate a patch out of a directory\",details:\"\\n      By default, this will print a patchfile on stdout based on the diff between the folder passed in and the original version of the package. Such file is suitable for consumption with the `patch:` protocol.\\n\\n      With the `-s,--save` option set, the patchfile won't be printed on stdout anymore and will instead be stored within a local file (by default kept within `.yarn/patches`, but configurable via the `patchFolder` setting). A `resolutions` entry will also be added to your top-level manifest, referencing the patched package via the `patch:` protocol.\\n\\n      Note that only folders generated by `yarn patch` are accepted as valid input for `yarn patch-commit`.\\n    \"});Ye();Pt();qt();var J0=class extends ut{constructor(){super(...arguments);this.update=ge.Boolean(\"-u,--update\",!1,{description:\"Reapply local patches that already apply to this packages\"});this.json=ge.Boolean(\"--json\",!1,{description:\"Format the output as an NDJSON stream\"});this.package=ge.String()}async execute(){let r=await Ke.find(this.context.cwd,this.context.plugins),{project:o,workspace:a}=await St.find(r,this.context.cwd),n=await Lr.find(r);if(!a)throw new rr(o.cwd,this.context.cwd);await o.restoreInstallState();let u=W.parseLocator(this.package);if(u.reference===\"unknown\"){let A=je.mapAndFilter([...o.storedPackages.values()],p=>p.identHash!==u.identHash?je.mapAndFilter.skip:W.isVirtualLocator(p)?je.mapAndFilter.skip:V0(p)!==this.update?je.mapAndFilter.skip:p);if(A.length===0)throw new it(\"No package found in the project for the given locator\");if(A.length>1)throw new it(`Multiple candidate packages found; explicitly choose one of them (use \\`yarn why <package>\\` to get more information as to who depends on them):\n${A.map(p=>`\n- ${W.prettyLocator(r,p)}`).join(\"\")}`);u=A[0]}if(!o.storedPackages.has(u.locatorHash))throw new it(\"No package found in the project for the given locator\");await Nt.start({configuration:r,json:this.json,stdout:this.context.stdout},async A=>{let p=sF(u),h=await RG(u,{cache:n,project:o});A.reportJson({locator:W.stringifyLocator(p),path:ue.fromPortablePath(h)});let C=this.update?\" along with its current modifications\":\"\";A.reportInfo(0,`Package ${W.prettyLocator(r,p)} got extracted with success${C}!`),A.reportInfo(0,`You can now edit the following folder: ${de.pretty(r,ue.fromPortablePath(h),\"magenta\")}`),A.reportInfo(0,`Once you are done run ${de.pretty(r,`yarn patch-commit -s ${process.platform===\"win32\"?'\"':\"\"}${ue.fromPortablePath(h)}${process.platform===\"win32\"?'\"':\"\"}`,\"cyan\")} and Yarn will store a patchfile based on your changes.`)})}};J0.paths=[[\"patch\"]],J0.usage=nt.Usage({description:\"prepare a package for patching\",details:\"\\n      This command will cause a package to be extracted in a temporary directory intended to be editable at will.\\n\\n      Once you're done with your changes, run `yarn patch-commit -s path` (with `path` being the temporary directory you received) to generate a patchfile and register it into your top-level manifest via the `patch:` protocol. Run `yarn patch-commit -h` for more details.\\n\\n      Calling the command when you already have a patch won't import it by default (in other words, the default behavior is to reset existing patches). However, adding the `-u,--update` flag will import any current patch.\\n    \"});var sDt={configuration:{enableInlineHunks:{description:\"If true, the installs will print unmatched patch hunks\",type:\"BOOLEAN\",default:!1},patchFolder:{description:\"Folder where the patch files must be written\",type:\"ABSOLUTE_PATH\",default:\"./.yarn/patches\"}},commands:[z0,J0],fetchers:[Uv],resolvers:[_v]},oDt=sDt;var UG={};Vt(UG,{PnpmLinker:()=>Hv,default:()=>ADt});Ye();Pt();qt();var Hv=class{getCustomDataKey(){return JSON.stringify({name:\"PnpmLinker\",version:3})}supportsPackage(e,r){return this.isEnabled(r)}async findPackageLocation(e,r){if(!this.isEnabled(r))throw new Error(\"Assertion failed: Expected the pnpm linker to be enabled\");let o=this.getCustomDataKey(),a=r.project.linkersCustomData.get(o);if(!a)throw new it(`The project in ${de.pretty(r.project.configuration,`${r.project.cwd}/package.json`,de.Type.PATH)} doesn't seem to have been installed - running an install there might help`);let n=a.pathsByLocator.get(e.locatorHash);if(typeof n>\"u\")throw new it(`Couldn't find ${W.prettyLocator(r.project.configuration,e)} in the currently installed pnpm map - running an install might help`);return n.packageLocation}async findPackageLocator(e,r){if(!this.isEnabled(r))return null;let o=this.getCustomDataKey(),a=r.project.linkersCustomData.get(o);if(!a)throw new it(`The project in ${de.pretty(r.project.configuration,`${r.project.cwd}/package.json`,de.Type.PATH)} doesn't seem to have been installed - running an install there might help`);let n=e.match(/(^.*\\/node_modules\\/(@[^/]*\\/)?[^/]+)(\\/.*$)/);if(n){let p=a.locatorByPath.get(n[1]);if(p)return p}let u=e,A=e;do{A=u,u=V.dirname(A);let p=a.locatorByPath.get(A);if(p)return p}while(u!==A);return null}makeInstaller(e){return new OG(e)}isEnabled(e){return e.project.configuration.get(\"nodeLinker\")===\"pnpm\"}},OG=class{constructor(e){this.opts=e;this.asyncActions=new je.AsyncActions(10);this.customData={pathsByLocator:new Map,locatorByPath:new Map};this.indexFolderPromise=PD(oe,{indexPath:V.join(e.project.configuration.get(\"globalFolder\"),\"index\")})}attachCustomData(e){}async installPackage(e,r,o){switch(e.linkType){case\"SOFT\":return this.installPackageSoft(e,r,o);case\"HARD\":return this.installPackageHard(e,r,o)}throw new Error(\"Assertion failed: Unsupported package link type\")}async installPackageSoft(e,r,o){let a=V.resolve(r.packageFs.getRealPath(),r.prefixPath),n=this.opts.project.tryWorkspaceByLocator(e)?V.join(a,dr.nodeModules):null;return this.customData.pathsByLocator.set(e.locatorHash,{packageLocation:a,dependenciesLocation:n}),{packageLocation:a,buildRequest:null}}async installPackageHard(e,r,o){let a=aDt(e,{project:this.opts.project}),n=a.packageLocation;this.customData.locatorByPath.set(n,W.stringifyLocator(e)),this.customData.pathsByLocator.set(e.locatorHash,a),o.holdFetchResult(this.asyncActions.set(e.locatorHash,async()=>{await oe.mkdirPromise(n,{recursive:!0}),await oe.copyPromise(n,r.prefixPath,{baseFs:r.packageFs,overwrite:!1,linkStrategy:{type:\"HardlinkFromIndex\",indexPath:await this.indexFolderPromise,autoRepair:!0}})}));let A=W.isVirtualLocator(e)?W.devirtualizeLocator(e):e,p={manifest:await Ot.tryFind(r.prefixPath,{baseFs:r.packageFs})??new Ot,misc:{hasBindingGyp:mA.hasBindingGyp(r)}},h=this.opts.project.getDependencyMeta(A,e.version),C=mA.extractBuildRequest(e,p,h,{configuration:this.opts.project.configuration});return{packageLocation:n,buildRequest:C}}async attachInternalDependencies(e,r){if(this.opts.project.configuration.get(\"nodeLinker\")!==\"pnpm\"||!LBe(e,{project:this.opts.project}))return;let o=this.customData.pathsByLocator.get(e.locatorHash);if(typeof o>\"u\")throw new Error(`Assertion failed: Expected the package to have been registered (${W.stringifyLocator(e)})`);let{dependenciesLocation:a}=o;!a||this.asyncActions.reduce(e.locatorHash,async n=>{await oe.mkdirPromise(a,{recursive:!0});let u=await lDt(a),A=new Map(u),p=[n],h=(I,v)=>{let x=v;LBe(v,{project:this.opts.project})||(this.opts.report.reportWarningOnce(0,\"The pnpm linker doesn't support providing different versions to workspaces' peer dependencies\"),x=W.devirtualizeLocator(v));let E=this.customData.pathsByLocator.get(x.locatorHash);if(typeof E>\"u\")throw new Error(`Assertion failed: Expected the package to have been registered (${W.stringifyLocator(v)})`);let R=W.stringifyIdent(I),L=V.join(a,R),U=V.relative(V.dirname(L),E.packageLocation),z=A.get(R);A.delete(R),p.push(Promise.resolve().then(async()=>{if(z){if(z.isSymbolicLink()&&await oe.readlinkPromise(L)===U)return;await oe.removePromise(L)}await oe.mkdirpPromise(V.dirname(L)),process.platform==\"win32\"&&this.opts.project.configuration.get(\"winLinkType\")===\"junctions\"?await oe.symlinkPromise(E.packageLocation,L,\"junction\"):await oe.symlinkPromise(U,L)}))},C=!1;for(let[I,v]of r)I.identHash===e.identHash&&(C=!0),h(I,v);!C&&!this.opts.project.tryWorkspaceByLocator(e)&&h(W.convertLocatorToDescriptor(e),e),p.push(cDt(a,A)),await Promise.all(p)})}async attachExternalDependents(e,r){throw new Error(\"External dependencies haven't been implemented for the pnpm linker\")}async finalizeInstall(){let e=MBe(this.opts.project);if(this.opts.project.configuration.get(\"nodeLinker\")!==\"pnpm\")await oe.removePromise(e);else{let r;try{r=new Set(await oe.readdirPromise(e))}catch{r=new Set}for(let{dependenciesLocation:o}of this.customData.pathsByLocator.values()){if(!o)continue;let a=V.contains(e,o);if(a===null)continue;let[n]=a.split(V.sep);r.delete(n)}await Promise.all([...r].map(async o=>{await oe.removePromise(V.join(e,o))}))}return await this.asyncActions.wait(),await MG(e),this.opts.project.configuration.get(\"nodeLinker\")!==\"node-modules\"&&await MG(OBe(this.opts.project)),{customData:this.customData}}};function OBe(t){return V.join(t.cwd,dr.nodeModules)}function MBe(t){return V.join(OBe(t),\".store\")}function aDt(t,{project:e}){let r=W.slugifyLocator(t),o=MBe(e),a=V.join(o,r,\"package\"),n=V.join(o,r,dr.nodeModules);return{packageLocation:a,dependenciesLocation:n}}function LBe(t,{project:e}){return!W.isVirtualLocator(t)||!e.tryWorkspaceByLocator(t)}async function lDt(t){let e=new Map,r=[];try{r=await oe.readdirPromise(t,{withFileTypes:!0})}catch(o){if(o.code!==\"ENOENT\")throw o}try{for(let o of r)if(!o.name.startsWith(\".\"))if(o.name.startsWith(\"@\")){let a=await oe.readdirPromise(V.join(t,o.name),{withFileTypes:!0});if(a.length===0)e.set(o.name,o);else for(let n of a)e.set(`${o.name}/${n.name}`,n)}else e.set(o.name,o)}catch(o){if(o.code!==\"ENOENT\")throw o}return e}async function cDt(t,e){let r=[],o=new Set;for(let a of e.keys()){r.push(oe.removePromise(V.join(t,a)));let n=W.tryParseIdent(a)?.scope;n&&o.add(`@${n}`)}return Promise.all(r).then(()=>Promise.all([...o].map(a=>MG(V.join(t,a)))))}async function MG(t){try{await oe.rmdirPromise(t)}catch(e){if(e.code!==\"ENOENT\"&&e.code!==\"ENOTEMPTY\")throw e}}var uDt={linkers:[Hv]},ADt=uDt;var WG={};Vt(WG,{StageCommand:()=>X0,default:()=>IDt,stageUtils:()=>lF});Ye();Pt();qt();Ye();Pt();var lF={};Vt(lF,{ActionType:()=>_G,checkConsensus:()=>aF,expandDirectory:()=>qG,findConsensus:()=>GG,findVcsRoot:()=>HG,genCommitMessage:()=>YG,getCommitPrefix:()=>UBe,isYarnFile:()=>jG});Pt();var _G=(n=>(n[n.CREATE=0]=\"CREATE\",n[n.DELETE=1]=\"DELETE\",n[n.ADD=2]=\"ADD\",n[n.REMOVE=3]=\"REMOVE\",n[n.MODIFY=4]=\"MODIFY\",n))(_G||{});async function HG(t,{marker:e}){do if(!oe.existsSync(V.join(t,e)))t=V.dirname(t);else return t;while(t!==\"/\");return null}function jG(t,{roots:e,names:r}){if(r.has(V.basename(t)))return!0;do if(!e.has(t))t=V.dirname(t);else return!0;while(t!==\"/\");return!1}function qG(t){let e=[],r=[t];for(;r.length>0;){let o=r.pop(),a=oe.readdirSync(o);for(let n of a){let u=V.resolve(o,n);oe.lstatSync(u).isDirectory()?r.push(u):e.push(u)}}return e}function aF(t,e){let r=0,o=0;for(let a of t)a!==\"wip\"&&(e.test(a)?r+=1:o+=1);return r>=o}function GG(t){let e=aF(t,/^(\\w\\(\\w+\\):\\s*)?\\w+s/),r=aF(t,/^(\\w\\(\\w+\\):\\s*)?[A-Z]/),o=aF(t,/^\\w\\(\\w+\\):/);return{useThirdPerson:e,useUpperCase:r,useComponent:o}}function UBe(t){return t.useComponent?\"chore(yarn): \":\"\"}var fDt=new Map([[0,\"create\"],[1,\"delete\"],[2,\"add\"],[3,\"remove\"],[4,\"update\"]]);function YG(t,e){let r=UBe(t),o=[],a=e.slice().sort((n,u)=>n[0]-u[0]);for(;a.length>0;){let[n,u]=a.shift(),A=fDt.get(n);t.useUpperCase&&o.length===0&&(A=`${A[0].toUpperCase()}${A.slice(1)}`),t.useThirdPerson&&(A+=\"s\");let p=[u];for(;a.length>0&&a[0][0]===n;){let[,C]=a.shift();p.push(C)}p.sort();let h=p.shift();p.length===1?h+=\" (and one other)\":p.length>1&&(h+=` (and ${p.length} others)`),o.push(`${A} ${h}`)}return`${r}${o.join(\", \")}`}var pDt=\"Commit generated via `yarn stage`\",hDt=11;async function _Be(t){let{code:e,stdout:r}=await Ur.execvp(\"git\",[\"log\",\"-1\",\"--pretty=format:%H\"],{cwd:t});return e===0?r.trim():null}async function gDt(t,e){let r=[],o=e.filter(h=>V.basename(h.path)===\"package.json\");for(let{action:h,path:C}of o){let I=V.relative(t,C);if(h===4){let v=await _Be(t),{stdout:x}=await Ur.execvp(\"git\",[\"show\",`${v}:${I}`],{cwd:t,strict:!0}),E=await Ot.fromText(x),R=await Ot.fromFile(C),L=new Map([...R.dependencies,...R.devDependencies]),U=new Map([...E.dependencies,...E.devDependencies]);for(let[z,te]of U){let le=W.stringifyIdent(te),he=L.get(z);he?he.range!==te.range&&r.push([4,`${le} to ${he.range}`]):r.push([3,le])}for(let[z,te]of L)U.has(z)||r.push([2,W.stringifyIdent(te)])}else if(h===0){let v=await Ot.fromFile(C);v.name?r.push([0,W.stringifyIdent(v.name)]):r.push([0,\"a package\"])}else if(h===1){let v=await _Be(t),{stdout:x}=await Ur.execvp(\"git\",[\"show\",`${v}:${I}`],{cwd:t,strict:!0}),E=await Ot.fromText(x);E.name?r.push([1,W.stringifyIdent(E.name)]):r.push([1,\"a package\"])}else throw new Error(\"Assertion failed: Unsupported action type\")}let{code:a,stdout:n}=await Ur.execvp(\"git\",[\"log\",`-${hDt}`,\"--pretty=format:%s\"],{cwd:t}),u=a===0?n.split(/\\n/g).filter(h=>h!==\"\"):[],A=GG(u);return YG(A,r)}var dDt={[0]:[\" A \",\"?? \"],[4]:[\" M \"],[1]:[\" D \"]},mDt={[0]:[\"A  \"],[4]:[\"M  \"],[1]:[\"D  \"]},HBe={async findRoot(t){return await HG(t,{marker:\".git\"})},async filterChanges(t,e,r,o){let{stdout:a}=await Ur.execvp(\"git\",[\"status\",\"-s\"],{cwd:t,strict:!0}),n=a.toString().split(/\\n/g),u=o?.staged?mDt:dDt;return[].concat(...n.map(p=>{if(p===\"\")return[];let h=p.slice(0,3),C=V.resolve(t,p.slice(3));if(!o?.staged&&h===\"?? \"&&p.endsWith(\"/\"))return qG(C).map(I=>({action:0,path:I}));{let v=[0,4,1].find(x=>u[x].includes(h));return v!==void 0?[{action:v,path:C}]:[]}})).filter(p=>jG(p.path,{roots:e,names:r}))},async genCommitMessage(t,e){return await gDt(t,e)},async makeStage(t,e){let r=e.map(o=>ue.fromPortablePath(o.path));await Ur.execvp(\"git\",[\"add\",\"--\",...r],{cwd:t,strict:!0})},async makeCommit(t,e,r){let o=e.map(a=>ue.fromPortablePath(a.path));await Ur.execvp(\"git\",[\"add\",\"-N\",\"--\",...o],{cwd:t,strict:!0}),await Ur.execvp(\"git\",[\"commit\",\"-m\",`${r}\n\n${pDt}\n`,\"--\",...o],{cwd:t,strict:!0})},async makeReset(t,e){let r=e.map(o=>ue.fromPortablePath(o.path));await Ur.execvp(\"git\",[\"reset\",\"HEAD\",\"--\",...r],{cwd:t,strict:!0})}};var yDt=[HBe],X0=class extends ut{constructor(){super(...arguments);this.commit=ge.Boolean(\"-c,--commit\",!1,{description:\"Commit the staged files\"});this.reset=ge.Boolean(\"-r,--reset\",!1,{description:\"Remove all files from the staging area\"});this.dryRun=ge.Boolean(\"-n,--dry-run\",!1,{description:\"Print the commit message and the list of modified files without staging / committing\"});this.update=ge.Boolean(\"-u,--update\",!1,{hidden:!0})}async execute(){let r=await Ke.find(this.context.cwd,this.context.plugins),{project:o}=await St.find(r,this.context.cwd),{driver:a,root:n}=await EDt(o.cwd),u=[r.get(\"cacheFolder\"),r.get(\"globalFolder\"),r.get(\"virtualFolder\"),r.get(\"yarnPath\")];await r.triggerHook(I=>I.populateYarnPaths,o,I=>{u.push(I)});let A=new Set;for(let I of u)for(let v of CDt(n,I))A.add(v);let p=new Set([r.get(\"rcFilename\"),dr.lockfile,dr.manifest]),h=await a.filterChanges(n,A,p),C=await a.genCommitMessage(n,h);if(this.dryRun)if(this.commit)this.context.stdout.write(`${C}\n`);else for(let I of h)this.context.stdout.write(`${ue.fromPortablePath(I.path)}\n`);else if(this.reset){let I=await a.filterChanges(n,A,p,{staged:!0});I.length===0?this.context.stdout.write(\"No staged changes found!\"):await a.makeReset(n,I)}else h.length===0?this.context.stdout.write(\"No changes found!\"):this.commit?await a.makeCommit(n,h,C):(await a.makeStage(n,h),this.context.stdout.write(C))}};X0.paths=[[\"stage\"]],X0.usage=nt.Usage({description:\"add all yarn files to your vcs\",details:\"\\n      This command will add to your staging area the files belonging to Yarn (typically any modified `package.json` and `.yarnrc.yml` files, but also linker-generated files, cache data, etc). It will take your ignore list into account, so the cache files won't be added if the cache is ignored in a `.gitignore` file (assuming you use Git).\\n\\n      Running `--reset` will instead remove them from the staging area (the changes will still be there, but won't be committed until you stage them back).\\n\\n      Since the staging area is a non-existent concept in Mercurial, Yarn will always create a new commit when running this command on Mercurial repositories. You can get this behavior when using Git by using the `--commit` flag which will directly create a commit.\\n    \",examples:[[\"Adds all modified project files to the staging area\",\"yarn stage\"],[\"Creates a new commit containing all modified project files\",\"yarn stage --commit\"]]});async function EDt(t){let e=null,r=null;for(let o of yDt)if((r=await o.findRoot(t))!==null){e=o;break}if(e===null||r===null)throw new it(\"No stage driver has been found for your current project\");return{driver:e,root:r}}function CDt(t,e){let r=[];if(e===null)return r;for(;;){(e===t||e.startsWith(`${t}/`))&&r.push(e);let o;try{o=oe.statSync(e)}catch{break}if(o.isSymbolicLink())e=V.resolve(V.dirname(e),oe.readlinkSync(e));else break}return r}var wDt={commands:[X0]},IDt=wDt;var KG={};Vt(KG,{default:()=>kDt});Ye();Ye();Pt();var GBe=$e(Jn());Ye();var jBe=$e(ZH()),BDt=\"e8e1bd300d860104bb8c58453ffa1eb4\",vDt=\"OFCNCOG2CU\",qBe=async(t,e)=>{let r=W.stringifyIdent(t),a=DDt(e).initIndex(\"npm-search\");try{return(await a.getObject(r,{attributesToRetrieve:[\"types\"]})).types?.ts===\"definitely-typed\"}catch{return!1}},DDt=t=>(0,jBe.default)(vDt,BDt,{requester:{async send(r){try{let o=await rn.request(r.url,r.data||null,{configuration:t,headers:r.headers});return{content:o.body,isTimedOut:!1,status:o.statusCode}}catch(o){return{content:o.response.body,isTimedOut:!1,status:o.response.statusCode}}}}});var YBe=t=>t.scope?`${t.scope}__${t.name}`:`${t.name}`,PDt=async(t,e,r,o)=>{if(r.scope===\"types\")return;let{project:a}=t,{configuration:n}=a;if(!(n.get(\"tsEnableAutoTypes\")??oe.existsSync(V.join(a.cwd,\"tsconfig.json\"))))return;let A=n.makeResolver(),p={project:a,resolver:A,report:new Qi};if(!await qBe(r,n))return;let C=YBe(r),I=W.parseRange(r.range).selector;if(!kr.validRange(I)){let L=n.normalizeDependency(r),U=await A.getCandidates(L,{},p);I=W.parseRange(U[0].reference).selector}let v=GBe.default.coerce(I);if(v===null)return;let x=`${Jc.Modifier.CARET}${v.major}`,E=W.makeDescriptor(W.makeIdent(\"types\",C),x),R=je.mapAndFind(a.workspaces,L=>{let U=L.manifest.dependencies.get(r.identHash)?.descriptorHash,z=L.manifest.devDependencies.get(r.identHash)?.descriptorHash;if(U!==r.descriptorHash&&z!==r.descriptorHash)return je.mapAndFind.skip;let te=[];for(let le of Ot.allDependencies){let he=L.manifest[le].get(E.identHash);typeof he>\"u\"||te.push([le,he])}return te.length===0?je.mapAndFind.skip:te});if(typeof R<\"u\")for(let[L,U]of R)t.manifest[L].set(U.identHash,U);else{try{let L=n.normalizeDependency(E);if((await A.getCandidates(L,{},p)).length===0)return}catch{return}t.manifest[Jc.Target.DEVELOPMENT].set(E.identHash,E)}},SDt=async(t,e,r)=>{if(r.scope===\"types\")return;let{project:o}=t,{configuration:a}=o;if(!(a.get(\"tsEnableAutoTypes\")??oe.existsSync(V.join(o.cwd,\"tsconfig.json\"))))return;let u=YBe(r),A=W.makeIdent(\"types\",u);for(let p of Ot.allDependencies)typeof t.manifest[p].get(A.identHash)>\"u\"||t.manifest[p].delete(A.identHash)},bDt=(t,e)=>{e.publishConfig&&e.publishConfig.typings&&(e.typings=e.publishConfig.typings),e.publishConfig&&e.publishConfig.types&&(e.types=e.publishConfig.types)},xDt={configuration:{tsEnableAutoTypes:{description:\"Whether Yarn should auto-install @types/ dependencies on 'yarn add'\",type:\"BOOLEAN\",isNullable:!0,default:null}},hooks:{afterWorkspaceDependencyAddition:PDt,afterWorkspaceDependencyRemoval:SDt,beforeWorkspacePacking:bDt}},kDt=xDt;var ZG={};Vt(ZG,{VersionApplyCommand:()=>Z0,VersionCheckCommand:()=>$0,VersionCommand:()=>eg,default:()=>zDt,versionUtils:()=>hw});Ye();Ye();qt();var hw={};Vt(hw,{Decision:()=>fw,applyPrerelease:()=>XBe,applyReleases:()=>XG,applyStrategy:()=>uF,clearVersionFiles:()=>VG,getUndecidedDependentWorkspaces:()=>qv,getUndecidedWorkspaces:()=>cF,openVersionFile:()=>pw,requireMoreDecisions:()=>WDt,resolveVersionFiles:()=>jv,suggestStrategy:()=>JG,updateVersionFiles:()=>zG,validateReleaseDecision:()=>Aw});Ye();Pt();Nl();qt();var JBe=$e(zBe()),BA=$e(Jn()),YDt=/^(>=|[~^]|)(0|[1-9]\\d*)\\.(0|[1-9]\\d*)\\.(0|[1-9]\\d*)(-(0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*)(\\.(0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*))*)?(\\+[0-9a-zA-Z-]+(\\.[0-9a-zA-Z-]+)*)?$/,fw=(u=>(u.UNDECIDED=\"undecided\",u.DECLINE=\"decline\",u.MAJOR=\"major\",u.MINOR=\"minor\",u.PATCH=\"patch\",u.PRERELEASE=\"prerelease\",u))(fw||{});function Aw(t){let e=BA.default.valid(t);return e||je.validateEnum((0,JBe.default)(fw,\"UNDECIDED\"),t)}async function jv(t,{prerelease:e=null}={}){let r=new Map,o=t.configuration.get(\"deferredVersionFolder\");if(!oe.existsSync(o))return r;let a=await oe.readdirPromise(o);for(let n of a){if(!n.endsWith(\".yml\"))continue;let u=V.join(o,n),A=await oe.readFilePromise(u,\"utf8\"),p=Ki(A);for(let[h,C]of Object.entries(p.releases||{})){if(C===\"decline\")continue;let I=W.parseIdent(h),v=t.tryWorkspaceByIdent(I);if(v===null)throw new Error(`Assertion failed: Expected a release definition file to only reference existing workspaces (${V.basename(u)} references ${h})`);if(v.manifest.version===null)throw new Error(`Assertion failed: Expected the workspace to have a version (${W.prettyLocator(t.configuration,v.anchoredLocator)})`);let x=v.manifest.raw.stableVersion??v.manifest.version,E=r.get(v),R=uF(x,Aw(C));if(R===null)throw new Error(`Assertion failed: Expected ${x} to support being bumped via strategy ${C}`);let L=typeof E<\"u\"?BA.default.gt(R,E)?R:E:R;r.set(v,L)}}return e&&(r=new Map([...r].map(([n,u])=>[n,XBe(u,{current:n.manifest.version,prerelease:e})]))),r}async function VG(t){let e=t.configuration.get(\"deferredVersionFolder\");!oe.existsSync(e)||await oe.removePromise(e)}async function zG(t,e){let r=new Set(e),o=t.configuration.get(\"deferredVersionFolder\");if(!oe.existsSync(o))return;let a=await oe.readdirPromise(o);for(let n of a){if(!n.endsWith(\".yml\"))continue;let u=V.join(o,n),A=await oe.readFilePromise(u,\"utf8\"),p=Ki(A),h=p?.releases;if(!!h){for(let C of Object.keys(h)){let I=W.parseIdent(C),v=t.tryWorkspaceByIdent(I);(v===null||r.has(v))&&delete p.releases[C]}Object.keys(p.releases).length>0?await oe.changeFilePromise(u,Ba(new Ba.PreserveOrdering(p))):await oe.unlinkPromise(u)}}}async function pw(t,{allowEmpty:e=!1}={}){let r=t.configuration;if(r.projectCwd===null)throw new it(\"This command can only be run from within a Yarn project\");let o=await ra.fetchRoot(r.projectCwd),a=o!==null?await ra.fetchBase(o,{baseRefs:r.get(\"changesetBaseRefs\")}):null,n=o!==null?await ra.fetchChangedFiles(o,{base:a.hash,project:t}):[],u=r.get(\"deferredVersionFolder\"),A=n.filter(x=>V.contains(u,x)!==null);if(A.length>1)throw new it(`Your current branch contains multiple versioning files; this isn't supported:\n- ${A.map(x=>ue.fromPortablePath(x)).join(`\n- `)}`);let p=new Set(je.mapAndFilter(n,x=>{let E=t.tryWorkspaceByFilePath(x);return E===null?je.mapAndFilter.skip:E}));if(A.length===0&&p.size===0&&!e)return null;let h=A.length===1?A[0]:V.join(u,`${wn.makeHash(Math.random().toString()).slice(0,8)}.yml`),C=oe.existsSync(h)?await oe.readFilePromise(h,\"utf8\"):\"{}\",I=Ki(C),v=new Map;for(let x of I.declined||[]){let E=W.parseIdent(x),R=t.getWorkspaceByIdent(E);v.set(R,\"decline\")}for(let[x,E]of Object.entries(I.releases||{})){let R=W.parseIdent(x),L=t.getWorkspaceByIdent(R);v.set(L,Aw(E))}return{project:t,root:o,baseHash:a!==null?a.hash:null,baseTitle:a!==null?a.title:null,changedFiles:new Set(n),changedWorkspaces:p,releaseRoots:new Set([...p].filter(x=>x.manifest.version!==null)),releases:v,async saveAll(){let x={},E=[],R=[];for(let L of t.workspaces){if(L.manifest.version===null)continue;let U=W.stringifyIdent(L.anchoredLocator),z=v.get(L);z===\"decline\"?E.push(U):typeof z<\"u\"?x[U]=Aw(z):p.has(L)&&R.push(U)}await oe.mkdirPromise(V.dirname(h),{recursive:!0}),await oe.changeFilePromise(h,Ba(new Ba.PreserveOrdering({releases:Object.keys(x).length>0?x:void 0,declined:E.length>0?E:void 0,undecided:R.length>0?R:void 0})))}}}function WDt(t){return cF(t).size>0||qv(t).length>0}function cF(t){let e=new Set;for(let r of t.changedWorkspaces)r.manifest.version!==null&&(t.releases.has(r)||e.add(r));return e}function qv(t,{include:e=new Set}={}){let r=[],o=new Map(je.mapAndFilter([...t.releases],([n,u])=>u===\"decline\"?je.mapAndFilter.skip:[n.anchoredLocator.locatorHash,n])),a=new Map(je.mapAndFilter([...t.releases],([n,u])=>u!==\"decline\"?je.mapAndFilter.skip:[n.anchoredLocator.locatorHash,n]));for(let n of t.project.workspaces)if(!(!e.has(n)&&(a.has(n.anchoredLocator.locatorHash)||o.has(n.anchoredLocator.locatorHash)))&&n.manifest.version!==null)for(let u of Ot.hardDependencies)for(let A of n.manifest.getForScope(u).values()){let p=t.project.tryWorkspaceByDescriptor(A);p!==null&&o.has(p.anchoredLocator.locatorHash)&&r.push([n,p])}return r}function JG(t,e){let r=BA.default.clean(e);for(let o of Object.values(fw))if(o!==\"undecided\"&&o!==\"decline\"&&BA.default.inc(t,o)===r)return o;return null}function uF(t,e){if(BA.default.valid(e))return e;if(t===null)throw new it(`Cannot apply the release strategy \"${e}\" unless the workspace already has a valid version`);if(!BA.default.valid(t))throw new it(`Cannot apply the release strategy \"${e}\" on a non-semver version (${t})`);let r=BA.default.inc(t,e);if(r===null)throw new it(`Cannot apply the release strategy \"${e}\" on the specified version (${t})`);return r}function XG(t,e,{report:r}){let o=new Map;for(let a of t.workspaces)for(let n of Ot.allDependencies)for(let u of a.manifest[n].values()){let A=t.tryWorkspaceByDescriptor(u);if(A===null||!e.has(A))continue;je.getArrayWithDefault(o,A).push([a,n,u.identHash])}for(let[a,n]of e){let u=a.manifest.version;a.manifest.version=n,BA.default.prerelease(n)===null?delete a.manifest.raw.stableVersion:a.manifest.raw.stableVersion||(a.manifest.raw.stableVersion=u);let A=a.manifest.name!==null?W.stringifyIdent(a.manifest.name):null;r.reportInfo(0,`${W.prettyLocator(t.configuration,a.anchoredLocator)}: Bumped to ${n}`),r.reportJson({cwd:ue.fromPortablePath(a.cwd),ident:A,oldVersion:u,newVersion:n});let p=o.get(a);if(!(typeof p>\"u\"))for(let[h,C,I]of p){let v=h.manifest[C].get(I);if(typeof v>\"u\")throw new Error(\"Assertion failed: The dependency should have existed\");let x=v.range,E=!1;if(x.startsWith(Xn.protocol)&&(x=x.slice(Xn.protocol.length),E=!0,x===a.relativeCwd))continue;let R=x.match(YDt);if(!R){r.reportWarning(0,`Couldn't auto-upgrade range ${x} (in ${W.prettyLocator(t.configuration,h.anchoredLocator)})`);continue}let L=`${R[1]}${n}`;E&&(L=`${Xn.protocol}${L}`);let U=W.makeDescriptor(v,L);h.manifest[C].set(I,U)}}}var KDt=new Map([[\"%n\",{extract:t=>t.length>=1?[t[0],t.slice(1)]:null,generate:(t=0)=>`${t+1}`}]]);function XBe(t,{current:e,prerelease:r}){let o=new BA.default.SemVer(e),a=o.prerelease.slice(),n=[];o.prerelease=[],o.format()!==t&&(a.length=0);let u=!0,A=r.split(/\\./g);for(let p of A){let h=KDt.get(p);if(typeof h>\"u\")n.push(p),a[0]===p?a.shift():u=!1;else{let C=u?h.extract(a):null;C!==null&&typeof C[0]==\"number\"?(n.push(h.generate(C[0])),a=C[1]):(n.push(h.generate()),u=!1)}}return o.prerelease&&(o.prerelease=[]),`${t}-${n.join(\".\")}`}var Z0=class extends ut{constructor(){super(...arguments);this.all=ge.Boolean(\"--all\",!1,{description:\"Apply the deferred version changes on all workspaces\"});this.dryRun=ge.Boolean(\"--dry-run\",!1,{description:\"Print the versions without actually generating the package archive\"});this.prerelease=ge.String(\"--prerelease\",{description:\"Add a prerelease identifier to new versions\",tolerateBoolean:!0});this.recursive=ge.Boolean(\"-R,--recursive\",{description:\"Release the transitive workspaces as well\"});this.json=ge.Boolean(\"--json\",!1,{description:\"Format the output as an NDJSON stream\"})}async execute(){let r=await Ke.find(this.context.cwd,this.context.plugins),{project:o,workspace:a}=await St.find(r,this.context.cwd),n=await Lr.find(r);if(!a)throw new rr(o.cwd,this.context.cwd);await o.restoreInstallState({restoreResolutions:!1});let u=await Nt.start({configuration:r,json:this.json,stdout:this.context.stdout},async A=>{let p=this.prerelease?typeof this.prerelease!=\"boolean\"?this.prerelease:\"rc.%n\":null,h=await jv(o,{prerelease:p}),C=new Map;if(this.all)C=h;else{let I=this.recursive?a.getRecursiveWorkspaceDependencies():[a];for(let v of I){let x=h.get(v);typeof x<\"u\"&&C.set(v,x)}}if(C.size===0){let I=h.size>0?\" Did you want to add --all?\":\"\";A.reportWarning(0,`The current workspace doesn't seem to require a version bump.${I}`);return}XG(o,C,{report:A}),this.dryRun||(p||(this.all?await VG(o):await zG(o,[...C.keys()])),A.reportSeparator())});return u.hasErrors()?u.exitCode():await o.installWithNewReport({json:this.json,stdout:this.context.stdout},{cache:n})}};Z0.paths=[[\"version\",\"apply\"]],Z0.usage=nt.Usage({category:\"Release-related commands\",description:\"apply all the deferred version bumps at once\",details:`\n      This command will apply the deferred version changes and remove their definitions from the repository.\n\n      Note that if \\`--prerelease\\` is set, the given prerelease identifier (by default \\`rc.%d\\`) will be used on all new versions and the version definitions will be kept as-is.\n\n      By default only the current workspace will be bumped, but you can configure this behavior by using one of:\n\n      - \\`--recursive\\` to also apply the version bump on its dependencies\n      - \\`--all\\` to apply the version bump on all packages in the repository\n\n      Note that this command will also update the \\`workspace:\\` references across all your local workspaces, thus ensuring that they keep referring to the same workspaces even after the version bump.\n    `,examples:[[\"Apply the version change to the local workspace\",\"yarn version apply\"],[\"Apply the version change to all the workspaces in the local workspace\",\"yarn version apply --all\"]]});Ye();Pt();qt();var AF=$e(Jn());var $0=class extends ut{constructor(){super(...arguments);this.interactive=ge.Boolean(\"-i,--interactive\",{description:\"Open an interactive interface used to set version bumps\"})}async execute(){return this.interactive?await this.executeInteractive():await this.executeStandard()}async executeInteractive(){PC(this.context);let{Gem:r}=await Promise.resolve().then(()=>(AQ(),Dj)),{ScrollableItems:o}=await Promise.resolve().then(()=>(gQ(),hQ)),{FocusRequest:a}=await Promise.resolve().then(()=>(Sj(),Xwe)),{useListInput:n}=await Promise.resolve().then(()=>(pQ(),Zwe)),{renderForm:u}=await Promise.resolve().then(()=>(EQ(),yQ)),{Box:A,Text:p}=await Promise.resolve().then(()=>$e(ic())),{default:h,useCallback:C,useState:I}=await Promise.resolve().then(()=>$e(sn())),v=await Ke.find(this.context.cwd,this.context.plugins),{project:x,workspace:E}=await St.find(v,this.context.cwd);if(!E)throw new rr(x.cwd,this.context.cwd);await x.restoreInstallState();let R=await pw(x);if(R===null||R.releaseRoots.size===0)return 0;if(R.root===null)throw new it(\"This command can only be run on Git repositories\");let L=()=>h.createElement(A,{flexDirection:\"row\",paddingBottom:1},h.createElement(A,{flexDirection:\"column\",width:60},h.createElement(A,null,h.createElement(p,null,\"Press \",h.createElement(p,{bold:!0,color:\"cyanBright\"},\"<up>\"),\"/\",h.createElement(p,{bold:!0,color:\"cyanBright\"},\"<down>\"),\" to select workspaces.\")),h.createElement(A,null,h.createElement(p,null,\"Press \",h.createElement(p,{bold:!0,color:\"cyanBright\"},\"<left>\"),\"/\",h.createElement(p,{bold:!0,color:\"cyanBright\"},\"<right>\"),\" to select release strategies.\"))),h.createElement(A,{flexDirection:\"column\"},h.createElement(A,{marginLeft:1},h.createElement(p,null,\"Press \",h.createElement(p,{bold:!0,color:\"cyanBright\"},\"<enter>\"),\" to save.\")),h.createElement(A,{marginLeft:1},h.createElement(p,null,\"Press \",h.createElement(p,{bold:!0,color:\"cyanBright\"},\"<ctrl+c>\"),\" to abort.\")))),U=({workspace:ye,active:ae,decision:Ie,setDecision:Fe})=>{let g=ye.manifest.raw.stableVersion??ye.manifest.version;if(g===null)throw new Error(`Assertion failed: The version should have been set (${W.prettyLocator(v,ye.anchoredLocator)})`);if(AF.default.prerelease(g)!==null)throw new Error(`Assertion failed: Prerelease identifiers shouldn't be found (${g})`);let Ee=[\"undecided\",\"decline\",\"patch\",\"minor\",\"major\"];n(Ie,Ee,{active:ae,minus:\"left\",plus:\"right\",set:Fe});let De=Ie===\"undecided\"?h.createElement(p,{color:\"yellow\"},g):Ie===\"decline\"?h.createElement(p,{color:\"green\"},g):h.createElement(p,null,h.createElement(p,{color:\"magenta\"},g),\" \\u2192 \",h.createElement(p,{color:\"green\"},AF.default.valid(Ie)?Ie:AF.default.inc(g,Ie)));return h.createElement(A,{flexDirection:\"column\"},h.createElement(A,null,h.createElement(p,null,W.prettyLocator(v,ye.anchoredLocator),\" - \",De)),h.createElement(A,null,Ee.map(ce=>h.createElement(A,{key:ce,paddingLeft:2},h.createElement(p,null,h.createElement(r,{active:ce===Ie}),\" \",ce)))))},z=ye=>{let ae=new Set(R.releaseRoots),Ie=new Map([...ye].filter(([Fe])=>ae.has(Fe)));for(;;){let Fe=qv({project:R.project,releases:Ie}),g=!1;if(Fe.length>0){for(let[Ee]of Fe)if(!ae.has(Ee)){ae.add(Ee),g=!0;let De=ye.get(Ee);typeof De<\"u\"&&Ie.set(Ee,De)}}if(!g)break}return{relevantWorkspaces:ae,relevantReleases:Ie}},te=()=>{let[ye,ae]=I(()=>new Map(R.releases)),Ie=C((Fe,g)=>{let Ee=new Map(ye);g!==\"undecided\"?Ee.set(Fe,g):Ee.delete(Fe);let{relevantReleases:De}=z(Ee);ae(De)},[ye,ae]);return[ye,Ie]},le=({workspaces:ye,releases:ae})=>{let Ie=[];Ie.push(`${ye.size} total`);let Fe=0,g=0;for(let Ee of ye){let De=ae.get(Ee);typeof De>\"u\"?g+=1:De!==\"decline\"&&(Fe+=1)}return Ie.push(`${Fe} release${Fe===1?\"\":\"s\"}`),Ie.push(`${g} remaining`),h.createElement(p,{color:\"yellow\"},Ie.join(\", \"))},Ae=await u(({useSubmit:ye})=>{let[ae,Ie]=te();ye(ae);let{relevantWorkspaces:Fe}=z(ae),g=new Set([...Fe].filter(ne=>!R.releaseRoots.has(ne))),[Ee,De]=I(0),ce=C(ne=>{switch(ne){case a.BEFORE:De(Ee-1);break;case a.AFTER:De(Ee+1);break}},[Ee,De]);return h.createElement(A,{flexDirection:\"column\"},h.createElement(L,null),h.createElement(A,null,h.createElement(p,{wrap:\"wrap\"},\"The following files have been modified in your local checkout.\")),h.createElement(A,{flexDirection:\"column\",marginTop:1,paddingLeft:2},[...R.changedFiles].map(ne=>h.createElement(A,{key:ne},h.createElement(p,null,h.createElement(p,{color:\"grey\"},ue.fromPortablePath(R.root)),ue.sep,ue.relative(ue.fromPortablePath(R.root),ue.fromPortablePath(ne)))))),R.releaseRoots.size>0&&h.createElement(h.Fragment,null,h.createElement(A,{marginTop:1},h.createElement(p,{wrap:\"wrap\"},\"Because of those files having been modified, the following workspaces may need to be released again (note that private workspaces are also shown here, because even though they won't be published, releasing them will allow us to flag their dependents for potential re-release):\")),g.size>3?h.createElement(A,{marginTop:1},h.createElement(le,{workspaces:R.releaseRoots,releases:ae})):null,h.createElement(A,{marginTop:1,flexDirection:\"column\"},h.createElement(o,{active:Ee%2===0,radius:1,size:2,onFocusRequest:ce},[...R.releaseRoots].map(ne=>h.createElement(U,{key:ne.cwd,workspace:ne,decision:ae.get(ne)||\"undecided\",setDecision:ee=>Ie(ne,ee)}))))),g.size>0?h.createElement(h.Fragment,null,h.createElement(A,{marginTop:1},h.createElement(p,{wrap:\"wrap\"},\"The following workspaces depend on other workspaces that have been marked for release, and thus may need to be released as well:\")),h.createElement(A,null,h.createElement(p,null,\"(Press \",h.createElement(p,{bold:!0,color:\"cyanBright\"},\"<tab>\"),\" to move the focus between the workspace groups.)\")),g.size>5?h.createElement(A,{marginTop:1},h.createElement(le,{workspaces:g,releases:ae})):null,h.createElement(A,{marginTop:1,flexDirection:\"column\"},h.createElement(o,{active:Ee%2===1,radius:2,size:2,onFocusRequest:ce},[...g].map(ne=>h.createElement(U,{key:ne.cwd,workspace:ne,decision:ae.get(ne)||\"undecided\",setDecision:ee=>Ie(ne,ee)}))))):null)},{versionFile:R},{stdin:this.context.stdin,stdout:this.context.stdout,stderr:this.context.stderr});if(typeof Ae>\"u\")return 1;R.releases.clear();for(let[ye,ae]of Ae)R.releases.set(ye,ae);await R.saveAll()}async executeStandard(){let r=await Ke.find(this.context.cwd,this.context.plugins),{project:o,workspace:a}=await St.find(r,this.context.cwd);if(!a)throw new rr(o.cwd,this.context.cwd);return await o.restoreInstallState(),(await Nt.start({configuration:r,stdout:this.context.stdout},async u=>{let A=await pw(o);if(A===null||A.releaseRoots.size===0)return;if(A.root===null)throw new it(\"This command can only be run on Git repositories\");if(u.reportInfo(0,`Your PR was started right after ${de.pretty(r,A.baseHash.slice(0,7),\"yellow\")} ${de.pretty(r,A.baseTitle,\"magenta\")}`),A.changedFiles.size>0){u.reportInfo(0,\"You have changed the following files since then:\"),u.reportSeparator();for(let v of A.changedFiles)u.reportInfo(null,`${de.pretty(r,ue.fromPortablePath(A.root),\"gray\")}${ue.sep}${ue.relative(ue.fromPortablePath(A.root),ue.fromPortablePath(v))}`)}let p=!1,h=!1,C=cF(A);if(C.size>0){p||u.reportSeparator();for(let v of C)u.reportError(0,`${W.prettyLocator(r,v.anchoredLocator)} has been modified but doesn't have a release strategy attached`);p=!0}let I=qv(A);for(let[v,x]of I)h||u.reportSeparator(),u.reportError(0,`${W.prettyLocator(r,v.anchoredLocator)} doesn't have a release strategy attached, but depends on ${W.prettyWorkspace(r,x)} which is planned for release.`),h=!0;(p||h)&&(u.reportSeparator(),u.reportInfo(0,\"This command detected that at least some workspaces have received modifications without explicit instructions as to how they had to be released (if needed).\"),u.reportInfo(0,\"To correct these errors, run `yarn version check --interactive` then follow the instructions.\"))})).exitCode()}};$0.paths=[[\"version\",\"check\"]],$0.usage=nt.Usage({category:\"Release-related commands\",description:\"check that all the relevant packages have been bumped\",details:\"\\n      **Warning:** This command currently requires Git.\\n\\n      This command will check that all the packages covered by the files listed in argument have been properly bumped or declined to bump.\\n\\n      In the case of a bump, the check will also cover transitive packages - meaning that should `Foo` be bumped, a package `Bar` depending on `Foo` will require a decision as to whether `Bar` will need to be bumped. This check doesn't cross packages that have declined to bump.\\n\\n      In case no arguments are passed to the function, the list of modified files will be generated by comparing the HEAD against `master`.\\n    \",examples:[[\"Check whether the modified packages need a bump\",\"yarn version check\"]]});Ye();qt();var fF=$e(Jn());var eg=class extends ut{constructor(){super(...arguments);this.deferred=ge.Boolean(\"-d,--deferred\",{description:\"Prepare the version to be bumped during the next release cycle\"});this.immediate=ge.Boolean(\"-i,--immediate\",{description:\"Bump the version immediately\"});this.strategy=ge.String()}async execute(){let r=await Ke.find(this.context.cwd,this.context.plugins),{project:o,workspace:a}=await St.find(r,this.context.cwd);if(!a)throw new rr(o.cwd,this.context.cwd);let n=r.get(\"preferDeferredVersions\");this.deferred&&(n=!0),this.immediate&&(n=!1);let u=fF.default.valid(this.strategy),A=this.strategy===\"decline\",p;if(u)if(a.manifest.version!==null){let C=JG(a.manifest.version,this.strategy);C!==null?p=C:p=this.strategy}else p=this.strategy;else{let C=a.manifest.version;if(!A){if(C===null)throw new it(\"Can't bump the version if there wasn't a version to begin with - use 0.0.0 as initial version then run the command again.\");if(typeof C!=\"string\"||!fF.default.valid(C))throw new it(`Can't bump the version (${C}) if it's not valid semver`)}p=Aw(this.strategy)}if(!n){let I=(await jv(o)).get(a);if(typeof I<\"u\"&&p!==\"decline\"){let v=uF(a.manifest.version,p);if(fF.default.lt(v,I))throw new it(`Can't bump the version to one that would be lower than the current deferred one (${I})`)}}let h=await pw(o,{allowEmpty:!0});return h.releases.set(a,p),await h.saveAll(),n?0:await this.cli.run([\"version\",\"apply\"])}};eg.paths=[[\"version\"]],eg.usage=nt.Usage({category:\"Release-related commands\",description:\"apply a new version to the current package\",details:\"\\n      This command will bump the version number for the given package, following the specified strategy:\\n\\n      - If `major`, the first number from the semver range will be increased (`X.0.0`).\\n      - If `minor`, the second number from the semver range will be increased (`0.X.0`).\\n      - If `patch`, the third number from the semver range will be increased (`0.0.X`).\\n      - If prefixed by `pre` (`premajor`, ...), a `-0` suffix will be set (`0.0.0-0`).\\n      - If `prerelease`, the suffix will be increased (`0.0.0-X`); the third number from the semver range will also be increased if there was no suffix in the previous version.\\n      - If `decline`, the nonce will be increased for `yarn version check` to pass without version bump.\\n      - If a valid semver range, it will be used as new version.\\n      - If unspecified, Yarn will ask you for guidance.\\n\\n      For more information about the `--deferred` flag, consult our documentation (https://yarnpkg.com/features/release-workflow#deferred-versioning).\\n    \",examples:[[\"Immediately bump the version to the next major\",\"yarn version major\"],[\"Prepare the version to be bumped to the next major\",\"yarn version major --deferred\"]]});var VDt={configuration:{deferredVersionFolder:{description:\"Folder where are stored the versioning files\",type:\"ABSOLUTE_PATH\",default:\"./.yarn/versions\"},preferDeferredVersions:{description:\"If true, running `yarn version` will assume the `--deferred` flag unless `--immediate` is set\",type:\"BOOLEAN\",default:!1}},commands:[Z0,$0,eg]},zDt=VDt;var $G={};Vt($G,{WorkspacesFocusCommand:()=>tg,WorkspacesForeachCommand:()=>sp,default:()=>ZDt});Ye();Ye();qt();var tg=class extends ut{constructor(){super(...arguments);this.json=ge.Boolean(\"--json\",!1,{description:\"Format the output as an NDJSON stream\"});this.production=ge.Boolean(\"--production\",!1,{description:\"Only install regular dependencies by omitting dev dependencies\"});this.all=ge.Boolean(\"-A,--all\",!1,{description:\"Install the entire project\"});this.workspaces=ge.Rest()}async execute(){let r=await Ke.find(this.context.cwd,this.context.plugins),{project:o,workspace:a}=await St.find(r,this.context.cwd),n=await Lr.find(r);await o.restoreInstallState({restoreResolutions:!1});let u;if(this.all)u=new Set(o.workspaces);else if(this.workspaces.length===0){if(!a)throw new rr(o.cwd,this.context.cwd);u=new Set([a])}else u=new Set(this.workspaces.map(A=>o.getWorkspaceByIdent(W.parseIdent(A))));for(let A of u)for(let p of this.production?[\"dependencies\"]:Ot.hardDependencies)for(let h of A.manifest.getForScope(p).values()){let C=o.tryWorkspaceByDescriptor(h);C!==null&&u.add(C)}for(let A of o.workspaces)u.has(A)?this.production&&A.manifest.devDependencies.clear():(A.manifest.installConfig=A.manifest.installConfig||{},A.manifest.installConfig.selfReferences=!1,A.manifest.dependencies.clear(),A.manifest.devDependencies.clear(),A.manifest.peerDependencies.clear(),A.manifest.scripts.clear());return await o.installWithNewReport({json:this.json,stdout:this.context.stdout},{cache:n,persistProject:!1})}};tg.paths=[[\"workspaces\",\"focus\"]],tg.usage=nt.Usage({category:\"Workspace-related commands\",description:\"install a single workspace and its dependencies\",details:\"\\n      This command will run an install as if the specified workspaces (and all other workspaces they depend on) were the only ones in the project. If no workspaces are explicitly listed, the active one will be assumed.\\n\\n      Note that this command is only very moderately useful when using zero-installs, since the cache will contain all the packages anyway - meaning that the only difference between a full install and a focused install would just be a few extra lines in the `.pnp.cjs` file, at the cost of introducing an extra complexity.\\n\\n      If the `-A,--all` flag is set, the entire project will be installed. Combine with `--production` to replicate the old `yarn install --production`.\\n    \"});Ye();Ye();Ye();qt();var gw=$e(Zo()),$Be=$e(rd());Za();var sp=class extends ut{constructor(){super(...arguments);this.from=ge.Array(\"--from\",{description:\"An array of glob pattern idents or paths from which to base any recursion\"});this.all=ge.Boolean(\"-A,--all\",{description:\"Run the command on all workspaces of a project\"});this.recursive=ge.Boolean(\"-R,--recursive\",{description:\"Run the command on the current workspace and all of its recursive dependencies\"});this.worktree=ge.Boolean(\"-W,--worktree\",{description:\"Run the command on all workspaces of the current worktree\"});this.verbose=ge.Boolean(\"-v,--verbose\",{description:\"Prefix each output line with the name of the originating workspace\"});this.parallel=ge.Boolean(\"-p,--parallel\",!1,{description:\"Run the commands in parallel\"});this.interlaced=ge.Boolean(\"-i,--interlaced\",!1,{description:\"Print the output of commands in real-time instead of buffering it\"});this.jobs=ge.String(\"-j,--jobs\",{description:\"The maximum number of parallel tasks that the execution will be limited to; or `unlimited`\",validator:LT([Ks([\"unlimited\"]),sI(NT(),[MT(),OT(1)])])});this.topological=ge.Boolean(\"-t,--topological\",!1,{description:\"Run the command after all workspaces it depends on (regular) have finished\"});this.topologicalDev=ge.Boolean(\"--topological-dev\",!1,{description:\"Run the command after all workspaces it depends on (regular + dev) have finished\"});this.include=ge.Array(\"--include\",[],{description:\"An array of glob pattern idents or paths; only matching workspaces will be traversed\"});this.exclude=ge.Array(\"--exclude\",[],{description:\"An array of glob pattern idents or paths; matching workspaces won't be traversed\"});this.publicOnly=ge.Boolean(\"--no-private\",{description:\"Avoid running the command on private workspaces\"});this.since=ge.String(\"--since\",{description:\"Only include workspaces that have been changed since the specified ref.\",tolerateBoolean:!0});this.dryRun=ge.Boolean(\"-n,--dry-run\",{description:\"Print the commands that would be run, without actually running them\"});this.commandName=ge.String();this.args=ge.Proxy()}async execute(){let r=await Ke.find(this.context.cwd,this.context.plugins),{project:o,workspace:a}=await St.find(r,this.context.cwd);if(!this.all&&!a)throw new rr(o.cwd,this.context.cwd);await o.restoreInstallState();let n=this.cli.process([this.commandName,...this.args]),u=n.path.length===1&&n.path[0]===\"run\"&&typeof n.scriptName<\"u\"?n.scriptName:null;if(n.path.length===0)throw new it(\"Invalid subcommand name for iteration - use the 'run' keyword if you wish to execute a script\");let A=ae=>{!this.dryRun||this.context.stdout.write(`${ae}\n`)},p=()=>{let ae=this.from.map(Ie=>gw.default.matcher(Ie));return o.workspaces.filter(Ie=>{let Fe=W.stringifyIdent(Ie.anchoredLocator),g=Ie.relativeCwd;return ae.some(Ee=>Ee(Fe)||Ee(g))})},h=[];if(this.since?(A(\"Option --since is set; selecting the changed workspaces as root for workspace selection\"),h=Array.from(await ra.fetchChangedWorkspaces({ref:this.since,project:o}))):this.from?(A(\"Option --from is set; selecting the specified workspaces\"),h=[...p()]):this.worktree?(A(\"Option --worktree is set; selecting the current workspace\"),h=[a]):this.recursive?(A(\"Option --recursive is set; selecting the current workspace\"),h=[a]):this.all&&(A(\"Option --all is set; selecting all workspaces\"),h=[...o.workspaces]),this.dryRun&&!this.all){for(let ae of h)A(`\n- ${ae.relativeCwd}\n  ${W.prettyLocator(r,ae.anchoredLocator)}`);h.length>0&&A(\"\")}let C;if(this.recursive?this.since?(A(\"Option --recursive --since is set; recursively selecting all dependent workspaces\"),C=new Set(h.map(ae=>[...ae.getRecursiveWorkspaceDependents()]).flat())):(A(\"Option --recursive is set; recursively selecting all transitive dependencies\"),C=new Set(h.map(ae=>[...ae.getRecursiveWorkspaceDependencies()]).flat())):this.worktree?(A(\"Option --worktree is set; recursively selecting all nested workspaces\"),C=new Set(h.map(ae=>[...ae.getRecursiveWorkspaceChildren()]).flat())):C=null,C!==null&&(h=[...new Set([...h,...C])],this.dryRun))for(let ae of C)A(`\n- ${ae.relativeCwd}\n  ${W.prettyLocator(r,ae.anchoredLocator)}`);let I=[],v=!1;if(u?.includes(\":\")){for(let ae of o.workspaces)if(ae.manifest.scripts.has(u)&&(v=!v,v===!1))break}for(let ae of h){if(u&&!ae.manifest.scripts.has(u)&&!v&&!(await un.getWorkspaceAccessibleBinaries(ae)).has(u)){A(`Excluding ${ae.relativeCwd} because it doesn't have a \"${u}\" script`);continue}if(!(u===r.env.npm_lifecycle_event&&ae.cwd===a.cwd)){if(this.include.length>0&&!gw.default.isMatch(W.stringifyIdent(ae.anchoredLocator),this.include)&&!gw.default.isMatch(ae.relativeCwd,this.include)){A(`Excluding ${ae.relativeCwd} because it doesn't match the --include filter`);continue}if(this.exclude.length>0&&(gw.default.isMatch(W.stringifyIdent(ae.anchoredLocator),this.exclude)||gw.default.isMatch(ae.relativeCwd,this.exclude))){A(`Excluding ${ae.relativeCwd} because it matches the --include filter`);continue}if(this.publicOnly&&ae.manifest.private===!0){A(`Excluding ${ae.relativeCwd} because it's a private workspace and --no-private was set`);continue}I.push(ae)}}if(this.dryRun)return 0;let x=this.verbose??this.context.stdout.isTTY,E=this.parallel?this.jobs===\"unlimited\"?1/0:Number(this.jobs)||Math.ceil(zi.availableParallelism()/2):1,R=E===1?!1:this.parallel,L=R?this.interlaced:!0,U=(0,$Be.default)(E),z=new Map,te=new Set,le=0,he=null,Ae=!1,ye=await Nt.start({configuration:r,stdout:this.context.stdout,includePrefix:!1},async ae=>{let Ie=async(Fe,{commandIndex:g})=>{if(Ae)return-1;!R&&x&&g>1&&ae.reportSeparator();let Ee=JDt(Fe,{configuration:r,verbose:x,commandIndex:g}),[De,ce]=ZBe(ae,{prefix:Ee,interlaced:L}),[ne,ee]=ZBe(ae,{prefix:Ee,interlaced:L});try{x&&ae.reportInfo(null,`${Ee} Process started`);let we=Date.now(),xe=await this.cli.run([this.commandName,...this.args],{cwd:Fe.cwd,stdout:De,stderr:ne})||0;De.end(),ne.end(),await ce,await ee;let ht=Date.now();if(x){let H=r.get(\"enableTimers\")?`, completed in ${de.pretty(r,ht-we,de.Type.DURATION)}`:\"\";ae.reportInfo(null,`${Ee} Process exited (exit code ${xe})${H}`)}return xe===130&&(Ae=!0,he=xe),xe}catch(we){throw De.end(),ne.end(),await ce,await ee,we}};for(let Fe of I)z.set(Fe.anchoredLocator.locatorHash,Fe);for(;z.size>0&&!ae.hasErrors();){let Fe=[];for(let[De,ce]of z){if(te.has(ce.anchoredDescriptor.descriptorHash))continue;let ne=!0;if(this.topological||this.topologicalDev){let ee=this.topologicalDev?new Map([...ce.manifest.dependencies,...ce.manifest.devDependencies]):ce.manifest.dependencies;for(let we of ee.values()){let xe=o.tryWorkspaceByDescriptor(we);if(ne=xe===null||!z.has(xe.anchoredLocator.locatorHash),!ne)break}}if(!!ne&&(te.add(ce.anchoredDescriptor.descriptorHash),Fe.push(U(async()=>{let ee=await Ie(ce,{commandIndex:++le});return z.delete(De),te.delete(ce.anchoredDescriptor.descriptorHash),ee})),!R))break}if(Fe.length===0){let De=Array.from(z.values()).map(ce=>W.prettyLocator(r,ce.anchoredLocator)).join(\", \");ae.reportError(3,`Dependency cycle detected (${De})`);return}let Ee=(await Promise.all(Fe)).find(De=>De!==0);he===null&&(he=typeof Ee<\"u\"?1:he),(this.topological||this.topologicalDev)&&typeof Ee<\"u\"&&ae.reportError(0,\"The command failed for workspaces that are depended upon by other workspaces; can't satisfy the dependency graph\")}});return he!==null?he:ye.exitCode()}};sp.paths=[[\"workspaces\",\"foreach\"]],sp.usage=nt.Usage({category:\"Workspace-related commands\",description:\"run a command on all workspaces\",details:\"\\n      This command will run a given sub-command on current and all its descendant workspaces. Various flags can alter the exact behavior of the command:\\n\\n      - If `-p,--parallel` is set, the commands will be ran in parallel; they'll by default be limited to a number of parallel tasks roughly equal to half your core number, but that can be overridden via `-j,--jobs`, or disabled by setting `-j unlimited`.\\n\\n      - If `-p,--parallel` and `-i,--interlaced` are both set, Yarn will print the lines from the output as it receives them. If `-i,--interlaced` wasn't set, it would instead buffer the output from each process and print the resulting buffers only after their source processes have exited.\\n\\n      - If `-t,--topological` is set, Yarn will only run the command after all workspaces that it depends on through the `dependencies` field have successfully finished executing. If `--topological-dev` is set, both the `dependencies` and `devDependencies` fields will be considered when figuring out the wait points.\\n\\n      - If `-A,--all` is set, Yarn will run the command on all the workspaces of a project.\\n\\n      - If `-R,--recursive` is set, Yarn will find workspaces to run the command on by recursively evaluating `dependencies` and `devDependencies` fields, instead of looking at the `workspaces` fields.\\n\\n      - If `-W,--worktree` is set, Yarn will find workspaces to run the command on by looking at the current worktree.\\n\\n      - If `--from` is set, Yarn will use the packages matching the 'from' glob as the starting point for any recursive search.\\n\\n      - If `--since` is set, Yarn will only run the command on workspaces that have been modified since the specified ref. By default Yarn will use the refs specified by the `changesetBaseRefs` configuration option.\\n\\n      - If `--dry-run` is set, Yarn will explain what it would do without actually doing anything.\\n\\n      - The command may apply to only some workspaces through the use of `--include` which acts as a whitelist. The `--exclude` flag will do the opposite and will be a list of packages that mustn't execute the script. Both flags accept glob patterns (if valid Idents and supported by [micromatch](https://github.com/micromatch/micromatch)). Make sure to escape the patterns, to prevent your own shell from trying to expand them.\\n\\n      Adding the `-v,--verbose` flag (automatically enabled in interactive terminal environments) will cause Yarn to print more information; in particular the name of the workspace that generated the output will be printed at the front of each line.\\n\\n      If the command is `run` and the script being run does not exist the child workspace will be skipped without error.\\n    \",examples:[[\"Publish all packages\",\"yarn workspaces foreach -A npm publish --tolerate-republish\"],[\"Run the build script on all descendant packages\",\"yarn workspaces foreach -A run build\"],[\"Run the build script on current and all descendant packages in parallel, building package dependencies first\",\"yarn workspaces foreach -Apt run build\"],[\"Run the build script on several packages and all their dependencies, building dependencies first\",\"yarn workspaces foreach -Rpt --from '{workspace-a,workspace-b}' run build\"]]}),sp.schema=[aI(\"all\",Gu.Forbids,[\"from\",\"recursive\",\"since\",\"worktree\"],{missingIf:\"undefined\"}),UT([\"all\",\"recursive\",\"since\",\"worktree\"],{missingIf:\"undefined\"})];function ZBe(t,{prefix:e,interlaced:r}){let o=t.createStreamReporter(e),a=new je.DefaultStream;a.pipe(o,{end:!1}),a.on(\"finish\",()=>{o.end()});let n=new Promise(A=>{o.on(\"finish\",()=>{A(a.active)})});if(r)return[a,n];let u=new je.BufferStream;return u.pipe(a,{end:!1}),u.on(\"finish\",()=>{a.end()}),[u,n]}function JDt(t,{configuration:e,commandIndex:r,verbose:o}){if(!o)return null;let n=`[${W.stringifyIdent(t.anchoredLocator)}]:`,u=[\"#2E86AB\",\"#A23B72\",\"#F18F01\",\"#C73E1D\",\"#CCE2A3\"],A=u[r%u.length];return de.pretty(e,n,A)}var XDt={commands:[tg,sp]},ZDt=XDt;var AC=()=>({modules:new Map([[\"@yarnpkg/cli\",s2],[\"@yarnpkg/core\",i2],[\"@yarnpkg/fslib\",Ww],[\"@yarnpkg/libzip\",S1],[\"@yarnpkg/parsers\",eI],[\"@yarnpkg/shell\",F1],[\"clipanion\",fI],[\"semver\",$Dt],[\"typanion\",Vo],[\"@yarnpkg/plugin-essentials\",tH],[\"@yarnpkg/plugin-compat\",oH],[\"@yarnpkg/plugin-constraints\",BH],[\"@yarnpkg/plugin-dlx\",vH],[\"@yarnpkg/plugin-exec\",SH],[\"@yarnpkg/plugin-file\",xH],[\"@yarnpkg/plugin-git\",eH],[\"@yarnpkg/plugin-github\",FH],[\"@yarnpkg/plugin-http\",RH],[\"@yarnpkg/plugin-init\",TH],[\"@yarnpkg/plugin-interactive-tools\",Lj],[\"@yarnpkg/plugin-link\",Oj],[\"@yarnpkg/plugin-nm\",wq],[\"@yarnpkg/plugin-npm\",CG],[\"@yarnpkg/plugin-npm-cli\",xG],[\"@yarnpkg/plugin-pack\",gG],[\"@yarnpkg/plugin-patch\",LG],[\"@yarnpkg/plugin-pnp\",cq],[\"@yarnpkg/plugin-pnpm\",UG],[\"@yarnpkg/plugin-stage\",WG],[\"@yarnpkg/plugin-typescript\",KG],[\"@yarnpkg/plugin-version\",ZG],[\"@yarnpkg/plugin-workspace-tools\",$G]]),plugins:new Set([\"@yarnpkg/plugin-essentials\",\"@yarnpkg/plugin-compat\",\"@yarnpkg/plugin-constraints\",\"@yarnpkg/plugin-dlx\",\"@yarnpkg/plugin-exec\",\"@yarnpkg/plugin-file\",\"@yarnpkg/plugin-git\",\"@yarnpkg/plugin-github\",\"@yarnpkg/plugin-http\",\"@yarnpkg/plugin-init\",\"@yarnpkg/plugin-interactive-tools\",\"@yarnpkg/plugin-link\",\"@yarnpkg/plugin-nm\",\"@yarnpkg/plugin-npm\",\"@yarnpkg/plugin-npm-cli\",\"@yarnpkg/plugin-pack\",\"@yarnpkg/plugin-patch\",\"@yarnpkg/plugin-pnp\",\"@yarnpkg/plugin-pnpm\",\"@yarnpkg/plugin-stage\",\"@yarnpkg/plugin-typescript\",\"@yarnpkg/plugin-version\",\"@yarnpkg/plugin-workspace-tools\"])});function rve({cwd:t,pluginConfiguration:e}){let r=new as({binaryLabel:\"Yarn Package Manager\",binaryName:\"yarn\",binaryVersion:tn??\"<unknown>\"});return Object.assign(r,{defaultContext:{...as.defaultContext,cwd:t,plugins:e,quiet:!1,stdin:process.stdin,stdout:process.stdout,stderr:process.stderr}})}function ePt(t){if(je.parseOptionalBoolean(process.env.YARN_IGNORE_NODE))return!0;let r=process.versions.node,o=\">=18.12.0\";if(kr.satisfiesWithPrereleases(r,o))return!0;let a=new it(`This tool requires a Node version compatible with ${o} (got ${r}). Upgrade Node, or set \\`YARN_IGNORE_NODE=1\\` in your environment.`);return as.defaultContext.stdout.write(t.error(a)),!1}async function nve({selfPath:t,pluginConfiguration:e}){return await Ke.find(ue.toPortablePath(process.cwd()),e,{strict:!1,usePathCheck:t})}function tPt(t,e,{yarnPath:r}){if(!oe.existsSync(r))return t.error(new Error(`The \"yarn-path\" option has been set, but the specified location doesn't exist (${r}).`)),1;process.on(\"SIGINT\",()=>{});let o={stdio:\"inherit\",env:{...process.env,YARN_IGNORE_PATH:\"1\"}};try{(0,eve.execFileSync)(process.execPath,[ue.fromPortablePath(r),...e],o)}catch(a){return a.status??1}return 0}function rPt(t,e){let r=null,o=e;return e.length>=2&&e[0]===\"--cwd\"?(r=ue.toPortablePath(e[1]),o=e.slice(2)):e.length>=1&&e[0].startsWith(\"--cwd=\")?(r=ue.toPortablePath(e[0].slice(6)),o=e.slice(1)):e[0]===\"add\"&&e[e.length-2]===\"--cwd\"&&(r=ue.toPortablePath(e[e.length-1]),o=e.slice(0,e.length-2)),t.defaultContext.cwd=r!==null?V.resolve(r):V.cwd(),o}function nPt(t,{configuration:e}){if(!e.get(\"enableTelemetry\")||tve.isCI||!process.stdout.isTTY)return;Ke.telemetry=new lC(e,\"puba9cdc10ec5790a2cf4969dd413a47270\");let o=/^@yarnpkg\\/plugin-(.*)$/;for(let a of e.plugins.keys())cC.has(a.match(o)?.[1]??\"\")&&Ke.telemetry?.reportPluginName(a);t.binaryVersion&&Ke.telemetry.reportVersion(t.binaryVersion)}function ive(t,{configuration:e}){for(let r of e.plugins.values())for(let o of r.commands||[])t.register(o)}async function iPt(t,e,{selfPath:r,pluginConfiguration:o}){if(!ePt(t))return 1;let a=await nve({selfPath:r,pluginConfiguration:o}),n=a.get(\"yarnPath\"),u=a.get(\"ignorePath\");if(n&&!u)return tPt(t,e,{yarnPath:n});delete process.env.YARN_IGNORE_PATH;let A=rPt(t,e);nPt(t,{configuration:a}),ive(t,{configuration:a});let p=t.process(A,t.defaultContext);return p.help||Ke.telemetry?.reportCommandName(p.path.join(\" \")),await t.run(p,t.defaultContext)}async function rhe({cwd:t=V.cwd(),pluginConfiguration:e=AC()}={}){let r=rve({cwd:t,pluginConfiguration:e}),o=await nve({pluginConfiguration:e,selfPath:null});return ive(r,{configuration:o}),r}async function sk(t,{cwd:e=V.cwd(),selfPath:r,pluginConfiguration:o}){let a=rve({cwd:e,pluginConfiguration:o});try{process.exitCode=await iPt(a,t,{selfPath:r,pluginConfiguration:o})}catch(n){as.defaultContext.stdout.write(a.error(n)),process.exitCode=1}finally{await oe.rmtempPromise()}}sk(process.argv.slice(2),{cwd:V.cwd(),selfPath:ue.toPortablePath(ue.resolve(process.argv[1])),pluginConfiguration:AC()});})();\n/*\nobject-assign\n(c) Sindre Sorhus\n@license MIT\n*/\n/*!\n * buildToken\n * Builds OAuth token prefix (helper function)\n *\n * @name buildToken\n * @function\n * @param {GitUrl} obj The parsed Git url object.\n * @return {String} token prefix\n */\n/*!\n * fill-range <https://github.com/jonschlinkert/fill-range>\n *\n * Copyright (c) 2014-present, Jon Schlinkert.\n * Licensed under the MIT License.\n */\n/*!\n * is-extglob <https://github.com/jonschlinkert/is-extglob>\n *\n * Copyright (c) 2014-2016, Jon Schlinkert.\n * Licensed under the MIT License.\n */\n/*!\n * is-glob <https://github.com/jonschlinkert/is-glob>\n *\n * Copyright (c) 2014-2017, Jon Schlinkert.\n * Released under the MIT License.\n */\n/*!\n * is-number <https://github.com/jonschlinkert/is-number>\n *\n * Copyright (c) 2014-present, Jon Schlinkert.\n * Released under the MIT License.\n */\n/*!\n * is-windows <https://github.com/jonschlinkert/is-windows>\n *\n * Copyright © 2015-2018, Jon Schlinkert.\n * Released under the MIT License.\n */\n/*!\n * to-regex-range <https://github.com/micromatch/to-regex-range>\n *\n * Copyright (c) 2015-present, Jon Schlinkert.\n * Released under the MIT License.\n */\n/**\n  @license\n  Copyright (c) 2015, Rebecca Turner\n\n  Permission to use, copy, modify, and/or distribute this software for any\n  purpose with or without fee is hereby granted, provided that the above\n  copyright notice and this permission notice appear in all copies.\n\n  THE SOFTWARE IS PROVIDED \"AS IS\" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH\n  REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND\n  FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,\n  INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM\n  LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR\n  OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR\n  PERFORMANCE OF THIS SOFTWARE.\n */\n/**\n  @license\n  Copyright Joyent, Inc. and other Node contributors.\n\n  Permission is hereby granted, free of charge, to any person obtaining a\n  copy of this software and associated documentation files (the\n  \"Software\"), to deal in the Software without restriction, including\n  without limitation the rights to use, copy, modify, merge, publish,\n  distribute, sublicense, and/or sell copies of the Software, and to permit\n  persons to whom the Software is furnished to do so, subject to the\n  following conditions:\n\n  The above copyright notice and this permission notice shall be included\n  in all copies or substantial portions of the Software.\n\n  THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS\n  OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\n  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN\n  NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,\n  DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR\n  OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE\n  USE OR OTHER DEALINGS IN THE SOFTWARE.\n*/\n/**\n  @license\n  Copyright Node.js contributors. All rights reserved.\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\n  deal in the Software without restriction, including without limitation the\n  rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n  sell copies of the Software, and to permit persons to whom the Software is\n  furnished to do so, subject to the following conditions:\n\n  The above copyright notice and this permission notice shall be included in\n  all copies or substantial portions of the Software.\n\n  THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n  FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n  IN THE SOFTWARE.\n*/\n/**\n  @license\n  The MIT License (MIT)\n\n  Copyright (c) 2014 Blake Embrey (hello@blakeembrey.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\n  all copies or substantial portions of the Software.\n\n  THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n  THE SOFTWARE.\n*/\n/** @license React v0.18.0\n * scheduler.production.min.js\n *\n * Copyright (c) Facebook, Inc. and its affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n */\n/** @license React v0.24.0\n * react-reconciler.production.min.js\n *\n * Copyright (c) Facebook, Inc. and its affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n */\n/** @license React v16.13.1\n * react.production.min.js\n *\n * Copyright (c) Facebook, Inc. and its affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n */\n"
  },
  {
    "path": ".yarn/sdks/integrations.yml",
    "content": "# This file is automatically generated by @yarnpkg/sdks.\n# Manual changes might be lost!\n\nintegrations:\n  - vscode\n"
  },
  {
    "path": ".yarn/sdks/typescript/lib/tsc.js",
    "content": "#!/usr/bin/env node\n\nconst {existsSync} = require(`fs`);\nconst {createRequire} = require(`module`);\nconst {resolve} = require(`path`);\n\nconst relPnpApiPath = \"../../../../.pnp.cjs\";\n\nconst absPnpApiPath = resolve(__dirname, relPnpApiPath);\nconst absRequire = createRequire(absPnpApiPath);\n\nif (existsSync(absPnpApiPath)) {\n  if (!process.versions.pnp) {\n    // Setup the environment to be able to require typescript/lib/tsc.js\n    require(absPnpApiPath).setup();\n  }\n}\n\n// Defer to the real typescript/lib/tsc.js your application uses\nmodule.exports = absRequire(`typescript/lib/tsc.js`);\n"
  },
  {
    "path": ".yarn/sdks/typescript/lib/tsserver.js",
    "content": "#!/usr/bin/env node\n\nconst {existsSync} = require(`fs`);\nconst {createRequire} = require(`module`);\nconst {resolve} = require(`path`);\n\nconst relPnpApiPath = \"../../../../.pnp.cjs\";\n\nconst absPnpApiPath = resolve(__dirname, relPnpApiPath);\nconst absRequire = createRequire(absPnpApiPath);\n\nconst moduleWrapper = tsserver => {\n  if (!process.versions.pnp) {\n    return tsserver;\n  }\n\n  const {isAbsolute} = require(`path`);\n  const pnpApi = require(`pnpapi`);\n\n  const isVirtual = str => str.match(/\\/(\\$\\$virtual|__virtual__)\\//);\n  const isPortal = str => str.startsWith(\"portal:/\");\n  const normalize = str => str.replace(/\\\\/g, `/`).replace(/^\\/?/, `/`);\n\n  const dependencyTreeRoots = new Set(pnpApi.getDependencyTreeRoots().map(locator => {\n    return `${locator.name}@${locator.reference}`;\n  }));\n\n  // VSCode sends the zip paths to TS using the \"zip://\" prefix, that TS\n  // doesn't understand. This layer makes sure to remove the protocol\n  // before forwarding it to TS, and to add it back on all returned paths.\n\n  function toEditorPath(str) {\n    // We add the `zip:` prefix to both `.zip/` paths and virtual paths\n    if (isAbsolute(str) && !str.match(/^\\^?(zip:|\\/zip\\/)/) && (str.match(/\\.zip\\//) || isVirtual(str))) {\n      // We also take the opportunity to turn virtual paths into physical ones;\n      // this makes it much easier to work with workspaces that list peer\n      // dependencies, since otherwise Ctrl+Click would bring us to the virtual\n      // file instances instead of the real ones.\n      //\n      // We only do this to modules owned by the the dependency tree roots.\n      // This avoids breaking the resolution when jumping inside a vendor\n      // with peer dep (otherwise jumping into react-dom would show resolution\n      // errors on react).\n      //\n      const resolved = isVirtual(str) ? pnpApi.resolveVirtual(str) : str;\n      if (resolved) {\n        const locator = pnpApi.findPackageLocator(resolved);\n        if (locator && (dependencyTreeRoots.has(`${locator.name}@${locator.reference}`) || isPortal(locator.reference))) {\n          str = resolved;\n        }\n      }\n\n      str = normalize(str);\n\n      if (str.match(/\\.zip\\//)) {\n        switch (hostInfo) {\n          // Absolute VSCode `Uri.fsPath`s need to start with a slash.\n          // VSCode only adds it automatically for supported schemes,\n          // so we have to do it manually for the `zip` scheme.\n          // The path needs to start with a caret otherwise VSCode doesn't handle the protocol\n          //\n          // Ref: https://github.com/microsoft/vscode/issues/105014#issuecomment-686760910\n          //\n          // 2021-10-08: VSCode changed the format in 1.61.\n          // Before | ^zip:/c:/foo/bar.zip/package.json\n          // After  | ^/zip//c:/foo/bar.zip/package.json\n          //\n          // 2022-04-06: VSCode changed the format in 1.66.\n          // Before | ^/zip//c:/foo/bar.zip/package.json\n          // After  | ^/zip/c:/foo/bar.zip/package.json\n          //\n          // 2022-05-06: VSCode changed the format in 1.68\n          // Before | ^/zip/c:/foo/bar.zip/package.json\n          // After  | ^/zip//c:/foo/bar.zip/package.json\n          //\n          case `vscode <1.61`: {\n            str = `^zip:${str}`;\n          } break;\n\n          case `vscode <1.66`: {\n            str = `^/zip/${str}`;\n          } break;\n\n          case `vscode <1.68`: {\n            str = `^/zip${str}`;\n          } break;\n\n          case `vscode`: {\n            str = `^/zip/${str}`;\n          } break;\n\n          // To make \"go to definition\" work,\n          // We have to resolve the actual file system path from virtual path\n          // and convert scheme to supported by [vim-rzip](https://github.com/lbrayner/vim-rzip)\n          case `coc-nvim`: {\n            str = normalize(resolved).replace(/\\.zip\\//, `.zip::`);\n            str = resolve(`zipfile:${str}`);\n          } break;\n\n          // Support neovim native LSP and [typescript-language-server](https://github.com/theia-ide/typescript-language-server)\n          // We have to resolve the actual file system path from virtual path,\n          // everything else is up to neovim\n          case `neovim`: {\n            str = normalize(resolved).replace(/\\.zip\\//, `.zip::`);\n            str = `zipfile://${str}`;\n          } break;\n\n          default: {\n            str = `zip:${str}`;\n          } break;\n        }\n      } else {\n        str = str.replace(/^\\/?/, process.platform === `win32` ? `` : `/`);\n      }\n    }\n\n    return str;\n  }\n\n  function fromEditorPath(str) {\n    switch (hostInfo) {\n      case `coc-nvim`: {\n        str = str.replace(/\\.zip::/, `.zip/`);\n        // The path for coc-nvim is in format of /<pwd>/zipfile:/<pwd>/.yarn/...\n        // So in order to convert it back, we use .* to match all the thing\n        // before `zipfile:`\n        return process.platform === `win32`\n          ? str.replace(/^.*zipfile:\\//, ``)\n          : str.replace(/^.*zipfile:/, ``);\n      } break;\n\n      case `neovim`: {\n        str = str.replace(/\\.zip::/, `.zip/`);\n        // The path for neovim is in format of zipfile:///<pwd>/.yarn/...\n        return str.replace(/^zipfile:\\/\\//, ``);\n      } break;\n\n      case `vscode`:\n      default: {\n        return str.replace(/^\\^?(zip:|\\/zip(\\/ts-nul-authority)?)\\/+/, process.platform === `win32` ? `` : `/`)\n      } break;\n    }\n  }\n\n  // Force enable 'allowLocalPluginLoads'\n  // TypeScript tries to resolve plugins using a path relative to itself\n  // which doesn't work when using the global cache\n  // https://github.com/microsoft/TypeScript/blob/1b57a0395e0bff191581c9606aab92832001de62/src/server/project.ts#L2238\n  // VSCode doesn't want to enable 'allowLocalPluginLoads' due to security concerns but\n  // TypeScript already does local loads and if this code is running the user trusts the workspace\n  // https://github.com/microsoft/vscode/issues/45856\n  const ConfiguredProject = tsserver.server.ConfiguredProject;\n  const {enablePluginsWithOptions: originalEnablePluginsWithOptions} = ConfiguredProject.prototype;\n  ConfiguredProject.prototype.enablePluginsWithOptions = function() {\n    this.projectService.allowLocalPluginLoads = true;\n    return originalEnablePluginsWithOptions.apply(this, arguments);\n  };\n\n  // And here is the point where we hijack the VSCode <-> TS communications\n  // by adding ourselves in the middle. We locate everything that looks\n  // like an absolute path of ours and normalize it.\n\n  const Session = tsserver.server.Session;\n  const {onMessage: originalOnMessage, send: originalSend} = Session.prototype;\n  let hostInfo = `unknown`;\n\n  Object.assign(Session.prototype, {\n    onMessage(/** @type {string | object} */ message) {\n      const isStringMessage = typeof message === 'string';\n      const parsedMessage = isStringMessage ? JSON.parse(message) : message;\n\n      if (\n        parsedMessage != null &&\n        typeof parsedMessage === `object` &&\n        parsedMessage.arguments &&\n        typeof parsedMessage.arguments.hostInfo === `string`\n      ) {\n        hostInfo = parsedMessage.arguments.hostInfo;\n        if (hostInfo === `vscode` && process.env.VSCODE_IPC_HOOK) {\n          const [, major, minor] = (process.env.VSCODE_IPC_HOOK.match(\n            // The RegExp from https://semver.org/ but without the caret at the start\n            /(0|[1-9]\\d*)\\.(0|[1-9]\\d*)\\.(0|[1-9]\\d*)(?:-((?:0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\\.(?:0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\\+([0-9a-zA-Z-]+(?:\\.[0-9a-zA-Z-]+)*))?$/\n          ) ?? []).map(Number)\n\n          if (major === 1) {\n            if (minor < 61) {\n              hostInfo += ` <1.61`;\n            } else if (minor < 66) {\n              hostInfo += ` <1.66`;\n            } else if (minor < 68) {\n              hostInfo += ` <1.68`;\n            }\n          }\n        }\n      }\n\n      const processedMessageJSON = JSON.stringify(parsedMessage, (key, value) => {\n        return typeof value === 'string' ? fromEditorPath(value) : value;\n      });\n\n      return originalOnMessage.call(\n        this,\n        isStringMessage ? processedMessageJSON : JSON.parse(processedMessageJSON)\n      );\n    },\n\n    send(/** @type {any} */ msg) {\n      return originalSend.call(this, JSON.parse(JSON.stringify(msg, (key, value) => {\n        return typeof value === `string` ? toEditorPath(value) : value;\n      })));\n    }\n  });\n\n  return tsserver;\n};\n\nif (existsSync(absPnpApiPath)) {\n  if (!process.versions.pnp) {\n    // Setup the environment to be able to require typescript/lib/tsserver.js\n    require(absPnpApiPath).setup();\n  }\n}\n\n// Defer to the real typescript/lib/tsserver.js your application uses\nmodule.exports = moduleWrapper(absRequire(`typescript/lib/tsserver.js`));\n"
  },
  {
    "path": ".yarn/sdks/typescript/lib/tsserverlibrary.js",
    "content": "#!/usr/bin/env node\n\nconst {existsSync} = require(`fs`);\nconst {createRequire} = require(`module`);\nconst {resolve} = require(`path`);\n\nconst relPnpApiPath = \"../../../../.pnp.cjs\";\n\nconst absPnpApiPath = resolve(__dirname, relPnpApiPath);\nconst absRequire = createRequire(absPnpApiPath);\n\nconst moduleWrapper = tsserver => {\n  if (!process.versions.pnp) {\n    return tsserver;\n  }\n\n  const {isAbsolute} = require(`path`);\n  const pnpApi = require(`pnpapi`);\n\n  const isVirtual = str => str.match(/\\/(\\$\\$virtual|__virtual__)\\//);\n  const isPortal = str => str.startsWith(\"portal:/\");\n  const normalize = str => str.replace(/\\\\/g, `/`).replace(/^\\/?/, `/`);\n\n  const dependencyTreeRoots = new Set(pnpApi.getDependencyTreeRoots().map(locator => {\n    return `${locator.name}@${locator.reference}`;\n  }));\n\n  // VSCode sends the zip paths to TS using the \"zip://\" prefix, that TS\n  // doesn't understand. This layer makes sure to remove the protocol\n  // before forwarding it to TS, and to add it back on all returned paths.\n\n  function toEditorPath(str) {\n    // We add the `zip:` prefix to both `.zip/` paths and virtual paths\n    if (isAbsolute(str) && !str.match(/^\\^?(zip:|\\/zip\\/)/) && (str.match(/\\.zip\\//) || isVirtual(str))) {\n      // We also take the opportunity to turn virtual paths into physical ones;\n      // this makes it much easier to work with workspaces that list peer\n      // dependencies, since otherwise Ctrl+Click would bring us to the virtual\n      // file instances instead of the real ones.\n      //\n      // We only do this to modules owned by the the dependency tree roots.\n      // This avoids breaking the resolution when jumping inside a vendor\n      // with peer dep (otherwise jumping into react-dom would show resolution\n      // errors on react).\n      //\n      const resolved = isVirtual(str) ? pnpApi.resolveVirtual(str) : str;\n      if (resolved) {\n        const locator = pnpApi.findPackageLocator(resolved);\n        if (locator && (dependencyTreeRoots.has(`${locator.name}@${locator.reference}`) || isPortal(locator.reference))) {\n          str = resolved;\n        }\n      }\n\n      str = normalize(str);\n\n      if (str.match(/\\.zip\\//)) {\n        switch (hostInfo) {\n          // Absolute VSCode `Uri.fsPath`s need to start with a slash.\n          // VSCode only adds it automatically for supported schemes,\n          // so we have to do it manually for the `zip` scheme.\n          // The path needs to start with a caret otherwise VSCode doesn't handle the protocol\n          //\n          // Ref: https://github.com/microsoft/vscode/issues/105014#issuecomment-686760910\n          //\n          // 2021-10-08: VSCode changed the format in 1.61.\n          // Before | ^zip:/c:/foo/bar.zip/package.json\n          // After  | ^/zip//c:/foo/bar.zip/package.json\n          //\n          // 2022-04-06: VSCode changed the format in 1.66.\n          // Before | ^/zip//c:/foo/bar.zip/package.json\n          // After  | ^/zip/c:/foo/bar.zip/package.json\n          //\n          // 2022-05-06: VSCode changed the format in 1.68\n          // Before | ^/zip/c:/foo/bar.zip/package.json\n          // After  | ^/zip//c:/foo/bar.zip/package.json\n          //\n          case `vscode <1.61`: {\n            str = `^zip:${str}`;\n          } break;\n\n          case `vscode <1.66`: {\n            str = `^/zip/${str}`;\n          } break;\n\n          case `vscode <1.68`: {\n            str = `^/zip${str}`;\n          } break;\n\n          case `vscode`: {\n            str = `^/zip/${str}`;\n          } break;\n\n          // To make \"go to definition\" work,\n          // We have to resolve the actual file system path from virtual path\n          // and convert scheme to supported by [vim-rzip](https://github.com/lbrayner/vim-rzip)\n          case `coc-nvim`: {\n            str = normalize(resolved).replace(/\\.zip\\//, `.zip::`);\n            str = resolve(`zipfile:${str}`);\n          } break;\n\n          // Support neovim native LSP and [typescript-language-server](https://github.com/theia-ide/typescript-language-server)\n          // We have to resolve the actual file system path from virtual path,\n          // everything else is up to neovim\n          case `neovim`: {\n            str = normalize(resolved).replace(/\\.zip\\//, `.zip::`);\n            str = `zipfile://${str}`;\n          } break;\n\n          default: {\n            str = `zip:${str}`;\n          } break;\n        }\n      } else {\n        str = str.replace(/^\\/?/, process.platform === `win32` ? `` : `/`);\n      }\n    }\n\n    return str;\n  }\n\n  function fromEditorPath(str) {\n    switch (hostInfo) {\n      case `coc-nvim`: {\n        str = str.replace(/\\.zip::/, `.zip/`);\n        // The path for coc-nvim is in format of /<pwd>/zipfile:/<pwd>/.yarn/...\n        // So in order to convert it back, we use .* to match all the thing\n        // before `zipfile:`\n        return process.platform === `win32`\n          ? str.replace(/^.*zipfile:\\//, ``)\n          : str.replace(/^.*zipfile:/, ``);\n      } break;\n\n      case `neovim`: {\n        str = str.replace(/\\.zip::/, `.zip/`);\n        // The path for neovim is in format of zipfile:///<pwd>/.yarn/...\n        return str.replace(/^zipfile:\\/\\//, ``);\n      } break;\n\n      case `vscode`:\n      default: {\n        return str.replace(/^\\^?(zip:|\\/zip(\\/ts-nul-authority)?)\\/+/, process.platform === `win32` ? `` : `/`)\n      } break;\n    }\n  }\n\n  // Force enable 'allowLocalPluginLoads'\n  // TypeScript tries to resolve plugins using a path relative to itself\n  // which doesn't work when using the global cache\n  // https://github.com/microsoft/TypeScript/blob/1b57a0395e0bff191581c9606aab92832001de62/src/server/project.ts#L2238\n  // VSCode doesn't want to enable 'allowLocalPluginLoads' due to security concerns but\n  // TypeScript already does local loads and if this code is running the user trusts the workspace\n  // https://github.com/microsoft/vscode/issues/45856\n  const ConfiguredProject = tsserver.server.ConfiguredProject;\n  const {enablePluginsWithOptions: originalEnablePluginsWithOptions} = ConfiguredProject.prototype;\n  ConfiguredProject.prototype.enablePluginsWithOptions = function() {\n    this.projectService.allowLocalPluginLoads = true;\n    return originalEnablePluginsWithOptions.apply(this, arguments);\n  };\n\n  // And here is the point where we hijack the VSCode <-> TS communications\n  // by adding ourselves in the middle. We locate everything that looks\n  // like an absolute path of ours and normalize it.\n\n  const Session = tsserver.server.Session;\n  const {onMessage: originalOnMessage, send: originalSend} = Session.prototype;\n  let hostInfo = `unknown`;\n\n  Object.assign(Session.prototype, {\n    onMessage(/** @type {string | object} */ message) {\n      const isStringMessage = typeof message === 'string';\n      const parsedMessage = isStringMessage ? JSON.parse(message) : message;\n\n      if (\n        parsedMessage != null &&\n        typeof parsedMessage === `object` &&\n        parsedMessage.arguments &&\n        typeof parsedMessage.arguments.hostInfo === `string`\n      ) {\n        hostInfo = parsedMessage.arguments.hostInfo;\n        if (hostInfo === `vscode` && process.env.VSCODE_IPC_HOOK) {\n          const [, major, minor] = (process.env.VSCODE_IPC_HOOK.match(\n            // The RegExp from https://semver.org/ but without the caret at the start\n            /(0|[1-9]\\d*)\\.(0|[1-9]\\d*)\\.(0|[1-9]\\d*)(?:-((?:0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\\.(?:0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\\+([0-9a-zA-Z-]+(?:\\.[0-9a-zA-Z-]+)*))?$/\n          ) ?? []).map(Number)\n\n          if (major === 1) {\n            if (minor < 61) {\n              hostInfo += ` <1.61`;\n            } else if (minor < 66) {\n              hostInfo += ` <1.66`;\n            } else if (minor < 68) {\n              hostInfo += ` <1.68`;\n            }\n          }\n        }\n      }\n\n      const processedMessageJSON = JSON.stringify(parsedMessage, (key, value) => {\n        return typeof value === 'string' ? fromEditorPath(value) : value;\n      });\n\n      return originalOnMessage.call(\n        this,\n        isStringMessage ? processedMessageJSON : JSON.parse(processedMessageJSON)\n      );\n    },\n\n    send(/** @type {any} */ msg) {\n      return originalSend.call(this, JSON.parse(JSON.stringify(msg, (key, value) => {\n        return typeof value === `string` ? toEditorPath(value) : value;\n      })));\n    }\n  });\n\n  return tsserver;\n};\n\nif (existsSync(absPnpApiPath)) {\n  if (!process.versions.pnp) {\n    // Setup the environment to be able to require typescript/lib/tsserverlibrary.js\n    require(absPnpApiPath).setup();\n  }\n}\n\n// Defer to the real typescript/lib/tsserverlibrary.js your application uses\nmodule.exports = moduleWrapper(absRequire(`typescript/lib/tsserverlibrary.js`));\n"
  },
  {
    "path": ".yarn/sdks/typescript/lib/typescript.js",
    "content": "#!/usr/bin/env node\n\nconst {existsSync} = require(`fs`);\nconst {createRequire} = require(`module`);\nconst {resolve} = require(`path`);\n\nconst relPnpApiPath = \"../../../../.pnp.cjs\";\n\nconst absPnpApiPath = resolve(__dirname, relPnpApiPath);\nconst absRequire = createRequire(absPnpApiPath);\n\nif (existsSync(absPnpApiPath)) {\n  if (!process.versions.pnp) {\n    // Setup the environment to be able to require typescript\n    require(absPnpApiPath).setup();\n  }\n}\n\n// Defer to the real typescript your application uses\nmodule.exports = absRequire(`typescript`);\n"
  },
  {
    "path": ".yarn/sdks/typescript/package.json",
    "content": "{\n  \"name\": \"typescript\",\n  \"version\": \"5.2.2-sdk\",\n  \"main\": \"./lib/typescript.js\",\n  \"type\": \"commonjs\",\n  \"bin\": {\n    \"tsc\": \"./bin/tsc\",\n    \"tsserver\": \"./bin/tsserver\"\n  }\n}\n"
  },
  {
    "path": ".yarnrc.yml",
    "content": "compressionLevel: mixed\n\nenableGlobalCache: false\n\nyarnPath: .yarn/releases/yarn-4.0.1.cjs\n"
  },
  {
    "path": "@planetarium/.editorconfig",
    "content": "[*]\nend_of_line = lf\ninsert_final_newline = true\nindent_style = space\nindent_size = 2\nmax_line_length = 80\n"
  },
  {
    "path": "@planetarium/.gitignore",
    "content": "package.tgz\n*.tsbuildinfo\n"
  },
  {
    "path": "@planetarium/account/.gitignore",
    "content": "coverage/\ndist/\n"
  },
  {
    "path": "@planetarium/account/README.md",
    "content": "@planetarium/account\n====================\n\n[![npm][npm-badge]][npm] ![Node.js version][]\n\nThis npm package provides abstractions for managing [Libplanet] signing\nkeys (`Account`), `PublicKey`s, and `Address`es derived from them.\nIt also contains an in-memory `RawPrivateKey` class which implements `Account`.\n\n[npm]: https://www.npmjs.com/package/@planetarium/account\n[npm-badge]: https://img.shields.io/npm/v/@planetarium/account\n[Node.js version]: https://img.shields.io/node/v-lts/@planetarium/account\n[Libplanet]: https://libplanet.io/\n"
  },
  {
    "path": "@planetarium/account/global.d.ts",
    "content": "declare module globalThis {\n  var crypto:\n    | undefined\n    | {\n        subtle: {\n          digest: (\n            algorithm: string,\n            data: ArrayBuffer | TypedArray | DataView\n          ) => Promise<ArrayBuffer>;\n        };\n      };\n  var TextEncoder:\n    | undefined\n    | (new () => { encode: (input: string) => Uint8Array });\n}\n"
  },
  {
    "path": "@planetarium/account/package.json",
    "content": "{\n  \"name\": \"@planetarium/account\",\n  \"private\": true,\n  \"description\": \"Libplanet accounts for JavaScript/TypeScript\",\n  \"type\": \"module\",\n  \"main\": \"./dist/index.js\",\n  \"exports\": {\n    \".\": {\n      \"types\": \"./dist/index.d.ts\",\n      \"import\": \"./dist/index.js\",\n      \"require\": \"./dist/index.cjs\"\n    }\n  },\n  \"types\": \"./dist/index.d.ts\",\n  \"files\": [\n    \"dist/**/*\"\n  ],\n  \"scripts\": {\n    \"build\": \"yarn && nanobundle build\",\n    \"prepack\": \"yarn && yarn build\",\n    \"dev\": \"yarn && vitest\",\n    \"test\": \"yarn && yarn run -T tsc -p tsconfig.json && vitest run\",\n    \"coverage\": \"yarn && vitest run --coverage\"\n  },\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"git+https://github.com/planetarium/libplanet.git\",\n    \"directory\": \"@planetarium/account\"\n  },\n  \"keywords\": [\n    \"libplanet\"\n  ],\n  \"author\": \"Planetarium (https://planetarium.dev/)\",\n  \"license\": \"LGPL-2.1-or-later\",\n  \"bugs\": {\n    \"url\": \"https://github.com/planetarium/libplanet/labels/js\"\n  },\n  \"homepage\": \"https://github.com/planetarium/libplanet/tree/main/@planetarium/account\",\n  \"devDependencies\": {\n    \"@types/node\": \"^18.13.0\",\n    \"@vitest/coverage-c8\": \"^0.29.2\",\n    \"@vitest/ui\": \"^0.29.2\",\n    \"fast-check\": \"^3.1.2\",\n    \"nanobundle\": \"^1.6.0\",\n    \"vite\": \"^4.1.1\",\n    \"vitest\": \"^0.29.2\"\n  },\n  \"dependencies\": {\n    \"@noble/hashes\": \"^1.2.0\",\n    \"@noble/secp256k1\": \"^1.7.1\",\n    \"buffer\": \"^6.0.3\"\n  }\n}\n"
  },
  {
    "path": "@planetarium/account/src/Account.ts",
    "content": "import { type Message } from \"./Message.js\";\nimport Address from \"./Address.js\";\nimport PublicKey from \"./PublicKey.js\";\nimport RawPrivateKey from \"./RawPrivateKey.js\";\nimport Signature from \"./Signature.js\";\n\nexport interface Account {\n  getAddress(): Promise<Address>;\n  getPublicKey(): Promise<PublicKey>;\n  sign(message: Message): Promise<Signature>;\n}\n\nexport function isAccount(account: unknown): account is Account {\n  return (\n    typeof account === \"object\" &&\n    account != null &&\n    \"getAddress\" in account &&\n    account.getAddress instanceof Function &&\n    \"getPublicKey\" in account &&\n    account.getPublicKey instanceof Function &&\n    \"sign\" in account &&\n    account.sign instanceof Function\n  );\n}\n\nexport interface ExportableAccount extends Account {\n  exportPrivateKey(): Promise<RawPrivateKey>;\n}\n\nexport default Account;\n"
  },
  {
    "path": "@planetarium/account/src/Address.ts",
    "content": "import { Buffer } from \"buffer\";\nimport { keccak_256 } from \"@noble/hashes/sha3\";\nimport { Account, isAccount } from \"./Account.js\";\nimport { PublicKey } from \"./PublicKey.js\";\n\nif (typeof globalThis.TextEncoder === \"undefined\") {\n  // FIXME: This is a workaround for the lack of TextEncoder in Vitest.\n  globalThis.TextEncoder = require(\"node:util\").TextEncoder;\n}\n\nfunction toHex(bytes: Uint8Array): string {\n  let hex = \"\";\n  for (let i = 0; i < bytes.length; i++) {\n    hex += bytes[i].toString(16).padStart(2, \"0\");\n  }\n  return hex;\n}\n\nfunction checksum(hex: string): string {\n  hex = hex.toLowerCase();\n\n  const hexAsciiIntoBytes = new TextEncoder!().encode(hex);\n  const hashedAddr = toHex(keccak_256(hexAsciiIntoBytes));\n  let checksum = \"\";\n  for (let nibbleIdx = 0; nibbleIdx < hex.length; nibbleIdx++) {\n    const nibbleHex = hex.charAt(nibbleIdx);\n    if (nibbleHex.match(/^[0-9]$/)) {\n      checksum += nibbleHex;\n      continue;\n    } else {\n      const nibble = parseInt(hashedAddr.charAt(nibbleIdx), 16);\n      checksum += nibble > 7 ? nibbleHex.toUpperCase() : nibbleHex;\n    }\n  }\n\n  return checksum;\n}\n\nexport class Address {\n  #bytes: Uint8Array;\n\n  private constructor(bytes: Uint8Array) {\n    this.#bytes = bytes;\n  }\n\n  static deriveFrom(publicKey: PublicKey): Address;\n  static deriveFrom(account: Account): Promise<Address>;\n\n  static deriveFrom(\n    publicKey: PublicKey | Account\n  ): Address | Promise<Address> {\n    if (isAccount(publicKey)) {\n      return publicKey.getPublicKey().then(this.#deriveFrom);\n    } else if (publicKey instanceof PublicKey) {\n      return this.#deriveFrom(publicKey);\n    }\n\n    throw new Error(\n      `Expected either PublicKey or Account, got ${typeof publicKey}`\n    );\n  }\n\n  static #deriveFrom(publicKey: PublicKey): Address {\n    const pub = publicKey.toBytes(\"uncompressed\").slice(1);\n    const digest = keccak_256(pub);\n    const addr = digest.slice(digest.length - 20);\n    return new Address(addr);\n  }\n\n  static fromHex(hex: string, ignoreChecksum: boolean = false): Address {\n    if (typeof hex !== \"string\") {\n      throw new Error(`Expected a string, but ${typeof hex} was given.`);\n    } else if (!hex.match(/^(0x)?[0-9a-f]{40}$/i)) {\n      throw new Error(\n        `Expected a string of 40 hexadecimals, but ${JSON.stringify(\n          hex\n        )} was given.`\n      );\n    }\n\n    if (hex.match(/^0x/i)) {\n      hex = hex.slice(2);\n    }\n\n    const addr = new Address(new Uint8Array(Buffer.from(hex, \"hex\")));\n    if (ignoreChecksum) {\n      return addr;\n    }\n\n    const expectedChecksum = checksum(hex);\n    if (expectedChecksum !== hex) {\n      throw new Error(\n        `Expected checksum is 0x${expectedChecksum}, but 0x${hex} was given.`\n      );\n    }\n\n    return addr;\n  }\n\n  static fromBytes(bytes: Uint8Array) {\n    if (!(bytes instanceof Uint8Array)) {\n      throw new Error(`Expected a Uint8Array, but ${typeof bytes} was given.`);\n    }\n\n    if (bytes.length !== 20) {\n      throw new Error(\n        `Expected 20 bytes, but ${bytes.length} bytes were given.`\n      );\n    }\n\n    return new Address(bytes);\n  }\n\n  toBytes(): Uint8Array {\n    return this.#bytes;\n  }\n\n  toHex(casing: \"checksum\" | \"lower\" = \"checksum\"): string {\n    const hex = toHex(this.#bytes);\n    return casing === \"checksum\" ? checksum(hex) : hex;\n  }\n\n  equals(other: Address): boolean {\n    if (!(other instanceof Address)) return false;\n    for (let i = 0; i < 20; i++) {\n      if (this.#bytes[i] !== other.#bytes[i]) return false;\n    }\n\n    return true;\n  }\n\n  isAddressOf(publicKey: PublicKey): boolean {\n    return Address.deriveFrom(publicKey).equals(this);\n  }\n\n  toString(): string {\n    return `0x${this.toHex()}`;\n  }\n}\n\nexport default Address;\n"
  },
  {
    "path": "@planetarium/account/src/KeyStore.ts",
    "content": "import { type Account } from \"./Account.js\";\nimport { RawPrivateKey } from \"./RawPrivateKey.js\";\n\nexport interface AccountMetadata<KeyId, Metadata = undefined> {\n  readonly keyId: Readonly<KeyId>;\n  readonly metadata: Readonly<Metadata>;\n  readonly createdAt?: Readonly<Date>;\n}\n\nexport type AccountRetrieval<\n  KeyId,\n  AccountType extends Account,\n  Metadata = undefined,\n> =\n  | ({\n      readonly result: \"success\";\n      readonly account: AccountType;\n    } & AccountMetadata<KeyId, Metadata>)\n  | { readonly keyId: Readonly<KeyId>; readonly result: \"keyNotFound\" }\n  | {\n      readonly keyId: Readonly<KeyId>;\n      readonly result: \"error\";\n      readonly message?: string;\n    };\n\nexport interface KeyStore<\n  KeyId,\n  AccountType extends Account,\n  Metadata = undefined,\n> {\n  list(): AsyncIterable<AccountMetadata<KeyId, Metadata>>;\n  get(\n    keyId: Readonly<KeyId>,\n  ): Promise<AccountRetrieval<KeyId, AccountType, Metadata>>;\n}\n\nexport type AccountGeneration<KeyId, AccountType extends Account> =\n  | {\n      readonly result: \"success\";\n      readonly keyId: Readonly<KeyId>;\n      readonly account: AccountType;\n    }\n  | { readonly result: \"error\"; readonly message?: string };\n\nexport type AccountDeletion<KeyId> =\n  | { readonly result: \"success\"; readonly keyId: Readonly<KeyId> }\n  | { readonly result: \"keyNotFound\"; readonly keyId: Readonly<KeyId> }\n  | { readonly result: \"error\"; readonly message?: string };\n\nexport interface MutableKeyStore<\n  KeyId,\n  AccountType extends Account,\n  Metadata = undefined,\n> extends KeyStore<KeyId, AccountType, Metadata> {\n  generate(\n    metadata?: Partial<Metadata>,\n  ): Promise<AccountGeneration<KeyId, AccountType>>;\n  delete(keyId: Readonly<KeyId>): Promise<AccountDeletion<KeyId>>;\n}\n\nexport type AccountImportation<KeyId> =\n  | { readonly result: \"success\"; readonly keyId: KeyId }\n  | { readonly result: \"error\"; readonly message?: string };\n\nexport interface ImportableKeyStore<\n  KeyId,\n  AccountType extends Account,\n  Metadata = undefined,\n> extends MutableKeyStore<KeyId, AccountType, Metadata> {\n  import(\n    privateKey: RawPrivateKey,\n    metadata?: Partial<Metadata>,\n  ): Promise<AccountImportation<KeyId>>;\n}\n"
  },
  {
    "path": "@planetarium/account/src/Message.ts",
    "content": "import { sha256 } from \"@noble/hashes/sha256\";\n\nexport type Message = Uint8Array;\n\nexport async function hashMessage(message: Message): Promise<Uint8Array> {\n  // TODO: Use Web Crypto API when it is available.\n  // return new Uint8Array(await crypto!.subtle.digest(\"SHA-256\", message));\n  return sha256(message);\n}\n\nexport default Message;\n"
  },
  {
    "path": "@planetarium/account/src/PublicKey.ts",
    "content": "import { Buffer } from \"buffer\";\nimport * as secp256k1 from \"@noble/secp256k1\";\nimport { Message, hashMessage } from \"./Message.js\";\nimport Signature from \"./Signature.js\";\n\nexport type PublicKeyForm = \"compressed\" | \"uncompressed\";\n\nexport class PublicKey {\n  readonly #point: secp256k1.Point;\n\n  private constructor(point: secp256k1.Point) {\n    this.#point = point;\n  }\n\n  static fromBytes(bytes: Uint8Array, form: PublicKeyForm): PublicKey {\n    if (!(bytes instanceof Uint8Array)) {\n      throw new Error(`Expected a Uint8Array, but got ${typeof bytes}`);\n    }\n    const header = bytes[0];\n    if (form === \"compressed\") {\n      if (bytes.length !== 33) {\n        throw new Error(\n          `Invalid compressed public key: expected 33 bytes, but got ${bytes.length} bytes`\n        );\n      } else if (header !== 0x02 && header !== 0x03) {\n        throw new Error(\n          `Invalid compressed public key: expected either 0x02 or 0x03 as the header, but got 0x${header\n            .toString(16)\n            .padStart(2, \"0\")}`\n        );\n      }\n    } else if (form === \"uncompressed\") {\n      if (bytes.length !== 65) {\n        throw new Error(\n          `Invalid uncompressed public key expected 65 bytes, but got ${bytes.length} bytes`\n        );\n      } else if (header !== 0x04) {\n        throw new Error(\n          `Invalid compressed public key: expected 0x04 as the header, but got 0x${header\n            .toString(16)\n            .padStart(2, \"0\")}`\n        );\n      }\n    } else {\n      throw new Error(\n        \"Invalid public key form: choose 'compressed' or 'uncompressed'\"\n      );\n    }\n    return new PublicKey(secp256k1.Point.fromHex(bytes));\n  }\n\n  // TODO: more explicit length checking\n  static fromHex(hex: string, form: PublicKeyForm): PublicKey {\n    if (typeof hex !== \"string\") {\n      throw new Error(`Expected a string, but got ${typeof hex}`);\n    } else if (form === \"compressed\" && hex.length !== 66) {\n      throw new Error(\n        `Invalid compressed public key: expected 33 hexadigits, but got ${hex.length} hexadigits`\n      );\n    } else if (form === \"uncompressed\" && hex.length !== 130) {\n      throw new Error(\n        `Invalid uncompressed public key expected 130 hexadigits, but got ${hex.length} hexadigits`\n      );\n    }\n    const bytes = new Uint8Array(Buffer.from(hex, \"hex\"));\n    return this.fromBytes(bytes, form);\n  }\n\n  async verify(message: Message, signature: Signature): Promise<boolean> {\n    if (!(message instanceof Uint8Array)) {\n      throw new Error(`Expected Uint8Array, but got ${typeof message}`);\n    } else if (!(signature instanceof Signature)) {\n      throw new Error(`Expected Signature, but got ${typeof signature}`);\n    }\n    const msgHash = await hashMessage(message);\n    return secp256k1.verify(signature.toBytes(), msgHash, this.#point);\n  }\n\n  toBytes(form: PublicKeyForm): Uint8Array {\n    if (form !== \"compressed\" && form !== \"uncompressed\") {\n      throw new Error(\n        \"Invalid public key form: choose 'compressed' or 'uncompressed'\"\n      );\n    }\n    return this.#point.toRawBytes(form === \"compressed\");\n  }\n\n  toHex(form: PublicKeyForm): string {\n    if (form !== \"compressed\" && form !== \"uncompressed\") {\n      throw new Error(\n        \"Invalid public key form: choose 'compressed' or 'uncompressed'\"\n      );\n    }\n    return this.#point.toHex(form === \"compressed\");\n  }\n\n  equals(other: PublicKey): boolean {\n    return other instanceof PublicKey && this.#point.equals(other.#point);\n  }\n}\n\nexport default PublicKey;\n"
  },
  {
    "path": "@planetarium/account/src/RawPrivateKey.ts",
    "content": "import { Buffer } from \"buffer\";\nimport * as secp256k1 from \"@noble/secp256k1\";\nimport Address from \"./Address.js\";\nimport { Message, hashMessage } from \"./Message.js\";\nimport PublicKey from \"./PublicKey.js\";\nimport Signature from \"./Signature.js\";\n\nexport class RawPrivateKey {\n  readonly #privatePart: Uint8Array;\n  #publicPart?: PublicKey;\n\n  private constructor(privatePart: Uint8Array) {\n    this.#privatePart = privatePart;\n  }\n\n  static fromBytes(bytes: Uint8Array): RawPrivateKey {\n    if (!(bytes instanceof Uint8Array)) {\n      throw new Error(`Expected Uint8Array, but got ${typeof bytes}`);\n    } else if (bytes.length !== 32) {\n      throw new Error(\n        `Incorrect private key length; expected 32 bytes, but got ${bytes.length} bytes`\n      );\n    } else if (!secp256k1.utils.isValidPrivateKey(bytes)) {\n      throw new Error(\"Invalid private key\");\n    }\n\n    // NOTE: The bytes should be copied because the original array can be\n    // mutated after the key is created.\n    return new RawPrivateKey(new Uint8Array(bytes));\n  }\n\n  static fromHex(hex: string): RawPrivateKey {\n    if (typeof hex !== \"string\") {\n      throw new Error(`Expected string, but got ${typeof hex}`);\n    } else if (hex.length !== 64) {\n      throw new Error(\n        `Incorrect private key length; expected 64 hexadigits, but got ${hex.length} hexadigits`\n      );\n    }\n    const bytes = new Uint8Array(Buffer.from(hex, \"hex\"));\n    if (!secp256k1.utils.isValidPrivateKey(bytes)) {\n      throw new Error(\"Invalid private key\");\n    }\n\n    return new RawPrivateKey(bytes);\n  }\n\n  static generate(): RawPrivateKey {\n    return this.fromBytes(secp256k1.utils.randomPrivateKey());\n  }\n\n  getAddress(): Promise<Address> {\n    return Promise.resolve(Address.deriveFrom(this.publicKey));\n  }\n\n  /**\n   * @deprecated Use {@link getPublicKey()} instead.\n   */\n  get publicKey(): PublicKey {\n    // TODO: This attribute is deprecated.  We should remove it and make\n    // getPublicKey() method the only choice in the future.\n    if (typeof this.#publicPart === \"undefined\") {\n      this.#publicPart = PublicKey.fromBytes(\n        secp256k1.getPublicKey(this.#privatePart),\n        \"uncompressed\"\n      );\n    }\n\n    return this.#publicPart;\n  }\n\n  getPublicKey(): Promise<PublicKey> {\n    return Promise.resolve(this.publicKey);\n  }\n\n  async sign(message: Message): Promise<Signature> {\n    const sig = await secp256k1.sign(\n      await hashMessage(message),\n      this.#privatePart,\n      { der: true }\n    );\n    return Signature.fromBytes(sig);\n  }\n\n  exportPrivateKey(): Promise<RawPrivateKey> {\n    return Promise.resolve(this);\n  }\n\n  toBytes(): Uint8Array {\n    // NOTE: The #privatePart should be copied because the returned reference\n    // can be mutated after this method is called.\n    return new Uint8Array(this.#privatePart);\n  }\n}\n\nexport default RawPrivateKey;\n"
  },
  {
    "path": "@planetarium/account/src/Signature.ts",
    "content": "import * as secp256k1 from \"@noble/secp256k1\";\n\nexport class Signature {\n  readonly #signature: secp256k1.Signature;\n\n  private constructor(signature: secp256k1.Signature) {\n    if (signature.hasHighS())\n      throw new RangeError(\n        \"A signature with high S is unsupported; \" +\n          \"normalize it to get rid of high S\",\n      );\n    this.#signature = signature;\n  }\n\n  static fromBytes(bytes: Uint8Array): Signature {\n    // NOTE: We decided to distinguish fromBytes from fromHex, although they\n    // call the same function in @noble/secp256k1 which takes both a hex string\n    // and a Uint8Array.\n    return new Signature(secp256k1.Signature.fromDER(bytes));\n  }\n\n  static fromHex(hex: string): Signature {\n    // NOTE: We decided to distinguish fromBytes from fromHex, although they\n    // call the same function in @noble/secp256k1 which takes both a hex string\n    // and a Uint8Array.\n    return new Signature(secp256k1.Signature.fromDER(hex));\n  }\n\n  toBytes(): Uint8Array {\n    return this.#signature.toDERRawBytes();\n  }\n\n  toHex(): string {\n    return this.#signature.toDERHex();\n  }\n\n  toString(): string {\n    return this.toHex();\n  }\n\n  [Symbol.for(\"nodejs.util.inspect.custom\")]() {\n    return `Signature { ${this.toHex()} }`;\n  }\n}\n\nexport default Signature;\n"
  },
  {
    "path": "@planetarium/account/src/index.ts",
    "content": "export { type Account, type ExportableAccount } from \"./Account.js\";\nexport { Address } from \"./Address.js\";\nexport {\n  type AccountDeletion,\n  type AccountGeneration,\n  type AccountImportation,\n  type AccountMetadata,\n  type AccountRetrieval,\n  type ImportableKeyStore,\n  type KeyStore,\n  type MutableKeyStore,\n} from \"./KeyStore.js\";\nexport { type Message } from \"./Message.js\";\nexport { PublicKey, type PublicKeyForm } from \"./PublicKey.js\";\nexport { RawPrivateKey } from \"./RawPrivateKey.js\";\nexport { Signature } from \"./Signature.js\";\n"
  },
  {
    "path": "@planetarium/account/test/Account.test.ts",
    "content": "import { expect, test } from \"vitest\";\nimport { isAccount } from \"../src/Account\";\nimport { RawPrivateKey } from \"../src/RawPrivateKey\";\n\ntest(\"isAccount\", async () => {\n  expect(isAccount(RawPrivateKey.generate())).toBeTruthy();\n  const key = RawPrivateKey.generate();\n  const validAccount = {\n    getAddress: key.getAddress,\n    getPublicKey: key.getPublicKey,\n    sign: key.sign.bind(key),\n  };\n  expect(isAccount(validAccount)).toBeTruthy();\n  for (const key of Object.keys(validAccount)) {\n    const invalidAccount = { ...validAccount, [key]: 1 };\n    expect(isAccount(invalidAccount)).toBeFalsy();\n    // rome-ignore lint/performance/noDelete: delete is needed\n    delete invalidAccount[key];\n    expect(isAccount(invalidAccount)).toBeFalsy();\n  }\n});\n"
  },
  {
    "path": "@planetarium/account/test/Address.test.ts",
    "content": "import { Address } from \"../src/Address\";\nimport { PublicKey } from \"../src/PublicKey\";\nimport { RawPrivateKey } from \"../src/RawPrivateKey\";\nimport * as fc from \"fast-check\";\nimport { describe, expect, test } from \"vitest\";\nimport { bytesEquals, toHex } from \"./utils\";\n\ndescribe(\"Address\", () => {\n  test(\"deriveFrom()\", async () => {\n    const pubKey = PublicKey.fromBytes(\n      new Uint8Array([\n        0x03, 0x43, 0x8b, 0x93, 0x53, 0x89, 0xa7, 0xeb, 0xf8, 0x38, 0xb3, 0xae,\n        0x41, 0x25, 0xbd, 0x28, 0x50, 0x6a, 0xa2, 0xdd, 0x45, 0x7f, 0x20, 0xaf,\n        0xc8, 0x43, 0x72, 0x9d, 0x3e, 0x7d, 0x60, 0xd7, 0x28,\n      ]),\n      \"compressed\",\n    );\n    const expectedAddress = Address.fromBytes(\n      new Uint8Array([\n        0xd4, 0x1f, 0xad, 0xf6, 0x1b, 0xad, 0xf5, 0xbe, 0x2d, 0xe6, 0x0e, 0x9f,\n        0xc3, 0x23, 0x0c, 0x0a, 0x8a, 0x43, 0x90, 0xf0,\n      ]),\n    );\n    expect(Address.deriveFrom(pubKey)).toHaveEqualBytes(expectedAddress);\n    const account = RawPrivateKey.generate();\n    expect(await Address.deriveFrom(account)).toHaveEqualBytes(\n      Address.deriveFrom(account.publicKey),\n    );\n    expect(() => Address.deriveFrom(123 as unknown as PublicKey)).toThrowError(\n      /got number/i,\n    );\n  });\n\n  test(\"fromHex() with ignoreChecksum: true\", () => {\n    fc.assert(\n      fc.property(\n        fc.constantFrom(\"\", \"0x\", \"0X\"),\n        fc.uint8Array({ minLength: 20, maxLength: 20 }),\n        (prefix, addressBytes: Uint8Array) => {\n          const hex = prefix + toHex(addressBytes);\n          return (\n            bytesEquals(Address.fromHex(hex, true).toBytes(), addressBytes) &&\n            bytesEquals(\n              Address.fromHex(hex.toUpperCase(), true).toBytes(),\n              addressBytes,\n            )\n          );\n        },\n      ),\n    );\n    expect(() => Address.fromHex(123 as unknown as string)).toThrowError(\n      /number was given/i,\n    );\n    fc.assert(\n      fc.property(\n        fc.constantFrom(\"\", \"0x\", \"0X\"),\n        fc.oneof(\n          fc.uint8Array({ maxLength: 19 }),\n          fc.uint8Array({ minLength: 21 }),\n        ),\n        (prefix: string, addressBytes: Uint8Array) => {\n          const hex = prefix + toHex(addressBytes);\n          try {\n            Address.fromHex(hex, true);\n          } catch (e) {\n            return e.toString().includes(\"40 hexa\");\n          }\n          return false;\n        },\n      ),\n    );\n  });\n\n  test(\"fromBytes()\", () => {\n    fc.assert(\n      fc.property(\n        fc.uint8Array({ minLength: 20, maxLength: 20 }),\n        (addressBytes: Uint8Array) => {\n          return bytesEquals(\n            Address.fromBytes(addressBytes).toBytes(),\n            addressBytes,\n          );\n        },\n      ),\n    );\n    expect(() => Address.fromBytes(123 as unknown as Uint8Array)).toThrowError(\n      /number was given/i,\n    );\n    fc.assert(\n      fc.property(\n        fc.oneof(\n          fc.uint8Array({ maxLength: 19 }),\n          fc.uint8Array({ minLength: 21 }),\n        ),\n        (addressBytes: Uint8Array) => {\n          try {\n            Address.fromBytes(addressBytes);\n          } catch (e) {\n            return e.toString().includes(`${addressBytes.length} bytes`);\n          }\n          return false;\n        },\n      ),\n    );\n  });\n\n  test(\"fromHex() with ignoreChecksum: false\", () => {\n    let expected = Address.fromBytes(\n      new Uint8Array([\n        0x5a, 0xae, 0xb6, 0x5, 0x3f, 0x3e, 0x94, 0xc9, 0xb9, 0xa0, 0x9f, 0x33,\n        0x66, 0x94, 0x35, 0xe7, 0xef, 0x1b, 0xea, 0xed,\n      ]),\n    );\n    expect(\n      Address.fromHex(\"5aAeb6053F3E94C9b9A09f33669435E7Ef1BeAed\", false),\n    ).toHaveEqualBytes(expected);\n\n    expected = Address.fromBytes(\n      new Uint8Array([\n        0xfb, 0x69, 0x16, 0x9, 0x5c, 0xa1, 0xdf, 0x60, 0xbb, 0x79, 0xce, 0x92,\n        0xce, 0x3e, 0xa7, 0x4c, 0x37, 0xc5, 0xd3, 0x59,\n      ]),\n    );\n    expect(\n      Address.fromHex(\"0xfB6916095ca1df60bB79Ce92cE3Ea74c37c5d359\", false),\n    ).toHaveEqualBytes(expected);\n\n    expected = Address.fromBytes(\n      new Uint8Array([\n        0xdb, 0xf0, 0x3b, 0x40, 0x7c, 0x01, 0xe7, 0xcd, 0x3c, 0xbe, 0xa9, 0x95,\n        0x09, 0xd9, 0x3f, 0x8d, 0xdd, 0xc8, 0xc6, 0xfb,\n      ]),\n    );\n    expect(\n      Address.fromHex(\"0XdbF03B407c01E7cD3CBea99509d93f8DDDC8C6FB\"),\n    ).toHaveEqualBytes(expected);\n\n    expect(() =>\n      Address.fromHex(\"D1220A0cf47c7B9Be7A2E6BA89F429762e7b9aDB\"),\n    ).toThrowError(/checksum/i);\n  });\n\n  test(\"toBytes()\", () => {\n    fc.assert(\n      fc.property(\n        fc.uint8Array({ minLength: 20, maxLength: 20 }),\n        (addressBytes: Uint8Array) => {\n          return bytesEquals(\n            Address.fromHex(toHex(addressBytes), true).toBytes(),\n            addressBytes,\n          );\n        },\n      ),\n    );\n  });\n\n  test(\"toHex('checksum')\", () => {\n    const address = Address.fromBytes(\n      new Uint8Array([\n        0xdb, 0xf0, 0x3b, 0x40, 0x7c, 0x01, 0xe7, 0xcd, 0x3c, 0xbe, 0xa9, 0x95,\n        0x09, 0xd9, 0x3f, 0x8d, 0xdd, 0xc8, 0xc6, 0xfb,\n      ]),\n    );\n    expect(address.toHex(\"checksum\")).toBe(\n      \"dbF03B407c01E7cD3CBea99509d93f8DDDC8C6FB\",\n    );\n  });\n\n  test(\"toHex('lower')\", () => {\n    const address = Address.fromBytes(\n      new Uint8Array([\n        0xdb, 0xf0, 0x3b, 0x40, 0x7c, 0x01, 0xe7, 0xcd, 0x3c, 0xbe, 0xa9, 0x95,\n        0x09, 0xd9, 0x3f, 0x8d, 0xdd, 0xc8, 0xc6, 0xfb,\n      ]),\n    );\n    expect(address.toHex(\"lower\")).toBe(\n      \"dbf03b407c01e7cd3cbea99509d93f8dddc8c6fb\",\n    );\n  });\n\n  test(\"equals()\", () => {\n    const address = Address.fromBytes(\n      new Uint8Array([\n        0xdb, 0xf0, 0x3b, 0x40, 0x7c, 0x01, 0xe7, 0xcd, 0x3c, 0xbe, 0xa9, 0x95,\n        0x09, 0xd9, 0x3f, 0x8d, 0xdd, 0xc8, 0xc6, 0xfb,\n      ]),\n    );\n    const address2 = Address.fromBytes(\n      new Uint8Array([\n        0xdb, 0xf0, 0x3b, 0x40, 0x7c, 0x01, 0xe7, 0xcd, 0x3c, 0xbe, 0xa9, 0x95,\n        0x09, 0xd9, 0x3f, 0x8d, 0xdd, 0xc8, 0xc6, 0xfb,\n      ]),\n    );\n    const address3 = Address.fromBytes(\n      new Uint8Array([\n        0xdb, 0xf0, 0x3b, 0x40, 0x7c, 0x01, 0xe7, 0xcd, 0x3c, 0xbe, 0xa9, 0x95,\n        0x09, 0xd9, 0x3f, 0x8d, 0xdd, 0xc8, 0xc6, 0xfc,\n      ]),\n    );\n    expect(address.equals(address2)).toBe(true);\n    expect(address2.equals(address)).toBe(true);\n    expect(address.equals(address3)).toBe(false);\n    expect(address2.equals(address3)).toBe(false);\n    expect(address3.equals(address)).toBe(false);\n  });\n\n  test(\"isAddressOf()\", () => {\n    const address = Address.fromHex(\"D9166B6361a077CAe2eCdEF0bb96AEe4542e231a\");\n    const pubKey = PublicKey.fromHex(\n      \"02b4cc2941408698d07f059db306bd8e207c29b14a3540bb19891b102666a963db\",\n      \"compressed\",\n    );\n    expect(address.isAddressOf(pubKey)).toBe(true);\n\n    const address2 = Address.fromBytes(\n      new Uint8Array([\n        0xdb, 0xf0, 0x3b, 0x40, 0x7c, 0x01, 0xe7, 0xcd, 0x3c, 0xbe, 0xa9, 0x95,\n        0x09, 0xd9, 0x3f, 0x8d, 0xdd, 0xc8, 0xc6, 0xfb,\n      ]),\n    );\n    expect(address2.isAddressOf(pubKey)).toBe(false);\n  });\n\n  test(\"toString()\", () => {\n    const address = Address.fromBytes(\n      new Uint8Array([\n        0xdb, 0xf0, 0x3b, 0x40, 0x7c, 0x01, 0xe7, 0xcd, 0x3c, 0xbe, 0xa9, 0x95,\n        0x09, 0xd9, 0x3f, 0x8d, 0xdd, 0xc8, 0xc6, 0xfb,\n      ]),\n    );\n    expect(address.toString()).toBe(\n      \"0xdbF03B407c01E7cD3CBea99509d93f8DDDC8C6FB\",\n    );\n  });\n});\n"
  },
  {
    "path": "@planetarium/account/test/Message.test.ts",
    "content": "import { hashMessage } from \"../src/Message\";\nimport { expect, test } from \"vitest\";\n\ntest(\"hashMessage()\", async () => {\n  const foo = new Uint8Array([0x66, 0x6f, 0x6f]);\n  expect(await hashMessage(foo)).toStrictEqual(\n    new Uint8Array(\n      Buffer.from(\n        \"2c26b46b68ffc68ff99b453c1d30413413422d706483bfa0f98a5e886266e7ae\",\n        \"hex\"\n      )\n    )\n  );\n\n  const bar = new Uint8Array([0x62, 0x61, 0x72]);\n  expect(await hashMessage(bar)).toStrictEqual(\n    new Uint8Array(\n      Buffer.from(\n        \"fcde2b2edba56bf408601fb721fe9b5c338d10ee429ea04fae5511b68fbf8fb9\",\n        \"hex\"\n      )\n    )\n  );\n});\n"
  },
  {
    "path": "@planetarium/account/test/PublicKey.test.ts",
    "content": "import { Message } from \"../src/Message\";\nimport { PublicKey } from \"../src/PublicKey\";\nimport { Signature } from \"../src/Signature\";\nimport { describe, expect, test } from \"vitest\";\n\ndescribe(\"PublicKey\", () => {\n  const compHex =\n    \"02472a659c7e655cbcf688997863fb9c7a7139635929429bdc9f75f10c60ed8070\";\n  const uncompHex =\n    \"04472a659c7e655cbcf688997863fb9c7a7139635929429bdc9f75f10c60ed807\" +\n    \"0302b403f1fb65851e90ccc75838b0346d052d5431e8baa64ec677d62be463170\";\n  test(\"fromBytes()\", () => {\n    // TODO: Test with a compressed pubkey with 0x03 header\n    const compBytes = Buffer.from(compHex, \"hex\");\n\n    // TypedArray() constructor refers to the memory if it takes an\n    // ArrayBuffer/Buffer, but it copies the memory if it takes a view\n    // (e.g. Uint8Array).  The below code calls the constructor twice by\n    // intention (to copy the data):\n    const inputCompBytes = new Uint8Array(new Uint8Array(compBytes));\n    const pubKey = PublicKey.fromBytes(inputCompBytes, \"compressed\");\n\n    expect(pubKey.toHex(\"compressed\")).toBe(compHex);\n    expect(pubKey.toHex(\"uncompressed\")).toBe(uncompHex);\n\n    // The inputCompBytes should not affect the RawPrivateKey instance which\n    // was created from it:\n    inputCompBytes.fill(0, 0, inputCompBytes.length);\n    expect(pubKey.toHex(\"compressed\")).toBe(compHex);\n\n    const pubKey2 = PublicKey.fromBytes(\n      pubKey.toBytes(\"uncompressed\"),\n      \"uncompressed\",\n    );\n    expect(pubKey2.toHex(\"compressed\")).toBe(compHex);\n\n    const invalidType = [] as unknown as Uint8Array;\n    expect(() => PublicKey.fromBytes(invalidType, \"compressed\")).toThrowError(\n      /got object/i,\n    );\n\n    const invalidCompLength = new Uint8Array(32);\n    expect(() =>\n      PublicKey.fromBytes(invalidCompLength, \"compressed\"),\n    ).toThrowError(/got 32 bytes/i);\n\n    const invalidCompHeader = new Uint8Array(33);\n    invalidCompHeader[0] = 0x04;\n    expect(() =>\n      PublicKey.fromBytes(invalidCompHeader, \"compressed\"),\n    ).toThrowError(/got 0x04/i);\n\n    const invalidUncompLength = new Uint8Array(64);\n    expect(() =>\n      PublicKey.fromBytes(invalidUncompLength, \"uncompressed\"),\n    ).toThrowError(/got 64 bytes/i);\n\n    const invalidUncompHeader = new Uint8Array(65);\n    invalidUncompHeader[0] = 0x02;\n    expect(() =>\n      PublicKey.fromBytes(invalidUncompHeader, \"uncompressed\"),\n    ).toThrowError(/got 0x02/i);\n\n    expect(() =>\n      PublicKey.fromBytes(\n        new Uint8Array(0),\n        \"invalid\" as unknown as \"compressed\" | \"uncompressed\",\n      ),\n    ).toThrowError(/invalid.*? form/i);\n  });\n\n  test(\"fromHex()\", () => {\n    // TODO: Test with a compressed pubkey with 0x03 header\n    const pubKey = PublicKey.fromHex(compHex, \"compressed\");\n\n    expect(pubKey.toHex(\"compressed\")).toBe(compHex);\n    expect(pubKey.toHex(\"uncompressed\")).toBe(uncompHex);\n\n    const pubKey2 = PublicKey.fromHex(\n      pubKey.toHex(\"uncompressed\"),\n      \"uncompressed\",\n    );\n    expect(pubKey2.toHex(\"compressed\")).toBe(compHex);\n\n    const invalidType = [] as unknown as string;\n    expect(() => PublicKey.fromHex(invalidType, \"compressed\")).toThrowError(\n      /got object/i,\n    );\n\n    const invalidCompLength = \"0\".repeat(65);\n    expect(() =>\n      PublicKey.fromHex(invalidCompLength, \"compressed\"),\n    ).toThrowError(/got 65 hexadigits/i);\n\n    const invalidCompHeader = \"04\" + \"0\".repeat(64);\n    expect(() =>\n      PublicKey.fromHex(invalidCompHeader, \"compressed\"),\n    ).toThrowError(/got 0x04/i);\n\n    const invalidUncompLength = \"0\".repeat(129);\n    expect(() =>\n      PublicKey.fromHex(invalidUncompLength, \"uncompressed\"),\n    ).toThrowError(/got 129 hexadigits/i);\n\n    const invalidUncompHeader = \"02\" + \"0\".repeat(128);\n    expect(() =>\n      PublicKey.fromHex(invalidUncompHeader, \"uncompressed\"),\n    ).toThrowError(/got 0x02/i);\n\n    expect(() =>\n      PublicKey.fromHex(\n        \"\",\n        \"invalid\" as unknown as \"compressed\" | \"uncompressed\",\n      ),\n    ).toThrowError(/invalid.*? form/i);\n  });\n\n  test(\"verify()\", async () => {\n    const pubKeyBytes = new Uint8Array([\n      0x04, 0xb5, 0xa2, 0x4a, 0xa2, 0x11, 0x27, 0x20, 0x42, 0x3b, 0xad, 0x39,\n      0xa0, 0x20, 0x51, 0x82, 0x37, 0x9d, 0x6f, 0x2b, 0x33, 0xe3, 0x48, 0x7c,\n      0x9a, 0xb6, 0xcc, 0x8f, 0xc4, 0x96, 0xf8, 0xa5, 0x48, 0x34, 0x40, 0xef,\n      0xbb, 0xef, 0x06, 0x57, 0xac, 0x2e, 0xf6, 0xc6, 0xee, 0x05, 0xdb, 0x06,\n      0xa9, 0x45, 0x32, 0xfd, 0xa7, 0xdd, 0xc4, 0x4a, 0x16, 0x95, 0xe5, 0xce,\n      0x1a, 0x3d, 0x3c, 0x76, 0xdb,\n    ]);\n    const pubKey = PublicKey.fromBytes(pubKeyBytes, \"uncompressed\");\n    const msg = new Uint8Array([\n      0x64, 0x37, 0x3a, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x6c, 0x65,\n      0x31, 0x30, 0x3a, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x5f, 0x6b, 0x65,\n      0x79, 0x36, 0x35, 0x3a, 0x04, 0xb5, 0xa2, 0x4a, 0xa2, 0x11, 0x27, 0x20,\n      0x42, 0x3b, 0xad, 0x39, 0xa0, 0x20, 0x51, 0x82, 0x37, 0x9d, 0x6f, 0x2b,\n      0x33, 0xe3, 0x48, 0x7c, 0x9a, 0xb6, 0xcc, 0x8f, 0xc4, 0x96, 0xf8, 0xa5,\n      0x48, 0x34, 0x40, 0xef, 0xbb, 0xef, 0x06, 0x57, 0xac, 0x2e, 0xf6, 0xc6,\n      0xee, 0x05, 0xdb, 0x06, 0xa9, 0x45, 0x32, 0xfd, 0xa7, 0xdd, 0xc4, 0x4a,\n      0x16, 0x95, 0xe5, 0xce, 0x1a, 0x3d, 0x3c, 0x76, 0xdb, 0x39, 0x3a, 0x72,\n      0x65, 0x63, 0x69, 0x70, 0x69, 0x65, 0x6e, 0x74, 0x32, 0x30, 0x3a, 0x8a,\n      0xe7, 0x2e, 0xfa, 0xb0, 0x95, 0x94, 0x66, 0x51, 0x12, 0xe6, 0xd4, 0x9d,\n      0xfd, 0x19, 0x41, 0x53, 0x8c, 0xf3, 0x74, 0x36, 0x3a, 0x73, 0x65, 0x6e,\n      0x64, 0x65, 0x72, 0x32, 0x30, 0x3a, 0xb6, 0xc0, 0x3d, 0xe5, 0x7d, 0xdf,\n      0x03, 0x69, 0xc7, 0x20, 0x7d, 0x2d, 0x11, 0x3a, 0xdf, 0xf8, 0x20, 0x51,\n      0x99, 0xcf, 0x39, 0x3a, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d,\n      0x70, 0x32, 0x37, 0x3a, 0x32, 0x30, 0x31, 0x38, 0x2d, 0x30, 0x31, 0x2d,\n      0x30, 0x32, 0x54, 0x30, 0x33, 0x3a, 0x30, 0x34, 0x3a, 0x30, 0x35, 0x2e,\n      0x30, 0x30, 0x36, 0x30, 0x30, 0x30, 0x5a, 0x65,\n    ]);\n    const sigBytes = new Uint8Array([\n      0x30, 0x44, 0x02, 0x20, 0x62, 0xcf, 0x8a, 0x04, 0x41, 0x9c, 0x6a, 0x03,\n      0xba, 0xf5, 0x5d, 0xe1, 0x0d, 0x9b, 0x20, 0x0e, 0xda, 0xa9, 0xdf, 0x2b,\n      0x9b, 0xf0, 0xcf, 0x98, 0x9f, 0xd6, 0x5d, 0x71, 0xc5, 0x5c, 0x35, 0x60,\n      0x02, 0x20, 0x2a, 0xa5, 0x59, 0x69, 0xd0, 0xad, 0xb1, 0x5e, 0x9e, 0x70,\n      0x8d, 0x83, 0x00, 0xe1, 0x05, 0x31, 0x1e, 0x1a, 0x16, 0x16, 0x5d, 0xb7,\n      0x3e, 0xd8, 0xf4, 0xf0, 0x05, 0x1d, 0x9f, 0x13, 0x81, 0xfd,\n    ]);\n    const sig = Signature.fromBytes(sigBytes);\n    expect(pubKey.verify(msg, sig)).toBeTruthy();\n\n    const invalidMsgType = \"\" as unknown as Message;\n    await expect(() => pubKey.verify(invalidMsgType, sig)).rejects.toThrowError(\n      /got string/,\n    );\n\n    const invalidSigType = \"\" as unknown as Signature;\n    await expect(() => pubKey.verify(msg, invalidSigType)).rejects.toThrowError(\n      /got string/,\n    );\n  });\n\n  test(\"toBytes()\", () => {\n    const pubKey = PublicKey.fromHex(compHex, \"compressed\");\n    expect(pubKey.toBytes(\"uncompressed\")).toStrictEqual(\n      new Uint8Array(Buffer.from(uncompHex, \"hex\")),\n    );\n\n    const pubKey2 = PublicKey.fromHex(uncompHex, \"uncompressed\");\n    expect(pubKey2.toBytes(\"compressed\")).toStrictEqual(\n      new Uint8Array(Buffer.from(compHex, \"hex\")),\n    );\n\n    const invalidForm = \"invalid\" as unknown as \"compressed\" | \"uncompressed\";\n    expect(() => pubKey.toBytes(invalidForm)).toThrowError(/invalid .*? form/i);\n  });\n\n  test(\"toHex()\", () => {\n    const pubKey = PublicKey.fromHex(compHex, \"compressed\");\n    expect(pubKey.toHex(\"uncompressed\")).toBe(uncompHex);\n\n    const pubKey2 = PublicKey.fromHex(uncompHex, \"uncompressed\");\n    expect(pubKey2.toHex(\"compressed\")).toBe(compHex);\n\n    const invalidForm = \"invalid\" as unknown as \"compressed\" | \"uncompressed\";\n    expect(() => pubKey.toHex(invalidForm)).toThrowError(/invalid .*? form/i);\n  });\n\n  test(\"equals()\", () => {\n    const pubKey = PublicKey.fromHex(compHex, \"compressed\");\n    const pubKey2 = PublicKey.fromHex(compHex, \"compressed\");\n    expect(pubKey.equals(pubKey2)).toBeTruthy();\n    expect(pubKey2.equals(pubKey)).toBeTruthy();\n\n    const pubKey3 = PublicKey.fromHex(\n      \"02b4cc2941408698d07f059db306bd8e207c29b14a3540bb19891b102666a963db\",\n      \"compressed\",\n    );\n    expect(pubKey3.equals(pubKey)).toBeFalsy();\n    expect(pubKey.equals(pubKey3)).toBeFalsy();\n  });\n});\n"
  },
  {
    "path": "@planetarium/account/test/RawPrivateKey.test.ts",
    "content": "import * as fc from \"fast-check\";\nimport * as secp256k1 from \"@noble/secp256k1\";\nimport { Address } from \"../src/Address\";\nimport { PublicKey } from \"../src/PublicKey\";\nimport { RawPrivateKey } from \"../src/RawPrivateKey\";\nimport { describe, expect, test } from \"vitest\";\n\ndescribe(\"RawPrivateKey\", () => {\n  test(\"fromBytes()\", () => {\n    const bytes = Buffer.from(\n      \"5760ea321bdd7ac302469e192aa527b6458e3a1e0ddf6c76d9618aca6f653b4d\",\n      \"hex\",\n    );\n\n    // TypedArray() constructor refers to the memory if it takes an\n    // ArrayBuffer/Buffer, but it copies the memory if it takes a view\n    // (e.g. Uint8Array).  The below code calls the constructor twice by\n    // intention (to copy the data):\n    const inputBytes = new Uint8Array(new Uint8Array(bytes));\n    const rawKey = RawPrivateKey.fromBytes(inputBytes);\n    expect(rawKey.toBytes()).toStrictEqual(new Uint8Array(bytes));\n\n    const pubKeyBytes = new Uint8Array(\n      Buffer.from(\n        \"02472a659c7e655cbcf688997863fb9c7a7139635929429bdc9f75f10c60ed8070\",\n        \"hex\",\n      ),\n    );\n    expect(rawKey.publicKey.toBytes(\"compressed\")).toStrictEqual(pubKeyBytes);\n\n    // The inputBytes should not affect the RawPrivateKey instance which\n    // was created from it:\n    inputBytes.fill(0, 0, inputBytes.length);\n    expect(rawKey.toBytes()).toStrictEqual(new Uint8Array(bytes));\n    expect(rawKey.publicKey.toBytes(\"compressed\")).toStrictEqual(pubKeyBytes);\n\n    const invalidType = [] as unknown as Uint8Array;\n    expect(() => RawPrivateKey.fromBytes(invalidType)).toThrowError(\n      /got object/i,\n    );\n\n    const invalidLength = new Uint8Array(31);\n    expect(() => RawPrivateKey.fromBytes(invalidLength)).toThrowError(\n      /got 31 bytes/i,\n    );\n\n    const invalidKey = new Uint8Array(32);\n    expect(() => RawPrivateKey.fromBytes(invalidKey)).toThrowError(/invalid/i);\n  });\n\n  test(\"fromHex()\", () => {\n    const hex =\n      \"5760ea321bdd7ac302469e192aa527b6458e3a1e0ddf6c76d9618aca6f653b4d\";\n    const rawKey = RawPrivateKey.fromHex(hex);\n    expect(rawKey.toBytes()).toStrictEqual(\n      new Uint8Array(Buffer.from(hex, \"hex\")),\n    );\n\n    const pubKeyBytes = new Uint8Array(\n      Buffer.from(\n        \"02472a659c7e655cbcf688997863fb9c7a7139635929429bdc9f75f10c60ed8070\",\n        \"hex\",\n      ),\n    );\n    expect(rawKey.publicKey.toBytes(\"compressed\")).toStrictEqual(pubKeyBytes);\n\n    const invalidType = new Uint8Array(32) as unknown as string;\n    expect(() => RawPrivateKey.fromHex(invalidType)).toThrowError(\n      /got object/i,\n    );\n\n    const invalidLength = \"0\".repeat(62);\n    expect(() => RawPrivateKey.fromHex(invalidLength)).toThrowError(\n      /got 62 hexadigits/i,\n    );\n\n    const invalidKey = \"0\".repeat(64);\n    expect(() => RawPrivateKey.fromHex(invalidKey)).toThrowError(/invalid/i);\n  });\n\n  test(\"generate()\", () => {\n    const rawKey = RawPrivateKey.generate();\n    const keyBytes = rawKey.toBytes();\n    expect(keyBytes.length).toBe(32);\n    expect(keyBytes).toSatisfy(secp256k1.utils.isValidPrivateKey);\n  });\n\n  test(\"getAddress()\", async () => {\n    const key = RawPrivateKey.fromHex(\n      \"5760ea321bdd7ac302469e192aa527b6458e3a1e0ddf6c76d9618aca6f653b4d\",\n    );\n    const address = await key.getAddress();\n    expect(address).toBeInstanceOf(Address);\n    expect(address.toHex()).toBe(\"8f64a97ACABB267B29854FdA9e6B1397A8991135\");\n  });\n\n  test(\"publicKey [deprecated]\", () => {\n    const key = RawPrivateKey.fromHex(\n      \"5760ea321bdd7ac302469e192aa527b6458e3a1e0ddf6c76d9618aca6f653b4d\",\n    );\n    expect(key.publicKey).toBeInstanceOf(PublicKey);\n    expect(key.publicKey.toHex(\"compressed\")).toStrictEqual(\n      \"02472a659c7e655cbcf688997863fb9c7a7139635929429bdc9f75f10c60ed8070\",\n    );\n  });\n\n  test(\"getPublicKey()\", async () => {\n    const key = RawPrivateKey.fromHex(\n      \"5760ea321bdd7ac302469e192aa527b6458e3a1e0ddf6c76d9618aca6f653b4d\",\n    );\n    const publicKey = await key.getPublicKey();\n    expect(publicKey).toBeInstanceOf(PublicKey);\n    expect(publicKey.toHex(\"compressed\")).toStrictEqual(\n      \"02472a659c7e655cbcf688997863fb9c7a7139635929429bdc9f75f10c60ed8070\",\n    );\n  });\n\n  test(\"sign()\", async () => {\n    // TODO: Compare with `planet key sign` command\n    // TODO: Turn the RawPrivateKey fixture into an arbitrary.\n    const key = RawPrivateKey.generate();\n    const pubKey = key.publicKey;\n    await fc.assert(\n      fc.asyncProperty(fc.uint8Array(), async (msg: Uint8Array) => {\n        const sig = await key.sign(msg);\n        return await pubKey.verify(msg, sig);\n      }),\n    );\n  });\n\n  test(\"exportPrivateKey()\", async () => {\n    const key = RawPrivateKey.generate();\n    const exported = await key.exportPrivateKey();\n    expect(exported).toBeInstanceOf(RawPrivateKey);\n    expect(exported).toHaveEqualBytes(key);\n  });\n\n  test(\"toBytes()\", () => {\n    const originalBytes = new Uint8Array(\n      Buffer.from(\n        \"5760ea321bdd7ac302469e192aa527b6458e3a1e0ddf6c76d9618aca6f653b4d\",\n        \"hex\",\n      ),\n    );\n    const rawKey = RawPrivateKey.fromBytes(originalBytes);\n    const bytes = rawKey.toBytes();\n    expect(bytes).toStrictEqual(originalBytes);\n\n    // The returned bytes should be a copy, and should not affect the original\n    // bytes in the RawPrivateKey instance:\n    bytes.fill(0, 0, bytes.length);\n    expect(rawKey.toBytes()).toStrictEqual(originalBytes);\n  });\n});\n"
  },
  {
    "path": "@planetarium/account/test/Signature.test.ts",
    "content": "import { Signature } from \"../src/Signature\";\nimport { inspect } from \"node:util\";\nimport { describe, expect, test } from \"vitest\";\n\ndescribe(\"Signature\", () => {\n  const sigBytes = new Uint8Array([\n    0x30, 0x44, 0x02, 0x20, 0x62, 0xcf, 0x8a, 0x04, 0x41, 0x9c, 0x6a, 0x03,\n    0xba, 0xf5, 0x5d, 0xe1, 0x0d, 0x9b, 0x20, 0x0e, 0xda, 0xa9, 0xdf, 0x2b,\n    0x9b, 0xf0, 0xcf, 0x98, 0x9f, 0xd6, 0x5d, 0x71, 0xc5, 0x5c, 0x35, 0x60,\n    0x02, 0x20, 0x2a, 0xa5, 0x59, 0x69, 0xd0, 0xad, 0xb1, 0x5e, 0x9e, 0x70,\n    0x8d, 0x83, 0x00, 0xe1, 0x05, 0x31, 0x1e, 0x1a, 0x16, 0x16, 0x5d, 0xb7,\n    0x3e, 0xd8, 0xf4, 0xf0, 0x05, 0x1d, 0x9f, 0x13, 0x81, 0xfd,\n  ]);\n  const sigHex =\n    \"3044022062cf8a04419c6a03baf55de10d9b200edaa9df2b9bf0cf989fd65d71c55c35\" +\n    \"6002202aa55969d0adb15e9e708d8300e105311e1a16165db73ed8f4f0051d9f1381fd\";\n\n  test(\"fromBytes()\", () => {\n    const inputBytes = new Uint8Array(sigBytes);\n    const sig = Signature.fromBytes(inputBytes);\n    expect(sig.toBytes()).toStrictEqual(sigBytes);\n    expect(sig.toHex()).toBe(sigHex);\n\n    // The inputBytes should not affect the Signature instance which\n    // was created from it:\n    inputBytes.fill(0, 0, inputBytes.length);\n    expect(sig.toBytes()).toStrictEqual(sigBytes);\n    expect(sig.toHex()).toBe(sigHex);\n\n    // A signature with high S is disallowed:\n    const sigWithHighS = new Uint8Array([\n      0x30, 0x45, 0x02, 0x20, 0x38, 0x43, 0x16, 0xdb, 0x7c, 0xfe, 0x12, 0x60,\n      0x6e, 0xa0, 0x54, 0x29, 0xd4, 0x4c, 0x10, 0xe0, 0xff, 0x8b, 0xd2, 0x8c,\n      0xc8, 0x73, 0xff, 0x10, 0x41, 0x4e, 0xbc, 0x40, 0x10, 0xe5, 0x9e, 0xe7,\n      0x02, 0x21, 0x00, 0xb7, 0xf4, 0x80, 0xd3, 0xcc, 0x9f, 0x65, 0x35, 0xcd,\n      0xe2, 0x96, 0x02, 0x63, 0xf7, 0x80, 0xeb, 0x82, 0xae, 0x5b, 0xe5, 0xdb,\n      0xba, 0x1d, 0x43, 0xaa, 0x16, 0x35, 0x62, 0xc6, 0x75, 0x85, 0xa7,\n    ]);\n    expect(() => Signature.fromBytes(sigWithHighS)).throws(\n      RangeError,\n      \"high S\",\n    );\n  });\n\n  test(\"fromHex()\", () => {\n    const sig = Signature.fromHex(sigHex);\n    expect(sig.toHex()).toBe(sigHex);\n    expect(sig.toBytes()).toStrictEqual(sigBytes);\n\n    // A signature with high S is disallowed:\n    const sigWithHighS =\n      \"30450220384316db7cfe12606ea05429d44c10e0ff8bd28cc873ff10414ebc4010e59ee\" +\n      \"7022100b7f480d3cc9f6535cde2960263f780eb82ae5be5dbba1d43aa163562c67585a7\";\n    expect(() => Signature.fromHex(sigWithHighS)).throws(RangeError, \"high S\");\n  });\n\n  test(\"toBytes()\", () => {\n    const sig = Signature.fromBytes(sigBytes);\n    expect(sig.toBytes()).toStrictEqual(sigBytes);\n  });\n\n  test(\"toHex()\", () => {\n    const sig = Signature.fromBytes(sigBytes);\n    expect(sig.toHex()).toBe(sigHex);\n  });\n\n  test(\"toString()\", () => {\n    const sig = Signature.fromBytes(sigBytes);\n    expect(sig.toString()).toBe(sigHex);\n  });\n\n  test(\"[nodejs.util.inspect.custom]()\", () => {\n    const sig = Signature.fromBytes(sigBytes);\n    expect(inspect(sig)).toBe(`Signature { ${sig.toString()} }`);\n  });\n});\n"
  },
  {
    "path": "@planetarium/account/test/setup.ts",
    "content": "import { expect } from \"vitest\";\n\ninterface HavingBytes {\n  toBytes(): Uint8Array;\n}\n\nexpect.extend({\n  toHaveEqualBytes: (received: HavingBytes, expected: HavingBytes) => {\n    const actualBytes = received.toBytes();\n    const expectedBytes = expected.toBytes();\n    const actualHex = Buffer.from(actualBytes).toString(\"hex\");\n    const expectedHex = Buffer.from(expectedBytes).toString(\"hex\");\n    if (actualBytes.length !== expectedBytes.length) {\n      return {\n        message: () =>\n          `expected to have ${expectedBytes.length} bytes, ` +\n          `got ${actualBytes.length}\\n` +\n          `expected: ${expectedHex}\\nactual: ${actualHex}`,\n        pass: false,\n      };\n    }\n\n    for (let i = 0; i < actualBytes.length; i++) {\n      if (actualBytes[i] !== expectedBytes[i]) {\n        return {\n          message: () =>\n            `expected ${received} to have equal bytes, ` +\n            `got ${actualBytes} at index ${i}\\n` +\n            `expected: ${expectedHex}\\nactual: ${actualHex}`,\n          pass: false,\n        };\n      }\n    }\n\n    return { message: () => \"passed\", pass: true };\n  },\n});\n"
  },
  {
    "path": "@planetarium/account/test/utils.ts",
    "content": "export function toHex(bytes: Uint8Array): string {\n  let hex = \"\";\n  for (let i = 0; i < bytes.length; i++) {\n    hex += bytes[i].toString(16).padStart(2, \"0\");\n  }\n  return hex;\n}\n\nexport function bytesEquals(a: Uint8Array, b: Uint8Array): boolean {\n  if (a.length !== b.length) {\n    return false;\n  }\n  for (let i = 0; i < a.length; i++) {\n    if (a[i] !== b[i]) {\n      return false;\n    }\n  }\n  return true;\n}\n"
  },
  {
    "path": "@planetarium/account/tsconfig.json",
    "content": "{\n  \"include\": [\"./src\", \"*.d.ts\", \"*.ts\"],\n  \"compilerOptions\": {\n    \"outDir\": \"dist\",\n    \"target\": \"ES2022\",\n    \"strict\": true,\n    \"noUnusedLocals\": true,\n    \"noImplicitReturns\": true,\n    \"esModuleInterop\": true,\n    \"skipLibCheck\": true,\n    \"forceConsistentCasingInFileNames\": true,\n    \"module\": \"nodenext\",\n    \"moduleResolution\": \"nodenext\"\n  },\n}\n"
  },
  {
    "path": "@planetarium/account/vitest.config.ts",
    "content": "import { defineConfig } from \"vitest/config\";\n\nexport default defineConfig({\n  test: {\n    setupFiles: [\"./test/setup.ts\"],\n    cache: false\n  },\n});\n"
  },
  {
    "path": "@planetarium/account-aws-kms/.gitignore",
    "content": "coverage/\ndist/\n"
  },
  {
    "path": "@planetarium/account-aws-kms/CONTRIBUTING.md",
    "content": "Contribution guide\n==================\n\n*See the monorepository's [contribution guide](../../CONTRIBUTING.md) as well.*\n\n\nAutomated tests\n---------------\n\nThe automated tests are closed to functional tests rather than unit tests.\nIt requires AWS credentials to run tests, and each test run charges a fee.\nTherefore, you should avoid to repeatedly run tests like a habit even when you\nchange much.\n\nThe test suite requires the following environment variables to be configured:\n\n -  `AWS_ACCESS_KEY_ID`\n -  `AWS_SECRET_ACCESS_KEY`\n -  `AWS_REGION`\n\nThe account requires several KMS permissions.  See also\nthe [*README.md*](README.md) for details.\n\nNote that it creates and immediately delete multiple keys to utilize them as\nfixture data.  They are scheduled to be deleted in seven days.  Repeated tests\nmay make your AWS KMS a mess, so be careful.  We recommend you to run the test\nsuite on a region you usually don't use.\n"
  },
  {
    "path": "@planetarium/account-aws-kms/README.md",
    "content": "@planetarium/account-aws-kms\n============================\n\nAn npm package for providing `AwsKmsKeyStore`, an implementation of `KeyStore`\nfrom *@planetarium/account* that uses AWS KMS as the backend.\n\nRequired permissions\n--------------------\n\n| Method                      | Required permissions                | Required for `AwsKmsKeyStoreOptions.scopingTags` |\n|-----------------------------|-------------------------------------|--------------------------------------------------|\n| `AwsKmsKeyStore.list()`     | `kms:ListKeys`                      | `kms:ListResourceTags`                           |\n| `AwsKmsKeyStore.get()`      | `kms:ListKeys`                      | `kms:ListResourceTags`                           |\n| `AwsKmsKeyStore.generate()` | `kms:CreateKey`, `kms:GetPublicKey` | `kms:TagResource`                                |\n| `AwsKmsKeyStore.delete()`   | `kms:ScheduleKeyDeletion`           |                                                  |\n| `AwsKmsAccount.sign()`[^1]  | `kms:Sign`                          |                                                  |\n\nReplace `[NUMERIC_ROOT_ACCOUNT_ID]` with your [12-digit root account ID][AWSId]:\n\n~~~~ json\n{\n  \"Version\": \"2012-10-17\",\n  \"Statement\": [\n    {\n      \"Effect\": \"Allow\",\n      \"Action\": [\n        \"kms:GetPublicKey\",\n        \"kms:ScheduleKeyDeletion\",\n        \"kms:DescribeKey\",\n        \"kms:ListResourceTags\",\n        \"kms:Sign\",\n        \"kms:TagResource\"\n      ],\n      \"Resource\": \"arn:aws:kms:*:[NUMERIC_ROOT_ACCOUNT_ID]:key/*\"\n    },\n    {\n      \"Effect\": \"Allow\",\n      \"Action\": [\n        \"kms:ListKeys\",\n        \"kms:CreateKey\"\n      ],\n      \"Resource\": \"*\"\n    }\n  ]\n}\n~~~~\n\n[^1]: An `AwsKmsAccount` instance can be obtained from `AwsKmsKeyStore.get()`.\n[AWSId]: https://docs.aws.amazon.com/signin/latest/userguide/FindingYourAWSId.html\n"
  },
  {
    "path": "@planetarium/account-aws-kms/examples/cli.ts",
    "content": "import { RawPrivateKey } from \"@planetarium/account\";\nimport { AwsKmsKeyStore, KMSClient } from \"@planetarium/account-aws-kms\";\n\n// Expects the below environment variables:\n// - AWS_ACCESS_KEY_ID\n// - AWS_SECRET_ACCESS_KEY\nconst store = new AwsKmsKeyStore(\n  new KMSClient({\n    region: \"ap-northeast-3\",\n  }),\n);\n\nif (process.argv[2] === \"list\") {\n  for await (const key of store.list()) {\n    console.log(key);\n  }\n} else if (process.argv[2] === \"get\") {\n  const keyId = process.argv[3];\n  if (keyId == null) {\n    console.error(\"error: missing key id\");\n    process.exit(1);\n  }\n  const key = await store.get(keyId);\n  console.log(key);\n} else if (process.argv[2] === \"generate\") {\n  console.log(await store.generate());\n} else if (process.argv[2] === \"delete\") {\n  const keyId = process.argv[3];\n  if (keyId == null) {\n    console.error(\"error: missing key id\");\n    process.exit(1);\n  }\n  const key = await store.delete(keyId);\n  console.log(key);\n} else {\n  console.error(\"usage: cli.ts list|get|generate|delete\");\n  process.exit(1);\n}\n"
  },
  {
    "path": "@planetarium/account-aws-kms/package.json",
    "content": "{\n  \"name\": \"@planetarium/account-aws-kms\",\n  \"private\": true,\n  \"description\": \"Libplanet account implementation using AWS KMS\",\n  \"type\": \"module\",\n  \"main\": \"./dist/index.js\",\n  \"imports\": {\n    \"#crypto\": {\n      \"node\": \"./src/crypto/node.ts\",\n      \"default\": \"./src/crypto/browser.ts\"\n    }\n  },\n  \"exports\": {\n    \".\": {\n      \"node\": {\n        \"types\": \"./dist/index.d.ts\",\n        \"import\": \"./dist/index.js\",\n        \"require\": \"./dist/index.cjs\"\n      },\n      \"browser\": \"./dist/index.browser.mjs\",\n      \"default\": \"./dist/index.js\"\n    }\n  },\n  \"files\": [\n    \"dist/**/*\"\n  ],\n  \"scripts\": {\n    \"build\": \"yarn && nanobundle build\",\n    \"prepack\": \"yarn && yarn build\",\n    \"dev\": \"yarn test\",\n    \"test\": \"bash -c 'yarn && yarn run -T tsc -p tsconfig.json && vitest run; status=$?; printf \\\"\\\\033[41;97mNOTE: running this test suite too many times may be costly, as this creates and deletes AWS KMS keys during testing. KMS keys are prorated per hour for the price of \\\\$1.00 per month per key.\\\\033[0m\\n\\\" > /dev/stderr; exit $status'\",\n    \"coverage\": \"yarn && vitest run --coverage\"\n  },\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"git+https://github.com/planetarium/libplanet.git\",\n    \"directory\": \"@planetarium/account-aws-kms\"\n  },\n  \"keywords\": [\n    \"libplanet\"\n  ],\n  \"author\": \"Planetarium (https://planetarium.dev/)\",\n  \"license\": \"LGPL-2.1-or-later\",\n  \"devDependencies\": {\n    \"@planetarium/account\": \"workspace:^\",\n    \"@types/node\": \"^18.13.0\",\n    \"@vitest/coverage-c8\": \"^0.29.3\",\n    \"@vitest/ui\": \"^0.29.3\",\n    \"es-aggregate-error\": \"^1.0.9\",\n    \"nanobundle\": \"^1.6.0\",\n    \"vite\": \"^4.1.1\",\n    \"vitest\": \"^0.29.3\"\n  },\n  \"dependencies\": {\n    \"@aws-sdk/client-kms\": \"^3.272.0\",\n    \"@noble/secp256k1\": \"^1.7.1\",\n    \"asn1js\": \"^3.0.5\"\n  },\n  \"peerDependencies\": {\n    \"@planetarium/account\": \"workspace:^\"\n  },\n  \"engines\": {\n    \"node\": \">=19.0.0\"\n  }\n}\n"
  },
  {
    "path": "@planetarium/account-aws-kms/src/AwsKmsAccount.ts",
    "content": "import { AwsKmsKeyId } from \"./AwsKmsKeyId.js\";\nimport { KMSClient, SignCommand } from \"@aws-sdk/client-kms\";\nimport { Signature as NobleSignature } from \"@noble/secp256k1\";\nimport { crypto } from \"#crypto\";\nimport {\n  Address,\n  type Account,\n  type Message,\n  PublicKey,\n  Signature,\n} from \"@planetarium/account\";\n\nexport class AwsKmsAccount implements Account {\n  readonly #client: KMSClient;\n\n  readonly keyId: AwsKmsKeyId;\n\n  // TODO: This attribute is deprecated.  We should remove it and make\n  // getPublicKey() method the only choice in the future.\n  /**\n   * @deprecated Use {@link getPublicKey()} instead.\n   */\n  readonly publicKey: PublicKey;\n\n  constructor(keyId: AwsKmsKeyId, publicKey: PublicKey, client: KMSClient) {\n    this.keyId = keyId;\n    this.publicKey = publicKey;\n    this.#client = client;\n  }\n\n  getAddress(): Promise<Address> {\n    return Promise.resolve(Address.deriveFrom(this.publicKey));\n  }\n\n  getPublicKey(): Promise<PublicKey> {\n    return Promise.resolve(this.publicKey);\n  }\n\n  async sign(message: Message): Promise<Signature> {\n    const digest = await crypto.subtle.digest(\"SHA-256\", message);\n    const digestArray = new Uint8Array(digest);\n\n    const cmd = new SignCommand({\n      KeyId: this.keyId,\n      Message: digestArray,\n      MessageType: \"DIGEST\",\n      SigningAlgorithm: \"ECDSA_SHA_256\",\n    });\n    const response = await this.#client.send(cmd);\n    if (response.Signature == null) throw new Error(\"Failed to sign message\");\n    const sig = NobleSignature.fromDER(response.Signature).normalizeS();\n    return Signature.fromHex(sig.toDERHex());\n  }\n}\n\nexport default AwsKmsAccount;\n"
  },
  {
    "path": "@planetarium/account-aws-kms/src/AwsKmsKeyId.ts",
    "content": "export type AwsKmsKeyId = string; // UUID\n\nexport default AwsKmsKeyId;\n"
  },
  {
    "path": "@planetarium/account-aws-kms/src/AwsKmsKeyStore.ts",
    "content": "import { AwsKmsAccount } from \"./AwsKmsAccount.js\";\nimport { AwsKmsKeyId } from \"./AwsKmsKeyId.js\";\nimport { AwsKmsMetadata } from \"./AwsKmsMetadata.js\";\nimport { parseSubjectPublicKeyInfo } from \"./asn1.js\";\nimport {\n  CreateKeyCommand,\n  DescribeKeyCommand,\n  GetPublicKeyCommand,\n  KMSClient,\n  KMSInvalidStateException,\n  type KeyMetadata,\n  ListKeysCommand,\n  ListResourceTagsCommand,\n  NotFoundException,\n  OriginType,\n  ScheduleKeyDeletionCommand,\n} from \"@aws-sdk/client-kms\";\nimport {\n  type AccountDeletion,\n  type AccountGeneration,\n  type AccountMetadata,\n  type AccountRetrieval,\n  type MutableKeyStore,\n  PublicKey,\n} from \"@planetarium/account\";\n\nexport interface AwsKmsKeyStoreOptions {\n  listWindow: number;\n  scopingTags: Record<string, string>;\n}\n\nexport class AwsKmsKeyStore\n  implements MutableKeyStore<AwsKmsKeyId, AwsKmsAccount, AwsKmsMetadata>\n{\n  readonly #client: KMSClient;\n  readonly #options: AwsKmsKeyStoreOptions;\n\n  constructor(client: KMSClient, options: Partial<AwsKmsKeyStoreOptions> = {}) {\n    this.#client = client;\n    this.#options = {\n      listWindow: options.listWindow ?? 100,\n      scopingTags: options.scopingTags ?? {},\n    };\n  }\n\n  #isValidKey(\n    metadata: KeyMetadata,\n  ): metadata is KeyMetadata & { KeyId: string } {\n    return (\n      metadata.KeyId != null &&\n      metadata.Enabled === true &&\n      metadata.DeletionDate == null &&\n      metadata.KeySpec === \"ECC_SECG_P256K1\" &&\n      metadata.KeyUsage === \"SIGN_VERIFY\"\n    );\n  }\n\n  #mapMetadata(metadata: KeyMetadata): AwsKmsMetadata {\n    return {\n      customKeyStoreId: metadata.CustomKeyStoreId,\n      description: metadata.Description ?? \"\",\n      multiRegion: metadata.MultiRegion ?? false,\n      origin: metadata.Origin ?? OriginType.AWS_KMS,\n    };\n  }\n\n  async #hasTags(\n    keyId: AwsKmsKeyId,\n    tags: Record<string, string>,\n  ): Promise<boolean> {\n    let marker: string | undefined;\n    const remainTags = new Map(Object.entries(tags));\n    do {\n      const cmd = new ListResourceTagsCommand({ KeyId: keyId, Marker: marker });\n      const result = await this.#client.send(cmd);\n      marker = result.NextMarker;\n      if (result.Tags == null) continue;\n      for (const { TagKey, TagValue } of result.Tags) {\n        if (TagKey == null || TagValue == null) continue;\n        if (remainTags.has(TagKey)) {\n          if (remainTags.get(TagKey) === TagValue) {\n            remainTags.delete(TagKey);\n            if (remainTags.size < 1) return true;\n          } else return false;\n        }\n      }\n    } while (marker != null);\n    return remainTags.size < 1;\n  }\n\n  async *list(): AsyncIterable<AccountMetadata<AwsKmsKeyId, AwsKmsMetadata>> {\n    let nextMarker: string | undefined;\n    const hasScopingTags = Object.keys(this.#options).length > 0;\n    do {\n      const listCmd = new ListKeysCommand({\n        Marker: nextMarker,\n        Limit: this.#options.listWindow,\n      });\n      const resp = await this.#client.send(listCmd);\n      const keys = resp.Keys ?? [];\n      for (let i = 0; i < keys.length; i += 5) {\n        const promises = keys\n          .slice(i, i + 5)\n          .map(({ KeyId }) => new DescribeKeyCommand({ KeyId }))\n          .map((cmd) => this.#client.send(cmd));\n        const responses = await Promise.all(promises);\n        for (const resp of responses) {\n          const metadata = resp.KeyMetadata;\n          if (\n            metadata == null ||\n            !this.#isValidKey(metadata) ||\n            (hasScopingTags &&\n              !this.#hasTags(metadata.KeyId, this.#options.scopingTags))\n          ) {\n            continue;\n          }\n          yield {\n            keyId: metadata.KeyId,\n            metadata: this.#mapMetadata(metadata),\n            createdAt: metadata.CreationDate,\n          };\n        }\n      }\n      nextMarker = resp.NextMarker;\n    } while (nextMarker != null);\n  }\n\n  async get(\n    keyId: AwsKmsKeyId,\n  ): Promise<AccountRetrieval<AwsKmsKeyId, AwsKmsAccount, AwsKmsMetadata>> {\n    const descCmd = new DescribeKeyCommand({ KeyId: keyId });\n    const pubKeyCmd = new GetPublicKeyCommand({ KeyId: keyId });\n    const descPromise = this.#client.send(descCmd);\n    const pubKeyPromise = this.#client.send(pubKeyCmd);\n    let descResp;\n    let pubKeyResp;\n    try {\n      [descResp, pubKeyResp] = await Promise.all([descPromise, pubKeyPromise]);\n    } catch (e) {\n      if (\n        e instanceof NotFoundException ||\n        e instanceof KMSInvalidStateException\n      ) {\n        return { result: \"keyNotFound\", keyId };\n      }\n      return { result: \"error\", keyId, message: `${e}` };\n    }\n    if (\n      descResp.KeyMetadata == null ||\n      !this.#isValidKey(descResp.KeyMetadata) ||\n      pubKeyResp.PublicKey == null\n    ) {\n      return { result: \"keyNotFound\", keyId };\n    }\n    const publicKeyBytes: Uint8Array = parseSubjectPublicKeyInfo(\n      pubKeyResp.PublicKey,\n    );\n    const publicKey = PublicKey.fromBytes(publicKeyBytes, \"uncompressed\");\n    return {\n      result: \"success\",\n      keyId,\n      account: new AwsKmsAccount(keyId, publicKey, this.#client),\n      metadata: this.#mapMetadata(descResp.KeyMetadata),\n      createdAt: descResp.KeyMetadata.CreationDate,\n    };\n  }\n\n  async generate(\n    metadata?: AwsKmsMetadata,\n  ): Promise<AccountGeneration<AwsKmsKeyId, AwsKmsAccount>> {\n    const cmd = new CreateKeyCommand({\n      KeySpec: \"ECC_SECG_P256K1\",\n      KeyUsage: \"SIGN_VERIFY\",\n      CustomKeyStoreId: metadata?.customKeyStoreId,\n      Description: metadata?.description,\n      MultiRegion: metadata?.multiRegion,\n      Origin: metadata?.origin,\n      Tags: Object.entries(this.#options.scopingTags).map(\n        ([TagKey, TagValue]) => ({ TagKey, TagValue }),\n      ),\n    });\n    let response;\n    try {\n      response = await this.#client.send(cmd);\n    } catch (e) {\n      return { result: \"error\", message: `${e}` };\n    }\n    const keyId = response.KeyMetadata?.KeyId;\n    if (keyId == null) {\n      return { result: \"error\", message: \"failed to determine keyId\" };\n    }\n    const pubKeyCmd = new GetPublicKeyCommand({ KeyId: keyId });\n    let pubKeyResp;\n    try {\n      pubKeyResp = await this.#client.send(pubKeyCmd);\n    } catch (e) {\n      return { result: \"error\", message: `${e}` };\n    }\n    if (pubKeyResp.PublicKey == null) {\n      return { result: \"error\", message: \"failed to get public key\" };\n    }\n    const publicKeyBytes: Uint8Array = parseSubjectPublicKeyInfo(\n      pubKeyResp.PublicKey,\n    );\n    const publicKey = PublicKey.fromBytes(publicKeyBytes, \"uncompressed\");\n    const account = new AwsKmsAccount(keyId, publicKey, this.#client);\n    return { result: \"success\", keyId, account };\n  }\n\n  async delete(keyId: AwsKmsKeyId): Promise<AccountDeletion<AwsKmsKeyId>> {\n    const cmd = new ScheduleKeyDeletionCommand({ KeyId: keyId });\n    try {\n      await this.#client.send(cmd);\n    } catch (e) {\n      if (\n        e instanceof NotFoundException ||\n        e instanceof KMSInvalidStateException\n      ) {\n        return { result: \"keyNotFound\", keyId };\n      }\n      return { result: \"error\", message: `${e}` };\n    }\n    return { result: \"success\", keyId };\n  }\n}\n"
  },
  {
    "path": "@planetarium/account-aws-kms/src/AwsKmsMetadata.ts",
    "content": "import { OriginType } from \"@aws-sdk/client-kms\";\n\nexport interface AwsKmsMetadata {\n  customKeyStoreId?: string;\n  description: string;\n  multiRegion: boolean;\n  origin: OriginType | string;\n}\n\nexport default AwsKmsMetadata;\n"
  },
  {
    "path": "@planetarium/account-aws-kms/src/asn1.ts",
    "content": "import {\n  Any,\n  BitString,\n  ObjectIdentifier,\n  Sequence,\n  verifySchema,\n} from \"asn1js\";\n\n// https://www.rfc-editor.org/rfc/rfc5280#section-4.1\nconst SubjectPublicKeyInfo = new Sequence({\n  name: \"subjectPublicKeyInfo\",\n  value: [\n    new Sequence({\n      name: \"algorithm\",\n      value: [\n        new ObjectIdentifier({\n          name: \"algorithm\",\n        }),\n        new Any({\n          name: \"parameters\",\n          optional: true,\n        }),\n      ],\n    }),\n    new BitString({\n      name: \"subjectPublicKey\",\n    }),\n  ],\n});\n\nexport function parseSubjectPublicKeyInfo(buf: Uint8Array) {\n  const { result, verified } = verifySchema(buf, SubjectPublicKeyInfo);\n  if (!verified) {\n    throw new RangeError(\"Failed to verify SubjectPublicKeyInfo data\");\n  }\n  const bitstring: BitString = (result as typeof SubjectPublicKeyInfo)\n    .valueBlock.value[1] as BitString;\n  return bitstring.valueBlock.valueHexView;\n}\n"
  },
  {
    "path": "@planetarium/account-aws-kms/src/crypto/browser.ts",
    "content": "declare const globalThis: Record<string, any> | undefined;\nexport const crypto =\n  typeof globalThis === \"object\" && \"crypto\" in globalThis\n    ? globalThis.crypto\n    : undefined;\n"
  },
  {
    "path": "@planetarium/account-aws-kms/src/crypto/node.ts",
    "content": "import * as nc from \"node:crypto\";\nexport const crypto =\n  nc && typeof nc === \"object\" && \"webcrypto\" in nc\n    ? // rome-ignore lint/suspicious/noExplicitAny: false\n      (nc.webcrypto as any)\n    : undefined;\n"
  },
  {
    "path": "@planetarium/account-aws-kms/src/index.ts",
    "content": "export { AwsKmsKeyStore } from \"./AwsKmsKeyStore.js\";\nexport { type AwsKmsKeyId } from \"./AwsKmsKeyId.js\";\nexport { AwsKmsAccount } from \"./AwsKmsAccount.js\";\nexport { type AwsKmsMetadata } from \"./AwsKmsMetadata.js\";\nexport { KMSClient } from \"@aws-sdk/client-kms\";\n"
  },
  {
    "path": "@planetarium/account-aws-kms/test/AwsKmsKeyStore.test.ts",
    "content": "import AwsKmsAccount from \"../src/AwsKmsAccount\";\nimport { AwsKmsKeyId } from \"../src/AwsKmsKeyId\";\nimport { AwsKmsKeyStore } from \"../src/AwsKmsKeyStore\";\nimport { parseSubjectPublicKeyInfo } from \"../src/asn1\";\nimport {\n  CreateKeyCommand,\n  DescribeKeyCommand,\n  GetPublicKeyCommand,\n  KMSClient,\n  type KeyMetadata,\n  ListKeysCommand,\n  OriginType,\n  ScheduleKeyDeletionCommand,\n} from \"@aws-sdk/client-kms\";\nimport { Address, PublicKey } from \"@planetarium/account\";\nimport { AggregateError } from \"es-aggregate-error\";\nimport { randomUUID } from \"node:crypto\";\nimport { hostname, userInfo } from \"node:os\";\nimport { inspect } from \"node:util\";\nimport { afterEach, describe, expect, test } from \"vitest\";\n\nconst envsConfigured =\n  !!process.env.AWS_ACCESS_KEY_ID &&\n  !!process.env.AWS_SECRET_ACCESS_KEY &&\n  !!process.env.AWS_REGION;\n\ninterface FixtureKey {\n  keyId: AwsKmsKeyId;\n  publicKey: PublicKey;\n  metadata: KeyMetadata;\n  clean(): Promise<void>;\n}\n\ndescribe.runIf(envsConfigured)(\"AwsKmsKeyStore\", async () => {\n  const client = new KMSClient({});\n  if (envsConfigured) {\n    console.info(\"The below tests are run on the following AWS session:\");\n    console.table({\n      AWS_ACCESS_KEY_ID: process.env.AWS_ACCESS_KEY_ID,\n      AWS_REGION: process.env.AWS_REGION,\n    });\n  }\n\n  const listCmd = new ListKeysCommand({ Limit: 1000 });\n  const keysList = envsConfigured ? await client.send(listCmd) : { Keys: null };\n  const listWindow = Math.max((keysList.Keys ?? []).length / 2, 2);\n  const testSessionId = randomUUID();\n  const store = new AwsKmsKeyStore(client, {\n    listWindow,\n    scopingTags: { TestSessionId: testSessionId },\n  });\n  const keyDescription = `Auto-generated by @planetarium/account-aws-kms unit tests; ran inside ${\n    userInfo().username\n  }@${hostname()}`;\n\n  async function createFixtureKey(): Promise<FixtureKey> {\n    const cmd = new CreateKeyCommand({\n      KeySpec: \"ECC_SECG_P256K1\",\n      KeyUsage: \"SIGN_VERIFY\",\n      Description: keyDescription,\n      MultiRegion: false,\n      Tags: [{ TagKey: \"TestSessionId\", TagValue: testSessionId }],\n    });\n    const response = await client.send(cmd);\n    if (response.KeyMetadata == null) throw new Error(\"Failed to generate key\");\n    const keyId = response.KeyMetadata.KeyId;\n    if (keyId == null) throw new Error(\"Failed to generate key\");\n\n    let alreadyDeleted = false;\n    async function clean(): Promise<void> {\n      if (alreadyDeleted) return;\n      const delCmd = new ScheduleKeyDeletionCommand({\n        KeyId: keyId,\n        PendingWindowInDays: 7,\n      });\n      try {\n        await client.send(delCmd);\n      } catch (_) {}\n      alreadyDeleted = true;\n    }\n\n    try {\n      const pubKeyCmd = new GetPublicKeyCommand({ KeyId: keyId });\n      const pubKeyResp = await client.send(pubKeyCmd);\n      if (pubKeyResp.PublicKey == null) {\n        throw new Error(\"Failed to get public key\");\n      }\n      const publicKeyBytes: Uint8Array = parseSubjectPublicKeyInfo(\n        pubKeyResp.PublicKey,\n      );\n      const publicKey = PublicKey.fromBytes(publicKeyBytes, \"uncompressed\");\n      return { keyId, publicKey, metadata: response.KeyMetadata, clean };\n    } catch (e) {\n      await clean();\n      throw e;\n    }\n  }\n\n  async function createFixtureKeys(\n    number: number,\n  ): Promise<[Record<AwsKmsKeyId, PublicKey>, () => Promise<void>]> {\n    const promises: Promise<FixtureKey>[] = [];\n    for (let i = 0; i < number; i++) {\n      promises.push(createFixtureKey());\n    }\n    const keys: FixtureKey[] = [];\n    const errors: Error[] = [];\n    for (const promise of promises) {\n      try {\n        keys.push(await promise);\n      } catch (e) {\n        errors.push(e);\n      }\n    }\n\n    async function cleanAll(): Promise<void> {\n      await Promise.all(keys.map((triple) => triple.clean()));\n    }\n\n    if (errors.length > 0) {\n      await cleanAll();\n      throw new AggregateError(errors);\n    }\n\n    return [\n      Object.fromEntries(\n        keys.map((triple) => [triple.keyId, triple.publicKey]),\n      ),\n      cleanAll,\n    ];\n  }\n\n  test(\"list\", async () => {\n    let i = 0;\n    for await (const _ of store.list()) i++;\n    expect(i).toBeFalsy();\n\n    const before = new Date();\n    const [expectedKeys, cleanFixtures] = await createFixtureKeys(5);\n    const after = new Date();\n    afterEach(cleanFixtures);\n\n    const fetched: Set<AwsKmsKeyId> = new Set();\n    for await (const key of store.list()) {\n      expect(key.createdAt).toBeDefined();\n      if (key.createdAt == null) throw new Error(); // type guard\n      expect(+key.createdAt).toBeGreaterThanOrEqual(+before - 1000);\n      expect(+key.createdAt).toBeLessThanOrEqual(+after + 1000);\n      fetched.add(key.keyId);\n    }\n\n    expect(fetched).toStrictEqual(new Set(Object.keys(expectedKeys)));\n  });\n\n  test(\"get\", async () => {\n    const result = await store.get(\"00000000-0000-0000-0000-000000000000\");\n    expect(result).toStrictEqual({\n      result: \"keyNotFound\",\n      keyId: \"00000000-0000-0000-0000-000000000000\",\n    });\n\n    const { keyId, publicKey, metadata, clean } = await createFixtureKey();\n    afterEach(clean);\n    const account = new AwsKmsAccount(keyId, publicKey, client);\n\n    const result2 = await store.get(keyId);\n    expect(result2).toStrictEqual({\n      result: \"success\",\n      keyId,\n      account,\n      metadata: {\n        customKeyStoreId: metadata.CustomKeyStoreId,\n        description: metadata.Description ?? \"\",\n        multiRegion: metadata.MultiRegion ?? false,\n        origin: metadata.Origin ?? OriginType.AWS_KMS,\n      },\n      createdAt: metadata.CreationDate,\n    });\n    expect((await account.getAddress()).toHex()).toStrictEqual(\n      Address.deriveFrom(publicKey).toHex(),\n    );\n    expect((await account.getPublicKey()).toHex(\"compressed\")).toStrictEqual(\n      publicKey.toHex(\"compressed\"),\n    );\n\n    const msg = new Uint8Array([0x01, 0x02, 0x03]);\n    const sig = await account.sign(msg);\n    const verified = await publicKey.verify(msg, sig);\n    if (!verified) {\n      console.log({ msg, sig, publicKey: publicKey.toHex(\"compressed\") });\n    }\n    expect(verified).toStrictEqual(true);\n  });\n\n  test(\"generate\", async () => {\n    const result = await store.generate({\n      description: keyDescription,\n      multiRegion: false,\n      origin: \"AWS_KMS\",\n    });\n\n    if (result.result === \"success\") {\n      let alreadyDeleted = false;\n      afterEach(async () => {\n        if (alreadyDeleted) return;\n        const delCmd = new ScheduleKeyDeletionCommand({\n          KeyId: result.keyId,\n          PendingWindowInDays: 7,\n        });\n        await client.send(delCmd);\n        alreadyDeleted = true;\n      });\n    } else throw new Error(`failed to generate: ${inspect(result)}`); // type guard\n\n    expect(result.result).toBe(\"success\");\n    const descCmd = new DescribeKeyCommand({ KeyId: result.keyId });\n    const resp = await client.send(descCmd);\n    expect(resp.KeyMetadata).toBeDefined();\n    expect(resp.KeyMetadata?.KeyId).toMatch(\n      new RegExp(`^${result.keyId}$`, \"i\"),\n    );\n  });\n\n  test(\"delete\", async () => {\n    const result = await store.delete(\"00000000-0000-0000-0000-000000000000\");\n    expect(result).toStrictEqual({\n      result: \"keyNotFound\",\n      keyId: \"00000000-0000-0000-0000-000000000000\",\n    });\n\n    const { keyId, clean } = await createFixtureKey();\n    afterEach(clean);\n\n    const result2 = await store.delete(keyId);\n    expect(result2).toStrictEqual({ result: \"success\", keyId });\n\n    const cmd = new DescribeKeyCommand({ KeyId: keyId });\n    const resp = await client.send(cmd);\n    expect(resp.KeyMetadata?.Enabled).toBeFalsy();\n\n    const result3 = await store.delete(keyId);\n    expect(result3).toStrictEqual({ result: \"keyNotFound\", keyId });\n  });\n});\n"
  },
  {
    "path": "@planetarium/account-aws-kms/test/asn1.test.ts",
    "content": "import { parseSubjectPublicKeyInfo } from \"../src/asn1\";\nimport { expect, test } from \"vitest\";\n\ntest(\"parseSubjectPublicKeyInfo()\", () => {\n  const input = new Uint8Array([\n    0x30, 0x56, 0x30, 0x10, 0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02,\n    0x01, 0x06, 0x05, 0x2b, 0x81, 0x04, 0x00, 0x0a, 0x03, 0x42, 0x00, 0x04,\n    0x25, 0xfd, 0xe7, 0x9e, 0x8c, 0x8b, 0x6a, 0x91, 0xf3, 0xd2, 0x3d, 0x99,\n    0xe8, 0xe6, 0x8e, 0xed, 0xc4, 0x32, 0x33, 0x0b, 0x5a, 0x99, 0x54, 0x14,\n    0x30, 0xd0, 0x62, 0xaf, 0x26, 0xe5, 0xb4, 0x51, 0x57, 0xfe, 0x64, 0x2b,\n    0xb5, 0x3d, 0xcd, 0x0d, 0x17, 0x92, 0x50, 0x48, 0x86, 0xc5, 0xfa, 0x2c,\n    0x29, 0xcd, 0xa3, 0x6b, 0xbd, 0x8c, 0x88, 0xea, 0xd4, 0x34, 0x5a, 0x54,\n    0x27, 0x44, 0x8d, 0xd2,\n  ]);\n  const expected = new Uint8Array([\n    0x04, 0x25, 0xfd, 0xe7, 0x9e, 0x8c, 0x8b, 0x6a, 0x91, 0xf3, 0xd2, 0x3d,\n    0x99, 0xe8, 0xe6, 0x8e, 0xed, 0xc4, 0x32, 0x33, 0x0b, 0x5a, 0x99, 0x54,\n    0x14, 0x30, 0xd0, 0x62, 0xaf, 0x26, 0xe5, 0xb4, 0x51, 0x57, 0xfe, 0x64,\n    0x2b, 0xb5, 0x3d, 0xcd, 0x0d, 0x17, 0x92, 0x50, 0x48, 0x86, 0xc5, 0xfa,\n    0x2c, 0x29, 0xcd, 0xa3, 0x6b, 0xbd, 0x8c, 0x88, 0xea, 0xd4, 0x34, 0x5a,\n    0x54, 0x27, 0x44, 0x8d, 0xd2,\n  ]);\n  expect(parseSubjectPublicKeyInfo(input)).toStrictEqual(expected);\n\n  const invalid = new Uint8Array([\n    0x30, 0x56, 0x30, 0x10, 0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02,\n    0x01, 0x06, 0x05, 0x2b, 0x81, 0x04, 0x00, 0x0a, 0x03, 0x42,\n  ]);\n  expect(() => parseSubjectPublicKeyInfo(invalid)).toThrowError(RangeError);\n});\n"
  },
  {
    "path": "@planetarium/account-aws-kms/tsconfig.json",
    "content": "{\n  \"include\": [\"./src\", \"*.d.ts\", \"src/*.ts\"],\n  \"compilerOptions\": {\n    \"rootDir\": \"./src\",\n    \"outDir\": \"dist\",\n    \"target\": \"ES2022\",\n    \"strict\": true,\n    \"noUnusedLocals\": true,\n    \"noImplicitReturns\": true,\n    \"esModuleInterop\": true,\n    \"skipLibCheck\": true,\n    \"forceConsistentCasingInFileNames\": true,\n    \"module\": \"nodenext\",\n    \"moduleResolution\": \"nodenext\",\n    \"lib\": [\"ES2022\"]\n  }\n}\n"
  },
  {
    "path": "@planetarium/account-aws-kms/vitest.config.ts",
    "content": "import { defineConfig } from \"vitest/config\";\n\nexport default defineConfig({\n  test: {\n    cache: false,\n    testTimeout: 30000,\n    alias: {\n      \"#crypto\": \"./src/crypto/node.ts\",\n    },\n  },\n});\n"
  },
  {
    "path": "@planetarium/account-web3-secret-storage/.gitignore",
    "content": "coverage/\ndist/\n*.timestamp-*"
  },
  {
    "path": "@planetarium/account-web3-secret-storage/README.md",
    "content": "@planetarium/account-web3-secret-storage\n========================================\n\nThis npm package implements the Ethereum Web3 Secret Storage which corresponds\nto `Libplanet.KeyStore.Web3KeyStore` as well.  `Web3KeyStore` complies with\nthe `KeyStore` interface (from *@planetarium/account* package).\n\nSee also *examples/cli.ts*.\n"
  },
  {
    "path": "@planetarium/account-web3-secret-storage/examples/cli.ts",
    "content": "import { RawPrivateKey } from \"@planetarium/account\";\nimport {\n  TtyPassphraseEntry,\n  Web3KeyStore,\n} from \"@planetarium/account-web3-secret-storage\";\n\nconst store = new Web3KeyStore({ passphraseEntry: new TtyPassphraseEntry() });\n\nif (process.argv[2] === \"list\") {\n  for await (const key of store.list()) {\n    console.log(key);\n  }\n} else if (process.argv[2] === \"get\") {\n  const keyId = process.argv[3];\n  if (keyId == null) {\n    console.error(\"error: missing key id\");\n    process.exit(1);\n  }\n  const key = await store.get(keyId);\n  console.log(key);\n} else if (process.argv[2] === \"generate\") {\n  console.log(await store.generate());\n} else if (process.argv[2] === \"import\") {\n  const privateKeyHex = process.argv[3];\n  if (privateKeyHex == null) {\n    console.error(\"error: missing private key hex\");\n    process.exit(1);\n  }\n  const privateKey = RawPrivateKey.fromHex(privateKeyHex);\n  console.log(await store.import(privateKey, undefined));\n} else if (process.argv[2] === \"delete\") {\n  const keyId = process.argv[3];\n  if (keyId == null) {\n    console.error(\"error: missing key id\");\n    process.exit(1);\n  }\n  const key = await store.delete(keyId);\n  console.log(key);\n} else {\n  console.error(\"usage: cli.ts list|get|generate|import|delete\");\n  process.exit(1);\n}\n"
  },
  {
    "path": "@planetarium/account-web3-secret-storage/package.json",
    "content": "{\n  \"name\": \"@planetarium/account-web3-secret-storage\",\n  \"private\": true,\n  \"description\": \"Libplanet account implementation using Ethereum Web3 Secret Storage\",\n  \"type\": \"module\",\n  \"main\": \"./dist/index.js\",\n  \"imports\": {\n    \"#crypto\": {\n      \"node\": \"./src/crypto/node.ts\",\n      \"default\": \"./src/crypto/browser.ts\"\n    },\n    \"#path\": {\n      \"node\": \"./src/path/node.ts\",\n      \"default\": \"./src/path/browser.ts\"\n    },\n    \"#fs\": {\n      \"node\": \"./src/fs/node.ts\",\n      \"default\": \"./src/fs/browser.ts\"\n    }\n  },\n  \"exports\": {\n    \".\": {\n      \"node\": {\n        \"types\": \"./dist/index.d.ts\",\n        \"require\": \"./dist/index.cjs\",\n        \"import\": \"./dist/index.mjs\"\n      },\n      \"browser\": \"./dist/index.browser.mjs\",\n      \"default\": \"./dist/index.js\"\n    }\n  },\n  \"files\": [\n    \"dist/**/*\"\n  ],\n  \"scripts\": {\n    \"build\": \"yarn && nanobundle build\",\n    \"prepack\": \"yarn && yarn build\",\n    \"dev\": \"yarn && vitest\",\n    \"test\": \"yarn && yarn run -T tsc -p tsconfig.json && vitest run\",\n    \"coverage\": \"yarn && vitest run --coverage\"\n  },\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"git+https://github.com/planetarium/libplanet.git\",\n    \"directory\": \"@planetarium/account-web3-secret-storage\"\n  },\n  \"keywords\": [\n    \"libplanet\"\n  ],\n  \"author\": \"Planetarium (https://planetarium.dev/)\",\n  \"license\": \"LGPL-2.1-or-later\",\n  \"devDependencies\": {\n    \"@planetarium/account\": \"workspace:^\",\n    \"@types/node\": \"^18.13.0\",\n    \"@types/stream-buffers\": \"^3\",\n    \"@vitest/coverage-c8\": \"^0.29.2\",\n    \"@vitest/ui\": \"^0.29.2\",\n    \"fast-check\": \"^3.8.0\",\n    \"nanobundle\": \"^1.6.0\",\n    \"stream-buffers\": \"^3.0.2\",\n    \"vite\": \"^4.1.4\",\n    \"vitest\": \"^0.29.2\"\n  },\n  \"dependencies\": {\n    \"@noble/hashes\": \"^1.3.1\",\n    \"@peculiar/webcrypto\": \"^1.4.3\"\n  },\n  \"peerDependencies\": {\n    \"@planetarium/account\": \"workspace:^\"\n  },\n  \"engines\": {\n    \"node\": \"20.2.0\"\n  }\n}\n"
  },
  {
    "path": "@planetarium/account-web3-secret-storage/src/KeyId.ts",
    "content": "import { crypto } from \"#crypto\";\n\nexport type KeyId = string;\n\nconst UUID_PATTERN =\n  /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;\n\nexport function isKeyId(keyId: string): keyId is KeyId {\n  return !!keyId.match(UUID_PATTERN);\n}\n\nexport function generateKeyId(): KeyId {\n  return crypto.randomUUID();\n}\n\nexport default KeyId;\n"
  },
  {
    "path": "@planetarium/account-web3-secret-storage/src/PassphraseEntry.ts",
    "content": "import { KeyId } from \"./KeyId.js\";\n\nexport type Passphrase = Uint8Array | string;\n\nexport interface PassphraseEntry {\n  authenticate(keyId: KeyId, firstAttempt: boolean): Promise<Passphrase>;\n  configurePassphrase(): Promise<Passphrase>;\n}\n"
  },
  {
    "path": "@planetarium/account-web3-secret-storage/src/TtyPassphraseEntry.ts",
    "content": "import { KeyId } from \"./KeyId.js\";\nimport { Passphrase, PassphraseEntry } from \"./PassphraseEntry.js\";\nimport * as readline from \"node:readline\";\nimport { Readable, Writable } from \"node:stream\";\n\nexport interface PassphraseReaderOptions {\n  input: Readable;\n  output: Writable;\n  mask: string | false;\n}\n\nfunction isNewLine(chunk: Buffer | string) {\n  return (\n    (typeof chunk === \"string\" && chunk.endsWith(\"\\n\")) ||\n    (chunk instanceof Buffer && chunk.at(chunk.length - 1) === 0x0a)\n  );\n}\n\nexport function readPassphrase(\n  prompt: string,\n  { input, output, mask }: PassphraseReaderOptions,\n): Promise<Passphrase> {\n  let masking = false;\n  const rl = readline.createInterface({\n    input,\n    output: new Writable({\n      write: (chunk, encoding: BufferEncoding, callback) => {\n        if (masking && !isNewLine(chunk)) {\n          output.write(\n            mask,\n            encoding.endsWith(\"buffer\") ? \"utf8\" : encoding,\n            callback,\n          );\n        } else output.write(chunk, encoding, callback);\n      },\n    }),\n    terminal: true,\n  });\n\n  return new Promise((resolve) => {\n    rl.question(prompt, (answer) => {\n      rl.close();\n      resolve(answer);\n    });\n    setTimeout(() => (masking = mask !== false), 0); // wait for I/O interrupt\n  });\n}\n\nconst prompts: {\n  authenticate: Record<string, string>;\n  authenticateRetry: Record<string, string>;\n  configurePassphrase: Record<string, string>;\n  configurePassphraseRetry: Record<string, string>;\n  confirmConfigurePassphrase: Record<string, string>;\n} = {\n  authenticate: {\n    \"\": \"Passphrase for {keyId}: \",\n    ko: \"{keyId} 키의 암호: \",\n    qts: \"AUTHENTICATE:{keyId}\", // for unit test\n  },\n  authenticateRetry: {\n    \"\": \"Incorrect; try again: \",\n    ko: \"틀림. 재시도: \",\n    qts: \"AUTHENTICATE_RETRY:{keyId}\", // for unit test\n  },\n  configurePassphrase: {\n    \"\": \"New passphrase: \",\n    ko: \"새 암호: \",\n    qts: \"CONFIGURE_PASSPHRASE\", // for unit test\n  },\n  configurePassphraseRetry: {\n    \"\": \"Mismatch; new passphrase: \",\n    ko: \"틀림. 새 암호 재입력:\",\n    qts: \"CONFIGURE_PASSPHRASE_RETRY\", // for unit test\n  },\n  confirmConfigurePassphrase: {\n    \"\": \"Confirm passphrase: \",\n    ko: \"암호 확인:\",\n    qts: \"CONFIRM_CONFIGURE_PASSPHRASE\", // for unit test\n  },\n};\n\nfunction getLocale(): string {\n  return Intl.DateTimeFormat().resolvedOptions().locale;\n}\n\ninterface TtyPassphraseEntryOptions extends PassphraseReaderOptions {\n  locale: string;\n}\n\nexport class TtyPassphraseEntry implements PassphraseEntry {\n  #options: TtyPassphraseEntryOptions;\n\n  constructor(options: Partial<TtyPassphraseEntryOptions> = {}) {\n    this.#options = {\n      input: options.input ?? process.stdin,\n      output: options.output ?? process.stdout,\n      mask: options.mask ?? \"*\",\n      locale: options.locale ?? getLocale(),\n    };\n  }\n\n  #getPrompt(promptType: keyof typeof prompts) {\n    const table = prompts[promptType];\n    let locale = this.#options.locale;\n    let msg;\n    while (msg == null) {\n      msg = table[locale];\n      locale = locale.replace(/(^|[-_.])[^-_.]*$/, \"\");\n    }\n    return msg;\n  }\n\n  authenticate(keyId: KeyId, firstAttempt: boolean): Promise<Passphrase> {\n    const message = this.#getPrompt(\n      firstAttempt ? \"authenticate\" : \"authenticateRetry\",\n    );\n    const prompt = message.replace(/\\{keyId\\}/g, keyId);\n    return readPassphrase(prompt, this.#options);\n  }\n\n  async configurePassphrase(): Promise<Passphrase> {\n    let prompt = this.#getPrompt(\"configurePassphrase\");\n    const retryPrompt = this.#getPrompt(\"configurePassphraseRetry\");\n    const confirmPrompt = this.#getPrompt(\"confirmConfigurePassphrase\");\n    while (true) {\n      const passphrase = await readPassphrase(prompt, this.#options);\n      const confirmPassphrase = await readPassphrase(\n        confirmPrompt,\n        this.#options,\n      );\n      if (passphrase === confirmPassphrase) return passphrase;\n      prompt = retryPrompt;\n    }\n  }\n}\n"
  },
  {
    "path": "@planetarium/account-web3-secret-storage/src/Web3Account.ts",
    "content": "import { isKeyId, KeyId } from \"./KeyId.js\";\nimport { Passphrase, PassphraseEntry } from \"./PassphraseEntry.js\";\nimport {\n  Address,\n  ExportableAccount,\n  PublicKey,\n  RawPrivateKey,\n  Signature,\n} from \"@planetarium/account\";\nimport { crypto } from \"#crypto\";\nimport { pbkdf2Async } from \"@noble/hashes/pbkdf2\";\nimport { scryptAsync } from \"@noble/hashes/scrypt\";\nimport { sha256 } from \"@noble/hashes/sha256\";\nimport { keccak_256 } from \"@noble/hashes/sha3\";\n\nexport type Web3KeyObjectKdf =\n  | {\n      kdf: \"pbkdf2\";\n      kdfparams: {\n        c: number;\n        dklen: number;\n        prf: \"hmac-sha256\";\n        salt: string;\n      };\n    }\n  | {\n      kdf: \"scrypt\";\n      kdfparams: {\n        dklen: number;\n        n: number;\n        p: number;\n        r: number;\n        salt: string;\n      };\n    };\n\nexport type Web3KeyObjectCipher = {\n  cipher: \"aes-128-ctr\";\n  cipherparams: {\n    iv: string;\n  };\n  ciphertext: string;\n  mac: string;\n};\n\nexport interface Web3KeyObject {\n  version: 3;\n  id: KeyId;\n  address: string;\n  crypto: Web3KeyObjectCipher & Web3KeyObjectKdf;\n}\n\nexport class Web3Account implements ExportableAccount {\n  #keyObject: Web3KeyObject;\n  #passphraseEntry: PassphraseEntry;\n  #options: Partial<Web3AccountOptions>;\n\n  constructor(\n    keyObject: Web3KeyObject,\n    passphraseEntry: PassphraseEntry,\n    options: Partial<Web3AccountOptions> = {},\n  ) {\n    this.#keyObject = keyObject;\n    this.#passphraseEntry = passphraseEntry;\n    this.#options = options;\n  }\n\n  async #exportPrivateKey(\n    options: Partial<Web3AccountOptions> = {},\n  ): Promise<RawPrivateKey> {\n    let firstAttempt = true;\n    let privateKey: RawPrivateKey;\n    while (true) {\n      const passphrase = await this.#passphraseEntry.authenticate(\n        this.#keyObject.id,\n        firstAttempt,\n      );\n      try {\n        const result = await decryptKeyObject(this.#keyObject, passphrase, {\n          ...this.#options,\n          ...options,\n        });\n        privateKey = result.privateKey;\n      } catch (e) {\n        if (e instanceof IncorrectPassphraseError) {\n          firstAttempt = false;\n          continue;\n        }\n        throw e;\n      }\n      break;\n    }\n    return privateKey;\n  }\n\n  exportPrivateKey(): Promise<RawPrivateKey> {\n    return this.#exportPrivateKey({ allowWeakPrivateKey: true });\n  }\n\n  getAddress(): Promise<Address> {\n    return Promise.resolve(Address.fromHex(this.#keyObject.address, true));\n  }\n\n  async getPublicKey(): Promise<PublicKey> {\n    const key = await this.#exportPrivateKey({ allowWeakPrivateKey: true });\n    return await key.getPublicKey();\n  }\n\n  async sign(message: Uint8Array): Promise<Signature> {\n    const key = await this.#exportPrivateKey();\n    return await key.sign(message);\n  }\n}\n\nfunction toHex(bytes: Uint8Array | ArrayBuffer): string {\n  const array = bytes instanceof Uint8Array ? bytes : new Uint8Array(bytes);\n  let hex = \"\";\n  for (let i = 0; i < array.length; i++) {\n    hex += array[i].toString(16).padStart(2, \"0\");\n  }\n  return hex;\n}\n\nexport async function encryptKeyObject(\n  keyId: KeyId,\n  privateKey: RawPrivateKey,\n  passphrase: Passphrase,\n): Promise<Web3KeyObject> {\n  if (!isKeyId(keyId)) {\n    throw new Error(`Invalid key ID: ${keyId}`);\n  }\n\n  const salt = new Uint8Array(32);\n  crypto.getRandomValues(salt);\n  const kdf: Web3KeyObjectKdf = {\n    kdf: \"pbkdf2\",\n    kdfparams: {\n      c: 10240,\n      dklen: 32,\n      prf: \"hmac-sha256\",\n      salt: toHex(salt),\n    },\n  };\n  const derivedKey = await deriveKey(kdf, passphrase);\n  const cipher = await encipher({\n    derivedKey,\n    privateKey: privateKey.toBytes(),\n  });\n  const address = await Address.deriveFrom(privateKey);\n\n  return {\n    version: 3,\n    id: keyId,\n    address: address.toHex(\"lower\"),\n    crypto: { ...cipher, ...kdf },\n  };\n}\n\nexport function isKeyObject(json: unknown): json is Web3KeyObject {\n  if (\n    typeof json !== \"object\" ||\n    json == null ||\n    !(\"version\" in json) ||\n    json.version !== 3 ||\n    !(\"id\" in json) ||\n    typeof json.id !== \"string\" ||\n    !isKeyId(json.id) ||\n    !(\"address\" in json) ||\n    typeof json.address !== \"string\"\n  ) {\n    return false;\n  }\n\n  try {\n    Address.fromHex(json.address, true);\n  } catch (e) {\n    return false;\n  }\n\n  return (\n    \"crypto\" in json &&\n    typeof json.crypto === \"object\" &&\n    isKeyObjectCipher(json.crypto) &&\n    isKeyObjectKdf(json.crypto)\n  );\n}\n\nfunction isKeyObjectCipher(json: unknown): json is Web3KeyObjectCipher {\n  return (\n    typeof json === \"object\" &&\n    json != null &&\n    \"cipher\" in json &&\n    json.cipher === \"aes-128-ctr\" &&\n    \"cipherparams\" in json &&\n    typeof json.cipherparams === \"object\" &&\n    json.cipherparams != null &&\n    \"iv\" in json.cipherparams &&\n    typeof json.cipherparams.iv === \"string\" &&\n    \"ciphertext\" in json &&\n    typeof json.ciphertext === \"string\" &&\n    \"mac\" in json &&\n    typeof json.mac === \"string\"\n  );\n}\n\nfunction isKeyObjectKdf(json: unknown): json is Web3KeyObjectKdf {\n  if (typeof json !== \"object\" || json == null || !(\"kdf\" in json)) {\n    return false;\n  }\n\n  switch (json.kdf) {\n    case \"pbkdf2\":\n      return (\n        \"kdfparams\" in json &&\n        typeof json.kdfparams === \"object\" &&\n        json.kdfparams != null &&\n        \"c\" in json.kdfparams &&\n        typeof json.kdfparams.c === \"number\" &&\n        \"dklen\" in json.kdfparams &&\n        typeof json.kdfparams.dklen === \"number\" &&\n        \"prf\" in json.kdfparams &&\n        json.kdfparams.prf === \"hmac-sha256\" &&\n        \"salt\" in json.kdfparams &&\n        typeof json.kdfparams.salt === \"string\"\n      );\n\n    case \"scrypt\":\n      return (\n        \"kdfparams\" in json &&\n        typeof json.kdfparams === \"object\" &&\n        json.kdfparams != null &&\n        \"dklen\" in json.kdfparams &&\n        typeof json.kdfparams.dklen === \"number\" &&\n        \"n\" in json.kdfparams &&\n        typeof json.kdfparams.n === \"number\" &&\n        \"p\" in json.kdfparams &&\n        typeof json.kdfparams.p === \"number\" &&\n        \"r\" in json.kdfparams &&\n        typeof json.kdfparams.r === \"number\" &&\n        \"salt\" in json.kdfparams &&\n        typeof json.kdfparams.salt === \"string\"\n      );\n\n    default:\n      return false;\n  }\n}\n\nexport interface Web3AccountOptions {\n  /**\n   * Whether to allow weak private keys (i.e. private keys with leading zeros).\n   */\n  readonly allowWeakPrivateKey: boolean;\n}\n\nexport class WeakPrivateKeyError extends Error {\n  readonly name = \"WeakPrivateKeyError\";\n}\n\nexport async function decryptKeyObject(\n  keyObject: Web3KeyObject,\n  passphrase: Passphrase,\n  options: Partial<Web3AccountOptions> = {},\n): Promise<{ keyId: KeyId; privateKey: RawPrivateKey }> {\n  if (keyObject == null) {\n    throw new Error(\"Key object is null.\");\n  } else if (keyObject.version !== 3) {\n    throw new Error(`Unsupported key object version: ${keyObject?.version}`);\n  } else if (keyObject.crypto == null) {\n    throw new Error(\"Key object does not have crypto field.\");\n  }\n\n  const keyObjectAddress = Address.fromHex(keyObject.address, true);\n  const derivedKey = await deriveKey(keyObject.crypto, passphrase);\n  let privateKeyBytes = await decipher(keyObject.crypto, derivedKey);\n  if (privateKeyBytes.length < 32) {\n    const zeroPadded = new Uint8Array(32);\n    zeroPadded.set(privateKeyBytes, 32 - privateKeyBytes.length);\n    privateKeyBytes = zeroPadded;\n  }\n  if (privateKeyBytes.at(0) === 0x00 && !options.allowWeakPrivateKey) {\n    throw new WeakPrivateKeyError(\n      \"The private key given is too weak; keys of length less than 32 bytes \" +\n        \"are disallowed by default.  See also \" +\n        \"the Web3AccountOptions.allowWeakPrivateKey option.\",\n    );\n  }\n  const privateKey = RawPrivateKey.fromBytes(privateKeyBytes);\n  const address = await Address.deriveFrom(privateKey);\n  if (!keyObjectAddress.equals(address)) {\n    throw new Error(\n      `Failed to decrypt the key object; expected account ${keyObjectAddress} but got ${address} instead.`,\n    );\n  }\n  return { keyId: keyObject.id, privateKey };\n}\n\nasync function deriveKey(\n  kdf: Web3KeyObjectKdf,\n  passphrase: Passphrase,\n): Promise<Uint8Array> {\n  if (kdf.kdf === \"pbkdf2\") {\n    const { c, dklen, prf, salt } = kdf.kdfparams;\n    if (dklen < 16) throw new Error(`Too short dklen: ${dklen}`);\n    if (prf !== \"hmac-sha256\") throw new Error(`Unsupported prf: ${prf}`);\n    const derivedKey = await pbkdf2Async(\n      sha256,\n      passphrase,\n      Buffer.from(salt, \"hex\"),\n      {\n        c,\n        dkLen: dklen,\n      },\n    );\n    if (derivedKey.length < dklen) {\n      throw new Error(`Key too short: ${toHex(derivedKey)}`);\n    }\n    return derivedKey;\n  } else if (kdf.kdf === \"scrypt\") {\n    const { dklen, n, p, r, salt } = kdf.kdfparams;\n    const derivedKey = await scryptAsync(passphrase, salt, { N: n, r, p, dkLen: dklen});\n    if (derivedKey.length < dklen) {\n      throw new Error(`Key too short: ${toHex(derivedKey)}`);\n    }\n    return derivedKey;\n  }\n\n  throw new Error(`Unsupported kdf: ${kdf[\"kdf\"]}`);\n}\n\nexport class IncorrectPassphraseError extends Error {\n  readonly name = \"IncorrectPassphraseError\";\n\n  constructor(\n    readonly expectedMac: Uint8Array,\n    readonly actualMac: Uint8Array,\n  ) {\n    super(`Expected: ${toHex(expectedMac)}, Actual: ${toHex(actualMac)}`);\n  }\n}\n\nasync function encipher({\n  derivedKey,\n  privateKey,\n}: {\n  derivedKey: Uint8Array;\n  privateKey: Uint8Array;\n}): Promise<Web3KeyObjectCipher> {\n  const iv = new Uint8Array(16);\n  crypto.getRandomValues(iv);\n  const ciphertext = await crypto.subtle.encrypt(\n    {\n      name: \"AES-CTR\",\n      counter: iv,\n      length: 128,\n    },\n    await crypto.subtle.importKey(\n      \"raw\",\n      derivedKey.subarray(0, 16),\n      { name: \"AES-CTR\" },\n      false,\n      [\"encrypt\"],\n    ),\n    privateKey,\n  );\n  return {\n    cipher: \"aes-128-ctr\",\n    cipherparams: { iv: toHex(iv) },\n    ciphertext: toHex(ciphertext),\n    mac: toHex(calculateMac(derivedKey, ciphertext)),\n  };\n}\n\nasync function decipher(\n  cipher: Web3KeyObjectCipher,\n  derivedKey: Uint8Array,\n): Promise<Uint8Array> {\n  if (cipher.cipher !== \"aes-128-ctr\") {\n    throw new Error(`Unsupported cipher: ${cipher.cipher}`);\n  }\n\n  const ciphertext = new Uint8Array(Buffer.from(cipher.ciphertext, \"hex\"));\n  const mac = calculateMac(derivedKey, ciphertext);\n  const expectedMac = new Uint8Array(Buffer.from(cipher.mac, \"hex\"));\n  if (!mac.every((v, i) => v === expectedMac[i])) {\n    throw new IncorrectPassphraseError(expectedMac, mac);\n  }\n  const decrypted = await crypto.subtle.decrypt(\n    {\n      name: \"AES-CTR\",\n      counter: new Uint8Array(Buffer.from(cipher.cipherparams.iv, \"hex\")),\n      length: 128,\n    },\n    await crypto.subtle.importKey(\n      \"raw\",\n      derivedKey.subarray(0, 16),\n      { name: \"AES-CTR\" },\n      false,\n      [\"decrypt\"],\n    ),\n    ciphertext,\n  );\n  // FIXME: This is a workaround for a bug in @peculiar/webcrypto.\n  return decrypted instanceof Uint8Array\n    ? decrypted\n    : new Uint8Array(decrypted);\n}\n\nfunction calculateMac(\n  derivedKey: Uint8Array,\n  ciphertext: Uint8Array | ArrayBuffer,\n): Uint8Array {\n  const keySubBytes = 16;\n  const ciphertextBytes =\n    ciphertext instanceof Uint8Array ? ciphertext : new Uint8Array(ciphertext);\n  const seal = new Uint8Array(keySubBytes + ciphertextBytes.length);\n  if (derivedKey.length < keySubBytes) {\n    throw new Error(\n      `Too short derived key (${derivedKey.length} < ${keySubBytes}): ${toHex(\n        derivedKey,\n      )}`,\n    );\n  }\n  seal.set(derivedKey.subarray(derivedKey.length - keySubBytes));\n  seal.set(ciphertextBytes, keySubBytes);\n  const mac = keccak_256(seal);\n  return mac;\n}\n"
  },
  {
    "path": "@planetarium/account-web3-secret-storage/src/Web3KeyStore.ts",
    "content": "import { generateKeyId, KeyId } from \"./KeyId.js\";\nimport { PassphraseEntry } from \"./PassphraseEntry.js\";\nimport {\n  encryptKeyObject,\n  isKeyObject,\n  type Web3AccountOptions,\n  Web3Account,\n  Web3KeyObject,\n} from \"./Web3Account.js\";\nimport {\n  type AccountDeletion,\n  type AccountGeneration,\n  type AccountImportation,\n  type AccountMetadata,\n  type AccountRetrieval,\n  Address,\n  type ImportableKeyStore,\n  RawPrivateKey,\n} from \"@planetarium/account\";\nimport { join, getDefaultWeb3KeyStorePath } from \"#path\";\nexport { getDefaultWeb3KeyStorePath } from \"#path\";\nimport * as fs from \"#fs\";\n\nexport interface Web3KeyStoreOptions {\n  path?: string;\n  passphraseEntry: PassphraseEntry;\n}\n\nconst pattern =\n  /^(?:UTC--([0-9]{4}-[0-9]{2}-[0-9]{2})T([0-9]{2}-[0-9]{2}-[0-9]{2})Z--)?([0-9a-f]{8}-(?:[0-9a-f]{4}-){3}[0-9a-f]{12})(?:.json)?$$/i;\nexport function parseKeyFilename(\n  name: string,\n): undefined | { keyId: KeyId; createdAt?: Date } {\n  const match = pattern.exec(name);\n  if (match == null) return undefined;\n  return {\n    keyId: match[3].toLowerCase(),\n    createdAt:\n      match[1] != null && match[2] != null\n        ? new Date(`${match[1]}T${match[2].replace(/-/g, \":\")}Z`)\n        : undefined,\n  };\n}\n\nexport interface Web3KeyMetadata {\n  address?: Address;\n}\n\nexport class Web3KeyStore\n  implements ImportableKeyStore<KeyId, Web3Account, Web3KeyMetadata>\n{\n  readonly #passphraseEntry: PassphraseEntry;\n  readonly #accountOptions: Partial<Web3AccountOptions>;\n\n  readonly path: string;\n\n  constructor(options: Web3KeyStoreOptions & Partial<Web3AccountOptions>) {\n    this.path = options.path ?? getDefaultWeb3KeyStorePath();\n    this.#passphraseEntry = options.passphraseEntry;\n    this.#accountOptions = options;\n  }\n\n  async *#listKeyFiles(): AsyncIterable<string> {\n    for await (const name of fs.listFiles(this.path)) {\n      yield name;\n    }\n  }\n\n  async #getKeyPath(\n    keyId: KeyId,\n  ): Promise<{ path: string; keyId: string; createdAt?: Date } | undefined> {\n    for await (const name of this.#listKeyFiles()) {\n      const parsed = parseKeyFilename(name);\n      if (parsed != null && parsed.keyId === keyId) {\n        return { ...parsed, path: join(this.path, name) };\n      }\n    }\n    return undefined;\n  }\n\n  async *list(): AsyncIterable<AccountMetadata<KeyId, Web3KeyMetadata>> {\n    for await (const name of this.#listKeyFiles()) {\n      const parsed = parseKeyFilename(name);\n      if (parsed == null) continue;\n      const keyPath = join(this.path, name);\n      let json: unknown;\n      try {\n        json = JSON.parse(await fs.readFile(keyPath, { encoding: \"utf8\" }));\n      } catch (_) {\n        continue;\n      }\n      if (!isKeyObject(json)) continue;\n      let address: Address;\n      try {\n        address = Address.fromHex(json.address, true);\n      } catch (_) {\n        continue;\n      }\n      const metadata: Web3KeyMetadata = { address };\n      yield { ...parsed, metadata };\n    }\n  }\n\n  async get(\n    keyId: Readonly<KeyId>,\n  ): Promise<AccountRetrieval<KeyId, Web3Account, Web3KeyMetadata>> {\n    const keyPath = await this.#getKeyPath(keyId);\n    if (keyPath == null) return { result: \"keyNotFound\", keyId };\n    let json;\n    try {\n      json = await fs.readFile(keyPath.path, {\n        encoding: \"utf8\",\n      });\n    } catch (e) {\n      if (\n        e != null &&\n        typeof e === \"object\" &&\n        \"code\" in e &&\n        e.code === \"ENOENT\"\n      ) {\n        return { result: \"keyNotFound\", keyId };\n      }\n      return { result: \"error\", keyId, message: `${e}` };\n    }\n    const keyObject: unknown = JSON.parse(json);\n    if (!isKeyObject(keyObject)) {\n      return { result: \"error\", keyId, message: \"Invalid key file\" };\n    }\n    const account = new Web3Account(\n      keyObject,\n      this.#passphraseEntry,\n      this.#accountOptions,\n    );\n    return {\n      result: \"success\",\n      account,\n      keyId,\n      metadata: { address: await account.getAddress() },\n      createdAt: keyPath.createdAt,\n    };\n  }\n\n  async generate(\n    metadata?: Partial<Web3KeyMetadata>,\n  ): Promise<AccountGeneration<KeyId, Web3Account>> {\n    if (metadata?.address != null) {\n      return {\n        result: \"error\",\n        message: \"Address cannot be predetermined before generating key\",\n      };\n    }\n    const privateKey = await RawPrivateKey.generate();\n    const result = await this.#import(privateKey, metadata);\n    if (result.result === \"success\") {\n      return {\n        result: \"success\",\n        keyId: result.keyId,\n        account: new Web3Account(result.keyObject, this.#passphraseEntry),\n      };\n    }\n    return result;\n  }\n\n  async delete(keyId: Readonly<KeyId>): Promise<AccountDeletion<KeyId>> {\n    const keyPath = await this.#getKeyPath(keyId);\n    if (keyPath == null) return { result: \"keyNotFound\", keyId };\n    try {\n      await fs.removeFile(keyPath.path);\n    } catch (e) {\n      return { result: \"error\", message: `${e}` };\n    }\n    return { result: \"success\", keyId };\n  }\n\n  async #import(\n    privateKey: RawPrivateKey,\n    metadata?: Partial<Web3KeyMetadata>,\n  ): Promise<\n    | {\n        readonly result: \"success\";\n        readonly keyId: KeyId;\n        readonly keyObject: Web3KeyObject;\n      }\n    | {\n        readonly result: \"error\";\n        readonly message?: string;\n      }\n  > {\n    if (\n      metadata?.address != null &&\n      !metadata.address.equals(await Address.deriveFrom(privateKey))\n    ) {\n      return {\n        result: \"error\",\n        message:\n          \"Address does not match the private key \" +\n          \"(hint: you do not have to specify it manually)\",\n      };\n    }\n    const passphrase = await this.#passphraseEntry.configurePassphrase();\n    const keyId = generateKeyId();\n    const keyObject = await encryptKeyObject(keyId, privateKey, passphrase);\n    try {\n      await fs.mkdir(this.path, { recursive: true });\n    } catch (e) {\n      return { result: \"error\", message: `${e}` };\n    }\n    const createdAt = new Date();\n    const keyPath = join(\n      this.path,\n      `UTC--${createdAt\n        .toISOString()\n        .replace(/\\.[0-9]+Z$/, \"Z\")\n        .replace(/:/g, \"-\")}--${keyId}`,\n    );\n    try {\n      await fs.writeFile(keyPath, JSON.stringify(keyObject), \"utf8\");\n    } catch (e) {\n      return { result: \"error\", message: `${e}` };\n    }\n    return { result: \"success\", keyId, keyObject };\n  }\n\n  async import(\n    privateKey: RawPrivateKey,\n    metadata?: Partial<Web3KeyMetadata>,\n  ): Promise<AccountImportation<KeyId>> {\n    const bytes = await privateKey.toBytes();\n    if (bytes.at(0) === 0x00 && !this.#accountOptions.allowWeakPrivateKey) {\n      return {\n        result: \"error\",\n        message:\n          \"The private key given is too weak; keys of length less than 32 bytes \" +\n          \"are disallowed by default.  See also \" +\n          \"the Web3AccountOptions.allowWeakPrivateKey option.\",\n      };\n    }\n\n    const result = await this.#import(privateKey, metadata);\n    if (result.result === \"success\") {\n      return { result: \"success\", keyId: result.keyId };\n    }\n    return result;\n  }\n}\n\nexport default Web3KeyStore;\n"
  },
  {
    "path": "@planetarium/account-web3-secret-storage/src/crypto/browser.ts",
    "content": "export const crypto = window.crypto;\n"
  },
  {
    "path": "@planetarium/account-web3-secret-storage/src/crypto/node.ts",
    "content": "import { Crypto } from \"@peculiar/webcrypto\";\nexport const crypto = new Crypto();\n"
  },
  {
    "path": "@planetarium/account-web3-secret-storage/src/fs/browser.ts",
    "content": "const PREFIX = \"PLANETARIUM_EMULATED_FS_\" as const;\n\nfunction prefixed(str: string): string {\n  return PREFIX + str;\n}\n\nexport async function mkdir(path: string, options?: unknown): Promise<void> {}\n\nexport async function readFile(\n  path: string,\n  options?: { encoding: \"utf8\" },\n): Promise<string> {\n  const item = localStorage.getItem(prefixed(path));\n  if (item == null) {\n    throw new Error(\"Not found\");\n  }\n\n  return item;\n}\n\nexport async function removeFile(path: string): Promise<void> {\n  localStorage.removeItem(prefixed(path));\n}\n\n// TODO: Implement with performant structure.\nexport async function* listFiles(directory: string): AsyncIterable<string> {\n  for (let i = 0; i < localStorage.length; ++i) {\n    const item = localStorage.key(i);\n    if (item == null) {\n      throw new Error(`Expected ${i}th item in localStorage.`);\n    }\n\n    if (item.startsWith(prefixed(directory))) {\n      let sliced = item.slice(prefixed(directory).length);\n      if (sliced.startsWith(\"/\")) {\n        sliced = sliced.slice(1);\n      }\n\n      yield sliced;\n    }\n  }\n}\n\nexport async function writeFile(\n  path: string,\n  content: string,\n  encoding?: \"utf8\",\n): Promise<void> {\n  localStorage.setItem(prefixed(path), content);\n}\n"
  },
  {
    "path": "@planetarium/account-web3-secret-storage/src/fs/node.ts",
    "content": "import * as fs from \"node:fs/promises\";\n\nexport async function mkdir(\n  path: string,\n  options?: { recursive: true },\n): Promise<void> {\n  await fs.mkdir(path, options);\n}\n\nexport function readFile(\n  path: string,\n  options?: { encoding: \"utf8\" },\n): Promise<string> {\n  return fs.readFile(path, options) as Promise<string>;\n}\n\nexport function removeFile(path: string): Promise<void> {\n  return fs.unlink(path);\n}\n\nexport async function* listFiles(directory: string): AsyncIterable<string> {\n  let dir;\n  try {\n    dir = await fs.opendir(directory);\n  } catch (e) {\n    if (\n      typeof e === \"object\" &&\n      e != null &&\n      \"code\" in e &&\n      e.code === \"ENOENT\"\n    ) {\n      // In case where there is no directory at all (it's likely the first\n      // time to run this operation in a system), it should be considered\n      // it's just empty (instead of considering it an exceptional case).\n      return;\n    }\n    throw e;\n  }\n  for await (const dirEntry of dir) {\n    if (!dirEntry.isFile()) continue;\n    yield dirEntry.name;\n  }\n}\n\nexport function writeFile(\n  path: string,\n  content: string,\n  encoding?: \"utf8\",\n): Promise<void> {\n  return fs.writeFile(path, content, encoding);\n}\n"
  },
  {
    "path": "@planetarium/account-web3-secret-storage/src/index.ts",
    "content": "export { KeyId } from \"./KeyId.js\";\nexport { PassphraseEntry } from \"./PassphraseEntry.js\";\nexport { TtyPassphraseEntry } from \"./TtyPassphraseEntry.js\";\nexport {\n  type Web3AccountOptions as DecryptionOptions,\n  WeakPrivateKeyError,\n  Web3Account,\n  type Web3KeyObject,\n} from \"./Web3Account.js\";\nexport {\n  getDefaultWeb3KeyStorePath,\n  Web3KeyStore,\n} from \"./Web3KeyStore.js\";\n"
  },
  {
    "path": "@planetarium/account-web3-secret-storage/src/path/browser.ts",
    "content": "export function join(...args: string[]): string {\n  if (args.length === 0) {\n    return \".\";\n  }\n\n  if (args.length === 1) {\n    return args[0];\n  }\n\n  const lastElement = args.at(-1);\n  if (args.length > 1 && lastElement !== undefined) {\n    return [\n      trimSlashEnd(args[0]),\n      ...args.slice(1, -1).map((x) => trimSlashStart(trimSlashEnd(x))),\n      trimSlashStart(lastElement),\n    ].join(\"/\");\n  }\n\n  throw new Error(\"All cases are covered.\");\n}\n\nfunction trimSlashEnd(s: string): string {\n  let ret = s;\n  while (ret.length > 0 && ret.at(-1) === \"/\") {\n    ret = ret.slice(0, -1);\n  }\n\n  return ret;\n}\n\nfunction trimSlashStart(s: string): string {\n  let ret = s;\n  while (ret.length > 0 && ret.at(0) === \"/\") {\n    ret = ret.slice(1);\n  }\n\n  return ret;\n}\n\nexport function getDefaultWeb3KeyStorePath(): string {\n  return \"/planetarium/account/web3-secret-storage/keystore\";\n}\n"
  },
  {
    "path": "@planetarium/account-web3-secret-storage/src/path/node.ts",
    "content": "export { join } from \"node:path\";\n\n/**\n * Determines the default key store path.  It depends on the platform:\n *\n * - Linux/macOS: `$HOME/.config/planetarium/keystore`\n * - Windows: `%AppData%\\planetarium\\keystore`\n */\nexport function getDefaultWeb3KeyStorePath(): string {\n  const { homedir } = require(\"node:os\");\n  const path = require(\"node:path\");\n  const baseDir =\n    process.platform === \"win32\"\n      ? process.env.AppData || path.join(homedir(), \"AppData\", \"Roaming\")\n      : process.env.XDG_CONFIG_HOME || path.join(homedir(), \".config\");\n  // Note that it's not necessary to explicitly choose one of `path.win32` or\n  // `path.posix` here, but it makes unit tests less dependent on mocks:\n  return (process.platform === \"win32\" ? path.win32 : path.posix).join(\n    baseDir,\n    \"planetarium\",\n    \"keystore\",\n  );\n}\n"
  },
  {
    "path": "@planetarium/account-web3-secret-storage/test/KeyId.test.ts",
    "content": "import { isKeyId } from \"../src/KeyId\";\nimport { expect, test } from \"vitest\";\n\ntest(\"isKeyId()\", () => {\n  expect(isKeyId(\"asdf\")).toBeFalsy();\n  expect(isKeyId(\"B9378E01-BF38-469B-AC6F-B40F01762A5\")).toBeFalsy();\n  expect(isKeyId(\"B9378E01-BF38-469B-AC6F-B40F01762A5Z\")).toBeFalsy();\n  expect(isKeyId(\"B9378E01-BF38-469B-AC6F-B40F01762A51\")).toBeTruthy();\n  expect(isKeyId(\"b9378e01-bf38-469b-ac6f-b40f01762a51\")).toBeTruthy();\n});\n"
  },
  {
    "path": "@planetarium/account-web3-secret-storage/test/MockPassphraseEntry.ts",
    "content": "import { KeyId } from \"../src/KeyId\";\nimport { Passphrase, PassphraseEntry } from \"../src/PassphraseEntry\";\n\nexport class MockPassphraseEntry implements PassphraseEntry {\n  rightPassphrase: Passphrase;\n  authenticateCalls: { keyId: KeyId; firstAttempt: boolean }[] = [];\n  configurePassphraseCalls: number = 0;\n  temporaryAuthenticateResult: { passphrase: Passphrase; times: number } = {\n    passphrase: \"passphrase\",\n    times: 0,\n  };\n\n  constructor(rightPassphrase: Passphrase = \"passphrase\") {\n    this.rightPassphrase = rightPassphrase;\n  }\n\n  setTemporaryAuthenticateResult(passphrase: Passphrase, times: number) {\n    this.temporaryAuthenticateResult = { passphrase, times };\n  }\n\n  async authenticate(keyId: KeyId, firstAttempt: boolean): Promise<Passphrase> {\n    this.authenticateCalls.push({ keyId, firstAttempt });\n    if (this.temporaryAuthenticateResult.times > 0) {\n      this.temporaryAuthenticateResult.times--;\n      return this.temporaryAuthenticateResult.passphrase;\n    }\n    if (this.authenticateCalls.length > 10) {\n      throw new Error(\"Failed to authenticate too many times; probably a bug\");\n    }\n    return this.rightPassphrase;\n  }\n\n  async configurePassphrase(): Promise<Passphrase> {\n    this.configurePassphraseCalls++;\n    return this.rightPassphrase;\n  }\n}\n"
  },
  {
    "path": "@planetarium/account-web3-secret-storage/test/TtyPassphraseEntry.test.ts",
    "content": "import { Passphrase } from \"../src/PassphraseEntry\";\nimport { TtyPassphraseEntry, readPassphrase } from \"../src/TtyPassphraseEntry\";\nimport { setTimeout } from \"node:timers/promises\";\nimport { ReadableStreamBuffer, WritableStreamBuffer } from \"stream-buffers\";\nimport { describe, expect, test } from \"vitest\";\n\nasync function waitUntilRead(\n  input: ReadableStreamBuffer,\n  dataToWrite: Buffer | string,\n): Promise<void> {\n  const data =\n    typeof dataToWrite === \"string\"\n      ? Buffer.from(dataToWrite, \"utf8\")\n      : dataToWrite;\n  await setTimeout(0); // mimics I/O interrupt\n  input.put(dataToWrite);\n  return await new Promise((resolve) => {\n    input.on(\"data\", (chunk: Buffer) => {\n      if (chunk.equals(data)) resolve();\n    });\n  });\n}\n\ndescribe(\"readPassphrase\", () => {\n  test(\"mask: '*'\", async () => {\n    const input = new ReadableStreamBuffer();\n    const output = new WritableStreamBuffer();\n\n    let result: Passphrase | undefined;\n    const awaitable = readPassphrase(\"Prompt: \", {\n      mask: \"*\",\n      input,\n      output,\n    }).then((passphrase) => {\n      result = passphrase;\n      return passphrase;\n    });\n    await setTimeout(100);\n    expect(result).toBeUndefined();\n    expect(output.getContentsAsString(\"utf8\")).toContain(\"Prompt: \");\n\n    await waitUntilRead(input, \"passphrase\");\n    expect(result).toBeUndefined();\n    expect(output.getContentsAsString(\"utf8\")).toContain(\"*********\");\n\n    await waitUntilRead(input, \"\\n\");\n    expect(await awaitable).toBe(\"passphrase\");\n    expect(result).toBe(\"passphrase\");\n    expect(output.getContentsAsString(\"utf8\")).toContain(\"\\n\");\n  });\n\n  test(\"mask: ''\", async () => {\n    const input = new ReadableStreamBuffer();\n    const output = new WritableStreamBuffer();\n\n    let result: Passphrase | undefined;\n    const awaitable = readPassphrase(\"Prompt: \", {\n      mask: \"\",\n      input,\n      output,\n    }).then((passphrase) => {\n      result = passphrase;\n      return passphrase;\n    });\n    await setTimeout(100);\n    expect(result).toBeUndefined();\n    expect(output.getContentsAsString(\"utf8\")).toContain(\"Prompt: \");\n\n    await waitUntilRead(input, \"passphrase\");\n    expect(result).toBeUndefined();\n    expect(output.getContentsAsString(\"utf8\")).toBeFalsy();\n\n    await waitUntilRead(input, \"\\n\");\n    expect(await awaitable).toBe(\"passphrase\");\n    expect(result).toBe(\"passphrase\");\n    expect(output.getContentsAsString(\"utf8\")).toContain(\"\\n\");\n  });\n\n  test(\"mask: false\", async () => {\n    const input = new ReadableStreamBuffer();\n    const output = new WritableStreamBuffer();\n\n    let result: Passphrase | undefined;\n    const awaitable = readPassphrase(\"Prompt: \", {\n      mask: false,\n      input,\n      output,\n    }).then((passphrase) => {\n      result = passphrase;\n      return passphrase;\n    });\n    await setTimeout(100);\n    expect(result).toBeUndefined();\n    expect(output.getContentsAsString(\"utf8\")).toContain(\"Prompt: \");\n\n    await waitUntilRead(input, \"passphrase\");\n    expect(result).toBeUndefined();\n    expect(output.getContentsAsString(\"utf8\")).toContain(\"passphrase\");\n\n    await waitUntilRead(input, \"\\n\");\n    expect(await awaitable).toBe(\"passphrase\");\n    expect(result).toBe(\"passphrase\");\n    expect(output.getContentsAsString(\"utf8\")).toContain(\"\\n\");\n  });\n});\n\ndescribe(\"TtyPassphraseEntry\", () => {\n  test(\"authenticate\", async () => {\n    const input = new ReadableStreamBuffer();\n    const output = new WritableStreamBuffer();\n    const entry = new TtyPassphraseEntry({\n      input,\n      output,\n      mask: \"#\",\n      locale: \"qts-XX\",\n    });\n    const awaitable = entry.authenticate(\n      \"00000000-0000-0000-0000-000000000000\",\n      true,\n    );\n    await waitUntilRead(input, \"wrong\\n\");\n    expect(output.getContentsAsString(\"utf8\")).toMatch(\n      /AUTHENTICATE:00000000-0000-0000-0000-000000000000.*?#####/,\n    );\n    expect(await awaitable).toBe(\"wrong\");\n\n    const awaitable2 = entry.authenticate(\n      \"00000000-0000-0000-0000-000000000000\",\n      false,\n    );\n    await waitUntilRead(input, \"passphrase\\n\");\n    expect(output.getContentsAsString(\"utf8\")).toMatch(\n      /AUTHENTICATE_RETRY:00000000-0000-0000-0000-000000000000.*?##########/,\n    );\n    expect(await awaitable2).toBe(\"passphrase\");\n  });\n\n  test(\"configurePassphrase\", async () => {\n    const input = new ReadableStreamBuffer();\n    const output = new WritableStreamBuffer();\n    const entry = new TtyPassphraseEntry({\n      input,\n      output,\n      mask: \"#\",\n      locale: \"qts-XX\",\n    });\n\n    const awaitable = entry.configurePassphrase();\n    await waitUntilRead(input, \"passphrase\\n\");\n    expect(output.getContentsAsString(\"utf8\")).toMatch(\n      /CONFIGURE_PASSPHRASE.*?##########/,\n    );\n    await waitUntilRead(input, \"unmatched\\n\");\n    expect(output.getContentsAsString(\"utf8\")).toMatch(\n      /CONFIRM_CONFIGURE_PASSPHRASE.*?#########/,\n    );\n    await waitUntilRead(input, \"passphrase\\n\");\n    expect(output.getContentsAsString(\"utf8\")).toMatch(\n      /CONFIGURE_PASSPHRASE_RETRY.*?##########/,\n    );\n    await waitUntilRead(input, \"passphrase\\n\");\n    expect(output.getContentsAsString(\"utf8\")).toMatch(\n      /CONFIRM_CONFIGURE_PASSPHRASE.*?##########/,\n    );\n    expect(await awaitable).toBe(\"passphrase\");\n  });\n});\n"
  },
  {
    "path": "@planetarium/account-web3-secret-storage/test/Web3Account.test.ts",
    "content": "import { PublicKey, RawPrivateKey } from \"@planetarium/account\";\nimport * as fc from \"fast-check\";\nimport * as crypto from \"node:crypto\";\nimport { describe, expect, test } from \"vitest\";\nimport { KeyId } from \"../src/KeyId\";\nimport { Passphrase } from \"../src/PassphraseEntry\";\nimport {\n  Web3AccountOptions,\n  decryptKeyObject,\n  encryptKeyObject,\n  IncorrectPassphraseError,\n  WeakPrivateKeyError,\n  Web3Account,\n  Web3KeyObject,\n} from \"../src/Web3Account\";\nimport { MockPassphraseEntry } from \"./MockPassphraseEntry\";\n\nconst pbkdf2KeyObject: Web3KeyObject = {\n  version: 3,\n  id: \"3c7bec5e-1f1d-4754-a1ce-3644ce1130f1\",\n  address: \"98a253783288c3971cf7960157b8e053bd263da7\",\n  crypto: {\n    ciphertext:\n      \"da63b632d3e48de4099e32e3664741fa60880547ab8740854abb77a8c5183638\",\n    cipherparams: {\n      iv: \"59b8523ebeaa3f37ea06898ff0860340\",\n    },\n    cipher: \"aes-128-ctr\",\n    kdfparams: {\n      c: 10240,\n      dklen: 32,\n      prf: \"hmac-sha256\",\n      salt: \"debd6928cf96f23e3cd5580aebd911c8ea4eb7c29d4db10c251ce8f29c2f32f6\",\n    },\n    kdf: \"pbkdf2\",\n    mac: \"5ea19f4c94faa5c698dbbcdd55390f72dac8b6383b2c1010328dfc9248eac2fc\",\n  },\n};\n\nconst scryptKeyObject: Web3KeyObject = {\n  crypto: {\n    cipher: \"aes-128-ctr\",\n    cipherparams: {\n      iv: \"740770fce12ce862af21264dab25f1da\",\n    },\n    ciphertext:\n      \"dd8a1132cf57db67c038c6763afe2cbe6ea1949a86abc5843f8ca656ebbb1ea2\",\n    kdf: \"scrypt\",\n    kdfparams: {\n      dklen: 32,\n      n: 262144,\n      p: 1,\n      r: 8,\n      salt: \"25710c2ccd7c610b24d068af83b959b7a0e5f40641f0c82daeb1345766191034\",\n    },\n    mac: \"337aeb86505d2d0bb620effe57f18381377d67d76dac1090626aa5cd20886a7c\",\n  },\n  id: \"3198bc9c-6672-5ab3-d995-4942343ae5b6\",\n  address: \"008aeeda4d805471df9b2a5b0f38a0c3bcba786b\",\n  version: 3,\n};\n\nconst insufficientLengthKeyObject: Web3KeyObject = {\n  crypto: {\n    cipher: \"aes-128-ctr\",\n    cipherparams: {\n      iv: \"24ece9686a10f8687dc70ca42873a063\",\n    },\n    ciphertext: \"14\",\n    kdf: \"pbkdf2\",\n    kdfparams: {\n      c: 10240,\n      dklen: 32,\n      prf: \"hmac-sha256\",\n      salt: \"99b480642f6406a10c67429168fb36ba35da7743965e10390eda649ec6da2ae8\",\n    },\n    mac: \"7856d88908c72f0af78457ccd085696ad6193f7d2bda525723862f450ce060fa\",\n  },\n  id: \"b35a2647-8581-43ff-a98e-6083dc952632\",\n  address: \"eb9afe072c781401bf364224c75a036e4d832f52\",\n  version: 3,\n};\n\ninterface TestVector {\n  keyObject: Web3KeyObject;\n  passphrase: Passphrase;\n  privateKey: RawPrivateKey;\n  options?: Partial<Web3AccountOptions>;\n}\n\nconst testVectors: Record<string, TestVector> = {\n  pbkdf: {\n    keyObject: pbkdf2KeyObject,\n    passphrase: \"passphrase\",\n    privateKey: RawPrivateKey.fromHex(\n      \"2af8da24b177f6723d8b99762b416fc3050289b572b8819ebbb0a6b143b1d55d\",\n    ),\n  },\n  scrypt: {\n    keyObject: scryptKeyObject,\n    passphrase: \"testpassword\",\n    privateKey: RawPrivateKey.fromHex(\n      \"7a28b5ba57c53603b0b07b56bba752f7784bf506fa95edc395f5cf6c7514fe9d\",\n    ),\n  },\n  insufficientLength: {\n    keyObject: insufficientLengthKeyObject,\n    passphrase: \"1\",\n    privateKey: RawPrivateKey.fromHex(\n      \"00000000000000000000000000000000000000000000000000000000000000aa\",\n    ),\n    options: {\n      allowWeakPrivateKey: true,\n    },\n  },\n};\n\ndescribe(\"Web3Account\", () => {\n  describe(\"getAddress()\", () => {\n    for (const [kdf, { keyObject, passphrase, options }] of Object.entries(\n      testVectors,\n    )) {\n      test(kdf, async () => {\n        const passphraseEntry = new MockPassphraseEntry(passphrase);\n        const key = new Web3Account(keyObject, passphraseEntry, options);\n        expect((await key.getAddress()).toHex(\"lower\")).toBe(keyObject.address);\n      });\n    }\n  });\n  describe(\"getPublicKey()\", () => {\n    test(\"fastcheck\", async () => {\n      const passphraseEntry = new MockPassphraseEntry();\n      const key = new Web3Account(pbkdf2KeyObject, passphraseEntry);\n\n      expect(passphraseEntry.authenticateCalls).toStrictEqual([]);\n      expect(passphraseEntry.configurePassphraseCalls).toBe(0);\n      const publicKey = await key.getPublicKey();\n      expect(passphraseEntry.authenticateCalls).toStrictEqual([\n        { keyId: \"3c7bec5e-1f1d-4754-a1ce-3644ce1130f1\", firstAttempt: true },\n      ]);\n      expect(passphraseEntry.configurePassphraseCalls).toBe(0);\n\n      expect(publicKey).toBeInstanceOf(PublicKey);\n      expect(publicKey.toHex(\"compressed\")).toStrictEqual(\n        \"03dfd25cea92d828d5c3b2836ffe5a843854285027b9de2dcca0920c0ff0beb5c4\",\n      );\n    });\n\n    for (const [\n      kdf,\n      { keyObject, passphrase, privateKey, options },\n    ] of Object.entries(testVectors)) {\n      test(kdf, async () => {\n        const passphraseEntry = new MockPassphraseEntry(passphrase);\n        const key = new Web3Account(keyObject, passphraseEntry, options);\n\n        expect(passphraseEntry.authenticateCalls).toStrictEqual([]);\n        expect(passphraseEntry.configurePassphraseCalls).toBe(0);\n        const publicKey = await key.getPublicKey();\n        expect(passphraseEntry.authenticateCalls).toStrictEqual([\n          { keyId: keyObject.id, firstAttempt: true },\n        ]);\n        expect(passphraseEntry.configurePassphraseCalls).toBe(0);\n\n        expect(publicKey).toBeInstanceOf(PublicKey);\n        expect(publicKey.toHex(\"compressed\")).toStrictEqual(\n          await (await privateKey.getPublicKey()).toHex(\"compressed\"),\n        );\n\n        if (options?.allowWeakPrivateKey) {\n          const keyWithStricterOptions = new Web3Account(\n            keyObject,\n            passphraseEntry,\n            {\n              allowWeakPrivateKey: false,\n            },\n          );\n          const publicKey2 = await key.getPublicKey();\n          expect(publicKey2).toBeInstanceOf(PublicKey);\n          expect(publicKey2.toHex(\"compressed\")).toStrictEqual(\n            await (await privateKey.getPublicKey()).toHex(\"compressed\"),\n          );\n        }\n      });\n    }\n  });\n\n  describe(\"sign()\", () => {\n    test(\"fastcheck\", async () => {\n      const pubKey = PublicKey.fromHex(\n        \"03dfd25cea92d828d5c3b2836ffe5a843854285027b9de2dcca0920c0ff0beb5c4\",\n        \"compressed\",\n      );\n      await fc.assert(\n        fc.asyncProperty(fc.uint8Array(), async (msg: Uint8Array) => {\n          const passphraseEntry = new MockPassphraseEntry();\n          const key = new Web3Account(pbkdf2KeyObject, passphraseEntry);\n          const sig = await key.sign(msg);\n          expect(passphraseEntry.authenticateCalls).toStrictEqual([\n            {\n              keyId: \"3c7bec5e-1f1d-4754-a1ce-3644ce1130f1\",\n              firstAttempt: true,\n            },\n          ]);\n          expect(passphraseEntry.configurePassphraseCalls).toBe(0);\n          return await pubKey.verify(msg, sig);\n        }),\n      );\n    });\n\n    for (const [\n      kdf,\n      { keyObject, passphrase, privateKey, options },\n    ] of Object.entries(testVectors)) {\n      const msg = new Uint8Array(128);\n      crypto.getRandomValues(msg);\n\n      test(kdf, async () => {\n        const passphraseEntry = new MockPassphraseEntry(passphrase);\n        const key = new Web3Account(keyObject, passphraseEntry, options);\n\n        expect(passphraseEntry.authenticateCalls).toStrictEqual([]);\n        expect(passphraseEntry.configurePassphraseCalls).toBe(0);\n        const sig = await key.sign(msg);\n        expect(passphraseEntry.authenticateCalls).toStrictEqual([\n          { keyId: keyObject.id, firstAttempt: true },\n        ]);\n        expect(passphraseEntry.configurePassphraseCalls).toBe(0);\n\n        const publicKey = await privateKey.getPublicKey();\n        expect(publicKey.verify(msg, sig)).toBeTruthy();\n\n        if (options?.allowWeakPrivateKey) {\n          const keyWithStricterOptions = new Web3Account(\n            keyObject,\n            passphraseEntry,\n            {\n              allowWeakPrivateKey: false,\n            },\n          );\n          expect(keyWithStricterOptions.sign(msg)).rejects.toThrowError(\n            WeakPrivateKeyError,\n          );\n        }\n      });\n    }\n  });\n\n  describe(\"exportPrivateKey()\", () => {\n    for (const [\n      kdf,\n      { keyObject, passphrase, privateKey, options },\n    ] of Object.entries(testVectors)) {\n      test(kdf, async () => {\n        const passphraseEntry = new MockPassphraseEntry(passphrase);\n        const key = new Web3Account(keyObject, passphraseEntry, options);\n\n        expect(passphraseEntry.authenticateCalls).toStrictEqual([]);\n        expect(passphraseEntry.configurePassphraseCalls).toBe(0);\n        const exported = await key.exportPrivateKey();\n        expect(passphraseEntry.authenticateCalls).toStrictEqual([\n          { keyId: keyObject.id, firstAttempt: true },\n        ]);\n        expect(passphraseEntry.configurePassphraseCalls).toBe(0);\n\n        expect(exported).toBeInstanceOf(RawPrivateKey);\n        expect(exported.toBytes()).toStrictEqual(privateKey.toBytes());\n\n        if (options?.allowWeakPrivateKey) {\n          const keyWithStricterOptions = new Web3Account(\n            keyObject,\n            passphraseEntry,\n            {\n              allowWeakPrivateKey: false,\n            },\n          );\n          const exported2 = await keyWithStricterOptions.exportPrivateKey();\n          expect(exported2.toBytes()).toStrictEqual(privateKey.toBytes());\n        }\n      });\n    }\n  });\n});\n\ntest(\"encryptKeyObject()\", async () => {\n  const privateKey = RawPrivateKey.fromHex(\n    \"b56fe718d3f29d5f111d3e975abe0ac57595f1717183793540a8065dd5ba34fd\",\n  );\n  await fc.assert(\n    fc.asyncProperty(\n      fc.uuid(),\n      fc.uint8Array(),\n      async (keyId: KeyId, passphrase: Passphrase) => {\n        const keyObject = await encryptKeyObject(keyId, privateKey, passphrase);\n        const decrypted = await decryptKeyObject(keyObject, passphrase);\n        expect(decrypted.keyId).toBe(keyId);\n        expect(decrypted.privateKey.toBytes()).toStrictEqual(\n          privateKey.toBytes(),\n        );\n      },\n    ),\n  );\n});\n\ndescribe(\"decryptKeyObject()\", async () => {\n  for (const [\n    kdf,\n    { keyObject, passphrase, privateKey, options },\n  ] of Object.entries(testVectors)) {\n    test(kdf, async () => {\n      const { keyId, privateKey } = await decryptKeyObject(\n        keyObject,\n        passphrase,\n        options,\n      );\n      expect(keyId).toBe(keyObject.id);\n      expect(privateKey.toBytes()).toStrictEqual(privateKey.toBytes());\n\n      await expect(\n        decryptKeyObject(keyObject, `wrong ${passphrase}`),\n      ).rejects.toThrow(IncorrectPassphraseError);\n\n      if (options?.allowWeakPrivateKey) {\n        await expect(\n          decryptKeyObject(keyObject, passphrase, {\n            allowWeakPrivateKey: false,\n          }),\n        ).rejects.toThrow(WeakPrivateKeyError);\n      }\n    });\n  }\n});\n"
  },
  {
    "path": "@planetarium/account-web3-secret-storage/test/Web3KeyStore.test.ts",
    "content": "import {\n  Web3KeyStore,\n  getDefaultWeb3KeyStorePath,\n  parseKeyFilename,\n} from \"../src/Web3KeyStore\";\nimport { Address, RawPrivateKey } from \"@planetarium/account\";\nimport { copyFile, mkdtemp, readdir, rm } from \"node:fs/promises\";\nimport { tmpdir } from \"node:os\";\nimport * as path from \"node:path\";\nimport { describe, expect, test, vi } from \"vitest\";\nimport { WeakPrivateKeyError, Web3Account } from \"../src/Web3Account\";\nimport { MockPassphraseEntry } from \"./MockPassphraseEntry\";\n\nvi.mock(\"node:os\", async (importOriginal) => ({\n  ...((await importOriginal()) as object),\n}));\n\nvi.mock(\"node:fs/promises\", async (importOriginal) => ({\n  ...((await importOriginal()) as object),\n}));\n\ndescribe(\"getDefaultWeb3KeyStorePath\", () => {\n  test(\"posix with XDG_CONFIG_HOME\", () => {\n    vi.stubGlobal(\"process\", {\n      ...process,\n      platform: \"linux\",\n    });\n    vi.stubEnv(\"XDG_CONFIG_HOME\", \"/home/user/.config\");\n    expect(getDefaultWeb3KeyStorePath()).toBe(\n      \"/home/user/.config/planetarium/keystore\",\n    );\n  });\n\n  test(\"posix without XDG_CONFIG_HOME\", async () => {\n    vi.stubGlobal(\"process\", {\n      ...process,\n      platform: \"linux\",\n    });\n    vi.stubEnv(\"XDG_CONFIG_HOME\", \"\");\n    vi.spyOn(require(\"node:os\"), \"homedir\").mockReturnValue(\"/home/user\");\n    expect(getDefaultWeb3KeyStorePath()).toBe(\n      \"/home/user/.config/planetarium/keystore\",\n    );\n  });\n\n  test(\"win32\", () => {\n    vi.stubGlobal(\"process\", {\n      ...process,\n      platform: \"win32\",\n    });\n    vi.stubEnv(\"AppData\", \"C:\\\\Users\\\\user\\\\AppData\\\\Roaming\");\n    expect(getDefaultWeb3KeyStorePath()).toBe(\n      \"C:\\\\Users\\\\user\\\\AppData\\\\Roaming\\\\planetarium\\\\keystore\",\n    );\n  });\n\n  test(\"win32 without AppData\", async () => {\n    vi.stubGlobal(\"process\", {\n      ...process,\n      platform: \"win32\",\n    });\n    vi.stubEnv(\"AppData\", \"\");\n    vi.spyOn(require(\"node:os\"), \"homedir\").mockReturnValue(\"C:\\\\Users\\\\user\");\n    expect(getDefaultWeb3KeyStorePath()).toBe(\n      \"C:\\\\Users\\\\user\\\\AppData\\\\Roaming\\\\planetarium\\\\keystore\",\n    );\n  });\n});\n\ndescribe(\"parseKeyFilename\", () => {\n  const filenames = {\n    \"UTC--2022-02-21T10-28-53Z--ababb677-86c3-450e-b142-b73207589b7f\": {\n      keyId: \"ababb677-86c3-450e-b142-b73207589b7f\",\n      createdAt: new Date(\"2022-02-21T10:28:53Z\"),\n    },\n    \"UTC--2023-02-03T08-31-05Z--5c6ea22a-6e51-4a28-b624-a33e545d49a1.json\": {\n      keyId: \"5c6ea22a-6e51-4a28-b624-a33e545d49a1\",\n      createdAt: new Date(\"2023-02-03T08:31:05Z\"),\n    },\n    \"99b24ec5-04c9-47e2-b204-82f292e8db57\": {\n      keyId: \"99b24ec5-04c9-47e2-b204-82f292e8db57\",\n      createdAt: undefined,\n    },\n    \"99B24EC5-04C9-47E2-B204-82F292E8DB57\": {\n      keyId: \"99b24ec5-04c9-47e2-b204-82f292e8db57\",\n      createdAt: undefined,\n    },\n    \"e64381d9-0447-4355-9514-cd38adbfc420.json\": {\n      keyId: \"e64381d9-0447-4355-9514-cd38adbfc420\",\n      createdAt: undefined,\n    },\n\n    // Wrong cases:\n    asdf: undefined,\n    \"UTC--2022-02-21T10-28-53Z--ababb677-86c3-450e-b142-b73207589b7f.dat\":\n      undefined,\n    \"e64381d9-0447-4355-9514-cd38adbfc420.wrong\": undefined,\n    \"KST--2022-02-21T10-28-53--ababb677-86c3-450e-b142-b73207589b7f\": undefined,\n  };\n  for (const [filename, expected] of Object.entries(filenames)) {\n    test(filename, () =>\n      expect(parseKeyFilename(filename)).toStrictEqual(expected),\n    );\n  }\n});\n\nfunction testInTempDir(label: string, fn: (dirPath: string) => Promise<void>) {\n  test(label, async () => {\n    const dirPath = await mkdtemp(\n      path.join(tmpdir(), \"account-web3-secret-storage-\"),\n    );\n    try {\n      await fn(dirPath);\n    } finally {\n      await rm(dirPath, { recursive: true, force: true });\n    }\n  });\n}\n\ndescribe(\"Web3KeyStore\", () => {\n  testInTempDir(\"list\", async (tmpDir) => {\n    const store = new Web3KeyStore({\n      path: tmpDir,\n      passphraseEntry: new MockPassphraseEntry(),\n    });\n    let i = 0;\n    for await (const key of store.list()) {\n      i++;\n    }\n    expect(i).toBeFalsy();\n\n    await copyFile(\n      path.join(\n        __dirname,\n        \"fixtures\",\n        \"UTC--2023-03-14T07-05-42Z--babfe5e0-f0f1-4f51-8b8e-97f1a461c690\",\n      ),\n      path.join(\n        tmpDir,\n        \"UTC--2023-03-14T07-05-42Z--babfe5e0-f0f1-4f51-8b8e-97f1a461c690\",\n      ),\n    );\n    i = 0;\n    for await (const key of store.list()) {\n      i++;\n      expect(key).toStrictEqual({\n        keyId: \"babfe5e0-f0f1-4f51-8b8e-97f1a461c690\",\n        createdAt: new Date(\"2023-03-14T07:05:42Z\"),\n        metadata: {\n          address: Address.fromHex(\"6A58a1222E562174943c98ECf6e2290adA79b1B8\"),\n        },\n      });\n    }\n    expect(i).toBe(1);\n\n    await copyFile(\n      path.join(\n        __dirname,\n        \"fixtures\",\n        \"UTC--2023-03-14T07-05-52Z--3b948485-9bd0-4149-9a36-59999b36abf3\",\n      ),\n      path.join(\n        tmpDir,\n        \"UTC--2023-03-14T07-05-52Z--3b948485-9bd0-4149-9a36-59999b36abf3\",\n      ),\n    );\n    i = 0;\n    for await (const key of store.list()) {\n      i++;\n      if (key.keyId === \"babfe5e0-f0f1-4f51-8b8e-97f1a461c690\") {\n        expect(key).toStrictEqual({\n          keyId: \"babfe5e0-f0f1-4f51-8b8e-97f1a461c690\",\n          createdAt: new Date(\"2023-03-14T07:05:42Z\"),\n          metadata: {\n            address: Address.fromHex(\n              \"6A58a1222E562174943c98ECf6e2290adA79b1B8\",\n            ),\n          },\n        });\n      } else {\n        expect(key).toStrictEqual({\n          keyId: \"3b948485-9bd0-4149-9a36-59999b36abf3\",\n          createdAt: new Date(\"2023-03-14T07:05:52Z\"),\n          metadata: {\n            address: Address.fromHex(\n              \"596f54a9f0c0c3da7b8BE6A577dCCb66dd36ed1E\",\n            ),\n          },\n        });\n      }\n    }\n    expect(i).toBe(2);\n  });\n\n  testInTempDir(\"get\", async (tmpDir) => {\n    const passphraseEntry = new MockPassphraseEntry();\n    const store = new Web3KeyStore({ path: tmpDir, passphraseEntry });\n    await copyFile(\n      path.join(\n        __dirname,\n        \"fixtures\",\n        \"UTC--2023-03-14T07-05-42Z--babfe5e0-f0f1-4f51-8b8e-97f1a461c690\",\n      ),\n      path.join(\n        tmpDir,\n        \"UTC--2023-03-14T07-05-42Z--babfe5e0-f0f1-4f51-8b8e-97f1a461c690\",\n      ),\n    );\n\n    expect(passphraseEntry.authenticateCalls).toStrictEqual([]);\n    expect(passphraseEntry.configurePassphraseCalls).toBe(0);\n    const result = await store.get(\"babfe5e0-f0f1-4f51-8b8e-97f1a461c690\");\n    expect(passphraseEntry.authenticateCalls).toStrictEqual([]);\n    expect(passphraseEntry.configurePassphraseCalls).toBe(0);\n    const account = RawPrivateKey.fromHex(\n      \"e8b612d1126989e1b85b0b94e511bfca5eff4866bb646fc7a42275759bc2d529\",\n    );\n    expect({ ...result, account: undefined }).toStrictEqual({\n      result: \"success\",\n      keyId: \"babfe5e0-f0f1-4f51-8b8e-97f1a461c690\",\n      createdAt: new Date(\"2023-03-14T07:05:42Z\"),\n      metadata: {\n        address: Address.fromHex(\"6A58a1222E562174943c98ECf6e2290adA79b1B8\"),\n      },\n      account: undefined,\n    });\n\n    // The above assertion is not enough to convince if the appropriate account\n    // is returned.  The following assertions are for that purpose:\n    if (result.result !== \"success\") throw new Error(); // type guard\n    expect(result.account).toBeInstanceOf(Web3Account);\n\n    const exportedKey = await result.account.exportPrivateKey();\n    expect(passphraseEntry.authenticateCalls).toStrictEqual([\n      { keyId: \"babfe5e0-f0f1-4f51-8b8e-97f1a461c690\", firstAttempt: true },\n    ]);\n    expect(passphraseEntry.configurePassphraseCalls).toBe(0);\n\n    expect(exportedKey.toBytes()).toStrictEqual(account.toBytes());\n\n    passphraseEntry.authenticateCalls = [];\n    passphraseEntry.setTemporaryAuthenticateResult(\"wrong pass\", 2);\n    await result.account.exportPrivateKey();\n    expect(passphraseEntry.authenticateCalls).toStrictEqual([\n      { keyId: \"babfe5e0-f0f1-4f51-8b8e-97f1a461c690\", firstAttempt: true },\n      { keyId: \"babfe5e0-f0f1-4f51-8b8e-97f1a461c690\", firstAttempt: false },\n      { keyId: \"babfe5e0-f0f1-4f51-8b8e-97f1a461c690\", firstAttempt: false },\n    ]);\n    expect(passphraseEntry.configurePassphraseCalls).toBe(0);\n\n    passphraseEntry.authenticateCalls = [];\n    const notFound = await store.get(\"00000000-0000-0000-0000-000000000000\");\n    expect(passphraseEntry.authenticateCalls).toStrictEqual([]);\n    expect(passphraseEntry.configurePassphraseCalls).toBe(0);\n    expect(notFound).toStrictEqual({\n      result: \"keyNotFound\",\n      keyId: \"00000000-0000-0000-0000-000000000000\",\n    });\n  });\n\n  testInTempDir(\"get insufficient lengthed key\", async (tmpDir) => {\n    const passphraseEntry = new MockPassphraseEntry(\"1\");\n    const store = new Web3KeyStore({ path: tmpDir, passphraseEntry });\n    await copyFile(\n      path.join(\n        __dirname,\n        \"fixtures\",\n        \"insufficient-lengthed-keys\",\n        \"UTC--2023-01-30T11-33-11Z--b35a2647-8581-43ff-a98e-6083dc952632\",\n      ),\n      path.join(\n        tmpDir,\n        \"UTC--2023-01-30T11-33-11Z--b35a2647-8581-43ff-a98e-6083dc952632\",\n      ),\n    );\n\n    const result = await store.get(\"b35a2647-8581-43ff-a98e-6083dc952632\");\n    if (result.result !== \"success\") throw new Error(); // type guard\n\n    const msg = new Uint8Array([1, 2, 3]);\n    expect(result.account.sign(msg)).rejects.toThrowError(WeakPrivateKeyError);\n\n    const nonStrictStore = new Web3KeyStore({\n      path: tmpDir,\n      passphraseEntry,\n      allowWeakPrivateKey: true,\n    });\n    const result2 = await nonStrictStore.get(\n      \"b35a2647-8581-43ff-a98e-6083dc952632\",\n    );\n    if (result2.result !== \"success\") throw new Error(); // type guard\n    const sig = await result2.account.sign(msg);\n    await expect(\n      (await result2.account.getPublicKey()).verify(msg, sig),\n    ).resolves.toBeTruthy();\n  });\n\n  testInTempDir(\"generate\", async (tmpDir) => {\n    const passphraseEntry = new MockPassphraseEntry();\n    const store = new Web3KeyStore({ path: tmpDir, passphraseEntry });\n\n    const before = new Date().setMilliseconds(0);\n    const result = await store.generate();\n    const after = new Date();\n    expect(passphraseEntry.authenticateCalls).toStrictEqual([]);\n    expect(passphraseEntry.configurePassphraseCalls).toBe(1);\n    expect(result.result).toBe(\"success\");\n    if (result.result !== \"success\") throw new Error(); // type guard\n\n    const files = await readdir(tmpDir);\n    expect(files.length).toBe(1);\n    const parsed = parseKeyFilename(files[0]);\n    if (parsed == null) throw new Error(\"Invalid key filename\");\n    expect(parsed.createdAt).toBeInstanceOf(Date);\n    if (parsed.createdAt == null) throw new Error(); // type guard\n    expect(+parsed.createdAt).toBeGreaterThanOrEqual(+before);\n    expect(+parsed.createdAt).toBeLessThanOrEqual(+after);\n    expect(parsed.keyId).toBe(result.keyId);\n\n    const error = await store.generate({\n      address: Address.fromHex(\"0000000000000000000000000000000000000000\"),\n    });\n    expect(error.result).toBe(\"error\");\n    if (error.result !== \"error\") throw new Error(); // type guard\n    expect(error.message).toMatch(/\\baddress\\s+cannot\\s+be\\s+predetermined\\b/i);\n  });\n\n  testInTempDir(\"delete\", async (tmpDir) => {\n    const passphraseEntry = new MockPassphraseEntry();\n    const store = new Web3KeyStore({ path: tmpDir, passphraseEntry });\n    await copyFile(\n      path.join(\n        __dirname,\n        \"fixtures\",\n        \"UTC--2023-03-14T07-05-42Z--babfe5e0-f0f1-4f51-8b8e-97f1a461c690\",\n      ),\n      path.join(\n        tmpDir,\n        \"UTC--2023-03-14T07-05-42Z--babfe5e0-f0f1-4f51-8b8e-97f1a461c690\",\n      ),\n    );\n\n    const result = await store.delete(\"babfe5e0-f0f1-4f51-8b8e-97f1a461c690\");\n    expect(passphraseEntry.authenticateCalls).toStrictEqual([]);\n    expect(passphraseEntry.configurePassphraseCalls).toBe(0);\n    expect(result).toStrictEqual({\n      result: \"success\",\n      keyId: \"babfe5e0-f0f1-4f51-8b8e-97f1a461c690\",\n    });\n\n    const files = await readdir(tmpDir);\n    expect(files.length).toBe(0);\n\n    const result2 = await store.delete(\"00000000-0000-0000-0000-000000000000\");\n    expect(passphraseEntry.authenticateCalls).toStrictEqual([]);\n    expect(passphraseEntry.configurePassphraseCalls).toBe(0);\n    expect(result2).toStrictEqual({\n      result: \"keyNotFound\",\n      keyId: \"00000000-0000-0000-0000-000000000000\",\n    });\n\n    await copyFile(\n      path.join(\n        __dirname,\n        \"fixtures\",\n        \"UTC--2023-03-14T07-05-42Z--babfe5e0-f0f1-4f51-8b8e-97f1a461c690\",\n      ),\n      path.join(\n        tmpDir,\n        \"UTC--2023-03-14T07-05-42Z--babfe5e0-f0f1-4f51-8b8e-97f1a461c690\",\n      ),\n    );\n    vi.spyOn(await import(\"node:fs/promises\"), \"unlink\").mockRejectedValue(\n      new Error(\"unlink error\"),\n    );\n    const result3 = await store.delete(\"babfe5e0-f0f1-4f51-8b8e-97f1a461c690\");\n    expect(result3).toStrictEqual({\n      result: \"error\",\n      message: \"Error: unlink error\",\n    });\n  });\n\n  testInTempDir(\"import\", async (tmpDir) => {\n    const passphraseEntry = new MockPassphraseEntry();\n    const store = new Web3KeyStore({ path: tmpDir, passphraseEntry });\n\n    const privateKey = RawPrivateKey.fromHex(\n      \"e8b612d1126989e1b85b0b94e511bfca5eff4866bb646fc7a42275759bc2d529\",\n    );\n    const before = new Date().setMilliseconds(0);\n    const result = await store.import(privateKey);\n    const after = new Date();\n    expect(passphraseEntry.authenticateCalls).toStrictEqual([]);\n    expect(passphraseEntry.configurePassphraseCalls).toBe(1);\n\n    const files = await readdir(tmpDir);\n    expect(files.length).toBe(1);\n    const parsed = parseKeyFilename(files[0]);\n    if (parsed == null) throw new Error(\"Invalid key filename\");\n    expect(parsed.createdAt).toBeInstanceOf(Date);\n    if (parsed.createdAt == null) throw new Error(); // type guard\n    expect(+parsed.createdAt).toBeGreaterThanOrEqual(+before);\n    expect(+parsed.createdAt).toBeLessThanOrEqual(+after);\n    expect(result).toStrictEqual({ result: \"success\", keyId: parsed.keyId });\n\n    const loaded = await store.get(parsed.keyId);\n    if (loaded.result !== \"success\") throw Error(); // type guard\n    const exportedKey = await loaded.account.exportPrivateKey();\n    expect(exportedKey.toBytes()).toStrictEqual(privateKey.toBytes());\n\n    const insufficientLenghtedKey = RawPrivateKey.fromHex(\n      \"00000000000000000000000000000000000000000000000000000000000000aa\",\n    );\n\n    const error = await store.import(insufficientLenghtedKey);\n    expect(error.result).toBe(\"error\");\n    if (error.result !== \"error\") throw new Error(); // type guard\n    expect(error.message).toMatch(/\\btoo\\s+weak\\b/i);\n\n    const nonStrictStore = new Web3KeyStore({\n      path: tmpDir,\n      passphraseEntry,\n      allowWeakPrivateKey: true,\n    });\n    const result2 = await nonStrictStore.import(insufficientLenghtedKey);\n    expect(result2.result).toBe(\"success\");\n    if (result2.result !== \"success\") throw new Error(); // type guard\n    const loaded2 = await nonStrictStore.get(result2.keyId);\n    if (loaded2.result !== \"success\") throw Error(); // type guard\n    expect((await loaded2.account.exportPrivateKey()).toBytes()).toStrictEqual(\n      insufficientLenghtedKey.toBytes(),\n    );\n\n    const error2 = await store.import(privateKey, {\n      address: Address.fromHex(\"0000000000000000000000000000000000000000\"),\n    });\n    expect(error2.result).toBe(\"error\");\n    if (error2.result !== \"error\") throw new Error(); // type guard\n    expect(error2.message).toMatch(/\\baddress\\s+does\\s+not\\s+match\\b/i);\n  });\n});\n"
  },
  {
    "path": "@planetarium/account-web3-secret-storage/test/fixtures/DO_NOT_USE_PRIVATE_KEYS_IN_THIS_DIR",
    "content": ""
  },
  {
    "path": "@planetarium/account-web3-secret-storage/test/fixtures/UTC--2023-03-14T07-05-42Z--babfe5e0-f0f1-4f51-8b8e-97f1a461c690",
    "content": "{\n  \"version\": 3,\n  \"id\": \"babfe5e0-f0f1-4f51-8b8e-97f1a461c690\",\n  \"address\": \"6a58a1222e562174943c98ecf6e2290ada79b1b8\",\n  \"crypto\": {\n    \"ciphertext\": \"902352dd97b4d73f9efcaf60b94a7ce204ba6cb8b92d669d29e99850ad61a00e\",\n    \"cipherparams\": {\n      \"iv\": \"3cbad56ae5446a32a141245f5b44147a\"\n    },\n    \"cipher\": \"aes-128-ctr\",\n    \"kdfparams\": {\n      \"c\": 10240,\n      \"dklen\": 32,\n      \"prf\": \"hmac-sha256\",\n      \"salt\": \"264020c7d11f2470316db06623390f488453df251b0731a4f33c7b8e2178afec\"\n    },\n    \"kdf\": \"pbkdf2\",\n    \"mac\": \"fd7c9047651a97713678cceeb19a23d8260c7bd77f384bc850ce4a1206d2d9bd\"\n  }\n}\n"
  },
  {
    "path": "@planetarium/account-web3-secret-storage/test/fixtures/UTC--2023-03-14T07-05-52Z--3b948485-9bd0-4149-9a36-59999b36abf3",
    "content": "{\n  \"version\": 3,\n  \"id\": \"3b948485-9bd0-4149-9a36-59999b36abf3\",\n  \"address\": \"596f54a9f0c0c3da7b8be6a577dccb66dd36ed1e\",\n  \"crypto\": {\n    \"ciphertext\": \"f3b18df2a2c391a3d1b1071470b4c81ce22f76ce582525a3f81b3a42c8d58613\",\n    \"cipherparams\": {\n      \"iv\": \"24c83f28f8d33411bf8ca06dcc5bfbe5\"\n    },\n    \"cipher\": \"aes-128-ctr\",\n    \"kdfparams\": {\n      \"c\": 10240,\n      \"dklen\": 32,\n      \"prf\": \"hmac-sha256\",\n      \"salt\": \"c7925c8fa327a114ac5b24560c0c7c4dc4715353976b858f7ee20fcde375f7fd\"\n    },\n    \"kdf\": \"pbkdf2\",\n    \"mac\": \"e665d78dc1796544aea4605230f4f25ad2994aa2ebdc5b63ab803d6c9cbefa39\"\n  }\n}\n"
  },
  {
    "path": "@planetarium/account-web3-secret-storage/test/fixtures/insufficient-lengthed-keys/UTC--2023-01-30T11-33-11Z--b35a2647-8581-43ff-a98e-6083dc952632",
    "content": "{\n  \"version\": 3,\n  \"id\": \"b35a2647-8581-43ff-a98e-6083dc952632\",\n  \"address\": \"eb9afe072c781401bf364224c75a036e4d832f52\",\n  \"crypto\": {\n    \"ciphertext\": \"14\",\n    \"cipherparams\": {\n      \"iv\": \"24ece9686a10f8687dc70ca42873a063\"\n    },\n    \"cipher\": \"aes-128-ctr\",\n    \"kdfparams\": {\n      \"c\": 10240,\n      \"dklen\": 32,\n      \"prf\": \"hmac-sha256\",\n      \"salt\": \"99b480642f6406a10c67429168fb36ba35da7743965e10390eda649ec6da2ae8\"\n    },\n    \"kdf\": \"pbkdf2\",\n    \"mac\": \"7856d88908c72f0af78457ccd085696ad6193f7d2bda525723862f450ce060fa\"\n  }\n}\n"
  },
  {
    "path": "@planetarium/account-web3-secret-storage/tsconfig.json",
    "content": "{\n  \"include\": [\"./src\", \"*.d.ts\", \"src/*.ts\"],\n  \"compilerOptions\": {\n    \"rootDir\": \"./src\",\n    \"outDir\": \"dist\",\n    \"target\": \"ESNext\",\n    \"strict\": true,\n    \"noUnusedLocals\": true,\n    \"noImplicitReturns\": true,\n    \"esModuleInterop\": true,\n    \"skipLibCheck\": true,\n    \"forceConsistentCasingInFileNames\": true,\n    \"moduleResolution\": \"nodenext\",\n    \"module\": \"NodeNext\",\n    \"lib\": [\"ESNext\", \"DOM\"]\n  }\n}\n"
  },
  {
    "path": "@planetarium/account-web3-secret-storage/vitest.config.ts",
    "content": "import { defineConfig } from \"vitest/config\";\n\nexport default defineConfig({\n  test: {\n    cache: false,\n    restoreMocks: true,\n    unstubEnvs: true,\n    unstubGlobals: true,\n    testTimeout: 30000,\n    alias: {\n      \"#crypto\": \"./src/crypto/node.ts\",\n      \"#path\": \"./src/path/node.ts\",\n      \"#fs\": \"./src/fs/node.ts\",\n    },\n  },\n});\n"
  },
  {
    "path": "@planetarium/tx/.gitignore",
    "content": "coverage/\ndist/\n"
  },
  {
    "path": "@planetarium/tx/.vscode/extensions.json",
    "content": "{\n  \"recommendations\": [\n    \"dbaeumer.vscode-eslint\",\n    \"zixuanchen.vitest-explorer\"\n  ]\n}\n"
  },
  {
    "path": "@planetarium/tx/.vscode/settings.json",
    "content": "{\n  \"vitest.enable\": true,\n  \"eslint.enable\": true,\n  \"eslint.format.enable\": true,\n  \"eslint.codeActionsOnSave.mode\": \"problems\",\n  \"[typescript]\": {\n    \"editor.codeActionsOnSave\": {\n      \"source.fixAll.eslint\": true\n    }\n  },\n  \"cSpell.words\": [\n    \"bencodex\",\n    \"encodable\"\n  ]\n}\n"
  },
  {
    "path": "@planetarium/tx/README.md",
    "content": "@planetarium/tx\n===============\n\n[![npm][npm-badge]][npm] ![Node.js version][]\n\nThis npm package provides functions to build transactions equivalent to\n[Libplanet]:\n\n -  Creating an unsigned transaction with a system action\n -  Creating an unsigned transaction with custom actions\n -  Signing a transaction\n\n[npm]: https://www.npmjs.com/package/@planetarium/tx\n[npm-badge]: https://img.shields.io/npm/v/@planetarium/tx\n[Node.js version]: https://img.shields.io/node/v-lts/@planetarium/tx\n[Libplanet]: https://libplanet.io/\n"
  },
  {
    "path": "@planetarium/tx/package.json",
    "content": "{\n  \"name\": \"@planetarium/tx\",\n  \"private\": true,\n  \"description\": \"Creating Libplanet transactions from JavaScript/TypeScript\",\n  \"type\": \"module\",\n  \"main\": \"./dist/index.js\",\n  \"exports\": {\n    \".\": {\n      \"types\": \"./dist/index.d.ts\",\n      \"import\": \"./dist/index.js\",\n      \"require\": \"./dist/index.cjs\"\n    }\n  },\n  \"types\": \"./dist/index.d.ts\",\n  \"files\": [\n    \"dist/**/*\"\n  ],\n  \"engines\": {\n    \"node\": \">=19.0.0\"\n  },\n  \"scripts\": {\n    \"build\": \"yarn && nanobundle build\",\n    \"prepack\": \"yarn && yarn build\",\n    \"dev\": \"yarn && dotnet build ../../tools/Libplanet.Tools && vitest\",\n    \"test\": \"yarn && yarn run -T tsc -p tsconfig.json && dotnet build ../../tools/Libplanet.Tools && vitest run\",\n    \"coverage\": \"yarn && vitest run --coverage\"\n  },\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"git+https://github.com/planetarium/libplanet.git\",\n    \"directory\": \"@planetarium/tx\"\n  },\n  \"keywords\": [\n    \"libplanet\"\n  ],\n  \"author\": \"Planetarium (https://planetarium.dev/)\",\n  \"license\": \"LGPL-2.1-or-later\",\n  \"bugs\": {\n    \"url\": \"https://github.com/planetarium/libplanet/labels/js\"\n  },\n  \"homepage\": \"https://github.com/planetarium/libplanet/tree/main/@planetarium/tx\",\n  \"devDependencies\": {\n    \"@planetarium/account\": \"workspace:^\",\n    \"@types/node\": \"^18.14.0\",\n    \"@vitest/coverage-c8\": \"^0.29.2\",\n    \"@vitest/ui\": \"^0.29.2\",\n    \"execa\": \"^6.1.0\",\n    \"fast-check\": \"^3.1.2\",\n    \"nanobundle\": \"^1.6.0\",\n    \"vite\": \"^4.1.3\",\n    \"vitest\": \"^0.29.2\"\n  },\n  \"dependencies\": {\n    \"@planetarium/bencodex\": \"^0.2.2\"\n  },\n  \"peerDependencies\": {\n    \"@planetarium/account\": \"workspace:^\"\n  }\n}\n"
  },
  {
    "path": "@planetarium/tx/src/address.ts",
    "content": "import { Key, Value } from \"@planetarium/bencodex\";\nimport { compareUint8Array } from \"./binary.js\";\n\nexport type Address = Uint8Array; // TODO: proper type definition\n\nexport function encodeAddress(address: Address): Key {\n  if (address.length !== 20) {\n    throw new TypeError(\n      `Address must be 20 bytes long, but got ${address.length} bytes.`,\n    );\n  }\n  return address;\n}\n\nexport function encodeAddressSet(addresses: Set<Address>): Value {\n  const array: Address[] = [];\n  addresses.forEach((addr) => array.push(addr));\n  array.sort(compareUint8Array);\n  return array.map(encodeAddress);\n}\n"
  },
  {
    "path": "@planetarium/tx/src/assets.ts",
    "content": "import { encode, RecordValue, RecordView, Value } from \"@planetarium/bencodex\";\nimport { Address, encodeAddressSet } from \"./address.js\";\n\nexport interface Currency {\n  ticker: string;\n  decimalPlaces: number;\n  minters: Set<Address> | null;\n  totalSupplyTrackable: boolean;\n  maximumSupply: {\n    major: bigint;\n    minor: bigint;\n  } | null;\n}\n\nexport function encodeCurrency(currency: Currency): Value {\n  const minters: Value =\n    currency.minters === null ? null : encodeAddressSet(currency.minters);\n  const serialized: RecordValue = {\n    ticker: currency.ticker,\n    decimalPlaces: new Uint8Array([currency.decimalPlaces]),\n    minters,\n  };\n\n  if (currency.maximumSupply !== null) {\n    if (!currency.totalSupplyTrackable) {\n      throw new TypeError(\"maximumSupply implies totalSupplyTrackable\");\n    }\n\n    serialized.maximumSupplyMajor = currency.maximumSupply.major;\n    serialized.maximumSupplyMinor = currency.maximumSupply.minor;\n  }\n\n  if (currency.totalSupplyTrackable) {\n    serialized.totalSupplyTrackable = true;\n  }\n\n  return new RecordView(serialized, \"text\");\n}\n\nfunction encodeCurrencyForHash(currency: Currency): Value {\n  const minters: Value =\n    currency.minters === null ? null : encodeAddressSet(currency.minters);\n  const serialized: RecordValue = {\n    ticker: currency.ticker,\n    decimals: BigInt(currency.decimalPlaces),\n    minters,\n  };\n\n  if (currency.maximumSupply !== null) {\n    if (!currency.totalSupplyTrackable) {\n      throw new TypeError(\"maximumSupply implies totalSupplyTrackable\");\n    }\n\n    serialized.maximumSupplyMajor = currency.maximumSupply.major;\n    serialized.maximumSupplyMinor = currency.maximumSupply.minor;\n  }\n\n  if (currency.totalSupplyTrackable) {\n    serialized.totalSupplyTrackable = true;\n  }\n\n  return new RecordView(serialized, \"text\");\n}\n\nexport async function getCurrencyHash(currency: Currency): Promise<Uint8Array> {\n  const encoded = encode(encodeCurrencyForHash(currency));\n  const buffer = await crypto.subtle.digest(\"SHA-1\", encoded);\n  return new Uint8Array(buffer);\n}\n\nexport interface FungibleAssetValue {\n  rawValue: bigint;\n  currency: Currency;\n}\n\nexport function encodeFungibleAssetValue(value: FungibleAssetValue): Value[] {\n  return [encodeCurrency(value.currency), value.rawValue];\n}\n\nfunction abs(value: bigint): bigint {\n  return value < 0n ? -value : value;\n}\n\nexport function getSign(value: FungibleAssetValue): -1 | 0 | 1 {\n  return value.rawValue < 0n ? -1 : value.rawValue > 0n ? 1 : 0;\n}\n\nexport function getMajorUnit(value: FungibleAssetValue): bigint {\n  return abs(value.rawValue) / 10n ** BigInt(value.currency.decimalPlaces);\n}\n\nexport function getMinorUnit(value: FungibleAssetValue): bigint {\n  return abs(value.rawValue) % 10n ** BigInt(value.currency.decimalPlaces);\n}\n"
  },
  {
    "path": "@planetarium/tx/src/binary.ts",
    "content": "\nexport function compareUint8Array(a: Uint8Array, b: Uint8Array) {\n  const length = Math.min(a.length, b.length);\n  for (let i = 0; i < length; i++) {\n    if (a[i] !== b[i]) return a[i] - b[i];\n  }\n  return a.length - b.length;\n}\n"
  },
  {
    "path": "@planetarium/tx/src/blockhash.ts",
    "content": "import { Value } from \"@planetarium/bencodex\";\n\nexport type BlockHash = Uint8Array; // TODO: proper type definition\n\nexport function encodeBlockHash(blockHash: BlockHash): Value {\n  if (blockHash.length !== 32) {\n    throw new TypeError(\n      `BlockHash must be 32 bytes long, but got ${blockHash.length} bytes.`,\n    );\n  }\n  return blockHash;\n}\n"
  },
  {
    "path": "@planetarium/tx/src/bytes.ts",
    "content": "\nexport function bytesEqual(\n  a: Uint8Array | ArrayBuffer,\n  b: Uint8Array | ArrayBuffer\n): boolean {\n  const x = a instanceof ArrayBuffer ? new Uint8Array(a) : a;\n  const y = b instanceof ArrayBuffer ? new Uint8Array(b) : b;\n  return x.length === y.length && x.every((v, i) => v === y[i]);\n}\n"
  },
  {
    "path": "@planetarium/tx/src/index.ts",
    "content": "export { type Address, encodeAddress } from \"./address.js\";\nexport {\n  type Currency,\n  encodeCurrency,\n  type FungibleAssetValue,\n  encodeFungibleAssetValue,\n  getCurrencyHash,\n  getMajorUnit,\n  getMinorUnit,\n  getSign,\n} from \"./assets.js\";\nexport type {\n  TxMetadata,\n  UnsignedTx,\n} from \"./tx/index.js\";\nexport {\n  encodeTxMetadata,\n  encodeUnsignedTx,\n} from \"./tx/index.js\";\nexport {\n  signTx,\n  encodeSignedTx,\n} from \"./tx/signed.js\";\n"
  },
  {
    "path": "@planetarium/tx/src/key.ts",
    "content": "import { Value } from \"@planetarium/bencodex\";\n\nexport type PublicKey = Uint8Array; // TODO: proper type definition\n\nexport function encodePublicKey(publicKey: PublicKey): Value {\n  if (publicKey.length < 1) {\n    throw new TypeError(\"Public key must not be empty.\");\n  }\n  return publicKey;\n}\n"
  },
  {
    "path": "@planetarium/tx/src/tx/index.ts",
    "content": "export type { TxMetadata } from \"./metadata.js\";\nexport { encodeTxMetadata } from \"./metadata.js\";\nexport type { UnsignedTx } from \"./unsigned.js\";\nexport type { SignedTx } from \"./signed.js\";\nexport { encodeUnsignedTx } from \"./unsigned.js\";\nexport { signTx, encodeSignedTx } from \"./signed.js\";\n"
  },
  {
    "path": "@planetarium/tx/src/tx/metadata.ts",
    "content": "import {\n  BencodexDictionary,\n  Dictionary,\n  Key,\n  Value,\n} from \"@planetarium/bencodex\";\nimport { Address, encodeAddress, encodeAddressSet } from \"../address.js\";\nimport { FungibleAssetValue, encodeFungibleAssetValue } from \"../assets.js\";\nimport { BlockHash, encodeBlockHash } from \"../blockhash.js\";\nimport { encodePublicKey, PublicKey } from \"../key.js\";\n\n/**\n * Represents an unsigned transaction without actions.  Corresponds to\n * Libplanet's `TxMetadata`.\n */\nexport interface TxMetadata {\n  nonce: bigint;\n  publicKey: PublicKey;\n  signer: Address; // TODO: This field can be derived from publicKey.\n  timestamp: Date;\n  updatedAddresses: Set<Address>;\n  genesisHash: BlockHash | null;\n  gasLimit: bigint | null;\n  maxGasPrice: FungibleAssetValue | null;\n}\n\nconst NONCE_KEY = new Uint8Array([0x6e]); // 'n'\nconst SIGNER_KEY = new Uint8Array([0x73]); // 's'\nconst GENESIS_HASH_KEY = new Uint8Array([0x67]); // 'g'\nconst UPDATED_ADDRESSES_KEY = new Uint8Array([0x75]); // 'u'\nconst PUBLIC_KEY_KEY = new Uint8Array([0x70]); // 'p'\nconst TIMESTAMP_KEY = new Uint8Array([0x74]); // 't'\nconst GAS_LIMIT_KEY = new Uint8Array([0x6c]); // 'l'\nconst MAX_GAS_PRICE_KEY = new Uint8Array([0x6d]); // 'm'\n\nexport function encodeTxMetadata(metadata: TxMetadata): Dictionary {\n  const updatedAddresses = encodeAddressSet(metadata.updatedAddresses);\n  const timestamp = metadata.timestamp.toISOString().replace(/Z$/, \"000Z\");\n  const pairs: [Key, Value][] = [\n    [NONCE_KEY, metadata.nonce],\n    [SIGNER_KEY, encodeAddress(metadata.signer)],\n    [UPDATED_ADDRESSES_KEY, updatedAddresses],\n    [PUBLIC_KEY_KEY, encodePublicKey(metadata.publicKey)],\n    [TIMESTAMP_KEY, timestamp],\n  ];\n  if (metadata.genesisHash !== null) {\n    pairs.push([GENESIS_HASH_KEY, encodeBlockHash(metadata.genesisHash)]);\n  }\n  if (metadata.gasLimit !== null) {\n    pairs.push([GAS_LIMIT_KEY, metadata.gasLimit]);\n  }\n  if (metadata.maxGasPrice !== null) {\n    pairs.push([MAX_GAS_PRICE_KEY, encodeFungibleAssetValue(metadata.maxGasPrice)]);\n  }\n\n  return new BencodexDictionary(pairs);\n}\n"
  },
  {
    "path": "@planetarium/tx/src/tx/signed.ts",
    "content": "import { Account, Address, Signature } from \"@planetarium/account\";\nimport { BencodexDictionary, Dictionary, encode } from \"@planetarium/bencodex\";\nimport { bytesEqual } from \"../bytes.js\";\nimport { type UnsignedTx, encodeUnsignedTx } from \"./unsigned.js\";\n\nconst SIGNATURE_KEY = new Uint8Array([0x53]); // 'S'\n\nexport type SignedTx = UnsignedTx & { signature: Signature };\n\nexport async function signTx(\n  tx: UnsignedTx,\n  signAccount: Account\n): Promise<SignedTx> {\n  if (\n    !bytesEqual(\n      tx.publicKey,\n      (await signAccount.getPublicKey()).toBytes(\"uncompressed\")\n    )\n  ) {\n    throw new Error(\"Public keys in the tx and the signAccount are mismatched\");\n  } else if (\n    !bytesEqual(\n      tx.signer,\n      Address.deriveFrom(await signAccount.getPublicKey()).toBytes()\n    )\n  ) {\n    throw new Error(\"The transaction signer does not match to the signAccount\");\n  }\n  const payload = encodeUnsignedTx(tx);\n  const signature = await signAccount.sign(encode(payload));\n  return {\n    ...tx,\n    signature,\n  };\n}\n\nexport function encodeSignedTx(tx: SignedTx): Dictionary {\n  const dict = encodeUnsignedTx(tx);\n  const sig = tx.signature.toBytes();\n  return new BencodexDictionary([...dict, [SIGNATURE_KEY, sig]]);\n}\n"
  },
  {
    "path": "@planetarium/tx/src/tx/unsigned.ts",
    "content": "import { BencodexDictionary, Dictionary, Value } from \"@planetarium/bencodex\";\nimport { encodeTxMetadata, TxMetadata } from \"./metadata.js\";\n\nconst ACTION_KEY = new Uint8Array([0x61]); // 'a'\n\nexport interface UnsignedTx extends TxMetadata {\n  actions: Value[];\n}\n\n/**\n * Encodes an unsigned transaction.\n * @param tx An unsigned transaction.\n * @returns An encoded transaction.\n */\nexport function encodeUnsignedTx(metadata: UnsignedTx): Dictionary {\n  return new BencodexDictionary([\n    ...encodeTxMetadata(metadata),\n    [ACTION_KEY, metadata.actions],\n  ]);\n}\n"
  },
  {
    "path": "@planetarium/tx/test/__snapshots__/assets.test.ts.snap",
    "content": "// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html\n\nexports[`encodeCurrency 1`] = `\n\"BencodexDictionary(3) {\n  'ticker' => 'FOO',\n  'decimalPlaces' => Uint8Array(1) [\n    2\n  ],\n  'minters' => null\n}\"\n`;\n\nexports[`encodeCurrency 2`] = `\nUint8Array [\n  100,\n  117,\n  49,\n  51,\n  58,\n  100,\n  101,\n  99,\n  105,\n  109,\n  97,\n  108,\n  80,\n  108,\n  97,\n  99,\n  101,\n  115,\n  49,\n  58,\n  2,\n  117,\n  55,\n  58,\n  109,\n  105,\n  110,\n  116,\n  101,\n  114,\n  115,\n  110,\n  117,\n  54,\n  58,\n  116,\n  105,\n  99,\n  107,\n  101,\n  114,\n  117,\n  51,\n  58,\n  70,\n  79,\n  79,\n  101,\n]\n`;\n\nexports[`encodeCurrency 3`] = `\n\"BencodexDictionary(6) {\n  'ticker' => 'BAR',\n  'decimalPlaces' => Uint8Array(1) [\n    0\n  ],\n  'minters' => [\n    Uint8Array(20) [\n      80,\n      3,\n      113,\n      43,\n      99,\n      186,\n      171,\n      152,\n      9,\n      74,\n      214,\n      120,\n      234,\n      43,\n      36,\n      188,\n      228,\n      69,\n      208,\n      118\n    ],\n    Uint8Array(20) [\n      214,\n      214,\n      57,\n      218,\n      90,\n      88,\n      167,\n      138,\n      86,\n      76,\n      44,\n      211,\n      219,\n      85,\n      250,\n      124,\n      235,\n      226,\n      68,\n      169\n    ]\n  ],\n  'maximumSupplyMajor' => 100n,\n  'maximumSupplyMinor' => 0n,\n  'totalSupplyTrackable' => true\n}\"\n`;\n\nexports[`encodeCurrency 4`] = `\nUint8Array [\n  100,\n  117,\n  49,\n  51,\n  58,\n  100,\n  101,\n  99,\n  105,\n  109,\n  97,\n  108,\n  80,\n  108,\n  97,\n  99,\n  101,\n  115,\n  49,\n  58,\n  0,\n  117,\n  49,\n  56,\n  58,\n  109,\n  97,\n  120,\n  105,\n  109,\n  117,\n  109,\n  83,\n  117,\n  112,\n  112,\n  108,\n  121,\n  77,\n  97,\n  106,\n  111,\n  114,\n  105,\n  49,\n  48,\n  48,\n  101,\n  117,\n  49,\n  56,\n  58,\n  109,\n  97,\n  120,\n  105,\n  109,\n  117,\n  109,\n  83,\n  117,\n  112,\n  112,\n  108,\n  121,\n  77,\n  105,\n  110,\n  111,\n  114,\n  105,\n  48,\n  101,\n  117,\n  55,\n  58,\n  109,\n  105,\n  110,\n  116,\n  101,\n  114,\n  115,\n  108,\n  50,\n  48,\n  58,\n  80,\n  3,\n  113,\n  43,\n  99,\n  186,\n  171,\n  152,\n  9,\n  74,\n  214,\n  120,\n  234,\n  43,\n  36,\n  188,\n  228,\n  69,\n  208,\n  118,\n  50,\n  48,\n  58,\n  214,\n  214,\n  57,\n  218,\n  90,\n  88,\n  167,\n  138,\n  86,\n  76,\n  44,\n  211,\n  219,\n  85,\n  250,\n  124,\n  235,\n  226,\n  68,\n  169,\n  101,\n  117,\n  54,\n  58,\n  116,\n  105,\n  99,\n  107,\n  101,\n  114,\n  117,\n  51,\n  58,\n  66,\n  65,\n  82,\n  117,\n  50,\n  48,\n  58,\n  116,\n  111,\n  116,\n  97,\n  108,\n  83,\n  117,\n  112,\n  112,\n  108,\n  121,\n  84,\n  114,\n  97,\n  99,\n  107,\n  97,\n  98,\n  108,\n  101,\n  116,\n  101,\n]\n`;\n\nexports[`getCurrencyHash 1`] = `\"81446cd346c1be9e686835742bfd3772194dea21\"`;\n\nexports[`getCurrencyHash 2`] = `\"42ce3a098fe14084e89d3d4449f56126693aeed1\"`;\n\nexports[`getCurrencyHash 3`] = `\"801990ea2885bd51eebca0e826cc0e27f0917a9b\"`;\n\nexports[`getCurrencyHash 4`] = `\"da42781871890f1e1b7d6f49c7f2733d3ba7b8bd\"`;\n\nexports[`getCurrencyHash 5`] = `\"d7fe111cae5b2503939c9bce864ca3b64d575e8d\"`;\n\nexports[`getCurrencyHash 6`] = `\"38bd85ea71c09ca7ed82b61fe91bc205101db191\"`;\n"
  },
  {
    "path": "@planetarium/tx/test/address.test.ts",
    "content": "import { test } from \"vitest\";\nimport * as fc from \"fast-check\";\nimport { encodeAddress, encodeAddressSet } from \"../src/address\";\nimport { compareUint8Array } from \"../src/binary\";\nimport { bytesEqual } from \"../src/bytes\";\n\ntest(\"encodeAddress\", () => {\n  fc.assert(\n    fc.property(\n      fc.uint8Array({ minLength: 20, maxLength: 20 }),\n      (bytes: Uint8Array) => {\n        const addr = encodeAddress(bytes);\n        return addr instanceof Uint8Array && bytesEqual(addr, bytes);\n      },\n    ),\n  );\n  fc.assert(\n    fc.property(\n      fc.uint8Array({ minLength: 0, maxLength: 19 }),\n      (shortBytes: Uint8Array) => {\n        try {\n          encodeAddress(shortBytes);\n        } catch (e) {\n          return e instanceof TypeError && e.message.includes(\"20 bytes\");\n        }\n      },\n    ),\n  );\n  fc.assert(\n    fc.property(\n      fc.uint8Array({ minLength: 21 }),\n      (longBytes: Uint8Array) => {\n        try {\n          encodeAddress(longBytes);\n        } catch (e) {\n          return e instanceof TypeError && e.message.includes(\"20 bytes\");\n        }\n      },\n    ),\n  );\n});\n\nfunction hex(bytes: ArrayBuffer | Uint8Array): string {\n  const u8a = bytes instanceof ArrayBuffer ? new Uint8Array(bytes) : bytes;\n  return Array.from(u8a)\n    .map((b) => b.toString(16).padStart(2, \"0\"))\n    .join(\"\");\n}\n\ntest(\"encodeAddressSet\", () => {\n  fc.assert(\n    fc.property(\n      fc.uniqueArray(fc.uint8Array({ minLength: 20, maxLength: 20 })),\n      (addresses: Uint8Array[]) => {\n        const set = new Set(addresses);\n        const checks = new Set(addresses.map(hex));\n        const encoded = encodeAddressSet(set);\n        if (!(encoded instanceof Array)) return false;\n        let prev: Uint8Array | null = null;\n        for (const v of encoded) {\n          if (!(v instanceof Uint8Array)) return false;\n          if (v.byteLength !== 20 || !checks.has(hex(v))) return false;\n          if (prev != null && compareUint8Array(prev, v) >= 0) return false;\n          checks.delete(hex(v));\n          prev = v;\n        }\n        return checks.size < 1;\n      },\n    ),\n  );\n});\n"
  },
  {
    "path": "@planetarium/tx/test/assets.test.ts",
    "content": "import { inspect } from \"node:util\";\nimport { encode } from \"@planetarium/bencodex\";\nimport { expect, test } from \"vitest\";\nimport { Address } from \"../src/address\";\nimport {\n  Currency,\n  encodeCurrency,\n  getCurrencyHash,\n  getMajorUnit,\n  getMinorUnit,\n  getSign,\n} from \"../src/assets\";\nimport { fromHex, toHex } from \"./hex\";\n\nif (globalThis.crypto == null) {\n  // FIXME: This is a workaround for the lack of Web Crypto API in Vitest.\n  globalThis.crypto = require(\"node:crypto\");\n}\n\nconst addressA: Address = fromHex(\"D6D639DA5a58A78A564C2cD3DB55FA7CeBE244A9\");\nconst addressB: Address = fromHex(\"5003712B63baAB98094aD678EA2B24BcE445D076\");\n\ntest(\"encodeCurrency\", () => {\n  const encoded = encodeCurrency({\n    ticker: \"FOO\",\n    decimalPlaces: 2,\n    minters: null,\n    totalSupplyTrackable: false,\n    maximumSupply: null,\n  });\n  expect(inspect(encoded, { compact: false })).toMatchSnapshot();\n  expect(encode(encoded)).toMatchSnapshot();\n\n  const encoded2 = encodeCurrency({\n    ticker: \"BAR\",\n    decimalPlaces: 0,\n    minters: new Set([addressA, addressB]),\n    totalSupplyTrackable: true,\n    maximumSupply: { major: 100n, minor: 0n },\n  });\n  expect(inspect(encoded2, { compact: false })).toMatchSnapshot();\n  expect(encode(encoded2)).toMatchSnapshot();\n});\n\ntest(\"getCurrencyHash\", async () => {\n  const legacy = await getCurrencyHash({\n    ticker: \"GOLD\",\n    decimalPlaces: 2,\n    minters: new Set([addressA]),\n    totalSupplyTrackable: false,\n    maximumSupply: null,\n  });\n  expect(toHex(legacy)).toMatchSnapshot();\n\n  const legacy2 = await getCurrencyHash({\n    ticker: \"NCG\",\n    decimalPlaces: 8,\n    minters: new Set([addressA, addressB]),\n    totalSupplyTrackable: false,\n    maximumSupply: null,\n  });\n  expect(toHex(legacy2)).toMatchSnapshot();\n\n  const legacy3 = await getCurrencyHash({\n    ticker: \"FOO\",\n    decimalPlaces: 0,\n    minters: new Set([]),\n    totalSupplyTrackable: false,\n    maximumSupply: null,\n  });\n  expect(toHex(legacy3)).toMatchSnapshot();\n\n  const legacy4 = await getCurrencyHash({\n    ticker: \"BAR\",\n    decimalPlaces: 1,\n    minters: null,\n    totalSupplyTrackable: false,\n    maximumSupply: null,\n  });\n  expect(toHex(legacy4)).toMatchSnapshot();\n\n  const uncapped = await getCurrencyHash({\n    ticker: \"BAZ\",\n    decimalPlaces: 1,\n    minters: null,\n    totalSupplyTrackable: true,\n    maximumSupply: null,\n  });\n  expect(toHex(uncapped)).toMatchSnapshot();\n\n  const capped = await getCurrencyHash({\n    ticker: \"BAZ\",\n    decimalPlaces: 1,\n    minters: null,\n    totalSupplyTrackable: true,\n    maximumSupply: { major: 100n, minor: 0n },\n  });\n  expect(toHex(capped)).toMatchSnapshot();\n});\n\nconst FOO: Currency = {\n  ticker: \"FOO\",\n  decimalPlaces: 2,\n  minters: null,\n  totalSupplyTrackable: true,\n  maximumSupply: null,\n};\n\nconst fooA = { rawValue: 12345n, currency: FOO };\nconst fooB = { rawValue: 45609n, currency: FOO };\nconst fooC = { rawValue: 10n, currency: FOO };\nconst fooD = { rawValue: 9n, currency: FOO };\nconst fooE = { rawValue: -78901n, currency: FOO };\nconst fooF = { rawValue: -2n, currency: FOO };\nconst fooG = { rawValue: 12300n, currency: FOO };\nconst fooH = { rawValue: 0n, currency: FOO };\n\ntest(\"getSign\", () => {\n  expect(getSign(fooA)).toBe(1);\n  expect(getSign(fooB)).toBe(1);\n  expect(getSign(fooC)).toBe(1);\n  expect(getSign(fooD)).toBe(1);\n  expect(getSign(fooE)).toBe(-1);\n  expect(getSign(fooF)).toBe(-1);\n  expect(getSign(fooG)).toBe(1);\n  expect(getSign(fooH)).toBe(0);\n});\n\ntest(\"getMajorUnit\", () => {\n  expect(getMajorUnit(fooA)).toBe(123n);\n  expect(getMajorUnit(fooB)).toBe(456n);\n  expect(getMajorUnit(fooC)).toBe(0n);\n  expect(getMajorUnit(fooD)).toBe(0n);\n  expect(getMajorUnit(fooE)).toBe(789n);\n  expect(getMajorUnit(fooF)).toBe(0n);\n  expect(getMajorUnit(fooG)).toBe(123n);\n  expect(getMajorUnit(fooH)).toBe(0n);\n});\n\ntest(\"getMinorUnit\", () => {\n  expect(getMinorUnit(fooA)).toBe(45n);\n  expect(getMinorUnit(fooB)).toBe(9n);\n  expect(getMinorUnit(fooC)).toBe(10n);\n  expect(getMinorUnit(fooD)).toBe(9n);\n  expect(getMinorUnit(fooE)).toBe(1n);\n  expect(getMinorUnit(fooF)).toBe(2n);\n  expect(getMinorUnit(fooG)).toBe(0n);\n  expect(getMinorUnit(fooH)).toBe(0n);\n});\n"
  },
  {
    "path": "@planetarium/tx/test/blockhash.test.ts",
    "content": "import { test } from \"vitest\";\nimport * as fc from \"fast-check\";\nimport { encodeBlockHash } from \"../src/blockhash\";\nimport { bytesEqual } from \"../src/bytes\";\n\ntest(\"encodeBlockHash\", () => {\n  fc.assert(\n    fc.property(\n      fc.uint8Array({ minLength: 32, maxLength: 32 }),\n      (bytes: Uint8Array) => {\n        const hash = encodeBlockHash(bytes);\n        return hash instanceof Uint8Array && bytesEqual(hash, bytes);\n      },\n    ),\n  );\n  fc.assert(\n    fc.property(\n      fc.uint8Array({ minLength: 0, maxLength: 31 }),\n      (shortBytes: Uint8Array) => {\n        try {\n          encodeBlockHash(shortBytes);\n        } catch (e) {\n          return e instanceof TypeError && e.message.includes(\"32 bytes\");\n        }\n      },\n    ),\n  );\n  fc.assert(\n    fc.property(fc.uint8Array({ minLength: 33 }), (longBytes: Uint8Array) => {\n      try {\n        encodeBlockHash(longBytes);\n      } catch (e) {\n        return e instanceof TypeError && e.message.includes(\"32 bytes\");\n      }\n    }),\n  );\n});\n"
  },
  {
    "path": "@planetarium/tx/test/hex.ts",
    "content": "\nconst hexTable: string[] = [];\nfor (let i = 0; i < 0x100; ++i) {\n  hexTable.push(i.toString(16).padStart(2, \"0\"));\n}\n\nexport function toHex(bytes: Uint8Array): string {\n  const result: string[] = [];\n  for (let i = 0; i < bytes.length; ++i) {\n    result.push(hexTable[bytes[i]]);\n  }\n  return result.join(\"\");\n}\n\nexport function fromHex(hex: string): Uint8Array {\n  if (hex.length % 2 !== 0) {\n    throw new RangeError(\"Invalid hex string; length must be even.\");\n  } else if (!hex.match(/^[0-9a-fA-F]*$/)) {\n    throw new RangeError(\"Invalid hex string; must be hexadecimal.\");\n  }\n  const result = new Uint8Array(hex.length / 2);\n  for (let i = 0; i < hex.length; i += 2) {\n    result[i / 2] = parseInt(hex.substring(i, i + 2), 16);\n  }\n  return result;\n}\n"
  },
  {
    "path": "@planetarium/tx/test/key.test.ts",
    "content": "import { test, expect } from \"vitest\";\nimport * as fc from \"fast-check\";\nimport { encodePublicKey } from \"../src/key\";\nimport { bytesEqual } from \"../src/bytes\";\n\ntest(\"encodePublicKey\", () => {\n  fc.assert(\n    fc.property(fc.uint8Array({ minLength: 1 }), (bytes: Uint8Array) => {\n      const key = encodePublicKey(bytes);\n      return key instanceof Uint8Array && bytesEqual(key, bytes);\n    }),\n  );\n  expect(() => encodePublicKey(new Uint8Array(0))).throws(TypeError, /empty/i);\n});\n"
  },
  {
    "path": "@planetarium/tx/test/setup.ts",
    "content": "import { expect } from \"vitest\";\nimport { Value, areValuesEqual } from \"@planetarium/bencodex\";\n\nexpect.extend({\n  toBeBencoded(\n    received: Value,\n    expected: Value,\n  ): { pass: boolean; message: () => string } {\n    if (areValuesEqual(received, expected)) {\n      return { pass: true, message: () => \"two values are equal\" };\n    }\n    // TODO: show diff\n    return { pass: false, message: () => \"two values are not equal\" };\n  },\n});\n"
  },
  {
    "path": "@planetarium/tx/test/tx/__snapshots__/metadata.test.ts.snap",
    "content": "// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html\n\nexports[`encodeTxMetadata 1`] = `\n\"BencodexDictionary(5) {\n  Uint8Array(1) [\n    110\n  ] => 123n,\n  Uint8Array(1) [\n    115\n  ] => Uint8Array(20) [\n    38,\n    131,\n    68,\n    186,\n    70,\n    230,\n    202,\n    42,\n    138,\n    80,\n    150,\n    86,\n    85,\n    72,\n    185,\n    1,\n    139,\n    198,\n    135,\n    206\n  ],\n  Uint8Array(1) [\n    117\n  ] => [],\n  Uint8Array(1) [\n    112\n  ] => Uint8Array(33) [\n    2,\n    0,\n    224,\n    39,\n    9,\n    204,\n    12,\n    5,\n    29,\n    193,\n    5,\n    24,\n    140,\n    69,\n    74,\n    46,\n    126,\n    247,\n    179,\n    107,\n    133,\n    218,\n    52,\n    82,\n    157,\n    58,\n    188,\n    25,\n    104,\n    22,\n    124,\n    245,\n    79\n  ],\n  Uint8Array(1) [\n    116\n  ] => '2022-05-23T01:02:00.000000Z'\n}\"\n`;\n\nexports[`encodeTxMetadata 2`] = `\nUint8Array [\n  100,\n  49,\n  58,\n  110,\n  105,\n  49,\n  50,\n  51,\n  101,\n  49,\n  58,\n  112,\n  51,\n  51,\n  58,\n  2,\n  0,\n  224,\n  39,\n  9,\n  204,\n  12,\n  5,\n  29,\n  193,\n  5,\n  24,\n  140,\n  69,\n  74,\n  46,\n  126,\n  247,\n  179,\n  107,\n  133,\n  218,\n  52,\n  82,\n  157,\n  58,\n  188,\n  25,\n  104,\n  22,\n  124,\n  245,\n  79,\n  49,\n  58,\n  115,\n  50,\n  48,\n  58,\n  38,\n  131,\n  68,\n  186,\n  70,\n  230,\n  202,\n  42,\n  138,\n  80,\n  150,\n  86,\n  85,\n  72,\n  185,\n  1,\n  139,\n  198,\n  135,\n  206,\n  49,\n  58,\n  116,\n  117,\n  50,\n  55,\n  58,\n  50,\n  48,\n  50,\n  50,\n  45,\n  48,\n  53,\n  45,\n  50,\n  51,\n  84,\n  48,\n  49,\n  58,\n  48,\n  50,\n  58,\n  48,\n  48,\n  46,\n  48,\n  48,\n  48,\n  48,\n  48,\n  48,\n  90,\n  49,\n  58,\n  117,\n  108,\n  101,\n  101,\n]\n`;\n"
  },
  {
    "path": "@planetarium/tx/test/tx/fixtures.ts",
    "content": "import { Address, RawPrivateKey } from \"@planetarium/account\";\nimport { fromHex } from \"../hex\";\nimport { Currency } from \"../../src/assets\";\n\nexport const FOO: Currency = {\n  ticker: \"FOO\",\n  decimalPlaces: 2,\n  minters: null,\n  totalSupplyTrackable: true,\n  maximumSupply: null,\n};\n\nexport const account1 = RawPrivateKey.fromHex(\n  \"9bf4664ba09a89faeb684b94e69ffde01d26ae14b556204d3f6ab58f61f78418\",\n);\n\nexport const address1 = await Address.deriveFrom(account1);\n\n// FIXME: Replace this with account1/address1:\nexport const key1 = {\n  private: account1.toBytes(),\n  public: (await account1.getPublicKey()).toBytes(\"compressed\"),\n  address: address1.toBytes(),\n};\n\nexport const account2 = RawPrivateKey.fromHex(\n  \"fcf30b333d04ccfeb562f000a32df488e7154949d31ddcac3cf9278acb5786c7\",\n);\n\nexport const address2 = await Address.deriveFrom(account2);\n\n// FIXME: Replace this with account2/address2:\nexport const key2 = {\n  private: account2.toBytes(),\n  public: (await account2.getPublicKey()).toBytes(\"compressed\"),\n  address: address2.toBytes(),\n};\n"
  },
  {
    "path": "@planetarium/tx/test/tx/metadata.test.ts",
    "content": "import { inspect } from \"node:util\";\nimport { encode } from \"@planetarium/bencodex\";\nimport { expect, test } from \"vitest\";\nimport { encodeTxMetadata } from \"../../src/tx/metadata\";\nimport { key1 } from \"./fixtures\";\n\ntest(\"encodeTxMetadata\", () => {\n  const encoded = encodeTxMetadata({\n    nonce: 123n,\n    publicKey: key1.public,\n    signer: key1.address,\n    timestamp: new Date(\"2022-05-23T01:02:00+00:00\"),\n    updatedAddresses: new Set(),\n    genesisHash: null,\n    maxGasPrice: null,\n    gasLimit: null,\n  });\n  expect(inspect(encoded, { compact: false })).toMatchSnapshot();\n  expect(encode(encoded)).toMatchSnapshot();\n});\n"
  },
  {
    "path": "@planetarium/tx/test/tx/signed.test.ts",
    "content": "import { join } from \"node:path\";\nimport { RecordView, encode } from \"@planetarium/bencodex\";\nimport { execa } from \"execa\";\nimport { describe, expect, test } from \"vitest\";\nimport { encodeSignedTx, signTx } from \"../../src/tx/signed\";\nimport { type UnsignedTx } from \"../../src/tx/unsigned\";\nimport { account1, address1 } from \"./fixtures\";\n\ndescribe(\"signTx\", () => {\n  test(\"UnsignedTx\", async () => {\n    const unsigned: UnsignedTx = {\n      nonce: 123n,\n      publicKey: account1.publicKey.toBytes(\"uncompressed\"),\n      signer: address1.toBytes(),\n      timestamp: new Date(\"2022-05-23T01:02:00+00:00\"),\n      updatedAddresses: new Set(),\n      genesisHash: null,\n      maxGasPrice: null,\n      gasLimit: null,\n      actions: [\n        new RecordView(\n          {\n            type_id: \"transfer_asset\",\n            values: new RecordView(\n              {\n                amount: [\n                  new RecordView(\n                    {\n                      decimalPlaces: Buffer.from([0x02]),\n                      minters: [\n                        Buffer.from(\n                          \"47d082a115c63e7b58b1532d20e631538eafadde\",\n                          \"hex\"\n                        ),\n                      ],\n                      ticker: \"NCG\",\n                    },\n                    \"text\"\n                  ),\n                  1000n,\n                ],\n                recipient: Buffer.from(\n                  \"5a533067D0cBa77490268b26195EdB10B990143D\",\n                  \"hex\"\n                ),\n                sender: Buffer.from(\n                  \"111CB8E18c6D70f5032000c5739c5ac36E793EDB\",\n                  \"hex\"\n                ),\n              },\n              \"text\"\n            ),\n          },\n          \"text\"\n        ),\n      ],\n    };\n    const signed = await signTx(unsigned, account1);\n    const encoded = await encodeSignedTx(signed);\n    const payload = encode(encoded);\n    const { stdout } = await execa(\n      \"dotnet\",\n      [\n        \"run\",\n        \"--no-build\",\n        \"--project\",\n        join(__dirname, \"..\", \"..\", \"..\", \"..\", \"tools\", \"Libplanet.Tools\"),\n        \"--\",\n        \"tx\",\n        \"analyze\",\n        \"-\",\n      ],\n      { input: payload }\n    );\n    expect(JSON.parse(stdout)).toStrictEqual({\n      id: \"49a645bb80fa96757009615ec33bc15a2e90e9121877de9f14de35b7d657a118\",\n      nonce: 123,\n      signer: \"268344BA46e6CA2A8a5096565548b9018bc687Ce\",\n      updatedAddresses: [],\n      signature: Buffer.from(signed.signature.toBytes()).toString(\"base64\"),\n      actions: [\n        {\n          \"\\ufefftype_id\": \"\\ufefftransfer_asset\",\n          \"\\ufeffvalues\": {\n            \"\\ufeffamount\": [\n              {\n                \"\\ufeffdecimalPlaces\": \"0x02\",\n                \"\\ufeffminters\": [\"0x47d082a115c63e7b58b1532d20e631538eafadde\"],\n                \"\\ufeffticker\": \"\\ufeffNCG\",\n              },\n              \"1000\",\n            ],\n            \"\\ufeffsender\": \"0x111cb8e18c6d70f5032000c5739c5ac36e793edb\",\n            \"\\ufeffrecipient\": \"0x5a533067d0cba77490268b26195edb10b990143d\",\n          },\n        },\n      ],\n      timestamp: \"2022-05-23T01:02:00+00:00\",\n      publicKey:\n        \"0200e02709cc0c051dc105188c454a2e7ef7b36b85da34529d3abc1968167cf54f\",\n      genesisHash: null,\n      gasLimit: null,\n      maxGasPrice: null,\n    });\n  }, 30_000);\n});\n"
  },
  {
    "path": "@planetarium/tx/test/tx/unsigned.test.ts",
    "content": "import { join } from \"node:path\";\nimport { RecordView, encode } from \"@planetarium/bencodex\";\nimport { execa } from \"execa\";\nimport { expect, test } from \"vitest\";\nimport { encodeUnsignedTx } from \"../../src/tx/unsigned\";\nimport { key1 } from \"./fixtures\";\n\ntest(\"encodeUnsignedTx\", async () => {\n  const encoded = encodeUnsignedTx({\n    nonce: 123n,\n    publicKey: key1.public,\n    signer: key1.address,\n    timestamp: new Date(\"2022-05-23T01:02:00+00:00\"),\n    updatedAddresses: new Set(),\n    genesisHash: null,\n    gasLimit: null,\n    maxGasPrice: null,\n    actions: [\n      new RecordView(\n        {\n          type_id: \"transfer_asset\",\n          values: {\n            amount: [\n              new RecordView(\n                {\n                  decimalPlaces: new Uint8Array([0x02]),\n                  minters: [\n                    new Uint8Array(\n                      Buffer.from(\n                        \"47d082a115c63e7b58b1532d20e631538eafadde\",\n                        \"hex\"\n                      )\n                    ),\n                  ],\n                  ticker: \"NCG\",\n                },\n                \"text\"\n              ),\n              1000n,\n            ],\n            recipient: new Uint8Array(\n              Buffer.from(\"5a533067D0cBa77490268b26195EdB10B990143D\", \"hex\")\n            ),\n            sender: new Uint8Array(\n              Buffer.from(\"111CB8E18c6D70f5032000c5739c5ac36E793EDB\", \"hex\")\n            ),\n          },\n        },\n        \"text\"\n      ),\n    ],\n  });\n  const payload = encode(encoded);\n  const { stdout } = await execa(\n    \"dotnet\",\n    [\n      \"run\",\n      \"--no-build\",\n      \"--project\",\n      join(__dirname, \"..\", \"..\", \"..\", \"..\", \"tools\", \"Libplanet.Tools\"),\n      \"--\",\n      \"tx\",\n      \"analyze\",\n      \"--unsigned\",\n      \"-\",\n    ],\n    {\n      input: Buffer.from(payload),\n    }\n  );\n  expect(JSON.parse(stdout)).toStrictEqual({\n    nonce: 123,\n    signer: \"268344BA46e6CA2A8a5096565548b9018bc687Ce\",\n    updatedAddresses: [],\n    actions: [\n      {\n        \"\\ufefftype_id\": \"\\ufefftransfer_asset\",\n        \"\\ufeffvalues\": {\n          \"\\ufeffamount\": [\n            {\n              \"\\ufeffdecimalPlaces\": \"0x02\",\n              \"\\ufeffminters\": [\"0x47d082a115c63e7b58b1532d20e631538eafadde\"],\n              \"\\ufeffticker\": \"\\ufeffNCG\",\n            },\n            \"1000\",\n          ],\n          \"\\ufeffsender\": \"0x111cb8e18c6d70f5032000c5739c5ac36e793edb\",\n          \"\\ufeffrecipient\": \"0x5a533067d0cba77490268b26195edb10b990143d\",\n        },\n      },\n    ],\n    timestamp: \"2022-05-23T01:02:00+00:00\",\n    publicKey:\n      \"0200e02709cc0c051dc105188c454a2e7ef7b36b85da34529d3abc1968167cf54f\",\n    genesisHash: null,\n    gasLimit: null,\n    maxGasPrice: null,\n  });\n}, 30_000);\n"
  },
  {
    "path": "@planetarium/tx/tsconfig.json",
    "content": "{\n  \"include\": [\"./src\", \"*.d.ts\", \"*.ts\"],\n  \"compilerOptions\": {\n    \"outDir\": \"dist\",\n    \"target\": \"ES2022\",\n    \"strict\": true,\n    \"noUnusedLocals\": true,\n    \"noImplicitReturns\": true,\n    \"esModuleInterop\": true,\n    \"skipLibCheck\": true,\n    \"forceConsistentCasingInFileNames\": true,\n    \"module\": \"nodenext\",\n    \"moduleResolution\": \"nodenext\"\n  }\n}\n"
  },
  {
    "path": "@planetarium/tx/vitest.config.ts",
    "content": "import { defineConfig } from \"vitest/config\";\n\nexport default defineConfig({\n  test: {\n    setupFiles: [\"./test/setup.ts\"],\n    cache: false,\n  },\n});\n"
  },
  {
    "path": "CHANGES.md",
    "content": "Libplanet changelog\n===================\n\nVersion 6.0.0\n-------------\n\nTo be released.\n\nFrom this version Libplanet projects use .NET 8.0 as target framework.\nTherefore `BinaryFormatter` related methods are removed\nsince it has been deprecated. See also: [.NET Document]\n\nAdded new projects:\n -  Libplanet.Node\n -  Libplanet.Node.Executable\n -  Libplanet.Node.Extensions\n -  Libplanet.Node.Tests\n\nLibplanet.Node is a project that helps users easily configure\nLibplanet-based nodes.\n\n### Deprecated APIs\n\n -  All classes became not to inherit `ISerializable` anymore.\n\n### Backward-incompatible API changes\n\n### Backward-incompatible network protocol changes\n\n### Backward-incompatible storage format changes\n\n### Added APIs\n\n### Behavioral changes\n\n### Bug fixes\n\n### Dependencies\n\n### CLI tools\n\n\n[.NET Document]: https://learn.microsoft.com/en-us/dotnet/core/compatibility/serialization/8.0/binaryformatter-disabled\n\n\nPrevious version changes\n------------------------\n\n -  [Version 5.x.x]\n -  [Version 4.x.x]\n -  [Version 3.x.x]\n -  [Version 2.x.x]\n -  [Version 1.x.x]\n -  [Version 0.x.x]\n\n\n[Version 4.x.x]: ./changes/v5.md\n[Version 4.x.x]: ./changes/v4.md\n[Version 3.x.x]: ./changes/v3.md\n[Version 2.x.x]: ./changes/v2.md\n[Version 1.x.x]: ./changes/v1.md\n[Version 0.x.x]: ./changes/v0.md\n"
  },
  {
    "path": "CONTRIBUTING.md",
    "content": "Contributor guide\n=================\n\nNote: This document at present is for only code contributors.\nWe should expand it so that it covers reporting bugs, filing issues,\nand writing docs.\n\n\nQuestions & online chat  [![Discord](https://img.shields.io/discord/928926944937013338.svg?color=7289da&logo=discord&logoColor=white)][Discord server]\n-----------------------\n\nWe have a [Discord server] to discuss Libplanet.  There are some channels\nfor purposes in the *Libplanet* category:\n\n -  *#libplanet-users*: Chat with game programmers who use Libplanet.\n    Ask questions to *use* Libplanet for your games.  People here usually\n    speak in Korean, but feel free to speak in English.\n -  *#libplanet-dev*: Chat with maintainers and contributors of Libplanet.\n    Ask questions to *hack* Libplanet and to make a patch for it.  People here\n    usually speak in Korean, but feel free to speak in English.\n\n[Discord server]: https://link.planetarium.dev/libplanet-contributing--pl-dev-discord\n\n\nPrerequisites\n-------------\n\nYou need [.NET Core] SDK 6.0+ which provides the latest C# compiler and .NET VM.\nRead and follow the instruction to install .NET Core SDK on\nthe [.NET Core downloads page][1].\nFYI if you use macOS and [Homebrew] you can install it by\n`brew cask install dotnet-sdk` command.\n\nMake sure that your .NET Core SDK is 6.0 or higher.  You could show\nthe version you are using by `dotnet --info` command.\n\nAlthough it is not necessary, you should install a proper IDE for .NET\n(or an [OmniSharp] extension for your favorite editor — except it takes\nhours to properly configure and integrate with your editor).\nC# is not like JavaScript or Python; it is painful to code in C# without IDE.\n\nUnless you already have your favorite setup, we recommend you to use\n[Visual Studio Code].  It is free, open source, and made by Microsoft, which\nmade .NET as well.  So Visual Studio Code has a [first-party C# extension][2]\nwhich works well together.\n\n[.NET Core]: https://dot.net/\n[Homebrew]: https://brew.sh/\n[OmniSharp]: http://www.omnisharp.net/\n[Visual Studio Code]: https://code.visualstudio.com/\n[1]: https://dotnet.microsoft.com/download\n[2]: https://marketplace.visualstudio.com/items?itemName=ms-vscode.csharp\n\n\nBuild\n-----\n\nThe following command installs dependencies (required library packages) and\nbuilds the entire *Libplanet* solution:\n\n    dotnet build\n\nWe use [SonarAnalyzer] to check our code quality but it takes longer to build.\nTo skip the analyzer, you can use:\n\n    dotnet build -p:SkipSonar=true\n\n[SonarAnalyzer]: https://github.com/SonarSource/sonar-dotnet\n\n### Mono\n\nTo build the solution with Mono, you must use the *ReleaseMono* solution\nconfiguration. It is identical with *Release* target (creates built files\nunder `{bin,obj}/Release` directory), except that *ReleaseMono* excludes\nprojects with dependencies that are incompatible with Mono\n(*Libplanet.Explorer&ast;*):\n\n    msbuild -restore -p:Configuration=ReleaseMono -p:TestsTargetFramework=net47\n\n\nProjects\n--------\n\nThe [planetarium/libplanet](https://github.com/planetarium/libplanet) repository\non GitHub consists of several projects.  There are two types of projects:\n\n -  .NET projects under the umbrella of *Libplanet.sln*\n -  TypeScript/JavaScript project under the [Yarn 3 workspace]\n\n[Yarn 3 workspace]: https://yarnpkg.com/features/workspaces\n\n\n### .NET projects\n\n -  *Libplanet*: The main project, which contains the most of implementation\n    code.  It is distributed as a NuGet package with the same name:\n    *[Libplanet][NuGet package]*.\n\n -  *Libplanet.Common*: The common utilities and extensions for *Libplanet*.\n    This is distributed as a distinct NuGet package:\n    *[Libplanet.Common][NuGet package]*.\n\n -  *Libplanet.Crypto*: The cryptography library for *Libplanet*.\n    This is distributed as a distinct NuGet package:\n    *[Libplanet.Crypto][NuGet package]*.\n\n -  *Libplanet.Types*: The common types for *Libplanet*.\n    This is distributed as a distinct NuGet package:\n    *[Libplanet.Types][NuGet package]*.\n\n -  *Libplanet.Store*: The store related functionalities for *Libplanet*.\n    This is distributed as a distinct NuGet package:\n    *[Libplanet.Store][NuGet package]*.\n\n -  *Libplanet.Action*: The action evaluation layer for *Libplanet*.\n    This is distributed as a distinct NuGet package:\n    *[Libplanet.Action][NuGet package]*.\n\n -  *Libplanet.Net*: The peer-to-peer networking layer built on top of\n    *Libplanet*.  This is distributed as a distinct NuGet package:\n    *[Libplanet.Net]*.\n\n -  *Libplanet.Stun*: The project dedicated to implement [TURN & STUN].\n    This is distributed as a distinct NuGet package: *[Libplanet.Stun]*.\n\n -  *Libplanet.Crypto.Secp256k1*: The `ICryptoBackend<T>` implementation built\n    on native [libsecp256k1].  As this depends on a platform-dependent library\n    (which is written in C), this is distributed as a distinct NuGet package:\n    *[Libplanet.Crypto.Secp256k1]*.\n\n -  *Libplanet.RocksDBStore*: The `IStore` implementation built on [RocksDB].\n    As this depends on platform-dependent libraries (which is written in C/C++),\n    this is distributed as a distinct NuGet package: *[Libplanet.RocksDBStore]*.\n\n -  *Libplanet.Store.Remote*: The `IKeyValueStore` implementation for use with\n    *Libplanet.Store* to store data in a remote server and communicate using\n    [gRPC]. This is cannot be used standalone. Need `IKeyValueStore`\n    implementation for local storage like *[Libplanet.RocksDBStore]*.\n\n -  *Libplanet.Mocks*: A mocking tool to be used for development when\n    designing `IAction`s and writing test codes.  This should not be\n    used or referenced in production code.\n\n -  *Libplanet.Analyzers*: Roslyn Analyzer (i.e., lint) for game programmers who\n    use Libplanet.  This project is distributed as a distinct NuGet package:\n    *[Libplanet.Analyzers]*.\n\n -  *Libplanet.Extensions.Cocona*: The project to provide the [Cocona] commands\n    to handle *Libplanet* structures in command line.  This is  distributed as\n    a distinct NuGet package: *[Libplanet.Extensions.Cocona]*.\n\n -  *Libplanet.Tools*: The CLI tools for Libplanet.  This project is distributed\n    as a distinct NuGet package: *[Libplanet.Tools]*. See its own\n    [README.md](tools/Libplanet.Tools/README.md).\n\n -  *Libplanet.Explorer*: Libplanet Explorer, a web server that exposes\n    a Libplanet blockchain as a [GraphQL] endpoint.  There is the official\n    web front-end depending on this too: [libplanet-explorer-frontend].\n    Note that this project in itself is a library, and packaging it as\n    an executable is done by a below project named\n    *Libplanet.Explorer.Executable*.\n\n -  *Libplanet.Explorer.Cocona*: Provides [Cocona] commands related to\n    *Libplanet.Explorer*.\n\n -  *Libplanet.Explorer.Executable*: (**DEPRECATED**) Turns Libplanet Explorer\n    into a single executable binary so that it is easy to distribute.\n\n -  *Libplanet.Node*: Library used to build libplanet node easily.\n    This project is distributed as a distinct NuGet package: *[Libplanet.Node]*.\n    See its own [README.md](sdk/node/Libplanet.Node/README.md).\n\n -  *Libplanet.Node.Extensions*: Provides extensions methods for\n    *Libplanet.Node*.\n\n -  *Libplanet.Node.Executable*: Turns Libplanet Node into a single executable\n    binary so that it is easy to distribute.\n\n -  *Libplanet.Benchmarks*: Performance benchmarks.\n    See the [*Benchmarks*](#benchmarks) section below.\n\n -  *Libplanet.Tests*: Unit tests for the *Libplanet* project.  See the *Tests*\n    section below.\n\n -  *Libplanet.Action.Tests*: Unit tests for the *Libplanet.Action* project.\n\n -  *Libplanet.Net.Tests*: Unit tests for the *Libplanet.Net* project.\n\n -  *Libplanet.Stun.Tests*: Unit tests of the *Libplanet.Stun* project.\n\n -  *Libplanet.Crypto.Secp256k1.Tests*: Unit tests for\n    the *Libplanet.Crypto.Secp256k1* project.\n\n -  *Libplanet.RocksDBStore.Tests*: Unit tests for the *Libplanet.RocksDBStore*\n    project.\n\n -  *Libplanet.Store.Remote.Tests*: Unit tests for the *Libplanet.Store.Remote*\n    project.\n\n -  *Libplanet.Analyzers.Tests*: Unit tests for the *Libplanet.Analyzers*\n    project.\n\n -  *Libplanet.Explorer.Tests*: Unit tests for the *Libplanet.Explorer*\n    project.\n\n -  *Libplanet.Explorer.Cocona.Tests*: Unit tests for the\n    *Libplanet.Explorer.Cocona* project.\n\n -  *Libplanet.Extensions.Cocona.Tests*: Unit tests for the\n    *Libplanet.Extensions.Cocona* project.\n\n -  *Libplanet.Node.Tests*: Unit tests for the *Libplanet.Node* project.\n\n\n[NuGet package]: https://www.nuget.org/packages/Libplanet/\n[Libplanet.Net]: https://www.nuget.org/packages/Libplanet.Net/\n[TURN & STUN]: https://snack.planetarium.dev/eng/2019/06/nat_traversal_2/\n[libsecp256k1]: https://github.com/bitcoin-core/secp256k1\n[RocksDB]: https://rocksdb.org/\n[gRPC]: https://grpc.io/\n[Libplanet.Stun]: https://www.nuget.org/packages/Libplanet.Stun/\n[Libplanet.Crypto.Secp256k1]: https://www.nuget.org/packages/Libplanet.Crypto.Secp256k1/\n[Libplanet.RocksDBStore]: https://www.nuget.org/packages/Libplanet.RocksDBStore/\n[Libplanet.Analyzers]: https://www.nuget.org/packages/Libplanet.Analyzers/\n[Cocona]: https://www.nuget.org/packages/Cocona\n[Libplanet.Node]: https://www.nuget.org/packages/Libplanet.Node\n[Libplanet.Extensions.Cocona]: https://www.nuget.org/packages/Libplanet.Extensions.Cocona\n[Libplanet.Tools]: https://www.nuget.org/packages/Libplanet.Tools/\n[GraphQL]: https://graphql.org/\n[libplanet-explorer-frontend]: https://github.com/planetarium/libplanet-explorer-frontend\n\n\nTests [![Build Status (CircleCI)](https://circleci.com/gh/planetarium/libplanet/tree/main.svg?style=shield)][CircleCI] [![Codecov](https://codecov.io/gh/planetarium/libplanet/branch/main/graph/badge.svg)][2]\n-----\n\nWe write as complete tests as possible to the corresponding implementation code.\nGoing near to the [code coverage][3] 100% is one of our goals.\n\nThe *Libplanet* solution consists of several projects.\nEvery project without *.Tests* suffix is an actual implementation.\nThese are built to *Libplanet\\*.dll* assemblies and packed into one NuGet\npackage.\n\n*Libplanet\\*.Tests* is a test suite for the *Libplanet\\*.dll* assembly.\nAll of them depend on [Xunit], and every namespace and class in these\ncorresponds to one in *Libplanet&ast;* projects.\nIf there's *Libplanet.Foo.Bar* class there also should be\n*Libplanet.Foo.Bar.Tests* to test it.\n\nTo build and run unit tests at a time with .NET Core execute the below command:\n\n    dotnet test\n\nTo run unit tests with .NET Framework on Windows:\n\n~~~~ pwsh\nnuget install xunit.runner.console -Version 2.4.1\nmsbuild /restore /p:TestsTargetFramework=net472\n& (gci xunit.runner.console.*\\tools\\net472\\xunit.console.exe | select -f 1) `\n  (gci *.Tests\\bin\\Debug\\net472\\*.Tests.dll)\n~~~~\n\nOr with Mono (As mentioned above in the [Mono](#Mono) section, use\n*ReleaseMono* solution configuration to avoid dependency issues):\n\n~~~~ bash\nnuget install xunit.runner.console\nmsbuild /restore /p:Configuration=ReleaseMono /p:TestsTargetFramework=net47\nmono xunit.runner.console.*/tools/net47/xunit.console.exe \\\n    *.Tests/bin/Release/net47/*.Tests.dll\n~~~~\n\n[CircleCI]: https://app.circleci.com/pipelines/github/planetarium/libplanet\n[3]: https://codecov.io/gh/planetarium/libplanet\n[Xunit]: https://xunit.github.io/\n\n\n### `TURN_SERVER_URLS`\n\nSome tests depend on a TURN server.  If `TURN_SERVER_URLS` environment variable\nis present, these tests also run.  Otherwise, these tests are skipped.\n\nAs the name implies, `TURN_SERVER_URLS` can have more than one TURN server URL.\nURLs are separated by whitespaces like `turn://user:password@host:3478/\nturn://user:password@host2:3478/`.  If multiple TURN servers are provided,\neach test case pick a random one to use so that loads are balanced.\n\nFYI there are several TURN implementations like [Coturn] and [gortc/turn],\nor cloud offers like [Xirsys].\n\n[Coturn]: https://github.com/coturn/coturn\n[gortc/turn]: https://github.com/gortc/turn\n[Xirsys]: https://xirsys.com/\n\n\n### [xunit-unity-runner]\n\nUnity is one of our platforms we primarily target to support, so we've been\ntesting Libplanet on the actual Unity runtime, and you could see whether it's\npassed on [CircleCI].\n\nHowever, if it fails and it does not fail on other platforms but only Unity,\nyou need to run Unity tests on your own machine so that you rapidily and\nrepeatedly tinker things, make a try, and immediately get feedback from them.\n\nHere's how to run Unity tests on your machine.  We've made and used\n[xunit-unity-runner] to run [Xunit] tests on the actual Unity runtime,\nand our build jobs on CircleCI also use this.  This test runner\nis actually a Unity app, though it's not a game app.  As of June 2019,\nthere are [executable binaries][4] for Linux, macOS, and Windows.\nIts usage is simple.  It's a CLI app that takes *absolute* paths to\n.NET assemblies (*.dll*) that consist of test classes (based on Xunit).\n\nYou can build these assemblies using `msbuild -r` Mono or .NET Framework\nprovide.\n*You can't build them using `dotnet build` command or `dotnet msbuild`,*\nbecause the Unity runtime is not based on .NET Core but Mono,\nwhich is compatible with .NET Framework 4.7.\nPlease be sure that Mono's *bin* directory is prior to .NET Core's one\n(or it's okay too if .NET Core is not installed at all).  Mono or .NET\nFramework's `msbuild` could try to use .NET Core's version of several\nutilities during build, and this could cause some errors.\nAlso be aware that you must be building the solution with the *ReleaseMono*\nconfiguration, as mentioned in the [Mono](#Mono) section.\n\nThe way to execute the runner binary depend on the platform.  For details,\nplease read [xunit-unity-runner]'s README.  FYI you can use `-h`/`--help`\noption as well.\n\nTo sum up, the instruction is like below (the example is assuming Linux):\n\n    msbuild -r -p:Configuration=ReleaseMono -p:TestsTargetFramework=net47\n    xunit-unity-runner/StandaloneLinux64 \\\n      \"$PWD\"/*.Tests/bin/Release/net47/*.Tests.dll\n\n[xunit-unity-runner]: https://github.com/planetarium/xunit-unity-runner\n[4]: https://github.com/planetarium/xunit-unity-runner/releases/latest\n\n\nStyle convention\n----------------\n\nPlease follow the existing coding convention.  We are already using several\nstatic analyzers.  They are automatically executed together with `msbuild`,\nand will warn you if there are any style errors.\n\nYou should also register Git hooks we commonly use:\n\n    git config core.hooksPath hooks\n\nWe highly recommend you to install an extension for [EditorConfig] in your\nfavorite editor.  Some recent editors have built-in support for EditorConfig,\ne.g., Rider (IntelliJ IDEA), Visual Studio.  Many editors have an extension to\nsupport EditorConfig, e.g., [Atom], [Emacs], [Vim], [VS Code].\n\n[EditorConfig]: https://editorconfig.org/\n[Atom]: https://atom.io/packages/editorconfig\n[Emacs]: https://github.com/editorconfig/editorconfig-emacs\n[Vim]: https://github.com/editorconfig/editorconfig-vim\n[VS Code]: https://marketplace.visualstudio.com/items?itemName=EditorConfig.EditorConfig\n\n\nBenchmarks\n----------\n\nIn order to track performance improvements or regressions, we maintain a set of\nbenchmarks and continuously measure them in the CI.  You can run benchmarks\non your local environment too:\n\n    dotnet run --project tools/Libplanet.Benchmarks -c Release -- -j short -f \"*\"\n\nNote that there is `-j short`; without this a whole set of benchmarks takes\nquite a long time.  This will print like below:\n\n    |               Method | UnrollFactor |      Mean |      Error |    StdDev |\n    |--------------------- |------------- |----------:|-----------:|----------:|\n    |       MineBlockEmpty |           16 |  12.20 ms |  11.649 ms | 0.6385 ms |\n    |  MineBlockOneTran... |            1 |  14.54 ms |   3.602 ms | 0.1974 ms |\n    |                  ... |          ... |       ... |        ... |       ... |\n\nYou can measure only part of benchmarks by `-f`/`--filter`ing them:\n\n    dotnet run --project tools/Libplanet.Benchmarks -c Release -- -j short-f \"*MineBlock*\"\n\nAll benchmark code is placed under *Libplanet.Benchmarks* project.\nAs our benchmarks are based on [BenchmarkDotNet], please read their official\ndocs for details.\n\n[BenchmarkDotNet]: https://benchmarkdotnet.org/\n\n\nReleasing a new version\n-----------------------\n\nRead the [Releasing guide](RELEASE.md) which dedicates to this topic.\n"
  },
  {
    "path": "Directory.Build.props",
    "content": "<Project>\n\n  <PropertyGroup>\n    <TargetFrameworks Condition=\"'$(_IsPacking)'=='true'\">net8.0</TargetFrameworks>\n    <TargetFramework Condition=\"'$(_IsPacking)'!='true'\">net8.0</TargetFramework>\n    <LangVersion>10</LangVersion>\n    <VersionPrefix>6.0.0</VersionPrefix>\n    <!-- Note: don't be confused by the word \"prefix\" here.  It's merely a\n    version without suffix like \"-dev.123\".  See the following examples:\n    Version: 1.2.3-dev.456\n    VersionPrefix: 1.2.3\n    VersionSuffix: dev.456\n    If it's a stable release the version becomes like:\n    Version: 1.2.3\n    VersionPrefix: 1.2.3\n    VersionSuffix: (N/A)\n    Note that the version suffix is filled through CLI option of dotnet command.\n    -->\n    <Nullable>enable</Nullable>\n    <PackageProjectUrl>https://libplanet.io/</PackageProjectUrl>\n    <RepositoryUrl>https://github.com/planetarium/libplanet.git</RepositoryUrl>\n    <RepositoryType>git</RepositoryType>\n    <Company>Planetarium</Company>\n    <Authors>Planetarium</Authors>\n    <PackageLicenseExpression>LGPL-2.1-or-later</PackageLicenseExpression>\n    <RequireLicenseAcceptance>true</RequireLicenseAcceptance>\n    <CodeAnalysisRuleSet>$(MSBuildThisFileDirectory)Libplanet.ruleset</CodeAnalysisRuleSet>\n    <CheckForOverflowUnderflow>true</CheckForOverflowUnderflow>\n    <NoWarn>$(NoWarn);S4035;CS1591;NU5104;MEN001;NU1902</NoWarn>\n\n    <PackageReleaseNotes>https://github.com/planetarium/libplanet/blob/main/CHANGES.md</PackageReleaseNotes>\n    <PackageTags>multiplayer online game;game;blockchain</PackageTags>\n    <PackageReadmeFile>README.md</PackageReadmeFile>\n    <PackageIcon>icon.png</PackageIcon>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <None Include=\"$(MSBuildThisFileDirectory)CHANGES.md\" Pack=\"true\" PackagePath=\"CHANGES.md\" />\n    <None Include=\"$(MSBuildThisFileDirectory)LICENSE\" Pack=\"true\" PackagePath=\"LICENSE.txt\" />\n    <None Include=\"$(MSBuildThisFileDirectory)README.md\" Pack=\"true\" PackagePath=\"README.md\" />\n    <None Include=\"$(MSBuildThisFileDirectory)icon.png\" Pack=\"true\" PackagePath=\"icon.png\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <AdditionalFiles Include=\"$(MSBuildThisFileDirectory)Menees.Analyzers.Settings.xml\">\n      <Link>Menees.Analyzers.Settings.xml</Link>\n    </AdditionalFiles>\n    <AdditionalFiles Include=\"$(MSBuildThisFileDirectory)stylecop.json\" />\n  </ItemGroup>\n\n  <ItemGroup>\n     <PackageReference Include=\"Menees.Analyzers.2017\" Version=\"2.0.3\">\n      <PrivateAssets>all</PrivateAssets>\n      <IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>\n    </PackageReference>\n    <PackageReference Include=\"Microsoft.DotNet.Analyzers.Compatibility\" Version=\"0.2.12-alpha\">\n      <PrivateAssets>all</PrivateAssets>\n      <IncludeAssets>\n        runtime; build; native; contentfiles; analyzers; buildtransitive\n      </IncludeAssets>\n    </PackageReference>\n    <PackageReference Include=\"StyleCop.Analyzers\" Version=\"1.2.0-beta.164\">\n      <PrivateAssets>all</PrivateAssets>\n      <IncludeAssets>\n        runtime; build; native; contentfiles; analyzers\n      </IncludeAssets>\n    </PackageReference>\n  </ItemGroup>\n\n  <ItemGroup Condition=\"'$(SkipSonar)' != 'true'\">\n    <PackageReference Include=\"SonarAnalyzer.CSharp\" Version=\"8.12.0.21095\">\n      <IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>\n      <PrivateAssets>all</PrivateAssets>\n    </PackageReference>\n  </ItemGroup>\n\n</Project>\n"
  },
  {
    "path": "Dockerfile.explorer",
    "content": "FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build-env\nWORKDIR /app\n\n# Copy csproj and restore as distinct layers\n# Note that it's ordered by the least frequently changed\nCOPY ./Directory.Build.props ./\nCOPY ./src/Directory.Build.props ./src/\nCOPY ./tools/Directory.Build.props ./tools/\nCOPY ./src/Libplanet.Stun/Libplanet.Stun.csproj ./src/Libplanet.Stun/\nRUN dotnet restore src/Libplanet.Stun\nCOPY ./src/Libplanet.RocksDBStore/Libplanet.RocksDBStore.csproj ./src/Libplanet.RocksDBStore/\nRUN dotnet restore src/Libplanet.RocksDBStore\nCOPY ./tools/Libplanet.Explorer.Executable/Libplanet.Explorer.Executable.csproj ./tools/Libplanet.Explorer.Executable/\nRUN dotnet restore tools/Libplanet.Explorer.Executable\nCOPY ./tools/Libplanet.Explorer/Libplanet.Explorer.csproj ./tools/Libplanet.Explorer/\nRUN dotnet restore tools/Libplanet.Explorer\nCOPY ./src/Libplanet/Libplanet.csproj ./src/Libplanet/\nRUN dotnet restore src/Libplanet\n\n# Copy everything else and build\nCOPY . ./\nRUN dotnet publish -c Release -r linux-x64 -o out tools/Libplanet.Explorer.Executable\n\n# Build runtime image\nFROM mcr.microsoft.com/dotnet/aspnet:6.0\nWORKDIR /app\nCOPY --from=build-env /app/out .\n\n# Install native deps & utilities for production\nRUN apt-get update \\\n    && apt-get install -y --allow-unauthenticated \\\n        libc6-dev jq \\\n     && rm -rf /var/lib/apt/lists/*\n\n# Runtime settings\nEXPOSE 5000\nVOLUME /data\n\nENTRYPOINT [\"Libplanet.Explorer.Executable\"]\n"
  },
  {
    "path": "Docs/.gitignore",
    "content": "*.nuget\n_site/\napi/*.yml\napi/.manifest\ndocfx/\ndocfx.zip\n/**/bin/\n/**/DROP/\n/**/packages/\n/**/obj/\n/**/TEMP/\n"
  },
  {
    "path": "Docs/api/.gitignore",
    "content": "\r\n###############\r\n#  temp file  #\r\n###############\r\n*.yml\r\n"
  },
  {
    "path": "Docs/api/index.md",
    "content": "<meta http-equiv=\"refresh\" content=\"0; url=Libplanet.Action.html\">\nMove to [Libplanet.Action](Libplanet.Action.yml)&hellip;\n"
  },
  {
    "path": "Docs/articles/design.md",
    "content": "Libplanet design\n================\n\nLibplanet is a network/storage library for [peer-to-peer][P2P] distributed\nmultiplayer games.  From the perspective of this library's user,\nit can be similar to a client library of a [PaaS] for games,\nexcept that autonomous nodes run by gamers communicate with\neach other without any authority of the centralized server.\n\nUnder the hood, because we need to prevent malicious nodes in the network from\ncorrupting network autonomy, the library utilizes [digital signature],\n[BFT] consensus, and data replication, or simply [blockchain].\n\nImplementing blockchain and BFT consensus for peer-to-peer distributed\nmultiplayer games is highly complicated, requires a lot of code to\nbe written, and is difficult and tedious to test.  For the future of\ndecentralized online games, rather than every single game making such redundant\neffort, it will be more cost-efficient to make a high quality open source\nlibrary for commonly performed tasks.\n\n[P2P]: https://en.wikipedia.org/wiki/Peer-to-peer\n[PaaS]: https://en.wikipedia.org/wiki/Platform_as_a_service\n[digital signature]: https://en.wikipedia.org/wiki/Digital_signature\n[BFT]: https://en.wikipedia.org/wiki/Byzantine_fault_tolerance\n[blockchain]: https://en.wikipedia.org/wiki/Blockchain\n\n\nPlatform and packaging\n----------------------\n\nPresently, Libplanet is a .NET library in order to be used along with [Unity],\none of the most popular multiplatform game engines.  (We have a long-running\nroadmap to support other platforms, though.)\n\nHowever, Libplanet is not only a Unity plugin distributed through\nthe [Unity Asset Store], but also a standard .NET library distributed through\n[NuGet].  Because, as [block mining] is indispensable for running\na decentralized public network, mining-only headless nodes need to exist besides\ngame clients that also act as nodes. A peer-to-peer distributed multiplayer game\nbased on Libplanet can be packaged as both: a Unity based game application for\nmultiplatform gaming devices (e.g., Android, iOS, macOS, Windows), and a mining\n[daemon] runnable on miners' machines (e.g., Linux).\n\nFor the maximum compatibility and portability, we currently target\n[.NET Standard] 2.0.\n\n[Unity]: https://unity3d.com/\n[Unity Asset Store]: https://assetstore.unity.com/\n[NuGet]: https://www.nuget.org/\n[block mining]: https://en.bitcoin.it/wiki/Mining\n[daemon]: https://en.wikipedia.org/wiki/Daemon_(computing)\n[.NET Standard]: https://docs.microsoft.com/en-us/dotnet/standard/net-standard\n\n\nTransactions and actions\n------------------------\n\nEvery action that happened in a game built on Libplanet should be recorded in\nthe blockchain.  Although trivial things like chatting between players could be\nan exception as these do not affect rules or incentives of a game, actions such\nas a character's movement, battle, progression (i.e., exp), item drops,\nreinforcements, breakages, trades, that are non-trivial and affect game states\nshould be recorded to the append-only log.  Each log has its own digital\nsignature to prove that the corresponding gamer is responsible.\n\nWe call the unit of such pair of log and its signature a\n@\"Libplanet.Tx.Transaction`1\", and it consists of multiple\n@\"Libplanet.Tx.Transaction`1.Actions\".  How transactions and actions grouped is\nleft to a game engineer's discretion.  For example, if there are four actions\nlike *A* to *D*, these can be grouped altogether (e.g., *{A, B, C, D}*),\nor be into two or three groups (e.g., *{A} & {B, C, D}*), or rather have\ntheir sole group (e.g., *{A} & {B} & {C} & {D}*).\n\nThe primary purpose of separating transactions and actions is to have\nthe flexible granularity of synchronization between nodes in the network.\nAn actor can at most put one signed transaction into a block. A transaction\nincluded in a block is confirmed by other nodes in the network\nwhen the block is mined.  It is also known as [consensus]\nin distributed systems.\n\nIt takes 5 to 20 seconds to mine a block.  It means that if we group four\nactions *A* to *D* into four distinct transactions like *{A} & {B} & {C} & {D}*\nit must take 20 seconds to 80 seconds until four actions are all confirmed in\nthe network.  On the other hand, if we group the actions into a single\ntransaction like *{A, B, C, D}* it takes only 5 seconds\nat best to 20 seconds even at worst.\n\nDoes it imply the best practice is to put as many actions as possible into\nas few transactions as possible?  Unfortunately it is not that simple.\n\nPutting many actions into few transactions decreases the immediacy of\neach action.  To other nodes (gamers), it looks like there is no change at\nall for a while, and then suddenly many things happening at once.\nGrouping actions into transactions is a balance between throughput and latency,\n so different strategies should be chosen for the goal that a game aims to.\n\nThere is another reason to group actions into transactions besides latency\ncontrol.  It is so that actions made by different players can interact with\neach other.\nFor example, in a card game, right after a player ends their turn, they need to\nwait until the opponent ends their turn.  Even if it is desirable to increase\nthroughput, it is nonsense to group two turns of actions into one transaction.\nA player's next turn can start only after the opponent's current turn is\ndetermined.  From this perspective, a transaction represents a unit of\ndependency, rather than a unit of throughput.\n\nAt a code level, another difference between @\"Libplanet.Tx.Transaction`1\" and\n@\"Libplanet.Action.IAction\" is that @\"Libplanet.Tx.Transaction`1\" is not\nextensible whereas @\"Libplanet.Action.IAction\" is.  By design, an extension\npoint for game engineers is @\"Libplanet.Action.IAction\".  To sum up,\n@\"Libplanet.Tx.Transaction`1\" purposes to control synchronization on\nthe network and @\"Libplanet.Action.IAction\" purposes to implement the actual\ngame logic.\n\n[consensus]: https://en.wikipedia.org/wiki/Consensus_(computer_science)\n\n\nAccounts and addresses\n----------------------\n\nLibplanet creates digital signatures to find which player node made each\ntransaction, without relying on the authority of a centralized server.\nIn the similar fashion to [Bitcoin] and [Ethereum], a transaction is signed\nwith [ECDSA], and a pair of each player's sole @\"Libplanet.Crypto.PrivateKey\"\nand @\"Libplanet.Crypto.PublicKey\" used to sign transactions construct\nan *account*.  Since a pair of keys for an account is *chosen* at offline,\nthe process of so-called \"account creation\" can be omitted.\n\nAn account can also be identified through the @\"Libplanet.Address\" which is\nderived from the corresponding @\"Libplanet.Crypto.PublicKey\".  It is shorter\nthan @\"Libplanet.Crypto.PublicKey\" and follows the same form to Ethereum's.\nThis means key pairs that have used for Ethereum can be reused for\nLibplanet-backed games too.  For example, a game can raise funding or receive\ndonations through Ethereum and then reward people when the game is released.\n\n[Bitcoin]: https://bitcoin.org/\n[Ethereum]: https://www.ethereum.org/\n[ECDSA]: https://en.wikipedia.org/wiki/Elliptic_Curve_Digital_Signature_Algorithm\n\n\nActions and states\n------------------\n\nEvery account starts with an empty state. The current state of the account is\ndetermined by actions that belong to the transactions signed by the account\nalong with other actions that refer to the account. This means state is not\nstored in the blockchain, but only the actions that change the state are.\n\nHowever, from a game engineer's view, Libplanet probably looks like its\nblockchain store states as well. Libplanet exposes methods to query the current\nstate of an account by computing the effect of actions under the hood. Since\nLibplanet's internal workings to calculate states will be further optimized\nat storage and network levels soon, game engineers are encouraged to use\nLibplanet's states API rather than implementing a similar function.\n\nSince all state changes need to be represented through actions, every object\nstored in states should be immutable.  Although the storage API accepts\nmutable objects too, in this way collaborators might not understand that every\nstate change needs to be represented by an action.\n\nA state needs to be serializable as it is transmitted over the network and\nsometimes cached in storage. Therefore, every game object that represents states\nmust be marked with @\"System.SerializableAttribute\".\n\n"
  },
  {
    "path": "Docs/articles/overview.md",
    "content": "Libplanet overview\n==================\n\nThis document describes the structure and usage of [Libplanet] designed to be easily used in [Unity].\n\n\n[Libplanet]: https://libplanet.io\n[Unity]: https://unity.com/\n\n\nLibplanet\n---------\n\nLibplanet is a network/storage library for games that run in distributed P2P network. In many traditional multiplayer games, it was up to the game server to manage the network and the state of games.\n\n```text\n                       Traditional multiplayer game\n\n                     +------------------------------+\n                     |           Server             |\n                     |                              |\n                     |                              |\n                     |  +------------------------+  |\n                     |  |                        |  |\n                     |  |       Game State       |  |\n                     |  |                        |  |\n                     |  +-+----------+---------+-+  |\n                     +----+----------+---------+----+\n                          |          |         |\n                          |          |         |\n                     +----+---+ +----+---+ +---+----+\n                     |        | |        | |        |\n                     | client | | client | | client |\n                     |        | |        | |        |\n                     +--------+ +--------+ +--------+\n```\n\nBut with Libplanet, all game clients can manage their own game state, enabling multiplayer games to be implemented without a central server.\n\n```text\n                    Multiplayer game with Libplanet\n\n\n+----------------------+ +----------------------+ +----------------------+\n|                      | |                      | |                      |\n|        Client        | |        Client        | |        Client        |\n|                      | |                      | |                      |\n| +------------------+ | | +------------------+ | | +------------------+ |\n| |                  | | | |                  | | | |                  | |\n| |    Game State    + +-+ +    Game State    + +-+ +    Game State    | |\n| |                  | | | |                  | | | |                  | |\n| +------------------+ | | +------------------+ | | +------------------+ |\n+---------+------------+ +----------------------+ +-----------+----------+\n          |                                                   |\n          +---------------------------------------------------+\n\n```\n\nFor the design rationale of Libplanet, refer to [this article][Libplanet Design].\n\n\n[Libplanet Design]: design.md\n\n\nAction and State\n----------------\n\nAs mentioned above, games using Libplanet can manage their state from each client, not from a central server. The **State** of games is transitioned through an **Action**.\n\n```text\n+------------+                  +------------+                  +------------+\n|            |                  |            |                  |            |\n|  State #1  |                  |  State #2  |                  |  State #3  |\n|            |  Battle(Action)  |            |  Battle(Action)  |            |\n|            +----------------->+            |----------------->+            |\n|    Lv 1    |                  |    Lv 2    |                  |    Lv 3    |\n|   Novice   |                  |   Warrior  |                  |   Veteran  |\n|            |                  |            |                  |            |\n+------------+                  +------------+                  +------------+\n\n```\n\n- Because the way of transitioning the State through an Action depends on each game, Libplanet does not directly provide implementation of the Action and only provides the interface @\"Libplanet.Action.IAction\".\n- The State is expressed in key-value pairs, and you can set appropriate values for each game.\n- The State is readable at any point, but transitioning it is only possible through an Action.\n- Libplanet does not directly share the transitioned State, but only shares the Action that will transition the State. Also, because State transitioned by an Action occurs on all nodes in the network, the Action must be written deterministically to return the same result from all nodes.\n\n\nTransaction and Block\n---------------------\n\nIn order to share an Action, Libplanet uses 2 concepts internally: **Block** and **Transaction**.\n\n\n```text\n+-----------------------+   +-----------------------+   +-----------------------+\n|                       |   |                       |   |                       |\n| Block #1              |   | Block #2              |   | Block #3              |\n|                       |   |                       |   |                       |\n| +-------------------+ |   | +-------------------+ |   | +-------------------+ |\n| |                   | |   | |                   | |   | |                   | |\n| | Transaction #1    | |   | | Transaction #2    | |   | | Transaction #4    | |\n| |                   | |   | |                   | |   | |                   | |\n| | +---------------+ | |   | | +---------------+ | |   | | +---------------+ | |\n| | |  Action #1-1  | | +-->+ | |  Action #2-1  | | +-->+ | |  Action #4-1  | | |\n| | +---------------+ | |   | | +---------------+ | |   | | +---------------+ | |\n| |                   | |   | |                   | |   | |                   | |\n| | +---------------+ | |   | +-------------------+ |   | +-------------------+ |\n| | |  Action #1-2  | | |   |                       |   |                       |\n| | +---------------+ | |   | +-------------------+ |   | +-------------------+ |\n| |                   | |   | |                   | |   | |                   | |\n| +-------------------+ |   | | Transaction #3    | |   | | Transaction #5    | |\n|                       |   | |                   | |   | |                   | |\n|                       |   | | +---------------+ | |   | +-------------------+ |\n|                       |   | | |  Action #3-1  | | |   |                       |\n|                       |   | | +---------------+ | |   |                       |\n|                       |   | |                   | |   |                       |\n|                       |   | +-------------------+ |   |                       |\n|                       |   |                       |   |                       |\n+-----------------------+   +-----------------------+   +-----------------------+\n\n```\n\n**Transaction** is a bundle of Actions and has the following characteristics:\n\n- Transaction is signed using a private key of the creator(signer) of Transaction and Action.\n- Transaction may not include an Action.\n- Action in Transaction can be specified in the order of execution and ensures same order execution on all nodes.\n- Transaction does not include the game code and cannot be extended. All game logic is implemented through Action.\n- It is the game developer's freedom to decide how to group Action units. See [this document][transactions and actions] for more information.\n\n**Block** is a bundle of Transaction and has the following characteristics:\n\n- Block is the smallest unit of mutual Actions in the network. Actions in a Block are either all evaluated, or all not evaluated.\n- A Block may include many Transactions or may not include any Transaction.\n- A Block may contain multiple users' Transactions.\n- A Block does not include game code and cannot be extended by the game developer.\n- Block's Transactions are evaluated in the order of execution calculated by deterministic random number to transition the state.\n\n\n[transactions and actions]: design.md#transactions-and-actions\n\n\nBlockChain\n----------\n\nTo manage these Blocks, Libplanet offers a class called @\"Libplanet.Blockchain.BlockChain`1\". This class allows game developers to:\n\n- Create and register Transactions that contain desired Actions.\n- Mine Blocks with registered Transactions.\n- Inquire State obtained by evaluating Blocks.\n\n\nRendering\n---------\n\nOne way for game developers to reflect the State of the game is by using\n@\"Libplanet.Blockchain.BlockChain`1.GetState(Libplanet.Address,System.Nullable{Libplanet.HashDigest{SHA256}},Libplanet.Blockchain.StateCompleter{`0})\".\n\n```csharp\npublic class Game : MonoBehaviour\n{\n    private BlockChain<Action> _blockChain;\n\n    private static void UpdateScore(long score)\n    {\n        // Update player's score in game.\n    }\n\n    // MonoBehaviour.Awake()\n    private void Awake()\n    {\n        UpdateScore((long?) _blockChain.GetState(playerAddress) ?? 0);\n    }\n}\n```\n\nState transition occurs after a Block containing an Action is added and confirmed to the chain. The code above is suboptimal because you are polling the @\"Libplanet.Blockchain.BlockChain`1\" object to see if a specific Action has been reflected.\n\n```csharp\npublic class Game : MonoBehaviour\n{\n    // ...\n\n    private IEnumerator CoScoreUpdater()\n    {\n        while (true)\n        {\n            UpdateScore((long?) _blockChain.GetState(playerAddress) ?? 0);\n            yield return new WaitForSeconds(1f);\n        }\n    }\n\n    // MonoBehaviour.Awake()\n    private void Awake()\n    {\n        StartCoroutine(CoScoreUpdater());\n    }\n}\n```\n\nAlthough this method works, there are still some problems because reflecting the State of the game depends only on time, regardless of whether the action is processed or not.\n\n- If the wait time is long, the interval between States being reflected in the game is also extended, and if it becomes too short, frequent State checks makes the process inefficient.\n- If multiple actions were executed in a short period of time, they would not be handled accurately.\n\nLibplanet provides a rendering mechanism called\n@\"Libplanet.Blockchain.Renderers.IRenderer`1\" and its subtype\n@\"Libplanet.Blockchain.Renderers.IActionRenderer`1\" to solve this problem.\n@\"Libplanet.Blockchain.Renderers.IActionRenderer`1.RenderAction(Libplanet.Action.IAction,Libplanet.Action.IActionContext,Libplanet.Action.IAccountStateDelta)\"\nis called after a @\"Libplanet.Blocks.Block`1\" with the corresponding\n@\"Libplanet.Action.IAction\"s is confirmed and the state is transitioned.\nThe following code has been re-implemented using\n@\"Libplanet.Blockchain.Renderers.IActionRenderer`1.RenderAction(Libplanet.Action.IAction,Libplanet.Action.IActionContext,Libplanet.Action.IAccountStateDelta)\".\n\n```csharp\npublic class WinRenderer : IActionRenderer<Win>\n{\n    // ...\n\n    public void RenderAction(IAction action,\n                             IActionContext context,\n                             IAccountStateDelta nextStates)\n    {\n        Game.UpdateScore((long?)nextStates.GetState())\n    }\n}\n```\n\n\nNetworking\n----------\n\nLibplanet has the feature to store Blocks and Transactions, as well as sharing them across other nodes in the P2P network. Game developers can use the @\"Libplanet.Net.Swarm`1\" class to propagate or receive Blocks from other nodes in the network.\n\nAlso, because the network is a P2P network without a central server, @\"Libplanet.Net.Swarm`1\" also does not need a specific server, however, it is necessary to specify a seed node with a specific address to configure the network. These seed nodes are completely the same as other nodes, except that they must have an IP address or domain accessible from the Internet.\n\n\nConsensus\n---------\n\n### Perspective\n\nLibplanet is a library that enables game developers to create \"centralized server\"-less multiplayer games. “Centralized server-less” means that not only one entity is responsible for the state of the game, but every node in the network has the state of the game and synchronizes it accordingly. To synchronize, it should maintain a consistent state even in the event of a failure or tampering. The way of choosing which state is canonical is also called [consensus] in distributed computing and multi-agent environments.\n\nThe algorithms used for consensus are various, with many different characteristics and pros and cons. For example, [Proof of Work (PoW)][PoW] allows anyone with computing power to participate in the network, but that cannot guarantee the state of the game at a specific time. In contrast, [Proof of Authority (PoA)][PoA] can guarantee that a game's state is established after a certain time, but only authorized users can join the network. These characteristics may work for some games, but won't for others, making the consensus algorithm also unusable for a general purpose network.\n\nLibplanet isn't a tool for creating games of any particular genre, but rather a tool for creating varied types of games. Also it assumes that each game has a different network and consensus algorithm. Nor is Libplanet itself a project that focuses on developing and testing any particular consensus algorithm or mechanism. That's why Libplanet aims to allow game developers to choose a consensus algorithm at implementation time to suit their game's characteristics.\n\n[Consensus]: https://en.wikipedia.org/wiki/Consensus_(computer_science)\n[PoW]: https://en.wikipedia.org/wiki/Proof_of_work\n[PoA]: https://en.wikipedia.org/wiki/Proof_of_authority\n\n\n### About PoW\n\nCurrently, the only consensus algorithm currently implemented in Libplanet is\na PoW ([Hashcash]). It has the following characteristics:\n\n- Anyone with hash power (= computing power) can join the network\n- Simple to implement, robust\n- Blocks aren't finalized and can be re-organized\n- Can't decrease block creation (≒ state transition) time below a certain amount (network propagation and validation time)\n\nThe main reason Libplanet chose PoW as its first consensus algorithm is its simple architecture. As mentioned earlier, Libplanet is not a library that aims to implement certain functions of the blockchain, but a library that allows the game to run without a centralized server. That's why we chose PoW as our first consensus algorithm, which allows us to create and run a complete game, even with a relatively simple implementation (although it does limit genre or features).\n\nAlso, PoW is not Libplanet's last or only consensus algorithm, as some games can't use it due to some of the characteristics of PoW. To Libplanet will add consensus algorithms that the community believes are needed later.\n\n[Hashcash]: https://en.wikipedia.org/wiki/Hashcash\n"
  },
  {
    "path": "Docs/articles/toc.yml",
    "content": "- name: Overview\n  href: overview.md\n- name: Design\n  href: design.md\n"
  },
  {
    "path": "Docs/build.ps1",
    "content": "#!/usr/bin/env pwsh\n# This PowerShell script builds the docs using DocFX.\n#\n# If you are on Linux or macOS you need to install PowerShell and Mono first.\n# See also the following articles:\n#\n# https://docs.microsoft.com/powershell/scripting/install/installing-powershell\n# https://www.mono-project.com/docs/getting-started/install/\n#\n# If prerequisites are satisfied you can run the script using the following\n# command:\n#\n#   ./build.ps1\n#\n# The above command generates static HTML files into _site/ directory.\n#\n# Note that this command can take options that docfx.exe can take.  For example,\n# the following command builds the docs and serves them through an HTTP server:\n#\n#   ./build.ps --serve\n#\nAdd-Type -AssemblyName System\nAdd-Type -AssemblyName System.IO.Compression.FileSystem\n\n# The below assumes that the working directory is Docs/.\n$BaseDir = Split-Path -Path $MyInvocation.MyCommand.Source\nSet-Location $BaseDir\n\n# Install docfx with `dotnet tool`. \ndotnet tool restore\n\n# As DocFX requires the Git remote named \"origin\", which is hard-coded in\n# the DocFX internals (see also: # https://github.com/dotnet/docfx/issues/5547),\n# it fails to get VCS metadata without it.  To work around this, this script\n# temporarily adds the remote named \"origin\" if it does not exist, and removes\n# it when the script ends.\n$originExisted = -not ( `\n  git remote | Select-String -AllMatches -CaseSensitive -Quiet \"origin\")\nif ($originExisted) {\n  git remote add origin \"https://github.com/planetarium/libplanet.git\"\n}\ntry {\n\n# Invoke docfx.exe which is a .NET application.  While it can be run in\n# the native way on Windows, it should be interpreted by Mono VM on other POSIX\n# systems.\nSet-Location $BaseDir\ndotnet tool run docfx docfx.json @args\n\nif (-not (Test-Path \"$BaseDir/_site/api/index.html\")) {\n      Write-Error @\"\nFailed to build: _site/api/Libplanet.html doesn't exist.\n\"@\n    exit 127\n}\n\n} finally {\n  if ($originExisted) {\n    git remote remove origin\n  }\n}\n"
  },
  {
    "path": "Docs/clean.ps1",
    "content": "#!/usr/bin/env pwsh\n$ErrorActionPreference = \"SilentlyContinue\"\nRemove-Item api/*.manifest\nRemove-Item api/*.yml\nRemove-Item docfx.zip\nRemove-Item -Recurse _site/\n"
  },
  {
    "path": "Docs/docfx.json",
    "content": "{\n  \"metadata\": [\n    {\n      \"src\": [\n        {\n          \"files\": [\n            \"src/Libplanet/Libplanet.csproj\",\n            \"src/Libplanet.Action/Libplanet.Action.csproj\",\n            \"src/Libplanet.Common/Libplanet.Common.csproj\",\n            \"src/Libplanet.Crypto/Libplanet.Crypto.csproj\",\n            \"src/Libplanet.Crypto.Secp256k1/Libplanet.Crypto.Secp256k1.csproj\",\n            \"tools/Libplanet.Explorer.Cocona/Libplanet.Explorer.Cocona.csproj\",\n            \"tools/Libplanet.Extensions.Cocona/Libplanet.Extensions.Cocona.csproj\",\n            \"test/Libplanet.Mocks/Libplanet.Mocks.csproj\",\n            \"src/Libplanet.Net/Libplanet.Net.csproj\",\n            \"src/Libplanet.RocksDBStore/Libplanet.RocksDBStore.csproj\",\n            \"src/Libplanet.Store/Libplanet.Store.csproj\",\n            \"src/Libplanet.Store.Remote/Libplanet.Store.Remote.csproj\",\n            \"src/Libplanet.Stun/Libplanet.Stun.csproj\",\n            \"src/Libplanet.Types/Libplanet.Types.csproj\"\n          ],\n          \"exclude\": [\"**/bin/**\", \"**/obj/**\"],\n          \"src\": \"../\"\n        }\n      ],\n      \"dest\": \"api\",\n      \"disableGitFeatures\": false,\n      \"disableDefaultFilter\": false,\n      \"properties\": {\n        \"TargetFramework\": \"netstandard2.1\"\n      }\n    }\n  ],\n  \"build\": {\n    \"content\": [\n      {\n        \"files\": [\n          \"api/**.yml\",\n          \"api/index.md\"\n        ]\n      },\n      {\n        \"files\": [\n          \"articles/**.md\",\n          \"articles/**/toc.yml\",\n          \"toc.yml\",\n          \"*.md\"\n        ]\n      },\n      {\n        \"src\": \"../tools/Libplanet.Analyzers\",\n        \"dest\": \"analyzer\",\n        \"files\": [\n          \"*.md\",\n          \"rules/*.md\"\n        ]\n      },\n      {\n        \"src\": \"../tools/Libplanet.Tools\",\n        \"dest\": \"cli\",\n        \"files\": [\n          \"*.md\"\n        ]\n      },\n      {\n        \"src\": \"../tools/Libplanet.Explorer\",\n        \"dest\": \"explorer\",\n        \"files\": [\n          \"*.md\"\n        ]\n      },\n      {\n        \"src\": \"../\",\n        \"files\": [\n          \"CHANGES.md\",\n          \"CONTRIBUTING.md\",\n          \"RELEASE.md\",\n          \"changes/**.md\"\n        ]\n      }\n    ],\n    \"resource\": [\n      {\n        \"files\": [\n          \"images/**\"\n        ]\n      }\n    ],\n    \"overwrite\": [\n      {\n        \"files\": [\n          \"apidoc/**.md\"\n        ],\n        \"exclude\": [\n          \"obj/**\",\n          \"_site/**\"\n        ]\n      }\n    ],\n    \"xrefService\": [\n      \"https://xref.docs.microsoft.com/query?uid={uid}\"\n    ],\n    \"dest\": \"_site\",\n    \"globalMetadata\": {\n      \"_appTitle\": \"Libplanet\",\n      \"_appLogoPath\": \"images/logo.svg\",\n      \"_appFaviconPath\": \"images/favicon.ico\",\n      \"_appFooter\": \"Copyright © 2018\\u20132023 <a href=\\\"https://planetariumhq.com/\\\">Planetarium</a>\"\n    },\n    \"globalMetadataFiles\": [],\n    \"fileMetadataFiles\": [],\n\n    \"template\": [\"default\"],\n\n    \"theme\": [\"theme\"],\n    \"postProcessors\": [],\n    \"markdownEngineName\": \"markdig\",\n    \"noLangKeyword\": false,\n    \"keepFileLink\": false,\n    \"cleanupCacheHistory\": false,\n    \"disableGitFeatures\": false,\n    \"repositoryRoot\": \"../\",\n    \"logLevel\": \"Verbose\"\n  }\n}\n"
  },
  {
    "path": "Docs/index.md",
    "content": "[!include[README](../README.md)]\n"
  },
  {
    "path": "Docs/publish.sh",
    "content": "#!/bin/bash\n# Publish docs to GitHub Pages.\n# Note that this script is intended to be run by GitHub Actions.\nif ! (env | grep '^GITHUB_'); then\n  {\n    echo \"This script is intended to be run by GitHub Actions.\"\n    echo \"You can run GitHub Actions locally using \\`act':\"\n    echo \"  https://github.com/nektos/act\"\n  } >&2\n  exit 1\nfi\n\nset -ev\n\nb64d() {\n  if command -v python > /dev/null; then\n    python -m base64 -d\n  else\n    base64 -d\n  fi\n}\n\nif [ \"$GHPAGES_SSH_KEY\" = \"\" ]; then\n  {\n    echo \"The environment variable GHPAGES_SSH_KEY is not configured.\"\n    echo \"Configure GHPAGES_SSH_KEY from GitHub Actions web page.\"\n    echo \"The key has to be also registered as a deploy key of the repository\" \\\n         \", and be allowed write access.\"\n    echo \"GHPAGES_SSH_KEY has to contain a base64-encoded private key without\" \\\n         \"new lines.\"\n  } >&2\n  exit 0\nfi\n\nif [ \"$GITHUB_EVENT_NAME\" = \"pull_request\" ]; then\n  if ! command -v jq > /dev/null; then\n    wget -O /usr/local/bin/jq \\\n      https://github.com/stedolan/jq/releases/download/jq-1.6/jq-linux64\n    chmod +x /usr/local/bin/jq\n  fi\n  pr_number=\"$(jq '.pull_request.number' \"$GITHUB_EVENT_PATH\")\"\n  slug=\"pulls/$pr_number\"\nelse\n  if [[ \"$GITHUB_REPOSITORY\" = \"planetarium/libplanet\" ]] && \\\n     [[ \"$GITHUB_REF\" != refs/tags/* ]] &&\n     [[ \"$GITHUB_REF\" != refs/heads/main ]] && \\\n     [[ \"$GITHUB_REF\" != refs/heads/maintenance-* ]]; then\n    echo \"This branch is not for releases, so docs won't be published.\" >&2\n    exit 0\n  fi\n  slug=\"$(echo -n \"$GITHUB_REF\" | sed -e 's/^refs\\/\\(heads\\|tags\\)\\///g')\"\nfi\n[ \"$slug\" != \"\" ]\n\necho \"Slug: $slug\" >&2\n\necho \"$GHPAGES_SSH_KEY\" | b64d > /tmp/github_id\nchmod 600 /tmp/github_id\nexport GIT_SSH_COMMAND='ssh -i /tmp/github_id -o \"StrictHostKeyChecking no\"'\n\nfor _ in 1 2 3; do\n  # If more than an action are running simultaneously git push may fail\n  # due to conflicts.  So try up to 3 times.\n\n  git clone -b gh-pages \"git@github.com:$GITHUB_REPOSITORY.git\" /tmp/gh-pages\n  git -C /tmp/gh-pages config user.name \"$(git log -n1 --format=%cn)\"\n  git -C /tmp/gh-pages config user.email \"$(git log -n1 --format=%ce)\"\n\n  rm -rf \"/tmp/gh-pages/$slug\"\n  mkdir -p \"/tmp/gh-pages/$(dirname \"$slug\")\"\n  cp -r Docs/_site \"/tmp/gh-pages/$slug\"\n  git -C /tmp/gh-pages add \"/tmp/gh-pages/$slug\"\n\n  latest_version=\"$(git tag --sort -v:refname | head -n1)\"\n  commit_hash=\"$(git log -n1 --pretty=%H)\"\n  tag=\"$(echo -n \"$GITHUB_REF\" | sed -e 's/^refs\\/tags\\///g')\"\n  if [ \"$(git tag -l)\" = \"\" ] || [ \"$latest_version\" = \"$tag\" ]; then\n    index=\"$(cat \"/tmp/gh-pages/$slug/index.html\")\"\n    {\n      echo -n \"${index%</title>*}</title>\"\n      echo \"<meta http-equiv=\\\"refresh\\\" content=\\\"0;$slug/\\\">\"\n      echo \"<base href=\\\"$slug/\\\">\"\n      echo -n \"${index#*</title>}\"\n    } > /tmp/gh-pages/index.html\n    git -C /tmp/gh-pages add /tmp/gh-pages/index.html\n  fi\n\n  git -C /tmp/gh-pages commit \\\n    --allow-empty \\\n    -m \"Publish docs from $commit_hash [ci skip]\"\n\n  if git -C /tmp/gh-pages push origin gh-pages; then\n    break\n  fi\n\n  rm -rf /tmp/gh-pages\ndone\n\nrm /tmp/github_id\n\nmkdir -p Docs/obj/\ngithub_user=\"${GITHUB_REPOSITORY%/*}\"\ngithub_repo=\"${GITHUB_REPOSITORY#*/}\"\necho -n \"https://$github_user.github.io/$github_repo/$slug/\" > Docs/obj/url.txt\n"
  },
  {
    "path": "Docs/theme/styles/main.css",
    "content": "@import url('https://fonts.googleapis.com/css2?family=Roboto+Mono:ital,wght@0,400;0,700;1,400;1,700&display=swap');\n@import url(\"https://cdn.jsdelivr.net/gh/orioncactus/pretendard/dist/web/variable/pretendardvariable.css\");/* COLOR VARIABLES*/\n:root {\n    --header-bg-color: #3e2a8c;\n    --header-ft-color: #f3f3f3;\n    --highlight-light: #00d1c2;\n    --highlight-dark: #007a8f;\n    --highlight-background: #007a8f22;\n    --accent-dim: #e0e0e0;\n    --accent-super-dim: #f3f3f3;\n    --code-color: #adbac7;\n    --font-color: #34393e;\n    --card-box-shadow: 0 1px 2px 0 rgba(61, 65, 68, 0.06),\n        0 1px 3px 1px rgba(61, 65, 68, 0.16);\n    --search-box-shadow: 0 1px 2px 0 rgba(41, 45, 48, 0.36),\n        0 1px 3px 1px rgba(41, 45, 48, 0.46);\n    --transition: 350ms;\n    --code-fonts: 'Roboto Mono', source-code-pro, Menlo, Monaco, Consolas,\n    \"Courier New\", monospace;\n}\n\n.container {\n    width: 100%;\n}\n\n.sideaffix, .sidetoc{\n    overflow: scroll;\n    scrollbar-width: none;\n    -ms-overflow-style: none;\n}\n\n.sideaffix::-webkit-scrollbar, .sidetoc::-webkit-scrollbar{\n    display: none;\n}\n\n.affix ul > li.active > ul, .affix ul > li.active > a::before, .affix ul > li > a:hover::before{\n    white-space: unset;\n}\n\n.affix ul > li > a:hover {\n    color: var(--highlight-dark);\n}\n\nbody {\n    color: var(--font-color);\n    font-family: 'Pretendard Variable', -apple-system, BlinkMacSystemFont, \"Segoe UI\",\n        Roboto, Oxygen, Ubuntu, Cantarell, \"Fira Sans\", \"Droid Sans\",\n        \"Helvetica Neue\", sans-serif;\n    font-weight: 470;\n    line-height: 1.63;\n    letter-spacing: 0.005rem;\n    text-rendering: optimizeLegibility;\n    font-size: 16px;\n    -moz-osx-font-smoothing: grayscale;\n    -ms-text-size-adjust: 100%;\n    -webkit-text-size-adjust: 100%;\n    word-wrap: break-word;\n}\n\n/* HIGHLIGHT COLOR */\n\nbutton,\na {\n    color: var(--highlight-dark);\n    cursor: pointer;\n}\n\nbutton:hover,\nbutton:focus,\na:hover,\na:focus {\n    color: var(--highlight-light);\n    text-decoration: none;\n}\n\narticle a, article var {\n    border-bottom: 1px solid rgba(0, 0, 0, 0.2);\n    background-color: var(--highlight-background);\n}\n\n.toc .nav > li.active > a {\n    color: var(--highlight-dark);\n}\n\n.toc .nav > li > a:hover,\n.toc .nav > li > a:focus {\n    color: var(--highlight-light);\n}\n\n.pagination > .active > a {\n    background-color: var(--header-bg-color);\n    border-color: var(--header-bg-color);\n}\n\n.pagination > .active > a,\n.pagination > .active > a:focus,\n.pagination > .active > a:hover,\n.pagination > .active > span,\n.pagination > .active > span:focus,\n.pagination > .active > span:hover {\n    background-color: var(--highlight-light);\n    border-color: var(--highlight-light);\n}\n\n/* HEADINGS */\n\nh1 {\n    font-weight: 600;\n    font-size: 32px;\n}\n\nh2 {\n    font-weight: 600;\n    font-size: 24px;\n    line-height: 1.8;\n}\n\nh3 {\n    font-weight: 600;\n    font-size: 20px;\n    line-height: 1.8;\n}\n\nh5 {\n    font-size: 14px;\n    padding: 10px 0px;\n}\n\narticle h1,\narticle h2,\narticle h3,\narticle h4 {\n    margin-top: 35px;\n    margin-bottom: 15px;\n}\n\narticle h4 {\n    padding-bottom: 8px;\n    border-bottom: 2px solid #ddd;\n}\n\n\n\n/* NAVBAR */\n\n.navbar-brand > img {\n    color: var(--header-ft-color);\n}\n\n.navbar {\n    border: none;\n    /* Both navbars use box-shadow */\n    -webkit-box-shadow: var(--card-box-shadow);\n    -moz-box-shadow: var(--card-box-shadow);\n    box-shadow: var(--card-box-shadow);\n}\n\n.subnav {\n    border-top: 1px solid #ddd;\n    background-color: #fff;\n}\n\n.navbar-inverse {\n    background-color: var(--header-bg-color);\n    z-index: 100;\n}\n\n.navbar-inverse .navbar-nav > li > a,\n.navbar-inverse .navbar-text {\n    color: var(--header-ft-color);\n    background-color: var(--header-bg-color);\n    border-bottom: 3px solid transparent;\n    padding-bottom: 12px;\n    transition: 350ms;\n}\n\n.navbar-inverse .navbar-nav > li > a:focus,\n.navbar-inverse .navbar-nav > li > a:hover {\n    color: var(--header-ft-color);\n    background-color: var(--header-bg-color);\n    border-bottom: 3px solid var(--highlight-light);\n}\n\n.navbar-inverse .navbar-nav > .active > a,\n.navbar-inverse .navbar-nav > .active > a:focus,\n.navbar-inverse .navbar-nav > .active > a:hover {\n    color: var(--header-ft-color);\n    background-color: var(--header-bg-color);\n    border-bottom: 3px solid var(--highlight-light);\n}\n\n.navbar-form .form-control {\n    border: 0;\n    border-radius: 4px;\n    box-shadow: var(--search-box-shadow);\n    transition: var(--transition);\n}\n\n.navbar-form .form-control:hover {\n    background-color: var(--accent-dim);\n}\n\n/* NAVBAR TOGGLED (small screens) */\n\n.navbar-inverse .navbar-collapse,\n.navbar-inverse .navbar-form {\n    border: none;\n}\n.navbar-inverse .navbar-toggle {\n    box-shadow: var(--card-box-shadow);\n    border: none;\n}\n\n.navbar-inverse .navbar-toggle:focus,\n.navbar-inverse .navbar-toggle:hover {\n    background-color: var(--highlight-dark);\n}\n\n/* SIDEBAR */\n.sidetoc {\n    width: 285px;\n}\n\n.toc .level1 > li {\n    font-weight: 700;\n}\n\n.toc .level2 > li {\n    font-weight: 600;\n}\n\n.toc .nav > li > a {\n    color: var(--font-color);\n}\n\n.sidefilter {\n    background-color: #fff;\n    border-left: none;\n    border-right: none;\n}\n\n.sidefilter {\n    background-color: #fff;\n    border-left: none;\n    border-right: none;\n}\n\n.toc-filter {\n    padding: 5px;\n    margin: 0;\n    box-shadow: var(--card-box-shadow);\n    transition: var(--transition);\n}\n\n.toc-filter:hover {\n    background-color: var(--accent-super-dim);\n}\n\n.toc-filter > input {\n    border: none;\n    background-color: inherit;\n    transition: inherit;\n}\n\n.toc-filter > .filter-icon {\n    display: none;\n}\n\n.sidetoc > .toc {\n    background-color: #fff;\n    overflow-x: hidden;\n}\n\n.sidetoc {\n    background-color: #fff;\n    border: none;\n}\n\n/* ALERTS */\n\n.alert {\n    padding: 0px 0px 5px 0px;\n    color: inherit;\n    background-color: inherit;\n    border: none;\n    box-shadow: var(--card-box-shadow);\n}\n\n.alert > p {\n    margin-bottom: 0;\n    padding: 5px 10px;\n}\n\n.alert > ul {\n    margin-bottom: 0;\n    padding: 5px 40px;\n}\n\n.alert > h5 {\n    padding: 10px 15px;\n    margin-top: 0;\n    text-transform: uppercase;\n    font-weight: bold;\n    border-radius: 4px 4px 0 0;\n}\n\n.alert-info > h5 {\n    color: #1976d2;\n    border-bottom: 4px solid #1976d2;\n    background-color: #e3f2fd;\n}\n\n.alert-warning > h5 {\n    color: #f57f17;\n    border-bottom: 4px solid #f57f17;\n    background-color: #fff3e0;\n}\n\n.alert-danger > h5 {\n    color: #d32f2f;\n    border-bottom: 4px solid #d32f2f;\n    background-color: #ffebee;\n}\n\n/* CODE HIGHLIGHT */\ncode, a.xref, span.xref {\n    font-family: var(--code-fonts);\n}\n\npre {\n    padding: 9.5px;\n    margin: 0 0 10px;\n    font-family: var(--code-fonts);\n    font-size: 14px;\n    word-break: break-all;\n    word-wrap: break-word;\n    color: var(--code-color);\n    background-color: #003847;\n    border-radius: 4px;\n    border: none;\n    font-weight: 500;\n    box-shadow: var(--card-box-shadow);\n}\n\narticle :is(a, em, h1, h2, h3, h4, h5, h6, li, p, strong) > :is(code, span.xref) {\n    background-color: #007a8f22;\n    color: #003847;\n    padding: 0 0.2rem;\n    word-break: break-word;\n}\n\n/* https://github.com/primer/github-syntax-light/blob/master/lib/github-light.css */\n.hljs-comment, .hljs-quote {\n    color: #768390;\n}\n.hljs-variable, .hljs-template-variable, .hljs-tag, .hljs-name, .hljs-selector-id, .hljs-selector-class, .hljs-regexp, .hljs-deletion{\n    color: #F69D50;\n}\n.hljs-number, .hljs-built_in, .hljs-builtin-name, .hljs-literal, .hljs-params, .hljs-meta, .hljs-link {\n    color: #956fb8;\n}\n.hljs-attribute, .hljs-type {\n    color: #859900;\n}\n.hljs-string, .hljs-symbol, .hljs-bullet, .hljs-addition {\n    color: #d33682;\n}\n.hljs-title, .hljs-section {\n    color: #dcbdfb;\n}\n.hljs-keyword, .hljs-selector-tag {\n    color: #f47067;\n}\n.hljs {\n    display: block;\n    overflow-x: auto;\n    background: #073642;\n    color: var(--code-color);\n    padding: 0.5em;\n}\narticle .hljs-emphasis {\n    font-style: italic;\n}\narticle .hljs-strong {\n    font-weight: bold;\n}\n\n/* STYLE FOR IMAGES */\n\n.article .small-image {\n    margin-top: 15px;\n    box-shadow: var(--card-box-shadow);\n    max-width: 350px;\n}\n\n.article .medium-image {\n    margin-top: 15px;\n    box-shadow: var(--card-box-shadow);\n    max-width: 550px;\n}\n\n.article .large-image {\n    margin-top: 15px;\n    box-shadow: var(--card-box-shadow);\n    max-width: 700px;\n}\n"
  },
  {
    "path": "Docs/theme/styles/main.js",
    "content": "(function () {\n  // Disable DocFX's default footer behavior.\n  var resetFooter = function () {\n    $('footer').attr('style', '');\n  };\n  $.fn.fadeIn = resetFooter;\n  $.fn.fadeOut = resetFooter;\n  resetFooter();\n})();\n"
  },
  {
    "path": "Docs/toc.yml",
    "content": "#- name: Articles\n#  href: articles/\n- name: Overview\n  href: articles/overview.md\n- name: Design\n  href: articles/design.md\n- name: API Reference\n  href: api/\n  homepage: api/Libplanet.Action.yml\n- name: Analyzer\n  href: ../Libplanet.Analyzers/\n  homepage: ../Libplanet.Analyzers/README.md\n- name: CLI Tools\n  href: ../Libplanet.Tools/README.md\n- name: Explorer\n  href: ../Libplanet.Explorer/\n  homepage: ../Libplanet.Explorer/README.md\n- name: Changelog\n  href: ../CHANGES.md\n- name: Contribute\n  href: ../CONTRIBUTING.md\n"
  },
  {
    "path": "LICENSE",
    "content": "                  GNU LESSER GENERAL PUBLIC LICENSE\n                       Version 2.1, February 1999\n\n Copyright (C) 1991, 1999 Free Software Foundation, Inc.\n 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n Everyone is permitted to copy and distribute verbatim copies\n of this license document, but changing it is not allowed.\n\n[This is the first released version of the Lesser GPL.  It also counts\n as the successor of the GNU Library Public License, version 2, hence\n the version number 2.1.]\n\n                            Preamble\n\n  The licenses for most software are designed to take away your\nfreedom to share and change it.  By contrast, the GNU General Public\nLicenses are intended to guarantee your freedom to share and change\nfree software--to make sure the software is free for all its users.\n\n  This license, the Lesser General Public License, applies to some\nspecially designated software packages--typically libraries--of the\nFree Software Foundation and other authors who decide to use it.  You\ncan use it too, but we suggest you first think carefully about whether\nthis license or the ordinary General Public License is the better\nstrategy to use in any particular case, based on the explanations below.\n\n  When we speak of free software, we are referring to freedom of use,\nnot price.  Our General Public Licenses are designed to make sure that\nyou have the freedom to distribute copies of free software (and charge\nfor this service if you wish); that you receive source code or can get\nit if you want it; that you can change the software and use pieces of\nit in new free programs; and that you are informed that you can do\nthese things.\n\n  To protect your rights, we need to make restrictions that forbid\ndistributors to deny you these rights or to ask you to surrender these\nrights.  These restrictions translate to certain responsibilities for\nyou if you distribute copies of the library or if you modify it.\n\n  For example, if you distribute copies of the library, whether gratis\nor for a fee, you must give the recipients all the rights that we gave\nyou.  You must make sure that they, too, receive or can get the source\ncode.  If you link other code with the library, you must provide\ncomplete object files to the recipients, so that they can relink them\nwith the library after making changes to the library and recompiling\nit.  And you must show them these terms so they know their rights.\n\n  We protect your rights with a two-step method: (1) we copyright the\nlibrary, and (2) we offer you this license, which gives you legal\npermission to copy, distribute and/or modify the library.\n\n  To protect each distributor, we want to make it very clear that\nthere is no warranty for the free library.  Also, if the library is\nmodified by someone else and passed on, the recipients should know\nthat what they have is not the original version, so that the original\nauthor's reputation will not be affected by problems that might be\nintroduced by others.\n\f\n  Finally, software patents pose a constant threat to the existence of\nany free program.  We wish to make sure that a company cannot\neffectively restrict the users of a free program by obtaining a\nrestrictive license from a patent holder.  Therefore, we insist that\nany patent license obtained for a version of the library must be\nconsistent with the full freedom of use specified in this license.\n\n  Most GNU software, including some libraries, is covered by the\nordinary GNU General Public License.  This license, the GNU Lesser\nGeneral Public License, applies to certain designated libraries, and\nis quite different from the ordinary General Public License.  We use\nthis license for certain libraries in order to permit linking those\nlibraries into non-free programs.\n\n  When a program is linked with a library, whether statically or using\na shared library, the combination of the two is legally speaking a\ncombined work, a derivative of the original library.  The ordinary\nGeneral Public License therefore permits such linking only if the\nentire combination fits its criteria of freedom.  The Lesser General\nPublic License permits more lax criteria for linking other code with\nthe library.\n\n  We call this license the \"Lesser\" General Public License because it\ndoes Less to protect the user's freedom than the ordinary General\nPublic License.  It also provides other free software developers Less\nof an advantage over competing non-free programs.  These disadvantages\nare the reason we use the ordinary General Public License for many\nlibraries.  However, the Lesser license provides advantages in certain\nspecial circumstances.\n\n  For example, on rare occasions, there may be a special need to\nencourage the widest possible use of a certain library, so that it becomes\na de-facto standard.  To achieve this, non-free programs must be\nallowed to use the library.  A more frequent case is that a free\nlibrary does the same job as widely used non-free libraries.  In this\ncase, there is little to gain by limiting the free library to free\nsoftware only, so we use the Lesser General Public License.\n\n  In other cases, permission to use a particular library in non-free\nprograms enables a greater number of people to use a large body of\nfree software.  For example, permission to use the GNU C Library in\nnon-free programs enables many more people to use the whole GNU\noperating system, as well as its variant, the GNU/Linux operating\nsystem.\n\n  Although the Lesser General Public License is Less protective of the\nusers' freedom, it does ensure that the user of a program that is\nlinked with the Library has the freedom and the wherewithal to run\nthat program using a modified version of the Library.\n\n  The precise terms and conditions for copying, distribution and\nmodification follow.  Pay close attention to the difference between a\n\"work based on the library\" and a \"work that uses the library\".  The\nformer contains code derived from the library, whereas the latter must\nbe combined with the library in order to run.\n\f\n                  GNU LESSER GENERAL PUBLIC LICENSE\n   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION\n\n  0. This License Agreement applies to any software library or other\nprogram which contains a notice placed by the copyright holder or\nother authorized party saying it may be distributed under the terms of\nthis Lesser General Public License (also called \"this License\").\nEach licensee is addressed as \"you\".\n\n  A \"library\" means a collection of software functions and/or data\nprepared so as to be conveniently linked with application programs\n(which use some of those functions and data) to form executables.\n\n  The \"Library\", below, refers to any such software library or work\nwhich has been distributed under these terms.  A \"work based on the\nLibrary\" means either the Library or any derivative work under\ncopyright law: that is to say, a work containing the Library or a\nportion of it, either verbatim or with modifications and/or translated\nstraightforwardly into another language.  (Hereinafter, translation is\nincluded without limitation in the term \"modification\".)\n\n  \"Source code\" for a work means the preferred form of the work for\nmaking modifications to it.  For a library, complete source code means\nall the source code for all modules it contains, plus any associated\ninterface definition files, plus the scripts used to control compilation\nand installation of the library.\n\n  Activities other than copying, distribution and modification are not\ncovered by this License; they are outside its scope.  The act of\nrunning a program using the Library is not restricted, and output from\nsuch a program is covered only if its contents constitute a work based\non the Library (independent of the use of the Library in a tool for\nwriting it).  Whether that is true depends on what the Library does\nand what the program that uses the Library does.\n\n  1. You may copy and distribute verbatim copies of the Library's\ncomplete source code as you receive it, in any medium, provided that\nyou conspicuously and appropriately publish on each copy an\nappropriate copyright notice and disclaimer of warranty; keep intact\nall the notices that refer to this License and to the absence of any\nwarranty; and distribute a copy of this License along with the\nLibrary.\n\n  You may charge a fee for the physical act of transferring a copy,\nand you may at your option offer warranty protection in exchange for a\nfee.\n\f\n  2. You may modify your copy or copies of the Library or any portion\nof it, thus forming a work based on the Library, and copy and\ndistribute such modifications or work under the terms of Section 1\nabove, provided that you also meet all of these conditions:\n\n    a) The modified work must itself be a software library.\n\n    b) You must cause the files modified to carry prominent notices\n    stating that you changed the files and the date of any change.\n\n    c) You must cause the whole of the work to be licensed at no\n    charge to all third parties under the terms of this License.\n\n    d) If a facility in the modified Library refers to a function or a\n    table of data to be supplied by an application program that uses\n    the facility, other than as an argument passed when the facility\n    is invoked, then you must make a good faith effort to ensure that,\n    in the event an application does not supply such function or\n    table, the facility still operates, and performs whatever part of\n    its purpose remains meaningful.\n\n    (For example, a function in a library to compute square roots has\n    a purpose that is entirely well-defined independent of the\n    application.  Therefore, Subsection 2d requires that any\n    application-supplied function or table used by this function must\n    be optional: if the application does not supply it, the square\n    root function must still compute square roots.)\n\nThese requirements apply to the modified work as a whole.  If\nidentifiable sections of that work are not derived from the Library,\nand can be reasonably considered independent and separate works in\nthemselves, then this License, and its terms, do not apply to those\nsections when you distribute them as separate works.  But when you\ndistribute the same sections as part of a whole which is a work based\non the Library, the distribution of the whole must be on the terms of\nthis License, whose permissions for other licensees extend to the\nentire whole, and thus to each and every part regardless of who wrote\nit.\n\nThus, it is not the intent of this section to claim rights or contest\nyour rights to work written entirely by you; rather, the intent is to\nexercise the right to control the distribution of derivative or\ncollective works based on the Library.\n\nIn addition, mere aggregation of another work not based on the Library\nwith the Library (or with a work based on the Library) on a volume of\na storage or distribution medium does not bring the other work under\nthe scope of this License.\n\n  3. You may opt to apply the terms of the ordinary GNU General Public\nLicense instead of this License to a given copy of the Library.  To do\nthis, you must alter all the notices that refer to this License, so\nthat they refer to the ordinary GNU General Public License, version 2,\ninstead of to this License.  (If a newer version than version 2 of the\nordinary GNU General Public License has appeared, then you can specify\nthat version instead if you wish.)  Do not make any other change in\nthese notices.\n\f\n  Once this change is made in a given copy, it is irreversible for\nthat copy, so the ordinary GNU General Public License applies to all\nsubsequent copies and derivative works made from that copy.\n\n  This option is useful when you wish to copy part of the code of\nthe Library into a program that is not a library.\n\n  4. You may copy and distribute the Library (or a portion or\nderivative of it, under Section 2) in object code or executable form\nunder the terms of Sections 1 and 2 above provided that you accompany\nit with the complete corresponding machine-readable source code, which\nmust be distributed under the terms of Sections 1 and 2 above on a\nmedium customarily used for software interchange.\n\n  If distribution of object code is made by offering access to copy\nfrom a designated place, then offering equivalent access to copy the\nsource code from the same place satisfies the requirement to\ndistribute the source code, even though third parties are not\ncompelled to copy the source along with the object code.\n\n  5. A program that contains no derivative of any portion of the\nLibrary, but is designed to work with the Library by being compiled or\nlinked with it, is called a \"work that uses the Library\".  Such a\nwork, in isolation, is not a derivative work of the Library, and\ntherefore falls outside the scope of this License.\n\n  However, linking a \"work that uses the Library\" with the Library\ncreates an executable that is a derivative of the Library (because it\ncontains portions of the Library), rather than a \"work that uses the\nlibrary\".  The executable is therefore covered by this License.\nSection 6 states terms for distribution of such executables.\n\n  When a \"work that uses the Library\" uses material from a header file\nthat is part of the Library, the object code for the work may be a\nderivative work of the Library even though the source code is not.\nWhether this is true is especially significant if the work can be\nlinked without the Library, or if the work is itself a library.  The\nthreshold for this to be true is not precisely defined by law.\n\n  If such an object file uses only numerical parameters, data\nstructure layouts and accessors, and small macros and small inline\nfunctions (ten lines or less in length), then the use of the object\nfile is unrestricted, regardless of whether it is legally a derivative\nwork.  (Executables containing this object code plus portions of the\nLibrary will still fall under Section 6.)\n\n  Otherwise, if the work is a derivative of the Library, you may\ndistribute the object code for the work under the terms of Section 6.\nAny executables containing that work also fall under Section 6,\nwhether or not they are linked directly with the Library itself.\n\f\n  6. As an exception to the Sections above, you may also combine or\nlink a \"work that uses the Library\" with the Library to produce a\nwork containing portions of the Library, and distribute that work\nunder terms of your choice, provided that the terms permit\nmodification of the work for the customer's own use and reverse\nengineering for debugging such modifications.\n\n  You must give prominent notice with each copy of the work that the\nLibrary is used in it and that the Library and its use are covered by\nthis License.  You must supply a copy of this License.  If the work\nduring execution displays copyright notices, you must include the\ncopyright notice for the Library among them, as well as a reference\ndirecting the user to the copy of this License.  Also, you must do one\nof these things:\n\n    a) Accompany the work with the complete corresponding\n    machine-readable source code for the Library including whatever\n    changes were used in the work (which must be distributed under\n    Sections 1 and 2 above); and, if the work is an executable linked\n    with the Library, with the complete machine-readable \"work that\n    uses the Library\", as object code and/or source code, so that the\n    user can modify the Library and then relink to produce a modified\n    executable containing the modified Library.  (It is understood\n    that the user who changes the contents of definitions files in the\n    Library will not necessarily be able to recompile the application\n    to use the modified definitions.)\n\n    b) Use a suitable shared library mechanism for linking with the\n    Library.  A suitable mechanism is one that (1) uses at run time a\n    copy of the library already present on the user's computer system,\n    rather than copying library functions into the executable, and (2)\n    will operate properly with a modified version of the library, if\n    the user installs one, as long as the modified version is\n    interface-compatible with the version that the work was made with.\n\n    c) Accompany the work with a written offer, valid for at\n    least three years, to give the same user the materials\n    specified in Subsection 6a, above, for a charge no more\n    than the cost of performing this distribution.\n\n    d) If distribution of the work is made by offering access to copy\n    from a designated place, offer equivalent access to copy the above\n    specified materials from the same place.\n\n    e) Verify that the user has already received a copy of these\n    materials or that you have already sent this user a copy.\n\n  For an executable, the required form of the \"work that uses the\nLibrary\" must include any data and utility programs needed for\nreproducing the executable from it.  However, as a special exception,\nthe materials to be distributed need not include anything that is\nnormally distributed (in either source or binary form) with the major\ncomponents (compiler, kernel, and so on) of the operating system on\nwhich the executable runs, unless that component itself accompanies\nthe executable.\n\n  It may happen that this requirement contradicts the license\nrestrictions of other proprietary libraries that do not normally\naccompany the operating system.  Such a contradiction means you cannot\nuse both them and the Library together in an executable that you\ndistribute.\n\f\n  7. You may place library facilities that are a work based on the\nLibrary side-by-side in a single library together with other library\nfacilities not covered by this License, and distribute such a combined\nlibrary, provided that the separate distribution of the work based on\nthe Library and of the other library facilities is otherwise\npermitted, and provided that you do these two things:\n\n    a) Accompany the combined library with a copy of the same work\n    based on the Library, uncombined with any other library\n    facilities.  This must be distributed under the terms of the\n    Sections above.\n\n    b) Give prominent notice with the combined library of the fact\n    that part of it is a work based on the Library, and explaining\n    where to find the accompanying uncombined form of the same work.\n\n  8. You may not copy, modify, sublicense, link with, or distribute\nthe Library except as expressly provided under this License.  Any\nattempt otherwise to copy, modify, sublicense, link with, or\ndistribute the Library is void, and will automatically terminate your\nrights under this License.  However, parties who have received copies,\nor rights, from you under this License will not have their licenses\nterminated so long as such parties remain in full compliance.\n\n  9. You are not required to accept this License, since you have not\nsigned it.  However, nothing else grants you permission to modify or\ndistribute the Library or its derivative works.  These actions are\nprohibited by law if you do not accept this License.  Therefore, by\nmodifying or distributing the Library (or any work based on the\nLibrary), you indicate your acceptance of this License to do so, and\nall its terms and conditions for copying, distributing or modifying\nthe Library or works based on it.\n\n  10. Each time you redistribute the Library (or any work based on the\nLibrary), the recipient automatically receives a license from the\noriginal licensor to copy, distribute, link with or modify the Library\nsubject to these terms and conditions.  You may not impose any further\nrestrictions on the recipients' exercise of the rights granted herein.\nYou are not responsible for enforcing compliance by third parties with\nthis License.\n\f\n  11. If, as a consequence of a court judgment or allegation of patent\ninfringement or for any other reason (not limited to patent issues),\nconditions are imposed on you (whether by court order, agreement or\notherwise) that contradict the conditions of this License, they do not\nexcuse you from the conditions of this License.  If you cannot\ndistribute so as to satisfy simultaneously your obligations under this\nLicense and any other pertinent obligations, then as a consequence you\nmay not distribute the Library at all.  For example, if a patent\nlicense would not permit royalty-free redistribution of the Library by\nall those who receive copies directly or indirectly through you, then\nthe only way you could satisfy both it and this License would be to\nrefrain entirely from distribution of the Library.\n\nIf any portion of this section is held invalid or unenforceable under any\nparticular circumstance, the balance of the section is intended to apply,\nand the section as a whole is intended to apply in other circumstances.\n\nIt is not the purpose of this section to induce you to infringe any\npatents or other property right claims or to contest validity of any\nsuch claims; this section has the sole purpose of protecting the\nintegrity of the free software distribution system which is\nimplemented by public license practices.  Many people have made\ngenerous contributions to the wide range of software distributed\nthrough that system in reliance on consistent application of that\nsystem; it is up to the author/donor to decide if he or she is willing\nto distribute software through any other system and a licensee cannot\nimpose that choice.\n\nThis section is intended to make thoroughly clear what is believed to\nbe a consequence of the rest of this License.\n\n  12. If the distribution and/or use of the Library is restricted in\ncertain countries either by patents or by copyrighted interfaces, the\noriginal copyright holder who places the Library under this License may add\nan explicit geographical distribution limitation excluding those countries,\nso that distribution is permitted only in or among countries not thus\nexcluded.  In such case, this License incorporates the limitation as if\nwritten in the body of this License.\n\n  13. The Free Software Foundation may publish revised and/or new\nversions of the Lesser General Public License from time to time.\nSuch new versions will be similar in spirit to the present version,\nbut may differ in detail to address new problems or concerns.\n\nEach version is given a distinguishing version number.  If the Library\nspecifies a version number of this License which applies to it and\n\"any later version\", you have the option of following the terms and\nconditions either of that version or of any later version published by\nthe Free Software Foundation.  If the Library does not specify a\nlicense version number, you may choose any version ever published by\nthe Free Software Foundation.\n\f\n  14. If you wish to incorporate parts of the Library into other free\nprograms whose distribution conditions are incompatible with these,\nwrite to the author to ask for permission.  For software which is\ncopyrighted by the Free Software Foundation, write to the Free\nSoftware Foundation; we sometimes make exceptions for this.  Our\ndecision will be guided by the two goals of preserving the free status\nof all derivatives of our free software and of promoting the sharing\nand reuse of software generally.\n\n                            NO WARRANTY\n\n  15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO\nWARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.\nEXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR\nOTHER PARTIES PROVIDE THE LIBRARY \"AS IS\" WITHOUT WARRANTY OF ANY\nKIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE\nIMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR\nPURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE\nLIBRARY IS WITH YOU.  SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME\nTHE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.\n\n  16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN\nWRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY\nAND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU\nFOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR\nCONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE\nLIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING\nRENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A\nFAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF\nSUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH\nDAMAGES.\n\n                     END OF TERMS AND CONDITIONS\n\f\n           How to Apply These Terms to Your New Libraries\n\n  If you develop a new library, and you want it to be of the greatest\npossible use to the public, we recommend making it free software that\neveryone can redistribute and change.  You can do so by permitting\nredistribution under these terms (or, alternatively, under the terms of the\nordinary General Public License).\n\n  To apply these terms, attach the following notices to the library.  It is\nsafest to attach them to the start of each source file to most effectively\nconvey the exclusion of warranty; and each file should have at least the\n\"copyright\" line and a pointer to where the full notice is found.\n\n    <one line to give the library's name and a brief idea of what it does.>\n    Copyright (C) <year>  <name of author>\n\n    This library is free software; you can redistribute it and/or\n    modify it under the terms of the GNU Lesser General Public\n    License as published by the Free Software Foundation; either\n    version 2.1 of the License, or (at your option) any later version.\n\n    This library is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n    Lesser General Public License for more details.\n\n    You should have received a copy of the GNU Lesser General Public\n    License along with this library; if not, write to the Free Software\n    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n\nAlso add information on how to contact you by electronic and paper mail.\n\nYou should also get your employer (if you work as a programmer) or your\nschool, if any, to sign a \"copyright disclaimer\" for the library, if\nnecessary.  Here is a sample; alter the names:\n\n  Yoyodyne, Inc., hereby disclaims all copyright interest in the\n  library `Frob' (a library for tweaking knobs) written by James Random Hacker.\n\n  <signature of Ty Coon>, 1 April 1990\n  Ty Coon, President of Vice\n\nThat's all there is to it!\n"
  },
  {
    "path": "Libplanet.Explorer.ruleset",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<RuleSet\n  Name=\"Rules for Libplanet\"\n  Description=\"Code analysis rules for Libplanet.csproj.\"\n  ToolsVersion=\"10.0\">\n\n  <Rules\n    AnalyzerId=\"Microsoft.Analyzers.ManagedCodeAnalysis\"\n    RuleNamespace=\"Microsoft.Rules.Managed\">\n\n    <!-- TODO: Write copyright -->\n    <Rule Id=\"SA1633\" Action=\"None\" />\n    <Rule Id=\"SA1652\" Action=\"None\" />\n    <!-- Allow field name to begin with an underscore. -->\n    <Rule Id=\"SA1309\" Action=\"None\" />\n    <!-- Allow an expression not to declare parentheses. -->\n    <Rule Id=\"SA1407\" Action=\"None\" />\n    <!-- Allow a rich text in a XML doc comment's <summary>. -->\n    <Rule Id=\"SA1462\" Action=\"None\" />\n    <Rule Id=\"SA1642\" Action=\"None\" />\n    <!-- Every property's docs doesn't have to start with \"Gets\", because\n    it's ridiculous. -->\n    <Rule Id=\"SA1623\" Action=\"None\" />\n    <!--Allow to call an instance member of the local class or a base class is\n    not prefixed with 'this.'. -->\n    <Rule Id=\"SA1101\" Action=\"None\" />\n    <!--Allow closing parenthesis to be placed in new line. -->\n    <Rule Id=\"SA1009\" Action=\"None\" />\n    <Rule Id=\"SA1111\" Action=\"None\" />\n    <!-- TODO: Documentation -->\n    <Rule Id=\"SA1600\" Action=\"None\" />\n    <Rule Id=\"SA1601\" Action=\"None\" />\n    <Rule Id=\"SA0001\" Action=\"None\" />\n  </Rules>\n\n  <Rules AnalyzerId=\"Menees.Analyzers\" RuleNamespace=\"Menees.Analyzers\">\n    <Rule Id=\"MEN002\" Action=\"Warning\" />\n    <Rule Id=\"MEN007\" Action=\"None\" />\n    <Rule Id=\"MEN009\" Action=\"Warning\" />\n    <Rule Id=\"MEN010\" Action=\"None\" />\n    <Rule Id=\"MEN011\" Action=\"None\" />\n  </Rules>\n</RuleSet>\n"
  },
  {
    "path": "Libplanet.Tests.ruleset",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<RuleSet\n  Name=\"Rules for Libplanet.Tests\"\n  Description=\"Code analysis rules for Libplanet.Tests.csproj.\"\n  ToolsVersion=\"10.0\">\n\n  <Rules\n    AnalyzerId=\"Microsoft.Analyzers.ManagedCodeAnalysis\"\n    RuleNamespace=\"Microsoft.Rules.Managed\">\n\n    <!-- Single line comment should begin with a space. -->\n    <Rule Id=\"SA1005\" Action=\"None\" />\n    <!-- Closing parenthesis should be on line of opening parenthesis -->\n    <Rule Id=\"SA1112\" Action=\"None\" />\n    <!-- The parameter spans multiple lines -->\n    <Rule Id=\"SA1118\" Action=\"None\" />\n    <!-- Allow tuple types in signatures omit element names. -->\n    <Rule Id=\"SA1414\" Action=\"None\" />\n    <!-- Allow tuple fields to be referred by index (i.e. ItemN). -->\n    <Rule Id=\"SA1142\" Action=\"None\" />\n    <!-- Single-line comment should be preceded by blank line. -->\n    <Rule Id=\"SA1515\" Action=\"None\" />\n    <!-- TODO: Write copyright -->\n    <Rule Id=\"SA1633\" Action=\"None\" />\n    <Rule Id=\"SA1652\" Action=\"None\" />\n    <!-- Allow field name to begin with an underscore. -->\n    <Rule Id=\"SA1309\" Action=\"None\" />\n    <!-- Allow an expression not to declare parentheses. -->\n    <Rule Id=\"SA1407\" Action=\"None\" />\n    <!-- Allow a rich text in a XML doc comment's <summary>. -->\n    <Rule Id=\"SA1462\" Action=\"None\" />\n    <Rule Id=\"SA1642\" Action=\"None\" />\n    <!-- Every property's docs doesn't have to start with \"Gets\", because\n    it's ridiculous. -->\n    <Rule Id=\"SA1623\" Action=\"None\" />\n    <!--Allow to call an instance member of the local class or a base class is\n    not prefixed with 'this.'. -->\n    <Rule Id=\"SA1101\" Action=\"None\" />\n    <!--Allow closing parenthesis to be placed in new line. -->\n    <Rule Id=\"SA1009\" Action=\"None\" />\n    <Rule Id=\"SA1111\" Action=\"None\" />\n    <!-- TODO: Documentation -->\n    <Rule Id=\"SA1600\" Action=\"None\" />\n    <Rule Id=\"SA1601\" Action=\"None\" />\n    <Rule Id=\"SA0001\" Action=\"None\" />\n  </Rules>\n\n  <Rules AnalyzerId=\"Menees.Analyzers\" RuleNamespace=\"Menees.Analyzers\">\n    <Rule Id=\"MEN002\" Action=\"Warning\" />\n    <Rule Id=\"MEN007\" Action=\"None\" />\n    <Rule Id=\"MEN009\" Action=\"Warning\" />\n    <Rule Id=\"MEN010\" Action=\"None\" />\n    <Rule Id=\"MEN011\" Action=\"None\" />\n    <Rule Id=\"MEN014\" Action=\"None\" />\n  </Rules>\n\n  <Rules AnalyzerId=\"SonarAnalyzer\" RuleNamespace=\"SonarAnalyzer\">\n    <!-- Either remove or fill this block of code. -->\n    <Rule Id=\"S108\" Action=\"None\" />\n    <!-- Add the default parameter value defined in the overridden method. -->\n    <Rule Id=\"S1006\" Action=\"None\" />\n    <!-- Take the required action to fix the issue indicated by this\n    'FIXME' comment. -->\n    <Rule Id=\"S1134\" Action=\"None\" />\n    <!-- Complete the task associated to this 'TODO' comment. -->\n    <Rule Id=\"S1135\" Action=\"None\" />\n    <!-- Add a nested comment explaining why this method is empty, throw a\n    'NotSupportedException' or complete the implementation. -->\n    <Rule Id=\"S1186\" Action=\"None\" />\n    <!-- Make field 'readonly'. -->\n    <Rule Id=\"S2933\" Action=\"None\" />\n    <!-- Return 'Task' instead. -->\n    <Rule Id=\"S3168\" Action=\"None\" />\n    <!-- Extract this nested ternary operation into an independent statement. -->\n    <Rule Id=\"S3358\" Action=\"Info\" />\n    <!-- Make this test method non-'async' or return 'Task'. -->\n    <Rule Id=\"S3433\" Action=\"None\" />\n    <!-- Fix this implementation of 'IDisposable' to conform to the dispose\n    pattern. -->\n    <Rule Id=\"S3881\" Action=\"None\" />\n\n    <!-- Rename parameter 'A' to 'B' to match the interface declaration. -->\n    <Rule Id=\"S927\" Action=\"None\" />\n    <!-- Add a 'protected' constructor or the 'static' keyword to the class\n    declaration. -->\n    <Rule Id=\"S1118\" Action=\"None\" />\n    <!-- Remove the unused local variable 'x'. -->\n    <Rule Id=\"S1481\" Action=\"None\" />\n\n    <!-- Remove this parameter 'x', whose value is ignored in the method. -->\n    <Rule Id=\"S1172\" Action=\"None\" />\n    <!-- Remove this useless assignment to local variable x -->\n    <Rule Id=\"S1854\" Action=\"None\" />\n    <!-- Change this condition so that it does not always evaluate to 'false'; some subsequent code is never executed. -->\n    <Rule Id=\"S2583\" Action=\"None\" />\n    <!-- Remove this redundant jump. -->\n    <Rule Id=\"S3626\" Action=\"None\" />\n    <!-- Restrict types of objects allowed to be deserialized. -->\n    <Rule Id=\"S5773\" Action=\"None\" />\n  </Rules>\n</RuleSet>\n"
  },
  {
    "path": "Libplanet.ruleset",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<RuleSet\n  Name=\"Rules for Libplanet\"\n  Description=\"Code analysis rules for Libplanet.csproj.\"\n  ToolsVersion=\"10.0\">\n\n  <Rules\n    AnalyzerId=\"Microsoft.Analyzers.ManagedCodeAnalysis\"\n    RuleNamespace=\"Microsoft.Rules.Managed\">\n\n    <!-- TODO: Write copyright -->\n    <Rule Id=\"SA1633\" Action=\"None\" />\n    <Rule Id=\"SA1652\" Action=\"None\" />\n    <!-- Allow field name to begin with an underscore. -->\n    <Rule Id=\"SA1309\" Action=\"None\" />\n    <!-- Allow an expression not to declare parentheses. -->\n    <Rule Id=\"SA1407\" Action=\"None\" />\n    <!-- Allow tuple types in signatures omit element names. -->\n    <Rule Id=\"SA1414\" Action=\"None\" />\n    <!-- Allow tuple fields to be referred by index (i.e. ItemN). -->\n    <Rule Id=\"SA1142\" Action=\"None\" />\n    <!-- Allow a rich text in a XML doc comment's <summary>. -->\n    <Rule Id=\"SA1462\" Action=\"None\" />\n    <Rule Id=\"SA1642\" Action=\"None\" />\n    <!-- Every property's docs doesn't have to start with \"Gets\", because\n    it's ridiculous. -->\n    <Rule Id=\"SA1623\" Action=\"None\" />\n    <!--Allow to call an instance member of the local class or a base class is\n    not prefixed with 'this.'. -->\n    <Rule Id=\"SA1101\" Action=\"None\" />\n    <!--Allow closing parenthesis to be placed in new line. -->\n    <Rule Id=\"SA1009\" Action=\"None\" />\n    <Rule Id=\"SA1111\" Action=\"None\" />\n    <!-- TODO: Documentation -->\n    <Rule Id=\"SA1600\" Action=\"None\" />\n    <Rule Id=\"SA1601\" Action=\"None\" />\n    <Rule Id=\"SA0001\" Action=\"None\" />\n  </Rules>\n\n  <Rules AnalyzerId=\"Menees.Analyzers\" RuleNamespace=\"Menees.Analyzers\">\n    <Rule Id=\"MEN002\" Action=\"Warning\" />\n    <Rule Id=\"MEN007\" Action=\"None\" />\n    <Rule Id=\"MEN009\" Action=\"Warning\" />\n    <Rule Id=\"MEN010\" Action=\"None\" />\n    <Rule Id=\"MEN011\" Action=\"None\" />\n    <Rule Id=\"MEN014\" Action=\"None\" />\n  </Rules>\n\n  <Rules AnalyzerId=\"SonarAnalyzer\" RuleNamespace=\"SonarAnalyzer\">\n    <!-- These warn about leaving parameters taking ICultureInfo default,\n    which implicitly follows the system's locale settings so that code is\n    non-deterministic. -->\n    <Rule Id=\"S1449\" Action=\"Warning\" />\n    <Rule Id=\"S4026\" Action=\"Warning\" />\n    <Rule Id=\"S4056\" Action=\"Warning\" />\n    <Rule Id=\"S4057\" Action=\"Warning\" />\n\n    <!-- Either remove or fill this block of code. -->\n    <Rule Id=\"S108\" Action=\"None\" />\n    <!-- 'System.NullReferenceException' should not be thrown by user code. -->\n    <Rule Id=\"S112\" Action=\"None\" />\n    <!-- Add the default parameter value defined in the overridden method. -->\n    <Rule Id=\"S1006\" Action=\"None\" />\n    <!-- Add an explanation -->\n    <Rule Id=\"S1123\" Action=\"None\" />\n    <!-- Take the required action to fix the issue indicated by this\n    'FIXME' comment. -->\n    <Rule Id=\"S1134\" Action=\"None\" />\n    <!-- Complete the task associated to this 'TODO' comment. -->\n    <Rule Id=\"S1135\" Action=\"None\" />\n    <!-- Return an empty collection instead of null. -->\n    <Rule Id=\"S1168\" Action=\"None\" />\n    <!-- Remove this unused method parameter 'cancellationToken'. -->\n    <Rule Id=\"S1172\" Action=\"None\" />\n    <!-- This struct overrides 'GetHashCode' and should therefore also override\n    'Equals'. -->\n    <Rule Id=\"S1206\" Action=\"None\" />\n    <!-- When implementing IComparable<T> or IComparable, you should also\n    override Equals, <, >, <=, >=, ==, !=. -->\n    <Rule Id=\"S1210\" Action=\"None\" />\n    <!-- Use a StringBuilder instead. -->\n    <Rule Id=\"S1643\" Action=\"None\" />\n    <!-- Use a 'null' check instead. -->\n    <Rule Id=\"S2219\" Action=\"None\" />\n    <!-- variable is null on at least one execution path. -->\n    <Rule Id=\"S2259\" Action=\"None\" />\n    <!-- Combine this 'try' with the one starting on line x. -->\n    <Rule Id=\"S2327\" Action=\"None\" />\n    <!-- Refactor property into a method, properties should not copy\n    collections. -->\n    <Rule Id=\"S2365\" Action=\"None\" />\n    <!-- Replace the control character at position 1 by its escape sequence\n    '\\n'. -->\n    <Rule Id=\"S2479\" Action=\"None\" />\n    <!-- A static field in a generic type is not shared among instances of\n    different close constructed types. -->\n    <Rule Id=\"S2743\" Action=\"None\" />\n    <!-- Make field 'readonly'. -->\n    <Rule Id=\"S2933\" Action=\"None\" />\n    <!-- Fix this implementation of 'IDisposable' to conform to the dispose\n    pattern. -->\n    <Rule Id=\"S3881\" Action=\"None\" />\n    <!-- Update this implementation of 'ISerializable' to conform to the\n    recommended serialization pattern. -->\n    <Rule Id=\"S3925\" Action=\"None\" />\n    <!-- Use a constructor overloads that allows a more meaningful exception\n    message to be provided. -->\n    <Rule Id=\"S3928\" Action=\"None\" />\n    <!-- Initialize all 'static fields' inline and remove the\n    'static constructor'. -->\n    <Rule Id=\"S3963\" Action=\"None\" />\n    <!-- Split this method into two, one handling parameters check and the\n    other handling the asynchronous code. -->\n    <Rule Id=\"S4457\" Action=\"None\" />\n\n    <!-- Remove the unused local variable 'x'. -->\n    <Rule Id=\"S1481\" Action=\"None\" />\n\n    <!-- Remove this useless assignment to local variable x -->\n    <Rule Id=\"S1854\" Action=\"None\" />\n    <!-- Remove this redundant jump. -->\n    <Rule Id=\"S3626\" Action=\"None\" />\n    <!-- Restrict types of objects allowed to be deserialized. -->\n    <Rule Id=\"S5773\" Action=\"None\" />\n  </Rules>\n</RuleSet>\n"
  },
  {
    "path": "Libplanet.sln",
    "content": "﻿\nMicrosoft Visual Studio Solution File, Format Version 12.00\n# Visual Studio Version 17\nVisualStudioVersion = 17.5.33424.131\nMinimumVisualStudioVersion = 15.0.26124.0\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"Libplanet.Stun\", \"src\\Libplanet.Stun\\Libplanet.Stun.csproj\", \"{4F5DB8F5-D0F4-454C-95A7-87F53E5D5E36}\"\nEndProject\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"Libplanet.Stun.Tests\", \"test\\Libplanet.Stun.Tests\\Libplanet.Stun.Tests.csproj\", \"{5C2B23E2-C286-412D-ADE1-F6796B7083DE}\"\nEndProject\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"Libplanet\", \"src\\Libplanet\\Libplanet.csproj\", \"{50E14C9A-3C2F-4A51-971F-6143952D0F1C}\"\nEndProject\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"Libplanet.Tests\", \"test\\Libplanet.Tests\\Libplanet.Tests.csproj\", \"{3BA7D9BE-EBBF-432E-9880-0E2D2C17FCF8}\"\nEndProject\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"Libplanet.Benchmarks\", \"tools\\Libplanet.Benchmarks\\Libplanet.Benchmarks.csproj\", \"{E010FB5E-0D68-4AF7-B632-5DB6B902F158}\"\nEndProject\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"Libplanet.RocksDBStore\", \"src\\Libplanet.RocksDBStore\\Libplanet.RocksDBStore.csproj\", \"{A5DE942D-912D-4012-8493-1E958E5445F4}\"\nEndProject\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"Libplanet.RocksDBStore.Tests\", \"test\\Libplanet.RocksDBStore.Tests\\Libplanet.RocksDBStore.Tests.csproj\", \"{ADCBBAC0-0A87-45B7-BD31-314F136F74D4}\"\nEndProject\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"Libplanet.Tools\", \"tools\\Libplanet.Tools\\Libplanet.Tools.csproj\", \"{A216C2F0-A9A6-4D7F-BF65-127EB80EA6A7}\"\nEndProject\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"Libplanet.Analyzers\", \"tools\\Libplanet.Analyzers\\Libplanet.Analyzers.csproj\", \"{5CEE1B93-3936-4E32-A414-522DCDCA26BB}\"\nEndProject\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"Libplanet.Analyzers.Tests\", \"test\\Libplanet.Analyzers.Tests\\Libplanet.Analyzers.Tests.csproj\", \"{B48782B9-6FA9-4D18-8564-1849FF4CF40E}\"\nEndProject\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"Libplanet.Explorer\", \"tools\\Libplanet.Explorer\\Libplanet.Explorer.csproj\", \"{B41C8F1C-5BD2-43B9-A3CC-FC03DFE04E23}\"\nEndProject\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"Libplanet.Explorer.Executable\", \"tools\\Libplanet.Explorer.Executable\\Libplanet.Explorer.Executable.csproj\", \"{BEDBC0F8-AD0A-44C3-9A53-C8EC4E631AF4}\"\nEndProject\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"Libplanet.Explorer.Tests\", \"test\\Libplanet.Explorer.Tests\\Libplanet.Explorer.Tests.csproj\", \"{48A7AC8E-2CB5-403B-8A18-11F493079619}\"\nEndProject\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"Libplanet.Extensions.Cocona\", \"tools\\Libplanet.Extensions.Cocona\\Libplanet.Extensions.Cocona.csproj\", \"{B3170309-55AB-462C-9100-D77107799E82}\"\nEndProject\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"Libplanet.Extensions.Cocona.Tests\", \"test\\Libplanet.Extensions.Cocona.Tests\\Libplanet.Extensions.Cocona.Tests.csproj\", \"{A43E44E5-F9C1-44BD-A593-419EC113117B}\"\nEndProject\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"Libplanet.Net\", \"src\\Libplanet.Net\\Libplanet.Net.csproj\", \"{2E17A091-DC29-41FB-ABC8-767BD75FFB07}\"\nEndProject\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"Libplanet.Net.Tests\", \"test\\Libplanet.Net.Tests\\Libplanet.Net.Tests.csproj\", \"{6D7A63C9-16AB-4B7E-B9C0-0956E1E02610}\"\nEndProject\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"Libplanet.Crypto.Secp256k1\", \"src\\Libplanet.Crypto.Secp256k1\\Libplanet.Crypto.Secp256k1.csproj\", \"{9F88C871-CB37-4A88-BACF-540AC253C202}\"\nEndProject\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"Libplanet.Crypto.Secp256k1.Tests\", \"test\\Libplanet.Crypto.Secp256k1.Tests\\Libplanet.Crypto.Secp256k1.Tests.csproj\", \"{B1A38DDE-5534-4625-A3F2-A585BA7A1198}\"\nEndProject\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"Libplanet.Explorer.Cocona\", \"tools\\Libplanet.Explorer.Cocona\\Libplanet.Explorer.Cocona.csproj\", \"{8698E0C2-1A82-43E6-8A26-3D9A825CF574}\"\nEndProject\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"Libplanet.Explorer.Cocona.Tests\", \"test\\Libplanet.Explorer.Cocona.Tests\\Libplanet.Explorer.Cocona.Tests.csproj\", \"{F782BC86-9CE6-4F69-8F77-710A399CB54F}\"\nEndProject\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"Libplanet.Common\", \"src\\Libplanet.Common\\Libplanet.Common.csproj\", \"{763BAD3E-3244-4E8F-8182-2BF35774262A}\"\nEndProject\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"Libplanet.Store\", \"src\\Libplanet.Store\\Libplanet.Store.csproj\", \"{2BC01C4C-288B-4768-BAD0-9BC441D82505}\"\nEndProject\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"Libplanet.Action\", \"src\\Libplanet.Action\\Libplanet.Action.csproj\", \"{DDD598B2-005F-4CB2-B26B-A40CC0F9DE8E}\"\nEndProject\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"Libplanet.Action.Tests\", \"test\\Libplanet.Action.Tests\\Libplanet.Action.Tests.csproj\", \"{5B2BF317-7315-431F-A854-488CD541F42E}\"\nEndProject\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"Libplanet.Crypto\", \"src\\Libplanet.Crypto\\Libplanet.Crypto.csproj\", \"{896946A7-35AB-40D0-972C-CED7A448B97A}\"\nEndProject\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"Libplanet.Types\", \"src\\Libplanet.Types\\Libplanet.Types.csproj\", \"{C7EFF544-391C-488F-A747-2663AFEED250}\"\nEndProject\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"Libplanet.Store.Remote\", \"src\\Libplanet.Store.Remote\\Libplanet.Store.Remote.csproj\", \"{CF31204A-12CF-43C0-9054-B9AF98EC83BD}\"\nEndProject\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"Libplanet.Store.Remote.Tests\", \"test\\Libplanet.Store.Remote.Tests\\Libplanet.Store.Remote.Tests.csproj\", \"{97F29346-636E-4BCA-B33D-6D0DB26A5AA6}\"\nEndProject\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"Libplanet.Mocks\", \"test\\Libplanet.Mocks\\Libplanet.Mocks.csproj\", \"{46C1A70D-D1DE-4173-A8C0-00F680F026E3}\"\nEndProject\nProject(\"{2150E333-8FDC-42A3-9474-1A3956D46DE8}\") = \"src\", \"src\", \"{AC908E33-B856-4E23-9F81-B7F7C97A07F9}\"\nEndProject\nProject(\"{2150E333-8FDC-42A3-9474-1A3956D46DE8}\") = \"test\", \"test\", \"{B9C00FAF-36CF-463A-83FA-43E6B974AE2E}\"\nEndProject\nProject(\"{2150E333-8FDC-42A3-9474-1A3956D46DE8}\") = \"tools\", \"tools\", \"{88E7FAF4-CEEC-48B6-9114-71CFE3FC0F50}\"\nEndProject\nProject(\"{2150E333-8FDC-42A3-9474-1A3956D46DE8}\") = \"sdk\", \"sdk\", \"{D8186A1A-6640-4986-9E97-FABE59F6DCE0}\"\nEndProject\nProject(\"{2150E333-8FDC-42A3-9474-1A3956D46DE8}\") = \"node\", \"node\", \"{8CA69CC9-3415-4484-9342-88D495AE2FF6}\"\nEndProject\nProject(\"{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}\") = \"Libplanet.Node\", \"sdk\\node\\Libplanet.Node\\Libplanet.Node.csproj\", \"{2CBD3BE8-9DBF-483D-8E38-88E9DBC86D91}\"\nEndProject\nProject(\"{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}\") = \"Libplanet.Node.Extensions\", \"sdk\\node\\Libplanet.Node.Extensions\\Libplanet.Node.Extensions.csproj\", \"{704BA731-9C70-4CBE-A607-1A2E1FB73753}\"\nEndProject\nProject(\"{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}\") = \"Libplanet.Node.Executable\", \"sdk\\node\\Libplanet.Node.Executable\\Libplanet.Node.Executable.csproj\", \"{A0EAD8F0-B7A3-4112-9F3F-2D9922A500BA}\"\nEndProject\nProject(\"{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}\") = \"Libplanet.Node.Tests\", \"sdk\\node\\Libplanet.Node.Tests\\Libplanet.Node.Tests.csproj\", \"{C050C5F0-8A40-4CB1-9715-A55EBF94FBF2}\"\nEndProject\nGlobal\n\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\n\t\tDebug|Any CPU = Debug|Any CPU\n\t\tDebug|x64 = Debug|x64\n\t\tDebug|x86 = Debug|x86\n\t\tReleaseMono|Any CPU = ReleaseMono|Any CPU\n\t\tReleaseMono|x64 = ReleaseMono|x64\n\t\tReleaseMono|x86 = ReleaseMono|x86\n\t\tRelease|Any CPU = Release|Any CPU\n\t\tRelease|x64 = Release|x64\n\t\tRelease|x86 = Release|x86\n\tEndGlobalSection\n\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\n\t\t{4F5DB8F5-D0F4-454C-95A7-87F53E5D5E36}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{4F5DB8F5-D0F4-454C-95A7-87F53E5D5E36}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{4F5DB8F5-D0F4-454C-95A7-87F53E5D5E36}.Debug|x64.ActiveCfg = Debug|Any CPU\n\t\t{4F5DB8F5-D0F4-454C-95A7-87F53E5D5E36}.Debug|x64.Build.0 = Debug|Any CPU\n\t\t{4F5DB8F5-D0F4-454C-95A7-87F53E5D5E36}.Debug|x86.ActiveCfg = Debug|Any CPU\n\t\t{4F5DB8F5-D0F4-454C-95A7-87F53E5D5E36}.Debug|x86.Build.0 = Debug|Any CPU\n\t\t{4F5DB8F5-D0F4-454C-95A7-87F53E5D5E36}.ReleaseMono|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{4F5DB8F5-D0F4-454C-95A7-87F53E5D5E36}.ReleaseMono|Any CPU.Build.0 = Release|Any CPU\n\t\t{4F5DB8F5-D0F4-454C-95A7-87F53E5D5E36}.ReleaseMono|x64.ActiveCfg = Release|Any CPU\n\t\t{4F5DB8F5-D0F4-454C-95A7-87F53E5D5E36}.ReleaseMono|x64.Build.0 = Release|Any CPU\n\t\t{4F5DB8F5-D0F4-454C-95A7-87F53E5D5E36}.ReleaseMono|x86.ActiveCfg = Release|Any CPU\n\t\t{4F5DB8F5-D0F4-454C-95A7-87F53E5D5E36}.ReleaseMono|x86.Build.0 = Release|Any CPU\n\t\t{4F5DB8F5-D0F4-454C-95A7-87F53E5D5E36}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{4F5DB8F5-D0F4-454C-95A7-87F53E5D5E36}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{4F5DB8F5-D0F4-454C-95A7-87F53E5D5E36}.Release|x64.ActiveCfg = Release|Any CPU\n\t\t{4F5DB8F5-D0F4-454C-95A7-87F53E5D5E36}.Release|x64.Build.0 = Release|Any CPU\n\t\t{4F5DB8F5-D0F4-454C-95A7-87F53E5D5E36}.Release|x86.ActiveCfg = Release|Any CPU\n\t\t{4F5DB8F5-D0F4-454C-95A7-87F53E5D5E36}.Release|x86.Build.0 = Release|Any CPU\n\t\t{5C2B23E2-C286-412D-ADE1-F6796B7083DE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{5C2B23E2-C286-412D-ADE1-F6796B7083DE}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{5C2B23E2-C286-412D-ADE1-F6796B7083DE}.Debug|x64.ActiveCfg = Debug|Any CPU\n\t\t{5C2B23E2-C286-412D-ADE1-F6796B7083DE}.Debug|x64.Build.0 = Debug|Any CPU\n\t\t{5C2B23E2-C286-412D-ADE1-F6796B7083DE}.Debug|x86.ActiveCfg = Debug|Any CPU\n\t\t{5C2B23E2-C286-412D-ADE1-F6796B7083DE}.Debug|x86.Build.0 = Debug|Any CPU\n\t\t{5C2B23E2-C286-412D-ADE1-F6796B7083DE}.ReleaseMono|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{5C2B23E2-C286-412D-ADE1-F6796B7083DE}.ReleaseMono|Any CPU.Build.0 = Release|Any CPU\n\t\t{5C2B23E2-C286-412D-ADE1-F6796B7083DE}.ReleaseMono|x64.ActiveCfg = Release|Any CPU\n\t\t{5C2B23E2-C286-412D-ADE1-F6796B7083DE}.ReleaseMono|x64.Build.0 = Release|Any CPU\n\t\t{5C2B23E2-C286-412D-ADE1-F6796B7083DE}.ReleaseMono|x86.ActiveCfg = Release|Any CPU\n\t\t{5C2B23E2-C286-412D-ADE1-F6796B7083DE}.ReleaseMono|x86.Build.0 = Release|Any CPU\n\t\t{5C2B23E2-C286-412D-ADE1-F6796B7083DE}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{5C2B23E2-C286-412D-ADE1-F6796B7083DE}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{5C2B23E2-C286-412D-ADE1-F6796B7083DE}.Release|x64.ActiveCfg = Release|Any CPU\n\t\t{5C2B23E2-C286-412D-ADE1-F6796B7083DE}.Release|x64.Build.0 = Release|Any CPU\n\t\t{5C2B23E2-C286-412D-ADE1-F6796B7083DE}.Release|x86.ActiveCfg = Release|Any CPU\n\t\t{5C2B23E2-C286-412D-ADE1-F6796B7083DE}.Release|x86.Build.0 = Release|Any CPU\n\t\t{50E14C9A-3C2F-4A51-971F-6143952D0F1C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{50E14C9A-3C2F-4A51-971F-6143952D0F1C}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{50E14C9A-3C2F-4A51-971F-6143952D0F1C}.Debug|x64.ActiveCfg = Debug|Any CPU\n\t\t{50E14C9A-3C2F-4A51-971F-6143952D0F1C}.Debug|x64.Build.0 = Debug|Any CPU\n\t\t{50E14C9A-3C2F-4A51-971F-6143952D0F1C}.Debug|x86.ActiveCfg = Debug|Any CPU\n\t\t{50E14C9A-3C2F-4A51-971F-6143952D0F1C}.Debug|x86.Build.0 = Debug|Any CPU\n\t\t{50E14C9A-3C2F-4A51-971F-6143952D0F1C}.ReleaseMono|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{50E14C9A-3C2F-4A51-971F-6143952D0F1C}.ReleaseMono|Any CPU.Build.0 = Release|Any CPU\n\t\t{50E14C9A-3C2F-4A51-971F-6143952D0F1C}.ReleaseMono|x64.ActiveCfg = Release|Any CPU\n\t\t{50E14C9A-3C2F-4A51-971F-6143952D0F1C}.ReleaseMono|x64.Build.0 = Release|Any CPU\n\t\t{50E14C9A-3C2F-4A51-971F-6143952D0F1C}.ReleaseMono|x86.ActiveCfg = Release|Any CPU\n\t\t{50E14C9A-3C2F-4A51-971F-6143952D0F1C}.ReleaseMono|x86.Build.0 = Release|Any CPU\n\t\t{50E14C9A-3C2F-4A51-971F-6143952D0F1C}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{50E14C9A-3C2F-4A51-971F-6143952D0F1C}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{50E14C9A-3C2F-4A51-971F-6143952D0F1C}.Release|x64.ActiveCfg = Release|Any CPU\n\t\t{50E14C9A-3C2F-4A51-971F-6143952D0F1C}.Release|x64.Build.0 = Release|Any CPU\n\t\t{50E14C9A-3C2F-4A51-971F-6143952D0F1C}.Release|x86.ActiveCfg = Release|Any CPU\n\t\t{50E14C9A-3C2F-4A51-971F-6143952D0F1C}.Release|x86.Build.0 = Release|Any CPU\n\t\t{3BA7D9BE-EBBF-432E-9880-0E2D2C17FCF8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{3BA7D9BE-EBBF-432E-9880-0E2D2C17FCF8}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{3BA7D9BE-EBBF-432E-9880-0E2D2C17FCF8}.Debug|x64.ActiveCfg = Debug|Any CPU\n\t\t{3BA7D9BE-EBBF-432E-9880-0E2D2C17FCF8}.Debug|x64.Build.0 = Debug|Any CPU\n\t\t{3BA7D9BE-EBBF-432E-9880-0E2D2C17FCF8}.Debug|x86.ActiveCfg = Debug|Any CPU\n\t\t{3BA7D9BE-EBBF-432E-9880-0E2D2C17FCF8}.Debug|x86.Build.0 = Debug|Any CPU\n\t\t{3BA7D9BE-EBBF-432E-9880-0E2D2C17FCF8}.ReleaseMono|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{3BA7D9BE-EBBF-432E-9880-0E2D2C17FCF8}.ReleaseMono|Any CPU.Build.0 = Release|Any CPU\n\t\t{3BA7D9BE-EBBF-432E-9880-0E2D2C17FCF8}.ReleaseMono|x64.ActiveCfg = Release|Any CPU\n\t\t{3BA7D9BE-EBBF-432E-9880-0E2D2C17FCF8}.ReleaseMono|x64.Build.0 = Release|Any CPU\n\t\t{3BA7D9BE-EBBF-432E-9880-0E2D2C17FCF8}.ReleaseMono|x86.ActiveCfg = Release|Any CPU\n\t\t{3BA7D9BE-EBBF-432E-9880-0E2D2C17FCF8}.ReleaseMono|x86.Build.0 = Release|Any CPU\n\t\t{3BA7D9BE-EBBF-432E-9880-0E2D2C17FCF8}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{3BA7D9BE-EBBF-432E-9880-0E2D2C17FCF8}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{3BA7D9BE-EBBF-432E-9880-0E2D2C17FCF8}.Release|x64.ActiveCfg = Release|Any CPU\n\t\t{3BA7D9BE-EBBF-432E-9880-0E2D2C17FCF8}.Release|x64.Build.0 = Release|Any CPU\n\t\t{3BA7D9BE-EBBF-432E-9880-0E2D2C17FCF8}.Release|x86.ActiveCfg = Release|Any CPU\n\t\t{3BA7D9BE-EBBF-432E-9880-0E2D2C17FCF8}.Release|x86.Build.0 = Release|Any CPU\n\t\t{E010FB5E-0D68-4AF7-B632-5DB6B902F158}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{E010FB5E-0D68-4AF7-B632-5DB6B902F158}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{E010FB5E-0D68-4AF7-B632-5DB6B902F158}.Debug|x64.ActiveCfg = Debug|Any CPU\n\t\t{E010FB5E-0D68-4AF7-B632-5DB6B902F158}.Debug|x64.Build.0 = Debug|Any CPU\n\t\t{E010FB5E-0D68-4AF7-B632-5DB6B902F158}.Debug|x86.ActiveCfg = Debug|Any CPU\n\t\t{E010FB5E-0D68-4AF7-B632-5DB6B902F158}.Debug|x86.Build.0 = Debug|Any CPU\n\t\t{E010FB5E-0D68-4AF7-B632-5DB6B902F158}.ReleaseMono|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{E010FB5E-0D68-4AF7-B632-5DB6B902F158}.ReleaseMono|Any CPU.Build.0 = Release|Any CPU\n\t\t{E010FB5E-0D68-4AF7-B632-5DB6B902F158}.ReleaseMono|x64.ActiveCfg = Release|Any CPU\n\t\t{E010FB5E-0D68-4AF7-B632-5DB6B902F158}.ReleaseMono|x64.Build.0 = Release|Any CPU\n\t\t{E010FB5E-0D68-4AF7-B632-5DB6B902F158}.ReleaseMono|x86.ActiveCfg = Release|Any CPU\n\t\t{E010FB5E-0D68-4AF7-B632-5DB6B902F158}.ReleaseMono|x86.Build.0 = Release|Any CPU\n\t\t{E010FB5E-0D68-4AF7-B632-5DB6B902F158}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{E010FB5E-0D68-4AF7-B632-5DB6B902F158}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{E010FB5E-0D68-4AF7-B632-5DB6B902F158}.Release|x64.ActiveCfg = Release|Any CPU\n\t\t{E010FB5E-0D68-4AF7-B632-5DB6B902F158}.Release|x64.Build.0 = Release|Any CPU\n\t\t{E010FB5E-0D68-4AF7-B632-5DB6B902F158}.Release|x86.ActiveCfg = Release|Any CPU\n\t\t{E010FB5E-0D68-4AF7-B632-5DB6B902F158}.Release|x86.Build.0 = Release|Any CPU\n\t\t{A5DE942D-912D-4012-8493-1E958E5445F4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{A5DE942D-912D-4012-8493-1E958E5445F4}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{A5DE942D-912D-4012-8493-1E958E5445F4}.Debug|x64.ActiveCfg = Debug|Any CPU\n\t\t{A5DE942D-912D-4012-8493-1E958E5445F4}.Debug|x64.Build.0 = Debug|Any CPU\n\t\t{A5DE942D-912D-4012-8493-1E958E5445F4}.Debug|x86.ActiveCfg = Debug|Any CPU\n\t\t{A5DE942D-912D-4012-8493-1E958E5445F4}.Debug|x86.Build.0 = Debug|Any CPU\n\t\t{A5DE942D-912D-4012-8493-1E958E5445F4}.ReleaseMono|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{A5DE942D-912D-4012-8493-1E958E5445F4}.ReleaseMono|Any CPU.Build.0 = Release|Any CPU\n\t\t{A5DE942D-912D-4012-8493-1E958E5445F4}.ReleaseMono|x64.ActiveCfg = Release|Any CPU\n\t\t{A5DE942D-912D-4012-8493-1E958E5445F4}.ReleaseMono|x64.Build.0 = Release|Any CPU\n\t\t{A5DE942D-912D-4012-8493-1E958E5445F4}.ReleaseMono|x86.ActiveCfg = Release|Any CPU\n\t\t{A5DE942D-912D-4012-8493-1E958E5445F4}.ReleaseMono|x86.Build.0 = Release|Any CPU\n\t\t{A5DE942D-912D-4012-8493-1E958E5445F4}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{A5DE942D-912D-4012-8493-1E958E5445F4}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{A5DE942D-912D-4012-8493-1E958E5445F4}.Release|x64.ActiveCfg = Release|Any CPU\n\t\t{A5DE942D-912D-4012-8493-1E958E5445F4}.Release|x64.Build.0 = Release|Any CPU\n\t\t{A5DE942D-912D-4012-8493-1E958E5445F4}.Release|x86.ActiveCfg = Release|Any CPU\n\t\t{A5DE942D-912D-4012-8493-1E958E5445F4}.Release|x86.Build.0 = Release|Any CPU\n\t\t{ADCBBAC0-0A87-45B7-BD31-314F136F74D4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{ADCBBAC0-0A87-45B7-BD31-314F136F74D4}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{ADCBBAC0-0A87-45B7-BD31-314F136F74D4}.Debug|x64.ActiveCfg = Debug|Any CPU\n\t\t{ADCBBAC0-0A87-45B7-BD31-314F136F74D4}.Debug|x64.Build.0 = Debug|Any CPU\n\t\t{ADCBBAC0-0A87-45B7-BD31-314F136F74D4}.Debug|x86.ActiveCfg = Debug|Any CPU\n\t\t{ADCBBAC0-0A87-45B7-BD31-314F136F74D4}.Debug|x86.Build.0 = Debug|Any CPU\n\t\t{ADCBBAC0-0A87-45B7-BD31-314F136F74D4}.ReleaseMono|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{ADCBBAC0-0A87-45B7-BD31-314F136F74D4}.ReleaseMono|Any CPU.Build.0 = Release|Any CPU\n\t\t{ADCBBAC0-0A87-45B7-BD31-314F136F74D4}.ReleaseMono|x64.ActiveCfg = Release|Any CPU\n\t\t{ADCBBAC0-0A87-45B7-BD31-314F136F74D4}.ReleaseMono|x64.Build.0 = Release|Any CPU\n\t\t{ADCBBAC0-0A87-45B7-BD31-314F136F74D4}.ReleaseMono|x86.ActiveCfg = Release|Any CPU\n\t\t{ADCBBAC0-0A87-45B7-BD31-314F136F74D4}.ReleaseMono|x86.Build.0 = Release|Any CPU\n\t\t{ADCBBAC0-0A87-45B7-BD31-314F136F74D4}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{ADCBBAC0-0A87-45B7-BD31-314F136F74D4}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{ADCBBAC0-0A87-45B7-BD31-314F136F74D4}.Release|x64.ActiveCfg = Release|Any CPU\n\t\t{ADCBBAC0-0A87-45B7-BD31-314F136F74D4}.Release|x64.Build.0 = Release|Any CPU\n\t\t{ADCBBAC0-0A87-45B7-BD31-314F136F74D4}.Release|x86.ActiveCfg = Release|Any CPU\n\t\t{ADCBBAC0-0A87-45B7-BD31-314F136F74D4}.Release|x86.Build.0 = Release|Any CPU\n\t\t{A216C2F0-A9A6-4D7F-BF65-127EB80EA6A7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{A216C2F0-A9A6-4D7F-BF65-127EB80EA6A7}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{A216C2F0-A9A6-4D7F-BF65-127EB80EA6A7}.Debug|x64.ActiveCfg = Debug|Any CPU\n\t\t{A216C2F0-A9A6-4D7F-BF65-127EB80EA6A7}.Debug|x64.Build.0 = Debug|Any CPU\n\t\t{A216C2F0-A9A6-4D7F-BF65-127EB80EA6A7}.Debug|x86.ActiveCfg = Debug|Any CPU\n\t\t{A216C2F0-A9A6-4D7F-BF65-127EB80EA6A7}.Debug|x86.Build.0 = Debug|Any CPU\n\t\t{A216C2F0-A9A6-4D7F-BF65-127EB80EA6A7}.ReleaseMono|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{A216C2F0-A9A6-4D7F-BF65-127EB80EA6A7}.ReleaseMono|Any CPU.Build.0 = Release|Any CPU\n\t\t{A216C2F0-A9A6-4D7F-BF65-127EB80EA6A7}.ReleaseMono|x64.ActiveCfg = Release|Any CPU\n\t\t{A216C2F0-A9A6-4D7F-BF65-127EB80EA6A7}.ReleaseMono|x64.Build.0 = Release|Any CPU\n\t\t{A216C2F0-A9A6-4D7F-BF65-127EB80EA6A7}.ReleaseMono|x86.ActiveCfg = Release|Any CPU\n\t\t{A216C2F0-A9A6-4D7F-BF65-127EB80EA6A7}.ReleaseMono|x86.Build.0 = Release|Any CPU\n\t\t{A216C2F0-A9A6-4D7F-BF65-127EB80EA6A7}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{A216C2F0-A9A6-4D7F-BF65-127EB80EA6A7}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{A216C2F0-A9A6-4D7F-BF65-127EB80EA6A7}.Release|x64.ActiveCfg = Release|Any CPU\n\t\t{A216C2F0-A9A6-4D7F-BF65-127EB80EA6A7}.Release|x64.Build.0 = Release|Any CPU\n\t\t{A216C2F0-A9A6-4D7F-BF65-127EB80EA6A7}.Release|x86.ActiveCfg = Release|Any CPU\n\t\t{A216C2F0-A9A6-4D7F-BF65-127EB80EA6A7}.Release|x86.Build.0 = Release|Any CPU\n\t\t{5CEE1B93-3936-4E32-A414-522DCDCA26BB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{5CEE1B93-3936-4E32-A414-522DCDCA26BB}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{5CEE1B93-3936-4E32-A414-522DCDCA26BB}.Debug|x64.ActiveCfg = Debug|Any CPU\n\t\t{5CEE1B93-3936-4E32-A414-522DCDCA26BB}.Debug|x64.Build.0 = Debug|Any CPU\n\t\t{5CEE1B93-3936-4E32-A414-522DCDCA26BB}.Debug|x86.ActiveCfg = Debug|Any CPU\n\t\t{5CEE1B93-3936-4E32-A414-522DCDCA26BB}.Debug|x86.Build.0 = Debug|Any CPU\n\t\t{5CEE1B93-3936-4E32-A414-522DCDCA26BB}.ReleaseMono|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{5CEE1B93-3936-4E32-A414-522DCDCA26BB}.ReleaseMono|Any CPU.Build.0 = Release|Any CPU\n\t\t{5CEE1B93-3936-4E32-A414-522DCDCA26BB}.ReleaseMono|x64.ActiveCfg = Release|Any CPU\n\t\t{5CEE1B93-3936-4E32-A414-522DCDCA26BB}.ReleaseMono|x64.Build.0 = Release|Any CPU\n\t\t{5CEE1B93-3936-4E32-A414-522DCDCA26BB}.ReleaseMono|x86.ActiveCfg = Release|Any CPU\n\t\t{5CEE1B93-3936-4E32-A414-522DCDCA26BB}.ReleaseMono|x86.Build.0 = Release|Any CPU\n\t\t{5CEE1B93-3936-4E32-A414-522DCDCA26BB}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{5CEE1B93-3936-4E32-A414-522DCDCA26BB}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{5CEE1B93-3936-4E32-A414-522DCDCA26BB}.Release|x64.ActiveCfg = Release|Any CPU\n\t\t{5CEE1B93-3936-4E32-A414-522DCDCA26BB}.Release|x64.Build.0 = Release|Any CPU\n\t\t{5CEE1B93-3936-4E32-A414-522DCDCA26BB}.Release|x86.ActiveCfg = Release|Any CPU\n\t\t{5CEE1B93-3936-4E32-A414-522DCDCA26BB}.Release|x86.Build.0 = Release|Any CPU\n\t\t{B48782B9-6FA9-4D18-8564-1849FF4CF40E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{B48782B9-6FA9-4D18-8564-1849FF4CF40E}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{B48782B9-6FA9-4D18-8564-1849FF4CF40E}.Debug|x64.ActiveCfg = Debug|Any CPU\n\t\t{B48782B9-6FA9-4D18-8564-1849FF4CF40E}.Debug|x64.Build.0 = Debug|Any CPU\n\t\t{B48782B9-6FA9-4D18-8564-1849FF4CF40E}.Debug|x86.ActiveCfg = Debug|Any CPU\n\t\t{B48782B9-6FA9-4D18-8564-1849FF4CF40E}.Debug|x86.Build.0 = Debug|Any CPU\n\t\t{B48782B9-6FA9-4D18-8564-1849FF4CF40E}.ReleaseMono|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{B48782B9-6FA9-4D18-8564-1849FF4CF40E}.ReleaseMono|Any CPU.Build.0 = Release|Any CPU\n\t\t{B48782B9-6FA9-4D18-8564-1849FF4CF40E}.ReleaseMono|x64.ActiveCfg = Release|Any CPU\n\t\t{B48782B9-6FA9-4D18-8564-1849FF4CF40E}.ReleaseMono|x64.Build.0 = Release|Any CPU\n\t\t{B48782B9-6FA9-4D18-8564-1849FF4CF40E}.ReleaseMono|x86.ActiveCfg = Release|Any CPU\n\t\t{B48782B9-6FA9-4D18-8564-1849FF4CF40E}.ReleaseMono|x86.Build.0 = Release|Any CPU\n\t\t{B48782B9-6FA9-4D18-8564-1849FF4CF40E}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{B48782B9-6FA9-4D18-8564-1849FF4CF40E}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{B48782B9-6FA9-4D18-8564-1849FF4CF40E}.Release|x64.ActiveCfg = Release|Any CPU\n\t\t{B48782B9-6FA9-4D18-8564-1849FF4CF40E}.Release|x64.Build.0 = Release|Any CPU\n\t\t{B48782B9-6FA9-4D18-8564-1849FF4CF40E}.Release|x86.ActiveCfg = Release|Any CPU\n\t\t{B48782B9-6FA9-4D18-8564-1849FF4CF40E}.Release|x86.Build.0 = Release|Any CPU\n\t\t{B41C8F1C-5BD2-43B9-A3CC-FC03DFE04E23}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{B41C8F1C-5BD2-43B9-A3CC-FC03DFE04E23}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{B41C8F1C-5BD2-43B9-A3CC-FC03DFE04E23}.Debug|x64.ActiveCfg = Debug|Any CPU\n\t\t{B41C8F1C-5BD2-43B9-A3CC-FC03DFE04E23}.Debug|x64.Build.0 = Debug|Any CPU\n\t\t{B41C8F1C-5BD2-43B9-A3CC-FC03DFE04E23}.Debug|x86.ActiveCfg = Debug|Any CPU\n\t\t{B41C8F1C-5BD2-43B9-A3CC-FC03DFE04E23}.Debug|x86.Build.0 = Debug|Any CPU\n\t\t{B41C8F1C-5BD2-43B9-A3CC-FC03DFE04E23}.ReleaseMono|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{B41C8F1C-5BD2-43B9-A3CC-FC03DFE04E23}.ReleaseMono|x64.ActiveCfg = Release|Any CPU\n\t\t{B41C8F1C-5BD2-43B9-A3CC-FC03DFE04E23}.ReleaseMono|x86.ActiveCfg = Release|Any CPU\n\t\t{B41C8F1C-5BD2-43B9-A3CC-FC03DFE04E23}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{B41C8F1C-5BD2-43B9-A3CC-FC03DFE04E23}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{B41C8F1C-5BD2-43B9-A3CC-FC03DFE04E23}.Release|x64.ActiveCfg = Release|Any CPU\n\t\t{B41C8F1C-5BD2-43B9-A3CC-FC03DFE04E23}.Release|x64.Build.0 = Release|Any CPU\n\t\t{B41C8F1C-5BD2-43B9-A3CC-FC03DFE04E23}.Release|x86.ActiveCfg = Release|Any CPU\n\t\t{B41C8F1C-5BD2-43B9-A3CC-FC03DFE04E23}.Release|x86.Build.0 = Release|Any CPU\n\t\t{BEDBC0F8-AD0A-44C3-9A53-C8EC4E631AF4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{BEDBC0F8-AD0A-44C3-9A53-C8EC4E631AF4}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{BEDBC0F8-AD0A-44C3-9A53-C8EC4E631AF4}.Debug|x64.ActiveCfg = Debug|Any CPU\n\t\t{BEDBC0F8-AD0A-44C3-9A53-C8EC4E631AF4}.Debug|x64.Build.0 = Debug|Any CPU\n\t\t{BEDBC0F8-AD0A-44C3-9A53-C8EC4E631AF4}.Debug|x86.ActiveCfg = Debug|Any CPU\n\t\t{BEDBC0F8-AD0A-44C3-9A53-C8EC4E631AF4}.Debug|x86.Build.0 = Debug|Any CPU\n\t\t{BEDBC0F8-AD0A-44C3-9A53-C8EC4E631AF4}.ReleaseMono|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{BEDBC0F8-AD0A-44C3-9A53-C8EC4E631AF4}.ReleaseMono|x64.ActiveCfg = Release|Any CPU\n\t\t{BEDBC0F8-AD0A-44C3-9A53-C8EC4E631AF4}.ReleaseMono|x86.ActiveCfg = Release|Any CPU\n\t\t{BEDBC0F8-AD0A-44C3-9A53-C8EC4E631AF4}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{BEDBC0F8-AD0A-44C3-9A53-C8EC4E631AF4}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{BEDBC0F8-AD0A-44C3-9A53-C8EC4E631AF4}.Release|x64.ActiveCfg = Release|Any CPU\n\t\t{BEDBC0F8-AD0A-44C3-9A53-C8EC4E631AF4}.Release|x64.Build.0 = Release|Any CPU\n\t\t{BEDBC0F8-AD0A-44C3-9A53-C8EC4E631AF4}.Release|x86.ActiveCfg = Release|Any CPU\n\t\t{BEDBC0F8-AD0A-44C3-9A53-C8EC4E631AF4}.Release|x86.Build.0 = Release|Any CPU\n\t\t{48A7AC8E-2CB5-403B-8A18-11F493079619}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{48A7AC8E-2CB5-403B-8A18-11F493079619}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{48A7AC8E-2CB5-403B-8A18-11F493079619}.Debug|x64.ActiveCfg = Debug|Any CPU\n\t\t{48A7AC8E-2CB5-403B-8A18-11F493079619}.Debug|x64.Build.0 = Debug|Any CPU\n\t\t{48A7AC8E-2CB5-403B-8A18-11F493079619}.Debug|x86.ActiveCfg = Debug|Any CPU\n\t\t{48A7AC8E-2CB5-403B-8A18-11F493079619}.Debug|x86.Build.0 = Debug|Any CPU\n\t\t{48A7AC8E-2CB5-403B-8A18-11F493079619}.ReleaseMono|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{48A7AC8E-2CB5-403B-8A18-11F493079619}.ReleaseMono|x64.ActiveCfg = Release|Any CPU\n\t\t{48A7AC8E-2CB5-403B-8A18-11F493079619}.ReleaseMono|x86.ActiveCfg = Release|Any CPU\n\t\t{48A7AC8E-2CB5-403B-8A18-11F493079619}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{48A7AC8E-2CB5-403B-8A18-11F493079619}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{48A7AC8E-2CB5-403B-8A18-11F493079619}.Release|x64.ActiveCfg = Release|Any CPU\n\t\t{48A7AC8E-2CB5-403B-8A18-11F493079619}.Release|x64.Build.0 = Release|Any CPU\n\t\t{48A7AC8E-2CB5-403B-8A18-11F493079619}.Release|x86.ActiveCfg = Release|Any CPU\n\t\t{48A7AC8E-2CB5-403B-8A18-11F493079619}.Release|x86.Build.0 = Release|Any CPU\n\t\t{B3170309-55AB-462C-9100-D77107799E82}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{B3170309-55AB-462C-9100-D77107799E82}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{B3170309-55AB-462C-9100-D77107799E82}.Debug|x64.ActiveCfg = Debug|Any CPU\n\t\t{B3170309-55AB-462C-9100-D77107799E82}.Debug|x64.Build.0 = Debug|Any CPU\n\t\t{B3170309-55AB-462C-9100-D77107799E82}.Debug|x86.ActiveCfg = Debug|Any CPU\n\t\t{B3170309-55AB-462C-9100-D77107799E82}.Debug|x86.Build.0 = Debug|Any CPU\n\t\t{B3170309-55AB-462C-9100-D77107799E82}.ReleaseMono|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{B3170309-55AB-462C-9100-D77107799E82}.ReleaseMono|Any CPU.Build.0 = Release|Any CPU\n\t\t{B3170309-55AB-462C-9100-D77107799E82}.ReleaseMono|x64.ActiveCfg = Release|Any CPU\n\t\t{B3170309-55AB-462C-9100-D77107799E82}.ReleaseMono|x64.Build.0 = Release|Any CPU\n\t\t{B3170309-55AB-462C-9100-D77107799E82}.ReleaseMono|x86.ActiveCfg = Release|Any CPU\n\t\t{B3170309-55AB-462C-9100-D77107799E82}.ReleaseMono|x86.Build.0 = Release|Any CPU\n\t\t{B3170309-55AB-462C-9100-D77107799E82}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{B3170309-55AB-462C-9100-D77107799E82}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{B3170309-55AB-462C-9100-D77107799E82}.Release|x64.ActiveCfg = Release|Any CPU\n\t\t{B3170309-55AB-462C-9100-D77107799E82}.Release|x64.Build.0 = Release|Any CPU\n\t\t{B3170309-55AB-462C-9100-D77107799E82}.Release|x86.ActiveCfg = Release|Any CPU\n\t\t{B3170309-55AB-462C-9100-D77107799E82}.Release|x86.Build.0 = Release|Any CPU\n\t\t{A43E44E5-F9C1-44BD-A593-419EC113117B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{A43E44E5-F9C1-44BD-A593-419EC113117B}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{A43E44E5-F9C1-44BD-A593-419EC113117B}.Debug|x64.ActiveCfg = Debug|Any CPU\n\t\t{A43E44E5-F9C1-44BD-A593-419EC113117B}.Debug|x64.Build.0 = Debug|Any CPU\n\t\t{A43E44E5-F9C1-44BD-A593-419EC113117B}.Debug|x86.ActiveCfg = Debug|Any CPU\n\t\t{A43E44E5-F9C1-44BD-A593-419EC113117B}.Debug|x86.Build.0 = Debug|Any CPU\n\t\t{A43E44E5-F9C1-44BD-A593-419EC113117B}.ReleaseMono|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{A43E44E5-F9C1-44BD-A593-419EC113117B}.ReleaseMono|Any CPU.Build.0 = Release|Any CPU\n\t\t{A43E44E5-F9C1-44BD-A593-419EC113117B}.ReleaseMono|x64.ActiveCfg = Release|Any CPU\n\t\t{A43E44E5-F9C1-44BD-A593-419EC113117B}.ReleaseMono|x64.Build.0 = Release|Any CPU\n\t\t{A43E44E5-F9C1-44BD-A593-419EC113117B}.ReleaseMono|x86.ActiveCfg = Release|Any CPU\n\t\t{A43E44E5-F9C1-44BD-A593-419EC113117B}.ReleaseMono|x86.Build.0 = Release|Any CPU\n\t\t{A43E44E5-F9C1-44BD-A593-419EC113117B}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{A43E44E5-F9C1-44BD-A593-419EC113117B}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{A43E44E5-F9C1-44BD-A593-419EC113117B}.Release|x64.ActiveCfg = Release|Any CPU\n\t\t{A43E44E5-F9C1-44BD-A593-419EC113117B}.Release|x64.Build.0 = Release|Any CPU\n\t\t{A43E44E5-F9C1-44BD-A593-419EC113117B}.Release|x86.ActiveCfg = Release|Any CPU\n\t\t{A43E44E5-F9C1-44BD-A593-419EC113117B}.Release|x86.Build.0 = Release|Any CPU\n\t\t{2E17A091-DC29-41FB-ABC8-767BD75FFB07}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{2E17A091-DC29-41FB-ABC8-767BD75FFB07}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{2E17A091-DC29-41FB-ABC8-767BD75FFB07}.Debug|x64.ActiveCfg = Debug|Any CPU\n\t\t{2E17A091-DC29-41FB-ABC8-767BD75FFB07}.Debug|x64.Build.0 = Debug|Any CPU\n\t\t{2E17A091-DC29-41FB-ABC8-767BD75FFB07}.Debug|x86.ActiveCfg = Debug|Any CPU\n\t\t{2E17A091-DC29-41FB-ABC8-767BD75FFB07}.Debug|x86.Build.0 = Debug|Any CPU\n\t\t{2E17A091-DC29-41FB-ABC8-767BD75FFB07}.ReleaseMono|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{2E17A091-DC29-41FB-ABC8-767BD75FFB07}.ReleaseMono|Any CPU.Build.0 = Release|Any CPU\n\t\t{2E17A091-DC29-41FB-ABC8-767BD75FFB07}.ReleaseMono|x64.ActiveCfg = Release|Any CPU\n\t\t{2E17A091-DC29-41FB-ABC8-767BD75FFB07}.ReleaseMono|x64.Build.0 = Release|Any CPU\n\t\t{2E17A091-DC29-41FB-ABC8-767BD75FFB07}.ReleaseMono|x86.ActiveCfg = Release|Any CPU\n\t\t{2E17A091-DC29-41FB-ABC8-767BD75FFB07}.ReleaseMono|x86.Build.0 = Release|Any CPU\n\t\t{2E17A091-DC29-41FB-ABC8-767BD75FFB07}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{2E17A091-DC29-41FB-ABC8-767BD75FFB07}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{2E17A091-DC29-41FB-ABC8-767BD75FFB07}.Release|x64.ActiveCfg = Release|Any CPU\n\t\t{2E17A091-DC29-41FB-ABC8-767BD75FFB07}.Release|x64.Build.0 = Release|Any CPU\n\t\t{2E17A091-DC29-41FB-ABC8-767BD75FFB07}.Release|x86.ActiveCfg = Release|Any CPU\n\t\t{2E17A091-DC29-41FB-ABC8-767BD75FFB07}.Release|x86.Build.0 = Release|Any CPU\n\t\t{6D7A63C9-16AB-4B7E-B9C0-0956E1E02610}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{6D7A63C9-16AB-4B7E-B9C0-0956E1E02610}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{6D7A63C9-16AB-4B7E-B9C0-0956E1E02610}.Debug|x64.ActiveCfg = Debug|Any CPU\n\t\t{6D7A63C9-16AB-4B7E-B9C0-0956E1E02610}.Debug|x64.Build.0 = Debug|Any CPU\n\t\t{6D7A63C9-16AB-4B7E-B9C0-0956E1E02610}.Debug|x86.ActiveCfg = Debug|Any CPU\n\t\t{6D7A63C9-16AB-4B7E-B9C0-0956E1E02610}.Debug|x86.Build.0 = Debug|Any CPU\n\t\t{6D7A63C9-16AB-4B7E-B9C0-0956E1E02610}.ReleaseMono|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{6D7A63C9-16AB-4B7E-B9C0-0956E1E02610}.ReleaseMono|Any CPU.Build.0 = Release|Any CPU\n\t\t{6D7A63C9-16AB-4B7E-B9C0-0956E1E02610}.ReleaseMono|x64.ActiveCfg = Release|Any CPU\n\t\t{6D7A63C9-16AB-4B7E-B9C0-0956E1E02610}.ReleaseMono|x64.Build.0 = Release|Any CPU\n\t\t{6D7A63C9-16AB-4B7E-B9C0-0956E1E02610}.ReleaseMono|x86.ActiveCfg = Release|Any CPU\n\t\t{6D7A63C9-16AB-4B7E-B9C0-0956E1E02610}.ReleaseMono|x86.Build.0 = Release|Any CPU\n\t\t{6D7A63C9-16AB-4B7E-B9C0-0956E1E02610}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{6D7A63C9-16AB-4B7E-B9C0-0956E1E02610}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{6D7A63C9-16AB-4B7E-B9C0-0956E1E02610}.Release|x64.ActiveCfg = Release|Any CPU\n\t\t{6D7A63C9-16AB-4B7E-B9C0-0956E1E02610}.Release|x64.Build.0 = Release|Any CPU\n\t\t{6D7A63C9-16AB-4B7E-B9C0-0956E1E02610}.Release|x86.ActiveCfg = Release|Any CPU\n\t\t{6D7A63C9-16AB-4B7E-B9C0-0956E1E02610}.Release|x86.Build.0 = Release|Any CPU\n\t\t{9F88C871-CB37-4A88-BACF-540AC253C202}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{9F88C871-CB37-4A88-BACF-540AC253C202}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{9F88C871-CB37-4A88-BACF-540AC253C202}.Debug|x64.ActiveCfg = Debug|Any CPU\n\t\t{9F88C871-CB37-4A88-BACF-540AC253C202}.Debug|x64.Build.0 = Debug|Any CPU\n\t\t{9F88C871-CB37-4A88-BACF-540AC253C202}.Debug|x86.ActiveCfg = Debug|Any CPU\n\t\t{9F88C871-CB37-4A88-BACF-540AC253C202}.Debug|x86.Build.0 = Debug|Any CPU\n\t\t{9F88C871-CB37-4A88-BACF-540AC253C202}.ReleaseMono|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{9F88C871-CB37-4A88-BACF-540AC253C202}.ReleaseMono|Any CPU.Build.0 = Debug|Any CPU\n\t\t{9F88C871-CB37-4A88-BACF-540AC253C202}.ReleaseMono|x64.ActiveCfg = Debug|Any CPU\n\t\t{9F88C871-CB37-4A88-BACF-540AC253C202}.ReleaseMono|x64.Build.0 = Debug|Any CPU\n\t\t{9F88C871-CB37-4A88-BACF-540AC253C202}.ReleaseMono|x86.ActiveCfg = Debug|Any CPU\n\t\t{9F88C871-CB37-4A88-BACF-540AC253C202}.ReleaseMono|x86.Build.0 = Debug|Any CPU\n\t\t{9F88C871-CB37-4A88-BACF-540AC253C202}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{9F88C871-CB37-4A88-BACF-540AC253C202}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{9F88C871-CB37-4A88-BACF-540AC253C202}.Release|x64.ActiveCfg = Release|Any CPU\n\t\t{9F88C871-CB37-4A88-BACF-540AC253C202}.Release|x64.Build.0 = Release|Any CPU\n\t\t{9F88C871-CB37-4A88-BACF-540AC253C202}.Release|x86.ActiveCfg = Release|Any CPU\n\t\t{9F88C871-CB37-4A88-BACF-540AC253C202}.Release|x86.Build.0 = Release|Any CPU\n\t\t{B1A38DDE-5534-4625-A3F2-A585BA7A1198}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{B1A38DDE-5534-4625-A3F2-A585BA7A1198}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{B1A38DDE-5534-4625-A3F2-A585BA7A1198}.Debug|x64.ActiveCfg = Debug|Any CPU\n\t\t{B1A38DDE-5534-4625-A3F2-A585BA7A1198}.Debug|x64.Build.0 = Debug|Any CPU\n\t\t{B1A38DDE-5534-4625-A3F2-A585BA7A1198}.Debug|x86.ActiveCfg = Debug|Any CPU\n\t\t{B1A38DDE-5534-4625-A3F2-A585BA7A1198}.Debug|x86.Build.0 = Debug|Any CPU\n\t\t{B1A38DDE-5534-4625-A3F2-A585BA7A1198}.ReleaseMono|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{B1A38DDE-5534-4625-A3F2-A585BA7A1198}.ReleaseMono|Any CPU.Build.0 = Debug|Any CPU\n\t\t{B1A38DDE-5534-4625-A3F2-A585BA7A1198}.ReleaseMono|x64.ActiveCfg = Debug|Any CPU\n\t\t{B1A38DDE-5534-4625-A3F2-A585BA7A1198}.ReleaseMono|x64.Build.0 = Debug|Any CPU\n\t\t{B1A38DDE-5534-4625-A3F2-A585BA7A1198}.ReleaseMono|x86.ActiveCfg = Debug|Any CPU\n\t\t{B1A38DDE-5534-4625-A3F2-A585BA7A1198}.ReleaseMono|x86.Build.0 = Debug|Any CPU\n\t\t{B1A38DDE-5534-4625-A3F2-A585BA7A1198}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{B1A38DDE-5534-4625-A3F2-A585BA7A1198}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{B1A38DDE-5534-4625-A3F2-A585BA7A1198}.Release|x64.ActiveCfg = Release|Any CPU\n\t\t{B1A38DDE-5534-4625-A3F2-A585BA7A1198}.Release|x64.Build.0 = Release|Any CPU\n\t\t{B1A38DDE-5534-4625-A3F2-A585BA7A1198}.Release|x86.ActiveCfg = Release|Any CPU\n\t\t{B1A38DDE-5534-4625-A3F2-A585BA7A1198}.Release|x86.Build.0 = Release|Any CPU\n\t\t{8698E0C2-1A82-43E6-8A26-3D9A825CF574}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{8698E0C2-1A82-43E6-8A26-3D9A825CF574}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{8698E0C2-1A82-43E6-8A26-3D9A825CF574}.Debug|x64.ActiveCfg = Debug|Any CPU\n\t\t{8698E0C2-1A82-43E6-8A26-3D9A825CF574}.Debug|x64.Build.0 = Debug|Any CPU\n\t\t{8698E0C2-1A82-43E6-8A26-3D9A825CF574}.Debug|x86.ActiveCfg = Debug|Any CPU\n\t\t{8698E0C2-1A82-43E6-8A26-3D9A825CF574}.Debug|x86.Build.0 = Debug|Any CPU\n\t\t{8698E0C2-1A82-43E6-8A26-3D9A825CF574}.ReleaseMono|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{8698E0C2-1A82-43E6-8A26-3D9A825CF574}.ReleaseMono|Any CPU.Build.0 = Debug|Any CPU\n\t\t{8698E0C2-1A82-43E6-8A26-3D9A825CF574}.ReleaseMono|x64.ActiveCfg = Debug|Any CPU\n\t\t{8698E0C2-1A82-43E6-8A26-3D9A825CF574}.ReleaseMono|x64.Build.0 = Debug|Any CPU\n\t\t{8698E0C2-1A82-43E6-8A26-3D9A825CF574}.ReleaseMono|x86.ActiveCfg = Debug|Any CPU\n\t\t{8698E0C2-1A82-43E6-8A26-3D9A825CF574}.ReleaseMono|x86.Build.0 = Debug|Any CPU\n\t\t{8698E0C2-1A82-43E6-8A26-3D9A825CF574}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{8698E0C2-1A82-43E6-8A26-3D9A825CF574}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{8698E0C2-1A82-43E6-8A26-3D9A825CF574}.Release|x64.ActiveCfg = Release|Any CPU\n\t\t{8698E0C2-1A82-43E6-8A26-3D9A825CF574}.Release|x64.Build.0 = Release|Any CPU\n\t\t{8698E0C2-1A82-43E6-8A26-3D9A825CF574}.Release|x86.ActiveCfg = Release|Any CPU\n\t\t{8698E0C2-1A82-43E6-8A26-3D9A825CF574}.Release|x86.Build.0 = Release|Any CPU\n\t\t{F782BC86-9CE6-4F69-8F77-710A399CB54F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{F782BC86-9CE6-4F69-8F77-710A399CB54F}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{F782BC86-9CE6-4F69-8F77-710A399CB54F}.Debug|x64.ActiveCfg = Debug|Any CPU\n\t\t{F782BC86-9CE6-4F69-8F77-710A399CB54F}.Debug|x64.Build.0 = Debug|Any CPU\n\t\t{F782BC86-9CE6-4F69-8F77-710A399CB54F}.Debug|x86.ActiveCfg = Debug|Any CPU\n\t\t{F782BC86-9CE6-4F69-8F77-710A399CB54F}.Debug|x86.Build.0 = Debug|Any CPU\n\t\t{F782BC86-9CE6-4F69-8F77-710A399CB54F}.ReleaseMono|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{F782BC86-9CE6-4F69-8F77-710A399CB54F}.ReleaseMono|Any CPU.Build.0 = Debug|Any CPU\n\t\t{F782BC86-9CE6-4F69-8F77-710A399CB54F}.ReleaseMono|x64.ActiveCfg = Debug|Any CPU\n\t\t{F782BC86-9CE6-4F69-8F77-710A399CB54F}.ReleaseMono|x64.Build.0 = Debug|Any CPU\n\t\t{F782BC86-9CE6-4F69-8F77-710A399CB54F}.ReleaseMono|x86.ActiveCfg = Debug|Any CPU\n\t\t{F782BC86-9CE6-4F69-8F77-710A399CB54F}.ReleaseMono|x86.Build.0 = Debug|Any CPU\n\t\t{F782BC86-9CE6-4F69-8F77-710A399CB54F}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{F782BC86-9CE6-4F69-8F77-710A399CB54F}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{F782BC86-9CE6-4F69-8F77-710A399CB54F}.Release|x64.ActiveCfg = Release|Any CPU\n\t\t{F782BC86-9CE6-4F69-8F77-710A399CB54F}.Release|x64.Build.0 = Release|Any CPU\n\t\t{F782BC86-9CE6-4F69-8F77-710A399CB54F}.Release|x86.ActiveCfg = Release|Any CPU\n\t\t{F782BC86-9CE6-4F69-8F77-710A399CB54F}.Release|x86.Build.0 = Release|Any CPU\n\t\t{763BAD3E-3244-4E8F-8182-2BF35774262A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{763BAD3E-3244-4E8F-8182-2BF35774262A}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{763BAD3E-3244-4E8F-8182-2BF35774262A}.Debug|x64.ActiveCfg = Debug|Any CPU\n\t\t{763BAD3E-3244-4E8F-8182-2BF35774262A}.Debug|x64.Build.0 = Debug|Any CPU\n\t\t{763BAD3E-3244-4E8F-8182-2BF35774262A}.Debug|x86.ActiveCfg = Debug|Any CPU\n\t\t{763BAD3E-3244-4E8F-8182-2BF35774262A}.Debug|x86.Build.0 = Debug|Any CPU\n\t\t{763BAD3E-3244-4E8F-8182-2BF35774262A}.ReleaseMono|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{763BAD3E-3244-4E8F-8182-2BF35774262A}.ReleaseMono|Any CPU.Build.0 = Debug|Any CPU\n\t\t{763BAD3E-3244-4E8F-8182-2BF35774262A}.ReleaseMono|x64.ActiveCfg = Debug|Any CPU\n\t\t{763BAD3E-3244-4E8F-8182-2BF35774262A}.ReleaseMono|x64.Build.0 = Debug|Any CPU\n\t\t{763BAD3E-3244-4E8F-8182-2BF35774262A}.ReleaseMono|x86.ActiveCfg = Debug|Any CPU\n\t\t{763BAD3E-3244-4E8F-8182-2BF35774262A}.ReleaseMono|x86.Build.0 = Debug|Any CPU\n\t\t{763BAD3E-3244-4E8F-8182-2BF35774262A}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{763BAD3E-3244-4E8F-8182-2BF35774262A}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{763BAD3E-3244-4E8F-8182-2BF35774262A}.Release|x64.ActiveCfg = Release|Any CPU\n\t\t{763BAD3E-3244-4E8F-8182-2BF35774262A}.Release|x64.Build.0 = Release|Any CPU\n\t\t{763BAD3E-3244-4E8F-8182-2BF35774262A}.Release|x86.ActiveCfg = Release|Any CPU\n\t\t{763BAD3E-3244-4E8F-8182-2BF35774262A}.Release|x86.Build.0 = Release|Any CPU\n\t\t{2BC01C4C-288B-4768-BAD0-9BC441D82505}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{2BC01C4C-288B-4768-BAD0-9BC441D82505}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{2BC01C4C-288B-4768-BAD0-9BC441D82505}.Debug|x64.ActiveCfg = Debug|Any CPU\n\t\t{2BC01C4C-288B-4768-BAD0-9BC441D82505}.Debug|x64.Build.0 = Debug|Any CPU\n\t\t{2BC01C4C-288B-4768-BAD0-9BC441D82505}.Debug|x86.ActiveCfg = Debug|Any CPU\n\t\t{2BC01C4C-288B-4768-BAD0-9BC441D82505}.Debug|x86.Build.0 = Debug|Any CPU\n\t\t{2BC01C4C-288B-4768-BAD0-9BC441D82505}.ReleaseMono|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{2BC01C4C-288B-4768-BAD0-9BC441D82505}.ReleaseMono|Any CPU.Build.0 = Release|Any CPU\n\t\t{2BC01C4C-288B-4768-BAD0-9BC441D82505}.ReleaseMono|x64.ActiveCfg = Release|Any CPU\n\t\t{2BC01C4C-288B-4768-BAD0-9BC441D82505}.ReleaseMono|x64.Build.0 = Release|Any CPU\n\t\t{2BC01C4C-288B-4768-BAD0-9BC441D82505}.ReleaseMono|x86.ActiveCfg = Release|Any CPU\n\t\t{2BC01C4C-288B-4768-BAD0-9BC441D82505}.ReleaseMono|x86.Build.0 = Release|Any CPU\n\t\t{2BC01C4C-288B-4768-BAD0-9BC441D82505}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{2BC01C4C-288B-4768-BAD0-9BC441D82505}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{2BC01C4C-288B-4768-BAD0-9BC441D82505}.Release|x64.ActiveCfg = Release|Any CPU\n\t\t{2BC01C4C-288B-4768-BAD0-9BC441D82505}.Release|x64.Build.0 = Release|Any CPU\n\t\t{2BC01C4C-288B-4768-BAD0-9BC441D82505}.Release|x86.ActiveCfg = Release|Any CPU\n\t\t{2BC01C4C-288B-4768-BAD0-9BC441D82505}.Release|x86.Build.0 = Release|Any CPU\n\t\t{DDD598B2-005F-4CB2-B26B-A40CC0F9DE8E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{DDD598B2-005F-4CB2-B26B-A40CC0F9DE8E}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{DDD598B2-005F-4CB2-B26B-A40CC0F9DE8E}.Debug|x64.ActiveCfg = Debug|Any CPU\n\t\t{DDD598B2-005F-4CB2-B26B-A40CC0F9DE8E}.Debug|x64.Build.0 = Debug|Any CPU\n\t\t{DDD598B2-005F-4CB2-B26B-A40CC0F9DE8E}.Debug|x86.ActiveCfg = Debug|Any CPU\n\t\t{DDD598B2-005F-4CB2-B26B-A40CC0F9DE8E}.Debug|x86.Build.0 = Debug|Any CPU\n\t\t{DDD598B2-005F-4CB2-B26B-A40CC0F9DE8E}.ReleaseMono|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{DDD598B2-005F-4CB2-B26B-A40CC0F9DE8E}.ReleaseMono|Any CPU.Build.0 = Debug|Any CPU\n\t\t{DDD598B2-005F-4CB2-B26B-A40CC0F9DE8E}.ReleaseMono|x64.ActiveCfg = Debug|Any CPU\n\t\t{DDD598B2-005F-4CB2-B26B-A40CC0F9DE8E}.ReleaseMono|x64.Build.0 = Debug|Any CPU\n\t\t{DDD598B2-005F-4CB2-B26B-A40CC0F9DE8E}.ReleaseMono|x86.ActiveCfg = Debug|Any CPU\n\t\t{DDD598B2-005F-4CB2-B26B-A40CC0F9DE8E}.ReleaseMono|x86.Build.0 = Debug|Any CPU\n\t\t{DDD598B2-005F-4CB2-B26B-A40CC0F9DE8E}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{DDD598B2-005F-4CB2-B26B-A40CC0F9DE8E}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{DDD598B2-005F-4CB2-B26B-A40CC0F9DE8E}.Release|x64.ActiveCfg = Release|Any CPU\n\t\t{DDD598B2-005F-4CB2-B26B-A40CC0F9DE8E}.Release|x64.Build.0 = Release|Any CPU\n\t\t{DDD598B2-005F-4CB2-B26B-A40CC0F9DE8E}.Release|x86.ActiveCfg = Release|Any CPU\n\t\t{DDD598B2-005F-4CB2-B26B-A40CC0F9DE8E}.Release|x86.Build.0 = Release|Any CPU\n\t\t{5B2BF317-7315-431F-A854-488CD541F42E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{5B2BF317-7315-431F-A854-488CD541F42E}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{5B2BF317-7315-431F-A854-488CD541F42E}.Debug|x64.ActiveCfg = Debug|Any CPU\n\t\t{5B2BF317-7315-431F-A854-488CD541F42E}.Debug|x64.Build.0 = Debug|Any CPU\n\t\t{5B2BF317-7315-431F-A854-488CD541F42E}.Debug|x86.ActiveCfg = Debug|Any CPU\n\t\t{5B2BF317-7315-431F-A854-488CD541F42E}.Debug|x86.Build.0 = Debug|Any CPU\n\t\t{5B2BF317-7315-431F-A854-488CD541F42E}.ReleaseMono|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{5B2BF317-7315-431F-A854-488CD541F42E}.ReleaseMono|Any CPU.Build.0 = Debug|Any CPU\n\t\t{5B2BF317-7315-431F-A854-488CD541F42E}.ReleaseMono|x64.ActiveCfg = Debug|Any CPU\n\t\t{5B2BF317-7315-431F-A854-488CD541F42E}.ReleaseMono|x64.Build.0 = Debug|Any CPU\n\t\t{5B2BF317-7315-431F-A854-488CD541F42E}.ReleaseMono|x86.ActiveCfg = Debug|Any CPU\n\t\t{5B2BF317-7315-431F-A854-488CD541F42E}.ReleaseMono|x86.Build.0 = Debug|Any CPU\n\t\t{5B2BF317-7315-431F-A854-488CD541F42E}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{5B2BF317-7315-431F-A854-488CD541F42E}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{5B2BF317-7315-431F-A854-488CD541F42E}.Release|x64.ActiveCfg = Release|Any CPU\n\t\t{5B2BF317-7315-431F-A854-488CD541F42E}.Release|x64.Build.0 = Release|Any CPU\n\t\t{5B2BF317-7315-431F-A854-488CD541F42E}.Release|x86.ActiveCfg = Release|Any CPU\n\t\t{5B2BF317-7315-431F-A854-488CD541F42E}.Release|x86.Build.0 = Release|Any CPU\n\t\t{896946A7-35AB-40D0-972C-CED7A448B97A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{896946A7-35AB-40D0-972C-CED7A448B97A}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{896946A7-35AB-40D0-972C-CED7A448B97A}.Debug|x64.ActiveCfg = Debug|Any CPU\n\t\t{896946A7-35AB-40D0-972C-CED7A448B97A}.Debug|x64.Build.0 = Debug|Any CPU\n\t\t{896946A7-35AB-40D0-972C-CED7A448B97A}.Debug|x86.ActiveCfg = Debug|Any CPU\n\t\t{896946A7-35AB-40D0-972C-CED7A448B97A}.Debug|x86.Build.0 = Debug|Any CPU\n\t\t{896946A7-35AB-40D0-972C-CED7A448B97A}.ReleaseMono|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{896946A7-35AB-40D0-972C-CED7A448B97A}.ReleaseMono|Any CPU.Build.0 = Release|Any CPU\n\t\t{896946A7-35AB-40D0-972C-CED7A448B97A}.ReleaseMono|x64.ActiveCfg = Release|Any CPU\n\t\t{896946A7-35AB-40D0-972C-CED7A448B97A}.ReleaseMono|x64.Build.0 = Release|Any CPU\n\t\t{896946A7-35AB-40D0-972C-CED7A448B97A}.ReleaseMono|x86.ActiveCfg = Release|Any CPU\n\t\t{896946A7-35AB-40D0-972C-CED7A448B97A}.ReleaseMono|x86.Build.0 = Release|Any CPU\n\t\t{896946A7-35AB-40D0-972C-CED7A448B97A}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{896946A7-35AB-40D0-972C-CED7A448B97A}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{896946A7-35AB-40D0-972C-CED7A448B97A}.Release|x64.ActiveCfg = Release|Any CPU\n\t\t{896946A7-35AB-40D0-972C-CED7A448B97A}.Release|x64.Build.0 = Release|Any CPU\n\t\t{896946A7-35AB-40D0-972C-CED7A448B97A}.Release|x86.ActiveCfg = Release|Any CPU\n\t\t{896946A7-35AB-40D0-972C-CED7A448B97A}.Release|x86.Build.0 = Release|Any CPU\n\t\t{C7EFF544-391C-488F-A747-2663AFEED250}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{C7EFF544-391C-488F-A747-2663AFEED250}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{C7EFF544-391C-488F-A747-2663AFEED250}.Debug|x64.ActiveCfg = Debug|Any CPU\n\t\t{C7EFF544-391C-488F-A747-2663AFEED250}.Debug|x64.Build.0 = Debug|Any CPU\n\t\t{C7EFF544-391C-488F-A747-2663AFEED250}.Debug|x86.ActiveCfg = Debug|Any CPU\n\t\t{C7EFF544-391C-488F-A747-2663AFEED250}.Debug|x86.Build.0 = Debug|Any CPU\n\t\t{C7EFF544-391C-488F-A747-2663AFEED250}.ReleaseMono|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{C7EFF544-391C-488F-A747-2663AFEED250}.ReleaseMono|Any CPU.Build.0 = Release|Any CPU\n\t\t{C7EFF544-391C-488F-A747-2663AFEED250}.ReleaseMono|x64.ActiveCfg = Release|Any CPU\n\t\t{C7EFF544-391C-488F-A747-2663AFEED250}.ReleaseMono|x64.Build.0 = Release|Any CPU\n\t\t{C7EFF544-391C-488F-A747-2663AFEED250}.ReleaseMono|x86.ActiveCfg = Release|Any CPU\n\t\t{C7EFF544-391C-488F-A747-2663AFEED250}.ReleaseMono|x86.Build.0 = Release|Any CPU\n\t\t{C7EFF544-391C-488F-A747-2663AFEED250}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{C7EFF544-391C-488F-A747-2663AFEED250}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{C7EFF544-391C-488F-A747-2663AFEED250}.Release|x64.ActiveCfg = Release|Any CPU\n\t\t{C7EFF544-391C-488F-A747-2663AFEED250}.Release|x64.Build.0 = Release|Any CPU\n\t\t{C7EFF544-391C-488F-A747-2663AFEED250}.Release|x86.ActiveCfg = Release|Any CPU\n\t\t{C7EFF544-391C-488F-A747-2663AFEED250}.Release|x86.Build.0 = Release|Any CPU\n\t\t{CF31204A-12CF-43C0-9054-B9AF98EC83BD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{CF31204A-12CF-43C0-9054-B9AF98EC83BD}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{CF31204A-12CF-43C0-9054-B9AF98EC83BD}.Debug|x64.ActiveCfg = Debug|Any CPU\n\t\t{CF31204A-12CF-43C0-9054-B9AF98EC83BD}.Debug|x64.Build.0 = Debug|Any CPU\n\t\t{CF31204A-12CF-43C0-9054-B9AF98EC83BD}.Debug|x86.ActiveCfg = Debug|Any CPU\n\t\t{CF31204A-12CF-43C0-9054-B9AF98EC83BD}.Debug|x86.Build.0 = Debug|Any CPU\n\t\t{CF31204A-12CF-43C0-9054-B9AF98EC83BD}.ReleaseMono|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{CF31204A-12CF-43C0-9054-B9AF98EC83BD}.ReleaseMono|Any CPU.Build.0 = Debug|Any CPU\n\t\t{CF31204A-12CF-43C0-9054-B9AF98EC83BD}.ReleaseMono|x64.ActiveCfg = Debug|Any CPU\n\t\t{CF31204A-12CF-43C0-9054-B9AF98EC83BD}.ReleaseMono|x64.Build.0 = Debug|Any CPU\n\t\t{CF31204A-12CF-43C0-9054-B9AF98EC83BD}.ReleaseMono|x86.ActiveCfg = Debug|Any CPU\n\t\t{CF31204A-12CF-43C0-9054-B9AF98EC83BD}.ReleaseMono|x86.Build.0 = Debug|Any CPU\n\t\t{CF31204A-12CF-43C0-9054-B9AF98EC83BD}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{CF31204A-12CF-43C0-9054-B9AF98EC83BD}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{CF31204A-12CF-43C0-9054-B9AF98EC83BD}.Release|x64.ActiveCfg = Release|Any CPU\n\t\t{CF31204A-12CF-43C0-9054-B9AF98EC83BD}.Release|x64.Build.0 = Release|Any CPU\n\t\t{CF31204A-12CF-43C0-9054-B9AF98EC83BD}.Release|x86.ActiveCfg = Release|Any CPU\n\t\t{CF31204A-12CF-43C0-9054-B9AF98EC83BD}.Release|x86.Build.0 = Release|Any CPU\n\t\t{97F29346-636E-4BCA-B33D-6D0DB26A5AA6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{97F29346-636E-4BCA-B33D-6D0DB26A5AA6}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{97F29346-636E-4BCA-B33D-6D0DB26A5AA6}.Debug|x64.ActiveCfg = Debug|Any CPU\n\t\t{97F29346-636E-4BCA-B33D-6D0DB26A5AA6}.Debug|x64.Build.0 = Debug|Any CPU\n\t\t{97F29346-636E-4BCA-B33D-6D0DB26A5AA6}.Debug|x86.ActiveCfg = Debug|Any CPU\n\t\t{97F29346-636E-4BCA-B33D-6D0DB26A5AA6}.Debug|x86.Build.0 = Debug|Any CPU\n\t\t{97F29346-636E-4BCA-B33D-6D0DB26A5AA6}.ReleaseMono|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{97F29346-636E-4BCA-B33D-6D0DB26A5AA6}.ReleaseMono|Any CPU.Build.0 = Debug|Any CPU\n\t\t{97F29346-636E-4BCA-B33D-6D0DB26A5AA6}.ReleaseMono|x64.ActiveCfg = Debug|Any CPU\n\t\t{97F29346-636E-4BCA-B33D-6D0DB26A5AA6}.ReleaseMono|x64.Build.0 = Debug|Any CPU\n\t\t{97F29346-636E-4BCA-B33D-6D0DB26A5AA6}.ReleaseMono|x86.ActiveCfg = Debug|Any CPU\n\t\t{97F29346-636E-4BCA-B33D-6D0DB26A5AA6}.ReleaseMono|x86.Build.0 = Debug|Any CPU\n\t\t{97F29346-636E-4BCA-B33D-6D0DB26A5AA6}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{97F29346-636E-4BCA-B33D-6D0DB26A5AA6}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{97F29346-636E-4BCA-B33D-6D0DB26A5AA6}.Release|x64.ActiveCfg = Release|Any CPU\n\t\t{97F29346-636E-4BCA-B33D-6D0DB26A5AA6}.Release|x64.Build.0 = Release|Any CPU\n\t\t{97F29346-636E-4BCA-B33D-6D0DB26A5AA6}.Release|x86.ActiveCfg = Release|Any CPU\n\t\t{97F29346-636E-4BCA-B33D-6D0DB26A5AA6}.Release|x86.Build.0 = Release|Any CPU\n\t\t{46C1A70D-D1DE-4173-A8C0-00F680F026E3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{46C1A70D-D1DE-4173-A8C0-00F680F026E3}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{46C1A70D-D1DE-4173-A8C0-00F680F026E3}.Debug|x64.ActiveCfg = Debug|Any CPU\n\t\t{46C1A70D-D1DE-4173-A8C0-00F680F026E3}.Debug|x64.Build.0 = Debug|Any CPU\n\t\t{46C1A70D-D1DE-4173-A8C0-00F680F026E3}.Debug|x86.ActiveCfg = Debug|Any CPU\n\t\t{46C1A70D-D1DE-4173-A8C0-00F680F026E3}.Debug|x86.Build.0 = Debug|Any CPU\n\t\t{46C1A70D-D1DE-4173-A8C0-00F680F026E3}.ReleaseMono|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{46C1A70D-D1DE-4173-A8C0-00F680F026E3}.ReleaseMono|Any CPU.Build.0 = Debug|Any CPU\n\t\t{46C1A70D-D1DE-4173-A8C0-00F680F026E3}.ReleaseMono|x64.ActiveCfg = Debug|Any CPU\n\t\t{46C1A70D-D1DE-4173-A8C0-00F680F026E3}.ReleaseMono|x64.Build.0 = Debug|Any CPU\n\t\t{46C1A70D-D1DE-4173-A8C0-00F680F026E3}.ReleaseMono|x86.ActiveCfg = Debug|Any CPU\n\t\t{46C1A70D-D1DE-4173-A8C0-00F680F026E3}.ReleaseMono|x86.Build.0 = Debug|Any CPU\n\t\t{46C1A70D-D1DE-4173-A8C0-00F680F026E3}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{46C1A70D-D1DE-4173-A8C0-00F680F026E3}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{46C1A70D-D1DE-4173-A8C0-00F680F026E3}.Release|x64.ActiveCfg = Release|Any CPU\n\t\t{46C1A70D-D1DE-4173-A8C0-00F680F026E3}.Release|x64.Build.0 = Release|Any CPU\n\t\t{46C1A70D-D1DE-4173-A8C0-00F680F026E3}.Release|x86.ActiveCfg = Release|Any CPU\n\t\t{46C1A70D-D1DE-4173-A8C0-00F680F026E3}.Release|x86.Build.0 = Release|Any CPU\n\t\t{2CBD3BE8-9DBF-483D-8E38-88E9DBC86D91}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{2CBD3BE8-9DBF-483D-8E38-88E9DBC86D91}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{2CBD3BE8-9DBF-483D-8E38-88E9DBC86D91}.Debug|x64.ActiveCfg = Debug|Any CPU\n\t\t{2CBD3BE8-9DBF-483D-8E38-88E9DBC86D91}.Debug|x64.Build.0 = Debug|Any CPU\n\t\t{2CBD3BE8-9DBF-483D-8E38-88E9DBC86D91}.Debug|x86.ActiveCfg = Debug|Any CPU\n\t\t{2CBD3BE8-9DBF-483D-8E38-88E9DBC86D91}.Debug|x86.Build.0 = Debug|Any CPU\n\t\t{2CBD3BE8-9DBF-483D-8E38-88E9DBC86D91}.ReleaseMono|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{2CBD3BE8-9DBF-483D-8E38-88E9DBC86D91}.ReleaseMono|Any CPU.Build.0 = Debug|Any CPU\n\t\t{2CBD3BE8-9DBF-483D-8E38-88E9DBC86D91}.ReleaseMono|x64.ActiveCfg = Debug|Any CPU\n\t\t{2CBD3BE8-9DBF-483D-8E38-88E9DBC86D91}.ReleaseMono|x64.Build.0 = Debug|Any CPU\n\t\t{2CBD3BE8-9DBF-483D-8E38-88E9DBC86D91}.ReleaseMono|x86.ActiveCfg = Debug|Any CPU\n\t\t{2CBD3BE8-9DBF-483D-8E38-88E9DBC86D91}.ReleaseMono|x86.Build.0 = Debug|Any CPU\n\t\t{2CBD3BE8-9DBF-483D-8E38-88E9DBC86D91}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{2CBD3BE8-9DBF-483D-8E38-88E9DBC86D91}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{2CBD3BE8-9DBF-483D-8E38-88E9DBC86D91}.Release|x64.ActiveCfg = Release|Any CPU\n\t\t{2CBD3BE8-9DBF-483D-8E38-88E9DBC86D91}.Release|x64.Build.0 = Release|Any CPU\n\t\t{2CBD3BE8-9DBF-483D-8E38-88E9DBC86D91}.Release|x86.ActiveCfg = Release|Any CPU\n\t\t{2CBD3BE8-9DBF-483D-8E38-88E9DBC86D91}.Release|x86.Build.0 = Release|Any CPU\n\t\t{704BA731-9C70-4CBE-A607-1A2E1FB73753}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{704BA731-9C70-4CBE-A607-1A2E1FB73753}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{704BA731-9C70-4CBE-A607-1A2E1FB73753}.Debug|x64.ActiveCfg = Debug|Any CPU\n\t\t{704BA731-9C70-4CBE-A607-1A2E1FB73753}.Debug|x64.Build.0 = Debug|Any CPU\n\t\t{704BA731-9C70-4CBE-A607-1A2E1FB73753}.Debug|x86.ActiveCfg = Debug|Any CPU\n\t\t{704BA731-9C70-4CBE-A607-1A2E1FB73753}.Debug|x86.Build.0 = Debug|Any CPU\n\t\t{704BA731-9C70-4CBE-A607-1A2E1FB73753}.ReleaseMono|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{704BA731-9C70-4CBE-A607-1A2E1FB73753}.ReleaseMono|Any CPU.Build.0 = Debug|Any CPU\n\t\t{704BA731-9C70-4CBE-A607-1A2E1FB73753}.ReleaseMono|x64.ActiveCfg = Debug|Any CPU\n\t\t{704BA731-9C70-4CBE-A607-1A2E1FB73753}.ReleaseMono|x64.Build.0 = Debug|Any CPU\n\t\t{704BA731-9C70-4CBE-A607-1A2E1FB73753}.ReleaseMono|x86.ActiveCfg = Debug|Any CPU\n\t\t{704BA731-9C70-4CBE-A607-1A2E1FB73753}.ReleaseMono|x86.Build.0 = Debug|Any CPU\n\t\t{704BA731-9C70-4CBE-A607-1A2E1FB73753}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{704BA731-9C70-4CBE-A607-1A2E1FB73753}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{704BA731-9C70-4CBE-A607-1A2E1FB73753}.Release|x64.ActiveCfg = Release|Any CPU\n\t\t{704BA731-9C70-4CBE-A607-1A2E1FB73753}.Release|x64.Build.0 = Release|Any CPU\n\t\t{704BA731-9C70-4CBE-A607-1A2E1FB73753}.Release|x86.ActiveCfg = Release|Any CPU\n\t\t{704BA731-9C70-4CBE-A607-1A2E1FB73753}.Release|x86.Build.0 = Release|Any CPU\n\t\t{A0EAD8F0-B7A3-4112-9F3F-2D9922A500BA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{A0EAD8F0-B7A3-4112-9F3F-2D9922A500BA}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{A0EAD8F0-B7A3-4112-9F3F-2D9922A500BA}.Debug|x64.ActiveCfg = Debug|Any CPU\n\t\t{A0EAD8F0-B7A3-4112-9F3F-2D9922A500BA}.Debug|x64.Build.0 = Debug|Any CPU\n\t\t{A0EAD8F0-B7A3-4112-9F3F-2D9922A500BA}.Debug|x86.ActiveCfg = Debug|Any CPU\n\t\t{A0EAD8F0-B7A3-4112-9F3F-2D9922A500BA}.Debug|x86.Build.0 = Debug|Any CPU\n\t\t{A0EAD8F0-B7A3-4112-9F3F-2D9922A500BA}.ReleaseMono|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{A0EAD8F0-B7A3-4112-9F3F-2D9922A500BA}.ReleaseMono|Any CPU.Build.0 = Debug|Any CPU\n\t\t{A0EAD8F0-B7A3-4112-9F3F-2D9922A500BA}.ReleaseMono|x64.ActiveCfg = Debug|Any CPU\n\t\t{A0EAD8F0-B7A3-4112-9F3F-2D9922A500BA}.ReleaseMono|x64.Build.0 = Debug|Any CPU\n\t\t{A0EAD8F0-B7A3-4112-9F3F-2D9922A500BA}.ReleaseMono|x86.ActiveCfg = Debug|Any CPU\n\t\t{A0EAD8F0-B7A3-4112-9F3F-2D9922A500BA}.ReleaseMono|x86.Build.0 = Debug|Any CPU\n\t\t{A0EAD8F0-B7A3-4112-9F3F-2D9922A500BA}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{A0EAD8F0-B7A3-4112-9F3F-2D9922A500BA}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{A0EAD8F0-B7A3-4112-9F3F-2D9922A500BA}.Release|x64.ActiveCfg = Release|Any CPU\n\t\t{A0EAD8F0-B7A3-4112-9F3F-2D9922A500BA}.Release|x64.Build.0 = Release|Any CPU\n\t\t{A0EAD8F0-B7A3-4112-9F3F-2D9922A500BA}.Release|x86.ActiveCfg = Release|Any CPU\n\t\t{A0EAD8F0-B7A3-4112-9F3F-2D9922A500BA}.Release|x86.Build.0 = Release|Any CPU\n\t\t{C050C5F0-8A40-4CB1-9715-A55EBF94FBF2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{C050C5F0-8A40-4CB1-9715-A55EBF94FBF2}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{C050C5F0-8A40-4CB1-9715-A55EBF94FBF2}.Debug|x64.ActiveCfg = Debug|Any CPU\n\t\t{C050C5F0-8A40-4CB1-9715-A55EBF94FBF2}.Debug|x64.Build.0 = Debug|Any CPU\n\t\t{C050C5F0-8A40-4CB1-9715-A55EBF94FBF2}.Debug|x86.ActiveCfg = Debug|Any CPU\n\t\t{C050C5F0-8A40-4CB1-9715-A55EBF94FBF2}.Debug|x86.Build.0 = Debug|Any CPU\n\t\t{C050C5F0-8A40-4CB1-9715-A55EBF94FBF2}.ReleaseMono|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{C050C5F0-8A40-4CB1-9715-A55EBF94FBF2}.ReleaseMono|Any CPU.Build.0 = Debug|Any CPU\n\t\t{C050C5F0-8A40-4CB1-9715-A55EBF94FBF2}.ReleaseMono|x64.ActiveCfg = Debug|Any CPU\n\t\t{C050C5F0-8A40-4CB1-9715-A55EBF94FBF2}.ReleaseMono|x64.Build.0 = Debug|Any CPU\n\t\t{C050C5F0-8A40-4CB1-9715-A55EBF94FBF2}.ReleaseMono|x86.ActiveCfg = Debug|Any CPU\n\t\t{C050C5F0-8A40-4CB1-9715-A55EBF94FBF2}.ReleaseMono|x86.Build.0 = Debug|Any CPU\n\t\t{C050C5F0-8A40-4CB1-9715-A55EBF94FBF2}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{C050C5F0-8A40-4CB1-9715-A55EBF94FBF2}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{C050C5F0-8A40-4CB1-9715-A55EBF94FBF2}.Release|x64.ActiveCfg = Release|Any CPU\n\t\t{C050C5F0-8A40-4CB1-9715-A55EBF94FBF2}.Release|x64.Build.0 = Release|Any CPU\n\t\t{C050C5F0-8A40-4CB1-9715-A55EBF94FBF2}.Release|x86.ActiveCfg = Release|Any CPU\n\t\t{C050C5F0-8A40-4CB1-9715-A55EBF94FBF2}.Release|x86.Build.0 = Release|Any CPU\n\tEndGlobalSection\n\tGlobalSection(SolutionProperties) = preSolution\n\t\tHideSolutionNode = FALSE\n\tEndGlobalSection\n\tGlobalSection(NestedProjects) = preSolution\n\t\t{4F5DB8F5-D0F4-454C-95A7-87F53E5D5E36} = {AC908E33-B856-4E23-9F81-B7F7C97A07F9}\n\t\t{5C2B23E2-C286-412D-ADE1-F6796B7083DE} = {B9C00FAF-36CF-463A-83FA-43E6B974AE2E}\n\t\t{50E14C9A-3C2F-4A51-971F-6143952D0F1C} = {AC908E33-B856-4E23-9F81-B7F7C97A07F9}\n\t\t{3BA7D9BE-EBBF-432E-9880-0E2D2C17FCF8} = {B9C00FAF-36CF-463A-83FA-43E6B974AE2E}\n\t\t{E010FB5E-0D68-4AF7-B632-5DB6B902F158} = {88E7FAF4-CEEC-48B6-9114-71CFE3FC0F50}\n\t\t{A5DE942D-912D-4012-8493-1E958E5445F4} = {AC908E33-B856-4E23-9F81-B7F7C97A07F9}\n\t\t{ADCBBAC0-0A87-45B7-BD31-314F136F74D4} = {B9C00FAF-36CF-463A-83FA-43E6B974AE2E}\n\t\t{A216C2F0-A9A6-4D7F-BF65-127EB80EA6A7} = {88E7FAF4-CEEC-48B6-9114-71CFE3FC0F50}\n\t\t{5CEE1B93-3936-4E32-A414-522DCDCA26BB} = {88E7FAF4-CEEC-48B6-9114-71CFE3FC0F50}\n\t\t{B48782B9-6FA9-4D18-8564-1849FF4CF40E} = {B9C00FAF-36CF-463A-83FA-43E6B974AE2E}\n\t\t{B41C8F1C-5BD2-43B9-A3CC-FC03DFE04E23} = {88E7FAF4-CEEC-48B6-9114-71CFE3FC0F50}\n\t\t{BEDBC0F8-AD0A-44C3-9A53-C8EC4E631AF4} = {88E7FAF4-CEEC-48B6-9114-71CFE3FC0F50}\n\t\t{48A7AC8E-2CB5-403B-8A18-11F493079619} = {B9C00FAF-36CF-463A-83FA-43E6B974AE2E}\n\t\t{B3170309-55AB-462C-9100-D77107799E82} = {88E7FAF4-CEEC-48B6-9114-71CFE3FC0F50}\n\t\t{A43E44E5-F9C1-44BD-A593-419EC113117B} = {B9C00FAF-36CF-463A-83FA-43E6B974AE2E}\n\t\t{2E17A091-DC29-41FB-ABC8-767BD75FFB07} = {AC908E33-B856-4E23-9F81-B7F7C97A07F9}\n\t\t{6D7A63C9-16AB-4B7E-B9C0-0956E1E02610} = {B9C00FAF-36CF-463A-83FA-43E6B974AE2E}\n\t\t{9F88C871-CB37-4A88-BACF-540AC253C202} = {AC908E33-B856-4E23-9F81-B7F7C97A07F9}\n\t\t{B1A38DDE-5534-4625-A3F2-A585BA7A1198} = {B9C00FAF-36CF-463A-83FA-43E6B974AE2E}\n\t\t{8698E0C2-1A82-43E6-8A26-3D9A825CF574} = {88E7FAF4-CEEC-48B6-9114-71CFE3FC0F50}\n\t\t{F782BC86-9CE6-4F69-8F77-710A399CB54F} = {B9C00FAF-36CF-463A-83FA-43E6B974AE2E}\n\t\t{763BAD3E-3244-4E8F-8182-2BF35774262A} = {AC908E33-B856-4E23-9F81-B7F7C97A07F9}\n\t\t{2BC01C4C-288B-4768-BAD0-9BC441D82505} = {AC908E33-B856-4E23-9F81-B7F7C97A07F9}\n\t\t{DDD598B2-005F-4CB2-B26B-A40CC0F9DE8E} = {AC908E33-B856-4E23-9F81-B7F7C97A07F9}\n\t\t{5B2BF317-7315-431F-A854-488CD541F42E} = {B9C00FAF-36CF-463A-83FA-43E6B974AE2E}\n\t\t{896946A7-35AB-40D0-972C-CED7A448B97A} = {AC908E33-B856-4E23-9F81-B7F7C97A07F9}\n\t\t{C7EFF544-391C-488F-A747-2663AFEED250} = {AC908E33-B856-4E23-9F81-B7F7C97A07F9}\n\t\t{CF31204A-12CF-43C0-9054-B9AF98EC83BD} = {AC908E33-B856-4E23-9F81-B7F7C97A07F9}\n\t\t{97F29346-636E-4BCA-B33D-6D0DB26A5AA6} = {B9C00FAF-36CF-463A-83FA-43E6B974AE2E}\n\t\t{46C1A70D-D1DE-4173-A8C0-00F680F026E3} = {B9C00FAF-36CF-463A-83FA-43E6B974AE2E}\n\t\t{8CA69CC9-3415-4484-9342-88D495AE2FF6} = {D8186A1A-6640-4986-9E97-FABE59F6DCE0}\n\t\t{2CBD3BE8-9DBF-483D-8E38-88E9DBC86D91} = {8CA69CC9-3415-4484-9342-88D495AE2FF6}\n\t\t{704BA731-9C70-4CBE-A607-1A2E1FB73753} = {8CA69CC9-3415-4484-9342-88D495AE2FF6}\n\t\t{A0EAD8F0-B7A3-4112-9F3F-2D9922A500BA} = {8CA69CC9-3415-4484-9342-88D495AE2FF6}\n\t\t{C050C5F0-8A40-4CB1-9715-A55EBF94FBF2} = {8CA69CC9-3415-4484-9342-88D495AE2FF6}\n\tEndGlobalSection\n\tGlobalSection(ExtensibilityGlobals) = postSolution\n\t\tSolutionGuid = {DB552D2A-94E1-4A1C-9F3E-E0097C6158CD}\n\tEndGlobalSection\nEndGlobal\n"
  },
  {
    "path": "Libplanet.sln.DotSettings",
    "content": "<wpf:ResourceDictionary\n  xml:space=\"preserve\"\n  xmlns:x=\"http://schemas.microsoft.com/winfx/2006/xaml\"\n  xmlns:s=\"clr-namespace:System;assembly=mscorlib\"\n  xmlns:ss=\"urn:shemas-jetbrains-com:settings-storage-xaml\"\n  xmlns:wpf=\"http://schemas.microsoft.com/winfx/2006/xaml/presentation\">\n\n  <s:Boolean x:Key=\"/Default/UserDictionary/Words/=Bencodex/@EntryIndexedValue\">True</s:Boolean>\n  <s:Boolean x:Key=\"/Default/UserDictionary/Words/=Bitcoin/@EntryIndexedValue\">True</s:Boolean>\n  <s:Boolean x:Key=\"/Default/UserDictionary/Words/=Ethereum/@EntryIndexedValue\">True</s:Boolean>\n  <s:Boolean x:Key=\"/Default/UserDictionary/Words/=Kademlia/@EntryIndexedValue\">True</s:Boolean>\n  <s:Boolean x:Key=\"/Default/UserDictionary/Words/=Libplanet/@EntryIndexedValue\">True</s:Boolean>\n  <s:Boolean x:Key=\"/Default/UserDictionary/Words/=Libplanet_0027s/@EntryIndexedValue\">True</s:Boolean>\n  <s:Boolean x:Key=\"/Default/UserDictionary/Words/=PRNG/@EntryIndexedValue\">True</s:Boolean>\n  <s:Boolean x:Key=\"/Default/UserDictionary/Words/=Unstage/@EntryIndexedValue\">True</s:Boolean>\n  <s:Boolean x:Key=\"/Default/UserDictionary/Words/=bencoded/@EntryIndexedValue\">True</s:Boolean>\n  <s:Boolean x:Key=\"/Default/UserDictionary/Words/=blockchain/@EntryIndexedValue\">True</s:Boolean>\n  <s:Boolean x:Key=\"/Default/UserDictionary/Words/=branchpoint/@EntryIndexedValue\">True</s:Boolean>\n  <s:Boolean x:Key=\"/Default/UserDictionary/Words/=broadcasted/@EntryIndexedValue\">True</s:Boolean>\n  <s:Boolean x:Key=\"/Default/UserDictionary/Words/=changeset/@EntryIndexedValue\">True</s:Boolean>\n  <s:Boolean x:Key=\"/Default/UserDictionary/Words/=ciphertext/@EntryIndexedValue\">True</s:Boolean>\n  <s:Boolean x:Key=\"/Default/UserDictionary/Words/=indeterministic/@EntryIndexedValue\">True</s:Boolean>\n  <s:Boolean x:Key=\"/Default/UserDictionary/Words/=marshaler/@EntryIndexedValue\">True</s:Boolean>\n  <s:Boolean x:Key=\"/Default/UserDictionary/Words/=nonces/@EntryIndexedValue\">True</s:Boolean>\n  <s:Boolean x:Key=\"/Default/UserDictionary/Words/=outdate/@EntryIndexedValue\">True</s:Boolean>\n  <s:Boolean x:Key=\"/Default/UserDictionary/Words/=parameterless/@EntryIndexedValue\">True</s:Boolean>\n  <s:Boolean x:Key=\"/Default/UserDictionary/Words/=preload/@EntryIndexedValue\">True</s:Boolean>\n  <s:Boolean x:Key=\"/Default/UserDictionary/Words/=roadmap/@EntryIndexedValue\">True</s:Boolean>\n  <s:Boolean x:Key=\"/Default/UserDictionary/Words/=ruleset/@EntryIndexedValue\">True</s:Boolean>\n  <s:Boolean x:Key=\"/Default/UserDictionary/Words/=runtimes/@EntryIndexedValue\">True</s:Boolean>\n  <s:Boolean x:Key=\"/Default/UserDictionary/Words/=secp256k1/@EntryIndexedValue\">True</s:Boolean>\n  <s:Boolean x:Key=\"/Default/UserDictionary/Words/=struct/@EntryIndexedValue\">True</s:Boolean>\n  <s:Boolean x:Key=\"/Default/UserDictionary/Words/=txid/@EntryIndexedValue\">True</s:Boolean>\n  <s:Boolean x:Key=\"/Default/UserDictionary/Words/=unmarshal/@EntryIndexedValue\">True</s:Boolean>\n  <s:Boolean x:Key=\"/Default/UserDictionary/Words/=unmarshaling/@EntryIndexedValue\">True</s:Boolean>\n  <s:Boolean x:Key=\"/Default/UserDictionary/Words/=unstage/@EntryIndexedValue\">True</s:Boolean>\n  <s:Boolean x:Key=\"/Default/UserDictionary/Words/=unstaged/@EntryIndexedValue\">True</s:Boolean>\n  <s:Boolean x:Key=\"/Default/UserDictionary/Words/=unrender/@EntryIndexedValue\">True</s:Boolean>\n  <s:Boolean x:Key=\"/Default/UserDictionary/Words/=unrendered/@EntryIndexedValue\">True</s:Boolean>\n  <s:Boolean x:Key=\"/Default/UserDictionary/Words/=unrenderer/@EntryIndexedValue\">True</s:Boolean>\n  <s:Boolean x:Key=\"/Default/UserDictionary/Words/=unrendering/@EntryIndexedValue\">True</s:Boolean>\n  <s:Boolean x:Key=\"/Default/UserDictionary/Words/=unrenders/@EntryIndexedValue\">True</s:Boolean>\n  <s:Boolean x:Key=\"/Default/UserDictionary/Words/=upstream_0027s/@EntryIndexedValue\">True</s:Boolean>\n</wpf:ResourceDictionary>\n"
  },
  {
    "path": "Menees.Analyzers.Settings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n<Menees.Analyzers.Settings>\n  <MaxLineColumns>100</MaxLineColumns>\n  <MaxMethodLines>200</MaxMethodLines>\n  <MaxFileLines>2500</MaxFileLines>\n</Menees.Analyzers.Settings>\n"
  },
  {
    "path": "README.md",
    "content": "Libplanet\n=========\n\n[![Discord](https://img.shields.io/discord/928926944937013338.svg?color=7289da&logo=discord&logoColor=white)][Discord]\n[![Build Status (CircleCI)](https://circleci.com/gh/planetarium/libplanet/tree/main.svg?style=shield)][CircleCI]\n[![Codecov](https://codecov.io/gh/planetarium/libplanet/branch/main/graph/badge.svg)][Codecov]\n[![NuGet](https://img.shields.io/nuget/v/Libplanet.svg?style=flat)][NuGet]\n[![NuGet (prerelease)](https://img.shields.io/nuget/vpre/Libplanet.svg?style=flat)][NuGet]\n\nLibplanet is a .NET library for creating multiplayer online game in\ndecentralized fashion, which means the whole gameplay occurs on a\npeer-to-peer network among equal nodes rather than an authorized central\nserver.  Under the hood, it incorporates many features (e.g.,\n[digital signature], [BFT] consensus, data replication) of a [blockchain].\n\nIt has competitive advantages over other solutions for decentralized gaming:\n\n -  *Embeddable*: A game app does not have to communicate with another running\n    process, hence it doesn't require extra marshaling or processes management.\n    To draw a parallel, Libplanet is closer to SQLite than MySQL or PostgreSQL.\n\n -  *Isomorphic*: Libplanet is a .NET library, so every game logic can be\n    written in the same language, C#, and run on the blockchain. No glue\n    code or \"smart contracts\" are needed.\n\n -  *Token-independent*: Unlike almost every blockchain system, it does not\n    force users to create and deal with yet-another-cryptocurrency. Your\n    game can be free to play, and enjoyed by regular gamers.\n\nTo learn more about why Planetarium is creating technology for fully\ndecentralized games, please refer to our [blog post].\n\n[Discord]: https://link.planetarium.dev/libplanet-readme--pl-dev-discord\n[CircleCI]: https://app.circleci.com/pipelines/github/planetarium/libplanet\n[Codecov]: https://codecov.io/gh/planetarium/libplanet\n[NuGet]: https://www.nuget.org/packages/Libplanet/\n[digital signature]: https://en.wikipedia.org/wiki/Digital_signature\n[BFT]: https://en.wikipedia.org/wiki/Byzantine_fault_tolerance\n[blockchain]: https://en.wikipedia.org/wiki/Blockchain\n[blog post]: https://medium.com/planetarium/introducing-planetarium-powering-games-with-freedom-22ab1ab70e0e\n\n\nNuGet\n-----\n\nFor every stable release, we pack Libplanet into a *.nupkg* and\nupload it to [NuGet] and GitHub [releases] page.\n(You can find the changelog for versions from [releases] page.)\nTo use Libplanet in your game, your project needs to add a dependency\nto *Libplanet* package.  On Visual Studio IDE, run the following command\nin Package Manager Console:\n\n    Install-Package Libplanet\n\nIf you prefer `dotnet` CLI run the following command instead:\n\n~~~~~~~~ bash\ndotnet add package Libplanet\n~~~~~~~~\n\nSee also Microsoft's docs on [different ways to install NuGet package][1].\n\nIn addition to stable releases, we also provide pre-release packages.\nFor every day and every merge commit, it is packed into a *.nupkg*\nand uploaded to [NuGet] with a hyphen-suffixed version name.\n\nFor a merge commit build, a version name looks like\n`0.1.0-dev.20181231235959+a0b1c2d` where `20181231235959` is a UTC timestamp of\nthe build and `a0b1c2d` is the first 7 hexadecimals of the Git commit hash.\nFor a daily build, a version name is like `0.1.0-nightly.20181231+a0b1c2d`.\n\nUnfortunately, Unity currently does not support NuGet.  There are some Unity\nplug-ins to deal with NuGet package system, and these seem immature at present.\nTo use Libplanet on Unity, you need to manually extract *Libplanet.dll*\nfrom *Libplanet.\\*.nupkg* file and place it inside of your Unity project.\nWe are acknowledging the fact Libplanet is currently not very usable together\nwith Unity, and promise to make it better in the next few minor releases.\nUntil then, you could try [MSBuildForUnity] which is experimental as of\nJanuary 2020.\n\n[releases]: https://github.com/planetarium/libplanet/releases\n[MSBuildForUnity]: https://github.com/microsoft/MSBuildForUnity\n[1]: https://docs.microsoft.com/nuget/consume-packages/ways-to-install-a-package\n\n\nBuild\n-----\n\nYou could build *Libplanet.dll* and *Libplanet.Stun.dll* assemblies\nfrom the source code.\n\nThe following command installs dependencies (required library packages) and\nbuilds the whole Libplanet solution:\n\n~~~~~~~~ bash\ndotnet build\n~~~~~~~~\n\nNote that `dotnet` command is distributed together with [.NET Core] SDK.\n\nIf you'd like to contribute code to the Libplanet project in earnest,\nplease read our [contributor guide](CONTRIBUTING.md).\n\n[.NET Core]: https://dot.net/\n"
  },
  {
    "path": "RELEASE.md",
    "content": "Releasing guide\n===============\n\n*(The current process to release a new version still has many manual tasks.\nThese should be further automated.)*\n\nThis document explains how to release a new version.  As the whole releasing\nprocess is half automated, this covers the other half that humans should\nmanually conduct.\n\nNote that there is the [quick summary](#quick-summary) to remind those who have\nalready read this document of checklist on the bottom.  If it is your first\ntime to this, you should read the whole document first.\n\n\nVersioning\n----------\n\nThe Libplanet project follows [Semantic Versioning].  If you are not familiar\nwith this versioning system, you should read its specification first.  We will\nuse the terms that Semantic Versioning defines, e.g., major/minor/patch\nversions.\n\nNote that we use two kinds of branches in the project:\n\n -  *main*: The unreleased code for the next *major*/*minor* version.\n    For example, if the highest released version is *1.2.3*, the *main* branch\n    contains the code for *1.3.0* or *2.0.0* (it depends on the roadmap).\n\n -  *<var>X</var>.<var>Y</var>-maintenance*: The unreleased code for the next\n    *patch* version.  There can be multiple maintenance branches at a time.\n    For example, there could be *1.1-maintenance* and *1.0-maintenance* at\n    a time.  These maintenance branches are closed when their corresponding\n    major/minor versions are decided to discontinue to support.\n\n[Semantic Versioning]: https://semver.org/\n\n\nChangelog\n---------\n\nImmediately before releasing a new version, you need to fill up the release\ndate on the changelog of the version to release.  As long as there is nothing\nwrong with it, there should be a section of the unreleased version in\nthe [*CHANGES.md*](CHANGES.md) file.\n\nFor example, let's suppose you are going to release the version *1.2.3*.\nThen there should be a section like this:\n\n~~~~ commonmark\nVersion 1.2.3\n-------------\n\nTo be released.\n\n...\n~~~~\n\nYou should replace the sentence <q>To be released</q> with\n<q>Released on ...</q> (put the release date instead):\n\n~~~~ commonmark\nVersion 1.2.3\n-------------\n\nReleased on October 20, 2020.\n\n...\n~~~~\n\nAlso, it's recommended to double-check if the changelog has any formatting\nerrors or is well rendered in the web browser.\n\nThe commit that contains this change should have the message like\n<q>Release 1.2.3</q>:\n\n~~~~ bash\ngit commit -m \"Release 1.2.3\" CHANGES.md\n~~~~\n\nSee also these commits for example:\n\n -  <https://github.com/planetarium/libplanet/commit/ea1086d161c72f1ac5d0d6bbb8d67728034f6451>\n -  <https://github.com/planetarium/libplanet/commit/eba9e7bd436c5186bb56851bc853105805ed747f>\n\nThe commit should not be pushed to the upstream repository, but be sent\nas a pull request instead.\n\nSee also the following pull requests for example:\n\n -  <https://github.com/planetarium/libplanet/pull/906>\n -  <https://github.com/planetarium/libplanet/pull/855>\n\n\nTagging\n-------\n\nAfter the pull request (which fills up the release date on the changelog)\nis merged, you need to tag the pull request's merge commit.  The tag name\nmust be the version number without any prefix or suffix, e.g., *1.2.3*;\nthe tag message should be like <q>Libplanet 1.2.3</q>.\n\n~~~~ bash\ngit tag -m \"Libplanet 1.2.3\" 1.2.3\n~~~~\n\nIf you have a GPG (PGP) key, it is recommended to sign the tag using your key:\n\n~~~~ bash\ngit tag --sign -m \"Libplanet 1.2.3\" 1.2.3\n~~~~\n\nNote that signed tags are visually distinct on GitHub:\n\n![Signed tags appearing distinct on GitHub.](https://git.io/JTRJs)\n\nThe created tag should be directly pushed to the upstream repository.\nA tag push triggers GitHub Actions to release a new version.  The script\nautomates the below processes:\n\n -  Listing a new version on [GitHub Releases].  The corresponding changelog\n    section is extracted to fill up the description of the release.\n    Each release contains:\n     -  NuGet packages (*Libplanet\\*.nupkg*)\n     -  Complete assemblies (*Libplanet\\*-net\\*.tar.xz*) for .NET Core and\n        .NET Framework/Mono\n     -  Prebuilt binaries of Libplanet Tools for Linux\n        (*planet-\\*-linux-\\*.tar.xz*), macOS (*planet-\\*-osx-\\*.tar.xz*),\n        and Windows (*planet-\\*-win-\\*.tar.xz*)\n -  Submitting NuGet packages of a new version.  The packages are listed\n    in the [Contributing guide](CONTRIBUTING.md#projects).\n -  Building a new version of docs and uploading it on\n    <https://docs.libplanet.net/>, which is hosted by GitHub Pages.\n    See also the *gh-pages* branch.\n -  Submitting Libplanet.Tools to npm [@planetarium/cli].\n\nIn other words, you don't have to do them by yourself.  However, you should\ncheck twice if all these packages and docs are successfully submitted.\nIf something went wrong, start the debugging by reading the build logs on\nGitHub Actions.\n\n[@planetarium/cli]: https://www.npmjs.com/package/@planetarium/cli\n[GitHub Releases]: https://github.com/planetarium/libplanet/releases\n\n\nPreparing next\n--------------\n\nAfter a new tag is merged and all automated processes are successful,\nyou need to prepare the next release.  This process is slightly tricky,\nbecause the process varies depending on whether the released version\nwas a major/minor release, or just a patch release.\n\n\n### Patch release\n\nIf what you have just released is a patch release, there are two manual tasks\nto do:\n\n -  Port the released code to the *main* branch, so that the next major/minor\n    release does not miss bugfixes from the previous patch release.\n -  Prepare the next patch release.\n\nFirst of all, your last release should be ported to the *main* branch.\nSwitch to the *main* branch and make sure it is up-to-date.\nThen, merge the tag (e.g., *1.2.3*) you made above into the *main* branch:\n\n~~~ bash\ngit switch main  # Or on Git < 2.23: git checkout main\ngit fetch upstream && git reset --hard upstream/main\ngit merge 1.2.3\n~~~\n\nTrying to merge like above will most likely have conflicts on the *CHANGES.md*\nfile, because both branches (*main* and *<var>X</var>.<var>Y</var>-maintenance*)\nhave their own topmost section in the changelog.  However, this can be simply\nresolved: leave both sections and place the *main* branch's section topmost.\n\nAfter successful merging, send a pull request of it to the upstream's *main*\nbranch.  See also the below commits for example:\n\n -  <https://github.com/planetarium/libplanet/commit/1b1e5e8b37c4b6a3003e1c06b42d4180c6d5048c>\n -  <https://github.com/planetarium/libplanet/commit/4d7cc983ee6111031781e50f89f07364021aedf8>\n\nYou also need to prepare the next patch release.  Switch to the maintenance\nbranch (e.g., *1.2-maintenance*), and make sure it is up-to-date.\n\nYou need to bump the patch version of the `<VersionPrefix>` field\nin the *Directory.Build.props* file.  For example, if the version you have\njust released is *1.2.3*, bump it to *1.2.4* (3 + 1 = 4).\n\nAlso the changelog section for the next patch release should be prepared; add\na new section like this on the topmost next the to-level heading of\nthe changelog document:\n\n~~~~ commonmark\nVersion 1.2.4\n-------------\n\nTo be released.\n\n~~~~\n\nNote that the release date for this is not decided. A simple message like\n<q>Version bump</q> is enough for a commit for the above changes.\n\nLastly, send a pull request of the commit to the upstream's\n*<var>X</var>.<var>Y</var>-maintenance* branch (e.g., *1.2-maintenance*).\n\nSee also the following commit for example:\n\n<https://github.com/planetarium/libplanet/commit/481b0e559b78bbc4027a88cc12698a1540bb4c5b>\n\nAnd a pull request:\n\n<https://github.com/planetarium/libplanet/pull/887>\n\n\n### Major/minor release\n\nIf what you have just released is a major or minor release, there are two\nmanual tasks:\n\n -  Prepare the next patch release.\n -  Prepare the next major or minor release.\n\nTo prepare for the next patch release, a new maintenance branch should be made.\nCreate a new branch named *<var>X</var>.<var>Y</var>-maintenance* branch and\nswitch it.  The branch's *HEAD* should refer to the upstream's *main* branch.\nSuppose you have just released a minor version *1.2.0*:\n\n~~~~ bash\ngit fetch upstream\ngit switch --create=1.2-maintenance  # Or: git checkout -b 1.2-maintenance\ngit reset --hard upstream/main\n~~~~\n\nSince this maintenance branch purposes to prepare the next patch release, e.g.,\n*1.2.1*, the `<VersionPrefix>` field of the *Directory.Build.props*\nfile also needs to be updated:\n\n~~~~ xml\n<VersionPrefix>1.2.1</VersionPrefix>\n~~~~\n\nAs there is no section for the next patch release (e.g., *1.2.1*) in\nthe changelog, you need to add an empty section for this at the top:\n\n~~~~ commonmark\nLibplanet changelog\n===================\n\nVersion 1.2.1\n-------------\n\nTo be released.\n\n~~~~\n\nNote that the release date for this is not decided. A simple message like\n<q>Version bump</q> is enough for a commit for the above changes.\n\nThe new maintenance branch and the added commit should be pushed to\nthe upstream.\n\nSee also the below commit for example:\n\n<https://github.com/planetarium/libplanet/commit/836949f72700cf49f56396be05b92d4d7c994abd>\n\nTo prepare the next *major* or *minor* release, you need to do the similar task\nagain.  Whether to release a new *major* version or a new *minor* version next\ndepends on the roadmap (it should be discussed in advance).  Suppose we plan\nto release *1.3.0* next time here.\n\nSwitch to the *main* branch and make sure it is up-to-date:\n\n~~~~ bash\ngit switch main  # Or on Git < 2.23: git checkout main\ngit fetch upstream && git reset --hard upstream/main\n~~~~\n\nThen, in a similar manner, update *Directory.Build.props*'s\n`<VersionPrefix>` to *1.3.0*, and add an empty section for *1.3.0* with\nthe release date undecided to the changelog.  Make a commit with a simple\nmessage like <q>Version bump</q>.\n\nAt this time, this change should be sent as a pull request on the upstream.\nThe PR should target at the *main* branch of course.\n\nSee also the following commit for example:\n\n<https://github.com/planetarium/libplanet/commit/8866560199e2c53fc353181623a28b8f5c07f5a7>\n\nPlus a pull request:\n\n<https://github.com/planetarium/libplanet/pull/857>\n\n\nQuick summary\n-------------\n\n*This summary is not for first-time readers.  You should read the whole document\nat the very first time.*\n\nNote that *<var>X</var>.<var>Y</var>.<var>Z</var>* means a version to release.\n\nThe checklist to release a new version:\n\n 1. Make sure that you are on the right branch\n    (*<var>X</var>.<var>Y</var>-maintenance* for a patch release,\n    and *main* for a major/minor release).\n 2. Fill up the released date on the changelog.\n 3. `git commit -m Release X.Y.Z`\n 4. Send a pull request and wait until it is merged.\n 5. `git tag --sign -m \"Libplanet X.Y.Z\" X.Y.Z`\n 6. `git push upstream X.Y.Z`\n 7. Check if the all automated processes are successful.\n     - GitHub Releases\n     - NuGet\n     - npm\n     - <https://docs.libplanet.io/> (GitHub Pages)\n\nThe checklist to prepare the next release:\n\n -  If you have just released a *patch version*:\n\n     1. Switch to the *main* branch and make sure it is up-to-date.\n     2. `git merge X.Y.Z`\n     3. Resolve conflicts on the *CHANGES.md* file.  Leave all sections from\n        both branches and place the *main* branch's section topmost.\n     4. Send a pull request to the upstream's *main* branch.\n     5. Switch to the *<var>X</var>.<var>Y</var>-maintenance* branch and\n        make sure it is up-to-date.\n     6. Bump `<VersionPrefix>`'s patch version on\n        *Directory.Build.props*.\n        (For example, if you have just released *1.2.3*, bump it to *1.2.4*.)\n     7. Add a new section for the next unreleased version to the changelog,\n        with the sentence <q>To be released</q> (no release date).\n     8. Commit the changes with a message <q>Version bump</q>.\n     9. Send a pull request to the upstream's\n        *<var>X</var>.<var>Y</var>-maintenance* branch.\n\n -  If you have just released a *major/minor version*:\n\n     1. Create a new branch named *<var>X</var>.<var>Y</var>-maintenance* and\n        switch to it.\n     2. Bump `<VersionPrefix>` on *Directory.Build.props* to\n        *<var>X</var>.<var>Y</var>.1*.\n     3. Add a new section for the next unreleased version\n        (*<var>X</var>.<var>Y</var>.1*) to the changelog, with the sentence\n        <q>To be released</q> (no release date).\n     4. Commit the changes with a message <q>Version bump</q>.\n     5. `git push upstream X.Y-maintenance`\n     6. Switch to the *main* branch.\n     7. Bump `<VersionPrefix>`'s minor version on *Directory.Build.props*.\n        (For example, if you have just released *1.2.0*, bump it to *1.3.0*.)\n     8. Add a new section for the next unreleased minor version to the\n        changelog, with the sentence <q>To be released</q> (no release date).\n     9. Commit the changes with a message <q>Version bump</q>.\n    10. Send a pull request to the upstream's main branch.\n"
  },
  {
    "path": "_typos.toml",
    "content": "[default]\nextend-ignore-re = [\n    \"\\\\\\\"([a-zA-Z0-9][a-zA-Z0-9])+\\\\\\\"\",  # for hexadecimal string values.\n    \"2nd\"\n]\n\n[default.extend-words]\nba = \"ba\"  # byte array\noce = \"oce\"  # OperationCanceledException\n\n[files]\nextend-exclude = [\n    \"hooks/*\"\n]\n"
  },
  {
    "path": "changes/v0.md",
    "content": "Libplanet changelog\n===================\n\nVersion 0.53.4\n--------------\n\nReleased on April 4, 2023.\n\n -  Fixed version resolution of typescript libraries for dependencies located\n    in the monorepo.  [[#3050], [#3052]]\n -  Exported the omitted `signTx()` and `encodeSignedTx()` functions in\n    *@planetarium/tx*.  [[#3052]]\n\n[#3050]: https://github.com/planetarium/libplanet/issues/3050\n[#3052]: https://github.com/planetarium/libplanet/pull/3052\n\n\nVersion 0.53.3\n--------------\n\nReleased on April 3, 2023.\n\n -  Adjusted level of the consensus related logs.  [[#3046]]\n\n[#3046]: https://github.com/planetarium/libplanet/pull/3046\n\n\nVersion 0.53.2\n--------------\n\nReleased on March 31, 2023.\n\n -  Ported changes from [Libplanet 0.50.7] release.  [[#3022]]\n -  `BlockChain<T>.Create()` is now get `IBlockChainState` and\n    `ActionEvaluator` as parameters.  [[#3029]]\n\n[Libplanet 0.50.7]: https://www.nuget.org/packages/Libplanet/0.50.7\n[#3022]: https://github.com/planetarium/libplanet/pull/3022\n[#3029]: https://github.com/planetarium/libplanet/pull/3029\n\n\nVersion 0.53.1\n--------------\n\nReleased on March 28, 2023.\n\n -  Ported changes from [Libplanet 0.50.6] release.  [[#3010]]\n -  Introduced a new `Initialize` system action.  [[#3010]\n\n[Libplanet 0.50.6]: https://www.nuget.org/packages/Libplanet/0.50.6\n[#3010]: https://github.com/planetarium/libplanet/pull/3010\n\n\nVersion 0.53.0\n--------------\n\nReleased on March 27, 2023.\n\nSince 0.53.0, we officially provide *[@planetarium/account-web3-secret-storage]*\nand *[@planetarium/account-aws-kms]*, which are npm packages that provides\n`KeyStore` implementations that comply with *[@planetarium/account]*.\n\n -  *@planetarium/account-web3-secret-storage*: An npm package for providing\n    `Web3KeyStore` which implements Ethereum Web3 Secret Storage (corresponds to\n    `Libplanet.KeyStore.Web3KeyStore`).\n\n -  *@planetarium/account-aws-kms*: An npm package for providing\n    `AwsKmsKeyStore` which implements `Account` and uses AWS KMS as the backend.\n\nSince 0.53.0, we do not provide *Libplanet.Node* package anymore.  If you still\nneed the package, use 0.52.0 or its patched versions.\n\nDue to changes in [[#2961]] and [[#2970]], a network ran with\n[Libplanet 0.51.0] or [Libplanet 0.52.0] is not compatible with this version.\nThus, it is recommended to skip [Libplanet 0.51.0] and [Libplanet 0.52.0] for\ndeployment if possible.\n\n### Backward-incompatible API changes\n\n -  (Libplanet.Node) Removed `Libplanet.Node` namespace.  [[#2971]]\n -  Removed state completion feature with related classes as below.  [[#2703]]\n    -  `StateCompleter`\n    -  `StateCompleters`\n    -  `TotalSupplyStateCompleter`\n    -  `TotalSupplyStateCompleters`\n    -  `ValidatorSetStateCompleter`\n    -  `ValidatorSetStateCompleters`\n -  Removed type parameter `T` for `IAction` from `ActionEvaluator` and\n    `IBlockChainStates`.  [[#2703]]\n -  (@planetarium/tx) It now depends on [@planetarium/bencodex] instead of\n    [disjukr/bencodex], so `Encodable` is replaced by `Value`.\n     -  The return type of `encodeBlockHash()` became `Value` (was `Encodable`).\n     -  The return type of `encodePublicKey()` became `Value` (was `Encodable`).\n     -  The return type of `encodeAddress()` became `Key` (was `Encodable`).\n     -  The return type of `encodeAddressSet()` became `Value`\n        (was `Encodable`).\n     -  The return type of `encodeSignedTx()` became `Dictionary`\n        (was `Map<string | Buffer, Encodable>`).\n     -  The return type of `encodeUnsignedTxWithSystemAction()` became `Value`\n        (was `Encodable`).\n     -  The return type of `encodeUnsignedTxWithCustomActions()` became `Value`\n        (was `Encodable`).\n     -  The `CustomAction` type is now an alias of `Value` (was an alias of\n        `Encodable`).\n     -  The return type of `encodeTxMetadata()` became `Dictionary`\n        (was `Map<string | Buffer, Encodable>`).\n     -  The return type of `encodeSystemAction()` became `Value`\n        (was `Encodable`).\n     -  The return type of `encodeCurrency()` became `Value` (was `Encodable`).\n     -  The return type of `encodeMint()` became `Value` (was `Encodable`).\n     -  The return type of `encodeTransfer()` became `Value` (was `Encodable`).\n -  (Libplanet.Net) Changed `Validator` and `ValidatorSet` to implement\n    `IBencodable`.  [[#2954]]\n     -  Changed `Validator(Dictionary)` to `Validator(IValue)`\n        and `ValidatorSet(List)` to `Validator(IValue)`.\n     -  Changed `Validator.Encoded` to `Validator.Bencoded`\n        and `ValidatorSet.Encoded` to `ValidatorSet.Bencoded`.\n -  Changed `BlockCommit` to implement `IBencodable`.  [[#2955]]\n     -  Changed `BlockCommit(Dictionary)` to `BlockCommit(IValue)`.\n     -  Changed `BlockCommit.Encoded` to `BlockCommit.Bencoded`.\n -  Changed `BlockHash` to implement `IBencodable`.  [[#2959]]\n     -  Changed `BlockHash(Binary)` to `BlockHash(IValue)`.\n     -  Added `BlockHash.Bencoded` property.\n -  Removed `ITxMetadata` interface.  [[#2977]]\n     -  The signature of `Transaction<T>(ITxMetadata, IAction, byte[])`\n        constructor became `Transaction<T>(TxMetadata, IAction, byte[])`.\n     -  The signature of `Transaction<T>(ITxMetadata, IEnumerable<T>, byte[])`\n        constructor became `Transaction<T>(TxMetadata, IEnumerable<T>, byte[])`.\n     -  The signature of `TxMetadata(ITxMetadata)` constructor became\n        `TxMetadata(ITransaction)`.\n -  Removed `ITxExcerpt` interface.  [[#1997], [#2977]]\n -  Removed `TxExcerptExtensions` static class.  [[#1997], [#2977]]\n -  (Libplanet.Net) Changed `VoteMetadata` and `Vote` to implement\n    `IBencodable`.  [[#2961]]\n     -  Changed `VoteMetadata(Dictionary)` to `VoteMetadata(IValue)`\n        and `Vote(Dictionary)` to `Vote(IValue)`.\n     -  Changed `VoteMetadata.Encoded` to `VoteMetadata.Bencoded`\n        and `Vote.Encoded` to `Vote.Bencoded`.\n -  Removed `byte` array related APIs from `BlockCommit`, `Vote`,\n    `VoteMetadata`.  [[#2970]]\n     -  Removed `BlockCommit(byte[])`, `BlockCommit.ByteArray`,\n        and `BlockCommit.ToByteArray()`.\n     -  Removed `Vote(byte[])`, `Vote.ByteArray`, and `Vote.ToByteArray()`.\n     -  Removed `VoteMetadata(byte[])`, `VoteMetadata.ByteArray`,\n        and `VoteMetadata.ToByteArray()`.\n -  `ActionEvaluator()` constructor now explicitly requires a new\n    `feeCalculator` parameter.  [[#2566]]\n\n### Backward-incompatible storage format changes\n\n -  (Libplanet.Net) Changed `BlockCommit`'s `IValue` encoding format.\n    [[#2961]]\n -  Changed `Block<T>`'s `IValue` encoding format.  [[#2970]]\n\n### Added APIs\n\n -  Added `TransactionExtensions` static class.  [[#2977]]\n -  (@planetarium/account) Added key store abstractions.  [[#2915]]\n     -  Added `AccountDeletion` type.\n     -  Added `AccountGeneration` type.\n     -  Added `AccountImportation` type.\n     -  Added `AccountMetadata` type.\n     -  Added `AccountRetrieval` type.\n     -  Added `ImportableKeyStore` interface.\n     -  Added `KeyStore` interface.\n     -  Added `MutableKeyStore` interface.\n -  Added `IFeeCalculator` interface. [[#2566]]\n\n### Behavioral changes\n\n -  (@planetarium/account) `Signature.fromBytes()` and `Signature.fromHex()`\n    no more accept signatures with high S.  Signatures with high S need to be\n    normalized first so that they get rid of high S.  [[#2962]]\n\n### Dependencies\n\n -  Added *[@planetarium/account-web3-secret-storage]* npm package.  [[#2915]]\n -  Added *[@planetarium/account-aws-kms]* npm package.  [[#2962]]\n -  Removed *Libplanet.Node* package.  *Libplanet.Node* 0.52.0 was its last\n    minor release.  [[#2971]]\n\n[Libplanet 0.52.0]: https://www.nuget.org/packages/Libplanet/0.52.0\n[#1997]: https://github.com/planetarium/libplanet/issues/1997\n[#2566]: https://github.com/planetarium/libplanet/pull/2566\n[#2703]: https://github.com/planetarium/libplanet/pull/2703\n[#2915]: https://github.com/planetarium/libplanet/pull/2915\n[#2954]: https://github.com/planetarium/libplanet/pull/2954\n[#2955]: https://github.com/planetarium/libplanet/pull/2955\n[#2959]: https://github.com/planetarium/libplanet/pull/2959\n[#2961]: https://github.com/planetarium/libplanet/pull/2961\n[#2962]: https://github.com/planetarium/libplanet/pull/2962\n[#2970]: https://github.com/planetarium/libplanet/pull/2970\n[#2971]: https://github.com/planetarium/libplanet/pull/2971\n[#2977]: https://github.com/planetarium/libplanet/pull/2977\n[@planetarium/account-web3-secret-storage]: https://www.npmjs.com/package/@planetarium/account-web3-secret-storage\n[@planetarium/account-aws-kms]: https://www.npmjs.com/package/@planetarium/account-aws-kms\n[@planetarium/bencodex]: https://www.npmjs.com/package/@planetarium/bencodex\n[disjukr/bencodex]: https://github.com/disjukr/bencodex\n\nVersion 0.52.2\n--------------\n\nReleased on March 28, 2023.\n\n -  Ported changes from [Libplanet 0.50.6] release.  [[#2976]]\n -  Introduced a new `Initialize` system action.  [[#2976]]\n\n[Libplanet 0.50.6]: https://www.nuget.org/packages/Libplanet/0.50.6\n[#2976]: https://github.com/planetarium/libplanet/pull/2976\n\n\nVersion 0.52.1\n--------------\n\nReleased on March 15, 2023.\n\n -  Ported changes from [Libplanet 0.51.2] release.  [[#2946]]\n\n[Libplanet 0.51.2]: https://www.nuget.org/packages/Libplanet/0.51.2\n[#2946]: https://github.com/planetarium/libplanet/pull/2946\n\n\nVersion 0.52.0\n--------------\n\nReleased on March 3, 2022.\n\nDue to changes in [[#2894]], under certain circumstances, a network ran with\n[Libplanet 0.51.0] may have difficulty getting up and running after an update\nto this version.  Thus, it is recommended to skip [Libplanet 0.51.0] for\ndeployment if possible.\n\n### Backward-incompatible API changes\n\n -  `BlockChain<T>()` no longer accepts an `IStore` where\n    `IStore.GetCanonicalChainId()` is `null`.  For on-the-fly `BlockChain<T>`\n    creation from scratch, use `BlockChain<T>.Create()` factory method instead.\n    [[#2863]]\n -  `BlockChain<T>.Append()` no longer accepts a genesis `Block<T>` (i.e.\n    any `Block<T>` with an index of `0`).  [[#2863]]\n -  `BlockChain<T>()` now throws an `ArgumentException` if provided `IStore`\n    does not have its canonical chain id set or provided chain id is not found.\n    [[#1486], [#2585], [#2889]]\n -  Added `IStore.GetChainBlockCommit()` and `IStore.PutChainBlockCommit()`\n    interface methods.  [[#2878], [#2894]]\n\n### Added APIs\n\n -  Added `BlockChain<T>.Create()` factory method for creating a `BlockChain<T>`\n    with an empty `IStore`.  [[#2863]]\n\n### Behavioral changes\n\n -  Changed `BlockChain<T>.Fork()` to copy `BlockCommit` for its newly forked\n    `BlockChain<T>.Tip`.  [[#2878], [#2894]]\n\n[Libplanet 0.51.0]: https://www.nuget.org/packages/Libplanet/0.51.0\n[#1486]: https://github.com/planetarium/libplanet/issues/1486\n[#2585]: https://github.com/planetarium/libplanet/issues/2585\n[#2863]: https://github.com/planetarium/libplanet/pull/2863\n[#2878]: https://github.com/planetarium/libplanet/issues/2878\n[#2889]: https://github.com/planetarium/libplanet/pull/2889\n[#2894]: https://github.com/planetarium/libplanet/pull/2894\n\n\nVersion 0.51.4\n--------------\n\nReleased on March 28, 2023.\n\n -  Ported changes from [Libplanet 0.50.6] release.  [[#2975]]\n -  Introduced a new `Initialize` system action.  [[#2975]]\n\n[Libplanet 0.50.6]: https://www.nuget.org/packages/Libplanet/0.50.6\n[#2975]: https://github.com/planetarium/libplanet/pull/2975\n\n\nVersion 0.51.3\n--------------\n\nReleased on March 17, 2023.\n\n### Bug fixes\n\n -  Ported changes from [Libplanet 0.50.5] release.  [[#2956]]\n\n[Libplanet 0.50.5]: https://www.nuget.org/packages/Libplanet/0.50.5\n\n\nVersion 0.51.2\n--------------\n\nReleased on March 15, 2023.\n\n -  Ported changes from [Libplanet 0.50.3] release.  [[#2937]]\n -  Fixed `BlockCommit.Encoded` to be more compact.  [[#2938]]\n -  Fixed `Vote.Encoded` and `Proposal.Encoded` to be more compact.  [[#2943]]\n\n[Libplanet 0.50.3]: https://www.nuget.org/packages/Libplanet/0.50.3\n[#2937]: https://github.com/planetarium/libplanet/pull/2937\n[#2938]: https://github.com/planetarium/libplanet/pull/2938\n[#2943]: https://github.com/planetarium/libplanet/pull/2943\n\n\nVersion 0.51.1\n--------------\n\nReleased on March 13, 2023.\n\n### Bug fixes\n\n -  (Libplanet.Net) Fixed a bug where `ActionExecutionState` hadn't generated\n    correctly because of wrong `TotalBlockCount`.  [[#2917]]\n\n[#2917]: https://github.com/planetarium/libplanet/pull/2917\n\n\nVersion 0.51.0\n--------------\n\nReleased on March 7, 2023.\n\nSince 0.51.0, we officially provide *[@planetarium/account]*, an npm package for\nproviding measures to represent accounts for apps developed with Libplanet in\nJavaScript/TypeScript.  Note that the feature set is being actively developed,\nand the specification might change in the near future.\n\n### Deprecated APIs\n\n -  Removed `TotalDifficultyComparer` class.  [[#2872]]\n -  Removed `IBlockPolicy<T>.GetNextBlockDifficulty()` interface method\n    and all its implementations.  [[#2872]]\n -  Removed `IBlockPolicy.TotalDifficulty` interface property and its\n    implementations.  [[#2872]]\n -  Removed all total difficulty related parameters.  [[#2872]]\n -  Removed `IBlockPolicy.Difficulty` interface property and its\n    implementations.  [[#2872]]\n -  Removed `IPreEvaluationBlockHeader.Nonce` interface property and\n    its implementations.  [[#2872]]\n -  Removed `InvalidBlockTotalDifficultyException` class.  [[#2872]]\n -  Removed `InvalidBlockDifficultyException` class.  [[#2872]]\n -  Removed `BlockChain<T>.MakeGenesisBlock()` and `BlockChain<T>.MineBlock()`\n    methods.  [[#2872]]\n -  Removed `HashAlgorithmType` class.  [[#2872]]\n -  Removed `PreEvaluationBlock<T>(IBlockContent<T>)` constructor.  [[#2872]]\n -  Removed `IBlockPolicy.GetMinBlockProtocolVersion()` interface method.\n    [[#2872]]\n\n### Backward-incompatible API changes\n\n -  Added `LastCommit` property to `IBlockMetadata`.  [[#2872]]\n -  Bumped `BlockMetadata.CurrentProtocolVersion` to 4.  [[#2872]]\n -  Changed `IPreEvaluationBlockHeader.PreEvaluationHash` type from\n    `ImmutableArray<byte>` to `HashDigest<SHA256>`.  [[#2872]]\n -  Added `IStore.GetBlockCommit(BlockHash)` method.  [[#2872]]\n -  Added `IStore.PutBlockCommit(BlockCommit)` method.  [[#2872]]\n -  Added `IStore.DeleteBlockCommit(BlockHash)` method.  [[#2872]]\n -  Added `IStore.GetBlockCommitHashes()` method.  [[#2872]]\n -  `BlockMetadata.MakeCandidateData()` now uses a SHA256 hash of `LastCommit`\n    for creating a candidate data for `PreEvaluationBlockHeader<T>`. Due to this\n    change, `PreEvaluationHash` results different with previous block hash\n    computation if the `BlockMetadata.LastCommit` is not null.  [[#2872]]\n -  (Libplanet.Net) Removed `SwarmOptions.StaticPeers`.  [[#2872]]\n -  Changed `BlockPolicy<T>()` constructor not to take\n    `Func<long, int>` type parameter named `getMinBlockProtocolVersion`.\n    [[#2872]]\n\n### Backward-incompatible network protocol changes\n\n -  (Libplanet.Net) Values for `Message.MessageType` are updated to\n    use entirely different values.  [[#2872]]\n\n### Added APIs\n\n -  Added `VoteFlag` enum.  [[#2872]]\n -  Added `IVoteMetadata` interface.  [[#2872]]\n -  Added `VoteMetadata` class.  [[#2872]]\n -  Added `Vote` class.  [[#2872]]\n -  Added `BlockContent.Propose()` method.  [[#2872]]\n -  Added `BlockCommit` class.  [[#2872]]\n -  Added `BlockChain.ProposeGenesisBlock()` static method.  [[#2872]]\n -  Added `BlockChain.ProposeBlock()` method.  [[#2872]]\n -  Added `BlockCommitExtensions` class.  [[#2872]]\n -  Added `ContextTimeoutOption` class.  [[#2872]]\n -  Added `BlockMarshaler.UnmarshalBlockHash()` method. [[#2872]]\n -  Added `BlockChain<T>.GetBlockCommit()` method.  [[#2872]]\n -  Added `InvalidBlockCommitException` class.  [[#2872]]\n -  Added `BlockChain<T>.ValidateBlockCommit()` method.  [[#2872]]\n -  (Libplanet.Net) Added `IReactor` interface.  [[#2872]]\n -  (Libplanet.Net) Added `ConsensusReactor` class which inherits\n    `IReactor` interface.  [[#2872]]\n -  (Libplanet.Net) Added `ConsensusContext` class.  [[#2872]]\n -  (Libplanet.Net) Added `Context` class.  [[#2872]]\n -  (Libplanet.Net) Added `Step` enum.  [[#2872]]\n -  (Libplanet.Net) Added `ConsensusMessage` abstract class which inherits\n    `Message` abstract class.  And added classes which implements\n    `ConsensusMessage` abstract class.  [[#2872]]\n     -  Added `ConsensusProposal` class.\n     -  Added `ConsensusVote` class.\n     -  Added `ConsensusCommit` class.\n -  (Libplanet.Net) Added enumeration items to `MessageType` enum.  [[#2872]]\n     -  Added `ConsensusProposal` of value `0x40`.\n     -  Added `ConsensusVote` of value `0x41`.\n     -  Added `ConsensusCommit` of value `0x42`.\n -  (Libplanet.Net) Added `ConsensusReactorOption` struct.  [[#2872]]\n -  (Libplanet.Net) Added `InvalidConsensusMessageException` class.  [[#2872]]\n -  (Libplanet.Net) Added `InvalidHeightIncreasingException` class.  [[#2872]]\n -  (Libplanet.Net) Added `Message.Id` property.  [[#2872]]\n -  (Libplanet.Net) Added `Gossip` class.  [[#2872]]\n -  (Libplanet.Net) Added `Proposal` class.  [[#2872]]\n -  (Libplanet.Net) Added `ProposalMetadata` class.  [[#2872]]\n -  (Libplanet.Net) Added `NetMQMessageCodec.ParseMessageType()`.  [[#2872]]\n -  (Libplanet.Explorer) Added `BoundPeerType` class.  [[#2872]]\n -  (Libplanet.Explorer) Added `BlockCommitType` class.  [[#2872]]\n -  (Libplanet.Explorer) Added `VoteFlagType` class.  [[#2872]]\n -  (Libplanet.Explorer) Added `VoteType` class.  [[#2872]]\n -  (Libplanet.Explorer) Added `BlockCommitType` as a return of `BlockQuery`.\n    [[#2872]]\n -  Added `PolymorphicAction<T>.ActionTypeLoader` static property to provide\n    a way to configure action type loader to be used in `PolymorphicAction<T>`.\n    [[#2873]]\n -  (@planetarium/tx) Added `SignedTx` type.  [[#2882]]\n -  (@planetarium/tx) Added `signTx` function.  [[#2882]]\n -  (@planetarium/tx) Added `encodeSignedTx` function.  [[#2882]]\n\n### Behavioral changes\n\n -  `PreEvaluationBlockHeader()` constructor became to throw\n    `InvalidBlockLastCommitException` when its metadata's `LastCommit` is\n    invalid.  [[#2872]]\n -  `BlockChain<T>.Append()` has new parameter `BlockCommit blockCommit`, which\n    is a set of commits for given block. `BlockCommit` is used for checks\n    whether a block is committed in consensus.  [[#2872]]\n -  `BlockChain<T>.Append()` method became to throw\n    `InvalidBlockCommitException` when the given `BlockCommit` is invalid with\n    given block.  [[#2872]]\n\n### Bug fixes\n\n -  (Libplanet.Explorer) Fixed a bug where `stateQuery` hadn't work\n    correctly in some situations.  [[#2872]]\n\n### Dependencies\n\n -  Added *[@planetarium/account]* npm package.  [[#2848]]\n\n[#2848]: https://github.com/planetarium/libplanet/pull/2848\n[#2872]: https://github.com/planetarium/libplanet/pull/2872\n[#2873]: https://github.com/planetarium/libplanet/pull/2873\n[#2882]: https://github.com/planetarium/libplanet/pull/2882\n[@planetarium/account]: https://www.npmjs.com/package/@planetarium/account\n\n\nVersion 0.50.7\n--------------\n\nReleased on March 29, 2023.\n\n -  Optimized internal byte array to hex string conversion in several places.\n    [[#2989], [#3007]]\n -  `IValidatorSupportStateDelta` is now public [[#3017]]\n -  Optimized `BlockChainState.GetStates()` by caching results.  [[#3018]]\n\n[#2989]: https://github.com/planetarium/libplanet/issues/2989\n[#3007]: https://github.com/planetarium/libplanet/pull/3007\n[#3017]: https://github.com/planetarium/libplanet/pull/3017\n[#3018]: https://github.com/planetarium/libplanet/pull/3018\n\n\nVersion 0.50.6\n--------------\n\nReleased on March 22, 2023.\n\n -  Remove `SetValidator` system action.  [[#2972]]\n -  `ValidatorStateExtensions` is now public.  [[#2972]]\n\n[#2972]: https://github.com/planetarium/libplanet/pull/2972\n\n\nVersion 0.50.5\n--------------\n\nReleased on March 17, 2023.\n\n### Bug fixes\n\n -  (Libplanet.Net) Fixed a bug where `DealerSocket` cannot connect to peers\n    because of IPv4 return of `ResolveNetMQAddressAsync()`.  [[#2956]]\n\n[#2956]: https://github.com/planetarium/libplanet/pull/2956\n\n\nVersion 0.50.4\n--------------\n\nReleased on March 16, 2023.\n\n -  Fixed `Validator.Encoded` to use a proper type `Bencodex.Types.Integer`\n    for `Validator.Power` instead of `Bencodex.Types.Binary`.  [[#2949]]\n\n[#2949]: https://github.com/planetarium/libplanet/pull/2949\n\n\nVersion 0.50.3\n--------------\n\nReleased on March 14, 2023.\n\n -  Ported changes from [Libplanet 0.49.3] release.  [[#2935]]\n\n[Libplanet 0.49.3]: https://www.nuget.org/packages/Libplanet/0.49.3\n[#2935]: https://github.com/planetarium/libplanet/pull/2935\n\n\nVersion 0.50.2\n--------------\n\nReleased on March 9, 2023.\n\n -  Added `PolymorphicAction<T>.ActionTypeLoader` static property to provide\n    a way to configure action type loader to be used in `PolymorphicAction<T>`.\n    [[#2875]]\n\n[#2875]: https://github.com/planetarium/libplanet/pull/2875\n\n\nVersion 0.50.1\n--------------\n\nReleased on March 6, 2023.\n\n -  Ported changes from [Libplanet 0.49.1] and [Libplanet 0.49.2] release.\n    [[#2884]]\n\n[Libplanet 0.49.1]: https://www.nuget.org/packages/Libplanet/0.49.1\n[Libplanet 0.49.2]: https://www.nuget.org/packages/Libplanet/0.49.2\n[#2884]: https://github.com/planetarium/libplanet/pull/2884\n\n\nVersion 0.50.0\n--------------\n\nReleased on February 27, 2023.\n\n### Backward-incompatible API changes\n\n -  Added `Message.Content` property.  [[#2772], [#2831]]\n -  Some properties and enum of `Message` class are removed and moved to\n    `MessageContent` class.  [[#2772], [#2831]]\n     -  Removed `Message.Type` property.\n     -  Removed `Message.DateField` property.\n     -  Removed `Message.MessageType` enum.\n -  `ITransport` interface and its implementations overhauled.\n    [[#2772], [#2831]]\n     -  `ITransport.SendMessageAsync(BoundPeer, Message, TimeSpan?,\n        CancellationToken)` method has changed to\n        `ITransport.SendMessageAsync(BoundPeer, MessageContent, TimeSpan?, int,\n        bool, CancellationToken)`.\n     -  `ITransport.SendMessageAsync(BoundPeer, Message, TimeSpan?,\n        CancellationToken)` method has changed to\n        `ITransport.SendMessageAsync(BoundPeer, MessageContent, TimeSpan?, int,\n        bool, CancellationToken)`.\n     -  `ITransport.BroadcastMessage(IEnumerable<BoundPeer>, Message)` method\n        has changed to\n        `ITransport.BroadcastMessage(IEnumerable<BoundPeer>, MessageContent)`.\n     -  `ITransport.ReplyMessageAsync(Message, CancellationToken)` method\n        has changed to `ITransport.ReplyMessageAsync(MessageContent,\n        byte[], CancellationToken)`.\n -  Removed `InvalidMessageException` class.\n    Instead, added `InvalidMessageContentException` class.  [[#2772], [#2831]]\n\n### Added APIs\n\n -  Added `MessageContent` class.  [[#2772], [#2831]]\n     -  All messages (e.g. `PingMsg`) became to inherit `MessageContent`\n        (were `Message`).\n\n### Behavioral changes\n\n -  `IBlockPolicy` is no longer enforced for genesis `Block<T>`s.  [[#2845]]\n\n[#2772]: https://github.com/planetarium/libplanet/issues/2772\n[#2831]: https://github.com/planetarium/libplanet/pull/2831\n[#2845]: https://github.com/planetarium/libplanet/pull/2845\n\n\nVersion 0.49.3\n--------------\n\nReleased on March 14, 2023.\n\n -  Ported changes from [Libplanet 0.48.1] release.  [[#2933]]\n\n[Libplanet 0.48.1]: https://www.nuget.org/packages/Libplanet/0.48.1\n[#2933]: https://github.com/planetarium/libplanet/pull/2933\n\n\nVersion 0.49.2\n--------------\n\nReleased on March 3, 2023.\n\n -  General logging changes for better comprehension.  [[#2874]]\n\n[#2874]: https://github.com/planetarium/libplanet/pull/2874\n\n\nVersion 0.49.1\n--------------\n\nReleased on February 24, 2023.\n\n -  (Libplanet.Net) Reduced logging due output being too verbose.  [[#2849]]\n\n[#2849]: https://github.com/planetarium/libplanet/pull/2849\n\n\nVersion 0.49.0\n--------------\n\nReleased on February 20, 2023.\n\n### Backward-incompatible API changes\n\n -  (Libplanet.Net) Changed `BlockCandidateTable<T>.Add(BlockHeader,\n    IEnumerable<Block<T>>)` to `BlockCandidateTable<T>.Add(BlockHeader,\n    Branch<T>)`.  [[#2822]]\n -  (Libplanet.Net) Changed the return type of\n    `BlockCandidateTable<T>.GetCurrentRoundCandidate()` from `List<Block<T>>?`\n    to `Branch<T>?`.  [[#2822]]\n\n### Added APIs\n\n -  Added `Branch<T>` class to represent a sequence of consecutive `Block<T>`s.\n    [[#2822]]\n\n### Behavioral changes\n\n -  `Swarm<T>` became not to spawn multiple task for process `BlockDemand`\n    for the same `BoundPeer`.  [[#2808], [#2814]]\n\n### Bug fixes\n\n -  Fixed a bug where `NetMQTransport`'s overall throughput had been dropped\n    when hostname resolving for some peers was delayed.  [[#2817]]\n\n[#2808]: https://github.com/planetarium/libplanet/issues/2808\n[#2814]: https://github.com/planetarium/libplanet/pull/2814\n[#2817]: https://github.com/planetarium/libplanet/pull/2817\n[#2822]: https://github.com/planetarium/libplanet/pull/2822\n\n\nVersion 0.48.1\n--------------\n\nReleased on March 14, 2023.\n\n -  Ported changes from [Libplanet 0.47.1] release.  [[#2931]]\n\n[Libplanet 0.47.1]: https://www.nuget.org/packages/Libplanet/0.47.1\n[#2931]: https://github.com/planetarium/libplanet/pull/2931\n\n\nVersion 0.48.0\n--------------\n\nReleased on February 14, 2023.\n\n### Backward-incompatible API changes\n\n -  Removed `BlockCandidateTable<T>.Any()` method.  [[#2794]]\n -  Changed the return type from `SortedList<long, Block<T>>?` to\n    `List<Block<T>>?` for `BlockCandidateTable<T>.GetCurrentRoundCandidate()`\n    method.  [[#2794]]\n -  Changed the behavior of `BlockCandidateTable<T>.Add()` method.  [[#2794]]\n -  Changed `TxId` to implement `IBencodable` interface.  [[#2795]]\n\n### Added APIs\n\n -  Added `Serializable` attribute back to `Address`.  [[#2798]]\n -  (Libplanet.Net) Added `Serializable` attribute back to `BoundPeer`.\n    [[#2798]]\n -  (@planetarium/tx) Added `encodeUnsignedTxWithCustomActions()` function.\n    [[#2805]]\n -  (@planetarium/tx) Added `CustomAction` type.  [[#2805]]\n -  (@planetarium/tx) Added `UnsignedTxWithCustomActions` type.  [[#2805]]\n\n### Behavioral changes\n\n -  (Libplanet.Net) Changed `Swarm<T>` to respond to a `GetBlocksMsg` request\n    with an empty `BlocksMsg` if no requested `Block<T>`s are found.\n    [[#2800], [#2803]]\n\n### Dependencies\n\n -  (@planetarium/tx) Because `globalThis.crypto` API is available since\n    Node.js version 19.0.0, it now explicitly requires 19.0.0 or later.\n    [[#2805]]\n\n[#2794]: https://github.com/planetarium/libplanet/pull/2794\n[#2795]: https://github.com/planetarium/libplanet/pull/2795\n[#2798]: https://github.com/planetarium/libplanet/pull/2798\n[#2800]: https://github.com/planetarium/libplanet/issues/2800\n[#2803]: https://github.com/planetarium/libplanet/pull/2803\n[#2805]: https://github.com/planetarium/libplanet/pull/2805\n\n\nVersion 0.47.1\n--------------\n\nReleased on March 14, 2023.\n\n -  Ported changes from [Libplanet 0.46.2] and [Libplanet 0.46.3].  [[#2929]]\n\n[Libplanet 0.46.2]: https://www.nuget.org/packages/Libplanet/0.46.2\n[Libplanet 0.46.3]: https://www.nuget.org/packages/Libplanet/0.46.3\n[#2929]: https://github.com/planetarium/libplanet/pull/2929\n\n\nVersion 0.47.0\n--------------\n\nReleased on February 6, 2023.\n\n### Backward-incompatible API changes\n\n -  The signature of `Address(ImmutableArray<byte>)` constructor became\n    `Address(in ImmutableArray<byte>)`.  [[#2756]]\n -  The signature of `BlockHash(ImmutableArray<byte>)` constructor became\n    `BlockHash(in ImmutableArray<byte>)`.  [[#2756]]\n -  The signature of `Nonce(ImmutableArray<byte>)` constructor became\n    `Nonce(in ImmutableArray<byte>)`.  [[#2756]]\n -  Removed `IAccountStateView.GetValidatorSet()` method.  [[#2733]]\n -  Removed `IAccountStateDelta.SetValidator(Validator)` method.  [[#2733]]\n -  (Libplanet.Extensions.Cocona)  Dropped .NET Standard 2.0 and .NET Core 3.1\n    target assemblies.  [[#2732]]\n -  (Libplanet.Extensions.Cocona)  Added .NET 6 target assembly.  [[#2732]]\n -  (Libplanet.Net) Added `ITransport.AppProtocolVersion`,\n    `ITransport.TrustedAppProtocolVersionSigners`,\n    and `ITransport.DifferentAppProtocolVersionEncountered` properties.\n    [[#2743]]\n -  (Libplanet.Net) Changed `Swarm<T>(BlockChain<T>, PrivateKey,\n    AppProtocolVersionOptions, HostOptions, SwarmOptions)` to\n    `Swarm<T>(BlockChain<T>, PrivateKey, ITransport, SwarmOptions)`.  [[#2743]]\n -  (Libplanet.Net) Changed the type for\n    `AppProtocolVersionOptions.TrustedAppProtocolVersionSigners` from\n    `IImmutableHashSet<PublicKey>?` to `IImmutableHashSet<PublicKey>`.\n    [[#2759]]\n -  (Libplanet.Net) Changed `BoundPeer` to implement `IBencodable` interface\n    and removed `[Serializable]` attribute from `BoundPeer`.  [[#2778]]\n -  (Libplanet.Net) Changed `BoundPeer(Dictionary)` constructor's signature to\n    `BoundPeer(IValue)`.  [[#2778]]\n -  Changed `Address` to implement `IBencodable` interface and removed\n    `[Serializable]` attribute from `Address`.  [[#2778]]\n -  Changed `Address(Binary)` constructor's signature to `Address(IValue)`.\n    [[#2778]]\n\n### Added APIs\n\n -  Introduced *Libplanet.Crypto.Secp256k1* package.  [[#2780]]\n -  Many more types became serialized and deserialized better with\n    [`System.Text.Json.JsonSerializer`] as they now have their own\n    [custom converters].  Note that these serializations are unavailable\n    on Unity due to its incomplete reflection support.  [[#2756]]\n     -  A `Nonce` became represented as a single hexadecimal string in JSON.\n     -  A `PublicKey` became represented as a single hexadecimal string in\n        JSON.\n     -  A `Block<T>` became represented as an object with values in JSON.\n -  Added `TxId(in ImmutableArray<byte>)` constructor.  [[#2756]]\n -  Added `ByteUtil.ParseHexToImmutable()` static method.  [[#2756]]\n\n### Bug fixes\n\n -  Fixed a JSON serializer bug where a `Transaction<T>` serialized into JSON\n    had lacked the content of its `PublicKey`.  [[#2756]]\n -  (Libplanet.Explorer) Fixed a bug where the query `stateQuery` hadn't work\n    correctly.  [[#2757]]\n -  Fixed a bug of `DefaultStore.PutTxExecution()` where sometimes `TxExecution`\n    data is in undefined state due to data corruption.  [[#2761]]\n -  (Libplanet.Node) Fixed a bug of `NodeUtils<T>.CreateGenesisBlock()` where\n    sometimes block data is in undefined state due to data corruption.\n    [[#2761]]\n -  Fixed where `Address(string)` could accept 42 chars with a wrong prefix.\n    [[#2781]]\n -  Fixed where `VolatileStagePolicy<T>(TimeSpan)` created with\n    `TimeSpan.MaxValue` as its argument would not behave properly and throw an\n    `ArgumentOutOfRangeException`.  [[#2783], [#2784]]\n\n### Dependencies\n\n -  Upgrade *Bencodex* from\n    [0.7.0-dev.20220923062845][Bencodex 0.7.0-dev.20220923062845] to\n    [0.8.0][Bencodex 0.8.0].  [[#2294]]\n -  Upgrade *Bencodex.Json* from\n    [0.7.0-dev.20220923062845][Bencodex.Json 0.7.0-dev.20220923062845] to\n    [0.8.0][Bencodex.Json 0.8.0].  [[#2294]]\n -  Upgrade *System.Text.Json* from [6.0.6][System.Text.Json 6.0.6] to\n    [6.0.7][System.Text.Json 6.0.7].  [[#2322]]\n\n### CLI tools\n\n -  Added `planet block` subcommand group. [[#2758]]\n     -  Added `planet block analyze` subcommand.\n     -  Added `planet block generate-genesis` subcommand.\n -  Fixed a bug of `planet tx analyze` subcommand where a serialized transaction\n    had lacked the content of its `\"publicKey\"`.  [[#2756]]\n\n[#2732]: https://github.com/planetarium/libplanet/pull/2732\n[#2733]: https://github.com/planetarium/libplanet/pull/2733\n[#2743]: https://github.com/planetarium/libplanet/pull/2743\n[#2747]: https://github.com/planetarium/libplanet/pull/2747\n[#2756]: https://github.com/planetarium/libplanet/pull/2756\n[#2757]: https://github.com/planetarium/libplanet/pull/2757\n[#2758]: https://github.com/planetarium/libplanet/pull/2758\n[#2759]: https://github.com/planetarium/libplanet/pull/2759\n[#2761]: https://github.com/planetarium/libplanet/pull/2761\n[#2778]: https://github.com/planetarium/libplanet/pull/2778\n[#2780]: https://github.com/planetarium/libplanet/pull/2780\n[#2781]: https://github.com/planetarium/libplanet/pull/2781\n[#2783]: https://github.com/planetarium/libplanet/issues/2783\n[#2784]: https://github.com/planetarium/libplanet/pull/2784\n[Bencodex 0.8.0]: https://www.nuget.org/packages/Bencodex/0.8.0\n[Bencodex.Json 0.8.0]: https://www.nuget.org/packages/Bencodex.Json/0.8.0\n[System.Text.Json 6.0.7]: https://www.nuget.org/packages/System.Text.Json/6.0.7\n\n\nVersion 0.46.3\n--------------\n\nReleased on March 14, 2023.\n\n -  Fixed `Validator.Encoded` to be more compact.  [[#2927]]\n\n[#2927]: https://github.com/planetarium/libplanet/pull/2927\n\n\nVersion 0.46.2\n--------------\n\nReleased on February 16th, 2023.\n\n -  Fix memory issues when preloading.  [[#2804]]\n\n[#2804]: https://github.com/planetarium/libplanet/pull/2804\n\n\nVersion 0.46.1\n--------------\n\nReleased on February 3, 2023.\n\n -  Ported changes from [Libplanet 0.45.5] release.\n -  General changes to log output for readability.  [[#2769]]\n\n[Libplanet 0.45.5]: https://www.nuget.org/packages/Libplanet/0.45.5\n[#2769]: https://github.com/planetarium/libplanet/pull/2769\n\n\nVersion 0.46.0\n--------------\n\nReleased on January 18th, 2023.\n\n### Backward-incompatible API changes\n\n -  Changed `BlockLocator` to throw an `ArgumentException` if an empty set of\n    `BlockHash`es are given during construction.  [[#2584]]\n -  `BlockChain<T>()` now explicitly requires both `store` and `stateStore`\n    arguments to be not `null`.  [[#2609]]\n -  `BlockChain<T>.Swap()` now throws an `InvalidOperationException` if called\n    on a non-canonical chain.  [[#2619]]\n -  Added `actionsLogsList` parameter to `TxSuccess` constructor.\n    [[#2474], [#2505]]\n -  Added `actionsLogsList` parameter to `TxFailure` constructor.\n    [[#2474], [#2505]]\n -  Removed `BlockLocator(Func<long, BlockHash?>, Func<BlockHash, long>, int)`\n    constructor.  Use `BlockLocator.Create()` static method instead.\n    [[#2580], [#2584]]\n -  Replaced `IAction?`-typed `policyBlockAction` parameter with\n    `PolicyBlockActionGetter`-typed `policyBlockActionGetter` parameter\n    in `ActionEvaluator` constructor.  [[#2646]]\n -  Removed `IStore.GetCanonicalGenesisBlock<T>()` interface method and all its\n    implementations.  [[#2664]]\n -  Replaced `IPreEvaluationBlockHeader`-typed `blockHeader` parameter with\n    `IActionTypeLoaderContext`-typed `context` parameter in the below methods.\n    [[#2653]]\n     - `IActionTypeLoader.Load()`.\n     - `IActionTypeLoader.LoadAllActionTypes()`.\n -  Added `IAccountStateDelta.SetValidator(Validator)` method.\n    [[#2716]]\n -  Added `IAccountStateView.GetValidatorSet()` method.  [[#2716]]\n -  Added `IBlockChainStates.GetValidatorSet(BlockHash,\n    ValidatorSetStateCompleter<T>)` method.  [[#2716]]\n     -  Added `BlockChain.GetValidatorSet(BlockHash,\n        ValidatorSetStateCompleter<T>)` method.\n     -  Added `BlockChainStates.GetValidatorSet(BlockHash,\n        ValidatorSetStateCompleter<T>)` method.\n -  Added `StateCompleterSet.ValidatorSetStateCompleter` property.  [[#2716]]\n -  (Libplanet.Net) Removed `workers` parameter from `NetMQTransport.Create()`\n    method and `Swarm<T>()` constructor.  [[#2690]]\n -  (Libplanet.Net) Changed `Swarm<T>()` and `NetMQTransport.Create()` to take\n    `AppProtocolVersionOptions` as a combined parameter instead of taking\n    `AppProtocolVersion`, `IImmutableSet<PublicKey>?`, and\n    `DifferentAppProtocolVersionEncountered` separately.  [[#2693]]\n -  (Libplanet.Net) Changed `Swarm<T>()` and `NetMQTransport.Create()` to take\n    `HostOptions` as a combined parameter instead of taking\n    `string?`, `IEnumerable<IceServer>?`, and `int?` separately.  [[#2701]]\n\n### Added APIs\n\n -  Added `TxExecution.ActionsLogsList` property.  [[#2474], [#2505]]\n -  Added `ActionEvaluation.Logs` property.  [[#2474], [#2505]]\n -  (Libplanet.Explorer) Added `TxResult.ActionsLogsList` property.\n    [[#2474], [#2505]]\n -  (Libplanet.Explorer) Added `actionsLogsList` field to `TxResultType`.\n    [[#2474], [#2505]]\n -  Added `BlockLocator.Create()` static method.  [[#2584]]\n -  Added `PolicyBlockActionGetter` delegator type.  [[#2646]]\n -  Added `IActionTypeLoader.LoadAllActionTypes()` method.  [[#2646]]\n     -  Added `StaticActionTypeLoader.LoadAllActionTypes()` method.\n -  Added `IActionTypeLoaderContext` interface.  [[#2653]]\n -  Added `AppProtocolVersionOptions` class.  [[#2693]]\n -  Added `HostOptions` class.  [[#2701]]\n -  Added `Validator` class.  [[#2716]]\n -  Added `ValidatorSet` class.  [[#2716]]\n -  Added `SetValidator` class.  [[#2716]]\n -  Added `ValidatorSetGetter` delegate.  [[#2716]]\n -  Added `ValidatorSetStateCompleter<T>` delegate.  [[#2716]]\n -  Added `ValidatorSetStateCompleters<T>` class.  [[#2716]]\n -  (Libplanet.Explorer) Added `ValidatorType` class.  [[#2716]]\n -  (Libplanet.Explorer) Added `validators` query in `StateQuery`.  [[#2716]]\n\n### Behavioral changes\n\n -  Changed `BlockChain<T>.FindNextHashes()` to return at most `count`\n    number of `BlockHash`es regardless of the result.\n    `BlockChain<T>`. [[#2581], [#2584]]\n -  Changed `BlockChain<T>.FindNextHashes()` to return zero `BlockHash`es\n    if no branch point `BlockHash` is found instead of returning\n    `BlockHash`es starting with the genesis `BlockHash`.  [[#2582], [#2584]]\n -  Changed the behavior of `BlockLocator` index selection and sampling when\n    creating an instance.  [[#2583], [#2584]]\n -  Changed the default `VolatileStagePolicy<T>.Lifetime` from 3 hours\n    to 10 minutes.  [[#2718]]\n\n### Bug fixes\n\n -  (Libplanet.Net) Fixed a bug `NetMQTransport` log shows socket count wrongly.\n    [[#2708]]\n -  (Libplanet.Net) Fixed a bug where `NetMQTransport.SendMessageAsync()` method\n    hadn't disposed of internal sockets properly when connecting failed.\n    [[#2719]]\n\n### CLI tools\n\n -  Fixed a bug `planet store` had not recognized RocksDB store\n    (`rocksdb+file:`).  [[#2699]]\n -  Added `planet store chain-ids` subcommand.  [[#2699], [#2704]]\n -  Added `-P`/`--public-key` option to `planet key derive` subcommand.\n    [[#2705]]\n\n[#2474]: https://github.com/planetarium/libplanet/discussions/2474\n[#2505]: https://github.com/planetarium/libplanet/pull/2505\n[#2580]: https://github.com/planetarium/libplanet/issues/2580\n[#2581]: https://github.com/planetarium/libplanet/issues/2581\n[#2582]: https://github.com/planetarium/libplanet/issues/2582\n[#2583]: https://github.com/planetarium/libplanet/issues/2583\n[#2584]: https://github.com/planetarium/libplanet/pull/2584\n[#2609]: https://github.com/planetarium/libplanet/pull/2609\n[#2619]: https://github.com/planetarium/libplanet/pull/2619\n[#2646]: https://github.com/planetarium/libplanet/pull/2646\n[#2653]: https://github.com/planetarium/libplanet/pull/2653\n[#2664]: https://github.com/planetarium/libplanet/pull/2664\n[#2690]: https://github.com/planetarium/libplanet/pull/2690\n[#2693]: https://github.com/planetarium/libplanet/pull/2693\n[#2699]: https://github.com/planetarium/libplanet/pull/2699\n[#2701]: https://github.com/planetarium/libplanet/pull/2701\n[#2704]: https://github.com/planetarium/libplanet/pull/2704\n[#2705]: https://github.com/planetarium/libplanet/pull/2705\n[#2718]: https://github.com/planetarium/libplanet/pull/2718\n[#2716]: https://github.com/planetarium/libplanet/pull/2716\n\n\nVersion 0.45.5\n--------------\n\nReleased on January 19, 2023.\n\n  -  Fixed a bug when `Web3KeyStore.Get()` hadn't worked properly on IL2CPP\n     environment.  [[#2727]]\n  -  Back-ported below changes from [Libplanet 0.46.0] release.\n     -  (Libplanet.Net) Fixed a bug `NetMQTransport` log shows socket count\n        wrongly. [[#2708]]\n     -  (Libplanet.Net) Fixed a bug where `NetMQTransport.SendMessageAsync()`\n        method hadn't disposed of internal sockets properly when connecting\n        failed. [[#2719]]\n     -  (Libplanet.Net) `BoundPeer()` constructor became to validate a hostname\n        of `endPoint` parameter.  [[#2721]]\n\n[Libplanet 0.46.0]: https://www.nuget.org/packages/Libplanet/0.46.0\n[#2708]: https://github.com/planetarium/libplanet/pull/2708\n[#2719]: https://github.com/planetarium/libplanet/pull/2719\n[#2721]: https://github.com/planetarium/libplanet/pull/2721\n[#2727]: https://github.com/planetarium/libplanet/pull/2727\n\n\nVersion 0.45.4\n--------------\n\nReleased on January 4, 2023.\n\n  -  Ported changes from [Libplaent 0.44.7] release.  [[#2684]]\n\n[Libplanet 0.44.7]: https://www.nuget.org/packages/Libplanet/0.44.7\n\n\nVersion 0.45.3\n--------------\n\nReleased on December 26, 2022.\n\n -  Ported changes from [Libplanet 0.44.6] release.  [[#2667]]\n\n[Libplanet 0.44.6]: https://www.nuget.org/packages/Libplanet/0.44.6\n\n\nVersion 0.45.2\n--------------\n\nReleased on December 21, 2022.\n\n -  Ported changes from [Libplanet 0.44.5] release.  [[#2654]]\n\n[Libplanet 0.44.5]: https://www.nuget.org/packages/Libplanet/0.44.5\n\n\nVersion 0.45.1\n--------------\n\nReleased on December 15, 2022.\n\n -  Ported changes from [Libplanet 0.44.4] release.  [[#2631]]\n -  (Libplanet.Net) Fixed a bug where `NetMQTransport.SendMessageAsync()`\n    hadn't been canceled properly.  [[#2641]]\n\n[Libplanet 0.44.4]: https://www.nuget.org/packages/Libplanet/0.44.4\n[#2641]: https://github.com/planetarium/libplanet/pull/2641\n\n\nVersion 0.45.0\n--------------\n\nReleased on December 3, 2022.\n\n### Deprecated APIs\n\n -  Removed `BlockChain<T>.MineBlock(PrivateKey, DateTimeOffset, bool, long,\n    int, int, IComparer<Transaction<T>>, CancellationToken?)` by making\n    it `internal`.  [[#2529]]\n -  Removed `IStore.SetBlockPerceivedTime()` and\n    `IStore.GetBlockPerceivedTime()` methods.  [[#2575]]\n -  Removed `BlockPerception` struct.  [[#2575]]\n -  Removed `BlockChain<T>.PerceiveBlock()` method.  [[#2575]]\n\n### Backward-incompatible API changes\n\n -  Changed `BlockChain<T>.MineBlock(PrivateKey, DateTimeOffset?, bool?, long?,\n    int?, int?, IComparer<Transaction<T>>, CancellationToken?)` to\n    `BlockChain<T>.MineBlock(PrivateKey, DateTimeOffset?, bool?,\n    IComparer<Transaction<T>>, CancellationToken?)` by removing policy\n    controlled parameters.  [[#2529]]\n -  Changed `BlockPolicy<T>()` constructor to take additional\n    `Func<long, int>` type parameter named `getMinBlockProtocolVersion`.\n    [[#2593]]\n\n### Added APIs\n\n -  Added `BlockChainStates<T>` class.  [[#2507]]\n -  Added new constructors of `BlockChain<T>` takes `IBlockChainStates<T>`\n    and `ActionEvaluator<T>` directly.  [[#2507]]\n -  Added non-generic interfaces.  [[#2539]]\n     -  Added `IPreEvaluationBlock` interface.\n     -  Added `IBlockContent` interface.\n     -  Added `ITransaction` interface.\n -  Added `IActionTypeLoader` interface.  [[#2539]]\n -  Added `StaticActionTypeLoader` class.  [[#2539]]\n -  (Libplanet.Explorer) Added a new GraphQL endpoint on `/graphql/explorer`.\n    [[#2562]]\n -  Added `IBlockPolicy.GetMinBlockProtocolVersion()` interface method.\n    [[#2593]]\n\n### Bug fixes\n\n -  (Libplanet.Net) Fixed a bug where `AppProtocolVersion.GetHashCode()`\n    did not work as intended.  [[#2518], [#2520]]\n\n### Dependencies\n\n -  Replaced *[BouncyCastle.NetCore 1.8.6]* with\n    *[BouncyCastle.Cryptography 2.0.0]*.  [[#2571]]\n\n### CLI tools\n\n -  Now `planet` can be installed using Homebrew on macOS: `brew install\n    planetarium/brew/planet`.  [[#2555]]\n -  Now `planet` supports command-line completion for bash and zsh.\n    See also [Cocona's manual on configuring command-line\n    completion][Cocona command-line completion].  [[#2586]]\n -  (Libplanet.Explorer) Added `serve` subcommand.  [[#2563]]\n     -  (Libplanet.Explorer) Deprecated primary command.\n        It will be obsoleted in 0.47.0 release.\n        You should use `serve` command instead.  [[#2563]]\n -  (Libplanet.Explorer) Added `schema` subcommand.  [[#2563]]\n\n[BouncyCastle.NetCore 1.8.6]: https://www.nuget.org/packages/BouncyCastle.NetCore/1.8.6\n[BouncyCastle.Cryptography 2.0.0]: https://www.nuget.org/packages/BouncyCastle.Cryptography/2.0.0\n[Cocona command-line completion]: https://github.com/mayuki/Cocona#shell-command-line-completion\n[#2507]: https://github.com/planetarium/libplanet/pull/2507\n[#2518]: https://github.com/planetarium/libplanet/issues/2518\n[#2520]: https://github.com/planetarium/libplanet/pull/2520\n[#2529]: https://github.com/planetarium/libplanet/pull/2529\n[#2539]: https://github.com/planetarium/libplanet/pull/2539\n[#2555]: https://github.com/planetarium/libplanet/pull/2555\n[#2562]: https://github.com/planetarium/libplanet/pull/2562\n[#2563]: https://github.com/planetarium/libplanet/pull/2563\n[#2571]: https://github.com/planetarium/libplanet/pull/2571\n[#2575]: https://github.com/planetarium/libplanet/pull/2575\n[#2586]: https://github.com/planetarium/libplanet/pull/2586\n[#2593]: https://github.com/planetarium/libplanet/pull/2593\n\n\nVersion 0.44.7\n--------------\n\nReleased on January 4, 2023.\n\n -  (Libplanet.Net) Fixed bugs where `NetMQTransport` hadn't worked expected\n    when not many threads were available.  [[#2684]]\n -  (Libplanet.Net) Fixed a bug where `NetMQTransport.ReplyMessageAsync()`\n    hadn't worked properly.  [[#2684]]\n\n[#2684]: https://github.com/planetarium/libplanet/pull/2684\n\n\nVersion 0.44.6\n--------------\n\nReleased on December 26, 2022.\n\n -  (Libplanet.Net) Fixed a bug where `NetMQTransport` hadn't worked properly\n    on Windows.  [[#2667]]\n -  Fixed a scope of readlock on `BlockChain<T>.GetBlockLocator()` method for\n    sake of parallelism.  [[#2667]]\n\n[#2667]: https://github.com/planetarium/libplanet/pull/2667\n\n\nVersion 0.44.5\n--------------\n\nReleased on December 21, 2022.\n\n -  Improved overall performance of `NetMQTransport` and `Swarm<T>`\n    classes.  [[#2654]]\n\n[#2654]: https://github.com/planetarium/libplanet/pull/2654\n\n\nVersion 0.44.4\n--------------\n\nReleased on December 15, 2022.\n\n -  Improved overall performance of `NetMQTransport` and `TxCompletion<T>`\n    classes.  [[#2631]]\n\n[#2631]: https://github.com/planetarium/libplanet/pull/2631\n\n\nVersion 0.44.3\n--------------\n\nReleased on December 1, 2022.\n\n -  Fixed a bug of `TxMetadata.ToBencodex()` method where the encoded\n    timestamp had differed from `TxMetadata.Timestamp` when it has non-zero\n    time zone offset.  [[#2598]]\n\n[#2598]: https://github.com/planetarium/libplanet/pull/2598\n\n\nVersion 0.44.2\n--------------\n\nReleased on November 29, 2022.\n\n -  Improved performance of `.Iterate()` and `.GetNextTxNonce()` of\n    `VolatileStagePolicy`.  [[#2589]]\n\n[#2589]: https://github.com/planetarium/libplanet/pull/2589\n\n\nVersion 0.44.1\n--------------\n\nReleased on November 7, 2022.\n\n -  (Libplanet.Net) Fixed a bug where `NetMQTransport.SendMessageAsnyc()` had\n    hung forever when given peer information isn't valid.  [[#2424], [#2521]]\n\n\nVersion 0.44.0\n--------------\n\nReleased on November 2, 2022.\n\n### Backward-incompatible API changes\n\n -  Removed all `TxMetadata.ToBencodex()` overload methods with parameters.\n    Use newly introduced parameterless `TxMetadata.ToBencodex()` instead.\n    [[#2457]]\n -  (Libplanet.Node) Changed `UntypedTransaction(ITxMetadata,\n    IEnumerable<IValue>, ImmutableArray<byte>)` to `UntypedTransaction(\n    ITxMetadata, IValue?, IValue?, ImmutableArray<byte>`) to support\n    `Transaction<T>.SystemAction`.  [[#2456], [#2457]]\n -  (Libplanet.Node) Renamed `UntypedTransaction.ActionValues` to\n    `UntypedTransaction.CustomActionsValue` and changed its type from\n    `IReadOnlyList<IValue>` to `IValue?`.  [[#2456], [#2457]]\n\n### Added APIs\n\n -  (Libplanet.Explorer) Added `json` field to `ActionType` GraphQL type.\n    [[#2418]]\n -  (Libplanet.Node) Added `IValue? SystemActionValue` property to\n    `UntypedTransaction`.  [[#2456], [#2457]]\n\n### Behavioral changes\n\n - Optimized `ByteUtil.CalculateHash()` method.  [[#2437], [#2459]]\n\n### Bug fixes\n\n -  (Libplanet.Explorer) `Libplanet.Explorer.Executable` became to work again.\n    [[#2420]]\n\n[#2420]: https://github.com/planetarium/libplanet/pull/2420\n\n### CLI tools\n\n -  Added builds for Apple Silicon to releases.  [[#2365]]\n\n[#2365]: https://github.com/planetarium/libplanet/pull/2365\n[#2418]: https://github.com/planetarium/libplanet/pull/2418\n[#2437]: https://github.com/planetarium/libplanet/issues/2437\n[#2459]: https://github.com/planetarium/libplanet/pull/2459\n[#2456]: https://github.com/planetarium/libplanet/issues/2456\n[#2457]: https://github.com/planetarium/libplanet/pull/2457\n\n\nVersion 0.43.3\n--------------\n\nReleased on November 7, 2022.\n\n -  (Libplanet.Net) Fixed a bug where `NetMQTransport.SendMessageAsnyc()` had\n    hung forever when given peer information isn't valid.  [[#2424], [#2521]]\n\n[#2424]: https://github.com/planetarium/libplanet/issues/2424\n[#2521]: https://github.com/planetarium/libplanet/pulls/2521\n\n\nVersion 0.43.2\n--------------\n\nReleased on November 1, 2022.\n\n -  (Libplanet.RocksDBStore) `RocksDBStore` no more crashes with stack overflow\n    during iterating block indices even if a chain is deeply nested (due to\n    forks).  [[#2338], [#2379]]\n\n[#2338]: https://github.com/planetarium/libplanet/issues/2338\n[#2379]: https://github.com/planetarium/libplanet/pull/2379\n\n\nVersion 0.43.1\n--------------\n\nReleased on October 17, 2022.\n\n### Added APIs\n\n -  (Libplanet.Explorer) Added `TxResultType.UpdatedStateType` and\n    `TxResultType.FungibleAssetBalancesType` GraphQL types.  [[#2405]]\n\n[#2405]: https://github.com/planetarium/libplanet/pull/2405\n\n\nVersion 0.43.0\n--------------\n\nReleased on October 14, 2022.\n\nSince 0.43.0, we officially provide *[@planetarium/tx]*, an npm package for\ncreating unsigned transactions in JavaScript/TypeScript.  Although it is still\nin experimental stage, which can build only unsigned transactions with\na system action, its features will be added more in the future.\n\n### Backward-incompatible API changes\n\n -  Removed `DateTimeOffset?` type parameter that allowed a creation of\n    a genesis `Block<T>` with specific timestamp from\n    `BlockChain<T>.MakeGenesisBlock()`.  [[#2321]]\n -  Overhauled constructors for `BlockMetadata`, `BlockContent<T>`,\n    `PreEvaluationBlockHeader`, `PreEvaluationBlock<T>`, `BlockHeader`,\n    and `Block<T>`.  [[#2321]]\n     -  All unsafe constructors have been removed in order to prevent\n        instantiation of invalid block related objects.\n     -  `BlockMetadata` has constructors `BlockMetadata(IBlockMetadata)`\n        and `BlockMetadata(long, DateTimeOffset, PublicKey, long, BigInteger,\n        BlockHash?, HashDigest<SHA256>)`.\n     -  `BlockContent` has constructors `BlockContent<T>(IBlockMetadata,\n        IEnumerable<Transaction<T>> transactions)`,\n        `BlockContent<T>(BlockMetadata)` and `BlockContent<T>(BlockMetadata,\n        IEnumerable<Trnasaction<T>> transactions)`.\n     -  `PreEvaluationBlockHeader` has constructors\n        `PreEvaluationBlockHeader(IPreEvaluationBlockHeader)` and\n        `PreEvaluationBlockHeader(BlockMetadata, (Nonce,\n        ImmutableArray<byte>))`.\n     -  `PreEvaluationBlock<T>` has constructors\n        `PreEvaluationBlock<T>(IPreEvaluationBlockHeader,\n        IEnumerable<Transaction<T>>)` and\n        `PreEvaluatoinBlock<T>(BlockContent<T>, (Nonce, ImmutableArray<byte>))`.\n     -  `BlockHeader` has constructors `BlockHeader(IBlockHeader)` and\n        `BlockHeader(PreEvaluationBlockHeader, (HashDigest<SHA256>,\n        ImmutableArray<byte>?, BlockHash))`.\n     -  `Block<T>` has constructors `Block<T>(IBlockHeader,\n        IEnumerable<Transaction<T>>)` and `Block<T>(PreEvaluationBlock<T>,\n        (HashDigest<SHA256>, ImmutableArray<byte>, BlockHash))`.\n -  `BlockContent<T>` no longer inherits `BlockMetadata` and\n    `PreEvaluationBlock<T>` no longer inherits `PreEvaluationBlockHeader`.\n    [[#2321]]\n -  Both `BlockMetadata` and `BlockContent<T>` are made immutable.  Their\n    properties can no longer be assigned to.  [[#2321]]\n -  Copy extension methods for `BlockMetadata` and `BlockContent<T>` removed.\n    [[#2321]]\n -  (Libplanet.Extensions.Cocona) The return type of\n    `Utils.DeserializeHumanReadable<T>()` static method became `T?` (was `T`).\n    [[#2322]]\n\n### Added APIs\n\n -  System actions now have methods to check equality.  [[#2294]]\n     -  `Mint` now implements `IEquatable<Mint>`.\n     -  `Mint` now implements `IEquatable<IAction>`.\n     -  `Transfer` now implements `IEquatable<Transfer>`.\n     -  `Transfer` now implements `IEquatable<IAction>`.\n -  (Libplanet.Net) Added `IRoutingTable` interface.  [[#2046], [#2229]]\n -  (Libplanet.Net) `RoutingTable` now implements `IRoutingTable` interface.\n    [[#2046], [#2229]]\n -  Added `ActionEvaluator<T>.GenerateRandomSeed()` static method.\n    [[#2131], [#2236]]\n -  Each `BlockMetadata`, `PreEvaluationBlockHeader`, and `BlockHeader`\n    can be accessed from any \"larger\" type object through properties.  [[#2321]]\n     -  `BlockMetadata` can be accessed through `BlockContent<T>.Metadata`\n        or `PreEvaluationBlockHeader.Metadata`.\n     -  `PreEvaluationBlockHeader` can be accessed through\n        `PreEvaluationBlock<T>.Header` or `BlockHeader.Header`.\n     -  `BlockHeader` can be accessed through `Block<T>.Header` (this has not\n        changed, but only listed here for completeness in narrative).\n -  (Libplanet.Explorer) Added `updatedStates`, `updatedFungibleAssets`,\n    `fungibleAssetsDelta` GraphQL fields to `TxResultType`.  [[#2353]]\n -  (Libplanet.Explorer) Added `nextNonce` query in `TransactionQuery<T>`.\n    [[#2356], [#2366]]\n\n### Behavioral changes\n\n -  Many types became serialized and deserialized better with\n    [`System.Text.Json.JsonSerializer`] as they now have their own\n    [custom converters].  Note that these serializations are unavailable\n    on Unity due to its incomplete reflection support.  [[#2294], [#2322]]\n     -  An `Address` became represented as a single hexadecimal string in JSON.\n        [[#2322]]\n     -  A `BlockHash` became represented as a single hexadecimal string in JSON.\n        [[#2322]]\n     -  A `Currency` became represented as an object with values in JSON.\n        Note that it contains its `Hash` and it throws `JsonException`\n        if a JSON object to deserialize has an inconsistent `Hash` with\n        other field values.  [[#2322]]\n     -  A `FungibleAssetValue` became represented as an object with\n        its `Currency` object and `Quantity` string.  [[#2322]]\n     -  A `HashDigest<T>` became represented as a single hexadecimal string in\n        JSON.  [[#2322]]\n     -  A `Transaction<T>` became represented as an object with values in JSON.\n        [[#2294]]\n     -  A `TxId` became represented as a single hexadecimal string in JSON.\n        [[#2322]]\n     -  System actions became represented as a [Bencodex JSON Representation]\n        of their `PlainValue` with `type_id` field.  [[#2294]]\n -  System actions' `GetHashCode()` and `Equals(object)` methods now check\n    value equality (rather than reference equality).  [[#2294]]\n -  A `ValidateAppProtocolVersion` became allow validation of different extra.\n    [[#2380]]\n\n### Bug fixes\n\n -  Interface methods `IComparable.CompareTo()` and\n    `IComparable<T>.CompareTo()` for `Address` are now accessible.  [[#2384]]\n\n### Dependencies\n\n -  Added *[@planetarium/tx]* npm package.  [[#2294]]\n -  Now depends on [*Bencodex.Json*\n    0.7.0-dev.20220923062846][Bencodex.Json 0.7.0-dev.20220923062845].\n    [[#2294]]\n -  Upgrade *Bencodex* from [0.6.0][Bencodex 0.6.0] to\n    [0.7.0-dev.20220923062845][Bencodex 0.7.0-dev.20220923062845].  [[#2294]]\n -  Upgrade *System.Text.Json* from [4.7.2][System.Text.Json 4.7.2] to\n    [6.0.6][System.Text.Json 6.0.6].  [[#2322]]\n\n### CLI tools\n\n -  Added `planet tx` subcommand group.  [[#2294]]\n     -  Added `planet tx analyze` subcommand.\n     -  Added `planet tx help` subcommand.\n\n[#2046]: https://github.com/planetarium/libplanet/issues/2046\n[#2131]: https://github.com/planetarium/libplanet/issues/2131\n[#2229]: https://github.com/planetarium/libplanet/pull/2229\n[#2236]: https://github.com/planetarium/libplanet/pull/2236\n[#2294]: https://github.com/planetarium/libplanet/pull/2294\n[#2321]: https://github.com/planetarium/libplanet/pull/2321\n[#2322]: https://github.com/planetarium/libplanet/pull/2322\n[#2353]: https://github.com/planetarium/libplanet/pull/2353\n[#2356]: https://github.com/planetarium/libplanet/issues/2356\n[#2366]: https://github.com/planetarium/libplanet/pull/2366\n[#2380]: https://github.com/planetarium/libplanet/pull/2380\n[#2384]: https://github.com/planetarium/libplanet/pull/2384\n[`System.Text.Json.JsonSerializer`]: https://docs.microsoft.com/en-us/dotnet/api/system.text.json.jsonserializer\n[custom converters]: https://docs.microsoft.com/en-us/dotnet/standard/serialization/system-text-json-converters-how-to\n[@planetarium/tx]: https://www.npmjs.com/package/@planetarium/tx\n[Bencodex JSON Representation]: https://github.com/planetarium/bencodex/blob/4a92a98e859a54bc6e9617d4dd3035250fe69a86/JSON.md\n[Bencodex 0.7.0-dev.20220923062845]: https://www.nuget.org/packages/Bencodex/0.7.0-dev.20220923062845\n[Bencodex.Json 0.7.0-dev.20220923062845]: https://www.nuget.org/packages/Bencodex.Json/0.7.0-dev.20220923062845\n[System.Text.Json 4.7.2]: https://www.nuget.org/packages/System.Text.Json/4.7.2\n[System.Text.Json 6.0.6]: https://www.nuget.org/packages/System.Text.Json/6.0.6\n\n\nVersion 0.42.2\n--------------\n\nReleased on September 29, 2022.\n\n -  (Libplanet.Explorer) Fixed a bug of `TransactionQuery<T>` that\n    `bindSignature()` had errored if `unsignedTransaction` has a system\n    action.  [[#2358]]\n\n\nVersion 0.42.1\n--------------\n\nReleased on September 23, 2022.\n\n -  Fixed a bug where `Transaction<T>.ToBencodex(bool)` method had incorrectly\n    serialized `SystemAction`.  [[#2339]]\n\n\nVersion 0.42.0\n--------------\n\nReleased on September 19, 2022.\n\n### Backward-incompatible API changes\n\n -  Renamed `BlockChain<T>.MakeTransaction(PrivateKey, IEnumerable<T>,\n    IImmutableSet<Address>, DateTimeOffset?)` method's `actions` parameter to\n    `customActions`.  [[#2151], [#2273]]\n -  Changed `IBlockPolicy.GetMaxBlockBytes()` to\n    `IBlockPolicy.GetMaxTransactionBytes()`.  Behaviourally, this is now used\n    as an upper limit for the encoded size of `Block<T>.Transactions`\n    instead of `Block<T>`.  [[#2290], [#2291]]\n     -  (Libplanet.Explorer) Changed `Options.MaxBlockBytes` to\n        `Options.MaxTransactionsBytes` and `Options.MaxGenesisBytes` to\n        `Options.MaxGenesisTransactionsBytes`.\n     -  (Libplanet.Explorer) Changed executable argument `max-block-bytes`\n        to `max-transactions-bytes` and `max-genesis-bytes` to\n        `max-genesis-transactions-bytes`.\n     -  All public method parameter names `maxBlockBytes` changed to\n        `maxTransactionsBytes`.\n\n### Added APIs\n\n -  `Address` now implements `IEquatable<Address>` interface. [[#2320]]\n -  `TxId` now implements `IEquatable<TxId>` interface.  [[#2320]]\n -  Added `BlockChain<T>.MakeTransaction(PrivateKey, IAction,\n    IImmutableSet<Address>, DateTimeOffset?)` overloaded method.\n    [[#2151], [#2273]]\n -  Added `GetInnerActionTypeName()` method. [[#1910], [#2189]]\n -  (Libplanet.Explorer) Added `LibplanetExplorerSchema` class.\n    [[#2065], [#2198]]\n\n### Dependencies\n\n -  Upgraded *Bencodex* from [0.4.0][Bencodex 0.4.0] to [0.5.0][Bencodex 0.5.0].\n    [[#2283]]\n -  Upgraded *Bencodex* from [0.5.0][Bencodex 0.5.0] to [0.6.0][Bencodex 0.6.0].\n    [[#2298]]\n\n[#1910]: https://github.com/planetarium/libplanet/issues/1910\n[#2065]: https://github.com/planetarium/libplanet/issues/2065\n[#2273]: https://github.com/planetarium/libplanet/pull/2273\n[#2283]: https://github.com/planetarium/libplanet/pull/2283\n[#2189]: https://github.com/planetarium/libplanet/pull/2189\n[#2290]: https://github.com/planetarium/libplanet/issues/2290\n[#2291]: https://github.com/planetarium/libplanet/pull/2291\n[#2298]: https://github.com/planetarium/libplanet/pull/2298\n[#2320]: https://github.com/planetarium/libplanet/pull/2320\n[Bencodex 0.5.0]: https://www.nuget.org/packages/Bencodex/0.5.0\n[Bencodex 0.6.0]: https://www.nuget.org/packages/Bencodex/0.6.0\n\n\nVersion 0.41.4\n--------------\n\nReleased on September 29, 2022.\n\n -  (Libplanet.Explorer) Fixed a bug of `TransactionQuery<T>` that\n    `bindSignature()` had errored if `unsignedTransaction` has a system\n    action.  [[#2358]]\n\n\nVersion 0.41.3\n--------------\n\nReleased on September 23, 2022.\n\n -  Fixed a bug where `Transaction<T>.ToBencodex(bool)` method had incorrectly\n    serialized `SystemAction`.  [[#2339]]\n\n\nVersion 0.41.2\n--------------\n\nReleased on September 13, 2022.\n\n -  Fixed a bug where `NetMQTransport` is not correctly disposed of due to\n    `NetMQTransport._router` already being stopped in prior to\n    `_router.Unbind()` call in `NetMQTransport.Dispose()`.  [[#2311]]\n\n[#2311]: https://github.com/planetarium/libplanet/pull/2311\n\n\nVersion 0.41.1\n--------------\n\nReleased on August 31, 2022.\n\n -  Fixed a bug where `Transaction<T>.Create(long, PrivateKey, BlockHash?,\n    IAction, IImmutableSet<Address>?, DateTimeOffset?)` method had thrown\n    `ArgumentNullException` with valid arguments.  [[#2268], [#2270]]\n\n[#2270]: https://github.com/planetarium/libplanet/pull/2270\n\n\nVersion 0.41.0\n--------------\n\nReleased on August 26, 2022.\n\n### Deprecated APIs\n\n -  (Libplanet.Net) Removed `NetMQTransport()` constructor.  Use\n    `NetMQTransport.Create()` instead.  [[#2215]]\n -  Unused `TcpMessageCodec` class removed.  [[#2216]]\n -  (Libplanet.Stun) Removed `TurnClient.IsConnectable()` method.  [[#2219]]\n -  (Libplanet.Stun) Removed `TurnClient.BindProxies()` method.\n    [[#2219]]\n -  (Libplanet.Stun) Removed `TurnClient()` constructor.\n    Use `TurnClient.Create()` instead.  [[#2219]]\n -  (Libplanet.Net) Removed `Peer` class.  Use `BoundPeer` instead.  [[#2233]]\n\n### Backward-incompatible API changes\n\n -  Removed unused transaction related methods from `IStore` and its\n    implementations.  [[#1538], [#2201]]\n    - `IterateTransactionIds()`\n    - `DeleteTransaction()`\n    - `CountTransactions()`\n -  Removed `Currency(string, byte, IImutableSet<Address>?)` constructor.\n    [[#2200]]\n -  Removed `Currency(string, byte, Address?)` constructor.\n    [[#2200]]\n -  Added static methods of `Currency` that defines different kinds of\n    `Currency`.  [[#2200]]\n     -  Added `Currency.Capped(string, byte, (BigInteger, BigInteger),\n        IImutableSet<Address>?)` static method which defines an instance of\n        `Currency` with a hard limit on the maximum minted supply.\n     -  Added `Currency.Capped(string, byte, (BigInteger, BigInteger),\n        Address)` static method which defines an instance of `Currency` with a\n        hard limit on the maximum minted supply.\n     -  Added `Currency.Uncapped(string, byte, IImutableSet<Address>?)` static\n        method which defines an instance of `Currency` without an enforced\n        maximum supply limit.\n     -  Added `Currency.Uncapped(string, byte, Address)` static method which\n        defines an instance of `Currency` without an enforced maximum supply\n        limit.\n     -  *OBSOLETE, ONLY FOR LEGACY SUPPORT*: Added `Currency.Legacy(string,\n        byte, IImutableSet<Address>?)` static method which defines a legacy\n        `Currency` instance which is compatible with `Currency` instances\n        defined before total supply tracking support was introduced.\n     -  *OBSOLETE, ONLY FOR LEGACY SUPPORT*: Added `Currency.Legacy(string,\n        byte, Address)` static method which defines a legacy `Currency`\n        instance which is compatible with `Currency` instances defined before\n        total supply tracking support was introduced.\n     -  *NOTE:* if you already have some `Currency` instances defined in prior\n        to the addition of total supply tracking on a live chain, you cannot\n        modify the already-defined `Currency` instances as a capped or uncapped\n        `Currency` but have to define them with `Currency.Legacy()` as\n        the new Currency kinds are internally backwards-incompatible with the\n        legacy `Currency`.\n -  Added `IAccountStateDelta.TotalSupplyUpdatedCurrencies` property.\n    [[#915], [#2200]]\n -  Added `IAccountStateView.GetTotalSupply(Currency)` method.\n    [[#915], [#2200]]\n -  Added `IBlockChainStates<T>.GetTotalSupply(Currency, BlockHash,\n    TotalSupplyStateCompleter<T>` method which gets the total supply of\n    a `Currency` in `FungibleAssetValue` from the state, and if not found,\n    returns null.  [[#915], [#2200]]\n -  (Libplanet.Net) `ITransport.AsPeer` and `Swarm<T>.AsPeer` type changed from\n    `Peer` to `BoundPeer`.  [[#2215]]\n -  (Libplanet.Net) All public return type, parameter type, and property type\n    of `Peer` changed to `BoundPeer`.  [[#2228]]\n -  (Libplanet.Net) Additional public return type, parameter type, and\n    property type of `Peer` that weren't handled by [#2228] changed to\n    `BoundPeer`.  [[#2233]]\n -  Reworked constructors of exception classes. Affected classes are:\n     - (Libplanet.Net) `PingTimeoutException`\n     - `CurrencyPermissionException`,\n     `DuplicateActionTypeIdentifierException`, `InsufficientBalanceException`,\n     `InvalidBlockPreEvaluationHashException`,\n     `InvalidBlockProtocolVersionException`, `InvalidBlockPublicKeyException`,\n     `InvalidBlockSignatureException`, `InvalidBlockStateRootHashException`,\n     `InvalidBlockTotalDifficultyException`, `InvalidGenesisBlockException`,\n     `InvalidTxException`, `InvalidTxGenesisHashException`,\n     `InvalidTxIdException`, `InvalidTxNonceException`,\n     `InvalidTxSignatureException`, `MissingActionTypeException`,\n     `NoKeyException`, `SupplyOverflowException`,\n     `TotalSupplyNotTrackableException`, `TxPolicyViolationException`,\n     `UnexpectedlyTerminatedActionException`.  [[#2239], [#2241]]\n\n### Added APIs\n\n -  Added `Currency.MaximumSupply` property.  [[#915], [#2200]]\n -  Added `Currency.TotalSupplyTrackable` field.  [[#915], [#2200]]\n -  Added `SupplyOverflowException` class.  [[#915], [#2200]]\n -  Added `TotalSupplyGetter` delegate.  [[#915], [#2200]]\n -  Added `TotalSupplyStateCompleter<T>` delegate.  [[#915], [#2200]]\n -  Added `TotalSupplyStateCompleters<T>` static class.  [[#915], [#2200]]\n -  Added `StateCompleterSet<T>.TotalSupplyStateCompleter` property.\n    [[#915], [#2200]]\n -  (Libplanet.Net) Added `BoundPeer.PeerString` property.  [[#2187], [#2232]]\n -  (Libplanet.Stun) Added `IIceServer` interface.  [[#2219]]\n -  (Libplanet.Stun) Added `TurnClient.Create()` static method.  [[#2219]]\n -  (Libplanet.Explorer) Added `stateQuery` field to the root node of GraphQL\n    endpoint.  [[#2149], [#2227]]\n -  (Libplanet.Explorer) Added `blockPolicy` field to the root node of GraphQL\n    endpoint.  [[#2149], [#2227]]\n -  (Libplanet.Explorer) Added `CurrencyType` class.  In GraphQL, it corresponds\n    to `Currency` type.  [[#2149], [#2227]]\n -  (Libplanet.Explorer) Added `FungibleAssetValueType` class.  In GraphQL,\n    it corresponds to `FungibleAssetValue` type.  [[#2149], [#2227]]\n -  (Libplanet.Explorer) Added `StateQuery<T>` class.  In GraphQL, it\n    corresponds to `StateQuery` type.  [[#2149], [#2227]]\n -  (Libplanet.Explorer) Added `BlockPolicyType<T>` class.  In GraphQL, it\n    corresponds to `BlockPolicy` type.  [[#2149], [#2227]]\n\n### Behavioral changes\n\n -  Bencodex related methods in `Currency` now accounts for the maximum\n    supply and total supply tracking.  [[#915], [#2200]]\n     -  For capped currencies, `Currency.Serialize()` method stores the `major`\n        and `minor` values of the maximum supply as `Integer` values under the\n        keys `maximumSupplyMajor` and `maximumSupplyMinor`. For uncapped and\n        legacy untracked currencies, the entries are omitted.\n     -  `Currency(IValue)` constructor now looks for the maximum supply and\n        total supply trackability in the given dictionary and restores them if\n        found.\n -  `Currency`'s implementation of `ISerializable` now accounts for the maximum\n    supply and total supply tracking.  [[#915], [#2200]]\n     -  `Currency`'s implementation of `ISerializable.GetObjectData` now stores\n         the maximum supply if the `Currency` is capped.\n     -  `Currency(SerializationInfo, StreamingContext)` constructor now looks\n        for the maximum supply and total supply trackability and restores it if\n        found.\n -  `IAccountStateDelta.MintAsset(Address, FungibleAssetValue)` and\n    `IAccountStateDelta.BurnAsset(Address, FungibleAssetValue)` methods now\n    track the total supply if the total supply of the `Currency` is trackable.\n    [[#915], [#2200]]\n     -  `IAccountStateDelta.MintAsset(Address, FungibleAssetValue)` method now\n        throws `SupplyOverflowException` if the sum of current total supply and\n        the value to be minted exceeds the maximum supply of the `Currency`\n        instance.\n -  (Libplanet.Net) `NetMQTransport`'s general behavior has changed.  [[#2215]]\n     -  `NetMQTransport` is now able to send requests and receive\n        replies as soon as it is created through `NetMQTransport.Create()`\n        factory method.\n     -  `NetMQTransport.StartAsync()` enables a `NetMQTransport` instance\n        to receive requests and send replies.\n     -  `NetMQTransport.StopAsync()` only disables a `NetMQTransport` instance\n        to stop receiving requests and sending replies.\n\n[#915]: https://github.com/planetarium/libplanet/issues/915\n[#1538]: https://github.com/planetarium/libplanet/issues/1538\n[#2187]: https://github.com/planetarium/libplanet/issues/2187\n[#2239]: https://github.com/planetarium/libplanet/issues/2239\n[#2200]: https://github.com/planetarium/libplanet/pull/2200\n[#2201]: https://github.com/planetarium/libplanet/pull/2201\n[#2215]: https://github.com/planetarium/libplanet/pull/2215\n[#2216]: https://github.com/planetarium/libplanet/pull/2216\n[#2219]: https://github.com/planetarium/libplanet/pull/2219\n[#2227]: https://github.com/planetarium/libplanet/pull/2227\n[#2228]: https://github.com/planetarium/libplanet/pull/2228\n[#2232]: https://github.com/planetarium/libplanet/pull/2232\n[#2233]: https://github.com/planetarium/libplanet/pull/2233\n[#2241]: https://github.com/planetarium/libplanet/pull/2241\n\n\nVersion 0.40.3\n--------------\n\nReleased on September 29, 2022.\n\n -  (Libplanet.Explorer) Fixed a bug of `TransactionQuery<T>` that\n    `bindSignature()` had errored if `unsignedTransaction` has a system\n    action.  [[#2358]]\n\n[#2358]: https://github.com/planetarium/libplanet/pull/2358\n\n\nVersion 0.40.2\n--------------\n\nReleased on September 23, 2022.\n\n -  Fixed a bug where `Transaction<T>.ToBencodex(bool)` method had incorrectly\n    serialized `SystemAction`.  [[#2339]]\n\n[#2339]: https://github.com/planetarium/libplanet/pull/2339\n\n\nVersion 0.40.1\n--------------\n\nReleased on August 31, 2022.\n\n -  Fixed a bug where `Transaction<T>.Create(long, PrivateKey, BlockHash?,\n    IAction, IImmutableSet<Address>?, DateTimeOffset?)` method had thrown\n    `ArgumentNullException` with valid arguments.  [[#2268]]\n\n[#2268]: https://github.com/planetarium/libplanet/pull/2268\n\n\nVersion 0.40.0\n--------------\n\nReleased on August 12, 2022.\n\n### Deprecated APIs\n\n -  `Transaction<T>(long, Address, PublicKey, BlockHash?,\n    IImmutableSet<Address>, DateTimeOffset, IEnumerable<T>, byte[])` constructor\n    is now deprecated.  Use `Transaction<T>(ITxMetadata, IEnumerable<T>,\n    byte[])` constructor or `Transaction<T>.Create()` static method instead.\n    [[#2175]]\n -  `Transaction<T>.Actions` property is now deprecated.  Use\n    `Transaction<T>.SystemAction` property or `Transaction<T>.CustomActions`\n    property instead.  [[#2149], [#2151], [#2175]]\n -  `IPreEvaluationBlockHeader.HashAlgorithm` property and its implementations\n    removed.  [[#2206], [#2207]]\n -  `IBlockPolicy.GetHashAlgorithm(long)` method and its implementations\n    removed.  [[#2206], [#2207]]\n -  `InvalidBlockHashAlgorithmTypeException` class removed.  [[#2206], [#2207]]\n -  `HashAlgorithmGetter` delegate removed.  [[#2206], [#2207]]\n\n### Backward-incompatible API changes\n\n -  The type of `Transaction<T>.Actions` property became\n    `IImmutableList<IAction>` (was `IImmutableList<T>` where `T : IAction,\n    new()`).  [[#2149], [#2151], [#2175]]\n -  Renamed parameters named `actions` of many methods to `customActions`.\n    [[#2149], [#2151], [#2175]]\n     -  Renamed `Transaction<T>(ITxMetadata, IEnumerable<T>, byte[])`\n        constructor's parameter `actions` to `customActions`.\n     -  Renamed `Transaction<T>(long, Address, PublicKey, BlockHash?,\n        IImmutableSet<Address>, DateTimeOffset, IEnumerable<T>, byte[])`\n        constructor's parameter `actions` to `customActions`.\n     -  Renamed `Transaction<T>.Create(long, PrivateKey, BlockHash?,\n        IEnumerable<T>, IImmutableSet<Address>?, DateTimeOffset?)` static\n        method's parameter `actions` to `customActions`.\n     -  Renamed `Transaction<T>.CreateUnsigned(long, PrivateKey, BlockHash?,\n        IEnumerable<T>, IImmutableSet<Address>?, DateTimeOffset?)` static\n        method's parameter `actions` to `customActions`.\n     -  Renamed `TxMetadata.ToBencodex(IEnumerable<IValue>,\n        IImmutableArray<byte>?)` method's parameter `actions` to\n        `customActions`.\n -  Added `IBlockPolicy<T>.NativeTokens` property.  [[#2149], [#2150], [#2175]]\n -  Added option `IImmutableSet<Currency>? nativeTokens` to `BlockPolicy<T>()`\n    constructor as its last parameter.  [[#2149], [#2150], [#2175]]\n -  Added `IActionContext.IsNativeToken(Currency)` method.\n    [[#2149], [#2150], [#2175]]\n -  Added parameter `Predicate<Currency> nativeTokenPredicate` to\n    all `PreEvaluationBlock<T>.Evaluate()` method as its second parameter\n    (parameter `IStateStore stateStore` remains at the last).\n    [[#2149], [#2150], [#2175]]\n -  Added parameter `Predicate<Currency> nativeTokenPredicate` to\n    all `PreEvaluationBlock<T>.DetermineStateRootHash()` overloads as their\n    second parameter (existing second and rest parameters were shifted).\n    [[#2149], [#2150], [#2175]]\n -  Added parameter `Predicate<Currency> nativeTokenPredicate` to\n    `BlockChain<T>.MakeGenesisBlock()` method as its last parameter.\n    [[#2149], [#2150], [#2175]]\n -  Added parameter `Predicate<Currency> nativeTokenPredicate` to\n    `ActionEvaluator<T>()` constructor as its last parameter.\n    [[#2149], [#2150], [#2175]]\n -  Removed `ChainIdNotFoundException` class.  [[#2047], [#2156]]\n -  Added `IStore.GetCanonicalGenesisBlock(HashAlgorithmGetter)` method.\n    [[#2162], [#2171]]\n -  Parameter `HashAlgorithmType hashAlgorithm` removed from\n    `BlockChain<T>.MakeGenesisBlock()` method.  [[#2206], [#2207]]\n -  Parameter `HashAlgorithmType hashAlgorithm` removed from\n    `BlockContent<T>.Mine()` method.  [[#2206], [#2207]]\n -  Parameter `HashAlgorithmType hashAlgorithm` removed from\n    `PreEvaluationBlock<T>()` constructors.  [[#2206], [#2207]]\n -  Parameter `HashAlgorithmType hashAlgorithm` removed from\n    `PreEvaluationBlockHeader<T>()` constructors.  [[#2206], [#2207]]\n -  Parameter `HashAlgorithmType hashAlgorithm` removed from\n    `BlockMetadata<T>.DerivePreEvaluationHash()` method.  [[#2206], [#2207]]\n -  Parameter `HashAlgorithmType hashAlgorithm` removed from\n    `BlockMetadata<T>.MineNonce()` methods.  [[#2206], [#2207]]\n -  Return type for `BlockMarshaler\n    .UnmarshalPreEvaluationBlockHeader(Dictionary)` changed from\n    `(BlockMetadata, Nonce, ImmutableArray<bytes>?)` to\n    `PreEvaluationBlockHeader`.  Removed overload method\n    `BlockMarshaler\n    .UnmarshalPreEvaluationBlockHeader(HashAlgorithm, Dictionary)`.\n    [[#2206], [#2207]]\n -  Parameter `HashAlgorithmGetter hashAlgorithmGetter` removed from\n    `BlockMarshaler.UnmarshalBlockHeader()` method.  [[#2206], [#2207]]\n -  Parameter `HashAlgorithmGetter hashAlgorithmGetter` removed from\n    `IStore<T>.GetCanonicalGenesisBlock<T>()` and\n    `IStore<T>.GetBlock<T>()` interface methods and their implementations.\n    [[#2206], [#2207]]\n -  Parameter `HashAlgorithmGetter hashAlgorithmGetter` removed from\n    `BlockSet<T>()` constructor.  [[#2206], [#2207]]\n -  Parameter `HashAlgorithmGetter hashAlgorithmGetter` removed from\n    `BlockDigest.GetHeader()` method.  [[#2206], [#2207]]\n -  Parameter `HashAlgorithmGetter hashAlgorithmGetter` removed from\n    `DelayedRenderer<T>()` constructor.  [[#2206], [#2207]]\n -  Parameter `HashAlgorithmGetter hashAlgorithmGetter` removed from\n    `DelayedActionRenderer<T>()` constructor.  [[#2206], [#2207]]\n -  (Libplanet.Node) Parameter `HashAlgorithmGetter hashAlgorithm` removed\n    from `UntypedBlock()` constructor.  [[#2206], [#2207]]\n\n### Added APIs\n\n -  (Libplanet.Explorer) Added `TransactionMutation<T>` class.  [[#2130]]\n -  (Libplanet.Explorer) Added `unsignedTransaction`, `bindSignature` and\n    `transactionResult` GraphQL fields to `TransactionQuery<T>`.  [[#2130]]\n -  Added `Transaction<T>.SystemAction` property.  [[#2149], [#2151], [#2175]]\n -  Added `Transaction<T>.CustomActions` property.  [[#2149], [#2151], [#2175]]\n -  Added overloads to take `systemAction` besides the existing constructors and\n    methods taking `customActions`.  [[#2149], [#2151], [#2175]]\n     -  Added `Transaction<T>(ITxMetadata, IAction, byte[])` overloaded\n        constructor.\n     -  Added `Transaction<T>.Create(long, PrivateKey, BlockHash?, IAction,\n        IImmutableSet<Address>?, DateTimeOffset?)` overloaded static method.\n     -  Added `Transaction<T>.CreateUnsigned(long, PrivateKey, BlockHash?,\n        IAction, IImmutableSet<Address>?, DateTimeOffset?)` overloaded static\n        method.\n     -  Added `TxMetadata.ToBencodex(IValue, ImmutableArray<byte>?)` overloaded\n        method.\n -  Introduced new system built-in actions.  [[#2149], [#2150], [#2175]]\n     -  Added `Mint` class.\n     -  Added `Transfer` class.\n -  Added `NonNativeTokenException` class.  [[#2149], [#2150], [#2175]]\n -  Added `BlockLocator` class.  [[#1762], [#2140]]\n -  Added methods required for decoupling *Libplanet.Net* from\n    *Libplanet*.  [[#1762], [#2140]]\n     -  Added `BlockChain<T>.FindNextHashes(BlockLocator, BlockHash?, int)`\n        method.\n     -  Added `BlockChain<T>.Fork(BlockHash, bool)` method.\n     -  Added `BlockChain<T>.GetBlockLocator(int)` method.\n -  Added `IActionContext.GenesisHash` property.  [[#1972], [#2179]]\n -  Added `ActionEvaluator<T>.GenesisHash` property.  [[#1972], [#2179]]\n -  Added `IAccountStateView` interface.  [[#2183]]\n -  `IAccountStateDelta` now inherits `IAccountStateView` interface.\n    [[#2183]]\n -  Added `BlockMetadata.HashAlgorithmType` static property.  [[#2206], [#2207]]\n -  Added `BlockMarshaler.UnmarshalNonce(Dictionary)` and\n    `BlockMarshaler.UnmarshalPreEvaluationHash(Dictionary)` methods.\n    [[#2206], [#2207]]\n\n### Behavioral changes\n\n -  `BlockChain<T>.PerceiveBlock()` method now uses millisecond precision for\n    perceive time of newly perceived blocks.  [[#2155], [#2159]]\n -  Nonexistent chain ids in `IStore` are now considered to be chain ids of\n    empty chains.  [[#2047], [#2156]]\n -  `Libplanet.Explorer` now targets .NET 6.0.  [[#2173]]\n -  Behavior of `Block<T>.GetHashCode()` changed.  [[#2206], [#2207]]\n\n[#1762]: https://github.com/planetarium/libplanet/issues/1762\n[#1972]: https://github.com/planetarium/libplanet/issues/1972\n[#2047]: https://github.com/planetarium/libplanet/issues/2047\n[#2140]: https://github.com/planetarium/libplanet/pull/2140\n[#2149]: https://github.com/planetarium/libplanet/issues/2149\n[#2150]: https://github.com/planetarium/libplanet/issues/2150\n[#2151]: https://github.com/planetarium/libplanet/issues/2151\n[#2155]: https://github.com/planetarium/libplanet/issues/2155\n[#2156]: https://github.com/planetarium/libplanet/pull/2156\n[#2159]: https://github.com/planetarium/libplanet/pull/2159\n[#2162]: https://github.com/planetarium/libplanet/issues/2162\n[#2171]: https://github.com/planetarium/libplanet/pull/2171\n[#2173]: https://github.com/planetarium/libplanet/pull/2173\n[#2175]: https://github.com/planetarium/libplanet/issues/2175\n[#2179]: https://github.com/planetarium/libplanet/pull/2179\n[#2183]: https://github.com/planetarium/libplanet/pull/2183\n[#2206]: https://github.com/planetarium/libplanet/issues/2206\n[#2207]: https://github.com/planetarium/libplanet/pull/2207\n\n\nVersion 0.39.0\n--------------\n\nReleased on July 18th, 2022.\n\n### Deprecated APIs\n\n -  (Libplanet.Net) Removed `TcpTransport` class.  [[#2139]]\n -  (Libplanet.Net) Removed `InvalidMagicCookieException` class.  [[#2139]]\n -  (Libplanet.Net) Removed `SwarmOptions.TransportType` property.  [[#2139]]\n -  (Libplanet.Node) Removed `InitConfig.TransportType` property.  [[#2139]]\n\n### Added APIs\n\n -  Added `DuplicateActionTypeIdentifierException` class.  [[#2142]]\n\n### Behavioral changes\n\n -  (Libplanet.Net) Raised the default value for `Swarm<T>()` constructor's\n    `workers` parameter to 100.  [[#2128], [#2134]]\n -  (Libplanet.Explorer) Raised the default value for `workers` console\n    argument to 100.  [[#2128], [#2134]]\n -  `PolymorphicAction<T>` now allows subclasses of `T` to be declared in\n    the entry assembly of the application besides the same assembly as `T`.\n    [[#2136], [#2142]]\n -  `PolymorphicAction<T>` now throws `DuplicateActionTypeIdentifierException`\n    when multiple subtypes of `T` are associated with the same\n    `ActionTypeAttribute.TypeIdentifier`.  [[#2142]]\n\n### Bug fixes\n\n -  Fixed a bug where `PrivateKey()` constructor had returned an invalid key\n    less than 32 bytes.  [[#1696], [#2091]]\n -  (Libplanet.Net) Invalid `Uri.UserInfo` with multiple colons is now\n    rejected by `IceServer(Uri url)` constructor and exception is thrown.\n    [[#2058], [#2116]]\n\n### CLI tools\n\n -  (Libplanet.Extensions.Cocona) Upgraded *Cocona.Lite* from 1.6.\\* to\n    [2.0.\\*][Cocona.Lite 2.0.0].  [[#2101]]\n -  Implemented *planet key derive*, now you can get public key and\n    address from private key directly!  [[#2108]]\n -  (Libplanet.Extensions.Cocona) Removed `DerivationCommand` class.\n    [[#2118]]\n\n[#1696]: https://github.com/planetarium/libplanet/issues/1696\n[#2058]: https://github.com/planetarium/libplanet/issues/2058\n[#2091]: https://github.com/planetarium/libplanet/pull/2091\n[#2101]: https://github.com/planetarium/libplanet/pull/2101\n[#2108]: https://github.com/planetarium/libplanet/pull/2108\n[#2116]: https://github.com/planetarium/libplanet/pull/2116\n[#2118]: https://github.com/planetarium/libplanet/pull/2118\n[#2128]: https://github.com/planetarium/libplanet/issues/2128\n[#2130]: https://github.com/planetarium/libplanet/pull/2130\n[#2134]: https://github.com/planetarium/libplanet/pull/2134\n[#2136]: https://github.com/planetarium/libplanet/pull/2136\n[#2139]: https://github.com/planetarium/libplanet/pull/2139\n[#2142]: https://github.com/planetarium/libplanet/pull/2142\n[Cocona.Lite 2.0.0]: https://www.nuget.org/packages/Cocona.Lite/2.0.0\n\n\nVersion 0.38.0\n--------------\n\nReleased on June 7th, 2022.\n\n### Backward-incompatible API changes\n\n -  (Libplanet.Net) Removed `username` and `credential` parameters from\n    `IceServer(string, string?, string?)` and\n    `IceServer(Uri, string?, string?)`.  [[#2048], [#2049]]\n -  (Libplanet.Net) Properties `IceServer.Username` and `IceServer.Credential`\n    are no longer nullable.  [[#2048], [#2049]]\n\n### Added APIs\n\n -  (Libplanet.Node) Added `NetworkConfig` class.  [[#1946], [#2000]]\n -  (Libplanet.Node) Added `NodeConfig` class.  [[#1946], [#2000]]\n -  (Libplanet.Node) Added `NodeUtils` class.  [[#2013]]\n -  (Libplanet.Node) Added `SwarmConfig`, `InitConfig`, `BootstrapConfig`\n    `PreloadConfig`, and `SyncConfig` classes.  [[#2021]]\n\n### Behavioral changes\n\n -  Added `PrivateKey(string)` constructor for hexadecimal string.\n    [[#2012], [#2022]]\n -  Allow `0x` prefix for `Address` class constructor.\n    `DeriveAddress` method will remove `0x` prefix string.\n    [[#2015], [#2018]]\n\n[#1946]: https://github.com/planetarium/libplanet/issues/1946\n[#2000]: https://github.com/planetarium/libplanet/pull/2000\n[#2012]: https://github.com/planetarium/libplanet/issues/2012\n[#2013]: https://github.com/planetarium/libplanet/pull/2013\n[#2015]: https://github.com/planetarium/libplanet/issues/2015\n[#2018]: https://github.com/planetarium/libplanet/pull/2018\n[#2021]: https://github.com/planetarium/libplanet/pull/2021\n[#2022]: https://github.com/planetarium/libplanet/pull/2022\n[#2048]: https://github.com/planetarium/libplanet/issues/2048\n[#2049]: https://github.com/planetarium/libplanet/pull/2049\n\n\nVersion 0.37.0\n--------------\n\nReleased on May 30th, 2022.\n\n### Backward-incompatible API changes\n\n -  (Libplanet.Net) Removed `SwarmOptions.BootstrapDialTimeout`.\n    Use `SwarmOptions.BootstrapOptions.DialTimeout` instead.  [[#2024]]\n -  (Libplanet.Net) Added `Swarm<T>.BootstrapAsync(CancellationToken)`\n    which utilizes values stored in `BootstrapOptions`.  [[#2024]]\n -  (Libplanet.Net) Parameter name `depth` changed to `searchDepth` for\n    `Swarm<T>.BootstrapAsync(IEnumerable<Peer>, TimeSpan?, int,\n    CancellationToken)` and made non-optional.  [[#2024]]\n -  (Libplanet.Net) `Swarm<T>.BootstrapAsync(IEnumerable<Peer>, depth,\n    CancellationToken)` removed.  [[#2024]]\n -  (Libplanet.Net) Removed `SwarmOptions.PreloadDialTimeout`.\n    Use `SwarmOptions.PreloadOptions.DialTimeout` instead.  [[#2025]]\n -  (Libplanet.Net) Added `Swarm<T>.PreloadAsync(IProgress<PreloadState>, bool,\n    CancellationToken)`.  [[#2025]]\n -  (Libplanet.Net) Changed the order of parameters from `Swarm<T>(TimeSpan,\n    IProgress<PreloadState>, bool, long, CancellationToken)` to `Swarm<T>(\n    TimeSpan?, long, IProgress<PreloadState>, bool, CancellationToken)`\n    with default value for `tipDeltaThreshold` removed.  [[#2025]]\n -  (Libplanet.Net) Parameter name `Urls` changed to `Url` for `IceServer`\n    and no longer accepts multiple Urls for single instance.  [[#2026]]\n\n### Added APIs\n\n -  (Libplanet.Net) Added `BootstrapOptions` class.  [[#2024]]\n -  (Libplanet.Net) Added `BootstrapOptions` property to `SwarmOptions`.\n    [[#2024]]\n -  (Libplanet.Net) Added `PreloadOptions` class.  [[#2025]]\n -  (Libplanet.Net) Added `PreloadOptions` property to `SwarmOptions`.\n    [[#2025]]\n\n[#2024]: https://github.com/planetarium/libplanet/pull/2024\n[#2025]: https://github.com/planetarium/libplanet/pull/2025\n[#2026]: https://github.com/planetarium/libplanet/pull/2026\n\n\nVersion 0.36.1\n--------------\n\nReleased on May 26th, 2022.\n\n -  Fixed `Transaction<T>()` constructor's bug that it had thrown\n    `KeyNotFoundException` when a Bencodex dictionary without\n    signature.  [[#2005]]\n\n[#2005]: https://github.com/planetarium/libplanet/pull/2005\n\n\nVersion 0.36.0\n--------------\n\nReleased on May 25th, 2022.\n\n### Backward-incompatible API changes\n\n -  Removed `InvalidTxPublicKeyException` class.  [[#1164], [#1978]]\n -  (Libplanet.Net) Property `SwarmOptions.BlockDownloadTimeout` removed.\n    [[#1981], [#1982]]\n -  (Libplanet.Net) `Swarm<T>.BootstrapAsync(IEnumerable<Peer>, TimeSpan?,\n    TimeSpan?, int, CancellationToken)` changed to `Swarm<T>.BootstrapAsync(\n    IEnumerable<Peer>, TimeSpan?, int, CancellationToken)`.  Parameter\n    `dialTimeout` now gets used for both old `pingSeedTimeout` and\n    `findNeighborsTimeout`.  [[#1990]]\n -  (Libplanet.Net) `IProtocol.BootstrapAsync(IEnumerable<BoundPeer>, TimeSpan?,\n    TimeSpan?, int, CancellationToken)` changed to `IProtocol.BootstrapAsync(\n    IEnumerable<Peer>, TimeSpan?, int, CancellationToken)`.  Parameter\n    `dialTimeout` now gets used for both old `pingSeedTimeout` and\n    `findNeighborsTimeout`.  [[#1990]]\n\n### Added APIs\n\n -  Introduced *Libplanet.Node* package.  [[#1974], [#1978]]\n -  Added `ITxMetadata` interface.  [[#1164], [#1974], [#1978]]\n -  Added `TxMetadata` class.  [[#1164], [#1974], [#1978]]\n -  Added `ITxExcerpt` interface.  [[#1164], [#1974], [#1978]]\n -  Added `TxExcerptExtensions` static class.  [[#1164], [#1974], [#1978]]\n -  `Transaction<T>` now implements `ITxExcerpt` interface.\n    [[#1164], [#1974], [#1978]]\n -  Added `Transaction<T>(ITxMetadata, IEnumerable<T>, byte[])` constructor.\n    [[#1164], [#1978]]\n -  Added `TxId.FromString()` static method.  [[#1978]]\n -  (Libplanet.Node) Added `UntypedTransaction` class.  [[#1974], [#1978]]\n -  (Libplanet.Node) Added `UntypedBlock` class.  [[#1974], [#1978]]\n\n### Behavioral changes\n\n -  `Transaction<T>(long, Address, PublicKey, BlockHash?,\n    IImmutableSet<Address>, DateTimeOffset, IEnumerable<T>, byte[])` constructor\n    became to ignore its second parameter `Address signer`.  Instead,\n    `Transaction<T>.Signer` property is now automatically derived from its\n    `PublicKey`.  [[#1164], [#1978]]\n\n### Bug fixes\n\n -  Fixed `InvalidOperationException` thrown by `PublicKey.Verify()` method\n    if `signature` is a `default(ImmutableArray<byte>)`.  Instead, it silently\n    returns `false` now.  [[#1978]]\n -  Fixed `NullReferenceException` thrown by `ByteUtil.Hex(in\n    ImmutabelArray<byte>)` method if a `default(ImmutableArray<byte>)` is\n    present.  Instead, it silently returns an empty string now.  [[#1978]]\n -  Fixed a `TxId(byte[])` constructor's bug where `ParamName` and `Message` of\n    `ArgumentOutOfRangeException` it had thrown had been reversed.  [[#1978]]\n\n[#1974]: https://github.com/planetarium/libplanet/issues/1974\n[#1978]: https://github.com/planetarium/libplanet/pull/1978\n[#1981]: https://github.com/planetarium/libplanet/issues/1981\n[#1982]: https://github.com/planetarium/libplanet/pull/1982\n[#1990]: https://github.com/planetarium/libplanet/pull/1990\n\n\nVersion 0.35.1\n--------------\n\nReleased on May 23rd, 2022.\n\n### Bug fixes\n\n -  (Libplanet.Net) Wrongly assigned default value to\n    `TimeoutOptions.PreloadDialTimeout` fixed.  [[#1983]]\n\n[#1983]: https://github.com/planetarium/libplanet/pull/1983\n\n\nVersion 0.35.0\n--------------\n\nReleased on May 20th, 2022.\n\n### Deprecated APIs\n\n -  (Libplanet.Net) Unused property `SwarmOptions.PollInterval` removed.\n    [[#1962]]\n\n### Backward-incompatible API changes\n\n -  `BlockCompletion<TPeer, TAction>.Complete()` no longer accepts\n    neither parameter `TimeSpan singleSessionTimeout` nor\n    `int millisecondsSingleSessionTimeout` to regulate a single session length.\n    [[#1961]]\n -  (Libplanet.Net) General API changes made to `Swarm<T>.BootstrapAsync()`,\n    `Swarm<T>.PreloadAsync()`, and `Swarm<T>.StartAsync()`.  [[#1962]]\n     -  `Swarm<T>.BootstrapAsync(IEnumerable<Peer>, double, double,\n        int, CancellationToken)` replaced with\n        `Swarm<T>.BootstrapAsync(IEnumerable<Peer>, int, CancellationToken)`\n        which uses default values provided by `SwarmOptions` for\n        `pingSeedTimeout` and `findPeerTimeout`.\n     -  `Swarm<T>.StartAsync(int, int, int CancellationToken)`\n        replaced with `Swarm<T>.StartAsync(CancellationToken)`\n        which uses default values provided by `SwarmOptions` for\n        `millisecondsDialTimeout`, `millisecondsBroadcastBlockInterval`\n        and `millisecondsBroadcastTxInterval`.\n     -  `Swarm<T>.PreloadAsync(IProgress<PreloadState>,\n        bool, long, CancellationToken)` overload method added and\n        `Swarm<T>.PreloadAsync(TimeSpan?, IProgress<PreloadState>, bool\n        long, CancellationToken)` changed to `Swarm<T>.PreloadAsync(\n        TimeSpan, IProgress<PreloadState>, bool, long, CancellationToken)`\n -  (Libplanet.Net) `TimeoutOptions` property added to `SwarmOptions` with\n    all timeout related options moved from `SwarmOptions` to `TimeoutOptions`.\n    [[#1957], [#1962]]\n\n### Added APIs\n\n -  Added `StoreLoader` delegate.  [[#1359], [#1953], [#1955]]\n -  Added `StoreLoaderAttribute` class.  [[#1359], [#1953], [#1955]]\n -  Added `TrieStateStore.Secure` property.  [[#1955]]\n -  Added `NameValueCollectionExtensions` static class.  [[#1955]]\n -  Type support for `Guid` added to `DataModel`.  [[#1959], [#1960]]\n -  `TimeoutOptions` class added.  [[#1957], [#1962]]\n -  `SwarmOptions.BlockBroadcastInterval` and `SwarmOptions.TxBroadcastInterval`\n    properties added.  [[#1962]]\n -  `TimeSpanExtensions.Multiply()` method added.  [[#1966]]\n\n### Behavioral changes\n\n -  `DefaultStore` and `DefaultKeyValueStore`-backed `TrieStateStore` now can be\n    instantiated with URI scheme `default+file:` using\n    `StoreLoaderAttribute.LoadStore()` method.  [[#1359], [#1953], [#1955]]\n -  `MemoryStore` and `MemoryKeyValueStore`-backed `TrieStateStore` now can be\n    instantiated with URI scheme `memory:` using\n    `StoreLoaderAttribute.LoadStore()` method.  [[#1359], [#1953], [#1955]]\n -  (Libplanet.RocksDBStore) `RocksDBStore` and `RocksDBKeyValueStore`-backed\n    `TrieStateStore` now can be instantiated with URI scheme `rocksdb+file:`\n    using `StoreLoaderAttribute.LoadStore()` method.\n    [[#1359], [#1953], [#1955]]\n\n### CLI tools\n\n -  The following store URI schemes are deprecated:  [[#1573], [#1955]]\n     - `default`: Use `default+file` instead.\n     - `rocksdb`: Use `rocksdb+file` instead.\n\n[#1359]: https://github.com/planetarium/libplanet/issues/1359\n[#1573]: https://github.com/planetarium/libplanet/issues/1573\n[#1953]: https://github.com/planetarium/libplanet/issues/1953\n[#1955]: https://github.com/planetarium/libplanet/pull/1955\n[#1957]: https://github.com/planetarium/libplanet/issues/1957\n[#1959]: https://github.com/planetarium/libplanet/issues/1959\n[#1960]: https://github.com/planetarium/libplanet/pull/1960\n[#1961]: https://github.com/planetarium/libplanet/pull/1961\n[#1962]: https://github.com/planetarium/libplanet/pull/1962\n[#1966]: https://github.com/planetarium/libplanet/pull/1966\n\n\nVersion 0.34.0\n--------------\n\nReleased on May 13th, 2022.\n\n### Added APIs\n\n -  Class `DataModel` added.  When inherited, this class assists in automatic\n    encoding and decoding to and from `Bencodex.Types.Dictionary`.\n    [[#1932], [#1935]]\n\n### Behavioral changes\n\n -  `TxPolicyViolationException` and `InvalidTxException` now have a new\n    constructor that takes an `Exception` as their `Exception.InnerException`.\n    [[#1830], [#1912], [#1916]]\n\n### CLI tools\n\n -  Added `planet key sign` to sign a message.  [[#1920]]\n\n[#1830]: https://github.com/planetarium/libplanet/issues/1830\n[#1912]: https://github.com/planetarium/libplanet/pull/1912\n[#1916]: https://github.com/planetarium/libplanet/pull/1916\n[#1920]: https://github.com/planetarium/libplanet/pull/1920\n[#1932]: https://github.com/planetarium/libplanet/issues/1932\n[#1935]: https://github.com/planetarium/libplanet/pull/1935\n\n\nVersion 0.33.1\n--------------\n\nReleased on April 28th, 2022.\n\n### Behavioral changes\n\n -  `Transaction<T>`'s relatively heavy policy validation is deferred until\n    after its nonce validation in order to speed up gathering `Transaction<T>`s\n    when mining.  [[#1924]]\n\n[#1924]: https://github.com/planetarium/libplanet/pull/1924\n\n\nVersion 0.33.0\n--------------\n\nReleased on April 19th, 2022.\n\n### Backward-incompatible API changes\n\n -  (Libplanet.Net) `IMessageCodec` and its implementations `NetMQMessageCodec`\n    and `TcpMessageCodec` overhauled.  [[#1906]]\n     -  `AppProtocolVersion` type parameter added to `IMessageCodec.Encode()`.\n     -  Both `NetMQMessageCodec()` and `TcpMessageCodec()` constructors are\n        made parameterless.\n     -  `IMessageCodec.Decode()` no longer throws\n        `InvalidMessageTimestampException` or\n        `DifferentAppProtocolVersionException`.\n -  (Libplanet.Net) Irrelevant context related properties removed from\n    `InvalidMessageTimestampException` and\n    `DifferentAppProtocolVersionException`.  [[#1906]]\n     -  `InvalidMessageTimestampException.Peer` property removed.\n     -  `DifferentAppProtocolVersionException.Peer` property removed.\n     -  `DifferentAppProtocolVersionException.Identity` property removed.\n -  (Libplanet.Net) Both `MessageValidator.ValidateTimestamp()` and\n    `MessageValidator.ValidateAppProtocolVersion()` now only accepts single\n    `Message` type parameter.  [[#1906]]\n -  (Libplanet.Net) `SendMessageFailedException` changed to\n    `SendMessageFailException`.  [[#1911]]\n -  (Libplanet.Net) `ITransport` exception handling overhauled.  [[#1911]]\n     -  `ITransport.SendMessageAsync()` now only throws\n        `CommunicationFailException` for a normal failure of sending and\n        receiving `Message`s; old exceptions such as `TimeoutException`,\n        `InvalidMessageSignatureException`, etc. are attached to\n        `InnerException` property to a thrown `CommunicationFailException`.\n     -  `InvalidCredentialException`, `InvalidMagicCookieException`,\n        `InvalidMessageSignatureException`, `SendMessageFailException` no longer\n        have public constructors.\n\n### Added APIs\n\n -  (Libplanet.Net) `InvalidCredentialException` class added.\n    [[#1904], [#1905]]\n -  (Libplanet.Net) `CommunicationFailException` class added.  [[#1911]]\n\n### Behavioral changes\n\n -  Inner logic of `ByteUtil.CalculateHashCode(byte[] bytes)` has modified.\n    [[#1866], [#1891]]\n -  (Libplanet.Net) `IMessageCodec.Encode()` now requires a *matching*\n    `PrivateKey` to be provided for `Peer`.  [[#1904], [#1905]]\n\n### Dependencies\n\n -  No longer depends on *Fody*.  [[#1866], [#1891]]\n -  No longer depends on *Equals.Fody*.  [[#1866], [#1891]]\n\n[#1866]: https://github.com/planetarium/libplanet/issues/1866\n[#1891]: https://github.com/planetarium/libplanet/pull/1891\n[#1904]: https://github.com/planetarium/libplanet/issues/1904\n[#1905]: https://github.com/planetarium/libplanet/pull/1905\n[#1906]: https://github.com/planetarium/libplanet/pull/1906\n[#1911]: https://github.com/planetarium/libplanet/pull/1911\n\n\nVersion 0.32.1\n--------------\n\nReleased on April 8th, 2022.\n\n### Behavioral changes\n\n -  (Libplanet.Net) `ITransport`'s behavior rolled back to send replies\n    with `DifferentVersion` type `Message` to a `Peer` with a different\n    `AppProtocolVersion` regardless of whether the `APV` from `Peer` is\n    signed by a trusted source or not.  [[#1900]]\n\n[#1900]: https://github.com/planetarium/libplanet/pull/1900\n\n\nVersion 0.32.0\n--------------\n\nReleased on April 8th, 2022.\n\n### Backward-incompatible API changes\n\n -  Added `IStore.PruneOutdatedChains(bool noopWithoutCanon)` method.\n    [[#1874], [#1878]]\n -  `IMessageCodec` interface and its implementations overhauled.  [[#1890]]\n     -  Removed `AppProtocolVersion version` parameter from\n        `IMessageCodec.Encode()`.\n     -  Removed `Action appProtocolVersionValidator` parameter from\n        `IMessageCodec.Decode()`.\n     -  Both `TcpMessageCodec()` and `NetMQMessageCodec()` now takes\n        additional parameters for setting up its `MessageValidator` instance\n        for running context.\n -  `DifferentAppProtocolVersionEncountered` delegate now returns `void`.\n    [[#1885], [#1890]]\n\n### Added APIs\n\n -  (Libplanet.Net) `DifferentAppProtocolVersionException` is made `public`.\n    [[#1889]]\n -  (Libplanet.Net) `InvalidMessageSignatureException` and\n    `InvalidMessageTimestampException` gained additional properties.\n    [[#1889]]\n -  (Libplanet.Net) `MessageValidator` helper class introduced.  [[#1890]]\n\n### Behavioral changes\n\n -  (Libplanet.Net) Internal cache size of a `KBucket` is now capped.\n    [[#1879]]\n -  (Libplanet.Net) `IMessageCodec` now never decodes a `Message` with\n    a different `AppProtocolVersion` from the local version.  [[#1885], [#1890]]\n -  (Libplanet.Net) `ITransport` no longer replies with `DifferentVersion` type\n    `Message` to a `Peer` with a different `AppProtocolVersion` that is not\n    signed by a trusted source.  [[#1890]]\n\n### Bug fixes\n\n -  (Libplanet.Net) Internal dictionaries of a `KBucket` are made to be\n    concurrent.  [[#1872], [#1879]]\n -  (Libplanet.Net) `DifferentAppProtocolVersionException` and\n    `InvalidMessageSignatureException` can now be serialized and deserialized.\n    [[#1889]]\n\n[#1872]: https://github.com/planetarium/libplanet/issues/1872\n[#1874]: https://github.com/planetarium/libplanet/issues/1874\n[#1878]: https://github.com/planetarium/libplanet/pull/1878\n[#1879]: https://github.com/planetarium/libplanet/pull/1879\n[#1885]: https://github.com/planetarium/libplanet/issues/1885\n[#1889]: https://github.com/planetarium/libplanet/pull/1889\n[#1890]: https://github.com/planetarium/libplanet/pull/1890\n\n\nVersion 0.31.0\n--------------\n\nReleased on March 31, 2022.\n\n### Backward-incompatible API changes\n\n -  (Libplanet.Net) Existing method name `Kademlia.CalculateDistance()`\n    changed to `Kademlia.CalculateDifference()` to better indicate its behavior.\n    [[#1877]]\n -  (Libplanet.Net) `Kademlia.CalculateDistance()` method reimplemented with\n    return type `int`.  [[#1877]]\n\n### Bug fixes\n\n -  (Libplanet.Stun) Increased the number of internal proxies to increase\n    the inbound network traffic throughput of a node when using a `TurnClient`.\n    [[#1864], [#1876]]\n\n[#1864]: https://github.com/planetarium/libplanet/issues/1864\n[#1876]: https://github.com/planetarium/libplanet/pull/1876\n[#1877]: https://github.com/planetarium/libplanet/pull/1877\n\n\nVersion 0.30.0\n--------------\n\nReleased on March 24, 2022.\n\n### Backward-incompatible storage format changes\n\n -  (Libplanet.RocksDBStore) `RocksDBStore` became not to use [column families]\n    to manage chain ids.  Instead, chain id is concatenated into key prefix.\n    [[#1862]]\n\n### CLI tools\n\n  - Added `planet store migrate-index` for index database migration\n    (from column families based to key-prefix).  [[#1862]]\n\n[#1862]: https://github.com/planetarium/libplanet/pull/1862\n[column families]: https://github.com/facebook/rocksdb/wiki/Column-Families\n\n\nVersion 0.29.0\n--------------\n\nReleased on March 17, 2022.\n\n### Backward-incompatible API changes\n\n -  (Libplanet.Net) `SwarmOptions.MessageLifespan` property changed to\n    `SwarmOptions.MessageTimestampBuffer`.  [[#1828], [#1831]]\n -  (Libplanet.Net) Unused parameter `dealerSocketLifetime` removed from\n    `NetMQTransport()`.  [[#1832]]\n -  (Libplanet.Net) Old `ITransport.SendMessageAsync()` method is deprecated.\n    `ITransport.SendMessageWithReplyAsync()` methods are renamed as\n    `ITransport.SendMessageAsync()`.  [[#1849]]\n\n### Behavioral changes\n\n -  (Libplanet.Net) Default value of `SwarmOptions.MessageTimestampBuffer` is\n    set to 60 seconds instead of `null`.  [[#1828], [#1831]]\n -  (Libplanet.Net) Acceptable timestamp range for `Message`s, when non-null\n    `SwarmOptions.MessageTimestampBuffer` is provided, has changed to allow\n    `Message`s with future timestamps.\n    [[#1828], [#1831]]\n -  (Libplanet.Net) `Swarm<T>` now replies `Pong`s to received `TxIds`\n    and `BlockHeaderMessage` messages.  [[#1845]]\n\n[#1828]: https://github.com/planetarium/libplanet/issues/1828\n[#1831]: https://github.com/planetarium/libplanet/pull/1831\n[#1832]: https://github.com/planetarium/libplanet/pull/1832\n[#1845]: https://github.com/planetarium/libplanet/pull/1845\n[#1849]: https://github.com/planetarium/libplanet/pull/1849\n\n\nVersion 0.28.2\n--------------\n\nReleased on March 15, 2022.\n\n -  (Libplanet.RocksDBStore) `RocksDBStore.GetBlockDigest()` became to silently\n    return `null` with no misleading error log when it's asked a non-existent\n    block hash.  [[#1500], [#1852]]\n\n[#1852]: https://github.com/planetarium/libplanet/pull/1852\n\n\nVersion 0.28.1\n--------------\n\nReleased on March 3, 2022.\n\n -  Fixed an evaluation log to output `IPreEvaluationBlock<T>.PreEvaluationHash`\n    as a hex formatted string.  [[#1835], [#1837]]\n -  (Libplanet.Net) Fixed a bug where some messages could not be sent using\n    `NetMQTransport` due to premature `DealerSocket` disposal.\n    [[#1836], [#1839]]\n\n[#1835]: https://github.com/planetarium/libplanet/issues/1835\n[#1836]: https://github.com/planetarium/libplanet/issues/1836\n[#1837]: https://github.com/planetarium/libplanet/pull/1837\n[#1839]: https://github.com/planetarium/libplanet/pull/1839\n\n\nVersion 0.28.0\n--------------\n\nReleased on February 23, 2022.\n\n### Deprecated APIs\n\n### Backward-incompatible API changes\n\n -  The return type of `MerkleTrieExtensions.DifferentNodes()` became\n    `IEnumerable<Tuple<KeyBytes, IValue, IValue>>` from\n    `IEnumerable<IGrouping<string, (HashDigest<SHA256> Root, IValue Value)>>`.\n    [[#1729]]\n -  (Libplanet.Extensions.Cocona) Replaced `string? passphrase = null` parameter\n    of methods belonging `KeyCommand` and `ApvCommand` with\n    `PassphraseParameters passphrase`.  [[#1593], [#1823]]\n -  (Libplanet.Extensions.Cocona) Replaced `KeyCommand.UnprotectKey(Guid keyId,\n    string? passphrase = null)` method with `UnprotectedKey(Guid,\n    PassphraseParameters, bool)` method.  [[#1593], [#1823]]\n -  (Libplanet.Net) `IMessageCodec<T>.Decode()` now throws\n    `InvalidMessageSignatureException` and `InvalidMessageTimestampException`\n    instead of `InvalidMessageException` and `InvalidTimestampException`\n    respectively.  [[#1771]]\n -  (Libplanet.Net) Added `long tipDeltaThreshold = 25L` option to\n    `Swarm<T>.PreloadAsync()` method.  [[#1775], [#1777], [#1779]]\n\n### Backward-incompatible network protocol changes\n\n -  The `Block<T>.CurrentProtocolVersion` is bumped from 2 to 3.\n    [[#1322], [#1323], [#1518]]\n\n### Backward-incompatible storage format changes\n\n### Added APIs\n\n -  (Libplanet.Extensions.Cocona) Added `PassphraseParameters` class.\n    [[#1593], [#1823]]\n -  (Libplanet.Extensions.Cocona) Added `KeyCommand.UnprotectKey(Guid keyId,\n    PassphraseParameters passphrase, bool ignoreStdin = false)` method.\n    [[#1593], [#1823]]\n -  (Libplanet.Net) Added `MessageSendFailedException` class.\n    [[#1781], [#1786]]\n\n### Behavioral changes\n\n -  `Block<T>.Transactions` is ordered using a different scheme for\n    evaluation due to protocol version bump.  [[#1322], [#1323], [#1518]]\n -  (Libplanet.Net) `NetMQTransport.SendMessageWithReplyAsync()` should now\n    complete its process within given timeframe `timeout` argument instead\n    of possibly taking longer on some edge cases when waiting for\n    multiple replies.  [[#1734], [#1789]]\n -  `ActionEvaluator<T>.Evaluate()` method became to log message directly\n    instead of other methods that use it.  [[#1773]]\n -  (Libplanet.Net) `NetMQTransport.DoBroadcast` now uses\n    `NetMQTransport.SendMessageAsync()` internally instead of\n    using `NetMQ` directly.  [[#1722], [#1824]]\n\n### Bug fixes\n\n -  (Libplanet.Net) Fixed a leak in handling `DealerSocket`s inside\n    `NetMQTransport.DoBroadcast()` method.  [[#1819], [#1825]]\n\n### Dependencies\n\n -  (Libplanet.Extensions.Cocona) Upgraded *Cocona.Lite* from 1.5.\\* to\n    [1.6.\\*][Cocona.Lite 1.6.0].  [[#1593], [#1823]]\n\n### CLI tools\n\n -  All `planet` subcommands taking passphrase now have `--passphrase-file`\n    option besides `-p`/`--passphrase` option to read it from the specified\n    file or standard input (`-`) instead.  [[#1593], [#1823]]\n -  Fixed a bug where `planet` subcommands taking passphrase had unexpectedly\n    terminated with an uncaught `InvalidOperationException` when it's not\n    associated to any terminal device (tty), i.e., piped.  [[#1593], [#1823]]\n -  `planet mpt diff` command became to output the key and its values\n    in one line as JSON whenever a different key is found,\n    than it outputs all of the different nodes at once.  [[#1729]]\n\n[#1322]: https://github.com/planetarium/libplanet/issues/1322\n[#1323]: https://github.com/planetarium/libplanet/issues/1323\n[#1518]: https://github.com/planetarium/libplanet/pull/1518\n[#1593]: https://github.com/planetarium/libplanet/pull/1593\n[#1722]: https://github.com/planetarium/libplanet/issues/1722\n[#1729]: https://github.com/planetarium/libplanet/pull/1729\n[#1734]: https://github.com/planetarium/libplanet/issues/1734\n[#1771]: https://github.com/planetarium/libplanet/pull/1771\n[#1773]: https://github.com/planetarium/libplanet/pull/1773\n[#1779]: https://github.com/planetarium/libplanet/pull/1779\n[#1781]: https://github.com/planetarium/libplanet/issues/1781\n[#1786]: https://github.com/planetarium/libplanet/pull/1786\n[#1789]: https://github.com/planetarium/libplanet/pull/1789\n[#1819]: https://github.com/planetarium/libplanet/issues/1819\n[#1823]: https://github.com/planetarium/libplanet/pull/1823\n[#1824]: https://github.com/planetarium/libplanet/pull/1824\n[#1825]: https://github.com/planetarium/libplanet/pull/1825\n[Cocona.Lite 1.6.0]: https://www.nuget.org/packages/Cocona.Lite/1.6.0\n\n\nVersion 0.27.7\n--------------\n\nReleased on February 18, 2022.\n\n -  Fixed `HashDigest<T>.DeriveFrom(ReadOnlySpan<byte>)` method's bug where\n    it had thrown `IndexOutOfRangeException` for the input longer or shorter\n    than `HashDigest<T>.Size` on .NET Standard 2.0.  [[#1706], [#1815]]\n -  Fixed `HashDigest<T>.DeriveFrom(ReadOnlySpan<byte>)` method's bug where\n    it had returned the wrong digest on .NET Standard 2.0.  [[#1706], [#1815]]\n\n\nVersion 0.27.6\n--------------\n\nReleased on February 18, 2022.\n\n -  (Libplanet.Net) Fixed a bug where `Swarm<T>.PreloadAsync()`\n    had not thrown `OperationCanceledException` even cancellation\n    was requested.  [[#1547], [#1796]]\n -  Fixed `ThreadStateException` thrown by `NonblockRenderer<T>` and\n    `NonblockActionRenderer<T>` classes.  [[#1772], [#1810]]\n\n\nVersion 0.27.5\n--------------\n\nReleased on February 16, 2022.\n\n -  Upgraded *Planetarium.RocksDbSharp* from 6.2.4-planetarium to\n    [6.2.6-planetarium][Planetarium.RocksDbSharp 6.2.6-planetarium].\n    [[#1791], [#1803]]\n -  (Libplanet.Net) Additional logs tagged `Metric` to monitor `ITransport`\n    behavior.  [[#1802]]\n\n\nVersion 0.27.4\n--------------\n\nReleased on February 16, 2022.\n\n -  Fixed *@planetarium/cli* npm package's bug where installation had not\n    worked since 0.27.0.  [[#1790], [#1799]]\n -  (Libplanet.Net) Return the fixed races between `Swarm<T>`'s dual systems\n    for block synchronization (polling and event-driven in parallel)\n    on updating chain by serializing the post-download process\n    which is common for both synchronization mechanisms.  [[#1731], [#1798]]\n\n\n[#1790]: https://github.com/planetarium/libplanet/issues/1790\n[#1798]: https://github.com/planetarium/libplanet/pull/1798\n[#1799]: https://github.com/planetarium/libplanet/pull/1799\n\n\nVersion 0.27.3\n--------------\n\nReleased on February 11, 2022.\n\n -  (Libplanet.Net) `Swarm<T>.CompleteBlockSync()` changed back,\n    reverting the behavior implemented in [#1759]\n    to fixed races between `Swarm<T>`'s dual systems for block\n    synchronization (polling and event-driven in parallel)\n    on updating chain  [[#1797]]\n\n[#1797]: https://github.com/planetarium/libplanet/pull/1797\n\n\nVersion 0.27.2\n--------------\n\nReleased on February 8, 2022.\n\n -  (Libplanet.Net) Sending a `Message` through `NetMQTransport` now fails\n    immediately if the `Message` cannot be queued to a `DealerSocket`\n    right away.  [[#1753], [#1778]]\n\n[#1753]: https://github.com/planetarium/libplanet/issues/1753\n[#1778]: https://github.com/planetarium/libplanet/pull/1778\n\n\nVersion 0.27.1\n--------------\n\nReleased on February 7, 2022.\n\n -  (Libplanet.Net) `Swarm<T>.PreloadAsync()` method became to catch up recent\n    blocks until the local tip is close enough to the topmost tip among peers.\n    [[#1775], [#1777]]\n\n[#1777]: https://github.com/planetarium/libplanet/pull/1777\n\n\nVersion 0.27.0\n--------------\n\nReleased on January 26, 2022.\n\n### Deprecated APIs\n\n -  Added `EnumerableMeasurement` static class.  [[#1764], [#1766]]\n\n### Backward-incompatible API changes\n\n -  Moved everything in `Libplanet.Net` namespace from *Libplanet* assembly\n    to *Libplanet.Net* assembly.  [[#1421], [#1760]]\n -  (Libplanet.Net) Parameters of `NetMQTransport()` constructor has modified.\n    [[#1741], [#1744]]\n     -  Removed `RoutingTable table` and `int minimumBroadcastTarget`\n        parameters.\n     -  Added `TimeSpan? dealerSocketLifetime` parameter.\n -  (Libplanet.Net) Removed `RoutingTable table` and\n    `int minimumBroadcastTarget` parameters from `TcpTransport()` constructor.\n    [[#1741], [#1744]]\n -  (Libplanet.Net) Removed `ITransport.BroadcastMessage(Address?, Message)`\n    method.  Instead, added\n    `ITransport.BroadcastMessage(IEnumerable<BoundPeer>, Message)` method.\n    [[#1741], [#1744]]\n\n### Added APIs\n\n -  Added `TrieStateStore.CopyStates()` method.  [[#1653], [#1691]]\n -  Added `NullBlockPolicy<T>` class.  [[#1531], [#1748]]\n -  (Libplanet.Net) Added classes which implements `Message` abstract class.\n    [[#1754], [#1756]]\n     -  Added `Ping` class.\n     -  Added `Pong` class.\n     -  Added `FindNeighbors` class.\n     -  Added `Neighbors` class.\n     -  Added `DifferentVersion` class.\n\n### Behavioral changes\n\n -  `MerkleTrie.Get()` method now finds multiple states in parallel.  [[#1743]]\n -  (Libplanet.Net) `DealerSocket`s used for broadcasting messages in\n    `NetMQTransport` became not to be disposed right after corresponding peer\n    is removed from the routing table.  Instead, it will be removed after\n    a certain amount of time.  [[#1741], [#1744]]\n -  (Libplanet.Net) `NetMQTransport` no longer attempts to retry failed\n    communications.  [[#1751], [#1752]]\n -  (Libplanet.Net) Fixed races between `Swarm<T>`'s dual systems for block\n    synchronization (polling and event-driven in parallel) on updating chain by\n    serializing the post-download process which is common for both\n    synchronization mechanisms.  [[#1731], [#1759]]\n -  New log output tagged with `Metric` added to measure evaluation time for\n    individual `Transaction<T>`s.  [[#1755], [#1758]]\n\n### Dependencies\n\n -  *Libplanet.Net* assembly is now distributed as a separate NuGet package:\n    *[Libplanet.Net]*.  [[#1421], [#1760]]\n\n### CLI tools\n\n -  Upgrade *node-fetch* for *@planetarium/cli* npm package.\n    [[CVE-2022-0235], [#1747]]\n\n[#1421]: https://github.com/planetarium/libplanet/issues/1421\n[#1531]: https://github.com/planetarium/libplanet/issues/1531\n[#1691]: https://github.com/planetarium/libplanet/pull/1691\n[#1731]: https://github.com/planetarium/libplanet/issues/1731\n[#1741]: https://github.com/planetarium/libplanet/issues/1741\n[#1743]: https://github.com/planetarium/libplanet/pull/1743\n[#1744]: https://github.com/planetarium/libplanet/pull/1744\n[#1747]: https://github.com/planetarium/libplanet/pull/1747\n[#1748]: https://github.com/planetarium/libplanet/pull/1748\n[#1751]: https://github.com/planetarium/libplanet/issues/1751\n[#1752]: https://github.com/planetarium/libplanet/pull/1752\n[#1754]: https://github.com/planetarium/libplanet/issues/1754\n[#1755]: https://github.com/planetarium/libplanet/issues/1755\n[#1756]: https://github.com/planetarium/libplanet/pull/1756\n[#1758]: https://github.com/planetarium/libplanet/pull/1758\n[#1759]: https://github.com/planetarium/libplanet/pull/1759\n[#1760]: https://github.com/planetarium/libplanet/pull/1760\n[#1766]: https://github.com/planetarium/libplanet/pull/1766\n[CVE-2022-0235]: https://github.com/advisories/GHSA-r683-j2x4-v87g\n[Libplanet.Net]: https://www.nuget.org/packages/Libplanet.Net/\n\n\nVersion 0.26.6\n--------------\n\nReleased on February 18, 2022.\n\n -  Fixed `HashDigest<T>.DeriveFrom(ReadOnlySpan<byte>)` method's bug where\n    it had thrown `IndexOutOfRangeException` for the input longer or shorter\n    than `HashDigest<T>.Size` on .NET Standard 2.0.  [[#1706], [#1815]]\n -  Fixed `HashDigest<T>.DeriveFrom(ReadOnlySpan<byte>)` method's bug where\n    it had returned the wrong digest on .NET Standard 2.0.  [[#1706], [#1815]]\n\n\nVersion 0.26.5\n--------------\n\nReleased on February 18, 2022.\n\n -  Fixed a bug where `Swarm<T>.PreloadAsync()`\n    had not thrown `OperationCanceledException` even cancellation\n    was requested.  [[#1547], [#1796]]\n -  Fixed `ThreadStateException` thrown by `NonblockRenderer<T>` and\n    `NonblockActionRenderer<T>` classes.  [[#1772], [#1810]]\n\n[#1547]: https://github.com/planetarium/libplanet/issues/1547\n[#1772]: https://github.com/planetarium/libplanet/issues/1772\n[#1796]: https://github.com/planetarium/libplanet/pull/1796\n[#1810]: https://github.com/planetarium/libplanet/pull/1810\n\n\nVersion 0.26.4\n--------------\n\nReleased on February 16, 2022.\n\n -  Upgraded *Planetarium.RocksDbSharp* from 6.2.4-planetarium to\n    [6.2.6-planetarium][Planetarium.RocksDbSharp 6.2.6-planetarium].\n    [[#1791], [#1803]]\n -  Additional logs tagged `Metric` to monitor `ITransport` behavior.  [[#1802]]\n\n[#1791]: https://github.com/planetarium/libplanet/pull/1791\n[#1802]: https://github.com/planetarium/libplanet/pull/1802\n[#1803]: https://github.com/planetarium/libplanet/pull/1803\n[Planetarium.RocksDbSharp 6.2.6-planetarium]: https://www.nuget.org/packages/Planetarium.RocksDbSharp/6.2.6-planetarium\n\n\nVersion 0.26.3\n--------------\n\nReleased on February 7, 2022.\n\n -  `Swarm<T>.PreloadAsync()` method became to catch up recent blocks\n    until the local tip is close enough to the topmost tip among peers.\n    [[#1775]]\n\n[#1775]: https://github.com/planetarium/libplanet/pull/1775\n\n\nVersion 0.26.2\n--------------\n\nReleased on January 26, 2022.\n\n -  Fixed a bug where `ActionEvaluator<T>`'s logs had been ignored due to\n    its initialization timings.  [[#1764]]\n -  The elapsed time taking for ordering `Transaction<T>`s before evaluating\n    them are now measured and logged.  [[#1764]]\n -  The time started and finished to calculate state root hashes are now\n    logged.  [[#1764]]\n\n[#1764]: https://github.com/planetarium/libplanet/pull/1764\n\n\nVersion 0.26.1\n--------------\n\nReleased on January 20, 2022.\n\n -  General logging overhaul in `NetMQTransport<T>` for consistency and\n    readability.  [[#1735]]\n\n[#1735]: https://github.com/planetarium/libplanet/pull/1735\n\n\nVersion 0.26.0\n--------------\n\nReleased on January 18, 2022.\n\n### Backward-incompatible API changes\n\n -  Replaced `IValue StateCompleter<T>(BlockChain<T>, BlockHash, Address)`\n    delegate with `IReadOnlyList<IValue?> StateCompleter<T>(BlockChain<T>,\n    BlockHash, IReadOnlyList<Address>)` delegate.  [[#1703]]\n -  Added `IAccountStateDelta.GetStates(IReadOnlyList<Address>)` method.\n    [[#1703]]\n -  Replaced `IValue AccountStateGetter(Address)` delegate with\n    `IReadOnlyList<IValue?> AccountStateGetter(IReadOnlyList<Address>)`\n    delegate.  [[#1703]]\n -  Removed `StateGetter<T>` delegate.  [[#1703]]\n -  Removed `BalanceGetter<T>` delegate.  [[#1703]]\n -  Removed `StateGetter<T> stateGetter` and `BalanceGetter<T> balanceGetter`\n    parameters from `ActionEvaluator<T>()` constructor.  [[#1703]]\n -  Added `IBlockChainStates<T> blockChainStates` parameter to\n    `ActionEvaluator<T>()` constructor.  [[#1703]]\n -  Replaced `ITrie.TryGet()` with `ITrie.Get()` method.  [[#1703]]\n -  Replaced `StateStoreExtensions.GetState()` static method with `GetStates()`\n    static method.  [[#1703]]\n -  `nullable` context enabled for `IProtocol` interface and `Kademlia`,\n    `KademliaProtocol`, and `RoutingTable` classes.  [[#1692]]\n -  `RoutingTable.Neighbors(Peer, int, bool)` changed to\n    `RoutingTable.Neighbors(BoundPeer, int, bool)`.  As a result,\n    `RoutingTable` class now only explicitly deals with `BoundPeer`s.\n    [[#1692]]\n -  `BlockChain<T>.StageTransaction()`, `IStagePolicy.Stage()`,\n    and `IStagePolicy.Unstage()` now all return `bool` to indicate whether\n    staging was successful or not.  [[#1710]]\n\n### Added APIs\n\n -  Added `BlockChain<T>.GetStates()` method.  [[#1703]]\n -  Added `IBlockChainStates<T>` interface.  [[#1703]]\n     -  `BlockChain<T>` now implements `IBlockChainStates<T>`.\n -  Added `StateStoreExtensions.GetStates()` static method.  [[#1703]]\n\n### Behavioral changes\n\n -  Improved performance of `Swarm<T>.FillBlocksAsync()`'s block sync.\n    [[#1663], [#1699]]\n     -  The way `Swarm<T>` synchronizes the attached `BlockChain<T>`\n        with peers became more performant by splitting downloading\n        and appending blocks\n        into two parallel tasks.\n\n### Bug fixes\n\n -  Fixed a bug where unnecessary additional attempts were made to\n    unresponsive `Peer`s when discovering a `Peer` through `KademliaProtocol`.\n    [[#1692]]\n\n[#1663]: https://github.com/planetarium/libplanet/issues/1663\n[#1692]: https://github.com/planetarium/libplanet/pull/1692\n[#1699]: https://github.com/planetarium/libplanet/pull/1699\n[#1703]: https://github.com/planetarium/libplanet/pull/1703\n[#1710]: https://github.com/planetarium/libplanet/pull/1710\n\n\nVersion 0.25.5\n--------------\n\nReleased on February 18, 2022.\n\n -  Fixed `HashDigest<T>.DeriveFrom(ReadOnlySpan<byte>)` method's bug where\n    it had thrown `IndexOutOfRangeException` for the input longer or shorter\n    than `HashDigest<T>.Size` on .NET Standard 2.0.  [[#1706], [#1815]]\n -  Fixed `HashDigest<T>.DeriveFrom(ReadOnlySpan<byte>)` method's bug where\n    it had returned the wrong digest on .NET Standard 2.0.  [[#1706], [#1815]]\n\n[#1706]: https://github.com/planetarium/libplanet/issues/1706\n[#1815]: https://github.com/planetarium/libplanet/pull/1815\n\n\nVersion 0.25.4\n--------------\n\nReleased on January 18, 2022.\n\n -  Some additional logging to track down issues with staging `Transaction<T>`s.\n    [[#1718]]\n -  (Libplanet.RocksDBStore) Fixed `RocksDBStore`'s inaccurate lock handling.\n    [[#1719]]\n\n[#1718]: https://github.com/planetarium/libplanet/pull/1718\n[#1719]: https://github.com/planetarium/libplanet/pull/1719\n\n\nVersion 0.25.3\n--------------\n\nReleased on January 14, 2022.\n\n -  Fixed a bug when message broadcasting on `Swarm<T>`\n    had been stopped suddenly.  [[#1715]]\n\n[#1715]: https://github.com/planetarium/libplanet/pull/1715\n\n\nVersion 0.25.2\n--------------\n\nReleased on January 11, 2022.\n\n -  Fixed a bug where `TxCompletion<TPeer, TAction>` failed to fetch\n    transactions from other peers.  [[#1704]]\n -  In `TxCompletion<TPeer, TAction>`, instead of maintaining single\n    `RequestTxsFromPeerAsync()` task for each peer, a new\n    `RequestTxsFromPeerAsync()` task is spawned every time a new\n    demand is received.  [[#1704]]\n\n[#1704]: https://github.com/planetarium/libplanet/pull/1704\n\n\nVersion 0.25.1\n--------------\n\nReleased on January 6, 2022.\n\n### Behavioral changes\n\n -  `Swarm<T>` changed back, reverting the behavior implemented in [#1606]\n    to append blocks to the canonical chain instead of using a forked chain\n    while syncing recent blocks.  [[#1693]]\n\n[#1693]: https://github.com/planetarium/libplanet/pull/1693\n\n\nVersion 0.25.0\n--------------\n\nReleased on January 5, 2022.\n\n### Backward-incompatible API changes\n\n -  Replaced `HashDigest<T>(ImmutableArray<byte>)` constructor with\n    `HashDigest<T>(in ImmutableArray<byte>)` constructor.  [[#1678]]\n -  `IKeyValueStore`'s key type became `KeyBytes` (was `byte[]`).  [[#1678]]\n     -  Replaced `IKeyValueStore.Get(byte[])` method with `Get(in KeyBytes)`\n        method.\n     -  Replaced `IKeyValueStore.Set(byte[], byte[])` method with\n        `Set(in KeyBytes, byte[])` method.\n     -  Replaced `IKeyValueStore.Set(IDictionary<byte[], byte[]>)` method with\n        `Set(IDictionary<KeyBytes, byte[]>)` method.\n     -  Replaced `IKeyValueStore.Delete(byte[])` method with\n        `Delete(in KeyBytes)` method.\n     -  Replaced `IKeyValueStore.Exists(byte[])` method with\n        `Exists(in KeyBytes)` method.\n     -  `IKeyValueStore.ListKeys()` method's return type became\n        `IEnumerable<KeyBytes>` (was `IEnumerable<byte[]>`).\n -  `ITrie`'s key type became `KeyBytes` (was `byte[]`).  [[#1689]]\n     -  Replaced `ITrie.Set(byte[], IValue)` method with\n        `Set(in KeyBytes, IValue)` method.\n     -  Replaced `ITrie.TryGet(byte[], out IValue?)` method with\n        `TryGet(in KeyBytes, out IValue?)` method.\n     -  The return type of `MerkleTrieExtensions.ListAllStates()` static method\n        became `IEnumerable<KeyValuePair<KeyBytes, IValue>>` (was\n        `IEnumerable<KeyValuePair<ImmutableArray<byte>, IValue>>`).  [[#1653]]\n -  Added `IKeyValueStore.Get(IEnumerable<KeyBytes>)` method.  [[#1678]]\n -  Added `IKeyValueStore.Delete(IEnumerable<KeyBytes>)` method.  [[#1678]]\n -  `nullable` context enabled for `Peer` and `BoundPeer` classes.  All public\n    constructors now explicitly take non-nullable parameters.  [[#1679]]\n     -  All publicly accessible properties of `Peer` and `BoundPeer` are\n        now non-nullable except for `Peer.PublicIPAddress`.\n -  Replaced `HashDigest<T>.DeriveFrom(ReadOnlySpan<byte>)` overloaded static\n    method with other new overloads.  [[#1680]]\n\n### Backward-incompatible network protocol changes\n\n -  Removed `Sender` property from `Messages.TxIds` and `Messages.TxIds`'s\n    `MessageType` value bumped to `0x31`.  [[#1681]]\n\n### Added APIs\n\n -  Added `KeyBytes` readonly struct.  [[#1678]]\n -  Added `HashDigest<T>(in ImmutableArray<byte>)` constructor.  [[#1678]]\n -  Added `HashDigest<T>.DeriveFrom(byte[])` overloaded static method.\n    [[#1680]]\n -  Added `HashDigest<T>.DeriveFrom(ImmutableArray<byte>)` overloaded static\n    method.  [[#1680]]\n -  Added `HashDigest<T>.DeriveFrom(ReadOnlySpan<byte>)` overloaded static\n    method.  [[#1680]]\n -  Added `StateStoreExtensions.EncodeKey()` static method.  [[#1689]]\n -  Added `StateStoreExtensions.DecodeKey()` static method.  [[#1689]]\n\n### Behavioral changes\n\n  -  Improved performance of `Swarm<T>`'s block propagation.  [[#1676]]\n  -  (Libplanet.RocksDBStore) Improved performance of\n     `RocksDBStore<T>.IterateIndexes()` method.  [[#1676]]\n\n[#1676]: https://github.com/planetarium/libplanet/pull/1676\n[#1678]: https://github.com/planetarium/libplanet/pull/1678\n[#1679]: https://github.com/planetarium/libplanet/pull/1679\n[#1680]: https://github.com/planetarium/libplanet/pull/1680\n[#1681]: https://github.com/planetarium/libplanet/pull/1681\n[#1689]: https://github.com/planetarium/libplanet/pull/1689\n\n\nVersion 0.24.2\n--------------\n\nReleased on December 24, 2021.\n\n -  Fixed a bug of `NonblockRenderer<T>` and `NonblockActionRenderer<T>` where\n    they had thrown `ThreadStateException` when any render events occurred after\n    disposed.  [[#1682]]\n -  Log output compacted by removing duplicate exception messages.\n    [[#1632], [#1677]]\n\n[#1632]: https://github.com/planetarium/libplanet/issues/1632\n[#1677]: https://github.com/planetarium/libplanet/pull/1677\n\n\nVersion 0.24.1\n--------------\n\nReleased on December 16, 2021.\n\n -  Fixed a bug where `Transaction<T>`s were unstaged when they were not\n    supposed to.  [[#1672]]\n\n[#1672]: https://github.com/planetarium/libplanet/pull/1672\n\n\nVersion 0.24.0\n--------------\n\nReleased on December 16, 2021.\n\n### Backward-incompatible API changes\n\n -  `IStagePolicy<T>`'s `interface` methods updated.  Notably,\n    all `IStagePolicy<T>` now accept `BlockChain<T>` as its parameter.\n    [[#1648]]\n     -  `Get(BlockChain<T> blockChain, TxId id, bool includeInstaged)` changed\n        to `Get(BlockChain<T> blockChain, TxId id, bool filtered = true)`.\n     -  `Iterate()` changed to\n        `Iterate(BlockChain<T> blockChain, bool filtered = true)`.\n     -  `GetNextTxNonce(Address address, long minedTxs)` changed to\n        `GetNextTxNonce(BlockChain<T> blockChain, Address address)`.\n\n### Behavioral changes\n\n -  Description of `IStagePolicy<T>` and its default implementation\n    `VolatileStagePolicy<T>` is overhauled.  [[#1648]]\n     -  `IStagePolicy<T>.Iterate()` no longer guarantees any kind of ordering.\n     -  `IStagePolicy<T>.Ignore()` now also unstages the `Transaction<T>`.\n     -  `VolatileStagePolicy<T>` now holds every previously known unconfirmed\n        `Transaction<T>` regardless of its staging/unstaging history unless\n        it is expired or ignored.\n -  New log output tagged with `Metric` added to measure execution time for\n    `BlockChain<T>.FindNextHashes()`.  [[#1669]]\n\n### Bug fixes\n\n -  Fixed a bug where `TxCompletion` had broadcasted invalid transactions.\n    [[#1661]]\n\n[#1648]: https://github.com/planetarium/libplanet/pull/1648\n[#1661]: https://github.com/planetarium/libplanet/pull/1661\n[#1669]: https://github.com/planetarium/libplanet/pull/1669\n\n\nVersion 0.23.4\n--------------\n\nReleased on December 24, 2021.\n\n -  Fixed a bug of `NonblockRenderer<T>` and `NonblockActionRenderer<T>` where\n    they had thrown `ThreadStateException` when any render events occurred after\n    disposed.  [[#1682]]\n\n[#1682]: https://github.com/planetarium/libplanet/pull/1682\n\n\nVersion 0.23.3\n--------------\n\nReleased on December 13, 2021.\n\n -  Virtually disabled state fragmentation due to its critical negative impact\n    on action evaluation performance.  This will be enabled again after more\n    practical tests in the future releases.  [[#1665]]\n\n[#1665]: https://github.com/planetarium/libplanet/pull/1665\n\n\nVersion 0.23.2\n--------------\n\nReleased on December 13, 2021.\n\n -  Removed unnecessary a reader lock on `BlockChain<T>.GetState()` method to\n    improve parallelism.  [[#1657]]\n -  Improved performance of `Swarm<T>`'s block synchronization.  [[#1657]]\n -  Fixed a bug where `Swarm<T>` had swapped to improper chain.  [[#1657]]\n -  (Libplanet.RocksDBStore) Fixed a bug where `RocksDBStore.ForkBlockIndexes()`\n    had created temporary chains unnecessarily.  [[#1657]]\n\n[#1657]: https://github.com/planetarium/libplanet/pull/1657\n\n\nVersion 0.23.1\n--------------\n\nReleased on December 10, 2021.\n\n -  Fixed `TrieStateStore.PruneStates()` method's bug that it had thrown\n    `ArgumentOutOfRangeException`.  [[#1653], [#1654]]\n\n[#1653]: https://github.com/planetarium/libplanet/issues/1653\n[#1654]: https://github.com/planetarium/libplanet/pull/1654\n\n\nVersion 0.23.0\n--------------\n\nReleased on December 8, 2021.\n\nFrom this version Libplanrt can be built on arm64 machines including\nApple Silicon (aarch64-apple-darwin).\n\n### Added APIs\n\n -  Added `PreEvaluationBlock<T>.DetermineStateRootHash(BlockChain<T>,\n    StateCompleterSet<T>, out IImmutableDictionary<string, IValue>)` overloaded\n    method.  [[#1636]]\n -  Added `PreEvaluationBlock<T>.DetermineStateRootHash(IAction?, IStateStore,\n    out IImmutableDictionary<string, IValue>)` overloaded method.  [[#1636]]\n -  Parameter `except` for `KBucket.GetRandomPeer()` now defaults to `null`.\n    [[#1631]]\n -  Added `ArrayEqualityComparer<T>` class.  [[#1636]]\n\n### Behavioral changes\n\n -  States became to take up much less space than before by reducing unnecessary\n    duplicate data.  Although this guarantees the backward compatibility with\n    the existing state store, in order to take complete effect of this\n    optimization, please replay your existing blockchain from the genesis block\n    with the empty store.  [[#1636]]\n -  (Libplanet.Analyzers) Rule LAA1002 no more warns about enumerating sorted\n    sets/dictionaries:\n     -  `System.Collections.Generic.SortedDictionary<TKey, TValue>`\n     -  `System.Collections.Generic.SortedSet<T>`\n     -  `System.Collections.Immutable.ImmutableSortedDictionary<TKey, TValue>`\n     -  `System.Collections.Immutable.ImmutableSortedSet<T>`\n     -  `Bencodex.Types.Dictionary` (which became to guarantee enumeration order\n        since [Bencodex 0.4.0])\n\n### Bug fixes\n\n -  `KBucket.Head` and `KBucket.Tail` now properly return `null` if\n    the bucket is empty instead of faulting.  [[#1631]]\n -  `TxCompletion.Demand()` no longer requests `Transaction<T>`s already in\n    storage.  [[#1649]]\n\n### Dependencies\n\n -  Upgraded *Bencodex* from 0.4.0-dev.20211123080042+d7f6c810 to\n    [0.4.0][Bencodex 0.4.0].  [[#1636]]\n -  Upgraded *Planetarium.RocksDbSharp* from 6.2.3 to\n    [6.2.4-planetarium][Planetarium.RocksDbSharp 6.2.4-planetarium].\n    [[#1635]]\n\n[#1631]: https://github.com/planetarium/libplanet/pull/1631\n[#1635]: https://github.com/planetarium/libplanet/pull/1635\n[#1636]: https://github.com/planetarium/libplanet/pull/1636\n[#1649]: https://github.com/planetarium/libplanet/pull/1649\n[Bencodex 0.4.0]: https://www.nuget.org/packages/Bencodex/0.4.0\n[Planetarium.RocksDbSharp 6.2.4-planetarium]: https://www.nuget.org/packages/Planetarium.RocksDbSharp/6.2.4-planetarium\n\n\nVersion 0.22.1\n--------------\n\nReleased on December 5, 2021.\n\n -  Compacted log output for convenience.  [[#1633]]\n -  Removed `ITransport.MessageHistory` property due to memory leak.  [[#1639]]\n\n[#1633]: https://github.com/planetarium/libplanet/pull/1633\n[#1639]: https://github.com/planetarium/libplanet/pull/1639\n\n\nVersion 0.22.0\n--------------\n\nReleased on November 30, 2021.\n\n### Backward-incompatible API changes\n\n -  Removed `Transaction<T>.BytesLength` property.  [[#1609]]\n -  Removed `Block<T>.BytesLength` property.  [[#1609]]\n -  The types of `BlockChain<T>.MineBlock()` overloaded methods' `maxBlockBytes`\n    parameters became `long?` (were `int?`).  [[#1609]]\n -  The type of `IBlockPolicy<T>.GetMaxBlockBytes(long)` method became `long`\n    (was `int`).  [[#1609]]\n -  The type of `BlockPolicy<T>()` constructor's `getMaxBlockBytes` parameter\n    became `Func<long, long>?` (was `Func<long, int>?`).  [[#1609]]\n -  The type of `InvalidBlockBytesLengthException()` constructor's `bytesLength`\n    parameter became `long` (was `int`).  [[#1609]]\n -  The type of `InvalidBlockBytesLengthException.BytesLength` property became\n    `long` (was `int`).  [[#1609]]\n -  Methods `IsEmpty()` and `IsFull()` of `KBucket` changed to properties\n    `IsEmpty` and `IsFull` respectively.  [[#1610]]\n -  `MessageCodec` class renamed to `TcpMessageCodec`.  [[#1610]]\n -  `lifetime` parameter removed from `IMessageCodec.Decode()`.\n    `messageLifespan` parameter added to constructors of `NetMQMessageCodec`\n    and `TcpMessageCodec`.  [[#1610]]\n -  Removed unused `PeerStates` property from `Swarm<T>`.  [[#1610]]\n -  Method name `BoundPeer.QueryAppProtocolVersion()` changed to\n    `BoundPeer.QueryAppProtocolVersionNetMQ()`.  [[#1610]]\n\n### Behavioral changes\n\n -  `Swarm<T>` became to append blocks to forked chain to avoid locking\n    the canonical chain while syncing recent blocks.  [[#1606]]\n -  More streamlined structured logging together with additional logs\n    tagged as `Metric`.  [[#1627]]\n\n### Bug fixes\n\n -  `InvalidMagicCookieException` and `InvalidTimestampException` can now\n    be serialized and deserialized.  [[#1613]]\n -  Fixed a bug where `PolymorphicAction<T>` had thrown `InvalidCastException`\n    when inner action's `.PlainValue` returns other value than\n    `Bencodex.Types.Dictionary`.  [[#1628]]\n\n### Dependencies\n\n -  *Libplanet.Stun* assembly is now distributed as a seaprate NuGet package:\n    [*Libplanet.Stun*][Libplanet.Stun].  [[#813], [#1279], [#1625]]\n -  Upgraded *Bencodex* from 0.3.0 to\n    [0.4.0-dev.20211123080042+d7f6c810][Bencodex 0.4.0-dev.20211123080042].\n    [[#1609]]\n -  Now depends on [*Caching.dll* 1.4.0.1][Caching.dll 1.4.0.1].\n\n[#813]: https://github.com/planetarium/libplanet/issues/813\n[#1279]: https://github.com/planetarium/libplanet/pull/1279\n[#1606]: https://github.com/planetarium/libplanet/pull/1606\n[#1609]: https://github.com/planetarium/libplanet/pull/1609\n[#1610]: https://github.com/planetarium/libplanet/pull/1610\n[#1613]: https://github.com/planetarium/libplanet/pull/1613\n[#1625]: https://github.com/planetarium/libplanet/pull/1625\n[#1627]: https://github.com/planetarium/libplanet/pull/1627\n[#1628]: https://github.com/planetarium/libplanet/pull/1628\n[Libplanet.Stun]: https://www.nuget.org/packages/Libplanet.Stun/\n[Bencodex 0.4.0-dev.20211123080042]: https://www.nuget.org/packages/Bencodex/0.4.0-dev.20211123080042\n[Caching.dll 1.4.0.1]: https://www.nuget.org/packages/Caching.dll/1.4.0.1\n\n\nVersion 0.21.2\n--------------\n\nReleased on November 25, 2021.\n\n -  `planet apv query` command became to communicate with `NetMQTransport`\n    instead of `TcpTransport`.   [[#1618]]\n\n[#1618]: https://github.com/planetarium/libplanet/pull/1618\n\n\nVersion 0.21.1\n--------------\n\nReleased on November 25, 2021.\n\n -  `SwarmOptions.TipLifespan` property' default value was changed.\n    The default lifespan for a tip going stale is now `60` seconds instead of\n    `30` seconds for the purpose of polling blocks.  [[#1614]]\n -  `Swarm<T>`'s internal logic for determining when the `BlockChain<T>.Tip`\n    becomes stale is now fixed.  [[#1614]]\n\n[#1614]: https://github.com/planetarium/libplanet/pull/1614\n\n\nVersion 0.21.0\n--------------\n\nReleased on November 16, 2021.\n\n### Backward-incompatible API changes\n\n -  (Libplanet.RocksDBStore) Removed `MonoRocksDBStore` class.\n    [[#1513], [#1579]]\n -  Removed `rehearsal` parameter from `ITrie.Commit()` method.\n    [[#1554], [#1570]]\n -  Removed `rehearsal` parameter from `StateStoreExtensions.Commit()`\n    extension method.  [[#1554], [#1570]]\n -  Removed `ITransport.RunAsync()` method.\n    `ITransport.StartAsync()` now conducts operation that\n    `ITransport.RunAsync()` used to conduct.  [[#1523]]\n -  Removed `ITransport.ReplyMessage()` method which was non-blocking.\n    Instead, added `ITransport.ReplyMessageAsync()` asynchronous method\n    which is awaited until the reply message is sent.  [[#1523]]\n -  The type of `ITransport.ProcessMessageHandler` became\n    `AsyncDelegate<T>` (which was `EventHandler`).  [[#1523]]\n -  Removed unused `BlockChain<T>` type parameter from\n    `IStagePolicy<T>.Iterate()` method.  [[#1553], [#1556]]\n -  Removed unused `HashAlgorithmTable` class.  [[#1600]]\n -  `BlockChain<T>.MineBlock()` and `BlockChain<T>.GatherTransactionsToMine()`\n    now additionally accepts `maxBlockBytes` parameter of type `int`.  [[#1600]]\n -  Removed `BlockInsufficientTxsException` and\n    `BlockExceedingTransactionsException` classes.  [[#1504], [#1600]]\n\n### Added APIs\n\n -  Added `ITransport.MessageHistory` property.  [[#1523]]\n -  Added `ITransport.WaitForRunning()` method.  [[#1523]]\n -  Added `TcpTransport` class which implements `ITransport` interface.\n    [[#1523]]\n -  Added `SwarmOptions.Type` property.  [[#1523]]\n -  Added `SwarmOptions.TransportType` enum.  [[#1523]]\n -  Added `AsyncDelegate<T>` class.  [[#1523]]\n -  Added `InvalidMagicCookieException` class.  [[#1523]]\n -  Added `MessageCodec` class which inherits `IMessageCodec<T>`.\n    [[#1523]]\n -  Added `IStagePolicy<T>.GetNextTxNonce()` method.  [[#1553], [#1556]]\n -  Added `InvalidBlockBytesLengthException`, `InvalidBlockTxCountException`,\n    `InvalidBlockHashAlgorithmTypeException`, and\n    `InvalidBlockTxCountPerSignerException` classes.  [[#1504], [#1600]]\n\n### Behavioral changes\n\n -  Improved performance of `MerkleTrie.Commit()` and\n    `BlockChain<T>.ExecuteActions()` methods.   [[#1554], [#1570]]\n -  `Swarm<T>.MineBlock()` now throws `OperationCanceledException` instead\n    of `BlockInsufficientTxsException` when there are no sufficient number\n    of blocks to mine.  [[#1600]]\n -  Default implementation `BlockPolicy<T>.ValidateNextBlock()`\n    of `IBlockPolicy<T>` now validates the type for `Block<T>.HashAlgorithm`,\n    size for `Block<T>.BytesLength`, and count for `Block<T>.Transactions`.\n    [[#1504], [#1600]]\n\n### CLI tools\n\n -  `planet stats` command's `-p`/`--path` option no more supports the store\n    type `monorocksdb`.  [[#1513], [#1579]]\n -  Subcommands under `planet store` no more supports the store type\n    `monorocksdb`.  [[#1513], [#1579]]\n\n[#1504]: https://github.com/planetarium/libplanet/issues/1504\n[#1554]: https://github.com/planetarium/libplanet/issues/1554\n[#1570]: https://github.com/planetarium/libplanet/pull/1570\n[#1579]: https://github.com/planetarium/libplanet/pull/1579\n[#1523]: https://github.com/planetarium/libplanet/pull/1523\n[#1600]: https://github.com/planetarium/libplanet/pull/1600\n\n\nVersion 0.20.2\n--------------\n\nReleased on November 9, 2021.\n\n -  (Libplnaet.RocksDBStore) Fixed `DefaultStore.ForkBlockIndexes()` method's\n    bug that it had been thrown `ChainIdNotFoundException` when received a\n    chain forked from already deleted.  [[#1591], [#1592]]\n -  Fixed improper implementations of `BlockExceedingTransactionsException`\n    `InvalidBlockBytesLengthException` in regards to serialization and\n    related tests.  [[#1594]]\n\n[#1591]: https://github.com/planetarium/libplanet/issues/1591\n[#1592]: https://github.com/planetarium/libplanet/pull/1592\n[#1594]: https://github.com/planetarium/libplanet/pull/1594\n\n\nVersion 0.20.1\n--------------\n\nReleased on November 8, 2021.\n\n -  `Swarm<T>` became to broadcast a new block to peers immediately after\n    `Swarm<T>.BlockChain`'s `Tip` changes while it is `Running`.\n    [[#1582], [#1586]]\n\n[#1586]: https://github.com/planetarium/libplanet/pull/1586\n\n\nVersion 0.20.0\n--------------\n\nReleased on November 3, 2021.\n\n### Deprecated APIs\n\n -  (Libplanet.RocksDBStore) `MonoRocksDBStore` will be gone in the next minor\n    release: 0.21.0.  [[#1513], [#1574]]\n\n### Backward-incompatible API changes\n\n -  Removed unused `BlockChain<T>` type parameter from\n    `IStagePolicy<T>.Iterate()` method.  [[#1553], [#1556]]\n\n### Added APIs\n\n -  Added `IStagePolicy<T>.GetNextTxNonce()` method.  [[#1553], [#1556]]\n\n[#1513]: https://github.com/planetarium/libplanet/issues/1513\n[#1553]: https://github.com/planetarium/libplanet/issues/1553\n[#1556]: https://github.com/planetarium/libplanet/pull/1556\n[#1574]: https://github.com/planetarium/libplanet/pull/1574\n\n\nVersion 0.19.3\n--------------\n\nReleased on November 8, 2021.\n\n -  `Swarm<T>` became to broadcast a new block to peers immediately after\n    `Swarm<T>.BlockChain`'s `Tip` changes while it is `Running`.  [[#1582]]\n\n[#1582]: https://github.com/planetarium/libplanet/pull/1582\n\n\nVersion 0.19.2\n--------------\n\nReleased on November 3, 2021.\n\n -  `PrivateKey(IReadOnlyList<byte>)` overloaded constructor no more accepts\n    a list shorter or longer than 32 bytes.  [[#1571], [#1572]]\n -  `PrivateKey.FromString()` method no more accept a hexadecimal digits\n    shorter or longer than 64 characters.  [[#1571], [#1572]]\n -  Fixed a bug where `HashAlgorithmType.Digest(byte[])` and\n    `HashAlgorithmType.Digest(ImmutableArray<byte>)` methods had returned\n    a wrong hash digest after `HashAlgorithmType.Digest(IEnumerable<byte[]>)`\n    or `HashAlgorithmType.Digest(IEnumerable<ImmutableArray<byte>>)` methods\n    had been once called.  [[#1575], [#1576]]\n\n[#1572]: https://github.com/planetarium/libplanet/pull/1572\n[#1576]: https://github.com/planetarium/libplanet/pull/1576\n\n\nVersion 0.19.1\n--------------\n\nReleased on October 29, 2021.\n\n -  `BlockMetadata.MineNonce()` method and other mining methods based on it\n    now do not spawn a new thread if the `workers` is less than 2.  [[#1564]]\n -  `BlockMetadata.MineNonce()` method and other mining methods based on it\n    now uses the half of the present logical processors (i.e.,\n    `Environment.ProcessorCount / 2`) by default.  If there is only one logical\n    processor, uses one worker.  [[#1564]]\n -  Rolled back the order of the header of a `Message` so that it is compatible\n    with nodes based on Libplanet pre-0.19.0.  [[#1565]]\n\n[#1565]: https://github.com/planetarium/libplanet/pull/1565\n[#1564]: https://github.com/planetarium/libplanet/pull/1564\n\n\nVersion 0.19.0\n--------------\n\nReleased on October 27, 2021.\n\n### Backward-incompatible API changes\n\n -  Removed `IStore.StageTransactionIds()` method.  [[#1166], [#1535]]\n -  Removed `IStore.UnstageTransactionIds()` method.  [[#1166], [#1535]]\n -  Removed `IStore.IterateStagedTransactionIds()` method.  [[#1166], [#1535]]\n -  Removed `Message.ToNetMQMessage()` method.\n    Use `IMessageCodec<T>.Encode()` method instead.  [[#1503]]\n -  Removed `Message.Parse()` static method.\n    Use `IMessageCodec<T>.Decode()` method instead.  [[#1503]]\n -  Removed unused `HashAlgorithmGetter` type parameter from\n    `ActionEvaluator<T>()` constructor.  [[#1537]]\n -  `Hashcash.Answer()` method became to take random `seed` value explicitly.\n    [[#1546]]\n\n### Backward-incompatible network protocol changes\n\n -  The order of the header of a `Message` has been modified.  [[#1503]]\n\n### Added APIs\n\n -  Added\n    `BlockMetadata.MineNonce(HashAlgorithmType, int, CancellationToken)`\n    overloaded method.  [[#1546]]\n -  Added `Message.MessageFrame` enum.  [[#1503]]\n -  Added `Message.Type` property.  [[#1503]]\n -  Added `Message.DataFrames` property.  [[#1503]]\n -  Added `IMessageCodec<T>` interface.  [[#1503]]\n -  Added `NetMQMessageCodec` class which inherits `IMessageCodec<T>`.\n    [[#1503]]\n -  Added `MemoryStore` class.  [[#1544]]\n -  Added `MemoryKeyValueStore` class.  [[#1544]]\n -  Added `BlockDemandTable.Remove()` method.  [[#1549]]\n -  Added\n    `BlockMetadata.MineNonce(HashAlgorithmType, int, CancellationToken)`\n    overloaded method.  [[#1546]]\n -  Added `SwarmOptions.TipLifespan` property.  [[#1557]]\n\n### Behavioral changes\n\n -  `BlockMetadata.MineNonce()` method became to use multithreading when\n    looking for the nonce.  [[#1546]]\n -  `IStore.ForkTxNonces()` method became to throw `ChainIdNotFoundException`\n    when a given `sourceChainId` does not exist.  [[#1544]]\n -  `Swarm<T>.StartAsync()` method became to poll neighbor peers if they have\n    any new blocks whether `Swarm<T>.BlockDemandTable` is empty or not.\n    The polling is triggered when `Swarm<T>.BlockChain`'s `Tip` has been\n    unchanged for a while.  Expiration time for tips can be configured\n    through `SwarmOptions.TipLifespan` property.  [[#1557]]\n\n### Bug fixes\n\n -  Fixed `DefaultStore.ForkBlockIndexes()` method's bug that it had done\n    silently no-op when a given `sourceChainId` had not existed, which had not\n    been compliant with `IStore.ForkBlockIndexes()` method's specification.\n    [[#1544]]\n -  Fixed `Swarm<T>`'s bug that it had thrown `PingTimeoutException` if any\n    peer in configured `SwarmOptions.StaticPeers` is unreachable.\n    [[#1550], [#1551]]\n -  (Libplanet.RocksDBStore) Fixed `RocksDBStore.ForkBlockIndexes()` method's\n    bug that it had done silently no-op when a given `sourceChainId` had not\n    existed, which had not been compliant with `IStore.ForkBlockIndexes()`\n    method's specification.  [[#1544]]\n -  (Libplanet.RocksDBStore) Fixed `MonoRocksDBStore.ForkBlockIndexes()`\n    method's bug that it had done silently no-op when a given `sourceChainId`\n    had not existed, which had not been compliant with\n    `IStore.ForkBlockIndexes()` method's specification.  [[#1544]]\n -  Fixed a bug where `Swarm<T>` did not removed failed block demands from the\n    `BlockDemandTable`.  [[#1549]]\n\n[#1166]: https://github.com/planetarium/libplanet/issues/1166\n[#1503]: https://github.com/planetarium/libplanet/pull/1503\n[#1535]: https://github.com/planetarium/libplanet/pull/1535\n[#1537]: https://github.com/planetarium/libplanet/pull/1537\n[#1544]: https://github.com/planetarium/libplanet/pull/1544\n[#1546]: https://github.com/planetarium/libplanet/pull/1546\n[#1550]: https://github.com/planetarium/libplanet/issues/1550\n[#1549]: https://github.com/planetarium/libplanet/pull/1549\n[#1551]: https://github.com/planetarium/libplanet/pull/1551\n[#1557]: https://github.com/planetarium/libplanet/pull/1557\n\n\nVersion 0.18.5\n--------------\n\nReleased on November 3, 2021.\n\n -  Fixed a bug where `HashAlgorithmType.Digest(byte[])` and\n    `HashAlgorithmType.Digest(ImmutableArray<byte>)` methods had returned\n    a wrong hash digest after `HashAlgorithmType.Digest(IEnumerable<byte[]>)`\n    or `HashAlgorithmType.Digest(IEnumerable<ImmutableArray<byte>>)` methods\n    had been once called.  [[#1575]]\n\n[#1575]: https://github.com/planetarium/libplanet/pull/1575\n\n\nVersion 0.18.4\n--------------\n\nReleased on November 2, 2021.\n\n -  `PrivateKey(IReadOnlyList<byte>)` overloaded constructor no more accepts\n    a list shorter or longer than 32 bytes.  [[#1571]]\n -  `PrivateKey.FromString()` method no more accept a hexadecimal digits\n    shorter or longer than 64 characters.  [[#1571]]\n\n[#1571]: https://github.com/planetarium/libplanet/pull/1571\n\n\nVersion 0.18.3\n--------------\n\nReleased on October 28, 2021.  Mainly backported critical bug fixes from\n0.19.0.  [[#1562]]\n\n -  `Swarm<T>.StartAsync()` method became to poll neighbor peers if they have\n    any new blocks whether `Swarm<T>.BlockDemandTable` is empty or not.\n    The polling is triggered when `Swarm<T>.BlockChain`'s `Tip` has been\n    unchanged for a while.  [[#1557]]\n -  Fixed `Swarm<T>`'s bug that it had thrown `PingTimeoutException` if any\n    peer in configured `SwarmOptions.StaticPeers` is unreachable.\n    [[#1550], [#1551]]\n -  Fixed a bug where `Swarm<T>` did not removed failed block demands from the\n    `BlockDemandTable`.  [[#1549]]\n\n[#1562]: https://github.com/planetarium/libplanet/pull/1562\n\n\nVersion 0.18.2\n--------------\n\nReleased on October 22, 2021.\n\n -  Fixed a bug that `Swarm<T>` had not responded to `GetBlocks` requests\n    when some of requested blocks fail to be loaded.  It now sends\n    a `Blocks` response with successfully loaded blocks for the same\n    situation.  [[#1540]]\n\n[#1540]: https://github.com/planetarium/libplanet/pull/1540\n\n\nVersion 0.18.1\n--------------\n\nReleased on October 21, 2021.\n\n -  Fixed a bug where `PublicKey.Verify()` method had thrown exceptions\n    for some invalid inputs.  [[#1520]]\n -  `BaseStore.GetBlock<T>()` method now throws `InvalidOperationException`\n    when it fails to load a requested block's transactions.  [[#1500], [#1532]]\n -  (Libplanet.RocksDBStore) Operations on `RocksDBStore` that update data\n    no longer suppress the internal failures.  [[#1500], [#1532]]\n\n[#1500]: https://github.com/planetarium/libplanet/issues/1500\n[#1520]: https://github.com/planetarium/libplanet/issues/1520\n[#1532]: https://github.com/planetarium/libplanet/pull/1532\n\n\nVersion 0.18.0\n--------------\n\nReleased on October 13, 2021.\n\n### Backward-incompatible API changes\n\n -  `Hashcash.Stamp(Nonce)` delegate's return type became `IEnumerable<byte[]>`\n    (was `byte[]`).  [[#1492]]\n -  Moved `BlockDigest` struct to `Libplanet.Store` namespace (from\n    `Libplanet.Blocks` namespace).  [[#1492]]\n -  Removed `Block<T>.ToBlockDigest()` method.  Use `BlockDigest.FromBlock<T>()`\n    static method instead.  [[#1492]]\n -  `ActionEvaluator<T>.Evaluate()` method's `block` parameter became to take\n    `IPreEvaluationBlock<T>` (was `IBlock<T>`).  [[#1146], [#1164], [#1492]]\n -  `Block<T>` and `BlockHeader` now guarantees that their every instance has\n    integrity.  [[#1164], [#1492]]\n     -  `Block<T>` became unable to be subclassed.\n     -  Remove `Block<T>(long, long, BigInteger, Nonce, Address, BlockHash?,\n        DateTimeOffset, IReadOnlyList<Transaction<T>>, HashAlgorithmType,\n        HashDigest<SHA256>, ImmutableArray<byte>?, int)` overloaded constructor.\n        Use other overloaded constructors instead.\n     -  Added `Block<T>(IBlockHeader header, IEnumerable<Transaction<T>>)`\n        overloaded constructor.\n     -  Added `Block<T>(PreEvaluationBlock<T>, HashDigest<SHA256>,\n        ImmutableArray<byte>?)` overloaded constructor.  [[#1457], [#1507]]\n     -  `BlockHeader` is no more readonly struct, but a sealed class.\n     -  Removed `BlockHeader(int, long, string, ImmutableArray<byte>,\n        ImmutableArray<byte>, long, BigInteger, ImmutableArray<byte>,\n        ImmutableArray<byte>, ImmutableArray<byte>, ImmutableArray<byte>,\n        ImmutableArray<byte>)` constructor.  Use other overloaded constructors\n        instead.\n     -  Added `BlockHeader(PreEvaluationBlockHeader, HashDigest<SHA256>,\n        ImmutableArray<byte>?)` overloaded constructor.  [[#1457], [#1507]]\n     -  Added `BlockHeader(PreEvaluationBlockHeader, HashDigest<SHA256>,\n        ImmutableArray<byte>?, BlockHash)` overloaded constructor.\n        [[#1457], [#1507]]\n -  `Block<T>` and `BlockHeader` have no more marshaling/unmarshalling methods.\n     -  Removed `Block<T>(Bencodex.Types.Dictionary)` overloaded constructor.\n        Use `BlockMarshaler.UnmarshalBlock()` static method instead.\n     -  Removed `Block<T>.Deserialize()` static method.  Instead, use\n        `BlockMarshaler.UnmarshalBlock()` static method and `Bencodex.Codec`\n        together.\n     -  Removed `Block<T>.ToBencodex()` method.\n        Use `BlockMarshaler.MarshalBlock()` static method instead.\n     -  Removed `Block<T>.Serialize()` method.  Instead, use\n        `BlockMarshaler.MarshalBlock()` static method and `Bencodex.Codec`\n        together.\n     -  Removed `BlockHeader(Bencodex.Types.Dictionary)` overloaded constructor.\n        Use `BlockMarshaler.UnmarshalBlockHeader()` static method instead.\n     -  Removed `BlockHeader.Deserialize()` static method.  Instead, use\n        `BlockMarshaler.UnmarshalBlockHeader()` static method and\n        `Bencodex.Codec` together.\n     -  Removed `BlockHeader.ToBencodex()` method.\n        Use `BlockMarshaler.MarshalBlockHeader()` static method instead.\n     -  Removed `BlockHeader.Serialize()` method.  Instead, use\n        `BlockMarshaler.MarshalBlockHeader()` static method and\n        `Bencodex.Codec` together.\n -  `Block<T>` and `BlockHeader` now guarantee that their every instance has\n    its `StateRootHash`.  [[#1128], [#1146], [#1492]]\n     -  `Block<T>.StateRootHash` property's type became `HashDigest<SHA256>`\n        (was `HashDigest<SHA256>?`).\n     -  Removed `Block<T>(Block<T>, HashDigest<SHA256>)` overloaded constructor.\n        Use `Block<T>(PreEvaluationBlock<T>, HashDigest<SHA256>)` overloaded\n        constructor instead.\n     -  Removed `Block<T>.Mine()` static method.  Use `BlockContent<T>.Mine()`\n        and `PreEvaluationBlock<T>.Evaluate()` methods instead.\n     -  `BlockHeader.StateRootHash` property's type became `HashDigest<SHA256>`\n        (was `HashDigest<SHA256>?`).\n     -  The type of `InvalidBlockStateRootHashException()` constructor's\n        `expectedStateRootHash` parameter became `HashDigest<SHA256>`\n        (was `HashDigest<SHA256>?`).  [[#1507]]\n     -  `InvalidBlockStateRootHashException.ExpectedStateRootHash` property's\n        type became `HashDigest<SHA256>` (was `HashDigest<SHA256>?`).  [[#1507]]\n -  `Block<T>` and `BlockHeader` became aware of `HashAlgorithmType` used for\n    proof-of-work mining.  [[#1492]]\n     -  Added `Block<T>.HashAlgorithm` property.\n     -  Added `BlockHeader.HashAlgorithm` property.\n     -  Removed `BlockHeader(int, long, DateTimeOffset, Nonce, Address, long,\n        BigInteger, BlockHash?, HashDigest<SHA256>?, BlockHash,\n        ImmutableArray<byte>, HashDigest<SHA256>?)` constructor.\n        Use `BlockHeader(int, long, DateTimeOffset, Nonce, Address, long,\n        BigInteger, BlockHash?, HashDigest<SHA256>?, BlockHash,\n        ImmutableArray<byte>, HashDigest<SHA256>, HashAlgorithmType)`\n        constructor instead.\n     -  Added `HashAlgorithmGetter hashAlgorithmGetter` parameter to\n        `IStore.GetBlock<T>()` method.\n     -  Removed `BlockDigest.Header` property.  Use `BlockDigest.GetHeader()`\n        method instead.\n     -  Added `BlockDigest.GetHeader()` method.\n     -  Added `HashAlgorithmGetter hashAlgorithmGetter` parameter to\n        `DelayedRenderer<T>()` constructor.\n     -  Added `HashAlgorithmGetter hashAlgorithmGetter` parameter to\n        `DelayedActionRenderer<T>()` constructor.\n     -  Added `DelayedRenderer<T>.HashAlgorithmGetter` property.\n -  Blocks became signed by the miner since the protocol version 2.\n    [[#1457], [#1507]]\n     -  Added `Block<T>(PreEvaluationBlock<T>, HashDigest<SHA256>,\n        ImmutableArray<byte>?)` overloaded constructor.  [[#1164], [#1492]]\n     -  Added `BlockHeader(PreEvaluationBlockHeader, HashDigest<SHA256>,\n        ImmutableArray<byte>?)` overloaded constructor.  [[#1164], [#1492]]\n     -  Added `BlockHeader(PreEvaluationBlockHeader, HashDigest<SHA256>,\n        ImmutableArray<byte>?, BlockHash)` overloaded constructor.\n        [[#1164], [#1492]]\n     -  Added `Block<T>.Signature` property.\n     -  Added `Block<T>.PublicKey` property.\n     -  Added `BlockHeader.Signature` property.\n     -  Added `BlockHeader.PublicKey` property.\n     -  Added `InvalidBlockPublicKeyException` class.\n     -  Added `InvalidBlockSignatureException` class.\n -  `IStateStore` now requires implementations to be trie.\n    [[#1128], [#1146], [#1492]]\n     -  Added `IStateStore.GetStateRoot()` method.\n     -  Added `IStateStore.PruneStates()` method.\n     -  Removed `IStateStore.SetStates<T>()` method.\n     -  Removed `IStateStore.GetState()` method.\n     -  Removed `IStateStore.ContainsBlockStates()` method.\n     -  Removed `IStateStore.ForkStates<T>()` method.\n -  `TrieStateStore` no more stores associations between\n    `Block<T>.Hash`/`Block<T>.PreEvaluationHash` and `Block<T>.StateRootHash`,\n    because `Block<T>.StateRootHash` became mandatory.\n    [[#1128], [#1146], [#1492]]\n     -  Added `ITrie.Recorded` property.\n     -  Removed `IKeyValueStore stateHashKeyValueStore` parameter from\n        `TrieStateStore()` constructor.\n     -  Removed `TrieStateStore.GetTrie()` method.\n     -  Removed `TrieStateStore.GetRootHash()` method.\n     -  Replaced `TrieStateStore.PruneStates(IImmutableSet<BlockHash>)` method\n        with `TrieStateStore.PruneStates(IImmutableSet<HashDigest<SHA256>>)`\n        method.\n -  The types of `BlockChain<T>.MineBlock()` overloaded methods' `miner`\n    parameter became `PrivateKey` (were `Address`).  [[#1457], [#1507]]\n\n### Backward-incompatible network protocol changes\n\n -  The `Block<T>.CurrentProtocolVersion` is bumped from 1 to 2:  [[#1507]]\n     -  Block's total difficulty value became included to the input of block\n        hashes and pre-evaluation hashes since the protocol version 2.\n     -  Blocks became to have miner's public key as well since the protocol\n        version 2.  [[#1457]]\n     -  Blocks became to have no miner's address since the protocol version 2,\n        because it can be derived from miner's public key.  [[#1457]]\n     -  Blocks became to have a signature made using miner's private key\n        since the protocol version 2.  Block signatures affect block hashes.\n        [[#1457]]\n\n### Added APIs\n\n -  Added `BlockMetadata` class.  [[#1164], [#1457], [#1492], [#1507]]\n -  Added `BlockContent<T>` class.  [[#1164], [#1492]]\n -  Added `PreEvaluationBlockHeader` class.\n    [[#1146], [#1164], [#1457], [#1492], [#1507]]\n -  Added `PreEvaluationBlock<T>` class.\n    [[#1146], [#1164], [#1457], [#1492], [#1507]]\n -  Added `BlockDigest.FromBlock<T>()` static method.  [[#1492]]\n -  Added `Block<T>(PreEvaluationBlock<T>, HashDigest<SHA256>)` overloaded\n    constructor.  [[#1146], [#1164], [#1492]]\n -  Added `Block<T>.HashAlgorithm` property.  [[#1492]]\n -  Added `Block<T>.PublicKey` property.  [[#1457], [#1507]]\n -  Added `Block<T>.Signature` property.  [[#1457], [#1507]]\n -  Added `Block<T>(PreEvaluationBlock<T>, HashDigest<SHA256>,\n    ImmutableArray<byte>?)` overloaded constructor.\n    [[#1164], [#1457], [#1492], [#1507]]\n -  Added `Block<T>(IBlockHeader, IEnumerable<Transaction<T>>)` overloaded\n    constructor.  [[#1164], [#1492]]\n -  Added `BlockHeader.HashAlgorithm` property.  [[#1492]]\n -  Added `BlockHeader.PublicKey` property.  [[#1457], [#1507]]\n -  Added `BlockHeader.Signature` property.  [[#1457], [#1507]]\n -  Added `BlockHeader(PreEvaluationBlockHeader, HashDigest<SHA256>,\n    ImmutableArray<byte>?)` overloaded constructor.\n    [[#1164], [#1457], [#1492], [#1507]]\n -  Added `BlockHeader(PreEvaluationBlockHeader, HashDigest<SHA256>,\n    ImmutableArray<byte>?, BlockHash)` overloaded constructor.\n    [[#1164], [#1457], [#1492], [#1507]]\n -  Added `IBlockMetadata` interface.  [[#1164], [#1457], [#1492], [#1507]]\n     -  `Block<T>` became to implement `IBlockMetadata` interface.\n     -  `BlockHeader` became to implement `IBlockMetadata` interface.\n     -  `BlockMetadata` became to implement `IBlockMetadata` interface.\n     -  `BlockContent<T>` became to implement `IBlockMetadata` interface.\n     -  `PreEvaluationBlockHeader` became to implement `IBlockMetadata`\n        interface.\n     -  `PreEvaluationBlock<T>` became to implement `IBlockMetadata` interface.\n     -  `BlockDigest` became to implement `IBlockMetadata` interface.\n -  Added `IBlockContent<T>` interface.  [[#1164], [#1492]]\n     -  `Block<T>` became to implement `IBlockContent<T>` interface.\n     -  `BlockContent<T>` became to implement `IBlockContent<T>` interface.\n     -  `PreEvaluationBlock<T>` became to implement `IBlockContent<T>`\n        interface.\n -  Added `IPreEvaluationBlockHeader` interface.  [[#1164], [#1492]]\n     -  `Block<T>` became to implement `IPreEvaluationBlockHeader` interface.\n     -  `BlockHeader` became to implement `IPreEvaluationBlockHeader` interface.\n     -  `PreEvaluationBlockHeader` became to implement\n        `IPreEvaluationBlockHeader` interface.\n     -  `PreEvaluationBlock<T>` became to implement `IPreEvaluationBlockHeader`\n        interface.\n -  Added `IPreEvaluationBlock<T>` interface.  [[#1164], [#1492]]\n     -  `Block<T>` became to implement `IPreEvaluationBlock<T>` interface.\n     -  `PreEvaluationBlock<T>` became to implement `IPreEvaluationBlock<T>`\n        interface.\n     -  `ActionEvaluator<T>.Evaluate()` method's `block` parameter became to\n        take `IPreEvaluationBlock<T>` (was `IBlock<T>`).\n -  Added `IBlockHeader` interface.  [[#1146], [#1164], [#1492]]\n     -  `Block<T>` became to implement `IBlockHeader` interface.\n     -  `BlockHeader` became to implement `BlockHeader` interface.\n -  Added `BlockMetadataExtensions` static class.  [[#1164], [#1492]]\n -  Added `BlockContentExtensions` static class.  [[#1164], [#1492]]\n -  Added `BlockMarshaler` static class.  [[#1164], [#1492]]\n -  Added `BlockDigest.GetHeader()` method.  [[#1492]]\n -  Added `StateStoreExtensions` static class.  [[#1128], [#1146], [#1492]]\n -  Added `StoreExtensions.GetStateRootHash()` extension method.\n    [[#1128], [#1146], [#1492]]\n -  Added `DelayedRenderer<T>.HashAlgorithmGetter` property.  [[#1492]]\n -  `BlockDigest` became to implement `IBlockExcerpt`.  [[#1492]]\n -  Added `InvalidBlockPublicKeyException` class.  [[#1457], [#1507]]\n -  Added `InvalidBlockSignatureException` class.  [[#1457], [#1507]]\n\n### Behavioral changes\n\n -  `Block<T>.Transactions` property is now ordered by `Transaction<T>.Id`\n    so that it's consistent with `IBlockContent<T>`'s other implementations.\n    As this behavior can be changed in the later releases, do not depend on\n    its ordering, but explicitly sort them before use when the order needs to b\n    guaranteed.  [[#1492]]\n -  Blocks and block metadata became to have their miners' public keys too.\n    Although it is backward compatible to the earlier protocol version than 2,\n    blocks with the protocol version 2 or later must have public keys.\n    If a block lacks public key, `InvalidBlockPublicKeyException` is thrown.\n    [[#1457], [#1507]]\n -  `PublicKey.ToString()` method now returns its hexadecimal representation\n    in compressed form.  [[#1507]]\n\n### Bug fixes\n\n -  Fixed `NullReferenceException` that `PublicKey.Verify()` method had thrown\n    with a non-null empty `signature`.  [[#1507]]\n -  Fixed `TxExecution` not updating during preload.  [[#1508], [#1509]]\n\n[#1128]: https://github.com/planetarium/libplanet/issues/1128\n[#1146]: https://github.com/planetarium/libplanet/issues/1146\n[#1164]: https://github.com/planetarium/libplanet/issues/1164\n[#1457]: https://github.com/planetarium/libplanet/issues/1457\n[#1492]: https://github.com/planetarium/libplanet/pull/1492\n[#1507]: https://github.com/planetarium/libplanet/pull/1507\n[#1508]: https://github.com/planetarium/libplanet/issues/1508\n[#1509]: https://github.com/planetarium/libplanet/pull/1509\n\n\nVersion 0.17.0\n--------------\n\nReleased on September 28, 2021.\n\n### Backward-incompatible API changes\n\n -  Added `StateCompleterSet<T>.ComplementAll` property.  [[#1358], [#1386]]\n -  Added `StateCompleterSet<T>.ComplementLatest` property.  [[#1358], [#1386]]\n -  `BlockPerception` now implements `IBlockExcerpt` interface.  [[#1440]]\n     -  `BlockPerception.Excerpt` property removed.\n -  `TotalDifficultyComparer` now implements `IComparer<IBlockExcerpt>`\n    interface.  [[#1442]]\n -  Return type for `BlockDemandTable.Add()` is now `void`.  [[#1435], [#1443]]\n -  Added `BlockInsufficientTxsException`.  [[#1445]]\n -  `PrivateKey()` constructor's parameter type became `IReadOnlyList<byte>`\n    (was `byte[]`).  [[#1464]]\n -  `PrivateKey.ByteArray` property's type became `ImmutableArray<byte>`\n    (was `byte[]`).  To get a mutable one, use `PrivateKey.ToByteArray()`\n    method instead.  [[#1464]]\n -  `PublicKey()` constructor's parameter type became `IReadOnlyList<byte>`\n    (was `byte[]`).  [[#1464]]\n -  `PublicKey.Verify()` method's both parameter types became\n    `IReadOnlyList<byte>` (were both `byte[]`).  [[#1464]]\n -  `HashDigest<T>.DeriveFrom()` method's parameter type became\n    `IReadOnlyList<byte>` (was `byte[]`).  [[#1464]]\n -  `IBlockPolicy<T>.GetMaxBlockBytes()` description changed for `0`\n    and negative values.  [[#1449], [#1463]]\n     -  Returned values from these will now be taken literally\n        by `BlockChain<T>`.\n -  Removed `IBlockPolicy<T>.MaxTransactionsPerBlock` property.  It is replaced\n    by `IBlockPolicy<T>.GetMaxTransactionsPerBlock(long index)` method.\n    [[#1447]]\n -  Added `IBlockPolicy<T>.GetMaxTransactionsPerBlock(long index)` method.\n    [[#1447]]\n -  Added `IBlockPolicy<T>.GetMinTransactionsPerBlock(long index)` method.\n    [[#1479]]\n -  Added `IBlockPolicy<T>.GetMaxTransactionsPerSignerPerBlock(long index)`\n    method.  [[#1449], [#1463]]\n -  Unused parameter `currentTime` removed from `BlockChain<T>.Append()`.\n    [[#1462], [#1465]]\n -  Added an optional `maxTransactionsPerSigner` parameter to\n    `BlockChain<T>.MineBlock()` method.  [[#1449], [#1463]]\n -  Added an optional `txPriority` parameter to `BlockChain<T>.MineBlock()`\n    method.  [[#1477]]\n -  `BlockHeader`'s properties are now represented as richer types than before.\n    [[#1470]]\n     -  `BlockHeader.Timestamp` property's type became `DateTimeOffset`\n        (was `string`).\n     -  `BlockHeader.Nonce` property's type became `Nonce` (was\n        `ImmutableArray<byte>`).\n     -  `BlockHeader.Miner` property's type became `Address` (was\n        `ImmutableArray<byte>`).\n     -  `BlockHeader.PreviousHash` property's type became `BlockHash?` (was\n        `ImmutableArray<byte>`).\n     -  `BlockHeader.TxHash` property's type became `HashDigest<SHA256>?` (was\n        `ImmutableArray<byte>`).\n     -  `BlockHeader.Hash` property's type became `BlockHash` (was\n        `ImmutableArray<byte>`).\n     -  `BlockHeader.StateRootHash` property's type became `HashDigest<SHA256>?`\n        (was `ImmutableArray<byte>`).\n     -  Removed `BlockHeader(int, long, string, ImmutableArray<byte>,\n        ImmutableArray<byte>, long, BigInteger, ImmutableArray<byte>,\n        ImmutableArray<byte>, ImmutableArray<byte>, ImmutableArray<byte>,\n        ImmutableArray<byte>)` constructor.  Use `BlockHeader(int, long,\n        DateTimeOffset, Nonce, Address, long, BigInteger, BlockHash?,\n        HashDigest<SHA256>?, BlockHash, ImmutableArray<byte>,\n        HashDigest<SHA256>?)` constructor instead.\n -  `IStore`, `IStateStore`, and `IKeyValueStore` interfaces now inherit\n    `IDisposable`.  [[#1448], [#1474]]\n -  Multiple changes for `IBlockPolicy<T>` interface.  [[#1485]]\n     -  `bool DoesTransactionFollowsPolicy(BlockChain<T>, Transaction<T>)`\n        changed to `TxPolicyViolationException? ValidateNextBlockTx(\n        BlockChain<T>, Transaction<T>)`.\n     -  `InvalidBlockException ValidateNextBlock(BlockChain<T>, Block<T>)`\n        changed to `BlockPolicyViolationException? ValidateNextBlock(\n        BlockChain<T>, Block<T>)`.\n     -  `BlockPolicy<T>`, the default implementation for `IBlockPolicy<T>`,\n        has been updated accordingly.\n -  Removed `BlockPolicy<T>()` constructor with `int blockIntervalMilliseconds`\n    parameter.  Use the one with `TimeSpan? blockInterval` instead.  [[#1485]]\n -  Replaced `int maxBlockBytes` and `int maxGenesisBytes` parameters from\n    `BlockPolicy<T>()` constructor with `Func<long, int>? getMaxBlockBytes`.\n    [[#1485]]\n -  Removed `TxViolatingBlockPolicyException` class.  [[#1485]]\n -  Optional parameter name `difficultyBoundDivisor` for `BlockPolicy<T>()`\n    constructor changed to `difficultyStability`.  [[#1495]]\n -  Type for optional parameter `difficultyStability` for `BlockPolicy<T>()`\n    constructor changed to `long?` from `int?`.  [[#1495]]\n\n### Backward-incompatible network protocol changes\n\n -  `Message` became to serialize peer with Bencodex instead of\n    `BinaryFormatter`.  [[#1455]]\n\n### Added APIs\n\n -  `IBlockExcerpt.ExcerptEquals` extension method added.  [[#1440]]\n -  Added `PrivateKey.FromString()` method.  [[#1475]]\n -  Added `PrivateKey.Sign(ImmutableArray<byte>)` overloaded method.  [[#1464]]\n -  Added `PrivateKey.Decrypt(ImmutableArray<byte>)` overloaded method.\n    [[#1464]]\n -  Added `PrivateKey.ToByteArray()` method.  [[#1464]]\n -  Added `PublicKey.Encrypt(ImmutableArray<byte>)` overloaded method.\n    [[#1464]]\n -  Added `PublicKey.ToImmutableArray()` method.  [[#1464]]\n -  Added `Nonce(ImmutableArray<byte>)` overloaded constructor.  [[#1464]]\n -  Added `HashAlgorithmType.Digest(IEnumerable<byte[]>)` overloaded method.\n    [[#1480]]\n -  Added `HashAlgorithmType.Digest(IEnumerable<ImmutableArray<byte>>)`\n    overloaded method.  [[#1480]]\n -  Added `BlockHeader(int, long, DateTimeOffset, Nonce, Address, long,\n    BigInteger, BlockHash?, HashDigest<SHA256>?, BlockHash,\n    ImmutableArray<byte>, HashDigest<SHA256>?)` constructor.  [[#1470]]\n -  Added `TxCompletion<TPeer, TAction>` class.  [[#1420], [#1478]]\n -  Added `BlockPolicyViolationException` and `TxPolicyViolationException`\n    classes.  [[#1485]]\n -  Added `DifficultyAdjustment` static class.  [[#1495]]\n -  Added `BlockPolicy<T>.DifficultyStability` and\n    `BlockPolicy<T>.MinimumDifficulty` properties.  [[#1495]]\n\n### Behavioral changes\n\n -  `StateCompleterSet<T>.Recalculate` now evaluates states even for those\n    already in `IStateStore`.  Moreover, it also terminates early if possible\n    after reaching the `BlockHash` provided with a call.  [[#1358], [#1386]]\n -  `TotalDifficultyComparer` no longer considers perceived time when comparing\n    `IBlockExcerpt`s.  [[#1442]]\n -  General logic for determining the canonical chain has been updated.\n    [[#1435], [#1443]]\n     -  Perceived time is only used for marking a received header in\n        `BlockDemandTable` in order to decide whether `BlockDemand` is stale\n        or not.  This should prevent a tip regression for a local node, as the\n        tip of a chain is never considered as stale.\n -  Block sync using `BlockDemand` became not to fill blocks\n    from multiple peers.  [[#1459]]\n -  `BlockChain<T>.MineBlock()` now uses `maxTransactions` literally.\n    [[#1449], [#1463]]\n     -  Before, `maxTransactions` were internally automatically set to a\n        value between `1` and `BlockChain<T>.Policy.MaxTransactionsPerBlock`.\n -  Similarly, `BlockChain<T>.MineBlock()` now internally uses\n    `BlockChain<T>.Policy.GetMaxBlockBytes()` literally.  [[#1449], [#1463]]\n -  `NetMQTransport` became to no more send CreatePermission to TURN client and\n    require permission-less TURN server.  See [coturn's relevant configuration](\n    https://github.com/coturn/coturn/blob/dc8f405f8543a83ad8c059ba6b9f930e1e5a1349/man/man1/turnserver.1#L402-L410)\n    as well.  [[#1423]]\n -  `Swarm<T>` became to sync transactions from multiple peers\n    at the same time.  [[#1420], [#1478]]\n\n### Bug fixes\n\n -  Improper sanity checks for `targetBlockInterval` (changed from the old name\n    `blockInterval`), `minimumDifficulty`, and `difficultyStability` (changed\n    from the old name `difficultyBoundDivisor`) arguments given to\n    `BlockPolicy<T>()` constructor fixed.  [[#1495]]\n     -  It was possible for `targetBlockInterval` to be zero, which would result\n        in division by zero, when this makes no sense.\n     -  It was possible for `difficultyStability` not to be positive when this\n        makes no sense.\n     -  Wrongly threw an `ArgumentOutOfRangeException` for the case where\n        `minimumDifficulty` would equal `difficultyStability`.\n     -  It was possible for `minimumDifficulty` to be zero, which would allow\n        difficulty to be stuck at zero indefinitely, when this does not\n        make sense.\n\n[#1358]: https://github.com/planetarium/libplanet/issues/1358\n[#1386]: https://github.com/planetarium/libplanet/pull/1386\n[#1420]: https://github.com/planetarium/libplanet/issues/1420\n[#1423]: https://github.com/planetarium/libplanet/pull/1423\n[#1435]: https://github.com/planetarium/libplanet/issues/1435\n[#1440]: https://github.com/planetarium/libplanet/pull/1440\n[#1442]: https://github.com/planetarium/libplanet/pull/1442\n[#1443]: https://github.com/planetarium/libplanet/pull/1443\n[#1445]: https://github.com/planetarium/libplanet/pull/1445\n[#1447]: https://github.com/planetarium/libplanet/pull/1447\n[#1448]: https://github.com/planetarium/libplanet/issues/1448\n[#1449]: https://github.com/planetarium/libplanet/issues/1449\n[#1455]: https://github.com/planetarium/libplanet/pull/1455\n[#1459]: https://github.com/planetarium/libplanet/pull/1459\n[#1462]: https://github.com/planetarium/libplanet/issues/1462\n[#1463]: https://github.com/planetarium/libplanet/pull/1463\n[#1464]: https://github.com/planetarium/libplanet/pull/1464\n[#1465]: https://github.com/planetarium/libplanet/pull/1465\n[#1470]: https://github.com/planetarium/libplanet/pull/1470\n[#1474]: https://github.com/planetarium/libplanet/pull/1474\n[#1475]: https://github.com/planetarium/libplanet/pull/1475\n[#1477]: https://github.com/planetarium/libplanet/pull/1477\n[#1478]: https://github.com/planetarium/libplanet/pull/1478\n[#1479]: https://github.com/planetarium/libplanet/pull/1479\n[#1480]: https://github.com/planetarium/libplanet/pull/1480\n[#1485]: https://github.com/planetarium/libplanet/pull/1485\n[#1495]: https://github.com/planetarium/libplanet/pull/1495\n\n\nVersion 0.16.0\n--------------\n\nReleased on August 25, 2021.\n\n### Backward-incompatible API changes\n\n -  Removed `Swarm<T>.BlockDemand` property.  [[#1419], [#1425]]\n -  `BlockChain<T>.Tip` property is now non-nullable.  [[#1430]]\n\n### Added APIs\n\n -  Added `BlockDemandTable<T>` class.  [[#1419], [#1425]]\n -  Added `Swarm<T>.BlockDemandTable` property.  [[#1419], [#1425]]\n -  Added `SwarmOptions.PollInterval` property.  [[#1419], [#1425]]\n -  Added `SwarmOptions.MaximumPollPeers` property.  [[#1419], [#1425]]\n\n### Behavioral changes\n\n -  `Swarm<T>` became to sync blocks from multiple peers.  [[#1419], [#1425]]\n\n### Bug fixes\n\n -  Fixed a bug where `Swarm<T>.PreloadAsync()` failed to sync blocks from\n    the peer that has chain with higher difficulty, but lower index.\n    [[#1419], [#1425]]\n\n[#1419]: https://github.com/planetarium/libplanet/issues/1419\n[#1425]: https://github.com/planetarium/libplanet/pull/1425\n[#1430]: https://github.com/planetarium/libplanet/pull/1430\n\n\nVersion 0.15.4\n--------------\n\nReleased on September 14, 2021.\n\n -  Fixed a bug where `BlockChain<T>.MineBlock()` had created a block that\n    includes both transactions when there are two or more transactions with\n    the same nonce on the stage.  [[#1491]]\n\n[#1491]: https://github.com/planetarium/libplanet/pull/1491\n\n\nVersion 0.15.3\n--------------\n\nReleased on September 10, 2021.\n\n -  Fixed a bug where `Swarm<T>` fails to reply transaction when any of the\n    requested transactions id in `GetTxs` message does not exist in the storage.\n    [[#1481]]\n\n[#1481]: https://github.com/planetarium/libplanet/pull/1481\n\n\nVersion 0.15.2\n--------------\n\nReleased on September 3, 2021.\n\n -  Removed `ITransport.SendMessageWithReplyAsync(BoundPeer,\n    Message, TimeSpan?, int, CancellationToken)` method.\n    Instead, added `ITransport.SendMessageWithReplyAsync(BoundPeer,\n    Message, TimeSpan?, int, bool, CancellationToken)` method.\n    [[#1458], [#1461]]\n -  Fixed a bug where `GetTxs` request failed to receive transactions\n    if any messages are missing.  [[#1458], [#1461]]\n\n[#1458]: https://github.com/planetarium/libplanet/issues/1458\n[#1461]: https://github.com/planetarium/libplanet/pull/1461\n\n\nVersion 0.15.1\n--------------\n\nReleased on August 28, 2021.\n\n -  `NetMQTransport` became to process message in non blocking way.  [[#1451]]\n\n [#1451]: https://github.com/planetarium/libplanet/pull/1451\n\n\nVersion 0.15.0\n--------------\n\nReleased on August 18, 2021.\n\n### Backward-incompatible API changes\n\n -  Added `IRandom.Seed` property.  [[#1431]]\n\n[#1431]: https://github.com/planetarium/libplanet/pull/1431\n\n\nVersion 0.14.1\n--------------\n\nReleased on August 18, 2021.\n\n -  Added additional tags to logging.  [[#1433]]\n\n[#1433]: https://github.com/planetarium/libplanet/pull/1433\n\n\nVersion 0.14.0\n--------------\n\nReleased on Aug 5, 2021.\n\n### Added APIs\n\n -  Added `NonblockRenderer<T>` class.  [[#1402], [#1422]]\n -  Added `NonblockActionRenderer<T>` class.  [[#1402], [#1422]]\n\n[#1402]: https://github.com/planetarium/libplanet/issues/1402\n[#1422]: https://github.com/planetarium/libplanet/pull/1422\n\n\nVersion 0.13.2\n--------------\n\nReleased on Aug 5, 2021.\n\n -  When a reorg happens, `Swarm<T>` now broadcasts a reorged chain tip first\n    before rendering.  [[#1385], [#1415]]\n -  Fixed a bug where `TurnClient` hadn't been recovered when TURN connection\n    had been disconnected.  [[#1424]]\n\n[#1385]: https://github.com/planetarium/libplanet/issues/1385\n[#1415]: https://github.com/planetarium/libplanet/pull/1415\n[#1424]: https://github.com/planetarium/libplanet/pull/1424\n\n\nVersion 0.13.1\n--------------\n\nReleased on July 29, 2021.\n\n -  Fixed `HashAlgorithmType.Digest()` method's bug that it returns an incorrect\n    digest bytes when it is called by multiple threads at a time.  [[#1411]]\n\n[#1411]: https://github.com/planetarium/libplanet/pull/1411\n\n\nVersion 0.13.0\n--------------\n\nReleased on July 28, 2021.\n\n### Backward-incompatible API changes\n\n -  Added `bool render = false` option to `Swarm<T>.PreloadAsync()`.\n    Blocks and actions in preloaded blocks will be rendered if the switch\n    is set to `true`.  [[#1391]]\n\n### Added APIs\n\n -  Added `Transaction<T>.CreateUnsigned()` method.  [[#1378]]\n -  Added `SwarmOptions.TableSize` property.  [[#1401]]\n -  Added `SwarmOptions.BucketSize` property.  [[#1401]]\n\n### Behavioral changes\n\n -  `Transaction<T>.Validate()` became to throw `InvalidTxSignatureException`\n    if the transaction was not signed.  [[#1378]]\n\n### Bug fixes\n\n -  Fixed a bug where `Swarm<T>` had stopped when `ObjectDisposedException`\n    is thrown during `NetMQTransport.DoBroadcast()`.  [[#1362], [#1365]]\n\n[#1362]: https://github.com/planetarium/libplanet/issues/1362\n[#1365]: https://github.com/planetarium/libplanet/pull/1365\n[#1378]: https://github.com/planetarium/libplanet/pull/1378\n[#1391]: https://github.com/planetarium/libplanet/pull/1391\n[#1401]: https://github.com/planetarium/libplanet/pull/1401\n\n\nVersion 0.12.1\n--------------\n\nReleased on July 28, 2021.\n\n -  `Swarm<T>.PreloadAsync()` now checks the existence of blocks in the storage\n    (was in the blockchain).  [[#1324]]\n\n[#1324]: https://github.com/planetarium/libplanet/pull/1324\n\n\nVersion 0.12.0\n--------------\n\nReleased on July 23, 2021.\n\n### Backward-incompatible API changes\n\n -  Block hashes are now represented as `BlockHash`, which was introduced in\n    this release, which has been done as `HashDigest<SHA256>`.\n    [[#1192], [#1197]]\n     -  The type of `Block<T>.Hash` property became `BlockHash`\n        (was `HashDigest<SHA256>`).\n     -  The type of `Block<T>.PreviousHash` property became `BlockHash?`\n        (was `HashDigest<SHA256>?`).\n     -  The types of `Block<T>()` constructors' `hash` parameter became\n        `BlockHash` (were `HashDigest<SHA256>`).\n     -  The types of `Block<T>()` constructors' `previousHash` parameter became\n        `BlockHash?` (were `HashDigest<SHA256>?`).\n     -  The type of `Block<T>.Mine()` method's `previousHash` parameter became\n        `BlockHash?` (was `HashDigest<SHA256>?`).\n     -  The return type of `HashCash.Hash()` method became `BlockHash`\n        (was `HashDigest<SHA256>`).\n     -  The type of `Transaction<T>()` constructor's `genesisHash` parameter\n        became `BlockHash?` (was `HashDigest<SHA256>?`).\n     -  The type of `Transaction<T>.Create()` method's `genesisHash` parameter\n        became `BlockHash?` (was `HashDigest<SHA256>?`).\n     -  The type of `Transaction<T>.GenesisHash` property became `BlockHash?`\n        (was `HashDigest<SHA256>?`).\n     -  The type of `Transaction<T>.EvaluateActionsGradually()` method's\n        `blockHash` parameter became `BlockHash` (was `HashDigest<SHA256>`).\n     -  The type of `Transaction<T>.EvaluateActions()` method's `blockHash`\n        parameter became `BlockHash` (was `HashDigest<SHA256>`).\n     -  The type of `BlockChain[]` indexer's parameter became `BlockHash`\n        (was `HashDigest<SHA256>`).\n     -  The type of `BlockChain.BlockHashes` property became\n        `IEnumerable<BlockHash>` (was `IEnumerable<HashDigest<SHA256>>`).\n     -  The type of `BlockChain.ContainsBlock()` method's `blockHash` parameter\n        became `BlockHash` (was `HashDigest<SHA256>`).\n     -  The type of `BlockChain.GetState()` method's `offset` parameter\n        became `BlockHash?` (was `HashDigest<SHA256>?`).\n     -  The type of `BlockChain.GetBalance()` method's `offset` parameter\n        became `BlockHash?` (was `HashDigest<SHA256>?`).\n     -  The type of `StateCompleter<T>` delegate's `blockHash` parameter\n        became `BlockHash` (was `HashDigest<SHA256>`).\n     -  The type of `FungibleAssetStateCompleter<T>` delegate's `blockHash`\n        parameter became `BlockHash` (was `HashDigest<SHA256>`).\n     -  `BlockSet<T>` no more implements\n        `IDictionary<HashDigest<SHA256>, Block<T>>`, but now implements\n        `IDictionary<BlockHash, Block<T>>`.\n     -  The type of `ActionExecutionState.ExecutedBlockHash` property became\n        `BlockHash` (was `HashDigest<SHA256>`).\n     -  The type of `BlockDownloadState.ReceivedBlockHash` property became\n        `BlockHash` (was `HashDigest<SHA256>`).\n     -  The type of `BlockVerificationState.VerifiedBlockHash` property became\n        `BlockHash` (was `HashDigest<SHA256>`).\n     -  The type of `IncompleteBlockStatesException()` constructor's\n        `blockHash` parameter became `BlockHash` (was `HashDigest<SHA256>`).\n     -  The type of `IncompleteBlockStatesException.BlockHash` property\n        became `BlockHash` (was `HashDigest<SHA256>`).\n     -  The types of `InvalidGenesisBlockException()` constructor's\n        `networkExpected` and `stored` parameters became `BlockHash`\n        (were `HashDigest<SHA256>`).\n     -  The type of `InvalidGenesisBlockException.NetworkExpected` property\n        became `BlockHash` (was `HashDigest<SHA256>`).\n     -  The type of `InvalidGenesisBlockException.Stored` property\n        became `BlockHash` (was `HashDigest<SHA256>`).\n     -  The type of `InvalidTxGenesisHashException()` constructor's\n        `expectedGenesisHash` parameter became `BlockHash`\n        (was `HashDigest<SHA256>`).\n     -  The type of `InvalidTxGenesisHashException()` constructor's\n        `improperGenesisHash` parameter became `BlockHash?`\n        (was `HashDigest<SHA256>?`).\n     -  The type of `InvalidTxGenesisHashException.ExpectedGenesisHash` property\n        became `BlockHash` (was `HashDigest<SHA256>`).\n     -  The type of `InvalidTxGenesisHashException.ImproperGenesisHash` property\n        became `BlockHash?` (was `HashDigest<SHA256>?`).\n     -  The return type of `IStore.IndexBlockHash()` method became `BlockHash?`\n        (was `HashDigest<SHA256>?`).\n     -  The type of `IStore.AppendIndex()` method's `hash` parameter became\n        `BlockHash` (was `HashDigest<SHA256>`).\n     -  Replaced `IStore.ForkBlockIndexes()` method's\n        `HashDigest<SHA256> branchPoint` parameter with `BlockHash branchpoint`.\n     -  The return type of `IStore.IterateIndexes()` method became\n        `IEnumerable<BlockHash>` (was `IEnumerable<HashDigest<SHA256>>`).\n     -  The return type of `IStore.IterateBlockHashes()` method became\n        `IEnumerable<BlockHash>` (was `IEnumerable<HashDigest<SHA256>>`).\n     -  The type of `IStore.GetBlock<T>()` method's `blockHash` parameter\n        became `BlockHash` (was `HashDigest<SHA256>`).\n     -  The type of `IStore.GetBlockIndex()` method's `blockHash` parameter\n        became `BlockHash` (was `HashDigest<SHA256>`).\n     -  The type of `IStore.GetBlockDigest()` method's `blockHash` parameter\n        became `BlockHash` (was `HashDigest<SHA256>`).\n     -  The type of `IStore.DeleteBlock()` method's `blockHash` parameter\n        became `BlockHash` (was `HashDigest<SHA256>`).\n     -  The type of `IStore.ContainsBlock()` method's `blockHash` parameter\n        became `BlockHash` (was `HashDigest<SHA256>`).\n     -  The type of `IStateStore.GetState()` method's `blockHash` parameter\n        became `BlockHash` (was `HashDigest<SHA256>`).\n     -  The type of `IStateStore.ContainsBlockStates()` method's `blockHash`\n        parameter became `BlockHash` (was `HashDigest<SHA256>`).\n     -  The type of `TrieStateStore.GetRootHash()` method's `blockHash`\n        parameter became `BlockHash` (was `HashDigest<SHA256>`).\n     -  The type of `TrieStateStore.PruneStates()` method's `excludeBlockHashes`\n        parameter became `IImmutableSet<BlockHash>`\n        (was `ImmutableHashSet<HashDigest<SHA256>>`).\n -  Hash algorithm for <abbr title=\"proof-of-work\">PoW</abbr> (Hashcash) became\n    configurable.  [#1314], [#1352]\n     -  Added `IBlockPolicy<T>.GetHashAlgorithm()` method.\n     -  Added an optional `HashAlgorithmType? hashAlgorithm` parameter to\n        `Block<T>(long, long, BigInteger, Nonce, Address?, BlockHash?,\n        DateTimeOffset, IReadOnlyList<Transaction<T>>, ImmutableArray<byte>?,\n        HashDigest<SHA256>?, int protocolVersion)` constructor.\n     -  Added `HashAlgorithmType hashAlgorithm` parameter to\n        `Block<T>.MineBlock()` method.\n     -  The type of `Block<T>.PreEvaluationHash` property became\n        `ImmutableArray<byte>?` (was `HashDigest<SHA256>?`).\n        [[#1192], [#1197]]\n     -  The types of `Block<T>()` constructors' `preEvaluationHash` parameter\n        became `ImmutableArray<byte>?` (were `HashDigest<SHA256>?`).\n        [[#1192], [#1197]]\n     -  The type of\n        `InvalidBlockPreEvaluationHashException.ActualPreEvaluationHash` and\n        `ExpectedPreEvaluationHash` properties became `ImmutableArray<byte>`\n        (were `HashDigest<SHA256>`).  [[#1192], [#1197]]\n     -  The type of `InvalidBlockPreEvaluationHashException()` constructor's\n        `actualPreEvaluationHash` and and `expectedPreEvaluationHash` parameters\n        became `ImmutableArray<byte>` (were `HashDigest<SHA256>`).\n        [[#1192], [#1197]]\n     -  Replaced `UnexpectedlyTerminatedActionException()` constructor's\n        `HashDigest<SHA256>? blockHash` parameter with\n        `ImmutableArray<byte>? preEvaluationHash`.\n        [[#1192], [#1197]]\n     -  Replaced `UnexpectedlyTerminatedActionException.BlockHash` property with\n        `PreEvaluationHash.`  [[#1192], [#1197]]\n     -  Replaced `Hashcash.Answer(Stamp, long, CancellationToken)` method with\n        `Hashcash.Answer<T>(Stamp, HashAlgorithm, long, CancellationToken)`\n        method.\n     -  Removed `Hashcash.Hash()` method.\n     -  Removed `HashDigest<T>.Satisfies()` method.  This was replaced by\n        `ByteUtil.Satisfies()` method instead.  [[#1192], [#1197]]\n     -  Added `hashAlgorithmGetter` parameter to `BlockSet<T>()` constructor.\n     -  Added `hashAlgorithm` parameter to `BlockChain<T>.MakeGenesisBlock()`\n        method.\n     -  Added an optional `hashAlgorithmGetter` parameter to `BlockPolicy<T>()`\n        constructor.\n -  Added `IActionContext.TxId` property.  [[#1275]]\n -  Added `IStore.PutTxExecution(TxSuccess)` method.  [[#1156], [#1289]]\n -  Added `IStore.PutTxExecution(TxFailure)` method.  [[#1156], [#1289]]\n -  Added `IStore.GetTxExecution()` method.  [[#1156], [#1289]]\n -  Removed the optional parameter `Guid? chainId = null` from\n    `IStateStore.GetState()` method.  [[#1289]]\n -  Removed `compress` parameter from `DefaultStore()` constructor.  [[#1289]]\n -  Removed `statesCacheSize` parameter from `DefaultStore()` constructor.\n    [[#1289]]\n -  Removed `StunMessage.Parse(Stream)` method.  [[#1228]]\n -  Moved `ITransport` and `NetMQTransport` from `Libplanet.Net` to\n    `Libplanet.Net.Transports`.  [[#1235]]\n -  `Block<T>` now enforces a collection of `Transaction<T>`s to be less\n    mutable.  [[#1274]]\n     -  The type of `Block<T>()` constructor's `transactions` parameter became\n        `IReadOnlyList<T>` (was `IEnumerable<T>`).\n     -  The type of `Transactions` property of `Block<T>` became\n        `IReadOnlyList<T>` (was `IEnumerable<T>`).\n -  Types of following properties became `IReadOnlyList<T>`\n    (was `IEnumerable<T>`).  [[#1230], [#1271]]\n     -  `RoutingTable.Peers`\n     -  `RoutingTable.PeerStates`\n     -  `Swarm<T>.Peers`\n     -  `Swarm<T>.PeerStates`\n -  Return type of `RoutingTable.Neighbors()` became `IReadOnlyList<BoundPeer>`\n    (was `IEnumerable<BoundPeer>`).  [[#1230], [#1271]]\n -  All methods pertaining to evaluating `IAction`s are moved\n    to a new `ActionEvaluator` class.  [[#1301], [#1305]]\n     -  Removed `Block<T>.Evaluate()` method.\n        Use `ActionEvaluator.Evaluate()` method instead.\n     -  Removed `Block<T>.EvaluateActionsPerTx()` method.\n     -  Removed `Transaction<T>.EvaluateActionsGradually()` method.\n     -  Removed `Transaction<T>.EvaluateActions()` method.\n -  Parameters `action`, `inputContext`, and `outputStates` for\n    `ActionEvaluation()` constructor can no longer be `null`.  [[#1305]]\n -  Added `IStore.PutTxIdBlockHashIndex(TxId, BlockHash)` method.\n    [[#1294], [#1328]]\n -  Added `IStore.GetFirstTxIdBlockHashIndex(TxId)` method.\n    [[#1294], [#1328]]\n -  Added `IStore.DeleteTxIdBlockHashIndex(TxId, BlockHash)` method.\n    [[#1294], [#1328]]\n -  Added `IStore.IterateTxIdBlockHashIndex(TxId)` method.  [[#1294], [#1328]]\n -  Parameter `miner` for `Block<T>()` and `Block<T>.Mine()` can no longer be\n    `null`.  [[#1341]]\n -  `Swarm<T>.StartAsync()` method became to receive `broadcastBlockInterval`\n    (or `millisecondsBroadcastBlockInterval`) parameter.  [[#1351]]\n -  Added the parameter `minimumBroadcastTarget` to `NetMQTransport()`\n    constructor.  [[#1379]]\n -  Removed `InvalidTxUpdatedAddressesException`.  [[#368], [#1389]]\n\n### Added APIs\n\n -  Added `ActionEvaluator` class.  [[#1301], [#1305]]\n -  Added `BlockHash` struct.  [[#1192], [#1197]]\n -  Added `HashDigest<T>.DeriveFrom()` method.  [[#1197]]\n -  Added `HashAlgorithmType` class.  [[#1314], [#1352]]\n -  Added `HashAlgorithmGetter` delegate.  [[#1314], [#1352]]\n -  Added `HashAlgorithmTable` static class.  [[#1314], [#1352]]\n -  Added `BlockChain<T>.GetTxExecution()` method.  [[#1156], [#1289]]\n -  Added `StunMessage.ParseAsync(Stream, CancellationToken)` method.\n    [[#1228]]\n -  Added `Swarm<T>.AddPeersAsync()` method.  [[#1234]]\n -  Added `NetMQTransport.QueryAppProtocolVersion()` static method.  [[#1235]]\n -  Added `BoundPeer.Parse()` static method.  [[#1240]]\n -  Added `TransportException` class.  [[#1242]]\n -  Added `SwarmOptions.StaticPeers` property.  [[#1230], [#1271]]\n -  Added `SwarmOptions.StaticPeersMaintainPeriod` property.  [[#1230], [#1367]]\n -  Added `SwarmOptions.BranchpointThreshold` property.  [[#1348]]\n -  Added `AtomicActionRenderer<T>` class.  [[#1267], [#1275]]\n -  Added `TxExecution` abstract class.  [[#1156], [#1289]]\n -  Added `TxSuccess` class.  [[#1156], [#1289]]\n -  Added `TxFailure` class.  [[#1156], [#1289]]\n -  Added `IExtractableException` interface.  [[#1156], [#1289]]\n -  Added `ExtractableException` static class.  [[#1156], [#1289]]\n -  Added `Address(Binary)` overloaded constructor.  [[#1289]]\n -  Added `Currency(IValue)` overloaded constructor.  [[#1289]]\n -  Added `Currency.Serialize()` method.  [[#1289]]\n -  Added `ByteUtil.TimingSafelyCompare()` method.  [[#1314], [#1352]]\n -  Added `ByteUtil.Satisfies()` method.  [[#1314], [#1352]]\n -  Added `BlockChain<T>.ExecuteActions()` method.  [[#1368]]\n -  Added `SwarmOptions.MinimumBroadcastTarget` property.  [[#1379]]\n\n### Behavioral changes\n\n -  `BlockChain<T>.Append()` now records a `TxExecution` for every single\n    transaction in the appended `Block<T>`, whether a transaction is successful\n    (`TxSuccess` is recorded for this case) or not (`TxFailure` is recorded\n    for this case).  [[#1156], [#1289]]\n -  `ITransport.StartAsync()` and `ITransport.RunAsync()` became to throw\n    `TransportException` instead of `SwarmException`.  [[#1242]]\n -  `NetMQTransport` became to enforce NetMQ/[AsyncIO] to use its pure .NET\n    implementation instead of Windows'\n    <abbr title=\"input/output completion port\">IOCP</abbr> when it is running\n    on Mono, which powers Unity engine, since Unity does not properly\n    implement the IOCP even on Windows.\n    It had been done by `Swarm<T>`, but as the `ITransport` is now separated\n    from it, this became done by `NetMQTransport` instead of `Swarm<T>`.\n    [[#247], [#1278]]\n -  (Libplanet.RocksDBStore) `RocksDBStore.ForkBlockIndexes()` became to share\n    common ancestors between forks rather than duplicating them so that much\n    less space is used.  [[#1280], [#1287]]\n -  `BlockChain<T>.Append()` cumulates indexes for pairs (TxId and BlockHash).\n    A transaction inclusion for a block is retrievable by using this index.\n    [[#1315], [#1329]]\n -  `ActionEvaluator<T>.EvaluateActions()` now throws an unmanaged exception\n    if `OutOfMemoryException` is caught from `IAction.Execute()`.\n    [[#1320], [#1343]]\n -  Improved performance of broadcasting using `Swarm<T>`.  [[#1334]]\n -  `Swarm<T>` now maintains static peers provided via\n    `SwarmOptions.StaticPeers` periodically.  [[#1230], [#1367]]\n -  `Block<T>.Header` is now cached instead of creating a new instance every\n    call.  [[#1347]]\n -  `BlockChain<T>.ExecuteActions()` became no longer throw\n    `InvalidTxUpdatedAddressesException`.  [[#368], [#1389]]\n\n### Bug fixes\n\n -  Fixed a bug where executing `Transaction<T>.Actions` had not been atomic.\n    `Actions` in a `Transaction<T>` now became executed all or nothing at all.\n    [[#1267], [#1275]]\n     -  `Transaction<T>.EvaluateActions()` method became atomic.\n     -  `Transaction<T>.EvaluateActionsGradually()` method had returned\n        the same number of `ActionEvaluation`s to `Transaction<T>.Actions`,\n        but now became to omit the evaluations after the first action throwing\n        an exception.  If no action throws any exception, it still returns\n        the same number of `ActionEvaluation`s to `Transaction<T>.Actions`.\n     -  State-wise, `Transaction<T>`s having any exception-throwing action\n        now do not commit any changes at all to `IStateStore`.\n     -  Rendering-wise, for actions following the first exception-throwing\n        action, action rendering methods in `IActionRenderer<T>`\n        (`RenderAction()`, `RenderActionError()`, `UnrenderAction()`, and\n        `UnrenderActionError()`) became not invoked.\n        If you want to dismiss all actions in unsuccessful transactions at all,\n        wrap your action renderer with `AtomicActionRenderer<T>`.\n -  Fixed a bug where `KademliaProtocol.BootstrapAsync()` has sent multiple\n    `Ping` messages to other peers.  [[#1219]]\n -  Fixed a bug where `KademliaProtocol.CheckReplacementCacheAsync()` has\n    updated cached peers multiple times.  [[#1219]]\n -  Fixed memory leak due to undisposed `CancellationTokenRegistration`s.\n    [[#1228]]\n -  Fixed a bug where `DefaultStore.Dispose()` and `TrieStateStore.Dispose()`\n    had not been idempotent.  [[#1272]]\n -  (Libplanet.RocksDBStore) Fixed a bug where `RocksDBStore.Dispose()`,\n    `MonoRocksDBStore.Dispose()`, and `RocksDBKeyValueStore.Dispose()` had not\n    been idempotent.  [[#1272], [#1289]]\n -  Fixed a bug where `NetMQTransport` had hung forever within Mono runtime.\n    [[#1278]]\n -  Fixed a bug where `DefaultStore.ForkBlockIndexes()` hadn't copied genesis\n    block.  [[#1325]]\n -  (Libplanet.RocksDBStore) Fixed a bug where `RocksDBStore.GetBlock<T>()`\n    and `RocksDBStore.GetTransaction<T>()` handn't returned expected values\n    in multithreading environment.  [[#1339], [#1342]]\n -  Fixed a bug where chain synchronization had been incorrectly updated with\n    an improper chain.  [[#1349], [#1350]]\n -  Fixed a bug where `Swarm<T>` hadn't respond immediately under load.\n    [[#1360]]\n\n### CLI tools\n\n -  Added the option `--json` to `planet apv analyze` command to print result\n    as JSON format.  [[#1240]]\n -  Added `planet apv query` subcommand to query app protocol version of\n    specific peer.  [[#1240]]\n -  Added the option `--no-passphrase` to `planet key remove` command to remove\n    key without asking passphrase.  [[#1213], [#1265]]\n -  Added `planet key derive` subcommand to derive the address or\n    public key from a private.  [[#1268]]\n -  Added `planet store [block-by-hash|block-by-index|tx-by-id]` commands\n    to retrieve the data from the store.  [[#1284], [#1285], [#1298]]\n -  Added `planet store block-by-tx-id` commands\n    to retrieve the data from the store.  [[#1316], [#1340]]\n -  Added `planet store build-index-tx-block` commands\n    to build index from TxId to BlockHash.  [[#1316], [#1340]]\n -  Added `planet stats summary` command to retrieve a state summary of a\n    stored chain in a CSV format.  [[#1353]]\n\n[#1156]: https://github.com/planetarium/libplanet/issues/1156\n[#1192]: https://github.com/planetarium/libplanet/issues/1192\n[#1197]: https://github.com/planetarium/libplanet/pull/1197\n[#1213]: https://github.com/planetarium/libplanet/issues/1213\n[#1219]: https://github.com/planetarium/libplanet/pull/1219\n[#1228]: https://github.com/planetarium/libplanet/pull/1228\n[#1230]: https://github.com/planetarium/libplanet/issues/1230\n[#1234]: https://github.com/planetarium/libplanet/pull/1234\n[#1235]: https://github.com/planetarium/libplanet/pull/1235\n[#1240]: https://github.com/planetarium/libplanet/pull/1240\n[#1242]: https://github.com/planetarium/libplanet/pull/1242\n[#1265]: https://github.com/planetarium/libplanet/pull/1265\n[#1267]: https://github.com/planetarium/libplanet/issues/1267\n[#1268]: https://github.com/planetarium/libplanet/pull/1268\n[#1271]: https://github.com/planetarium/libplanet/pull/1271\n[#1272]: https://github.com/planetarium/libplanet/pull/1272\n[#1274]: https://github.com/planetarium/libplanet/pull/1274\n[#1275]: https://github.com/planetarium/libplanet/pull/1275\n[#1278]: https://github.com/planetarium/libplanet/pull/1278\n[#1280]: https://github.com/planetarium/libplanet/issues/1280\n[#1284]: https://github.com/planetarium/libplanet/issues/1284\n[#1285]: https://github.com/planetarium/libplanet/issues/1285\n[#1287]: https://github.com/planetarium/libplanet/pull/1287\n[#1289]: https://github.com/planetarium/libplanet/pull/1289\n[#1294]: https://github.com/planetarium/libplanet/issues/1294\n[#1298]: https://github.com/planetarium/libplanet/pull/1298\n[#1301]: https://github.com/planetarium/libplanet/issues/1301\n[#1305]: https://github.com/planetarium/libplanet/pull/1305\n[#1314]: https://github.com/planetarium/libplanet/issues/1314\n[#1315]: https://github.com/planetarium/libplanet/issues/1315\n[#1316]: https://github.com/planetarium/libplanet/issues/1316\n[#1320]: https://github.com/planetarium/libplanet/issues/1320\n[#1325]: https://github.com/planetarium/libplanet/pull/1325\n[#1326]: https://github.com/planetarium/libplanet/pull/1326\n[#1328]: https://github.com/planetarium/libplanet/pull/1328\n[#1329]: https://github.com/planetarium/libplanet/pull/1329\n[#1334]: https://github.com/planetarium/libplanet/pull/1334\n[#1339]: https://github.com/planetarium/libplanet/issues/1339\n[#1340]: https://github.com/planetarium/libplanet/pull/1340\n[#1341]: https://github.com/planetarium/libplanet/pull/1341\n[#1342]: https://github.com/planetarium/libplanet/pull/1342\n[#1343]: https://github.com/planetarium/libplanet/pull/1343\n[#1347]: https://github.com/planetarium/libplanet/pull/1347\n[#1348]: https://github.com/planetarium/libplanet/pull/1348\n[#1349]: https://github.com/planetarium/libplanet/issues/1349\n[#1350]: https://github.com/planetarium/libplanet/pull/1350\n[#1351]: https://github.com/planetarium/libplanet/pull/1351\n[#1352]: https://github.com/planetarium/libplanet/pull/1352\n[#1353]: https://github.com/planetarium/libplanet/pull/1353\n[#1360]: https://github.com/planetarium/libplanet/pull/1360\n[#1367]: https://github.com/planetarium/libplanet/pull/1367\n[#1368]: https://github.com/planetarium/libplanet/pull/1368\n[#1379]: https://github.com/planetarium/libplanet/pull/1379\n[#1389]: https://github.com/planetarium/libplanet/pull/1389\n\n\nVersion 0.11.1\n-------------\n\nReleased on April 22, 2021.\n\n -  Fixed a bug where block synchronization had stopped due to internal\n    errors.  [[#1259]]\n\n[#1259]: https://github.com/planetarium/libplanet/pull/1259\n\n\nVersion 0.11.0\n--------------\n\nReleased on March 30, 2021.\n\n### Backward-incompatible API changes\n\n -  Added the parameter `protocolVersion` to `Block<T>(long, long, BigInteger,\n    Nonce, Address?, HashDigest<SHA256>?, DateTimeOffset,\n    IEnumerable<Transaction<T>> transactions, HashDigest<SHA256>?,\n    HashDigest<SHA256>?)` constructor.  [[#1142], [#1147], [#1162]]\n -  Added the parameter to `protocolVersion` to `Block<T>.Mine()` method.\n    [[#1142], [#1147], [#1162]]\n -  Added the first parameter `protocolVersion` to `BlockHeader()` constructor.\n    [[#1142], [#1147], [#1162]]\n -  Added `stagePolicy` as the second parameter to `BlockChain<T>()`\n    constructor.  [[#1130], [#1131]]\n -  Added `IBlockPolicy<T>.CanonicalChainComparer` property to make\n    the canonical chain.  [[#1155], [#1165], [#1184]]\n -  Added `canonicalChainComparer` as the last parameter to `BlockPolicy()`\n    constructors.  [[#1155], [#1165], [#1184]]\n -  Added `canonicalChainComparer` as the second parameter to\n    `DelayedRenderer()` constructor.  [[#1155], [#1165], [#1184]]\n -  Added `canonicalChainComparer` as the second parameter to\n    `DelayedActionRenderer()` constructor.  [[#1155], [#1165], [#1184]]\n -  Added `reorgResistantHeight` parameter into `DelayedActionRenderer<T>()`\n    constructor.  [[#1163]]\n -  Added `IStore.SetBlockPerceivedTime()` method.  [[#1184]]\n -  Added `IStore.GetBlockPerceivedTime()` method.  [[#1184]]\n -  Removed `TransactionSet<T>` class.  [[#1165]]\n -  Removed `IBlockStatesStore` interface.  [[#1117]]\n -  Removed `BaseBlockStatesStore` abstract class.  [[#1117]]\n -  Removed `Swarm<T>.GetTrustedStateCompleterAsync()` method.  [[#1117]]\n -  Removed `trustedStateValidators` parameter from `Swarm<T>.PreloadAsync()`\n    method.  [[#1117]]\n -  Removed `Swarm<T>.TraceTable()` method.  [[#1120]]\n -  Added `IActionContext.BlockAction` property.  [[#1143]]\n -  Added nullable `TimeSpan`-typed `messageLifespan` parameter into\n    `NetMQTransport()` constructor.  [[#1171]]\n -  Added `IStore.ForkTxNonces()` method.  [[#1198]]\n -  Removed `PeerState.Address` Property.  [[#1215]]\n -  `IProtocol.RebuildConnectionAsync(CancellationToken)` method was\n    replaced by, `IProtocol.RebuildConnectionAsync(int, CancellationToken)`\n    method.  [[#1215]]\n\n### Backward-incompatible network protocol changes\n\n -  `Swarm<T>` became no longer retry when `Swarm<T>` receives\n    less than 500 blocks.  [[#1112]]\n -  The existing `ChainStatus` message type (with the type number `0x24`) was\n    replaced by a new `ChainStatus` message type (with the type number `0x25`).\n    [[#1155], [#1165]]\n -  Removed the message types depended on features of `IBlockStatesStore`\n    interface.  [[#1117]]\n     -  `GetRecentStates` message type (with the type number `0x0b`)\n     -  `RecentStates` message type (with the type number `0x13`)\n     -  `GetBlockStates` message type (with the type number `0x22`)\n     -  `BlockStates` message type (with the type number `0x23`)\n -  `Swarm<T>` became to ignore messages made earlier than a certain amount of\n    time, which is configured by `SwarmOptions.MessageLifespan`.\n    [[#1160], [#1171]]\n\n### Backward-incompatible storage format changes\n\n -  (Libplanet.RocksDBStore) The blocks and transactions became stored in\n    multiple databases.  Each block and transaction belongs to a partition\n    of the database, according to its epoch unit, which is its Unix timestamp.\n    Every epoch is divided by certain seconds, configured by `RocksDBStore()`\n    constructor's `txEpochUnitSeconds` and `blockEpochUnitSeconds` parameters\n    (86,400 by default).   [[#1183], [#1194]]\n -  (Libplanet.RocksDBStore) Continue on partitioning of database,\n    `RocksDBStore()` is manage database connection by LRU Cache.\n    The max size of connection cache is configured by `RocksDBStore()`\n    constructor's `dbConnectionCacheSize` parameters (100\n    by default).   [[#1183], [#1194]]\n -  (Libplanet.RockDBStore) The `RocksDBStore` that was previously used\n    has been separated into a class called `MonoRocksDBStore`.\n    Please use this class if you need to migrate.   [[#1183], [#1204]]\n\n### Added APIs\n\n -  Added `Block<T>.CurrentProtocolVersion` constant.  [[#1142], [#1147]]\n -  Added `Block<T>.ProtocolVersion` property.  [[#1142], [#1147]]\n -  Added `Block<T>.Header` property.  [[#1070], [#1102]]\n -  Added `BlockHeader.ProtocolVersion` property.  [[#1142], [#1147]]\n -  Added `IBlockExcerpt` interface.  [[#1155], [#1165], [#1170]]\n -  Added `BlockExcerpt` static class.  [[#1155], [#1165], [#1170], [#1184]]\n -  `Block<T>` became to implement `IBlockExcerpt` interface.\n    [[#1155], [#1165], [#1170]]\n -  `BlockHeader` became to implement `IBlockExcerpt` interface.\n    [[#1155], [#1165], [#1170]]\n -  Added `BlockPerception` struct.  [[#1155], [#1184]]\n -  Added `BlockChain<T>.PerceiveBlock()` method.  [[#1155], [#1184]]\n -  Added `DelayedRenderer<T>.CanonicalChainComparer` and\n    `DelayedActionRenderer<T>.CanonicalChainComparer` properties.\n    [[#1155], [#1165], [#1184]]\n -  Added `TotalDifficultyComparer` class.  [[#1155], [#1165], [#1170], [#1184]]\n -  Added `IStagePolicy<T>` interface.  [[#1130], [#1131], [#1186]]\n -  Added `VolatileStagePolicy<T>` class.  [[#1130], [#1131], [#1136], [#1186]]\n -  Added `ITransport` interface.  [[#1052]]\n -  Added `NetMQTransport` class which implements `ITransport`.  [[#1052]]\n -  Added `Message` abstract class.  [[#1052]]\n -  Added `BlockExceedingTransactionsException` class.  [[#1104], [#1110]]\n -  Added `BlockChain<T>.GetStagedTransactionIds()` method.  [[#1089]]\n -  (Libplanet.RocksDBStore) Added `maxTotalWalSize`, `keepLogFileNum` and\n    `maxLogFileSize` parameters into `RocksDBStore()` constructor.\n    [[#1065], [#1102], [#1132]]\n -  Added `Swarm<T>.BlockDemand` property.  [[#1068], [#1102]]\n -  Added `BlockDemand` struct.  [[#1068], [#1102]]\n -  Added `TurnClient.PublicAddress` property.  [[#1074], [#1102]]\n -  Added `TurnClient.EndPoint` property.  [[#1074], [#1102]]\n -  Added `TurnClient.BehindNAT` property.  [[#1074], [#1102]]\n -  Added `TurnClient.InitializeTurnAsync(int, CancellationToken)` method.\n    [[#1074], [#1102]]\n -  Added `TurnClient.StartAsync(int, CancellationToken)` method.\n    [[#1074], [#1102]]\n -  Added `TurnClient.ReconnectTurn(int, CancellationToken)` method.\n    [[#1074], [#1102]]\n -  Added `TurnClient.IsConnectable(CancellationToken)` method.\n    [[#1074], [#1102]]\n -  Added `TurnClient.ReconnectTurn(CancellationToken)` method.\n    [[#1074], [#1102]]\n -  Added `Libplanet.Blockchain.Renderers.Debug.RenderRecord<T>` abstract class\n    and its subclasses:  [[#1119]]\n     -  `RenderRecord<T>.ActionBase` abstract class\n     -  `RenderRecord<T>.ActionSuccess` class\n     -  `RenderRecord<T>.ActionError` class\n     -  `RenderRecord<T>.BlockBase` abstract class\n     -  `RenderRecord<T>.Block` class\n     -  `RenderRecord<T>.Reorg` class\n -  Added `Libplanet.Blockchain.Renderers.Debug.RecordingActionRenderer<T>`\n    class.  [[#1119]]\n -  Added `Libplanet.Blockchain.Renderers.Debug.ValidatingActionRenderer<T>`\n    class.  [[#1119]]\n -  Added `Libplanet.Blockchain.Renderers.Debug.InvalidRenderException<T>`\n    class.  [[#1119]]\n -  Added `InvalidBlockProtocolVersionException` class.  [[#1142], [#1147]]\n -  Added `InvalidBlockTxHashException` class.  [[#1116]]\n -  Added `Swarm<T>.PeerStates` property.  [[#1120]]\n -  Added `IProtocol` interface.  [[#1120]]\n -  Added `KademliaProtocol` class which implements `IProtocol`.\n    [[#1120], [#1135]]\n -  Added `reorgResistantHeight` parameters into `DelayedActionRenderer<T>()`\n    constructor.  [[#1163]]\n -  Added `InvalidBlockPreEvaluationHashException` class.  [[#1148]]\n -  Added the parameter `validate` which is `true` by default,\n    to `Transaction<T>.Deserialize()`.  [[#1149]]\n -  Added `SwarmOptions.MessageLifespan` property.  [[#1171]]\n -  Added `InvalidTimestampException` class.  [[#1171]]\n -  Added `PeerState.Peer` Property.  [[#1215]]\n -  Added `SwarmOptions.RefreshPeriod` property,\n    which is 10 seconds by default.  [[#1215]]\n -  Added `SwarmOptions.RefreshLifespan` property,\n    which is 60 seconds by default.  [[#1215]]\n\n### Behavioral changes\n\n -  Upgraded *Bencodex* package (which is a dependency) so that Libplanet gets\n    benefits from its recent optimizations.\n    [[#1081], [#1084], [#1086], [#1101]]\n -  Introduced the [protocol versioning scheme][#1142].  This purposes to change\n    the protocol without breaking backward compatibility.  Even the protocol\n    is changed, the existing blocks made before the new protocol are guaranteed\n    to behave as it had done.\n    [[#1142], [#1147], [#1155] [#1162], [#1170], [#1184]]\n -  Since `BlockHeader.ProtocolVersion` was added, the existing blocks are\n    considered protocol compliant with the protocol version zero.\n    [[#1142], [#1147], [#1162]]\n -  When a `BlockChain<T>` follows `VolatileStagePolicy<T>`, which is\n    Libplanet's the only built-in `IStagePolicy<T>` implementation at\n    the moment, as its `StagePolicy`, its staged transactions are no longer\n    persistent but volatile instead.  It also automatically purges staged\n    transactions after the given `Lifetime`, which is 3 hours by default.\n    [[#1130], [#1131], [#1136], [#1186]]\n -  `Swarm<T>` became not to receive states from trusted peers.\n    [[#1061], [#1102]]\n -  `Swarm<T>` became not to retry when block downloading.  [[#1062], [#1102]]\n -  Improved performance of `BlockChain<T>.MineBlock()`.  [[#1116], [#1124]]\n -  Improved performance of `Block<T>.Deserialize()`.  [[#1116]]\n -  `Swarm<T>` became not to fill states from trusted peers, because now states\n    can be validated rather than trusted due to MPT.  [[#1117]]\n -  `HashDigest<SHA256>` became serializable.  [[#795], [#1125]]\n -  `Transaction<T>()` constructors became not to validate itself.  [[#1149]]\n -  `BlockChain<T>.Append()` became to validate the given `Block<T>`\n    before storing its `StateRootHash`.  [[#1172]]\n -  `Blockchain<T>` became not to stage transactions having nonce\n    less than or equal to the nonce of the same signer's latest\n    transaction in already mined blocks.  [[#1173], [#1180], [#1186]]\n -  Improved security of `Message.Parse()`.  [[#1161], [#1181]]\n -  Improved performance of `BlockChain<T>.Fork()`.  [[#1198]]\n -  `Swarm<T>` became not to call `KademliaProtocol.RebuildConnectionAsync()`\n    right after `Swarm<T>.StartAsync()`.  If you called\n    `Swarm<T>.BootstrapAsync()` before `Swarm<T>.StartAsync()`,\n    peers in your table may not have you in their table right after\n    `Swarm<T>.StartAsync()` (which was almost guaranteed before).  [[#1208]]\n -  Peers added during `Swarm<T>.BootstrapAsync()` before\n    `Swarm<T>.StartAsync()` are now marked as stale so that\n    `Swarm<T>.RefreshTableAsync()` will update.  [[#1215]]\n -  Following classes became to leave log messages with its class as logging\n    context.  [[#1218]]\n     -  `TrieStateStore` class\n     -  `TurnClient` class\n     -  `ActionEvaluation` class\n\n### Bug fixes\n\n -  Fixed a bug where `BlockChain<T>.MineBlock()` was not automatically\n    cancelled when the tip of the chain was changed occasionally.  [[#1141]]\n -  Fixed a bug where blocks with invalid `PreEvaluationHash` was considered\n    as a valid block.  [[#1148], [#1202]]\n -  Fixed a vulnerability of the `IAccountStateDelta.TransferAsset()`'s\n    internal implementation that it had doubled recipient's balance when\n    a sender and a recipient is the same.\n    *Since this changes the protocol, for backward compatibility, the actions\n    belonging to the existing block, which was mined before the protocol v1,\n    are guaranteed to still behave as it had done.  [[#1152]]\n -  Fixed a bug where `Block<T>.Evaluate()` hadn't validate its hash.  [[#1168]]\n -  Fixed memory leak due to undisposed `CancellationTokenSource`s.\n    [[#1182], [#1212]]\n -  Fixed a bug where `TurnClient` hadn't released its relay connections after\n    reconnecting.  [[#1185]]\n\n### CLI tools\n\n -  `planet mpt diff` command became to take 4 arguments (which was 3)\n    so that it can compare state root hashes from two different\n    <abbr title=\"key–value\">KV</abbr> stores.  The existing commands\n    like `planet mpt diff STORE A B` do not work anymore,\n    and these should be instead like `planet mpt diff STORE A STORE B`.\n    [[#1129]]\n -  Store aliases used by `planet mpt` became to disallow names looking like\n    URIs to disambiguate aliases from the literal store URIs.  [[#1129]]\n -  Added new subcommands `planet mpt list` and `planet mpt query`.  [[#1137]]\n -  `planet mpt diff` command became to print the differences between\n    other state root hashes into stdout as JSON format.\n    [[#1138], [#1191], [#1233]]\n\n[#795]: https://github.com/planetarium/libplanet/issues/795\n[#1052]: https://github.com/planetarium/libplanet/pull/1052\n[#1061]: https://github.com/planetarium/libplanet/pull/1061\n[#1062]: https://github.com/planetarium/libplanet/pull/1062\n[#1065]: https://github.com/planetarium/libplanet/pull/1065\n[#1068]: https://github.com/planetarium/libplanet/pull/1068\n[#1070]: https://github.com/planetarium/libplanet/pull/1070\n[#1074]: https://github.com/planetarium/libplanet/pull/1074\n[#1081]: https://github.com/planetarium/libplanet/pull/1081\n[#1084]: https://github.com/planetarium/libplanet/pull/1084\n[#1086]: https://github.com/planetarium/libplanet/pull/1086\n[#1089]: https://github.com/planetarium/libplanet/pull/1089\n[#1101]: https://github.com/planetarium/libplanet/pull/1101\n[#1102]: https://github.com/planetarium/libplanet/pull/1102\n[#1110]: https://github.com/planetarium/libplanet/pull/1110\n[#1112]: https://github.com/planetarium/libplanet/pull/1112\n[#1116]: https://github.com/planetarium/libplanet/pull/1116\n[#1117]: https://github.com/planetarium/libplanet/pull/1117\n[#1119]: https://github.com/planetarium/libplanet/pull/1119\n[#1120]: https://github.com/planetarium/libplanet/pull/1120\n[#1124]: https://github.com/planetarium/libplanet/pull/1124\n[#1125]: https://github.com/planetarium/libplanet/pull/1125\n[#1129]: https://github.com/planetarium/libplanet/pull/1129\n[#1130]: https://github.com/planetarium/libplanet/issues/1130\n[#1131]: https://github.com/planetarium/libplanet/pull/1131\n[#1132]: https://github.com/planetarium/libplanet/pull/1132\n[#1135]: https://github.com/planetarium/libplanet/pull/1135\n[#1136]: https://github.com/planetarium/libplanet/pull/1136\n[#1137]: https://github.com/planetarium/libplanet/pull/1137\n[#1138]: https://github.com/planetarium/libplanet/issues/1138\n[#1141]: https://github.com/planetarium/libplanet/pull/1141\n[#1142]: https://github.com/planetarium/libplanet/issues/1142\n[#1143]: https://github.com/planetarium/libplanet/pull/1143\n[#1147]: https://github.com/planetarium/libplanet/pull/1147\n[#1148]: https://github.com/planetarium/libplanet/issues/1148\n[#1149]: https://github.com/planetarium/libplanet/issues/1149\n[#1152]: https://github.com/planetarium/libplanet/pull/1152\n[#1155]: https://github.com/planetarium/libplanet/issues/1155\n[#1160]: https://github.com/planetarium/libplanet/issues/1160\n[#1161]: https://github.com/planetarium/libplanet/issues/1161\n[#1162]: https://github.com/planetarium/libplanet/pull/1162\n[#1163]: https://github.com/planetarium/libplanet/pull/1163\n[#1165]: https://github.com/planetarium/libplanet/pull/1165\n[#1168]: https://github.com/planetarium/libplanet/pull/1168\n[#1170]: https://github.com/planetarium/libplanet/pull/1170\n[#1171]: https://github.com/planetarium/libplanet/pull/1171\n[#1172]: https://github.com/planetarium/libplanet/pull/1172\n[#1173]: https://github.com/planetarium/libplanet/issues/1173\n[#1180]: https://github.com/planetarium/libplanet/pull/1180\n[#1181]: https://github.com/planetarium/libplanet/pull/1181\n[#1182]: https://github.com/planetarium/libplanet/pull/1182\n[#1183]: https://github.com/planetarium/libplanet/issues/1183\n[#1184]: https://github.com/planetarium/libplanet/pull/1184\n[#1185]: https://github.com/planetarium/libplanet/pull/1185\n[#1186]: https://github.com/planetarium/libplanet/pull/1186\n[#1191]: https://github.com/planetarium/libplanet/pull/1191\n[#1194]: https://github.com/planetarium/libplanet/pull/1194\n[#1198]: https://github.com/planetarium/libplanet/pull/1198\n[#1202]: https://github.com/planetarium/libplanet/pull/1202\n[#1204]: https://github.com/planetarium/libplanet/pull/1204\n[#1208]: https://github.com/planetarium/libplanet/pull/1208\n[#1212]: https://github.com/planetarium/libplanet/pull/1212\n[#1215]: https://github.com/planetarium/libplanet/pull/1215\n[#1218]: https://github.com/planetarium/libplanet/pull/1218\n[#1233]: https://github.com/planetarium/libplanet/pull/1233\n\n\nVersion 0.10.3\n--------------\n\nReleased on January 28, 2021.\n\n -  `BlockChain<T>.MineBlock()` became to unstage transactions that have lower\n    nonce than expected.  [[#1174]]\n\n[#1174]: https://github.com/planetarium/libplanet/pull/1174\n\n\nVersion 0.10.2\n--------------\n\nReleased on November 25, 2020.\n\n -  Fixed `BlockChain<T>.Append()` method's bug that it had accepted\n    a `Block<T>` having more `Transactions` than the number specified by\n    the `IBlockPolicy<T>.MaxTransactionsPerBlock` property.  Now it throws\n    `InvalidBlockException` instead for such case.  [[#1104]]\n\n[#1104]: https://github.com/planetarium/libplanet/pull/1104\n\n\nVersion 0.10.1\n--------------\n\nReleased on November 24, 2020.\n\n -  `Transaction<T>.Id` property became lazy-loaded and cached if it's once\n    loaded.  (It had been loaded when the object is instantiated.)\n    [[#1079], [#1080]]\n -  The result bytes of `Transaction<T>.Serialize()` became cached\n    under the hood.  [[#1079, #1080]]\n -  Fixed `BlockChain<T>.MineBlock()` method's bug which excludes one's\n    all transactions virtually forever after a signer's transactions once have\n    been staged without the ascending order of nonce (usually due to their\n    inconsistent propagation latency on the network).  [[#1057], [#1059]]\n -  `BlockChain<T>.MineBlock()` method became to cut off staged transactions\n    to mine if it takes longer than 4 seconds to collect and validate them.\n    Those rest staged transactions are postponed until next block mining.\n    [[#1057], [#1059]]\n -  `BlockChain<T>.ContainsBlock()` method was optimized so that it does not\n    needlessly load an entire block, but looks up only an index instead.\n    [[#1057], [#1059]]\n -  `BlockChain<T>` became not to validate genesis block during fork,\n    where the state store is not an implementation of `IBlockStatesStore`.\n    [[#1063]]\n -  Fixed a bug where `Swarm<T>.GetPeerChainStateAsync()` has thrown\n    `NullReferenceException` when peers in table does failed to respond.\n    [[#1066]]\n -  Fixed a bug where `BlockChain<T>` had not locked readers–writer lock for\n    state changes during `MineBlock()`.  [[#1077], [#1087]]\n -  `PolymorphicAction<T>.ToString()` became more human-readable.\n    [[#1085], [#1087]]\n -  Fixed a bug where `MerkleTrie` had had `MrrkleTrie.EmptyRootHash` as root\n    node, which had been unable to insert new nodes.  [[#1087], [#1091]]\n\n[#1057]: https://github.com/planetarium/libplanet/pull/1057\n[#1059]: https://github.com/planetarium/libplanet/pull/1059\n[#1063]: https://github.com/planetarium/libplanet/pull/1063\n[#1066]: https://github.com/planetarium/libplanet/pull/1066\n[#1077]: https://github.com/planetarium/libplanet/pull/1077\n[#1079]: https://github.com/planetarium/libplanet/pull/1079\n[#1080]: https://github.com/planetarium/libplanet/pull/1080\n[#1085]: https://github.com/planetarium/libplanet/pull/1085\n[#1087]: https://github.com/planetarium/libplanet/pull/1087\n[#1091]: https://github.com/planetarium/libplanet/pull/1091\n\n\nVersion 0.10.0\n--------------\n\nReleased on October 27, 2020.\n\n### Backward-incompatible API changes\n\n -  Extracted rendering methods from `IAction` to `IRenderer<T>`,\n    which is introduced in this version.\n    From now on, rendering logic needs to be *injected* from outside\n    through `BlockChain<T>.Renderers`, rather than `IAction`s knowing\n    how to render themselves.\n    `IRenderer<T>` also unified `BlockChain<T>.TipChanged` event,\n    and introduced new events like `IActionRenderer<T>.RenderActionError()`,\n    `IActionRenderer<T>.RenderBlockEnd()`, `IRenderer<T>.RenderReorg()`, and\n    `IRenderer<T>.RenderReorgEnd()`.\n    [[#860], [#875], [#959], [#963]]\n     -  Removed `IAction.Render()` method, which was replaced by\n        `IActionRenderer<T>.RenderAction()`.\n     -  Removed `IAction.Unrender()` method, which was replaced by\n        `IActionRenderer<T>.UnrenderAction()`.\n     -  Removed `BlockChain<T>.TipChanged` event, which was replaced by\n        `IRenderer<T>.RenderBlock()`.\n     -  Removed `PolymorphicAction<T>.Render()` and `Unrender()` methods.\n     -  Removed `BlockChain<T>.TipChangedEventArgs` class.\n -  Added methods related fungible asset states to `IAccountStateDelta`:\n    [[#861], [#900], [#954]]\n     -  `UpdatedFungibleAssetsAccounts` property\n     -  `MintAsset(Address, Currency, BigInteger)` method\n     -  `TransferAsset(Address, Address, Currency, BigInteger)` method\n     -  `BurnAsset(Address, Currency, BigInteger)` method\n     -  `GetBalance(Address, Currency)` method\n -  Added `IAccountStateDelta.StateUpdatedAddresses` property in order to\n    distinguish state updates from asset states.  [[#861], [#900]]\n -  Added an optional parameter `AccountBalanceGetter accountBalanceGetter` to\n    `Block<T>.EvaluateActionsPerTx()` method.  [[#861], [#900]]\n -  `BlockChain<T>.StageTransaction()` became to throw\n    `InvalidTxGenesisHashException` when it takes a `Transaction<T>` from\n    a heterogeneous `BlockChain<T>` with a different genesis block.\n    [[#796], [#878]]\n -  Added `renderers` optional parameter to `BlockChain<T>()` constructor.\n    [[#883], [#959], [#963]]\n -  Added `BigInteger`-typed `totalDifficulty` parameter to `Block<T>()`\n    constructor.  [[#666], [#917]]\n -  Added `BigInteger`-typed `previousTotalDifficulty` parameter to\n    `Block<T>.Mine()` static method.  [[#666], [#917]]\n -  Added `options` optional parameter to `Swarm<T>()` constructor.\n    [[#926]]\n -  `ICryptoBackend` became to `ICryptoBackend<T>`.  [[#932]]\n -  `ICryptoBackend.Verify(HashDigest<SHA256>, byte[], PublicKey)` became to\n    `ICryptoBackend<T>.Verify(HashDigest<T>, byte[], PublicKey)` [[#932]]\n -  Added `ICryptoBackend<T>.Sign(HashDigest<T>, PrivateKey)` method.\n    [[#932]]\n -  `DefaultCryptoBackend` became to `DefaultCryptoBackend<T>`.  [[#932]]\n -  Added `ImmutableArray<byte>`-typed `preEvaluationHash` parameter to\n    `BlockHeader` constructor.  [[#931], [#935]]\n -  Added `HashDigest<SHA256>`-typed `preEvaluationHash` parameter to\n    `Block<T>()` constructor.  [[#931], [#935]]\n -  Replaced `SerializationInfoExtensions.GetValueOrDefault<T>()` to\n    `SerializationInfoExtensions.TryGetValue<T>()`.  [[#940]]\n -  Added `bool append = true` option to both `BlockChain<T>.MineBlock()`\n    overloaded methods.  Although this breaks ABI-level backward compatibility\n    (i.e., you need to rebuild your assemblies), still is backward-compatible at\n    API-level as the option is turned on by default.  [[#946]]\n -  Added `int? maxTransactions` option to both `BlockChain<T>.MineBlock()`\n    overloaded methods.\n    Although this breaks ABI-level backward compatibility (i.e., you need to\n    rebuild your assemblies), still is backward-compatible at API-level as\n    the option is turned on by default.  [[#1037], [#1039], [#1050]]\n -  Added `StateCompleterSet<T>? stateCompleters` option to two\n    `BlockChain<T>.Append()` overloaded methods.  Although this breaks ABI-level\n    backward compatibility (i.e., you need to rebuild your assemblies), still\n    is backward-compatible at API-level as the option has the default value\n    (`StateCompleterSet<T>.Recalculate`).  [[#946]]\n -  Added `CancellationToken cancellationToken = default(CancellationToken)`\n    option to `BlockChain<T>.MineBlock(Address miner)` overloaded method.\n    Although this breaks ABI-level backward compatibility (i.e., you need to\n    rebuild your assemblies), still is backward-compatible at API-level as\n    the option has the default value.  [[#946]]\n -  Added `IImmutableSet<Address> trustedStateValidators = null` option to both\n    `Swarm<T>.StartAsync()` overloaded methods.  Although this breaks ABI-level\n    backward compatibility (i.e., you need to rebuild your assemblies), still\n    is backward-compatible at API-level as the option is turned on by default.\n    [[#946]]\n -  Removed `Peer.AppProtocolVersion` property.  [[#949]]\n -  Removed `Peer.IsCompatibleWith()` method.  [[#949]]\n -  Replaced `Peer(PublicKey, AppProtocolVersion)` constructor with\n    `Peer(PublicKey)` constructor.  [[#949]]\n -  Replaced `BoundPeer(PublicKey, DnsEndPoint, AppProtocolVersion)` constructor\n    with `Peer(PublicKey, DnsEndPoint)` constructor.  [[#949]]\n -  Extracted `IStore`'s some methods dedicated to block states into\n    `IBlockStatesStore`.  [[#950]]\n     -  `ListStateKeys()` method.\n     -  `ListAllStateReferences()` method.\n     -  `LookupStateReference()` method.\n     -  `IterateStateReferences()` method.\n     -  `StoreStateReference()` method.\n     -  `ForkStateReferences()` method.\n     -  `GetBlockStates()` method.\n     -  `SetBlockStates()` method.\n     -  `PruneBlockStates()` method.\n -  The signature of `IStore.LookupStateReference<T>(Guid, string, Block<T>)`\n    method was changed to `LookupStateReference(Guid, string, long)`.  [[#950]]\n -  Added `IStateStore`-typed `stateStore` to `BlockChain<T>` constructor.\n    [[#950]]\n -  Replaced `Swarm<T>.FindSpecificPeerAsync(Address, Address, int,\n    BoundPeer, TimeSpan?, CancellationToken)` method with\n    `Swarm<T>.FindSpecificPeerAsync(Address, int, TimeSpan?,\n    CancellationToken)`.  [[#981]]\n -  Added `IActionContext.GetUnconsumedContext()` method.  [[#980]]\n -  Added `ImmutableArray<byte>`-typed `stateRootHash` parameter to\n    `BlockHeader` constructor.  [[#986]]\n -  Added `HashDigest<SHA256>`-typed `stateRootHash` parameter to\n    `Block<T>()` constructor.  [[#986]]\n -  Added `IBlockPolicy<T>.MaxTransactionsPerBlock` property.\n    [[#1037], [#1050]]\n -  Added `IBlockPolicy<T>.GetMaxBlockBytes()` method.  [[#201], [#1050]]\n -  `IBlockPolicy<T>.DoesTransactionFollowPolicy()` method became to take\n    additional `BlockChain<T>` parameter as its context.  [[#1012]]\n -  Methods in `BlockPolicy<T>` class became `virtual`.  [[#1010]]\n -  Added `int maxTransactionsPerBlock` option to both `BlockPolicy<T>()`\n    overloaded constructors.  [[#1037], [#1050]]\n -  Added `int maxBlockBytes` and `int maxGenesisBytes` options to both\n    `BlockPolicy<T>()` overloaded constructors.  [[#201], [#1050]]\n -  `BlockPolicy<T>()` constructor's `doesTransactionFollowPolicy` parameter\n    became `Func<Transaction<T>, BlockChain<T>, bool>` on .  [[#1012]]\n -  Added `cacheSize` optional parameter to `BlockSet<T>()` constructor.\n    [[#1013]]\n -  Removed `Address(SerializationInfo, StreamingContext)` constructor.\n    [[#1022]]\n -  Removed constructors from `InvalidMessageException` class.  [[#1021]]\n\n### Backward-incompatible network protocol changes\n\n -  The message field `RecentStates.StateReferences` became to\n    `IImmutableDictionary<string, IImmutableList<HashDigest<SHA256>>>` from\n    `IImmutableDictionary<Address, IImmutableList<HashDigest<SHA256>>>`.\n    [[#912]]\n -  The existing `RecentStates` message type (with the type number `0x0f`) was\n    replaced by a new `RecentStates` message type\n    (with the type number `0x13`).  [[#912]]\n -  Added `BlockHeader.TotalDifficulty` property.  [[#666], [#917]]\n -  The existing `Pong` message type (with the type number `0x02`) was\n    replaced by a new `Pong` message type\n    (with the type number `0x14`).  [[#459], [#919], [#920], [#930]]\n -  The `TimestampThreshold` between `Block<T>`s was changed from 15 minutes to\n    15 seconds.  [[#922], [#925]]\n -  `Swarm<T>` became to have 5 more message types:\n     -  `GetChainStatus` (`0x20`)  [[#920], [#930]]\n     -  `ChainStatus` (`0x24`)  [[#920], [#930], [#1003], [#1004]]\n     -  `GetBlockStates` (`0x22`)  [[#946]]\n     -  `BlockStates` (`0x23`)  [[#946]]\n     -  `DifferentVersion` (`0x30`)  [[#949]]\n -  Every message now contains app protocol version in its header.  [[#949]]\n -  The existing `BlockHeaderMessage` message type (with the type number `0x0d`)\n    was replaced by a new `BlockHeaderMessage` message type\n    (with the type number `0x0c`).  [[#1003], [#1004]]\n -  Removed `PreloadBlockDownloadFailEventArgs` class.  [[#1002]]\n -  Removed `blockDownloadFailed` parameter from `Swarm<T>.PreloadAsync()`\n    method.  Use `SwarmOptions.BlockDownloadTimeout` instead.  [[#1002]]\n\n### Backward-incompatible storage format changes\n\n -  Added `RawTransaction<T>.GenesisHash` property.  [[#796], [#878]]\n -  Added `BlockHeader.TotalDifficulty` property.  [[#666], [#917]]\n\n### Added APIs\n\n -  Added `Currency` struct.  [[#861], [#900], [#954]]\n -  Added `FungibleAssetValue` struct.  [[#861], [#944], [#954]]\n -  Added `AccountBalanceGetter` delegate.  [[#861], [#900], [#954]]\n -  Added `TurnClient.BindProxies()` method.  [[#756], [#868]]\n -  Added `ActionEvaluation.Exception` property.  [[#860], [[#875]]]\n -  Added `InvalidTxGenesisHashException` class.  [[#796], [#878]]\n -  Added `InvalidBlockBytesLengthException` class.  [[#201], [#1050]]\n -  Added `CurrencyPermissionException` class.  [[#861], [#900]]\n -  Added `InsufficientBalanceException` class.  [[#861], [#900], [#954]]\n -  Added `BlockChain<T>.GetBalance()` method.  [[#861], [#900]]\n -  Added `Block<T>.TotalDifficulty` property.  [[#666], [#917]]\n -  Added `Block<T>.BytesLength` property.  [[#201], [#1050]]\n -  Added `SwarmOptions` class.  [[#926]]\n -  Added `PeerChainState` struct.  [[#936]]\n -  Added `Swarm<T>.GetPeerChainStateAsync()` method.  [[#936]]\n -  Added `Swarm<T>.LastMessageTimestamp` property.  [[#964]]\n -  Added `Block<T>.PreEvaluationHash` property.  [[#931], [#935]]\n -  Added `BlockHeader.PreEvaluationHash` property.  [[#931], [#935]]\n -  Added `Transaction<T>.BytesLength` property.  [[#201], [#1050]]\n -  Added `HashDigest(ImmutableArray<byte>)` constructor.  [[#931], [#935]]\n -  Incomplete block states became able to be handled in more flexible way.\n    [[#929], [#934], [#946], [#954]]\n     -  Replaced `BlockChain<T>.GetState(Address, HashDigest<SHA256>?, bool)`\n        method with `GetState(Address, HashDigest<SHA256>?, StateCompleter<T>)`\n        method.  Specifying `completeStates: true` and `false` can be replaced\n        by `stateCompleter: StateCompleters<T>.Recalculate` and\n        `StateCompleters<T>.Reject`, respectively.\n     -  Replaced\n        `BlockChain<T>.GetBalance(Address, Currency, HashDigest<SHA256>?, bool)`\n        method with\n        `GetState(Address, Currency, HashDigest<SHA256>?, StateCompleter<T>)`\n        method.  Specifying `completeStates: true` and `false` can be replaced\n        by `stateCompleter: FungibleAssetStateCompleters<T>.Recalculate` and\n        `FungibleAssetStateCompleters<T>.Reject`, respectively.\n     -  Added `StateCompleter<T>` delegate.\n     -  Added `FungibleAssetStateCompleter<T>` delegate.\n     -  Added `StateCompleterSet<T>` struct.\n     -  Added `StateCompleters<T>` static class.\n     -  Added `FungibleAssetStateCompleters<T>` static class.\n     -  Added `Swarm<T>.GetTrustedStateCompleterAsync()` method.\n -  Added `IRenderer<T>` interface.  [[#959], [#963]]\n -  Added `IActionRenderer<T>` interface.  [[#959], [#967], [#970]]\n -  Added `AnonymousRenderer<T>` class.  [[#959], [#963]]\n -  Added `AnonymousActionRenderer<T>` interface.  [[#959], [#967], [#970]]\n -  Added `DelayedRenderer<T>` class.  [[#980], [#1029]]\n -  Added `DelayedActionRenderer<T>` class.  [[#980], [#1029]]\n -  Added `LoggedRenderer<T>` class.  [[#959], [#963]]\n -  Added `LoggedActionRenderer<T>` interface.  [[#959], [#967], [#970]]\n -  Added `BlockChain<T>.Renderers` property.  [[#945], [#959], [#963]]\n -  Added `BlockChain<T>.ActionRenderers` property.  [[#959], [#967], [#970]]\n -  Added `Swarm<T>.AppProtocolVersion` property.  [[#949]]\n -  `DefaultStore` became to implement `IBlockStatesStore`.  [[#950]]\n -  Added `IStateStore` interface.  [[#950]]\n -  Added `IBlockStatesStore` interface.  [[#950]]\n -  Added `TrieStateStore` class.  [[#939]]\n -  Added `ITrie` interface.  [[#939], [#1023]]\n -  Added `MerkleTrie` class.  [[#939], [#1023]]\n -  Added `IKeyValueStore` interface.  [[#939]]\n -  Added `DefaultKeyValueStore` class.  [[#939]]\n -  Added `CacheableKeyValueStore` class.  [[#939]]\n -  (Libplanet.RocksDBStore) `RocksDBStore` became to implement\n    `IBlockStatesStore`.  [[#950]]\n -  (Libplanet.RocksDBStore) Added `RocksDBKeyValueStore`.  [[#939]]\n -  Added `InvalidBlockStateRootHashException` class.  [[#986]]\n -  Added `Block<T>.StateRootHash` property.  [[#986]]\n -  Added `BlockHeader.StateRootHash` property.  [[#986]]\n -  Added `MerkleTrieExtensions` static class.  [[#1023]]\n -  Added `IAccountStateDelta.PreviousStateRootHash` property to\n    calculate states until previous action as state root hash.  [[#1030]]\n -  Added `UnexpectedlyTerminatedActionException.PreviousStateRootHash`\n    property.  [[#1032]]\n\n### Behavioral changes\n\n -  Improved performance of `Swarm<T>`.\n     -  Multiplexed response and broadcast.  [[#858], [#859]]\n     -  Reduced internal delays.  [[#871], [#879]]\n -  `Transaction<T>.Create()`, `Transaction<T>.EvaluateActions()` and\n    `Transaction<T>.EvaluateActionsGradually()` no longer throw\n    `UnexpectedlyTerminatedActionException` directly.  Instead, it records\n    an exception to `ActionEvaluation`s.  [[#860], [#875]]\n -  Added `Transaction<T>.GenesisHash` property.  [[#796], [#878]]\n -  Added `IAccountStateDelta.UpdatedAddresses` property contains\n    asset updates besides state updates.  [[#861], [#900]]\n -  `BlockChain<T>.Append()` method became to throw\n    `InvalidBlockBytesLengthException` if the given block's serialized bytes\n    is longer than the limitation configured by\n    `IBlockPolicy.GetMaxBlockBytes()`.  [[#201], [#1050]]\n -  `BlockChain<T>.MineBlock()` method became to cut off transactions to include\n    to fit into the limitation configured by `IBlockPolicy.GetMaxBlockBytes()`.\n    [[#201], [#1050]]\n -  `Swarm<T>` became to ignore received transaction with different\n    genesis hash.  [[#796], [#878]]\n -  `Swarm<T>` became to ignore invalid `BlockHeader`s immediately.  [[#898]]\n -  `Swarm<T>.PreloadAsync()` became to clean up only temporary chains.\n    [[#902]]\n -  `BlockPolicy<T>` became to validate `Block<T>.TotalDifficulty` property\n    of a `Block<T>`.  [[#666], [#917]]\n -  `Swarm<T>` became to preload from peer that has the most difficult chain.\n    [[#459], [#919]]\n -  `Swarm<T>` became to promote the most difficult chain as a canonical chain\n    instead of the longest chain.  [[#459], [#919]]\n -  `Swarm<T>.BootstrapAsync()` method became not to throw `TimeoutException`\n    when it fails to connect to all neighbors.  [[#933]]\n -  `Swarm<T>` became to respond to the messages with different app protocol\n    version.  [[#949]]\n -  `Swarm<T>.PreloadAsync()` became to execute the actions from the branchpoint\n    rather than the genesis block when there is a branch point.  [[#991]]\n -  `BlockPolicy<T>` became to validate `Block<T>.StateRootHash` property\n     of a `Block<T>`.  [[#986]]\n -  `Swarm<T>` became not to sync `Block<T>`s from the peers with\n    different genesis block.  [[#1003], [#1004]]\n -  `Swarm<T>` became to ignore `BlockHeaderMessage` from the peers with\n    different genesis block.  [[#1003], [#1004]]\n -  `BlockChain<T>` instead of `BlockPolicy<T>` became to validate `Block<T>`s\n    to append so that even if an empty implementation of `IBlockPolicy<T>` is\n    used `Block<T>`s are unable to be appended to `BlockChain<T>`.  [[#1010]]\n -  `BlockSet<T>[HashDigest<SHA256>]` and `BlockChain<T>.Genesis` became cached\n    so that they become faster to get.  [[#1013]]\n -  `Swarm<T>.PreloadAsync()` became to do not render blocks.  [[#1029]]\n\n### Bug fixes\n\n -  Fixed a bug that `Swarm<T>` had failed to receive a request from TURN relay\n    connections.  [[#404], [#871], [#890]]\n -  Fixed a bug where `Swarm<T>` had been terminated and never reconnected when\n    it had been once disconnected from TURN (mostly due to [sleep mode], etc.).\n    [[#909]]\n -  Fixed a bug in which pre-computed state delivery had failed when a state\n    key is not an `Address` when preloading.  [[#912]]\n -  Fixed a bug where `UnexpectedlyTerminatedException` hadn't been serialized\n    with `BinaryFormatter`.  [[#913]]\n -  Fixed a bug where `TurnClient` hadn't applied cancellation token to its\n    connections.  [[#916]]\n -  Fixed a bug where `BlockChain<T>.GetRawState()` had overwritten block states\n    without read lock.  [[#927]]\n -  Fixed a bug that `Swarm<T>` had not respond to `GetRecentStates` message\n    when the target block does not exist in the chain.  [[#941]]\n -  Fixed a bug that `Swarm<T>.StartAsync()` had not worked after\n    `Swarm<T>.StopAsync()` was once called.  [[#965]]\n -  Fixed a bug that `TurnClient` had thrown `InvalidOperationException` when\n    reconnecting.  [[#957], [#972]]\n -  Fixed a bug that `Swarm<T>` had not received block headers after failing\n    to receive previous blocks.  [[#996]]\n -  Fixed a bug that `Swarm<T>` had thrown `InvalidGenesisBlockException`\n    when reorg its chain repeatedly.  [[#996]]\n -  Fixed a bug that `Swarm<T>` had propagated invalid transactions.\n    [[#1043]]\n\n### Static analyzer\n\n -  Introduced the *Libplanet.Analyzers* package, a Roslyn Analyzer, which\n    checks if code has common mistakes prone to made with Libplanet-powered\n    game apps, e.g., breaking determinism in `IAction` implementations.\n    [[#1034]]\n\n### CLI tools\n\n -  The `planet` command became installable using `npm`.  [[#923], [#982]]\n -  Fixed a bug that <kbd>^H</kbd> had not removed the rightmost character\n    in passphrase prompts.  [[#983], [#984]]\n -  Added a new sub-command `planet mpt`.  [[#1023], [#1026]]\n -  Introduced a configuration file.  It's placed in:  [[#1023], [#1026]]\n     -  Linux/macOS: *<var>$XDG_CONFIG_HOME</var>/planetarium/cli.json*\n     -  Windows: *<var>%AppData%</var>\\planetarium\\cli.json*\n\n[#201]: https://github.com/planetarium/libplanet/issues/201\n[#404]: https://github.com/planetarium/libplanet/issues/404\n[#459]: https://github.com/planetarium/libplanet/issues/459\n[#666]: https://github.com/planetarium/libplanet/issues/666\n[#756]: https://github.com/planetarium/libplanet/issues/756\n[#796]: https://github.com/planetarium/libplanet/issues/796\n[#858]: https://github.com/planetarium/libplanet/issues/858\n[#859]: https://github.com/planetarium/libplanet/pull/859\n[#860]: https://github.com/planetarium/libplanet/issues/860\n[#861]: https://github.com/planetarium/libplanet/issues/861\n[#868]: https://github.com/planetarium/libplanet/pull/868\n[#871]: https://github.com/planetarium/libplanet/issues/871\n[#875]: https://github.com/planetarium/libplanet/pull/875\n[#878]: https://github.com/planetarium/libplanet/pull/878\n[#879]: https://github.com/planetarium/libplanet/pull/879\n[#883]: https://github.com/planetarium/libplanet/pull/883\n[#890]: https://github.com/planetarium/libplanet/pull/890\n[#898]: https://github.com/planetarium/libplanet/pull/898\n[#900]: https://github.com/planetarium/libplanet/pull/900\n[#902]: https://github.com/planetarium/libplanet/pull/902\n[#909]: https://github.com/planetarium/libplanet/pull/909\n[#912]: https://github.com/planetarium/libplanet/pull/912\n[#913]: https://github.com/planetarium/libplanet/pull/913\n[#916]: https://github.com/planetarium/libplanet/pull/916\n[#917]: https://github.com/planetarium/libplanet/pull/917\n[#919]: https://github.com/planetarium/libplanet/pull/919\n[#920]: https://github.com/planetarium/libplanet/issues/920\n[#922]: https://github.com/planetarium/libplanet/issues/922\n[#923]: https://github.com/planetarium/libplanet/pull/923\n[#925]: https://github.com/planetarium/libplanet/pull/925\n[#926]: https://github.com/planetarium/libplanet/pull/926\n[#927]: https://github.com/planetarium/libplanet/pull/927\n[#929]: https://github.com/planetarium/libplanet/issues/929\n[#930]: https://github.com/planetarium/libplanet/pull/930\n[#931]: https://github.com/planetarium/libplanet/issues/931\n[#932]: https://github.com/planetarium/libplanet/pull/932\n[#933]: https://github.com/planetarium/libplanet/pull/933\n[#934]: https://github.com/planetarium/libplanet/pull/934\n[#935]: https://github.com/planetarium/libplanet/pull/935\n[#936]: https://github.com/planetarium/libplanet/pull/936\n[#939]: https://github.com/planetarium/libplanet/pull/939\n[#940]: https://github.com/planetarium/libplanet/pull/940\n[#941]: https://github.com/planetarium/libplanet/pull/941\n[#944]: https://github.com/planetarium/libplanet/issues/944\n[#945]: https://github.com/planetarium/libplanet/pull/945\n[#946]: https://github.com/planetarium/libplanet/pull/946\n[#949]: https://github.com/planetarium/libplanet/pull/949\n[#950]: https://github.com/planetarium/libplanet/pull/950\n[#957]: https://github.com/planetarium/libplanet/issues/957\n[#959]: https://github.com/planetarium/libplanet/issues/959\n[#954]: https://github.com/planetarium/libplanet/pull/954\n[#963]: https://github.com/planetarium/libplanet/pull/963\n[#964]: https://github.com/planetarium/libplanet/pull/964\n[#965]: https://github.com/planetarium/libplanet/pull/965\n[#967]: https://github.com/planetarium/libplanet/issues/967\n[#970]: https://github.com/planetarium/libplanet/pull/970\n[#972]: https://github.com/planetarium/libplanet/pull/972\n[#980]: https://github.com/planetarium/libplanet/pull/980\n[#981]: https://github.com/planetarium/libplanet/pull/981\n[#982]: https://github.com/planetarium/libplanet/pull/982\n[#983]: https://github.com/planetarium/libplanet/issues/983\n[#984]: https://github.com/planetarium/libplanet/pull/984\n[#986]: https://github.com/planetarium/libplanet/pull/986\n[#991]: https://github.com/planetarium/libplanet/pull/991\n[#996]: https://github.com/planetarium/libplanet/pull/996\n[#1002]: https://github.com/planetarium/libplanet/pull/1002\n[#1003]: https://github.com/planetarium/libplanet/issues/1003\n[#1004]: https://github.com/planetarium/libplanet/pull/1004\n[#1010]: https://github.com/planetarium/libplanet/pull/1010\n[#1012]: https://github.com/planetarium/libplanet/pull/1012\n[#1013]: https://github.com/planetarium/libplanet/pull/1013\n[#1021]: https://github.com/planetarium/libplanet/pull/1021\n[#1022]: https://github.com/planetarium/libplanet/pull/1022\n[#1023]: https://github.com/planetarium/libplanet/pull/1023\n[#1026]: https://github.com/planetarium/libplanet/pull/1026\n[#1029]: https://github.com/planetarium/libplanet/pull/1029\n[#1030]: https://github.com/planetarium/libplanet/pull/1030\n[#1032]: https://github.com/planetarium/libplanet/pull/1032\n[#1034]: https://github.com/planetarium/libplanet/pull/1034\n[#1037]: https://github.com/planetarium/libplanet/pull/1037\n[#1039]: https://github.com/planetarium/libplanet/pull/1039\n[#1043]: https://github.com/planetarium/libplanet/pull/1043\n[#1050]: https://github.com/planetarium/libplanet/pull/1050\n[sleep mode]: https://en.wikipedia.org/wiki/Sleep_mode\n\n\nVersion 0.9.5\n-------------\n\nReleased on June 12, 2020.\n\n -  Fixed a bug that had not properly received block hashes after the chain had\n    reorged.  [[#880], [#905]]\n\n[#905]: https://github.com/planetarium/libplanet/pull/905\n\n\nVersion 0.9.4\n--------------\n\nReleased on June 2, 2020.\n\n -  (Libplanet.RocksDBStore) Fixed a bug that  `RocksDBStore.DeleteChainId()`\n    method had thrown `KeyNotFoundException` when there's no such chain ID.\n    [[#891]]\n -  (Libplanet.RocksDBStore) Fixed a bug that `RocksDBStore` had written logs\n    into the incorrect context `DefaultContext`, not `RocksDBStore`\n    the correct one.  [[#891]]\n\n[#891]: https://github.com/planetarium/libplanet/pull/891\n\n\nVersion 0.9.3\n-------------\n\nReleased on May 29, 2020.\n\n -  Fixed a `Swarm<T>.PreloadAsync()` method's bug that had hanged in a state\n    downloading block hashes and finally unexpectedly terminated when a peer's\n    chain had gotten reorged.   [[#880], [#884]]\n\n[#880]: https://github.com/planetarium/libplanet/issues/880\n[#884]: https://github.com/planetarium/libplanet/pull/884\n\n\nVersion 0.9.2\n-------------\n\nReleased on May 20, 2020.\n\n -  (Libplanet.RocksDBStore) Fixed a memory leak bug in `RocksDBStore`.\n    [[#870]]\n\n[#870]: https://github.com/planetarium/libplanet/pull/870\n\n\nVersion 0.9.1\n-------------\n\nReleased on May 7, 2020.\n\n -  Fixed a bug where the canonical chain had changed if any actions had thrown\n    an exception during `Swarm<T>.PreloadAsync()`.  [[#862]]\n -  Fixed a `Swarm<T>.PreloadAsync()` method's bug that it had hung forever and\n    raised `InvalidOperationException`.  [[#847], [#864]]\n\n[#847]: https://github.com/planetarium/libplanet/issues/847\n[#862]: https://github.com/planetarium/libplanet/pull/862\n[#864]: https://github.com/planetarium/libplanet/pull/864\n\n\nVersion 0.9.0\n-------------\n\nReleased on April 27, 2020.\n\n### Backward-incompatible API changes\n\n -  `BaseStore` class became to implement `IDisposable`.  [[#789]]\n -  Removed `IStore.DeleteIndex(Guid, HashDigest<SHA256>)` method.  [[#802]]\n -  Extension classes was renamed.  However, it would not be affected\n    if you have called it by using instance method syntax.  [[#803]]\n     -  Renamed `StunAddressExtension` class to `StunAddressExtensions`.\n     -  Renamed `BytesConvertExtension` class to `BytesConvertExtensions`.\n     -  Renamed `RandomExtension` class to `RandomExtensions`.\n     -  Renamed `AddressExtension` class to `AddressExtensions`.\n     -  Renamed `HashDigestExtension` class to `HashDigestExtensions`.\n     -  Renamed `NetMQFrameExtension` class to `NetMQFrameExtensions`.\n     -  Renamed `NetMQSocketExtension` class to `NetMQSocketExtensions`.\n     -  Renamed `SerializationInfoExtension` class to\n        `SerializationInfoExtensions`.\n     -  Renamed `StoreExtension` class to `StoreExtensions`.\n -  All parameters, fields, property, and method return values that had been\n    represented as an `Int32` became retyped to `AppProtocolVersion`.\n    [[#266], [#815]]\n     -  `Swarm()` constructor's parameter `appProtocolVersion` became\n        `AppProtocolVersion` (was `Int32`).\n     -  `Peer()` and `BoundPeer()` constructors' parameter `appProtocolVersion`\n        became `AppProtocolVersion` (was `Int32`).\n     -  `Peer.AppProtocolVersion` property became `AppProtocolVersion`\n        (was `Int32`).\n     -  `DifferentProtocolVersionEventArgs.ExpectedVersion` and\n        `DifferentProtocolVersionEventArgs.ActualVersion` properties became\n        `AppProtocolVersion` (was `Int32`).\n     -  Removed `DifferentAppProtocolVersionException` class.\n -  `Swarm()` constructor's `EventHandler<DifferentProtocolVersionEventArgs>\n    differentVersionPeerEncountered = null` parameter became replaced by\n    `DifferentAppProtocolVersionEncountered\n    differentAppProtocolVersionEncountered = null` parameter.  [[#266], [#815]]\n -  Added `IEnumerable<PublicKey> trustedAppProtocolVersionSigners = null`\n    parameter to `Swarm()` constructor.  [[#266], [#815]]\n -  Removed `DifferentProtocolVersionEventArgs` class.  [[#266], [#815]]\n -  Removed `createdAt` parameter from `Swarm()` constructor.  [[#838]]\n -  Replaced `BlockChain<T>.StageTransactions()` with `.StageTransaction()`\n    that receives only one transaction.  [[#820]]\n -  Replaced `BlockChain<T>.UnstageTransactions()` with `.UnstageTransaction()`\n    that receives only one transaction.  [[#820]]\n -  Added `IBlockPolicy.DoesTransactionFollowPolicy()` method which is a method\n    to determine if a transaction follows the block policy.  [[#827]]\n\n### Backward-incompatible network protocol changes\n\n -  The existing `BlockHashes` message type (with the type number `0x05`) was\n    replaced by a new `BlockHashes` message type (with type number `0x0e`)\n    in order to include an offset block index besides block hashes\n    so that a receiver is able to determine their block indices too.\n    [[#707], [#798]]\n -  `Peer` became to have 3 more fields to represent the whole fields of\n    `AppProtocolVersion`, which is newly introduced.  [[#266], [#815]]\n -  The existing `RecentStates` message type (with the type number `0x0c`) was\n    replaced by a new `RecentStates` message type (with type number `0x0f`)\n    in order to compress its states.  [[#700], [#850]]\n\n### Added APIs\n\n -  Added `AddressExtensions.ToAddress(this PrivateKey)` overloaded extension\n    method.  [[#825]]\n -  Added `BlockHashDownloadState` class, a subclass of `PreloadState`.\n    [[#707], [#798]]\n -  Added `BlockVerificationState` class, a subclass of `PreloadState`.\n    [[#798]]\n -  Added `AppProtocolVersion` struct.  [[#266], [#815]]\n -  Added `IKeyStore` interface.  [[#831]]\n -  Added `Web3KeyStore` class.  [[#831]]\n -  Added `BlockDigest` struct.  [[#785]]\n -  Added `BlockHeader` struct.  [[#785]]\n -  Added `IStore.GetBlockDigest(HashDigest<SHA256>)` method.  [[#785]]\n -  Added `Block<T>.ToBlockDigest()` method.  [[#785]]\n -  Added `ByteArrayExtensions` class.  [[#803]]\n -  Added `IStore.PruneBlockStates<T>(Guid, Block<T>)` method.  [[#790]]\n -  Added `DifferentAppProtocolVersionEncountered` delegate.  [[#266], [#815]]\n -  Added `Swarm<T>.TrustedAppProtocolVersionSigners` property.\n    [[#266], [#815]]\n -  Added `Peer.IsCompatibleWith()` method.  [[#266], [#815]]\n -  Added `TxViolatingBlockPolicyException` class.  [[#827]]\n -  Added `KeyStoreException` class.  [[#831]]\n -  Added `NoKeyException` class.  [[#831]]\n\n### Behavioral changes\n\n -  `BlockChain.MineBlock()` method became to ignore transactions having\n    lower nonce than the expected nonce in the chain.  [[#791]]\n -  `Swarm<T>.PreloadAsync()` and `Swarm<T>.StartAsync()` became to download\n    only a list of block hashes first and then download blocks from\n    simultaneously multiple peers.  [[#707], [#798]]\n -  Improved performance of `Swarm<T>` by preventing unnecessary task\n    creation.  [[#817], [#837]]\n -  Improved performance of `Swarm<T>.PreloadAsync()` by parallelizing\n    connections.  [[#846]]\n -  Improved response throughput of `Swarm<T>`.  [[#849]]\n\n### Bug fixes\n\n -  `Swarm<T>` became not to sync the same `Block<T>`s or `Transaction<T>`s\n    multiple times.  [[#784]]\n -  Fixed a `Swarm<T>`'s bug that had broadcasted a message to its source peer\n    when the number of peers is not enough (less than the minimum number).\n    [[#788]]\n -  Fixed a bug where `BlockChain.MineBlock()` had produced an invalid block\n    when there is any staged transaction which has lower nonce than the expected\n    nonce, that means, shares an already taken nonce by the same signer.\n    [[#791]]\n -  Fixed a `Swarm<T>.PreloadAsync()` method's bug that temporary chain IDs\n    in the store had been completely cleaned up in some corner cases\n    if `cancellationToken` was requested.  [[#798]]\n -  Fixed a bug where `Swarm<T>` had crashed if it received invalid\n    `Transaction<T>` from the nodes.  [[#820]]\n -  Fixed a bug where `Swarm<T>` hadn't reported `IProgress<PreloadState>`s\n    correctly.[[#839]]\n -  Fixed a `Swarm<T>.PreloadAsync()` method's bug that it had hung forever\n    when a block failed to be fetched due to an unexpected inner exception.\n    [[#839]]\n -  Fixed a bug where actions had been evaluated twice when receiving blocks.\n    [[#843], [#844]]\n -  Fixed `OverflowException` being thrown when a `passphrase` containing\n    any non-ASCII characters was passed to `Pbkdf2.Derive()` method or\n    `ProtectedPrivateKey.Protect()` method.  [[#845]]\n\n### CLI tools\n\n -  Added the `planet` command and its alias `dotnet planet`.\n\n[#266]: https://github.com/planetarium/libplanet/issues/266\n[#700]: https://github.com/planetarium/libplanet/issues/700\n[#707]: https://github.com/planetarium/libplanet/pull/707\n[#784]: https://github.com/planetarium/libplanet/pull/784\n[#785]: https://github.com/planetarium/libplanet/pull/785\n[#788]: https://github.com/planetarium/libplanet/pull/788\n[#789]: https://github.com/planetarium/libplanet/pull/789\n[#790]: https://github.com/planetarium/libplanet/pull/790\n[#791]: https://github.com/planetarium/libplanet/pull/791\n[#798]: https://github.com/planetarium/libplanet/pull/798\n[#802]: https://github.com/planetarium/libplanet/pull/802\n[#803]: https://github.com/planetarium/libplanet/pull/803\n[#815]: https://github.com/planetarium/libplanet/pull/815\n[#817]: https://github.com/planetarium/libplanet/issues/817\n[#820]: https://github.com/planetarium/libplanet/pull/820\n[#825]: https://github.com/planetarium/libplanet/pull/825\n[#827]: https://github.com/planetarium/libplanet/pull/827\n[#831]: https://github.com/planetarium/libplanet/pull/831\n[#837]: https://github.com/planetarium/libplanet/pull/837\n[#838]: https://github.com/planetarium/libplanet/pull/838\n[#839]: https://github.com/planetarium/libplanet/pull/839\n[#843]: https://github.com/planetarium/libplanet/issues/843\n[#844]: https://github.com/planetarium/libplanet/pull/844\n[#845]: https://github.com/planetarium/libplanet/pull/845\n[#846]: https://github.com/planetarium/libplanet/pull/846\n[#849]: https://github.com/planetarium/libplanet/pull/849\n[#850]: https://github.com/planetarium/libplanet/pull/850\n\n\nVersion 0.8.0\n-------------\n\nReleased on February 4, 2020.\n\n### Backward-incompatible API changes\n\n -  The internal representation for state keys became `string` (was `Address`).\n    [[#368], [#774]]\n     -  The return type of `IStore.GetBlockStates()` method became\n        `IImmutableDictionary<string, IValue>` (was `AddressStateMap`,\n        which was removed too).  [[#368], [#774]]\n     -  The type of the second parameter of `IStore.SetBlockStates()` method\n        became `IImmutableDictionary<string, IValue>` (was `AddressStateMap`,\n        which was removed too).  [[#368], [#774]]\n     -  The second parameter of `IStore.IterateStateReferences()` method became\n        `string key` (was `Address address`).  [[#368], [#774]]\n     -  The second parameter of `IStore.StoreStateReference()` method became\n        `IImmutableSet<string> keys` (was `IImmutableSet<Address> addresses`).\n        [[#368], [#774]]\n     -  `IStore.ListAddresses()` method was replaced by `IStore.ListStateKeys()`\n        method.  [[#368], [#774]]\n -  Added `Swarm<T>.FindSpecificPeer()` method to find a specific peer given\n    the address.  [[#570], [#580]]\n -  Removed `LiteDBStore` class.  Use `DefaultStore` instead.  [[#662]]\n -  Removed `BlockChain<T>.Contains(TxId)` method.\n    Use `IStore.ContainsTransaction(TxId)` instead.  [[#676]]\n -  Renamed `BlockChain<T>.Contains(HashDigest<SHA256>)` method to\n    `BlockChain<T>.ContainsBlock(HashDigest<SHA256>)`.  [[#678]]\n -  Removed `BlockChain<T>.Contains(Block<T>)` method.  [[#678]]\n -  Changed semantics of `BlockChain<T>.ContainsBlock(HashDigest<SHA256>)`\n    method and `BlockChain<T>[HashDigest<SHA256>]` indexer as lookups only\n    the current chain, not entire storage.  [[#678]]\n -  Added `IStore.ContainsBlock(HashDigest<SHA256>)` method.  [[#678]]\n -  Removed `AddressStateMap` class.  [[#98], [#368], [#692], [#774]]\n     -  The return type of `BlockChain<T>.GetState()` method became `IValue`\n        (was `AddressStateMap`).\n     -  The return type of `IStore.GetBlockStates()` method became\n        `IImmutableDictionary<string, IValue>` (was `AddressStateMap`).\n     -  `IStore.SetBlockStates()` method became to take\n        `IImmutableDictionary<string, IValue>` instead of `AddressStateMap`.\n -  `Swarm<T>.PreloadAsync()` method and `Swarm<T>.StartAsync()` method became\n    to take `preloadBlockDownloadFailed` event handler as an argument.\n    [[#694]]\n -  Added the `genesisBlock` parameter to\n    `BlockChain<T>()` constructor.  [[#688]]\n -  Removed `StateReferenceDownloadState` class.  [[#703]]\n -  Removed `BlockStateDownloadState` class.  [[#703]]\n -  Removed `TxReceived` and `BlockReceived` `AsyncAutoResetEvent`s\n    from `Swarm<T>`.  [[#705], [#725]]\n -  Added `workers` optional parameter into `Swarm<T>()` constructor.\n    [[#613], [#727]]\n -  `Block<T>` class became not to implement `ISerializable`.  [[#751]]\n -  `Transaction<T>` class became not to implement `ISerializable`.  [[#751]]\n -  `Block<T>.ToBencodex()` became to return `Bencodex.Types.Dictionary`.\n    [[#751]]\n -  `Transaction<T>.ToBencodex()` became to return `Bencodex.Types.Dictionary`.\n    [[#751]]\n -  Removed `Block<T>.FromBencodex(byte[])` method.  [[#751]]\n -  Removed `Transaction<T>.FromBencodex(byte[])` method.  [[#751]]\n -  `Block<T>.ToBencodex()` became to take no arguments.  [[#749], [#757]]\n -  Removed `Swarm<T>.BroadcastBlocks(IEnumerable<Block<T>>)` method.  [[#764]]\n -  `StoreExtension.LookupStateReference<T>()` method was replaced by\n    `IStore.LookupStateReference<T>()` method.  [[#722], [#774]]\n\n### Backward-incompatible network protocol changes\n\n -  Added `long`-typed `offset` parameter to `RecentStates` and\n    `GetRecentStates` messages.  [[#703]]\n -  Added `int`-typed `iteration` parameter to `RecentStates` message.\n    [[#703]]\n -  Added `BlockHeaderMessage` message.  [[#764]]\n\n### Backward-incompatible storage format changes\n\n -  The introduced `DefaultStore` is incompatible at the file-level with\n    the `LiteDBStore` which had existed.  `DefaultStore` became to take\n    a directory instead of a single file, and it consists of multiple\n    subdirectories and a LiteDB file for indices.  [[#662], [#680]]\n\n### Added APIs\n\n -  Added `DefaultStore` class to replace `LiteDBStore`.  [[#662]]\n -  Added `IStore.ListAllStateReferences<T>()` method.  [[#701], [#703]]\n -  Added `IStore.ListStateKeys()` method to replace `IStore.ListAddresses()`\n    method.  [[#368], [#774]]\n -  Added `IStore.LookupStateReference<T>()` method to replace\n    `StoreExtension.LookupStateReference<T>()` method.  [[#368], [#722], [#774]]\n -  Added `BlockChain<T>.Genesis` property.  [[#688]]\n -  Added `BlockChain<T>.MakeGenesisBlock()` static method.  [[#688]]\n -  Added `InvalidGenesisBlockException` class.  [[#688]]\n -  Added `StateDownloadState` class, a subclass of `PreloadState`,\n    which reports state preloading iteration progress.  [[#703]]\n -  Added `PeerDiscoveryException` class which inherits `SwarmException`\n    class.  [[#604], [#726]]\n -  Added `Swarm<T>.Peers` property which returns an enumerable of peers in\n    `Swarm<T>`'s routing table.  [[#739]]\n -  Added `Block<T>.Serialize()` method which returns `byte[]`.  [[#751]]\n -  Added `Transaction<T>.Serialize()` method which returns `byte[]`.  [[#751]]\n -  Added `Block<T>(Bencodex.Types.Dictionary)` constructor.  [[#751]]\n -  Added `Transaction<T>(Bencodex.Types.Dictionary)` constructor.  [[#751]]\n -  Added `Block<T>.Deserialize(byte[])` method.  [[#751]]\n -  Added `Transaction<T>.Deserialize(byte[])` method.  [[#751]]\n -  Added `StoreExtension.Copy(this IStore, IStore)` extension method.  [[#753]]\n -  Added a `HashDigest<SHA256>?`-typed `TxHash` property which digests\n    all transactions in the block to `Block<T>` class.  [[#749], [#757]]\n -  Added `CryptoConfig` class.  [[#758]]\n -  Added `ICryptoBackend` class.  [[#758]]\n -  Added `DefaultCryptoBackend` class.  [[#758]]\n -  Added `Swarm<T>.BroadcastBlock(Block<T>)` method.  [[#764]]\n -  Added `Swarm<T>.PeerStates` property.  [[#772]]\n -  Added `PeerState` class which represents a `Peer`s state in the\n    routing table.  [[#772]]\n -  Added `Swarm<T>.CheckAllPeersAsync()` method.  [[#772]]\n\n### Behavioral changes\n\n -  `Swarm<T>` became to compare only peer's addresses instead of public keys\n    to determine if a peer is in routing table or not.  [[#665]]\n -  When `Swarm<T>.PreloadAsync()` method fails to download blocks,\n    `Swarm<T>` became to call `preloadBlockDownloadFailed` event handler\n    taken as an argument.  If the event handler is not present, `Swarm<T>`\n    throws `SwarmException`.  [[#694]]\n -  `Swarm<T>.PreloadAsync()` became not to sync state references and block\n    states at once.  [[#703]]\n -  `Swarm<T>` became to print less logs on debug level during sending states.\n    [[#706]]\n -  Increased `Swarm<T>`'s network timeout value, in order to be stable\n    a high latency internet connection.  [[#709]]\n -  `Swarm<T>.BootstrapAsync()` became to report `PeerDiscoveryException`\n    instead of `SwarmException` directly.  [[#604], [#726]]\n -  `BlockChain<T>.Append()` became to unstage the staged `Transaction<T>`s\n    that have lower nonce than the highest nonce of the same signer's\n    transactions in the same chain, since these virtually never become valid.\n    [[#721], [#728]]\n -  `Swarm<T>` became not to fill blocks if received block hashes are\n    continuous.  [[#732]]\n -  `Swarm<T>` became to can process more requests at once by creating TURN\n    relaying proxy concurrently.  [[#744]]\n -  `Swarm<T>` became to throw `InvalidGenesisBlockException` when receiving\n    block from the nodes that have a different genesis block.  [[#746]]\n -  `Swarm<T>` became to distinguish the starting stages clearly.\n    In other words, `Swarm<T>.StartAsync()` became not to call\n    `Swarm<T>.PreloadAsync()`.  [[#735], [#760]]\n -  The hash of `Block<T>` has changed due to the change in the method of\n    serialization.  [[#762]]\n -  `Swarm<T>` became to ignore broadcasted block that has lower index than\n    the current tip.  [[#764]]\n -  The way `Swarm<T>` chose peers to spread messages has changed.\n    [[#765], [#767]]\n     -  If there are less than 10 peers in the routing table, select all peers.\n     -  If there are more than 10 peers in the routing table,\n        choose one from each bucket, and if the number is less than 10,\n        then select an additional peers so that the total is 10.\n\n### Bug fixes\n\n -  Fixed a bug where the canonical chain could be deleted if `Swarm<T>` failed\n    to download blocks due to network connection.  [[#675]]\n -  Fixed bug that re-download block from scratch in preloading.  [[#685]]\n -  Fixed a bug where state references become outdated if a chain is forked\n    and then adding existing blocks into it.  [[#704]]\n -  Fixed a bug where `Swarm<T>` had exhausted all available sockets.  [[#709]]\n -  Fixed a bug where `Swarm<T>` had infinitely repeated failed requests.\n    [[#709]]\n -  Fixed a bug where `Swarm<T>` hadn't stopped properly.  [[#709]]\n -  Fixed a bug where `Swarm<T>.BootstrapAsync()` had stopped due to trivial\n    (recoverable) `TimeoutException`s.  [[#715], [#716]]\n -  Fixed a bug where `BlockChain<T>.GetNextTxNonce()` had returned invalid tx\n    nonce.  [[#718]]\n -  Fixed a bug where mined transactions were staged again.  [[#719]]\n -  Fixed a bug where `Block<T>.Hash` property, `Block<T>.Mine()` method,\n    `Block<T>.FromBencodex()` method, `Block<T>.ToBencodex()` method,\n    `Transaction<T>.Id` property, `Transaction<T>.Signature` property,\n    `Transaction<T>.Create()` method, `Transaction<T>.FromBencodex()` method,\n    and `Transaction<T>.ToBencodex()` method had been non-deterministic on\n    some `CultureInfo.CurrentCulture` (e.g., `ar_SA`, `fr_FR`, `th_TH`)\n    so that it had caused network protocol incompatibilities.\n    [[#734]]\n -  Fixed a bug where the states became empty between the tip of the peer to\n    receive the states and the tip of the downloaded block.  [[#736]]\n -  Fixed a bug where `Swarm<T>.StartAsync()` had thrown\n    `NullReferenceException` when `host` parameter is present on the outside\n    of NAT.  [[#744]]\n -  Fixed a bug where `Swarm<T>` had failed to request a TURN relay when it has\n    an IPv6 address.  [[#744]]\n -  Fixed a bug where `DefaultStore` had invalid state references cache after\n    fork.  [[#759]]\n -  Fixed a bug where `BlockChain<T>` had rendered and evaluated actions in\n    the genesis block during forking.  [[#763]]\n -  Fixed a `Swam<T>`'s bug that some `Transaction<T>`s had become excluded from\n    mining `Block<T>`s after reorg from α to β where a `Transaction<T>` was once\n    included by a `Block<T>` (α) and not included by an other `Block<T>` (β) for\n    the same `Index` due to the latency gap between nodes.  [[#775]]\n -  Fixed a bug where `TransactionSet` and `BlockSet` has halt whole process\n    when run `Trace.Assert()`.  [[#806], [#833]]\n\n[#368]: https://github.com/planetarium/libplanet/issues/368\n[#570]: https://github.com/planetarium/libplanet/issues/570\n[#580]: https://github.com/planetarium/libplanet/pull/580\n[#604]: https://github.com/planetarium/libplanet/issues/604\n[#613]: https://github.com/planetarium/libplanet/issues/613\n[#662]: https://github.com/planetarium/libplanet/pull/662\n[#665]: https://github.com/planetarium/libplanet/pull/665\n[#675]: https://github.com/planetarium/libplanet/pull/675\n[#676]: https://github.com/planetarium/libplanet/pull/676\n[#678]: https://github.com/planetarium/libplanet/pull/678\n[#680]: https://github.com/planetarium/libplanet/pull/680\n[#685]: https://github.com/planetarium/libplanet/pull/685\n[#688]: https://github.com/planetarium/libplanet/pull/688\n[#692]: https://github.com/planetarium/libplanet/pull/692\n[#694]: https://github.com/planetarium/libplanet/pull/694\n[#701]: https://github.com/planetarium/libplanet/pull/701\n[#703]: https://github.com/planetarium/libplanet/pull/703\n[#704]: https://github.com/planetarium/libplanet/pull/704\n[#705]: https://github.com/planetarium/libplanet/issues/705\n[#706]: https://github.com/planetarium/libplanet/pull/706\n[#709]: https://github.com/planetarium/libplanet/pull/709\n[#715]: https://github.com/planetarium/libplanet/issues/715\n[#716]: https://github.com/planetarium/libplanet/pull/716\n[#718]: https://github.com/planetarium/libplanet/pull/718\n[#719]: https://github.com/planetarium/libplanet/pull/719\n[#721]: https://github.com/planetarium/libplanet/issues/721\n[#722]: https://github.com/planetarium/libplanet/pull/722\n[#725]: https://github.com/planetarium/libplanet/pull/725\n[#726]: https://github.com/planetarium/libplanet/pull/726\n[#727]: https://github.com/planetarium/libplanet/pull/727\n[#728]: https://github.com/planetarium/libplanet/pull/728\n[#732]: https://github.com/planetarium/libplanet/pull/732\n[#734]: https://github.com/planetarium/libplanet/pull/734\n[#735]: https://github.com/planetarium/libplanet/issues/735\n[#736]: https://github.com/planetarium/libplanet/pull/736\n[#739]: https://github.com/planetarium/libplanet/pull/739\n[#744]: https://github.com/planetarium/libplanet/pull/744\n[#746]: https://github.com/planetarium/libplanet/pull/746\n[#749]: https://github.com/planetarium/libplanet/issues/749\n[#751]: https://github.com/planetarium/libplanet/pull/751\n[#753]: https://github.com/planetarium/libplanet/pull/753\n[#757]: https://github.com/planetarium/libplanet/pull/757\n[#758]: https://github.com/planetarium/libplanet/pull/758\n[#759]: https://github.com/planetarium/libplanet/pull/759\n[#760]: https://github.com/planetarium/libplanet/pull/760\n[#762]: https://github.com/planetarium/libplanet/pull/762\n[#763]: https://github.com/planetarium/libplanet/pull/763\n[#764]: https://github.com/planetarium/libplanet/pull/764\n[#765]: https://github.com/planetarium/libplanet/issues/765\n[#767]: https://github.com/planetarium/libplanet/pull/767\n[#772]: https://github.com/planetarium/libplanet/pull/772\n[#774]: https://github.com/planetarium/libplanet/pull/774\n[#775]: https://github.com/planetarium/libplanet/pull/775\n[#806]: https://github.com/planetarium/libplanet/issues/806\n[#833]: https://github.com/planetarium/libplanet/pull/833\n\n\nVersion 0.7.0\n-------------\n\nReleased on November 8, 2019.\n\n### Backward-incompatible interface changes\n\n -  Renamed `minValue`/`maxValue` parameters to `lowerBound`/`upperBound` of\n    `IRandom.Next()` methods.  [[#555], [#558]]\n -  Renamed `IStore.IterateIndex()` method to `IterateIndexes()`.\n    [[#462], [#560]]\n -  `Swarm<T>` class became to implement `IDisposable` again and should be\n    disposed to clean up its internal resources.  [[#485]]\n -  `IStore.IterateStateReferences()` method became to receive\n    `highestIndex`, `lowestIndex`, and `limit` parameters.  [[#447], [#545]]\n -  Reworked `BlockChain<T>.GetStates()` into `GetState()` which takes only\n    one `Address` instead of `IEnumerable<Address>`.  [[#510], [#563]]\n -  Types of `IAction.PlainValue` and states became restricted to\n    `Bencodex.Types.IValue`.  [[#541], [#552]]\n     -  `IAction.LoadPlainValue(IImmutableDictionary<string, object>)` method\n        became replaced by `LoadPlainValue(IValue)`.\n     -  `AccountStateGetter` became to return `IValue`, not `object`.\n     -  Added `BencodexExtension` static class.\n -  Removed `BlockChain<T>.Blocks`.  [[#409], [#583]]\n -  Removed `BlockChain<T>.Transactions`.  [[#409], [#583]]\n -  Removed the `linger` parameter from the `Swarm<T>()` constructor, and added\n    the `waitFor` parameter to `Swarm<T>.StopAsync()` method instead.  [[#581]]\n -  Removed the `dialTimeout` parameter from the `Swarm<T>`() constructor, and\n    added it to `Swarm<T>.PreloadAsync()` & `Swarm<T>.StartAsync()` methods.\n    [[#581]]\n -  Removed `broadcast` parameter from `BlockChain<T>.MakeTransaction()` method.\n    [[#609]]\n -  `BlockChain<T>` does not implement `IReadOnlyList<T>` anymore.  [[#630]]\n     -  Added `BlockChain<T>.Count` property.  [[#630]]\n     -  Removed `BlockChain<T>.LongCount()` method.  [[#630]]\n     -  Removed `BlockChain<T>.Validate()` method.  [[#630]]\n     -  Removed `BlockChain<T>.GetEnumerate()` method.  [[#630]]\n     -  Removed `BlockPolicyExtension.ValidateBlocks()` method.  [[#630]]\n     -  `IBlockPolicy<T>.GetNextBlockDifficulty()` method became to receive\n        `BlockChain<T>` instead of `IReadOnlyList<Block<T>>`.  [[#630]]\n     -  `IBlockPolicy<T>.ValidateNextBlock()` method became to receive\n        `BlockChain<T>` instead of `IReadOnlyList<Block<T>>`.  [[#630]]\n\n### Added interfaces\n\n -  Added `ProtectedPrivateKey` class.  [[#577], [#614]]\n -  Added `IncorrectPassphraseException` class.  [[#577], [#614]]\n -  Added `MismatchedAddressException` class.  [[#577], [#614]]\n -  Added `KeyJsonException` abstract class.  [[#577], [#614]]\n -  Added `InvalidKeyJsonException` class.  [[#577], [#614]]\n -  Added `UnsupportedKeyJsonException` class.  [[#577], [#614]]\n -  Added `ICipher` interface.  [[#577], [#614]]\n -  Added `Aes128Ctr` class.  [[#577], [#614]]\n -  Added `IKdf` interface.  [[#577], [#614]]\n -  Added `Pbkdf2` class.  [[#577], [#614]]\n -  Added `Scrypt` class.  [[#642], [#654]]\n -  Added `BlockChain<T>.LongCount()` method.  [[#575]]\n -  Added `BlockChain<T>[HashDigest<T>]` indexer.  [[#409], [#583]]\n -  Added `BlockChain<T>.Contains(HashDigest<T>)` method.  [[#409], [#583]]\n -  Added `BlockChain<T>.GetTransaction(TxId)` method.  [[#409], [#583]]\n -  Added `BlockChain<T>.Contains(TxId)` method.  [[#409], [#583]]\n -  Added `ByteUtil.Hex(ImmutableArray<byte>)` overloaded method.  [[#614]]\n -  Added `BlockChain<T>.Contains(Block<T>)` method.  [[#630]]\n -  Added `BlockDownloadState.SourcePeer` property.  [[#636]]\n\n### Behavioral changes\n\n -  Changed to send `Pong` before updating the message sender to the routing\n    table when `Ping` is received.  [[#566]]\n -  Improved performance of `StoreExtension.LookupStateReference<T>()` method.\n    [[#447], [#545]]\n -  Added .NET Core 2.2 as a targeted framework.  [[#209], [#561]]\n -  `TurnClient.AcceptRelayedStreamAsync()` became to ignore disconnected\n    connections.  [[#469]]\n -  `Swarm<T>.PreloadAsync()` became to ignore peers with lower tip.  [[#592]]\n -  `Swarm<T>` became to validate only stale peers.  [[#568], [#593]]\n -  `Swarm<T>` became not to check cached peers immediately after\n    removing peers from its routing table.  Instead, it checks cached peers\n    periodically.  [[#608]]\n -  Marked `Address` and `HashDigest` as readonly.  [[#610]]\n -  `IceServer.CreateTurnClient()` became to throw `ArgumentException` when\n    received invalid url.  [[#622]]\n -  `Swarm<T>` became to update peer table when receiving messages that are\n    not related with [Kademlia protocol][Kademlia].  [[#594], [#627]]\n -  `Swarm<T>` became not to check least recently used peer every time when\n    new peer is fetched.  [[#627]]\n -  `IAction` became guaranteed that the given\n    `IActionContext.PreviousStates.GetState()` never throws\n    `IncompleteBlockStatesException`.  Instead, now it may calculate the\n    incomplete states from the beginning if necessary.  [[#645]]\n -  `IStore.PutBlock<T>()` became to do nothing when it takes\n    the `Block<T>` more than once.  [[#647]]\n -  `Swarm<T>.PreloadAsync()` became to try downloading blocks from all neighbor\n    peers, even if any peer among them is unavailable to send blocks.  [[#636]]\n\n### Bug fixes\n\n -  Fixed a bug where `Swarm<T>` had tried to update a peer infinitely when\n    the peer is evicted from its table.  [[#566]]\n -  Fixed a bug where `Swarm<T>.AppendBlocksAsync()` re-requests blocks that\n    already received when blockchain is empty.  [[#550], [#562]]\n -  Fixed a bug that `Swarm<T>` had thrown `SocketException` with a message\n    `Operation on non-blocking socket would block`.  [[#405], [#485]]\n -  Fixed a bug that accessed all blocks from the genesis block when a swap\n    occurred.  [[#575]]\n -  Fixed a bug that `Swarm<T>` had thrown `InvalidBlockIndexException` during\n    synchronizing with other reorganized peer.  [[#528], [#576]]\n -  Fixed a bug where `Swarm<T>` does not render actions in blocks which are\n    filled from other peers.  [[#579]]\n -  Fixed a bug where `Swarm<T>` renders actions in same block multiple times\n    when reorg happens.  [[#579]]\n -  `LiteDBStore` became to guarantee atomicity of storing blocks.  [[#584]]\n -  Fixed a bug that `BlockChain<T>` had appended a block even if fails to\n    evaluate.  [[#591]]\n -  Fixed a bug where `Swarm<T>` hadn't removed stale peers.\n    [[#568], [#593], [#602]]\n -  Fixed a bug that `TurnClient` had thrown `IOException` when accepting\n    connection through a TURN relay server.  [[#453], [#599]]\n -  Fixed a bug that `KeyNotFoundException` occurred when sending a message\n    through the TurnClient.\n -  Fixed a bug where `BlockChain<T>.GetNextTxNonce` only returned the same\n    nonce when transactions with an old nonce were staged.  [[#637]]\n -  Fixed a bug that `BlockChain<T>` had reset when `Swarm<T>.PreloadAsync()`\n    fails.  [[#644]]\n -  Fixed bug that whole processes could halt when received an invalid\n    type of message.  [[#628], [#641]]\n -  Fixed a bug that received blocks could not be processed if a branch point\n    is a stale block.  [[#655]]\n\n[#209]: https://github.com/planetarium/libplanet/issues/209\n[#405]: https://github.com/planetarium/libplanet/issues/405\n[#409]: https://github.com/planetarium/libplanet/issues/409\n[#447]: https://github.com/planetarium/libplanet/issues/447\n[#453]: https://github.com/planetarium/libplanet/issues/453\n[#462]: https://github.com/planetarium/libplanet/issues/462\n[#469]: https://github.com/planetarium/libplanet/pull/469\n[#485]: https://github.com/planetarium/libplanet/pull/485\n[#510]: https://github.com/planetarium/libplanet/issues/510\n[#528]: https://github.com/planetarium/libplanet/issues/528\n[#541]: https://github.com/planetarium/libplanet/issues/541\n[#545]: https://github.com/planetarium/libplanet/pull/545\n[#550]: https://github.com/planetarium/libplanet/issues/550\n[#552]: https://github.com/planetarium/libplanet/pull/552\n[#555]: https://github.com/planetarium/libplanet/issues/555\n[#558]: https://github.com/planetarium/libplanet/pull/558\n[#560]: https://github.com/planetarium/libplanet/pull/560\n[#561]: https://github.com/planetarium/libplanet/pull/561\n[#562]: https://github.com/planetarium/libplanet/pull/562\n[#563]: https://github.com/planetarium/libplanet/pull/563\n[#566]: https://github.com/planetarium/libplanet/pull/566\n[#568]: https://github.com/planetarium/libplanet/issues/568\n[#575]: https://github.com/planetarium/libplanet/pull/575\n[#576]: https://github.com/planetarium/libplanet/pull/576\n[#577]: https://github.com/planetarium/libplanet/issues/577\n[#579]: https://github.com/planetarium/libplanet/pull/579\n[#581]: https://github.com/planetarium/libplanet/pull/581\n[#583]: https://github.com/planetarium/libplanet/pull/583\n[#584]: https://github.com/planetarium/libplanet/pull/584\n[#591]: https://github.com/planetarium/libplanet/pull/591\n[#592]: https://github.com/planetarium/libplanet/pull/592\n[#593]: https://github.com/planetarium/libplanet/pull/593\n[#594]: https://github.com/planetarium/libplanet/issues/594\n[#599]: https://github.com/planetarium/libplanet/pull/599\n[#602]: https://github.com/planetarium/libplanet/pull/602\n[#608]: https://github.com/planetarium/libplanet/pull/608\n[#609]: https://github.com/planetarium/libplanet/pull/609\n[#610]: https://github.com/planetarium/libplanet/pull/610\n[#614]: https://github.com/planetarium/libplanet/pull/614\n[#622]: https://github.com/planetarium/libplanet/pull/622\n[#627]: https://github.com/planetarium/libplanet/pull/627\n[#628]: https://github.com/planetarium/libplanet/issues/628\n[#630]: https://github.com/planetarium/libplanet/pull/630\n[#636]: https://github.com/planetarium/libplanet/pull/636\n[#637]: https://github.com/planetarium/libplanet/pull/637\n[#641]: https://github.com/planetarium/libplanet/pull/641\n[#642]: https://github.com/planetarium/libplanet/issues/642\n[#644]: https://github.com/planetarium/libplanet/pull/644\n[#645]: https://github.com/planetarium/libplanet/pull/645\n[#647]: https://github.com/planetarium/libplanet/pull/647\n[#654]: https://github.com/planetarium/libplanet/pull/654\n[#655]: https://github.com/planetarium/libplanet/pull/655\n\n\nVersion 0.6.0\n-------------\n\nReleased on October 1, 2019.\n\n### Backward-incompatible interface changes\n\n -  `BlockChain<T>.MineBlock()` is now `async` and became to throw\n    `OperationCanceledException` if `BlockChain<T>`'s tip index is changed while\n    mining.  [[#460], [#517]]\n -  Users became able to give a cancellation token to `Block<T>.Mine()` and\n    `Hashcash.Answer()` to cancel the operation.  [[#460], [#517]]\n -  Replaced `UnexpectedlyTerminatedTxRehearsalException` with\n    `UnexpectedlyTerminatedActionException`.  [[#498]]\n -  The following methods became to throw\n    `UnexpectedlyTerminatedActionException` with having its `InnerException`\n    during actions being evaluated if any action of them throws an exception:\n    [[#498]]\n    -  `Transaction<T>.EvaluateActions()`\n    -  `Transaction<T>.EvaluateActionsGradually()`\n    -  `Block<T>.EvaluateActionsPerTx()`\n    -  `Block<T>.Evaluate()`\n    -  `BlockChain<T>.GetStates(completeStates: true)`\n -  The concept of \"namespaces\" in `IStore` was replaced by \"chain IDs\"\n    to be consistent with `BlockChain<T>`.  [[#483], [#486]]\n     -  Renamed `IStore.ListNamespaces()` method to `ListChainIds()`.\n     -  Renamed `IStore.DeleteNamespace()` method to `DeleteChainId()`.\n     -  Renamed `IStore.GetCanonicalNamespace()` method to\n        `GetCanonicalChainId()`.\n     -  Renamed `IStore.SetCanonicalNamespace(string)` method to\n        `SetCanonicalChainId(Guid)`.\n     -  Replaced `namespace`/`sourceNamespace`/`destinationNamespace` parameters\n        taking `string` of methods in `IStore` and `StoreExtension` with\n        `chainId`/`sourceChainId`/`destinationChainId` taking `Guid`.\n     -  Renamed `NamespaceNotFoundException` to `ChainIdNotFoundException`.\n     -  Replaced `NamespaceNotFoundException(string, string)` constructor with\n        `ChainIdNotFoundException(Guid, string)` constructor.\n     -  Replaced `NamespaceNotFoundException.Namespace` property with\n        `ChainIdNotFoundException.ChainId` property.\n -  `IStore.StoreStateReference<T>(string, IImmutableSet<Address>, Block<T>)`\n    method became replaced by `StoreStateReference(Guid, IImmutableSet<Address>,\n    HashDigest<SHA256>, long)` method so that it takes hash and index of\n    a block instead of an entire block.  [[#420]]\n -  Added `IStore.ForkBlockIndexes()` method.  [[#420]]\n -  Removed `addressesToStrip` parameter from `IStore.ForkStateReferences<T>()`\n    method.  [[#454], [#467], [#509], [#522]]\n -  Removed the concept of \"staged transactions that should not be broadcasted,\"\n    because its primary usage had been to make a transaction of a reward action\n    for a candidate for block miner, and the case became achieved through\n    `IBlockPolicy<T>.BlockAction` property which was introduced at 0.5.0.\n    All staged transactions became broadcasted.  [[#319], [#470]]\n     -  `BlockChain<T>.StageTransactions(IDictionary<Transaction<T>, bool>)`\n        method became replaced by\n        `StageTransactions(IImmutableSet<Transaction<T>>)`.\n     -  Removed `toBroadcast` parameter from\n        `IStore.IterateStagedTransactionIds(bool)` method.\n     -  `IStore.StageTransactionIds(IDictionary<TxId, bool>)` method became\n        replaced by `StageTransactionIds(IImmutableSet<TxId>()`.\n -  Removed `Swarm<T>.AddPeersAsync()` method.  To connect with seed peers, use\n    `Swarm<T>.BootstrapAsync()` method instead.  [[#353]]\n -  `Peer` with endpoints should be typed as `BoundPeer` which is inherited from\n    `Peer`.  [[#353]]\n -  Removed `IActionContext.NewGuid()` method.  To get a randomly generated\n    [Guid][Guid], use `RandomExtension.GenerateRandomGuid()` which implements\n    [RFC 4122] instead.  [[#508]]\n\n### Added interfaces\n\n -  Added `BlockChain<T>.TipChanged` event which is invoked with an argument\n    of `BlockChain<T>.TipChangedEventArgs` when `BlockChain<T>.Tip` is changed.\n    [[#517], [#526]]\n -  Added `BlockChain<T>.TipChangedEventArgs` class.  [[#526]]\n -  Added `Swarm<T>.BootstrapAsync()` method to connect with seed peers.\n    [[#353]]\n -  Added `RandomExtension` static class.  [[#508]]\n -  `TxId` class became to implement `IComparable<TxId>` and\n    `IComparable` interfaces.  [[#244], [#511]]\n\n### Behavioral changes\n\n -  `Swarm<T>` now broadcasts transactions as soon as new transactions are\n    received.  [[#463], [#496]]\n -  `Swarm<T>` now ignores block hashes which already exists.  [[#461], [#484]]\n -  `Swarm<T>.PreloadAsync()` method became to download precalculated states\n    of blocks from a likely branchpoint instead of a genesis block from\n    a trusted peer (i.e., `trustedStateValidators`) where there are branches\n    between peers.  [[#465], [#481]]\n -  `Swarm<T>`'s internal `GetRecentStates` message became to take\n    `BlockLocator`, an internal data type to approximates a path of\n    a chain of blocks for heuristics to search a likely branchpoint,\n    instead of `HashDigest<SHA256>`.  [[#465], [#481]]\n -  NetMQ instances are now initialized at `Swarm<T>.StartAsync()` instead of\n    `Swarm<T>()`.  [[#353]]\n -  Peers now connected via [Kademlia protocol][Kademlia].\n    Peers are now selectively connected to each peer.  [[#353]]\n -  `TxId`s and `Block`s are now broadcasted to selected peers from routing\n    table of the host peer.  [[#353]]\n -  `PolymorphicAction<T>.ToString()` method became to show the runtime type of\n    its `InnerAction` for the sake of easier debugging.  [[#512]]\n -  The order of `Block<T>.Transactions` became to be determined by\n    both a `Block<T>.Hash` and a `Transaction<T>.Id`, so that signers cannot\n    predict the order of transactions in a block before it's mined.\n    If there are multiple transactions signed by the same signer in a block\n    these transactions become grouped together and the order is determined by\n    a `Block<T>.Hash` and a fingerprint derived from all these transactions,\n    and transactions in each group (per signer) are ordered by\n    `Transaction<T>.Nonce`.  [[#244], [#355], [#511], [#520]]\n -  `LiteDBStore()` became to create the database in memory if the `path`\n    parameter is `null`.  [[#521]]\n\n### Bug fixes\n\n -  Fixed a bug that `Swarm<T>` hadn't released its TURN related resources on\n    `Swarm<T>.StopAsync()`.  [[#450]]\n -  Fixed a bug that `IActionContext.Random` had been possible to generated\n    equivalent results between actions of different transactions in\n    a `Block<T>`.  [[#519]]\n -  Fixed a bug where a forked chain would not be deleted when an exception\n    occurred during fetching block from other peers.  [[#527], [#537], [#540]]\n\n[#244]: https://github.com/planetarium/libplanet/issues/244\n[#353]: https://github.com/planetarium/libplanet/pull/353\n[#355]: https://github.com/planetarium/libplanet/pull/355\n[#420]: https://github.com/planetarium/libplanet/pull/420\n[#450]: https://github.com/planetarium/libplanet/pull/450\n[#460]: https://github.com/planetarium/libplanet/issues/460\n[#461]: https://github.com/planetarium/libplanet/issues/461\n[#463]: https://github.com/planetarium/libplanet/issues/463\n[#467]: https://github.com/planetarium/libplanet/pull/467\n[#470]: https://github.com/planetarium/libplanet/pull/470\n[#481]: https://github.com/planetarium/libplanet/pull/481\n[#483]: https://github.com/planetarium/libplanet/issues/483\n[#484]: https://github.com/planetarium/libplanet/pull/484\n[#486]: https://github.com/planetarium/libplanet/pull/486\n[#498]: https://github.com/planetarium/libplanet/pull/498\n[#496]: https://github.com/planetarium/libplanet/pull/496\n[#508]: https://github.com/planetarium/libplanet/pull/508\n[#509]: https://github.com/planetarium/libplanet/issues/509\n[#511]: https://github.com/planetarium/libplanet/pull/511\n[#512]: https://github.com/planetarium/libplanet/pull/512\n[#517]: https://github.com/planetarium/libplanet/pull/517\n[#519]: https://github.com/planetarium/libplanet/pull/519\n[#520]: https://github.com/planetarium/libplanet/pull/520\n[#521]: https://github.com/planetarium/libplanet/pull/521\n[#522]: https://github.com/planetarium/libplanet/pull/522\n[#526]: https://github.com/planetarium/libplanet/pull/526\n[#527]: https://github.com/planetarium/libplanet/issues/527\n[#537]: https://github.com/planetarium/libplanet/pull/537\n[#540]: https://github.com/planetarium/libplanet/pull/540\n[Kademlia]: https://en.wikipedia.org/wiki/Kademlia\n[Guid]: https://docs.microsoft.com/ko-kr/dotnet/api/system.guid?view=netframework-4.8\n[RFC 4122]: https://tools.ietf.org/html/rfc4122\n\n\nVersion 0.5.3\n-------------\n\nReleased on September 9, 2019.\n\n### Bug fixes\n\n -  Fix bug where `IAccountStateDelta.GetState()` hadn't returned proper state\n    when the block action is evaluated.  [[#500]]\n\n[#500]: https://github.com/planetarium/libplanet/pull/500\n\n\nVersion 0.5.2\n-------------\n\nReleased on August 29, 2019.\n\n### Bug fixes\n\n -  Fixed a bug that `Swarm<T>.PreloadAsync()` method had thrown `LiteException`\n    (or other exception depending on `IStore`), which indicates a state\n    reference is duplicate, where `trustedStateValidators` is present and\n    a miner tries to download precalculated states from a trusted peer.\n    [[#465], [#474]]\n -  Fixed a bug tag `Swarm<T>.StartAsync()` sometimes had thrown an exception\n    from `IStore` (e.g., `NullReferenceException`) during broadcasting\n    transactions.  [[#352], [#476]]\n\n[#352]: https://github.com/planetarium/libplanet/issues/352\n[#465]: https://github.com/planetarium/libplanet/issues/465\n[#474]: https://github.com/planetarium/libplanet/pull/474\n[#476]: https://github.com/planetarium/libplanet/pull/476\n\n\nVersion 0.5.1\n-------------\n\nReleased on August 28, 2019.\n\n### Bug fixes\n\n -  Fixed a bug that `ArgumentNullException` had been thrown when a blockchain,\n    which consists of incomplete states (i.e., precalculated states downloaded\n    from trusted peers), encounters a new branch so that reorg is made.\n    [[#454], [#466]]\n -  Fixed a bug that unnecessarily received all blocks in multiple miner\n    situations.  [[#457], [#468]]\n\n[#454]: https://github.com/planetarium/libplanet/issues/454\n[#457]: https://github.com/planetarium/libplanet/issues/457\n[#466]: https://github.com/planetarium/libplanet/pull/466\n[#468]: https://github.com/planetarium/libplanet/pull/468\n\n\nVersion 0.5.0\n-------------\n\nReleased on August 22, 2019.\n\n### Backward-incompatible interface changes\n\n -  Added `IStore.GetBlockIndex()` method.  [[#385]]\n -  `StoreExtension.LookupStateReference<T>()` method became to return\n    `Tuple<HashDigest<SHA256>, long>` which is a nullable tuple of\n    `Block<T>.Hash` and `Block<T>.Index`.  [[#350]]\n -  Added `IBlockPolicy<T>.BlockAction` property.  [[#319], [#367]]\n -  Removed the type parameter of `ActionEvaluation`.  [[#319], [#367]]\n -  `ActionEvaluation.Action` became to `IAction` type.  [[#319], [#367]]\n -  `LiteDBStore()` constructor became to have a new option named `flush` and\n    turned on by default.  [[#387], [LiteDB #1268]]\n -  `LiteDBStore()` constructor became to have a new option named `readOnly` and\n    turned off by default.  [[#434]]\n -  `BaseIndex.ContainsKey()` method became `abstract`.  [[#390]]\n -  `BlockDownloadState.TotalBlockCount` and\n    `BlockDownloadState.ReceivedBlockCount` became to `Int64` type.\n    [[#396], [#399]]\n -  `IStore.IterateIndex()` method became to receive `offset` and `limit`\n    parameters.  [[#425]]\n -  Added `IStore.GetCanonicalNamespace()` method.  [[#426]]\n -  Added `IStore.SetCanonicalNamespace()` method.  [[#426]]\n -  Removed `IRandom.NextDouble()` method, because [floating-point arithmetics,\n    which is underspecified, likely introduce\n    indeterminism][floating-point determinism].  [[#410], [#419]]\n -  Added `IActionContext.NewGuId()` method.  [[#371], [#439]]\n -  `Address(byte[])` became to throw `ArgumentNullException`\n    instead of `NullReferenceException`.  [[#443]]\n -  Removed `FileStore` class.  [[#446]]\n\n### Added interfaces\n\n -  Added `trustedStateValidators` option to `Swarm<T>.PreloadAsync()` method.\n    If any peer in this set is reachable and there is no built up blockchain\n    in a current node, `Swarm<T>` receives the latest states of the major\n    blockchain from that trusted peer, which is also calculated by that peer,\n    instead of autonomously calculating the states from scratch.\n    Note that this option is intended to be exposed to end users through\n    a feasible user interface so that they can decide whom to trust\n    for themselves.\n    [[#272], [#343]]\n -  Added `StoreExtension.ListAllStateReferences(this IStore, string,\n    HashDigest<SHA256>?, HashDigest<SHA256>?)` extension method.\n    [[#363], [#384], [#385]]\n -  `Address` class became to implement `IComparable<Address>` and\n    `IComparable` interfaces.  [[#363]]\n -  Added `BlockChain<T>.BlockHashes` property.  [[#389]]\n -  `Swarm<T>.PreloadAsync(IProgress<PreloadState>, IImmutableSet<Address>,\n    CancellationToken)` became to report progress for all phases.\n    [[#397], [#400]]\n -  Added `PreloadState`, `ActionExecutionState`, `StateReferenceDownloadState`,\n    and `BlockStateDownloadState` classes to cover all phases in the entire\n    preloading process.  [[#397], [#400]]\n -  Added `Address(ImmutableArray<byte>)` constructor.  [[#442], [#443]]\n\n### Behavioral changes\n\n -  `BlockChain<T>.PreloadAsync()` method became to omit rendering of\n    `IAction`s in the preloaded behind blocks.  [[#272], [#343]]\n -  `Swarm<T>` became to have two more message types: `GetRecentStates` (`0x0b`)\n    and `RecentStates` (`0x0c`).  [[#272], [#343]]\n -  `BlockChain<T>.MineBlock()` and `BlockChain<T>.GetNextTxNonce()` methods\n    became to ignore transactions that didn't follow `Transaction<T>.Nonce`\n    sequentially and treat them as pendings.  [[#365]]\n -  `BlockChain<T>` became to evaluate `IBlockPolicy<T>.BlockAction` and set the\n    state when a block is appended to the chain.  [[#319], [#367]]\n -  `BlockSet<T>.ContainsKey()` and `TransactionSet<T>.ContainsKey()` methods\n    became O(1) time complexity through omitting iteration and relying\n    own retrieve implementations.  [[#390]]\n -  The way `LiteDBStore` stores state references became efficient,\n    but the file-level backward compatibility was also broken.  [[#395], [#398]]\n -  `Swarm<T>.PreloadAsync()` method became to report a block downloading\n    progress with the total number of blocks to download in the entire batch,\n    instead of the window size of a chunk (i.e., 500).  [[#396], [#399]]\n -  `Swarm<T>.PreloadAsync()` became to get the first parameter, `progress`,\n    which accepts `IProgress<PreloadState>`.  [[#397], [#400]]\n -  `BlockHashes` messages became to contain one more higher hash.\n    [[#408], [#445]]\n -  `Swarm<T>.PreloadAsync()` became safe from data corruption even\n    if a preloading process suddenly gets shutdown.  [[#417]]\n -  `FileStore` and `LiteDBStore` became to guarantee atomicity of storing\n    transactions.  [[#413]]\n -  `IStore.PutTransaction<T>()` became to do nothing when it takes\n    the `Transaction<T>` more than once.  [[#413]]\n -  `BlockChain<T>.Swap()` became to omit common block finding when `render` is\n    `false`.  [[#423]]\n -  `PrivateKey(byte[])` constructor became to check validity.  [[#438]]\n\n### Bug fixes\n\n -  Fixed a bug where the `LiteDBStore.IterateStagedTransactionIds()` returns\n    duplicated transaction ids.  [[#366]]\n -  Fixed a bug that `NullReferenceException` occurred when serializing default\n    `Address`.  [[#369]]\n -  Removed unnecessary mutex in `Swarm<T>` to avoid continuous delays in peer\n    registration in some situations.  [[#375]]\n -  Fixed a bug that `TurnClient` had thrown `KeyNotFoundException` and\n    `IOException` on startup.  [[#377], [#378]]\n -  Fixed a `LiteDBStore` bug that blocks or transactions had got corrupted\n    sometimes.  Instead, `LiteDBStore.GetTransaction()` became possible to\n    return `null` even for already stored transactions, and for that case,\n    a warning will be logged through Serilog.\n    [[#386], [#387], [LiteDB #1268]]\n -  Fixed a bug that `NetworkStreamProxy.StartAsync()` hadn't stopped properly\n    when the connection had reset by a remote peer.  [[#414]]\n -  Fixed a bug that `Swarm<T>` had hung forever after a remote peer had\n    disconnected while receiving.  [[#416]]\n -  Fixed a bug that `Swarm<T>.PreloadAsync()` had been processed even if there\n    is no appropriate peer.  [[#418]]\n -  Fixed a bug that TURN-related tasks hadn't restarted automatically when an\n    exception occurred.  [[#422]]\n -  Fixed a bug that TURN relay connection had disconnected when preloading\n    took a long time.  [[#424]]\n\n[#319]: https://github.com/planetarium/libplanet/issues/319\n[#343]: https://github.com/planetarium/libplanet/pull/343\n[#350]: https://github.com/planetarium/libplanet/pull/350\n[#363]: https://github.com/planetarium/libplanet/pull/363\n[#365]: https://github.com/planetarium/libplanet/pull/365\n[#366]: https://github.com/planetarium/libplanet/pull/366\n[#367]: https://github.com/planetarium/libplanet/pull/367\n[#369]: https://github.com/planetarium/libplanet/pull/369\n[#371]: https://github.com/planetarium/libplanet/issues/371\n[#375]: https://github.com/planetarium/libplanet/pull/375\n[#377]: https://github.com/planetarium/libplanet/issues/377\n[#378]: https://github.com/planetarium/libplanet/pull/378\n[#384]: https://github.com/planetarium/libplanet/issues/384\n[#385]: https://github.com/planetarium/libplanet/pull/385\n[#386]: https://github.com/planetarium/libplanet/pull/386\n[#387]: https://github.com/planetarium/libplanet/pull/387\n[#389]: https://github.com/planetarium/libplanet/pull/389\n[#390]: https://github.com/planetarium/libplanet/pull/390\n[#395]: https://github.com/planetarium/libplanet/issues/395\n[#396]: https://github.com/planetarium/libplanet/issues/396\n[#397]: https://github.com/planetarium/libplanet/issues/397\n[#398]: https://github.com/planetarium/libplanet/pull/398\n[#399]: https://github.com/planetarium/libplanet/pull/399\n[#400]: https://github.com/planetarium/libplanet/pull/400\n[#408]: https://github.com/planetarium/libplanet/issues/408\n[#410]: https://github.com/planetarium/libplanet/issues/410\n[#413]: https://github.com/planetarium/libplanet/pull/413\n[#414]: https://github.com/planetarium/libplanet/pull/414\n[#416]: https://github.com/planetarium/libplanet/pull/416\n[#417]: https://github.com/planetarium/libplanet/pull/417\n[#418]: https://github.com/planetarium/libplanet/pull/418\n[#419]: https://github.com/planetarium/libplanet/pull/419\n[#422]: https://github.com/planetarium/libplanet/pull/422\n[#423]: https://github.com/planetarium/libplanet/pull/423\n[#424]: https://github.com/planetarium/libplanet/pull/424\n[#426]: https://github.com/planetarium/libplanet/pull/426\n[#434]: https://github.com/planetarium/libplanet/pull/434\n[#438]: https://github.com/planetarium/libplanet/pull/438\n[#439]: https://github.com/planetarium/libplanet/pull/439\n[#442]: https://github.com/planetarium/libplanet/issues/442\n[#443]: https://github.com/planetarium/libplanet/pull/443\n[#445]: https://github.com/planetarium/libplanet/pull/445\n[#446]: https://github.com/planetarium/libplanet/pull/446\n[LiteDB #1268]: https://github.com/mbdavid/LiteDB/issues/1268\n[floating-point determinism]: https://wp.me/p1fTCO-kT\n\n\nVersion 0.4.1\n-------------\n\nReleased on July 11, 2019.\n\n### Bug fixes\n\n -  Fixed a bug where the `BlockChain<T>.GetStates()` method had not returned\n    the latest state when there are multiple addresses.  [[#346]]\n\n[#346]: https://github.com/planetarium/libplanet/pull/346\n\n\nVersion 0.4.0\n-------------\n\nReleased on July 8, 2019.\n\n### Backward-incompatible interface changes\n\n -  `Peer.AppProtocolVersion` became nullable to represent `Peer` whose version\n    is unknown.  [[#280]]\n -  Added `IStore.ListAddresses()` method.  [[#272], [#285]]\n -  Added `IStore.ListTxNonces()` method.  [[#272], [#309], [#310]]\n -  Removed `BlockChain<T>.GetNonce()` method.  [[#294]]\n -  `BlockChain<T>.StageTransactions` became to receive\n    `IDictionary<Transaction<T>, bool>` instead of `ISet<Transaction<T>>`.\n    [[#274], [#297]]\n -  `IStore.StageTransactionIds()` method became to receive\n    `IDictionary<TxId, bool>` instead of `ISet<TxId>`.  [[#274], [#297]]\n -  `IStore.IterateStagedTransactionIds()` method became to receive\n    `bool toBroadcast` which is whether to iterate only the TxId set to\n    broadcast.  [[#274], [#297]]\n -  `Swarm<T>.StartAsync()` method became to receive `broadcastTxInterval`\n    (or `millisecondsBroadcastTxInterval`) parameter.  [[#274], [#297]]\n -  `IStore` became to treat a \"tx nonce\" mere a `long` integer instead of\n    a stack of block hashes.  [[#272], [#307], [#309], [#310]]\n     -  `IStore.IncreaseTxNonce<T>(string, Block<T>)` method was replaced by\n        `IStore.IncreaseTxNonce(string, Address, long)` method.\n     -  Removed `IStore.ForkTxNonce()` method.\n     -  `FileStore` became to occupy fewer bytes for storing tx nonces.\n        This change broke file-level backward compatibility.\n -  `IStore` became possible to look up multiple state references in a stack.\n    [[#272], [#307]]\n     -  Removed `IStore.LookupStateReference<T>()` method.\n        Instead, a newly added static class `StoreExtension` provides\n        an extension method of the same name.\n     -  Added `IStore.IterateStateReferences()` method.\n -  `Swarm` became to have type parameter `T` to represent an action type as\n    like as `BlockChain<T>`.  [[#324]]\n -  `Swarm<T>` constructor became to receive `BlockChain<T>`.  [[#324]]\n -  Methods  in `Swarm<T>` that had taken a parameter of `BlockChain<T>` type\n    became to neither longer take `BlockChain<T>` nor a generic method.\n    Because the `Swarm<T>` constructor takes it instead.  [[#324]]\n -  `Swarm<T>` does not implement `ICollection<Peer>` anymore.  [[#326]]\n -  Added `IStore.DeleteNamespace()` method.  [[#329]]\n -  Removed the `id` parameter from the `BlockChain<T>` constructor, and it\n    became to automatically detect an appropriate `BlockChain<T>.Id`.\n    [[#279], [#332]]\n\n### Added interfaces\n\n -  Added `LiteDBStore` backend that uses [LiteDB] under the hood.  [[#269]]\n -  All `*Async()` methods belonging to `TurnClient` class became to have\n    `cancellationToken` option.  [[#287]]\n -  Added a `Peer` constructor omitting `appProtocolVersion` parameter\n    to create a `Peer` whose version is unknown.  [[#280]]\n -  Added `IncompleteBlockStatesException` class.  [[#272], [#285]]\n -  Added `completeStates` option to `BlockChain<T>.GetStates()` method.\n    [[#272], [#285]]\n -  Added `BlockChain<T>.MakeTransaction(PrivateKey, IEnumerable<T>,\n    IImmutableSet<Address>, DateTimeOffset?)` method.  [[#294]]\n -  Added `BlockChain<T>.GetNextTxNonce()` method which counts staged\n    transactions too during nonce computation.  [[#270], [#294]]\n -  Added `StoreExtension` static class.  [[#272], [#307]]\n -  Added `Swarm<T>.BlockChain` property.  [[#272], [#343]]\n\n### Behavioral changes\n\n -  `BlockChain<T>.GetStates()` method became to throw\n    `IncompleteBlockStatesException` if its `Store` lacks the states of a block\n    that a requested address lastly updated.  [[#272], [#285]]\n -  A message `Swarm<T>` makes became to have multiple blocks within it, which\n    means round trips on the network are now much reduced.  [[#273], [#276]]\n -  `Message.Block` has been replaced by `Message.Blocks` and the magic number\n    has been changed to `0x0a`.  [[#276]]\n -  Improved performance of `Swarm<T>`'s response time to `GetBlockHashes`\n    request messages.  [[#277]]\n -  Added IPv6 support to `Libplanet.Stun.StunAddress`.  [[#267], [#271]]\n -  `IStore.GetBlockStates()` became able to return `null` to represent\n    an absence of states (i.e., incomplete states).  [[#272], [#285]]\n -  `Swarm<T>` became to broadcast staged `Transaction`s periodically\n     so that game apps no more need to maintain their own thread to\n     broadcast staged transactions.  [[#274], [#297]]\n -  Previously, `Swarm<T>` had sent an empty `GetTxs` message when it receives\n    an empty `TxIds` from peers, and it had made the network waste bandwidth for\n    unnecessary messages.  `Swam<T>` became to no more send such empty `GetTxs`.\n    [[#297]]\n -  `BlockChain<T>.Swap()` became to delete an index, tx nonces, and state\n    references in the replaced chain.  [[#329]]\n -  Reduced the memory footprint of `BlockChain<T>.FindBranchPoint()` method\n    under the circumstances that the height of\n    the `BlockChain<T>` object is high.  [[#282], [#299]]\n\n### Bug fixes\n\n -  Fixed a bug that `Swarm<T>` reported `TaskCanceledException` as an unknown\n    exception while stopping.  [[#275]]\n -  Fixed a bug that `Swarm<T>` didn't stop properly during\n    `Swarm<T>.PreloadAsync()`.  [[#275]]\n -  Fixed a bug where the oldest `TxNonce` of an address is not invalidated\n    when forking using `FileStore.ForkTxNonce()` method.  [[#281]]\n -  Fixed a bug where `LiteDBStore.GetTxNonce()` method throws a\n    `System.IO.IOException` after forking.  [[#281]]\n -  Fixed a bug that `TurnClient` had not stopped properly.  [[#287]]\n -  Fixed a bug that `TurnClient` had been trying to use an already closed\n    connection.  [[#303], [#308]]\n -  Fixed a bug that `KeyNotFoundException` had been thrown instead of\n    `ArgumentOutOfRangeException` when `Blockchain<T>[int]` called while the\n    index of a block that does not exist locally.  [[#208], [#317]]\n -  Fixed a bug that `Swarm<T>` had not dial to other peer after\n    `Swarm<T>.PreloadAsync()`.  [[#311]]\n -  Fixed an issue where unknown exceptions occurred when `Swarm<T>` receiving\n    a message.  [[#321], [#327]]\n\n[LiteDB]: https://www.litedb.org/\n[#208]: https://github.com/planetarium/libplanet/issues/208\n[#267]: https://github.com/planetarium/libplanet/issues/267\n[#269]: https://github.com/planetarium/libplanet/pull/269\n[#270]: https://github.com/planetarium/libplanet/pull/270\n[#271]: https://github.com/planetarium/libplanet/pull/271\n[#272]: https://github.com/planetarium/libplanet/issues/272\n[#273]: https://github.com/planetarium/libplanet/issues/273\n[#274]: https://github.com/planetarium/libplanet/issues/274\n[#275]: https://github.com/planetarium/libplanet/pull/275\n[#276]: https://github.com/planetarium/libplanet/pull/276\n[#277]: https://github.com/planetarium/libplanet/pull/277\n[#279]: https://github.com/planetarium/libplanet/issues/279\n[#280]: https://github.com/planetarium/libplanet/pull/280\n[#281]: https://github.com/planetarium/libplanet/pull/281\n[#282]: https://github.com/planetarium/libplanet/issues/282\n[#285]: https://github.com/planetarium/libplanet/pull/285\n[#287]: https://github.com/planetarium/libplanet/pull/287\n[#294]: https://github.com/planetarium/libplanet/pull/294\n[#297]: https://github.com/planetarium/libplanet/pull/297\n[#299]: https://github.com/planetarium/libplanet/pull/299\n[#303]: https://github.com/planetarium/libplanet/issues/303\n[#307]: https://github.com/planetarium/libplanet/pull/307\n[#308]: https://github.com/planetarium/libplanet/pull/308\n[#309]: https://github.com/planetarium/libplanet/issues/309\n[#310]: https://github.com/planetarium/libplanet/pull/310\n[#311]: https://github.com/planetarium/libplanet/pull/311\n[#317]: https://github.com/planetarium/libplanet/pull/317\n[#321]: https://github.com/planetarium/libplanet/pull/321\n[#324]: https://github.com/planetarium/libplanet/pull/324\n[#326]: https://github.com/planetarium/libplanet/pull/326\n[#327]: https://github.com/planetarium/libplanet/pull/327\n[#329]: https://github.com/planetarium/libplanet/pull/329\n[#332]: https://github.com/planetarium/libplanet/pull/332\n\nVersion 0.3.0\n-------------\n\nReleased on May 31, 2019.\n\n### Backward-incompatible interface changes\n\n -  Added `IAction.Render(IActionContext, IAccountStateDelta)` method.\n    [[#31], [#212]]\n -  Added `IAction.Unrender(IActionContext, IAccountStateDelta)` method.\n    [[#31], [#212]]\n -  `BlockChain<T>.Validate()` method became to receive\n    `IReadOnlyList<Block<T>>` instead of `IEnumerable<Block<T>>`.  [[#205]]\n -  `IBlockPolicy<T>.GetNextBlockDifficulty()` method became to receive\n    `IReadOnlyList<Block<T>>` instead of `IEnumerable<Block<T>>`.  [[#205]]\n -  Added\n    `IBlockPolicy<T>.ValidateNextBlock(IReadOnlyList<Block<T>>, Block<T>)`\n    method.  [[#210]]\n -  Removed `IBlockPolicy<T>.ValidateBlocks()` method.  [[#210]]\n -  `BlockChain<T>[int]` became to throw `ArgumentOutOfRangeException` instead\n    of `IndexOutOfRangeException`.  [[#210]]\n -  Removed `KeyEquals()` methods from all classes and structs.  [[#216]]\n -  `Swarm` class now does not implement `IEquatable<Swarm>` anymore and\n    its `Equals(object)` method and `GetHashCode()` method became to have\n    default behavior of `object` class.  [[#216]]\n -  Also, `Swarm` class now does not implement `IDisposable` too.  Thus\n    `Swarm.Dispose()` was removed too.  [[#218]]\n -  `Swarm` became to use a queue to maintain internal messages.  [[#218]]\n     -  The broadcasting methods are no more `async`, so they are renamed\n        as below.\n        -  `Swarm.BroadcastBlocksAsync()` → `Swarm.BroadcastBlocks()`\n        -  `Swarm.BroadcastTxsAsync()` → `Swarm.BroadcastTxs()`\n -  The type of `Block<T>.Difficulty` is changed to `long` instead of `int`, and\n    related classes method parameters and field types have changed accordingly.\n -  Removed `HashDigest.HasLeadingZeroBits()` method.  [[#213]]\n -  The signature of `IStore.PutBlock<T>(Block<T>)` method was changed to\n    `PutBlock<T>(Block<T>, Address)`.  [[#189], [#197]]\n -  `Block<T>.Hash` is no longer calculated using the full data of the\n    `Transaction<T>`, but is calculated using only the `Transaction<T>.Id`.\n    [[#234]]\n -  Added `IStore.LookupStateReference<T>(string, Address, Block<T>)` method.\n    [[#232]]\n -  Added `IStore.StoreStateReference<T>(string, Block<T>)` method.\n    [[#232]]\n -  Added `IStore.ForkStateReferences<T>(string, string, Block<T>,\n    IImmutableSet<Address>` method.  [[#232]]\n -  Removed `Block<T>.Validate()` and `Block<T>.EvaluateActions()` method.\n    [[#243]]\n -  Added `Transaction<T>.Nonce` and `RawTransaction.Nonce` properties.\n    [[#246]]\n -  Added `IStore.GetTxNonce(string, Address)` method.  [[#246]]\n -  Added `IStore.IncreaseTxNonce<T>(string, Block<T>)` method.  [[#246]]\n -  Added `IStore.ForkTxNonce<T>(string, string, Block<T>,\n    IImmutableSet<Address>` method.  [[#246]]\n\n### Added interfaces\n\n -  `BlockChain<T>` became to implement `IReadOnlyList<Block<T>>`.  [[#205]]\n -  Added `Swarm.DifferentVersionPeerEncountered` event handler that can handle\n    events when a different version of a peer is discovered.  [[#167]], [[#185]]\n -  Added `Peer.AppProtocolVersion` property.  [[#185]]\n -  Added `Swarm.PreloadAsync()` method to explicitly and preemptively download\n    initial blocks before `Swarm.StartAsync<T>()` being called.\n    [[#204]], [[#206]]\n -  Added `BlockDownloadState` class to represent a block downloading state.\n    [[#204]], [[#206]]\n -  Added `BlockPolicyExtension.ValidateBlocks<T>(IBlockPolicy<T>,\n    IReadOnlyList<Block<T>>, DateTimeOffset)` method.  [[#210]]\n -  Added `Transaction<T>.EvaluateActionsGradually(HashDigest<SHA256>, long,\n    IAccountStateDelta, Address, bool)` method.  [[#31], [#212]]\n -  Added `Block<T>.EvaluateActionsPerTx(AccountStateGetter)` method.\n    [[#31], [#212]]\n -  Added `HashDigest.Satisfies()` method.  [[#213]]\n -  `BlockPolicy<T>` constructor became to receive the `minimumDifficulty`\n    and the mining `difficultyBoundDivisor`.  [[#213]]\n -  Added `BlockChain<T>.UnstageTransactions()` method.  [[#223]]\n -  `Swarm` constructor became to receive a `linger` (or `millisecondsLinger`)\n    parameter.  This purposes to determine how long to wait for pending\n    messages when a `Swarm` instance is requested to terminate.\n -  Added `NamespaceNotFoundException` class.  [[#232]]\n -  Added `Block<T>.Evaluate()` method.  [[#243]]\n -  Made `InvalidBlockTimestampException` class `public` so that it can be\n    caught.  [[#133], [#251]]\n -  Added `InvalidTxNonceException` class.  [[#246]]\n\n### Behavioral changes\n\n -  `Swarm.StartAsync()` now receives the height of blocks (tip `Index`) from\n    other known peers and synchronizes the blocks if necessary\n    before propagating/receiving pinpointed recent blocks to prevent inefficient\n    round-trips.  [[#187], [#190]]\n -  The calculation algorithm of `BlockPolicy<T>.GetNextBlockDifficulty()`\n    method was changed to the [Ethereum Homestead algorithm] except for the\n    difficulty bomb.  [[#213]]\n -  The difficulty was changed from representing the number of leading zeros of\n    target number to representing a divisor to obtain the target number.\n    [[#213]]\n -  `BlockSet<T>[int]` changed so as not to validate a block.  [[#231]]\n -  Improved read performance of `Block<T>.Hash` and `Transaction<T>.Id`.\n    [[#228], [#234]]\n -  `Swarm.StartAsync()` now does not call `Swarm.StopAsync()` anymore,\n    therefore `Swarm.StopAsync()` should be explicitly called.  [[#236]]\n -  `Transaction<T>.EvaluateActionsGradually()` became to record\n    `IAccountStateDelta.SetState()` calls even if its argument is the same\n    to the previous state.  [[#241]]\n -  `Block<T>.Validate()` and `Block<T>.EvaluateActions()` are integrated into\n    `Block<T>.Evaluate()`.  [[#243]]\n -  `BlockChain<T>.Append()` became to execute `Action.Execute()` only once per\n    action in the `Block<T>`.  [[#243]]\n -  `BlockChain<T>.Append()` method became to throw `InvalidTxNonceException`\n    when the `Transaction<T>.Nonce` does not correspond to its `Signer`'s\n    current nonce.  [[#246]]\n -  `Swarm` became to enforce `ForceDotNet.Force()` in [AsyncIO] while\n    it's running on Mono runtime.  [[#247]]\n\n### Bug fixes\n\n -  Fixed a bug that TURN relay had been disconnected when being connected for\n    longer than 5 minutes.  [[#198]]\n -  Fixed a bug that `Swarm` had attempted to use TURN relay even if the `host`\n    argument was given.  [[#198]]\n -  Improved the read throughput of `BlockChain<T>.Append()`.\n -  Improved overall read throughput of `BlockChain<T>` while blocks are being\n    mined by `BlockChain<T>.MineBlock()`.  [[#191]]\n -  Fixed a bug that `TurnClientException` had been thrown by Swarm when a STUN\n    nonce is stale.  [[#193]]\n -  Fixed `BlockChain<T>.GetStates()` had descended to the bottom\n    (i.e., the genesis block) where a given `Address` refers to\n    a nonexistent account (i.e., never used before).  [[#189], [#192]]\n -  Fixed a bug that a TURN connection had turned unavailable after\n    it once failed to parse a message (due to a corrupted packet).\n    [[#215]]\n -  Instead of validating the entire blocks, `BlockChain<T>.Append()` method\n    became to validate only the next block to be appended.  [[#210]]\n -  Improved `BlockChain<T>.Fork()` performance by avoiding double validation\n    of already validated blocks.  [[#215]]\n -  Removed unnecessary writer locks on `BlockChain<T>.StageTransactions()`.\n    [[#217]]\n -  Improved concurrency of `BlockChain<T>.Append()` method by removing\n    unnecessary race conditions.  [[#217]]\n -  Fixed a bug that `Swarm` could not properly communicate with `Peer` behind\n    NAT.  [[#240]]\n -  Fixed a bug that `BlockChain<T>.FindNextHashes()` throws\n    `ArgumentOutOfRangeException` when chain is empty.\n -  Fixed a bug that `TurnClient.AcceptRelayedStreamAsync()`didn't handle\n    concurrent connections correctly.  [[#256]]\n\n[AsyncIO]: https://github.com/somdoron/AsyncIO\n[Ethereum Homestead algorithm]: https://github.com/ethereum/EIPs/blob/master/EIPS/eip-2.md\n[#31]: https://github.com/planetarium/libplanet/issues/31\n[#133]: https://github.com/planetarium/libplanet/issues/133\n[#185]: https://github.com/planetarium/libplanet/pull/185\n[#187]: https://github.com/planetarium/libplanet/issues/187\n[#190]: https://github.com/planetarium/libplanet/pull/190\n[#191]: https://github.com/planetarium/libplanet/pull/191\n[#193]: https://github.com/planetarium/libplanet/pull/193\n[#197]: https://github.com/planetarium/libplanet/pull/197\n[#198]: https://github.com/planetarium/libplanet/pull/198\n[#204]: https://github.com/planetarium/libplanet/issues/204\n[#205]: https://github.com/planetarium/libplanet/pull/205\n[#206]: https://github.com/planetarium/libplanet/pull/206\n[#210]: https://github.com/planetarium/libplanet/pull/210\n[#212]: https://github.com/planetarium/libplanet/pull/212\n[#213]: https://github.com/planetarium/libplanet/pull/213\n[#215]: https://github.com/planetarium/libplanet/pull/215\n[#216]: https://github.com/planetarium/libplanet/pull/216\n[#217]: https://github.com/planetarium/libplanet/pull/217\n[#218]: https://github.com/planetarium/libplanet/pull/218\n[#223]: https://github.com/planetarium/libplanet/pull/223\n[#228]: https://github.com/planetarium/libplanet/issues/228\n[#231]: https://github.com/planetarium/libplanet/pull/231\n[#232]: https://github.com/planetarium/libplanet/pull/232\n[#234]: https://github.com/planetarium/libplanet/pull/234\n[#236]: https://github.com/planetarium/libplanet/pull/236\n[#240]: https://github.com/planetarium/libplanet/pull/240\n[#241]: https://github.com/planetarium/libplanet/pull/241\n[#243]: https://github.com/planetarium/libplanet/pull/243\n[#246]: https://github.com/planetarium/libplanet/pull/246\n[#247]: https://github.com/planetarium/libplanet/pull/247\n[#251]: https://github.com/planetarium/libplanet/pull/251\n[#256]: https://github.com/planetarium/libplanet/pull/256\n\n\nVersion 0.2.2\n-------------\n\nReleased on April 12, 2019.\n\n -  Fixed a bug that `BlockChain<T>.GetStates()` had returned slower than\n    necessary for many addresses.  [[#189], [#192]]\n\n[#189]: https://github.com/planetarium/libplanet/issues/189\n[#192]: https://github.com/planetarium/libplanet/pull/192\n\n\nVersion 0.2.1\n-------------\n\nReleased on April 7, 2019.\n\nThis version purposes to entirely replace *0.2.0*, because a wrong *.nupkg*\nfile was uploaded to *0.2.0* on NuGet Gallery.  Note that *0.2.0* on NuGet\nGallery was unlisted.\n\n\nVersion 0.2.0\n-------------\n\nReleased on April 5, 2019.\n\n -  `PrivateKey.Decrypt()` now throws an `InvalidCiphertextException`\n    instead of returning `null` when `cipherText` is invalid.  [[#140]]\n -  `Transaction<T>`'s `Sender`–`Recipient` model was replaced by\n    `Signer`–`UpdatedAddresses` model.   Unlike cryptocurrencies,\n    transactions in games are not necessarily a transfer of assets,\n    so it is difficult to determine what type of assert is transferred\n    or who will receives the asset.  A more useful perspective is,\n    like what kind of transformation is performed, or what states\n    are changed.  To be close to this perspective, we decided to\n    get rid of `Transaction<T>.Recipient` (which is singular) and\n    have `Transaction<T>.UpdatedAddresses` (which is plural) instead.\n    As there is no more asset to transfer, the term `Sender` was also\n    renamed to `Signer`, which fits more to the new perspective.\n    [[#121]]\n\n     -  Renamed `Transaction<T>.Sender`, `RawTransaction.Signer`, and\n        `IActionContext.From` properties to `Signer`.\n        The corresponding parameter names on constructors and\n        methods were also renamed too.\n     -  Old `Transaction<T>.Make()` factory method is replaced by\n        new `Transaction<T>.Create()` factory method.  The `timestamp` parameter\n        became optional, and the new optional `updatedAddresses` parameter was\n        added.\n     -  Removed `IActionContext.To` property.\n     -  `Transaction<T>.Recipient` and `RawTransaction.Recipient` properties\n        were replaced by `Transaction<T>.UpdatedAddresses` and\n        `RawTransaction.UpdatedAddresses` properties.\n        The corresponding parameter names on constructors and methods were\n        replaced too.\n     -  Since the schema of `RawTransaction` class was changed,\n        the serialization format of transactions and blocks were also changed.\n        It affects to the way to generate `Transaction<T>.Signature`,\n        `Transaction<T>.Id`, and `Block.Hash` values as well.\n     -  Added `InvalidTxUpdatedAddressesException` exception class.\n     -  A nullary overload of `Block<T>.Validate()` method was gone\n        so that the block validation API is always time-wise.\n        Instead, `Block<T>.Validate()` method now has only one overload:\n        `Validate(DateTimeOffset, AccountStateGetter)` returning\n        `IAccountStateDelta`.\n     -  `Block<T>.Validate()` and `BlockChain<T>.Validate()` methods now can\n        throw an `InvalidTxUpdateAddressesException`.\n\n -  The `Address`es `IAction` tries to update no more need to be manually\n    coded using `IAction.RequestStates()` method.  That method was\n    removed at all, and updated `Address`es became automatically determined\n    (for the most cases) by track \"dirties\" on <dfn>rehearsal mode<dfn>.\n    This mode dry-runs `IAction`s with empty `IActionContext.PreviousStates`.\n    [[#121]]\n\n     -  Added `AccountStateGetter` delegate to provide a read-only view to\n        account states.\n     -  Added `IAccountStateDelta` interface to replace `AddressStateMap`.\n        The interface purposes to provide a read-write view to account states\n        with maintaining `UpdatedAddresses` (so-called \"dirty\").\n        [[#98]]\n     -  The type of `IActionContext.PreviousStates` property was changed from\n        `AddressStateMap` to `IAccountStateDelta`.\n     -  Added `IActionContext.Rehearsal` property.  [[#131], [#135]]\n     -  Added `UnexpectedlyTerminatedTxRehearsalException` class.\n        [[#132], [#136]]\n     -  The return type of `IAction.Execute()` method was changed from\n        `AddressStateMap` to `IAccountStateDelta`.\n     -  Removed `IAction.RequestStates()` method because there is no need for it\n        and thus it is not used anymore.\n     -  Added `Transaction<T>.EvaluateActions()` method.\n     -  Added `Block<T>.EvaluateActions()` generator method.\n\n -  The built-in subtype polymorphism of `IAction` and `Transaction<T>` was\n    moved to a separated new `PolymorphicAction<T>` abstract class.\n    Polymorphic actions now should be wrapped by `PolymorphicAction<T>`.\n    For example, the following code:\n\n    ~~~~ csharp\n    public abstract class AbstractAction : IAction { ... }\n\n    [ActionType(\"attack\")]\n    public sealed class Attack : AbstractAction { ... }\n\n    [ActionType(\"sleep\")]\n    public sealed class Sleep : AbstractAction { ... }\n    ~~~~\n\n    ~~~~ csharp\n    var tx = Transaction<AbstractAction>.Create(\n        ...,\n        actions: new[] { new Attack(...), ... }\n    );\n    ~~~~\n\n    should be changed to like:\n\n    ~~~~ csharp\n    var tx = Transaction<PolymorphicAction<AbstractAction>>.Create(\n        ...,\n        actions: new[] {\n            new PolymorphicAction<AbstractAction>(new Attack(...)),\n            ...\n        }\n    );\n    ~~~~\n\n    It can be simpler by implicit casting:\n\n    ~~~~ csharp\n    var tx = Transaction<PolymorphicAction<AbstractAction>>.Create(\n        ...,\n        actions: new PolymorphicAction<AbstractAction>[] { new Attack(...), }\n    );\n    ~~~~\n\n    [[#169]]\n\n     -  The type parameter `T` of `Transaction<T>`, `Block<T>`, and\n        `BlockChain<T>` became to require having a `public` parameterless\n        constructor (i.e., `new()`) besides implementing `IAction` interface.\n        This means an `abstract class` or an `interface` no more can be passed\n        to `T`, but only a concrete `class` or a `struct` can be passed.\n\n -  Fixed a bug that mutating a collection of `IAction`s passed to\n    constructors or factory methods of `Transaction<T>` had affected\n    made instances as well.\n    The type of `Transaction<T>.Actions` property was changed from\n    `IList<T>` to `IImmutableList<T>`.  The corresponding parameters on\n    constructors and factory methods also were changed to take\n    `IEnumerable<T>` instead of `IList<T>`.\n -  `Address` and `TxId` are now serializable.\n    [[#99], [#124] by Qria]\n -  `InvalidTxException` and its subclasses became to have `TxId` property\n    and the corresponding constructor parameter.  This can be useful when\n    multiple `Transaction<T>` objects are validated at once.\n -  Added `Address.Size` constant, which is fixed to the `Int32` 20.\n -  Fixed a bug that `Block<T>.Validate()` had not thrown `InvalidTxException`\n    even if there is any integrity error on its `Transactions`.\n -  Improved the write throughput of `BlockChain<T>` while polling\n    `BlockChain<T>.GetStates()`\n -  `Swarm.AddPeersAsync()` was fixed so that unreachable `Peer`s are ignored.\n    [[#128]]\n -  `Swarm` became able to relay their connection via TURN ([RFC 5766])\n    to NAT traversal.  To enable this, its constructor (`Swarm()`) takes the\n    newly added `IceServer`s as configuration.\n -  Since we decided to depend on TURN ([RFC 5766]) and STUN ([RFC 5389]) to\n    work around NAT so that `Peer`'s endpoints don't have to be multiple,\n    `Peer.Urls` was renamed to `Peer.EndPoint` and its type also was changed\n    from `IImmutableList<Uri>` to `DnsEndPoint`.\n    [[#120], [#123] by Yang Chun Ung, [#126], [#127], [#165], [#166]]\n -  `Swarm` became to ignore tip blocks of the same height (`Index`) that it\n    already has and deal with only longer (higher) blocks.\n -  Fixed a bug that occurred when `Swarm` was handling multiple responses at\n    the same time.\n -  Fixed a bug that the `Swarm` constructor had hanged in certain runtimes\n    like Unity engine.\n -  Removed `AddressTransactionSet` which handles handle `Address` to\n    `IEnumerable<TxId>` indices, and the following methods in `IStore`:\n     -  `IStore.IterateAddresses()`\n     -  `IStore.GetAddressTransactionIds()`\n     -  `IStore.AppendAddressTransactionId()`\n     -  `IStore.CountAddresses()`\n -  Added `IStore.ListNamespaces()` method.\n -  `IStore.CountBlocks()` and `IStore.CountTransactions()` became to return\n    `long`.\n -  Block/tx-related methods in `IStore` and `BaseIndex<T>` no longer\n    accepts `@namespace` parameter.  It means that even if a forking occurs, the\n    same block/tx files are shared.\n -  Fixed a bug that made unnecessary fork when receiving blocks from other\n    peer.\n -  Action classes that implement `IAction` but lack `ActionTypeAttribute`\n    became reported by `PolymorphicAction<T>` throwing\n    `MissingActionTypeException` at runtime.  [[#28], [#144], [#169]]\n -  Turn into parameter in `BlockPolicy`'s constructor to milliseconds.\n    [[#151]]\n -  `BencodexFormatter` became able to serialize `BigInteger`.  [[#159]]\n -  Made `Swarm` possible to configure its network `appProtocolVersion` and,\n    to ignore peers if their version is different.  [[#167]], [[#170]]\n -  Added `DifferentAppProtocolVersionException` class.  [[#167], [#170]]\n -  Added `IActionContext.Miner` property.  [[#173]], [[#174]]\n -  Renamed `Block<T>.RewardBeneficiary` to `Block<T>.Miner`.  [[#174]]\n -  Added `BlockChain<T>.Blocks` property.  [[#176]]\n -  Added `BlockChain<T>.Transactions` property.  [[#176]]\n\n[#28]: https://github.com/planetarium/libplanet/issues/28\n[#98]: https://github.com/planetarium/libplanet/issues/98\n[#99]: https://github.com/planetarium/libplanet/issues/99\n[#120]: https://github.com/planetarium/libplanet/issues/120\n[#121]: https://github.com/planetarium/libplanet/pull/121\n[#123]: https://github.com/planetarium/libplanet/pull/123\n[#124]: https://github.com/planetarium/libplanet/pull/124\n[#126]: https://github.com/planetarium/libplanet/issues/126\n[#127]: https://github.com/planetarium/libplanet/pull/127\n[#128]: https://github.com/planetarium/libplanet/pull/128\n[#131]: https://github.com/planetarium/libplanet/issues/131\n[#132]: https://github.com/planetarium/libplanet/issues/132\n[#135]: https://github.com/planetarium/libplanet/pull/135\n[#136]: https://github.com/planetarium/libplanet/pull/136\n[#140]: https://github.com/planetarium/libplanet/pull/140\n[#144]: https://github.com/planetarium/libplanet/pull/144\n[#151]: https://github.com/planetarium/libplanet/pull/151\n[#159]: https://github.com/planetarium/libplanet/pull/159\n[#165]: https://github.com/planetarium/libplanet/issues/165\n[#166]: https://github.com/planetarium/libplanet/pull/166\n[#167]: https://github.com/planetarium/libplanet/issues/167\n[#169]: https://github.com/planetarium/libplanet/pull/169\n[#170]: https://github.com/planetarium/libplanet/pull/170\n[#173]: https://github.com/planetarium/libplanet/issues/173\n[#174]: https://github.com/planetarium/libplanet/pull/174\n[#176]: https://github.com/planetarium/libplanet/pull/176\n[RFC 5389]: https://tools.ietf.org/html/rfc5389\n[RFC 5766]: https://tools.ietf.org/html/rfc5766\n\n\nVersion 0.1.1\n-------------\n\nReleased on March 5, 2019.\n\n -  Improved stability of `Swarm` and `SwarmTest`.\n\n\nVersion 0.1.0\n-------------\n\nInitial release.  Released on February 26, 2019.\n"
  },
  {
    "path": "changes/v1.md",
    "content": "Libplanet changelog\n===================\n\nVersion 1.4.0\n-------------\n\nReleased on June 7, 2023.\n\n### Backward-incompatible API changes\n\n -  Removed `IBlockChainStates.GetTrie()` interface method.  [[#3168]]\n -  Removed `PolymorphicAction<T>` class.  [[#3193]]\n -  Changed `BlockChain.Create()` to accept `IActionEvaluator` interface\n    instead of `ActionEvaluator` object.  [[#3195]]\n -  Removed `blockAction` parameter from `BlockChain.EvaluateGenesis()`,\n    `BlockChain.DetermineGenesisStateRootHash()`,\n    and `BlockChain.ProposeGenesisBlock()` methods.  [[#3195]]\n\n[#3168]: https://github.com/planetarium/libplanet/pull/3168\n[#3193]: https://github.com/planetarium/libplanet/pull/3193\n[#3195]: https://github.com/planetarium/libplanet/pull/3195\n\n\nVersion 1.3.0\n-------------\n\nReleased on May 19, 2023.\n\n### Backward-incompatible API changes\n\n -  Renamed `PreloadState` as `BlockSyncState`.  [[#3154]]\n -  Replaced `Swarm<T>.PreloadAsync`'s parameter\n    `IProgress<PreloadState> progress`\n    as `IProgress<BlockSyncState> progress`.  [[#3154]]\n -  Moved `IAccountStateDelta` and relations interface to\n    `Libplanet.State` namespace (from `Libplanet.Action` namespace).\n    [[#3173]]\n -  Changed `BlockChain<T>()` constructors to explicitly require an\n    `IBlockChainStates` and an `IActionEvaluator`.  [[#3172]]\n -  Changed `BlockChain<T>.DetermineGenesisStateRootHash()`,\n    `BlockChain<T>.EvaluateGenesis()`, and `BlockChain<T>.ProposeGenesisBlock()`\n    to explicitly require `IActionEvaluator`.  [[#3172]]\n -  Removed type parameter `T` from `BlockChain<T>` class.  [[#3182]]\n -  Removed type parameter `T` from `IBlockPolicy<T>` interface.  [[#3182]]\n -  Removed type parameter `T` from `IStagePolicy<T>` interface.  [[#3182]]\n -  Removed type parameter `T` from `Context<T>` class.  [[#3183]]\n -  Removed type parameter `T` from `ConsensusContext<T>` class.  [[#3183]]\n -  Removed type parameter `T` from `ConsensusReactor<T>` class.  [[#3183]]\n -  Removed type parameter `T` from `BlockCandidateTable<T>` class.  [[#3184]]\n -  Removed type parameter `T` from `TxCompletion<T>` class.  [[#3184]]\n -  Removed type parameter `T` from `Swarm<T>` class.  [[#3184]]\n -  (Libplanet.Explorer) Removed type parameter `T` requiring `T` as\n    `IAction` from all classes.  [[#3185]]\n\n### Behavioral changes\n\n -  `Gossip` became to store the `MessageId`s received through the\n    `HaveMessage` instead of immediately replying to them, and send the\n    `WantMessage` requests all at once during each `HeartbeatTask`.\n    [#3152]\n -  `Swarm<T>.PreloadAsync()` use `PullBlocksAsync()` and\n    `ConsumeBlockCandidates()`.  [[#3154]]\n -  `Swarm<T>.PreloadAsync()` uses `BlockCandidateTable<T>` to cache\n    downloaded `Block`s, instead of storing them on forked `BlockChain<T>`.\n    [[#3154]]\n -  `Swarm<T>.PullBlocksAsync()` and `Swarm<T>.GetDemandBlockHashes()` iterates\n    using new parameter `chunkSize`.  [[#3154]]\n -  `Swarm<T>.ConsumeBlockCandidates()` repeats iff new parameter\n    `checkInterval` is not null.  [[#3154]]\n -  `Swarm<T>.ConsumeBlockCandidates()` does not renders if new parameter\n    `render` is `false`.  [[#3154]]\n -  `Swarm<T>.PullBlocksAsync()` and `Swarm<T>.GetDemandBlockHashes()`\n    receives new parameter `IProgress<BlockSyncState> progress` and will\n    report progress to it, if it's given.  [[#3154]]\n -  Moved creation of `BlockDemandTable` and `BlockCandidateTable`\n    to constructor of `Swarm<T>` from `Swarm<T>.StartAsync()`.  [[#3154]]\n\n[#3152]: https://github.com/planetarium/libplanet/pull/3152\n[#3154]: https://github.com/planetarium/libplanet/pull/3154\n[#3172]: https://github.com/planetarium/libplanet/pull/3172\n[#3173]: https://github.com/planetarium/libplanet/pull/3173\n[#3182]: https://github.com/planetarium/libplanet/pull/3182\n[#3183]: https://github.com/planetarium/libplanet/pull/3183\n[#3184]: https://github.com/planetarium/libplanet/pull/3184\n[#3185]: https://github.com/planetarium/libplanet/pull/3185\n\n\nVersion 1.2.1\n-------------\n\nReleased on May 17, 2023.\n\n -  (Libplanet.Explorer) Fixed a bug where a `TransactionQuery` could not\n    properly retrieve actions.  [[#3174]]\n\n[#3174]: https://github.com/planetarium/libplanet/pull/3174\n\n\nVersion 1.2.0\n-------------\n\nReleased on May 16, 2023.\n\n### Deprecated APIs\n\n -  Removed `StaticActionLoader` class.  Use `SingleActionLoader` instead.\n    [[#3148]]\n -  Removed `Mint` and `Transfer` class.  [[#3159]]\n\n### Backward-incompatible API changes\n\n -  Removed type parameter `T` from `Transaction.Create<T>()` and\n    `PreEvaluationBlock.Evaluate<T>()`.  [[#3122]]\n -  Signatures of `IActionRenderer<T>`'s methods was changed.  [[#3117]]\n     -  The signature of\n        `RenderAction(IAction, IActionContext, IAccountStateDelta)`\n        method was changed to\n        `RenderAction(IValue, IActionContext, IAccountStateDelta)`.\n     -  The signature of\n       `RenderActionError(IAction, IActionContext, Exception)`\n        method was changed to\n        `RenderActionError(IValue, IActionContext, Exception)`.\n -  Added `SingleActionLoader`, `TypedActionLoader`, and `IndexedActionLoader`\n    classes.  [[#3148]]\n -  Removed `trieGetter` parameter from `ActionEvaluator` constructor.\n    [[#3149]]\n -  Added `IBlockChainStates.GetTrie()` interface method.  [[#3149]]\n -  `BlockChain<T>.Create()` static method now requires `actionEvaluator`\n    parameter explicitly.  [[#3149]]\n -  Removed `IBlockPolicy.NativeTokens` property.  [[#3153]]\n     - Removed `NonNativeTokenException` class.\n     - Removed `IActionContext.IsNativeToken()` method.\n     - Removed `nativeTokenPredicate` parameter from `ActionEvaluator()`\n     - Removed `nativeTokenPredicate` parameter from all `BlockChain<T>`'s\n       methods.\n     - (Libplanet.Explorer) Removed `BlockPolicyType<T>` class.\n -  Removed generic type parameter `T` from `IRenderer<T>` and all its\n    implementations.  [[#3163]]\n -  Removed `IActionContext.GenesisHash` property.  [[#3164]]\n -  Removed `genesisHash` parameter from `ActionEvaluator()`.  [[#3164]]\n\n### Added APIs\n\n -  Added `IActionContext.GasUsed()` method.\n    [[#3144]]\n -  Added `IActionContext.GasLimit()` method.\n    [[#3144]]\n -  Added `PolymorphicAction<T>.ReloadLoader()` static method.  [[#3158]]\n\n### Behavioral changes\n\n -  `Transaction.Create()` method no more fills `Transaction.UpdatedAddresses`\n    automatically.  [[#368], [#3122]]\n -  `Mint` and `Transfer` `IAction`s no longer check for native tokens.\n    [[#3153]]\n\n[#3117]: https://github.com/planetarium/libplanet/pull/3117\n[#3122]: https://github.com/planetarium/libplanet/pull/3122\n[#3144]: https://github.com/planetarium/libplanet/pull/3144\n[#3148]: https://github.com/planetarium/libplanet/pull/3148\n[#3149]: https://github.com/planetarium/libplanet/pull/3149\n[#3153]: https://github.com/planetarium/libplanet/pull/3153\n[#3158]: https://github.com/planetarium/libplanet/pull/3158\n[#3159]: https://github.com/planetarium/libplanet/pull/3159\n[#3163]: https://github.com/planetarium/libplanet/pull/3163\n[#3164]: https://github.com/planetarium/libplanet/pull/3164\n\n\nVersion 1.1.1\n-------------\n\nReleased on May 15, 2023.\n\n -  (@planetarium/cli) Fixed the installer bug that it had failed on Linux and\n    macOS since version 1.0.2.  [[#3107], [#3160], [#3161]]\n\n[#3161]: https://github.com/planetarium/libplanet/pull/3161\n\n\nVersion 1.1.0\n-------------\n\nReleased on May 9, 2023.\n\n### Backward-incompatible API changes\n\n -  Changed the encoding scheme and related methods for `TxActionList`.\n    [[#3083]]\n     -  Removed `TxActionList.FromBencodex<T>()` method.\n     -  Changed the return type for `TxActionList.ToBencodex()` from\n        `Dictionary` to `IValue`.\n -  Removed `IRenderer<T>.RenderReorg()`, `IRenderer<T>.RenderReorgEnd()`,\n    `IActionRenderer<T>.UnrenderAction()`, and\n    `IActionRenderer<T>.UnrenderActionError()`.  [[#3092]]\n -  Removed `NonblockRenderer`, `NonblockActionRenderer`, `DelayedRenderer`,\n    and `DelayedActionRenderer` classes.  [[#3098]]\n -  (Libplanet.Net) Removed optional `render` parameter from\n    all `Swarm<T>.PreloadAsync()` overload methods.  No rendering is done\n    during the preloading phase.  [[#3108]]\n -  `TxActionList` now implements `IBencodable` interface.  [[#3110]]\n     -  Removed `FromBencodex()` static method; use `TxActionList(IValue)`\n        constructor instead.\n     -  Removed `ToBencodex()` method; use `TxActionList.Bencoded` instead.\n -  `TxActionList` now implements `IEnumerable<IValue>` instead of\n    `IEnumerable<IAction>`.  [[#3110]]\n     -  Changed `TxSystemAction.SystemAction` to return an `IValue`.\n     -  Changed `TxCustomActions.CustomActions` to return an\n        `IImmutableList<IValue>`.\n -  `TxActionList`'s JSON representation has changed.  It no longer has\n    `\"type\"` field.  [[#3110]]\n -  Changed the type for `ActionTypeAttribute.TypeIdentifier`\n    from `string` to `IValue`.  [[#3111]]\n -  Changed the return type for `ActionTypeAttribute.ValueOf()` from\n    `string?` to `IValue?`.  [[#3111]]\n -  Changed the return type for `IActionTypeLoader.Load()` from\n    `IDictionary<string, Type>` to `IDictionary<IValue, Type>`.  [[#3111]]\n -  Changed return types and parameter types of several methods from\n    `IReadOnlyList<ActionEvaluation>` to `IReadOnlyList<IActionEvaluation>`.\n    [[#3089]]\n     -  `BlockChain<T>.DetermineGenesisStateRootHash()`\n        method's `evaluations` parameter type.\n     -  `BlockChain<T>.DetermineBlockStateRootHash()`\n        method's `evaluations` parameter type.\n     -  `BlockChain<T>.EvaluateBlock()` method's return type.\n     -  `BlockChain<T>.EvaluateGenesis()` method's return type.\n -  Removed `BlockChain<T>.MakeTransaction(PrivateKey, IAction,\n    IImmutableSet<Address>, DateTimeOffset?)`.  [[#3116]]\n -  Removed `Transaction<T>.Create(long, PrivateKey, BlockHash?, IAction,\n    IImmutableSet<Address>?, DateTimeOffset?)`.  [[#3116]]\n -  Added `Transaction<T>.Create(long, PrivateKey, BlockHash?,\n    IEnumerable<IValue>, IImmutableSet<Address>?, DateTimeOffset?)`.  [[#3116]]\n -  Removed `ITransaction.SystemAction` and `ITransaction.CustomActions`.\n    Use `ITxInvoice.Actions` instead.  [[#3116]]\n -  Overhauled `TxActionList` class.  [[#3116]]\n     -  Changed `TxActionList` class to be `sealed` from `abstract`.\n        `TxActionList` is pretty much the old `TxCustomActionsList`.\n     -  Changed the JSON representation of `TxActionList` to be more simple.\n     -  Removed `TxSystemActionList` and `TxCustomActionsList`\n -  Changed `Transaction<T>` to `Transaction` to be non-generic.  [[#3121]]\n -  Changed `Block<T>` to `Block` to be non-generic.  [[#3123]]\n     -  Removed `IBlockContent<T>` interface.  Use `IBlockContent` instead.\n        Also changed `IBlockContent.IImmutableSet<ITransaction>` to\n        `IBlockContent.ReadOnlyList<ITransaction>`.\n     -  Changed `BlockContent<T>` to `BlockContent`.\n     -  Removed `IPreEvaluationBlock<T>` interface.  Use `IPreEvaluationBlock`\n        instead.\n     -  Changed `PreEvaluationBlock<T>` to `PreEvaluationBlock`.\n         -  `PreEvaluationBlock.Evaluate<T>()` now requires type parameter `T`.\n -  Removed `PreEvaluationBlock.Evaluate<T>()` method.  [[#3127]]\n -  Renamed `IActionTypeLoader` to `IActionLoader`.  [[#3135]]\n     -  Added `IActionLoader.Load(long, IValue)` interface method.\n     -  Removed `ActionTypeLoaderContext` class.  Use `long` instead.\n     -  Renamed `StaticActionTypeLoader` to `StaticActionLoader`.\n -  Added `IActionEvaluator.IActionLoader` property.  [[#3136]]\n -  Changed `IActionLoader.LoadAction()` to throw `InvalidActionException`\n    instead of `ArgumentException` when an action cannot be instantiated.\n    [[#3140]]\n\n### Added APIs\n\n -  Added `IActionEvaluator` interface.  [[#3082]]\n -  Added `SwarmOptions.TaskRegulationOptions` property.  [[#3109]]\n -  Added `TaskRegulationOptions` class.  [[#3109]]\n -  Added `ActionTypeAttribute(int)` constructor.  [[#3111]]\n -  Added `IActionEvaluation` interface.  [[#3089]]\n -  Added parameterless constructor to `Mint`, `Transfer`, and `Initialize`.\n    [[#3112]]\n -  Added `InvalidActionException` class.  [[#3140]]\n\n### Behavioral changes\n\n -  Changed `BlockChain<T>` to ignore `IRenderer<T>.RenderReorg()`,\n    `IRenderer<T>.RenderReorgEnd()`, `IActionRenderer<T>.UnrenderAction()`,\n    and `IActionRenderer<T>.UnrenderActionError()`, i.e., these interface\n    methods are no longer invoked by a `BlockChain<T>`.  [[#3087]]\n -  Changed `Context<T>.ConsumeMutation()` to iteratively call\n    `Context<T>.ProcessGenericUponRules()` itself, instead of producing\n    submutations of it.  [[#3137]]\n -  (Libplanet.Explorer) The `CurrencyInputType`'s `totalSupplyTrackable` field\n    became nullable with `false` as its default value.  [[#3151]]\n\n### Bug fixes\n\n -  Fixes a bug where `BlockChain<T>` could not propose if a certain type of\n    invalid `Transaction` was staged.  [[#3136]]\n -  Fixes a bug where `Context<T>` would completely halt if a `Block`\n    with an `IValue` as one of its action that cannot be instantiated via\n    its `IActionLoader`.  [[#3140]]\n\n### Dependencies\n\n -  Upgrade *Bencodex* from [0.8.0][Bencodex 0.8.0] to\n    [0.10.0][Bencodex 0.10.0].  [[#3106]]\n -  Upgrade *Bencodex.Json* from [0.8.0][Bencodex.Json 0.8.0] to\n    [0.10.0][Bencodex.Json 0.10.0].  [[#3106]]\n\n[#3082]: https://github.com/planetarium/libplanet/pull/3082\n[#3083]: https://github.com/planetarium/libplanet/pull/3083\n[#3087]: https://github.com/planetarium/libplanet/pull/3087\n[#3089]: https://github.com/planetarium/libplanet/pull/3089\n[#3092]: https://github.com/planetarium/libplanet/pull/3092\n[#3098]: https://github.com/planetarium/libplanet/pull/3098\n[#3106]: https://github.com/planetarium/libplanet/pull/3106\n[#3108]: https://github.com/planetarium/libplanet/pull/3108\n[#3110]: https://github.com/planetarium/libplanet/pull/3110\n[#3111]: https://github.com/planetarium/libplanet/pull/3111\n[#3112]: https://github.com/planetarium/libplanet/pull/3112\n[#3116]: https://github.com/planetarium/libplanet/pull/3116\n[#3121]: https://github.com/planetarium/libplanet/pull/3121\n[#3123]: https://github.com/planetarium/libplanet/pull/3123\n[#3127]: https://github.com/planetarium/libplanet/pull/3127\n[#3135]: https://github.com/planetarium/libplanet/pull/3135\n[#3136]: https://github.com/planetarium/libplanet/pull/3136\n[#3137]: https://github.com/planetarium/libplanet/pull/3137\n[#3140]: https://github.com/planetarium/libplanet/pull/3140\n[#3151]: https://github.com/planetarium/libplanet/pull/3151\n[Bencodex 0.10.0]: https://www.nuget.org/packages/Bencodex/0.10.0\n[Bencodex.Json 0.10.0]: https://www.nuget.org/packages/Bencodex.Json/0.10.0\n\n\nVersion 1.0.3\n-------------\n\nReleased on May 15, 2023.\n\n -  (@planetarium/cli) Fixed the installer bug that it had failed on Linux and\n    macOS since version 1.0.2.  [[#3107], [#3160]]\n\n[#3160]: https://github.com/planetarium/libplanet/pull/3160\n\n\nVersion 1.0.2\n-------------\n\nReleased on May 4, 2023.\n\n -  (Libplanet.Tools) The `planet` command now falls back to the default\n    cryptography backend instead of crash when it fails to load *libsecp256k1*\n    at runtime.  [[#3138]]\n -  (@planetarium/cli) Fixed the installer bug that it had failed with some\n    recent Node.js versions on Windows.   [[#3107], [#3138]]\n\n[#3107]: https://github.com/planetarium/libplanet/issues/3107\n[#3138]: https://github.com/planetarium/libplanet/pull/3138\n\n\nVersion 1.0.1\n-------------\n\nReleased on May 3, 2023.\n\n -  Fixed a bug where `BlockChain<T>.Append()` hadn't update tx executions\n    even `evaluateActions` set to `true` when `actionEvaluations` are given.\n    [[#3125]]\n -  (Libplanet.Explorer) Fixed a bug where `BlockQuery.blocks` field had thrown\n    `KeyNotFoundException` when appending block simultaneously.\n    [[#3126], [#3130]]\n\n[#3125]: https://github.com/planetarium/libplanet/pull/3125\n[#3126]: https://github.com/planetarium/libplanet/issues/3126\n[#3130]: https://github.com/planetarium/libplanet/pull/3130\n\n\nVersion 1.0.0\n-------------\n\nReleased on April 18, 2023.\n\n### Deprecated APIs\n\n -  (@planerarium/account)  Deprecated `RawPrivateKey.publicKey` property in\n    favour of `RawPrivateKey.getPublicKey()` async method.  [[#3061]]\n -  (@planetarium/account-aws-kms)  Deprecated `AwsKmsAccount.publicKey` in\n    favour of `AwsKmsAccount.getPublicKey()` async method.  [[#3061]]\n\n### Backward-incompatible API changes\n\n -  Removed `TxMetadata` class.  [[#1164], [#2986]]\n     -  Removed `Transaction<T>(TxMetadata, IAction, byte[])` constructor.\n     -  Removed `Transaction<T>(TxMetadata, IEnumerable<T>, byte[])`\n        constructor.\n -  Reorganized `ITransaction` interface in general.  [[#1164], [#2986]]\n     -  `ITransaction` now inherits `IUnsignedTx` interface instead of having\n        properties such as `GenesisHash`, `UpdatedAddresses`, `Timestamp`,\n        `Nonce`, `Signer`, and `PublicKey`.\n     -  `SystemAction` property is replaced by `Actions` property which is\n        inherited from `IUnsignedTx` interface.\n     -  `CustomActions` property is replaced by `Actions` property which is\n        inherited from `IUnsignedTx` interface.\n -  `Transaction<T>` no more accept empty `Signature` as a valid state.\n    Instead, you should use `UnsignedTx` class to represent an unsigned\n    transaction.  [[#1164], [#2986]]\n     -  Removed `Transaction<T>(long, Address, PublicKey, BlockHash?,\n        IImmutableSet<Address>, DateTimeOffset, IEnumerable<T>, byte[])`\n        constructor.\n     -  Removed `Transaction<T>.CreateUnsigned()` static method.\n     -  Removed `Transaction<T>.Validate()` method.\n     -  Removed `sign` parameter from `Transaction<T>.Serialize()` method.\n     -  Removed `validate` parameter from `Transaction<T>.Deserialize()`\n        method.\n -  `Transaction<T>` now has `Actions` in a uniform way regardless they\n    are custom actions or system actions, through `TxActionList` abstract\n    class.  [[#1164], [#2986]]\n     -  Changed the type of `Transaction<T>.Actions` property from\n        `IImmutableList<IAction>` to `TxActionList`, which is also an\n        `IReadOnlyList<IAction>`.  The property once was deprecated\n        in favour of `Transaction<T>.CustomActions` and\n        `Transaction<T>.SystemAction`, but now it replaces them both.\n     -  Removed `Transaction<T>.CustomActions` property.\n     -  Removed `Transaction<T>.SystemAction` property.\n -  `Transaction<T>(Bencodex.Types.Dictionary)` constructor is removed.\n    Use `TxMarshaler.UnmarshalTransaction<T>()` method instead.  [[#2986]]\n -  Removed `PreEvaluationBlock<T>.Evaluate(PrivateKey, IAction?,\n    Predicate<Currency>, IStateStore)`,\n    `PreEvaluationBlock<T>.DetermineStateRootHash(IAction?, Predicate<Currency>,\n    IStateStore)`, `PreEvaluationBlock<T>.DetermineStateRootHash(IAction?,\n    Predicate<Currency>, IStateStore,\n    out IImmutableDictionary<string, IValue>)`,\n    `PreEvaluationBlock<T>.DetermineStateRootHash(BlockChain<T>)`,\n    and `PreEvaluationBlock<T>.DetermineStateRootHash(BlockChain<T>,\n    out IImmutableDictionary<string, IValue>)`,\n    `BlockChain<T>.ExecuteActions(Block<T>)`.  [[#3037]]\n -  (Libplanet.Extensions.Cocona) Changed signature of\n    `ApvCommand.Verify(string?, string[]?, bool)` method to\n    `ApvCommand.Verify(string?, PublicKey[]?, bool)`.  [[#3044]]\n -  Removed `PreEvaluationBlock<T>.Mine()` and `BlockMetadata.MineNonce()`\n    methods.  [[#3067]]\n -  Removed `HashCash` class.  [[#3067]]\n -  (@planetarium/account) Replaced `Account.publicKey` property with\n    `Account.getPublicKey()` async method.  [[#3061]]\n -  (@planetarium/account) Added `Account.getAddress()` async method.  [[#3084]]\n -  (@planetarium/account) `Address.deriveFrom()` method now returns\n    `Promise<Address>` when an `Account` is given.  However, it still returns\n    `Address` when a `PublicKey` is given.  [[#3061]]\n -  (@planetarium/account-web3-secret-storage) `Web3KeyStore` no more implements\n    `ImportableKeyStore<KeyId, RawPrivateKey>`.  Instead, it now implements\n    `ImportableKeyStore<KeyId, Web3Account, Web3KeyMetadata>`.\n    [[#3061], [#3084]]\n -  (Libplanet.Explorer) Added `Index` field to `IBlockChainContext` interface.\n    [[#2613]]\n -  Removed `BlockChain<T>.ProposeBlock(PrivateKey, DateTimeOffset, long, int,\n    int, IComparer<Transaction<T>>, BlockCommit)` method.  [[#3072]]\n -  Changed `BlockChain<T>.ProposeBlock(PrivateKey, DateTimeOffset,\n    BlockCommit, IComparer<Transaction<T>>)` method to\n    `BlockChain<T>.ProposeBlock(PrivateKey, BlockCommit,\n    IComparer<Transaction<T>>)`.  [[#3077]]\n -  Changed `BlockChain<T>.ProposeGenesisBlock(IEnumerable<T>,\n    IEnumerable<IAction>, PrivateKey, DateTimeOffset?, IAction,\n    Predicate<Currency>)` to `BlockChain<T>.ProposeGenesisBlock(\n    PrivateKey, ImmutableList<Transaction<T>>, DateTimeOffset?, IAction,\n    Predicate<Currency>)`.  [[#3079]]\n -  (Libplanet.Explorer) `Currency.decimalPlaces`' type became `Byte`\n    from `UInt`.  [[#3085]]\n -  (Libplanet.Explorer) `currencyHash` parameter was removed from\n    `balance` and `totalSupply` in `StateQuery` type.  [[#3085]]\n\n### Added APIs\n\n -  Added `ITxInvoice` interface.  [[#1164], [#2986]]\n -  Added `ITxSigningMetadata` interface.  [[#1164], [#2986]]\n -  Added `IUnsignedTx` interface.  [[#1164], [#2986]]\n -  Added `TxInvoice` class.  [[#1164], [#2986]]\n -  Added `TxSigningMetadata` class.  [[#1164], [#2986]]\n -  Added `UnsignedTx` class.  [[#1164], [#2986]]\n -  Added `Transaction<T>(IUnsignedTx, ImmutableArray<byte>)`.\n    [[#1164], [#2986]]\n -  Added `BlockChain<T>.DetermineGenesisStateRootHash()`,\n    `BlockChain<T>.EvaluateGenesis()`,\n    `BlockChain<T>.DetermineBlockStateRootHash()`,\n    and `BlockChain<T>.EvaluateBlock()`.  [[#3037]]\n -  Added `PublicKey.FromHex()` static method.  [[#2709], [#3044]]\n -  Added `PublicKey.ToHex()` method.  [[#2709], [#3044]]\n -  (Libplanet.Net) Added `Gossip.PublishMessage()` method.  [[#3054], [#3060]]\n -  (@planetarium/account) Added `Account.getPublicKey()` async method.\n    [[#3061]]\n -  (@planetarium/account) Added `Account.getAddress()` async method.  [[#3084]]\n -  (@planetarium/account) Added `RawPrivateKey.getPublicKey()` async method.\n    [[#3061]]\n -  (@planetarium/account) Added `RawPrivateKey.getAddress()` async method.\n    [[#3084]]\n -  (@planetarium/account-aws-kms) Added `AwsKmsAccount.getPublicKey()` async\n    method.  [[#3061]]\n -  (@planetarium/account-aws-kms) Added `AwsKmsAccount.getAddress()` async\n    method.  [[#3084]]\n -  (@planetarium/account-web3-secret-storage) Added `Web3Account` class.\n    [[#3061], [#3084]]\n -  (@planetarium/account-web3-secret-storage) Added `Web3KeyObject` interface.\n    [[#3061]]\n -  (Libplanet.Explorer) Added several interfaces and classes that pertain to\n    blockchain indexing.  [[#2613]]\n     -  Added `IBlockChainIndex` interface.\n     -  Added `IIndexingContext` interface.\n     -  Added `BlockChainIndexBase` abstract class.\n     -  Added `RocksDbBlockChainIndex` class.\n     -  Added `RocksDbIndexingContext` class.\n     -  Added `IndexingService` class.\n     -  Added `IndexMismatchException` class.\n -  (Libplanet.Explorer.Cocona) New project was added to provide Cocona\n    commands related to *Libplanet.Explorer* project.  [[#2613]]\n     -  Added `IndexCommand` Cocona command class.\n -  (Libplanet.Explorer) Added `states` query in `StateQuery`.  [[#3080]]\n -  (@planetarium/account) Added `Address.equals()` method.  [[#3071]]\n -  (@planetarium/account) Added `Address.isAddressOf()` method.  [[#3071]]\n -  (@planetarium/account) Added `PublicKey.equals()` method.  [[#3071]]\n -  (@planetarium/account-web3-secret-storage) Added `DecryptionOptions`\n    interface.  [[#3071]]\n     -  Added `Web3KeyStoreOptions.decryptionOptions` attribute.\n -  (@planetarium/account-web3-secret-storage) Added `WeakPrivateKeyError`\n    class.  [[#3071]]\n -  (@planetarium/account-web3-secret-storage) Added `Web3KeyMetadata`\n    interface.  [[#3084]]\n -  (Libplanet.Tools) Added `-v`/`--validator-key` option to\n    `planet block generate-genesis` command.  [[#3088]]\n -  (Libplanet.Explorer) Added `CurrencyInput` type.  [[#3085]]\n -  (Libplanet.Explorer) Added `CurrencyInput`-typed `currency` parameter to\n    `balance` and `totalSupply` in `StateQuery` type.  [[#3085]]\n\n### Behavioral changes\n\n -  Added `TypeConverter` to commonly-used types.  [[#2711], [#3044]]\n\n     -  `Address` now can be converted from and to `string` through\n        `TypeConverter`.\n     -  `HashDigest<T>` now can be converted from and to `string` through\n        `TypeConverter`.\n     -  `PublicKey` now can be converted from and to `string` through\n        `TypeConverter`.\n\n -  `Transaction<T>` no more supports deserialization from JSON when it contains\n    custom actions.  However, it still can be deserialized from JSON when it\n    contains a system action.  [[#2986]]\n\n -  `Transaction<T>.UpdatedAddresses` now preserves the order of `Address`es\n    so that it is no more reordered during deserialization.  [[#3074]]\n\n -  The JSON representation of `Transaction<T>` now includes the `\"actions\"`\n    field, which includes a system action or a list of custom actions and\n    a `\"type\"` field denoting one of `\"system\"` or `\"custom\"`.\n\n    For example:\n\n    ~~~~\n    {\n       // ... other fields\n       \"actions\": {\n         \"type\": \"system\",\n         \"systemAction\": {\n           // system action details\n         }\n       }\n    }\n    ~~~~\n\n    Instead of:\n\n    ~~~~\n    {\n       // ... other fields\n      \"systemAction\": {\n         // system action details\n      }\n    }\n    ~~~~\n\n -  (@planetarium/account-web3-secret-storage) `Web3KeyStore.get()` method now\n    defers `PassphraseEntry.authenticate()` call and account unlocking so that\n    `AccountRetrieval` instance can be gathered without unlocking the account.\n    Instead, `PassphraseEntry.authenticate()` is called when operations that\n    require unlocking `Web3Account` are called, such as `sign()` or\n    `getPublicKey()`.  [[#3061]]\n -  (Libplanet.Explorer) Now, when an `IBlockChainIndex` instance is available\n    in the optional `Index` property of the injected `IBlockChainContext`\n    instance, GraphQL queries can benefit from the improved lookup performance\n    of the index.  Applications willing to take advantage of the index should\n    provide an instance of `IBlockChainIndex` to the `IBlockChainContext`\n    implementation and add the `IndexingService` hosted service to sync the\n    index in the background.  Note that the synchronization may take a long\n    time if you have a lot of blocks (over 24 hours for ~5M blocks).  [[#2613]]\n     -  `BlockRef` property of `TransactionType` now uses `IBlockChainIndex`\n        if available.\n     -  `transactionResult` query in `TransactionQuery` now uses\n        `IBlockChainIndex` if available.\n\n -  (@planetarium/account-web3-secret-storage) `Web3KeyStore` now supports\n    Scrypt as one of KDF functions besides PBKDF2.  [[#3071]]\n\n### Bug fixes\n\n -  In `PreVote` block validation, `Context<T>.IsValid()`, validate the block\n    header and also the block content (e.g., Tx nonces, Policy defined\n    validation rules, or state root hash.)  [[#2973], [#2996]]\n -  (@planetarium/account-web3-secret-storage) Fixed a bug where\n    `Web3KeyStore.import()` and `Web3KeyStore.generate()` methods had written\n    JSON field `\"Crypto\"` instead of `\"crypto\"` in the key file.  [[#3071]]\n\n### Dependencies\n\n -  *@planetarium/account-aws-kms* now has *@planetarium/account* as a peer\n    dependency instead of a normal dependency.  [[#3069]]\n -  *@planetarium/account-web3-secret-storage* now has *@planetarium/account*\n    as a peer dependency instead of a normal dependency.  [[#3069]]\n -  *@planetarium/tx* now has *@planetarium/account* as a peer dependency\n    instead of a normal dependency.  [[#3069]]\n\n### CLI tools\n\n -  (Libplanet.Explorer.Executable) Project is now deprecated. It is currently\n    nonfunctional.  [[#2243], [#2588]]\n -  (Libplanet.Tools) Now `planet` uses *libsecp256k1* (which is the same\n    library used in Bitcoin and written in C) instead of\n    *BouncyCastle.Cryptography* (which is written in C#).  [[#3074]]\n\n[#2243]: https://github.com/planetarium/libplanet/discussions/2243\n[#2588]: https://github.com/planetarium/libplanet/discussions/2588\n[#2613]: https://github.com/planetarium/libplanet/pull/2613\n[#2709]: https://github.com/planetarium/libplanet/issues/2709\n[#2711]: https://github.com/planetarium/libplanet/issues/2711\n[#2986]: https://github.com/planetarium/libplanet/pull/2986\n[#2973]: https://github.com/planetarium/libplanet/issues/2973\n[#2996]: https://github.com/planetarium/libplanet/pull/2995\n[#3037]: https://github.com/planetarium/libplanet/pull/3037\n[#3044]: https://github.com/planetarium/libplanet/pull/3044\n[#3054]: https://github.com/planetarium/libplanet/issues/3054\n[#3060]: https://github.com/planetarium/libplanet/pull/3060\n[#3061]: https://github.com/planetarium/libplanet/pull/3061\n[#3067]: https://github.com/planetarium/libplanet/pull/3067\n[#3069]: https://github.com/planetarium/libplanet/pull/3069\n[#3071]: https://github.com/planetarium/libplanet/pull/3071\n[#3072]: https://github.com/planetarium/libplanet/pull/3072\n[#3074]: https://github.com/planetarium/libplanet/pull/3074\n[#3077]: https://github.com/planetarium/libplanet/pull/3077\n[#3079]: https://github.com/planetarium/libplanet/pull/3079\n[#3080]: https://github.com/planetarium/libplanet/pull/3080\n[#3084]: https://github.com/planetarium/libplanet/pull/3084\n[#3085]: https://github.com/planetarium/libplanet/pull/3085\n[#3088]: https://github.com/planetarium/libplanet/pull/3088\n"
  },
  {
    "path": "changes/v2.md",
    "content": "Libplanet changelog\n===================\n\nVersion 2.5.0\n-------------\n\nReleased on July 12, 2023.\n\nDue to changes in [[#3272]], a network ran with a prior version may not\nbe compatible with this version.\n\n### Backward-incompatible API changes\n\n -  (Libplanet.Net) Added\n    `Gossip.PublishMessage(MessageContent, IEnumerable<BoundPeer>)` method.\n    [[#3206]]\n -  (Libplanet.Net) Added `Context.AddMaj23()` method.  [[#3206]]\n -  (Libplanet.Net) Added `Context.GetVoteSetBits()` method.  [[#3206]]\n -  (Libplanet.Net) Added `Context.GetVoteSetBitsResponse()` method.  [[#3206]]\n -  (Libplanet.Net) Added `ConsensusContext.HandleMaj23()` method.\n    [[#3206]]\n -  (Libplanet.Net) Added `ConsensusContext.HandleVoteSetBits()` method.\n    [[#3206]]\n -  (Libplanet.Net) Added `ConsensusContext.HandleProposalClaim()` method.\n    [[#3206]]\n -  Removed `ActionTypeAttribute.ValueOf()` method.  [[#3267]]\n -  Added `Action<Message> validateMessageToReceive` parameter\n    to `Gossip`'s constructor.  [[#3273]]\n -  Added `Action<MessageContent> validateMessageToSend` parameter\n    to `Gossip`'s constructor.  [[#3273]]\n -  Removed `Action<Message> validateMessage` parameter\n    from `Gossip`'s constructor.  [[#3273]]\n -  Removed `AccountStateGetter`, `AccountBalanceGetter`, `TotalSupplyGetter`,\n    and `ValidatorSetGetter` delegates.  [[#3282]]\n -  Removed `IFeeCalculator` interface.  [[#3283]]\n -  Removed `IBlockPolicy.FeeCalculator` interface property.  [[#3283]]\n -  Removed `TxExecution.ActionsLogsList`, `TxFailure.ActionsLogsList`,\n    and `TxSuccess.ActionsLogsList` properties.  [[#3291]]\n -  (Libplanet.Explorer) Removed `TxResult.ActionsLogsList` property.  [[#3291]]\n -  Removed `IActionContext.Logs` property and `IActionContext.PutLog()` method.\n    [[#3292]]\n -  Removed `IActionEvaluation.Logs` property. [[#3292]]\n\n### Added APIs\n\n -  Added `VoteSetBits` and its related classes.  [[#3206]]\n     -  Added `VoteSetBits` class.\n     -  Added `VoteSetBitsMetadata` class.\n     -  (Libplanet.Net) Added `ConsensusVoteSetBitsMsg` class.\n -  Added `ProposalClaim` and its related class.  [[#3206]]\n     -  Added `ProposalClaim` class.\n     -  Added `ProposalClaimMetadata` class.\n     -  (Libplanet.Net) Added `ConsensusProposalClaimMsg` class.\n -  (Libplanet.Net) Added `ConsensusMaj23Msg` class.  [[#3206]]\n -  (Libplanet.Net) Added enumeration items to `MessageType` enum.  [[#3206]]\n     -  Added `ConsensusMaj23Msg` of value `0x53`.\n     -  Added `ConsensusVoteSetBitsMsg` of value `0x54`.\n     -  Added `ConsensusProposalClaimMsg` of value `0x55`.\n -  Added `IActionContext.Logs` interface property.  [[#3274]]\n -  Changed the type for `IActionEvaluation.Logs` to\n    `IReadOnlyList<string>` from `List<string>`.  [[#3274]]\n -  Changed the type for `TxExecution.ActionsLogList` to\n    `List<IReadOnlyList<string>>?` from `List<List<string>>?`.  [[#3274]]\n -  (Libplanet.Explorer) Changed the type for `TxResult.ActionsLogList` to\n    `List<IReadOnlyList<string>>?` from `List<List<string>>?`.  [[#3274]]\n -  (Libplanet.Explorer) Added `BlockType.PreEvaluationHash` field.\n    [[#3280], [#3281]]\n -  (Libplanet.Net) Added `VoteSet.GetAllVotes()` method.  [[#3288]]\n\n### Behavioral changes\n\n -  (Libplanet.Net) `Context` became to remove its proposal\n    when +2/3 valid votes were collected.  [[#3206]]\n -  Changed `ActionEvaluator` to evaluate all `IAction`s in a `Transaction`\n    without early termination even if an `IAction` throws an `Exception`.\n    [[#3272]]\n -  `Gossip.HandleMessageAsync()` now executes `_validateMessageToReceive`\n    on given message received.  [[#3273]]\n -  `Gossip.SendWantAsync()` now executes `_validateMessageToReceive`\n    on replies of `WantMessage`.  [[#3273]]\n -  `Gossip.HandleWantAsync()` now executes `_validateMessageToSend`\n    on given message to send as a reply of `WantMessage`.  [[#3273]]\n -  `GossipConsensusMessageCommunicator` now prevents sending a message\n    with a round other than its own as a reply to a `WantMessage`.  [[#3273]]\n -  `GossipConsensusMessageCommunicator` now executes anti-spam logic\n    when messages are received.  [[#3273]]\n\n### Bug fixes\n\n -  Fixed a broken backwards compatibility of Currency  [[#3268], [#3284]]\n\n[#3206]: https://github.com/planetarium/libplanet/pull/3206\n[#3267]: https://github.com/planetarium/libplanet/pull/3267\n[#3268]: https://github.com/planetarium/libplanet/issues/3268\n[#3272]: https://github.com/planetarium/libplanet/pull/3272\n[#3273]: https://github.com/planetarium/libplanet/pull/3273\n[#3274]: https://github.com/planetarium/libplanet/pull/3274\n[#3280]: https://github.com/planetarium/libplanet/issues/3280\n[#3281]: https://github.com/planetarium/libplanet/pull/3281\n[#3282]: https://github.com/planetarium/libplanet/pull/3282\n[#3283]: https://github.com/planetarium/libplanet/pull/3283\n[#3284]: https://github.com/planetarium/libplanet/pull/3284\n[#3288]: https://github.com/planetarium/libplanet/pull/3288\n[#3291]: https://github.com/planetarium/libplanet/pull/3291\n[#3292]: https://github.com/planetarium/libplanet/pull/3292\n\n\nVersion 2.4.1\n-------------\n\nReleased on July 14, 2023.\n\n -  Slight speed and memory optimization for `ByteUtil.Hex()`.  [[#3297]]\n -  (Libplanet.RocksDBStore) Slight improvement for speed and memory usage.\n    [[#3298]]\n -  Upgrade *Bencodex* from [0.10.0][Bencodex 0.10.0] to\n    [0.11.0][Bencodex 0.11.0].  [[#3302]]\n\n[#3297]: https://github.com/planetarium/libplanet/pull/3297\n[#3298]: https://github.com/planetarium/libplanet/pull/3298\n[#3302]: https://github.com/planetarium/libplanet/pull/3302\n[Bencodex 0.11.0]: https://www.nuget.org/packages/Bencodex/0.11.0\n\n\nVersion 2.4.0\n-------------\n\nReleased on July 3, 2023.\n\n### Deprecated APIs\n\n -  (Libplanet.Net) Removed `ConsensusContext.BroadcastMessage` property.\n    [[#3260]]\n\n### Backward-incompatible API changes\n\n -  `Vote.BlockHash` property became `BlockHash` type. (was `BlockHash?`)\n    [[#3249]]\n -  `VoteMetadata(long, int, BlockHash?, DateTimeOffset, PublicKey, VoteFlag)`\n    constructor became\n    `VoteMetadata(long, int, BlockHash, DateTimeOffset, PublicKey, VoteFlag)`\n    [[#3249]]\n -  (Libplanet.Net) Renamed `Step` enum to `ConsensusStep`\n    to remove ambiguity.  [[#3249]]\n -  (Libplanet.Net) `ConsensusProposalMsg`, `ConsensusPreVoteMsg` and\n    `ConsensusPreCommitMsg` became to inherit `ConsensusVoteMsg`.  [[#3249]]\n -  (Libplanet.Net) Removed `ConsensusMsg.BlockHash` property.  [[#3249]]\n -  (Libplanet.Net) Some enumeration items to `MessageType` enum has modified.\n    [[#3249]]\n     -  `ConsensusProposal` changed to `0x50` (was `0x40`).\n     -  `ConsensusVote` changed to `0x51` (was `0x41`).\n     -  `ConsensusCommit` changed to `0x52` (was `0x42`).\n -  (Libplanet.Net) Added `Flag` property to `ConsensusVoteMsg` abstract class.\n    [[#3260]]\n -  (Libplanet.Net) `ConsensusProposalMsg` no longer inherits\n    `ConsensusVoteMsg`. Instead, inherits `ConsensusMsg`.  [[#3260]]\n -  (Libplanet.Net) Added parameter\n    `IConsensusMessageCommunicator consensusMessageCommunicator` to\n    `ConsensusContext`.  [[#3260]]\n -  (Libplanet.Net) Removed parameter\n    `DelegateBroadcastMessage broadcastMessage` from `ConsensusContext`.\n    [[#3260]]\n -  (Libplanet.Net) Added parameter\n    `IConsensusMessageCommunicator consensusMessageCommunicator` to\n    `Context`.  [[#3260]]\n -  (Libplanet.Net) Renamed `Context.BroadcastMessage(ConsensusMsg)`\n    as `Context.PublishMessage(ConsensusMsg)`.  [[#3260]]\n -  (Libplanet.Net) Removed constructor of `MessageCache` class.  [[#3260]]\n -  (Libplanet.Explorer) Changed `TxResult.UpdatedStates`'s type to\n    `IImmutableDictionary<Address, IValue>` from\n    `IImmutableDictionary<Address, IValue?>`.  [[#3262]]\n\n### Added APIs\n\n -  Added `Maj23` and its related classes.  [[#3249]]\n     -  Added `Maj23` class.\n     -  Added `Maj23Metadata` class.\n -  (Libplanet.Net) Added `VoteSet` class.  [[#3249]]\n -  (Libplanet.Net) Added `HeightVoteSet` class.  [[#3249]]\n -  (Libplanet.Net) Added `ConsensusVoteMsg` abstract class.  [[#3249]]\n -  (Libplanet.Net) Added `InvalidProposalException` class.  [[#3249]]\n -  (Libplanet.Net) Added `InvalidVoteException` class.  [[#3249]]\n -  (Libplanet.Net) Added `InvalidMaj23Exception` class.  [[#3249]]\n -  Added `IAccountDelta.OrderedSum()` extension method.  [[#3256]]\n -  Added `IAccountDelta.ToRawDelta()` extension method.  [[#3256]]\n -  Removed several properties from `IAccountStateDelta` pertaining to\n    the delta part of `IAccountStateDelta`.  Access the equivalent data\n    through `IAccountStateDelta.Delta` instead.  [[#3257]]\n     -  Removed `IAccountStateDelta.UpdatedAddresses` property.\n     -  Removed `IAccountStateDelta.StateUpdatedAddresses` property.\n     -  Removed `IAccountStateDelta.UpdatedFungibleAssets` property.\n     -  Removed `IAccountStateDelta.UpdatedTotalSupplyCurrencies` property.\n -  Changed `IBlockStates` to `IBlockState`.  [[#3259]]\n -  Changed `IBlockChainStates.GetBlockStates()` to\n    `IBlockChainStates.GetBlockState()`.  [[#3259]]\n -  Changes `IActionContext.PreviousStates` to `IActionContext.PreviousState`.\n -  Changed `IActionEvaluation.OutputStates` to `IActionEvaluation.OutputState`.\n    [[#3259]]\n -  (Libplanet.Net) Added `IConsensusMessageCommunicator` interface\n    and its related classes.  [[#3260]]\n     -  (Libplanet.Net) Added `GossipConsensusMessageCommunicator` class.\n        [[#3260]]\n -  (Libplanet.Net) Added `Gossip.DenyPeer(BoundPeer)` method.  [[#3260]]\n -  (Libplanet.Net) Added `Gossip.AllowPeer(BoundPeer)` method.  [[#3260]]\n -  (Libplanet.Net) Added `Gossip.ClearCache()` method.  [[#3260]]\n -  (Libplanet.Net) Added `Gossip.ClearDenySet(BoundPeer)` method.  [[#3260]]\n\n### Behavioral changes\n\n -  (Libplanet.Net) `Gossip` now maintains single message cache,\n    and contents of this cache does not decayed by time or new messages.\n    This cache is cleared only by `Gossip.ClearCache()` method.  [[#3260]]\n -  (Libplanet.Net) There are no mechanism for bootstrapping consensus\n    any more. Instead, logic change on `Gossip` solves bootstrapping\n    problem.  [[#3260]]\n -  (Libplanet.Net) `Context.Start()` now triggers\n    `IConsensusMessageCommunicator.OnStartHeight()`.  [[#3260]]\n -  (Libplanet.Net) `Context.StartRound()` now triggers\n    `IConsensusMessageCommunicator.OnStartRound()`.  [[#3260]]\n\n[#3249]: https://github.com/planetarium/libplanet/pull/3249\n[#3256]: https://github.com/planetarium/libplanet/pull/3256\n[#3257]: https://github.com/planetarium/libplanet/pull/3257\n[#3259]: https://github.com/planetarium/libplanet/pull/3259\n[#3260]: https://github.com/planetarium/libplanet/pull/3260\n[#3262]: https://github.com/planetarium/libplanet/pull/3262\n\n\nVersion 2.3.0\n-------------\n\nReleased on June 28, 2023.\n\n### Backward-incompatible API changes\n\n -  (@planetarium/tx) Removed some types and functions related to actions\n    because the concept of `SystemAction` and `CustomAction` was removed\n    since 1.1.0 and some system actions were removed since 1.2.0.  [[#3230]]\n     -  Removed `encodeUnsignedTxWithCustomActions()` function.\n     -  Removed `encodeUnsignedTxWithSystemAction()` function.\n     -  Removed `UnsignedTxWithCustomActions` type.\n     -  Removed `UnsignedTxWithSystemAction` type.\n     -  Removed `encodeMint()` function.\n     -  Removed `encodeTransfer()` function.\n     -  Removed `encodeSystemAction()` function.\n     -  Removed `CustomAction` type.\n     -  Removed `SystemAction` type.\n     -  Removed `Mint` type.\n     -  Removed `Transfer` type.\n     -  Added `encodeUnsignedTx()` function.\n     -  Added `UnsignedTx` type.\n     -  `signTx(UnsignedTxWithCustomActions | UnsignedTxWithSystemAction)`\n        function's signature became `signTx(UnsignedTx)`.\n     -  `SignedTx<T extends UnsignedTxWithCustomActions |\n         UnsignedTxWithSystemAction>`'s signature became\n         `SignedTx<T extends UnsignedTx>`.\n -  Changed the type for `IAccountStateDelta.UpdatedFungibleAssets`\n    to `IImmutableSet<(Address, Currency)>`\n    from `IImmutableDictionary<Address, IImmutableSet<Currency>>`.  [[#3244]]\n -  Changed the type for `IAccountStateDelta.TotalUpdatedFungibleAssets`\n    to `IImmutableSet<(Address, Currency)>`\n    from `IImmutableDictionary<Address, IImmutableSet<Currency>>`.  [[#3244]]\n -  Added `IAccountStateDelta.Delta` property.  [[#3245]]\n -  Removed `IValidatorSupportStateDelta` interface.  [[#3247]]\n -  Added `IAccountStateDeltaView.GetValidatorSet()` interface method.\n    [[#3247]]\n -  Added `IAccountStateDelta.SetValidator()` interface method.  [[#3247]]\n -  Changed the name `IAccountStateDelta.TotalSupplyUpdatedCurrencies` to\n    `IAccountStateDelta.UpdatedTotalSupplyCurrencies`.  [[#3248]]\n -  Changed `TxSuccess.UpdatedStates`'s type to\n    `IImmutableDictionary<Address, IValue>` from\n    `IImmutableDictionary<Address, IValue?>`.  [[#3248]]\n -  Added `IBlockChainStates.GetState()` interface method.  [[#3250]]\n -  Added `IBlockStates.GetState()` interface method.  [[#3250]]\n -  Changed `IBlockStates` to inherit `IAccountState` interface.  [[#3251]]\n\n### Added APIs\n\n -  Added `IAccountDelta` interface and its default implementation\n    `AccountDelta` class.  [[#3245]]\n\n[#3230]: https://github.com/planetarium/libplanet/pull/3230\n[#3244]: https://github.com/planetarium/libplanet/pull/3244\n[#3245]: https://github.com/planetarium/libplanet/pull/3245\n[#3247]: https://github.com/planetarium/libplanet/pull/3247\n[#3248]: https://github.com/planetarium/libplanet/pull/3248\n[#3250]: https://github.com/planetarium/libplanet/pull/3250\n[#3251]: https://github.com/planetarium/libplanet/pull/3251\n\n\nVersion 2.2.0\n-------------\n\nReleased on June 23, 2023.\n\n### Backward-incompatible API changes\n\n -  Added `BlockProtocolVersion` property to `IActionContext`.  [[#3228]]\n -  Changed `IAccountStateDelta.TransferAsset()` to require additional\n    `IActionContext` parameter.  [[#3229]]\n -  Changed `IAccountStateDelta.MintAsset()` and\n    `IAccountStateDelta.BurnAsset()` to each require an additional\n    `IActionContext` parameter.  [[#3231]]\n\n### Bug fixes\n\n -  Fixed a bug where `IActionContext.BlockProtocolVersion` was not being set\n    properly in [#3228].\n\n[#3228]: https://github.com/planetarium/libplanet/pull/3228\n[#3229]: https://github.com/planetarium/libplanet/pull/3229\n[#3231]: https://github.com/planetarium/libplanet/pull/3231\n\n\nVersion 2.1.1\n-------------\n\nReleased on June 22, 2023.\n\n -  Ported changes from [Libplanet 2.0.1] release.  [[#3234]]\n\n[Libplanet 2.0.1]: https://www.nuget.org/packages/Libplanet/2.0.1\n[#3234]: https://github.com/planetarium/libplanet/pull/3234\n\n\nVersion 2.1.0\n-------------\n\nReleased on June 20, 2023.\n\n### Backward-incompatible API changes\n\n -  All `IBlockChainStates` methods now take nullable `BlockHash?`\n    instead of `BlockHash` as `offset` parameter.  [[#3214]]\n -  Removed `IncompleteBlockStatesException` class.  [[#3214]]\n -  Changed `BlockChain`'s implementation of `IBlockChainStates` to match\n    interface description.  [[#3214]]\n -  Added `IBlockChainStates.GetBlockStates()` interface method.  [[#3216]]\n\n### Added APIs\n\n -  Added `IBlockStates` interface and its default implementation\n    `BlockStates`.  [[#3216]]\n\n### Behavioral changes\n\n -  Improved performance of fungible asset APIs on default\n    `IAccountStateDelta` implementation.  [[#3218]]\n\n### Bug fixes\n\n -  Fixed a bug where `BlockAction` could have unintended\n    `AccountStateDeltaImpl.Signer` during its execution.  [[#3215]]\n\n[#3214]: https://github.com/planetarium/libplanet/pull/3214\n[#3215]: https://github.com/planetarium/libplanet/pull/3215\n[#3216]: https://github.com/planetarium/libplanet/pull/3216\n[#3218]: https://github.com/planetarium/libplanet/pull/3218\n\nVersion 2.0.1\n-------------\n\nReleased on June 22, 2023.\n\n -  (@planetarium/tx) Fixed a bug where an `encodeCurrency` serialized\n    `Currency` in an incompatible way with Libplanet.  [[#3225]]\n\n[#3225]: https://github.com/planetarium/libplanet/pull/3225\n\n\nVersion 2.0.0\n-------------\n\nReleased on June 14, 2023.\n\n### Backward-incompatible API changes\n\n -  Added `IAccountStateDelta.TotalUpdatedFungibleAssets` interface property.\n    [[#3208]]\n -  Removed `blockAction` parameter from `ActionContext()`.\n    [[#3209]]\n -  Added `ITransaction.MaxGasPrice` property.  [[#3201]]\n -  Added `ITransaction.GasLimit` property.  [[#3201]]\n -  `Currency.Serialize()`'s behavioral is changed.\n    the serialize field is replaced.  [[#3201]]\n\n### Added APIs\n\n -  Added `FungibleAssetValue.Serialize()` method.  [[#3201]]\n\n### Behavioral changes\n\n -  Improved performance of `StateStoreExtensions.Commit()` extension method\n    and `MerkleTrie.Commit()` method.  [[#3165]]\n -  Improved performance of `HashDigest<T>.DeriveFrom()` static method on\n    .NET Standard 2.1+.  [[#3165]]\n\n[#3165]: https://github.com/planetarium/libplanet/pull/3165\n[#3201]: https://github.com/planetarium/libplanet/pull/3201\n[#3208]: https://github.com/planetarium/libplanet/pull/3208\n[#3209]: https://github.com/planetarium/libplanet/pull/3209\n"
  },
  {
    "path": "changes/v3.md",
    "content": "Libplanet changelog\n===================\n\nVersion 3.9.6\n-------------\n\nReleased on January 26, 2024.\n\n -  (Libplanet.Store) Optimized `TrieStateStore.CopyStates()` to greatly\n    reduce the amount of memory used.  [[#3634]]\n\n[#3634]: https://github.com/planetarium/libplanet/pull/3634\n\n\nVersion 3.9.5\n-------------\n\nReleased on January 18, 2024.\n\n -  (Libplanet.Store) Changed `IStateStore.Commit()` to return an `ITrie`\n    with either its `Root` as `null` or a `HashNode`.  [[#3610]]\n -  (Libplanet.Store) Removed `IStateStore.PruneStates()` method.\n    [[#3613], [#3614]]\n\n[#3610]: https://github.com/planetarium/libplanet/pull/3610\n[#3613]: https://github.com/planetarium/libplanet/issues/3613\n[#3614]: https://github.com/planetarium/libplanet/pull/3614\n\n\nVersion 3.9.4\n-------------\n\nReleased on January 11, 2024.\n\n -  (Libplanet.Explorer) Rolled back some changes to the API to be\n    more compatible with pre-3.9.3 API.  [[#3600]]\n     -  Changed the name `BencodexValueType` to `IValueType`.\n     -  Changed the name `LegacyBencodexValueType` to `BencodexValueType`.\n     -  Changed `AddressType.Name` from `address` to `Address`.\n     -  Changed `BlockHashType.Name` from `blockHash` to `BlockHash`.\n     -  Changed `PublicKeyType.Name` from `publicKey` to `PublicKey`.\n     -  Changed `TxIdType.Name` from `txId` to `TxId`.\n\n[#3600]: https://github.com/planetarium/libplanet/pull/3600\n\n\nVersion 3.9.3\n-------------\n\nReleased on January 4, 2024.\n\nDue to changes in [#3567], a network ran with a prior version may not\nbe compatible with this version,  specifically, those that ran with\n[Libplanet 2.0.0] and onwards prior to this release that have included\n`Transaction`s that aren't compatible with the updated specification in [#3567].\n\n -  (Libplanet.Explorer) Added `BlockHashType` and `TxIdType`.  [[#3559]]\n -  (Libplanet.Explorer) Changed `HashDigestSHA256Type` to `HashDigestType<T>`.\n    [[#3559]]\n -  (Libplanet.Explorer) Changed `BencodexValueType` to inherit\n    `ObjectGraphType<IValue>` instead of `StringGraphType`.  Instead of\n    simply being a hexadecimal representation of `byte[]` encoded `IValue`,\n    now one can choose its representation format.  [[#3560]]\n -  (Libplanet.Explorer) Added `HelperQuery`, a collection of utility like\n    queries.  [[#3561]]\n -  (Libplanet.Explorer) Removed `IRichStore.StoreUpdatedAddressReferences()`\n    and `IterateUpdatedAddressReferences()` interface methods.  [[#3562]]\n -  (Libplanet.Explorer) Removed `involvedAddress` argument from all\n    `TransactionQuery` query methods.  [[#3562]]\n -  (Libplanet.Explorer) Removed `IRichStore` interface.  [[#3564]]\n -  (Libplanet.Explorer) Removed parameters `mysql-server`, `mysql-port`,\n    `mysql-username`, `mysql-password`, and `mysql-database` from\n    `Libplanet.Explorer.Executable`.  [[#3564]]\n -  Changed `TxInvoice` to no longer allow negative values for\n    `MaxGasPrice` and `GasLimit`.  [[#3567]]\n -  (Libplanet.Explorer) Added `AccountStateType` class.  [[#3570]]\n -  (Libplanet.Explorer) Added `account` and `accounts` query to `StateQuery`.\n    [[#3570]]\n -  (Libplanet.Store) Changed `ShortNode` to no longer inherit `BaseNode`.\n    `ShortNode.Value` is no longer nullable.  [[#3572]]\n -  (Libplanet.Store) Removed `FullNode()` and added `FullNode.Empty`.\n    [[#3573]]\n -  (Libplanet.Store) Slightly optimized `ITrie` performance.  [[#3573]]\n -  (Libplanet.Store) Changed `FullNode` to no longer inherit `BaseNode`.\n    [[#3574]]\n -  (Libplanet.Store) Removed `BaseNode`.  [[#3574]]\n -  (Libplanet.Store) Added `ITrie.Remove()` interface method.  [[#3576]]\n -  (Libplanet.Store) Added `FullNode.RemoveChild()` method.  [[#3576]]\n -  (Libplanet.Action) Added `IAccount.RemoveState()` interface method.\n    [[#3577]]\n -  (Libplanet.Explorer) Added `LegacyBencodexValueType` class that is\n    a copy of an old `BencodexValueType` with its name changed\n    for backwards compatibility.  Changed old `states` query\n    to use `LegacyBencodexValueType` instead of `BencodexValueType`.  [[#3579]]\n\n[#3559]: https://github.com/planetarium/libplanet/pull/3559\n[#3560]: https://github.com/planetarium/libplanet/pull/3560\n[#3561]: https://github.com/planetarium/libplanet/pull/3561\n[#3562]: https://github.com/planetarium/libplanet/pull/3562\n[#3564]: https://github.com/planetarium/libplanet/pull/3564\n[#3567]: https://github.com/planetarium/libplanet/pull/3567\n[#3570]: https://github.com/planetarium/libplanet/pull/3570\n[#3572]: https://github.com/planetarium/libplanet/pull/3572\n[#3573]: https://github.com/planetarium/libplanet/pull/3573\n[#3574]: https://github.com/planetarium/libplanet/pull/3574\n[#3576]: https://github.com/planetarium/libplanet/pull/3576\n[#3577]: https://github.com/planetarium/libplanet/pull/3577\n[#3579]: https://github.com/planetarium/libplanet/pull/3579\n\n\nVersion 3.9.2\n-------------\n\nReleased on December 15, 2023.\n\n -  (Libplanet.RocksDBStore) Added `DBOptions` type parameter to\n    `RocksDBKeyValueStore()`.  [[#3553]]\n\n[#3553]: https://github.com/planetarium/libplanet/pull/3553\n\n\nVersion 3.9.1\n-------------\n\nReleased on December 8, 2023.\n\n -  (Libplanet.Explorer) Added `INCLUDED` to `TxStatus` enum.  [[#3542]]\n\n[#3542]: https://github.com/planetarium/libplanet/pull/3542\n\n\nVersion 3.9.0\n-------------\n\nReleased on December 5, 2023.\n\nDue to changes in [#3529], a network ran with a prior version may not\nbe compatible with this version,  specifically, those that ran with\n[Libplanet 2.0.0] and onwards prior to this release that have included\n`Transaction`s that aren't compatible with the updated specification in [#3529].\n\n### Backward-incompatible API changes\n\n -  (Libplanet.Action) Removed unnecessary extension methods:  [[#3520]]\n     -  `IReadOnlyList<IActionEvaluation>.GetRawTotalDelta()`\n     -  `IReadOnlyList<IAccountDelta>.OrderedSum()`\n     -  `IAccountDelta.ToRawDelta()`\n     -  `IAccount.GetUpdatedStates()`\n     -  `IAccount.GetUpdatedBalances()`\n     -  `IAccount.GetUpdatedTotalSupplies()`\n -  (Libplanet.Action) Changed `IAccount` to no longer track `IAccountDelta`.\n    [[#3520]]\n -  (Libplanet.Action) Removed `IAccountDelta` as parameter for constructors\n    of `Account` class.  [[#3520]]\n -  (Libplanet.Action) Removed `hashedSignature` of type `byte[]` parameter\n    from `ActionEvaluator.GenerateRandomSeed()`.  [[#3523]]\n -  Changed `TxInvoice` to no longer allow having the null-ness of\n    `MaxGasPrice` and `GasLimit` to be different, i.e. either both should be\n    null or both should not be null at the same time.  [[#3529]]\n -  (Libplanet.Action) Removed `IAccountDelta` interface.  [[#3535]]\n -  (Libplanet.Action) Removed `IAccount.Delta` interface property.  [[#3535]]\n -  (Libplanet.Action) Changed constructor `IAccount(IAccountState,\n    IImmutableDictionary<(Address, Currency), BigInteger>)` to\n    `IAccount(IAccountState, IImmutableHashSet<(Address, Currency)>)`.\n    [[#3537]]\n\n[#3520]: https://github.com/planetarium/libplanet/pull/3520\n[#3523]: https://github.com/planetarium/libplanet/pull/3523\n[#3529]: https://github.com/planetarium/libplanet/pull/3529\n[#3535]: https://github.com/planetarium/libplanet/pull/3535\n[#3537]: https://github.com/planetarium/libplanet/pull/3537\n[Libplanet 2.0.0]: https://www.nuget.org/packages/Libplanet/2.0.0\n\n\nVersion 3.8.1\n-------------\n\nReleased on November 27, 2023.\n\n -  (Libplanet.Net) Fixed a bug where `GossipConsensusMessageCommunicator`\n    does not clear `_peerCatchupRounds` on `OnStartHeight()`.  [[#3519]]\n -  (Libplanet.Net) `GossipConsensusMessageCommunicator` now filters\n    `ConsensusVoteMsg` which height is different from latest `Context`.\n    [[#3519]]\n -  (Libplanet.Action) Fixed a bug where initialization of `AccountMetrics`\n    is absent.  [[#3521]]\n\n[#3519]: https://github.com/planetarium/libplanet/pull/3519\n[#3521]: https://github.com/planetarium/libplanet/pull/3521\n\n\nVersion 3.8.0\n-------------\n\nReleased on November 24, 2023.\n\n### Backward-incompatible API changes\n\n -  Removed `updatedAddresses` parameter from `BlockChain.MakeTransaction()`\n    [[#3480]]\n -  Removed `updatedAddresses` parameter from `Transaction.Create()`.  [[#3480]]\n -  Removed `updatedAddresses` parameter from all `TxInvoice()`.  [[#3480]]\n -  Removed `Rehearsal` property from `IActionContext` and\n    `ICommittedActionContext`.  [[#3485]]\n -  (Libplanet.Crypto) Removed `ToAddress()` extension method for\n    `PrivateKey` and `PublicKey`.  [[#3486]]\n -  (Libplanet.Crypto) Added `Address` property to `PrivateKey` and `PublicKey`.\n    [[#3486]]\n\n### Backward-incompatible storage format changes\n\n  -  (Libplanet.Store) Changed `Libplanet.RocksDBStore` to use\n     [`RocksDb`] instead of [`RocksDBSharp`].\n     *Note* Cannot read new version of `Libplanet.RocksDBStore`\n     storage from under `Libplanet.RocksDBStore` version 3.6.1.\n     [[#1848], [#3487]]\n\n### Added APIs\n\n -  (Libplanet.RocksDBStore) Added `RocksDBInstanceType` enum.  [[#3488]]\n -  (Libplanet.RocksDBStore) Changed `RocksDBStore` and `RocksDBKeyValueStore`\n    to accept `RocksDBInstanceType` type `instanceType` parameter instead of\n    `@readonly` parameter in their constructor.\n    [[#3488], [RocksDb Instance Types]]\n\n[#1848]: https://github.com/planetarium/libplanet/issues/1848\n[#3480]: https://github.com/planetarium/libplanet/pull/3480\n[#3485]: https://github.com/planetarium/libplanet/pull/3485\n[#3486]: https://github.com/planetarium/libplanet/pull/3486\n[#3487]: https://github.com/planetarium/libplanet/pull/3487\n[#3488]: https://github.com/planetarium/libplanet/pull/3488\n[`RocksDb`]: https://www.nuget.org/packages/RocksDB\n[`RocksDBSharp`]: https://www.nuget.org/packages/Planetarium.RocksDbSharp\n[RocksDb Instance Types]: https://github.com/facebook/rocksdb/wiki/Read-only-and-Secondary-instances\n\n\nVersion 3.7.1\n-------------\n\nReleased on November 21, 2023.\n\n -  Ported changes from [Libplanet 3.6.1] release.  [[#3500]]\n -  Ported changes from [Libplanet 3.6.2] release.  [[#3509]]\n\n[#3500]: https://github.com/planetarium/libplanet/pull/3500\n[#3509]: https://github.com/planetarium/libplanet/pull/3509\n[Libplanet 3.6.1]: https://www.nuget.org/packages/Libplanet/3.6.1\n[Libplanet 3.6.2]: https://www.nuget.org/packages/Libplanet/3.6.2\n\nVersion 3.7.0\n-------------\n\nReleased on October 27, 2023.\n\n### Backward-incompatible API changes\n\n -  Added `IBencodable` interface to `HashDigest<T>`.  [[#3455]]\n\n### Behavioral changes\n\n -  Slightly optimized `BlockMarshaler`.  [[#3454]]\n\n### Dependencies\n\n -  Upgrade *Bencodex* from [0.14.0][Bencodex 0.14.0] to\n    [0.16.0][Bencodex 0.16.0].  [[#3461]]\n -  Upgrade *Bencodex.Json* from [0.11.0][Bencodex.Json 0.11.0] to\n    [0.16.0][Bencodex.Json 0.16.0].  [[#3461]]\n\n[#3454]: https://github.com/planetarium/libplanet/pull/3454\n[#3455]: https://github.com/planetarium/libplanet/pull/3455\n[#3461]: https://github.com/planetarium/libplanet/pull/3461\n[Bencodex 0.16.0]: https://www.nuget.org/packages/Bencodex/0.16.0\n[Bencodex.Json 0.11.0]: https://www.nuget.org/packages/Bencodex.json/0.11.0\n[Bencodex.Json 0.16.0]: https://www.nuget.org/packages/Bencodex.json/0.16.0\n\n\nVersion 3.6.2\n-------------\n\nReleased on November 21, 2023.\n\n -  (Libplanet.Net) Changed default `ContextTimeoutOption` values for\n    more consistent and stable consensus.  [[#3506]]\n\n[#3506]: https://github.com/planetarium/libplanet/pull/3506\n\n\nVersion 3.6.1\n-------------\n\nReleased on November 20, 2023.\n\n -  (Libplanet.Store) Added optional `cache` parameter of type `HashNodeCache`\n    to `MerkleTrie()` constructors.  [[#3495]]\n -  (Libplanet.Store) Added `HashNodeCache` class.  [[#3495]]\n -  (Libplanet.Store) Changed internal caching strategy of `TrieStateStore` for\n    read/write optimization.  [[#3495]]\n\n[#3495]: https://github.com/planetarium/libplanet/pull/3495\n\n\nVersion 3.6.0\n-------------\n\nReleased on October 6, 2023.\n\n### Backward-incompatible API changes\n\n -  Changed `IActionEvaluator.Evaluate()`'s return type to\n    `IReadOnlyList<ICommittedActionEvaluation>` from\n    `IReadOnlyList<IActionEvaluation>`.  [[#3445]]\n -  Changed `BlockChain.DetermineStateRootHash(IActionEvaluator,\n    IPreEvaluationBlock, out IReadOnlyList<IActionEvaluation>)` to\n    `BlockChain.DetermineStateRootHash(IActionEvaluator,\n    IPreEvaluationBlock, out IReadOnlyList<ICommittedActionEvaluation>)`.\n    [[#3445]]\n -  Changed `BlockChain.EvaluateGenesis()`'s return type to\n    `IReadOnlyList<ICommittedActionEvaluation>` from\n    `IReadOnlyList<IActionEvaluation>`.  [[#3445]]\n -  Changed `BlockChain.EvaluateBlock()`'s return type to\n    `IReadOnlyList<ICommittedActionEvaluation>` from\n    `IReadOnlyList<IActionEvaluation>`.  [[#3445]]\n -  Removed `StateStoreExtensions` class.  [[#3323], [#3450]]\n\n### Added APIs\n\n -  (Libplanet.Explorer) Added `TxResult.InputState` of type\n    `HashDigest<SHA256>?`.  [[#3446], [#3447]]\n -  (Libplanet.Explorer) Added `TxResult.OutputState` of type\n    `HashDigest<SHA256>?`.  [[#3446], [#3447]]\n -  (Libplanet.Explorer) Added `offsetStateRootHash` of type\n    `HashDigest<SHA256>?` argument for `StateQuery.states` field.\n    [[#3448], [#3449]]\n -  (Libplanet.Explorer) Added `offsetStateRootHash` of type\n    `HashDigest<SHA256>?` argument for `StateQuery.balance` field.\n    [[#3448], [#3449]]\n -  (Libplanet.Explorer) Added `offsetStateRootHash` of type\n    `HashDigest<SHA256>?` argument for `StateQuery.totalSupply` field.\n    [[#3448], [#3449]]\n -  (Libplanet.Explorer) Added `offsetStateRootHash` of type\n    `HashDigest<SHA256>?` argument for `StateQuery.validators` field.\n    [[#3448], [#3449]]\n\n### Behavioral changes\n\n -  `IActionEvaluator.Evaluate()`, `BlockChain.EvaluateGenesis()`,\n    and `BlockChain.EvaluateBlock()` have a side-effect of storing\n    data to `IStateStore` when called.  [[#3445]]\n\n[#3323]: https://github.com/planetarium/libplanet/issues/3323\n[#3445]: https://github.com/planetarium/libplanet/pull/3445\n[#3446]: https://github.com/planetarium/libplanet/issues/3446\n[#3447]: https://github.com/planetarium/libplanet/pull/3447\n[#3448]: https://github.com/planetarium/libplanet/issues/3448\n[#3449]: https://github.com/planetarium/libplanet/pull/3449\n[#3450]: https://github.com/planetarium/libplanet/pull/3450\n\n\nVersion 3.5.0\n-------------\n\nReleased on October 4, 2023.\n\n### Backward-incompatible API changes\n\n -  Removed `IActionContext.Random` property.  Use `IActionContext.GetRandom()`\n    instead.  [[#3437]]\n -  Added `IActionContext.RandomSeed` property.  [[#3437]]\n -  Added `IActionContext.GetRandom()` method.  [[#3437]]\n -  Changed `IActionEvaluator.Evaluate(IPreEvaluationBlock)` to\n    `IActionEvaluator.Evaluate(IPreEvaluationBlock, HashDigest<SHA256>)`.\n    [[#3438]]\n -  Changed `ActionEvaluator` to accept `IStateStore` instead of\n    `IBlockChainStates`  [[#3439]]\n\n[#3437]: https://github.com/planetarium/libplanet/pull/3437\n[#3438]: https://github.com/planetarium/libplanet/pull/3438\n[#3439]: https://github.com/planetarium/libplanet/pull/3439\n\n\nVersion 3.4.0\n-------------\n\nReleased on September 25, 2023.\n\n### Backward-incompatible API changes\n\n -  Added `IBlockChainStates.GetAccountState(HashDigest<SHA256>?)`\n    interface method.  [[#3425]]\n -  Removed `TxFailure.ExceptionMetadata` property.  [[#3428]]\n -  Removed `ISerializable` interface from `TxExecution`, `TxSuccess`,\n    and `TxFailure`.  [[#3428]]\n -  Removed `TxSuccess` and `TxFailure` class.  [[#3429]]\n -  Changed `TxExecution` class as `sealed` from `abstract.`  [[#3429]]\n -  All properties of `TxExecution` except `BlockHash` and `TxId` were\n    overhauled.  [[#3429]]\n -  (Libplanet.Store) Removed `IStore.PutTxExecution(TxSuccess)` and\n    `IStore.PutTxExecution(TxFailure)`;\n    added `IStore.PutTxExecution(TxExecution)`.  [[#3429]]\n -  (Libplanet.Explorer) Removed `TxResult.ExceptionName` of type `string?`\n    and added `TxResult.ExceptionNames` of type `List<string?>?`.  [[#3429]]\n -  (Libplanet.Explorer) Removed `TxResult.UpdatedStates` and\n    `TxResult.UpdatedFungibleAssets`.  [[#3429]]\n -  Changed `IActionRenderer.RenderAction(IValue, IActionContext, IAccount)`\n    to `IActionRenderer.RenderAction(IValue, ICommittedActionContext,\n    HashDigest<SHA256>)`.  [[#3431]]\n -  Changed `IActionRenderer.RenderActionError(IValue, IActionContext,\n    Exception)` to `IActionRenderer.RenderActionError(IValue,\n    ICommittedActionContext, Exception)`.  [[#3431]]\n\n### Added APIs\n\n -  Added `AccountDiff` class.  [[#3424]]\n -  Added `ICommittedActionContext` interface.  [[#3431]]\n -  Added `ICommittedActionEvaluation` interface.  [[#3431]]\n\n[#3424]: https://github.com/planetarium/libplanet/pull/3424\n[#3425]: https://github.com/planetarium/libplanet/pull/3425\n[#3428]: https://github.com/planetarium/libplanet/pull/3428\n[#3429]: https://github.com/planetarium/libplanet/pull/3429\n[#3431]: https://github.com/planetarium/libplanet/pull/3431\n\n\nVersion 3.3.1\n-------------\n\nReleased on September 8, 2023.\n\n-  (Libplanet.Store) Fixed a bug where `ITrie.Get()` could wrongly retrieve\n   an `IValue` from a non-existent path.  [[#3420]]\n\n[#3420]: https://github.com/planetarium/libplanet/pull/3420\n\n\nVersion 3.3.0\n-------------\n\nReleased on September 7, 2023.\n\n### Backward-incompatible API changes\n\n -  (Libplanet.Store) Removed `ITrie.Commit()` method.  [[#3392]]\n -  (Libplanet.Store) Added `IStateStore.Commit()` method.  [[#3398]]\n -  (Libplanet.Store) Removed `IKeyValueStore.Get(IEnumerable<KeyBytes> keys)`\n    method.  [[#3362], [#3400]]\n -  (Libplanet.Store) Added `PathCursor` struct.  [[#3399]]\n -  (Libplanet.Store) Added `Nibbles` struct.  [[#3399]]\n -  (Libplanet.Store) Changed `KeyBytes` to no longer implement\n    `IEquatable<byte[]>` and `IEquatable<ImmutableArray<byte>>`.  [[#3402]]\n -  (Libplanet.Store) Added `ITrie.GetNode()` method.  [[#3401]]\n -  (Libplanet.Store) Added `ITrie.IterateValues()` method.  [[#3405]]\n -  (Libplanet.Store) Added `ITrie.IterateNodes()` method.  [[#3405]]\n -  (Libplanet.Store) Removed `Secure` option from `TrieStateStore`.  [[#3407]]\n     -  Removed `secure` parameter from `TrieStateStore()`.\n     -  Removed `ITrie.Secure` property.\n     -  Removed `secure` parameter from `MerkleTrie()`.\n     -  Removed `secure` parameter from `PathCursor()`.\n -  (Libplanet.Store) Added `ITrie.Diff()` method.  [[#3410]]\n -  (Libplanet.Store) Removed `MerkleTrieExtensions.DifferentNodes()`\n    static method.  [[#3410]]\n -  Removed `IBlockState` interface.  [[#3413]]\n -  Removed `IBlockChainState.GetBlockState()` interface method.  [[#3413]]\n -  Added `IBlockChainState.GetAccountState()` interface method.  [[#3413]]\n -  Added `IAccountState` interface.  [[#3416]]\n -  Added `AccountState` class.  [[#3416]]\n\n### Added APIs\n\n -  (Libplanet.RocksDBStore) `RocksDBStore` and `RocksDBKeyValueStore` became to\n    receive `@readonly` parameter in their constructor. If it is true, it opens\n    rocksdb as read-only mode.  [[#3354], [#3356], [RocksDB Read Only]]\n\n### Behavioral changes\n\n -  (Libplanet.Store) Changed `ShortNode` to no longer accept empty `byte`\n    arrays.  [[#3390]]\n\n### Bug fixes\n\n -  (Libplanet.Store) Fixed `Equals()` for `FullNode` and `ShortNode`.\n    [[#3377]]\n -  (Libplanet.Store) Fixed a bug where adding two `byte` arrays as keys\n    with one being a subsequence of the other would break `MerkleTrie`\n    and lose data.  [[#3390]]\n -  (Libplanet.Store) Fixed a bug where when trying to add a value to\n    an existing `FullNode` would throw an `Exception`.  [[#3390]]\n -  (Libplanet.Store) Fixed a bug where committing an `ITrie` may return\n    an `ITrie` with a different path security scheme.  [[#3401]]\n\n[#3354]: https://github.com/planetarium/libplanet/issues/3354\n[#3356]: https://github.com/planetarium/libplanet/pull/3356\n[#3362]: https://github.com/planetarium/libplanet/issues/3362\n[#3377]: https://github.com/planetarium/libplanet/pull/3377\n[#3390]: https://github.com/planetarium/libplanet/pull/3390\n[#3392]: https://github.com/planetarium/libplanet/pull/3392\n[#3398]: https://github.com/planetarium/libplanet/pull/3398\n[#3399]: https://github.com/planetarium/libplanet/pull/3399\n[#3400]: https://github.com/planetarium/libplanet/pull/3400\n[#3401]: https://github.com/planetarium/libplanet/pull/3401\n[#3402]: https://github.com/planetarium/libplanet/pull/3402\n[#3405]: https://github.com/planetarium/libplanet/pull/3405\n[#3407]: https://github.com/planetarium/libplanet/pull/3407\n[#3410]: https://github.com/planetarium/libplanet/pull/3410\n[#3413]: https://github.com/planetarium/libplanet/pull/3413\n[#3416]: https://github.com/planetarium/libplanet/pull/3416\n[RocksDB Read Only]: https://github.com/facebook/rocksdb/wiki/Read-only-and-Secondary-instances\n\n\nVersion 3.2.0\n-------------\n\nReleased on August 10, 2023.\n\n### Backward-incompatible API changes\n\n -  (Libplanet.Action) Renamed `IAccountStateDelta` as `IAccount`.\n    [[#3337]]\n -  (Libplanet.Store) Optimized `MerkleTrie.Get()`.  [[#3347]]\n -  (Libplanet.Types) Removed `TxSuccess.FungibleAssetsDelta`  [[#3357]]\n -  (Libplanet.Explorer) Removed `TxResult.ExceptionMetadata` and\n    `TxResult.FungibleAssetsDelta`.  [[#3357]]\n -  (Libplanet.Store) Added `ITrie.Get(KeyBytes)` interface method.  [[#3359]]\n -  (Libplanet.Store) Optimized `MerkleTrie.Get()` by allowing parallel\n    processing when more than 4 `KeyBytes` keys are given.  [[#3359]]\n\n[#3337]: https://github.com/planetarium/libplanet/pull/3337\n[#3347]: https://github.com/planetarium/libplanet/pull/3347\n[#3357]: https://github.com/planetarium/libplanet/pull/3357\n[#3359]: https://github.com/planetarium/libplanet/pull/3359\n\n\nVersion 3.1.2\n-------------\n\nReleased on August 10, 2023.\n\n -  Upgrade *Bencodex* from [0.12.0][Bencodex 0.12.0] to\n    [0.14.0][Bencodex 0.14.0].  [[#3367]]\n\n[#3367]: https://github.com/planetarium/libplanet/pull/3367\n[Bencodex 0.14.0]: https://www.nuget.org/packages/Bencodex/0.14.0\n\n\nVersion 3.1.1\n-------------\n\nReleased on August 9, 2023.\n\n -  Fixed a bug where `Swarm` checks block existent when preloading.\n    [[#3253], [#3353], [#3360]]\n\n[#3253]: https://github.com/planetarium/libplanet/issues/3253\n[#3353]: https://github.com/planetarium/libplanet/pull/3353\n[#3360]: https://github.com/planetarium/libplanet/pull/3360\n\n\nVersion 3.1.0\n-------------\n\nReleased on July 27, 2023.\n\n### Backward-incompatible API changes\n\n -  Changed `StateStoreExtensions.Commit()` to accept\n    `IImmutableDictionary<KeyBytes, IValue>` instead of\n    `IImmutableDictionary<string, IValue>`.  [[#3321]]\n -  Changed `AccountDeltaExtensions.ToRawDelta()` to return\n    `IImmutableDictionary<KeyBytes, IValue>` instead of\n    `IImmutableDictionary<string, IValue>`.  [[#3321]]\n -  Changed `ActionEvaluatorExtensions.GetRawTotalDelta()` to return\n    `IImmutableDictionary<KeyBytes, IValue>` instead of\n    `IImmutableDictionary<string, IValue>`.  [[#3321]]\n -  Removed `EnumerableMeasurement` class.  [[#3325]]\n -  Removed `KeyValueExtensions` class.  [[#3325]]\n -  Removed `StateStoreExtensions.EncodeKey()` and\n    `StateStoreExtensions.DecodeKey()` methods.  [[#3328]]\n -  Removed `StateStoreExtensions.GetStates(IStateStore, HashDigest<SHA256>?,\n    IReadOnlyList<string>)` method.  [[#3328]]\n -  Removed `TrieExtensions.Set(ITrie,\n    IEnumerable<KeyValuePair<string, IValue?>)` method.  [[#3328]]\n -  Removed `KeyBytes(string, Encoding)` constructor.  [[#3328]]\n\n### Added APIs\n\n -  Added `StateStoreExtensions.GetStates(IStateStore, HashDigest<SHA256>,\n    IReadOnlyList<KeyBytes>)` method.  [[#3321]]\n -  Added `KeyBytes.Encoding` static property.  [[#3328]]\n -  Added `KeyBytes(string)` constructor.  [[#3328]]\n\n### Behavioral changes\n\n -  Optimized read and write access to `IStateStore` both for memory and speed.\n    [[#3321]]\n\n### Dependencies\n\n -  Upgrade *Bencodex* from [0.11.0][Bencodex 0.11.0] to\n    [0.12.0][Bencodex 0.12.0].  [[#3335]]\n\n[#3321]: https://github.com/planetarium/libplanet/pull/3321\n[#3325]: https://github.com/planetarium/libplanet/pull/3325\n[#3328]: https://github.com/planetarium/libplanet/pull/3328\n[#3335]: https://github.com/planetarium/libplanet/pull/3335\n[Bencodex 0.12.0]: https://www.nuget.org/packages/Bencodex/0.12.0\n\n\nVersion 3.0.1\n-------------\n\nReleased on July 21, 2023.\n\n -  Fixed builds and tests.  [[#3326]]\n\n[#3326]: https://github.com/planetarium/libplanet/pull/3326\n\n\nVersion 3.0.0\n-------------\n\nReleased on July 19, 2023.\n\n### Backward-incompatible API changes\n\n -  (Libplanet.Common) Moved packages from `Libplanet`.  [[#3300]]\n     -  `Libplanet.Serialization`\n     -  `Libplanet.JsonConverters`\n -  (Libplanet.Common) Moved packages from `Libplanet`.  [[#3314]]\n     -  `Libplanet.Misc`\n -  (Libplanet.Crypto) Moved packages from `Libplanet`.  [[#3314]]\n     -  `Libplanet.Crypto`\n -  (Libplanet.Types) Moved packages from `Libplanet`.  [[#3314]]\n     -  `Libplanet.Assets`\n     -  `Libplanet.Blocks`\n     -  `Libplanet.Consensus`\n     -  `Libplanet.Tx`\n -  (Libplanet.Store) Moved packages from `Libplanet`.  [[#3303]]\n     -  `Libplanet.Store`\n -  (Libplanet.Action) Moved packages from `Libplanet`.  [[#3310]]\n     -  `Libplanet.Action`\n -  Removed `IExtractableException` and `ExtractableException`.  [[#3304]]\n\n### Added APIs\n\n -  (Libplanet.Net) Added `Gossip.DeniedPeers` property.  [[#3313]]\n\n### Behavioral changes\n\n -  `TxFailure` no longer tracks `ExceptionMetadata` and is always\n    set to `null` even for already stored `TxFailure`.  [[#3304]]\n\n[#3300]: https://github.com/planetarium/libplanet/pull/3300\n[#3303]: https://github.com/planetarium/libplanet/pull/3303\n[#3304]: https://github.com/planetarium/libplanet/pull/3304\n[#3310]: https://github.com/planetarium/libplanet/pull/3310\n[#3313]: https://github.com/planetarium/libplanet/pull/3313\n[#3314]: https://github.com/planetarium/libplanet/pull/3314\n"
  },
  {
    "path": "changes/v4.md",
    "content": "Libplanet changelog\n===================\n\nVersion 4.6.1\n-------------\n\nReleased on June 11, 2024.\n\n-  Ported changes from [Libplanet 4.5.2] release.  [[#3816]]\n\n[#3816]: https://github.com/planetarium/libplanet/pull/3816\n[Libplanet 4.5.2]: https://www.nuget.org/packages/Libplanet/4.5.2\n\n\nVersion 4.6.0\n-------------\n\nReleased on May 27, 2024.\n\nDue to changes in [#3789], a network ran with a prior version\nmay not be compatible with this version.  The native implementation of\n`IActionEvaluator`, which is `ActionEvaluator`, no longer supports\nevaluation of PoW `Block`s.  That is, it is no longer possible to\nreconstruct states with valid state root hashes purely from past\n`Block`s that includes PoW `Block`s.\n\n### Deprecated APIs\n\n -  (Libplanet.Common) Removed `Nonce` struct.  [[#3793], [#3794]]\n -  Removed `AtomicActionRenderer` class.  [[#3795]]\n\n### Backward-incompatible API changes\n\n -  (Libplanet.Action) Changed `ActionEvaluate.Evaluate()` to no longer\n    accept `IPreEvaluationBlock` with a protocol version less than\n    `BlockMetadata.PBFTProtocolVersion`.  [[#3789]]\n -  (Libplanet.Action) Changed the description of `IActionEvaluate.Evaluate()`\n    so that it may throw `BlockProtocolVersionNotSupportedException` if\n    its implementation is not able to handle `IPreEvaluationBlock` with\n    certain `BlockMetadata.ProtocolVersion`s.  [[#3789]]\n -  (Libplanet.Types) Removed `nonce` parameter from\n    `BlockMetadata.DerivePreEvaluationHash()` and\n    `BlockMetadata.MakeCandidateData()` methods.  [[#3793], [#3794]]\n -  (Libplanet.Explorer.Executable) Removed unused `difficultyBoundDivisor`\n    parameter for the executable and removed `Options.DifficultyBoundDivisor`\n    property.  [[#3796]]\n -  (Libplanet.Explorer) Added `balance`, `totalSupply`, and `validatorSet`\n    queries to `WorldStateType`.  [[#3792], [#3798]]\n -  (Libplanet.Explorer) Deprecated `balance`, `balances`, `totalSupply` and\n    `validatorSet` query from `AccountStateType`.  [[#3792], [#3798]]\n -  (Libplanet.Explorer) Changed `totalSupply` query under `StateQuery` to\n    no longer throw an `Exception` and return a zero amount instead.  [[#3799]]\n\n### Added APIs\n\n -  (Libplanet.Action) Added `BlockProtocolVersionNotSupportedException` class.\n    [[#3789]]\n -  (Libplanet.Mocks) Added `MockBlockChainStates` class.  [[#3799]]\n\n[#3789]: https://github.com/planetarium/libplanet/pull/3789\n[#3792]: https://github.com/planetarium/libplanet/issues/3792\n[#3793]: https://github.com/planetarium/libplanet/issues/3793\n[#3794]: https://github.com/planetarium/libplanet/pull/3794\n[#3795]: https://github.com/planetarium/libplanet/pull/3795\n[#3796]: https://github.com/planetarium/libplanet/pull/3796\n[#3798]: https://github.com/planetarium/libplanet/pull/3798\n[#3799]: https://github.com/planetarium/libplanet/pull/3799\n\n\nVersion 4.5.2\n-------------\n\nReleased on June 10, 2024.\n\n -  (Libplanet.Explorer) Added `ProtocolVersion` field to `BlockType`.\n    [[#3810]]\n\n[#3810]: https://github.com/planetarium/libplanet/pull/3810\n\n\nVersion 4.5.1\n-------------\n\nReleased on May 27, 2024.\n\n -  Suppressed build warnings as a temporary measure that may result in\n    build failures due to security vulnerabilities found in\n    [LiteDB 4.1.4] and [BouncyCastle.Cryptography 2.0.0] packages.  [[#3800]]\n\n[#3800]: https://github.com/planetarium/libplanet/pull/3800\n[BouncyCastle.Cryptography 2.0.0]: https://www.nuget.org/packages/BouncyCastle.Cryptography/2.0.0\n\n\nVersion 4.5.0\n-------------\n\nReleased on May 14, 2024.\n\nDue to changes in [#3780] and [#3783], a network ran with a prior version\nmay not be compatible with this version.  Regarding [#3780], a network\nthat ran with an `IAction` that has used `GetTotalSupply()` with\nits execution result dependent on its value may not be compatible.\nRegarding [#3783], a network that ran with an `IAction` that has either\nused `MintAsset()` and `BurnAsset()` with its execution result dependent on\nhandling of a possible `Exception` thrown by these methods\nmay not be compatible.\n\n### Backward-incompatible API changes\n\n -  (Libplanet.Types) Updated `BlockMetadata.CurrentProtocolVersion`\n    from 6 to 7.  [[#3769]]\n -  (Libplanet.Store) Added `IterateSubTrieValues(KeyBytes)` and\n    `IterateSubTrieNodes(KeyBytes)` methods to `MerkleTrie`.  [[#3774]]\n -  (Libplanet.Types) Added `BlockMetadata.CurrencyAccountProtocolVersion`.\n    [[#3775]]\n -  (Libplanet.Mocks) Removed `MockWorldState.ToModern()` and\n    `MockWorldState.SetTotalSupply()` methods.  [[#3778]]\n -  (Libplanet.Action) Removed `TotalSupplyNotTrackableException` class.\n    [[#3780]]\n -  (Libplanet.Action) `IWorldState.GetTotalSupply()` no longer throws\n    a `TotalSupplyNotTrackableException` but returns a zero amount of\n    corresponding `FungibleAssetValue`.  [[#3780]]\n -  (Libplanet.Action) Changed the precednce for the types of `Exception`s\n    that may be thrown by `IWorld.MintAsset()` and\n    `IWorld.BurnAsset()`.\n\n### Added APIs\n\n -  (Libplanet.Action) Added `CurrencyAccount` class.  [[#3779]]\n\n### Behavioral changes\n\n -  (Libplanet.Mocks) `MockWorldState.SetBalance()` now automatically updates\n    the total supply of the provided `Currency`.  [[#3778]]\n\n[#3769]: https://github.com/planetarium/libplanet/pull/3769\n[#3774]: https://github.com/planetarium/libplanet/pull/3774\n[#3775]: https://github.com/planetarium/libplanet/pull/3775\n[#3778]: https://github.com/planetarium/libplanet/pull/3778\n[#3779]: https://github.com/planetarium/libplanet/pull/3779\n[#3780]: https://github.com/planetarium/libplanet/pull/3780\n[#3783]: https://github.com/planetarium/libplanet/pull/3783\n\n\nVersion 4.4.2\n-------------\n\nReleased on April 29, 2024.\n\n -  (Libplanet.Explorer) Added `KeyBytesType` and `TrieType`.  [[#3763]]\n -  (Libplanet.Explorer) Added `RawStateQuery`.  [[#3763]]\n\n[#3763]: https://github.com/planetarium/libplanet/pull/3763\n\n\nVersion 4.4.1\n-------------\n\nReleased on April 18, 2024.\n\n -  Ported changes from [Libplanet 4.3.1] release.  [[#3757]]\n\n[#3757]: https://github.com/planetarium/libplanet/pull/3757\n[Libplanet 4.3.1]: https://www.nuget.org/packages/Libplanet/4.3.1\n\n\nVersion 4.4.0\n-------------\n\nReleased on April 17, 2024.\n\n### Backward-incompatible API changes\n\n -  (Libplanet.Action) Removed `IWorld.SetValidator()` extension method.\n    Use `IWorld.SetValidatorSet()` extension method instead.  [[#3735]]\n -  (Libplanet.Types) Renamed `BlockMetadata.PoWProtocolVersion` to\n    `BlockMetadata.PBFTProtocolVersion` and `BlockMetadata.LegacyStateVersion`\n    to `BlockMetadata.WorldStateProtocolVersion` while increasing each value\n    by 1.  [[#3736]]\n -  (Libplanet.Store) Changed the type of `TrieMetadata.Version` from\n    `BigInteger` to `int`.  [[#3738]]\n -  (Libplanet.Store) Changed `TrieMetadata` to throw an `ArgumentException`\n    when trying to create an instance with an invalid version.  [[#3738]]\n -  (Libplanet.Action) Added `IWorldState.Version` interface property.\n    [[#3739]]\n -  (Libplanet.Types) Updated `BlockMetadata.CurrentProtocolVersion`\n    from 5 to 6.  [[#3741]]\n -  (Libplanet.Types) Added `BlockMetadata.TransferFixProtocolVersion`,\n    `BlockMetadata.SignatureProtocolVersion`, and\n    `BlockMetadata.TransactionOrderingFixProtocolVersion` constants.  [[#3742]]\n -  (Libplanet.Action) Removed `ReservedAddresses.FungibleAssetAccount`.\n    [[#3745]]\n -  (Libplanet.Action) Changed `ReservedAddresses.ValidatorSetAccount`'s value\n    from `0x1000000000000000000000000000000000000002`\n    to `0x100000000000000000000000000000000000001`.  [[#3745]]\n\n### Added APIs\n\n -  (Libplanet.Action) Added `ValidatorSetAccount` class.  [[#3745]]\n -  (Libplanet.Explorer) Added `WorldState.version` field.  [[#3746]]\n\n[#3735]: https://github.com/planetarium/libplanet/pull/3735\n[#3736]: https://github.com/planetarium/libplanet/pull/3736\n[#3738]: https://github.com/planetarium/libplanet/pull/3738\n[#3739]: https://github.com/planetarium/libplanet/pull/3739\n[#3741]: https://github.com/planetarium/libplanet/pull/3741\n[#3742]: https://github.com/planetarium/libplanet/pull/3742\n[#3745]: https://github.com/planetarium/libplanet/pull/3745\n[#3746]: https://github.com/planetarium/libplanet/pull/3746\n\n\nVersion 4.3.1\n-------------\n\nReleased on April 18, 2024.\n\n -  Downgraded *LiteDB* from [5.0.15][LiteDB 5.0.15] to\n    [4.1.4][LiteDB 4.1.4].  [[#3753]]\n\n[#3753]: https://github.com/planetarium/libplanet/pull/3753\n\n\nVersion 4.3.0\n-------------\n\nReleased on April 8, 2024.\n\nDue to changes in #3728, a network ran with a prior version may not be\ncompatible with this version, specifically those that ran with\n`IAction`s that has allowed negative balances through `TransferAssets()`\nwith `allowNegativeBalance` as `true`.\n\n### Backward-incompatible API changes\n\n -  (Libplanet.Action) Added `Txs` property of\n    type `IReadOnlyList<ITransaction>?` to `IActionContext`.  [[#3713]]\n -  (Libplanet.Action) Removed `TotalFungibleAssets` property from\n    `IWorld`.  [[#3714]]\n -  (Libplanet.Action) Changed `GetBalance()`, `GetTotalSupply()`, and\n    `GetValidatorSet()` of `IWorldState` to extension methods.  [[#3715]]\n -  (Libplanet.Action) Changed `MintAsset()`, `BurnAsset()`, `TransferAsset()`,\n    and `SetValidator()` of `IWorld` to extension methods.  [[#3715]]\n -  (Libplanet.Action) Removed `allowNegativeBalance` parameter from\n    `IWorld.TransferAsset()` extension method.  [[#3725], [#3728]]\n -  (Libplanet.Store) Removed `journal`, `indexCacheSize`, and `flush`\n    parameters from `DefaultStore`'s constructor.  [[#3729]]\n\n### Dependencies\n\n -  Upgraded *LiteDB* from [4.1.4][LiteDB 4.1.4] to\n    [5.0.15][LiteDB 5.0.15].  [[#3729]]\n\n[#3713]: https://github.com/planetarium/libplanet/pull/3713\n[#3714]: https://github.com/planetarium/libplanet/pull/3714\n[#3715]: https://github.com/planetarium/libplanet/pull/3715\n[#3725]: https://github.com/planetarium/libplanet/issues/3725\n[#3728]: https://github.com/planetarium/libplanet/pull/3728\n[#3729]: https://github.com/planetarium/libplanet/pull/3729\n[LiteDB 4.1.4]: https://www.nuget.org/packages/LiteDB/4.1.4\n[LiteDB 5.0.15]: https://www.nuget.org/packages/LiteDB/5.0.15\n\n\nVersion 4.2.0\n-------------\n\nReleased on March 22, 2024.\n\n### Backward-incompatible API changes\n\n -  (Libplanet.Action) Moved `GetBalance()` and `GetTotalSupply()` methods from\n    `IAccountState` to `IWorldState`.  [[#3694], [#3697]]\n -  (Libplanet.Action) Moved `MintAsset()`, `BurnAsset()`, and `TransferAsset()`\n    methods from `IAccount` to `IWorld`.  [[#3694], [#3697]]\n -  (Libplanet.Action) Removed `TotalSupplyDiff`, `FungibleAssetValueDiff`,\n    and `ValidatorDiff` properties from `AccountDiff`.  [[#3694], [#3697]]\n -  (Libplanet.Action) Removed `Uncommitted` property and `CommitAccount()`\n    method from `IWorldDelta`.  [[#3694], [#3699]]\n -  (Libplanet.Action) Moved `GetValidatorSet()` from `IAccountState`\n    to `IWorldState`.  [[#3702]]\n -  (Libplanet.Action) Moved `SetValidator()` from `IAccount` to `IWorld`.\n    [[#3702]]\n\n### Added APIs\n\n -  Added `Libplanet.Mocks` project.  [[#3642]]\n\n[#3642]: https://github.com/planetarium/libplanet/pull/3642\n[#3694]: https://github.com/planetarium/libplanet/issues/3694\n[#3697]: https://github.com/planetarium/libplanet/pull/3697\n[#3699]: https://github.com/planetarium/libplanet/pull/3699\n[#3702]: https://github.com/planetarium/libplanet/pull/3702\n\n\nVersion 4.1.0\n-------------\n\nReleased on March 8, 2024.\n\n### Backward-incompatible API changes\n\n -  Removed the '#nullable disable' from 3 projects\n    (Action, Common, Explorer). [[#3622]]\n -  Removed the '#nullable disable' from the Libplanet.Store project. [[#3644]]\n -  Removed the '#nullable disable' from the Libplanet.RocksDBStore project.\n    [[#3651]]\n -  Removed `BaseIndex` class and changed `BlockSet` base class from\n    `BaseIndex<BlockHash, Block>` to `IReadOnlyDictionary<BlockHash, Block>`.\n    [[#3686]]\n\n### Backward-incompatible network protocol changes\n\n -  (Libplanet.Net) Changed some types due to removal of 'nullable keyword'.\n    [[#3669]]\n     -  Changed `blocks` parameter type of `Branch` class constructor from\n        `IEnumerable<(Block, BlockCommit)>` to\n        `IEnumerable<(Block, BlockCommit?)>`.\n     -  Changed `AppProtocolVersion.Extra` field type from\n        `IValue` to `IValue?`.\n     -  Changed `extra` parameter type of `AppProtocolVersion` class constructor\n        from `IValue` to `IValue?`.\n     -  Changed `extra` parameter type of `AppProtocolVersion.Sign` method\n        from `IValue` to `IValue?`.\n\n### Added APIs\n\n -  (Libplanet.Store.Remote) Introduce\n    `Libplanet.Store.Server.RemoteKeyValueService`  [[#3688]]\n -  (Libplanet.Store.Remote) Introduce\n    `Libplanet.Store.Client.RemoteKeyValueStore`  [[#3688]]\n\n### Behavioral changes\n\n -  (Libplanet.Store) Optimized `ITrie.IterateNodes()` to greatly\n    reduce the amount of memory used.  [[#3687]]\n\n\n[#3622]: https://github.com/planetarium/libplanet/pull/3622\n[#3644]: https://github.com/planetarium/libplanet/pull/3644\n[#3651]: https://github.com/planetarium/libplanet/pull/3651\n[#3669]: https://github.com/planetarium/libplanet/pull/3669\n[#3686]: https://github.com/planetarium/libplanet/pull/3686\n[#3687]: https://github.com/planetarium/libplanet/pull/3687\n[#3688]: https://github.com/planetarium/libplanet/pull/3688\n\n\nVersion 4.0.6\n-------------\n\nReleased on February 22, 2024.\n\n -  (Libplanet.Action) Fixed a bug where `FeeCollector.Mortgage()`\n    unintentionally resets accumulated `Account.TotalUpdatedFungibleAssets`.\n    [[#3680]]\n\n[#3680]: https://github.com/planetarium/libplanet/pull/3680\n\n\nVersion 4.0.5\n-------------\n\nReleased on February 20, 2024.\n\n -  (Libplanet.Action) Optimized `ActionEvaluation` by removing\n    redundant commits.  [[#3675]]\n\n[#3675]: https://github.com/planetarium/libplanet/pull/3675\n\n\nVersion 4.0.4\n-------------\n\nReleased on February 7, 2024.\n\n -  (Libplanet.Explorer) Revert a GraphQL query argument type change to make it\n    compatible with old schema.  [[#3663]]\n\n[#3663]: https://github.com/planetarium/libplanet/pull/3663\n\n\nVersion 4.0.3\n-------------\n\nReleased on February 6, 2024.\n\n -  (Libplanet.Explorer) Revert GraphQL types to make it more compatible\n    with old schema.  [[#3657]]\n     -  Rolled back `TxResultType`'s name to auto generated `TxResultType`\n        from specified `TxResult`.\n     -  Rolled back `BlockHash` and `TxId` to be handled as `IDGraphType`\n        instead of `BlockHashType` and `TxIdType` in legacy queries.\n     -  Rolled back `HashDigest<SHA256>` to be handled as `HashDigestSHA256Type`\n        instead of `HashDigestType<T>` in legacy queries.\n\n[#3657]: https://github.com/planetarium/libplanet/pull/3657\n\n\nVersion 4.0.2\n-------------\n\nReleased on February 6, 2024.\n\n -  (Libplanet.Net) Changed `AppProtocolVersion.FromToken()` to throw an\n    `Exception` with more details.  [[#3648]]\n -  (Libplanet.Explorer) Updated outdated GraphQL schema.  [[#3649]]\n\n[#3648]: https://github.com/planetarium/libplanet/pull/3648\n[#3649]: https://github.com/planetarium/libplanet/pull/3649\n\n\nVersion 4.0.1\n-------------\n\nReleased on January 26, 2024.\n\n -  (Libplanet.Action) Changed `IWorld.SetAccount()` to throw an\n    `ArgumentException` under certain undesirable circumstances.  [[#3633]]\n\n[#3633]: https://github.com/planetarium/libplanet/pull/3633\n\n\nVersion 4.0.0\n-------------\n\nReleased on January 22, 2024.\n\n### Backward-incompatible API changes\n\n -  Bumped `BlockMetadata.CurrentProtocolVersion` to 5.  [[#3524]]\n -  Removed `BlockChain.GetBalance(Address, Currency, Address)` method.\n    [[#3583]]\n -  Removed `BlockChain.GetTotalSupply(Currency, Address)` method.\n    [[#3583]]\n -  (Libplanet.Action) Changed `ActionEvaluator` to accept `IWorld`\n    instead of `IAccount`.  [[#3462]]\n -  (Libplanet.Action) `IActionEvaluation.OutputState` became `IWorld`.\n    (was `IAccount`)  [[#3462]]\n -  (Libplanet.Action) `IAction.Execute()` became to return `IWorld`.\n    (was `IAccount`)  [[#3462]]\n -  (Libplanet.Action) `IActionContext.PreviousState` became `IWorld`.\n    (was `IAccount`)  [[#3462]]\n -  (Libplanet.Action) Following methods in `IFeeCollector` interface\n    became to accept and return `IWorld`. (was `IAccount`)  [[#3462]]\n     -  `IFeeCollector.Mortgage()`\n     -  `IFeeCollector.Refund()`\n     -  `IFeeCollector.Reward()`\n -  (Libplanet.Action) `IBlockChainStates` interface has been overhauled.\n    [[#3462], [#3583]]\n     -  Added `IBlockChainStates.GetWorldState(BlockHash?)` method.\n     -  Added `IBlockChainStates.GetWorldState(HashDigest<SHA256>?)` method.\n     -  Removed `IBlockChainStates.GetAccountState(BlockHash?)` method.\n     -  Removed `IBlockChainStates.GetState(Address, BlockHash?)` method.\n     -  Removed\n        `IBlockChainStates.GetStates(IReadOnlyList<Address>, BlockHash?)`\n        method.\n     -  Removed\n        `IBlockChainStates.GetBalance(Address, Currency, BlockHash?)`\n        method.\n     -  Removed `IBlockChainStates.GetTotalSupply(Currency, BlockHash?)` method.\n     -  Removed `IBlockChainStates.GetValidatorSet(BlockHash?)` method.\n -  (@planetarium/tx)  Remove the `T` generic argument of `SignedTx<T>`.\n    [[#3512]]\n -  (Libplanet.Common) Removed `EnumerableExtensions` class.  [[#3625], [#3626]]\n\n### Added APIs\n\n -  Added `BlockMetadata.LegacyStateVersion` constant.  [[#3524]]\n -  (Libplanet.Action) Added `IWorld` interface and its implementation.\n    [[#3462]]\n     -  Added `World` class.\n -  (Libplanet.Action) Added `IWorldDelta` interface.  [[#3462]]\n -  (Libplanet.Action) Added `IWorldState` interface and its implementation.\n    [[#3462]]\n     -  Added `WorldBaseState` class.\n -  (Libplanet.Action) Added `ReservedAddresses` static class.  [[#3462]]\n -  (Libplanet.Store) Added `TrieMetadata` class.  [[#3540]]\n -  (Libplanet.Explorer) Added `AccountStateType` class.  [[#3462]]\n -  (Libplanet.Explorer) Added `WorldStateType` class.  [[#3462]]\n -  (Libplanet.Explorer) Added `StateQuery.world` field.  [[#3462]]\n -  (Libplanet.Explorer) Changed `account` and `accounts` query in\n    `StateQuery` to be compatible with `stateQuery.world`.  [[#3589]]\n\n[#3462]: https://github.com/planetarium/libplanet/pull/3462\n[#3494]: https://github.com/planetarium/libplanet/pull/3494\n[#3512]: https://github.com/planetarium/libplanet/pull/3512\n[#3524]: https://github.com/planetarium/libplanet/pull/3524\n[#3540]: https://github.com/planetarium/libplanet/pull/3540\n[#3583]: https://github.com/planetarium/libplanet/pull/3583\n[#3589]: https://github.com/planetarium/libplanet/pull/3589\n[#3625]: https://github.com/planetarium/libplanet/issues/3625\n[#3626]: https://github.com/planetarium/libplanet/pull/3626\n"
  },
  {
    "path": "changes/v5.md",
    "content": "Libplanet changelog\n===================\n\nVersion 5.5.0\n-------------\n\nReleased on January 15, 2025.\n\n### Backward-incompatible API changes\n\n -  Changed `IMessageCodec.Encode(MessageContent, PrivateKey,\n    AppProtocolVersion, BoundPeer, DateTimeOffset, byte[]?)` to\n    `IMessageCodec.Encode(Message, PrivateKey)`.  [[#3997]]\n -  (Libplanet.Explorer) Added `raw` field to `BlockType`.  [[#4006]]\n\n### Bug fixes\n\n -  Fixed a bug in `IStore.PruneOutdatedChains()`.  [[#3999]]\n\n\n[#3997]: https://github.com/planetarium/libplanet/pull/3997\n[#3999]: https://github.com/planetarium/libplanet/pull/3999\n[#4006]: https://github.com/planetarium/libplanet/pull/4006\n\n\nVersion 5.4.2\n-------------\n\nReleased on December 13, 2024.\n\n### Backward-incompatible API changes\n\n -  Removed `ContextTimeoutOption` class. Instead, added `ContextOption` class.\n    The unit of the time-related options in `ContextOption` is millisecond,\n    whereas `ContextTimeoutOption` was second.  [[#4007]]\n -  Removed `ConsensusReactorOption.ContextTimeoutOptions` property.\n    Instead, added `ConsensusReactorOption.ContextOption` property.  [[#4007]]\n -  `ConsensusReactor` constructor requires `ContextOption` parameter\n    instead of the `ContextTimeoutOption` parameter.  [[#4007]]\n\n### Behavioral changes\n\n -  `Gossip.RebuildTableAsync()` now bootstrap peers from the seed peers.\n    [[#4007]]\n\n[#4007]: https://github.com/planetarium/libplanet/pull/4007\n\n\nVersion 5.4.1\n-------------\n\nReleased on November 22, 2024.\n\n -  Ported changes from [Libplanet 5.3.2] release.  [[#3973]]\n\n[Libplanet 5.4.1]: https://www.nuget.org/packages/Libplanet/5.4.1\n\n\nVersion 5.4.0\n-------------\n\nReleased on November 13, 2024.\n\n### Backward-incompatible API changes\n\n -  (Libplanet.Action) Added `MaxGasPrice` property to `IActionContext`\n    interface and its implementations.  [[#3912]]\n -  (Libplanet.Explorer) Added `self` field to `NoteStateType`.  [[#3912]]\n -  (Libplanet.Action) Removed `IFeeCollector` interface\n    and its implementations.  [[#3912]]\n -  (Libplanet.Action) Removed following methods from the\n    `IActionContext` interface.  [[#3912]]\n     -  Removed `IActionContext.UseGas(long)`.\n     -  Removed `IActionContext.GasUsed()`.\n     -  Removed `IActionContext.GasLimit()`.\n -  (Libplanet.Action) Added `GasTracer` static class.  [[#3912]]\n -  (Libplanet.Action) Added `LastCommit` property to `IActionContext`\n    interface and its implementations.  [[#3912]]\n -  (Libplanet.Action) Added `CancelTrace` method to `GasTracer`.  [[#3974]]\n\n[#3912]: https://github.com/planetarium/libplanet/pull/3912\n[#3974]: https://github.com/planetarium/libplanet/pull/3974\n\n\nVersion 5.3.2\n-------------\n\nReleased on November 21, 2024\n\n -  There is no longer a check at block validation time to see\n    if the actions contained in a block are interpretable. [[#3973]]\n\n[#3973]: https://github.com/planetarium/libplanet/pull/3973\n\n\nVersion 5.3.1\n-------------\n\nReleased on October 14, 2024.\n\n### Dependencies\n\n -  (Libplanet.Extensions.Cocona) Changed *System.Text.Json* from [6.0.7] to\n    [6.0.*].  [[#3967]]\n -  Changed *BouncyCastle.Cryptography* from\n    [2.0.0] to [2.4.0].  [[#3968]]\n -  (Libplanet.Crypto) Changed *BouncyCastle.Cryptography* from\n    [2.0.0] to [2.4.0].  [[#3968]]\n\n\n[#3967]: https://github.com/planetarium/libplanet/pull/3967\n[#3968]: https://github.com/planetarium/libplanet/pull/3968\n\n\nVersion 5.3.0\n-------------\n\nReleased on October 10, 2024.\n\n### Backward-incompatible API changes\n\n -  Removed `threshold` parameter from `BlockChain.GetBlockLocator()`.\n    [[#3913]]\n -  (Libplanet.Net) Removed `SwarmOptions.BranchpointThreshold` property.\n    [[#3913]]\n -  (Libplanet.Store) Removed unused `HashNode.Serialize()` method.\n    [[#3922], [#3924]]\n -  (Libplanet.Net) Removed `Header` property and added `BlockExcerpt` property\n    to `BlockDemand`.  [[#3934]]\n -  Removed `BlockLocator.Create()`.  [[#3942]]\n -  Changed `BlockLocator()` to take a single `BlockHash`.  [[#3942]]\n -  Changed `BlockLocator()` to no longer implemnet `IEnumerable<BlockHash>`.\n    [[#3942]]\n -  (Libplanet.Net) Changed `BlockHashDownloadState` and `BlockDownloadState`\n    to be `Obsolete`.  [[#3943]]\n -  Removed `Fork()` method from `BlockChain`.  [[#3948]]\n -  Changed the return type for `BlockChain.FindNextHashes()`\n    to `IReadOnlyList<BlockHash>`.  [[#3949]]\n -  (Libplanet.Net) Changed `ActionExecutionState` and `BlockVerificationState`\n    to be `Obsolete`.  [[#3943]]\n -  (Libplanet.Action) Export `IPolicyActionsRegistry` interface\n    from `PolicyActionsRegistry`.  [[#3960]]\n\n### Backward-incompatible network protocol changes\n\n -  (Libplanet.Net) Changed the encoding for `GetBlockHashesMsg` and\n    `BlockHashesMsg`.  [[#3949]]\n\n### Behavioral changes\n\n -  Changed `BlockChain.FindBranchPoint()` to only check for the first\n    `BlockHash` in a given `BlockLocator`.  [[#3913]]\n -  (Libplanet.Store) Optimized `HashNode.ToBencodex()` method.\n    [[#3922], [#3924]]\n -  (Libplanet.Store) Optimized internal conversions to `KeyBytes`.  [[#3926]]\n -  (Libplanet.Net) Changed to no longer report `BlockHashDownloadState`\n    and `BlockDownloadState` during preloading.  It is strongly advised\n    not to rely on these to track the progress of preloading.  [[#3943]]\n -  (Libplanet.Store) Optimized LRU Cache for `HashNode` and `BlockSet`.\n    [[#3962]]\n\n[#3913]: https://github.com/planetarium/libplanet/pull/3913\n[#3922]: https://github.com/planetarium/libplanet/issues/3922\n[#3924]: https://github.com/planetarium/libplanet/pull/3924\n[#3926]: https://github.com/planetarium/libplanet/pull/3926\n[#3934]: https://github.com/planetarium/libplanet/pull/3934\n[#3942]: https://github.com/planetarium/libplanet/pull/3942\n[#3943]: https://github.com/planetarium/libplanet/pull/3943\n[#3948]: https://github.com/planetarium/libplanet/pull/3948\n[#3949]: https://github.com/planetarium/libplanet/pull/3949\n[#3950]: https://github.com/planetarium/libplanet/pull/3950\n[#3960]: https://github.com/planetarium/libplanet/pull/3960\n[#3962]: https://github.com/planetarium/libplanet/pull/3962\n\n\nVersion 5.2.2\n-------------\n\nReleased on August 8, 2024.\n\n - (Libplanet.Explorer) Fix an issue with high CPU usage\n   when querying blocks [[#3897]]\n\n[#3897]: https://github.com/planetarium/libplanet/pull/3897\n\n\nVersion 5.2.1\n-------------\n\nReleased on July 31, 2024.\n\n - Ported changes from [Libplanet 5.1.3] release.  [[#3902]]\n\n[#3902]: https://github.com/planetarium/libplanet/pull/3902\n[Libplanet 5.1.3]: https://www.nuget.org/packages/Libplanet/5.1.3\n\n\nVersion 5.2.0\n-------------\n\nReleased on July 23, 2024.\n\n### Backward-incompatible API changes\n\n -  Removed `IBlockPolicy.BlockAction` property.  [[#3701]]\n -  Added `IBlockPolicy.PolicyActionsRegistry` property.  [[#3701]]\n -  `BlockPolicy` constructor now requires `policyActionsRegistry`\n    parameter instead of the `blockAction` parameter.  [[#3701], [#3748]]\n -  (Libplanet.Action) Removed `PolicyBlockActionGetter` delegate.\n    [[#3701], [#3748]]\n -  (Libplanet.Action) `ActionEvaluator` constructor requires\n    `PolicyActionsRegistry` parameter instead of the\n    `policyBlockActionGetter` parameter.  [[#3701], [#3748]]\n -  (Libplanet.Action) Renamed `IActionContext.BlockAction` property to\n    `IActionContext.IsPolicyAction`.  [[#3764]]\n\n### Added APIs\n\n -  (Libplanet.Store) Added `MerkleTrie.GenerateProof()` method.  [[#3870]]\n -  (Libplanet.Store) Added `MerkleTrie.ValidateProof()` method.  [[#3870]]\n -  (Libplanet.Action) Added `PolicyActionsRegistry` class.  [[#3748]]\n\n[#3870]: https://github.com/planetarium/libplanet/pull/3870\n[#3701]: https://github.com/planetarium/libplanet/pull/3701\n[#3748]: https://github.com/planetarium/libplanet/pull/3748\n[#3764]: https://github.com/planetarium/libplanet/pull/3764\n\n\nVersion 5.1.3\n-------------\n\nReleased on July 30, 2024.\n\n -  (Libplanet.Explorer) Removed code that was used in development.  [[#3898]]\n\n[#3898]: https://github.com/planetarium/libplanet/pull/3898\n\n\nVersion 5.1.2\n-------------\n\nReleased on July 17, 2024.\n\n -  Fix an issue where currency does not work correctly in dotnet6.\n    [[#3880]]\n -  Fix an issue where evidence queries cause errors in the explorer. [[#3883]]\n\n[#3880]: https://github.com/planetarium/libplanet/pull/3880\n[#3883]: https://github.com/planetarium/libplanet/pull/3883\n\n\nVersion 5.1.1\n-------------\n\nReleased on July 15, 2024.\n\n -  Fixed an issue with the evidence hash changing depending on the version.\n    [[#3874]]\n\n[#3874]: https://github.com/planetarium/libplanet/pull/3874\n\n\nVersion 5.1.0\n-------------\n\nReleased on July 11, 2024.\n\n### Backward-incompatible API changes\n\n -  (Libplanet.Explorer) Added `ValidatorPower` field to `VoteType`.\n    [[#3737], [#3813]]\n -  (Libplanet.Types) Added `ValidatorPower` property to `IVoteMetadata`\n    interface and its implementations.  [[#3737], [#3813]]\n -  (Libplanet.Types) Added `IBlockMetadata.EvidenceHash` property and\n    the parameters required by the derived class's properties and constructors\n    have been added.\n    Affected classes are `Block`, `BlockContent`, `BlockHeader`,\n    `BlockMetadata`, `PreEvaluationBlockHeader`.  [[#3696]]\n -  (Libplanet.Types) Added `IBlockContent.Evidence` property and the\n    parameters required by the derived class's properties and constructors\n    have been added.\n    Affected classes are `Block`, `BlockContent`, `BlockHeader`,\n    `PreEvaluationBlock`.  [[#3696]]\n -  (Libplanet) Added `IBlockPolicy.GetMaxEvidencePendingDuration` method.\n    [[#3696]]\n\n### Added APIs\n\n -  (Libplanet.Types) Added `InvalidBlockEvidenceHashException` class.\n    [[#3696]]\n -  (Libplanet.Types) Added `InvalidBlockEvidencePendingDurationException`\n    class.  [[#3696]]\n -  (Libplanet.Types) Added `EvidenceBase` abstract class.  [[#3696]]\n -  (Libplanet.Types) Added `DuplicateVoteEvidence` class.  [[#3696]]\n -  (Libplanet.Types) Added `DuplicateVoteException` class.  [[#3696]]\n -  (Libplanet.Types) Added `EvidenceContext` class.  [[#3696]]\n -  (Libplanet.Types) Added `EvidenceException` class.  [[#3696]]\n -  (Libplanet.Types) Added `EvidenceId` class.  [[#3696]]\n -  (Libplanet.Types) Added `IEvidenceContext` class.  [[#3696]]\n -  (Libplanet.Types) Added `InvalidEvidenceException` class.  [[#3696]]\n -  (Libplanet.Net) Added `EvidenceCompletion` class.  [[#3696]]\n -  (Libplanet.Store) Added `IStore.IteratePendingEvidenceIds`. method.\n    [[#3696]]\n -  (Libplanet.Store) Added `IStore.GetPendingEvidence`. method.  [[#3696]]\n -  (Libplanet.Store) Added `IStore.GetCommittedEvidence`. method.  [[#3696]]\n -  (Libplanet.Store) Added `IStore.PutPendingEvidence`. method.  [[#3696]]\n -  (Libplanet.Store) Added `IStore.PutCommittedEvidence`. method.  [[#3696]]\n -  (Libplanet.Store) Added `IStore.DeletePendingEvidence`. method.  [[#3696]]\n -  (Libplanet.Store) Added `IStore.DeleteCommittedEvidence`. method.  [[#3696]]\n -  (Libplanet.Store) Added `IStore.ContainsPendingEvidence`. method.  [[#3696]]\n -  (Libplanet.Store) Added `IStore.ContainsCommittedEvidence`. method.\n    [[#3696]]\n -  (Libplanet) Added `BlockChain.GetPendingEvidence`. method.  [[#3696]]\n -  (Libplanet) Added `BlockChain.GetCommittedEvidence`. method.  [[#3696]]\n -  (Libplanet) Added `BlockChain.AddEvidence`. method.  [[#3696]]\n -  (Libplanet) Added `BlockChain.CommitEvidence`. method.  [[#3696]]\n -  (Libplanet) Added `BlockChain.IsEvidencePending`. method.  [[#3696]]\n -  (Libplanet) Added `BlockChain.IsEvidenceCommitted`. method.  [[#3696]]\n -  (Libplanet) Added `BlockChain.IsEvidenceExpired`. method.  [[#3696]]\n -  (Libplanet) Added `BlockChain.DeletePendingEvidence`. method.  [[#3696]]\n -  (Libplanet.Action) Added `IActionContext.Evidence`. property.  [[#3696]]\n -  (Libplanet.Net) Added `Swarm.BroadcastEvidence`. property.  [[#3696]]\n -  (Libplanet.Net) Added `Context.CollectEvidenceExceptions`. property.\n    [[#3696]]\n\n### Dependencies\n\nThe entire project is now defined by common properties in the\n`Directory.Build.props` file. The Directory.Build.props file is located at\nthe root and in the src, tools, test path.\n\nThe project structure and affected Directory.Build.props locations are shown\nbelow.\n\n```plain\n┌ Directory.Build.props\n├ src\n│  ├ Directory.Build.props\n│  ├ Libplanet\n│  ├ Libplanet.Action\n│  ├ Libplanet.Common\n│  ├ Libplanet.Crypto.Secp256k1\n│  ├ Libplanet.Crypto\n│  ├ Libplanet.Net\n│  ├ Libplanet.RocksDBStore\n│  ├ Libplanet.Store.Remote\n│  ├ Libplanet.Store\n│  ├ Libplanet.Stun\n│  └ Libplanet.Types\n├ test\n│  ├ Directory.Build.props\n│  ├ Libplanet.Action.Tests\n│  ├ Libplanet.Analyzers.Tests\n│  ├ Libplanet.Crypto.Secp256k1.Tests\n│  ├ Libplanet.Explorer.Cocona.Tests\n│  ├ Libplanet.Explorer.Tests\n│  ├ Libplanet.Extensions.Cocona.Tests\n│  ├ Libplanet.Mocks\n│  ├ Libplanet.Net.Tests\n│  ├ Libplanet.RocksDBStore.Tests\n│  ├ Libplanet.Store.Remote.Tests\n│  ├ Libplanet.Stun.Tests\n│  └ Libplanet.Tests\n└ tools\n   ├ Directory.Build.props\n   ├ Libplanet.Analyzers\n   ├ Libplanet.Benchmarks\n   ├ Libplanet.Explorer.Cocona\n   ├ Libplanet.Explorer.Executable\n   ├ Libplanet.Explorer\n   ├ Libplanet.Extensions.Cocona\n   └ Libplanet.Tools\n```\n\nThe default SDK version for the project has been bumped up to .NET 6.0.\nThe list of supported SDKs is as follows\n - netstandard2.0\n - netstandard2.1\n - netcoreapp3.1\n - net6.0\"\n\n> Support for `netstandard2.0` is coming to an end soon, please note that\nprojects using `netstandard2.0` will be deprecated.\n\nThe `VersionPrefix` property has been moved from the\n*src/Libplanet/Libplanet.csproj* file to the `Directory.Build.props` file.\n\n[#3696]: https://github.com/planetarium/libplanet/pull/3696\n[#3737]: https://github.com/planetarium/libplanet/pull/3737\n[#3813]: https://github.com/planetarium/libplanet/pull/3813\n\n\nVersion 5.0.0\n-------------\n\nReleased on July 2, 2024.\n\n### Deprecated APIs\n\n -  `BlockChain.DetermineGenesisStateRootHash()` has been removed.  [[#3811]]\n -  `BlockChain.EvaluateGenesis()` has been removed.  [[#3811]]\n -  `BlockChain.DetermineBlockStateRootHash()` has been removed.\n    [[#3811]]\n\n### Backward-incompatible API changes\n\n -  (Libplanet.Action) `IBlockChainStates.GetWorldState(BlockHash?)`\n    does not accept null parameter any more.  [[#3811]]\n -  Bumped `BlockMetadata.CurrentProtocolVersion` to 8.  [[#3811]]\n -  `BlockChain.EvaluateBlock()` accepts `Block`\n    instead of `IPreEvaluationBlock`.  [[#3811]]\n -  `BlockChain.ProposeGenesisBlock()` receives parameter\n    `HashDigest<SHA256>? stateRootHash`.  [[#3811]]\n -  `BlockChain.ProposeGenesisBlock()` does not receive\n    parameter `IActionEvaluator actionEvaluator` any more.  [[#3811]]\n -  `BlockChain.ProposeBlock()` receives parameter\n    `HashDigest<SHA256> stateRootHash`.  [[#3811]]\n -  (Libplanet.Net) Changed `Context()` to accept additional `BlockCommit?`\n    typed argument.  Removed `lastCommit` parameter from `Context.Start()`.\n    [[#3833], [#3845]]\n -  (Libplanet.Net) Changed `Context.Start()` to throw an\n    `InvalidOperationException` when `Context` is not in a valid state.\n    [[#3846]]\n -  (Libplanet.Net) Removed `IConsensusMessageCommunicator` parameter from\n    `Context()`.  [[#3848], [#3849]]\n -  (Libplanet.Net) Added `Running` property to `ConsensusContext`.  [[#3851]]\n -  (Libplanet.Net) Added `Start()` method to `ConsensusContext`.  [[#3851]]\n -  (Libplanet.Net) Changed `NewHeight()` to throw a `NullReferenceException`\n    if it is called while its internal `BlockChain` is in an invalid state.\n    [[#3851]]\n -  (Libplanet.Net) Removed `Null` value from `ConsensusStep` enum.  [[#3851]]\n\n### Added APIs\n\n -  Added `BlockChain.DetermineNextBlockStateRootHash()` method.  [[#3811]]\n\n### Behavioral changes\n\n -  `Context.ProcessHeightOrRoundUponRules()` now appends block asynchronously,\n    as a manner of fire-and-forget.  [[#3808]]\n -  `BlockHeader.StateRootHash` now means state root hash calculated by\n    `BlockChain.DetermineNextBlockStateRootHash(previousBlockHash)`.\n    [[#3811]]\n\n[#3808]: https://github.com/planetarium/libplanet/pull/3808\n[#3811]: https://github.com/planetarium/libplanet/pull/3811\n[#3833]: https://github.com/planetarium/libplanet/issues/3833\n[#3845]: https://github.com/planetarium/libplanet/pull/3845\n[#3846]: https://github.com/planetarium/libplanet/pull/3846\n[#3848]: https://github.com/planetarium/libplanet/issues/3848\n[#3849]: https://github.com/planetarium/libplanet/issues/3849\n[#3851]: https://github.com/planetarium/libplanet/pull/3851\n"
  },
  {
    "path": "codecov.yml",
    "content": "coverage:\n  range: 70..95\n  status:\n    project:\n      default:\n        target: auto\n        threshold: 1\n        base: auto\n\nparsers:\n  gcov:\n    branch_detection:\n      conditional: yes\n      loop: yes\n      method: no\n      macro: no\n\ncomment:\n  require_changes: true\n  layout: \"diff, files\"\n\nignore:\n  - \"*Tests/*\"\n  - \"*Tests/**/*\"\n  - \"*Benchmarks/*\"\n  - \"*Benchmarks/**/*\"\n"
  },
  {
    "path": "global.json",
    "content": "{\n  \"sdk\": {\n    \"version\": \"8.0.0\",\n    \"rollForward\": \"minor\"\n  }\n}\n"
  },
  {
    "path": "hooks/check-bom",
    "content": "#!/bin/bash\nset -e\n\nlist_bom_files() {\n  git grep -lI $'\\xEF\\xBB\\xBF' . | grep -Ev '.sln$'\n}\n\ncheck_bom() {\n  if list_bom_files > /dev/null; then\n    {\n      echo \"The following files have BOM:\"\n      list_bom_files | awk '{ print \"  \" $0 }'\n      echo \"You can trim these BOMs by the below command:\"\n      echo \"  $0 --apply\"\n    } > /dev/stderr\n    exit 1\n  fi\n}\n\ntrim_bom() {\n  if list_bom_files > /dev/null; then\n    {\n      echo \"Trimming BOM from the following files:\"\n      list_bom_files | awk '{ print \"  \" $0 }'\n    } > /dev/stderr\n\n    temp_file=\"$(mktemp)\"\n    list_bom_files | \\\n      while IFS= read -r filename; do\n        sed '1s/^\\xEF\\xBB\\xBF//' \"$filename\" > \"$temp_file\"\n        cat \"$temp_file\" > \"$filename\"\n      done\n  else\n    exit 1\n  fi\n}\n\nif [[ \"$1\" = \"-a\" || \"$1\" = \"--apply\" ]]; then\n  trim_bom\nelse\n  check_bom\nfi\n\n# vim: set filetype=sh ts=2 sw=2 et:\n"
  },
  {
    "path": "hooks/check-changelog",
    "content": "#!/bin/bash\nset -e\n\nLANG=en_US.UTF8\nFILE_PATH=CHANGES.md\n\nduplicated_links() {\n  grep -E '^\\[[^]\\n]+\\]: ' \"$1\" \\\n  | awk 'BEGIN {FS = \": \"}; {print $1}' \\\n  | sort \\\n  | uniq -d\n}\n\nif [[ \"$(duplicated_links \"$FILE_PATH\")\" != \"\" ]]; then\n  if [[ -t 2 ]]; then\n    color=always\n  else\n    color=never\n  fi\n  {\n    echo \"CHANGES.md contains duplicated link definitions:\"\n    duplicated_links \"$FILE_PATH\" | while read -r link; do\n      grep --color=\"$color\" -nF \"$link\" \"$FILE_PATH\"\n    done | sed -e 's/^/  /'\n  } > /dev/stderr\n  exit 1\nfi\n\nreached=\nline_no=1\nwhile IFS= read -r line; do\n  line=\"${line%$'\\r'}\"\n  if [[ ${#line} -gt 80 &&\n        \"$(echo -n \"$line\" | LANG=en_US.UTF-8 wc -m)\" -gt 80 &&\n        $line != *https://* &&\n        $line != *http://* ]]; then\n    if [[ \"$reached\" != \"1\" ]]; then\n      echo 'LINE#   CONTENT'\n    fi\n    printf '%5d   %s\\n' \"$line_no\" \"$line\"\n    reached=1\n  fi\n  ((line_no++))\ndone < \"$FILE_PATH\" > /dev/stderr\nif [[ \"$reached\" = \"1\" ]]; then\n  exit 1\nfi\n"
  },
  {
    "path": "hooks/check-projects",
    "content": "#!/bin/bash\nset -e\n\nSOLUTION=\"$(dirname \"$0\")/../Libplanet.sln\"\n\nif ! [[ -f \"$SOLUTION\" ]]; then\n  echo \"No such solution file: $SOLUTION\" > /dev/stderr\n  exit 1\nfi\n\nlist-projects() {\n  dotnet sln \"$SOLUTION\" list | grep -E $'(src|tools|\"sdk\\/node\"|test).+\\\\...proj\\r?$' | sed 's/[/][^/]*$//'\n}\n\n# shellcheck source=.github/bin/constants.sh\n. \"$(dirname \"$0\")/../.github/bin/constants.sh\"\nprojects_index=\" ${projects[*]} \"\n\ncheck-github-actions() {\n  # shellcheck disable=SC2076\n  if [[ ! \"$projects_index\" =~ \" $1 \" ]]; then\n    echo \"The project $1 is missing from the projects constant in the \" \\\n      \".github/bin/constants.sh file.\" > /dev/stderr\n    exit 1\n  fi\n}\n\ncheck-contributing() {\n  name=$(echo \"$1\" | sed -re 's/(src|tools|\"sdk\\/node\"|test)\\///')\n  if ! grep -E \"^ -  \\*$name\\*: \" CONTRIBUTING.md > /dev/null; then\n    echo \"The project $1 is not documented in the CONTRIBUTING.md file.\" \\\n      > /dev/stderr\n    exit 1\n  fi\n}\n\ncheck-docfx() {\n  if ! grep \"$1\" Docs/docfx.json > /dev/null; then\n    echo \"The project $1 is not listed in the Docs/docfx.json file.\" \\\n      > /dev/stderr\n    exit 1\n  fi\n}\n\nfor project in $(list-projects); do\n  if ! [[ \"$project\" = *.Tests || \"$project\" = *.UnitTests \\\n       || \"$project\" = *.Benchmarks ]]; then\n    check-github-actions \"$project\" || exit 1\n    if [[ \"$project\" != *.Executable ]]; then\n      check-docfx \"$project\" || exit 1\n    fi\n  fi\n  check-contributing \"$project\" || exit 1\ndone\n\n# vim: set filetype=sh ts=2 sw=2 et:\n"
  },
  {
    "path": "hooks/commit-msg",
    "content": "#!/bin/bash\nset -e\n\nversion_regex='[Rr]elease ([0-9]+\\.[0-9]+\\.[0-9]+)'\nif [[ \"$(head -n1 \"$1\")\" =~ $version_regex ]]; then\n  version=\"${BASH_REMATCH[1]}\"\n  \"$(dirname \"$0\")/validate-release\" \"$version\"\nfi\n\n# vim: set filetype=sh ts=2 sw=2 et:\n"
  },
  {
    "path": "hooks/pre-commit",
    "content": "#!/bin/bash\nset -e\n\n\"$(dirname \"$0\")/check-bom\"\n\"$(dirname \"$0\")/check-changelog\"\n\"$(dirname \"$0\")/check-projects\"\n\nif command -v yarn --help > /dev/null; then\n  if [[ \"$CI\" = \"true\" ]]; then\n    yarn --immutable\n  else\n    yarn --silent\n  fi\n\n  # FIXME: The following workaround should be removed when Rome fixes their bug\n  # which fails to resolve symlinks referring to the parent directory.\n  rm -f @planetarium/cli\n  trap \"ln -sf ../tools/Libplanet.Tools @planetarium/cli\" EXIT\n  yarn rome check .\nelse\n  echo warn: yarn is not available\\; not running commands pertaining to node.js. >&2\n  exit 0\nfi\n\n# vim: set filetype=sh ts=2 sw=2 et:\n"
  },
  {
    "path": "hooks/validate-release",
    "content": "#!/bin/bash\nset -e\n\nroot=\"$(dirname \"$0\")/..\"\nif command -v realpath > /dev/null; then\n  root=\"$(realpath \"$root\")\"\nfi\n\nif [[ \"$#\" -lt \"1\" ]]; then\n  {\n    echo \"$0: error: missing version number\"\n    echo \"usage: $0 VERSION\"\n  } > /dev/stderr\n  exit 1\nfi\n\nversion=\"$1\"\n\nif [[ \"$version\" = *-* ]]; then\n  {\n    echo \"$0: error: the version number must not end with any suffix:\"\n    echo \"  $version\"\n  } > /dev/stderr\n  exit 1\nfi\n\ncsproj=\"$root/src/Libplanet/Libplanet.csproj\"\nif command -v xmllint > /dev/null; then\n  csproj_version=\"$(xmllint \\\n    --xpath '/*[local-name()=\"Project\"]\n             /*[local-name()=\"PropertyGroup\"]\n             /*[local-name()=\"VersionPrefix\"]\n             /text()' \\\n    \"$csproj\")\"\nelse\n  regex='<VersionPrefix>([0-9]+\\.[0-9]+\\.[0-9]+)</VersionPrefix>'\n  if [[ \"$(grep '<VersionPrefix>[^>]*</VersionPrefix>' \"$csproj\")\" =~ $regex ]]\n  then\n    csproj_version=\"${BASH_REMATCH[1]}\"\n  else\n    echo \"$0: error: failed to find <VersionPrefix> tag from $csproj file\" \\\n      > /dev/stderr\n    exit 1\n  fi\nfi\n\nif [[ \"$csproj_version\" != \"$version\" ]]; then\n  {\n    echo \"$0: error: the version numbers must match\"\n    echo \"  $version (tag)\"\n    echo \"  $csproj_version ($csproj)\"\n  } > /dev/stderr\n  exit 1\nfi\n\nif grep -i 'to be released' \"$root/CHANGES.md\" > /dev/stderr; then\n  echo \"$0: error: $root/CHANGES.md file must not contain unreleased notes.\" \\\n    > /dev/stderr\n  exit 1\nfi\n\n# vim: set filetype=sh ts=2 sw=2 et:\n"
  },
  {
    "path": "package.json",
    "content": "{\n  \"packageManager\": \"yarn@4.0.1\",\n  \"private\": true,\n  \"workspaces\": [\n    \"@planetarium/account\",\n    \"@planetarium/account-aws-kms\",\n    \"@planetarium/account-web3-secret-storage\",\n    \"@planetarium/tx\",\n    \"tools/Libplanet.Tools\"\n  ],\n  \"scripts\": {\n    \"build\": \"printf \\\"\\\\033[41;97mLibplanet note: currently, it is expected for `yarn build` to fail on the first run and succeed on the second run due to an unknown issue unrelated to the codebase (see issue #3492,) so the build phase runs twice. Whenever the culprit is specified please remove this message and the duplicate call.\\\\033[0m\\n\\\" >&2 && _libplanet_build=1 yarn workspaces foreach -p -A run build || _libplanet_build=1 yarn workspaces foreach -p -A run build\",\n    \"pack-all\": \"yarn workspaces foreach -p -A --include @planetarium/\\\\* pack\",\n    \"postinstall\": \"env | grep -E '^_libplanet_build=1$' || yarn build && echo ran yarn build\",\n    \"prepack\": \"printf \\\"\\\\033[41;97mLibplanet note: `yarn pack` is not allowed on the project root level, as it produces useless empty package. use `yarn pack-all` instead.\\\\033[0m\\n\\\" > /dev/stderr && false\",\n    \"test\": \"yarn workspaces foreach -p -A run test\"\n  },\n  \"devDependencies\": {\n    \"@vitest/coverage-c8\": \"^0.29.2\",\n    \"nanobundle\": \"^1.6.0\",\n    \"node-fetch\": \"^3.1.1\",\n    \"rome\": \"^11.0.0\",\n    \"typescript\": \"^4.5.0\",\n    \"unzipper\": \"^0.10.11\",\n    \"vitest\": \"^0.29.2\"\n  },\n  \"files\": []\n}\n"
  },
  {
    "path": "rome.json",
    "content": "{\n  \"$schema\": \"https://github.com/rome/tools/raw/cli/v11.0.0/npm/rome/configuration_schema.json\",\n  \"files\": {\n    \"ignore\": [\n      \"./Libplanet/**/*\",\n      \"./Libplanet.*/**/*\",\n      \"./@planetarium/*/dist/**/*\",\n      \"./@planetarium/*/coverage/**/*\",\n      \"./.pnp.*\",\n      \"./**/*/crypto/**/*\"\n    ]\n  },\n  \"linter\": {\n    \"enabled\": true,\n    \"rules\": {\n      \"recommended\": true,\n      \"style\": {\n        \"recommended\": true,\n        \"useTemplate\": \"off\"\n      },\n      \"correctness\": {\n        \"recommended\": true,\n        \"noUnnecessaryContinue\": \"off\"\n      }\n    }\n  },\n  \"formatter\": {\n    \"enabled\": false,\n    \"indentStyle\": \"space\"\n  }\n}\n"
  },
  {
    "path": "scripts/.editorconfig",
    "content": "[*.js]\nend_of_line = lf\ninsert_final_newline = true\nindent_style = space\nindent_size = 2\nmax_line_length = 80\n"
  },
  {
    "path": "scripts/determine-version.js",
    "content": "#!/usr/bin/env node\n// This script is used to determine the version of the current build.\n// Intended to be run on CI, but can be run locally as well.\nconst fs = require(\"node:fs\").promises;\nconst path = require(\"node:path\");\nconst util = require(\"node:util\");\nconst execFile = util.promisify(require(\"node:child_process\").execFile);\n\nasync function readVersionPrefix(xmlFile) {\n  // TODO: Use proper XML parser...\n  const xml = await fs.readFile(xmlFile, \"utf8\");\n  const pattern = /<VersionPrefix>([0-9]+\\.[0-9]+\\.[0-9]+)<\\/VersionPrefix>/g;\n  const match = pattern.exec(xml);\n  if (!match) {\n    throw new Error(`Could not determine version prefix from ${xmlFile}`);\n  }\n  return match[1];\n}\n\nasync function getCommitHash() {\n  if (process.env.GITHUB_SHA) {\n    return process.env.GITHUB_SHA;\n  }\n  const { stdout } = await execFile(\"git\", [\"rev-parse\", \"HEAD\"]);\n  return stdout.trim();\n}\n\nasync function getCommitTimestamp() {\n  let timestamp;\n  if (process.env.GITHUB_EVENT_PATH) {\n    const event = JSON.parse(await fs.readFile(process.env.GITHUB_EVENT_PATH));\n    timestamp = event.head_commit.timestamp;\n  }\n  const { stdout } = await execFile(\"git\", [\n    \"show\",\n    \"--no-patch\",\n    \"--format=%cI\",\n    \"HEAD\",\n  ]);\n  timestamp = stdout.trim();\n  if (timestamp) return new Date(timestamp);\n  return new Date();\n}\n\nasync function getTag() {\n  if (process.env.GITHUB_REF_TYPE === \"branch\") return null;\n  if (process.env.GITHUB_REF_TYPE === \"tag\" && process.env.GITHUB_REF_NAME) {\n    return process.env.GITHUB_REF_NAME;\n  }\n  try {\n    const { stdout } = await execFile(\"git\", [\n      \"describe\",\n      \"--exact-match\",\n      \"--tags\",\n      \"HEAD\",\n    ]);\n  } catch (e) {\n    return null;\n  }\n  const tag = stdout.trim();\n  if (tag) return tag;\n  return null;\n}\n\nfunction getScheduledJobDate() {\n  if (process.env.GITHUB_EVENT_NAME?.startsWith(\"schedule\")) {\n    // TODO: Read the date from the event payload for determinism.\n    const now = new Date();\n    return `${now.getUTCFullYear()}${\n      now.getUTCMonth() + 1\n    }${now.getUTCDate()}}`;\n  }\n  return null;\n}\n\nasync function main() {\n  const csprojPath = path.join(\n    path.dirname(__dirname),\n    \"Directory.Build.props\",\n  );\n  const versionPrefix = await readVersionPrefix(csprojPath);\n  const scheduledJobDate = getScheduledJobDate();\n  const tag = await getTag();\n  const commitHash = (await getCommitHash()).substring(0, 7);\n  let packageVersion;\n  let versionSuffix;\n  let versionType;\n  if (scheduledJobDate != null) {\n    // Nightly\n    versionSuffix = `nightly.${scheduledJobDate}`;\n    packageVersion = `${versionPrefix}-${versionSuffix}`;\n    versionSuffix += `+${commitHash}`;\n    versionType = \"nightly\";\n  } else if (tag != null) {\n    // Tagged\n    if (tag === versionPrefix) {\n      // Release\n      packageVersion = tag;\n      versionType = \"stable\";\n    } else if (tag.startsWith(versionPrefix)) {\n      // Prerelease\n      packageVersion = tag;\n      delimIndex = tag.indexOf(\"-\");\n      versionSuffix = tag.substring(delimIndex + 1);\n      versionType = \"prerelease\";\n      if (delimIndex < 0 || !versionSuffix) {\n        console.error(\n          `Git tag (${tag}) is not in a proper format for prerelease`,\n        );\n        process.exit(1);\n      }\n    } else {\n      console.error(\n        `Git tag (${tag}) does not contain VersionPrefix (${versionPrefix})`,\n      );\n      process.exit(1);\n    }\n  } else {\n    // Dev\n    const timestamp = await getCommitTimestamp();\n    const ts =\n      timestamp.getUTCFullYear().toString() +\n      (timestamp.getUTCMonth() + 1).toString().padStart(2, \"0\") +\n      timestamp.getUTCDate().toString().padStart(2, \"0\") +\n      timestamp.getUTCHours().toString().padStart(2, \"0\") +\n      timestamp.getUTCMinutes().toString().padStart(2, \"0\") +\n      timestamp.getUTCSeconds().toString().padStart(2, \"0\");\n    versionSuffix = `dev.${ts}`;\n    packageVersion = `${versionPrefix}-${versionSuffix}`;\n    versionSuffix += `+${commitHash}`;\n    versionType = \"dev\";\n  }\n  console.error(\"VersionPrefix:\", versionPrefix);\n  if (versionSuffix) console.error(\"VersionSuffix:\", versionSuffix);\n  console.error(\"PackageVersion:\", packageVersion);\n  console.error(\"VersionType:\", versionType);\n  if (process.env.GITHUB_OUTPUT) {\n    // https://docs.github.com/en/actions/using-workflows/workflow-commands-for-github-actions#environment-files\n    await fs.appendFile(\n      process.env.GITHUB_OUTPUT,\n      `version-prefix=${versionPrefix}\\n`,\n    );\n    if (versionSuffix)\n      await fs.appendFile(\n        process.env.GITHUB_OUTPUT,\n        `version-suffix=${versionSuffix}\\n`,\n      );\n    await fs.appendFile(\n      process.env.GITHUB_OUTPUT,\n      `package-version=${packageVersion}\\n`,\n    );\n    await fs.appendFile(\n      process.env.GITHUB_OUTPUT,\n      `version-type=${versionType}\\n`,\n    );\n  }\n}\n\nmain();\n"
  },
  {
    "path": "sdk/.editorconfig",
    "content": "[*.proto]\nindent_size = 2\n\n[*.cs]\n\n# S3903: Types should be defined in named namespaces\ndotnet_diagnostic.S3903.severity = none\n\n# IDE0008: Use explicit type\ndotnet_diagnostic.IDE0008.severity = none\n\n# MEN016: Avoid top-level statements\ndotnet_diagnostic.MEN016.severity = none\n\n[**/obj/**/*.cs]\n\n# CS8981: The type name only contains lower-cased ascii characters\ndotnet_diagnostic.CS8981.severity = none\n\n"
  },
  {
    "path": "sdk/Directory.Build.props",
    "content": "<Project>\n\n  <Import Project=\"$([MSBuild]::GetPathOfFileAbove('Directory.Build.props', '$(MSBuildThisFileDirectory)../'))\" />\n\n  <PropertyGroup>\n    <TargetFrameworks Condition=\"'$(_IsPacking)'=='true'\">net8.0</TargetFrameworks>\n    <TargetFramework Condition=\"'$(_IsPacking)'!='true'\">net8.0</TargetFramework>\n    <LangVersion>12</LangVersion>\n    <IsPackable>true</IsPackable>\n    <IsTestProject>false</IsTestProject>\n    <Title>$(ProjectName)</Title>\n    <ImplicitUsings>enable</ImplicitUsings>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <PackageReference Remove=\"StyleCop.Analyzers\" />\n    <PackageReference Remove=\"Menees.Analyzers.2017\" />\n    <PackageReference Remove=\"Microsoft.DotNet.Analyzers.Compatibility\" />\n    <PackageReference Remove=\"SonarAnalyzer.CSharp\" />\n\n    <AdditionalFiles Remove=\"stylecop.json\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <PackageReference Include=\"StyleCop.Analyzers\" Version=\"1.2.0-beta.556\">\n      <PrivateAssets>all</PrivateAssets>\n      <IncludeAssets>\n        runtime; build; native; contentfiles; analyzers\n      </IncludeAssets>\n    </PackageReference>\n    <PackageReference Include=\"Menees.Analyzers\" Version=\"3.2.2\">\n      <PrivateAssets>all</PrivateAssets>\n      <IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>\n    </PackageReference>\n    <PackageReference Include=\"SonarAnalyzer.CSharp\" Version=\"9.27.0.93347\">\n      <PrivateAssets>all</PrivateAssets>\n      <IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>\n    </PackageReference>\n\n    <AdditionalFiles Include=\"$(MSBuildThisFileDirectory)stylecop.json\" />\n  </ItemGroup>\n\n</Project>\n"
  },
  {
    "path": "sdk/node/Libplanet.Node/Actions/PluginLoadContext.cs",
    "content": "using System.Reflection;\nusing System.Runtime.Loader;\n\nnamespace Libplanet.Node.Actions;\n\ninternal sealed class PluginLoadContext(string pluginPath) : AssemblyLoadContext\n{\n    private readonly AssemblyDependencyResolver _resolver = new(pluginPath);\n\n    protected override Assembly? Load(AssemblyName assemblyName)\n    {\n        var assemblyPath = _resolver.ResolveAssemblyToPath(assemblyName);\n        if (assemblyPath is not null)\n        {\n            return LoadFromAssemblyPath(assemblyPath);\n        }\n\n        return null;\n    }\n\n    protected override IntPtr LoadUnmanagedDll(string unmanagedDllName)\n    {\n        var libraryPath = _resolver.ResolveUnmanagedDllToPath(unmanagedDllName);\n        if (libraryPath is not null)\n        {\n            return LoadUnmanagedDllFromPath(libraryPath);\n        }\n\n        return IntPtr.Zero;\n    }\n}\n"
  },
  {
    "path": "sdk/node/Libplanet.Node/Actions/PluginLoader.cs",
    "content": "using System.Diagnostics.CodeAnalysis;\nusing System.Reflection;\nusing System.Runtime.Loader;\nusing Libplanet.Action;\nusing Libplanet.Action.Loader;\n\nnamespace Libplanet.Node.Actions;\n\ninternal static class PluginLoader\n{\n    public static IActionLoader LoadActionLoader(string modulePath, string typeName)\n    {\n        var assembly = LoadAssembly(modulePath);\n        return Create<IActionLoader>(assembly, typeName);\n    }\n\n    public static IPolicyActionsRegistry LoadPolicyActionRegistry(\n        string relativePath, string typeName)\n    {\n        var assembly = LoadAssembly(relativePath);\n        return Create<IPolicyActionsRegistry>(assembly, typeName);\n    }\n\n    private static T Create<T>(Assembly assembly, string typeName)\n        where T : class\n    {\n        if (assembly.GetType(typeName) is not { } type)\n        {\n            throw new ApplicationException(\n                $\"Can't find {typeName} in {assembly} from {assembly.Location}\");\n        }\n\n        if (Activator.CreateInstance(type) is not T obj)\n        {\n            throw new ApplicationException(\n                $\"Can't create an instance of {type} in {assembly} from {assembly.Location}\");\n        }\n\n        return obj;\n    }\n\n    private static bool TryGetLoadedAssembly(\n        string modulePath, [MaybeNullWhen(false)] out Assembly assembly)\n    {\n        var loadedAssemblies = AssemblyLoadContext.All\n            .SelectMany(context => context.Assemblies)\n            .ToList();\n        var comparison = StringComparison.OrdinalIgnoreCase;\n        var comparer = new Predicate<Assembly>(\n            assembly => string.Equals(assembly.Location, modulePath, comparison));\n\n        if (loadedAssemblies.Find(comparer) is Assembly loadedAssembly)\n        {\n            assembly = loadedAssembly;\n            return true;\n        }\n\n        assembly = null;\n        return false;\n    }\n\n    private static Assembly LoadAssembly(string modulePath)\n    {\n        if (TryGetLoadedAssembly(modulePath, out var assembly))\n        {\n            return assembly;\n        }\n\n        var loadContext = new PluginLoadContext(modulePath);\n        if (File.Exists(modulePath))\n        {\n            return loadContext.LoadFromAssemblyPath(modulePath);\n        }\n\n        if (Path.GetFileNameWithoutExtension(modulePath) is { } filename)\n        {\n            return loadContext.LoadFromAssemblyName(new AssemblyName(filename));\n        }\n\n        throw new ApplicationException($\"Can't load plugin from {modulePath}\");\n    }\n}\n"
  },
  {
    "path": "sdk/node/Libplanet.Node/AssemblyInfo.cs",
    "content": "using System.Runtime.CompilerServices;\n\n[assembly: InternalsVisibleTo(\"Libplanet.Node.Extensions\")]\n[assembly: InternalsVisibleTo(\"Libplanet.Node.Tests\")]\n"
  },
  {
    "path": "sdk/node/Libplanet.Node/DataAnnotations/AddressAttribute.cs",
    "content": "#pragma warning disable SA1402 // File may only contain a single type\nusing System.ComponentModel.DataAnnotations;\n\nnamespace Libplanet.Node.DataAnnotations;\n\n[AttributeUsage(AttributeTargets.Property)]\npublic sealed class AddressAttribute : RegularExpressionAttribute\n{\n    public const string OriginPattern = \"0x[0-9a-fA-F]{40}\";\n\n    public AddressAttribute()\n        : base($\"^{OriginPattern}$\")\n    {\n    }\n}\n\n[AttributeUsage(AttributeTargets.Property)]\npublic sealed class AddressArrayAttribute : ArrayAttribute<AddressAttribute>\n{\n}\n"
  },
  {
    "path": "sdk/node/Libplanet.Node/DataAnnotations/AppProtocolVersionAttribute.cs",
    "content": "#pragma warning disable SA1402 // File may only contain a single type\nusing System.ComponentModel.DataAnnotations;\n\nnamespace Libplanet.Node.DataAnnotations;\n\n[AttributeUsage(AttributeTargets.Property)]\npublic sealed class AppProtocolVersionAttribute : RegularExpressionAttribute\n{\n    public const string VersionPattern = @\"\\d+\";\n    public const string AddressPattern = @\"[0-9a-fA-F]{40}\";\n    public const string Base64Pattern\n        = @\"(?:[A-Za-z0-9+\\.]{4})*(?:[A-Za-z0-9+\\.]{2}==|[A-Za-z0-9+\\.]{3}=)?\";\n\n    public static readonly string OriginPattern = GenerateOriginPattern();\n\n    public AppProtocolVersionAttribute()\n        : base($\"^{OriginPattern}$\")\n    {\n    }\n\n    private static string GenerateOriginPattern()\n    {\n        var items = new string[]\n        {\n            $\"(?<version>{VersionPattern})\",\n            $\"(?<address>{AddressPattern})\",\n            $\"(?<signature>{Base64Pattern})\",\n            $\"(?<extra>{Base64Pattern})\",\n        };\n\n        return string.Join('/', items);\n    }\n}\n"
  },
  {
    "path": "sdk/node/Libplanet.Node/DataAnnotations/ArrayAttribute.cs",
    "content": "#pragma warning disable SA1402 // File may only contain a single type\nusing System.Collections;\nusing System.ComponentModel.DataAnnotations;\nusing System.Diagnostics;\n\nnamespace Libplanet.Node.DataAnnotations;\n\n[AttributeUsage(AttributeTargets.Property)]\npublic class ArrayAttribute(Type validationType, params object?[] values) : ValidationAttribute\n{\n    private readonly object?[] _values = values;\n\n    public ArrayAttribute(Type validationAttributeType)\n        : this(validationAttributeType, [])\n    {\n    }\n\n    public Type ValidationType { get; } = validationType;\n\n    internal ValidationAttribute CreateAttribute()\n    {\n        if (!ValidationType.IsSubclassOf(typeof(ValidationAttribute)))\n        {\n            throw new InvalidOperationException(\n                \"ValidationType must be a subclass of ValidationAttribute.\");\n        }\n\n        var args = _values;\n        if (Activator.CreateInstance(ValidationType, args) is ValidationAttribute validation)\n        {\n            return validation;\n        }\n\n        throw new UnreachableException(\"Activator.CreateInstance should not return null.\");\n    }\n\n    protected override ValidationResult? IsValid(object? value, ValidationContext validationContext)\n    {\n        var validation = CreateAttribute();\n        if (value is IEnumerable array)\n        {\n            foreach (var item in array)\n            {\n                if (!validation.IsValid(item))\n                {\n                    return new ValidationResult(validation.ErrorMessage);\n                }\n            }\n        }\n\n        return ValidationResult.Success;\n    }\n}\n\npublic class ArrayAttribute<T> : ArrayAttribute\n    where T : Attribute\n{\n    public ArrayAttribute()\n        : base(typeof(T))\n    {\n    }\n\n    public ArrayAttribute(object value)\n        : base(typeof(T), value)\n    {\n    }\n}\n"
  },
  {
    "path": "sdk/node/Libplanet.Node/DataAnnotations/BoundPeerAttribute.cs",
    "content": "#pragma warning disable SA1402 // File may only contain a single type\nusing System.ComponentModel.DataAnnotations;\n\nnamespace Libplanet.Node.DataAnnotations;\n\n[AttributeUsage(AttributeTargets.Property)]\npublic sealed class BoundPeerAttribute : RegularExpressionAttribute\n{\n    public BoundPeerAttribute()\n        : base(GetPattern())\n    {\n    }\n\n    private static string GetPattern()\n    {\n        var items = new string[]\n        {\n            PublicKeyAttribute.OriginPattern,\n            DnsEndPointAttribute.HostPattern,\n            DnsEndPointAttribute.PortPattern,\n        };\n        var pattern = string.Join(\",\", items);\n        return @$\"^$|^{pattern}$\";\n    }\n}\n\n[AttributeUsage(AttributeTargets.Property)]\npublic sealed class BoundPeerArrayAttribute : ArrayAttribute<BoundPeerAttribute>\n{\n}\n"
  },
  {
    "path": "sdk/node/Libplanet.Node/DataAnnotations/DnsEndPointAttribute.cs",
    "content": "#pragma warning disable SA1402 // File may only contain a single type\nusing System.ComponentModel.DataAnnotations;\n\nnamespace Libplanet.Node.DataAnnotations;\n\n[AttributeUsage(AttributeTargets.Property)]\npublic sealed class DnsEndPointAttribute : RegularExpressionAttribute\n{\n    public const string HostPattern\n        = @\"(?:(?:[a-zA-Z0-9\\-\\.]+)|(?:\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}))\";\n\n    public const string PortPattern = @\"\\d{1,5}\";\n    public static readonly string OriginPattern\n        = $\"{HostPattern}:{PortPattern}\";\n\n    public DnsEndPointAttribute()\n        : base($\"^{OriginPattern}$\")\n    {\n    }\n}\n\n[AttributeUsage(AttributeTargets.Property)]\npublic sealed class DnsEndPointArrayAttribute : ArrayAttribute<DnsEndPointAttribute>\n{\n}\n"
  },
  {
    "path": "sdk/node/Libplanet.Node/DataAnnotations/PrivateKeyAttribute.cs",
    "content": "#pragma warning disable SA1402 // File may only contain a single type\nusing System.ComponentModel.DataAnnotations;\n\nnamespace Libplanet.Node.DataAnnotations;\n\n[AttributeUsage(AttributeTargets.Property)]\npublic sealed class PrivateKeyAttribute : RegularExpressionAttribute\n{\n    public const string OriginPattern = \"[0-9a-fA-F]{64}\";\n\n    public PrivateKeyAttribute()\n        : base($\"^{OriginPattern}$\")\n    {\n    }\n}\n\n[AttributeUsage(AttributeTargets.Property)]\npublic sealed class PrivateKeyArrayAttribute : ArrayAttribute<PrivateKeyAttribute>\n{\n}\n"
  },
  {
    "path": "sdk/node/Libplanet.Node/DataAnnotations/PublicKeyAttribute.cs",
    "content": "#pragma warning disable SA1402 // File may only contain a single type\nusing System.ComponentModel.DataAnnotations;\n\nnamespace Libplanet.Node.DataAnnotations;\n\n[AttributeUsage(AttributeTargets.Property)]\npublic sealed class PublicKeyAttribute : RegularExpressionAttribute\n{\n    public const string OriginPattern = \"(?:[0-9a-fA-F]{130}|[0-9a-fA-F]{66})\";\n\n    public PublicKeyAttribute()\n        : base($\"^{OriginPattern}$\")\n    {\n    }\n}\n\n[AttributeUsage(AttributeTargets.Property)]\npublic sealed class PublicKeyArrayAttribute : ArrayAttribute<PublicKeyAttribute>\n{\n}\n"
  },
  {
    "path": "sdk/node/Libplanet.Node/EndPointUtility.cs",
    "content": "using System.Diagnostics.CodeAnalysis;\nusing System.Globalization;\nusing System.Net;\nusing System.Net.Sockets;\n\nnamespace Libplanet.Node;\n\npublic static class EndPointUtility\n{\n    private static readonly object LockObject = new();\n    private static readonly List<int> PortList = [];\n\n    public static (string Host, int Port) GetElements(EndPoint endPoint)\n    {\n        if (endPoint is DnsEndPoint dnsEndPoint)\n        {\n            return (dnsEndPoint.Host, dnsEndPoint.Port);\n        }\n        else if (endPoint is IPEndPoint iPEndPoint)\n        {\n            return ($\"{iPEndPoint.Address}\", iPEndPoint.Port);\n        }\n\n        throw new NotSupportedException($\"'{endPoint}' is not supported.\");\n    }\n\n    public static string ToString(EndPoint endPoint)\n    {\n        if (endPoint is DnsEndPoint dnsEndPoint)\n        {\n            return $\"{dnsEndPoint.Host}:{dnsEndPoint.Port}\";\n        }\n        else if (endPoint is IPEndPoint iPEndPoint)\n        {\n            return $\"{iPEndPoint.Address}:{iPEndPoint.Port}\";\n        }\n\n        throw new NotSupportedException($\"'{endPoint}' is not supported.\");\n    }\n\n    public static EndPoint Parse(string text)\n    {\n        var items = text.Split(':');\n        if (IPAddress.TryParse(items[0], out var address))\n        {\n            return new IPEndPoint(address, int.Parse(items[1], CultureInfo.InvariantCulture));\n        }\n        else if (items.Length == 2)\n        {\n            return new DnsEndPoint(items[0], int.Parse(items[1], CultureInfo.InvariantCulture));\n        }\n\n        throw new NotSupportedException($\"'{text}' is not supported.\");\n    }\n\n    public static bool TryParse(string text, [MaybeNullWhen(false)] out EndPoint endPoint)\n    {\n        try\n        {\n            endPoint = Parse(text);\n            return true;\n        }\n        catch\n        {\n            endPoint = null;\n            return false;\n        }\n    }\n\n    public static DnsEndPoint Next() => new(\"localhost\", GetPort());\n\n    internal static IPEndPoint ConvertToIPEndPoint(EndPoint endPoint)\n    {\n        var (host, port) = GetElements(endPoint);\n        if (IPAddress.TryParse(host, out var address))\n        {\n            return new IPEndPoint(address, port);\n        }\n\n        var addresses = Dns.GetHostAddresses(host)\n                           .Where(item => item.AddressFamily == AddressFamily.InterNetwork)\n                           .ToArray();\n        if (addresses.Length > 0)\n        {\n            return new IPEndPoint(addresses[0], port);\n        }\n\n        throw new NotSupportedException($\"'{host}' is not supported.\");\n    }\n\n    private static int GetPort()\n    {\n        lock (LockObject)\n        {\n            var port = GetRandomPort();\n            while (PortList.Contains(port))\n            {\n                port = GetRandomPort();\n            }\n\n            PortList.Add(port);\n            return port;\n        }\n    }\n\n    private static int GetRandomPort()\n    {\n        var listener = new TcpListener(IPAddress.Loopback, 0);\n        listener.Start();\n        var port = ((IPEndPoint)listener.LocalEndpoint).Port;\n        listener.Stop();\n        return port;\n    }\n}\n"
  },
  {
    "path": "sdk/node/Libplanet.Node/Libplanet.Node.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <ItemGroup>\n    <PackageReference Include=\"Grpc.AspNetCore\" Version=\"2.40.0\" />\n    <PackageReference Include=\"Microsoft.Extensions.DependencyInjection\" Version=\"8.0.0\" />\n    <PackageReference Include=\"Microsoft.Extensions.Hosting\" Version=\"8.0.0\" />\n    <PackageReference Include=\"Microsoft.Extensions.Hosting.Abstractions\" Version=\"8.0.0\" />\n    <PackageReference Include=\"Microsoft.Extensions.Options\" Version=\"8.0.2\" />\n    <PackageReference Include=\"Microsoft.Extensions.Options.DataAnnotations\" Version=\"8.0.0\" />\n    <PackageReference Include=\"NJsonSchema\" Version=\"11.0.2\" />\n    <PackageReference Include=\"NJsonSchema.CodeGeneration.CSharp\" Version=\"11.0.2\" />\n    <PackageReference Include=\"R3\" Version=\"1.2.6\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <ProjectReference Include=\"..\\..\\..\\src\\Libplanet.RocksDBStore\\Libplanet.RocksDBStore.csproj\" />\n    <ProjectReference Include=\"..\\..\\..\\src\\Libplanet.Store\\Libplanet.Store.csproj\" />\n    <ProjectReference Include=\"..\\..\\..\\src\\Libplanet\\Libplanet.csproj\" />\n    <ProjectReference Include=\"..\\..\\..\\src\\Libplanet.Net\\Libplanet.Net.csproj\" />\n  </ItemGroup>\n\n</Project>\n"
  },
  {
    "path": "sdk/node/Libplanet.Node/Options/ActionOptions.cs",
    "content": "namespace Libplanet.Node.Options;\n\n[Options(Position)]\npublic sealed class ActionOptions : OptionsBase<ActionOptions>\n{\n    public const string Position = \"Action\";\n\n    public string ModulePath { get; set; } = string.Empty;\n\n    public string ActionLoaderType { get; set; } = string.Empty;\n\n    public string PolicyActionRegistryType { get; set; } = string.Empty;\n}\n"
  },
  {
    "path": "sdk/node/Libplanet.Node/Options/AppProtocolOptionsBase.cs",
    "content": "using System.ComponentModel;\nusing Libplanet.Node.DataAnnotations;\n\nnamespace Libplanet.Node.Options;\n\npublic abstract class AppProtocolOptionsBase<T> : OptionsBase<T>\n    where T : AppProtocolOptionsBase<T>\n{\n    [AppProtocolVersion]\n    [Description(\"The version of the application protocol.\")]\n    public string AppProtocolVersion { get; set; } = string.Empty;\n}\n"
  },
  {
    "path": "sdk/node/Libplanet.Node/Options/ConfigureNamedOptionsBase.cs",
    "content": "using Microsoft.Extensions.Options;\n\nnamespace Libplanet.Node.Options;\n\npublic abstract class ConfigureNamedOptionsBase<T> : IConfigureNamedOptions<T>\n    where T : OptionsBase<T>\n{\n    void IConfigureNamedOptions<T>.Configure(string? name, T options)\n    {\n        if (options.IsConfigured)\n        {\n            throw new ArgumentException(\n                message: \"The options have already been configured.\",\n                paramName: nameof(options));\n        }\n\n        OnConfigure(name, options);\n        options.IsConfigured = true;\n    }\n\n    void IConfigureOptions<T>.Configure(T options)\n    {\n        throw new NotSupportedException();\n    }\n\n    protected abstract void OnConfigure(string? name, T options);\n}\n"
  },
  {
    "path": "sdk/node/Libplanet.Node/Options/GenesisOptions.cs",
    "content": "using System.ComponentModel;\nusing Libplanet.Node.DataAnnotations;\n\nnamespace Libplanet.Node.Options;\n\n[Options(Position)]\n[Description(\"Options for the genesis block.\")]\npublic sealed class GenesisOptions : OptionsBase<GenesisOptions>\n{\n    public const string Position = \"Genesis\";\n\n    [PrivateKey]\n    [Description(\n        $\"The PrivateKey used to generate the genesis block. \" +\n        $\"This property cannot be used with {nameof(GenesisBlockPath)} and \" +\n        $\"{nameof(GenesisConfigurationPath)}.\")]\n    public string GenesisKey { get; set; } = string.Empty;\n\n    [PublicKeyArray]\n    [Description(\n        $\"Public keys of the validators. This property cannot be used with \" +\n        $\"{nameof(GenesisBlockPath)}.\")]\n    public string[] Validators { get; set; } = [];\n\n    [Description(\"The timestamp of the genesis block.\")]\n    public DateTimeOffset Timestamp { get; set; } = DateTimeOffset.MinValue;\n\n    [Description(\n        $\"The path of the genesis block, which can be a file path or a URI.\" +\n        $\"This property cannot be used with {nameof(GenesisKey)} and \" +\n        $\"{nameof(GenesisConfigurationPath)}.\")]\n    public string GenesisBlockPath { get; set; } = string.Empty;\n\n    [Description(\n        $\"The path of the genesis configuration, which can be a file path or a URI.\" +\n        $\"This property cannot be used with {nameof(GenesisKey)} and {nameof(GenesisBlockPath)}.\")]\n    public string GenesisConfigurationPath { get; set; } = string.Empty;\n}\n"
  },
  {
    "path": "sdk/node/Libplanet.Node/Options/GenesisOptionsConfigurator.cs",
    "content": "using Libplanet.Common;\nusing Libplanet.Crypto;\nusing Microsoft.Extensions.Logging;\nusing Microsoft.Extensions.Options;\n\nnamespace Libplanet.Node.Options;\n\ninternal sealed class GenesisOptionsConfigurator(\n    IOptions<SwarmOptions> nodeOptions, ILogger<GenesisOptionsConfigurator> logger)\n    : OptionsConfiguratorBase<GenesisOptions>\n{\n    protected override void OnConfigure(GenesisOptions options)\n    {\n        if (options.GenesisBlockPath == string.Empty &&\n            options.GenesisConfigurationPath == string.Empty)\n        {\n            if (options.GenesisKey == string.Empty)\n            {\n                var privateKey = new PrivateKey();\n                options.GenesisKey = ByteUtil.Hex(privateKey.ByteArray);\n                logger.LogWarning(\n                    \"Genesis key is not set. A new private key is generated:{PrivateKey}\",\n                    options.GenesisKey);\n            }\n\n            if (options.Validators.Length == 0)\n            {\n                var privateKey = PrivateKey.FromString(nodeOptions.Value.PrivateKey);\n                options.Validators = [privateKey.PublicKey.ToHex(compress: false)];\n                logger.LogWarning(\n                    \"Validators are not set. Use the node's private key as a validator.\");\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "sdk/node/Libplanet.Node/Options/GenesisOptionsValidator.cs",
    "content": "using Microsoft.Extensions.Options;\n\nnamespace Libplanet.Node.Options;\n\ninternal sealed class GenesisOptionsValidator : OptionsValidatorBase<GenesisOptions>\n{\n    protected override void OnValidate(string? name, GenesisOptions options)\n    {\n        if (options.GenesisBlockPath != string.Empty)\n        {\n            if (options.GenesisKey != string.Empty)\n            {\n                var message = $\"{nameof(options.GenesisKey)} cannot be used with \" +\n                              $\"{nameof(options.GenesisBlockPath)}.\";\n                throw new OptionsValidationException(\n                    optionsName: name ?? string.Empty,\n                    optionsType: typeof(GenesisOptions),\n                    failureMessages: [message]);\n            }\n\n            if (options.GenesisConfigurationPath != string.Empty)\n            {\n                var message = $\"{nameof(options.GenesisConfigurationPath)} cannot be used with \" +\n                              $\"{nameof(options.GenesisBlockPath)}.\";\n                throw new OptionsValidationException(\n                    optionsName: name ?? string.Empty,\n                    optionsType: typeof(GenesisOptions),\n                    failureMessages: [message]);\n            }\n\n            if (options.Validators.Length > 0)\n            {\n                var message = $\"{nameof(options.Validators)} cannot be used with \" +\n                              $\"{nameof(options.GenesisBlockPath)}.\";\n                throw new OptionsValidationException(\n                optionsName: name ?? string.Empty,\n                optionsType: typeof(GenesisOptions),\n                failureMessages: [message]);\n            }\n\n            if (!Uri.TryCreate(options.GenesisBlockPath, UriKind.Absolute, out _)\n                && !File.Exists(options.GenesisBlockPath))\n            {\n                var message = $\"{nameof(options.GenesisBlockPath)} must be a Uri or a existing \" +\n                              $\"file path.\";\n                throw new OptionsValidationException(\n                    optionsName: name ?? string.Empty,\n                    optionsType: typeof(GenesisOptions),\n                    failureMessages: [message]);\n            }\n        }\n\n        if (options.GenesisConfigurationPath != string.Empty)\n        {\n            if (options.GenesisBlockPath != string.Empty)\n            {\n                var message = $\"{nameof(options.GenesisBlockPath)} cannot be used with \" +\n                              $\"{nameof(options.GenesisConfigurationPath)}.\";\n                throw new OptionsValidationException(\n                    optionsName: name ?? string.Empty,\n                    optionsType: typeof(GenesisOptions),\n                    failureMessages: [message]);\n            }\n\n            if (options.GenesisKey == string.Empty)\n            {\n                var message = $\"{nameof(options.GenesisConfigurationPath)} must be used with \" +\n                              $\"{nameof(options.GenesisKey)}.\";\n                throw new OptionsValidationException(\n                    optionsName: name ?? string.Empty,\n                    optionsType: typeof(GenesisOptions),\n                    failureMessages: [message]);\n            }\n\n            if (!Uri.TryCreate(options.GenesisConfigurationPath, UriKind.Absolute, out _)\n                && !File.Exists(options.GenesisConfigurationPath))\n            {\n                var message = $\"{nameof(options.GenesisConfigurationPath)} must be a Uri or a \" +\n                              $\"existing file path.\";\n                throw new OptionsValidationException(\n                    optionsName: name ?? string.Empty,\n                    optionsType: typeof(GenesisOptions),\n                    failureMessages: [message]);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "sdk/node/Libplanet.Node/Options/OptionsAttribute.cs",
    "content": "namespace Libplanet.Node.Options;\n\n[AttributeUsage(AttributeTargets.Class, AllowMultiple = true)]\npublic sealed class OptionsAttribute(string name) : Attribute\n{\n    public string Name { get; } = name;\n}\n"
  },
  {
    "path": "sdk/node/Libplanet.Node/Options/OptionsBase.cs",
    "content": "namespace Libplanet.Node.Options;\n\npublic abstract class OptionsBase<T>\n    where T : OptionsBase<T>\n{\n    public bool IsConfigured { get; internal set; }\n\n    public bool IsValidated { get; internal set; }\n\n    public T Verify()\n    {\n        if (!IsConfigured)\n        {\n            throw new InvalidOperationException(\n                $\"The options {typeof(T)} have not been configured yet.\");\n        }\n\n        if (!IsValidated)\n        {\n            throw new InvalidOperationException(\n                $\"The options {typeof(T)} have not been validated yet.\");\n        }\n\n        return (T)this;\n    }\n}\n"
  },
  {
    "path": "sdk/node/Libplanet.Node/Options/OptionsConfiguratorBase.cs",
    "content": "using Microsoft.Extensions.Options;\n\nnamespace Libplanet.Node.Options;\n\npublic abstract class OptionsConfiguratorBase<T> : IConfigureOptions<T>\n    where T : OptionsBase<T>\n{\n    void IConfigureOptions<T>.Configure(T options)\n    {\n        if (options.IsConfigured)\n        {\n            throw new ArgumentException(\n                message: \"The options have already been configured.\",\n                paramName: nameof(options));\n        }\n\n        OnConfigure(options);\n        options.IsConfigured = true;\n    }\n\n    protected abstract void OnConfigure(T options);\n}\n"
  },
  {
    "path": "sdk/node/Libplanet.Node/Options/OptionsValidatorBase.cs",
    "content": "using Microsoft.Extensions.Options;\n\nnamespace Libplanet.Node.Options;\n\npublic abstract class OptionsValidatorBase<T> : IValidateOptions<T>\n    where T : OptionsBase<T>\n{\n    ValidateOptionsResult IValidateOptions<T>.Validate(string? name, T options)\n    {\n        if (options.IsValidated)\n        {\n            throw new InvalidOperationException(\"The options have already been validated.\");\n        }\n\n        try\n        {\n            OnValidate(name, options);\n            return ValidateOptionsResult.Success;\n        }\n        catch (Exception e)\n        {\n            return ValidateOptionsResult.Fail($\"{e}\");\n        }\n        finally\n        {\n            options.IsValidated = true;\n        }\n    }\n\n    protected abstract void OnValidate(string? name, T options);\n}\n"
  },
  {
    "path": "sdk/node/Libplanet.Node/Options/Schema/OptionsSchemaBuilder.cs",
    "content": "using System.ComponentModel;\nusing System.Reflection;\nusing NJsonSchema;\nusing NJsonSchema.Generation;\n\nnamespace Libplanet.Node.Options.Schema;\n\npublic sealed class OptionsSchemaBuilder\n{\n#pragma warning disable S1075 // URIs should not be hardcoded\n    public const string BaseSchemaUrl = \"https://json.schemastore.org/appsettings.json\";\n#pragma warning restore S1075 // URIs should not be hardcoded\n\n    private readonly Dictionary<string, Type> _typeByName = [];\n\n    public static async Task<string> GetSchemaAsync(CancellationToken cancellationToken)\n    {\n        var schemaBuilder = new OptionsSchemaBuilder();\n        var optionsTypes = ServiceUtility.GetTypes(typeof(OptionsAttribute), inherit: true);\n        foreach (var optionsType in optionsTypes)\n        {\n            var optionsAttributes = GetAttributes(optionsType, scope: string.Empty);\n            foreach (var optionsAttribute in optionsAttributes)\n            {\n                schemaBuilder.Add(optionsAttribute.Name, optionsType);\n            }\n\n            cancellationToken.ThrowIfCancellationRequested();\n        }\n\n        return await schemaBuilder.BuildAsync(cancellationToken);\n\n        static IEnumerable<OptionsAttribute> GetAttributes(Type type, string scope)\n            => Attribute.GetCustomAttributes(type, typeof(OptionsAttribute))\n                .OfType<OptionsAttribute>();\n    }\n\n    public void Add(string name, Type type)\n    {\n        _typeByName.Add(name, type);\n    }\n\n    public async Task<string> BuildAsync(CancellationToken cancellationToken)\n    {\n        var schema = new JsonSchema();\n        var originSchema = await JsonSchema.FromUrlAsync(BaseSchemaUrl, cancellationToken);\n        var optionsSchema = new JsonSchema\n        {\n            Type = JsonObjectType.Object,\n        };\n\n        schema.Definitions[\"appsettings\"] = originSchema;\n        schema.AllOf.Add(new JsonSchema\n        {\n            Reference = originSchema,\n        });\n        schema.AllOf.Add(optionsSchema);\n        foreach (var (name, type) in _typeByName)\n        {\n            var optionsType = typeof(OptionsBase<>).MakeGenericType(type);\n            var settings = new SystemTextJsonSchemaGeneratorSettings\n            {\n                ExcludedTypeNames = [optionsType.FullName!],\n                FlattenInheritanceHierarchy = true,\n            };\n            var schemaGenerator = new OptionsSchemaGenerator(settings);\n            var typeSchema = schemaGenerator.Generate(type);\n            schema.Definitions[name] = typeSchema;\n            optionsSchema.Properties.Add(name, new JsonSchemaProperty()\n            {\n                Description = GetDescription(type),\n                Reference = typeSchema,\n            });\n        }\n\n        return schema.ToJson();\n    }\n\n    private static string GetDescription(Type type)\n    {\n        if (type.GetCustomAttribute<DescriptionAttribute>() is { } descriptionAttribute)\n        {\n            return descriptionAttribute.Description;\n        }\n\n        return $\"Type '{type.Name}' does not have a description.\";\n    }\n}\n"
  },
  {
    "path": "sdk/node/Libplanet.Node/Options/Schema/OptionsSchemaGenerator.cs",
    "content": "using System.ComponentModel.DataAnnotations;\nusing Libplanet.Node.DataAnnotations;\nusing Namotion.Reflection;\nusing NJsonSchema;\nusing NJsonSchema.Generation;\n\nnamespace Libplanet.Node.Options.Schema;\n\ninternal sealed class OptionsSchemaGenerator : JsonSchemaGenerator\n{\n    public OptionsSchemaGenerator(JsonSchemaGeneratorSettings settings)\n        : base(settings)\n    {\n    }\n\n    public override void ApplyDataAnnotations(\n        JsonSchema schema, JsonTypeDescription typeDescription)\n    {\n        base.ApplyDataAnnotations(schema, typeDescription);\n\n        var contextualType = typeDescription.ContextualType;\n        if (typeDescription.ContextualType.OriginalType.IsArray && schema.Item is not null)\n        {\n            var arrayAttribute = contextualType.GetContextAttributes(true)\n                .OfType<ArrayAttribute>()\n                .FirstOrDefault();\n            if (arrayAttribute != null)\n            {\n                var validationAttribute = arrayAttribute.CreateAttribute();\n                if (validationAttribute is RegularExpressionAttribute regexAttribute)\n                {\n                    schema.Item.Pattern = regexAttribute.Pattern;\n                }\n            }\n        }\n    }\n\n    protected override void GenerateEnum(JsonSchema schema, JsonTypeDescription typeDescription)\n    {\n        var contextualType = typeDescription.ContextualType;\n\n        schema.Type = JsonObjectType.String;\n        schema.Enumeration.Clear();\n        schema.EnumerationNames.Clear();\n        schema.IsFlagEnumerable = contextualType.IsAttributeDefined<FlagsAttribute>(true);\n\n        foreach (var enumName in Enum.GetNames(contextualType.Type))\n        {\n            schema.Enumeration.Add(enumName);\n        }\n\n        if (Settings.GenerateEnumMappingDescription)\n        {\n            schema.Description = (schema.Description + \"\\n\\n\" +\n                string.Join(\"\\n\", schema.EnumerationNames)).Trim();\n        }\n    }\n}\n"
  },
  {
    "path": "sdk/node/Libplanet.Node/Options/SeedOptions.cs",
    "content": "using System.ComponentModel;\nusing System.ComponentModel.DataAnnotations;\nusing Libplanet.Node.DataAnnotations;\n\nnamespace Libplanet.Node.Options;\n\npublic sealed class SeedOptions : AppProtocolOptionsBase<SeedOptions>\n{\n    public const string BlocksyncSeed = nameof(BlocksyncSeed);\n    public const string ConsensusSeed = nameof(ConsensusSeed);\n\n    [DnsEndPoint]\n    [Description(\"The endpoint of the seed node.\")]\n    public string EndPoint { get; set; } = string.Empty;\n\n    [PrivateKey]\n    [Description(\"The private key of Seed.\")]\n    public string PrivateKey { get; set; } = string.Empty;\n\n    [Range(0, int.MaxValue)]\n    [Description(\"The interval to refresh the peer list.\")]\n    public int RefreshInterval { get; set; } = 5;\n\n    [Range(0, int.MaxValue)]\n    [Description(\"The lifetime of a peer.\")]\n    public int PeerLifetime { get; set; } = 120;\n\n    [Range(0, int.MaxValue)]\n    [Description(\"The timeout for a ping.\")]\n    public int PingTimeout { get; set; } = 5;\n}\n"
  },
  {
    "path": "sdk/node/Libplanet.Node/Options/SeedOptionsConfigurator.cs",
    "content": "using Libplanet.Common;\nusing Libplanet.Crypto;\nusing Microsoft.Extensions.Logging;\n\nnamespace Libplanet.Node.Options;\n\npublic sealed class SeedOptionsConfigurator(\n    ILogger<SeedOptionsConfigurator> logger)\n    : ConfigureNamedOptionsBase<SeedOptions>\n{\n    private static readonly PrivateKey _defaultPrivateKey = new();\n\n    protected override void OnConfigure(string? name, SeedOptions options)\n    {\n        if (name == SeedOptions.BlocksyncSeed)\n        {\n            if (options.PrivateKey == string.Empty)\n            {\n                options.PrivateKey = ByteUtil.Hex(_defaultPrivateKey.ByteArray);\n                logger.LogWarning(\n                    \"BlocksyncSeed's private key is not set. A new private key is generated: \" +\n                    \"{PrivateKey}\",\n                    options.PrivateKey);\n            }\n        }\n        else if (name == SeedOptions.ConsensusSeed)\n        {\n            if (options.PrivateKey == string.Empty)\n            {\n                options.PrivateKey = ByteUtil.Hex(_defaultPrivateKey.ByteArray);\n                logger.LogWarning(\n                    \"ConsensusSeed's private key is not set. A new private key is generated: \" +\n                    \"{PrivateKey}\",\n                    options.PrivateKey);\n            }\n        }\n        else\n        {\n            logger.LogWarning(\n                \"SeedOptionsConfigurator is called with an unexpected name: {Name}\",\n                name);\n        }\n\n        if (options.EndPoint == string.Empty)\n        {\n            options.EndPoint = EndPointUtility.ToString(EndPointUtility.Next());\n            logger.LogWarning(\n                \"{Name}'s endpoint is not set. A new endpoint is generated: {EndPoint}\",\n                name,\n                options.EndPoint);\n        }\n    }\n}\n"
  },
  {
    "path": "sdk/node/Libplanet.Node/Options/SoloOptions.cs",
    "content": "using System.ComponentModel;\nusing Libplanet.Node.DataAnnotations;\n\nnamespace Libplanet.Node.Options;\n\n[Options(Position)]\npublic class SoloOptions : OptionsBase<SoloOptions>\n{\n    public const string Position = \"Solo\";\n\n    public bool IsEnabled { get; set; }\n\n    public long BlockInterval { get; set; } = 4000;\n\n    [PrivateKey]\n    [Description(\"The private key of the node.\")]\n    public string PrivateKey { get; set; } = string.Empty;\n}\n"
  },
  {
    "path": "sdk/node/Libplanet.Node/Options/SoloOptionsConfigurator.cs",
    "content": "using Libplanet.Common;\nusing Libplanet.Crypto;\nusing Microsoft.Extensions.Logging;\n\nnamespace Libplanet.Node.Options;\n\ninternal sealed class SoloOptionsConfigurator(\n    ILogger<SoloOptionsConfigurator> logger)\n    : OptionsConfiguratorBase<SoloOptions>\n{\n    protected override void OnConfigure(SoloOptions options)\n    {\n        if (options.PrivateKey == string.Empty)\n        {\n            options.PrivateKey = ByteUtil.Hex(new PrivateKey().ByteArray);\n            logger.LogWarning(\n                \"Node's private key is not set. A new private key is generated: {PrivateKey}\",\n                options.PrivateKey);\n        }\n    }\n}\n"
  },
  {
    "path": "sdk/node/Libplanet.Node/Options/StoreOptions.cs",
    "content": "using System.ComponentModel;\n\nnamespace Libplanet.Node.Options;\n\n[Options(Position)]\npublic sealed class StoreOptions : OptionsBase<StoreOptions>\n{\n    public const string Position = \"Store\";\n\n    public const string DefaultRootPath = \".db\";\n    public const string DefaultStorePath = \"store\";\n    public const string DefaultStateStorePath = \"state\";\n\n    /// <summary>\n    /// The type of the store.\n    /// </summary>\n    [Description(\"The type of the store.\")]\n    public StoreType Type { get; set; } = StoreType.InMemory;\n\n    /// <summary>\n    /// The root directory path of the store.\n    /// </summary>\n    [Description(\"The root directory path of the store.\")]\n    public string RootPath { get; set; } = string.Empty;\n\n    /// <summary>\n    /// The directory name of the store to be created under <see cref=\"RootPath\"/>.\n    /// </summary>\n    [Description(\n        \"The directory name of the store to be created under RootPath. If not specified,\" +\n        \"the default value is 'store'.\")]\n    public string StoreName { get; set; } = string.Empty;\n\n    /// <summary>\n    /// The directory name of the state store to be created under <see cref=\"RootPath\"/>.\n    /// </summary>\n    [Description(\n        \"The directory name of the state store to be created under RootPath. If not specified,\" +\n        \"the default value is 'state'.\")]\n    public string StateStoreName { get; set; } = string.Empty;\n}\n"
  },
  {
    "path": "sdk/node/Libplanet.Node/Options/StoreOptionsConfigurator.cs",
    "content": "using Microsoft.Extensions.Logging;\n\nnamespace Libplanet.Node.Options;\n\ninternal sealed class StoreOptionsConfigurator(ILogger<StoreOptionsConfigurator> logger)\n    : OptionsConfiguratorBase<StoreOptions>\n{\n    protected override void OnConfigure(StoreOptions options)\n    {\n        if (options.Type == StoreType.InMemory)\n        {\n            if (options.RootPath != string.Empty)\n            {\n                options.RootPath = string.Empty;\n                logger.LogWarning(\n                    \"RootPath is ignored because StoreType is {Memory}.\", StoreType.InMemory);\n            }\n\n            if (options.StoreName != string.Empty)\n            {\n                options.StoreName = string.Empty;\n                logger.LogWarning(\n                    \"StorePath is ignored because StoreType is {Memory}.\", StoreType.InMemory);\n            }\n\n            if (options.StateStoreName != string.Empty)\n            {\n                options.StateStoreName = string.Empty;\n                logger.LogWarning(\n                    \"StateStorePath is ignored because StoreType is {Memory}.\", StoreType.InMemory);\n            }\n        }\n        else\n        {\n            if (options.RootPath == string.Empty)\n            {\n                options.RootPath = StoreOptions.DefaultRootPath;\n                logger.LogDebug(\n                    \"RootPath is not set. Use the default path: {RootPath}\", options.RootPath);\n            }\n\n            if (options.StoreName == string.Empty)\n            {\n                options.StoreName = StoreOptions.DefaultStorePath;\n                logger.LogDebug(\n                    \"StorePath is not set. Use the default path: {StorePath}\",\n                    options.StoreName);\n            }\n\n            if (options.StateStoreName == string.Empty)\n            {\n                options.StateStoreName = StoreOptions.DefaultStateStorePath;\n                logger.LogDebug(\n                    \"StateStorePath is not set. Use the default path: {StateStorePath}\",\n                    options.StateStoreName);\n            }\n\n            options.RootPath = Path.GetFullPath(options.RootPath);\n            options.StoreName = Path.GetFullPath(\n                Path.Combine(options.RootPath, options.StoreName));\n            options.StateStoreName = Path.GetFullPath(\n                Path.Combine(options.RootPath, options.StateStoreName));\n        }\n    }\n}\n"
  },
  {
    "path": "sdk/node/Libplanet.Node/Options/StoreType.cs",
    "content": "namespace Libplanet.Node.Options;\n\npublic enum StoreType\n{\n    /// <summary>\n    /// Store data in disk.\n    /// </summary>\n    RocksDB,\n\n    /// <summary>\n    /// Store data in memory.\n    /// </summary>\n    InMemory,\n}\n"
  },
  {
    "path": "sdk/node/Libplanet.Node/Options/SwarmOptions.cs",
    "content": "using System.ComponentModel;\nusing Libplanet.Node.DataAnnotations;\n\nnamespace Libplanet.Node.Options;\n\n[Options(Position)]\npublic sealed class SwarmOptions : AppProtocolOptionsBase<SwarmOptions>\n{\n    public const string Position = \"Swarm\";\n\n    public bool IsEnabled { get; set; }\n\n    [PrivateKey]\n    [Description(\"The private key of Swarm.\")]\n    public string PrivateKey { get; set; } = string.Empty;\n\n    [DnsEndPoint]\n    public string EndPoint { get; set; } = string.Empty;\n\n    [BoundPeer]\n    [Description(\"The endpoint of the node to block sync.\")]\n    public string BlocksyncSeedPeer { get; set; } = string.Empty;\n\n    [PublicKeyArray]\n    public string[] TrustedAppProtocolVersionSigners { get; set; } = [];\n}\n"
  },
  {
    "path": "sdk/node/Libplanet.Node/Options/SwarmOptionsConfigurator.cs",
    "content": "using Libplanet.Common;\nusing Libplanet.Crypto;\nusing Libplanet.Net;\nusing Microsoft.Extensions.Logging;\n\nnamespace Libplanet.Node.Options;\n\ninternal sealed class SwarmOptionsConfigurator(\n    ILogger<SwarmOptionsConfigurator> logger)\n    : OptionsConfiguratorBase<SwarmOptions>\n{\n    protected override void OnConfigure(SwarmOptions options)\n    {\n        if (options.PrivateKey == string.Empty)\n        {\n            options.PrivateKey = ByteUtil.Hex(new PrivateKey().ByteArray);\n            logger.LogWarning(\n                \"Node's private key is not set. A new private key is generated: {PrivateKey}\",\n                options.PrivateKey);\n        }\n\n        if (options.EndPoint == string.Empty)\n        {\n            options.EndPoint = EndPointUtility.ToString(EndPointUtility.Next());\n            logger.LogWarning(\n                \"Node's endpoint is not set. A new endpoint is generated: {EndPoint}\",\n                options.EndPoint);\n        }\n\n        if (options.AppProtocolVersion == string.Empty)\n        {\n            var privateKey = PrivateKey.FromString(options.PrivateKey);\n            var version = 0;\n            options.AppProtocolVersion = AppProtocolVersion.Sign(privateKey, version).Token;\n            logger.LogWarning(\n                \"SwarmOptions.AppProtocolVersion is not set. A new version is \" +\n                \"generated: {AppProtocolVersion}\",\n                options.AppProtocolVersion);\n        }\n    }\n}\n"
  },
  {
    "path": "sdk/node/Libplanet.Node/Options/SwarmOptionsValidator.cs",
    "content": "using Microsoft.Extensions.Options;\n\nnamespace Libplanet.Node.Options;\n\ninternal sealed class SwarmOptionsValidator(\n    IOptions<SoloOptions> soloOptions)\n    : OptionsValidatorBase<SwarmOptions>\n{\n    protected override void OnValidate(string? name, SwarmOptions options)\n    {\n        var soloOptionsValue = soloOptions.Value;\n        if (options.IsEnabled && soloOptionsValue.IsEnabled)\n        {\n            throw new OptionsValidationException(\n                optionsName: name ?? string.Empty,\n                optionsType: typeof(SwarmOptions),\n                failureMessages: [\n                    \"Both Swarm and SoloPropose cannot be enabled at the same time.\"]);\n        }\n    }\n}\n"
  },
  {
    "path": "sdk/node/Libplanet.Node/Options/ValidatorOptions.cs",
    "content": "using System.ComponentModel;\nusing Libplanet.Node.DataAnnotations;\n\nnamespace Libplanet.Node.Options;\n\n[Options(Position)]\npublic sealed class ValidatorOptions : AppProtocolOptionsBase<ValidatorOptions>\n{\n    public const string Position = \"Validator\";\n\n    public bool IsEnabled { get; set; }\n\n    [PrivateKey]\n    [Description(\"The private key of Validator.\")]\n    public string PrivateKey { get; set; } = string.Empty;\n\n    [DnsEndPoint]\n    public string EndPoint { get; set; } = string.Empty;\n\n    [BoundPeer]\n    [Description(\"The endpoint of the node to consensus.\")]\n    public string ConsensusSeedPeer { get; set; } = string.Empty;\n}\n"
  },
  {
    "path": "sdk/node/Libplanet.Node/Options/ValidatorOptionsConfigurator.cs",
    "content": "using Microsoft.Extensions.Logging;\nusing Microsoft.Extensions.Options;\n\nnamespace Libplanet.Node.Options;\n\ninternal sealed class ValidatorOptionsConfigurator(\n    IOptions<SwarmOptions> swarmOptions,\n    ILogger<ValidatorOptionsConfigurator> logger)\n    : OptionsConfiguratorBase<ValidatorOptions>\n{\n    protected override void OnConfigure(ValidatorOptions options)\n    {\n        if (options.PrivateKey == string.Empty)\n        {\n            options.PrivateKey = swarmOptions.Value.PrivateKey;\n            logger.LogWarning(\n                \"Validator's private key is not set. Use the swarm's private key: {PrivateKey}\",\n                options.PrivateKey);\n        }\n\n        if (options.AppProtocolVersion == string.Empty)\n        {\n            options.AppProtocolVersion = swarmOptions.Value.AppProtocolVersion;\n            logger.LogWarning(\n                \"Validator's app protocol version is not set. Use the swarm's \" +\n                \"app protocol version: {AppProtocolVersion}\",\n                options.AppProtocolVersion);\n        }\n\n        if (options.EndPoint == string.Empty)\n        {\n            options.EndPoint = EndPointUtility.ToString(EndPointUtility.Next());\n            logger.LogWarning(\n                \"Validator's endpoint is not set. A new endpoint is generated: {EndPoint}\",\n                options.EndPoint);\n        }\n    }\n}\n"
  },
  {
    "path": "sdk/node/Libplanet.Node/Options/ValidatorOptionsValidator.cs",
    "content": "using Microsoft.Extensions.Options;\n\nnamespace Libplanet.Node.Options;\n\ninternal sealed class ValidatorOptionsValidator(\n    IOptions<SwarmOptions> swarmOptions)\n    : OptionsValidatorBase<ValidatorOptions>\n{\n    protected override void OnValidate(string? name, ValidatorOptions options)\n    {\n        var swarmOptionsValue = swarmOptions.Value;\n        if (options.IsEnabled && !swarmOptionsValue.IsEnabled)\n        {\n            throw new OptionsValidationException(\n                optionsName: name ?? string.Empty,\n                optionsType: typeof(ValidatorOptions),\n                failureMessages: [\n                    \"Validator cannot be enabled when Swarm is disabled.\"]);\n        }\n    }\n}\n"
  },
  {
    "path": "sdk/node/Libplanet.Node/README.md",
    "content": "Libplanet Node\n==============\n\n[![NuGet][nuget-badge]][NuGet]\n[![NuGet (prerelease)][nuget-prerelease-badge]][NuGet]\n\nThis library is a collection of utilities for application programmers who\ncreate a blockchain node powered by [Libplanet].\n\n[NuGet]: https://www.nuget.org/packages/Libplanet.Node/\n[nuget-badge]: https://img.shields.io/nuget/v/Libplanet.Node.svg?style=flat\n[nuget-prerelease-badge]: https://img.shields.io/nuget/vpre/Libplanet.Node.svg?style=flat\n[Libplanet]: https://libplanet.io/\n"
  },
  {
    "path": "sdk/node/Libplanet.Node/ServiceUtility.cs",
    "content": "using System.Reflection;\n\nnamespace Libplanet.Node;\n\npublic static class ServiceUtility\n{\n    public static IEnumerable<Type> GetTypes(Assembly assembly, Type attributeType, bool inherit)\n        => assembly.GetTypes()\n            .Where(type => Attribute.IsDefined(type, attributeType, inherit))\n            .Where(type => type.IsClass && !type.IsAbstract);\n\n    public static IEnumerable<Type> GetTypes(Type attributeType, bool inherit)\n        => AppDomain.CurrentDomain.GetAssemblies()\n            .SelectMany(assembly => GetTypes(assembly, attributeType, inherit));\n}\n"
  },
  {
    "path": "sdk/node/Libplanet.Node/Services/ActionService.cs",
    "content": "using Libplanet.Action;\nusing Libplanet.Action.Loader;\nusing Libplanet.Node.Actions;\nusing Libplanet.Node.Options;\nusing Microsoft.Extensions.Options;\n\nnamespace Libplanet.Node.Services;\n\ninternal sealed class ActionService(IOptions<ActionOptions> options)\n    : IActionService\n{\n    public IActionLoader ActionLoader { get; } = GetActionLoader(options.Value);\n\n    public IPolicyActionsRegistry PolicyActionsRegistry { get; }\n        = GetPolicyActionsRegistry(options.Value);\n\n    private static IActionLoader GetActionLoader(ActionOptions options)\n    {\n        if (options.ActionLoaderType != string.Empty)\n        {\n            var modulePath = options.ModulePath;\n            var actionLoaderType = options.ActionLoaderType;\n            return PluginLoader.LoadActionLoader(modulePath, actionLoaderType);\n        }\n\n        return new AggregateTypedActionLoader();\n    }\n\n    private static IPolicyActionsRegistry GetPolicyActionsRegistry(ActionOptions options)\n    {\n        if (options.PolicyActionRegistryType != string.Empty)\n        {\n            var modulePath = options.ModulePath;\n            var policyActionRegistryType = options.PolicyActionRegistryType;\n            return PluginLoader.LoadPolicyActionRegistry(modulePath, policyActionRegistryType);\n        }\n\n        return new PolicyActionsRegistry();\n    }\n}\n"
  },
  {
    "path": "sdk/node/Libplanet.Node/Services/BlockChainService.cs",
    "content": "using System.Collections.Immutable;\nusing System.Diagnostics;\nusing System.Numerics;\nusing System.Text.Json;\nusing Bencodex;\nusing Bencodex.Types;\nusing Libplanet.Action;\nusing Libplanet.Action.Loader;\nusing Libplanet.Action.State;\nusing Libplanet.Action.Sys;\nusing Libplanet.Blockchain;\nusing Libplanet.Blockchain.Policies;\nusing Libplanet.Blockchain.Renderers;\nusing Libplanet.Common;\nusing Libplanet.Crypto;\nusing Libplanet.Node.Options;\nusing Libplanet.Store;\nusing Libplanet.Store.Trie;\nusing Libplanet.Types.Blocks;\nusing Libplanet.Types.Consensus;\nusing Libplanet.Types.Tx;\nusing Microsoft.Extensions.Options;\n\nnamespace Libplanet.Node.Services;\n\ninternal sealed class BlockChainService(\n    IOptions<GenesisOptions> genesisOptions,\n    IStoreService storeService,\n    IActionService actionService,\n    PolicyService policyService,\n    RendererService rendererService) : IBlockChainService\n{\n    private static readonly Codec _codec = new();\n    private readonly BlockChain _blockChain = CreateBlockChain(\n        genesisOptions: genesisOptions.Value,\n        store: storeService.Store,\n        stateStore: storeService.StateStore,\n        actionLoader: actionService.ActionLoader,\n        policyActionsRegistry: actionService.PolicyActionsRegistry,\n        stagePolicy: policyService.StagePolicy,\n        renderers: [rendererService]);\n\n    public BlockChain BlockChain => _blockChain;\n\n    private static BlockChain CreateBlockChain(\n        GenesisOptions genesisOptions,\n        IStore store,\n        IStateStore stateStore,\n        IActionLoader actionLoader,\n        IPolicyActionsRegistry policyActionsRegistry,\n        IStagePolicy stagePolicy,\n        IRenderer[] renderers)\n    {\n        var actionEvaluator = new ActionEvaluator(\n            policyActionsRegistry: policyActionsRegistry,\n            stateStore,\n            actionLoader);\n        var genesisBlock = CreateGenesisBlock(genesisOptions, stateStore);\n        var policy = new BlockPolicy(\n            policyActionsRegistry: policyActionsRegistry,\n            blockInterval: TimeSpan.FromSeconds(8),\n            validateNextBlockTx: (chain, transaction) => null,\n            validateNextBlock: (chain, block) => null,\n            getMaxTransactionsBytes: l => long.MaxValue,\n            getMinTransactionsPerBlock: l => 0,\n            getMaxTransactionsPerBlock: l => int.MaxValue,\n            getMaxTransactionsPerSignerPerBlock: l => int.MaxValue\n        );\n\n        var blockChainStates = new BlockChainStates(store, stateStore);\n        if (store.GetCanonicalChainId() is null)\n        {\n            return BlockChain.Create(\n                policy: policy,\n                stagePolicy: stagePolicy,\n                store: store,\n                stateStore: stateStore,\n                genesisBlock: genesisBlock,\n                actionEvaluator: actionEvaluator,\n                renderers: renderers,\n                blockChainStates: blockChainStates);\n        }\n\n        return new BlockChain(\n            policy: policy,\n            stagePolicy: stagePolicy,\n            store: store,\n            stateStore: stateStore,\n            genesisBlock: genesisBlock,\n            blockChainStates: blockChainStates,\n            actionEvaluator: actionEvaluator,\n            renderers: renderers);\n    }\n\n    private static Block CreateGenesisBlock(\n        GenesisOptions genesisOptions,\n        IStateStore stateStore)\n    {\n        if (genesisOptions.GenesisBlockPath != string.Empty)\n        {\n            return genesisOptions.GenesisBlockPath switch\n            {\n                { } path when Uri.TryCreate(path, UriKind.Absolute, out var uri)\n                    => LoadGenesisBlockFromUrl(uri),\n                { } path => LoadGenesisBlock(path),\n                _ => throw new NotSupportedException(),\n            };\n        }\n\n        if (genesisOptions.GenesisConfigurationPath != string.Empty)\n        {\n            var raw = genesisOptions.GenesisConfigurationPath switch\n            {\n                { } path when Uri.TryCreate(path, UriKind.Absolute, out var uri)\n                    => LoadConfigurationFromUri(uri),\n                { } path => LoadConfigurationFromFilePath(path),\n                _ => throw new NotSupportedException(),\n            };\n\n            return CreateGenesisBlockFromConfiguration(\n                PrivateKey.FromString(genesisOptions.GenesisKey),\n                raw,\n                stateStore);\n        }\n\n        if (genesisOptions.GenesisKey != string.Empty)\n        {\n            var genesisKey = PrivateKey.FromString(genesisOptions.GenesisKey);\n            var validatorKeys = genesisOptions.Validators.Select(PublicKey.FromHex).ToArray();\n            return CreateGenesisBlock(genesisKey, validatorKeys);\n        }\n\n        throw new UnreachableException(\"Genesis block path is not set.\");\n    }\n\n    private static Block CreateGenesisBlock(PrivateKey genesisKey, PublicKey[] validatorKeys)\n    {\n        var validators = validatorKeys\n            .Select(item => new Validator(item, new BigInteger(1000)))\n            .ToArray();\n        var validatorSet = new ValidatorSet(validators: [.. validators]);\n        var nonce = 0L;\n        IAction[] actions =\n        [\n            new Initialize(\n                validatorSet: validatorSet,\n                states: ImmutableDictionary.Create<Address, IValue>()),\n        ];\n\n        var transaction = Transaction.Create(\n            nonce: nonce,\n            privateKey: genesisKey,\n            genesisHash: null,\n            actions: [.. actions.Select(item => item.PlainValue)],\n            timestamp: DateTimeOffset.MinValue);\n        var transactions = ImmutableList.Create(transaction);\n        return BlockChain.ProposeGenesisBlock(\n            privateKey: genesisKey,\n            transactions: transactions,\n            timestamp: DateTimeOffset.MinValue);\n    }\n\n    private static Block LoadGenesisBlock(string genesisBlockPath)\n    {\n        var rawBlock = File.ReadAllBytes(Path.GetFullPath(genesisBlockPath));\n        var blockDict = (Dictionary)new Codec().Decode(rawBlock);\n        return BlockMarshaler.UnmarshalBlock(blockDict);\n    }\n\n    private static Block LoadGenesisBlockFromUrl(Uri genesisBlockUri)\n    {\n        using var client = new HttpClient();\n        var rawBlock = client.GetByteArrayAsync(genesisBlockUri).Result;\n        var blockDict = (Dictionary)_codec.Decode(rawBlock);\n        return BlockMarshaler.UnmarshalBlock(blockDict);\n    }\n\n    private static byte[] LoadConfigurationFromFilePath(string configurationPath)\n    {\n        return File.ReadAllBytes(Path.GetFullPath(configurationPath));\n    }\n\n    private static byte[] LoadConfigurationFromUri(Uri configurationUri)\n    {\n        using var client = new HttpClient();\n        return configurationUri.IsFile\n            ? LoadConfigurationFromFilePath(configurationUri.AbsolutePath)\n            : client.GetByteArrayAsync(configurationUri).Result;\n    }\n\n    private static Block CreateGenesisBlockFromConfiguration(\n        PrivateKey genesisKey,\n        byte[] config,\n        IStateStore stateStore)\n    {\n        Dictionary<string, Dictionary<string, string>>? data =\n            JsonSerializer.Deserialize<Dictionary<string, Dictionary<string, string>>>(config);\n        if (data == null || data.Count == 0)\n        {\n            return BlockChain.ProposeGenesisBlock(\n                privateKey: genesisKey,\n                timestamp: DateTimeOffset.MinValue);\n        }\n\n        var nullTrie = stateStore.GetStateRoot(null);\n        nullTrie = nullTrie.SetMetadata(new TrieMetadata(BlockMetadata.WorldStateProtocolVersion));\n        IWorld world = new World(new WorldBaseState(nullTrie, stateStore));\n        var codec = new Codec();\n\n        foreach (var accountKv in data)\n        {\n            var key = new Address(accountKv.Key);\n            IAccount account = world.GetAccount(key);\n\n            foreach (var stateKv in accountKv.Value)\n            {\n                account = account.SetState(\n                    new Address(stateKv.Key),\n                    codec.Decode(ByteUtil.ParseHex(stateKv.Value)));\n            }\n\n            world = world.SetAccount(key, account);\n        }\n\n        var worldTrie = world.Trie;\n        foreach (var account in world.Delta.Accounts)\n        {\n            var accountTrie = stateStore.Commit(account.Value.Trie);\n            worldTrie = worldTrie.Set(\n                KeyConverters.ToStateKey(account.Key),\n                new Binary(accountTrie.Hash.ByteArray));\n        }\n\n        worldTrie = stateStore.Commit(worldTrie);\n        return BlockChain.ProposeGenesisBlock(\n            privateKey: genesisKey,\n            stateRootHash: worldTrie.Hash,\n            timestamp: DateTimeOffset.MinValue);\n    }\n}\n"
  },
  {
    "path": "sdk/node/Libplanet.Node/Services/IActionService.cs",
    "content": "using Libplanet.Action;\nusing Libplanet.Action.Loader;\n\nnamespace Libplanet.Node.Services;\n\npublic interface IActionService\n{\n    IActionLoader ActionLoader { get; }\n\n    IPolicyActionsRegistry PolicyActionsRegistry { get; }\n}\n"
  },
  {
    "path": "sdk/node/Libplanet.Node/Services/IBlockChainService.cs",
    "content": "using Libplanet.Blockchain;\n\nnamespace Libplanet.Node.Services;\n\npublic interface IBlockChainService\n{\n    BlockChain BlockChain { get; }\n}\n"
  },
  {
    "path": "sdk/node/Libplanet.Node/Services/IBlocksyncSeedService.cs",
    "content": "using Libplanet.Net;\n\nnamespace Libplanet.Node.Services;\n\npublic interface IBlocksyncSeedService\n{\n    BoundPeer BoundPeer { get; }\n}\n"
  },
  {
    "path": "sdk/node/Libplanet.Node/Services/IConsensusSeedService.cs",
    "content": "using Libplanet.Net;\n\nnamespace Libplanet.Node.Services;\n\npublic interface IConsensusSeedService\n{\n    BoundPeer BoundPeer { get; }\n}\n"
  },
  {
    "path": "sdk/node/Libplanet.Node/Services/IReadChainService.cs",
    "content": "using Libplanet.Types.Blocks;\n\nnamespace Libplanet.Node.Services;\n\npublic interface IReadChainService\n{\n    public Block Tip { get; }\n\n    public Block GetBlock(BlockHash hash);\n\n    public Block GetBlock(long height);\n}\n"
  },
  {
    "path": "sdk/node/Libplanet.Node/Services/IRendererService.cs",
    "content": "namespace Libplanet.Node.Services;\n\npublic interface IRendererService\n{\n    IObservable<RenderBlockInfo> RenderBlock { get; }\n\n    IObservable<RenderActionInfo> RenderAction { get; }\n\n    IObservable<RenderActionErrorInfo> RenderActionError { get; }\n\n    IObservable<RenderBlockInfo> RenderBlockEnd { get; }\n}\n"
  },
  {
    "path": "sdk/node/Libplanet.Node/Services/IStoreService.cs",
    "content": "using Libplanet.Store;\nusing Libplanet.Store.Trie;\n\nnamespace Libplanet.Node.Services;\n\npublic interface IStoreService\n{\n    IStore Store { get; }\n\n    IStateStore StateStore { get; }\n\n    IKeyValueStore KeyValueStore { get; }\n}\n"
  },
  {
    "path": "sdk/node/Libplanet.Node/Services/ISwarmService.cs",
    "content": "using Libplanet.Net;\nusing R3;\n\nnamespace Libplanet.Node.Services;\n\npublic interface ISwarmService\n{\n    IObservable<Unit> Started { get; }\n\n    IObservable<Unit> Stopped { get; }\n\n    Swarm Swarm { get; }\n\n    bool IsRunning { get; }\n}\n"
  },
  {
    "path": "sdk/node/Libplanet.Node/Services/IValidatorService.cs",
    "content": "namespace Libplanet.Node.Services;\n\npublic interface IValidatorService\n{\n}\n"
  },
  {
    "path": "sdk/node/Libplanet.Node/Services/Peer.cs",
    "content": "using System.Diagnostics;\nusing Libplanet.Crypto;\nusing Libplanet.Net;\nusing Libplanet.Net.Messages;\nusing Libplanet.Net.Transports;\n\nnamespace Libplanet.Node.Services;\n\ninternal sealed class Peer(ITransport transport, BoundPeer boundPeer)\n{\n    private readonly ITransport _transport = transport;\n\n    public Address Address => BoundPeer.Address;\n\n    public BoundPeer BoundPeer { get; } = boundPeer;\n\n    public DateTimeOffset LastUpdated { get; private set; }\n\n    public DateTimeOffset LifeTime { get; private set; }\n\n    public TimeSpan LifeTimeSpan { get; init; } = TimeSpan.FromSeconds(120);\n\n    public TimeSpan Latency { get; private set; } = TimeSpan.MinValue;\n\n    public bool IsAlive => DateTimeOffset.UtcNow < LifeTime;\n\n    public void Update()\n    {\n        LastUpdated = DateTimeOffset.UtcNow;\n        LifeTime = LastUpdated + LifeTimeSpan;\n    }\n\n    public async Task<bool> PingAsync(TimeSpan timeout, CancellationToken cancellationToken)\n    {\n        try\n        {\n            var pingMsg = new PingMsg();\n            var stopwatch = Stopwatch.StartNew();\n            var replyMessage = await _transport.SendMessageAsync(\n                BoundPeer,\n                pingMsg,\n                timeout,\n                cancellationToken);\n            var latency = Stopwatch.GetElapsedTime(stopwatch.ElapsedTicks);\n\n            if (replyMessage.Content is PongMsg)\n            {\n                Latency = latency;\n                return true;\n            }\n        }\n        catch\n        {\n            // Ignore\n        }\n\n        Latency = TimeSpan.MinValue;\n        return false;\n    }\n}\n"
  },
  {
    "path": "sdk/node/Libplanet.Node/Services/PeerCollection.cs",
    "content": "using System.Collections;\nusing System.Collections.Concurrent;\nusing Libplanet.Crypto;\nusing Libplanet.Net;\nusing Libplanet.Net.Transports;\nusing Libplanet.Node.Options;\nusing Serilog;\n\nnamespace Libplanet.Node.Services;\n\ninternal sealed class PeerCollection(SeedOptions seedOptions) : IEnumerable<Peer>\n{\n    private readonly ConcurrentDictionary<Address, Peer> _infoByAddress = [];\n    private readonly SeedOptions _seedOptions = seedOptions;\n    private readonly ILogger _logger = Log.ForContext<Seed>();\n\n    public int Count => _infoByAddress.Count;\n\n    public void AddOrUpdate(BoundPeer boundPeer, ITransport transport)\n    {\n        _infoByAddress.AddOrUpdate(\n            key: boundPeer.Address,\n            addValueFactory: _ =>\n            {\n                var peer = new Peer(transport, boundPeer)\n                {\n                    LifeTimeSpan = TimeSpan.FromSeconds(_seedOptions.PeerLifetime),\n                };\n                peer.Update();\n                return peer;\n            },\n            updateValueFactory: (_, peer) =>\n            {\n                peer.Update();\n                return peer;\n            });\n    }\n\n    public async Task RefreshAsync(CancellationToken cancellationToken)\n    {\n        var peers = _infoByAddress.Values.ToArray();\n        var pingTimeout = TimeSpan.FromSeconds(_seedOptions.PingTimeout);\n        var updatedCount = 0;\n        await Parallel.ForEachAsync(_infoByAddress.Values, cancellationToken, async (peer, ct) =>\n        {\n            if (await peer.PingAsync(pingTimeout, ct))\n            {\n                Interlocked.Increment(ref updatedCount);\n            }\n            else\n            {\n                _infoByAddress.TryRemove(peer.Address, out _);\n            }\n        });\n        _logger.Information(\n            \"Refreshing peers in table. (Total: {Total}, Candidate: {Candidate})\",\n            peers.Length,\n            updatedCount);\n    }\n\n    public IEnumerator<Peer> GetEnumerator()\n        => _infoByAddress.Values.GetEnumerator();\n\n    IEnumerator IEnumerable.GetEnumerator()\n        => _infoByAddress.Values.GetEnumerator();\n}\n"
  },
  {
    "path": "sdk/node/Libplanet.Node/Services/PolicyService.cs",
    "content": "using Libplanet.Blockchain.Policies;\n\nnamespace Libplanet.Node.Services;\n\npublic class PolicyService\n{\n    public IStagePolicy StagePolicy { get; } = new VolatileStagePolicy();\n}\n"
  },
  {
    "path": "sdk/node/Libplanet.Node/Services/ReadChainService.cs",
    "content": "using Libplanet.Types.Blocks;\n\nnamespace Libplanet.Node.Services;\n\ninternal sealed class ReadChainService(IBlockChainService blockChainService) : IReadChainService\n{\n    public Block Tip => blockChainService.BlockChain.Tip;\n\n    public Block GetBlock(BlockHash hash) => blockChainService.BlockChain[hash];\n\n    public Block GetBlock(long height) => blockChainService.BlockChain[height];\n}\n"
  },
  {
    "path": "sdk/node/Libplanet.Node/Services/RenderActionErrorInfo.cs",
    "content": "using Bencodex.Types;\nusing Libplanet.Action;\n\nnamespace Libplanet.Node.Services;\n\npublic readonly record struct RenderActionErrorInfo(\n    IValue Action,\n    ICommittedActionContext Context,\n    Exception Exception);\n"
  },
  {
    "path": "sdk/node/Libplanet.Node/Services/RenderActionInfo.cs",
    "content": "using System.Security.Cryptography;\nusing Bencodex.Types;\nusing Libplanet.Action;\nusing Libplanet.Common;\n\nnamespace Libplanet.Node.Services;\n\npublic readonly record struct RenderActionInfo(\n    IValue Action,\n    ICommittedActionContext Context,\n    HashDigest<SHA256> NextState);\n"
  },
  {
    "path": "sdk/node/Libplanet.Node/Services/RenderBlockInfo.cs",
    "content": "using Libplanet.Types.Blocks;\n\nnamespace Libplanet.Node.Services;\n\npublic readonly record struct RenderBlockInfo(\n    Block OldTip,\n    Block NewTip);\n"
  },
  {
    "path": "sdk/node/Libplanet.Node/Services/RendererService.cs",
    "content": "using System.Security.Cryptography;\nusing Bencodex.Types;\nusing Libplanet.Action;\nusing Libplanet.Blockchain.Renderers;\nusing Libplanet.Common;\nusing Libplanet.Types.Blocks;\nusing Microsoft.Extensions.Logging;\nusing R3;\n\nnamespace Libplanet.Node.Services;\n\ninternal sealed class RendererService : IRendererService, IActionRenderer, IDisposable\n{\n    private readonly Subject<RenderBlockInfo> _renderBlock = new();\n    private readonly Subject<RenderActionInfo> _renderAction = new();\n    private readonly Subject<RenderActionErrorInfo> _renderActionError = new();\n    private readonly Subject<RenderBlockInfo> _renderBlockEnd = new();\n    private readonly SynchronizationContext _synchronizationContext;\n    private readonly ILogger<RendererService> _logger;\n\n    private IObservable<RenderBlockInfo>? _renderBlockObservable;\n    private IObservable<RenderActionInfo>? _renderActionObservable;\n    private IObservable<RenderActionErrorInfo>? _renderActionErrorObservable;\n    private IObservable<RenderBlockInfo>? _renderBlockEndObservable;\n\n    public RendererService(\n        SynchronizationContext synchronizationContext,\n        ILogger<RendererService> logger)\n    {\n        _synchronizationContext = synchronizationContext;\n        _logger = logger;\n        _renderBlockObservable = _renderBlock.AsSystemObservable();\n        _renderActionObservable = _renderAction.AsSystemObservable();\n        _renderActionErrorObservable = _renderActionError.AsSystemObservable();\n        _renderBlockEndObservable = _renderBlock.AsSystemObservable();\n    }\n\n    IObservable<RenderBlockInfo> IRendererService.RenderBlock\n        => _renderBlockObservable ??= _renderBlock.AsSystemObservable();\n\n    IObservable<RenderActionInfo> IRendererService.RenderAction\n        => _renderActionObservable ??= _renderAction.AsSystemObservable();\n\n    IObservable<RenderActionErrorInfo> IRendererService.RenderActionError\n        => _renderActionErrorObservable ??= _renderActionError.AsSystemObservable();\n\n    IObservable<RenderBlockInfo> IRendererService.RenderBlockEnd\n        => _renderBlockEndObservable ??= _renderBlock.AsSystemObservable();\n\n    public void Dispose()\n    {\n        _renderBlock.Dispose();\n        _renderAction.Dispose();\n        _renderActionError.Dispose();\n        _renderBlockEnd.Dispose();\n    }\n\n    void IActionRenderer.RenderAction(\n        IValue action, ICommittedActionContext context, HashDigest<SHA256> nextState)\n    {\n        _synchronizationContext.Post(\n            state =>\n            {\n                _renderAction.OnNext(new(action, context, nextState));\n                _logger.LogDebug(\n                    \"Rendered an action: {Action} {Context} {NextState}\",\n                    action,\n                    context,\n                    nextState);\n            },\n            null);\n    }\n\n    void IActionRenderer.RenderActionError(\n        IValue action, ICommittedActionContext context, Exception exception)\n    {\n        _synchronizationContext.Post(\n            state =>\n            {\n                _renderActionError.OnNext(new(action, context, exception));\n                _logger.LogError(\n                    exception,\n                    \"Failed to render an action: {Action} {Context}\",\n                    action,\n                    context);\n            },\n            null);\n    }\n\n    void IRenderer.RenderBlock(Block oldTip, Block newTip)\n    {\n        _synchronizationContext.Post(\n            state =>\n            {\n                _renderBlock.OnNext(new(oldTip, newTip));\n                _logger.LogDebug(\n                    \"Rendered a block: {OldTip} {NewTip}\",\n                    oldTip,\n                    newTip);\n            },\n            null);\n    }\n\n    void IActionRenderer.RenderBlockEnd(Block oldTip, Block newTip)\n    {\n        _synchronizationContext.Post(\n            state =>\n            {\n                _renderBlockEnd.OnNext(new(oldTip, newTip));\n                _logger.LogDebug(\n                    \"Rendered a block end: {OldTip} {NewTip}\",\n                    oldTip,\n                    newTip);\n            },\n            null);\n    }\n}\n"
  },
  {
    "path": "sdk/node/Libplanet.Node/Services/Seed.cs",
    "content": "using System.Net;\nusing Dasync.Collections;\nusing Libplanet.Crypto;\nusing Libplanet.Net;\nusing Libplanet.Net.Messages;\nusing Libplanet.Net.Options;\nusing Libplanet.Net.Transports;\nusing Libplanet.Node.Options;\nusing Serilog;\n\nnamespace Libplanet.Node.Services;\n\ninternal class Seed(SeedOptions seedOptions) : IAsyncDisposable\n{\n    private readonly ILogger _logger = Log.ForContext<Seed>();\n\n    private ITransport? _transport;\n    private CancellationTokenSource? _cancellationTokenSource;\n    private Task _task = Task.CompletedTask;\n    private Task _refreshTask = Task.CompletedTask;\n\n    public event EventHandler<SeedMessageEventArgs>? MessageReceived;\n\n    public ILogger Logger => _logger;\n\n    public bool IsRunning { get; private set; }\n\n    public PeerCollection Peers { get; } = new(seedOptions);\n\n    public BoundPeer BoundPeer => new(\n        PrivateKey.FromString(seedOptions.PrivateKey).PublicKey,\n        (DnsEndPoint)EndPointUtility.Parse(seedOptions.EndPoint));\n\n    public async Task StartAsync(CancellationToken cancellationToken)\n    {\n        if (IsRunning)\n        {\n            throw new InvalidOperationException(\"Seed node is already running.\");\n        }\n\n        _cancellationTokenSource\n            = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken);\n        _transport = await CreateTransport();\n        _transport.ProcessMessageHandler.Register(ReceiveMessageAsync);\n        _task = _transport.StartAsync(_cancellationTokenSource.Token);\n        await _transport.WaitForRunningAsync();\n        _refreshTask = RefreshContinuouslyAsync(_cancellationTokenSource.Token);\n        IsRunning = true;\n    }\n\n    public async Task StopAsync(CancellationToken cancellationToken)\n    {\n        if (!IsRunning)\n        {\n            throw new InvalidOperationException(\"Seed node is not running.\");\n        }\n\n        if (_cancellationTokenSource is not null)\n        {\n            await _cancellationTokenSource.CancelAsync();\n            _cancellationTokenSource.Dispose();\n            _cancellationTokenSource = null;\n        }\n\n        if (_transport is not null)\n        {\n            await _transport.StopAsync(TimeSpan.FromSeconds(0), cancellationToken);\n            _transport.Dispose();\n            _transport = null;\n        }\n\n        await _refreshTask;\n        await _task;\n        _refreshTask = Task.CompletedTask;\n        _task = Task.CompletedTask;\n        IsRunning = false;\n    }\n\n    public async ValueTask DisposeAsync()\n    {\n        if (_cancellationTokenSource is not null)\n        {\n            await _cancellationTokenSource.CancelAsync();\n            _cancellationTokenSource.Dispose();\n            _cancellationTokenSource = null;\n        }\n\n        if (_transport is not null)\n        {\n            _transport.Dispose();\n            _transport = null;\n        }\n\n        await _refreshTask;\n        await _task;\n        _refreshTask = Task.CompletedTask;\n        _task = Task.CompletedTask;\n    }\n\n    private async Task<NetMQTransport> CreateTransport()\n    {\n        var privateKey = PrivateKey.FromString(seedOptions.PrivateKey);\n        var appProtocolVersion = AppProtocolVersion.FromToken(seedOptions.AppProtocolVersion);\n        var appProtocolVersionOptions = new AppProtocolVersionOptions\n        {\n            AppProtocolVersion = appProtocolVersion,\n            TrustedAppProtocolVersionSigners = [],\n        };\n        var endPoint = (DnsEndPoint)EndPointUtility.Parse(seedOptions.EndPoint);\n        var host = endPoint.Host;\n        var port = endPoint.Port;\n        var hostOptions = new HostOptions(host, [], port);\n        return await NetMQTransport.Create(privateKey, appProtocolVersionOptions, hostOptions);\n    }\n\n    private async Task RefreshContinuouslyAsync(CancellationToken cancellationToken)\n    {\n        var interval = TimeSpan.FromSeconds(seedOptions.RefreshInterval);\n        var peers = Peers;\n        while (!cancellationToken.IsCancellationRequested)\n        {\n            try\n            {\n                await Task.Delay(interval, cancellationToken);\n                await peers.RefreshAsync(cancellationToken);\n            }\n            catch (TaskCanceledException)\n            {\n                break;\n            }\n        }\n    }\n\n    private async Task ReceiveMessageAsync(Message message)\n    {\n        if (_transport is null || _cancellationTokenSource is null)\n        {\n            throw new InvalidOperationException(\"Seed node is not running.\");\n        }\n\n        var messageIdentity = message.Identity;\n        var cancellationToken = _cancellationTokenSource.Token;\n        var transport = _transport;\n        var peers = Peers;\n\n        switch (message.Content)\n        {\n            case FindNeighborsMsg:\n                var alivePeers = peers.Where(item => item.IsAlive)\n                                      .Select(item => item.BoundPeer)\n                                      .ToArray();\n                var neighborsMsg = new NeighborsMsg(alivePeers);\n                await transport.ReplyMessageAsync(\n                    neighborsMsg,\n                    messageIdentity,\n                    cancellationToken: cancellationToken);\n                break;\n\n            default:\n                var pongMsg = new PongMsg();\n                await transport.ReplyMessageAsync(\n                    content: pongMsg,\n                    identity: messageIdentity,\n                    cancellationToken: cancellationToken);\n                break;\n        }\n\n        if (message.Remote is BoundPeer boundPeer)\n        {\n            peers.AddOrUpdate(boundPeer, transport);\n        }\n\n        MessageReceived?.Invoke(this, new SeedMessageEventArgs(message));\n    }\n}\n"
  },
  {
    "path": "sdk/node/Libplanet.Node/Services/SeedMessageEventArgs.cs",
    "content": "using Libplanet.Net.Messages;\n\nnamespace Libplanet.Node.Services;\n\ninternal sealed class SeedMessageEventArgs(Message message) : EventArgs\n{\n    public Message Message { get; } = message;\n}\n"
  },
  {
    "path": "sdk/node/Libplanet.Node/Services/SeedServiceBase.cs",
    "content": "using Libplanet.Net;\nusing Libplanet.Node.Options;\nusing Microsoft.Extensions.Hosting;\nusing Microsoft.Extensions.Logging;\n\nnamespace Libplanet.Node.Services;\n\ninternal class SeedServiceBase(SeedOptions seedOptions, ILogger logger)\n    : IHostedService\n{\n    private readonly Seed _seed = new(seedOptions);\n\n    public BoundPeer BoundPeer => _seed.BoundPeer;\n\n    public virtual string Name => GetType().Name;\n\n    public async Task StartAsync(CancellationToken cancellationToken)\n    {\n        var boundPeer = _seed.BoundPeer;\n        await _seed.StartAsync(cancellationToken);\n        logger.LogInformation(\"{Name} started: {Port}\", Name, boundPeer.EndPoint.Port);\n    }\n\n    public async Task StopAsync(CancellationToken cancellationToken)\n    {\n        await _seed.StopAsync(cancellationToken);\n        logger.LogInformation(\"{Name} stopped.\", Name);\n    }\n}\n"
  },
  {
    "path": "sdk/node/Libplanet.Node/Services/SoloProposeService.cs",
    "content": "using Libplanet.Blockchain;\nusing Libplanet.Crypto;\nusing Libplanet.Node.Options;\nusing Microsoft.Extensions.Hosting;\nusing Microsoft.Extensions.Logging;\nusing Microsoft.Extensions.Options;\n\nnamespace Libplanet.Node.Services;\n\ninternal sealed class SoloProposeService : BackgroundService\n{\n    private readonly BlockChain _blockChain;\n    private readonly PrivateKey _privateKey;\n    private readonly TimeSpan _blockInterval;\n    private readonly ILogger<SoloProposeService> _logger;\n\n    public SoloProposeService(\n        IBlockChainService blockChainService,\n        ILogger<SoloProposeService> logger,\n        IOptions<SoloOptions> soloProposeOption)\n    {\n        _blockChain = blockChainService.BlockChain;\n        var options = soloProposeOption.Value;\n        _privateKey = options.PrivateKey is null\n            ? new PrivateKey()\n            : PrivateKey.FromString(options.PrivateKey);\n        _blockInterval = TimeSpan.FromMilliseconds(options.BlockInterval);\n        _logger = logger;\n        _logger.LogInformation(\n            \"SoloProposeService initialized. Interval: {BlockInterval}\",\n            _blockInterval);\n    }\n\n    protected async override Task ExecuteAsync(CancellationToken stoppingToken)\n    {\n        try\n        {\n            await ProposeBlockAsync(stoppingToken);\n        }\n        catch (OperationCanceledException e)\n        {\n            _logger.LogInformation(e, \"Timed Hosted Service is stopping.\");\n        }\n    }\n\n    private async Task ProposeBlockAsync(CancellationToken cancellationToken)\n    {\n        while (!cancellationToken.IsCancellationRequested)\n        {\n            ProposeBlock();\n            await Task.Delay(_blockInterval, cancellationToken);\n        }\n    }\n\n    private void ProposeBlock()\n    {\n        var tip = _blockChain.Tip;\n        var block = _blockChain.ProposeBlock(\n            _privateKey,\n            _blockChain.GetBlockCommit(tip.Hash));\n        _blockChain.Append(\n            block,\n            _blockChain.GetBlockCommit(tip.Hash),\n            validate: false);\n\n        _logger.LogInformation(\n            \"Proposed block: {Height}: {Hash}\",\n            block.Index,\n            block.Hash);\n    }\n}\n"
  },
  {
    "path": "sdk/node/Libplanet.Node/Services/StoreService.cs",
    "content": "using Libplanet.Node.Options;\nusing Libplanet.RocksDBStore;\nusing Libplanet.Store;\nusing Libplanet.Store.Trie;\nusing Microsoft.Extensions.Options;\n\nnamespace Libplanet.Node.Services;\n\ninternal sealed class StoreService(IOptions<StoreOptions> storeOptions) : IStoreService\n{\n    private IStateStore? _stateStore;\n\n    public IStore Store { get; } = CreateStore(storeOptions.Value);\n\n    public IKeyValueStore KeyValueStore { get; } = CreateKeyValueStore(storeOptions.Value);\n\n    public IStateStore StateStore => _stateStore ??= new TrieStateStore(KeyValueStore);\n\n    private static IStore CreateStore(StoreOptions storeOptions)\n        => storeOptions.Type switch\n        {\n            StoreType.RocksDB => new RocksDBStore.RocksDBStore(storeOptions.StoreName),\n            StoreType.InMemory => new MemoryStore(),\n            _ => throw new NotSupportedException($\"Unsupported store type: {storeOptions.Type}\"),\n        };\n\n    private static IKeyValueStore CreateKeyValueStore(StoreOptions storeOptions)\n        => storeOptions.Type switch\n        {\n            StoreType.RocksDB => new RocksDBKeyValueStore(storeOptions.StateStoreName),\n            StoreType.InMemory => new MemoryKeyValueStore(),\n            _ => throw new NotSupportedException($\"Unsupported store type: {storeOptions.Type}\"),\n        };\n}\n"
  },
  {
    "path": "sdk/node/Libplanet.Node/Services/SwarmService.cs",
    "content": "using System.Net;\nusing Libplanet.Common;\nusing Libplanet.Crypto;\nusing Libplanet.Net;\nusing Libplanet.Net.Consensus;\nusing Libplanet.Net.Transports;\nusing Libplanet.Node.Options;\nusing Microsoft.Extensions.Hosting;\nusing Microsoft.Extensions.Logging;\nusing Microsoft.Extensions.Options;\nusing R3;\n\nnamespace Libplanet.Node.Services;\n\ninternal sealed class SwarmService(\n    IBlockChainService blockChainService,\n    IOptions<SwarmOptions> options,\n    IOptions<ValidatorOptions> validatorOptions,\n    ILogger<SwarmService> logger)\n    : IHostedService, ISwarmService, IAsyncDisposable\n{\n    private readonly SwarmOptions _options = options.Value;\n    private readonly ValidatorOptions _validatorOptions = validatorOptions.Value;\n    private readonly ILogger<SwarmService> _logger = logger;\n    private readonly Subject<Unit> _started = new();\n    private readonly Subject<Unit> _stopped = new();\n\n    private IObservable<Unit>? _startedObservable;\n    private IObservable<Unit>? _stoppedObservable;\n\n    private Swarm? _swarm;\n    private Task _startTask = Task.CompletedTask;\n    private Seed? _blocksyncSeed;\n    private Seed? _consensusSeed;\n\n    IObservable<Unit> ISwarmService.Started\n        => _startedObservable ??= _started.AsSystemObservable();\n\n    IObservable<Unit> ISwarmService.Stopped\n        => _stoppedObservable ??= _stopped.AsSystemObservable();\n\n    public bool IsRunning => _swarm is not null;\n\n    public Swarm Swarm => _swarm ?? throw new InvalidOperationException(\"Node is not running.\");\n\n    public async Task StartAsync(CancellationToken cancellationToken)\n    {\n        if (_swarm is not null)\n        {\n            throw new InvalidOperationException(\"Node is already running.\");\n        }\n\n        var seedPrivateKey = new PrivateKey();\n        var blockChain = blockChainService.BlockChain;\n\n        if (_options.BlocksyncSeedPeer == string.Empty)\n        {\n            _blocksyncSeed = new Seed(new()\n            {\n                PrivateKey = ByteUtil.Hex(seedPrivateKey.ByteArray),\n                EndPoint = EndPointUtility.ToString(EndPointUtility.Next()),\n                AppProtocolVersion = _options.AppProtocolVersion,\n            });\n            _options.BlocksyncSeedPeer = _blocksyncSeed.BoundPeer.PeerString;\n            await _blocksyncSeed.StartAsync(cancellationToken);\n        }\n\n        if (_validatorOptions.ConsensusSeedPeer == string.Empty)\n        {\n            _consensusSeed = new Seed(new()\n            {\n                PrivateKey = ByteUtil.Hex(seedPrivateKey.ByteArray),\n                EndPoint = EndPointUtility.ToString(EndPointUtility.Next()),\n                AppProtocolVersion = _options.AppProtocolVersion,\n            });\n            _validatorOptions.ConsensusSeedPeer = _consensusSeed.BoundPeer.PeerString;\n            await _consensusSeed.StartAsync(cancellationToken);\n        }\n\n        var nodeOptions = _options;\n        var privateKey = PrivateKey.FromString(nodeOptions.PrivateKey);\n        var appProtocolVersion = AppProtocolVersion.FromToken(nodeOptions.AppProtocolVersion);\n        var trustedAppProtocolVersionSigners = nodeOptions.TrustedAppProtocolVersionSigners\n            .Select(PublicKey.FromHex).ToArray();\n        var swarmEndPoint = (DnsEndPoint)EndPointUtility.Parse(nodeOptions.EndPoint);\n        var swarmTransport = await CreateTransport(\n            privateKey: privateKey,\n            endPoint: swarmEndPoint,\n            appProtocolVersion: appProtocolVersion,\n            trustedAppProtocolVersionSigners);\n        var blocksyncSeedPeer = BoundPeer.ParsePeer(nodeOptions.BlocksyncSeedPeer);\n        var swarmOptions = new Net.Options.SwarmOptions\n        {\n            StaticPeers = [blocksyncSeedPeer],\n            BootstrapOptions = new()\n            {\n                SeedPeers = [blocksyncSeedPeer],\n            },\n        };\n\n        var consensusTransport = _validatorOptions.IsEnabled\n            ? await CreateConsensusTransportAsync(\n                privateKey,\n                appProtocolVersion,\n                trustedAppProtocolVersionSigners,\n                _validatorOptions,\n                cancellationToken)\n            : null;\n        var consensusReactorOption = _validatorOptions.IsEnabled\n            ? CreateConsensusReactorOption(privateKey, _validatorOptions)\n            : (ConsensusReactorOption?)null;\n\n        _swarm = new Swarm(\n            blockChain: blockChain,\n            privateKey: privateKey,\n            transport: swarmTransport,\n            options: swarmOptions,\n            consensusTransport: consensusTransport,\n            consensusOption: consensusReactorOption);\n        _startTask = _swarm.StartAsync(cancellationToken: default);\n        _logger.LogDebug(\"Node.Swarm is starting: {Address}\", _swarm.Address);\n        await _swarm.BootstrapAsync(cancellationToken: default);\n        _logger.LogDebug(\"Node.Swarm is bootstrapped: {Address}\", _swarm.Address);\n        _started.OnNext(Unit.Default);\n    }\n\n    public async Task StopAsync(CancellationToken cancellationToken)\n    {\n        if (_swarm is null)\n        {\n            throw new InvalidOperationException(\"Node is not running.\");\n        }\n\n        await _swarm.StopAsync(cancellationToken: cancellationToken);\n        await _startTask;\n        _logger.LogDebug(\"Node.Swarm is stopping: {Address}\", _swarm.Address);\n        _swarm.Dispose();\n        _logger.LogDebug(\"Node.Swarm is stopped: {Address}\", _swarm.Address);\n\n        _swarm = null;\n        _startTask = Task.CompletedTask;\n\n        if (_consensusSeed is not null)\n        {\n            await _consensusSeed.StopAsync(cancellationToken: default);\n            _consensusSeed = null;\n        }\n\n        if (_blocksyncSeed is not null)\n        {\n            await _blocksyncSeed.StopAsync(cancellationToken: default);\n            _blocksyncSeed = null;\n        }\n\n        _stopped.OnNext(Unit.Default);\n    }\n\n    public async ValueTask DisposeAsync()\n    {\n        if (_swarm is not null)\n        {\n            await _swarm.StopAsync(cancellationToken: default);\n            _swarm.Dispose();\n        }\n\n        await (_startTask ?? Task.CompletedTask);\n        _startTask = Task.CompletedTask;\n\n        if (_consensusSeed is not null)\n        {\n            await _consensusSeed.StopAsync(cancellationToken: default);\n            _consensusSeed = null;\n        }\n\n        if (_blocksyncSeed is not null)\n        {\n            await _blocksyncSeed.StopAsync(cancellationToken: default);\n            _blocksyncSeed = null;\n        }\n    }\n\n    private static async Task<NetMQTransport> CreateTransport(\n        PrivateKey privateKey,\n        DnsEndPoint endPoint,\n        AppProtocolVersion appProtocolVersion,\n        PublicKey[] trustedAppProtocolVersionSigners)\n    {\n        var appProtocolVersionOptions = new Net.Options.AppProtocolVersionOptions\n        {\n            AppProtocolVersion = appProtocolVersion,\n            TrustedAppProtocolVersionSigners = [.. trustedAppProtocolVersionSigners],\n        };\n        var hostOptions = new Net.Options.HostOptions(endPoint.Host, [], endPoint.Port);\n        return await NetMQTransport.Create(\n            privateKey,\n            appProtocolVersionOptions,\n            hostOptions,\n            TimeSpan.FromSeconds(60));\n    }\n\n    private static ConsensusReactorOption CreateConsensusReactorOption(\n        PrivateKey privateKey, ValidatorOptions options)\n    {\n        var consensusSeedPeer = BoundPeer.ParsePeer(options.ConsensusSeedPeer);\n        var consensusEndPoint = (DnsEndPoint)EndPointUtility.Parse(options.EndPoint);\n        return new ConsensusReactorOption\n        {\n            SeedPeers = [consensusSeedPeer],\n            ConsensusPort = consensusEndPoint.Port,\n            ConsensusPrivateKey = privateKey,\n            TargetBlockInterval = TimeSpan.FromSeconds(2),\n            ContextOption = new(),\n        };\n    }\n\n    private static async Task<NetMQTransport> CreateConsensusTransportAsync(\n        PrivateKey privateKey,\n        AppProtocolVersion appProtocolVersion,\n        PublicKey[] trustedAppProtocolVersionSigners,\n        ValidatorOptions options,\n        CancellationToken cancellationToken)\n    {\n        var consensusEndPoint = (DnsEndPoint)EndPointUtility.Parse(options.EndPoint);\n        await Task.Delay(1, cancellationToken);\n        return await CreateTransport(\n            privateKey: privateKey,\n            endPoint: consensusEndPoint,\n            appProtocolVersion: appProtocolVersion,\n            trustedAppProtocolVersionSigners);\n    }\n}\n"
  },
  {
    "path": "sdk/node/Libplanet.Node/Services/TransactionService.cs",
    "content": "using Libplanet.Blockchain;\nusing Libplanet.Types.Tx;\n\nnamespace Libplanet.Node.Services;\n\ninternal sealed class TransactionService(IBlockChainService blockChainService)\n{\n    private readonly BlockChain _blockChain = blockChainService.BlockChain;\n\n    public void StageTransaction(Transaction transaction) =>\n        _blockChain.StageTransaction(transaction);\n}\n"
  },
  {
    "path": "sdk/node/Libplanet.Node/Services/ValidatorService.cs",
    "content": "using Libplanet.Node.Options;\nusing Microsoft.Extensions.Options;\n\nnamespace Libplanet.Node.Services;\n\ninternal sealed class ValidatorService(IOptions<ValidatorOptions> options) : IValidatorService\n{\n    // TODO: The consensus reactor settings should be implemented here in order to pass them as parameters to the Swarm constructor.\n#pragma warning disable S1144 // Unused private types or members should be removed\n    private readonly ValidatorOptions _options = options.Value;\n#pragma warning restore S1144 // Unused private types or members should be removed\n}\n"
  },
  {
    "path": "sdk/node/Libplanet.Node.Executable/BlockChainRendererTracer.cs",
    "content": "using Libplanet.Node.Services;\n\nnamespace Libplanet.Node.API;\n\ninternal sealed class BlockChainRendererTracer(\n    IRendererService rendererService, ILogger<BlockChainRendererTracer> logger)\n    : IHostedService\n{\n    private readonly ILogger<BlockChainRendererTracer> _logger = logger;\n    private IDisposable? _observer;\n\n    public Task StartAsync(CancellationToken cancellationToken)\n    {\n        rendererService.RenderBlockEnd.Subscribe(\n            info => _logger.LogInformation(\n                \"-Pattern2- #{Height} Block end: {Hash}\",\n                info.NewTip.Index,\n                info.NewTip.Hash));\n        return Task.CompletedTask;\n    }\n\n    public Task StopAsync(CancellationToken cancellationToken)\n    {\n        _observer?.Dispose();\n        _observer = null;\n        return Task.CompletedTask;\n    }\n}\n"
  },
  {
    "path": "sdk/node/Libplanet.Node.Executable/Dockerfile",
    "content": "FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS base\nWORKDIR /app\nEXPOSE 80\nEXPOSE 443\n\nFROM mcr.microsoft.com/dotnet/sdk:8.0 AS build\nARG BUILD_CONFIGURATION=Release\nWORKDIR /src\nCOPY [\"sdk/node/Libplanet.Node.API/Libplanet.Node.API.csproj\", \"sdk/node/Libplanet.Node.API/\"]\nRUN dotnet restore \"sdk/node/Libplanet.Node.API/Libplanet.Node.API.csproj\"\nCOPY . .\nWORKDIR \"/src/sdk/node/Libplanet.Node.API\"\nRUN dotnet build \"Libplanet.Node.API.csproj\" -c $BUILD_CONFIGURATION -o /app/build\n\nFROM build AS publish\nARG BUILD_CONFIGURATION=Release\nRUN dotnet publish \"Libplanet.Node.API.csproj\" -c $BUILD_CONFIGURATION -o /app/publish /p:UseAppHost=false\n\nFROM base AS final\nWORKDIR /app\nCOPY --from=publish /app/publish .\nENTRYPOINT [\"dotnet\", \"Libplanet.Node.API.dll\"]\n"
  },
  {
    "path": "sdk/node/Libplanet.Node.Executable/Explorer/BlockChainContext.cs",
    "content": "using System.Reflection;\nusing Libplanet.Blockchain;\nusing Libplanet.Explorer.Indexing;\nusing Libplanet.Explorer.Interfaces;\nusing Libplanet.Net;\nusing Libplanet.Node.Services;\nusing Libplanet.Store;\n\nnamespace Libplanet.Node.API.Explorer;\n\ninternal sealed class BlockChainContext(\n    IBlockChainService blockChainService, ISwarmService swarmService) : IBlockChainContext\n{\n    public bool Preloaded => false;\n\n    public BlockChain BlockChain => blockChainService.BlockChain;\n\n#pragma warning disable S3011 // Reflection should not be used to increase accessibility ...\n    public IStore Store\n    {\n        get\n        {\n            var bindingFlags = BindingFlags.NonPublic | BindingFlags.Instance;\n            var propertyInfo = typeof(BlockChain).GetProperty(\"Store\", bindingFlags) ??\n                throw new InvalidOperationException(\"Store property not found.\");\n            if (propertyInfo.GetValue(BlockChain) is IStore store)\n            {\n                return store;\n            }\n\n            throw new InvalidOperationException(\"Store property is not IStore.\");\n        }\n    }\n#pragma warning restore S3011\n\n    public Swarm Swarm => swarmService.Swarm;\n\n    public IBlockChainIndex Index => throw new NotSupportedException();\n}\n"
  },
  {
    "path": "sdk/node/Libplanet.Node.Executable/Explorer/ExplorerExtensions.cs",
    "content": "using Libplanet.Explorer;\nusing Libplanet.Node.Extensions;\n\nnamespace Libplanet.Node.API.Explorer;\n\npublic static class ExplorerExtensions\n{\n    public static IServiceCollection AddNodeExplorer(\n        this IServiceCollection services)\n    {\n        var serviceProvider = services.BuildServiceProvider();\n\n        services.AddSingleton<BlockChainContext>();\n        services.AddSingleton<ExplorerStartup<BlockChainContext>>();\n        serviceProvider = services.BuildServiceProvider();\n        var startUp\n            = serviceProvider.GetRequiredService<ExplorerStartup<BlockChainContext>>();\n        startUp.ConfigureServices(services);\n\n        return services;\n    }\n\n    public static IApplicationBuilder UseNodeExplorer(this IApplicationBuilder builder)\n    {\n        var serviceProvider = builder.ApplicationServices;\n        var environment = serviceProvider.GetRequiredService<IWebHostEnvironment>();\n        var startUp = serviceProvider.GetService<ExplorerStartup<BlockChainContext>>();\n        startUp?.Configure(builder, environment);\n\n        return builder;\n    }\n\n    public static bool IsExplorerEnabled(this IHostApplicationBuilder builder)\n        => builder.Configuration.IsOptionsEnabled(ExplorerOptions.Position);\n}\n"
  },
  {
    "path": "sdk/node/Libplanet.Node.Executable/Explorer/ExplorerOptions.cs",
    "content": "using System.ComponentModel;\nusing Libplanet.Node.Options;\n\nnamespace Libplanet.Node.API.Explorer;\n\n[Options(Position)]\npublic sealed class ExplorerOptions : OptionsBase<ExplorerOptions>\n{\n    public const string Position = \"Explorer\";\n\n    [DefaultValue(true)]\n    public bool IsEnabled { get; set; } = true;\n}\n"
  },
  {
    "path": "sdk/node/Libplanet.Node.Executable/Libplanet.Node.Executable.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk.Web\">\n\n  <PropertyGroup>\n    <DockerDefaultTargetOS>Linux</DockerDefaultTargetOS>\n    <RootNamespace>Libplanet.Node.API</RootNamespace>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <Protobuf Include=\"Protos\\*.proto\" GrpcServices=\"Server\"/>\n  </ItemGroup>\n\n  <ItemGroup>\n    <PackageReference Include=\"Grpc.AspNetCore\" Version=\"2.40.0\"/>\n    <PackageReference Include=\"Grpc.AspNetCore.Server.Reflection\" Version=\"2.64.0\" />\n    <PackageReference Include=\"Swashbuckle.AspNetCore.Swagger\" Version=\"6.7.0\" />\n    <PackageReference Include=\"Swashbuckle.AspNetCore.SwaggerGen\" Version=\"6.7.0\" />\n    <PackageReference Include=\"Swashbuckle.AspNetCore.SwaggerUI\" Version=\"6.7.0\" />\n    <PackageReference Include=\"Microsoft.AspNetCore.Authentication.JwtBearer\" Version=\"8.0.7\" />\n    <PackageReference Include=\"Serilog.Sinks.Console\" Version=\"6.0.0\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <Content Include=\"..\\..\\..\\.dockerignore\">\n      <Link>.dockerignore</Link>\n    </Content>\n  </ItemGroup>\n\n  <ItemGroup>\n    <ProjectReference Include=\"..\\..\\..\\tools\\Libplanet.Explorer.Executable\\Libplanet.Explorer.Executable.csproj\" />\n    <ProjectReference Include=\"..\\..\\..\\src\\Libplanet.Crypto.Secp256k1\\Libplanet.Crypto.Secp256k1.csproj\" />\n    <ProjectReference Include=\"..\\Libplanet.Node.Extensions\\Libplanet.Node.Extensions.csproj\" />\n    <ProjectReference Include=\"..\\Libplanet.Node\\Libplanet.Node.csproj\" />\n  </ItemGroup>\n\n</Project>\n"
  },
  {
    "path": "sdk/node/Libplanet.Node.Executable/Program.cs",
    "content": "using Libplanet.Node.API;\nusing Libplanet.Node.API.Explorer;\nusing Libplanet.Node.API.Services;\nusing Libplanet.Node.Extensions;\nusing Microsoft.AspNetCore.Server.Kestrel.Core;\nusing Serilog;\nusing Serilog.Events;\n\nvar builder = WebApplication.CreateBuilder(args);\nbuilder.Logging.AddConsole();\nif (builder.Environment.IsDevelopment())\n{\n    builder.WebHost.ConfigureKestrel(options =>\n    {\n        // Setup a HTTP/2 endpoint without TLS.\n        options.ListenLocalhost(5259, o => o.Protocols =\n            HttpProtocols.Http1AndHttp2);\n        options.ListenLocalhost(5260, o => o.Protocols =\n            HttpProtocols.Http2);\n    });\n\n    builder.Services.AddEndpointsApiExplorer();\n    builder.Services.AddSwaggerGen();\n    builder.Services.AddAuthorization();\n    builder.Services.AddAuthentication(\"Bearer\").AddJwtBearer();\n}\n\nbuilder.Services.AddGrpc();\nbuilder.Services.AddGrpcReflection();\nbuilder.Services.AddLibplanetNode(builder.Configuration);\nbuilder.Services.AddHostedService<BlockChainRendererTracer>();\n\nif (builder.IsExplorerEnabled())\n{\n    builder.Services.AddNodeExplorer();\n}\n\nvar handlerMessage = \"\"\"\n    Communication with gRPC endpoints must be made through a gRPC client. To learn how to\n    create a client, visit: https://go.microsoft.com/fwlink/?linkid=2086909\n    \"\"\";\nusing var app = builder.Build();\n\napp.MapGrpcService<BlockchainGrpcServiceV1>();\napp.MapGrpcService<SchemaGrpcServiceV1>();\napp.MapGet(\"/\", () => handlerMessage);\nif (builder.Environment.IsDevelopment())\n{\n    app.MapGrpcReflectionService().AllowAnonymous();\n\n    app.UseSwagger();\n    app.UseSwaggerUI();\n}\n\napp.MapSchemaBuilder(\"/v1/schema\");\napp.MapGet(\"/schema\", context => Task.Run(() => context.Response.Redirect(\"/v1/schema\")));\n\nif (builder.IsExplorerEnabled())\n{\n    app.UseNodeExplorer();\n}\n\nawait app.RunAsync();\n"
  },
  {
    "path": "sdk/node/Libplanet.Node.Executable/Properties/launchSettings.json",
    "content": "{\n  \"profiles\": {\n    \"Libplanet.Node.API\": {\n      \"commandName\": \"Project\",\n      \"dotnetRunMessages\": true,\n      \"launchBrowser\": false,\n      \"applicationUrl\": \"http://localhost:5259\",\n      \"environmentVariables\": {\n        \"ASPNETCORE_ENVIRONMENT\": \"Development\"\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "sdk/node/Libplanet.Node.Executable/Protos/blockchain.proto",
    "content": "syntax = \"proto3\";\n\noption csharp_namespace = \"Libplanet.Node.API\";\n\npackage node.blockchain.v1;\n\nservice Blockchain {\n  rpc GetGenesisBlock (GetGenesisBlockRequest) returns (GetGenesisBlockReply);\n  rpc GetTip(Empty) returns (GetTipReply);\n  rpc GetBlock(GetBlockRequest) returns (GetBlockReply);\n}\n\nmessage Empty {\n}\n\nmessage GetGenesisBlockRequest {\n}\n\nmessage GetGenesisBlockReply {\n  string hash = 1;\n}\n\nmessage GetTipReply {\n  string hash = 1;\n  int64 height = 2;\n}\n\nmessage GetBlockRequest {\n  oneof block_identifier {\n    int64 height = 1;\n    string hash = 2;\n  }\n}\n\nmessage GetBlockReply {\n  string hash = 1;\n  int64 height = 2;\n  string miner = 3;\n  string public_key = 4;\n  string previous_hash = 5;\n  string state_root_hash = 6;\n  string signature = 7;\n  int64 protocol_version = 8;\n}\n"
  },
  {
    "path": "sdk/node/Libplanet.Node.Executable/Protos/schema.proto",
    "content": "syntax = \"proto3\";\n\noption csharp_namespace = \"Libplanet.Node.API\";\n\npackage node.schema.v1;\n\nservice Schema {\n  rpc GetList(GetListRequest) returns (GetListReply);\n  rpc GetSchema(GetSchemaRequest) returns (GetSchemaReply);\n}\n\nmessage GetListRequest {\n}\n\nmessage GetListReply {\n  repeated string list = 1;\n}\n\nmessage GetSchemaRequest {\n}\n\nmessage GetSchemaReply {\n  string schema = 1;\n}\n"
  },
  {
    "path": "sdk/node/Libplanet.Node.Executable/Protos/seed.proto",
    "content": "syntax = \"proto3\";\n\noption csharp_namespace = \"Libplanet.Node.API\";\n\npackage node;\n\n// The greeting service definition.\nservice Seed {\n  // Sends a greeting\n  rpc GetSeed(GetSeedRequest) returns (GetSeedReply);\n}\n\nmessage GetSeedRequest {\n}\n\nmessage GetSeedReply {\n  string blocksync_seed = 1;\n  string consensus_seed = 2;\n}\n"
  },
  {
    "path": "sdk/node/Libplanet.Node.Executable/Services/BlockchainGrpcServiceV1.cs",
    "content": "using Grpc.Core;\nusing Libplanet.Common;\nusing Libplanet.Node.Services;\nusing Libplanet.Types.Blocks;\n\nnamespace Libplanet.Node.API.Services;\n\npublic class BlockchainGrpcServiceV1(IReadChainService blockChain) : Blockchain.BlockchainBase\n{\n    private readonly IReadChainService _blockChain = blockChain;\n\n    public override Task<GetGenesisBlockReply> GetGenesisBlock(\n        GetGenesisBlockRequest request,\n        ServerCallContext context)\n    {\n        return Task.FromResult(new GetGenesisBlockReply\n        {\n            Hash = _blockChain.Tip.Hash.ToString(),\n        });\n    }\n\n    public override Task<GetTipReply> GetTip(Empty request, ServerCallContext context)\n    {\n        return Task.FromResult(new GetTipReply\n        {\n            Hash = _blockChain.Tip.Hash.ToString(),\n            Height = _blockChain.Tip.Index,\n        });\n    }\n\n    public override Task<GetBlockReply> GetBlock(GetBlockRequest request, ServerCallContext context)\n    {\n        return Task.Run(GetResult);\n\n        Block GetBlock() => request.BlockIdentifierCase switch\n        {\n            GetBlockRequest.BlockIdentifierOneofCase.Hash\n                => _blockChain.GetBlock(BlockHash.FromString(request.Hash)),\n            GetBlockRequest.BlockIdentifierOneofCase.Height\n                => _blockChain.GetBlock(request.Height),\n            _ => throw new InvalidOperationException(\"Invalid block identifier.\"),\n        };\n\n        GetBlockReply GetResult()\n        {\n            var block = GetBlock();\n            return new GetBlockReply\n            {\n                Hash = block.Hash.ToString(),\n                Height = block.Index,\n                Miner = block.Miner.ToString(),\n                PublicKey = $\"{block.PublicKey}\",\n                PreviousHash = $\"{block.PreviousHash}\",\n                StateRootHash = $\"{block.StateRootHash}\",\n                Signature = $\"{ByteUtil.Hex(block.Signature ?? [])}\",\n                ProtocolVersion = block.ProtocolVersion,\n            };\n        }\n    }\n}\n"
  },
  {
    "path": "sdk/node/Libplanet.Node.Executable/Services/SchemaGrpcServiceV1.cs",
    "content": "using Grpc.Core;\nusing Libplanet.Node.Options;\nusing Libplanet.Node.Options.Schema;\n\nnamespace Libplanet.Node.API.Services;\n\ninternal sealed class SchemaGrpcServiceV1 : Schema.SchemaBase\n{\n    private string[]? _list;\n    private string? _schema;\n\n    public override async Task<GetListReply> GetList(\n        GetListRequest request, ServerCallContext context)\n    {\n        _list ??= await Task.Run(GetOptionsList);\n\n        return new GetListReply\n        {\n            List = { _list },\n        };\n    }\n\n    public override async Task<GetSchemaReply> GetSchema(\n        GetSchemaRequest request, ServerCallContext context)\n    {\n        _schema ??= await GetOptionsSchemaAsync(context.CancellationToken);\n\n        return new GetSchemaReply\n        {\n            Schema = _schema,\n        };\n    }\n\n    private static string[] GetOptionsList()\n    {\n        var optionsTypes = ServiceUtility.GetTypes(typeof(OptionsAttribute), inherit: true);\n        var optionList = new List<string>();\n        foreach (var optionsType in optionsTypes)\n        {\n            var optionsAttributes = GetAttributes(optionsType, scope: string.Empty);\n            foreach (var optionsAttribute in optionsAttributes)\n            {\n                optionList.Add(optionsAttribute.Name);\n            }\n        }\n\n        return [.. optionList];\n    }\n\n    private static async Task<string> GetOptionsSchemaAsync(CancellationToken cancellationToken)\n    {\n        var schemaBuilder = new OptionsSchemaBuilder();\n        var optionsTypes = ServiceUtility.GetTypes(typeof(OptionsAttribute), inherit: true);\n        foreach (var optionsType in optionsTypes)\n        {\n            var optionsAttributes = GetAttributes(optionsType, scope: string.Empty);\n            foreach (var optionsAttribute in optionsAttributes)\n            {\n                schemaBuilder.Add(optionsAttribute.Name, optionsType);\n            }\n\n            cancellationToken.ThrowIfCancellationRequested();\n        }\n\n        return await schemaBuilder.BuildAsync(cancellationToken);\n    }\n\n    private static IEnumerable<OptionsAttribute> GetAttributes(Type type, string scope)\n        => Attribute.GetCustomAttributes(type, typeof(OptionsAttribute))\n            .OfType<OptionsAttribute>();\n}\n"
  },
  {
    "path": "sdk/node/Libplanet.Node.Executable/Services/SeedGrpcService.cs",
    "content": "using Grpc.Core;\nusing Libplanet.Node.Services;\n\nnamespace Libplanet.Node.API.Services;\n\npublic class SeedGrpcService(\n    IServiceProvider serviceProvider)\n    : Seed.SeedBase\n{\n    public override Task<GetSeedReply> GetSeed(GetSeedRequest request, ServerCallContext context)\n    {\n        var blocksyncSeedService = serviceProvider.GetService<IBlocksyncSeedService>();\n        var consensusSeedService = serviceProvider.GetService<IConsensusSeedService>();\n        if (blocksyncSeedService is null || consensusSeedService is null)\n        {\n            throw new RpcException(\n                new Status(StatusCode.Unavailable, \"Seed services are not available.\"));\n        }\n\n        return Task.FromResult(new GetSeedReply\n        {\n            BlocksyncSeed = EndPointUtility.ToString(blocksyncSeedService.BoundPeer.EndPoint),\n            ConsensusSeed = EndPointUtility.ToString(consensusSeedService.BoundPeer.EndPoint),\n        });\n    }\n}\n"
  },
  {
    "path": "sdk/node/Libplanet.Node.Executable/appsettings-schema.json",
    "content": "{\n  \"$schema\": \"http://json-schema.org/draft-04/schema#\",\n  \"definitions\": {\n    \"appsettings\": {\n      \"$schema\": \"http://json-schema.org/draft-04/schema#\",\n      \"id\": \"https://json.schemastore.org/appsettings.json\",\n      \"title\": \"JSON schema ASP.NET Core's appsettings.json file\",\n      \"type\": \"object\",\n      \"properties\": {\n        \"Kestrel\": {\n          \"$ref\": \"#/definitions/appsettings/definitions/kestrel\"\n        },\n        \"Logging\": {\n          \"$ref\": \"#/definitions/appsettings/definitions/logging\"\n        },\n        \"AllowedHosts\": {\n          \"$ref\": \"#/definitions/appsettings/definitions/allowedHosts\"\n        },\n        \"ConnectionStrings\": {\n          \"$ref\": \"#/definitions/appsettings/definitions/connectionStrings\"\n        }\n      },\n      \"patternProperties\": {\n        \"^WebOptimizer$\": {\n          \"$ref\": \"#/definitions/appsettings/definitions/webOptimizer\"\n        },\n        \"^webOptimizer$\": {\n          \"$ref\": \"#/definitions/appsettings/definitions/webOptimizer\"\n        },\n        \"^weboptimizer$\": {\n          \"$ref\": \"#/definitions/appsettings/definitions/webOptimizer\"\n        },\n        \"^(cdn|Cdn)$\": {\n          \"$ref\": \"#/definitions/appsettings/definitions/cdn\"\n        },\n        \"^(pwa|PWA|Pwa)$\": {\n          \"$ref\": \"#/definitions/appsettings/definitions/pwa\"\n        },\n        \"^(ElmahIo|Elmahio|elmahIo|elmahio)$\": {\n          \"$ref\": \"#/definitions/appsettings/definitions/ElmahIo\"\n        },\n        \"^(nlog|Nlog|NLog)$\": {\n          \"$ref\": \"#/definitions/appsettings/definitions/NLog\"\n        },\n        \"^(Serilog|serilog)$\": {\n          \"$ref\": \"#/definitions/appsettings/definitions/Serilog\"\n        }\n      },\n      \"definitions\": {\n        \"webOptimizer\": {\n          \"title\": \"web optimizer\",\n          \"type\": \"object\",\n          \"description\": \"Settings for WebOptimizer.Core\",\n          \"properties\": {\n            \"enableCaching\": {\n              \"type\": \"boolean\",\n              \"description\": \"Determines if the \\\"cache-control\\\" HTTP headers should be set and if conditional GET (304) requests should be supported. This could be helpful to disable while in development mode.\"\n            },\n            \"enableTagHelperBundling\": {\n              \"type\": \"boolean\",\n              \"description\": \"Determines if `<script>` and `<link>` elements should point to the bundled path or a reference per source file should be created. This is helpful to disable when in development mode.\",\n              \"default\": true\n            }\n          }\n        },\n        \"cdn\": {\n          \"title\": \"CDN\",\n          \"type\": \"object\",\n          \"description\": \"Definitions for WebEssentials.AspNetCore.CdnTagHelpers\",\n          \"properties\": {\n            \"url\": {\n              \"type\": \"string\",\n              \"description\": \"An absolute URL used as a prefix for static resources\",\n              \"pattern\": \"^((//|https?://).+|)$\"\n            },\n            \"prefetch\": {\n              \"type\": \"boolean\",\n              \"description\": \"If true, injects a <link rel='dns-prefetch'> tag that speeds up DNS resolution to the CDN.\",\n              \"default\": true\n            }\n          }\n        },\n        \"pwa\": {\n          \"properties\": {\n            \"cacheId\": {\n              \"type\": \"string\",\n              \"description\": \"The cache identifier of the service worker (can be any string). Change this property to force the service worker to reload in browsers.\",\n              \"default\": \"v1.0\"\n            },\n            \"offlineRoute\": {\n              \"type\": \"string\",\n              \"description\": \"The route to the page to show when offline.\",\n              \"default\": \"/offline.html\"\n            },\n            \"registerServiceWorker\": {\n              \"type\": \"boolean\",\n              \"description\": \"Determines if a script that registers the service worker should be injected into the bottom of the HTML page.\",\n              \"default\": true\n            },\n            \"registerWebmanifest\": {\n              \"type\": \"boolean\",\n              \"description\": \"Determines if a meta tag that points to the web manifest should be inserted at the end of the head element.\",\n              \"default\": true\n            },\n            \"routesToPreCache\": {\n              \"type\": \"string\",\n              \"description\": \"A comma separated list of routes to pre-cache when service worker installs in the browser.\",\n              \"default\": \"\"\n            },\n            \"strategy\": {\n              \"description\": \"Selects one of the predefined service worker types.\",\n              \"default\": \"cacheFirstSafe\",\n              \"enum\": [\n                \"cacheFirst\",\n                \"cacheFirstSafe\",\n                \"minimal\",\n                \"networkFirst\"\n              ]\n            }\n          }\n        },\n        \"ElmahIo\": {\n          \"required\": [\n            \"ApiKey\",\n            \"LogId\"\n          ],\n          \"properties\": {\n            \"ApiKey\": {\n              \"type\": \"string\",\n              \"description\": \"An elmah.io API key with the Messages | Write permission.\",\n              \"pattern\": \"^([0-9a-f]{32})|(#\\\\{.*\\\\}#?)$\"\n            },\n            \"LogId\": {\n              \"type\": \"string\",\n              \"description\": \"The Id of the elmah.io log to store messages in.\",\n              \"pattern\": \"^([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})|(#\\\\{.*\\\\}#?)$\"\n            },\n            \"Application\": {\n              \"type\": \"string\",\n              \"description\": \"An application name to put on all error messages.\"\n            },\n            \"HandledStatusCodesToLog\": {\n              \"type\": \"array\",\n              \"description\": \"A list of HTTP status codes (besides 404) to log even though no exception is thrown.\",\n              \"items\": {\n                \"type\": \"integer\"\n              }\n            },\n            \"TreatLoggingAsBreadcrumbs\": {\n              \"type\": \"boolean\",\n              \"description\": \"Include log messages from Microsoft.Extensions.Logging as breadcrumbs.\"\n            },\n            \"HeartbeatId\": {\n              \"type\": \"string\",\n              \"description\": \"The Id of the elmah.io heartbeat to notify.\",\n              \"pattern\": \"^([0-9a-f]{32})|(#\\\\{.*\\\\}#?)$\"\n            }\n          }\n        },\n        \"protocols\": {\n          \"type\": \"string\",\n          \"description\": \"The protocols enabled on the endpoint.\",\n          \"enum\": [\n            \"None\",\n            \"Http1\",\n            \"Http2\",\n            \"Http1AndHttp2\",\n            \"Http3\",\n            \"Http1AndHttp2AndHttp3\"\n          ]\n        },\n        \"certificate\": {\n          \"title\": \"certificate\",\n          \"type\": \"object\",\n          \"description\": \"Certificate configuration.\",\n          \"properties\": {\n            \"Path\": {\n              \"type\": \"string\",\n              \"description\": \"The certificate file path. If a file path is specified then the certificate will be loaded from the file system.\"\n            },\n            \"KeyPath\": {\n              \"type\": \"string\",\n              \"description\": \"The certificate key file path. Available in .NET 5 and later.\"\n            },\n            \"Password\": {\n              \"type\": \"string\",\n              \"description\": \"The certificate password used to access the private key.\"\n            },\n            \"Subject\": {\n              \"type\": \"string\",\n              \"description\": \"The certificate subject. If a subject is specified then the certificate will be loaded from the certificate store.\"\n            },\n            \"Store\": {\n              \"type\": \"string\",\n              \"description\": \"The certificate store name. Defaults to 'My'.\",\n              \"default\": \"My\"\n            },\n            \"Location\": {\n              \"type\": \"string\",\n              \"description\": \"The certificate store location. Defaults to 'CurrentUser'.\",\n              \"default\": \"CurrentUser\",\n              \"enum\": [\n                \"LocalMachine\",\n                \"CurrentUser\"\n              ]\n            },\n            \"AllowInvalid\": {\n              \"type\": \"boolean\",\n              \"description\": \"A value indicating whether or not to load certificates that are considered invalid. Defaults to false.\",\n              \"default\": false\n            }\n          }\n        },\n        \"sslProtocols\": {\n          \"type\": \"array\",\n          \"description\": \"Specifies allowable SSL protocols. Defaults to 'None' which allows the operating system to choose the best protocol to use, and to block protocols that are not secure. Unless your app has a specific reason not to, you should use this default. Available in .NET 5 and later.\",\n          \"items\": {\n            \"type\": \"string\",\n            \"default\": \"None\",\n            \"enum\": [\n              \"None\",\n              \"Tls\",\n              \"Tls11\",\n              \"Tls12\",\n              \"Tls13\"\n            ]\n          }\n        },\n        \"clientCertificateMode\": {\n          \"type\": \"string\",\n          \"description\": \"Specifies the client certificate requirements for a HTTPS connection. Defaults to 'NoCertificate'. Available in .NET 5 and later.\",\n          \"default\": \"NoCertificate\",\n          \"enum\": [\n            \"NoCertificate\",\n            \"AllowCertificate\",\n            \"RequireCertificate\"\n          ]\n        },\n        \"kestrel\": {\n          \"title\": \"kestrel\",\n          \"type\": \"object\",\n          \"description\": \"ASP.NET Core Kestrel server configuration.\",\n          \"properties\": {\n            \"Endpoints\": {\n              \"title\": \"endpoints\",\n              \"type\": \"object\",\n              \"description\": \"Endpoints that Kestrel listens to for network requests. Each endpoint has a name specified by its JSON property name.\",\n              \"additionalProperties\": {\n                \"title\": \"endpoint options\",\n                \"type\": \"object\",\n                \"description\": \"Kestrel endpoint configuration.\",\n                \"required\": [\n                  \"Url\"\n                ],\n                \"properties\": {\n                  \"Url\": {\n                    \"type\": \"string\",\n                    \"description\": \"The scheme, host name, and port the endpoint will listen on. A Url is required.\",\n                    \"format\": \"uri\"\n                  },\n                  \"Protocols\": {\n                    \"$ref\": \"#/definitions/appsettings/definitions/protocols\"\n                  },\n                  \"SslProtocols\": {\n                    \"$ref\": \"#/definitions/appsettings/definitions/sslProtocols\"\n                  },\n                  \"Certificate\": {\n                    \"$ref\": \"#/definitions/appsettings/definitions/certificate\"\n                  },\n                  \"ClientCertificateMode\": {\n                    \"$ref\": \"#/definitions/appsettings/definitions/clientCertificateMode\"\n                  },\n                  \"Sni\": {\n                    \"title\": \"SNI\",\n                    \"type\": \"object\",\n                    \"description\": \"Server Name Indication (SNI) configuration. This enables the mapping of client requested host names to certificates and other TLS settings. Wildcard names prefixed with '*.', as well as a top level '*' are supported. Available in .NET 5 and later.\",\n                    \"additionalProperties\": {\n                      \"title\": \"SNI options\",\n                      \"type\": \"object\",\n                      \"description\": \"Endpoint SNI configuration.\",\n                      \"properties\": {\n                        \"Protocols\": {\n                          \"$ref\": \"#/definitions/appsettings/definitions/protocols\"\n                        },\n                        \"SslProtocols\": {\n                          \"$ref\": \"#/definitions/appsettings/definitions/sslProtocols\"\n                        },\n                        \"Certificate\": {\n                          \"$ref\": \"#/definitions/appsettings/definitions/certificate\"\n                        },\n                        \"ClientCertificateMode\": {\n                          \"$ref\": \"#/definitions/appsettings/definitions/clientCertificateMode\"\n                        }\n                      }\n                    }\n                  }\n                }\n              }\n            },\n            \"EndpointDefaults\": {\n              \"title\": \"endpoint defaults\",\n              \"type\": \"object\",\n              \"description\": \"Default configuration applied to all endpoints. Named endpoint specific configuration overrides defaults.\",\n              \"properties\": {\n                \"Protocols\": {\n                  \"$ref\": \"#/definitions/appsettings/definitions/protocols\"\n                },\n                \"SslProtocols\": {\n                  \"$ref\": \"#/definitions/appsettings/definitions/sslProtocols\"\n                },\n                \"ClientCertificateMode\": {\n                  \"$ref\": \"#/definitions/appsettings/definitions/clientCertificateMode\"\n                }\n              }\n            },\n            \"Certificates\": {\n              \"title\": \"certificates\",\n              \"type\": \"object\",\n              \"description\": \"Certificates that Kestrel uses with HTTPS endpoints. Each certificate has a name specified by its JSON property name. The 'Default' certificate is used by HTTPS endpoints that haven't specified a certificate.\",\n              \"additionalProperties\": {\n                \"$ref\": \"#/definitions/appsettings/definitions/certificate\"\n              }\n            }\n          }\n        },\n        \"logLevelThreshold\": {\n          \"type\": \"string\",\n          \"description\": \"Log level threshold.\",\n          \"enum\": [\n            \"Trace\",\n            \"Debug\",\n            \"Information\",\n            \"Warning\",\n            \"Error\",\n            \"Critical\",\n            \"None\"\n          ]\n        },\n        \"logLevel\": {\n          \"title\": \"logging level options\",\n          \"type\": \"object\",\n          \"description\": \"Log level configurations used when creating logs. Only logs that exceeds its matching log level will be enabled. Each log level configuration has a category specified by its JSON property name. For more information about configuring log levels, see https://docs.microsoft.com/aspnet/core/fundamentals/logging/#configure-logging.\",\n          \"additionalProperties\": {\n            \"$ref\": \"#/definitions/appsettings/definitions/logLevelThreshold\"\n          }\n        },\n        \"logging\": {\n          \"title\": \"logging options\",\n          \"type\": \"object\",\n          \"description\": \"Configuration for Microsoft.Extensions.Logging.\",\n          \"additionalProperties\": {\n            \"title\": \"provider logging settings\",\n            \"type\": \"object\",\n            \"description\": \"Logging configuration for a provider. The provider name must match the configuration's JSON property property name.\",\n            \"properties\": {\n              \"LogLevel\": {\n                \"$ref\": \"#/definitions/appsettings/definitions/logLevel\"\n              }\n            }\n          },\n          \"properties\": {\n            \"LogLevel\": {\n              \"$ref\": \"#/definitions/appsettings/definitions/logLevel\"\n            },\n            \"Console\": {\n              \"properties\": {\n                \"LogLevel\": {\n                  \"$ref\": \"#/definitions/appsettings/definitions/logLevel\"\n                },\n                \"FormatterName\": {\n                  \"type\": \"string\",\n                  \"description\": \"Name of the log message formatter to use. Defaults to 'simple'.\",\n                  \"default\": \"simple\"\n                },\n                \"FormatterOptions\": {\n                  \"title\": \"formatter options\",\n                  \"type\": \"object\",\n                  \"description\": \"Log message formatter options. Additional properties are available on the options depending on the configured formatter. The formatter is specified by FormatterName.\",\n                  \"properties\": {\n                    \"IncludeScopes\": {\n                      \"type\": \"boolean\",\n                      \"description\": \"Include scopes when true. Defaults to false.\",\n                      \"default\": false\n                    },\n                    \"TimestampFormat\": {\n                      \"type\": \"string\",\n                      \"description\": \"Format string used to format timestamp in logging messages. Defaults to null.\"\n                    },\n                    \"UseUtcTimestamp\": {\n                      \"type\": \"boolean\",\n                      \"description\": \"Indication whether or not UTC timezone should be used to for timestamps in logging messages. Defaults to false.\",\n                      \"default\": false\n                    }\n                  }\n                },\n                \"LogToStandardErrorThreshold\": {\n                  \"description\": \"The minimum level of messages are written to Console.Error.\",\n                  \"$ref\": \"#/definitions/appsettings/definitions/logLevelThreshold\"\n                }\n              }\n            },\n            \"EventSource\": {\n              \"properties\": {\n                \"LogLevel\": {\n                  \"$ref\": \"#/definitions/appsettings/definitions/logLevel\"\n                }\n              }\n            },\n            \"Debug\": {\n              \"properties\": {\n                \"LogLevel\": {\n                  \"$ref\": \"#/definitions/appsettings/definitions/logLevel\"\n                }\n              }\n            },\n            \"EventLog\": {\n              \"properties\": {\n                \"LogLevel\": {\n                  \"$ref\": \"#/definitions/appsettings/definitions/logLevel\"\n                }\n              }\n            },\n            \"ElmahIo\": {\n              \"properties\": {\n                \"LogLevel\": {\n                  \"$ref\": \"#/definitions/appsettings/definitions/logLevel\"\n                }\n              }\n            },\n            \"ElmahIoBreadcrumbs\": {\n              \"properties\": {\n                \"LogLevel\": {\n                  \"$ref\": \"#/definitions/appsettings/definitions/logLevel\"\n                }\n              }\n            }\n          }\n        },\n        \"allowedHosts\": {\n          \"type\": \"string\",\n          \"description\": \"ASP.NET Core host filtering middleware configuration. Allowed hosts is a semicolon-delimited list of host names without port numbers. Requests without a matching host name will be refused. Host names may be prefixed with a '*.' wildcard, or use '*' to allow all hosts.\"\n        },\n        \"connectionStrings\": {\n          \"title\": \"connection string options\",\n          \"type\": \"object\",\n          \"description\": \"Connection string configuration. Get connection strings with the IConfiguration.GetConnectionString(string) extension method.\",\n          \"additionalProperties\": {\n            \"type\": \"string\",\n            \"description\": \"Connection string configuration. Each connection string has a name specified by its JSON property name.\"\n          }\n        },\n        \"NLog\": {\n          \"title\": \"NLog options\",\n          \"type\": \"object\",\n          \"description\": \"NLog configuration\",\n          \"default\": {},\n          \"properties\": {\n            \"autoReload\": {\n              \"type\": \"boolean\",\n              \"description\": \"Automatically reload the NLog configuration when notified that appsettings.json file has changed.\",\n              \"default\": false\n            },\n            \"throwConfigExceptions\": {\n              \"type\": [\n                \"boolean\",\n                \"null\"\n              ],\n              \"description\": \"Throws an exception when there is a config error? If not set, then throwExceptions will be used for this setting.\",\n              \"default\": false\n            },\n            \"throwExceptions\": {\n              \"type\": \"boolean\",\n              \"description\": \"Throws an exception when there is an error. For unit testing only and advanced troubleshooting.\",\n              \"default\": false\n            },\n            \"internalLogLevel\": {\n              \"type\": \"string\",\n              \"description\": \"The minimal log level for the internal logger.\",\n              \"default\": \"Off\",\n              \"enum\": [\n                \"Trace\",\n                \"Debug\",\n                \"Info\",\n                \"Warn\",\n                \"Error\",\n                \"Fatal\",\n                \"Off\"\n              ]\n            },\n            \"internalLogFile\": {\n              \"type\": \"string\",\n              \"description\": \"Write internal log to the specified filepath\"\n            },\n            \"internalLogToConsole\": {\n              \"type\": \"boolean\",\n              \"description\": \"Write internal log to a console\",\n              \"default\": \"false\"\n            },\n            \"internalLogToConsoleError\": {\n              \"type\": \"boolean\",\n              \"description\": \"Write internal log to a console with error stream\",\n              \"default\": \"false\"\n            },\n            \"globalThreshold\": {\n              \"type\": \"string\",\n              \"description\": \"Log events below this threshold are not logged.\",\n              \"default\": \"Off\",\n              \"enum\": [\n                \"Trace\",\n                \"Debug\",\n                \"Info\",\n                \"Warn\",\n                \"Error\",\n                \"Fatal\",\n                \"Off\"\n              ]\n            },\n            \"autoShutdown\": {\n              \"type\": \"boolean\",\n              \"description\": \"Automatically call `LogFactory.Shutdown` on AppDomain.Unload or AppDomain.ProcessExit\",\n              \"default\": \"true\"\n            },\n            \"extensions\": {\n              \"type\": \"array\",\n              \"description\": \"Load NLog extension packages for additional targets and layouts\",\n              \"default\": [],\n              \"items\": {\n                \"title\": \"extension\",\n                \"type\": \"object\",\n                \"description\": \"\",\n                \"default\": {},\n                \"properties\": {\n                  \"assembly\": {\n                    \"type\": \"string\",\n                    \"description\": \"Assembly Name of the NLog extension package.\"\n                  },\n                  \"prefix\": {\n                    \"type\": \"string\",\n                    \"description\": \"Appends prefix to all type-names loaded from the assembly\",\n                    \"default\": \"\"\n                  },\n                  \"assemblyFile\": {\n                    \"type\": \"string\",\n                    \"description\": \"Absolute filepath to the Assembly-file of the NLog extension package.\",\n                    \"default\": \"\"\n                  }\n                }\n              }\n            },\n            \"variables\": {\n              \"title\": \"variables\",\n              \"type\": \"object\",\n              \"description\": \"Key-value pair of variables\",\n              \"patternProperties\": {\n                \".*\": {\n                  \"type\": [\n                    \"boolean\",\n                    \"number\",\n                    \"string\"\n                  ]\n                }\n              },\n              \"propertyNames\": {\n                \"pattern\": \"^[A-Za-z0-9_.-]+$\"\n              }\n            },\n            \"targetDefaultWrapper\": {\n              \"title\": \"default wrapper\",\n              \"type\": \"object\",\n              \"description\": \"Wrap all defined targets with this custom target wrapper.\",\n              \"default\": {},\n              \"required\": [\n                \"type\"\n              ],\n              \"properties\": {\n                \"type\": {\n                  \"type\": \"string\",\n                  \"description\": \"\"\n                }\n              }\n            },\n            \"targets\": {\n              \"title\": \"targets\",\n              \"type\": \"object\",\n              \"description\": \"\",\n              \"default\": {},\n              \"properties\": {\n                \"async\": {\n                  \"type\": \"boolean\",\n                  \"description\": \"Wrap all defined targets using AsyncWrapper with OverflowAction=Discard for better performance.\"\n                }\n              }\n            },\n            \"rules\": {\n              \"oneOf\": [\n                {\n                  \"type\": \"array\",\n                  \"description\": \"\",\n                  \"default\": [],\n                  \"items\": {\n                    \"$ref\": \"#/definitions/appsettings/definitions/NLogRulesItem\"\n                  }\n                },\n                {\n                  \"title\": \"rules\",\n                  \"type\": \"object\",\n                  \"patternProperties\": {\n                    \".*\": {\n                      \"$ref\": \"#/definitions/appsettings/definitions/NLogRulesItem\"\n                    }\n                  },\n                  \"propertyNames\": {\n                    \"pattern\": \"^[0-9]+$\"\n                  }\n                }\n              ]\n            }\n          }\n        },\n        \"NLogRulesItem\": {\n          \"title\": \"NLog rule item\",\n          \"type\": \"object\",\n          \"description\": \"Redirect LogEvents from matching Logger objects to specified targets\",\n          \"default\": {},\n          \"required\": [\n            \"logger\"\n          ],\n          \"properties\": {\n            \"logger\": {\n              \"type\": \"string\",\n              \"description\": \"Match Logger objects based on their Logger-name. Can use wildcard characters ('*' or '?').\"\n            },\n            \"ruleName\": {\n              \"type\": \"string\",\n              \"description\": \"Rule identifier to allow rule lookup with Configuration.FindRuleByName and Configuration.RemoveRuleByName.\"\n            },\n            \"level\": {\n              \"anyOf\": [\n                {\n                  \"type\": \"string\",\n                  \"description\": \"\",\n                  \"enum\": [\n                    \"Trace\",\n                    \"Debug\",\n                    \"Info\",\n                    \"Warn\",\n                    \"Error\",\n                    \"Fatal\"\n                  ]\n                },\n                {\n                  \"type\": \"string\"\n                }\n              ]\n            },\n            \"levels\": {\n              \"type\": \"string\",\n              \"description\": \"Comma separated list of levels that this rule matches.\"\n            },\n            \"minLevel\": {\n              \"anyOf\": [\n                {\n                  \"type\": \"string\",\n                  \"description\": \"\",\n                  \"enum\": [\n                    \"Trace\",\n                    \"Debug\",\n                    \"Info\",\n                    \"Warn\",\n                    \"Error\",\n                    \"Fatal\"\n                  ]\n                },\n                {\n                  \"type\": \"string\"\n                }\n              ]\n            },\n            \"maxLevel\": {\n              \"anyOf\": [\n                {\n                  \"type\": \"string\",\n                  \"description\": \"\",\n                  \"enum\": [\n                    \"Trace\",\n                    \"Debug\",\n                    \"Info\",\n                    \"Warn\",\n                    \"Error\",\n                    \"Fatal\"\n                  ]\n                },\n                {\n                  \"type\": \"string\"\n                }\n              ]\n            },\n            \"finalMinLevel\": {\n              \"anyOf\": [\n                {\n                  \"type\": \"string\",\n                  \"description\": \"\",\n                  \"enum\": [\n                    \"Trace\",\n                    \"Debug\",\n                    \"Info\",\n                    \"Warn\",\n                    \"Error\",\n                    \"Fatal\"\n                  ]\n                },\n                {\n                  \"type\": \"string\"\n                }\n              ]\n            },\n            \"writeTo\": {\n              \"type\": \"string\",\n              \"description\": \"Name or names of a target - separated by comma. Remove this property for sending events to the blackhole.\"\n            },\n            \"final\": {\n              \"type\": \"boolean\",\n              \"description\": \"Ignore further rules if this one matches.\",\n              \"default\": false\n            },\n            \"enabled\": {\n              \"type\": \"boolean\",\n              \"description\": \"\",\n              \"default\": true\n            },\n            \"filters\": {\n              \"oneOf\": [\n                {\n                  \"type\": \"array\",\n                  \"description\": \"\",\n                  \"default\": [],\n                  \"items\": {\n                    \"title\": \"filter\",\n                    \"type\": \"object\",\n                    \"description\": \"\",\n                    \"default\": {},\n                    \"required\": [\n                      \"type\"\n                    ],\n                    \"properties\": {\n                      \"type\": {\n                        \"type\": \"string\",\n                        \"description\": \"\"\n                      },\n                      \"action\": {\n                        \"type\": \"string\",\n                        \"description\": \"Result action when filter matches logevent.\",\n                        \"default\": \"Neutral\",\n                        \"enum\": [\n                          \"Neutral\",\n                          \"Log\",\n                          \"Ignore\",\n                          \"LogFinal\",\n                          \"IgnoreFinal\"\n                        ]\n                      }\n                    }\n                  }\n                },\n                {\n                  \"title\": \"filter\",\n                  \"type\": \"object\",\n                  \"description\": \"\",\n                  \"default\": {}\n                }\n              ]\n            },\n            \"filterDefaultAction\": {\n              \"type\": \"string\",\n              \"description\": \"Default action if none of the filters match.\",\n              \"default\": \"Ignore\",\n              \"enum\": [\n                \"Neutral\",\n                \"Log\",\n                \"Ignore\",\n                \"LogFinal\",\n                \"IgnoreFinal\"\n              ]\n            }\n          }\n        },\n        \"Serilog\": {\n          \"title\": \"Serilog appSettings\",\n          \"type\": \"object\",\n          \"description\": \"Serilog appSettings Configuration\",\n          \"additionalProperties\": false,\n          \"properties\": {\n            \"$schema\": {\n              \"title\": \"Schema\",\n              \"type\": \"string\",\n              \"description\": \"Pointer to the schema against which this document should be validated.\"\n            },\n            \"Using\": {\n              \"title\": \"List of Auto-discovery of configuration assemblies\",\n              \"type\": \"array\",\n              \"description\": \"Using section contains list of assemblies in which configuration methods. Can be required depending of the project type: See: https://github.com/serilog/serilog-settings-configuration#using-section-and-auto-discovery-of-configuration-assemblies\",\n              \"uniqueItems\": true,\n              \"items\": {\n                \"$ref\": \"#/definitions/appsettings/definitions/Serilog/definitions/AssemblyReference\"\n              }\n            },\n            \"LevelSwitches\": {\n              \"type\": \"object\",\n              \"additionalProperties\": false,\n              \"patternProperties\": {\n                \"^(?<SerilogLevelSwitcherName>\\\\${0,1}[A-Za-z]+[A-Za-z0-9]*)$\": {\n                  \"$ref\": \"#/definitions/appsettings/definitions/Serilog/definitions/SerilogLogEventLevel\"\n                }\n              }\n            },\n            \"FilterSwitches\": {\n              \"type\": \"object\",\n              \"additionalProperties\": false,\n              \"patternProperties\": {\n                \"^(?<SerilogLevelSwitcherName>\\\\${0,1}[A-Za-z]+[A-Za-z0-9]*)$\": {\n                  \"type\": \"string\"\n                }\n              }\n            },\n            \"MinimumLevel\": {\n              \"title\": \"Minimum LogLevel Threshold\",\n              \"type\": [\n                \"object\",\n                \"string\"\n              ],\n              \"description\": \"Minimum LogLevel Threshold. (Support dynamic reload if the underlying IConfigurationProvider supports it)\",\n              \"oneOf\": [\n                {\n                  \"$ref\": \"#/definitions/appsettings/definitions/Serilog/definitions/SerilogLogEventLevel\"\n                },\n                {\n                  \"$ref\": \"#/definitions/appsettings/definitions/Serilog/definitions/DetailedMinimumLevel\"\n                }\n              ]\n            },\n            \"Properties\": {\n              \"title\": \"Log events Properties\",\n              \"type\": \"object\",\n              \"description\": \"This section defines a static list of key-value pairs that will enrich log events.\",\n              \"additionalProperties\": {\n                \"type\": \"string\"\n              }\n            },\n            \"Enrich\": {\n              \"title\": \"Log events Enriches\",\n              \"description\": \"This section defines Enriches that will be applied to log events.\",\n              \"allOf\": [\n                {\n                  \"$ref\": \"#/definitions/appsettings/definitions/Serilog/definitions/MethodCallReference\"\n                }\n              ]\n            },\n            \"Destructure\": {\n              \"title\": \"Log events Destructure\",\n              \"description\": \"This section defines Destructure.\",\n              \"allOf\": [\n                {\n                  \"$ref\": \"#/definitions/appsettings/definitions/Serilog/definitions/MethodCallReference\"\n                }\n              ]\n            },\n            \"Filter\": {\n              \"title\": \"Log events filters\",\n              \"description\": \"This section defines filters that will be applied to log events.\",\n              \"allOf\": [\n                {\n                  \"$ref\": \"#/definitions/appsettings/definitions/Serilog/definitions/MethodCallReference\"\n                }\n              ]\n            },\n            \"WriteTo\": {\n              \"title\": \"Configuration for log destination\",\n              \"description\": \"This section configures the sinks that log events will be emitted to.\",\n              \"allOf\": [\n                {\n                  \"$ref\": \"#/definitions/appsettings/definitions/Serilog/definitions/MethodCallReference\"\n                }\n              ]\n            },\n            \"AuditTo\": {\n              \"title\": \"Configuration for log destination for auditing\",\n              \"description\": \"This section configures sinks for auditing, instead of regular (safe) logging. Obs: When auditing is used, exceptions from sinks and any intermediate filters propagate back to the caller.\",\n              \"allOf\": [\n                {\n                  \"$ref\": \"#/definitions/appsettings/definitions/Serilog/definitions/MethodCallReference\"\n                }\n              ]\n            }\n          },\n          \"patternProperties\": {\n            \"^Enrich:((?<EnvironmentVariableName>[a-zA-Z_]\\\\w*)|(?<ArrayIndex>\\\\d*))$\": {\n              \"title\": \"Log events Enriches\",\n              \"description\": \"This section defines Enriches that will be applied to log events.\",\n              \"allOf\": [\n                {\n                  \"$ref\": \"#/definitions/appsettings/definitions/Serilog/definitions/MethodCallReferenceItem\"\n                }\n              ]\n            },\n            \"^Destructure:((?<EnvironmentVariableName>[a-zA-Z_]\\\\w*)|(?<ArrayIndex>\\\\d*))$\": {\n              \"title\": \"Log events Destructure\",\n              \"description\": \"This section defines Destructure.\",\n              \"allOf\": [\n                {\n                  \"$ref\": \"#/definitions/appsettings/definitions/Serilog/definitions/MethodCallReferenceItem\"\n                }\n              ]\n            },\n            \"^Filter:((?<EnvironmentVariableName>[a-zA-Z_]\\\\w*)|(?<ArrayIndex>\\\\d*))$\": {\n              \"title\": \"Log events filters\",\n              \"description\": \"This section defines filters that will be applied to log events.\",\n              \"allOf\": [\n                {\n                  \"$ref\": \"#/definitions/appsettings/definitions/Serilog/definitions/MethodCallReferenceItem\"\n                }\n              ]\n            },\n            \"^WriteTo:((?<EnvironmentVariableName>[a-zA-Z_]\\\\w*)|(?<ArrayIndex>\\\\d*))$\": {\n              \"title\": \"Configuration for log destination\",\n              \"description\": \"This section configures the sinks that log events will be emitted to.\",\n              \"allOf\": [\n                {\n                  \"$ref\": \"#/definitions/appsettings/definitions/Serilog/definitions/MethodCallReferenceItem\"\n                }\n              ]\n            },\n            \"^AuditTo:((?<EnvironmentVariableName>[a-zA-Z_]\\\\w*)|(?<ArrayIndex>\\\\d*))$\": {\n              \"title\": \"Configuration for log destination for auditing\",\n              \"description\": \"This section configures sinks for auditing, instead of regular (safe) logging. Obs: When auditing is used, exceptions from sinks and any intermediate filters propagate back to the caller.\",\n              \"allOf\": [\n                {\n                  \"$ref\": \"#/definitions/appsettings/definitions/Serilog/definitions/MethodCallReferenceItem\"\n                }\n              ]\n            }\n          },\n          \"definitions\": {\n            \"SerilogLogEventLevel\": {\n              \"title\": \"Log level\",\n              \"type\": \"string\",\n              \"description\": \"Log level threshold.\",\n              \"enum\": [\n                \"Verbose\",\n                \"Debug\",\n                \"Information\",\n                \"Warning\",\n                \"Error\",\n                \"Fatal\"\n              ]\n            },\n            \"LoggingLevelSwitch\": {\n              \"title\": \"LevelSwitches name\",\n              \"type\": \"string\",\n              \"description\": \"Log Level Switch string reference.\",\n              \"pattern\": \"^(?<SerilogLevelSwitcherName>\\\\${0,1}[A-Za-z]+[A-Za-z0-9]*)$\"\n            },\n            \"SerilogLogLevelThreshold\": {\n              \"title\": \"Log Level or LevelSwitches name\",\n              \"type\": \"string\",\n              \"description\": \"A Serilog Log Level or a reference to a Log Level Switch name on `LevelSwitches` configuration.\",\n              \"anyOf\": [\n                {\n                  \"$ref\": \"#/definitions/appsettings/definitions/Serilog/definitions/SerilogLogEventLevel\"\n                },\n                {\n                  \"$ref\": \"#/definitions/appsettings/definitions/Serilog/definitions/LoggingLevelSwitch\"\n                }\n              ]\n            },\n            \"DetailedMinimumLevel\": {\n              \"title\": \"Detailed Log level.\",\n              \"type\": \"object\",\n              \"description\": \"Detailed Log level threshold object. Allowing set log levels be overridden per logging source.\",\n              \"additionalProperties\": false,\n              \"properties\": {\n                \"Default\": {\n                  \"$ref\": \"#/definitions/appsettings/definitions/Serilog/definitions/SerilogLogLevelThreshold\"\n                },\n                \"ControlledBy\": {\n                  \"$ref\": \"#/definitions/appsettings/definitions/Serilog/definitions/LoggingLevelSwitch\"\n                },\n                \"Override\": {\n                  \"title\": \"Logging Source Log level object.\",\n                  \"type\": \"object\",\n                  \"description\": \"Set the Log level threshold or LevelSwitcher reference per Logging Source.\",\n                  \"additionalProperties\": {\n                    \"$ref\": \"#/definitions/appsettings/definitions/Serilog/definitions/SerilogLogLevelThreshold\"\n                  }\n                }\n              }\n            },\n            \"AssemblyReference\": {\n              \"title\": \"Assembly Name\",\n              \"type\": \"string\",\n              \"description\": \".NET Assembly Name, without the file extension\",\n              \"minLength\": 1,\n              \"pattern\": \"^(?<AssemblyName>\\\\S+)$\"\n            },\n            \"ComplexMethodCallReference\": {\n              \"type\": \"object\",\n              \"additionalProperties\": false,\n              \"required\": [\n                \"Name\"\n              ],\n              \"properties\": {\n                \"Name\": {\n                  \"$ref\": \"#/definitions/appsettings/definitions/Serilog/definitions/CSharpMethodName\"\n                },\n                \"Args\": {\n                  \"type\": \"object\",\n                  \"additionalProperties\": false,\n                  \"patternProperties\": {\n                    \"^(?<CSharpMethodArgumentName>[a-zA-Z_]\\\\w*)$\": {}\n                  }\n                }\n              }\n            },\n            \"MethodCallReferenceItem\": {\n              \"type\": [\n                \"null\",\n                \"object\",\n                \"string\"\n              ],\n              \"oneOf\": [\n                {\n                  \"$ref\": \"#/definitions/appsettings/definitions/Serilog/definitions/CSharpMethodName\"\n                },\n                {\n                  \"$ref\": \"#/definitions/appsettings/definitions/Serilog/definitions/ComplexMethodCallReference\"\n                }\n              ]\n            },\n            \"MethodCallReference\": {\n              \"type\": [\n                \"array\",\n                \"object\",\n                \"string\"\n              ],\n              \"minLength\": 1,\n              \"pattern\": \"^(?<CSharpMethodName>[a-zA-Z_]\\\\w*)$\",\n              \"minItems\": 1,\n              \"uniqueItems\": true,\n              \"additionalProperties\": {\n                \"$ref\": \"#/definitions/appsettings/definitions/Serilog/definitions/MethodCallReferenceItem\"\n              },\n              \"items\": {\n                \"$ref\": \"#/definitions/appsettings/definitions/Serilog/definitions/MethodCallReferenceItem\"\n              }\n            },\n            \"CSharpMethodName\": {\n              \"title\": \"Method Name\",\n              \"type\": \"string\",\n              \"description\": \"A name referring to a C# Class method\",\n              \"minLength\": 1,\n              \"pattern\": \"^(?<CSharpMethodName>[a-zA-Z_]\\\\w*)$\"\n            },\n            \"CSharpMethodArgumentName\": {\n              \"title\": \"Argument Name\",\n              \"type\": \"string\",\n              \"description\": \"A name referring to a C# Class method argument\",\n              \"minLength\": 1,\n              \"pattern\": \"^(?<CSharpMethodArgumentName>[a-zA-Z_]\\\\w*)$\"\n            },\n            \"EnvironmentVariableName\": {\n              \"title\": \"Environment Variable Name\",\n              \"type\": \"string\",\n              \"description\": \"A name referring to a OS Environment Variable\",\n              \"minLength\": 1,\n              \"pattern\": \"^(?<EnvironmentVariableName>[a-zA-Z_]\\\\w*)$\"\n            },\n            \"SerilogLevelSwitcherName\": {\n              \"title\": \"A Level Switcher Name\",\n              \"type\": \"string\",\n              \"description\": \"A name referring to a Serilog Settings Configuration Level Switcher\",\n              \"minLength\": 1,\n              \"pattern\": \"^(?<SerilogLevelSwitcherName>\\\\${0,1}[A-Za-z]+[A-Za-z0-9]*)$\"\n            }\n          }\n        }\n      }\n    },\n    \"Explorer\": {\n      \"title\": \"ExplorerOptions\",\n      \"type\": \"object\",\n      \"additionalProperties\": false,\n      \"properties\": {\n        \"IsEnabled\": {\n          \"type\": \"boolean\",\n          \"default\": true\n        }\n      }\n    },\n    \"Action\": {\n      \"title\": \"ActionOptions\",\n      \"type\": \"object\",\n      \"additionalProperties\": false,\n      \"properties\": {\n        \"ModulePath\": {\n          \"type\": \"string\"\n        },\n        \"ActionLoaderType\": {\n          \"type\": \"string\"\n        },\n        \"PolicyActionRegistryType\": {\n          \"type\": \"string\"\n        }\n      }\n    },\n    \"Genesis\": {\n      \"title\": \"GenesisOptions\",\n      \"type\": \"object\",\n      \"description\": \"Options for the genesis block.\",\n      \"additionalProperties\": false,\n      \"properties\": {\n        \"GenesisKey\": {\n          \"type\": \"string\",\n          \"description\": \"The PrivateKey used to generate the genesis block. This property cannot be used with GenesisBlockPath.\",\n          \"pattern\": \"^[0-9a-fA-F]{64}$\"\n        },\n        \"Validators\": {\n          \"type\": \"array\",\n          \"description\": \"Public keys of the validators. This property cannot be used with GenesisBlockPath.\",\n          \"items\": {\n            \"type\": \"string\",\n            \"pattern\": \"^(?:[0-9a-fA-F]{130}|[0-9a-fA-F]{66})$\"\n          }\n        },\n        \"Timestamp\": {\n          \"type\": \"string\",\n          \"description\": \"The timestamp of the genesis block.\",\n          \"format\": \"date-time\"\n        },\n        \"GenesisBlockPath\": {\n          \"type\": \"string\",\n          \"description\": \"The path of the genesis block, which can be a file path or a URI.This property cannot be used with GenesisKey.\"\n        }\n      }\n    },\n    \"Solo\": {\n      \"title\": \"SoloOptions\",\n      \"type\": \"object\",\n      \"additionalProperties\": false,\n      \"properties\": {\n        \"IsEnabled\": {\n          \"type\": \"boolean\"\n        },\n        \"BlockInterval\": {\n          \"type\": \"integer\",\n          \"format\": \"int64\"\n        },\n        \"PrivateKey\": {\n          \"type\": \"string\",\n          \"description\": \"The private key of the node.\",\n          \"pattern\": \"^[0-9a-fA-F]{64}$\"\n        }\n      }\n    },\n    \"Store\": {\n      \"title\": \"StoreOptions\",\n      \"type\": \"object\",\n      \"additionalProperties\": false,\n      \"properties\": {\n        \"Type\": {\n          \"description\": \"The type of the store.\",\n          \"oneOf\": [\n            {\n              \"$ref\": \"#/definitions/Store/definitions/StoreType\"\n            }\n          ]\n        },\n        \"RootPath\": {\n          \"type\": \"string\",\n          \"description\": \"The root directory path of the store.\"\n        },\n        \"StoreName\": {\n          \"type\": \"string\",\n          \"description\": \"The directory name of the store to be created under RootPath. If not specified,the default value is 'store'.\"\n        },\n        \"StateStoreName\": {\n          \"type\": \"string\",\n          \"description\": \"The directory name of the state store to be created under RootPath. If not specified,the default value is 'state'.\"\n        }\n      },\n      \"definitions\": {\n        \"StoreType\": {\n          \"type\": \"string\",\n          \"description\": \"\",\n          \"enum\": [\n            \"Disk\",\n            \"Memory\"\n          ]\n        }\n      }\n    },\n    \"Swarm\": {\n      \"title\": \"SwarmOptions\",\n      \"type\": \"object\",\n      \"additionalProperties\": false,\n      \"properties\": {\n        \"PrivateKey\": {\n          \"type\": \"string\",\n          \"description\": \"The private key.\",\n          \"pattern\": \"^[0-9a-fA-F]{64}$\"\n        },\n        \"AppProtocolVersion\": {\n          \"type\": \"string\",\n          \"description\": \"The version of the application protocol.\",\n          \"pattern\": \"^(?<version>\\\\d+)/(?<address>[0-9a-fA-F]{40})/(?<signature>(?:[A-Za-z0-9+\\\\.]{4})*(?:[A-Za-z0-9+\\\\.]{2}==|[A-Za-z0-9+\\\\.]{3}=)?)/(?<extra>(?:[A-Za-z0-9+\\\\.]{4})*(?:[A-Za-z0-9+\\\\.]{2}==|[A-Za-z0-9+\\\\.]{3}=)?)$\"\n        },\n        \"IsEnabled\": {\n          \"type\": \"boolean\"\n        },\n        \"EndPoint\": {\n          \"type\": \"string\",\n          \"pattern\": \"^(?:(?:[a-zA-Z0-9\\\\-\\\\.]+)|(?:\\\\d{1,3}\\\\.\\\\d{1,3}\\\\.\\\\d{1,3}\\\\.\\\\d{1,3})):\\\\d{1,5}$\"\n        },\n        \"BlocksyncSeedPeer\": {\n          \"type\": \"string\",\n          \"description\": \"The endpoint of the node to block sync.\",\n          \"pattern\": \"^$|^(?:[0-9a-fA-F]{130}|[0-9a-fA-F]{66}),(?:(?:[a-zA-Z0-9\\\\-\\\\.]+)|(?:\\\\d{1,3}\\\\.\\\\d{1,3}\\\\.\\\\d{1,3}\\\\.\\\\d{1,3})),\\\\d{1,5}$\"\n        },\n        \"TrustedAppProtocolVersionSigners\": {\n          \"type\": \"array\",\n          \"items\": {\n            \"type\": \"string\"\n          }\n        }\n      }\n    },\n    \"Validator\": {\n      \"title\": \"ValidatorOptions\",\n      \"type\": \"object\",\n      \"additionalProperties\": false,\n      \"properties\": {\n        \"PrivateKey\": {\n          \"type\": \"string\",\n          \"description\": \"The private key.\",\n          \"pattern\": \"^[0-9a-fA-F]{64}$\"\n        },\n        \"AppProtocolVersion\": {\n          \"type\": \"string\",\n          \"description\": \"The version of the application protocol.\",\n          \"pattern\": \"^(?<version>\\\\d+)/(?<address>[0-9a-fA-F]{40})/(?<signature>(?:[A-Za-z0-9+\\\\.]{4})*(?:[A-Za-z0-9+\\\\.]{2}==|[A-Za-z0-9+\\\\.]{3}=)?)/(?<extra>(?:[A-Za-z0-9+\\\\.]{4})*(?:[A-Za-z0-9+\\\\.]{2}==|[A-Za-z0-9+\\\\.]{3}=)?)$\"\n        },\n        \"IsEnabled\": {\n          \"type\": \"boolean\",\n          \"default\": true\n        },\n        \"EndPoint\": {\n          \"type\": \"string\",\n          \"pattern\": \"^(?:(?:[a-zA-Z0-9\\\\-\\\\.]+)|(?:\\\\d{1,3}\\\\.\\\\d{1,3}\\\\.\\\\d{1,3}\\\\.\\\\d{1,3})):\\\\d{1,5}$\"\n        },\n        \"ConsensusSeedPeer\": {\n          \"type\": \"string\",\n          \"description\": \"The endpoint of the node to consensus.\",\n          \"pattern\": \"^$|^(?:[0-9a-fA-F]{130}|[0-9a-fA-F]{66}),(?:(?:[a-zA-Z0-9\\\\-\\\\.]+)|(?:\\\\d{1,3}\\\\.\\\\d{1,3}\\\\.\\\\d{1,3}\\\\.\\\\d{1,3})),\\\\d{1,5}$\"\n        }\n      }\n    }\n  },\n  \"allOf\": [\n    {\n      \"$ref\": \"#/definitions/appsettings\"\n    },\n    {\n      \"type\": \"object\",\n      \"properties\": {\n        \"Explorer\": {\n          \"description\": \"Type 'ExplorerOptions' does not have a description.\",\n          \"$ref\": \"#/definitions/Explorer\"\n        },\n        \"Action\": {\n          \"description\": \"Type 'ActionOptions' does not have a description.\",\n          \"$ref\": \"#/definitions/Action\"\n        },\n        \"Genesis\": {\n          \"description\": \"Options for the genesis block.\",\n          \"$ref\": \"#/definitions/Genesis\"\n        },\n        \"Solo\": {\n          \"description\": \"Type 'SoloOptions' does not have a description.\",\n          \"$ref\": \"#/definitions/Solo\"\n        },\n        \"Store\": {\n          \"description\": \"Type 'StoreOptions' does not have a description.\",\n          \"$ref\": \"#/definitions/Store\"\n        },\n        \"Swarm\": {\n          \"description\": \"Type 'SwarmOptions' does not have a description.\",\n          \"$ref\": \"#/definitions/Swarm\"\n        },\n        \"Validator\": {\n          \"description\": \"Type 'ValidatorOptions' does not have a description.\",\n          \"$ref\": \"#/definitions/Validator\"\n        }\n      }\n    }\n  ]\n}\n"
  },
  {
    "path": "sdk/node/Libplanet.Node.Executable/appsettings.Development.json",
    "content": "{\n  \"$schema\": \"./appsettings-schema.json\",\n  \"Logging\": {\n    \"LogLevel\": {\n      \"Default\": \"Information\",\n      \"Microsoft.AspNetCore\": \"Warning\"\n    }\n  },\n  \"Kestrel\": {\n    \"EndpointDefaults\": {\n      \"Protocols\": \"Http2\"\n    }\n  },\n  \"Swarm\": {\n    \"IsEnabled\": true\n  },\n  \"Validator\": {\n    \"IsEnabled\": true\n  }\n}\n"
  },
  {
    "path": "sdk/node/Libplanet.Node.Executable/appsettings.json",
    "content": "{\n  \"$schema\": \"./appsettings-schema.json\",\n  \"Logging\": {\n    \"LogLevel\": {\n      \"Default\": \"Information\",\n      \"Microsoft.AspNetCore\": \"Warning\"\n    }\n  },\n  \"AllowedHosts\": \"*\",\n  \"Kestrel\": {\n    \"EndpointDefaults\": {\n      \"Protocols\": \"Http2\"\n    }\n  }\n}\n"
  },
  {
    "path": "sdk/node/Libplanet.Node.Extensions/Libplanet.Node.Extensions.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <ItemGroup>\n    <PackageReference Include=\"Microsoft.Extensions.DependencyInjection\" Version=\"8.0.0\" />\n    <PackageReference Include=\"Microsoft.Extensions.Hosting\" Version=\"8.0.0\" />\n    <PackageReference Include=\"Microsoft.Extensions.Options.DataAnnotations\" Version=\"8.0.0\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <ProjectReference Include=\"..\\Libplanet.Node\\Libplanet.Node.csproj\" />\n  </ItemGroup>\n\n</Project>\n"
  },
  {
    "path": "sdk/node/Libplanet.Node.Extensions/LibplanetServicesExtensions.cs",
    "content": "using Libplanet.Node.Extensions.NodeBuilder;\nusing Libplanet.Node.Options;\nusing Libplanet.Node.Options.Schema;\nusing Libplanet.Node.Services;\nusing Microsoft.AspNetCore.Builder;\nusing Microsoft.Extensions.Configuration;\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.Options;\n\nnamespace Libplanet.Node.Extensions;\n\npublic static class LibplanetServicesExtensions\n{\n    public static ILibplanetNodeBuilder AddLibplanetNode(\n        this IServiceCollection services,\n        IConfiguration configuration)\n    {\n        SynchronizationContext.SetSynchronizationContext(SynchronizationContext.Current ?? new());\n        services.AddSingleton(SynchronizationContext.Current!);\n        services.AddOptions<GenesisOptions>()\n                .Bind(configuration.GetSection(GenesisOptions.Position));\n        services.AddSingleton<IConfigureOptions<GenesisOptions>, GenesisOptionsConfigurator>();\n        services.AddSingleton<IValidateOptions<GenesisOptions>, GenesisOptionsValidator>();\n\n        services.AddOptions<StoreOptions>()\n                .Bind(configuration.GetSection(StoreOptions.Position));\n        services.AddSingleton<IConfigureOptions<StoreOptions>, StoreOptionsConfigurator>();\n\n        services.AddOptions<ActionOptions>()\n                .Bind(configuration.GetSection(ActionOptions.Position));\n\n        services.AddOptions<SwarmOptions>()\n                .Bind(configuration.GetSection(SwarmOptions.Position));\n        services.AddSingleton<IConfigureOptions<SwarmOptions>, SwarmOptionsConfigurator>();\n        services.AddSingleton<IValidateOptions<SwarmOptions>, SwarmOptionsValidator>();\n\n        services.AddOptions<ValidatorOptions>()\n                .Bind(configuration.GetSection(ValidatorOptions.Position));\n        services.AddSingleton<IConfigureOptions<ValidatorOptions>, ValidatorOptionsConfigurator>();\n        services.AddSingleton<IValidateOptions<ValidatorOptions>, ValidatorOptionsValidator>();\n\n        services.AddOptions<SoloOptions>()\n                .Bind(configuration.GetSection(SoloOptions.Position));\n        services.AddSingleton<IConfigureOptions<SoloOptions>, SoloOptionsConfigurator>();\n\n        services.AddSingleton<PolicyService>();\n        services.AddSingleton<StoreService>();\n        services.AddSingleton(s => (IStoreService)s.GetRequiredService<StoreService>());\n        services.AddSingleton<ActionService>();\n        services.AddSingleton(s => (IActionService)s.GetRequiredService<ActionService>());\n        services.AddSingleton<RendererService>();\n        services.AddSingleton(s => (IRendererService)s.GetRequiredService<RendererService>());\n        services.AddSingleton<IBlockChainService, BlockChainService>();\n        services.AddSingleton<IReadChainService, ReadChainService>();\n        services.AddSingleton<TransactionService>();\n\n        var nodeBuilder = new LibplanetNodeBuilder(services);\n\n        if (configuration.IsOptionsEnabled(SoloOptions.Position))\n        {\n            nodeBuilder.WithSolo();\n        }\n\n        if (configuration.IsOptionsEnabled(SwarmOptions.Position))\n        {\n            nodeBuilder.WithSwarm();\n        }\n\n        if (configuration.IsOptionsEnabled(ValidatorOptions.Position))\n        {\n            nodeBuilder.WithValidator();\n        }\n\n        return nodeBuilder;\n    }\n\n    public static IApplicationBuilder MapSchemaBuilder(this IApplicationBuilder app, string pattern)\n    {\n        app.UseRouting();\n        app.UseEndpoints(endPoint =>\n        {\n            string? schema = null;\n            endPoint.MapGet(pattern, async () =>\n            {\n                schema ??= await OptionsSchemaBuilder.GetSchemaAsync(default);\n                return schema;\n            });\n        });\n\n        return app;\n    }\n\n    public static bool IsOptionsEnabled(\n        this IConfiguration configuration, string name)\n        => configuration.GetValue<bool>($\"{name}:IsEnabled\");\n\n    public static bool IsOptionsEnabled(\n        this IConfiguration configuration, string name, string propertyName)\n    {\n        var key = $\"{name}:{propertyName}\";\n        return configuration.GetValue<bool>(key);\n    }\n}\n"
  },
  {
    "path": "sdk/node/Libplanet.Node.Extensions/NodeBuilder/ILibplanetNodeBuilder.cs",
    "content": "using Microsoft.Extensions.DependencyInjection;\n\nnamespace Libplanet.Node.Extensions.NodeBuilder;\n\npublic interface ILibplanetNodeBuilder\n{\n    IServiceCollection Services { get; }\n\n    ILibplanetNodeBuilder WithSolo();\n\n    ILibplanetNodeBuilder WithSwarm();\n\n    ILibplanetNodeBuilder WithValidator();\n}\n"
  },
  {
    "path": "sdk/node/Libplanet.Node.Extensions/NodeBuilder/LibplanetNodeBuilder.cs",
    "content": "using Libplanet.Node.Services;\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.Hosting;\n\nnamespace Libplanet.Node.Extensions.NodeBuilder;\n\npublic class LibplanetNodeBuilder : ILibplanetNodeBuilder\n{\n    private readonly List<string> _scopeList = [string.Empty];\n\n    internal LibplanetNodeBuilder(IServiceCollection services)\n    {\n        Services = services;\n    }\n\n    public IServiceCollection Services { get; }\n\n    public string[] Scopes => [.. _scopeList];\n\n    public ILibplanetNodeBuilder WithSolo()\n    {\n        Services.AddHostedService<SoloProposeService>();\n        _scopeList.Add(\"Solo\");\n        return this;\n    }\n\n    public ILibplanetNodeBuilder WithSwarm()\n    {\n        Services.AddSingleton<SwarmService>();\n        Services.AddSingleton(s => (ISwarmService)s.GetRequiredService<SwarmService>());\n        Services.AddSingleton(s => (IHostedService)s.GetRequiredService<SwarmService>());\n        _scopeList.Add(\"Swarm\");\n        return this;\n    }\n\n    public ILibplanetNodeBuilder WithValidator()\n    {\n        Services.AddSingleton<IValidatorService, ValidatorService>();\n        _scopeList.Add(\"Validator\");\n        return this;\n    }\n}\n"
  },
  {
    "path": "sdk/node/Libplanet.Node.Tests/AsyncDisposerCollection.cs",
    "content": "using System.Collections;\n\nnamespace Libplanet.Node.Tests;\n\ninternal sealed class AsyncDisposerCollection(IEnumerable<IAsyncDisposable> disposables)\n    : IEnumerable<IAsyncDisposable>, IAsyncDisposable\n{\n    private readonly List<IAsyncDisposable> _items = disposables.ToList();\n\n    public async ValueTask DisposeAsync()\n        => await Parallel.ForEachAsync(_items, async (item, _) => await item.DisposeAsync());\n\n    public IEnumerator<IAsyncDisposable> GetEnumerator() => _items.GetEnumerator();\n\n    IEnumerator IEnumerable.GetEnumerator() => _items.GetEnumerator();\n}\n"
  },
  {
    "path": "sdk/node/Libplanet.Node.Tests/BlockChainUtility.cs",
    "content": "using Libplanet.Action;\nusing Libplanet.Blockchain;\nusing Libplanet.Crypto;\nusing Libplanet.Types.Blocks;\nusing Libplanet.Types.Tx;\n\nnamespace Libplanet.Node.Tests;\n\ninternal static class BlockChainUtility\n{\n    public static Task<Block> AppendBlockAsync(BlockChain blockChain)\n        => AppendBlockAsync(blockChain, new PrivateKey());\n\n    public static async Task<Block> AppendBlockAsync(BlockChain blockChain, PrivateKey privateKey)\n    {\n        var tip = blockChain.Tip;\n        var height = tip.Index + 1;\n        var block = blockChain.ProposeBlock(\n            proposer: privateKey,\n            lastCommit: blockChain.GetBlockCommit(tip.Hash));\n        blockChain.Append(\n            block,\n            blockChain.GetBlockCommit(tip.Hash),\n            validate: false);\n\n        while (blockChain.Tip.Index < height)\n        {\n            await Task.Delay(100);\n        }\n\n        await Task.Delay(1000);\n\n        return block;\n    }\n\n    public static void StageTransaction(\n        BlockChain blockChain, IAction[] actions)\n        => StageTransaction(blockChain, new PrivateKey(), actions);\n\n    public static void StageTransaction(\n        BlockChain blockChain, PrivateKey privateKey, IAction[] actions)\n    {\n        var transaction = CreateTransaction(blockChain, privateKey, actions);\n        blockChain.StageTransaction(transaction);\n    }\n\n    public static Transaction CreateTransaction(\n        BlockChain blockChain, IAction[] actions)\n        => CreateTransaction(blockChain, new PrivateKey(), actions);\n\n    public static Transaction CreateTransaction(\n        BlockChain blockChain, PrivateKey privateKey, IAction[] actions)\n    {\n        var genesisBlock = blockChain.Genesis;\n        var nonce = blockChain.GetNextTxNonce(privateKey.Address);\n        var values = actions.Select(item => item.PlainValue).ToArray();\n        return Transaction.Create(\n            nonce: nonce,\n            privateKey: privateKey,\n            genesisHash: genesisBlock.Hash,\n            actions: new TxActionList(values));\n    }\n}\n"
  },
  {
    "path": "sdk/node/Libplanet.Node.Tests/DisposerCollection.cs",
    "content": "using System.Collections;\n\nnamespace Libplanet.Node.Tests;\n\ninternal sealed class DisposerCollection(IEnumerable<IDisposable> disposables)\n    : IEnumerable<IDisposable>, IDisposable\n{\n    private readonly List<IDisposable> _items = disposables.ToList();\n\n    public void Dispose() => _items.ForEach(item => item.Dispose());\n\n    public IEnumerator<IDisposable> GetEnumerator() => _items.GetEnumerator();\n\n    IEnumerator IEnumerable.GetEnumerator() => _items.GetEnumerator();\n}\n"
  },
  {
    "path": "sdk/node/Libplanet.Node.Tests/DumbAction.cs",
    "content": "using System.Diagnostics;\nusing Bencodex.Types;\nusing Libplanet.Action;\nusing Libplanet.Action.State;\n\nnamespace Libplanet.Node.Tests;\n\npublic class DumbAction : IAction\n{\n    public string ErrorMessage { get; set; } = string.Empty;\n\n    public IValue PlainValue => Dictionary.Empty\n        .Add(\"error_message\", ErrorMessage);\n\n    public void LoadPlainValue(IValue plainValue)\n    {\n        if (plainValue is Dictionary dictionary)\n        {\n            ErrorMessage = (Text)dictionary[\"error_message\"];\n        }\n        else\n        {\n            throw new UnreachableException(\"The plain value of DumbAction must be a dictionary.\");\n        }\n    }\n\n    public IWorld Execute(IActionContext context)\n    {\n        if (ErrorMessage != string.Empty)\n        {\n            throw new InvalidOperationException(ErrorMessage);\n        }\n\n        return context.PreviousState;\n    }\n}\n"
  },
  {
    "path": "sdk/node/Libplanet.Node.Tests/DumbActionLoader.cs",
    "content": "using Bencodex.Types;\nusing Libplanet.Action;\nusing Libplanet.Action.Loader;\nusing Libplanet.Action.Sys;\n\nnamespace Libplanet.Node.Tests;\n\npublic sealed class DumbActionLoader : IActionLoader\n{\n    public IAction LoadAction(long index, IValue value)\n    {\n        if (Registry.IsSystemAction(value))\n        {\n            return Registry.Deserialize(value);\n        }\n\n        var action = new DumbAction();\n        action.LoadPlainValue(value);\n        return action;\n    }\n}\n"
  },
  {
    "path": "sdk/node/Libplanet.Node.Tests/Libplanet.Node.Tests.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <PropertyGroup>\n    <IsPackable>false</IsPackable>\n    <IsTestProject>true</IsTestProject>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <PackageReference Include=\"JunitXml.TestLogger\" Version=\"3.0.98\" />\n    <PackageReference Include=\"coverlet.collector\" Version=\"6.0.0\" />\n    <PackageReference Include=\"Microsoft.NET.Test.Sdk\" Version=\"17.8.0\" />\n    <PackageReference Include=\"xunit\" Version=\"2.5.3\" />\n    <PackageReference Include=\"xunit.runner.visualstudio\" Version=\"2.5.3\" />\n    <PackageReference Include=\"Moq\" Version=\"4.20.70\" />\n    <PackageReference Include=\"Moq.AutoMock\" Version=\"3.5.0\" />\n    <PackageReference Include=\"Microsoft.CodeAnalysis.CSharp\" Version=\"4.11.0\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <Using Include=\"Xunit\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <ProjectReference Include=\"..\\Libplanet.Node\\Libplanet.Node.csproj\" />\n    <ProjectReference Include=\"..\\Libplanet.Node.Extensions\\Libplanet.Node.Extensions.csproj\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <Compile Remove=\".\\Services\\ActionServiceTestSource.cs\" />\n    <EmbeddedResource Include=\".\\Services\\ActionServiceTestSource.cs\" />\n  </ItemGroup>\n\n</Project>\n"
  },
  {
    "path": "sdk/node/Libplanet.Node.Tests/Options/OptionsBaseTest.cs",
    "content": "using Libplanet.Node.Options;\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.Logging;\nusing Microsoft.Extensions.Logging.Abstractions;\nusing Microsoft.Extensions.Options;\n\nnamespace Libplanet.Node.Tests.Options;\n\npublic class OptionsBaseTest\n{\n    [Fact]\n    public void Configured_Test()\n    {\n        var services = new ServiceCollection();\n        services.AddLogging(configure => configure.AddProvider(NullLoggerProvider.Instance));\n        services.AddSingleton<IConfigureOptions<TestOptions>, TestOptionsConfigurator>();\n        var serviceProvider = services.BuildServiceProvider();\n        var options = serviceProvider.GetRequiredService<IOptions<TestOptions>>().Value;\n\n        Assert.True(options.IsConfigured);\n    }\n\n    [Fact]\n    public void NotConfigured_Test()\n    {\n        var services = new ServiceCollection();\n        services.AddLogging(configure => configure.AddProvider(NullLoggerProvider.Instance));\n        var serviceProvider = services.BuildServiceProvider();\n        var options = serviceProvider.GetRequiredService<IOptions<TestOptions>>().Value;\n\n        Assert.False(options.IsConfigured);\n    }\n\n    [Fact]\n    public void Validated_Test()\n    {\n        var services = new ServiceCollection();\n        services.AddLogging(configure => configure.AddProvider(NullLoggerProvider.Instance));\n        services.AddSingleton<IValidateOptions<TestOptions>, TestOptionsValidator>();\n        var serviceProvider = services.BuildServiceProvider();\n        var options = serviceProvider.GetRequiredService<IOptions<TestOptions>>().Value;\n\n        Assert.True(options.IsValidated);\n    }\n\n    [Fact]\n    public void NotValidated_Test()\n    {\n        var services = new ServiceCollection();\n        services.AddLogging(configure => configure.AddProvider(NullLoggerProvider.Instance));\n        var serviceProvider = services.BuildServiceProvider();\n        var options = serviceProvider.GetRequiredService<IOptions<TestOptions>>().Value;\n\n        Assert.False(options.IsValidated);\n    }\n\n    private sealed class TestOptions : OptionsBase<TestOptions>\n    {\n        public string Value { get; set; } = string.Empty;\n    }\n\n    private sealed class TestOptionsConfigurator : OptionsConfiguratorBase<TestOptions>\n    {\n        protected override void OnConfigure(TestOptions options)\n        {\n        }\n    }\n\n    private sealed class TestOptionsValidator : OptionsValidatorBase<TestOptions>\n    {\n        protected override void OnValidate(string? name, TestOptions options)\n        {\n        }\n    }\n}\n"
  },
  {
    "path": "sdk/node/Libplanet.Node.Tests/RandomBoundPeer.cs",
    "content": "using System.Net;\nusing Libplanet.Crypto;\nusing Libplanet.Net;\n\nnamespace Libplanet.Node.Tests;\n\ninternal sealed class RandomBoundPeer : IDisposable\n{\n    private readonly BoundPeer _boundPeer;\n    private readonly PrivateKey _privateKey = new();\n    private readonly RandomEndPoint _endPoint = new();\n\n    public RandomBoundPeer() => _boundPeer = new BoundPeer(PublicKey, _endPoint);\n\n    public RandomBoundPeer(PrivateKey privateKey)\n    {\n        _privateKey = privateKey;\n        _boundPeer = new BoundPeer(PublicKey, _endPoint);\n    }\n\n    public PrivateKey PrivateKey => _privateKey;\n\n    public PublicKey PublicKey => _privateKey.PublicKey;\n\n    public EndPoint EndPoint => _endPoint;\n\n    public static implicit operator BoundPeer(RandomBoundPeer randomBoundPeer)\n        => randomBoundPeer._boundPeer;\n\n    public override string ToString() => $\"{PublicKey}, {_endPoint}\";\n\n    public void Dispose() => _endPoint.Dispose();\n}\n"
  },
  {
    "path": "sdk/node/Libplanet.Node.Tests/RandomEndPoint.cs",
    "content": "using System.Net;\nusing System.Net.Sockets;\n\nnamespace Libplanet.Node.Tests;\n\ninternal sealed class RandomEndPoint : IDisposable\n{\n    private static readonly object LockObject = new();\n    private static readonly List<int> PortList = [];\n\n    private readonly DnsEndPoint _endPoint;\n    private bool _isDisposed;\n\n    public RandomEndPoint() => _endPoint = new DnsEndPoint(\"localhost\", GetPort());\n\n    public string Host => _endPoint.Host;\n\n    public int Port => _endPoint.Port;\n\n    public static implicit operator DnsEndPoint(RandomEndPoint endPointObject)\n        => endPointObject._endPoint;\n\n    public override string ToString() => $\"{_endPoint.Host}:{_endPoint.Port}\";\n\n    public void Dispose()\n    {\n        ObjectDisposedException.ThrowIf(_isDisposed, this);\n\n        lock (LockObject)\n        {\n            PortList.Remove(_endPoint.Port);\n        }\n\n        _isDisposed = true;\n    }\n\n    private static int GetPort()\n    {\n        lock (LockObject)\n        {\n            var port = GetRandomPort();\n            while (PortList.Contains(port))\n            {\n                port = GetRandomPort();\n            }\n\n            PortList.Add(port);\n            return port;\n        }\n    }\n\n    private static int GetRandomPort()\n    {\n        var listener = new TcpListener(IPAddress.Loopback, 0);\n        listener.Start();\n        var port = ((IPEndPoint)listener.LocalEndpoint).Port;\n        listener.Stop();\n        return port;\n    }\n}\n"
  },
  {
    "path": "sdk/node/Libplanet.Node.Tests/RandomPrivateKey.cs",
    "content": "using Libplanet.Common;\nusing Libplanet.Crypto;\nusing Libplanet.Net;\n\nnamespace Libplanet.Node.Tests;\n\ninternal sealed class RandomPrivateKey\n{\n    private readonly PrivateKey _privateKey = new();\n\n    public PublicKey PublicKey => _privateKey.PublicKey;\n\n    public Address Address => _privateKey.PublicKey.Address;\n\n    public static implicit operator PrivateKey(RandomPrivateKey randomPrivateKey)\n        => randomPrivateKey._privateKey;\n\n    public override string ToString() => ByteUtil.Hex(_privateKey.ByteArray);\n\n    public AppProtocolVersion ToAppProtocolVersion(int version)\n        => AppProtocolVersion.Sign(_privateKey, version);\n}\n"
  },
  {
    "path": "sdk/node/Libplanet.Node.Tests/Services/ActionServiceTest.cs",
    "content": "using Libplanet.Action;\nusing Libplanet.Action.Loader;\nusing Libplanet.Node.Options;\nusing Libplanet.Node.Services;\nusing Microsoft.Extensions.DependencyInjection;\n\nnamespace Libplanet.Node.Tests.Services;\n\npublic class ActionServiceTest(TempDirectoryFixture tempDirectoryFixture)\n    : IClassFixture<TempDirectoryFixture>\n{\n    private readonly TempDirectoryFixture _tempDirectoryFixture = tempDirectoryFixture;\n\n    [Fact]\n    public void Base_Test()\n    {\n        var serviceProvider = TestUtility.CreateServiceProvider();\n        var actionService = serviceProvider.GetRequiredService<IActionService>();\n\n        Assert.IsType<AggregateTypedActionLoader>(actionService.ActionLoader);\n        Assert.IsType<PolicyActionsRegistry>(actionService.PolicyActionsRegistry);\n    }\n\n    [Fact]\n    public void Base_WithModulePath_Test()\n    {\n        var actionLoaderType = \"Libplanet.Node.DumbActions.DumbActionLoader\";\n        var policyActionRegistryType = \"Libplanet.Node.DumbActions.DumbActionPolicyActionsRegistry\";\n        var codePath = \"Libplanet.Node.Tests.Services.ActionServiceTestSource.cs\";\n        var codeStream = typeof(ActionServiceTest).Assembly.GetManifestResourceStream(codePath)\n            ?? throw new FileNotFoundException($\"Resource '{codePath}' not found.\");\n        using var reader = new StreamReader(codeStream);\n        var code = reader.ReadToEnd();\n        var assemblyName = Path.GetRandomFileName();\n        var assemblyPath = $\"{_tempDirectoryFixture.GetRandomFileName()}.dll\";\n\n        var settings = new Dictionary<string, string?>\n        {\n            [$\"{ActionOptions.Position}:{nameof(ActionOptions.ModulePath)}\"]\n                = assemblyPath,\n            [$\"{ActionOptions.Position}:{nameof(ActionOptions.ActionLoaderType)}\"]\n                = actionLoaderType,\n            [$\"{ActionOptions.Position}:{nameof(ActionOptions.PolicyActionRegistryType)}\"]\n                = policyActionRegistryType,\n        };\n\n        RuntimeCompiler.CompileCode(code, assemblyName, assemblyPath);\n\n        var serviceProvider = TestUtility.CreateServiceProvider(settings);\n        var actionService = serviceProvider.GetRequiredService<IActionService>();\n\n        Assert.Equal(actionLoaderType, actionService.ActionLoader.GetType().FullName);\n        Assert.Equal(\n            expected: policyActionRegistryType,\n            actual: actionService.PolicyActionsRegistry.GetType().FullName);\n    }\n}\n"
  },
  {
    "path": "sdk/node/Libplanet.Node.Tests/Services/ActionServiceTestSource.cs",
    "content": "// This code does not compile because it is used by ActionServiceTest test.\n#pragma warning disable MEN008 // A file's name should match or include the name of the main type it contains.\nusing System.Collections.Immutable;\nusing Bencodex.Types;\nusing Libplanet.Action;\nusing Libplanet.Action.Loader;\nusing Libplanet.Action.State;\nusing Libplanet.Action.Sys;\n\nnamespace Libplanet.Node.DumbActions;\n\npublic class DumbAction : IAction\n{\n    public IValue PlainValue => Dictionary.Empty;\n\n    public void LoadPlainValue(IValue plainValue)\n    {\n        // Do nothing.\n    }\n\n    public IWorld Execute(IActionContext context) =>\n        context.PreviousState;\n}\n\npublic sealed class DumbBeginAction : DumbAction\n{\n}\n\npublic sealed class DumbEndAction : DumbAction\n{\n}\n\npublic sealed class DumbBeginTxAction : DumbAction\n{\n}\n\npublic sealed class DumbEndTxAction : DumbAction\n{\n}\n\npublic sealed class DumbActionLoader : IActionLoader\n{\n    public IAction LoadAction(long index, IValue value)\n    {\n        if (Registry.IsSystemAction(value))\n        {\n            return Registry.Deserialize(value);\n        }\n\n        return new DumbAction();\n    }\n}\n\npublic sealed class DumbActionPolicyActionsRegistry : IPolicyActionsRegistry\n{\n    public ImmutableArray<IAction> BeginBlockActions => [new DumbBeginAction()];\n\n    public ImmutableArray<IAction> EndBlockActions => [new DumbEndAction()];\n\n    public ImmutableArray<IAction> BeginTxActions => [new DumbBeginTxAction()];\n\n    public ImmutableArray<IAction> EndTxActions => [new DumbEndTxAction()];\n}\n"
  },
  {
    "path": "sdk/node/Libplanet.Node.Tests/Services/BlockChainServiceTest.cs",
    "content": "using Bencodex;\nusing Bencodex.Types;\nusing Libplanet.Common;\nusing Libplanet.Crypto;\nusing Libplanet.Node.Extensions;\nusing Libplanet.Node.Services;\nusing Microsoft.Extensions.Configuration;\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.Logging;\nusing Microsoft.Extensions.Logging.Abstractions;\n\nnamespace Libplanet.Node.Tests.Services;\n\npublic class BlockChainServiceTest\n{\n    [Fact]\n    public void Create_Test()\n    {\n        var serviceProvider = TestUtility.CreateServiceProvider();\n        var blockChainService = serviceProvider.GetRequiredService<IBlockChainService>();\n        var blockChain = blockChainService.BlockChain;\n\n        Assert.Equal(1, blockChain.Count);\n    }\n\n    [Fact]\n    public void Create_Using_Genesis_Configuration_Test()\n    {\n        var genesisKey = new PrivateKey();\n        string tempDirectory = Path.GetTempPath();\n        string tempFilePath = Path.Combine(tempDirectory, Guid.NewGuid().ToString() + \".json\");\n        Address accountA = new(\"0000000000000000000000000000000000000000\");\n        Address accountB = new(\"0000000000000000000000000000000000000001\");\n        Address addressA = new(\"0000000000000000000000000000000000000000\");\n        Address addressB = new(\"0000000000000000000000000000000000000001\");\n        var codec = new Codec();\n\n        try\n        {\n            string jsonContent = $@\"\n            {{\n                \"\"{accountA}\"\": {{\n                    \"\"{addressA}\"\": \"\"{ByteUtil.Hex(codec.Encode((Text)\"A\"))}\"\",\n                    \"\"{addressB}\"\": \"\"{ByteUtil.Hex(codec.Encode((Integer)123))}\"\"\n                }},\n                \"\"{accountB}\"\": {{\n                    \"\"{addressA}\"\": \"\"{ByteUtil.Hex(codec.Encode((Text)\"B\"))}\"\",\n                    \"\"{addressB}\"\": \"\"{ByteUtil.Hex(codec.Encode((Integer)456))}\"\"\n                }}\n            }}\";\n            File.WriteAllText(tempFilePath, jsonContent);\n            var configDict = new Dictionary<string, string>\n            {\n                { \"Genesis:GenesisConfigurationPath\", tempFilePath },\n                { \"Genesis:GenesisKey\", ByteUtil.Hex(genesisKey.ToByteArray()) },\n            };\n\n            var configuration = new ConfigurationBuilder()\n                .AddInMemoryCollection(configDict!)\n                .Build();\n\n            var services = new ServiceCollection();\n            services.AddSingleton<ILoggerFactory, NullLoggerFactory>();\n            services.AddLogging();\n            services.AddLibplanetNode(configuration);\n            var serviceProvider = services.BuildServiceProvider();\n            var blockChainService = serviceProvider.GetRequiredService<IBlockChainService>();\n            var blockChain = blockChainService.BlockChain;\n            var worldState = blockChain.GetNextWorldState()!;\n            Assert.Equal((Text)\"A\", worldState.GetAccountState(accountA).GetState(addressA));\n            Assert.Equal((Integer)123, worldState.GetAccountState(accountA).GetState(addressB));\n            Assert.Equal((Text)\"B\", worldState.GetAccountState(accountB).GetState(addressA));\n            Assert.Equal((Integer)456, worldState.GetAccountState(accountB).GetState(addressB));\n        }\n        finally\n        {\n            if (File.Exists(tempFilePath))\n            {\n                File.Delete(tempFilePath);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "sdk/node/Libplanet.Node.Tests/Services/PeerTest.cs",
    "content": "using Libplanet.Net;\nusing Libplanet.Net.Messages;\nusing Libplanet.Net.Transports;\nusing Libplanet.Node.Services;\nusing Moq;\n\nnamespace Libplanet.Node.Tests.Services;\n\npublic class PeerTest\n{\n    [Fact]\n    public void Base_Test()\n    {\n        var transportMock = new Mock<ITransport>();\n        using var boundPeer = new RandomBoundPeer();\n        var peer = new Peer(transportMock.Object, boundPeer);\n\n        Assert.Equal(boundPeer.PublicKey.Address, peer.Address);\n        Assert.Equal(boundPeer, peer.BoundPeer);\n        Assert.Equal(DateTimeOffset.MinValue, peer.LastUpdated);\n        Assert.Equal(DateTimeOffset.MinValue, peer.LifeTime);\n        Assert.Equal(TimeSpan.FromSeconds(120), peer.LifeTimeSpan);\n        Assert.Equal(TimeSpan.MinValue, peer.Latency);\n        Assert.False(peer.IsAlive);\n    }\n\n    [Fact]\n    public void Update_Test()\n    {\n        var transportMock = new Mock<ITransport>();\n        using var boundPeer = new RandomBoundPeer();\n        var peer = new Peer(transportMock.Object, boundPeer);\n        var now = DateTimeOffset.UtcNow;\n        peer.Update();\n\n        Assert.True(now <= peer.LastUpdated);\n        Assert.True(now + TimeSpan.FromSeconds(120) <= peer.LifeTime);\n        Assert.True(peer.IsAlive);\n    }\n\n    [Fact]\n    public async Task PingAsync_TestAsync()\n    {\n        var pongMsg = new PongMsg();\n        var apv = AppProtocolVersion.Sign(new(), 0);\n        using var messageBoundPeer = new RandomBoundPeer();\n        var message = new Message(pongMsg, apv, messageBoundPeer, DateTimeOffset.Now, []);\n        var transportMock = new Mock<ITransport>();\n\n        transportMock.Setup(item => item.SendMessageAsync(\n            It.IsAny<BoundPeer>(),\n            It.IsAny<PingMsg>(),\n            It.IsAny<TimeSpan>(),\n            It.IsAny<CancellationToken>()))\n            .ReturnsAsync(message);\n\n        using var boundPeer = new RandomBoundPeer();\n        var timeout = TimeSpan.FromSeconds(1);\n        var peer = new Peer(transportMock.Object, boundPeer);\n\n        var result = await peer.PingAsync(timeout, cancellationToken: default);\n\n        transportMock.Verify();\n        Assert.True(result);\n    }\n\n    [Fact]\n    public async Task PingAsync_Cancel_TestAsync()\n    {\n        var pongMsg = new PongMsg();\n        var apv = AppProtocolVersion.Sign(new(), 0);\n        using var messageBoundPeer = new RandomBoundPeer();\n        var message = new Message(pongMsg, apv, messageBoundPeer, DateTimeOffset.Now, []);\n        var transportMock = new Mock<ITransport>();\n\n        async Task<Message> SendMessageAsync(\n            BoundPeer peer,\n            MessageContent content,\n            TimeSpan? timeout,\n            CancellationToken cancellationToken)\n        {\n            await Task.Delay(1000, cancellationToken);\n            return message;\n        }\n\n        transportMock\n            .Setup(item => item.SendMessageAsync(\n                It.IsAny<BoundPeer>(),\n                It.IsAny<PingMsg>(),\n                It.IsAny<TimeSpan>(),\n                It.IsAny<CancellationToken>()))\n            .Returns(SendMessageAsync);\n\n        using var boundPeer = new RandomBoundPeer();\n        var timeout = TimeSpan.FromSeconds(1);\n        var peer = new Peer(transportMock.Object, boundPeer);\n        using var cancellationTokenSource = new CancellationTokenSource(1);\n\n        var result = await peer.PingAsync(timeout, cancellationTokenSource.Token);\n\n        Assert.False(result);\n        Assert.Equal(TimeSpan.MinValue, peer.Latency);\n    }\n}\n"
  },
  {
    "path": "sdk/node/Libplanet.Node.Tests/Services/ReadChainServiceTest.cs",
    "content": "using Libplanet.Node.Services;\nusing Microsoft.Extensions.DependencyInjection;\n\nnamespace Libplanet.Node.Tests.Services;\n\npublic class ReadChainServiceTest\n{\n    [Fact]\n    public void Tip_Test()\n    {\n        var serviceProvider = TestUtility.CreateServiceProvider();\n        var readChainService = serviceProvider.GetRequiredService<IReadChainService>();\n        var expectedBlock = readChainService.GetBlock(0);\n\n        Assert.Equal(expectedBlock, readChainService.Tip);\n    }\n\n    [Fact]\n    public async Task GetBlock_WithHash_TestAsync()\n    {\n        var serviceProvider = TestUtility.CreateServiceProvider();\n        var blockChainService = serviceProvider.GetRequiredService<IBlockChainService>();\n        var blockChain = blockChainService.BlockChain;\n        var readChainService = serviceProvider.GetRequiredService<IReadChainService>();\n        var expectedBlock = await BlockChainUtility.AppendBlockAsync(blockChain);\n\n        Assert.Equal(expectedBlock, readChainService.GetBlock(expectedBlock.Hash));\n    }\n\n    [Fact]\n    public async Task GetBlock_WithHeight_TestAsync()\n    {\n        var serviceProvider = TestUtility.CreateServiceProvider();\n        var blockChainService = serviceProvider.GetRequiredService<IBlockChainService>();\n        var blockChain = blockChainService.BlockChain;\n        var readChainService = serviceProvider.GetRequiredService<IReadChainService>();\n        var height = blockChain.Count;\n        var expectedBlock = await BlockChainUtility.AppendBlockAsync(blockChain);\n\n        Assert.Equal(expectedBlock, readChainService.GetBlock(height));\n    }\n}\n"
  },
  {
    "path": "sdk/node/Libplanet.Node.Tests/Services/RendererServiceTest.cs",
    "content": "using Libplanet.Action;\nusing Libplanet.Node.Options;\nusing Libplanet.Node.Services;\nusing Microsoft.Extensions.DependencyInjection;\n\nnamespace Libplanet.Node.Tests.Services;\n\npublic class RendererServiceTest\n{\n    [Fact]\n    public async Task RenderBlock_TestAsync()\n    {\n        var serviceProvider = TestUtility.CreateServiceProvider();\n        var blockChainService = serviceProvider.GetRequiredService<IBlockChainService>();\n        var rendererService = serviceProvider.GetRequiredService<IRendererService>();\n        var blockChain = blockChainService.BlockChain;\n\n        using var observer = new TestObserver<RenderBlockInfo>(rendererService.RenderBlock);\n        await Assert.RaisesAnyAsync<RenderBlockInfo>(\n            attach: handler => observer.Next += handler,\n            detach: handler => observer.Next -= handler,\n            testCode: async () => await BlockChainUtility.AppendBlockAsync(blockChain));\n    }\n\n    [Fact]\n    public async Task RenderAction_TestAsync()\n    {\n        var settings = new Dictionary<string, string?>\n        {\n            [$\"{ActionOptions.Position}:{nameof(ActionOptions.ModulePath)}\"]\n                = typeof(DumbActionLoader).Assembly.Location,\n            [$\"{ActionOptions.Position}:{nameof(ActionOptions.ActionLoaderType)}\"]\n                = typeof(DumbActionLoader).FullName,\n        };\n\n        var serviceProvider = TestUtility.CreateServiceProvider(settings);\n        var blockChainService = serviceProvider.GetRequiredService<IBlockChainService>();\n        var rendererService = serviceProvider.GetRequiredService<IRendererService>();\n        var blockChain = blockChainService.BlockChain;\n\n        var actions = new IAction[]\n        {\n            new DumbAction(),\n            new DumbAction(),\n            new DumbAction(),\n        };\n\n        using var observer = new TestObserver<RenderActionInfo>(rendererService.RenderAction);\n        await Assert.RaisesAnyAsync<RenderActionInfo>(\n            attach: handler => observer.Next += handler,\n            detach: handler => observer.Next -= handler,\n            testCode: async () =>\n            {\n                BlockChainUtility.StageTransaction(blockChain, actions);\n                await BlockChainUtility.AppendBlockAsync(blockChain);\n            });\n    }\n\n    [Fact]\n    public async Task RenderActionError_TestAsync()\n    {\n        var settings = new Dictionary<string, string?>\n        {\n            [$\"{ActionOptions.Position}:{nameof(ActionOptions.ModulePath)}\"]\n                = typeof(DumbActionLoader).Assembly.Location,\n            [$\"{ActionOptions.Position}:{nameof(ActionOptions.ActionLoaderType)}\"]\n                = typeof(DumbActionLoader).FullName,\n        };\n\n        var serviceProvider = TestUtility.CreateServiceProvider(settings);\n        var blockChainService = serviceProvider.GetRequiredService<IBlockChainService>();\n        var rendererService = serviceProvider.GetRequiredService<IRendererService>();\n        var blockChain = blockChainService.BlockChain;\n        var errorMessage = \"123\";\n\n        var actions = new IAction[]\n        {\n            new DumbAction() { ErrorMessage = errorMessage },\n        };\n\n        using var observer = new TestObserver<RenderActionErrorInfo>(\n            rendererService.RenderActionError);\n        var errorInfo = await Assert.RaisesAnyAsync<RenderActionErrorInfo>(\n            attach: handler => observer.Next += handler,\n            detach: handler => observer.Next -= handler,\n            testCode: async () =>\n            {\n                BlockChainUtility.StageTransaction(blockChain, actions);\n                await BlockChainUtility.AppendBlockAsync(blockChain);\n            });\n        Assert.Equal(errorMessage, errorInfo.Arguments.Exception.InnerException!.Message);\n    }\n\n    [Fact]\n    public async Task RenderBlockEnd_TestAsync()\n    {\n        var serviceProvider = TestUtility.CreateServiceProvider();\n        var blockChainService = serviceProvider.GetRequiredService<IBlockChainService>();\n        var rendererService = serviceProvider.GetRequiredService<IRendererService>();\n        var blockChain = blockChainService.BlockChain;\n\n        using var observer = new TestObserver<RenderBlockInfo>(rendererService.RenderBlockEnd);\n        await Assert.RaisesAnyAsync<RenderBlockInfo>(\n            attach: handler => observer.Next += handler,\n            detach: handler => observer.Next -= handler,\n            testCode: async () => await BlockChainUtility.AppendBlockAsync(blockChain));\n    }\n}\n"
  },
  {
    "path": "sdk/node/Libplanet.Node.Tests/Services/RuntimeCompiler.cs",
    "content": "using System.Reflection;\nusing System.Runtime.InteropServices;\nusing System.Text;\nusing Bencodex.Types;\nusing Libplanet.Action;\nusing Microsoft.CodeAnalysis;\nusing Microsoft.CodeAnalysis.CSharp;\n\nnamespace Libplanet.Node.Tests.Services;\n\ninternal static class RuntimeCompiler\n{\n    public static void CompileCode(string code, string assemblyName, string assemblyPath)\n    {\n        var syntaxTree = CSharpSyntaxTree.ParseText(code);\n        var references = new MetadataReference[]\n        {\n            MetadataReference.CreateFromFile(typeof(object).Assembly.Location),\n            MetadataReference.CreateFromFile(typeof(IAction).Assembly.Location),\n            MetadataReference.CreateFromFile(typeof(IValue).Assembly.Location),\n            MetadataReference.CreateFromFile(GetRuntimeLibraryPath(\"netstandard.dll\")),\n            MetadataReference.CreateFromFile(GetRuntimeLibraryPath(\"System.Runtime.dll\")),\n            MetadataReference.CreateFromFile(\n                GetRuntimeLibraryPath(\"System.Collections.Immutable.dll\")),\n        };\n\n        var options = new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary);\n        var compilation = CSharpCompilation.Create(\n            assemblyName, [syntaxTree], references, options);\n\n        // 어셈블리 스트림 생성\n        using var fs = new FileStream(assemblyPath, FileMode.Create);\n        var result = compilation.Emit(fs);\n\n        if (!result.Success)\n        {\n            var sb = new StringBuilder();\n            sb.AppendLine(\"Compilation failed.\");\n            foreach (var diagnostic in result.Diagnostics)\n            {\n                sb.AppendLine(diagnostic.ToString());\n            }\n\n            throw new InvalidOperationException(sb.ToString());\n        }\n\n        fs.Close();\n    }\n\n    private static string GetRuntimeLibraryPath(string name)\n        => Path.Combine(RuntimeEnvironment.GetRuntimeDirectory(), name);\n}\n"
  },
  {
    "path": "sdk/node/Libplanet.Node.Tests/Services/SeedTest.cs",
    "content": "using Libplanet.Net;\nusing Libplanet.Net.Messages;\nusing Libplanet.Net.Options;\nusing Libplanet.Net.Transports;\nusing Libplanet.Node.Options;\nusing Libplanet.Node.Services;\n\nnamespace Libplanet.Node.Tests.Services;\n\npublic class SeedTest\n{\n    private static readonly TimeSpan Timeout = TimeSpan.FromSeconds(10);\n\n    [Fact]\n    public void Base_Test()\n    {\n        var privateKey = new RandomPrivateKey();\n        using var endPoint = new RandomEndPoint();\n        var options = new SeedOptions\n        {\n            PrivateKey = privateKey.ToString(),\n            EndPoint = endPoint.ToString(),\n            AppProtocolVersion = privateKey.ToAppProtocolVersion(0).Token,\n        };\n        var seed = new Seed(options);\n        Assert.Equal(endPoint.Host, seed.BoundPeer.EndPoint.Host);\n        Assert.Equal(endPoint.Port, seed.BoundPeer.EndPoint.Port);\n        Assert.Equal(privateKey.PublicKey, seed.BoundPeer.PublicKey);\n        Assert.False(seed.IsRunning);\n        Assert.Empty(seed.Peers);\n    }\n\n    [Fact]\n    public async Task StartAsync_TestAsync()\n    {\n        var privateKey = new RandomPrivateKey();\n        using var endPoint = new RandomEndPoint();\n        var options = new SeedOptions\n        {\n            PrivateKey = privateKey.ToString(),\n            EndPoint = endPoint.ToString(),\n            AppProtocolVersion = privateKey.ToAppProtocolVersion(0).Token,\n        };\n        await using var seed = new Seed(options);\n        await seed.StartAsync(cancellationToken: default);\n        Assert.True(seed.IsRunning);\n    }\n\n    [Fact]\n    public async Task StartAsync_Twice_ThrowTestAsync()\n    {\n        var privateKey = new RandomPrivateKey();\n        using var endPoint = new RandomEndPoint();\n        var options = new SeedOptions\n        {\n            PrivateKey = privateKey.ToString(),\n            EndPoint = endPoint.ToString(),\n            AppProtocolVersion = privateKey.ToAppProtocolVersion(0).Token,\n        };\n        await using var seed = new Seed(options);\n        await seed.StartAsync(cancellationToken: default);\n        await Assert.ThrowsAsync<InvalidOperationException>(async () =>\n        {\n            await seed.StartAsync(cancellationToken: default);\n        });\n    }\n\n    [Fact]\n    public async Task StopAsync_TestAsync()\n    {\n        var privateKey = new RandomPrivateKey();\n        using var endPoint = new RandomEndPoint();\n        var options = new SeedOptions\n        {\n            PrivateKey = privateKey.ToString(),\n            EndPoint = endPoint.ToString(),\n            AppProtocolVersion = privateKey.ToAppProtocolVersion(0).Token,\n        };\n        await using var seed = new Seed(options);\n        await seed.StartAsync(cancellationToken: default);\n        await seed.StopAsync(cancellationToken: default);\n        Assert.False(seed.IsRunning);\n    }\n\n    [Fact]\n    public async Task StopAsync_NotRunning_ThrowTestAsync()\n    {\n        var privateKey = new RandomPrivateKey();\n        using var endPoint = new RandomEndPoint();\n        var options = new SeedOptions\n        {\n            PrivateKey = privateKey.ToString(),\n            EndPoint = endPoint.ToString(),\n            AppProtocolVersion = privateKey.ToAppProtocolVersion(0).Token,\n        };\n        await using var seed = new Seed(options);\n        await Assert.ThrowsAsync<InvalidOperationException>(async () =>\n        {\n            await seed.StopAsync(cancellationToken: default);\n        });\n    }\n\n    [Fact]\n    public async Task MessageReceived_TestAsync()\n    {\n        // Given\n        var apv = AppProtocolVersion.Sign(new(), 0);\n        var remotePrivateKey = new RandomPrivateKey();\n        using var remoteEndPoint = new RandomEndPoint();\n        var remoteBoundPeer = new BoundPeer(remotePrivateKey.PublicKey, remoteEndPoint);\n        var remoteHostOptions = new HostOptions(remoteEndPoint.Host, [], remoteEndPoint.Port);\n        var remoteAPVOptions = new AppProtocolVersionOptions\n        {\n            AppProtocolVersion = apv,\n        };\n        using var transport = await NetMQTransport.Create(\n            remotePrivateKey, remoteAPVOptions, remoteHostOptions);\n\n        var seedPrivateKey = new RandomPrivateKey();\n        using var seedEndPoint = new RandomEndPoint();\n        var seedBoundPeer = new BoundPeer(seedPrivateKey.PublicKey, seedEndPoint);\n        var options = new SeedOptions\n        {\n            PrivateKey = seedPrivateKey.ToString(),\n            EndPoint = seedEndPoint.ToString(),\n            AppProtocolVersion = apv.Token,\n        };\n        await using var seed = new Seed(options);\n        await seed.StartAsync(cancellationToken: default);\n\n        // When\n        var now = DateTimeOffset.UtcNow;\n        var args = await Assert.RaisesAsync<SeedMessageEventArgs>(\n            handler => seed.MessageReceived += handler,\n            handler => seed.MessageReceived -= handler,\n            async () =>\n            {\n                await transport.SendMessageAsync(\n                    seedBoundPeer, new PingMsg(), TimeSpan.FromSeconds(10), default);\n            });\n\n        // Then\n        Assert.IsType<PingMsg>(args.Arguments.Message.Content);\n        var peer = seed.Peers.Single();\n        Assert.Equal(remoteBoundPeer, peer.BoundPeer);\n        Assert.True(now <= peer.LastUpdated);\n        Assert.True(now + TimeSpan.FromSeconds(120) <= peer.LifeTime);\n        Assert.True(peer.IsAlive);\n    }\n\n    [Fact]\n    public async Task GetNeighborsMsg_TestAsync()\n    {\n        // Given\n        var apv = AppProtocolVersion.Sign(new(), 0);\n        var length = Random.Shared.Next(3, 10);\n        var remotePrivateKeys = new RandomPrivateKey[length];\n        var remoteEndPoints = new RandomEndPoint[length];\n        var remoteBoundPeers = new BoundPeer[length];\n        var remoteAPVOptions = new AppProtocolVersionOptions\n        {\n            AppProtocolVersion = apv,\n        };\n        var transports = new ITransport[length];\n        for (var i = 0; i < length; i++)\n        {\n            remotePrivateKeys[i] = new RandomPrivateKey();\n            remoteEndPoints[i] = new RandomEndPoint();\n            remoteBoundPeers[i] = new BoundPeer(remotePrivateKeys[i].PublicKey, remoteEndPoints[i]);\n            transports[i] = await NetMQTransport.Create(\n                privateKey: remotePrivateKeys[i],\n                appProtocolVersionOptions: remoteAPVOptions,\n                hostOptions: new(remoteEndPoints[i].Host, [], remoteEndPoints[i].Port));\n        }\n\n        using var d1 = new DisposerCollection(remoteEndPoints);\n        using var d2 = new DisposerCollection(transports);\n\n        var seedPrivateKey = new RandomPrivateKey();\n        var seedEndPoint = new RandomEndPoint();\n        var seedBoundPeer = new BoundPeer(seedPrivateKey.PublicKey, seedEndPoint);\n        var options = new SeedOptions\n        {\n            PrivateKey = seedPrivateKey.ToString(),\n            EndPoint = seedEndPoint.ToString(),\n            AppProtocolVersion = apv.Token,\n        };\n        await using var seed = new Seed(options);\n        await seed.StartAsync(cancellationToken: default);\n\n        await Parallel.ForEachAsync(transports, async (transport, _) =>\n        {\n            await transport.SendMessageAsync(\n                seedBoundPeer, new PingMsg(), Timeout, default);\n        });\n\n        // When\n        var transport = transports[Random.Shared.Next(length)];\n        var replyMessage = await transport.SendMessageAsync(\n            seedBoundPeer, new FindNeighborsMsg(target: default), Timeout, default);\n\n        // Then\n        Assert.Equal(length, seed.Peers.Count);\n        Assert.IsType<NeighborsMsg>(replyMessage.Content);\n        var neighborsMsg = (NeighborsMsg)replyMessage.Content;\n        Assert.Equal(length, neighborsMsg.Found.Count);\n    }\n}\n"
  },
  {
    "path": "sdk/node/Libplanet.Node.Tests/Services/StoreServiceTest.cs",
    "content": "using Libplanet.Node.Options;\nusing Libplanet.Node.Services;\nusing Libplanet.Store;\nusing Libplanet.Store.Trie;\nusing Microsoft.Extensions.DependencyInjection;\n\nnamespace Libplanet.Node.Tests.Services;\n\npublic class StoreServiceTest\n{\n    [Fact]\n    public void RocksDB_Test()\n    {\n        var settings = new Dictionary<string, string?>\n        {\n            [$\"{StoreOptions.Position}:{nameof(StoreOptions.Type)}\"] = $\"{StoreType.RocksDB}\",\n        };\n        var serviceProvider = TestUtility.CreateServiceProvider(settings);\n        var storeService = serviceProvider.GetRequiredService<IStoreService>();\n\n        Assert.IsType<RocksDBStore.RocksDBStore>(storeService.Store);\n        Assert.IsType<RocksDBStore.RocksDBKeyValueStore>(storeService.KeyValueStore);\n    }\n\n    [Fact]\n    public void InMemory_Test()\n    {\n        var settings = new Dictionary<string, string?>\n        {\n            [$\"{StoreOptions.Position}:{nameof(StoreOptions.Type)}\"] = $\"{StoreType.InMemory}\",\n        };\n        var serviceProvider = TestUtility.CreateServiceProvider(settings);\n        var storeService = serviceProvider.GetRequiredService<IStoreService>();\n\n        Assert.IsType<MemoryStore>(storeService.Store);\n        Assert.IsType<MemoryKeyValueStore>(storeService.KeyValueStore);\n    }\n}\n"
  },
  {
    "path": "sdk/node/Libplanet.Node.Tests/Services/SwarmServiceTest.cs",
    "content": "using Libplanet.Node.Options;\nusing Libplanet.Node.Services;\nusing Microsoft.Extensions.DependencyInjection;\nusing R3;\n\nnamespace Libplanet.Node.Tests.Services;\n\npublic class SwarmServiceTest\n{\n    [Fact]\n    public void Enable_Test()\n    {\n        var settings = new Dictionary<string, string?>\n        {\n            [$\"{SwarmOptions.Position}:{nameof(SwarmOptions.IsEnabled)}\"] = \"true\",\n        };\n        var serviceProvider = TestUtility.CreateServiceProvider(settings);\n        var swarmService = serviceProvider.GetRequiredService<ISwarmService>();\n        Assert.NotNull(swarmService);\n        Assert.False(swarmService.IsRunning);\n    }\n\n    [Fact]\n    public void Disable_ThrowTest()\n    {\n        var serviceProvider = TestUtility.CreateServiceProvider();\n        Assert.ThrowsAny<Exception>(serviceProvider.GetRequiredService<ISwarmService>);\n    }\n\n    [Fact]\n    public async Task Start_TestAsync()\n    {\n        var serviceProvider = CreateServiceProviderWithSwarm();\n        var swarmService = serviceProvider.GetRequiredService<ISwarmService>();\n        var swarmServiceHost = serviceProvider.GetRequiredService<SwarmService>();\n\n        using var observer = new TestObserver<Unit>(swarmService.Started);\n        await Assert.RaisesAnyAsync<Unit>(\n            attach: handler => observer.Next += handler,\n            detach: handler => observer.Next -= handler,\n            async () => await swarmServiceHost.StartAsync(default));\n        Assert.True(swarmService.IsRunning);\n    }\n\n    [Fact]\n    public async Task Start_ThrowTestAsync()\n    {\n        var serviceProvider = CreateServiceProviderWithSwarm();\n        var swarmService = serviceProvider.GetRequiredService<ISwarmService>();\n        var swarmServiceHost = serviceProvider.GetRequiredService<SwarmService>();\n\n        await swarmServiceHost.StartAsync(default);\n        await Assert.ThrowsAsync<InvalidOperationException>(\n            async () => await swarmServiceHost.StartAsync(default));\n    }\n\n    [Fact]\n    public async Task Stop_TestAsync()\n    {\n        var serviceProvider = CreateServiceProviderWithSwarm();\n        var swarmService = serviceProvider.GetRequiredService<ISwarmService>();\n        var swarmServiceHost = serviceProvider.GetRequiredService<SwarmService>();\n        await swarmServiceHost.StartAsync(default);\n\n        using var observer = new TestObserver<Unit>(swarmService.Stopped);\n        await Assert.RaisesAnyAsync<Unit>(\n            attach: handler => observer.Next += handler,\n            detach: handler => observer.Next -= handler,\n            async () => await swarmServiceHost.StopAsync(default));\n        Assert.False(swarmService.IsRunning);\n    }\n\n    [Fact]\n    public async Task Stop_ThrowTestAsync()\n    {\n        var serviceProvider = CreateServiceProviderWithSwarm();\n        var swarmService = serviceProvider.GetRequiredService<ISwarmService>();\n        var swarmServiceHost = serviceProvider.GetRequiredService<SwarmService>();\n\n        await Assert.ThrowsAsync<InvalidOperationException>(\n            async () => await swarmServiceHost.StopAsync(default));\n    }\n\n    private static IServiceProvider CreateServiceProviderWithSwarm()\n    {\n        var settings = new Dictionary<string, string?>\n        {\n            [$\"{SwarmOptions.Position}:{nameof(SwarmOptions.IsEnabled)}\"] = \"true\",\n        };\n\n        return TestUtility.CreateServiceProvider(settings);\n    }\n}\n"
  },
  {
    "path": "sdk/node/Libplanet.Node.Tests/Services/ValidatorServiceTest.cs",
    "content": "using Libplanet.Node.Options;\nusing Libplanet.Node.Services;\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.Options;\n\nnamespace Libplanet.Node.Tests.Services;\n\npublic class ValidatorServiceTest\n{\n    [Fact]\n    public void Enable_Test()\n    {\n        var settings = new Dictionary<string, string?>\n        {\n            [$\"{SwarmOptions.Position}:{nameof(SwarmOptions.IsEnabled)}\"] = \"true\",\n            [$\"{ValidatorOptions.Position}:{nameof(ValidatorOptions.IsEnabled)}\"] = \"true\",\n        };\n        var serviceProvider = TestUtility.CreateServiceProvider(settings);\n        var validatorService = serviceProvider.GetRequiredService<IValidatorService>();\n        Assert.NotNull(validatorService);\n    }\n\n    [Fact]\n    public void Enable_WithoutSwarm_ThrowTest()\n    {\n        var settings = new Dictionary<string, string?>\n        {\n            [$\"{ValidatorOptions.Position}:{nameof(ValidatorOptions.IsEnabled)}\"] = \"true\",\n        };\n        var serviceProvider = TestUtility.CreateServiceProvider(settings);\n        Assert.Throws<OptionsValidationException>(\n            serviceProvider.GetRequiredService<IValidatorService>);\n    }\n\n    [Fact]\n    public void Disable_ThrowTest()\n    {\n        var serviceProvider = TestUtility.CreateServiceProvider();\n        Assert.ThrowsAny<InvalidOperationException>(\n            serviceProvider.GetRequiredService<ISwarmService>);\n    }\n}\n"
  },
  {
    "path": "sdk/node/Libplanet.Node.Tests/TempDirectoryFixture.cs",
    "content": "namespace Libplanet.Node.Tests;\n\npublic sealed class TempDirectoryFixture : IDisposable\n{\n    public TempDirectoryFixture()\n    {\n        TempDirectory = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName());\n        Directory.CreateDirectory(TempDirectory);\n    }\n\n    public string TempDirectory { get; }\n\n    public string GetRandomFileName()\n    {\n        if (!Directory.Exists(TempDirectory))\n        {\n            Directory.CreateDirectory(TempDirectory);\n        }\n\n        return Path.Combine(TempDirectory, Path.GetRandomFileName());\n    }\n\n    public void Dispose()\n    {\n        if (Directory.Exists(TempDirectory))\n        {\n            try\n            {\n                Directory.Delete(TempDirectory, true);\n            }\n            catch (UnauthorizedAccessException)\n            {\n                // ignore\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "sdk/node/Libplanet.Node.Tests/TestObserver.cs",
    "content": "namespace Libplanet.Node.Tests;\n\ninternal sealed class TestObserver<T> : IObserver<T>, IDisposable\n{\n    private IDisposable? _subscription;\n\n    public TestObserver(IObservable<T> observable)\n    {\n        _subscription = observable.Subscribe(this);\n    }\n\n    public event EventHandler? Completed;\n\n    public event EventHandler? Error;\n\n    public event EventHandler<T>? Next;\n\n    public void Dispose()\n    {\n        if (_subscription is not null)\n        {\n            _subscription.Dispose();\n            _subscription = null;\n        }\n    }\n\n    void IObserver<T>.OnCompleted() => Completed?.Invoke(this, EventArgs.Empty);\n\n    void IObserver<T>.OnError(Exception error) => Error?.Invoke(this, EventArgs.Empty);\n\n    void IObserver<T>.OnNext(T value) => Next?.Invoke(this, value);\n}\n"
  },
  {
    "path": "sdk/node/Libplanet.Node.Tests/TestUtility.cs",
    "content": "using Libplanet.Node.Extensions;\nusing Microsoft.Extensions.Configuration;\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.Logging;\nusing Microsoft.Extensions.Logging.Abstractions;\n\nnamespace Libplanet.Node.Tests;\n\ninternal static class TestUtility\n{\n    public static IServiceProvider CreateServiceProvider()\n    {\n        var services = new ServiceCollection();\n        var configuration = new ConfigurationBuilder().Build();\n        services.AddSingleton<ILoggerFactory, NullLoggerFactory>();\n        services.AddLogging();\n        services.AddLibplanetNode(configuration);\n        return services.BuildServiceProvider();\n    }\n\n    public static IServiceProvider CreateServiceProvider(IConfiguration configuration)\n    {\n        var services = new ServiceCollection();\n        services.AddSingleton<ILoggerFactory, NullLoggerFactory>();\n        services.AddLogging();\n        services.AddLibplanetNode(configuration);\n        return services.BuildServiceProvider();\n    }\n\n    public static IServiceProvider CreateServiceProvider(\n        IReadOnlyDictionary<string, string?> settings)\n    {\n        var configuration = CreateConfiguration(settings);\n        return CreateServiceProvider(configuration);\n    }\n\n    public static IConfiguration CreateConfiguration(IReadOnlyDictionary<string, string?> settings)\n    {\n        return new ConfigurationBuilder().AddInMemoryCollection(settings).Build();\n    }\n}\n"
  },
  {
    "path": "sdk/stylecop.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/DotNetAnalyzers/StyleCopAnalyzers/master/StyleCop.Analyzers/StyleCop.Analyzers/Settings/stylecop.schema.json\",\n  \"settings\": {\n    \"orderingRules\": {\n      \"usingDirectivesPlacement\": \"outsideNamespace\"\n    }\n  }\n}\n"
  },
  {
    "path": "src/Directory.Build.props",
    "content": "<Project>\n\n  <Import Project=\"$([MSBuild]::GetPathOfFileAbove('Directory.Build.props', '$(MSBuildThisFileDirectory)../'))\" />\n\n  <PropertyGroup>\n    <TargetFrameworks Condition=\"'$(_IsPacking)'=='true'\">$(TargetFrameworks);netstandard2.0;netstandard2.1;netcoreapp3.1</TargetFrameworks>\n    <LangVersion>9</LangVersion>\n    <IsPackable>true</IsPackable>\n    <IsTestProject>false</IsTestProject>\n    <Title>$(ProjectName)</Title>\n  </PropertyGroup>\n\n</Project>\n"
  },
  {
    "path": "src/Libplanet/AssemblyInfo.cs",
    "content": "using System.Runtime.CompilerServices;\n\n[assembly: InternalsVisibleTo(\"Libplanet.Benchmarks\")]\n[assembly: InternalsVisibleTo(\"Libplanet.Explorer\")]\n[assembly: InternalsVisibleTo(\"Libplanet.Explorer.Tests\")]\n[assembly: InternalsVisibleTo(\"Libplanet.Extensions.Cocona\")]\n[assembly: InternalsVisibleTo(\"Libplanet.Extensions.Cocona.Tests\")]\n[assembly: InternalsVisibleTo(\"Libplanet.Net\")]\n[assembly: InternalsVisibleTo(\"Libplanet.Net.Tests\")]\n[assembly: InternalsVisibleTo(\"Libplanet.RocksDBStore\")]\n[assembly: InternalsVisibleTo(\"Libplanet.RocksDBStore.Tests\")]\n[assembly: InternalsVisibleTo(\"Libplanet.Tests\")]\n"
  },
  {
    "path": "src/Libplanet/Blockchain/BlockChain.Evaluate.cs",
    "content": "#nullable disable\nusing System;\nusing System.Collections.Generic;\nusing System.Diagnostics;\nusing System.Diagnostics.Contracts;\nusing System.Linq;\nusing System.Security.Cryptography;\nusing Libplanet.Action;\nusing Libplanet.Action.Loader;\nusing Libplanet.Common;\nusing Libplanet.Crypto;\nusing Libplanet.Store;\nusing Libplanet.Types.Blocks;\n\nnamespace Libplanet.Blockchain\n{\n    public partial class BlockChain\n    {\n        /// <summary>\n        /// Determines the state root hash given <paramref name=\"block\"/> and\n        /// <paramref name=\"evaluations\"/>.\n        /// </summary>\n        /// <param name=\"block\">The <see cref=\"IPreEvaluationBlock\"/> to execute for\n        /// <paramref name=\"evaluations\"/>.</param>\n        /// <param name=\"evaluations\">The list of <see cref=\"IActionEvaluation\"/>s\n        /// from which to extract the states to commit.</param>\n        /// <exception cref=\"InvalidActionException\">Thrown when given <paramref name=\"block\"/>\n        /// contains an action that cannot be loaded with <see cref=\"IActionLoader\"/>.</exception>\n        /// <returns>The state root hash given <paramref name=\"block\"/> and\n        /// its <paramref name=\"evaluations\"/>.\n        /// </returns>\n        /// <remarks>\n        /// Since the state root hash can only be calculated by making a commit\n        /// to an <see cref=\"IStateStore\"/>, this always has a side-effect to\n        /// <see cref=\"StateStore\"/> regardless of whether the state root hash\n        /// obdatined through committing to <see cref=\"StateStore\"/>\n        /// matches the <paramref name=\"block\"/>'s <see cref=\"Block.StateRootHash\"/> or not.\n        /// </remarks>\n        /// <seealso cref=\"EvaluateBlockPrecededStateRootHash\"/>\n        /// <seealso cref=\"ValidateBlockPrecededStateRootHash\"/>\n        public HashDigest<SHA256> DetermineNextBlockStateRootHash(\n            Block block, out IReadOnlyList<ICommittedActionEvaluation> evaluations)\n        {\n            _rwlock.EnterWriteLock();\n            try\n            {\n                Stopwatch stopwatch = new Stopwatch();\n                stopwatch.Start();\n                evaluations = EvaluateBlock(block);\n\n                _logger.Debug(\n                    \"Took {DurationMs} ms to evaluate block #{BlockIndex} \" +\n                    \"hash {Hash} with {Count} action evaluations\",\n                    stopwatch.ElapsedMilliseconds,\n                    block.Index,\n                    block.Hash,\n                    evaluations.Count);\n\n                if (evaluations.Count > 0)\n                {\n                    return evaluations.Last().OutputState;\n                }\n                else\n                {\n                    return Store.GetStateRootHash(block.Hash) is { } stateRootHash\n                        ? stateRootHash\n                        : StateStore.GetStateRoot(null).Hash;\n                }\n            }\n            finally\n            {\n                _rwlock.ExitWriteLock();\n            }\n        }\n\n        /// <summary>\n        /// Evaluates the <see cref=\"IAction\"/>s in given <paramref name=\"block\"/>.\n        /// </summary>\n        /// <param name=\"block\">The <see cref=\"IPreEvaluationBlock\"/> to execute.</param>\n        /// <returns>An <see cref=\"IReadOnlyList{T}\"/> of <ses cref=\"ICommittedActionEvaluation\"/>s\n        /// for given <paramref name=\"block\"/>.</returns>\n        /// <exception cref=\"InvalidActionException\">Thrown when given <paramref name=\"block\"/>\n        /// contains an action that cannot be loaded with <see cref=\"IActionLoader\"/>.</exception>\n        /// <seealso cref=\"ValidateBlockPrecededStateRootHash\"/>\n        [Pure]\n        public IReadOnlyList<ICommittedActionEvaluation> EvaluateBlock(Block block) =>\n            block.ProtocolVersion >= BlockMetadata.SlothProtocolVersion\n                ? ActionEvaluator.Evaluate(\n                    block,\n                    Store.GetStateRootHash(block.Hash))\n                : ActionEvaluator.Evaluate(\n                    block,\n                    Store.GetStateRootHash(block.PreviousHash));\n\n        /// <summary>\n        /// Evaluates all actions in the <see cref=\"PreEvaluationBlock.Transactions\"/> and\n        /// optional <see cref=\"IAction\"/>s in\n        /// <see cref=\"Policies.IBlockPolicy.PolicyActionsRegistry\"/> and returns\n        /// a <see cref=\"Block\"/> instance combined with the <see cref=\"Block.StateRootHash\"/>\n        /// The returned <see cref=\"Block\"/> is signed by the given <paramref name=\"privateKey\"/>.\n        /// </summary>\n        /// <param name=\"preEvaluationBlock\">The <see cref=\"PreEvaluationBlock\"/> to evaluate\n        /// and sign.</param>\n        /// <param name=\"privateKey\">The private key to be used for signing the block.\n        /// This must match to the block's <see cref=\"PreEvaluationBlockHeader.Miner\"/> and\n        /// <see cref=\"PreEvaluationBlockHeader.PublicKey\"/>.</param>\n        /// <returns>The block combined with the resulting <see cref=\"Block.StateRootHash\"/>.\n        /// It is signed by the given <paramref name=\"privateKey\"/>.</returns>\n        /// <exception cref=\"ArgumentException\">Thrown when the block's\n        /// <see cref=\"PreEvaluationBlockHeader.ProtocolVersion\"/> is less than 2.</exception>\n        /// <exception cref=\"ArgumentException\">Thrown when the given <paramref name=\"privateKey\"/>\n        /// does not match to the block miner's <see cref=\"PublicKey\"/>.</exception>\n        // FIXME: Remove this method.\n        internal Block EvaluateAndSign(\n            PreEvaluationBlock preEvaluationBlock, PrivateKey privateKey)\n        {\n            if (preEvaluationBlock.ProtocolVersion < BlockMetadata.SlothProtocolVersion)\n            {\n                if (preEvaluationBlock.ProtocolVersion < BlockMetadata.SignatureProtocolVersion)\n                {\n                    throw new ArgumentException(\n                        $\"Given {nameof(preEvaluationBlock)} must have protocol version \" +\n                        $\"2 or greater: {preEvaluationBlock.ProtocolVersion}\");\n                }\n                else\n                {\n                    return preEvaluationBlock.Sign(\n                        privateKey,\n                        DetermineBlockPrecededStateRootHash(preEvaluationBlock, out _));\n                }\n            }\n            else\n            {\n                if (preEvaluationBlock.Index < 1)\n                {\n                    throw new ArgumentException(\n                        $\"Given {nameof(preEvaluationBlock)} must have block index \" +\n                        $\"higher than 0\");\n                }\n                else\n                {\n                    var prevBlock = _blocks[(BlockHash)preEvaluationBlock.PreviousHash];\n                    var stateRootHash = GetNextStateRootHash(prevBlock.Hash)\n                        ?? throw new NullReferenceException(\n                            $\"State root hash of block is not prepared\");\n                    return preEvaluationBlock.Sign(privateKey, stateRootHash);\n                }\n            }\n        }\n\n        /// <summary>\n        /// Determines the state root hash given <paramref name=\"block\"/> and\n        /// <paramref name=\"evaluations\"/>.\n        /// </summary>\n        /// <param name=\"block\">The <see cref=\"IPreEvaluationBlock\"/> to execute for\n        /// <paramref name=\"evaluations\"/>.</param>\n        /// <param name=\"evaluations\">The list of <see cref=\"IActionEvaluation\"/>s\n        /// from which to extract the states to commit.</param>\n        /// <exception cref=\"InvalidActionException\">Thrown when given <paramref name=\"block\"/>\n        /// contains an action that cannot be loaded with <see cref=\"IActionLoader\"/>.</exception>\n        /// <returns>The state root hash given <paramref name=\"block\"/> and\n        /// its <paramref name=\"evaluations\"/>.\n        /// </returns>\n        /// <remarks>\n        /// Since the state root hash can only be calculated by making a commit\n        /// to an <see cref=\"IStateStore\"/>, this always has a side-effect to\n        /// <see cref=\"StateStore\"/> regardless of whether the state root hash\n        /// obdatined through committing to <see cref=\"StateStore\"/>\n        /// matches the <paramref name=\"block\"/>'s <see cref=\"Block.StateRootHash\"/> or not.\n        /// </remarks>\n        /// <seealso cref=\"EvaluateBlockPrecededStateRootHash\"/>\n        /// <seealso cref=\"ValidateBlockPrecededStateRootHash\"/>\n        internal HashDigest<SHA256> DetermineBlockPrecededStateRootHash(\n            IPreEvaluationBlock block, out IReadOnlyList<ICommittedActionEvaluation> evaluations)\n        {\n            _rwlock.EnterWriteLock();\n            try\n            {\n                Stopwatch stopwatch = new Stopwatch();\n                stopwatch.Start();\n                evaluations = EvaluateBlockPrecededStateRootHash(block);\n\n                _logger.Debug(\n                    \"Took {DurationMs} ms to evaluate block #{BlockIndex} \" +\n                    \"pre-evaluation hash {PreEvaluationHash} with {Count} action evaluations\",\n                    stopwatch.ElapsedMilliseconds,\n                    block.Index,\n                    block.PreEvaluationHash,\n                    evaluations.Count);\n\n                if (evaluations.Count > 0)\n                {\n                    return evaluations.Last().OutputState;\n                }\n                else\n                {\n                    return Store.GetStateRootHash(block.PreviousHash) is { } prevStateRootHash\n                        ? prevStateRootHash\n                        : StateStore.GetStateRoot(null).Hash;\n                }\n            }\n            finally\n            {\n                _rwlock.ExitWriteLock();\n            }\n        }\n\n        /// <summary>\n        /// Evaluates the <see cref=\"IAction\"/>s in given <paramref name=\"preEvaluationBlock\"/>.\n        /// </summary>\n        /// <param name=\"preEvaluationBlock\">The <see cref=\"IPreEvaluationBlock\"/> to execute.\n        /// </param>\n        /// <returns>An <see cref=\"IReadOnlyList{T}\"/> of <ses cref=\"ICommittedActionEvaluation\"/>s\n        /// for given <paramref name=\"preEvaluationBlock\"/>.</returns>\n        /// <exception cref=\"InvalidActionException\">Thrown when given\n        /// <paramref name=\"preEvaluationBlock\"/>\n        /// contains an action that cannot be loaded with <see cref=\"IActionLoader\"/>.</exception>\n        /// <seealso cref=\"ValidateBlockPrecededStateRootHash\"/>\n        [Pure]\n        internal IReadOnlyList<ICommittedActionEvaluation> EvaluateBlockPrecededStateRootHash(\n            IPreEvaluationBlock preEvaluationBlock) =>\n            ActionEvaluator.Evaluate(\n                preEvaluationBlock,\n                Store.GetStateRootHash(preEvaluationBlock.PreviousHash));\n    }\n}\n"
  },
  {
    "path": "src/Libplanet/Blockchain/BlockChain.Evidence.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Collections.Immutable;\nusing System.Linq;\nusing Libplanet.Action.State;\nusing Libplanet.Types.Evidence;\n\nnamespace Libplanet.Blockchain\n{\n    public partial class BlockChain\n    {\n        /// <summary>\n        /// Retrieve pending <see cref=\"EvidenceBase\"/>s from the <see cref=\"Store\"/>.\n        /// </summary>\n        /// <returns><see cref=\"EvidenceBase\"/>s that are pending waiting to be committed.\n        /// Returned <see cref=\"EvidenceBase\"/>s are sorted by its <see cref=\"EvidenceBase.Id\"/>.\n        /// </returns>\n        public ImmutableArray<EvidenceBase> GetPendingEvidence()\n            => Store.IteratePendingEvidenceIds()\n                    .OrderBy(id => id)\n                    .Select(id => Store.GetPendingEvidence(id))\n                    .OfType<EvidenceBase>()\n                    .ToImmutableArray();\n\n        public EvidenceBase GetPendingEvidence(EvidenceId evidenceId)\n        {\n            if (Store.GetPendingEvidence(evidenceId) is EvidenceBase evidence)\n            {\n                return evidence;\n            }\n\n            throw new KeyNotFoundException($\"Pending evidence {evidenceId} is not found.\");\n        }\n\n        public EvidenceBase GetCommittedEvidence(EvidenceId evidenceId)\n        {\n            if (Store.GetCommittedEvidence(evidenceId) is EvidenceBase evidence)\n            {\n                return evidence;\n            }\n\n            throw new KeyNotFoundException($\"Committed evidence {evidenceId} is not found.\");\n        }\n\n        /// <summary>\n        /// Add given <paramref name=\"evidence\"/> to the <see cref=\"Store\"/> as pending.\n        /// </summary>\n        /// <param name=\"evidence\"><see cref=\"EvidenceBase\"/> to be added on the\n        /// pending pool.</param>\n        /// <exception cref=\"ArgumentException\">Thrown if <paramref name=\"evidence\"/>\n        /// is already on the <see cref=\"Store\"/>.</exception>\n        public void AddEvidence(EvidenceBase evidence)\n        {\n            if (IsEvidenceCommitted(evidence.Id))\n            {\n                throw new ArgumentException(\n                    message: $\"Evidence {evidence.Id} is already committed.\",\n                    paramName: nameof(evidence));\n            }\n\n            if (IsEvidencePending(evidence.Id))\n            {\n                throw new ArgumentException(\n                    message: $\"Evidence {evidence.Id} is already pending.\",\n                    paramName: nameof(evidence));\n            }\n\n            if (evidence.Height > Tip.Index)\n            {\n                throw new ArgumentException(\n                    message: $\"Evidence {evidence.Id} is from the future: \" +\n                             $\"{evidence.Height} > {Tip.Index + 1}\",\n                    paramName: nameof(evidence));\n            }\n\n            if (IsEvidenceExpired(evidence))\n            {\n                throw new ArgumentException($\"Evidence {evidence.Id} is expired\");\n            }\n\n            var stateRootHash = GetNextStateRootHash(evidence.Height);\n            var worldState = GetWorldState(stateRootHash);\n            var validatorSet = worldState.GetValidatorSet();\n            var evidenceContext = new EvidenceContext(validatorSet);\n            evidence.Verify(evidenceContext);\n            Store.PutPendingEvidence(evidence);\n        }\n\n        /// <summary>\n        /// Add given <paramref name=\"evidence\"/> to the <see cref=\"Store\"/> as committed.\n        /// If <paramref name=\"evidence\"/> is pending, it will be dropped from the pending pool.\n        /// </summary>\n        /// <param name=\"evidence\"><see cref=\"EvidenceBase\"/> to be added on the\n        /// committed pool.</param>\n        /// <exception cref=\"ArgumentException\">Thrown if <paramref name=\"evidence\"/>\n        /// is already on the <see cref=\"Store\"/> as committed.</exception>\n        public void CommitEvidence(EvidenceBase evidence)\n        {\n            if (IsEvidenceCommitted(evidence.Id))\n            {\n                throw new ArgumentException($\"Evidence {evidence.Id} is already committed.\");\n            }\n\n            if (IsEvidenceExpired(evidence))\n            {\n                throw new ArgumentException($\"Evidence {evidence.Id} is expired\");\n            }\n\n            if (IsEvidencePending(evidence.Id))\n            {\n                DeletePendingEvidence(evidence.Id);\n            }\n\n            Store.PutCommittedEvidence(evidence);\n        }\n\n        /// <summary>\n        /// Check if <see cref=\"EvidenceBase\"/> is on the <see cref=\"Store\"/>'s pending pool.\n        /// </summary>\n        /// <param name=\"evidenceId\"><see cref=\"EvidenceId\"/> of the <see cref=\"EvidenceBase\"/>\n        /// to be checked.</param>\n        /// <returns>\n        /// <see langword=\"true\"/> if the <see cref=\"Store\"/> contains <see cref=\"EvidenceBase\"/>\n        /// with the specified <paramref name=\"evidenceId\"/> on the pending pool;\n        /// otherwise, <see langword=\"false\"/>.\n        /// </returns>\n        public bool IsEvidencePending(EvidenceId evidenceId)\n            => Store.ContainsPendingEvidence(evidenceId);\n\n        /// <summary>\n        /// Check if <see cref=\"EvidenceBase\"/> is on the <see cref=\"Store\"/>'s committed pool.\n        /// </summary>\n        /// <param name=\"evidenceId\"><see cref=\"EvidenceId\"/> of the <see cref=\"EvidenceBase\"/>\n        /// to be checked.</param>\n        /// <returns>\n        /// <see langword=\"true\"/> if the <see cref=\"Store\"/> contains <see cref=\"EvidenceBase\"/>\n        /// with the specified <paramref name=\"evidenceId\"/> on the committed pool;\n        /// otherwise, <see langword=\"false\"/>.\n        /// </returns>\n        public bool IsEvidenceCommitted(EvidenceId evidenceId)\n            => Store.ContainsCommittedEvidence(evidenceId);\n\n        /// <summary>\n        /// Check if <see cref=\"EvidenceBase\"/> is expired.\n        /// </summary>\n        /// <param name=\"evidence\"><see cref=\"EvidenceBase\"/> to check its expiry.</param>\n        /// <returns>\n        /// <see langword=\"true\"/> if the <see cref=\"EvidenceBase\"/> is expired;\n        /// otherwise, <see langword=\"false\"/>.\n        /// </returns>\n        public bool IsEvidenceExpired(EvidenceBase evidence)\n            => evidence.Height + Policy.GetMaxEvidencePendingDuration(evidence.Height) < Tip.Index;\n\n        /// <summary>\n        /// Delete pending <see cref=\"EvidenceBase\"/> from the <see cref=\"Store\"/> with\n        /// its <see cref=\"EvidenceBase.Id\"/>.\n        /// </summary>\n        /// <param name=\"evidenceId\"><see cref=\"EvidenceId\"/> of the <see cref=\"EvidenceBase\"/>\n        /// to delete.</param>\n        /// <returns>\n        /// <see langword=\"true\"/> if <see cref=\"EvidenceBase\"/> is deleted from the pending pool.\n        /// </returns>\n        public bool DeletePendingEvidence(EvidenceId evidenceId)\n        {\n            if (IsEvidencePending(evidenceId))\n            {\n                Store.DeletePendingEvidence(evidenceId);\n                return true;\n            }\n\n            return false;\n        }\n    }\n}\n"
  },
  {
    "path": "src/Libplanet/Blockchain/BlockChain.ProposeBlock.cs",
    "content": "#nullable disable\nusing System;\nusing System.Collections.Generic;\nusing System.Collections.Immutable;\nusing System.Linq;\nusing System.Security.Cryptography;\nusing Bencodex.Types;\nusing Libplanet.Blockchain.Policies;\nusing Libplanet.Common;\nusing Libplanet.Crypto;\nusing Libplanet.Store.Trie;\nusing Libplanet.Types.Blocks;\nusing Libplanet.Types.Evidence;\nusing Libplanet.Types.Tx;\n\nnamespace Libplanet.Blockchain\n{\n    public partial class BlockChain\n    {\n        /// <summary>\n        /// <para>\n        /// Propose a genesis block for creating a <see cref=\"BlockChain\"/>.\n        /// </para>\n        /// <para>\n        /// Note that a genesis <see cref=\"Block\"/> produced may not be suitable as\n        /// a genesis for <see cref=\"BlockChain.Create\"/> if given\n        /// <paramref name=\"transactions\"/> is invalid.\n        /// </para>\n        /// <para>\n        /// Make sure that the nonces for <paramref name=\"transactions\"/> are correct and\n        /// each <see cref=\"Transaction.GenesisHash\"/> is set to <see langword=\"null\"/>.\n        /// </para>\n        /// </summary>\n        /// <param name=\"privateKey\">A private key to sign the transaction and the genesis block.\n        /// If it's null, it will use new private key as default.</param>\n        /// <param name=\"stateRootHash\">A state root hash of genesis block.  If it's null,\n        /// it will use empty state root hash.</param>\n        /// <param name=\"transactions\">A list of <see cref=\"Transaction\"/>s to include\n        /// in the genesis <see cref=\"Block\"/>.</param>\n        /// <param name=\"timestamp\">The timestamp of the genesis block.  If it's null, it will\n        /// use <see cref=\"DateTimeOffset.UtcNow\"/> as default.</param>\n        /// <returns>A genesis <see cref=\"Block\"/> proposed with given parameters.</returns>\n        /// <seealso cref=\"BlockChain.Create\"/>\n        // FIXME: This method should take a IBlockPolicy instead of params blockAction\n        // (Or at least there should be such an overload).\n        public static Block ProposeGenesisBlock(\n            PrivateKey privateKey = null,\n            HashDigest<SHA256>? stateRootHash = null,\n            ImmutableList<Transaction> transactions = null,\n            DateTimeOffset? timestamp = null)\n        {\n            privateKey ??= new PrivateKey();\n            transactions = transactions is { } txs\n                ? txs.OrderBy(tx => tx.Id).ToImmutableList()\n                : ImmutableList<Transaction>.Empty;\n\n            BlockContent content = new BlockContent(\n                new BlockMetadata(\n                    index: 0L,\n                    timestamp: timestamp ?? DateTimeOffset.UtcNow,\n                    publicKey: privateKey.PublicKey,\n                    previousHash: null,\n                    txHash: BlockContent.DeriveTxHash(transactions),\n                    lastCommit: null,\n                    evidenceHash: null),\n                transactions: transactions,\n                evidence: Array.Empty<EvidenceBase>());\n\n            PreEvaluationBlock preEval = content.Propose();\n            stateRootHash ??= MerkleTrie.EmptyRootHash;\n            return preEval.Sign(privateKey, (HashDigest<SHA256>)stateRootHash);\n        }\n\n        /// <summary>\n        /// <para>\n        /// Proposes a next <see cref=\"Block\"/> using staged <see cref=\"Transaction\"/>s.\n        /// </para>\n        /// <para>\n        /// By default, if successful, a policy adhering <see cref=\"Block\"/> is produced with\n        /// current timestamp that can be appended to the current chain.\n        /// </para>\n        /// </summary>\n        /// <param name=\"proposer\">The proposer's <see cref=\"PublicKey\"/> that proposes the block.\n        /// </param>\n        /// <param name=\"lastCommit\">The <see cref=\"BlockCommit\"/> evidence of the previous\n        /// <see cref=\"Block\"/>.</param>\n        /// <param name=\"evidence\">The pending <see cref=\"EvidenceBase\"/>s to be committed on the\n        /// <see cref=\"Block\"/>.</param>\n        /// <param name=\"txPriority\">An optional comparer for give certain transactions to\n        /// priority to belong to the block.  No certain priority by default.</param>\n        /// <returns>A <see cref=\"Block\"/> that is proposed.</returns>\n        /// <exception cref=\"OperationCanceledException\">Thrown when\n        /// <see cref=\"BlockChain.Tip\"/> is changed while proposing.</exception>\n        public Block ProposeBlock(\n            PrivateKey proposer,\n            BlockCommit lastCommit = null,\n            ImmutableArray<EvidenceBase>? evidence = null,\n            IComparer<Transaction> txPriority = null)\n        {\n            long index = Count;\n            _logger.Debug(\"Starting to propose block #{Index}...\", index);\n\n            ImmutableList<Transaction> transactions;\n            try\n            {\n                transactions = GatherTransactionsToPropose(index, txPriority);\n            }\n            catch (InvalidOperationException ioe)\n            {\n                throw new OperationCanceledException(\n                    $\"Failed to gather transactions to propose for block #{index}.\",\n                    ioe);\n            }\n\n            var block = ProposeBlock(\n                proposer,\n                transactions,\n                lastCommit,\n                evidence ?? ImmutableArray<EvidenceBase>.Empty);\n            _logger.Debug(\n                \"Proposed block #{Index} {Hash} with previous hash {PreviousHash}\",\n                block.Index,\n                block.Hash,\n                block.PreviousHash);\n\n            return block;\n        }\n\n        /// <summary>\n        /// <para>\n        /// Proposes a next <see cref=\"Block\"/> using a specified\n        /// list of <see cref=\"Transaction\"/>s.\n        /// </para>\n        /// <para>\n        /// Unlike <see cref=\"ProposeBlock(PrivateKey, BlockCommit, ImmutableArray{EvidenceBase}?,\n        /// IComparer{Transaction})\"/>,\n        /// this may result in a <see cref=\"Block\"/> that does not conform to the\n        /// <see cref=\"Policy\"/>.\n        /// </para>\n        /// </summary>\n        /// <param name=\"proposer\">The proposer's <see cref=\"PublicKey\"/> that proposes the block.\n        /// </param>\n        /// <param name=\"transactions\">The list of <see cref=\"Transaction\"/>s to include.</param>\n        /// <param name=\"lastCommit\">The <see cref=\"BlockCommit\"/> evidence of the previous\n        /// <see cref=\"Block\"/>.</param>\n        /// <param name=\"evidence\">The <see cref=\"EvidenceBase\"/>s to be committed.</param>\n        /// <returns>A <see cref=\"Block\"/> that is proposed.</returns>\n        internal Block ProposeBlock(\n            PrivateKey proposer,\n            ImmutableList<Transaction> transactions,\n            BlockCommit lastCommit,\n            ImmutableArray<EvidenceBase> evidence)\n        {\n            long index = Count;\n            BlockHash prevHash = Store.IndexBlockHash(Id, index - 1)\n                ?? throw new NullReferenceException($\"Chain {Id} is missing block #{index - 1}\");\n\n            HashDigest<SHA256> stateRootHash = GetNextStateRootHash(prevHash) ??\n                throw new InvalidOperationException(\n                    $\"Cannot propose a block as the next state root hash \" +\n                    $\"for block {prevHash} is missing.\");\n\n            // FIXME: Should use automated public constructor.\n            // Manual internal constructor is used purely for testing custom timestamps.\n            var orderedTransactions = transactions.OrderBy(tx => tx.Id).ToList();\n            var orderedEvidence = evidence.OrderBy(e => e.Id).ToList();\n            var blockContent = new BlockContent(\n                new BlockMetadata(\n                    protocolVersion: BlockMetadata.CurrentProtocolVersion,\n                    index: index,\n                    timestamp: DateTimeOffset.UtcNow,\n                    miner: proposer.Address,\n                    publicKey: proposer.PublicKey,\n                    previousHash: prevHash,\n                    txHash: BlockContent.DeriveTxHash(orderedTransactions),\n                    lastCommit: lastCommit,\n                    evidenceHash: BlockContent.DeriveEvidenceHash(orderedEvidence)),\n                transactions: orderedTransactions,\n                evidence: orderedEvidence);\n            var preEval = blockContent.Propose();\n            return ProposeBlock(proposer, preEval, stateRootHash);\n        }\n\n        internal Block ProposeBlock(\n            PrivateKey proposer,\n            PreEvaluationBlock preEvaluationBlock,\n            HashDigest<SHA256> stateRootHash) =>\n            preEvaluationBlock.Sign(proposer, stateRootHash);\n\n        /// <summary>\n        /// Gathers <see cref=\"Transaction\"/>s for proposing a <see cref=\"Block\"/> for\n        /// index <pararef name=\"index\"/>.  Gathered <see cref=\"Transaction\"/>s are\n        /// guaranteed to satisfied the following <see cref=\"Transaction\"/> related\n        /// policies:\n        /// <list type=\"bullet\">\n        ///     <item><description>\n        ///         <see cref=\"BlockPolicy.GetMaxTransactionsBytes\"/>\n        ///     </description></item>\n        ///     <item><description>\n        ///         <see cref=\"BlockPolicy.GetMaxTransactionsPerBlock\"/>\n        ///     </description></item>\n        ///     <item><description>\n        ///         <see cref=\"BlockPolicy.GetMaxTransactionsPerSignerPerBlock\"/>\n        ///     </description></item>\n        ///     <item><description>\n        ///         <see cref=\"BlockPolicy.GetMinTransactionsPerBlock\"/>\n        ///     </description></item>\n        /// </list>\n        /// </summary>\n        /// <param name=\"index\">The index of the <see cref=\"Block\"/> to propose.</param>\n        /// <param name=\"txPriority\">An optional comparer for give certain transactions to\n        /// priority to belong to the block.  No certain priority by default.</param>\n        /// <returns>An <see cref=\"ImmutableList\"/> of <see cref=\"Transaction\"/>s\n        /// to propose.</returns>\n        /// <exception cref=\"InvalidOperationException\">Thrown when not all policies\n        /// can be satisfied.</exception>\n        internal ImmutableList<Transaction> GatherTransactionsToPropose(\n            long index,\n            IComparer<Transaction> txPriority = null) =>\n            GatherTransactionsToPropose(\n                Policy.GetMaxTransactionsBytes(index),\n                Policy.GetMaxTransactionsPerBlock(index),\n                Policy.GetMaxTransactionsPerSignerPerBlock(index),\n                Policy.GetMinTransactionsPerBlock(index),\n                txPriority);\n\n        /// <summary>\n        /// Gathers <see cref=\"Transaction\"/>s for proposing a next block\n        /// from the current set of staged <see cref=\"Transaction\"/>s.\n        /// </summary>\n        /// <param name=\"maxTransactionsBytes\">The maximum number of bytes a block can have.</param>\n        /// <param name=\"maxTransactions\">The maximum number of <see cref=\"Transaction\"/>s\n        /// allowed.</param>\n        /// <param name=\"maxTransactionsPerSigner\">The maximum number of\n        /// <see cref=\"Transaction\"/>s with the same signer allowed.</param>\n        /// <param name=\"minTransactions\">The minimum number of <see cref=\"Transaction\"/>s\n        /// allowed.</param>\n        /// <param name=\"txPriority\">An optional comparer for give certain transactions to\n        /// priority to belong to the block.  No certain priority by default.</param>\n        /// <returns>An <see cref=\"ImmutableList\"/> of <see cref=\"Transaction\"/>s with its\n        /// count not exceeding <paramref name=\"maxTransactions\"/> and the number of\n        /// <see cref=\"Transaction\"/>s in the list for each signer not exceeding\n        /// <paramref name=\"maxTransactionsPerSigner\"/>.</returns>\n        /// <exception cref=\"InvalidOperationException\">Thrown when not all policies\n        /// can be satisfied.</exception>\n        internal ImmutableList<Transaction> GatherTransactionsToPropose(\n            long maxTransactionsBytes,\n            int maxTransactions,\n            int maxTransactionsPerSigner,\n            int minTransactions,\n            IComparer<Transaction> txPriority = null)\n        {\n            long index = Count;\n            ImmutableList<Transaction> stagedTransactions = ListStagedTransactions(txPriority);\n            _logger.Information(\n                \"Gathering transactions to propose for block #{Index} from {TxCount} \" +\n                \"staged transactions...\",\n                index,\n                stagedTransactions.Count);\n\n            var transactions = new List<Transaction>();\n\n            // FIXME: The tx collection timeout should be configurable.\n            DateTimeOffset timeout = DateTimeOffset.UtcNow + TimeSpan.FromSeconds(4);\n\n            List estimatedEncoding = BlockMarshaler.MarshalTransactions(\n                new List<Transaction>());\n            var storedNonces = new Dictionary<Address, long>();\n            var nextNonces = new Dictionary<Address, long>();\n            var toProposeCounts = new Dictionary<Address, int>();\n\n            foreach (\n                (Transaction tx, int i) in stagedTransactions.Select((val, idx) => (val, idx)))\n            {\n                _logger.Verbose(\n                    \"Validating tx {Iter}/{Total} {TxId} to include in block #{Index}...\",\n                    i,\n                    stagedTransactions.Count,\n                    tx.Id,\n                    index);\n\n                // We don't care about nonce ordering here because `.ListStagedTransactions()`\n                // returns already ordered transactions by its nonce.\n                if (!storedNonces.ContainsKey(tx.Signer))\n                {\n                    storedNonces[tx.Signer] = Store.GetTxNonce(Id, tx.Signer);\n                    nextNonces[tx.Signer] = storedNonces[tx.Signer];\n                    toProposeCounts[tx.Signer] = 0;\n                }\n\n                if (transactions.Count >= maxTransactions)\n                {\n                    _logger.Information(\n                        \"Ignoring tx {Iter}/{Total} {TxId} and the rest of the \" +\n                        \"staged transactions due to the maximum number of \" +\n                        \"transactions per block allowed has been reached: {Max}\",\n                        i,\n                        stagedTransactions.Count,\n                        tx.Id,\n                        maxTransactions);\n                    break;\n                }\n\n                if (storedNonces[tx.Signer] <= tx.Nonce && tx.Nonce == nextNonces[tx.Signer])\n                {\n                    if (Policy.ValidateNextBlockTx(this, tx) is { } tpve)\n                    {\n                        _logger.Debug(\n                            \"Ignoring tx {Iter}/{Total} {TxId} as it does not follow policy\",\n                            i,\n                            stagedTransactions.Count,\n                            tx.Id);\n                        StagePolicy.Ignore(this, tx.Id);\n                        continue;\n                    }\n\n                    List txAddedEncoding = estimatedEncoding.Add(\n                        BlockMarshaler.MarshalTransaction(tx));\n                    if (txAddedEncoding.EncodingLength > maxTransactionsBytes)\n                    {\n                        _logger.Debug(\n                            \"Ignoring tx {Iter}/{Total} {TxId} due to the maximum size allowed \" +\n                            \"for transactions in a block: {CurrentEstimate}/{MaximumBlockBytes}\",\n                            i,\n                            stagedTransactions.Count,\n                            tx.Id,\n                            txAddedEncoding.EncodingLength,\n                            maxTransactionsBytes);\n                        continue;\n                    }\n                    else if (toProposeCounts[tx.Signer] >= maxTransactionsPerSigner)\n                    {\n                        _logger.Debug(\n                            \"Ignoring tx {Iter}/{Total} {TxId} due to the maximum number \" +\n                            \"of transactions allowed per single signer per block \" +\n                            \"has been reached: {Max}\",\n                            i,\n                            stagedTransactions.Count,\n                            tx.Id,\n                            maxTransactionsPerSigner);\n                        continue;\n                    }\n\n                    try\n                    {\n                        foreach (IValue rawAction in tx.Actions)\n                        {\n                            _ = ActionEvaluator.ActionLoader.LoadAction(index, rawAction);\n                        }\n                    }\n                    catch (Exception e)\n                    {\n                        _logger.Error(\n                            e,\n                            \"Failed to load an action in tx; marking tx {TxId} as ignored...\",\n                            tx.Id);\n                        StagePolicy.Ignore(this, tx.Id);\n                        continue;\n                    }\n\n                    _logger.Verbose(\n                        \"Adding tx {Iter}/{Total} {TxId} to the list of transactions \" +\n                        \"to be proposed\",\n                        i,\n                        stagedTransactions.Count,\n                        tx.Id);\n                    transactions.Add(tx);\n                    nextNonces[tx.Signer] += 1;\n                    toProposeCounts[tx.Signer] += 1;\n                    estimatedEncoding = txAddedEncoding;\n                }\n                else if (tx.Nonce < storedNonces[tx.Signer])\n                {\n                    _logger.Debug(\n                        \"Ignoring tx {Iter}/{Total} {TxId} by {Signer} \" +\n                        \"as it has lower nonce {Actual} than expected nonce {Expected}\",\n                        i,\n                        stagedTransactions.Count,\n                        tx.Id,\n                        tx.Signer,\n                        tx.Nonce,\n                        nextNonces[tx.Signer]);\n                }\n                else\n                {\n                    _logger.Debug(\n                        \"Ignoring tx {Iter}/{Total} {TxId} by {Signer} \" +\n                        \"as it has higher nonce {Actual} than expected nonce {Expected}\",\n                        i,\n                        stagedTransactions.Count,\n                        tx.Id,\n                        tx.Signer,\n                        tx.Nonce,\n                        nextNonces[tx.Signer]);\n                }\n\n                if (timeout < DateTimeOffset.UtcNow)\n                {\n                    _logger.Debug(\n                        \"Reached the time limit to collect staged transactions; other staged \" +\n                        \"transactions will be proposed later\");\n                    break;\n                }\n            }\n\n            if (transactions.Count < minTransactions)\n            {\n                throw new InvalidOperationException(\n                    $\"Only gathered {transactions.Count} transactions where \" +\n                    $\"the minimal number of transactions to propose is {minTransactions}.\");\n            }\n\n            _logger.Information(\n                \"Gathered total of {TransactionsCount} transactions to propose for \" +\n                \"block #{Index} from {StagedTransactionsCount} staged transactions\",\n                transactions.Count,\n                index,\n                stagedTransactions.Count);\n            return transactions.ToImmutableList();\n        }\n    }\n}\n"
  },
  {
    "path": "src/Libplanet/Blockchain/BlockChain.States.cs",
    "content": "using System;\nusing System.Security.Cryptography;\nusing Libplanet.Action.State;\nusing Libplanet.Common;\nusing Libplanet.Types.Blocks;\n\nnamespace Libplanet.Blockchain\n{\n    public partial class BlockChain\n    {\n        /// <summary>\n        /// Gets the current world state in the <see cref=\"BlockChain\"/>.\n        /// </summary>\n        /// <returns>The current world state.</returns>\n        public IWorldState GetWorldState() => GetWorldState(Tip.Hash);\n\n        /// <inheritdoc cref=\"IBlockChainStates.GetWorldState(BlockHash)\" />\n        public IWorldState GetWorldState(BlockHash offset)\n            => _blockChainStates.GetWorldState(offset);\n\n        /// <inheritdoc cref=\"IBlockChainStates.GetWorldState(HashDigest{SHA256}?)\" />\n        public IWorldState GetWorldState(HashDigest<SHA256>? stateRootHash)\n            => _blockChainStates.GetWorldState(stateRootHash);\n\n        /// <summary>\n        /// Gets the next world state in the <see cref=\"BlockChain\"/>.\n        /// </summary>\n        /// <returns>The next world state.  If it does not exist, returns null.</returns>\n        public IWorldState? GetNextWorldState()\n        {\n            if (GetNextStateRootHash() is { } nsrh)\n            {\n                var trie = StateStore.GetStateRoot(nsrh);\n                return trie.Recorded\n                    ? new WorldBaseState(trie, StateStore)\n                    : throw new InvalidOperationException(\n                        $\"Could not find state root {nsrh} in {nameof(StateStore)} for \" +\n                        $\"the current tip.\");\n            }\n            else\n            {\n                return null;\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/Libplanet/Blockchain/BlockChain.Swap.cs",
    "content": "#nullable disable\nusing System;\nusing System.Collections.Generic;\nusing System.Diagnostics;\nusing System.Linq;\nusing Libplanet.Action;\nusing Libplanet.Blockchain.Renderers;\nusing Libplanet.Types.Blocks;\n\nnamespace Libplanet.Blockchain\n{\n    public partial class BlockChain\n    {\n        /// <summary>\n        /// Render actions of the given <paramref name=\"block\"/>.\n        /// </summary>\n        /// <param name=\"evaluations\"><see cref=\"IActionEvaluation\"/>s of the block.  If it is\n        /// <see langword=\"null\"/>, evaluate actions of the <paramref name=\"block\"/> again.</param>\n        /// <param name=\"block\"><see cref=\"Block\"/> to render actions.</param>\n        internal void RenderActions(\n            IReadOnlyList<ICommittedActionEvaluation> evaluations,\n            Block block)\n        {\n            if (evaluations is null)\n            {\n                throw new NullReferenceException(nameof(evaluations));\n            }\n\n            Stopwatch stopwatch = new Stopwatch();\n            stopwatch.Start();\n            _logger.Debug(\n                \"Rendering actions in block #{BlockIndex} {BlockHash}...\",\n                block.Index,\n                block.Hash);\n\n            long count = 0;\n            foreach (var evaluation in evaluations)\n            {\n                foreach (IActionRenderer renderer in ActionRenderers)\n                {\n                    if (evaluation.Exception is null)\n                    {\n                        renderer.RenderAction(\n                            evaluation.Action,\n                            evaluation.InputContext,\n                            evaluation.OutputState);\n                    }\n                    else\n                    {\n                        renderer.RenderActionError(\n                            evaluation.Action,\n                            evaluation.InputContext,\n                            evaluation.Exception);\n                    }\n\n                    count++;\n                }\n            }\n\n            _logger\n                .ForContext(\"Tag\", \"Metric\")\n                .ForContext(\"Subtag\", \"BlockRenderDuration\")\n                .Debug(\n                    \"Finished rendering {RenderCount} renders for actions in \" +\n                    \"block #{BlockIndex} {BlockHash} in {DurationMs} ms\",\n                    count,\n                    block.Index,\n                    block.Hash,\n                    stopwatch.ElapsedMilliseconds);\n        }\n\n        /// <summary>\n        /// Generates a list of <see cref=\"BlockHash\"/>es to traverse starting from\n        /// the tip of <paramref name=\"chain\"/> to reach <paramref name=\"targetHash\"/>.\n        /// </summary>\n        /// <param name=\"chain\">The <see cref=\"BlockChain\"/> to traverse.</param>\n        /// <param name=\"targetHash\">The target <see cref=\"BlockHash\"/> to reach.</param>\n        /// <returns>\n        /// An <see cref=\"IReadOnlyList{T}\"/> of <see cref=\"BlockHash\"/>es to traverse from\n        /// the tip of <paramref name=\"chain\"/> to reach <paramref name=\"targetHash\"/> excluding\n        /// <paramref name=\"targetHash\"/>.\n        /// </returns>\n        /// <remarks>\n        /// <para>\n        /// This is a reverse of <see cref=\"GetFastForwardPath\"/>.\n        /// </para>\n        /// <para>\n        /// As the genesis is always fixed, returned results never include the genesis.\n        /// </para>\n        /// </remarks>\n        private static IReadOnlyList<BlockHash> GetRewindPath(\n            BlockChain chain,\n            BlockHash targetHash)\n        {\n            if (!chain.ContainsBlock(targetHash))\n            {\n                throw new KeyNotFoundException(\n                    $\"Given chain {chain.Id} must contain target hash {targetHash}\");\n            }\n\n            long target = chain[targetHash].Index;\n            List<BlockHash> path = new List<BlockHash>();\n            for (long idx = chain.Tip.Index; idx > target; idx--)\n            {\n                path.Add(chain.Store.IndexBlockHash(chain.Id, idx) ??\n                    throw new NullReferenceException(\n                        $\"Chain {chain.Id} is missing block #{idx}\"));\n            }\n\n            return path;\n        }\n\n        /// <summary>\n        /// Generates a list of <see cref=\"BlockHash\"/>es to traverse starting from\n        /// <paramref name=\"originHash\"/> to reach the tip of <paramref name=\"chain\"/>.\n        /// </summary>\n        /// <param name=\"chain\">The <see cref=\"BlockChain\"/> to traverse.</param>\n        /// <param name=\"originHash\">The <see cref=\"BlockHash\"/> to start from.</param>\n        /// <returns>\n        /// An <see cref=\"IReadOnlyList{T}\"/> of <see cref=\"BlockHash\"/>es to traverse\n        /// to reach the tip of <paramref name=\"chain\"/> from <paramref name=\"originHash\"/>\n        /// excluding <paramref name=\"originHash\"/>.\n        /// </returns>\n        /// <remarks>\n        /// This is a reverse of <see cref=\"GetRewindPath\"/>.\n        /// </remarks>\n        private static IReadOnlyList<BlockHash> GetFastForwardPath(\n            BlockChain chain,\n            BlockHash originHash)\n        {\n            if (!chain.ContainsBlock(originHash))\n            {\n                throw new KeyNotFoundException(\n                    $\"Given chain {chain.Id} must contain origin hash {originHash}\");\n            }\n\n            return GetRewindPath(chain, originHash).Reverse().ToList();\n        }\n\n        /// <summary>\n        /// Finds the top most common <see cref=\"Block\"/> between chains <paramref name=\"c1\"/>\n        /// and <paramref name=\"c2\"/>.\n        /// </summary>\n        /// <param name=\"c1\">The first <see cref=\"BlockChain\"/> to compare.</param>\n        /// <param name=\"c2\">The second <see cref=\"BlockChain\"/> to compare.</param>\n        /// <returns>\n        /// The top most common <see cref=\"Block\"/> between chains <paramref name=\"c1\"/>\n        /// and <paramref name=\"c2\"/>. If there is no such <see cref=\"Block\"/>,\n        /// returns <see langword=\"null\"/> instead.\n        /// </returns>\n        private static Block FindTopCommon(BlockChain c1, BlockChain c2)\n        {\n            long shorterHeight = Math.Min(c1.Count, c2.Count) - 1;\n            Block b1 = c1[shorterHeight], b2 = c2[shorterHeight];\n\n            while (true)\n            {\n                if (b1.Equals(b2))\n                {\n                    return b1;\n                }\n\n                if (b1.PreviousHash is { } b1ph && b2.PreviousHash is { } b2ph)\n                {\n                    b1 = c1[b1ph];\n                    b2 = c2[b2ph];\n                }\n                else\n                {\n                    break;\n                }\n            }\n\n            return null;\n        }\n    }\n}\n"
  },
  {
    "path": "src/Libplanet/Blockchain/BlockChain.TxExecution.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing Libplanet.Action;\nusing Libplanet.Store.Trie;\nusing Libplanet.Types.Blocks;\nusing Libplanet.Types.Tx;\n\nnamespace Libplanet.Blockchain\n{\n    public partial class BlockChain\n    {\n        /// <summary>\n        /// Makes <see cref=\"TxExecution\"/> instances from the given <paramref name=\"evaluations\"/>.\n        /// </summary>\n        /// <param name=\"block\">The block that evaluated actions belong to.</param>\n        /// <param name=\"evaluations\">The result of evaluated actions.</param>\n        /// <returns>The corresponding <see cref=\"TxExecution\"/>s.</returns>\n        internal IEnumerable<TxExecution> MakeTxExecutions(\n            Block block,\n            IReadOnlyList<ICommittedActionEvaluation> evaluations\n        )\n        {\n            List<(TxId?, List<ICommittedActionEvaluation>)> groupedEvals =\n                new List<(TxId?, List<ICommittedActionEvaluation>)>();\n            foreach (ICommittedActionEvaluation eval in evaluations)\n            {\n                if (groupedEvals.Count == 0)\n                {\n                    groupedEvals.Add(\n                        (eval.InputContext.TxId, new List<ICommittedActionEvaluation>() { eval }));\n                }\n                else\n                {\n                    if (groupedEvals.Last().Item1.Equals(eval.InputContext.TxId))\n                    {\n                        groupedEvals.Last().Item2.Add(eval);\n                    }\n                    else\n                    {\n                        groupedEvals.Add(\n                            (\n                                eval.InputContext.TxId,\n                                new List<ICommittedActionEvaluation>() { eval }\n                            ));\n                    }\n                }\n            }\n\n            ITrie trie = GetWorldState(block.StateRootHash).Trie;\n\n            int count = 0;\n            foreach (var group in groupedEvals)\n            {\n                if (group.Item1 is { } txId)\n                {\n                    // If txId is not null, group has at least one element.\n                    List<Exception?> exceptions = group.Item2\n                        .Select(eval => eval.Exception)\n                        .Select(exception => exception is { } e && e.InnerException is { } i\n                            ? i\n                            : exception)\n                        .ToList();\n\n                    yield return new TxExecution(\n                        block.Hash,\n                        txId,\n                        exceptions.Any(exception => exception is { }),\n                        group.Item2.First().InputContext.PreviousState,\n                        group.Item2.Last().OutputState,\n                        exceptions.ToList());\n\n                    count++;\n                }\n            }\n\n            _logger.Verbose(\n                \"Prepared \" + nameof(TxExecution) +\n                \"s for {Txs} transactions within the block #{BlockIndex} {BlockHash}\",\n                count,\n                block.Index,\n                block.Hash);\n        }\n\n        internal void UpdateTxExecutions(IEnumerable<TxExecution> txExecutions)\n        {\n            int count = 0;\n            foreach (TxExecution txExecution in txExecutions)\n            {\n                Store.PutTxExecution(txExecution);\n                count++;\n\n                _logger.Verbose(\n                    \"Updated \" + nameof(TxExecution) + \" for tx {TxId} within block {BlockHash}\",\n                    txExecution.TxId,\n                    txExecution.BlockHash);\n            }\n\n            _logger.Verbose(\n                \"Updated \" + nameof(TxExecution) + \"s for {Txs} transactions\",\n                count\n            );\n        }\n    }\n}\n"
  },
  {
    "path": "src/Libplanet/Blockchain/BlockChain.Validate.cs",
    "content": "#nullable disable\nusing System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Numerics;\nusing System.Security.Cryptography;\nusing Bencodex.Types;\nusing Libplanet.Action;\nusing Libplanet.Action.State;\nusing Libplanet.Common;\nusing Libplanet.Crypto;\nusing Libplanet.Store;\nusing Libplanet.Types.Blocks;\nusing Libplanet.Types.Consensus;\nusing Libplanet.Types.Evidence;\nusing Libplanet.Types.Tx;\n\nnamespace Libplanet.Blockchain\n{\n    public partial class BlockChain\n    {\n        internal static Dictionary<Address, long> ValidateGenesisNonces(\n            Block block)\n        {\n            var nonceDeltas = new Dictionary<Address, long>();\n            foreach (Transaction tx in block.Transactions.OrderBy(tx => tx.Nonce))\n            {\n                nonceDeltas.TryGetValue(tx.Signer, out var nonceDelta);\n                long expectedNonce = nonceDelta;\n\n                if (!expectedNonce.Equals(tx.Nonce))\n                {\n                    throw new InvalidTxNonceException(\n                        $\"Transaction {tx.Id} has an invalid nonce {tx.Nonce} that is different \" +\n                        $\"from expected nonce {expectedNonce}.\",\n                        tx.Id,\n                        expectedNonce,\n                        tx.Nonce);\n                }\n\n                nonceDeltas[tx.Signer] = nonceDelta + 1;\n            }\n\n            return nonceDeltas;\n        }\n\n        /// <summary>\n        /// Checks if given <paramref name=\"block\"/> is a valid genesis <see cref=\"Block\"/>.\n        /// </summary>\n        /// <param name=\"block\">The target <see cref=\"Block\"/> to validate.</param>\n        /// <exception cref=\"ArgumentException\">If <paramref name=\"block\"/> has\n        /// <see cref=\"Block.Index\"/> value anything other than 0.</exception>\n        /// <exception cref=\"InvalidBlockException\">Thrown when given <paramref name=\"block\"/>\n        /// is invalid.</exception>\n        internal static void ValidateGenesis(Block block)\n        {\n            if (block.Index != 0)\n            {\n                throw new ArgumentException(\n                    $\"Given {nameof(block)} must have index 0 but has index {block.Index}\",\n                    nameof(block));\n            }\n\n            int actualProtocolVersion = block.ProtocolVersion;\n            const int currentProtocolVersion = Block.CurrentProtocolVersion;\n            if (block.ProtocolVersion > Block.CurrentProtocolVersion)\n            {\n                throw new InvalidBlockProtocolVersionException(\n                    $\"The protocol version ({actualProtocolVersion}) of the block \" +\n                    $\"#{block.Index} {block.Hash} is not supported by this node.\" +\n                    $\"The highest supported protocol version is {currentProtocolVersion}.\",\n                    actualProtocolVersion);\n            }\n\n            if (block.PreviousHash is { } previousHash)\n            {\n                throw new InvalidBlockPreviousHashException(\n                    \"A genesis block should not have previous hash, \" +\n                    $\"but its value is {previousHash}.\");\n            }\n\n            if (block.LastCommit is { } lastCommit)\n            {\n                throw new InvalidBlockLastCommitException(\n                    \"A genesis block should not have lastCommit, \" +\n                    $\"but its value is {lastCommit}.\");\n            }\n        }\n\n        internal void ValidateBlockCommit(\n            Block block,\n            BlockCommit blockCommit)\n        {\n            if (block.ProtocolVersion < BlockMetadata.PBFTProtocolVersion)\n            {\n                if (blockCommit is { })\n                {\n                    throw new InvalidBlockCommitException(\n                        \"PoW Block doesn't have blockCommit.\");\n                }\n                else\n                {\n                    // To allow the PoW block to be appended, we skips the validation.\n                    return;\n                }\n            }\n\n            if (block.Index == 0)\n            {\n                if (blockCommit is { })\n                {\n                    throw new InvalidBlockCommitException(\n                        \"Genesis block does not have blockCommit.\");\n                }\n                else\n                {\n                    return;\n                }\n            }\n\n            if (block.Index != 0 && blockCommit == null)\n            {\n                throw new InvalidBlockCommitException(\n                    $\"Block #{block.Hash} BlockCommit is required except for the genesis block.\");\n            }\n\n            if (block.Index != blockCommit.Height)\n            {\n                throw new InvalidBlockCommitException(\n                    \"BlockCommit has height value that is not same with block index. \" +\n                    $\"Block index is {block.Index}, however, BlockCommit height is \" +\n                    $\"{blockCommit.Height}.\");\n            }\n\n            if (!block.Hash.Equals(blockCommit.BlockHash))\n            {\n                throw new InvalidBlockCommitException(\n                    $\"BlockCommit has different block. Block hash is {block.Hash}, \" +\n                    $\"however, BlockCommit block hash is {blockCommit.BlockHash}.\");\n            }\n\n            // FIXME: When the dynamic validator set is possible, the functionality of this\n            // condition should be checked once more.\n            var validators = block.ProtocolVersion < BlockMetadata.SlothProtocolVersion\n                ? GetWorldState(block.PreviousHash ?? Genesis.Hash).GetValidatorSet()\n                : GetWorldState(block.StateRootHash).GetValidatorSet();\n\n            if (block.ProtocolVersion < BlockMetadata.EvidenceProtocolVersion)\n            {\n                validators.ValidateLegacyBlockCommitValidators(blockCommit);\n            }\n            else\n            {\n                validators.ValidateBlockCommitValidators(blockCommit);\n            }\n\n            BigInteger commitPower = blockCommit.Votes.Aggregate(\n                BigInteger.Zero,\n                (power, vote) => power + (vote.Flag == VoteFlag.PreCommit\n                    ? validators.GetValidator(vote.ValidatorPublicKey).Power\n                    : BigInteger.Zero));\n            if (validators.TwoThirdsPower >= commitPower)\n            {\n                throw new InvalidBlockCommitException(\n                    $\"BlockCommit of BlockHash {blockCommit.BlockHash} \" +\n                    $\"has insufficient vote power {commitPower} compared to 2/3 of \" +\n                    $\"the total power {validators.TotalPower}\");\n            }\n        }\n\n        internal Dictionary<Address, long> ValidateBlockNonces(\n            Dictionary<Address, long> storedNonces,\n            Block block)\n        {\n            var nonceDeltas = new Dictionary<Address, long>();\n            foreach (Transaction tx in block.Transactions.OrderBy(tx => tx.Nonce))\n            {\n                nonceDeltas.TryGetValue(tx.Signer, out var nonceDelta);\n                storedNonces.TryGetValue(tx.Signer, out var storedNonce);\n\n                long expectedNonce = nonceDelta + storedNonce;\n\n                if (!expectedNonce.Equals(tx.Nonce))\n                {\n                    throw new InvalidTxNonceException(\n                        $\"Transaction {tx.Id} has an invalid nonce {tx.Nonce} that is different \" +\n                        $\"from expected nonce {expectedNonce}.\",\n                        tx.Id,\n                        expectedNonce,\n                        tx.Nonce);\n                }\n\n                nonceDeltas[tx.Signer] = nonceDelta + 1;\n            }\n\n            return nonceDeltas;\n        }\n\n        internal void ValidateBlockLoadActions(Block block)\n        {\n            foreach (Transaction tx in block.Transactions)\n            {\n                foreach (IValue rawAction in tx.Actions)\n                {\n                    _ = ActionEvaluator.ActionLoader.LoadAction(block.Index, rawAction);\n                }\n            }\n        }\n\n        internal void ValidateBlock(Block block)\n        {\n            if (block.Index <= 0)\n            {\n                throw new ArgumentException(\n                    $\"Given {nameof(block)} must have a positive index but has index {block.Index}\",\n                    nameof(block));\n            }\n\n            long index = Count;\n            if (block.Index != index)\n            {\n                throw new InvalidBlockIndexException(\n                    $\"The expected index of block {block.Hash} is #{index}, \" +\n                    $\"but its index is #{block.Index}.\");\n            }\n\n            int actualProtocolVersion = block.ProtocolVersion;\n            const int currentProtocolVersion = Block.CurrentProtocolVersion;\n\n            // FIXME: Crude way of checking protocol version for non-genesis block.\n            // Ideally, whether this is called during instantiation should be made more explicit.\n            if (actualProtocolVersion > currentProtocolVersion)\n            {\n                string message =\n                    $\"The protocol version ({actualProtocolVersion}) of the block \" +\n                    $\"#{block.Index} {block.Hash} is not supported by this node.\" +\n                    $\"The highest supported protocol version is {currentProtocolVersion}.\";\n                throw new InvalidBlockProtocolVersionException(\n                    message,\n                    actualProtocolVersion\n                );\n            }\n            else if (actualProtocolVersion < Tip.ProtocolVersion)\n            {\n                string message =\n                    \"The protocol version is disallowed to be downgraded from the topmost block \" +\n                    $\"in the chain ({actualProtocolVersion} < {Tip.ProtocolVersion}).\";\n                throw new InvalidBlockProtocolVersionException(message, actualProtocolVersion);\n            }\n\n            Block lastBlock = this[index - 1];\n            BlockHash? prevHash = lastBlock?.Hash;\n            DateTimeOffset? prevTimestamp = lastBlock?.Timestamp;\n\n            if (!block.PreviousHash.Equals(prevHash))\n            {\n                throw new InvalidBlockPreviousHashException(\n                    $\"The block #{index} {block.Hash} is not continuous from the \" +\n                    $\"block #{index - 1}; while previous block's hash is \" +\n                    $\"{prevHash}, the block #{index} {block.Hash}'s pointer to \" +\n                    \"the previous hash refers to \" +\n                    (block.PreviousHash?.ToString() ?? \"nothing\") + \".\");\n            }\n\n            if (block.Timestamp < prevTimestamp)\n            {\n                throw new InvalidBlockTimestampException(\n                    $\"The block #{index} {block.Hash}'s timestamp \" +\n                    $\"({block.Timestamp}) is earlier than \" +\n                    $\"the block #{index - 1}'s ({prevTimestamp}).\");\n            }\n\n            if (block.Index <= 1)\n            {\n                if (block.LastCommit is { })\n                {\n                    throw new InvalidBlockLastCommitException(\n                        \"The genesis block and the next block should not have lastCommit.\");\n                }\n            }\n            else\n            {\n                // Any block after a PoW block should not have a last commit regardless of\n                // the protocol version.  As we have the target block index > 2, if it is a PoW\n                // block, the previous block would be a PoW block and is covered by this case.\n                if (lastBlock?.ProtocolVersion < BlockMetadata.PBFTProtocolVersion)\n                {\n                    if (block.LastCommit is { })\n                    {\n                        throw new InvalidBlockLastCommitException(\n                            \"A block after a PoW block should not have lastCommit.\");\n                    }\n                }\n                else\n                {\n                    if (block.LastCommit is null)\n                    {\n                        throw new InvalidBlockLastCommitException(\n                            \"A PBFT block that does not have zero or one index or \" +\n                            \"is not a block after a PoW block should have lastCommit.\");\n                    }\n                }\n\n                try\n                {\n                    ValidateBlockCommit(this[block.PreviousHash ?? Genesis.Hash], block.LastCommit);\n                }\n                catch (InvalidBlockCommitException ibce)\n                {\n                    throw new InvalidBlockLastCommitException(ibce.Message);\n                }\n            }\n\n            foreach (var ev in block.Evidence)\n            {\n                var stateRootHash = GetNextStateRootHash(ev.Height);\n                var worldState = GetWorldState(stateRootHash);\n                var validatorSet = worldState.GetValidatorSet();\n                var evidenceContext = new EvidenceContext(validatorSet);\n                ev.Verify(evidenceContext);\n            }\n        }\n\n        /// <summary>\n        /// Validates a result obtained from <see cref=\"EvaluateBlock\"/> by\n        /// comparing the state root hash from <see cref=\"GetNextStateRootHash(BlockHash)\"/>\n        /// which stores state root hash from <see cref=\"DetermineNextBlockStateRootHash\"/>,\n        /// to the one in <paramref name=\"block\"/>.\n        /// </summary>\n        /// <param name=\"block\">The <see cref=\"Block\"/> to validate against.</param>\n        /// <exception cref=\"InvalidOperationException\">If this method is called\n        /// when the result of <see cref=\"GetNextStateRootHash(BlockHash)\"/>\n        /// is <see langword=\"null\"/>.  This can happen if <paramref name=\"block\"/>\n        /// is an index higher than the tip but its result is not ready yet.</exception>\n        /// <exception cref=\"InvalidBlockStateRootHashException\">If the state root hash\n        /// calculated by committing to the <see cref=\"IStateStore\"/> does not match\n        /// the <paramref name=\"block\"/>'s <see cref=\"Block.StateRootHash\"/>.</exception>\n        /// <seealso cref=\"EvaluateBlock\"/>\n        /// <seealso cref=\"DetermineNextBlockStateRootHash\"/>\n        internal void ValidateBlockStateRootHash(Block block)\n        {\n            // NOTE: Since previous hash validation is on block validation,\n            // assume block is genesis if previous hash is null.\n            if (!(block.PreviousHash is BlockHash previousHash))\n            {\n                return;\n            }\n\n            HashDigest<SHA256> stateRootHash = GetNextStateRootHash(previousHash) ??\n                throw new InvalidOperationException(\n                    $\"Cannot validate a block' state root hash as the next \" +\n                    $\"state root hash for block {previousHash} is missing.\");\n\n            if (!stateRootHash.Equals(block.StateRootHash))\n            {\n                var message = $\"Block #{block.Index} {block.Hash}'s state root hash \" +\n                    $\"is {block.StateRootHash}, but the execution result is {stateRootHash}.\";\n                throw new InvalidBlockStateRootHashException(\n                    message,\n                    block.StateRootHash,\n                    stateRootHash);\n            }\n        }\n\n        /// <summary>\n        /// Validates a result obtained from <see cref=\"EvaluateBlockPrecededStateRootHash\"/> by\n        /// comparing the state root hash calculated using\n        /// <see cref=\"DetermineBlockPrecededStateRootHash\"/>\n        /// to the one in <paramref name=\"block\"/>.\n        /// </summary>\n        /// <param name=\"block\">The <see cref=\"Block\"/> to validate against.</param>\n        /// <param name=\"evaluations\">The list of <see cref=\"IActionEvaluation\"/>s\n        /// from which to extract the states to commit.</param>\n        /// <exception cref=\"InvalidBlockStateRootHashException\">If the state root hash\n        /// calculated by committing to the <see cref=\"IStateStore\"/> does not match\n        /// the <paramref name=\"block\"/>'s <see cref=\"Block.StateRootHash\"/>.</exception>\n        /// <remarks>\n        /// Since the state root hash for can only be calculated from making a commit\n        /// to an <see cref=\"IStateStore\"/>, this always has a side-effect to the\n        /// <see cref=\"IStateStore\"/> regardless of whether the state root hash\n        /// obdatined through committing to the <see cref=\"IStateStore\"/>\n        /// matches the <paramref name=\"block\"/>'s <see cref=\"Block.StateRootHash\"/> or not.\n        /// </remarks>\n        /// <seealso cref=\"EvaluateBlockPrecededStateRootHash\"/>\n        /// <seealso cref=\"DetermineBlockPrecededStateRootHash\"/>\n        internal void ValidateBlockPrecededStateRootHash(\n            Block block, out IReadOnlyList<ICommittedActionEvaluation> evaluations)\n        {\n            var rootHash = DetermineBlockPrecededStateRootHash(block, out evaluations);\n            if (!rootHash.Equals(block.StateRootHash))\n            {\n                var message = $\"Block #{block.Index} {block.Hash}'s state root hash \" +\n                    $\"is {block.StateRootHash}, but the execution result is {rootHash}.\";\n                throw new InvalidBlockStateRootHashException(\n                    message,\n                    block.StateRootHash,\n                    rootHash);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/Libplanet/Blockchain/BlockChain.cs",
    "content": "#nullable disable\nusing System;\nusing System.Collections.Generic;\nusing System.Collections.Immutable;\nusing System.Diagnostics;\nusing System.Diagnostics.CodeAnalysis;\nusing System.Globalization;\nusing System.Linq;\nusing System.Security.Cryptography;\nusing System.Threading;\nusing Libplanet.Action;\nusing Libplanet.Action.Loader;\nusing Libplanet.Action.State;\nusing Libplanet.Blockchain.Policies;\nusing Libplanet.Blockchain.Renderers;\nusing Libplanet.Common;\nusing Libplanet.Crypto;\nusing Libplanet.Store;\nusing Libplanet.Types.Assets;\nusing Libplanet.Types.Blocks;\nusing Libplanet.Types.Consensus;\nusing Libplanet.Types.Tx;\nusing Serilog;\n\nnamespace Libplanet.Blockchain\n{\n#pragma warning disable MEN002\n    /// <summary>\n    /// <para>\n    /// A class have <see cref=\"Block\"/>s, <see cref=\"Transaction\"/>s, and the chain\n    /// information.\n    /// </para>\n    /// <para>\n    /// In order to watch its state changes, implement <see cref=\"IRenderer\"/> interface\n    /// and pass it to the\n    /// <see cref=\"BlockChain(IBlockPolicy, IStagePolicy, IStore, IStateStore, Block, IBlockChainStates, IActionEvaluator, IEnumerable{IRenderer})\"/>\n    /// constructor.\n    /// </para>\n    /// </summary>\n    /// <remarks>This object is guaranteed that it has at least one block, since it takes a genesis\n    /// block when it's instantiated.</remarks>\n#pragma warning restore MEN002\n    public partial class BlockChain : IBlockChainStates\n    {\n        // FIXME: The _rwlock field should be private.\n        [SuppressMessage(\n            \"StyleCop.CSharp.OrderingRules\",\n            \"SA1401:FieldsMustBePrivate\",\n            Justification = \"Temporary visibility.\")]\n        internal readonly ReaderWriterLockSlim _rwlock;\n        private readonly object _txLock;\n        private readonly ILogger _logger;\n        private readonly IBlockChainStates _blockChainStates;\n\n        /// <summary>\n        /// All <see cref=\"Block\"/>s in the <see cref=\"BlockChain\"/>\n        /// storage, including orphan <see cref=\"Block\"/>s.\n        /// Keys are <see cref=\"Block.Hash\"/>es and values are\n        /// their corresponding <see cref=\"Block\"/>s.\n        /// </summary>\n        private BlockSet _blocks;\n\n        /// <summary>\n        /// Cached genesis block.\n        /// </summary>\n        private Block _genesis;\n\n        private HashDigest<SHA256>? _nextStateRootHash;\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"BlockChain\"/> class by loading\n        /// the canonical chain from given <paramref name=\"store\"/>.\n        /// </summary>\n        /// <param name=\"policy\"><see cref=\"IBlockPolicy\"/> to use in the\n        /// <see cref=\"BlockChain\"/>.</param>\n        /// <param name=\"stagePolicy\">The staging policy to follow.</param>\n        /// <param name=\"store\"><see cref=\"IStore\"/> to store <see cref=\"Block\"/>s,\n        /// <see cref=\"Transaction\"/>s, and <see cref=\"BlockChain\"/> information.</param>\n        /// <param name=\"genesisBlock\">The genesis <see cref=\"Block\"/> of\n        /// the <see cref=\"BlockChain\"/>, which is a part of the consensus.\n        /// If the given <paramref name=\"store\"/> already contains the genesis block\n        /// it checks if the existing genesis block and this argument is the same.\n        /// If the <paramref name=\"store\"/> has no genesis block yet this argument will\n        /// be used for that.</param>\n        /// <param name=\"blockChainStates\">The <see cref=\"IBlockChainStates\"/> implementation for\n        /// state lookup.</param>\n        /// <param name=\"actionEvaluator\">The <see cref=\"ActionEvaluator\" /> implementation to\n        /// calculate next states when append new blocks.</param>\n        /// <param name=\"renderers\">Listens state changes on the created chain.  Listens nothing\n        /// by default or if it is <see langword=\"null\"/>.  Note that action renderers receive\n        /// events made by unsuccessful transactions as well.</param>\n        /// <param name=\"stateStore\"><see cref=\"IStateStore\"/> to store states.</param>\n        /// <exception cref=\"ArgumentException\">Thrown when <paramref name=\"store\"/> does not\n        /// have canonical chain id set, i.e. <see cref=\"IStore.GetCanonicalChainId()\"/> is\n        /// <see langword=\"null\"/>.</exception>\n        /// <exception cref=\"ArgumentNullException\">Thrown when either of <paramref name=\"store\"/>\n        /// or <paramref name=\"stateStore\"/> is <see langword=\"null\"/>.</exception>\n        /// <exception cref=\"InvalidGenesisBlockException\">Thrown when the <paramref name=\"store\"/>\n        /// has a genesis block and it does not match to what the network expects\n        /// (i.e., <paramref name=\"genesisBlock\"/>).</exception>\n        public BlockChain(\n            IBlockPolicy policy,\n            IStagePolicy stagePolicy,\n            IStore store,\n            IStateStore stateStore,\n            Block genesisBlock,\n            IBlockChainStates blockChainStates,\n            IActionEvaluator actionEvaluator,\n            IEnumerable<IRenderer> renderers = null)\n#pragma warning disable SA1118  // The parameter spans multiple lines\n            : this(\n                policy,\n                stagePolicy,\n                store,\n                stateStore,\n                store.GetCanonicalChainId() ??\n                    throw new ArgumentException(\n                        $\"Given {nameof(store)} does not have canonical chain id set.\",\n                        nameof(store)),\n                genesisBlock,\n                blockChainStates,\n                actionEvaluator,\n                renderers)\n        {\n        }\n\n        private BlockChain(\n            IBlockPolicy policy,\n            IStagePolicy stagePolicy,\n            IStore store,\n            IStateStore stateStore,\n            Guid id,\n            Block genesisBlock,\n            IBlockChainStates blockChainStates,\n            IActionEvaluator actionEvaluator,\n            IEnumerable<IRenderer> renderers)\n        {\n            if (store is null)\n            {\n                throw new ArgumentNullException(nameof(store));\n            }\n            else if (store.CountIndex(id) == 0)\n            {\n                throw new ArgumentException(\n                    $\"Given store does not contain chain id {id}.\", nameof(store));\n            }\n            else if (stateStore is null)\n            {\n                throw new ArgumentNullException(nameof(stateStore));\n            }\n\n            Id = id;\n            Policy = policy;\n            StagePolicy = stagePolicy;\n            Store = store;\n            StateStore = stateStore;\n\n            _blockChainStates = blockChainStates;\n\n            _blocks = new BlockSet(store);\n            Renderers = renderers is IEnumerable<IRenderer> r\n                ? r.ToImmutableArray()\n                : ImmutableArray<IRenderer>.Empty;\n            ActionRenderers = Renderers.OfType<IActionRenderer>().ToImmutableArray();\n            _rwlock = new ReaderWriterLockSlim(LockRecursionPolicy.SupportsRecursion);\n            _txLock = new object();\n\n            _logger = Log\n                .ForContext<BlockChain>()\n                .ForContext(\"Source\", nameof(BlockChain))\n                .ForContext(\"ChainId\", Id);\n            ActionEvaluator = actionEvaluator;\n\n            if (!Genesis.Equals(genesisBlock))\n            {\n                string msg =\n                    $\"The genesis block that the given {nameof(IStore)} contains does not match \" +\n                    \"to the genesis block that the network expects.  You might pass the wrong \" +\n                    \"store which is incompatible with this chain.  Or your network might \" +\n                    \"restarted the chain with a new genesis block so that it is incompatible \" +\n                    \"with your existing chain in the local store.\";\n                throw new InvalidGenesisBlockException(\n                    message: msg,\n                    networkExpected: genesisBlock.Hash,\n                    stored: Genesis.Hash\n                );\n            }\n\n            if (Tip.ProtocolVersion < BlockMetadata.SlothProtocolVersion)\n            {\n                _nextStateRootHash = Tip.StateRootHash;\n            }\n            else\n            {\n                _nextStateRootHash =\n                    DetermineNextBlockStateRootHash(Tip, out var actionEvaluations);\n                IEnumerable<TxExecution> txExecutions = MakeTxExecutions(Tip, actionEvaluations);\n                UpdateTxExecutions(txExecutions);\n            }\n        }\n\n        ~BlockChain()\n        {\n            _rwlock?.Dispose();\n        }\n\n        /// <summary>\n        /// An event that is invoked when <see cref=\"Tip\"/> is changed.\n        /// </summary>\n        /// <remarks>\n        /// This is only invoked when <see cref=\"Tip\"/> is changed, <em>not</em> when\n        /// a <see cref=\"BlockChain\"/> is instantiated.  Furthermore, it is guaranteed\n        /// that the new tip event argument's <see cref=\"Block.Index\"/> will always\n        /// be <em>increasing</em> for each invocation.\n        /// </remarks>\n        // FIXME: This should be completely replaced by IRenderer.RenderBlock() or any other\n        // alternatives.\n        internal event EventHandler<(Block OldTip, Block NewTip)> TipChanged;\n\n#pragma warning disable MEN002\n        /// <summary>\n        /// The list of registered renderers listening the state changes.\n        /// </summary>\n        /// <remarks>\n        /// Since this value is immutable, renderers cannot be registered after once a <see\n        /// cref=\"BlockChain\"/> object is instantiated; use <c>renderers</c> option of\n        /// <see cref=\"BlockChain(IBlockPolicy, IStagePolicy, IStore, IStateStore, Block, IBlockChainStates, IActionEvaluator, IEnumerable{IRenderer})\"/>\n        /// constructor instead.\n        /// </remarks>\n#pragma warning restore MEN002\n        public IImmutableList<IRenderer> Renderers { get; }\n\n        /// <summary>\n        /// A filtered list, from <see cref=\"Renderers\"/>, which contains only <see\n        /// cref=\"IActionRenderer\"/> instances.\n        /// </summary>\n        public IImmutableList<IActionRenderer> ActionRenderers { get; }\n\n        /// <summary>\n        /// The block and blockchain policy.\n        /// </summary>\n        public IBlockPolicy Policy { get; }\n\n        /// <summary>\n        /// The staging policy.\n        /// </summary>\n        public IStagePolicy StagePolicy { get; set; }\n\n        /// <summary>\n        /// The topmost <see cref=\"Block\"/> of the current blockchain.\n        /// </summary>\n        public Block Tip => this[-1];\n\n        /// <summary>\n        /// The first <see cref=\"Block\"/> in the <see cref=\"BlockChain\"/>.\n        /// </summary>\n        public Block Genesis => _genesis ??= this[0];\n\n        public Guid Id { get; private set; }\n\n        /// <summary>\n        /// All <see cref=\"Block.Hash\"/>es in the current index.  The genesis block's hash goes\n        /// first, and the tip goes last.\n        /// Returns a <see cref=\"long\"/> integer that represents the number of elements in the\n        /// <see cref=\"BlockChain\"/>.\n        /// </summary>\n        public IEnumerable<BlockHash> BlockHashes => IterateBlockHashes();\n\n        /// <summary>\n        /// Returns a <see cref=\"long\"/> that represents the number of <see cref=\"Block\"/>s in a\n        /// <see cref=\"BlockChain\"/>.  This is guaranteed to be greater than or equal to 1,\n        /// as <see cref=\"BlockChain\"/> always contains at least\n        /// its genesis <see cref=\"Block\"/>.\n        /// </summary>\n        /// <returns>The number of <see cref=\"Block\"/>s in the <see cref=\"BlockChain\"/>.\n        /// </returns>\n        public long Count => Store.CountIndex(Id);\n\n        internal IStore Store { get; }\n\n        internal IStateStore StateStore { get; }\n\n        internal IActionEvaluator ActionEvaluator { get; }\n\n        /// <summary>\n        /// Whether the instance is canonical or not.\n        /// </summary>\n        internal bool IsCanonical => Store.GetCanonicalChainId() is Guid guid && Id == guid;\n\n        /// <summary>\n        /// Gets the block corresponding to the <paramref name=\"index\"/>.\n        /// </summary>\n        /// <param name=\"index\">A number of index of <see cref=\"Block\"/>.</param>\n        /// <exception cref=\"ArgumentOutOfRangeException\">Thrown when the given index of\n        /// <see cref=\"Block\"/> does not exist.</exception>\n        public Block this[int index] => this[(long)index];\n\n        /// <summary>\n        /// Gets the block corresponding to the <paramref name=\"index\"/>.\n        /// </summary>\n        /// <param name=\"index\">A number of index of <see cref=\"Block\"/>.</param>\n        /// <exception cref=\"ArgumentOutOfRangeException\">Thrown when the given index of\n        /// <see cref=\"Block\"/> does not exist.</exception>\n        public Block this[long index]\n        {\n            get\n            {\n                _rwlock.EnterReadLock();\n                try\n                {\n                    BlockHash? blockHash = Store.IndexBlockHash(Id, index);\n                    return blockHash is { } bh\n                        ? _blocks[bh]\n                        : throw new ArgumentOutOfRangeException();\n                }\n                finally\n                {\n                    _rwlock.ExitReadLock();\n                }\n            }\n        }\n\n        /// <summary>\n        /// Gets the block corresponding to the <paramref name=\"blockHash\"/>.\n        /// </summary>\n        /// <param name=\"blockHash\">A <see cref=\"Block.Hash\"/> of the <see cref=\"Block\"/> to\n        /// get. </param>\n        /// <exception cref=\"KeyNotFoundException\">Thrown when there is no <see cref=\"Block\"/>\n        /// with a given <paramref name=\"blockHash\"/>.</exception>\n        public Block this[in BlockHash blockHash]\n        {\n            get\n            {\n                if (!ContainsBlock(blockHash))\n                {\n                    throw new KeyNotFoundException(\n                        $\"The given hash[{blockHash}] was not found in this chain.\"\n                    );\n                }\n\n                _rwlock.EnterReadLock();\n                try\n                {\n                    return _blocks[blockHash];\n                }\n                finally\n                {\n                    _rwlock.ExitReadLock();\n                }\n            }\n        }\n\n#pragma warning disable SA1611\n        /// <summary>\n        /// Creates a new instance of <see cref=\"BlockChain\"/> from an empty\n        /// <see cref=\"IStore\"/>.\n        /// </summary>\n        /// <returns>A newly created <see cref=\"BlockChain\"/>.</returns>\n        /// <exception cref=\"ArgumentNullException\">Thrown when either <paramref name=\"store\"/>\n        /// or <paramref name=\"stateStore\"/> is <see langword=\"null\"/>.</exception>\n        /// <exception cref=\"ArgumentException\">Thrown when <paramref name=\"store\"/> already has a\n        /// canonical chain id.</exception>\n        /// <exception cref=\"InvalidBlockException\">Thrown when <paramref name=\"genesisBlock\"/>\n        /// is invalid.</exception>\n        /// <exception cref=\"InvalidTxException\">Thrown when <paramref name=\"genesisBlock\"/>\n        /// contains an invalid <see cref=\"Transaction\"/>.</exception>\n        public static BlockChain Create(\n            IBlockPolicy policy,\n            IStagePolicy stagePolicy,\n            IStore store,\n            IStateStore stateStore,\n            Block genesisBlock,\n            IActionEvaluator actionEvaluator,\n            IEnumerable<IRenderer> renderers = null,\n            IBlockChainStates blockChainStates = null)\n#pragma warning restore SA1611  // The documentation for parameters are missing.\n        {\n            if (store is null)\n            {\n                throw new ArgumentNullException(nameof(store));\n            }\n            else if (stateStore is null)\n            {\n                throw new ArgumentNullException(nameof(stateStore));\n            }\n            else if (actionEvaluator is null)\n            {\n                throw new ArgumentNullException(nameof(actionEvaluator));\n            }\n            else if (store.GetCanonicalChainId() is { } canonId)\n            {\n                throw new ArgumentException(\n                    $\"Given {nameof(store)} already has its canonical chain id set: {canonId}\",\n                    nameof(store));\n            }\n\n            var id = Guid.NewGuid();\n\n            if (genesisBlock.ProtocolVersion < BlockMetadata.SlothProtocolVersion)\n            {\n                var preEval = new PreEvaluationBlock(\n                    genesisBlock.Header, genesisBlock.Transactions, genesisBlock.Evidence);\n                var computedStateRootHash =\n                    actionEvaluator.Evaluate(preEval, null).Last().OutputState;\n                if (!genesisBlock.StateRootHash.Equals(computedStateRootHash))\n                {\n                    throw new InvalidBlockStateRootHashException(\n                        $\"Given block #{genesisBlock.Index} {genesisBlock.Hash} has \" +\n                        $\"a state root hash {genesisBlock.StateRootHash} that is different \" +\n                        $\"from the calculated state root hash {computedStateRootHash}\",\n                        genesisBlock.StateRootHash,\n                        computedStateRootHash);\n                }\n            }\n\n            ValidateGenesis(genesisBlock);\n            var nonceDeltas = ValidateGenesisNonces(genesisBlock);\n\n            store.PutBlock(genesisBlock);\n            store.AppendIndex(id, genesisBlock.Hash);\n\n            foreach (var tx in genesisBlock.Transactions)\n            {\n                store.PutTxIdBlockHashIndex(tx.Id, genesisBlock.Hash);\n            }\n\n            foreach (KeyValuePair<Address, long> pair in nonceDeltas)\n            {\n                store.IncreaseTxNonce(id, pair.Key, pair.Value);\n            }\n\n            store.SetCanonicalChainId(id);\n\n            blockChainStates ??= new BlockChainStates(store, stateStore);\n            return new BlockChain(\n                policy,\n                stagePolicy,\n                store,\n                stateStore,\n                id,\n                genesisBlock,\n                blockChainStates,\n                actionEvaluator,\n                renderers);\n        }\n\n        /// <summary>\n        /// Determines whether the <see cref=\"BlockChain\"/> contains <see cref=\"Block\"/>\n        /// the specified <paramref name=\"blockHash\"/>.\n        /// </summary>\n        /// <param name=\"blockHash\">The <see cref=\"HashDigest{T}\"/> of the <see cref=\"Block\"/> to\n        /// check if it is in the <see cref=\"BlockChain\"/>.</param>\n        /// <returns>\n        /// <see langword=\"true\"/> if the <see cref=\"BlockChain\"/> contains\n        /// <see cref=\"Block\"/> with the specified <paramref name=\"blockHash\"/>; otherwise,\n        /// <see langword=\"false\"/>.\n        /// </returns>\n        public bool ContainsBlock(BlockHash blockHash)\n        {\n            _rwlock.EnterReadLock();\n            try\n            {\n                return\n                    _blocks.ContainsKey(blockHash) &&\n                    Store.GetBlockIndex(blockHash) is { } branchPointIndex &&\n                    branchPointIndex <= Tip.Index &&\n                    Store.IndexBlockHash(Id, branchPointIndex).Equals(blockHash);\n            }\n            finally\n            {\n                _rwlock.ExitReadLock();\n            }\n        }\n\n        /// <summary>\n        /// Gets the transaction corresponding to the <paramref name=\"txId\"/>.\n        /// </summary>\n        /// <param name=\"txId\">A <see cref=\"TxId\"/> of the <see cref=\"Transaction\"/> to get.\n        /// </param>\n        /// <returns><see cref=\"Transaction\"/> with <paramref name=\"txId\"/>.</returns>\n        /// <exception cref=\"KeyNotFoundException\">Thrown when there is no\n        /// <see cref=\"Transaction\"/> with a given <paramref name=\"txId\"/>.</exception>\n        public Transaction GetTransaction(TxId txId)\n        {\n            if (StagePolicy.Get(this, txId) is { } tx)\n            {\n                return tx;\n            }\n\n            _rwlock.EnterReadLock();\n            try\n            {\n                if (Store.GetTransaction(txId) is { } transaction)\n                {\n                    return transaction;\n                }\n\n                throw new KeyNotFoundException($\"No such transaction: {txId}\");\n            }\n            finally\n            {\n                _rwlock.ExitReadLock();\n            }\n        }\n\n        /// <summary>\n        /// Queries the recorded <see cref=\"TxExecution\"/> for a successful or failed\n        /// <see cref=\"Transaction\"/> within a <see cref=\"Block\"/>.\n        /// </summary>\n        /// <param name=\"blockHash\">The <see cref=\"Block.Hash\"/> of the <see cref=\"Block\"/>\n        /// that the <see cref=\"Transaction\"/> is executed within.</param>\n        /// <param name=\"txid\">The executed <see cref=\"Transaction\"/>'s\n        /// <see cref=\"Transaction.Id\"/>.</param>\n        /// <returns>The recorded <see cref=\"TxExecution\"/>.  If the transaction has never been\n        /// executed within the block, it returns <see langword=\"null\"/> instead.</returns>\n        public TxExecution GetTxExecution(BlockHash blockHash, TxId txid) =>\n            Store.GetTxExecution(blockHash, txid);\n\n        /// <summary>\n        /// Adds a <paramref name=\"block\"/> to the end of this chain.\n        /// <para><see cref=\"Block.Transactions\"/> in the <paramref name=\"block\"/> updates\n        /// states and balances in the blockchain, and <see cref=\"TxExecution\"/>s for\n        /// transactions are recorded.</para>\n        /// <para>Note that <see cref=\"Renderers\"/> receive events right after the <paramref\n        /// name=\"block\"/> is confirmed (and thus all states reflect changes in the <paramref\n        /// name=\"block\"/>).</para>\n        /// </summary>\n        /// <param name=\"block\">A next <see cref=\"Block\"/>, which is mined,\n        /// to add.</param>\n        /// <param name=\"blockCommit\">A <see cref=\"BlockCommit\"/> that has +2/3 commits for the\n        /// given block.</param>\n        /// <param name=\"validate\">Validate block.</param>\n        /// <exception cref=\"BlockPolicyViolationException\">Thrown when given\n        /// <paramref name=\"block\"/> does not satisfy any of the constraints\n        /// validated by <see cref=\"IBlockPolicy.ValidateNextBlock\"/> of <see cref=\"Policy\"/>.\n        /// </exception>\n        /// <exception cref=\"InvalidBlockException\">Thrown when the given <paramref name=\"block\"/>\n        /// is invalid, in itself or according to the <see cref=\"Policy\"/>.</exception>\n        /// <exception cref=\"InvalidActionException\">Thrown when given <paramref name=\"block\"/>\n        /// contains an action that cannot be loaded with <see cref=\"IActionLoader\"/>.</exception>\n        /// <exception cref=\"InvalidTxNonceException\">Thrown when the\n        /// <see cref=\"Transaction.Nonce\"/> is different from\n        /// <see cref=\"GetNextTxNonce\"/> result of the\n        /// <see cref=\"Transaction.Signer\"/>.</exception>\n        /// <exception cref=\"InvalidBlockCommitException\">Thrown when the given\n        /// <paramref name=\"block\"/> and <paramref name=\"blockCommit\"/> is invalid.</exception>\n        public void Append(\n            Block block,\n            BlockCommit blockCommit,\n            bool validate = true)\n        {\n            if (block.ProtocolVersion < BlockMetadata.SlothProtocolVersion)\n            {\n                AppendStateRootHashPreceded(block, blockCommit, render: true);\n            }\n            else\n            {\n                Append(block, blockCommit, render: true, validate: validate);\n            }\n        }\n\n        /// <summary>\n        /// Adds <paramref name=\"transaction\"/> to the pending list so that a next\n        /// <see cref=\"Block\"/> to be mined may contain given <paramref name=\"transaction\"/>.\n        /// </summary>\n        /// <param name=\"transaction\"><see cref=\"Transaction\"/> to add to the pending list.\n        /// </param>\n        /// <returns><see langword=\"true\"/> if staging was successful,\n        /// <see langword=\"false\"/> otherwise.</returns>\n        /// <exception cref=\"InvalidTxGenesisHashException\">Thrown when given\n        /// <paramref name=\"transaction\"/> has invalid <see cref=\"Transaction.GenesisHash\"/>.\n        /// </exception>\n        public bool StageTransaction(Transaction transaction)\n        {\n            if (!transaction.GenesisHash.Equals(Genesis.Hash))\n            {\n                var msg = \"GenesisHash of the transaction is not compatible \" +\n                          \"with the BlockChain.Genesis.Hash.\";\n                throw new InvalidTxGenesisHashException(\n                    msg,\n                    transaction.Id,\n                    Genesis.Hash,\n                    transaction.GenesisHash);\n            }\n\n            return StagePolicy.Stage(this, transaction);\n        }\n\n        /// <summary>\n        /// Removes a <paramref name=\"transaction\"/> from the pending list.\n        /// </summary>\n        /// <param name=\"transaction\">A <see cref=\"Transaction\"/>\n        /// to remove from the pending list.</param>\n        /// <returns><see langword=\"true\"/> if unstaging was successful,\n        /// <see langword=\"false\"/> otherwise.</returns>\n        /// <seealso cref=\"StageTransaction\"/>\n        public bool UnstageTransaction(Transaction transaction) =>\n            StagePolicy.Unstage(this, transaction.Id);\n\n        /// <summary>\n        /// Gets next <see cref=\"Transaction.Nonce\"/> of the address.\n        /// </summary>\n        /// <param name=\"address\">The <see cref=\"Address\"/> from which to obtain the\n        /// <see cref=\"Transaction.Nonce\"/> value.</param>\n        /// <returns>The next <see cref=\"Transaction.Nonce\"/> value of the\n        /// <paramref name=\"address\"/>.</returns>\n        public long GetNextTxNonce(Address address)\n            => StagePolicy.GetNextTxNonce(this, address);\n\n        /// <summary>\n        /// Creates a new <see cref=\"Transaction\"/> with custom actions and stage it.\n        /// It's available only if the genesis block exists.\n        /// </summary>\n        /// <param name=\"privateKey\">A <see cref=\"PrivateKey\"/> of the account who creates and\n        /// signs a new transaction.</param>\n        /// <param name=\"actions\">A list of custom actions to include to a new transaction.\n        /// </param>\n        /// <param name=\"maxGasPrice\"> The maximum gas price this transaction can pay fee. </param>\n        /// <param name=\"gasLimit\"> The maximum amount of gas this transaction can consume.\n        /// </param>\n        /// <param name=\"timestamp\">The time this <see cref=\"Transaction\"/> is created and\n        /// signed.</param>\n        /// <returns>A created new <see cref=\"Transaction\"/> signed by the given\n        /// <paramref name=\"privateKey\"/>.</returns>\n        public Transaction MakeTransaction(\n            PrivateKey privateKey,\n            IEnumerable<IAction> actions,\n            FungibleAssetValue? maxGasPrice = null,\n            long? gasLimit = null,\n            DateTimeOffset? timestamp = null)\n        {\n            timestamp = timestamp ?? DateTimeOffset.UtcNow;\n            lock (_txLock)\n            {\n                // FIXME: Exception should be documented when the genesis block does not exist.\n                Transaction tx = Transaction.Create(\n                    GetNextTxNonce(privateKey.Address),\n                    privateKey,\n                    Genesis.Hash,\n                    actions.Select(x => x.PlainValue),\n                    maxGasPrice,\n                    gasLimit,\n                    timestamp);\n                StageTransaction(tx);\n                return tx;\n            }\n        }\n\n        /// <summary>\n        /// Lists all staged <see cref=\"TxId\"/>s.\n        /// </summary>\n        /// <returns><see cref=\"IImmutableSet{TxId}\"/> of staged transactions.</returns>\n        public IImmutableSet<TxId> GetStagedTransactionIds()\n        {\n            // FIXME: How about turning this method to the StagedTransactions property?\n            return StagePolicy.Iterate(this).Select(tx => tx.Id).ToImmutableHashSet();\n        }\n\n        /// <summary>\n        /// Finds the branch point <see cref=\"BlockHash\"/> between this <see cref=\"BlockChain\"/>\n        /// and <paramref name=\"locator\"/> and returns the list of <see cref=\"BlockHash\"/>es of\n        /// successive <see cref=\"Block\"/>s starting from the branch point\n        /// <see cref=\"BlockHash\"/>.</summary>\n        /// <param name=\"locator\">The <see cref=\"BlockLocator\"/> to find the branching point\n        /// from.</param>\n        /// <param name=\"count\">The Maximum number of <see cref=\"BlockHash\"/>es to return.</param>\n        /// <returns>A list of <see cref=\"BlockHash\"/>es including\n        /// the branch point <see cref=\"BlockHash\"/>.  If no branch point is found,\n        /// returns an empty list of <see cref=\"BlockHash\"/>es.</returns>\n        public IReadOnlyList<BlockHash> FindNextHashes(\n            BlockLocator locator,\n            int count = 500)\n        {\n            Stopwatch stopwatch = new Stopwatch();\n            stopwatch.Start();\n\n            if (!(FindBranchpoint(locator) is { } branchpoint))\n            {\n                return Array.Empty<BlockHash>();\n            }\n\n            if (!(Store.GetBlockIndex(branchpoint) is { } branchpointIndex))\n            {\n                return Array.Empty<BlockHash>();\n            }\n\n            var result = new List<BlockHash>();\n            foreach (BlockHash hash in Store.IterateIndexes(Id, (int)branchpointIndex, count))\n            {\n                if (count == 0)\n                {\n                    break;\n                }\n\n                result.Add(hash);\n                count--;\n            }\n\n            _logger\n                .ForContext(\"Tag\", \"Metric\")\n                .ForContext(\"Subtag\", \"FindHashesDuration\")\n                .Information(\n                    \"Found {HashCount} hashes from storage with {ChainIdCount} chain ids \" +\n                    \"in {DurationMs} ms\",\n                    result.Count,\n                    Store.ListChainIds().Count(),\n                    stopwatch.ElapsedMilliseconds);\n\n            return result;\n        }\n\n        /// <summary>\n        /// Returns a new <see cref=\"BlockLocator\"/> from the tip of current chain.\n        /// </summary>\n        /// <returns>A instance of block locator.</returns>\n        public BlockLocator GetBlockLocator()\n        {\n            _rwlock.EnterReadLock();\n            try\n            {\n                return new BlockLocator(Tip.Hash);\n            }\n            finally\n            {\n                _rwlock.ExitReadLock();\n            }\n        }\n\n        /// <summary>\n        /// Returns a <see cref=\"BlockCommit\"/> of given <see cref=\"Block\"/> index.\n        /// </summary>\n        /// <param name=\"index\">A index value (height) of <see cref=\"Block\"/> to retrieve.\n        /// </param>\n        /// <returns>Returns a <see cref=\"BlockCommit\"/> of given <see cref=\"Block\"/> index.\n        /// Following conditions will return <see langword=\"null\"/>:\n        /// <list type=\"bullet\">\n        ///     <item>\n        ///         Given <see cref=\"Block\"/> <see cref=\"Block.ProtocolVersion\"/> is\n        ///         Proof-of-Work.\n        ///     </item>\n        ///     <item>\n        ///         Given <see cref=\"Block\"/> is <see cref=\"BlockChain.Genesis\"/> block.\n        ///     </item>\n        /// </list>\n        /// </returns>\n        /// <exception cref=\"KeyNotFoundException\">Thrown if given index does not exist in the\n        /// blockchain.</exception>\n        /// <remarks>The <see cref=\"BlockChain.Genesis\"/> block does not have\n        /// <see cref=\"BlockCommit\"/> because the genesis block is not committed by a consensus.\n        /// </remarks>\n        public BlockCommit GetBlockCommit(long index)\n        {\n            Block block = this[index];\n\n            if (block.ProtocolVersion < BlockMetadata.PBFTProtocolVersion)\n            {\n                return null;\n            }\n\n            return index == Tip.Index\n                ? Store.GetChainBlockCommit(Id)\n                : this[index + 1].LastCommit;\n        }\n\n        /// <summary>\n        /// Returns a <see cref=\"BlockCommit\"/> of given <see cref=\"Block\"/> index.\n        /// </summary>\n        /// <param name=\"blockHash\">A hash value of <see cref=\"Block\"/> to retrieve.\n        /// </param>\n        /// <returns>Returns a <see cref=\"BlockCommit\"/> of given <see cref=\"Block\"/> hash, if\n        /// the <see cref=\"BlockCommit\"/> of <see cref=\"BlockChain.Genesis\"/> block is requested,\n        /// then returns <see langword=\"null\"/>.</returns>\n        /// <exception cref=\"KeyNotFoundException\">Thrown if given hash does not exist in the\n        /// blockchain.</exception>\n        /// <remarks>The <see cref=\"BlockChain.Genesis\"/> block does not have\n        /// <see cref=\"BlockCommit\"/> because the genesis block is not committed by a consensus.\n        /// </remarks>\n        public BlockCommit GetBlockCommit(BlockHash blockHash) =>\n            GetBlockCommit(this[blockHash].Index);\n\n#pragma warning disable MEN003\n        internal void Append(\n            Block block,\n            BlockCommit blockCommit,\n            bool render,\n            bool validate = true)\n        {\n            if (Count == 0)\n            {\n                throw new ArgumentException(\n                    \"Cannot append a block to an empty chain.\");\n            }\n            else if (block.Index == 0)\n            {\n                throw new ArgumentException(\n                    $\"Cannot append genesis block #{block.Index} {block.Hash} to a chain.\",\n                    nameof(block));\n            }\n\n            _logger.Information(\n                \"Trying to append block #{BlockIndex} {BlockHash}...\", block.Index, block.Hash);\n\n            if (validate)\n            {\n                block.ValidateTimestamp();\n            }\n\n            _rwlock.EnterUpgradeableReadLock();\n            Block prevTip = Tip;\n            try\n            {\n                if (validate)\n                {\n                    ValidateBlock(block);\n                    ValidateBlockCommit(block, blockCommit);\n                }\n\n                var nonceDeltas = ValidateBlockNonces(\n                    block.Transactions\n                        .Select(tx => tx.Signer)\n                        .Distinct()\n                        .ToDictionary(signer => signer, signer => Store.GetTxNonce(Id, signer)),\n                    block);\n\n                if (validate)\n                {\n                    ValidateBlockLoadActions(block);\n                }\n\n                if (validate && Policy.ValidateNextBlock(this, block) is { } bpve)\n                {\n                    throw bpve;\n                }\n\n                foreach (Transaction tx in block.Transactions)\n                {\n                    if (validate && Policy.ValidateNextBlockTx(this, tx) is { } tpve)\n                    {\n                        throw new TxPolicyViolationException(\n                            \"According to BlockPolicy, this transaction is not valid.\",\n                            tx.Id,\n                            tpve);\n                    }\n                }\n\n                _rwlock.EnterWriteLock();\n                try\n                {\n                    if (validate)\n                    {\n                        ValidateBlockStateRootHash(block);\n                    }\n\n                    // FIXME: Using evaluateActions as a proxy flag for preloading status.\n                    const string TimestampFormat = \"yyyy-MM-ddTHH:mm:ss.ffffffZ\";\n                    _logger\n                        .ForContext(\"Tag\", \"Metric\")\n                        .ForContext(\"Subtag\", \"BlockAppendTimestamp\")\n                        .Information(\n                            \"Block #{BlockIndex} {BlockHash} with \" +\n                            \"timestamp {BlockTimestamp} appended at {AppendTimestamp}\",\n                            block.Index,\n                            block.Hash,\n                            block.Timestamp.ToString(\n                                TimestampFormat, CultureInfo.InvariantCulture),\n                            DateTimeOffset.UtcNow.ToString(\n                                TimestampFormat, CultureInfo.InvariantCulture));\n\n                    _blocks[block.Hash] = block;\n\n                    foreach (KeyValuePair<Address, long> pair in nonceDeltas)\n                    {\n                        Store.IncreaseTxNonce(Id, pair.Key, pair.Value);\n                    }\n\n                    foreach (var tx in block.Transactions)\n                    {\n                        Store.PutTxIdBlockHashIndex(tx.Id, block.Hash);\n                    }\n\n                    if (block.Index != 0 && blockCommit is { })\n                    {\n                        Store.PutChainBlockCommit(Id, blockCommit);\n                    }\n\n                    foreach (var ev in block.Evidence)\n                    {\n                        if (Store.GetPendingEvidence(ev.Id) != null)\n                        {\n                            Store.DeletePendingEvidence(ev.Id);\n                        }\n\n                        Store.PutCommittedEvidence(ev);\n                    }\n\n                    Store.AppendIndex(Id, block.Hash);\n                    _nextStateRootHash = null;\n\n                    foreach (var ev in GetPendingEvidence().ToArray())\n                    {\n                        if (IsEvidenceExpired(ev))\n                        {\n                            Store.DeletePendingEvidence(ev.Id);\n                        }\n                    }\n                }\n                finally\n                {\n                    _rwlock.ExitWriteLock();\n                }\n\n                if (IsCanonical)\n                {\n                    _logger.Information(\n                        \"Unstaging {TxCount} transactions from block #{BlockIndex} {BlockHash}...\",\n                        block.Transactions.Count(),\n                        block.Index,\n                        block.Hash);\n                    foreach (Transaction tx in block.Transactions)\n                    {\n                        UnstageTransaction(tx);\n                    }\n\n                    _logger.Information(\n                        \"Unstaged {TxCount} transactions from block #{BlockIndex} {BlockHash}...\",\n                        block.Transactions.Count(),\n                        block.Index,\n                        block.Hash);\n                }\n                else\n                {\n                    _logger.Information(\n                        \"Skipping unstaging transactions from block #{BlockIndex} {BlockHash} \" +\n                        \"for non-canonical chain {ChainID}\",\n                        block.Index,\n                        block.Hash,\n                        Id);\n                }\n\n                TipChanged?.Invoke(this, (prevTip, block));\n                _logger.Information(\n                    \"Appended the block #{BlockIndex} {BlockHash}\",\n                    block.Index,\n                    block.Hash);\n\n                HashDigest<SHA256> nextStateRootHash =\n                    DetermineNextBlockStateRootHash(block, out var actionEvaluations);\n                _nextStateRootHash = nextStateRootHash;\n\n                IEnumerable<TxExecution> txExecutions =\n                    MakeTxExecutions(block, actionEvaluations);\n                UpdateTxExecutions(txExecutions);\n\n                if (render)\n                {\n                    _logger.Information(\n                        \"Invoking {RendererCount} renderers and \" +\n                        \"{ActionRendererCount} action renderers for #{BlockIndex} {BlockHash}\",\n                        Renderers.Count,\n                        ActionRenderers.Count,\n                        block.Index,\n                        block.Hash);\n                    foreach (IRenderer renderer in Renderers)\n                    {\n                        renderer.RenderBlock(oldTip: prevTip ?? Genesis, newTip: block);\n                    }\n\n                    if (ActionRenderers.Any())\n                    {\n                        RenderActions(evaluations: actionEvaluations, block: block);\n                        foreach (IActionRenderer renderer in ActionRenderers)\n                        {\n                            renderer.RenderBlockEnd(oldTip: prevTip ?? Genesis, newTip: block);\n                        }\n                    }\n\n                    _logger.Information(\n                        \"Invoked {RendererCount} renderers and \" +\n                        \"{ActionRendererCount} action renderers for #{BlockIndex} {BlockHash}\",\n                        Renderers.Count,\n                        ActionRenderers.Count,\n                        block.Index,\n                        block.Hash);\n                }\n            }\n            finally\n            {\n                _rwlock.ExitUpgradeableReadLock();\n            }\n        }\n#pragma warning restore MEN003\n\n#pragma warning disable MEN003\n        internal void AppendStateRootHashPreceded(\n            Block block,\n            BlockCommit blockCommit,\n            bool render,\n            IReadOnlyList<ICommittedActionEvaluation> actionEvaluations = null\n        )\n        {\n            if (Count == 0)\n            {\n                throw new ArgumentException(\n                    \"Cannot append a block to an empty chain.\");\n            }\n            else if (block.Index == 0)\n            {\n                throw new ArgumentException(\n                    $\"Cannot append genesis block #{block.Index} {block.Hash} to a chain.\",\n                    nameof(block));\n            }\n\n            _logger.Information(\n                \"Trying to append block #{BlockIndex} {BlockHash}...\", block.Index, block.Hash);\n\n            block.ValidateTimestamp();\n\n            _rwlock.EnterUpgradeableReadLock();\n            Block prevTip = Tip;\n            try\n            {\n                ValidateBlock(block);\n                ValidateBlockCommit(block, blockCommit);\n\n                var nonceDeltas = ValidateBlockNonces(\n                    block.Transactions\n                        .Select(tx => tx.Signer)\n                        .Distinct()\n                        .ToDictionary(signer => signer, signer => Store.GetTxNonce(Id, signer)),\n                    block);\n\n                if (Policy.ValidateNextBlock(this, block) is { } bpve)\n                {\n                    throw bpve;\n                }\n\n                foreach (Transaction tx in block.Transactions)\n                {\n                    if (Policy.ValidateNextBlockTx(this, tx) is { } tpve)\n                    {\n                        throw new TxPolicyViolationException(\n                            \"According to BlockPolicy, this transaction is not valid.\",\n                            tx.Id,\n                            tpve);\n                    }\n                }\n\n                _rwlock.EnterWriteLock();\n                try\n                {\n                    if (actionEvaluations is null)\n                    {\n                        _logger.Information(\n                            \"Executing actions in block #{BlockIndex} {BlockHash}...\",\n                            block.Index,\n                            block.Hash);\n                        ValidateBlockPrecededStateRootHash(block, out actionEvaluations);\n                        _logger.Information(\n                            \"Executed actions in block #{BlockIndex} {BlockHash}\",\n                            block.Index,\n                            block.Hash);\n                    }\n\n                    // FIXME: Using evaluateActions as a proxy flag for preloading status.\n                    const string TimestampFormat = \"yyyy-MM-ddTHH:mm:ss.ffffffZ\";\n                    _logger\n                        .ForContext(\"Tag\", \"Metric\")\n                        .ForContext(\"Subtag\", \"BlockAppendTimestamp\")\n                        .Information(\n                            \"Block #{BlockIndex} {BlockHash} with \" +\n                            \"timestamp {BlockTimestamp} appended at {AppendTimestamp}\",\n                            block.Index,\n                            block.Hash,\n                            block.Timestamp.ToString(\n                                TimestampFormat, CultureInfo.InvariantCulture),\n                            DateTimeOffset.UtcNow.ToString(\n                                TimestampFormat, CultureInfo.InvariantCulture));\n\n                    _blocks[block.Hash] = block;\n\n                    foreach (KeyValuePair<Address, long> pair in nonceDeltas)\n                    {\n                        Store.IncreaseTxNonce(Id, pair.Key, pair.Value);\n                    }\n\n                    foreach (var tx in block.Transactions)\n                    {\n                        Store.PutTxIdBlockHashIndex(tx.Id, block.Hash);\n                    }\n\n                    if (block.Index != 0 && blockCommit is { })\n                    {\n                        Store.PutChainBlockCommit(Id, blockCommit);\n                    }\n\n                    foreach (var evidence in block.Evidence)\n                    {\n                        if (Store.GetPendingEvidence(evidence.Id) != null)\n                        {\n                            Store.DeletePendingEvidence(evidence.Id);\n                        }\n\n                        Store.PutCommittedEvidence(evidence);\n                    }\n\n                    Store.AppendIndex(Id, block.Hash);\n                    _nextStateRootHash = block.StateRootHash;\n                    IEnumerable<TxExecution> txExecutions =\n                        MakeTxExecutions(block, actionEvaluations);\n                    UpdateTxExecutions(txExecutions);\n\n                    foreach (var evidence in GetPendingEvidence().ToArray())\n                    {\n                        if (IsEvidenceExpired(evidence))\n                        {\n                            Store.DeletePendingEvidence(evidence.Id);\n                        }\n                    }\n                }\n                finally\n                {\n                    _rwlock.ExitWriteLock();\n                }\n\n                if (IsCanonical)\n                {\n                    _logger.Information(\n                        \"Unstaging {TxCount} transactions from block #{BlockIndex} {BlockHash}...\",\n                        block.Transactions.Count(),\n                        block.Index,\n                        block.Hash);\n                    foreach (Transaction tx in block.Transactions)\n                    {\n                        UnstageTransaction(tx);\n                    }\n\n                    _logger.Information(\n                        \"Unstaged {TxCount} transactions from block #{BlockIndex} {BlockHash}...\",\n                        block.Transactions.Count(),\n                        block.Index,\n                        block.Hash);\n                }\n                else\n                {\n                    _logger.Information(\n                        \"Skipping unstaging transactions from block #{BlockIndex} {BlockHash} \" +\n                        \"for non-canonical chain {ChainID}\",\n                        block.Index,\n                        block.Hash,\n                        Id);\n                }\n\n                TipChanged?.Invoke(this, (prevTip, block));\n                _logger.Information(\n                    \"Appended the block #{BlockIndex} {BlockHash}\",\n                    block.Index,\n                    block.Hash);\n\n                if (render)\n                {\n                    _logger.Information(\n                        \"Invoking {RendererCount} renderers and \" +\n                        \"{ActionRendererCount} action renderers for #{BlockIndex} {BlockHash}\",\n                        Renderers.Count,\n                        ActionRenderers.Count,\n                        block.Index,\n                        block.Hash);\n                    foreach (IRenderer renderer in Renderers)\n                    {\n                        renderer.RenderBlock(oldTip: prevTip ?? Genesis, newTip: block);\n                    }\n\n                    if (ActionRenderers.Any())\n                    {\n                        RenderActions(evaluations: actionEvaluations, block: block);\n                        foreach (IActionRenderer renderer in ActionRenderers)\n                        {\n                            renderer.RenderBlockEnd(oldTip: prevTip ?? Genesis, newTip: block);\n                        }\n                    }\n\n                    _logger.Information(\n                        \"Invoked {RendererCount} renderers and \" +\n                        \"{ActionRendererCount} action renderers for #{BlockIndex} {BlockHash}\",\n                        Renderers.Count,\n                        ActionRenderers.Count,\n                        block.Index,\n                        block.Hash);\n                }\n            }\n            finally\n            {\n                _rwlock.ExitUpgradeableReadLock();\n            }\n        }\n#pragma warning restore MEN003\n\n        /// <summary>\n        /// Finds an approximate topmost common ancestor between this\n        /// <see cref=\"BlockChain\"/> and a given <see cref=\"BlockLocator\"/>.\n        /// </summary>\n        /// <param name=\"locator\">A block locator that contains common ancestor candidates.</param>\n        /// <returns>An approximate to the topmost common ancestor if found, otherwise\n        /// <see langword=\"null\"/>.</returns>\n        internal BlockHash? FindBranchpoint(BlockLocator locator)\n        {\n            if (ContainsBlock(locator.Hash))\n            {\n                _logger.Debug(\n                    \"Found a branchpoint with locator [{LocatorHead}]: {Hash}\",\n                    locator.Hash,\n                    locator.Hash);\n                return locator.Hash;\n            }\n\n            _logger.Debug(\n                \"Failed to find a branchpoint locator [{LocatorHead}]\",\n                locator.Hash);\n            return null;\n        }\n\n        /// <summary>\n        /// Lists the all staged transactions, with properly ordered nonces.\n        /// </summary>\n        /// <param name=\"txPriority\">An optional comparer for give certain transactions to\n        /// priority to belong to the block.  No certain priority by default.</param>\n        /// <returns>A list of staged transactions.  This guarantees that for transactions signed\n        /// by the same address, those with greater nonce never comes before those with\n        /// lesser nonce.</returns>\n        internal ImmutableList<Transaction> ListStagedTransactions(\n            IComparer<Transaction> txPriority = null\n        )\n        {\n            IEnumerable<Transaction> unorderedTxs = StagePolicy.Iterate(this);\n            if (txPriority is { } comparer)\n            {\n                unorderedTxs = unorderedTxs.OrderBy(tx => tx, comparer);\n            }\n\n            Transaction[] txs = unorderedTxs.ToArray();\n\n            Dictionary<Address, LinkedList<Transaction>> seats = txs\n                .GroupBy(tx => tx.Signer)\n                .Select(g => (g.Key, new LinkedList<Transaction>(g.OrderBy(tx => tx.Nonce))))\n                .ToDictionary(pair => pair.Item1, pair => pair.Item2);\n\n            return txs.Select(tx =>\n            {\n                LinkedList<Transaction> seat = seats[tx.Signer];\n                Transaction first = seat.First.Value;\n                seat.RemoveFirst();\n                return first;\n            }).ToImmutableList();\n        }\n\n        internal IEnumerable<Block> IterateBlocks(int offset = 0, int? limit = null)\n        {\n            _rwlock.EnterUpgradeableReadLock();\n\n            try\n            {\n                foreach (BlockHash hash in IterateBlockHashes(offset, limit))\n                {\n                    yield return _blocks[hash];\n                }\n            }\n            finally\n            {\n                _rwlock.ExitUpgradeableReadLock();\n            }\n        }\n\n        internal IEnumerable<BlockHash> IterateBlockHashes(int offset = 0, int? limit = null)\n        {\n            _rwlock.EnterUpgradeableReadLock();\n\n            try\n            {\n                IEnumerable<BlockHash> indices = Store.IterateIndexes(Id, offset, limit);\n\n                // NOTE: The reason why this does not simply return indices, but iterates over\n                // indices and yields hashes step by step instead, is that we need to ensure\n                // the read lock held until the whole iteration completes.\n                foreach (BlockHash hash in indices)\n                {\n                    yield return hash;\n                }\n            }\n            finally\n            {\n                _rwlock.ExitUpgradeableReadLock();\n            }\n        }\n\n        /// <summary>\n        /// Cleans up every <see cref=\"BlockCommit\"/> in the store with\n        /// <see cref=\"BlockCommit.Height\"/> less than <paramref name=\"limit\"/>.\n        /// </summary>\n        /// <param name=\"limit\">A exceptional index that is not to be removed.</param>\n        /// <exception cref=\"InvalidOperationException\">Thrown when <see cref=\"IsCanonical\"/> is\n        /// <see langword=\"false\"/>.</exception>\n        internal void CleanupBlockCommitStore(long limit)\n        {\n            // FIXME: This still isn't enough to prevent the canonical chain\n            // removing cached block commits that are needed by other non-canonical chains.\n            if (!IsCanonical)\n            {\n                throw new InvalidOperationException(\n                    $\"Cannot perform {nameof(CleanupBlockCommitStore)}() from a \" +\n                    \"non canonical chain.\");\n            }\n\n            List<BlockHash> hashes = Store.GetBlockCommitHashes().ToList();\n\n            _logger.Debug(\"Removing old BlockCommits with heights lower than {Limit}...\", limit);\n            foreach (var hash in hashes)\n            {\n                if (Store.GetBlockCommit(hash) is { } commit && commit.Height < limit)\n                {\n                    Store.DeleteBlockCommit(hash);\n                }\n            }\n        }\n\n        internal HashDigest<SHA256>? GetNextStateRootHash() => _nextStateRootHash;\n\n        internal HashDigest<SHA256>? GetNextStateRootHash(long index) =>\n            GetNextStateRootHash(this[index]);\n\n        internal HashDigest<SHA256>? GetNextStateRootHash(BlockHash blockHash) =>\n            GetNextStateRootHash(this[blockHash]);\n\n        internal ValidatorSet GetValidatorSet(long index)\n        {\n            if (index == 0)\n            {\n                return GetNextWorldState().GetValidatorSet();\n            }\n\n            if (GetBlockCommit(index) is { } commit)\n            {\n                var validatorList = commit.Votes.Select(CreateValidator).ToList();\n                return new ValidatorSet(validatorList);\n            }\n\n            throw new ArgumentException(\"Cannot find a validator set for the given index.\");\n\n            static Validator CreateValidator(Vote vote)\n                => new Validator(vote.ValidatorPublicKey, vote.ValidatorPower ?? 0);\n        }\n\n        private HashDigest<SHA256>? GetNextStateRootHash(Block block)\n        {\n            if (block.ProtocolVersion < BlockMetadata.SlothProtocolVersion)\n            {\n                return block.StateRootHash;\n            }\n            else if (block.Index < Tip.Index)\n            {\n                return this[block.Index + 1].StateRootHash;\n            }\n            else\n            {\n                return GetNextStateRootHash();\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/Libplanet/Blockchain/BlockChainStates.cs",
    "content": "#nullable enable\nusing System;\nusing System.Diagnostics;\nusing System.Security.Cryptography;\nusing Libplanet.Action.State;\nusing Libplanet.Common;\nusing Libplanet.Store;\nusing Libplanet.Store.Trie;\nusing Libplanet.Types.Blocks;\n\nnamespace Libplanet.Blockchain\n{\n    /// <summary>\n    /// A default implementation of <see cref=\"IBlockChainStates\" /> interface.\n    /// </summary>\n    public class BlockChainStates : IBlockChainStates\n    {\n        private readonly IStore _store;\n        private readonly IStateStore _stateStore;\n        private readonly ActivitySource _activitySource;\n\n        public BlockChainStates(IStore store, IStateStore stateStore)\n        {\n            _store = store;\n            _stateStore = stateStore;\n            _activitySource = new ActivitySource(\"Libplanet.Blockchain.BlockChainStates\");\n        }\n\n        /// <inheritdoc cref=\"IBlockChainStates.GetWorldState(BlockHash)\"/>\n        public IWorldState GetWorldState(BlockHash offset)\n        {\n            using Activity? a = _activitySource\n                .StartActivity(ActivityKind.Internal)?\n                .AddTag(\"BlockHash\", offset.ToString());\n            return new WorldBaseState(GetTrie(offset), _stateStore);\n        }\n\n        /// <inheritdoc cref=\"IBlockChainStates.GetWorldState(HashDigest{SHA256}?)\"/>\n        public IWorldState GetWorldState(HashDigest<SHA256>? stateRootHash)\n            => new WorldBaseState(GetTrie(stateRootHash), _stateStore);\n\n        /// <summary>\n        /// Returns the state root associated with <see cref=\"BlockHash\"/>\n        /// <paramref name=\"offset\"/>.\n        /// </summary>\n        /// <param name=\"offset\">The <see cref=\"BlockHash\"/> to look up in\n        /// the internally held <see cref=\"IStore\"/>.</param>\n        /// <returns>An <see cref=\"ITrie\"/> representing the state root associated with\n        /// <paramref name=\"offset\"/>.</returns>\n        /// <exception cref=\"ArgumentException\">Thrown for one of the following reasons.\n        /// <list type=\"bullet\">\n        ///     <item><description>\n        ///         If <paramref name=\"offset\"/> is not <see langword=\"null\"/> and\n        ///         <paramref name=\"offset\"/> cannot be found in <see cref=\"IStore\"/>.\n        ///     </description></item>\n        ///     <item><description>\n        ///         If <paramref name=\"offset\"/> is not <see langword=\"null\"/> and\n        ///         the state root hash associated with <paramref name=\"offset\"/>\n        ///         cannot be found in <see cref=\"IStateStore\"/>.\n        ///     </description></item>\n        /// </list>\n        /// </exception>\n        /// <remarks>\n        /// An <see cref=\"ITrie\"/> returned by this method is read-only.\n        /// </remarks>\n        private ITrie GetTrie(BlockHash offset)\n        {\n            using Activity? a = _activitySource\n                .StartActivity(ActivityKind.Internal)?\n                .AddTag(\"BlockHash\", offset.ToString());\n            if (_store.GetStateRootHash(offset) is { } stateRootHash)\n            {\n                a?.SetStatus(ActivityStatusCode.Ok);\n                return GetTrie(stateRootHash);\n            }\n            else\n            {\n                a?.SetStatus(ActivityStatusCode.Error);\n                throw new ArgumentException(\n                    $\"Could not find block hash {offset} in {nameof(IStore)}.\",\n                    nameof(offset));\n            }\n        }\n\n        private ITrie GetTrie(HashDigest<SHA256>? hash)\n        {\n            ITrie trie = _stateStore.GetStateRoot(hash);\n            return trie.Recorded\n                ? trie\n                : throw new ArgumentException(\n                    $\"Could not find state root {hash} in {nameof(IStateStore)}.\",\n                    nameof(hash));\n        }\n    }\n}\n"
  },
  {
    "path": "src/Libplanet/Blockchain/BlockLocator.cs",
    "content": "using System;\nusing Libplanet.Types.Blocks;\n\nnamespace Libplanet.Blockchain\n{\n    /// <summary>\n    /// A class that thinly wraps a <see cref=\"BlockHash\"/> for the purpose of syncing blocks.\n    /// </summary>\n    public class BlockLocator : IEquatable<BlockLocator>\n    {\n        /// <summary>\n        /// Initializes a new instance of <see cref=\"BlockLocator\"/> from <paramref name=\"hash\"/>.\n        /// </summary>\n        /// <param name=\"hash\">The <see cref=\"BlockHash\"/> value to hold.</param>\n        public BlockLocator(BlockHash hash)\n        {\n            Hash = hash;\n        }\n\n        public BlockHash Hash { get; }\n\n        /// <inheritdoc/>\n        public bool Equals(BlockLocator? other) =>\n            other is { } locator && Hash.Equals(locator.Hash);\n\n        /// <inheritdoc/>\n        public override bool Equals(object? obj) =>\n            obj is BlockLocator other && Equals(other);\n\n        /// <inheritdoc/>\n        public override int GetHashCode() => Hash.GetHashCode();\n    }\n}\n"
  },
  {
    "path": "src/Libplanet/Blockchain/Branch.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Collections.Immutable;\nusing System.Linq;\nusing Libplanet.Types.Blocks;\n\nnamespace Libplanet.Blockchain\n{\n    /// <summary>\n    /// A class representing a consecutive list of <see cref=\"Block\"/>s.\n    /// </summary>\n    public class Branch\n    {\n        /// <summary>\n        /// Initializes a new instance of <see cref=\"Branch\"/> from <paramref name=\"blocks\"/>.\n        /// </summary>\n        /// <param name=\"blocks\">An enumerable of <see cref=\"Block\"/> and\n        /// <see cref=\"BlockCommit\"/> pairs to convert from.</param>\n        /// <exception cref=\"ArgumentException\">Thrown for failing to satisfy any of the following:\n        /// <list type=\"bullet\">\n        ///     <item><description>\n        ///         Given <paramref name=\"blocks\"/> is non-empty.\n        ///     </description></item>\n        ///     <item><description>\n        ///         Given <paramref name=\"blocks\"/> are consecutive in the sense that indices\n        ///         are unique, consecutive, and every <see cref=\"Block.PreviousHash\"/> match\n        ///         the <see cref=\"Block.Hash\"/> of the previous <see cref=\"Block\"/>.\n        ///     </description></item>\n        /// </list>\n        /// </exception>\n        public Branch(IEnumerable<(Block, BlockCommit?)> blocks)\n        {\n            ImmutableArray<(Block, BlockCommit?)> sorted =\n                blocks.OrderBy(block => block.Item1.Index).ToImmutableArray();\n            if (!sorted.Any())\n            {\n                throw new ArgumentException(\n                    $\"Given {nameof(blocks)} must not be empty.\", nameof(blocks));\n            }\n            else if (!sorted\n                         .Zip(\n                             sorted.Skip(1),\n                             (prev, next) =>\n                                 prev.Item1.Index + 1 == next.Item1.Index &&\n                                 prev.Item1.Hash.Equals(next.Item1.PreviousHash))\n                         .All(pred => pred))\n            {\n                throw new ArgumentException(\n                    $\"Given {nameof(blocks)} must be consecutive.\",\n                    nameof(blocks));\n            }\n\n            Blocks = sorted;\n        }\n\n        /// <summary>\n        /// An <see cref=\"ImmutableArray{T}\"/> of <see cref=\"Block\"/> and\n        /// <see cref=\"BlockCommit\"/> pairs guaranteed to satisfy\n        /// the following properties:\n        /// <list type=\"bullet\">\n        ///     <item><description>\n        ///         The collection is non-empty.\n        ///     </description></item>\n        ///     <item><description>\n        ///         The collection is sorted by index.\n        ///     </description></item>\n        ///     <item><description>\n        ///         The elements are consecutive in the sense that indices\n        ///         are unique, consecutive, and every <see cref=\"Block.PreviousHash\"/> match\n        ///         the <see cref=\"Block.Hash\"/> of the previous <see cref=\"Block\"/>.\n        ///     </description></item>\n        /// </list>\n        /// </summary>\n        public ImmutableArray<(Block, BlockCommit?)> Blocks { get; }\n    }\n}\n"
  },
  {
    "path": "src/Libplanet/Blockchain/MineBlockEventArgs.cs",
    "content": "#nullable disable\nusing Libplanet.Types.Blocks;\n\nnamespace Libplanet.Blockchain\n{\n    public class MineBlockEventArgs\n    {\n        public MineBlockEventArgs(Block block)\n        {\n            Block = block;\n        }\n\n        public Block Block { get; }\n    }\n}\n"
  },
  {
    "path": "src/Libplanet/Blockchain/Policies/BlockPolicy.cs",
    "content": "using System;\nusing System.Diagnostics.Contracts;\nusing System.Linq;\nusing Libplanet.Action;\nusing Libplanet.Blocks;\nusing Libplanet.Types.Blocks;\nusing Libplanet.Types.Evidence;\nusing Libplanet.Types.Tx;\n\nnamespace Libplanet.Blockchain.Policies\n{\n    /// <summary>\n    /// A default implementation of <see cref=\"IBlockPolicy\"/> interface.\n    /// </summary>\n    public class BlockPolicy : IBlockPolicy\n    {\n        public static readonly TimeSpan DefaultTargetBlockInterval = TimeSpan.FromSeconds(5);\n\n        private readonly Func<BlockChain, Transaction, TxPolicyViolationException?>\n            _validateNextBlockTx;\n\n        private readonly Func<BlockChain, Block, BlockPolicyViolationException?>\n            _validateNextBlock;\n\n        private readonly IPolicyActionsRegistry _policyActionsRegistry;\n        private readonly Func<long, long> _getMaxTransactionsBytes;\n        private readonly Func<long, int> _getMinTransactionsPerBlock;\n        private readonly Func<long, int> _getMaxTransactionsPerBlock;\n        private readonly Func<long, int> _getMaxTransactionsPerSignerPerBlock;\n        private readonly Func<long, long> _getMaxEvidencePendingDuration;\n\n        /// <summary>\n        /// <para>\n        /// Creates a default <see cref=\"BlockPolicy\"/> instance.\n        /// </para>\n        /// <para>\n        /// Each unprovided argument will be assigned a default value.  See each parameter\n        /// description for more detail.\n        /// </para>\n        /// </summary>\n        /// <param name=\"policyActionsRegistry\">\n        /// A class containing policy actions to evaluate at each situation.\n        /// </param>\n        /// <param name=\"blockInterval\">Goes to <see cref=\"BlockInterval\"/>.\n        /// Set to <see cref=\"DefaultTargetBlockInterval\"/> by default.\n        /// </param>\n        /// <param name=\"validateNextBlockTx\">The predicate that determines if\n        /// a <see cref=\"Transaction\"/> follows the policy.  Set to a constant function of\n        /// <see langword=\"null\"/> by default.</param>\n        /// <param name=\"validateNextBlock\">The predicate that determines if\n        /// a <see cref=\"Block\"/> follows the policy.  Set to a default implementation\n        /// where block's hash algorithm type, bytes count, and transactions count are validated.\n        /// </param>\n        /// <param name=\"getMaxTransactionsBytes\">The function determining the maximum size of\n        /// <see cref=\"Block.Transactions\"/> in number of <c>byte</c>s given\n        /// its <see cref=\"Block.Index\"/>.  Goes to <see cref=\"GetMaxTransactionsBytes\"/>.\n        /// Set to a constant size of <c>100</c>KiB, i.e. <c>100 * 1024</c>, by default.</param>\n        /// <param name=\"getMinTransactionsPerBlock\">The function determining the minimum number of\n        /// <see cref=\"Transaction\"/>s that must be included in a <see cref=\"Block\"/>.\n        /// Goes to <see cref=\"GetMinTransactionsPerBlock\"/>.  Set to a constant function\n        /// of <c>0</c> by default.</param>\n        /// <param name=\"getMaxTransactionsPerBlock\">The function determining how many\n        /// <see cref=\"Transaction\"/>s can be included in a <see cref=\"Block\"/>.\n        /// Goes to <see cref=\"GetMaxTransactionsPerBlock\"/>.  Set to a constant function\n        /// of <c>100</c> by default.</param>\n        /// <param name=\"getMaxTransactionsPerSignerPerBlock\">The function determining the maximum\n        /// number of transactions from the same signer that can be included in\n        /// a <see cref=\"Block\"/> given the <see cref=\"Block\"/>'s index.\n        /// Goes to <see cref=\"GetMaxTransactionsPerSignerPerBlock\"/>.  Set to\n        /// <see cref=\"GetMaxTransactionsPerBlock\"/> by default.</param>\n        /// <param name=\"getMaxEvidencePendingDuration\">The function determining the maximum\n        /// pending duration of <see cref=\"EvidenceBase\"/> to be committed.\n        /// Goes to <see cref=\"GetMaxEvidencePendingDuration\"/>.  Set to a constant function\n        /// of <c>10</c> by default.</param>\n        public BlockPolicy(\n            IPolicyActionsRegistry? policyActionsRegistry = null,\n            TimeSpan? blockInterval = null,\n            Func<BlockChain, Transaction, TxPolicyViolationException?>?\n                validateNextBlockTx = null,\n            Func<BlockChain, Block, BlockPolicyViolationException?>?\n                validateNextBlock = null,\n            Func<long, long>? getMaxTransactionsBytes = null,\n            Func<long, int>? getMinTransactionsPerBlock = null,\n            Func<long, int>? getMaxTransactionsPerBlock = null,\n            Func<long, int>? getMaxTransactionsPerSignerPerBlock = null,\n            Func<long, long>? getMaxEvidencePendingDuration = null)\n        {\n            _policyActionsRegistry = policyActionsRegistry ?? new PolicyActionsRegistry();\n            BlockInterval = blockInterval ?? DefaultTargetBlockInterval;\n            _getMaxTransactionsBytes = getMaxTransactionsBytes ?? (_ => 100L * 1024L);\n            _getMinTransactionsPerBlock = getMinTransactionsPerBlock ?? (_ => 0);\n            _getMaxTransactionsPerBlock = getMaxTransactionsPerBlock ?? (_ => 100);\n            _getMaxTransactionsPerSignerPerBlock = getMaxTransactionsPerSignerPerBlock\n                ?? GetMaxTransactionsPerBlock;\n            _getMaxEvidencePendingDuration = getMaxEvidencePendingDuration ?? (_ => 10L);\n\n            _validateNextBlockTx = validateNextBlockTx ?? ((_, __) => null);\n            if (validateNextBlock is { } vnb)\n            {\n                _validateNextBlock = vnb;\n            }\n            else\n            {\n                _validateNextBlock = (blockchain, block) =>\n                {\n                    long maxTransactionsBytes = GetMaxTransactionsBytes(block.Index);\n                    int minTransactionsPerBlock = GetMinTransactionsPerBlock(block.Index);\n                    int maxTransactionsPerBlock = GetMaxTransactionsPerBlock(block.Index);\n                    int maxTransactionsPerSignerPerBlock =\n                        GetMaxTransactionsPerSignerPerBlock(block.Index);\n                    long maxEvidencePendingDuration = GetMaxEvidencePendingDuration(block.Index);\n\n                    long blockBytes = BlockMarshaler.MarshalTransactions(block.Transactions)\n                        .EncodingLength;\n                    if (blockBytes > maxTransactionsBytes)\n                    {\n                        return new InvalidBlockBytesLengthException(\n                            $\"The size of block #{block.Index} {block.Hash} is too large where \" +\n                            $\"the maximum number of bytes allowed is {maxTransactionsBytes}: \" +\n                            $\"{blockBytes}.\",\n                            blockBytes\n                        );\n                    }\n                    else if (block.Transactions.Count < minTransactionsPerBlock)\n                    {\n                        return new InvalidBlockTxCountException(\n                            $\"Block #{block.Index} {block.Hash} should include \" +\n                            $\"at least {minTransactionsPerBlock} transaction(s): \" +\n                            $\"{block.Transactions.Count}\",\n                            block.Transactions.Count);\n                    }\n                    else if (block.Transactions.Count > maxTransactionsPerBlock)\n                    {\n                        return new InvalidBlockTxCountException(\n                            $\"Block #{block.Index} {block.Hash} should include \" +\n                            $\"at most {maxTransactionsPerBlock} transaction(s): \" +\n                            $\"{block.Transactions.Count}\",\n                            block.Transactions.Count);\n                    }\n                    else\n                    {\n                        var groups = block.Transactions\n                            .GroupBy(tx => tx.Signer)\n                            .Where(group => group.Count() > maxTransactionsPerSignerPerBlock);\n                        if (groups.FirstOrDefault() is { } offendingGroup)\n                        {\n                            int offendingGroupCount = offendingGroup.Count();\n                            return new InvalidBlockTxCountPerSignerException(\n                                $\"Block #{block.Index} {block.Hash} includes too many \" +\n                                $\"transactions from signer {offendingGroup.Key} where \" +\n                                $\"the maximum number of transactions allowed by a single signer \" +\n                                $\"per block is {maxTransactionsPerSignerPerBlock}: \" +\n                                $\"{offendingGroupCount}\",\n                                offendingGroup.Key,\n                                offendingGroupCount);\n                        }\n                    }\n\n                    long evidenceExpirationHeight = block.Index - maxEvidencePendingDuration;\n                    if (block.Evidence.Any(evidence => evidence.Height < evidenceExpirationHeight))\n                    {\n                        return new InvalidBlockEvidencePendingDurationException(\n                            $\"Block #{block.Index} {block.Hash} includes evidence\" +\n                            $\"that is older than expiration height {evidenceExpirationHeight}\");\n                    }\n\n                    return null;\n                };\n            }\n        }\n\n        public IPolicyActionsRegistry PolicyActionsRegistry => _policyActionsRegistry;\n\n        /// <summary>\n        /// Targeted time interval between two consecutive <see cref=\"Block\"/>s.\n        /// </summary>\n        public TimeSpan BlockInterval { get; }\n\n        /// <inheritdoc/>\n        public virtual TxPolicyViolationException? ValidateNextBlockTx(\n            BlockChain blockChain, Transaction transaction)\n        {\n            return _validateNextBlockTx(blockChain, transaction);\n        }\n\n        /// <inheritdoc/>\n        public virtual BlockPolicyViolationException? ValidateNextBlock(\n            BlockChain blockChain,\n            Block nextBlock)\n        {\n            return _validateNextBlock(blockChain, nextBlock);\n        }\n\n        /// <inheritdoc/>\n        [Pure]\n        public long GetMaxTransactionsBytes(long index) => _getMaxTransactionsBytes(index);\n\n        /// <inheritdoc/>\n        [Pure]\n        public int GetMinTransactionsPerBlock(long index) => _getMinTransactionsPerBlock(index);\n\n        /// <inheritdoc/>\n        [Pure]\n        public int GetMaxTransactionsPerBlock(long index) => _getMaxTransactionsPerBlock(index);\n\n        /// <inheritdoc/>\n        [Pure]\n        public int GetMaxTransactionsPerSignerPerBlock(long index)\n            => _getMaxTransactionsPerSignerPerBlock(index);\n\n        /// <inheritdoc/>\n        [Pure]\n        public long GetMaxEvidencePendingDuration(long index)\n            => _getMaxEvidencePendingDuration(index);\n    }\n}\n"
  },
  {
    "path": "src/Libplanet/Blockchain/Policies/IBlockPolicy.cs",
    "content": "using System.Diagnostics.Contracts;\nusing Libplanet.Action;\nusing Libplanet.Types.Blocks;\nusing Libplanet.Types.Evidence;\nusing Libplanet.Types.Tx;\n\nnamespace Libplanet.Blockchain.Policies\n{\n    /// <summary>\n    /// <para>\n    /// An interface to determine if consecutive <see cref=\"Block\"/>s are valid.\n    /// </para>\n    /// <para>\n    /// An implementation of this interface should perform <em>all policy dependent checks</em>,\n    /// such as whether a <see cref=\"Block\"/> has the right difficulty,\n    /// a <see cref=\"Transaction\"/> has the right signer, etc.\n    /// </para>\n    /// <para>\n    /// Note that all index dependent sub-policies are ignored for genesis <see cref=\"Block\"/>s.\n    /// </para>\n    /// </summary>\n    public interface IBlockPolicy\n    {\n        /// <summary>\n        /// A set of policy <see cref=\"IAction\"/>s to evaluate at each situation.\n        /// </summary>\n        IPolicyActionsRegistry PolicyActionsRegistry { get; }\n\n        /// <summary>\n        /// Checks if a <see cref=\"Transaction\"/> can be included in a yet to be mined\n        /// <see cref=\"Block\"/> that can be appended to the given <see cref=\"BlockChain\"/>.\n        /// </summary>\n        /// <param name=\"blockChain\">The target <see cref=\"BlockChain\"/> to include\n        /// given <paramref name=\"transaction\"/>.</param>\n        /// <param name=\"transaction\">The <see cref=\"Transaction\"/> to consider.</param>\n        /// <returns>A <see cref=\"TxPolicyViolationException\"/> with a description\n        /// as to why given <paramref name=\"transaction\"/> is <em>invalid</em>,\n        /// or <see langword=\"null\"/> if <paramref name=\"transaction\"/> is <em>valid</em>.</returns>\n        /// <remarks>\n        /// This is used in two different cases:\n        /// <list type=\"bullet\">\n        /// <item>\n        ///     <description>When selecting which <see cref=\"Transaction\"/> to include\n        ///     when mining a next <see cref=\"Block\"/>.</description>\n        /// </item>\n        /// <item>\n        ///     <description>When appending a <see cref=\"Block\"/>\n        ///     with <paramref name=\"transaction\"/> to a <see cref=\"BlockChain\"/>.</description>\n        /// </item>\n        /// </list>\n        /// This is called separately from <see cref=\"ValidateNextBlock\"/> from\n        /// a <see cref=\"BlockChain\"/>.\n        /// </remarks>\n        TxPolicyViolationException? ValidateNextBlockTx(\n            BlockChain blockChain, Transaction transaction);\n\n        /// <summary>\n        /// Checks if a <see cref=\"Block\"/> can be appended to\n        /// the given <see cref=\"BlockChain\"/>.\n        /// </summary>\n        /// <param name=\"blockChain\">The target <see cref=\"BlockChain\"/> to\n        /// append <paramref name=\"nextBlock\"/>.</param>\n        /// <param name=\"nextBlock\">The next block to append to\n        /// <paramref name=\"blockChain\"/>.</param>\n        /// <returns>A <see cref=\"BlockPolicyViolationException\"/> with a description\n        /// as to why given <paramref name=\"nextBlock\"/> is <em>invalid</em>,\n        /// or <see langword=\"null\"/> if <paramref name=\"nextBlock\"/> is <em>valid</em>.</returns>\n        /// <remarks>\n        /// Note that <see cref=\"ValidateNextBlockTx\"/> will be called separately from\n        /// a <see cref=\"BlockChain\"/> when appending a <see cref=\"Block\"/>.\n        /// Hence, to reduce redundancy, an implementation of this interface should not\n        /// call <see cref=\"ValidateNextBlockTx\"/>.\n        /// </remarks>\n        BlockPolicyViolationException? ValidateNextBlock(\n            BlockChain blockChain, Block nextBlock);\n\n        /// <summary>\n        /// Gets the maximum length of <see cref=\"Block.Transactions\"/> in bytes.\n        /// </summary>\n        /// <param name=\"index\">The <see cref=\"Block.Index\"/> of the <see cref=\"Block\"/>\n        /// for which this constraint should apply.</param>\n        /// <returns>The maximum length of <see cref=\"Block.Transactions\"/> in bytes\n        /// to accept.</returns>\n        long GetMaxTransactionsBytes(long index);\n\n        /// <summary>\n        /// Gets the minimum number of <see cref=\"Transaction\"/>s allowed for\n        /// a valid <see cref=\"Block\"/>.\n        /// </summary>\n        /// <param name=\"index\">The <see cref=\"Block.Index\"/> of the <see cref=\"Block\"/>\n        /// for which this constraint should apply.</param>\n        /// <returns>The minimum number of <see cref=\"Transaction\"/>s allowed for\n        /// a valid <see cref=\"Block\"/> can accept.</returns>\n        [Pure]\n        int GetMinTransactionsPerBlock(long index);\n\n        /// <summary>\n        /// Gets the maximum number of <see cref=\"Transaction\"/>s allowed for\n        /// a valid <see cref=\"Block\"/>.\n        /// </summary>\n        /// <param name=\"index\">The <see cref=\"Block.Index\"/> of the <see cref=\"Block\"/>\n        /// for which this constraint should apply.</param>\n        /// <returns>The maximum number of <see cref=\"Transaction\"/>s allowed for\n        /// a valid <see cref=\"Block\"/> can accept.</returns>\n        [Pure]\n        int GetMaxTransactionsPerBlock(long index);\n\n        /// <summary>\n        /// Gets the maximum number of <see cref=\"Transaction\"/>s allowed per signer for\n        /// a valid <see cref=\"Block\"/>.\n        /// </summary>\n        /// <param name=\"index\">The <see cref=\"Block.Index\"/> of the <see cref=\"Block\"/>\n        /// for which this constraint should apply.</param>\n        /// <returns>The maximum number of <see cref=\"Transaction\"/>s allowed per signer for\n        /// a valid <see cref=\"Block\"/> can accept.</returns>\n        [Pure]\n        int GetMaxTransactionsPerSignerPerBlock(long index);\n\n        /// <summary>\n        /// Gets the maximum duration of <see cref=\"EvidenceBase\"/> before to be committed.\n        /// </summary>\n        /// <param name=\"index\">The <see cref=\"Block.Index\"/> of the <see cref=\"Block\"/>\n        /// for which this constraint should apply.</param>\n        /// <returns>The maximum duration of <see cref=\"EvidenceBase\"/>s before to be committed.\n        /// </returns>\n        [Pure]\n        long GetMaxEvidencePendingDuration(long index);\n    }\n}\n"
  },
  {
    "path": "src/Libplanet/Blockchain/Policies/IStagePolicy.cs",
    "content": "using System.Collections.Generic;\nusing Libplanet.Crypto;\nusing Libplanet.Types.Tx;\n\nnamespace Libplanet.Blockchain.Policies\n{\n    /// <summary>\n    /// An interface to configure a <see cref=\"BlockChain\"/>'s strategy to deal with staged\n    /// transactions.\n    /// </summary>\n    /// <remarks>\n    /// Every operation of an implementation of this <c>interface</c> must be thread-safe.\n    /// </remarks>\n    public interface IStagePolicy\n    {\n        /// <summary>\n        /// Stages a <paramref name=\"transaction\"/>.\n        /// </summary>\n        /// <param name=\"blockChain\">The <see cref=\"BlockChain\"/> that the stage belongs to.\n        /// </param>\n        /// <param name=\"transaction\">The <seealso cref=\"Transaction\"/> to be staged.</param>\n        /// <returns><see langword=\"true\"/> if staging was successful,\n        /// <see langword=\"false\"/> otherwise.</returns>\n        /// <remarks>\n        /// <para>\n        /// This does not throw any exception regardless of whether <paramref name=\"transaction\"/>\n        /// was successfully staged or not.\n        /// </para>\n        /// <para>\n        /// If the <see cref=\"Transaction.Id\"/> of <paramref name=\"transaction\"/> is marked\n        /// as ignored, <paramref name=\"transaction\"/> will not be staged.\n        /// </para>\n        /// </remarks>\n        public bool Stage(BlockChain blockChain, Transaction transaction);\n\n        /// <summary>\n        /// Unstages a transaction <paramref name=\"id\"/>.\n        /// </summary>\n        /// <param name=\"blockChain\">The <see cref=\"BlockChain\"/> that the stage belongs to.\n        /// </param>\n        /// <param name=\"id\">The <seealso cref=\"Transaction.Id\"/> to unstage.</param>\n        /// <returns><see langword=\"true\"/> if unstaging was successful,\n        /// <see langword=\"false\"/> otherwise.</returns>\n        /// <remarks>\n        /// This does not throw any exception regardless of whether <paramref name=\"id\"/> was\n        /// successfully unstaged or not.\n        /// </remarks>\n        public bool Unstage(BlockChain blockChain, TxId id);\n\n        /// <summary>\n        /// Marks given <paramref name=\"id\"/> as ignored.\n        /// </summary>\n        /// <param name=\"blockChain\">The <see cref=\"BlockChain\"/> that the stage belongs to.\n        /// </param>\n        /// <param name=\"id\">The <see cref=\"Transaction.Id\"/> to ignore.</param>\n        /// <remarks>\n        /// If the <see cref=\"Transaction\"/> associated with <paramref name=\"id\"/> is already\n        /// staged, this also unstages the <see cref=\"Transaction\"/>.\n        /// </remarks>\n        public void Ignore(BlockChain blockChain, TxId id);\n\n        /// <summary>\n        /// Checks if given <paramref name=\"id\"/> is marked as ignored.\n        /// </summary>\n        /// <param name=\"blockChain\">The <see cref=\"BlockChain\"/> that the stage belongs to.\n        /// </param>\n        /// <param name=\"id\">The <see cref=\"Transaction.Id\"/> to check.</param>\n        /// <returns><see langword=\"true\"/> if <paramref name=\"id\"/> is marked as ignored,\n        /// <see langword=\"false\"/> otherwise.</returns>\n        public bool Ignores(BlockChain blockChain, TxId id);\n\n        /// <summary>\n        /// Retrieves a staged <see cref=\"Transaction\"/> by its <paramref name=\"id\"/>.\n        /// </summary>\n        /// <param name=\"blockChain\">The <see cref=\"BlockChain\"/> that the stage belongs to.\n        /// </param>\n        /// <param name=\"id\">The <see cref=\"Transaction.Id\"/> to get.</param>\n        /// <param name=\"filtered\">Whether to filter masked staged <see cref=\"Transaction\"/>s\n        /// or not.  Set to <see langword=\"true\"/> by default.</param>\n        /// <returns>The staged <see cref=\"Transaction\"/> associated with <paramref name=\"id\"/>\n        /// if found,  <see langword=\"null\"/> otherwise.</returns>\n        public Transaction? Get(BlockChain blockChain, TxId id, bool filtered = true);\n\n        /// <summary>\n        /// Enumerates all staged <see cref=\"Transaction\"/>s.\n        /// </summary>\n        /// <param name=\"blockChain\">The <see cref=\"BlockChain\"/> that the stage belongs to.\n        /// </param>\n        /// <param name=\"filtered\">Whether to filter masked staged <see cref=\"Transaction\"/>s\n        /// or not.  Set to <see langword=\"true\"/> by default.</param>\n        /// <returns>All staged transactions.  No ordering is guaranteed.</returns>\n        public IEnumerable<Transaction> Iterate(BlockChain blockChain, bool filtered = true);\n\n        /// <summary>\n        /// Calculates the next nonce according for given <paramref name=\"address\"/>.\n        /// </summary>\n        /// <param name=\"blockChain\">The <see cref=\"BlockChain\"/> that the stage belongs to.\n        /// </param>\n        /// <param name=\"address\">The <see cref=\"Address\"/> to calculate the next nonce for.\n        /// </param>\n        /// <returns>The next appropriate nonce for <paramref name=\"address\"/>.</returns>\n        public long GetNextTxNonce(BlockChain blockChain, Address address);\n    }\n}\n"
  },
  {
    "path": "src/Libplanet/Blockchain/Policies/NullBlockPolicy.cs",
    "content": "#nullable disable\nusing System;\nusing System.Collections.Generic;\nusing System.Collections.Immutable;\nusing Libplanet.Action;\nusing Libplanet.Crypto;\nusing Libplanet.Types.Blocks;\nusing Libplanet.Types.Tx;\n\nnamespace Libplanet.Blockchain.Policies\n{\n    public class NullBlockPolicy : IBlockPolicy\n    {\n        private readonly BlockPolicyViolationException _exceptionToThrow;\n\n        public NullBlockPolicy(\n            BlockPolicyViolationException exceptionToThrow = null)\n        {\n            _exceptionToThrow = exceptionToThrow;\n        }\n\n        public ISet<Address> BlockedMiners { get; } = new HashSet<Address>();\n\n        public IPolicyActionsRegistry PolicyActionsRegistry => new PolicyActionsRegistry();\n\n        public ImmutableArray<IAction> BeginBlockActions => ImmutableArray<IAction>.Empty;\n\n        public ImmutableArray<IAction> EndBlockActions => ImmutableArray<IAction>.Empty;\n\n        public ImmutableArray<IAction> BeginTxActions => ImmutableArray<IAction>.Empty;\n\n        public ImmutableArray<IAction> EndTxActions => ImmutableArray<IAction>.Empty;\n\n        public int GetMinTransactionsPerBlock(long index) => 0;\n\n        public int GetMaxTransactionsPerBlock(long index) => int.MaxValue;\n\n        public virtual TxPolicyViolationException ValidateNextBlockTx(\n            BlockChain blockChain, Transaction transaction) => null;\n\n        public virtual BlockPolicyViolationException ValidateNextBlock(\n            BlockChain blockChain,\n            Block nextBlock\n        )\n        {\n            if (_exceptionToThrow != null)\n            {\n                return _exceptionToThrow;\n            }\n\n            return BlockedMiners.Contains(nextBlock.Miner)\n                ? new BlockPolicyViolationException(\n                    $\"Disallowed #{nextBlock.Index} {nextBlock.Hash} mined by {nextBlock.Miner}.\")\n                : null;\n        }\n\n        public long GetMaxTransactionsBytes(long index) => 1024 * 1024;\n\n        public int GetMaxTransactionsPerSignerPerBlock(long index) =>\n            GetMaxTransactionsPerBlock(index);\n\n        public long GetMaxEvidencePendingDuration(long index) => 10L;\n    }\n}\n"
  },
  {
    "path": "src/Libplanet/Blockchain/Policies/VolatileStagePolicy.cs",
    "content": "using System;\nusing System.Collections.Concurrent;\nusing System.Collections.Generic;\nusing System.Globalization;\nusing System.Linq;\nusing System.Threading;\nusing Libplanet.Crypto;\nusing Libplanet.Types.Tx;\nusing Serilog;\n\nnamespace Libplanet.Blockchain.Policies\n{\n    /// <summary>\n    /// <para>\n    /// An in memory implementation of the <see cref=\"IStagePolicy\"/>.\n    /// </para>\n    /// <para>\n    /// This implementation holds on to every unconfirmed <see cref=\"Transaction\"/> except\n    /// for the following reasons:\n    /// <list type=\"bullet\">\n    ///     <item>\n    ///         <description>A <see cref=\"Transaction\"/> has been specifically marked to\n    ///         be ignored due to <see cref=\"Transaction\"/> not being valid.</description>\n    ///     </item>\n    ///     <item>\n    ///         <description>A <see cref=\"Transaction\"/> has expired due to its staleness.\n    ///         </description>\n    ///     </item>\n    /// </list>\n    /// </para>\n    /// <para>\n    /// Additionally, any <see cref=\"Transaction\"/> with a lower nonce than that of returned by\n    /// the <see cref=\"BlockChain\"/> is masked and filtered by default.\n    /// </para>\n    /// </summary>\n    public class VolatileStagePolicy : IStagePolicy\n    {\n        private readonly ConcurrentDictionary<TxId, Transaction> _staged;\n        private readonly HashSet<TxId> _ignored;\n        private readonly ReaderWriterLockSlim _lock;\n        private readonly ILogger _logger;\n\n        /// <summary>\n        /// Creates a new <see cref=\"VolatileStagePolicy\"/> instance.\n        /// By default, <see cref=\"Lifetime\"/> is set to 10 minutes.\n        /// </summary>\n        public VolatileStagePolicy()\n            : this(TimeSpan.FromSeconds(10 * 60))\n        {\n        }\n\n        /// <summary>\n        /// Creates a new <see cref=\"VolatileStagePolicy\"/> instance.\n        /// </summary>\n        /// <param name=\"lifetime\">Volatilizes staged transactions older than this\n        /// <see cref=\"TimeSpan\"/>.  See also <see cref=\"Lifetime\"/>.</param>\n        public VolatileStagePolicy(TimeSpan lifetime)\n        {\n            _logger = Log\n                .ForContext<VolatileStagePolicy>()\n                .ForContext(\"Source\", nameof(VolatileStagePolicy));\n            Lifetime = lifetime;\n            _staged = new ConcurrentDictionary<TxId, Transaction>();\n            _ignored = new HashSet<TxId>();\n            _lock = new ReaderWriterLockSlim(LockRecursionPolicy.NoRecursion);\n        }\n\n        /// <summary>\n        /// Lifespan for <see cref=\"Transaction\"/>s.  Any <see cref=\"Transaction\"/> older\n        /// than this <see cref=\"TimeSpan\"/> will be considered expired.\n        /// </summary>\n        /// <remarks>\n        /// Expired <see cref=\"Transaction\"/>s cannot be staged.\n        /// </remarks>\n        public TimeSpan Lifetime { get; }\n\n        /// <inheritdoc/>\n        public bool Stage(BlockChain blockChain, Transaction transaction)\n        {\n            if (Expired(transaction))\n            {\n                return false;\n            }\n\n            bool result;\n            _lock.EnterUpgradeableReadLock();\n            try\n            {\n                if (_ignored.Contains(transaction.Id))\n                {\n                    return false;\n                }\n                else\n                {\n                    _lock.EnterWriteLock();\n                    try\n                    {\n                        result = _staged.TryAdd(transaction.Id, transaction);\n                        if (result)\n                        {\n                            const string TimestampFormat = \"yyyy-MM-ddTHH:mm:ss.ffffffZ\";\n                            _logger\n                                .ForContext(\"Tag\", \"Metric\")\n                                .ForContext(\"Subtag\", \"TxStageTimestamp\")\n                                .Information(\n                                    \"Transaction {TxId} by {Signer} \" +\n                                    \"with timestamp {TxTimestamp} staged at {StagedTimestamp}\",\n                                    transaction.Id,\n                                    transaction.Signer,\n                                    transaction.Timestamp.ToString(\n                                        TimestampFormat, CultureInfo.InvariantCulture),\n                                    DateTimeOffset.UtcNow.ToString(\n                                        TimestampFormat, CultureInfo.InvariantCulture));\n                            _logger\n                                .ForContext(\"Tag\", \"Metric\")\n                                .ForContext(\"Subtag\", \"StagedCount\")\n                                .Information(\n                                    \"There are {Count} transactions staged\",\n                                    _staged.Count);\n                        }\n                    }\n                    finally\n                    {\n                        _lock.ExitWriteLock();\n                    }\n                }\n            }\n            finally\n            {\n                _lock.ExitUpgradeableReadLock();\n            }\n\n            return result;\n        }\n\n        /// <inheritdoc/>\n        public bool Unstage(BlockChain blockChain, TxId id)\n        {\n            bool result;\n            _lock.EnterWriteLock();\n            try\n            {\n                result = _staged.TryRemove(id, out _);\n            }\n            finally\n            {\n                _lock.ExitWriteLock();\n            }\n\n            return result;\n        }\n\n        /// <inheritdoc/>\n        public void Ignore(BlockChain blockChain, TxId id)\n        {\n            _lock.EnterUpgradeableReadLock();\n            try\n            {\n                if (_ignored.Contains(id))\n                {\n                    return;\n                }\n\n                _lock.EnterWriteLock();\n                try\n                {\n                    _ignored.Add(id);\n                    _logger.Information(\n                        \"Transaction {TxId} is marked as ignored\",\n                        id);\n                }\n                finally\n                {\n                    _lock.ExitWriteLock();\n                }\n            }\n            finally\n            {\n                _lock.ExitUpgradeableReadLock();\n            }\n        }\n\n        /// <inheritdoc/>\n        public bool Ignores(BlockChain blockChain, TxId id)\n        {\n            _lock.EnterReadLock();\n            try\n            {\n                return _ignored.Contains(id);\n            }\n            finally\n            {\n                _lock.ExitReadLock();\n            }\n        }\n\n        /// <inheritdoc/>\n        public Transaction? Get(BlockChain blockChain, TxId id, bool filtered = true)\n        {\n            _lock.EnterReadLock();\n            try\n            {\n                return GetInner(blockChain, id, filtered);\n            }\n            finally\n            {\n                _lock.ExitReadLock();\n            }\n        }\n\n        /// <inheritdoc/>\n        public IEnumerable<Transaction> Iterate(BlockChain blockChain, bool filtered = true)\n        {\n            List<Transaction> transactions = new List<Transaction>();\n\n            _lock.EnterReadLock();\n            try\n            {\n                List<TxId> txIds = _staged.Keys.ToList();\n                foreach (TxId txId in txIds)\n                {\n                    if (GetInner(blockChain, txId, filtered) is Transaction tx)\n                    {\n                        transactions.Add(tx);\n                    }\n                }\n            }\n            finally\n            {\n                _lock.ExitReadLock();\n            }\n\n            return transactions;\n        }\n\n        /// <inheritdoc/>\n        public long GetNextTxNonce(BlockChain blockChain, Address address)\n        {\n            long nonce = blockChain.Store.GetTxNonce(blockChain.Id, address);\n            IEnumerable<Transaction> orderedTxs = Iterate(blockChain, filtered: true)\n                .Where(tx => tx.Signer.Equals(address))\n                .OrderBy(tx => tx.Nonce);\n\n            foreach (Transaction tx in orderedTxs)\n            {\n                if (nonce < tx.Nonce)\n                {\n                    break;\n                }\n                else if (nonce == tx.Nonce)\n                {\n                    nonce++;\n                }\n            }\n\n            return nonce;\n        }\n\n        private bool Expired(Transaction transaction) =>\n            Lifetime < DateTimeOffset.UtcNow - transaction.Timestamp;\n\n        /// <remarks>\n        /// It has been intended to avoid recursive lock, hence doesn't hold any synchronous scope.\n        /// Therefore, we should manage the lock from its caller side.\n        /// </remarks>\n        private Transaction? GetInner(BlockChain blockChain, TxId id, bool filtered)\n        {\n            if (_staged.TryGetValue(id, out Transaction? tx) && tx is { })\n            {\n                if (Expired(tx) || _ignored.Contains(tx.Id))\n                {\n                    _staged.TryRemove(id, out _);\n                    return null;\n                }\n                else if (filtered)\n                {\n                    return blockChain.Store.GetTxNonce(blockChain.Id, tx.Signer) <= tx.Nonce\n                        ? tx\n                        : null;\n                }\n                else\n                {\n                    return tx;\n                }\n            }\n            else\n            {\n                return null;\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/Libplanet/Blockchain/Renderers/AnonymousActionRenderer.cs",
    "content": "using System;\nusing System.Security.Cryptography;\nusing Bencodex.Types;\nusing Libplanet.Action;\nusing Libplanet.Common;\nusing Libplanet.Types.Blocks;\n\nnamespace Libplanet.Blockchain.Renderers\n{\n    /// <summary>\n    /// An <see cref=\"IActionRenderer\"/> that invokes its callbacks.\n    /// In other words, this is an <see cref=\"IActionRenderer\"/> version of\n    /// <see cref=\"AnonymousRenderer\"/>.\n    /// <para>This class is useful when you want an one-use ad-hoc implementation (i.e., Java-style\n    /// anonymous class) of <see cref=\"IActionRenderer\"/> interface.</para>\n    /// </summary>\n    /// <example>\n    /// With object initializers, you can easily make an one-use action renderer:\n    /// <code><![CDATA[\n    /// var actionRenderer = new AnonymousActionRenderer\n    /// {\n    ///     ActionRenderer = (action, context, nextState) =>\n    ///     {\n    ///         // Implement RenderAction() here.\n    ///     };\n    /// };\n    /// ]]></code>\n    /// </example>\n    public sealed class AnonymousActionRenderer : AnonymousRenderer, IActionRenderer\n    {\n        /// <summary>\n        /// A callback function to be invoked together with\n        /// <see cref=\"RenderAction(IValue, ICommittedActionContext, HashDigest{SHA256})\"/>.\n        /// </summary>\n        public Action<IValue, ICommittedActionContext, HashDigest<SHA256>>? ActionRenderer\n            { get; set; }\n\n        /// <summary>\n        /// A callback function to be invoked together with\n        /// <see cref=\"RenderActionError(IValue, ICommittedActionContext, Exception)\"/>.\n        /// </summary>\n        public Action<IValue, ICommittedActionContext, Exception>? ActionErrorRenderer { get; set; }\n\n        /// <summary>\n        /// A callback function to be invoked together with\n        /// <see cref=\"RenderBlockEnd(Block, Block)\"/>.\n        /// </summary>\n        public Action<Block, Block>? BlockEndRenderer { get; set; }\n\n        /// <inheritdoc cref=\"IActionRenderer.RenderAction\"/>\n        public void RenderAction(\n            IValue action,\n            ICommittedActionContext context,\n            HashDigest<SHA256> nextState\n        ) =>\n            ActionRenderer?.Invoke(action, context, nextState);\n\n        /// <inheritdoc\n        /// cref=\"IActionRenderer.RenderActionError(IValue, ICommittedActionContext, Exception)\"/>\n        public void RenderActionError(\n            IValue action,\n            ICommittedActionContext context,\n            Exception exception) =>\n                ActionErrorRenderer?.Invoke(action, context, exception);\n\n        /// <inheritdoc cref=\"IActionRenderer.RenderBlockEnd(Block, Block)\"/>\n        public void RenderBlockEnd(Block oldTip, Block newTip) =>\n            BlockEndRenderer?.Invoke(oldTip, newTip);\n    }\n}\n"
  },
  {
    "path": "src/Libplanet/Blockchain/Renderers/AnonymousRenderer.cs",
    "content": "using System;\nusing Libplanet.Types.Blocks;\n\nnamespace Libplanet.Blockchain.Renderers\n{\n    /// <summary>\n    /// A renderer that invokes its callbacks.\n    /// <para>This class is useful when you want an one-use ad-hoc implementation (i.e., Java-style\n    /// anonymous class) of <see cref=\"IRenderer\"/> interface.</para>\n    /// </summary>\n    /// <example>\n    /// With object initializers, you can easily make an one-use renderer:\n    /// <code>\n    /// var renderer = new AnonymousRenderer;\n    /// {\n    ///     BlockRenderer = (oldTip, newTip) =>\n    ///     {\n    ///         // Implement RenderBlock() here.\n    ///     };\n    /// };\n    /// </code>\n    /// </example>\n    public class AnonymousRenderer : IRenderer\n    {\n        /// <summary>\n        /// A callback function to be invoked together with\n        /// <see cref=\"RenderBlock(Block, Block)\"/>.\n        /// </summary>\n        public Action<Block, Block>? BlockRenderer { get; set; }\n\n        /// <inheritdoc cref=\"IRenderer.RenderBlock(Block, Block)\"/>\n        public void RenderBlock(Block oldTip, Block newTip) =>\n            BlockRenderer?.Invoke(oldTip, newTip);\n    }\n}\n"
  },
  {
    "path": "src/Libplanet/Blockchain/Renderers/Debug/InvalidRenderException.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Linq;\n\nnamespace Libplanet.Blockchain.Renderers.Debug\n{\n    /// <summary>\n    /// Exception thrown by <see cref=\"ValidatingActionRenderer\"/>.\n    /// </summary>\n    public class InvalidRenderException : Exception\n    {\n        /// <summary>\n        /// Creates a new <see cref=\"ValidatingActionRenderer\"/> instance.\n        /// </summary>\n        /// <param name=\"message\">The exception message string.</param>\n        /// <param name=\"records\">Recorded render events.</param>\n        public InvalidRenderException(\n            string message,\n            IReadOnlyList<RenderRecord> records\n        )\n            : base(message)\n        {\n            Records = records;\n        }\n\n        /// <summary>\n        /// Recorded render events.\n        /// </summary>\n        public IReadOnlyList<RenderRecord> Records { get; }\n\n        /// <inheritdoc cref=\"Exception.Message\"/>\n        public override string Message\n        {\n            get\n            {\n                string MakeCompact(string stackTrace)\n                {\n                    int pos = 0;\n                    for (int i = 0; pos >= 0 && i < 10; i++)\n                    {\n                        pos = stackTrace.IndexOf('\\n', pos + 1);\n                    }\n\n                    return pos < 0\n                        ? stackTrace\n                        : stackTrace.Substring(0, pos);\n                }\n\n                string pre = base.Message;\n                if (Records.Count < 1)\n                {\n                    return pre + \"\\n(0 records.)\";\n                }\n\n                RenderRecord first = Records[Records.Count - 1];\n                var firstLine = $\"{pre}\\n{first}\";\n                if (Records.Count < 2)\n                {\n                    return $\"{firstLine}\\n{MakeCompact(first.StackTrace)}\\n(1 record.)\";\n                }\n\n                // Find common postfix\n                string firstTrace = first.StackTrace;\n                int commonPostfix = 0;\n                for (int i = 0, end = Records.Min(r => r.StackTrace.Length); i < end; i++)\n                {\n                    char charInFirst = firstTrace[firstTrace.Length - (i + 1)];\n                    bool allEqual = Records.Skip(1).All(r =>\n                    {\n                        string stackTrace = r.StackTrace;\n                        char charFromEnd = stackTrace[stackTrace.Length - (i + 1)];\n                        return charFromEnd.Equals(charInFirst);\n                    });\n\n                    if (!allEqual)\n                    {\n                        commonPostfix = i;\n                        break;\n                    }\n                }\n\n                firstTrace =\n                    MakeCompact(firstTrace.Substring(0, firstTrace.Length - commonPostfix));\n                firstLine += $\"\\n{firstTrace}\";\n                RenderRecord second = Records[Records.Count - 2];\n                IEnumerable<RenderRecord> rest = Records.Reverse().Skip(2);\n                string secondTrace = second.StackTrace;\n                string secondCompactTrace =\n                    MakeCompact(secondTrace.Substring(0, secondTrace.Length - commonPostfix));\n                return $\"{firstLine}\\n{second}\\n{secondCompactTrace}\\n\" +\n                       string.Join(\"\\n\", rest) + $\"\\n({Records.Count} records.)\";\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/Libplanet/Blockchain/Renderers/Debug/RecordingActionRenderer.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Collections.Immutable;\nusing System.Linq;\nusing System.Security.Cryptography;\nusing Bencodex.Types;\nusing Libplanet.Action;\nusing Libplanet.Common;\nusing Libplanet.Types.Blocks;\nusing Serilog;\n\nnamespace Libplanet.Blockchain.Renderers.Debug\n{\n    /// <summary>\n    /// Records every render events.\n    /// </summary>\n    public class RecordingActionRenderer : IActionRenderer\n    {\n        private readonly List<RenderRecord> _records;\n        private long _nextIndex;\n\n        /// <summary>\n        /// Creates a new <see cref=\"RecordingActionRenderer\"/> instance.\n        /// </summary>\n        public RecordingActionRenderer()\n        {\n            _nextIndex = 0;\n            _records = new List<RenderRecord>();\n        }\n\n        /// <summary>\n        /// The list of recorded render events.\n        /// </summary>\n        public IReadOnlyList<RenderRecord> Records => _records;\n\n        internal IReadOnlyList<RenderRecord.ActionBase> ActionRecords =>\n            Records.OfType<RenderRecord.ActionBase>().ToImmutableArray();\n\n        internal IReadOnlyList<RenderRecord.ActionSuccess> ActionSuccessRecords =>\n            Records.OfType<RenderRecord.ActionSuccess>().ToImmutableArray();\n\n        internal IReadOnlyList<RenderRecord.ActionError> ActionErrorRecords =>\n            Records.OfType<RenderRecord.ActionError>().ToImmutableArray();\n\n        internal IReadOnlyList<RenderRecord.BlockEvent> BlockRecords =>\n            Records.OfType<RenderRecord.BlockEvent>().ToImmutableArray();\n\n        internal EventHandler<IValue>? RenderEventHandler { get; set; }\n\n        /// <summary>\n        /// Empties the render event <see cref=\"Records\"/>.\n        /// </summary>\n        public void ResetRecords()\n        {\n            _nextIndex = 0;\n            _records.Clear();\n            Log.Logger.ForContext<RecordingActionRenderer>().Debug(\"Reset records\");\n        }\n\n        /// <inheritdoc cref=\"IActionRenderer.RenderAction\"/>\n        public virtual void RenderAction(\n            IValue action,\n            ICommittedActionContext context,\n            HashDigest<SHA256> nextState\n        )\n        {\n            _records.Add(\n                new RenderRecord.ActionSuccess(\n                    index: _nextIndex++,\n                    stackTrace: RemoveFirstLine(Environment.StackTrace).TrimEnd(),\n                    action: action,\n                    context: context,\n                    nextState: nextState\n                )\n            );\n\n            RenderEventHandler?.Invoke(action, action);\n        }\n\n        /// <inheritdoc cref=\"IActionRenderer.RenderActionError\"/>\n        public virtual void RenderActionError(\n            IValue action,\n            ICommittedActionContext context,\n            Exception exception\n        ) =>\n            _records.Add(\n                new RenderRecord.ActionError(\n                    index: _nextIndex++,\n                    stackTrace: RemoveFirstLine(Environment.StackTrace).TrimEnd(),\n                    action: action,\n                    context: context,\n                    exception: exception\n                )\n            );\n\n        /// <inheritdoc cref=\"IRenderer.RenderBlock(Block, Block)\"/>\n        public virtual void RenderBlock(Block oldTip, Block newTip) =>\n            _records.Add(\n                new RenderRecord.BlockEvent(\n                    index: _nextIndex++,\n                    stackTrace: RemoveFirstLine(Environment.StackTrace).TrimEnd(),\n                    oldTip: oldTip,\n                    newTip: newTip\n                )\n            );\n\n        /// <inheritdoc cref=\"IActionRenderer.RenderBlockEnd(Block, Block)\"/>\n        public virtual void RenderBlockEnd(Block oldTip, Block newTip) =>\n            _records.Add(\n                new RenderRecord.BlockEvent(\n                    index: _nextIndex++,\n                    stackTrace: RemoveFirstLine(Environment.StackTrace).TrimEnd(),\n                    end: true,\n                    oldTip: oldTip,\n                    newTip: newTip\n                )\n            );\n\n        private static string RemoveFirstLine(string stackTrace)\n        {\n            int pos = stackTrace.IndexOf('\\n');\n            return pos < 0 ? stackTrace : stackTrace.Substring(pos + 1);\n        }\n    }\n}\n"
  },
  {
    "path": "src/Libplanet/Blockchain/Renderers/Debug/RenderRecord.cs",
    "content": "using System;\nusing System.Security.Cryptography;\nusing Bencodex.Types;\nusing Libplanet.Action;\nusing Libplanet.Common;\nusing Libplanet.Types.Blocks;\n\nnamespace Libplanet.Blockchain.Renderers.Debug\n{\n    /// <summary>\n    /// A render event represented by <see cref=\"RecordingActionRenderer\"/>.\n    /// </summary>\n    public abstract class RenderRecord\n    {\n        protected RenderRecord(long index, string stackTrace)\n        {\n            Index = index;\n            StackTrace = stackTrace;\n        }\n\n        /// <summary>\n        /// The ordinal number of the render event.\n        /// </summary>\n        public long Index { get; }\n\n        /// <summary>\n        /// The stack trace of the render event.\n        /// </summary>\n        public string StackTrace { get; }\n\n        /// <inheritdoc cref=\"object.ToString()\"/>\n        public override string ToString() => $\"{Index}.\";\n\n        /// <summary>\n        /// Represents an action render/unrender event.\n        /// </summary>\n        public abstract class ActionBase : RenderRecord\n        {\n            protected ActionBase(\n                long index,\n                string stackTrace,\n                IValue action,\n                ICommittedActionContext context,\n                bool unrender = false\n            )\n                : base(index, stackTrace)\n            {\n                Action = action;\n                Context = context;\n                Render = !unrender;\n            }\n\n            /// <summary>\n            /// The rendered action.\n            /// </summary>\n            public IValue Action { get; }\n\n            /// <summary>\n            /// The action evaluation context.\n            /// </summary>\n            public ICommittedActionContext Context { get; }\n\n            /// <summary>\n            /// Whether it is not an unrender event, but a render event.\n            /// </summary>\n            public bool Render { get; }\n\n            /// <summary>\n            /// Whether it is a render event, but an unrender event.\n            /// </summary>\n            public bool Unrender => !Render;\n\n            /// <inheritdoc cref=\"RenderRecord.ToString()\"/>\n            public override string ToString() =>\n                $\"{base.ToString()} #{Context.BlockIndex} \" +\n                (Render ? \"Render\" : \"Unrender\") + \"Action\";\n        }\n\n        /// <summary>\n        /// Represents a succeeded action render/unrender event.\n        /// </summary>\n        public class ActionSuccess : ActionBase\n        {\n            /// <summary>\n            /// Creates a succeeded action render/unrender event record.\n            /// </summary>\n            /// <param name=\"index\">The ordinal number of the render event.</param>\n            /// <param name=\"stackTrace\">The stack trace of the render event.</param>\n            /// <param name=\"action\">The rendered action.</param>\n            /// <param name=\"context\">The action evaluation context.</param>\n            /// <param name=\"nextState\">The resulting state after the action is evaluated.</param>\n            /// <param name=\"unrender\">Whether it is an unrender event.</param>\n            public ActionSuccess(\n                long index,\n                string stackTrace,\n                IValue action,\n                ICommittedActionContext context,\n                HashDigest<SHA256> nextState,\n                bool unrender = false\n            )\n                : base(index, stackTrace, action, context, unrender: unrender)\n            {\n                NextState = nextState;\n            }\n\n            /// <summary>\n            /// The resulting states after the action is evaluated.\n            /// </summary>\n            public HashDigest<SHA256> NextState { get; }\n\n            /// <inheritdoc cref=\"RenderRecord.ToString()\"/>\n            public override string ToString() => $\"{base.ToString()} [success]\";\n        }\n\n        /// <summary>\n        /// Represents a failed action render/unrender event.\n        /// </summary>\n        public class ActionError : ActionBase\n        {\n            /// <summary>\n            /// Creates a failed action render/unrender event record.\n            /// </summary>\n            /// <param name=\"index\">The ordinal number of the render event.</param>\n            /// <param name=\"stackTrace\">The stack trace of the render event.</param>\n            /// <param name=\"action\">The rendered action.</param>\n            /// <param name=\"context\">The action evaluation context.</param>\n            /// <param name=\"exception\">The exception thrown by the action.</param>\n            /// <param name=\"unrender\">Whether it is an unrender event.</param>\n            public ActionError(\n                long index,\n                string stackTrace,\n                IValue action,\n                ICommittedActionContext context,\n                Exception exception,\n                bool unrender = false\n            )\n                : base(index, stackTrace, action, context, unrender: unrender)\n            {\n                Exception = exception;\n            }\n\n            /// <summary>\n            /// The exception thrown by the action.\n            /// </summary>\n            public Exception Exception { get; }\n\n            /// <inheritdoc cref=\"RenderRecord.ToString()\"/>\n            public override string ToString() => $\"{base.ToString()} [error]\";\n        }\n\n        /// <summary>\n        /// Represents a block event.\n        /// </summary>\n        public abstract class BlockBase : RenderRecord\n        {\n            protected BlockBase(\n                long index,\n                string stackTrace,\n                Block oldTip,\n                Block newTip,\n                bool end = false\n            )\n                : base(index, stackTrace)\n            {\n                OldTip = oldTip;\n                NewTip = newTip;\n                Begin = !end;\n            }\n\n            /// <summary>\n            /// The tip before update.\n            /// </summary>\n            public Block OldTip { get; }\n\n            /// <summary>\n            /// The tip after update.\n            /// </summary>\n            public Block NewTip { get; }\n\n            /// <summary>\n            /// Whether it is not an <c>End</c> event.\n            /// </summary>\n            public bool Begin { get; }\n\n            /// <summary>\n            /// Whether it is an <c>End</c> event.\n            /// </summary>\n            public bool End => !Begin;\n\n            /// <inheritdoc cref=\"RenderRecord.ToString()\"/>\n            public override string ToString() =>\n                $\"{base.ToString()} \" +\n                $\"#{OldTip.Index} {OldTip.Hash} -> #{NewTip.Index} {NewTip.Hash} Render...\" +\n                (End ? \"End\" : string.Empty);\n        }\n\n        /// <summary>\n        /// Represents a block event.\n        /// </summary>\n        public class BlockEvent : BlockBase\n        {\n            /// <summary>\n            /// Creates a block event record.\n            /// </summary>\n            /// <param name=\"index\">The ordinal number of the render event.</param>\n            /// <param name=\"stackTrace\">The stack trace of the render event.</param>\n            /// <param name=\"oldTip\">The tip before update.</param>\n            /// <param name=\"newTip\">The tip after update.</param>\n            /// <param name=\"end\">Whether it is an <c>End</c> event.</param>\n            public BlockEvent(\n                long index,\n                string stackTrace,\n                Block oldTip,\n                Block newTip,\n                bool end = false\n            )\n                : base(index, stackTrace, oldTip, newTip, end)\n            {\n            }\n\n            /// <inheritdoc cref=\"RenderRecord.ToString()\"/>\n            public override string ToString() =>\n                base.ToString().Replace(\"Render...\", \"RenderBlock\");\n        }\n    }\n}\n"
  },
  {
    "path": "src/Libplanet/Blockchain/Renderers/Debug/ValidatingActionRenderer.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Security.Cryptography;\nusing Bencodex.Types;\nusing Libplanet.Action;\nusing Libplanet.Common;\nusing Libplanet.Types.Blocks;\n\nnamespace Libplanet.Blockchain.Renderers.Debug\n{\n    /// <summary>\n    /// Validates if rendering events are in the correct order according to the documented automata\n    /// (see also the docs for <see cref=\"IRenderer\"/> and <see cref=\"IActionRenderer\"/>)\n    /// using profiling-guided analysis.\n    /// </summary>\n    public class ValidatingActionRenderer : RecordingActionRenderer\n    {\n        private readonly Action<InvalidRenderException>? _onError;\n\n        /// <summary>\n        /// Creates a new <see cref=\"ValidatingActionRenderer\"/> instance.\n        /// </summary>\n        /// <param name=\"onError\">An optional event handler which is triggered when invalid\n        /// render events occur.</param>\n        public ValidatingActionRenderer(Action<InvalidRenderException>? onError = null)\n        {\n            _onError = onError;\n        }\n\n        private enum RenderState\n        {\n            Ready,\n            Block,\n            BlockEnd,\n        }\n\n        /// <inheritdoc cref=\"IRenderer.RenderBlock(Block, Block)\"/>\n        public override void RenderBlock(Block oldTip, Block newTip)\n        {\n            base.RenderBlock(oldTip, newTip);\n            Validate();\n        }\n\n        /// <inheritdoc cref=\"IActionRenderer.RenderAction\"/>\n        public override void RenderAction(\n            IValue action,\n            ICommittedActionContext context,\n            HashDigest<SHA256> nextState\n        )\n        {\n            base.RenderAction(action, context, nextState);\n            Validate();\n        }\n\n        /// <inheritdoc cref=\"IActionRenderer.RenderActionError\"/>\n        public override void RenderActionError(\n            IValue action,\n            ICommittedActionContext context,\n            Exception exception\n        )\n        {\n            base.RenderActionError(action, context, exception);\n            Validate();\n        }\n\n        /// <inheritdoc cref=\"IActionRenderer.RenderBlockEnd(Block, Block)\"/>\n        public override void RenderBlockEnd(Block oldTip, Block newTip)\n        {\n            base.RenderBlockEnd(oldTip, newTip);\n            Validate();\n        }\n\n        private void Validate()\n        {\n            var state = RenderState.Ready;\n            RenderRecord.BlockEvent? blockState = null;\n            long previousActionBlockIndex = -1L;\n            var records = new List<RenderRecord>(Records.Count);\n\n            Exception BadRenderExc(string msg) => Error(records, msg);\n\n            foreach (RenderRecord record in Records)\n            {\n                records.Add(record);\n                switch (state)\n                {\n                    case RenderState.Ready:\n                    {\n#pragma warning disable S2589\n                        if (!(blockState is null))\n#pragma warning restore S2589\n                        {\n                            throw BadRenderExc($\"Unexpected block state: {blockState}.\");\n                        }\n                        else if (record is RenderRecord.BlockBase blockBase && blockBase.Begin)\n                        {\n#pragma warning disable S1066\n                            if (blockBase is RenderRecord.BlockEvent block)\n#pragma warning restore S1066\n                            {\n                                blockState = block;\n                                state = RenderState.Block;\n                                break;\n                            }\n                        }\n\n                        throw BadRenderExc($\"Expected {nameof(IRenderer.RenderBlock)}.\");\n                    }\n\n                    case RenderState.Block:\n                    {\n                        if (blockState is null)\n                        {\n                            throw BadRenderExc(\"Unexpected block state: null.\");\n                        }\n                        else if (record is RenderRecord.BlockEvent block && block.End)\n                        {\n                            if (block.OldTip != blockState.OldTip ||\n                                block.NewTip != blockState.NewTip)\n                            {\n                                throw BadRenderExc(\n                                    $\"{nameof(IRenderer.RenderBlock)} and \" +\n                                    $\"{nameof(IActionRenderer.RenderBlockEnd)} which matches \" +\n                                    \"to it should have the same oldTip and newTip.\"\n                                );\n                            }\n\n#pragma warning disable S2583\n                            state = RenderState.Ready;\n#pragma warning restore S2583\n                            blockState = null;\n                            break;\n                        }\n                        else if (record is RenderRecord.ActionBase actionBase &&\n                                 actionBase.Render)\n                        {\n                            long idx = actionBase.Context.BlockIndex;\n                            if (idx > blockState.NewTip.Index)\n                            {\n                                throw BadRenderExc(\n                                    \"An action is from a block which has an unexpected index \" +\n                                    $\"#{idx} (expected max: #{blockState.NewTip.Index}).\"\n                                );\n                            }\n\n                            previousActionBlockIndex = idx;\n                            break;\n                        }\n\n                        throw BadRenderExc(\n                            $\"Expected {nameof(IActionRenderer.RenderBlockEnd)} or \" +\n                            $\"{nameof(IActionRenderer.RenderAction)} or \" +\n                            $\"{nameof(IActionRenderer.RenderActionError)}\"\n                        );\n                    }\n\n                    case RenderState.BlockEnd:\n                    {\n                        if (!(blockState is null))\n                        {\n                            throw BadRenderExc($\"Unexpected block states: {blockState}\");\n                        }\n\n                        throw BadRenderExc(\n                            $\"Unexpected block state/record encountered: \" +\n                            $\"{blockState}/{record}\");\n                    }\n                }\n            }\n        }\n\n        private InvalidRenderException Error(IReadOnlyList<RenderRecord> records, string msg)\n        {\n            var exception = new InvalidRenderException(msg, records);\n            _onError?.Invoke(exception);\n            return exception;\n        }\n    }\n}\n"
  },
  {
    "path": "src/Libplanet/Blockchain/Renderers/IActionRenderer.cs",
    "content": "using System;\nusing System.Security.Cryptography;\nusing Bencodex.Types;\nusing Libplanet.Action;\nusing Libplanet.Common;\nusing Libplanet.Store;\nusing Libplanet.Types.Blocks;\nusing Libplanet.Types.Tx;\n\nnamespace Libplanet.Blockchain.Renderers\n{\n    /// <summary>\n    /// Listens state changes of every step of actions, besides blocks,\n    /// on a <see cref=\"BlockChain\"/>.\n    /// If you need more fine-grained events than <see cref=\"IRenderer\"/>,\n    /// implement this interface instead.\n    /// <para>The invocation order of methods for each <see cref=\"Block\"/> are:</para>\n    /// <list type=\"number\">\n    /// <item><description><see cref=\"IRenderer.RenderBlock(Block, Block)\"/> (one time)\n    /// </description></item>\n    /// <item><description><see cref=\"RenderAction\"/>\n    /// &amp; <see cref=\"RenderActionError\"/> (zero or more\n    /// times)</description>\n    /// </item>\n    /// <item><description><see cref=\"RenderBlockEnd(Block, Block)\"/> (one time)</description>\n    /// </item>\n    /// </list>\n    /// </summary>\n    /// <remarks>Although <see cref=\"Transaction\"/>s affect the states in\n    /// the <see cref=\"IStateStore\"/> all or nothing at all (i.e., atomically),\n    /// <see cref=\"IActionRenderer\"/> receives all action-related events\n    /// (<see cref=\"RenderAction\"/>/<see cref=\"RenderActionError\"/>) <em>immediately</em>\n    /// without buffering, which means actions are rendered <em>even before</em> whether there are\n    /// any actions throwing an exception in the same transaction is determined.  In other words,\n    /// for <see cref=\"IActionRenderer\"/>s, it is not guaranteed that actions in a transaction\n    /// are atomic.\n    /// </remarks>\n    public interface IActionRenderer : IRenderer\n    {\n        /// <summary>\n        /// Does things that should be done right after an <paramref name=\"action\"/>\n        /// is executed and applied to the blockchain.\n        /// </summary>\n        /// <param name=\"action\">An executed action.</param>\n        /// <param name=\"context\">The equivalent context object to an object passed to\n        /// the <paramref name=\"action\"/>'s <see cref=\"IAction.Execute(IActionContext)\"/> method.\n        /// That means <see cref=\"IActionContext.PreviousState\"/> are the states right\n        /// <em>before</em> this action executed.  For the states after this action executed,\n        /// use the <paramref name=\"nextState\"/> argument instead.</param>\n        /// <param name=\"nextState\">The state root hash right <em>after</em> this action executed,\n        /// which means it is equivalent to the states <paramref name=\"action\"/>'s\n        /// <see cref=\"IAction.Execute(IActionContext)\"/> method returned.</param>\n        /// <remarks>\n        /// It is guaranteed to be called only once for an <paramref name=\"action\"/>,\n        /// and only after applied to the blockchain, unless an exception is thrown during executing\n        /// the <paramref name=\"action\"/> (in that case <see\n        /// cref=\"RenderActionError\"/> is called instead) or\n        /// once the <paramref name=\"action\"/> has been unrendered.\n        /// <para>Also note that this method is invoked after <see\n        /// cref=\"IRenderer.RenderBlock(Block, Block)\"/> method is called\n        /// (where its second parameter <c>newTip</c> contains a transaction the <paramref\n        /// name=\"action\"/> belongs to).</para>\n        /// </remarks>\n        void RenderAction(\n            IValue action,\n            ICommittedActionContext context,\n            HashDigest<SHA256> nextState);\n\n        /// <summary>\n        /// Does the similar things to <see cref=\"RenderAction\"/>, except that this method\n        /// is invoked when <paramref name=\"action\"/> has terminated with an exception.\n        /// </summary>\n        /// <param name=\"action\">An action which threw an exception during execution.</param>\n        /// <param name=\"context\">The equivalent context object to an object passed to\n        /// the <paramref name=\"action\"/>'s <see cref=\"IAction.Execute(IActionContext)\"/> method.\n        /// That means <see cref=\"IActionContext.PreviousState\"/> are the states right\n        /// <em>before</em> this action executed.</param>\n        /// <param name=\"exception\">The exception thrown during executing the <paramref\n        /// name=\"action\"/>.</param>\n        /// <remarks>\n        /// Also note that this method is invoked after <see\n        /// cref=\"IRenderer.RenderBlock(Block, Block)\"/> method is called\n        /// (where its second parameter <c>newTip</c> contains a transaction the <paramref\n        /// name=\"action\"/> belongs to).\n        /// </remarks>\n        void RenderActionError(IValue action, ICommittedActionContext context, Exception exception);\n\n        /// <summary>\n        /// Does things that should be done right all actions in a new <see cref=\"Block\"/> are\n        /// rendered.\n        /// </summary>\n        /// <remarks>It is guaranteed to be called only once for a block.</remarks>\n        /// <param name=\"oldTip\">The previous <see cref=\"BlockChain.Tip\"/>.</param>\n        /// <param name=\"newTip\">The current <see cref=\"BlockChain.Tip\"/>.</param>\n        void RenderBlockEnd(Block oldTip, Block newTip);\n    }\n}\n"
  },
  {
    "path": "src/Libplanet/Blockchain/Renderers/IRenderer.cs",
    "content": "using Libplanet.Types.Blocks;\n\nnamespace Libplanet.Blockchain.Renderers\n{\n    /// <summary>\n    /// Listens state changes on a <see cref=\"BlockChain\"/>.\n    /// <para>Usually, implementations of this interface purpose to update the in-memory game states\n    /// (if exist), or send a signal to the UI thread (usually the main thread) so that the graphics\n    /// on the display is redrawn.</para>\n    /// <para>The invocation order of methods for each <see cref=\"Block\"/> are:</para>\n    /// <list type=\"number\">\n    /// <item><description><see cref=\"RenderBlock(Block, Block)\"/> (one time)</description>\n    /// </item>\n    /// </list>\n    /// </summary>\n    public interface IRenderer\n    {\n        /// <summary>\n        /// Does things that should be done right after a new <see cref=\"Block\"/> is appended to\n        /// a <see cref=\"BlockChain\"/> (so that its <see cref=\"BlockChain.Tip\"/> has changed).\n        /// </summary>\n        /// <remarks>It is guaranteed to be called only once for a block, and only after applied to\n        /// the blockchain.</remarks>\n        /// <param name=\"oldTip\">The previous <see cref=\"BlockChain.Tip\"/>.</param>\n        /// <param name=\"newTip\">The current <see cref=\"BlockChain.Tip\"/>.</param>\n        void RenderBlock(Block oldTip, Block newTip);\n    }\n}\n"
  },
  {
    "path": "src/Libplanet/Blockchain/Renderers/LoggedActionRenderer.cs",
    "content": "using System;\nusing System.Security.Cryptography;\nusing Bencodex.Types;\nusing Libplanet.Action;\nusing Libplanet.Common;\nusing Libplanet.Types.Blocks;\nusing Serilog;\nusing Serilog.Events;\n\nnamespace Libplanet.Blockchain.Renderers\n{\n    /// <summary>\n    /// Decorates an <see cref=\"IActionRenderer\"/> so that all event messages are logged.\n    /// In other words, this is an <see cref=\"IActionRenderer\"/> version of\n    /// <see cref=\"LoggedRenderer\"/>.\n    /// <para>Every single event message causes two log messages: one is logged <em>before</em>\n    /// rendering, and other one is logged <em>after</em> rendering.  If any exception is thrown\n    /// it is also logged with the log level <see cref=\"LogEventLevel.Error\"/> (regardless of\n    /// <see cref=\"LoggedRenderer.Level\"/> configuration).</para>\n    /// </summary>\n    /// <example>\n    /// <code><![CDATA[\n    /// IActionRenderer actionRenderer = new SomeActionRenderer();\n    /// // Wraps the action renderer with LoggedActionRenderer:\n    /// actionRenderer = new LoggedActionRenderer(\n    ///     actionRenderer,\n    ///     Log.Logger,\n    ///     LogEventLevel.Information,\n    /// );\n    /// ]]></code>\n    /// </example>\n    public class LoggedActionRenderer : LoggedRenderer, IActionRenderer\n    {\n        /// <summary>\n        /// Creates a new <see cref=\"LoggedActionRenderer\"/> instance which decorates the given\n        /// action <paramref name=\"renderer\"/>.\n        /// </summary>\n        /// <param name=\"renderer\">The actual action renderer to forward all event messages to and\n        /// actually render things.</param>\n        /// <param name=\"logger\">The logger to write log messages to.  Note that all log messages\n        /// this decorator writes become in the context of the <paramref name=\"renderer\"/>'s\n        /// type (with the context property <c>SourceContext</c>).</param>\n        /// <param name=\"level\">The log event level.  All log messages become this level.</param>\n        public LoggedActionRenderer(\n            IActionRenderer renderer,\n            ILogger logger,\n            LogEventLevel level = LogEventLevel.Debug\n        )\n            : base(renderer, logger, level)\n        {\n            ActionRenderer = renderer;\n        }\n\n        /// <summary>\n        /// The inner action renderer to forward all event messages to and actually render things.\n        /// </summary>\n        public IActionRenderer ActionRenderer { get; }\n\n        /// <inheritdoc cref=\"IActionRenderer.RenderBlockEnd(Block, Block)\"/>\n        public void RenderBlockEnd(\n            Block oldTip,\n            Block newTip\n        ) =>\n            LogBlockRendering(\n                nameof(RenderBlockEnd),\n                oldTip,\n                newTip,\n                ActionRenderer.RenderBlockEnd\n            );\n\n        /// <inheritdoc cref=\"IActionRenderer.RenderAction\"/>\n        public void RenderAction(\n            IValue action,\n            ICommittedActionContext context,\n            HashDigest<SHA256> nextState\n        ) =>\n            LogActionRendering(\n                nameof(RenderAction),\n                action,\n                context,\n                () => ActionRenderer.RenderAction(action, context, nextState)\n            );\n\n        /// <inheritdoc cref=\"IActionRenderer.RenderActionError\"/>\n        public void RenderActionError(\n            IValue action,\n            ICommittedActionContext context,\n            Exception exception\n        ) =>\n            LogActionRendering(\n                nameof(RenderActionError),\n                action,\n                context,\n                () => ActionRenderer.RenderActionError(action, context, exception)\n            );\n\n        private void LogActionRendering(\n            string methodName,\n            IValue action,\n            ICommittedActionContext context,\n            System.Action callback\n        )\n        {\n            Type actionType = action.GetType();\n            const string startMessage =\n                \"Invoking {MethodName}() for an action {ActionType} at block #{BlockIndex}...\";\n            Logger.Write(\n                Level,\n                startMessage,\n                methodName,\n                actionType,\n                context.BlockIndex);\n\n            try\n            {\n                callback();\n            }\n            catch (Exception e)\n            {\n                const string errorMessage =\n                    \"An exception was thrown during {MethodName}() for an action {ActionType} at \" +\n                    \"block #{BlockIndex}\";\n                Logger.Error(\n                    e,\n                    errorMessage,\n                    methodName,\n                    actionType,\n                    context.BlockIndex);\n                throw;\n            }\n\n            const string endMessage =\n                \"Invoked {MethodName}() for an action {ActionType} at block #{BlockIndex}\";\n            Logger.Write(\n                Level,\n                endMessage,\n                methodName,\n                actionType,\n                context.BlockIndex);\n        }\n    }\n}\n"
  },
  {
    "path": "src/Libplanet/Blockchain/Renderers/LoggedRenderer.cs",
    "content": "using System;\nusing Libplanet.Types.Blocks;\nusing Serilog;\nusing Serilog.Events;\n\nnamespace Libplanet.Blockchain.Renderers\n{\n    /// <summary>\n    /// Decorates an <see cref=\"IRenderer\"/> so that all event messages are logged.\n    /// <para>Every single event message causes two log messages: one is logged <em>before</em>\n    /// rendering, and other one is logged <em>after</em> rendering.  If any exception is thrown\n    /// it is also logged with the log level <see cref=\"LogEventLevel.Error\"/> (regardless of\n    /// <see cref=\"Level\"/> configuration).</para>\n    /// </summary>\n    /// <example>\n    /// <code>\n    /// IRenderer renderer = new SomeRenderer();\n    /// // Wraps the renderer with LoggedRenderer:\n    /// renderer = new LoggedRenderer(\n    ///     renderer,\n    ///     Log.Logger,\n    ///     LogEventLevel.Information,\n    /// );\n    /// </code>\n    /// </example>\n    /// <remarks>Since <see cref=\"IActionRenderer\"/> is a subtype of <see cref=\"IRenderer\"/>,\n    /// <see cref=\"LoggedRenderer(IRenderer, ILogger, LogEventLevel)\"/> constructor can take\n    /// an <see cref=\"IActionRenderer\"/> instance as well.  However, even it takes an action\n    /// renderer, action-level fine-grained events will not be logged.  For action renderers,\n    /// please use <see cref=\"LoggedActionRenderer\"/> instead.</remarks>\n    public class LoggedRenderer : IRenderer\n    {\n        /// <summary>\n        /// Creates a new <see cref=\"LoggedRenderer\"/> instance which decorates the given\n        /// <paramref name=\"renderer\"/>.\n        /// </summary>\n        /// <param name=\"renderer\">The actual renderer to forward all event messages to and actually\n        /// render things.</param>\n        /// <param name=\"logger\">The logger to write log messages to.  Note that all log messages\n        /// this decorator writes become in the context of the <paramref name=\"renderer\"/>'s\n        /// type (with the context property <c>SourceContext</c>).</param>\n        /// <param name=\"level\">The log event level.  All log messages become this level.</param>\n        public LoggedRenderer(\n            IRenderer renderer,\n            ILogger logger,\n            LogEventLevel level = LogEventLevel.Debug\n        )\n        {\n            Renderer = renderer;\n            Logger = logger\n                .ForContext<LoggedRenderer>()\n                .ForContext(\"Source\", nameof(LoggedRenderer))\n                .ForContext(renderer.GetType());\n            Level = level;\n        }\n\n        /// <summary>\n        /// The inner renderer to forward all event messages to and actually render things.\n        /// </summary>\n        public IRenderer Renderer { get; }\n\n        /// <summary>\n        /// The log event level.  All log messages become this level.\n        /// </summary>\n        public LogEventLevel Level { get; }\n\n        /// <summary>\n        /// The logger to write log messages to.  Note that all log messages this decorator writes\n        /// become in the context of the <see cref=\"Renderer\"/>'s type (with the context\n        /// property <c>SourceContext</c>).\n        /// </summary>\n        protected ILogger Logger { get; }\n\n        /// <inheritdoc cref=\"IRenderer.RenderBlock(Block, Block)\"/>\n        public void RenderBlock(\n            Block oldTip,\n            Block newTip\n        ) =>\n            LogBlockRendering(\n                nameof(RenderBlock),\n                oldTip,\n                newTip,\n                Renderer.RenderBlock\n            );\n\n        protected void LogBlockRendering(\n            string methodName,\n            Block oldTip,\n            Block newTip,\n            System.Action<Block, Block> callback\n        )\n        {\n            Logger.Write(\n                Level,\n                \"Invoking {MethodName}() for #{NewIndex} {NewHash} (was #{OldIndex} {OldHash})...\",\n                methodName,\n                newTip.Index,\n                newTip.Hash,\n                oldTip.Index,\n                oldTip.Hash\n            );\n\n            try\n            {\n                callback(oldTip, newTip);\n            }\n            catch (Exception e)\n            {\n                const string errorMessage =\n                    \"An exception was thrown during {MethodName}() for #{NewIndex} {NewHash} \" +\n                    \"(was #{OldIndex} {OldHash})\";\n                Logger.Error(\n                    e,\n                    errorMessage,\n                    methodName,\n                    newTip.Index,\n                    newTip.Hash,\n                    oldTip.Index,\n                    oldTip.Hash);\n                throw;\n            }\n\n            Logger.Write(\n                Level,\n                \"Invoked {MethodName}() for #{NewIndex} {NewHash} (was #{OldIndex} {OldHash})\",\n                methodName,\n                newTip.Index,\n                newTip.Hash,\n                oldTip.Index,\n                oldTip.Hash\n            );\n        }\n    }\n}\n"
  },
  {
    "path": "src/Libplanet/Consensus/Maj23.cs",
    "content": "using System;\nusing System.Collections.Immutable;\nusing System.Diagnostics.Contracts;\nusing System.Linq;\nusing System.Text.Json.Serialization;\nusing Bencodex;\nusing Bencodex.Types;\nusing Libplanet.Common;\nusing Libplanet.Crypto;\nusing Libplanet.Types.Blocks;\nusing Libplanet.Types.Consensus;\n\nnamespace Libplanet.Consensus\n{\n    /// <summary>\n    /// A class used to claim that a peer has collected two thirds majority of\n    /// <see cref=\"Vote\"/>s.\n    /// </summary>\n    public class Maj23 : IEquatable<Maj23>\n    {\n        // FIXME: This should be private.  Left as internal for testing reasons.\n        internal static readonly Binary SignatureKey = new Binary(new byte[] { 0x53 }); // 'S'\n        private static readonly Codec _codec = new Codec();\n\n        private readonly Maj23Metadata _maj23Metadata;\n\n        /// <summary>\n        /// Instantiates a <see cref=\"Maj23\"/> with given <paramref name=\"maj23Metadata\"/>\n        /// and its <paramref name=\"signature\"/>.\n        /// </summary>\n        /// <param name=\"maj23Metadata\">A <see cref=\"Maj23Metadata\"/> to claim.</param>\n        /// <param name=\"signature\">A signature signed with <paramref name=\"maj23Metadata\"/>.\n        /// </param>\n        /// <exception cref=\"ArgumentNullException\">Thrown if given <paramref name=\"signature\"/> is\n        /// empty.</exception>\n        /// <exception cref=\"ArgumentException\">Thrown if given <paramref name=\"signature\"/> is\n        /// invalid and cannot be verified with <paramref name=\"maj23Metadata\"/>.</exception>\n        public Maj23(Maj23Metadata maj23Metadata, ImmutableArray<byte> signature)\n        {\n            _maj23Metadata = maj23Metadata;\n            Signature = signature;\n\n            if (signature.IsDefaultOrEmpty)\n            {\n                throw new ArgumentNullException(\n                    nameof(signature),\n                    \"Signature cannot be null or empty.\");\n            }\n            else if (!Verify())\n            {\n                throw new ArgumentException(\"Signature is invalid.\", nameof(signature));\n            }\n        }\n\n        public Maj23(byte[] marshaled)\n            : this((Dictionary)_codec.Decode(marshaled))\n        {\n        }\n\n#pragma warning disable SA1118 // The parameter spans multiple lines\n        public Maj23(Dictionary encoded)\n            : this(\n                new Maj23Metadata(encoded),\n                encoded.ContainsKey(SignatureKey)\n                    ? ((Binary)encoded[SignatureKey]).ByteArray\n                    : ImmutableArray<byte>.Empty)\n        {\n        }\n#pragma warning restore SA1118\n\n        /// <inheritdoc cref=\"Maj23Metadata.Height\"/>\n        public long Height => _maj23Metadata.Height;\n\n        /// <inheritdoc cref=\"Maj23Metadata.Round\"/>\n        public int Round => _maj23Metadata.Round;\n\n        /// <inheritdoc cref=\"Maj23Metadata.BlockHash\"/>\n        public BlockHash BlockHash => _maj23Metadata.BlockHash;\n\n        /// <inheritdoc cref=\"Maj23Metadata.Timestamp\"/>\n        public DateTimeOffset Timestamp => _maj23Metadata.Timestamp;\n\n        /// <inheritdoc cref=\"Maj23Metadata.ValidatorPublicKey\"/>\n        public PublicKey ValidatorPublicKey => _maj23Metadata.ValidatorPublicKey;\n\n        /// <inheritdoc cref=\"Maj23Metadata.Flag\"/>\n        public VoteFlag Flag => _maj23Metadata.Flag;\n\n        /// <summary>\n        /// A signature that signed with <see cref=\"Maj23Metadata\"/>.\n        /// </summary>\n        public ImmutableArray<byte> Signature { get; }\n\n        /// <summary>\n        /// A Bencodex-encoded value of <see cref=\"Maj23\"/>.\n        /// </summary>\n        [JsonIgnore]\n        public Dictionary Encoded =>\n            !Signature.IsEmpty\n                ? _maj23Metadata.Encoded.Add(SignatureKey, Signature)\n                : _maj23Metadata.Encoded;\n\n        /// <summary>\n        /// <see cref=\"byte\"/> encoded <see cref=\"Maj23\"/> data.\n        /// </summary>\n        public ImmutableArray<byte> ByteArray => ToByteArray().ToImmutableArray();\n\n        public byte[] ToByteArray() => _codec.Encode(Encoded);\n\n        /// <summary>\n        /// Verifies whether the <see cref=\"Maj23Metadata\"/> is properly signed by\n        /// <see cref=\"Validator\"/>.\n        /// </summary>\n        /// <returns><see langword=\"true\"/> if the <see cref=\"Signature\"/> is not empty\n        /// and is a valid signature signed by <see cref=\"Validator\"/>.</returns>\n        [Pure]\n        public bool Verify() =>\n            !Signature.IsDefaultOrEmpty &&\n            ValidatorPublicKey.Verify(\n                _maj23Metadata.ByteArray.ToImmutableArray(),\n                Signature);\n\n        /// <inheritdoc/>\n        [Pure]\n        public bool Equals(Maj23? other)\n        {\n            return other is { } maj23 &&\n                   _maj23Metadata.Equals(maj23._maj23Metadata) &&\n                   Signature.SequenceEqual(maj23.Signature);\n        }\n\n        /// <inheritdoc/>\n        [Pure]\n        public override bool Equals(object? obj)\n        {\n            return obj is Maj23 other && Equals(other);\n        }\n\n        /// <inheritdoc/>\n        [Pure]\n        public override int GetHashCode()\n        {\n            return HashCode.Combine(\n                _maj23Metadata.GetHashCode(),\n                ByteUtil.CalculateHashCode(Signature.ToArray()));\n        }\n    }\n}\n"
  },
  {
    "path": "src/Libplanet/Consensus/Maj23Metadata.cs",
    "content": "using System;\nusing System.Collections.Immutable;\nusing System.Globalization;\nusing System.Text.Json.Serialization;\nusing Bencodex;\nusing Bencodex.Types;\nusing Libplanet.Crypto;\nusing Libplanet.Types.Blocks;\nusing Libplanet.Types.Consensus;\n\nnamespace Libplanet.Consensus\n{\n    public class Maj23Metadata : IEquatable<Maj23Metadata>\n    {\n        private const string TimestampFormat = \"yyyy-MM-ddTHH:mm:ss.ffffffZ\";\n        private static readonly Binary HeightKey =\n            new Binary(new byte[] { 0x48 }); // 'H'\n\n        private static readonly Binary RoundKey =\n            new Binary(new byte[] { 0x52 }); // 'R'\n\n        private static readonly Binary TimestampKey =\n            new Binary(new byte[] { 0x74 }); // 't'\n\n        private static readonly Binary ValidatorPublicKeyKey =\n            new Binary(new byte[] { 0x50 }); // 'P'\n\n        private static readonly Binary BlockHashKey =\n            new Binary(new byte[] { 0x42 }); // 'B'\n\n        private static readonly Binary FlagKey =\n            new Binary(new byte[] { 0x46 }); // 'F'\n\n        private static readonly Codec _codec = new Codec();\n\n        public Maj23Metadata(\n            long height,\n            int round,\n            BlockHash blockHash,\n            DateTimeOffset timestamp,\n            PublicKey validatorPublicKey,\n            VoteFlag flag)\n        {\n            if (height < 0)\n            {\n                throw new ArgumentOutOfRangeException(\n                    nameof(height),\n                    \"Height must be greater than or equal to 0.\");\n            }\n            else if (round < 0)\n            {\n                throw new ArgumentOutOfRangeException(\n                    nameof(round),\n                    \"Round must be greater than or equal to 0.\");\n            }\n\n            if (flag == VoteFlag.Null || flag == VoteFlag.Unknown)\n            {\n                throw new ArgumentException(\n                    \"Vote flag should be PreVote or PreCommit.\",\n                    nameof(flag));\n            }\n\n            Height = height;\n            Round = round;\n            BlockHash = blockHash;\n            Timestamp = timestamp;\n            ValidatorPublicKey = validatorPublicKey;\n            Flag = flag;\n        }\n\n#pragma warning disable SA1118 // The parameter spans multiple lines\n        public Maj23Metadata(Dictionary encoded)\n            : this(\n                height: (Integer)encoded[HeightKey],\n                round: (Integer)encoded[RoundKey],\n                blockHash: new BlockHash(encoded[BlockHashKey]),\n                timestamp: DateTimeOffset.ParseExact(\n                    (Text)encoded[TimestampKey],\n                    TimestampFormat,\n                    CultureInfo.InvariantCulture),\n                validatorPublicKey: new PublicKey(\n                    ((Binary)encoded[ValidatorPublicKeyKey]).ByteArray),\n                flag: (VoteFlag)(int)(Integer)encoded[FlagKey])\n        {\n        }\n#pragma warning restore SA1118\n\n        /// <summary>\n        /// A height of given maj23 values.\n        /// </summary>\n        public long Height { get; }\n\n        /// <summary>\n        /// A round of given maj23 values.\n        /// </summary>\n        public int Round { get; }\n\n        /// <summary>\n        /// The <see cref=\"Types.Blocks.BlockHash\"/> of vote claim.\n        /// </summary>\n        public BlockHash BlockHash { get; }\n\n        /// <summary>\n        /// The time at which the claim took place.\n        /// </summary>\n        public DateTimeOffset Timestamp { get; }\n\n        /// <summary>\n        /// A <see cref=\"PublicKey\"/> of claimant.\n        /// </summary>\n        public PublicKey ValidatorPublicKey { get; }\n\n        /// <summary>\n        /// The <see cref=\"VoteFlag\"/> of the <see cref=\"Maj23Metadata\"/>.\n        /// </summary>\n        public VoteFlag Flag { get; }\n\n        /// <summary>\n        /// A Bencodex-encoded value of <see cref=\"Maj23Metadata\"/>.\n        /// </summary>\n        [JsonIgnore]\n        public Dictionary Encoded\n        {\n            get\n            {\n                Dictionary encoded = Bencodex.Types.Dictionary.Empty\n                    .Add(HeightKey, Height)\n                    .Add(RoundKey, Round)\n                    .Add(\n                        TimestampKey,\n                        Timestamp.ToString(TimestampFormat, CultureInfo.InvariantCulture))\n                    .Add(ValidatorPublicKeyKey, ValidatorPublicKey.Format(compress: true))\n                    .Add(BlockHashKey, BlockHash.ByteArray)\n                    .Add(FlagKey, (int)Flag);\n\n                return encoded;\n            }\n        }\n\n        public ImmutableArray<byte> ByteArray => ToByteArray().ToImmutableArray();\n\n        public byte[] ToByteArray() => _codec.Encode(Encoded);\n\n        /// <summary>\n        /// Signs given <see cref=\"Maj23Metadata\"/> with given <paramref name=\"signer\"/>.\n        /// </summary>\n        /// <param name=\"signer\">A <see cref=\"PrivateKey\"/> to sign.</param>\n        /// <returns>Returns a signed <see cref=\"Maj23\"/>.</returns>\n        public Maj23 Sign(PrivateKey signer) =>\n            new Maj23(this, signer.Sign(ByteArray).ToImmutableArray());\n\n        /// <inheritdoc/>\n        public bool Equals(Maj23Metadata? other)\n        {\n            return other is { } metadata &&\n                Height == metadata.Height &&\n                Round == metadata.Round &&\n                BlockHash.Equals(metadata.BlockHash) &&\n                Timestamp\n                    .ToString(TimestampFormat, CultureInfo.InvariantCulture).Equals(\n                        metadata.Timestamp.ToString(\n                            TimestampFormat,\n                            CultureInfo.InvariantCulture)) &&\n                ValidatorPublicKey.Equals(metadata.ValidatorPublicKey) &&\n                Flag == metadata.Flag;\n        }\n\n        /// <inheritdoc/>\n        public override bool Equals(object? obj) =>\n            obj is Maj23Metadata other && Equals(other);\n\n        /// <inheritdoc/>\n        public override int GetHashCode()\n        {\n            return HashCode.Combine(\n                Height,\n                Round,\n                BlockHash,\n                Timestamp.ToString(TimestampFormat, CultureInfo.InvariantCulture),\n                ValidatorPublicKey,\n                Flag);\n        }\n    }\n}\n"
  },
  {
    "path": "src/Libplanet/Consensus/Proposal.cs",
    "content": "using System;\nusing System.Collections.Immutable;\nusing System.Diagnostics.Contracts;\nusing System.Linq;\nusing System.Text.Json.Serialization;\nusing Bencodex;\nusing Bencodex.Types;\nusing Libplanet.Common;\nusing Libplanet.Crypto;\nusing Libplanet.Types.Blocks;\nusing Libplanet.Types.Consensus;\n\nnamespace Libplanet.Consensus\n{\n    /// <summary>\n    /// Represents a <see cref=\"Proposal\"/> from a validator for consensus.  It contains an\n    /// essential information <see cref=\"ProposalMetadata\"/> to propose a block for a consensus\n    /// in a height and a round, and its signature to verify. The signature is verified in\n    /// constructor, so the instance of <see cref=\"Proposal\"/> should be valid.\n    /// </summary>\n    public class Proposal : IEquatable<Proposal>\n    {\n        // FIXME: This should be private.  Left as internal for testing reasons.\n        internal static readonly Binary SignatureKey = new Binary(new byte[] { 0x53 }); // 'S'\n        private static readonly Codec _codec = new Codec();\n\n        private readonly ProposalMetadata _proposalMetadata;\n\n        /// <summary>\n        /// Instantiates a <see cref=\"Proposal\"/> with given <paramref name=\"proposalMetadata\"/>\n        /// and its <paramref name=\"signature\"/>.\n        /// </summary>\n        /// <param name=\"proposalMetadata\">A <see cref=\"ProposalMetadata\"/> to propose.</param>\n        /// <param name=\"signature\">A signature signed with <paramref name=\"proposalMetadata\"/>.\n        /// </param>\n        /// <exception cref=\"ArgumentNullException\">Thrown if given <paramref name=\"signature\"/> is\n        /// empty.</exception>\n        /// <exception cref=\"ArgumentException\">Thrown if given <paramref name=\"signature\"/> is\n        /// invalid and cannot be verified with <paramref name=\"proposalMetadata\"/>.</exception>\n        public Proposal(ProposalMetadata proposalMetadata, ImmutableArray<byte> signature)\n        {\n            _proposalMetadata = proposalMetadata;\n            Signature = signature;\n\n            if (signature.IsDefaultOrEmpty)\n            {\n                throw new ArgumentNullException(\n                    nameof(signature),\n                    \"Signature cannot be null or empty.\");\n            }\n            else if (!Verify())\n            {\n                throw new ArgumentException(\"Signature is invalid.\", nameof(signature));\n            }\n        }\n\n        public Proposal(byte[] marshaled)\n            : this((Dictionary)_codec.Decode(marshaled))\n        {\n        }\n\n#pragma warning disable SA1118 // The parameter spans multiple lines\n        public Proposal(Dictionary encoded)\n            : this(\n                new ProposalMetadata(encoded),\n                encoded.ContainsKey(SignatureKey)\n                    ? ((Binary)encoded[SignatureKey]).ByteArray\n                    : ImmutableArray<byte>.Empty)\n        {\n        }\n#pragma warning restore SA1118\n\n        /// <inheritdoc cref=\"ProposalMetadata.Height\"/>\n        public long Height => _proposalMetadata.Height;\n\n        /// <inheritdoc cref=\"ProposalMetadata.Round\"/>\n        public int Round => _proposalMetadata.Round;\n\n        /// <inheritdoc cref=\"ProposalMetadata.BlockHash\"/>\n        public BlockHash BlockHash => _proposalMetadata.BlockHash;\n\n        /// <inheritdoc cref=\"ProposalMetadata.Timestamp\"/>\n        public DateTimeOffset Timestamp => _proposalMetadata.Timestamp;\n\n        /// <inheritdoc cref=\"ProposalMetadata.ValidatorPublicKey\"/>\n        public PublicKey ValidatorPublicKey => _proposalMetadata.ValidatorPublicKey;\n\n        /// <inheritdoc cref=\"ProposalMetadata.MarshaledBlock\"/>\n        public byte[] MarshaledBlock => _proposalMetadata.MarshaledBlock;\n\n        /// <inheritdoc cref=\"ProposalMetadata.ValidRound\"/>\n        public int ValidRound => _proposalMetadata.ValidRound;\n\n        /// <summary>\n        /// A signature that signed with <see cref=\"ProposalMetadata\"/>.\n        /// </summary>\n        public ImmutableArray<byte> Signature { get; }\n\n        /// <summary>\n        /// A Bencodex-encoded value of <see cref=\"Proposal\"/>.\n        /// </summary>\n        [JsonIgnore]\n        public Dictionary Encoded =>\n            !Signature.IsEmpty\n                ? _proposalMetadata.Encoded.Add(SignatureKey, Signature)\n                : _proposalMetadata.Encoded;\n\n        /// <summary>\n        /// <see cref=\"byte\"/> encoded <see cref=\"Proposal\"/> data.\n        /// </summary>\n        public ImmutableArray<byte> ByteArray => ToByteArray().ToImmutableArray();\n\n        public byte[] ToByteArray() => _codec.Encode(Encoded);\n\n        /// <summary>\n        /// Verifies whether the <see cref=\"ProposalMetadata\"/> is properly signed by\n        /// <see cref=\"Validator\"/>.\n        /// </summary>\n        /// <returns><see langword=\"true\"/> if the <see cref=\"Signature\"/> is not empty\n        /// and is a valid signature signed by <see cref=\"Validator\"/>.</returns>\n        [Pure]\n        public bool Verify() =>\n            !Signature.IsDefaultOrEmpty &&\n            ValidatorPublicKey.Verify(\n                _proposalMetadata.ByteArray.ToImmutableArray(),\n                Signature);\n\n        /// <inheritdoc/>\n        [Pure]\n        public bool Equals(Proposal? other)\n        {\n            return other is Proposal proposal &&\n                   _proposalMetadata.Equals(proposal._proposalMetadata) &&\n                   Signature.SequenceEqual(proposal.Signature);\n        }\n\n        /// <inheritdoc/>\n        [Pure]\n        public override bool Equals(object? obj)\n        {\n            return obj is Proposal other && Equals(other);\n        }\n\n        /// <inheritdoc/>\n        [Pure]\n        public override int GetHashCode()\n        {\n            return HashCode.Combine(\n                _proposalMetadata.GetHashCode(),\n                ByteUtil.CalculateHashCode(Signature.ToArray()));\n        }\n    }\n}\n"
  },
  {
    "path": "src/Libplanet/Consensus/ProposalClaim.cs",
    "content": "using System;\nusing System.Collections.Immutable;\nusing System.Diagnostics.Contracts;\nusing System.Linq;\nusing System.Text.Json.Serialization;\nusing Bencodex;\nusing Bencodex.Types;\nusing Libplanet.Common;\nusing Libplanet.Crypto;\nusing Libplanet.Types.Blocks;\nusing Libplanet.Types.Consensus;\n\nnamespace Libplanet.Consensus\n{\n    /// <summary>\n    /// Represents a <see cref=\"ProposalClaim\"/> from a validator for consensus.  It contains an\n    /// essential information <see cref=\"ProposalClaimMetadata\"/> to claim a <see cref=\"Proposal\"/>\n    /// for a consensus in a height, round, <see cref=\"BlockHash\"/>, and its signature to verify.\n    /// The signature is verified in\n    /// constructor, so the instance of <see cref=\"ProposalClaim\"/> should be valid.\n    /// </summary>\n    public class ProposalClaim : IEquatable<ProposalClaim>\n    {\n        // FIXME: This should be private.  Left as internal for testing reasons.\n        internal static readonly Binary SignatureKey = new Binary(new byte[] { 0x53 }); // 'S'\n        private static readonly Codec _codec = new Codec();\n\n        private readonly ProposalClaimMetadata _metadata;\n\n        /// <summary>\n        /// Instantiates a <see cref=\"ProposalClaim\"/> with given <paramref name=\"metadata\"/>\n        /// and its <paramref name=\"signature\"/>.\n        /// </summary>\n        /// <param name=\"metadata\">A <see cref=\"ProposalClaimMetadata\"/> to claim.</param>\n        /// <param name=\"signature\">A signature signed with <paramref name=\"metadata\"/>.\n        /// </param>\n        /// <exception cref=\"ArgumentNullException\">Thrown if given <paramref name=\"signature\"/> is\n        /// empty.</exception>\n        /// <exception cref=\"ArgumentException\">Thrown if given <paramref name=\"signature\"/> is\n        /// invalid and cannot be verified with <paramref name=\"metadata\"/>.</exception>\n        public ProposalClaim(ProposalClaimMetadata metadata, ImmutableArray<byte> signature)\n        {\n            _metadata = metadata;\n            Signature = signature;\n\n            if (signature.IsDefaultOrEmpty)\n            {\n                throw new ArgumentNullException(\n                    nameof(signature),\n                    \"Signature cannot be null or empty.\");\n            }\n            else if (!Verify())\n            {\n                throw new ArgumentException(\"Signature is invalid.\", nameof(signature));\n            }\n        }\n\n        public ProposalClaim(byte[] marshaled)\n            : this((Dictionary)_codec.Decode(marshaled))\n        {\n        }\n\n#pragma warning disable SA1118 // The parameter spans multiple lines\n        public ProposalClaim(Dictionary encoded)\n            : this(\n                new ProposalClaimMetadata(encoded),\n                encoded.ContainsKey(SignatureKey)\n                    ? ((Binary)encoded[SignatureKey]).ByteArray\n                    : ImmutableArray<byte>.Empty)\n        {\n        }\n#pragma warning restore SA1118\n\n        /// <inheritdoc cref=\"ProposalClaimMetadata.Height\"/>\n        public long Height => _metadata.Height;\n\n        /// <inheritdoc cref=\"ProposalClaimMetadata.Round\"/>\n        public int Round => _metadata.Round;\n\n        /// <inheritdoc cref=\"ProposalClaimMetadata.BlockHash\"/>\n        public BlockHash BlockHash => _metadata.BlockHash;\n\n        /// <inheritdoc cref=\"ProposalClaimMetadata.Timestamp\"/>\n        public DateTimeOffset Timestamp => _metadata.Timestamp;\n\n        /// <inheritdoc cref=\"ProposalClaimMetadata.ValidatorPublicKey\"/>\n        public PublicKey ValidatorPublicKey => _metadata.ValidatorPublicKey;\n\n        /// <summary>\n        /// A signature that signed with <see cref=\"ProposalMetadata\"/>.\n        /// </summary>\n        public ImmutableArray<byte> Signature { get; }\n\n        /// <summary>\n        /// A Bencodex-encoded value of <see cref=\"ProposalClaim\"/>.\n        /// </summary>\n        [JsonIgnore]\n        public Dictionary Encoded =>\n            !Signature.IsEmpty\n                ? _metadata.Encoded.Add(SignatureKey, Signature)\n                : _metadata.Encoded;\n\n        /// <summary>\n        /// <see cref=\"byte\"/> encoded <see cref=\"Proposal\"/> data.\n        /// </summary>\n        public ImmutableArray<byte> ByteArray => ToByteArray().ToImmutableArray();\n\n        public byte[] ToByteArray() => _codec.Encode(Encoded);\n\n        /// <summary>\n        /// Verifies whether the <see cref=\"ProposalMetadata\"/> is properly signed by\n        /// <see cref=\"Validator\"/>.\n        /// </summary>\n        /// <returns><see langword=\"true\"/> if the <see cref=\"Signature\"/> is not empty\n        /// and is a valid signature signed by <see cref=\"Validator\"/>.</returns>\n        [Pure]\n        public bool Verify() =>\n            !Signature.IsDefaultOrEmpty &&\n            ValidatorPublicKey.Verify(\n                _metadata.ByteArray.ToImmutableArray(),\n                Signature);\n\n        /// <inheritdoc/>\n        [Pure]\n        public bool Equals(ProposalClaim? other)\n        {\n            return other is ProposalClaim proposalClaim &&\n                   _metadata.Equals(proposalClaim._metadata) &&\n                   Signature.SequenceEqual(proposalClaim.Signature);\n        }\n\n        /// <inheritdoc/>\n        [Pure]\n        public override bool Equals(object? obj)\n        {\n            return obj is ProposalClaim other && Equals(other);\n        }\n\n        /// <inheritdoc/>\n        [Pure]\n        public override int GetHashCode()\n        {\n            return HashCode.Combine(\n                _metadata.GetHashCode(),\n                ByteUtil.CalculateHashCode(Signature.ToArray()));\n        }\n    }\n}\n"
  },
  {
    "path": "src/Libplanet/Consensus/ProposalClaimMetadata.cs",
    "content": "using System;\nusing System.Collections.Immutable;\nusing System.Globalization;\nusing System.Text.Json.Serialization;\nusing Bencodex;\nusing Bencodex.Types;\nusing Libplanet.Crypto;\nusing Libplanet.Types.Blocks;\n\nnamespace Libplanet.Consensus\n{\n    /// <summary>\n    /// A class for constructing <see cref=\"ProposalClaim\"/>. This class contains proposal claim\n    /// information in consensus of a height, round and <see cref=\"BlockHash\"/>.\n    /// Use <see cref=\"Sign\"/> to create a <see cref=\"ProposalClaim\"/>.\n    /// </summary>\n    public class ProposalClaimMetadata : IEquatable<ProposalClaimMetadata>\n    {\n        private const string TimestampFormat = \"yyyy-MM-ddTHH:mm:ss.ffffffZ\";\n        private static readonly Binary HeightKey =\n            new Binary(new byte[] { 0x48 }); // 'H'\n\n        private static readonly Binary RoundKey =\n            new Binary(new byte[] { 0x52 }); // 'R'\n\n        private static readonly Binary BlockHashKey =\n            new Binary(new byte[] { 0x68 }); // 'h'\n\n        private static readonly Binary TimestampKey =\n            new Binary(new byte[] { 0x74 }); // 't'\n\n        private static readonly Binary ValidatorPublicKeyKey =\n            new Binary(new byte[] { 0x50 }); // 'P'\n\n        private static readonly Codec _codec = new Codec();\n\n        /// <summary>\n        /// Instantiates <see cref=\"ProposalClaimMetadata\"/> with given parameters.\n        /// </summary>\n        /// <param name=\"height\">A height of given claim values.</param>\n        /// <param name=\"round\">A round of given claim values.</param>\n        /// <param name=\"blockHash\">A <see cref=\"BlockHash\"/> of given proposal to claim.</param>\n        /// <param name=\"timestamp\">The time at which the proposal took place.</param>\n        /// <param name=\"validatorPublicKey\">a <see cref=\"PublicKey\"/> of proposing validator.\n        /// </param>\n        /// <exception cref=\"ArgumentOutOfRangeException\">This can be thrown in following reasons:\n        /// <list type=\"bullet\">\n        /// <item><description>\n        ///     Given <paramref name=\"height\"/> is less than 0.\n        /// </description></item>\n        /// <item><description>\n        ///     Given <paramref name=\"round\"/> is less than 0.\n        /// </description></item>\n        /// </list>\n        /// </exception>\n        public ProposalClaimMetadata(\n            long height,\n            int round,\n            BlockHash blockHash,\n            DateTimeOffset timestamp,\n            PublicKey validatorPublicKey)\n        {\n            if (height < 0)\n            {\n                throw new ArgumentOutOfRangeException(\n                    nameof(height),\n                    \"Height must be greater than or equal to 0.\");\n            }\n            else if (round < 0)\n            {\n                throw new ArgumentOutOfRangeException(\n                    nameof(round),\n                    \"Round must be greater than or equal to 0.\");\n            }\n\n            Height = height;\n            Round = round;\n            BlockHash = blockHash;\n            Timestamp = timestamp;\n            ValidatorPublicKey = validatorPublicKey;\n        }\n\n#pragma warning disable SA1118 // The parameter spans multiple lines\n        public ProposalClaimMetadata(Dictionary encoded)\n            : this(\n                height: (Integer)encoded[HeightKey],\n                round: (Integer)encoded[RoundKey],\n                blockHash: new BlockHash(encoded[BlockHashKey]),\n                timestamp: DateTimeOffset.ParseExact(\n                    (Text)encoded[TimestampKey],\n                    TimestampFormat,\n                    CultureInfo.InvariantCulture),\n                validatorPublicKey: new PublicKey(\n                    ((Binary)encoded[ValidatorPublicKeyKey]).ByteArray))\n        {\n        }\n#pragma warning restore SA1118\n\n        /// <summary>\n        /// A height of given proposal values.\n        /// </summary>\n        public long Height { get; }\n\n        /// <summary>\n        /// A round of given proposal values.\n        /// </summary>\n        public int Round { get; }\n\n        /// <summary>\n        /// The <see cref=\"Types.Blocks.BlockHash\"/> of <see cref=\"Proposal\"/> to claim.\n        /// </summary>\n        public BlockHash BlockHash { get; }\n\n        /// <summary>\n        /// The time at which the proposal took place.\n        /// </summary>\n        public DateTimeOffset Timestamp { get; }\n\n        /// <summary>\n        /// A <see cref=\"PublicKey\"/> of proposing validator.\n        /// </summary>\n        public PublicKey ValidatorPublicKey { get; }\n\n        /// <summary>\n        /// A Bencodex-encoded value of <see cref=\"ProposalMetadata\"/>.\n        /// </summary>\n        [JsonIgnore]\n        public Dictionary Encoded\n        {\n            get\n            {\n                Dictionary encoded = Bencodex.Types.Dictionary.Empty\n                    .Add(HeightKey, Height)\n                    .Add(RoundKey, Round)\n                    .Add(BlockHashKey, BlockHash.ByteArray)\n                    .Add(\n                        TimestampKey,\n                        Timestamp.ToString(TimestampFormat, CultureInfo.InvariantCulture))\n                    .Add(ValidatorPublicKeyKey, ValidatorPublicKey.Format(compress: true));\n\n                return encoded;\n            }\n        }\n\n        public ImmutableArray<byte> ByteArray => ToByteArray().ToImmutableArray();\n\n        public byte[] ToByteArray() => _codec.Encode(Encoded);\n\n        /// <summary>\n        /// Signs given <see cref=\"ProposalMetadata\"/> with given <paramref name=\"signer\"/>.\n        /// </summary>\n        /// <param name=\"signer\">A <see cref=\"PrivateKey\"/> to sign.</param>\n        /// <returns>Returns a signed <see cref=\"Proposal\"/>.</returns>\n        public ProposalClaim Sign(PrivateKey signer) =>\n            new ProposalClaim(this, signer.Sign(ByteArray).ToImmutableArray());\n\n        /// <inheritdoc/>\n        public bool Equals(ProposalClaimMetadata? other)\n        {\n            return other is ProposalClaimMetadata metadata &&\n                Height == metadata.Height &&\n                Round == metadata.Round &&\n                BlockHash.Equals(metadata.BlockHash) &&\n                Timestamp\n                    .ToString(TimestampFormat, CultureInfo.InvariantCulture).Equals(\n                        metadata.Timestamp.ToString(\n                            TimestampFormat,\n                            CultureInfo.InvariantCulture)) &&\n                ValidatorPublicKey.Equals(metadata.ValidatorPublicKey);\n        }\n\n        /// <inheritdoc/>\n        public override bool Equals(object? obj) =>\n            obj is ProposalMetadata other && Equals(other);\n\n        /// <inheritdoc/>\n        public override int GetHashCode()\n        {\n            return HashCode.Combine(\n                Height,\n                Round,\n                BlockHash,\n                Timestamp.ToString(TimestampFormat, CultureInfo.InvariantCulture),\n                ValidatorPublicKey);\n        }\n    }\n}\n"
  },
  {
    "path": "src/Libplanet/Consensus/ProposalMetadata.cs",
    "content": "using System;\nusing System.Collections.Immutable;\nusing System.Globalization;\nusing System.Text.Json.Serialization;\nusing Bencodex;\nusing Bencodex.Types;\nusing Libplanet.Crypto;\nusing Libplanet.Types.Blocks;\n\nnamespace Libplanet.Consensus\n{\n    /// <summary>\n    /// A class for constructing <see cref=\"Proposal\"/>. This class contains proposal information\n    /// in consensus of a height and a round. Use <see cref=\"Sign\"/> to create a\n    /// <see cref=\"Proposal\"/>.\n    /// </summary>\n    public class ProposalMetadata : IEquatable<ProposalMetadata>\n    {\n        private const string TimestampFormat = \"yyyy-MM-ddTHH:mm:ss.ffffffZ\";\n        private static readonly Binary HeightKey =\n            new Binary(new byte[] { 0x48 }); // 'H'\n\n        private static readonly Binary RoundKey =\n            new Binary(new byte[] { 0x52 }); // 'R'\n\n        private static readonly Binary TimestampKey =\n            new Binary(new byte[] { 0x74 }); // 't'\n\n        private static readonly Binary ValidatorPublicKeyKey =\n            new Binary(new byte[] { 0x50 }); // 'P'\n\n        private static readonly Binary BlockKey =\n            new Binary(new byte[] { 0x42 }); // 'B'\n\n        private static readonly Binary ValidRoundKey =\n            new Binary(new byte[] { 0x56 }); // 'V'\n\n        private static readonly Codec _codec = new Codec();\n\n        /// <summary>\n        /// Instantiates <see cref=\"ProposalMetadata\"/> with given parameters.\n        /// </summary>\n        /// <param name=\"height\">a height of given proposal values.</param>\n        /// <param name=\"round\">a round of given proposal values.</param>\n        /// <param name=\"timestamp\">The time at which the proposal took place.</param>\n        /// <param name=\"validatorPublicKey\">a <see cref=\"PublicKey\"/> of proposing validator.\n        /// </param>\n        /// <param name=\"validRound\">a latest valid round at the moment of given proposal.</param>\n        /// <param name=\"marshaledBlock\">a marshaled bencodex-encoded <see cref=\"byte\"/> array of\n        /// block.</param>\n        /// <exception cref=\"ArgumentOutOfRangeException\">This can be thrown in following reasons:\n        /// <list type=\"bullet\">\n        /// <item><description>\n        ///     Given <paramref name=\"height\"/> is less than 0.\n        /// </description></item>\n        /// <item><description>\n        ///     Given <paramref name=\"round\"/> is less than 0.\n        /// </description></item>\n        /// <item><description>\n        ///     Given <paramref name=\"validRound\"/> is less than -1.\n        /// </description></item>\n        /// </list>\n        /// </exception>\n        public ProposalMetadata(\n            long height,\n            int round,\n            DateTimeOffset timestamp,\n            PublicKey validatorPublicKey,\n            byte[] marshaledBlock,\n            int validRound)\n        {\n            if (height < 0)\n            {\n                throw new ArgumentOutOfRangeException(\n                    nameof(height),\n                    \"Height must be greater than or equal to 0.\");\n            }\n            else if (round < 0)\n            {\n                throw new ArgumentOutOfRangeException(\n                    nameof(round),\n                    \"Round must be greater than or equal to 0.\");\n            }\n            else if (validRound < -1)\n            {\n                throw new ArgumentOutOfRangeException(\n                    nameof(validRound),\n                    \"ValidRound must be greater than or equal to -1.\");\n            }\n\n            Height = height;\n            Round = round;\n            BlockHash = BlockMarshaler.UnmarshalBlockHash(\n                (Dictionary)_codec.Decode(marshaledBlock));\n            Timestamp = timestamp;\n            ValidatorPublicKey = validatorPublicKey;\n            MarshaledBlock = marshaledBlock;\n            ValidRound = validRound;\n        }\n\n#pragma warning disable SA1118 // The parameter spans multiple lines\n        public ProposalMetadata(Dictionary encoded)\n            : this(\n                height: (Integer)encoded[HeightKey],\n                round: (Integer)encoded[RoundKey],\n                timestamp: DateTimeOffset.ParseExact(\n                    (Text)encoded[TimestampKey],\n                    TimestampFormat,\n                    CultureInfo.InvariantCulture),\n                validatorPublicKey: new PublicKey(\n                    ((Binary)encoded[ValidatorPublicKeyKey]).ByteArray),\n                marshaledBlock: ((Binary)encoded[BlockKey]).ToByteArray(),\n                validRound: (Integer)encoded[ValidRoundKey])\n        {\n        }\n#pragma warning restore SA1118\n\n        /// <summary>\n        /// A height of given proposal values.\n        /// </summary>\n        public long Height { get; }\n\n        /// <summary>\n        /// A round of given proposal values.\n        /// </summary>\n        public int Round { get; }\n\n        /// <summary>\n        /// The <see cref=\"Types.Blocks.BlockHash\"/> of <see cref=\"MarshaledBlock\"/>.\n        /// This is automatically derived from <see cref=\"MarshaledBlock\"/>.\n        /// </summary>\n        public BlockHash BlockHash { get; }\n\n        /// <summary>\n        /// The time at which the proposal took place.\n        /// </summary>\n        public DateTimeOffset Timestamp { get; }\n\n        /// <summary>\n        /// A <see cref=\"PublicKey\"/> of proposing validator.\n        /// </summary>\n        public PublicKey ValidatorPublicKey { get; }\n\n        /// <summary>\n        /// A marshaled bencodex-encoded <see cref=\"byte\"/> array of block.\n        /// </summary>\n        public byte[] MarshaledBlock { get; }\n\n        /// <summary>\n        /// a latest valid round at the moment of given proposal.\n        /// </summary>\n        public int ValidRound { get; }\n\n        /// <summary>\n        /// A Bencodex-encoded value of <see cref=\"ProposalMetadata\"/>.\n        /// </summary>\n        [JsonIgnore]\n        public Dictionary Encoded\n        {\n            get\n            {\n                Dictionary encoded = Bencodex.Types.Dictionary.Empty\n                    .Add(HeightKey, Height)\n                    .Add(RoundKey, Round)\n                    .Add(\n                        TimestampKey,\n                        Timestamp.ToString(TimestampFormat, CultureInfo.InvariantCulture))\n                    .Add(ValidatorPublicKeyKey, ValidatorPublicKey.Format(compress: true))\n                    .Add(BlockKey, MarshaledBlock)\n                    .Add(ValidRoundKey, ValidRound);\n\n                return encoded;\n            }\n        }\n\n        public ImmutableArray<byte> ByteArray => ToByteArray().ToImmutableArray();\n\n        public byte[] ToByteArray() => _codec.Encode(Encoded);\n\n        /// <summary>\n        /// Signs given <see cref=\"ProposalMetadata\"/> with given <paramref name=\"signer\"/>.\n        /// </summary>\n        /// <param name=\"signer\">A <see cref=\"PrivateKey\"/> to sign.</param>\n        /// <returns>Returns a signed <see cref=\"Proposal\"/>.</returns>\n        public Proposal Sign(PrivateKey signer) =>\n            new Proposal(this, signer.Sign(ByteArray).ToImmutableArray());\n\n        /// <inheritdoc/>\n        public bool Equals(ProposalMetadata? other)\n        {\n            return other is ProposalMetadata metadata &&\n                Height == metadata.Height &&\n                Round == metadata.Round &&\n                BlockHash.Equals(metadata.BlockHash) &&\n                Timestamp\n                    .ToString(TimestampFormat, CultureInfo.InvariantCulture).Equals(\n                        metadata.Timestamp.ToString(\n                            TimestampFormat,\n                            CultureInfo.InvariantCulture)) &&\n                ValidatorPublicKey.Equals(metadata.ValidatorPublicKey) &&\n                ValidRound == metadata.ValidRound;\n        }\n\n        /// <inheritdoc/>\n        public override bool Equals(object? obj) =>\n            obj is ProposalMetadata other && Equals(other);\n\n        /// <inheritdoc/>\n        public override int GetHashCode()\n        {\n            return HashCode.Combine(\n                Height,\n                Round,\n                BlockHash,\n                Timestamp.ToString(TimestampFormat, CultureInfo.InvariantCulture),\n                ValidatorPublicKey,\n                ValidRound);\n        }\n    }\n}\n"
  },
  {
    "path": "src/Libplanet/Consensus/VoteSetBits.cs",
    "content": "using System;\nusing System.Collections.Immutable;\nusing System.Diagnostics.Contracts;\nusing System.Linq;\nusing System.Text.Json.Serialization;\nusing Bencodex;\nusing Bencodex.Types;\nusing Libplanet.Common;\nusing Libplanet.Crypto;\nusing Libplanet.Types.Blocks;\nusing Libplanet.Types.Consensus;\n\nnamespace Libplanet.Consensus\n{\n    /// <summary>\n    /// A class used to requests lacking votes by sending <see cref=\"Vote\"/>s that the peer has.\n    /// </summary>\n    public class VoteSetBits : IEquatable<VoteSetBits>\n    {\n        // FIXME: This should be private.  Left as internal for testing reasons.\n        internal static readonly Binary SignatureKey = new Binary(new byte[] { 0x53 }); // 'S'\n        private static Codec _codec = new Codec();\n\n        private readonly VoteSetBitsMetadata _voteSetBitsMetadata;\n\n        /// <summary>\n        /// Instantiates a <see cref=\"VoteSetBits\"/> with given\n        /// <paramref name=\"voteSetBitsMetadata\"/> and its <paramref name=\"signature\"/>.\n        /// </summary>\n        /// <param name=\"voteSetBitsMetadata\">\n        /// A <see cref=\"VoteSetBitsMetadata\"/> to request.</param>\n        /// <param name=\"signature\">A signature signed with <paramref name=\"voteSetBitsMetadata\"/>.\n        /// </param>\n        /// <exception cref=\"ArgumentNullException\">Thrown if given <paramref name=\"signature\"/> is\n        /// empty.</exception>\n        /// <exception cref=\"ArgumentException\">Thrown if given <paramref name=\"signature\"/> is\n        /// invalid and cannot be verified with <paramref name=\"voteSetBitsMetadata\"/>.</exception>\n        public VoteSetBits(VoteSetBitsMetadata voteSetBitsMetadata, ImmutableArray<byte> signature)\n        {\n            _voteSetBitsMetadata = voteSetBitsMetadata;\n            Signature = signature;\n\n            if (signature.IsDefaultOrEmpty)\n            {\n                throw new ArgumentNullException(\n                    nameof(signature),\n                    \"Signature cannot be null or empty.\");\n            }\n            else if (!Verify())\n            {\n                throw new ArgumentException(\"Signature is invalid.\", nameof(signature));\n            }\n        }\n\n        public VoteSetBits(byte[] marshaled)\n            : this((Dictionary)_codec.Decode(marshaled))\n        {\n        }\n\n#pragma warning disable SA1118 // The parameter spans multiple lines\n        public VoteSetBits(Dictionary encoded)\n            : this(\n                new VoteSetBitsMetadata(encoded),\n                encoded.ContainsKey(SignatureKey)\n                    ? ((Binary)encoded[SignatureKey]).ByteArray\n                    : ImmutableArray<byte>.Empty)\n        {\n        }\n#pragma warning restore SA1118\n\n        /// <inheritdoc cref=\"VoteSetBitsMetadata.Height\"/>\n        public long Height => _voteSetBitsMetadata.Height;\n\n        /// <inheritdoc cref=\"VoteSetBitsMetadata.Round\"/>\n        public int Round => _voteSetBitsMetadata.Round;\n\n        /// <inheritdoc cref=\"VoteSetBitsMetadata.BlockHash\"/>\n        public BlockHash BlockHash => _voteSetBitsMetadata.BlockHash;\n\n        /// <inheritdoc cref=\"VoteSetBitsMetadata.Timestamp\"/>\n        public DateTimeOffset Timestamp => _voteSetBitsMetadata.Timestamp;\n\n        /// <inheritdoc cref=\"VoteSetBitsMetadata.ValidatorPublicKey\"/>\n        public PublicKey ValidatorPublicKey => _voteSetBitsMetadata.ValidatorPublicKey;\n\n        /// <inheritdoc cref=\"VoteSetBitsMetadata.Flag\"/>\n        public VoteFlag Flag => _voteSetBitsMetadata.Flag;\n\n        /// <inheritdoc cref=\"VoteSetBitsMetadata.VoteBits\"/>\n        public ImmutableArray<bool> VoteBits => _voteSetBitsMetadata.VoteBits;\n\n        /// <summary>\n        /// A signature that signed with <see cref=\"VoteSetBitsMetadata\"/>.\n        /// </summary>\n        public ImmutableArray<byte> Signature { get; }\n\n        /// <summary>\n        /// A Bencodex-encoded value of <see cref=\"VoteSetBits\"/>.\n        /// </summary>\n        [JsonIgnore]\n        public Dictionary Encoded =>\n            !Signature.IsEmpty\n                ? _voteSetBitsMetadata.Encoded.Add(SignatureKey, Signature)\n                : _voteSetBitsMetadata.Encoded;\n\n        /// <summary>\n        /// <see cref=\"byte\"/> encoded <see cref=\"VoteSetBits\"/> data.\n        /// </summary>\n        public ImmutableArray<byte> ByteArray => ToByteArray().ToImmutableArray();\n\n        public byte[] ToByteArray() => _codec.Encode(Encoded);\n\n        /// <summary>\n        /// Verifies whether the <see cref=\"VoteSetBitsMetadata\"/> is properly signed by\n        /// <see cref=\"Validator\"/>.\n        /// </summary>\n        /// <returns><see langword=\"true\"/> if the <see cref=\"Signature\"/> is not empty\n        /// and is a valid signature signed by <see cref=\"Validator\"/>.</returns>\n        [Pure]\n        public bool Verify() =>\n            !Signature.IsDefaultOrEmpty &&\n            ValidatorPublicKey.Verify(\n                _voteSetBitsMetadata.ByteArray.ToImmutableArray(),\n                Signature);\n\n        /// <inheritdoc/>\n        [Pure]\n        public bool Equals(VoteSetBits? other)\n        {\n            return other is { } voteSetBits &&\n                   _voteSetBitsMetadata.Equals(voteSetBits._voteSetBitsMetadata) &&\n                   Signature.SequenceEqual(voteSetBits.Signature);\n        }\n\n        /// <inheritdoc/>\n        [Pure]\n        public override bool Equals(object? obj)\n        {\n            return obj is VoteSetBits other && Equals(other);\n        }\n\n        /// <inheritdoc/>\n        [Pure]\n        public override int GetHashCode()\n        {\n            return HashCode.Combine(\n                _voteSetBitsMetadata.GetHashCode(),\n                ByteUtil.CalculateHashCode(Signature.ToArray()));\n        }\n    }\n}\n"
  },
  {
    "path": "src/Libplanet/Consensus/VoteSetBitsMetadata.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Collections.Immutable;\nusing System.Globalization;\nusing System.Linq;\nusing System.Text.Json.Serialization;\nusing Bencodex;\nusing Bencodex.Types;\nusing Libplanet.Crypto;\nusing Libplanet.Types.Blocks;\nusing Libplanet.Types.Consensus;\n\nnamespace Libplanet.Consensus\n{\n    public class VoteSetBitsMetadata : IEquatable<VoteSetBitsMetadata>\n    {\n        private const string TimestampFormat = \"yyyy-MM-ddTHH:mm:ss.ffffffZ\";\n        private static readonly Binary HeightKey =\n            new Binary(new byte[] { 0x48 }); // 'H'\n\n        private static readonly Binary RoundKey =\n            new Binary(new byte[] { 0x52 }); // 'R'\n\n        private static readonly Binary TimestampKey =\n            new Binary(new byte[] { 0x74 }); // 't'\n\n        private static readonly Binary ValidatorPublicKeyKey =\n            new Binary(new byte[] { 0x50 }); // 'P'\n\n        private static readonly Binary BlockHashKey =\n            new Binary(new byte[] { 0x42 }); // 'B'\n\n        private static readonly Binary FlagKey =\n            new Binary(new byte[] { 0x46 }); // 'F'\n\n        private static readonly Binary VoteBitsKey =\n            new Binary(new byte[] { 0x56 }); // 'V'\n\n        private static readonly Codec _codec = new Codec();\n\n        public VoteSetBitsMetadata(\n            long height,\n            int round,\n            BlockHash blockHash,\n            DateTimeOffset timestamp,\n            PublicKey validatorPublicKey,\n            VoteFlag flag,\n            IEnumerable<bool> voteBits)\n        {\n            if (height < 0)\n            {\n                throw new ArgumentOutOfRangeException(\n                    nameof(height),\n                    \"Height must be greater than or equal to 0.\");\n            }\n            else if (round < 0)\n            {\n                throw new ArgumentOutOfRangeException(\n                    nameof(round),\n                    \"Round must be greater than or equal to 0.\");\n            }\n\n            if (flag == VoteFlag.Null || flag == VoteFlag.Unknown)\n            {\n                throw new ArgumentException(\n                    \"Vote flag should be PreVote or PreCommit.\",\n                    nameof(flag));\n            }\n\n            Height = height;\n            Round = round;\n            BlockHash = blockHash;\n            Timestamp = timestamp;\n            ValidatorPublicKey = validatorPublicKey;\n            Flag = flag;\n            VoteBits = voteBits.ToImmutableArray();\n        }\n\n#pragma warning disable SA1118 // The parameter spans multiple lines\n        public VoteSetBitsMetadata(Dictionary encoded)\n            : this(\n                height: (Integer)encoded[HeightKey],\n                round: (Integer)encoded[RoundKey],\n                blockHash: new BlockHash(encoded[BlockHashKey]),\n                timestamp: DateTimeOffset.ParseExact(\n                    (Text)encoded[TimestampKey],\n                    TimestampFormat,\n                    CultureInfo.InvariantCulture),\n                validatorPublicKey: new PublicKey(\n                    ((Binary)encoded[ValidatorPublicKeyKey]).ByteArray),\n                flag: (VoteFlag)(int)(Integer)encoded[FlagKey],\n                voteBits: ((List)encoded[VoteBitsKey])\n                    .Select(bit => (bool)(Bencodex.Types.Boolean)bit))\n        {\n        }\n#pragma warning restore SA1118\n\n        /// <summary>\n        /// A height of the votes in the given vote set.\n        /// </summary>\n        public long Height { get; }\n\n        /// <summary>\n        /// A round of the votes in the given vote set.\n        /// </summary>\n        public int Round { get; }\n\n        /// <summary>\n        /// The <see cref=\"Types.Blocks.BlockHash\"/> of the votes in the vote sets.\n        /// </summary>\n        public BlockHash BlockHash { get; }\n\n        /// <summary>\n        /// The time at which the set is created.\n        /// </summary>\n        public DateTimeOffset Timestamp { get; }\n\n        /// <summary>\n        /// A <see cref=\"PublicKey\"/> of the vote set.\n        /// </summary>\n        public PublicKey ValidatorPublicKey { get; }\n\n        /// <summary>\n        /// The <see cref=\"VoteFlag\"/> of the votes in the vote set.\n        /// </summary>\n        public VoteFlag Flag { get; }\n\n        /// <summary>\n        /// <see cref=\"bool\"/>s of the vote set to be .\n        /// </summary>\n        public ImmutableArray<bool> VoteBits { get; }\n\n        /// <summary>\n        /// A Bencodex-encoded value of <see cref=\"VoteSetBitsMetadata\"/>.\n        /// </summary>\n        [JsonIgnore]\n        public Dictionary Encoded\n        {\n            get\n            {\n                Dictionary encoded = Bencodex.Types.Dictionary.Empty\n                    .Add(HeightKey, Height)\n                    .Add(RoundKey, Round)\n                    .Add(\n                        TimestampKey,\n                        Timestamp.ToString(TimestampFormat, CultureInfo.InvariantCulture))\n                    .Add(ValidatorPublicKeyKey, ValidatorPublicKey.Format(compress: true))\n                    .Add(BlockHashKey, BlockHash.ByteArray)\n                    .Add(FlagKey, (int)Flag)\n                    .Add(\n                        VoteBitsKey,\n                        new List(VoteBits.Select(bit => (Bencodex.Types.Boolean)bit)));\n\n                return encoded;\n            }\n        }\n\n        public ImmutableArray<byte> ByteArray => ToByteArray().ToImmutableArray();\n\n        public byte[] ToByteArray() => _codec.Encode(Encoded);\n\n        /// <summary>\n        /// Signs given <see cref=\"VoteSetBitsMetadata\"/> with given <paramref name=\"signer\"/>.\n        /// </summary>\n        /// <param name=\"signer\">A <see cref=\"PrivateKey\"/> to sign.</param>\n        /// <returns>Returns a signed <see cref=\"VoteSetBits\"/>.</returns>\n        public VoteSetBits Sign(PrivateKey signer) =>\n            new VoteSetBits(this, signer.Sign(ByteArray).ToImmutableArray());\n\n        /// <inheritdoc/>\n        public bool Equals(VoteSetBitsMetadata? other)\n        {\n            return other is { } metadata &&\n                Height == metadata.Height &&\n                Round == metadata.Round &&\n                BlockHash.Equals(metadata.BlockHash) &&\n                Timestamp\n                    .ToString(TimestampFormat, CultureInfo.InvariantCulture).Equals(\n                        metadata.Timestamp.ToString(\n                            TimestampFormat,\n                            CultureInfo.InvariantCulture)) &&\n                ValidatorPublicKey.Equals(metadata.ValidatorPublicKey) &&\n                Flag == metadata.Flag &&\n                VoteBits.SequenceEqual(other.VoteBits);\n        }\n\n        /// <inheritdoc/>\n        public override bool Equals(object? obj) =>\n            obj is VoteSetBitsMetadata other && Equals(other);\n\n        /// <inheritdoc/>\n        public override int GetHashCode()\n        {\n            int voteBitsHashCode = VoteBits.Aggregate(\n                0,\n                (current, voteBit) => (current * 397) ^ voteBit.GetHashCode());\n\n            return HashCode.Combine(\n                Height,\n                Round,\n                BlockHash,\n                Timestamp.ToString(TimestampFormat, CultureInfo.InvariantCulture),\n                ValidatorPublicKey,\n                Flag,\n                voteBitsHashCode);\n        }\n    }\n}\n"
  },
  {
    "path": "src/Libplanet/KeyStore/Ciphers/Aes128Ctr.cs",
    "content": "#nullable disable\nusing System;\nusing System.Collections.Immutable;\nusing System.Diagnostics.Contracts;\nusing System.Linq;\nusing System.Text.Json;\nusing Libplanet.Common;\nusing Org.BouncyCastle.Crypto;\nusing Org.BouncyCastle.Crypto.Parameters;\nusing Org.BouncyCastle.Security;\n\nnamespace Libplanet.KeyStore.Ciphers\n{\n    /// <summary>\n    /// AES-128-CTR (AES 128-bit in counter moder).\n    /// </summary>\n    [Pure]\n    public sealed class Aes128Ctr : ICipher\n    {\n        /// <summary>\n        /// Creates an <see cref=\"Aes128Ctr\"/> instance with the given <paramref name=\"iv\"/>.\n        /// </summary>\n        /// <param name=\"iv\">Initialization vector.</param>\n        /// <exception cref=\"ArgumentException\">Thrown when the length of <paramref name=\"iv\"/> is\n        /// invalid.</exception>\n        public Aes128Ctr(byte[] iv)\n            : this(ImmutableArray.Create(iv))\n        {\n        }\n\n        /// <summary>\n        /// Creates an <see cref=\"Aes128Ctr\"/> instance with the given <paramref name=\"iv\"/>.\n        /// </summary>\n        /// <param name=\"iv\">Initialization vector.</param>\n        /// <exception cref=\"ArgumentException\">Thrown when the length of <paramref name=\"iv\"/> is\n        /// invalid.</exception>\n        public Aes128Ctr(in ImmutableArray<byte> iv)\n        {\n            if (iv.Length > 16)\n            {\n                throw new ArgumentOutOfRangeException(nameof(iv), \"IV cannot be greater than 16.\");\n            }\n            else if (iv.IsEmpty)\n            {\n                throw new ArgumentException(\"IV should be provided.\", nameof(iv));\n            }\n\n            Iv = iv;\n        }\n\n        /// <summary>\n        /// Initialization vector.\n        /// </summary>\n        [Pure]\n        public ImmutableArray<byte> Iv { get; }\n\n        /// <inheritdoc />\n        [Pure]\n        public ImmutableArray<byte> Encrypt(\n            in ImmutableArray<byte> key,\n            in ImmutableArray<byte> plaintext\n        ) =>\n            Cipher(true, key, plaintext);\n\n        /// <inheritdoc />\n        [Pure]\n        public ImmutableArray<byte> Decrypt(\n            in ImmutableArray<byte> key,\n            in ImmutableArray<byte> ciphertext\n        ) =>\n            Cipher(false, key, ciphertext);\n\n        /// <inheritdoc />\n        public string WriteJson(Utf8JsonWriter writer)\n        {\n            writer.WriteStartObject();\n            writer.WriteString(\"iv\", ByteUtil.Hex(Iv));\n            writer.WriteEndObject();\n            return \"aes-128-ctr\";\n        }\n\n        internal static ICipher FromJson(in JsonElement paramsElement)\n        {\n            if (!paramsElement.TryGetProperty(\"iv\", out JsonElement ivElement))\n            {\n                throw new InvalidKeyJsonException(\n                    \"The \\\"cipherparams\\\" field must have an \\\"iv\\\" field.\"\n                );\n            }\n\n            string ivString;\n            try\n            {\n                ivString = ivElement.GetString();\n            }\n            catch (InvalidOperationException)\n            {\n                throw new InvalidKeyJsonException(\"The \\\"iv\\\" field must be a string.\");\n            }\n\n            if (ivString is null)\n            {\n                throw new InvalidKeyJsonException(\n                    \"The \\\"iv\\\" field must not be null, but a string.\"\n                );\n            }\n\n            byte[] iv;\n            try\n            {\n                iv = ByteUtil.ParseHex(ivString);\n            }\n            catch (Exception e)\n            {\n                throw new InvalidKeyJsonException(\n                    \"The \\\"iv\\\" field must be a hexadecimal string of bytes.\\n\" + e\n                );\n            }\n\n            return new Aes128Ctr(iv);\n        }\n\n        private ImmutableArray<byte> Cipher(\n            in bool encrypt,\n            in ImmutableArray<byte> key,\n            in ImmutableArray<byte> input\n        )\n        {\n            int keyLength = key.Length;\n            if (keyLength != 16 && keyLength != 24 && keyLength != 32)\n            {\n                throw new ArgumentException(\n                    \"Key length must be one of 16/24/32 bytes (128/192/256 bits, respectively).\",\n                    nameof(key)\n                );\n            }\n\n            // FIXME: Rather than depending on BouncyCastle, which is a pure C# implementation,\n            //        it's better to use .NET Standard's System.Security.Cryptography API.\n            IBufferedCipher cipher = CipherUtilities.GetCipher(\"AES/CTR/NoPadding\");\n\n            KeyParameter keyParam = ParameterUtilities.CreateKeyParameter(\n                \"AES128\",\n                key.ToArray()\n            );\n            byte[] iv = Iv.ToArray();\n            ICipherParameters cipherParams = new ParametersWithIV(keyParam, iv);\n            cipher.Init(encrypt, cipherParams);\n            return cipher.DoFinal(input.ToArray()).ToImmutableArray();\n        }\n    }\n}\n"
  },
  {
    "path": "src/Libplanet/KeyStore/Ciphers/ICipher.cs",
    "content": "#nullable disable\nusing System.Collections.Immutable;\nusing System.Diagnostics.Contracts;\nusing System.Text.Json;\n\nnamespace Libplanet.KeyStore.Ciphers\n{\n    /// <summary>\n    /// An interface to define symmetric cipher algorithm.\n    /// </summary>\n    public interface ICipher\n    {\n        /// <summary>\n        /// Encrypts the given <paramref name=\"plaintext\"/> using the given <paramref name=\"key\"/>.\n        /// </summary>\n        /// <param name=\"key\">A symmetric key.</param>\n        /// <param name=\"plaintext\">An immutable <see cref=\"byte\"/> array to encrypt.</param>\n        /// <returns>The ciphertext made from the <paramref name=\"plaintext\"/>\n        /// using the <paramref name=\"key\"/>.</returns>\n        [Pure]\n        ImmutableArray<byte> Encrypt(\n            in ImmutableArray<byte> key,\n            in ImmutableArray<byte> plaintext\n        );\n\n        /// <summary>\n        /// Decrypts the given <paramref name=\"ciphertext\"/> using the given <paramref name=\"key\"/>.\n        /// </summary>\n        /// <param name=\"key\">A symmetric key.</param>\n        /// <param name=\"ciphertext\">An immutable <see cref=\"byte\"/> array to decrypt.</param>\n        /// <returns>The plain text decrypted from the <paramref name=\"ciphertext\"/>\n        /// using the <paramref name=\"key\"/>.</returns>\n        [Pure]\n        ImmutableArray<byte> Decrypt(\n            in ImmutableArray<byte> key,\n            in ImmutableArray<byte> ciphertext\n        );\n\n        /// <summary>\n        /// Dumps the cipher parameters as a JSON representation according to Ethereum's\n        /// <a href=\"https://github.com/ethereum/wiki/wiki/Web3-Secret-Storage-Definition\">Web3\n        /// Secret Storage Definition</a>.\n        /// </summary>\n        /// <param name=\"writer\">A JSON writer which has not begun object nor array.</param>\n        /// <returns>A unique identifier of the cipher algorithm.  This is going to be the\n        /// <c>crypto.cipher</c> field in the key JSON file.</returns>\n        string WriteJson(Utf8JsonWriter writer);\n    }\n}\n"
  },
  {
    "path": "src/Libplanet/KeyStore/IKeyStore.cs",
    "content": "using System;\nusing System.Collections.Generic;\n\nnamespace Libplanet.KeyStore\n{\n    /// <summary>\n    /// The interface to store <see cref=\"ProtectedPrivateKey\"/>s.  An appropriate implementation\n    /// should be used according to a running platform.\n    /// </summary>\n    public interface IKeyStore\n    {\n        /// <summary>\n        /// Lists all keys IDs in the key store.\n        /// </summary>\n        /// <returns>All keys IDs in the key store.  The order is undefined and not deterministic.\n        /// </returns>\n        public IEnumerable<Guid> ListIds();\n\n        /// <summary>\n        /// Lists all keys in the key store.\n        /// </summary>\n        /// <returns>All keys in the key store.  The order is undefined and not deterministic.\n        /// </returns>\n        public IEnumerable<Tuple<Guid, ProtectedPrivateKey>> List();\n\n        /// <summary>\n        /// Looks for a key having the requested <paramref name=\"id\"/> in the key store.\n        /// </summary>\n        /// <param name=\"id\">The key ID to look for.</param>\n        /// <returns>The found key.</returns>\n        /// <exception cref=\"NoKeyException\">Thrown when there are no key of the given\n        /// <paramref name=\"id\"/>.</exception>\n        public ProtectedPrivateKey Get(Guid id);\n\n        /// <summary>\n        /// Adds a new <paramref name=\"key\"/> into the key store.\n        /// </summary>\n        /// <param name=\"key\">A key to add.</param>\n        /// <returns>The id of the added <paramref name=\"key\"/>.</returns>\n        /// <exception cref=\"ArgumentNullException\">Thrown when <see langword=\"null\"/> is passed to\n        /// <paramref name=\"key\"/>.</exception>\n        public Guid Add(ProtectedPrivateKey key);\n\n        /// <summary>\n        /// Removes a key having the given <pramref name=\"id\"/> from the key store.\n        /// </summary>\n        /// <param name=\"id\">The key ID to remove.</param>\n        /// <exception cref=\"NoKeyException\">Thrown when there is no key having\n        /// the given <paramref name=\"id\"/>.</exception>\n        public void Remove(Guid id);\n    }\n}\n"
  },
  {
    "path": "src/Libplanet/KeyStore/IncorrectPassphraseException.cs",
    "content": "using System;\nusing System.Collections.Immutable;\nusing Libplanet.Common;\n\nnamespace Libplanet.KeyStore\n{\n    /// <summary>\n    /// The exception that is thrown when a user input passphrase (i.e., password) is incorrect.\n    /// </summary>\n    public class IncorrectPassphraseException : ArgumentException\n    {\n        /// <summary>\n        /// Creates a new <see cref=\"IncorrectPassphraseException\"/> object.\n        /// </summary>\n        /// <param name=\"message\">The error message that explains the reason for the exception.\n        /// </param>\n        /// <param name=\"paramName\">The name of the parameter that caused the current exception.\n        /// </param>\n        /// <param name=\"expectedMac\">The expected MAC of the correct passphrase.\n        /// It is automatically included to the <paramref name=\"message\"/> string.</param>\n        /// <param name=\"inputMac\">The actual MAC of the user input passphrase.\n        /// It is automatically included to the <paramref name=\"message\"/> string.</param>\n        public IncorrectPassphraseException(\n            string message,\n            string paramName,\n            in ImmutableArray<byte> expectedMac,\n            in ImmutableArray<byte> inputMac\n        )\n            : base(\n                $\"{message}\\nExpected MAC: {ByteUtil.Hex(expectedMac)}\\n\" +\n                $\"Input MAC: {ByteUtil.Hex(inputMac)}\",\n                paramName\n            )\n        {\n            ExpectedMac = expectedMac;\n            InputMac = inputMac;\n        }\n\n        /// <summary>\n        /// The expected MAC of the correct passphrase.\n        /// </summary>\n        public ImmutableArray<byte> ExpectedMac { get; }\n\n        /// <summary>\n        /// The actual MAC of the user input passphrase.\n        /// </summary>\n        public ImmutableArray<byte> InputMac { get; }\n    }\n}\n"
  },
  {
    "path": "src/Libplanet/KeyStore/InvalidKeyJsonException.cs",
    "content": "namespace Libplanet.KeyStore\n{\n    /// <summary>\n    /// The exception that is thrown when a key JSON is invalid, e.g., missing field.\n    /// </summary>\n    public class InvalidKeyJsonException : KeyJsonException\n    {\n        /// <summary>\n        /// Creates a new <see cref=\"InvalidKeyJsonException\"/> instance.\n        /// </summary>\n        /// <param name=\"message\">A detailed exception message.</param>\n        public InvalidKeyJsonException(string message)\n            : base(message)\n        {\n        }\n    }\n}\n"
  },
  {
    "path": "src/Libplanet/KeyStore/Kdfs/IKdf.cs",
    "content": "#nullable disable\nusing System.Collections.Immutable;\nusing System.Diagnostics.Contracts;\nusing System.Text.Json;\n\nnamespace Libplanet.KeyStore.Kdfs\n{\n    /// <summary>\n    /// An interface to form key derivation functions (KDF) that are used to derive a valid\n    /// cryptographic key from a user input passphrase (i.e., password).\n    /// </summary>\n    public interface IKdf\n    {\n        /// <summary>\n        /// Derives a cryptographic key in <see cref=\"byte\"/>s from a user input\n        /// <paramref name=\"passphrase\"/>.\n        /// </summary>\n        /// <param name=\"passphrase\">A user input passphrase.</param>\n        /// <returns>A derived cryptographic key.</returns>\n        [Pure]\n        ImmutableArray<byte> Derive(string passphrase);\n\n        /// <summary>\n        /// Dumps the KDF parameters as a JSON representation.\n        /// </summary>\n        /// <param name=\"writer\">A JSON writer which has not begun object nor array.</param>\n        /// <returns>A unique identifier of the KDF.  This is going to be the\n        /// <c>crypto.kdf</c> field in the key JSON file.</returns>\n        string WriteJson(Utf8JsonWriter writer);\n    }\n}\n"
  },
  {
    "path": "src/Libplanet/KeyStore/Kdfs/Pbkdf2.cs",
    "content": "#nullable disable\nusing System;\nusing System.Collections.Immutable;\nusing System.Diagnostics.CodeAnalysis;\nusing System.Diagnostics.Contracts;\nusing System.Globalization;\nusing System.Linq;\nusing System.Text.Json;\nusing Libplanet.Common;\nusing Org.BouncyCastle.Crypto;\nusing Org.BouncyCastle.Crypto.Digests;\nusing Org.BouncyCastle.Crypto.Generators;\nusing Org.BouncyCastle.Crypto.Parameters;\n\nnamespace Libplanet.KeyStore.Kdfs\n{\n    /// <summary>\n    /// <a href=\"https://en.wikipedia.org/wiki/PBKDF2\">PBKDF2</a>.\n    /// </summary>\n    /// <typeparam name=\"T\">PRF (pseudorandom function) to use, e.g.,\n    /// <see cref=\"Sha256Digest\"/>.</typeparam>\n    [SuppressMessage(\n        \"Microsoft.StyleCop.CSharp.ReadabilityRules\",\n        \"SA1402\",\n        Justification = \"There are just generic & non-generic versions of the same name classes.\")]\n    [Pure]\n    public sealed class Pbkdf2<T> : IKdf\n        where T : GeneralDigest, new()\n    {\n        /// <summary>\n        /// Configures parameters of <a href=\"https://en.wikipedia.org/wiki/PBKDF2\">PBKDF2</a>.\n        /// </summary>\n        /// <param name=\"iterations\">The number of iterations desired.\n        /// Corresponds to <c>c</c>.</param>\n        /// <param name=\"salt\">A cryptographic salt.</param>\n        /// <param name=\"keyLength\">The desired byte-length of the derived key.\n        /// Corresponds to <c>dkLen</c> except that it's not bit-wise but byte-wise.</param>\n        public Pbkdf2(int iterations, byte[] salt, int keyLength)\n            : this(iterations, ImmutableArray.Create(salt, 0, salt.Length), keyLength)\n        {\n        }\n\n        /// <summary>\n        /// Configures parameters of <a href=\"https://en.wikipedia.org/wiki/PBKDF2\">PBKDF2</a>.\n        /// </summary>\n        /// <param name=\"iterations\">The number of iterations desired.\n        /// Corresponds to <c>c</c>.</param>\n        /// <param name=\"salt\">A cryptographic salt.</param>\n        /// <param name=\"keyLength\">The desired byte-length of the derived key.\n        /// Corresponds to <c>dkLen</c> except that it's not bit-wise but byte-wise.</param>\n        public Pbkdf2(int iterations, in ImmutableArray<byte> salt, int keyLength)\n        {\n            Iterations = iterations;\n            Salt = salt;\n            KeyLength = keyLength;\n        }\n\n        /// <summary>\n        /// The number of iterations desired.  Corresponds to <c>c</c>.\n        /// </summary>\n        public int Iterations { get; }\n\n        /// <summary>\n        /// The desired byte-length of the derived key.\n        /// Corresponds to <c>dkLen</c> except that it's not bit-wise but byte-wise.\n        /// </summary>\n        public int KeyLength { get; }\n\n        /// <summary>\n        /// A cryptographic salt.\n        /// </summary>\n        public ImmutableArray<byte> Salt { get; }\n\n        /// <inheritdoc/>\n        [Pure]\n        public ImmutableArray<byte> Derive(string passphrase)\n        {\n            var pdb = new Pkcs5S2ParametersGenerator(new T());\n            pdb.Init(\n                PbeParametersGenerator.Pkcs5PasswordToUtf8Bytes(passphrase.ToCharArray()),\n                Salt.ToArray(),\n                Iterations\n            );\n            var key = (KeyParameter)pdb.GenerateDerivedMacParameters(KeyLength * 8);\n            return ImmutableArray.Create(key.GetKey(), 0, KeyLength);\n        }\n\n        /// <inheritdoc/>\n        public string WriteJson(Utf8JsonWriter writer)\n        {\n            writer.WriteStartObject();\n            writer.WriteNumber(\"c\", Iterations);\n            writer.WriteNumber(\"dklen\", KeyLength);\n            string alg = new T().AlgorithmName;\n            writer.WriteString(\n                \"prf\",\n                \"hmac-\" + alg.ToLower(CultureInfo.InvariantCulture).Replace(\"-\", string.Empty)\n            );\n            writer.WriteString(\"salt\", ByteUtil.Hex(Salt));\n            writer.WriteEndObject();\n            return \"pbkdf2\";\n        }\n    }\n\n    internal static class Pbkdf2\n    {\n        internal static IKdf FromJson(in JsonElement element)\n        {\n            if (!element.TryGetProperty(\"c\", out JsonElement c))\n            {\n                throw new InvalidKeyJsonException(\n                    \"The \\\"kdfparams\\\" field must have a \\\"c\\\" field, the number of iterations.\"\n                );\n            }\n\n            if (c.ValueKind != JsonValueKind.Number || !c.TryGetInt32(out int iterations))\n            {\n                throw new InvalidKeyJsonException(\n                    \"The \\\"c\\\" field, the number of iterations, must be a number.\"\n                );\n            }\n\n            if (!element.TryGetProperty(\"dklen\", out JsonElement dklen))\n            {\n                throw new InvalidKeyJsonException(\n                    \"The \\\"kdfparams\\\" field must have a \\\"dklen\\\" field, \" +\n                    \"the length of key in bytes.\"\n                );\n            }\n\n            if (dklen.ValueKind != JsonValueKind.Number ||\n                !dklen.TryGetInt32(out int keyLength))\n            {\n                throw new InvalidKeyJsonException(\n                    \"The \\\"dklen\\\" field, the length of key in bytes, must be a number.\"\n                );\n            }\n\n            if (!element.TryGetProperty(\"salt\", out JsonElement saltElement))\n            {\n                throw new InvalidKeyJsonException(\n                    \"The \\\"kdfparams\\\" field must have a \\\"salt\\\" field.\"\n                );\n            }\n\n            string saltString;\n            try\n            {\n                saltString = saltElement.GetString();\n            }\n            catch (InvalidOperationException)\n            {\n                throw new InvalidKeyJsonException(\"The \\\"salt\\\" field must be a string.\");\n            }\n\n            byte[] salt;\n            try\n            {\n                salt = ByteUtil.ParseHex(saltString);\n            }\n            catch (ArgumentNullException)\n            {\n                throw new InvalidKeyJsonException(\n                    \"The \\\"salt\\\" field must not be null, but a string.\"\n                );\n            }\n            catch (Exception e)\n            {\n                throw new InvalidKeyJsonException(\n                    \"The \\\"salt\\\" field must be a hexadecimal string of bytes.\\n\" + e\n                );\n            }\n\n            if (!element.TryGetProperty(\"prf\", out JsonElement prfElement))\n            {\n                throw new InvalidKeyJsonException(\n                    \"The \\\"kdfparams\\\" field must have a \\\"prf\\\" field.\"\n                );\n            }\n\n            string prf;\n            try\n            {\n                prf = prfElement.GetString();\n            }\n            catch (InvalidOperationException)\n            {\n                throw new InvalidKeyJsonException(\n                    \"The \\\"prf\\\" field must be a string.\"\n                );\n            }\n\n            return prf switch\n            {\n                \"hmac-sha256\" => new Pbkdf2<Sha256Digest>(iterations, salt, keyLength),\n                null =>\n                    throw new InvalidKeyJsonException(\n                        \"The \\\"prf\\\" field must not be null, but a string.\"),\n                _ =>\n                    throw new UnsupportedKeyJsonException($\"Unsupported \\\"prf\\\" type: \\\"{prf}\\\".\"),\n            };\n        }\n    }\n}\n"
  },
  {
    "path": "src/Libplanet/KeyStore/Kdfs/Scrypt.cs",
    "content": "#nullable disable\nusing System;\nusing System.Collections.Immutable;\nusing System.Diagnostics.Contracts;\nusing System.Linq;\nusing System.Text.Json;\nusing Libplanet.Common;\n\nnamespace Libplanet.KeyStore.Kdfs\n{\n    /// <summary>\n    /// <a href=\"https://en.wikipedia.org/wiki/Scrypt\">Scrypt</a>.\n    /// </summary>\n    [Pure]\n    public sealed class Scrypt : IKdf\n    {\n        /// <summary>\n        /// Configures parameters of <a href=\"https://en.wikipedia.org/wiki/Scrypt\">Scrypt</a>.\n        /// </summary>\n        /// <param name=\"cost\">The CPU/memory cost parameter. Corresponds to <c>n</c>.</param>\n        /// <param name=\"salt\">A cryptographic salt.</param>\n        /// <param name=\"keyLength\">The desired byte-length of the derived key.\n        /// Corresponds to <c>dkLen</c> except that it's not bit-wise but byte-wise.</param>\n        /// <param name=\"parallelization\">The parallelization parameter.\n        /// Corresponds to <c>p</c>.</param>\n        /// <param name=\"blockSize\">The blocksize parameter. Corresponds to <c>r</c>.</param>\n        public Scrypt(\n            int cost,\n            byte[] salt,\n            int keyLength,\n            int parallelization,\n            int blockSize\n        )\n            : this(\n                cost,\n                ImmutableArray.Create(salt, 0, salt.Length),\n                keyLength,\n                parallelization,\n                blockSize\n            )\n        {\n        }\n\n        /// <summary>\n        /// Configures parameters of <a href=\"https://en.wikipedia.org/wiki/Scrypt\">Scrypt</a>.\n        /// </summary>\n        /// <param name=\"cost\">The CPU/memory cost parameter. Corresponds to <c>n</c>.</param>\n        /// <param name=\"salt\">A cryptographic salt.</param>\n        /// <param name=\"keyLength\">The desired byte-length of the derived key.\n        /// Corresponds to <c>dkLen</c> except that it's not bit-wise but byte-wise.</param>\n        /// <param name=\"parallelization\">The parallelization parameter.\n        /// Corresponds to <c>p</c>.</param>\n        /// <param name=\"blockSize\">The blocksize parameter. Corresponds to <c>r</c>.</param>\n        public Scrypt(\n            int cost,\n            in ImmutableArray<byte> salt,\n            int keyLength,\n            int parallelization,\n            int blockSize\n        )\n        {\n            if (cost < 2 || (cost & (cost - 1)) != 0)\n            {\n                throw new ArgumentOutOfRangeException(\n                    nameof(cost),\n                    \"Cost must be a power of 2 greater than 1!\"\n                );\n            }\n\n            if (cost > int.MaxValue / 128 / blockSize)\n            {\n                throw new ArgumentOutOfRangeException(\n                    nameof(cost),\n                    \"Parameter cost is too large!\"\n                );\n            }\n\n            if (blockSize > int.MaxValue / 128 / parallelization)\n            {\n                throw new ArgumentOutOfRangeException(\n                    nameof(blockSize),\n                    \"Parameter blockSize is too large!\"\n                );\n            }\n\n            Cost = cost;\n            Salt = salt;\n            KeyLength = keyLength;\n            Parallelization = parallelization;\n            BlockSize = blockSize;\n        }\n\n        /// <summary>\n        /// The CPU/memory cost parameter. Corresponds to <c>n</c>.\n        /// </summary>\n        public int Cost { get; }\n\n        /// <summary>\n        /// The desired byte-length of the derived key.\n        /// Corresponds to <c>dkLen</c> except that it's not bit-wise but byte-wise.\n        /// </summary>\n        public int KeyLength { get; }\n\n        /// <summary>\n        /// A cryptographic salt.\n        /// </summary>\n        public ImmutableArray<byte> Salt { get; }\n\n        /// <summary>\n        /// The parallelization parameter. Corresponds to <c>p</c>.\n        /// </summary>\n        public int Parallelization { get; }\n\n        /// <summary>\n        /// The blocksize parameter. Corresponds to <c>r</c>.\n        /// </summary>\n        public int BlockSize { get; }\n\n        /// <inheritdoc/>\n        [Pure]\n        public ImmutableArray<byte> Derive(string passphrase)\n        {\n            var key = Norgerman.Cryptography.Scrypt.ScryptUtil.Scrypt(\n                passphrase, Salt.ToArray(), Cost, BlockSize, Parallelization, KeyLength\n            );\n            return ImmutableArray.Create(key, 0, KeyLength);\n        }\n\n        /// <inheritdoc/>\n        public string WriteJson(Utf8JsonWriter writer)\n        {\n            writer.WriteStartObject();\n            writer.WriteNumber(\"dklen\", KeyLength);\n            writer.WriteNumber(\"n\", Cost);\n            writer.WriteNumber(\"p\", Parallelization);\n            writer.WriteNumber(\"r\", BlockSize);\n            writer.WriteString(\"salt\", ByteUtil.Hex(Salt));\n            writer.WriteEndObject();\n            return \"scrypt\";\n        }\n\n        internal static IKdf FromJson(in JsonElement element)\n        {\n            if (!element.TryGetProperty(\"n\", out JsonElement n))\n            {\n                throw new InvalidKeyJsonException(\n                    \"The \\\"kdfparams\\\" field must have a \\\"n\\\" field, ....\"\n                );\n            }\n\n            if (n.ValueKind != JsonValueKind.Number || !n.TryGetInt32(out int cost))\n            {\n                throw new InvalidKeyJsonException(\n                    \"The \\\"n\\\" field, the number of iterations, must be a number.\"\n                );\n            }\n\n            if (!element.TryGetProperty(\"r\", out JsonElement r))\n            {\n                throw new InvalidKeyJsonException(\n                    \"The \\\"kdfparams\\\" field must have a \\\"r\\\" field, ....\"\n                );\n            }\n\n            if (r.ValueKind != JsonValueKind.Number || !r.TryGetInt32(out int blockSize))\n            {\n                throw new InvalidKeyJsonException(\n                    \"The \\\"r\\\" field, the number of iterations, must be a number.\"\n                );\n            }\n\n            if (!element.TryGetProperty(\"p\", out JsonElement p))\n            {\n                throw new InvalidKeyJsonException(\n                    \"The \\\"kdfparams\\\" field must have a \\\"p\\\" field, ....\"\n                );\n            }\n\n            if (p.ValueKind != JsonValueKind.Number || !p.TryGetInt32(out int parallelization))\n            {\n                throw new InvalidKeyJsonException(\n                    \"The \\\"n\\\" field, the number of iterations, must be a number.\"\n                );\n            }\n\n            if (!element.TryGetProperty(\"dklen\", out JsonElement dklen))\n            {\n                throw new InvalidKeyJsonException(\n                    \"The \\\"kdfparams\\\" field must have a \\\"dklen\\\" field, \" +\n                    \"the length of key in bytes.\"\n                );\n            }\n\n            if (dklen.ValueKind != JsonValueKind.Number ||\n                !dklen.TryGetInt32(out int keyLength))\n            {\n                throw new InvalidKeyJsonException(\n                    \"The \\\"dklen\\\" field, the length of key in bytes, must be a number.\"\n                );\n            }\n\n            if (!element.TryGetProperty(\"salt\", out JsonElement saltElement))\n            {\n                throw new InvalidKeyJsonException(\n                    \"The \\\"kdfparams\\\" field must have a \\\"salt\\\" field.\"\n                );\n            }\n\n            string saltString;\n            try\n            {\n                saltString = saltElement.GetString();\n            }\n            catch (InvalidOperationException)\n            {\n                throw new InvalidKeyJsonException(\"The \\\"salt\\\" field must be a string.\");\n            }\n\n            byte[] salt;\n            try\n            {\n                salt = ByteUtil.ParseHex(saltString);\n            }\n            catch (ArgumentNullException)\n            {\n                throw new InvalidKeyJsonException(\n                    \"The \\\"salt\\\" field must not be null, but a string.\"\n                );\n            }\n            catch (Exception e)\n            {\n                throw new InvalidKeyJsonException(\n                    \"The \\\"salt\\\" field must be a hexadecimal string of bytes.\\n\" + e\n                );\n            }\n\n            return new Scrypt(cost, salt, keyLength, parallelization, blockSize);\n        }\n    }\n}\n"
  },
  {
    "path": "src/Libplanet/KeyStore/KeyJsonException.cs",
    "content": "using System;\n\nnamespace Libplanet.KeyStore\n{\n    /// <summary>\n    /// Serves as the base class for exceptions thrown by\n    /// <see cref=\"ProtectedPrivateKey.FromJson\"/> method.\n    /// </summary>\n    public abstract class KeyJsonException : Exception\n    {\n        /// <summary>\n        /// Creates a new <see cref=\"KeyJsonException\"/> instance with a message.\n        /// </summary>\n        /// <param name=\"message\">A detailed exception message.</param>\n        protected KeyJsonException(string message)\n            : base(message)\n        {\n        }\n    }\n}\n"
  },
  {
    "path": "src/Libplanet/KeyStore/KeyStoreException.cs",
    "content": "using System;\n\nnamespace Libplanet.KeyStore\n{\n    /// <summary>\n    /// Serves as the base class for exceptions thrown by <see cref=\"IKeyStore\"/>\n    /// implementations.\n    /// </summary>\n    public abstract class KeyStoreException : Exception\n    {\n        /// <summary>\n        /// Initializes a new instance with the given <paramref name=\"message\"/>.\n        /// </summary>\n        /// <param name=\"message\">A descriptive error message for programmers.\n        /// Goes to <see cref=\"System.Exception.Message\"/>.</param>\n        protected KeyStoreException(string message)\n            : base(message)\n        {\n        }\n    }\n}\n"
  },
  {
    "path": "src/Libplanet/KeyStore/MismatchedAddressException.cs",
    "content": "using System;\nusing Libplanet.Crypto;\n\nnamespace Libplanet.KeyStore\n{\n    /// <summary>\n    /// The exception that is thrown when an unprotected private key's actual address does\n    /// not match to the expected address.\n    /// </summary>\n    public class MismatchedAddressException : InvalidOperationException\n    {\n        /// <summary>\n        /// Creates a new <see cref=\"MismatchedAddressException\"/> object.\n        /// </summary>\n        /// <param name=\"message\">The error message that explains the reason for the exception.\n        /// </param>\n        /// <param name=\"expectedAddress\">The expected address of a protected private key.\n        /// It is automatically included to the <paramref name=\"message\"/> string.</param>\n        /// <param name=\"actualAddress\">The actual address of an unprotected private key.\n        /// It is automatically included to the <paramref name=\"message\"/> string.</param>\n        public MismatchedAddressException(\n            string message,\n            in Address expectedAddress,\n            in Address actualAddress\n        )\n            : base(\n                $\"{message}\\nExpected address: {expectedAddress}\\n\" +\n                $\"Actual address: {actualAddress}\"\n            )\n        {\n            ExpectedAddress = expectedAddress;\n            ActualAddress = actualAddress;\n        }\n\n        /// <summary>\n        /// The expected address of the protected private key.\n        /// </summary>\n        public Address ExpectedAddress { get; }\n\n        /// <summary>\n        /// The actual address of the unprotected private key.\n        /// </summary>\n        public Address ActualAddress { get; }\n    }\n}\n"
  },
  {
    "path": "src/Libplanet/KeyStore/NoKeyException.cs",
    "content": "using System;\n\nnamespace Libplanet.KeyStore\n{\n    /// <summary>\n    /// The exception that is thrown when there is no <see cref=\"ProtectedPrivateKey\"/>\n    /// with a given key ID in an <see cref=\"IKeyStore\"/>.\n    /// </summary>\n    public class NoKeyException : KeyStoreException\n    {\n        /// <summary>\n        /// Instantiates a new exception object with proper metadata.\n        /// </summary>\n        /// <param name=\"message\">A descriptive error message for programmers.\n        /// Goes to <see cref=\"System.Exception.Message\"/>.</param>\n        /// <param name=\"keyId\">The key ID tried to look for.\n        /// It is automatically included to the <see cref=\"System.Exception.Message\"/>\n        /// string.\n        /// </param>\n        public NoKeyException(string message, Guid keyId)\n            : base($\"{message}: {keyId}\")\n        {\n            KeyId = keyId;\n        }\n\n        /// <summary>\n        /// The key ID tried to look for.\n        /// </summary>\n        public Guid KeyId { get; }\n    }\n}\n"
  },
  {
    "path": "src/Libplanet/KeyStore/ProtectedPrivateKey.cs",
    "content": "#nullable disable\nusing System;\nusing System.Collections.Immutable;\nusing System.Diagnostics.Contracts;\nusing System.Globalization;\nusing System.IO;\nusing System.Linq;\nusing System.Security.Cryptography;\nusing System.Text.Json;\nusing Libplanet.Common;\nusing Libplanet.Crypto;\nusing Libplanet.KeyStore.Ciphers;\nusing Libplanet.KeyStore.Kdfs;\nusing Org.BouncyCastle.Crypto.Digests;\n\nnamespace Libplanet.KeyStore\n{\n    /// <summary>\n    /// Protects a <see cref=\"PrivateKey\"/> with a passphrase (i.e., password).\n    /// </summary>\n    public sealed class ProtectedPrivateKey\n    {\n        /// <summary>\n        /// Loads a protected private key.\n        /// </summary>\n        /// <param name=\"address\">The address of the protected private key.</param>\n        /// <param name=\"kdf\">A key derivation function to derive a symmetric key to decrypt\n        /// a <see cref=\"PrivateKey\"/>.</param>\n        /// <param name=\"mac\">MAC digest to check if a derived key is correct or not.</param>\n        /// <param name=\"cipher\">A symmetric cipher to decrypt a <see cref=\"PrivateKey\"/>.</param>\n        /// <param name=\"ciphertext\">An encrypted <see cref=\"PrivateKey\"/>.</param>\n        public ProtectedPrivateKey(\n            Address address,\n            IKdf kdf,\n            byte[] mac,\n            ICipher cipher,\n            byte[] ciphertext\n        )\n            : this(\n                address,\n                kdf,\n                ImmutableArray.Create(mac),\n                cipher,\n                ImmutableArray.Create(ciphertext)\n            )\n        {\n        }\n\n        /// <summary>\n        /// Loads a protected private key.\n        /// </summary>\n        /// <param name=\"address\">The address of the protected private key.</param>\n        /// <param name=\"kdf\">A key derivation function to derive a symmetric key to decrypt\n        /// a <see cref=\"PrivateKey\"/>.</param>\n        /// <param name=\"mac\">MAC digest to check if a derived key is correct or not.</param>\n        /// <param name=\"cipher\">A symmetric cipher to decrypt a <see cref=\"PrivateKey\"/>.</param>\n        /// <param name=\"ciphertext\">An encrypted <see cref=\"PrivateKey\"/>.</param>\n        public ProtectedPrivateKey(\n            Address address,\n            IKdf kdf,\n            ImmutableArray<byte> mac,\n            ICipher cipher,\n            ImmutableArray<byte> ciphertext\n        )\n        {\n            Address = address;\n            Kdf = kdf;\n            Mac = mac;\n            Cipher = cipher;\n            Ciphertext = ciphertext;\n        }\n\n        /// <summary>\n        /// The address of the protected private key.\n        /// </summary>\n        public Address Address { get; }\n\n        /// <summary>\n        /// A key derivation function to derive a symmetric key to decrypt\n        /// a <see cref=\"PrivateKey\"/>.\n        /// </summary>\n        [Pure]\n        public IKdf Kdf { get; }\n\n        [Pure]\n        public ImmutableArray<byte> Mac { get; }\n\n        /// <summary>\n        /// A symmetric cipher to decrypt a <see cref=\"PrivateKey\"/>.\n        /// </summary>\n        [Pure]\n        public ICipher Cipher { get; }\n\n        /// <summary>\n        /// An encrypted <see cref=\"PrivateKey\"/>.\n        /// </summary>\n        [Pure]\n        public ImmutableArray<byte> Ciphertext { get; }\n\n        /// <summary>\n        /// Protects a bare <see cref=\"PrivateKey\"/> using a user input\n        /// <paramref name=\"passphrase\"/>.\n        /// </summary>\n        /// <param name=\"privateKey\">A bare private key to protect.</param>\n        /// <param name=\"passphrase\">A user input passphrase (i.e., password).</param>\n        /// <returns>A passphrase-protected private key.</returns>\n        [Pure]\n        public static ProtectedPrivateKey Protect(PrivateKey privateKey, string passphrase)\n        {\n            var salt = new byte[32];\n            using RandomNumberGenerator rng = RandomNumberGenerator.Create();\n            rng.GetBytes(salt);\n            var kdf = new Pbkdf2<Sha256Digest>(10240, salt, 32);\n            ImmutableArray<byte> derivedKey = kdf.Derive(passphrase);\n            ImmutableArray<byte> encKey = MakeEncryptionKey(derivedKey);\n            var iv = new byte[16];\n            rng.GetBytes(iv);\n            var cipher = new Aes128Ctr(iv);\n            ImmutableArray<byte> ciphertext = cipher.Encrypt(encKey, privateKey.ByteArray);\n            ImmutableArray<byte> mac = CalculateMac(derivedKey, ciphertext);\n            Address address = privateKey.Address;\n            return new ProtectedPrivateKey(address, kdf, mac, cipher, ciphertext);\n        }\n\n        /// <summary>\n        /// Loads a <see cref=\"ProtectedPrivateKey\"/> from a JSON, according to Ethereum's\n        /// <a href=\"https://github.com/ethereum/wiki/wiki/Web3-Secret-Storage-Definition\">Web3\n        /// Secret Storage Definition</a>.\n        /// </summary>\n        /// <param name=\"json\">A JSON string that encodes a <see cref=\"ProtectedPrivateKey\"/>.\n        /// </param>\n        /// <returns>A protected private key loaded from the given <paramref name=\"json\"/>.\n        /// </returns>\n        /// <exception cref=\"JsonException\">Thrown when the given <paramref name=\"json\"/> is not\n        /// a valid JSON.</exception>\n        /// <exception cref=\"InvalidKeyJsonException\">Thrown when the given key data lacks some\n        /// required fields or consists of wrong types.</exception>\n        /// <exception cref=\"UnsupportedKeyJsonException\">Thrown when the given key data depends on\n        /// an unsupported features (e.g., KDF).</exception>\n        public static ProtectedPrivateKey FromJson(string json)\n        {\n            var options = new JsonDocumentOptions\n            {\n                AllowTrailingCommas = true,\n                CommentHandling = JsonCommentHandling.Skip,\n            };\n\n            using JsonDocument doc = JsonDocument.Parse(json, options);\n            JsonElement rootElement = doc.RootElement;\n            if (rootElement.ValueKind != JsonValueKind.Object)\n            {\n                throw new InvalidKeyJsonException(\n                    \"The root of the key JSON must be an object, but it is a/an \" +\n                    $\"{rootElement.ValueKind}.\"\n                );\n            }\n\n            if (!rootElement.TryGetProperty(\"version\", out JsonElement versionElement))\n            {\n                throw new InvalidKeyJsonException(\n                    \"The key JSON must contain \\\"version\\\" field, but it lacks.\"\n                );\n            }\n\n            if (versionElement.ValueKind != JsonValueKind.Number ||\n                !versionElement.TryGetDecimal(out decimal versionNum))\n            {\n                throw new InvalidKeyJsonException(\"The \\\"version\\\" field must be a number.\");\n            }\n            else if (versionNum != 3)\n            {\n                throw new UnsupportedKeyJsonException(\n                    $\"The key JSON format version {versionNum} is unsupported; \" +\n                    \"Only version 3 is supported.\"\n                );\n            }\n\n            string GetStringProperty(JsonElement element, string fieldName)\n            {\n                if (!element.TryGetProperty(fieldName, out JsonElement fieldElement))\n                {\n                    throw new InvalidKeyJsonException(\n                        $\"The key JSON must contain \\\"{fieldName}\\\" field, but it lacks.\"\n                    );\n                }\n\n                string str;\n                try\n                {\n                    str = fieldElement.GetString();\n                }\n                catch (InvalidOperationException)\n                {\n                    throw new InvalidKeyJsonException(\n                        $\"The \\\"{fieldName}\\\" field must be a string.\"\n                    );\n                }\n\n                if (str is null)\n                {\n                    throw new InvalidKeyJsonException(\n                        $\"The \\\"{fieldName}\\\" field must not be null, but a string.\"\n                    );\n                }\n\n                return str;\n            }\n\n            JsonElement GetObjectProperty(JsonElement element, string fieldName)\n            {\n                if (!element.TryGetProperty(fieldName, out var fieldElement))\n                {\n                    throw new InvalidKeyJsonException(\n                        $\"The key JSON must contain \\\"{fieldName}\\\" field, but it lacks.\"\n                    );\n                }\n                else if (fieldElement.ValueKind != JsonValueKind.Object)\n                {\n                    throw new InvalidKeyJsonException(\n                        $\"The \\\"{fieldName}\\\" field must be an object, but it is a/an \" +\n                        $\"{fieldElement.ValueKind}.\"\n                    );\n                }\n\n                return fieldElement;\n            }\n\n            byte[] GetHexProperty(JsonElement element, string fieldName)\n            {\n                string str = GetStringProperty(element, fieldName);\n                byte[] bytes;\n                try\n                {\n                    bytes = ByteUtil.ParseHex(str);\n                }\n                catch (Exception e)\n                {\n                    throw new InvalidKeyJsonException(\n                        $\"The \\\"{fieldName}\\\" field must be a hexadecimal string.\\n{e}\"\n                    );\n                }\n\n                return bytes;\n            }\n\n            JsonElement crypto = GetObjectProperty(rootElement, \"crypto\");\n            string cipherType = GetStringProperty(crypto, \"cipher\");\n            JsonElement cipherParamsElement = GetObjectProperty(crypto, \"cipherparams\");\n            byte[] ciphertext = GetHexProperty(crypto, \"ciphertext\");\n            byte[] mac = GetHexProperty(crypto, \"mac\");\n            string kdfType = GetStringProperty(crypto, \"kdf\");\n            JsonElement kdfParamsElement = GetObjectProperty(crypto, \"kdfparams\");\n            byte[] addressBytes = GetHexProperty(rootElement, \"address\");\n            Address address;\n            try\n            {\n                address = new Address(addressBytes);\n            }\n            catch (ArgumentException e)\n            {\n                throw new InvalidKeyJsonException(\n                    \"The \\\"address\\\" field must contain an Ethereum-style address which \" +\n                    \"consists of 40 hexadecimal letters: \" + e\n                );\n            }\n\n            var cipher = cipherType switch\n            {\n                \"aes-128-ctr\" => Aes128Ctr.FromJson(cipherParamsElement),\n                _ =>\n                    throw new UnsupportedKeyJsonException(\n                        $\"Unsupported cipher type: \\\"{cipherType}\\\".\"),\n            };\n\n            IKdf kdf;\n            try\n            {\n                kdf = kdfType switch\n                {\n                    \"pbkdf2\" => Pbkdf2.FromJson(kdfParamsElement),\n                    \"scrypt\" => Scrypt.FromJson(kdfParamsElement),\n                    _ =>\n                        throw new UnsupportedKeyJsonException(\n                            $\"Unsupported cipher type: \\\"{kdfType}\\\".\"),\n                };\n            }\n            catch (ArgumentException e)\n            {\n                throw new InvalidKeyJsonException(e.Message);\n            }\n\n            return new ProtectedPrivateKey(address, kdf, mac, cipher, ciphertext);\n        }\n\n        /// <summary>\n        /// Gets the protected <see cref=\"PrivateKey\"/> using a user input\n        /// <paramref name=\"passphrase\"/>.\n        /// </summary>\n        /// <param name=\"passphrase\">A user input passphrase (i.e., password).</param>\n        /// <returns>A bare <see cref=\"PrivateKey\"/>.</returns>\n        /// <exception cref=\"IncorrectPassphraseException\">Thrown when the given\n        /// <paramref name=\"passphrase\"/> does not match to the <see cref=\"ProtectedPrivateKey\"/>'s\n        /// passphrase.</exception>\n        /// <exception cref=\"MismatchedAddressException\">Thrown when the unprotected\n        /// <see cref=\"PrivateKey\"/> does not match to the expected <see cref=\"Address\"/>.\n        /// </exception>\n        [Pure]\n        public PrivateKey Unprotect(string passphrase)\n        {\n            ImmutableArray<byte> derivedKey = Kdf.Derive(passphrase);\n            var mac = CalculateMac(derivedKey, Ciphertext);\n            if (!Mac.SequenceEqual(mac))\n            {\n                throw new IncorrectPassphraseException(\n                    \"The input passphrase is incorrect.\",\n                    nameof(passphrase),\n                    Mac,\n                    mac\n                );\n            }\n\n            ImmutableArray<byte> encKey = MakeEncryptionKey(derivedKey);\n            ImmutableArray<byte> plaintext = Cipher.Decrypt(encKey, Ciphertext);\n\n            var key = new PrivateKey(\n                unverifiedKey: plaintext.ToBuilder().ToArray(),\n                informedConsent: true\n            );\n            Address actualAddress = key.Address;\n            if (!Address.Equals(actualAddress))\n            {\n                throw new MismatchedAddressException(\n                    \"The actual address of the unprotected private key does not match to \" +\n                    \"the expected address of the protected private key.\",\n                    Address,\n                    actualAddress\n                );\n            }\n\n            return key;\n        }\n\n        /// <summary>\n        /// Dumps the cipher parameters as a JSON representation according to Ethereum's\n        /// <a href=\"https://github.com/ethereum/wiki/wiki/Web3-Secret-Storage-Definition\">Web3\n        /// Secret Storage Definition</a>.\n        /// </summary>\n        /// <param name=\"writer\">A JSON writer which has not begun object nor array.</param>\n        /// <param name=\"id\">A unique identifier, which goes to the <c>id</c> field in the key JSON\n        /// file.  If <see langword=\"null\"/> (which is default) it is random-generated.</param>\n        public void WriteJson(Utf8JsonWriter writer, [Pure] in Guid? id = null)\n        {\n            writer.WriteStartObject();\n            writer.WriteNumber(\"version\", 3);\n            writer.WriteString(\n                \"id\",\n                (id ?? Guid.NewGuid()).ToString().ToLower(CultureInfo.InvariantCulture)\n            );\n            writer.WriteString(\"address\", Address.ToHex().ToLower(CultureInfo.InvariantCulture));\n            writer.WriteStartObject(\"crypto\");\n            writer.WriteString(\"ciphertext\", ByteUtil.Hex(Ciphertext));\n            writer.WritePropertyName(\"cipherparams\");\n            string cipherName = Cipher.WriteJson(writer);\n            writer.WriteString(\"cipher\", cipherName);\n            writer.WritePropertyName(\"kdfparams\");\n            string kdfName = Kdf.WriteJson(writer);\n            writer.WriteString(\"kdf\", kdfName);\n            writer.WriteString(\"mac\", ByteUtil.Hex(Mac));\n            writer.WriteEndObject();\n            writer.WriteEndObject();\n        }\n\n        /// <summary>\n        /// Dumps the cipher parameters as a JSON representation according to Ethereum's\n        /// <a href=\"https://github.com/ethereum/wiki/wiki/Web3-Secret-Storage-Definition\">Web3\n        /// Secret Storage Definition</a>.\n        /// </summary>\n        /// <param name=\"stream\">The destination for writing JSON text.</param>\n        /// <param name=\"id\">A unique identifier, which goes to the <c>id</c> field in the key JSON\n        /// file.  If <see langword=\"null\"/> (which is default) it is random-generated.</param>\n        public void WriteJson(Stream stream, [Pure] in Guid? id = null)\n        {\n            using var writer = new Utf8JsonWriter(stream);\n            WriteJson(writer, id);\n        }\n\n        private static ImmutableArray<byte> MakeEncryptionKey(ImmutableArray<byte> derivedKey)\n        {\n            const int keySubBytes = 16;\n            return ImmutableArray.Create(derivedKey, 0, derivedKey.Length - keySubBytes);\n        }\n\n        private static ImmutableArray<byte> CalculateMac(\n            ImmutableArray<byte> derivedKey,\n            ImmutableArray<byte> ciphertext\n        )\n        {\n            const int keySubBytes = 16;\n            var seal = new byte[keySubBytes + ciphertext.Length];\n            derivedKey.CopyTo(derivedKey.Length - keySubBytes, seal, 0, keySubBytes);\n            ciphertext.CopyTo(seal, keySubBytes);\n            var digest = new KeccakDigest(256);\n            var mac = new byte[digest.GetDigestSize()];\n            digest.BlockUpdate(seal, 0, seal.Length);\n            digest.DoFinal(mac, 0);\n            return ImmutableArray.Create(mac);\n        }\n    }\n}\n"
  },
  {
    "path": "src/Libplanet/KeyStore/UnsupportedKeyJsonException.cs",
    "content": "namespace Libplanet.KeyStore\n{\n    /// <summary>\n    /// The exception that is thrown when a key JSON is valid but uses an unsupported feature,\n    /// e.g., unsupported cipher algorithm.\n    /// </summary>\n    public class UnsupportedKeyJsonException : KeyJsonException\n    {\n        /// <summary>\n        /// Creates a new <see cref=\"UnsupportedKeyJsonException\"/> instance with a message.\n        /// </summary>\n        /// <param name=\"message\">A detailed exception message.</param>\n        public UnsupportedKeyJsonException(string message)\n            : base(message)\n        {\n        }\n    }\n}\n"
  },
  {
    "path": "src/Libplanet/KeyStore/Web3KeyStore.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Globalization;\nusing System.IO;\nusing System.Linq;\nusing System.Text.RegularExpressions;\nusing Serilog;\n\nnamespace Libplanet.KeyStore\n{\n    /// <summary>\n    /// <a href=\"https://github.com/ethereum/wiki/wiki/Web3-Secret-Storage-Definition\">Web3 Secret\n    /// Storage</a> (i.e., Ethereum-style key store) compliant <see cref=\"IKeyStore\"/>\n    /// implementation.  Key files are placed in a directory of the <see cref=\"Path\"/>.\n    /// <para>Use <see cref=\"DefaultKeyStore\"/> property to get an instance.</para>\n    /// <para>In order to get an instance with a customized directory,\n    /// use the <see cref=\"Web3KeyStore(string)\"/> constructor.</para>\n    /// </summary>\n    public class Web3KeyStore : IKeyStore\n    {\n        private static readonly string DefaultPath = System.IO.Path.Combine(\n            Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) is { } p && p.Any()\n                ? p\n                : System.IO.Path.Combine(\n                    Environment.GetFolderPath(Environment.SpecialFolder.UserProfile),\n                    \".config\"),\n            \"planetarium\",\n            \"keystore\"\n        );\n\n        private static readonly string NameFormat =\n            \"UTC--{0:yyyy-MM-dd}T{0:HH-mm-ss}Z--{1:D}\";\n\n        private static readonly Regex NamePattern = new Regex(\n            @\"^UTC--\\d{4}-\\d\\d-\\d\\dT\\d\\d-\\d\\d-\\d\\dZ--([\\da-f]{8}-?(?:[\\da-f]{4}-?){3}[\\da-f]{12})$\",\n            RegexOptions.Compiled | RegexOptions.CultureInvariant | RegexOptions.IgnoreCase\n        );\n\n        private readonly ILogger _logger;\n\n        /// <summary>\n        /// Creates a <see cref=\"Web3KeyStore\"/> instance with a custom directory\n        /// <paramref name=\"path\"/>.\n        /// </summary>\n        /// <param name=\"path\">A path of the directory to store key files.  A new directory is\n        /// created if not exists.</param>\n        /// <exception cref=\"ArgumentNullException\">Thrown when <see langword=\"null\"/> is passed to\n        /// <paramref name=\"path\"/>.</exception>\n        /// <seealso cref=\"DefaultKeyStore\"/>\n        public Web3KeyStore(string path)\n        {\n            _logger = Log.ForContext<Web3KeyStore>().ForContext(\"DirectoryPath\", path);\n\n            if (path is null)\n            {\n                throw new ArgumentNullException(nameof(path));\n            }\n            else if (!Directory.Exists(path))\n            {\n                Directory.CreateDirectory(path);\n                _logger.Debug(\n                    \"Created a directory {DirectoryPath} as it did not exist\",\n                    path\n                );\n            }\n\n            Path = path;\n        }\n\n        /// <summary>\n        /// A default <see cref=\"Web3KeyStore\"/> instance which refers to a user-local directory.\n        /// The <see cref=\"Path\"/> differs on the platform:\n        /// <list type=\"table\">\n        /// <listheader>\n        /// <term>OS</term>\n        /// <description>Directory path</description>\n        /// </listheader>\n        /// <item>\n        /// <term>Linux/macOS</term>\n        /// <description><var>$HOME</var>/.config/planetarium/keystore</description>\n        /// </item>\n        /// <item>\n        /// <term>Windows</term>\n        /// <description><var>%AppData%</var>\\planetarium\\keystore</description>\n        /// </item>\n        /// </list>\n        /// </summary>\n        /// <seealso cref=\"Web3KeyStore(string)\"/>\n        public static Web3KeyStore DefaultKeyStore =>\n            new Web3KeyStore(DefaultPath);\n\n        /// <summary>\n        /// The path of the directory key files are placed.\n        /// </summary>\n        public string Path { get; }\n\n        /// <inheritdoc/>\n        public IEnumerable<Tuple<Guid, ProtectedPrivateKey>> List() =>\n            ListFiles().Select(pair => Tuple.Create(pair.Item1, Get(pair.Item2)));\n\n        /// <inheritdoc/>\n        public IEnumerable<Guid> ListIds() =>\n            ListFiles().Select(pair => pair.Item1);\n\n        /// <inheritdoc/>\n        public ProtectedPrivateKey Get(Guid id)\n        {\n            IEnumerable<(Guid, string)> files = ListFiles();\n            string keyPath;\n            try\n            {\n                (_, keyPath) = files.First(pair => pair.Item1.Equals(id));\n            }\n            catch (InvalidOperationException)\n            {\n                throw new NoKeyException(\"There is no key with such ID\", id);\n            }\n\n            return Get(keyPath);\n        }\n\n        /// <inheritdoc/>\n        public Guid Add(ProtectedPrivateKey key)\n        {\n            if (key is null)\n            {\n                throw new ArgumentNullException(nameof(key));\n            }\n\n            Guid keyId = Guid.NewGuid();\n            string filename = string.Format(\n                CultureInfo.InvariantCulture,\n                NameFormat,\n                DateTimeOffset.UtcNow,\n                keyId\n            );\n            var keyPath = System.IO.Path.Combine(Path, filename);\n            using Stream f = new FileStream(keyPath, FileMode.CreateNew);\n            key.WriteJson(f, keyId);\n            return keyId;\n        }\n\n        /// <inheritdoc/>\n        public void Remove(Guid id)\n        {\n            foreach ((Guid keyId, string keyPath) in ListFiles())\n            {\n                if (keyId.Equals(id))\n                {\n                    System.IO.File.Delete(keyPath);\n                    return;\n                }\n            }\n\n            throw new NoKeyException(\"No key have such ID\", id);\n        }\n\n        private IEnumerable<(Guid, string)> ListFiles()\n        {\n            IEnumerable<string> keyPaths = Directory.EnumerateFiles(Path);\n            foreach (string keyPath in keyPaths)\n            {\n                if (System.IO.Path.GetFileName(keyPath) is string f)\n                {\n                    Match m = NamePattern.Match(f);\n                    if (m.Success)\n                    {\n#pragma warning disable S4056\n                        if (!Guid.TryParse(m.Groups[1].Value, out Guid id))\n#pragma warning restore S4056\n                        {\n                            _logger.Debug(\n                                \"Failed to parse the file name due to invalid UUID: {keyPath}\",\n                                Path);\n                            continue;\n                        }\n\n                        yield return (id, keyPath);\n                    }\n                }\n            }\n        }\n\n        private ProtectedPrivateKey Get(string keyPath)\n        {\n            using StreamReader reader = new StreamReader(keyPath);\n            return ProtectedPrivateKey.FromJson(reader.ReadToEnd());\n        }\n    }\n}\n"
  },
  {
    "path": "src/Libplanet/Libplanet.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <PropertyGroup>\n    <Summary>A .NET library for creating multiplayer online game in decentralized fashion.</Summary>\n    <Description>A .NET library for creating multiplayer online game in decentralized fashion.\nSee also the docs for details:\nhttps://docs.libplanet.io/</Description>\n    <!-- FIXME: The above summary/description should be rewritten. -->\n  </PropertyGroup>\n\n  <PropertyGroup>\n    <ProduceReferenceAssembly>true</ProduceReferenceAssembly>\n    <GenerateDocumentationFile>true</GenerateDocumentationFile>\n    <TreatWarningsAsErrors>true</TreatWarningsAsErrors>\n    <NoWarn>$(NoWarn);S4035;CS1591;NU5104;MEN001;NU1902</NoWarn>\n    <!-- FIXME: S4035 and CS1591 should be turned on eventually. -->\n    <!-- FIXME: NU1902 should be removed once BouncyCastle is bumped to a secure version -->\n  </PropertyGroup>\n\n  <ItemGroup>\n    <PackageReference Include=\"System.Collections.Immutable\" Version=\"1.*\" />\n    <PackageReference Include=\"System.Diagnostics.DiagnosticSource\" Version=\"8.0.0\" />\n    <PackageReference Include=\"System.Text.Json\" Version=\"6.0.*\" />\n    <PackageReference Include=\"Bencodex\" Version=\"0.16.0\" />\n    <PackageReference Include=\"BouncyCastle.Cryptography\" Version=\"2.4.0\" />\n    <PackageReference Include=\"Serilog\" Version=\"2.8.0\" />\n    <PackageReference Include=\"Microsoft.Bcl.HashCode\" Version=\"1.1.1\" />\n    <PackageReference Include=\"Norgerman.Cryptography.Scrypt\" Version=\"2.0.1\" />\n    <PackageReference Include=\"Nito.AsyncEx\" Version=\"5.0.0\" />\n    <PackageReference Include=\"System.Linq.Async\" Version=\"4.0.*\" />\n  </ItemGroup>\n\n  <ItemGroup Condition=\" '$(TargetFramework)' == 'netstandard2.0' or\n                         '$(TargetFramework)' == 'netstandard2.1'\">\n    <PackageReference Include=\"System.Threading.Channels\" Version=\"5.0.0\" />\n  </ItemGroup>\n\n  <ItemGroup Condition=\" '$(TargetFramework)' == 'netstandard2.0'\">\n    <PackageReference Include=\"System.Memory\" Version=\"4.5.5\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <ProjectReference Include=\"..\\Libplanet.Common\\Libplanet.Common.csproj\" />\n    <ProjectReference Include=\"..\\Libplanet.Crypto\\Libplanet.Crypto.csproj\" />\n    <ProjectReference Include=\"..\\Libplanet.Types\\Libplanet.Types.csproj\" />\n    <ProjectReference Include=\"..\\Libplanet.Store\\Libplanet.Store.csproj\" />\n    <ProjectReference Include=\"..\\Libplanet.Action\\Libplanet.Action.csproj\" />\n  </ItemGroup>\n\n</Project>\n"
  },
  {
    "path": "src/Libplanet.Action/AccountMetrics.cs",
    "content": "using System.Diagnostics;\nusing System.Threading;\n\nnamespace Libplanet.Action\n{\n    public static class AccountMetrics\n    {\n        public static readonly AsyncLocal<Stopwatch> GetStateTimer = new AsyncLocal<Stopwatch>();\n        public static readonly AsyncLocal<int> GetStateCount = new AsyncLocal<int>();\n\n        public static void Initialize()\n        {\n            GetStateTimer.Value = new Stopwatch();\n            GetStateCount.Value = 0;\n        }\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Action/ActionContext.cs",
    "content": "using System.Collections.Generic;\nusing System.Collections.Immutable;\nusing System.Diagnostics.Contracts;\nusing Libplanet.Action.State;\nusing Libplanet.Crypto;\nusing Libplanet.Types.Assets;\nusing Libplanet.Types.Blocks;\nusing Libplanet.Types.Evidence;\nusing Libplanet.Types.Tx;\n\nnamespace Libplanet.Action\n{\n    internal class ActionContext : IActionContext\n    {\n        private readonly IReadOnlyList<ITransaction> _txs;\n\n        public ActionContext(\n            Address signer,\n            TxId? txid,\n            Address miner,\n            long blockIndex,\n            int blockProtocolVersion,\n            BlockCommit? lastCommit,\n            IWorld previousState,\n            int randomSeed,\n            bool isPolicyAction,\n            FungibleAssetValue? maxGasPrice,\n            IReadOnlyList<ITransaction>? txs = null,\n            IReadOnlyList<EvidenceBase>? evidence = null)\n        {\n            Signer = signer;\n            TxId = txid;\n            Miner = miner;\n            BlockIndex = blockIndex;\n            BlockProtocolVersion = blockProtocolVersion;\n            LastCommit = lastCommit;\n            PreviousState = previousState;\n            RandomSeed = randomSeed;\n            IsPolicyAction = isPolicyAction;\n            MaxGasPrice = maxGasPrice;\n            _txs = txs ?? ImmutableList<Transaction>.Empty;\n            Evidence = evidence ?? ImmutableList<EvidenceBase>.Empty;\n        }\n\n        /// <inheritdoc cref=\"IActionContext.Signer\"/>\n        public Address Signer { get; }\n\n        /// <inheritdoc cref=\"IActionContext.TxId\"/>\n        public TxId? TxId { get; }\n\n        /// <inheritdoc cref=\"IActionContext.Miner\"/>\n        public Address Miner { get; }\n\n        /// <inheritdoc cref=\"IActionContext.BlockIndex\"/>\n        public long BlockIndex { get; }\n\n        /// <inheritdoc cref=\"IActionContext.BlockProtocolVersion\"/>\n        public int BlockProtocolVersion { get; }\n\n        /// <inheritdoc cref=\"IActionContext.LastCommit\"/>\n        public BlockCommit? LastCommit { get;  }\n\n        /// <inheritdoc cref=\"IActionContext.PreviousState\"/>\n        public IWorld PreviousState { get; }\n\n        /// <inheritdoc cref=\"IActionContext.RandomSeed\"/>\n        public int RandomSeed { get; }\n\n        /// <inheritdoc cref=\"IActionContext.IsPolicyAction\"/>\n        public bool IsPolicyAction { get; }\n\n        /// <inheritdoc cref=\"IActionContext.MaxGasPrice\"/>\n        [Pure]\n        public FungibleAssetValue? MaxGasPrice { get; }\n\n        /// <inheritdoc cref=\"IActionContext.Txs\"/>\n        public IReadOnlyList<ITransaction> Txs => IsPolicyAction\n            ? _txs\n            : ImmutableList<ITransaction>.Empty;\n\n        /// <inheritdoc cref=\"IActionContext.Evidence\"/>\n        public IReadOnlyList<EvidenceBase> Evidence { get; }\n\n        /// <inheritdoc cref=\"IActionContext.GetRandom\"/>\n        public IRandom GetRandom() => new Random(RandomSeed);\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Action/ActionEvaluation.cs",
    "content": "using System;\nusing Bencodex.Types;\nusing Libplanet.Action.State;\n\nnamespace Libplanet.Action\n{\n    /// <summary>\n    /// A record type to represent an evaluation plan and result of\n    /// a single action.\n    /// </summary>\n    public class ActionEvaluation : IActionEvaluation\n    {\n        /// <summary>\n        /// Creates an <see cref=\"ActionEvaluation\"/> instance\n        /// with filling properties.\n        /// </summary>\n        /// <param name=\"action\">An action to evaluate.</param>\n        /// <param name=\"inputContext\">An input <see cref=\"IActionContext\"/> to\n        /// evaluate <paramref name=\"action\"/>.</param>\n        /// <param name=\"outputState\">The result states that\n        /// <paramref name=\"action\"/> makes.</param>\n        /// <param name=\"exception\">An exception that has risen during evaluating a given\n        /// <paramref name=\"action\"/>.</param>\n        public ActionEvaluation(\n            IAction action,\n            IActionContext inputContext,\n            IWorld outputState,\n            Exception? exception = null)\n        {\n            Action = action;\n            InputContext = inputContext;\n            OutputState = outputState;\n            Exception = exception;\n        }\n\n        IValue IActionEvaluation.Action => Action.PlainValue;\n\n        /// <summary>\n        /// An action to evaluate.\n        /// </summary>\n        public IAction Action { get; }\n\n        /// <summary>\n        /// An input <see cref=\"IActionContext\"/> to evaluate\n        /// <see cref=\"Action\"/>.\n        /// </summary>\n        /// <remarks>Its <see cref=\"IActionContext.Random\"/> property\n        /// is not consumed yet.</remarks>\n        public IActionContext InputContext { get; }\n\n        /// <summary>\n        /// The result states that <see cref=\"Action\"/> makes.\n        /// </summary>\n        public IWorld OutputState { get; }\n\n        /// <summary>\n        /// An exception that had risen during evaluation.\n        /// </summary>\n        public Exception? Exception { get; }\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Action/ActionEvaluator.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Collections.Immutable;\nusing System.Diagnostics;\nusing System.Diagnostics.Contracts;\nusing System.Linq;\nusing System.Numerics;\nusing System.Security.Cryptography;\nusing Bencodex.Types;\nusing Libplanet.Action.Loader;\nusing Libplanet.Action.State;\nusing Libplanet.Common;\nusing Libplanet.Store;\nusing Libplanet.Store.Trie;\nusing Libplanet.Types.Blocks;\nusing Libplanet.Types.Tx;\nusing Serilog;\n\nnamespace Libplanet.Action\n{\n    /// <summary>\n    /// Class responsible for handling of <see cref=\"IAction\"/> evaluations.\n    /// </summary>\n    public class ActionEvaluator : IActionEvaluator\n    {\n        private readonly ILogger _logger;\n        private readonly IPolicyActionsRegistry _policyActionsRegistry;\n        private readonly IStateStore _stateStore;\n        private readonly IActionLoader _actionLoader;\n\n        /// <summary>\n        /// Creates a new <see cref=\"ActionEvaluator\"/>.\n        /// </summary>\n        /// <param name=\"policyActionsRegistry\">\n        /// A <see cref=\"PolicyActionsRegistry\"/> containing delegators\n        /// to get policy actions to evaluate at each situation.\n        /// </param>\n        /// <param name=\"stateStore\">The <see cref=\"IStateStore\"/> to use to retrieve\n        /// the states for a provided <see cref=\"HashDigest{SHA256}\"/>.</param>\n        /// <param name=\"actionTypeLoader\"> A <see cref=\"IActionLoader\"/> implementation using\n        /// action type lookup.</param>\n        public ActionEvaluator(\n            IPolicyActionsRegistry policyActionsRegistry,\n            IStateStore stateStore,\n            IActionLoader actionTypeLoader)\n        {\n            _logger = Log.ForContext<ActionEvaluator>()\n                .ForContext(\"Source\", nameof(ActionEvaluator));\n            _policyActionsRegistry = policyActionsRegistry;\n            _stateStore = stateStore;\n            _actionLoader = actionTypeLoader;\n        }\n\n        private delegate (ITrie, int) StateCommitter(\n            ITrie worldTrie, IActionEvaluation evaluation);\n\n        /// <inheritdoc cref=\"IActionEvaluator.ActionLoader\"/>\n        [Pure]\n        public IActionLoader ActionLoader => _actionLoader;\n\n        /// <summary>\n        /// Creates a random seed.\n        /// </summary>\n        /// <param name=\"preEvaluationHashBytes\">The pre-evaluation hash as bytes.\n        /// </param>\n        /// <param name=\"signature\">The signature of the <see cref=\"Transaction\"/> the target\n        /// <see cref=\"IAction\"/> belongs to.  Must be empty if the target <see cref=\"IAction\"/>\n        /// is a block action.</param>\n        /// <param name=\"actionOffset\">The offset of the target <see cref=\"IAction\"/>.</param>\n        /// <returns>An integer of the random seed.\n        /// </returns>\n        /// <exception cref=\"ArgumentException\">Thrown when\n        /// <paramref name=\"preEvaluationHashBytes\"/> is empty.</exception>\n        [Pure]\n        public static int GenerateRandomSeed(\n            byte[] preEvaluationHashBytes,\n            byte[] signature,\n            int actionOffset)\n        {\n            using (var sha1 = SHA1.Create())\n            {\n                unchecked\n                {\n                    return ((preEvaluationHashBytes.Length > 0\n                        ? BitConverter.ToInt32(preEvaluationHashBytes, 0)\n                        : throw new ArgumentException(\n                            $\"Given {nameof(preEvaluationHashBytes)} cannot be empty\",\n                            nameof(preEvaluationHashBytes)))\n                    ^ (signature.Any()\n                        ? BitConverter.ToInt32(sha1.ComputeHash(signature), 0)\n                        : 0))\n                    + actionOffset;\n                }\n            }\n        }\n\n        /// <inheritdoc cref=\"IActionEvaluator.Evaluate\"/>\n        [Pure]\n        public IReadOnlyList<ICommittedActionEvaluation> Evaluate(\n            IPreEvaluationBlock block,\n            HashDigest<SHA256>? baseStateRootHash)\n        {\n            if (block.ProtocolVersion < BlockMetadata.PBFTProtocolVersion)\n            {\n                throw new BlockProtocolVersionNotSupportedException(\n                    $\"The native implementation does not support an evaluation of a block \" +\n                    $\"#{block.Index} pre-evaluation hash {block.PreEvaluationHash} \" +\n                    $\"with protocol version less than {BlockMetadata.PBFTProtocolVersion}: \" +\n                    $\"{block.ProtocolVersion}\",\n                    block.ProtocolVersion);\n            }\n\n            _logger.Information(\n                \"Evaluating actions in the block #{BlockIndex} \" +\n                \"pre-evaluation hash {PreEvaluationHash}...\",\n                block.Index,\n                ByteUtil.Hex(block.PreEvaluationHash.ByteArray)\n            );\n            Stopwatch stopwatch = new Stopwatch();\n            stopwatch.Start();\n            try\n            {\n                IWorld previousState = _stateStore.GetWorld(baseStateRootHash);\n                previousState = _stateStore.MigrateWorld(previousState, block.ProtocolVersion);\n\n                var evaluations = ImmutableList<ActionEvaluation>.Empty;\n                if (_policyActionsRegistry.BeginBlockActions.Length > 0)\n                {\n                    evaluations = evaluations.AddRange(EvaluatePolicyBeginBlockActions(\n                        block, previousState\n                    ));\n                    previousState = evaluations.Last().OutputState;\n                }\n\n                evaluations = evaluations.AddRange(\n                    EvaluateBlock(block, previousState).ToImmutableList()\n                );\n\n                if (_policyActionsRegistry.EndBlockActions.Length > 0)\n                {\n                    previousState = evaluations.Count > 0\n                        ? evaluations.Last().OutputState\n                        : previousState;\n                    evaluations = evaluations.AddRange(EvaluatePolicyEndBlockActions(\n                        block, previousState\n                    ));\n                }\n\n                var committed = ToCommittedEvaluation(block, evaluations, baseStateRootHash);\n                return committed;\n            }\n            catch (Exception e)\n            {\n                const string errorMessage =\n                    \"Failed to evaluate block #{BlockIndex} pre-evaluation hash \" +\n                    \"pre-evaluation has {PreEvaluationHash}\";\n                _logger.Error(\n                    e,\n                    errorMessage,\n                    block.Index,\n                    ByteUtil.Hex(block.PreEvaluationHash.ByteArray));\n                throw;\n            }\n            finally\n            {\n                _logger\n                    .ForContext(\"Tag\", \"Metric\")\n                    .ForContext(\"Subtag\", \"BlockEvaluationDuration\")\n                    .Information(\n                        \"Actions in {TxCount} transactions for block #{BlockIndex} \" +\n                        \"pre-evaluation hash {PreEvaluationHash} evaluated in {DurationMs} ms\",\n                        block.Transactions.Count,\n                        block.Index,\n                        ByteUtil.Hex(block.PreEvaluationHash.ByteArray),\n                        stopwatch.ElapsedMilliseconds);\n            }\n        }\n\n        /// <summary>\n        /// Executes <see cref=\"IAction\"/>s in <paramref name=\"actions\"/>.  All other evaluation\n        /// calls resolve to this method.\n        /// </summary>\n        /// <param name=\"block\">The <see cref=\"IPreEvaluationBlock\"/> to evaluate.</param>\n        /// <param name=\"tx\">The <see cref=\"Transaction\"/> that <paramref name=\"actions\"/>\n        /// belong to.  This should be <see langword=\"null\"/> if <paramref name=\"actions\"/>\n        /// do not belong to a <see cref=\"Transaction\"/>, i.e.\n        /// <see cref=\"IBlockPolicy.BlockAction\"/>.</param>\n        /// <param name=\"previousState\">The states immediately before <paramref name=\"actions\"/>\n        /// being executed.</param>\n        /// <param name=\"actions\">Actions to evaluate.</param>\n        /// <param name=\"stateStore\">An <see cref=\"IStateStore\"/> to use.</param>\n        /// <param name=\"isPolicyAction\">\n        /// Flag indicates that whether the action is a policy action.</param>\n        /// <param name=\"logger\">An optional logger.</param>\n        /// <returns>An enumeration of <see cref=\"ActionEvaluation\"/>s for each\n        /// <see cref=\"IAction\"/> in <paramref name=\"actions\"/>.\n        /// </returns>\n        [Pure]\n        internal static IEnumerable<ActionEvaluation> EvaluateActions(\n            IPreEvaluationBlock block,\n            ITransaction? tx,\n            IWorld previousState,\n            IImmutableList<IAction> actions,\n            IStateStore stateStore,\n            bool isPolicyAction,\n            ILogger? logger = null)\n        {\n            IActionContext CreateActionContext(\n                IWorld prevState,\n                int randomSeed)\n            {\n                return new ActionContext(\n                    signer: tx?.Signer ?? block.Miner,\n                    txid: tx?.Id ?? null,\n                    miner: block.Miner,\n                    blockIndex: block.Index,\n                    blockProtocolVersion: block.ProtocolVersion,\n                    lastCommit: block.LastCommit,\n                    txs: block.Transactions,\n                    previousState: prevState,\n                    isPolicyAction: isPolicyAction,\n                    randomSeed: randomSeed,\n                    maxGasPrice: tx?.MaxGasPrice,\n                    evidence: block.Evidence);\n            }\n\n            byte[] preEvaluationHashBytes = block.PreEvaluationHash.ToByteArray();\n            byte[] signature = tx?.Signature ?? Array.Empty<byte>();\n            int seed = GenerateRandomSeed(preEvaluationHashBytes, signature, 0);\n\n            IWorld state = previousState;\n            foreach (IAction action in actions)\n            {\n                IActionContext context = CreateActionContext(state, seed);\n                ActionEvaluation evaluation = EvaluateAction(\n                    block,\n                    tx,\n                    context,\n                    action,\n                    stateStore,\n                    isPolicyAction,\n                    logger);\n\n                yield return evaluation;\n\n                state = evaluation.OutputState;\n\n                unchecked\n                {\n                    seed++;\n                }\n            }\n        }\n\n        internal static ActionEvaluation EvaluateAction(\n            IPreEvaluationBlock block,\n            ITransaction? tx,\n            IActionContext context,\n            IAction action,\n            IStateStore stateStore,\n            bool isPolicyAction,\n            ILogger? logger = null)\n        {\n            if (!context.PreviousState.Trie.Recorded)\n            {\n                throw new InvalidOperationException(\n                    $\"Given {nameof(context)} must have its previous state's \" +\n                    $\"{nameof(ITrie)} recorded.\");\n            }\n\n            IActionContext inputContext = context;\n            IWorld state = inputContext.PreviousState;\n            Exception? exc = null;\n\n            IActionContext CreateActionContext(IWorld newPrevState)\n            {\n                return new ActionContext(\n                    signer: inputContext.Signer,\n                    txid: inputContext.TxId,\n                    miner: inputContext.Miner,\n                    blockIndex: inputContext.BlockIndex,\n                    blockProtocolVersion: inputContext.BlockProtocolVersion,\n                    lastCommit: inputContext.LastCommit,\n                    previousState: newPrevState,\n                    randomSeed: inputContext.RandomSeed,\n                    isPolicyAction: isPolicyAction,\n                    maxGasPrice: tx?.MaxGasPrice,\n                    txs: inputContext.Txs,\n                    evidence: inputContext.Evidence);\n            }\n\n            try\n            {\n                Stopwatch stopwatch = new Stopwatch();\n                stopwatch.Start();\n                AccountMetrics.Initialize();\n                context = CreateActionContext(state);\n                state = action.Execute(context);\n                logger?\n                    .ForContext(\"Tag\", \"Metric\")\n                    .ForContext(\"Subtag\", \"ActionExecutionTime\")\n                    .Information(\n                        \"Action {Action} took {DurationMs} ms to execute, \" +\n                        \"GetState called {GetStateCount} times \" +\n                        \"and took {GetStateDurationMs} ms\",\n                        action,\n                        stopwatch.ElapsedMilliseconds,\n                        AccountMetrics.GetStateCount.Value,\n                        AccountMetrics.GetStateTimer.Value?.ElapsedMilliseconds);\n            }\n            catch (OutOfMemoryException e)\n            {\n                // Because OutOfMemory is thrown non-deterministically depending on the state\n                // of the node, we should throw without further handling.\n                var message =\n                    \"Action {Action} of tx {TxId} of block #{BlockIndex} with \" +\n                    \"pre-evaluation hash {PreEvaluationHash} threw an exception \" +\n                    \"during execution\";\n                logger?.Error(\n                    e,\n                    message,\n                    action,\n                    tx?.Id,\n                    block.Index,\n                    ByteUtil.Hex(block.PreEvaluationHash.ByteArray));\n                throw;\n            }\n            catch (Exception e)\n            {\n                var message =\n                    \"Action {Action} of tx {TxId} of block #{BlockIndex} with \" +\n                    \"pre-evaluation hash {PreEvaluationHash} threw an exception \" +\n                    \"during execution\";\n                logger?.Error(\n                    e,\n                    message,\n                    action,\n                    tx?.Id,\n                    block.Index,\n                    ByteUtil.Hex(block.PreEvaluationHash.ByteArray));\n                var innerMessage =\n                    $\"The action {action} (block #{block.Index}, \" +\n                    $\"pre-evaluation hash \" +\n                    $\"{ByteUtil.Hex(block.PreEvaluationHash.ByteArray)}, \" +\n                    $\"tx {tx?.Id} threw an exception during execution.  \" +\n                    \"See also this exception's InnerException property\";\n                logger?.Error(\n                    \"{Message}\\nInnerException: {ExcMessage}\", innerMessage, e.Message);\n                exc = new UnexpectedlyTerminatedActionException(\n                    innerMessage,\n                    block.PreEvaluationHash,\n                    block.Index,\n                    tx?.Id,\n                    null,\n                    action,\n                    e);\n            }\n\n            state = stateStore.CommitWorld(state);\n\n            if (!state.Trie.Recorded)\n            {\n                throw new InvalidOperationException(\n                    $\"Failed to record {nameof(IAccount)}'s {nameof(ITrie)}.\");\n            }\n\n            return new ActionEvaluation(\n                    action: action,\n                    inputContext: inputContext,\n                    outputState: state,\n                    exception: exc);\n        }\n\n        /// <summary>\n        /// Deterministically shuffles <paramref name=\"txs\"/> for evaluation using\n        /// <paramref name=\"preEvaluationHashBytes\"/> as a random seed.\n        /// </summary>\n        /// <param name=\"protocolVersion\">The <see cref=\"IBlockMetadata.ProtocolVersion\"/>\n        /// that <paramref name=\"txs\"/> belong to.</param>\n        /// <param name=\"txs\">The list of <see cref=\"ITransaction\"/>s to shuffle.</param>\n        /// <param name=\"preEvaluationHashBytes\">The\n        /// <see cref=\"IPreEvaluationBlockHeader.PreEvaluationHash\"/>\n        /// to use as a random seed when\n        /// shuffling.</param>\n        /// <returns>An <see cref=\"IEnumerable{T}\"/> of <see cref=\"ITransaction\"/>s in evaluation\n        /// order with the following properties:\n        /// <list type=\"bullet\">\n        /// <item><see cref=\"ITransaction\"/>s with the same <see cref=\"ITxSigningMetadata.Signer\"/>\n        /// value appear consecutive in the list.</item>\n        /// <item><see cref=\"ITransaction\"/>s with the same <see cref=\"ITxSigningMetadata.Signer\"/>\n        /// value are ordered by <see cref=\"ITxSigningMetadata.Nonce\"/> value in ascending order.\n        /// </item>\n        /// </list>\n        /// </returns>\n        /// <remarks>\n        /// This is to prevent an attempt to gain a first move advantage by participants.\n        /// </remarks>\n        [Pure]\n        internal static IEnumerable<ITransaction> OrderTxsForEvaluation(\n            int protocolVersion,\n            IEnumerable<ITransaction> txs,\n            ImmutableArray<byte> preEvaluationHashBytes)\n        {\n            return protocolVersion >= BlockMetadata.TransactionOrderingFixProtocolVersion\n                ? OrderTxsForEvaluationV3(txs, preEvaluationHashBytes)\n                : OrderTxsForEvaluationV0(txs, preEvaluationHashBytes);\n        }\n\n        /// <summary>\n        /// Evaluates <see cref=\"IAction\"/>s in <see cref=\"IBlockContent.Transactions\"/>\n        /// of a given <see cref=\"IPreEvaluationBlock\"/>.\n        /// </summary>\n        /// <param name=\"block\">The <see cref=\"IPreEvaluationBlock\"/> to evaluate.</param>\n        /// <param name=\"previousState\">The states immediately before an execution of any\n        /// <see cref=\"IAction\"/>s.</param>\n        /// <returns>An <see cref=\"IEnumerable{T}\"/> of <see cref=\"ActionEvaluation\"/>s\n        /// where each <see cref=\"ActionEvaluation\"/> is the evaluation of an <see cref=\"IAction\"/>.\n        /// </returns>\n        [Pure]\n        internal IEnumerable<ActionEvaluation> EvaluateBlock(\n            IPreEvaluationBlock block,\n            IWorld previousState)\n        {\n            IWorld delta = previousState;\n            IEnumerable<ITransaction> orderedTxs = OrderTxsForEvaluation(\n                block.ProtocolVersion,\n                block.Transactions,\n                block.PreEvaluationHash.ByteArray);\n\n            foreach (ITransaction tx in orderedTxs)\n            {\n                Stopwatch stopwatch = new Stopwatch();\n                stopwatch.Start();\n\n                IEnumerable<ActionEvaluation> evaluations = EvaluateTx(\n                    block: block,\n                    tx: tx,\n                    previousState: delta);\n\n                var actions = new List<IAction>();\n                foreach (ActionEvaluation evaluation in evaluations)\n                {\n                    yield return evaluation;\n                    delta = evaluation.OutputState;\n                    actions.Add(evaluation.Action);\n                }\n\n                // FIXME: This is dependent on when the returned value is enumerated.\n                ILogger logger = _logger\n                    .ForContext(\"Tag\", \"Metric\")\n                    .ForContext(\"Subtag\", \"TxEvaluationDuration\");\n                logger.Information(\n                    \"Took {DurationMs} ms to evaluate {ActionCount} actions {ActionTypes} \" +\n                    \"in transaction {TxId} by {Signer} as a part of block #{Index} \" +\n                    \"pre-evaluation hash {PreEvaluationHash}\",\n                    stopwatch.ElapsedMilliseconds,\n                    actions.Count,\n                    actions.Select(action => action.ToString()!.Split('.')\n                        .LastOrDefault()?.Replace(\">\", string.Empty)),\n                    tx.Id,\n                    tx.Signer,\n                    block.Index,\n                    ByteUtil.Hex(block.PreEvaluationHash.ByteArray));\n            }\n        }\n\n        [Pure]\n        internal IEnumerable<ActionEvaluation> EvaluateTx(\n            IPreEvaluationBlock block,\n            ITransaction tx,\n            IWorld previousState)\n        {\n            GasTracer.Initialize(tx.GasLimit ?? long.MaxValue);\n            var evaluations = ImmutableList<ActionEvaluation>.Empty;\n            if (_policyActionsRegistry.BeginTxActions.Length > 0)\n            {\n                GasTracer.IsTxAction = true;\n                evaluations = evaluations.AddRange(\n                    EvaluatePolicyBeginTxActions(block, tx, previousState));\n                previousState = evaluations.Last().OutputState;\n                GasTracer.IsTxAction = false;\n            }\n\n            ImmutableList<IAction> actions =\n                ImmutableList.CreateRange(LoadActions(block.Index, tx));\n            evaluations = evaluations.AddRange(EvaluateActions(\n                block: block,\n                tx: tx,\n                previousState: previousState,\n                actions: actions,\n                stateStore: _stateStore,\n                isPolicyAction: false,\n                logger: _logger));\n\n            if (_policyActionsRegistry.EndTxActions.Length > 0)\n            {\n                previousState = evaluations.Count > 0\n                    ? evaluations.Last().OutputState\n                    : previousState;\n                evaluations = evaluations.AddRange(\n                    EvaluatePolicyEndTxActions(block, tx, previousState));\n            }\n\n            GasTracer.Release();\n\n            return evaluations;\n        }\n\n        /// <summary>\n        /// Evaluates the <see cref=\"IBlockPolicy.BeginBlockActions\"/> set by the policy when\n        /// this <see cref=\"ActionEvaluator\"/> was instantiated for a given\n        /// <see cref=\"IPreEvaluationBlockHeader\"/>.\n        /// </summary>\n        /// <param name=\"block\">The <see cref=\"IPreEvaluationBlock\"/> to evaluate.</param>\n        /// <param name=\"previousState\">The states immediately before the evaluation of\n        /// the <see cref=\"IBlockPolicy.BeginBlockActions\"/> held by the instance.</param>\n        /// <returns>The <see cref=\"ActionEvaluation\"/> of evaluating\n        /// the <see cref=\"IBlockPolicy.BeginBlockActions\"/> held by the instance\n        /// for the <paramref name=\"block\"/>.</returns>\n        [Pure]\n        internal ActionEvaluation[] EvaluatePolicyBeginBlockActions(\n            IPreEvaluationBlock block,\n            IWorld previousState)\n        {\n            _logger.Information(\n                $\"Evaluating policy begin block actions for block #{block.Index} \" +\n                $\"{ByteUtil.Hex(block.PreEvaluationHash.ByteArray)}\");\n\n            return EvaluateActions(\n                block: block,\n                tx: null,\n                previousState: previousState,\n                actions: _policyActionsRegistry.BeginBlockActions,\n                stateStore: _stateStore,\n                isPolicyAction: true,\n                logger: _logger).ToArray();\n        }\n\n        /// <summary>\n        /// Evaluates the <see cref=\"IBlockPolicy.EndBlockActions\"/> set by the policy when\n        /// this <see cref=\"ActionEvaluator\"/> was instantiated for a given\n        /// <see cref=\"IPreEvaluationBlockHeader\"/>.\n        /// </summary>\n        /// <param name=\"block\">The <see cref=\"IPreEvaluationBlock\"/> to evaluate.</param>\n        /// <param name=\"previousState\">The states immediately before the evaluation of\n        /// the <see cref=\"IBlockPolicy.EndBlockActions\"/> held by the instance.</param>\n        /// <returns>The <see cref=\"ActionEvaluation\"/> of evaluating\n        /// the <see cref=\"IBlockPolicy.EndBlockActions\"/> held by the instance\n        /// for the <paramref name=\"block\"/>.</returns>\n        [Pure]\n        internal ActionEvaluation[] EvaluatePolicyEndBlockActions(\n            IPreEvaluationBlock block,\n            IWorld previousState)\n        {\n            _logger.Information(\n                $\"Evaluating policy end block actions for block #{block.Index} \" +\n                $\"{ByteUtil.Hex(block.PreEvaluationHash.ByteArray)}\");\n\n            return EvaluateActions(\n                block: block,\n                tx: null,\n                previousState: previousState,\n                actions: _policyActionsRegistry.EndBlockActions,\n                stateStore: _stateStore,\n                isPolicyAction: true,\n                logger: _logger).ToArray();\n        }\n\n        /// <summary>\n        /// Evaluates the <see cref=\"IBlockPolicy.BeginTxActions\"/> set by the policy when\n        /// this <see cref=\"ActionEvaluator\"/> was instantiated for a given\n        /// <see cref=\"IPreEvaluationBlockHeader\"/>.\n        /// </summary>\n        /// <param name=\"block\">The <see cref=\"IPreEvaluationBlock\"/> to evaluate.</param>\n        /// <param name=\"transaction\">The transaction that the tx action belongs to.</param>\n        /// <param name=\"previousState\">The states immediately before the evaluation of\n        /// the <see cref=\"IBlockPolicy.BlockAction\"/> held by the instance.</param>\n        /// <returns>The <see cref=\"ActionEvaluation\"/> of evaluating\n        /// the <see cref=\"IBlockPolicy.BlockAction\"/> held by the instance\n        /// for the <paramref name=\"block\"/>.</returns>\n        [Pure]\n        internal ActionEvaluation[] EvaluatePolicyBeginTxActions(\n            IPreEvaluationBlock block,\n            ITransaction transaction,\n            IWorld previousState)\n        {\n            _logger.Information(\n                $\"Evaluating policy begin tx actions for block #{block.Index} \" +\n                $\"{ByteUtil.Hex(block.PreEvaluationHash.ByteArray)}\");\n\n            return EvaluateActions(\n                block: block,\n                tx: transaction,\n                previousState: previousState,\n                actions: _policyActionsRegistry.BeginTxActions,\n                stateStore: _stateStore,\n                isPolicyAction: true,\n                logger: _logger).ToArray();\n        }\n\n        /// <summary>\n        /// Evaluates the <see cref=\"IBlockPolicy.BeginTxActions\"/> set by the policy when\n        /// this <see cref=\"ActionEvaluator\"/> was instantiated for a given\n        /// <see cref=\"IPreEvaluationBlockHeader\"/>.\n        /// </summary>\n        /// <param name=\"block\">The <see cref=\"IPreEvaluationBlock\"/> to evaluate.</param>\n        /// <param name=\"transaction\">The transaction that the tx action belongs to.</param>\n        /// <param name=\"previousState\">The states immediately before the evaluation of\n        /// the <see cref=\"IBlockPolicy.BlockAction\"/> held by the instance.</param>\n        /// <returns>The <see cref=\"ActionEvaluation\"/> of evaluating\n        /// the <see cref=\"IBlockPolicy.BlockAction\"/> held by the instance\n        /// for the <paramref name=\"block\"/>.</returns>\n        [Pure]\n        internal ActionEvaluation[] EvaluatePolicyEndTxActions(\n            IPreEvaluationBlock block,\n            ITransaction transaction,\n            IWorld previousState)\n        {\n            _logger.Information(\n                $\"Evaluating policy end tx actions for block #{block.Index} \" +\n                $\"{ByteUtil.Hex(block.PreEvaluationHash.ByteArray)}\");\n\n            return EvaluateActions(\n                block: block,\n                tx: transaction,\n                previousState: previousState,\n                actions: _policyActionsRegistry.EndTxActions,\n                stateStore: _stateStore,\n                isPolicyAction: true,\n                logger: _logger).ToArray();\n        }\n\n        internal IReadOnlyList<ICommittedActionEvaluation>\n            ToCommittedEvaluation(\n                IPreEvaluationBlock block,\n                IReadOnlyList<IActionEvaluation> evaluations,\n                HashDigest<SHA256>? baseStateRootHash)\n        {\n            Stopwatch stopwatch = new Stopwatch();\n            stopwatch.Start();\n\n            var committedEvaluations = new List<CommittedActionEvaluation>();\n            foreach (var evaluation in evaluations)\n            {\n#pragma warning disable SA1118\n                var committedEvaluation = new CommittedActionEvaluation(\n                    action: evaluation.Action,\n                    inputContext: new CommittedActionContext(\n                        signer: evaluation.InputContext.Signer,\n                        txId: evaluation.InputContext.TxId,\n                        miner: evaluation.InputContext.Miner,\n                        blockIndex: evaluation.InputContext.BlockIndex,\n                        blockProtocolVersion: evaluation.InputContext.BlockProtocolVersion,\n                        previousState: evaluation.InputContext.PreviousState.Trie.Recorded\n                            ? evaluation.InputContext.PreviousState.Trie.Hash\n                            : throw new ArgumentException(\"Trie is not recorded\"),\n                        randomSeed: evaluation.InputContext.RandomSeed,\n                        isPolicyAction: evaluation.InputContext.IsPolicyAction),\n                    outputState: evaluation.OutputState.Trie.Recorded\n                        ? evaluation.OutputState.Trie.Hash\n                        : throw new ArgumentException(\"Trie is not recorded\"),\n                    exception: evaluation.Exception);\n                committedEvaluations.Add(committedEvaluation);\n#pragma warning restore SA1118\n            }\n\n            return committedEvaluations;\n        }\n\n        [Pure]\n        private static IEnumerable<ITransaction> OrderTxsForEvaluationV0(\n            IEnumerable<ITransaction> txs,\n            ImmutableArray<byte> preEvaluationHashBytes)\n        {\n            // As the order of transactions should be unpredictable until a block is mined,\n            // the sorter key should be derived from both a block hash and a txid.\n            var maskInteger = new BigInteger(preEvaluationHashBytes.ToArray());\n\n            // Transactions with the same signers are grouped first and the ordering of the groups\n            // is determined by the XOR aggregate of the txid's in the group with XOR bitmask\n            // applied using the pre-evaluation hash provided.  Then within each group,\n            // transactions are ordered by nonce.\n            return txs\n                .GroupBy(tx => tx.Signer)\n                .OrderBy(\n                    group => maskInteger ^ group\n                        .Select(tx => new BigInteger(tx.Id.ToByteArray()))\n                        .Aggregate((first, second) => first ^ second))\n                .SelectMany(group => group.OrderBy(tx => tx.Nonce));\n        }\n\n        [Pure]\n        private static IEnumerable<ITransaction> OrderTxsForEvaluationV3(\n            IEnumerable<ITransaction> txs,\n            ImmutableArray<byte> preEvaluationHashBytes)\n        {\n            using SHA256 sha256 = SHA256.Create();\n\n            // Some deterministic preordering is necessary.\n            var groups = txs.GroupBy(tx => tx.Signer).OrderBy(group => group.Key).ToList();\n\n            // Although strictly not necessary, additional hash computation removes zero padding\n            // just in case.\n            byte[] reHash = sha256.ComputeHash(preEvaluationHashBytes.ToArray());\n\n            // As BigInteger uses little-endian, we take the last byte for parity to prevent\n            // the value of reverse directly tied to the parity of startIndex below.\n            bool reverse = reHash.Last() % 2 == 1;\n\n            // This assumes the entropy of preEvaluationHash, thus reHash, is large enough and\n            // its range with BigInteger conversion also is large enough that selection of\n            // startIndex is approximately uniform.\n            int startIndex = groups.Count <= 1\n                ? 0\n                : (int)(new BigInteger(reHash) % groups.Count);\n            startIndex = startIndex >= 0 ? startIndex : -startIndex;\n\n            var result = groups\n                .Skip(startIndex)\n                .Concat(groups.Take(startIndex));\n            if (reverse)\n            {\n                result = result.Reverse();\n            }\n\n            return result.SelectMany(group => group.OrderBy(tx => tx.Nonce));\n        }\n\n        private IEnumerable<IAction> LoadActions(long index, ITransaction tx)\n        {\n            if (tx.Actions is { } actions)\n            {\n                foreach (IValue rawAction in actions)\n                {\n                    yield return _actionLoader.LoadAction(index, rawAction);\n                }\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Action/ActionTypeAttribute.cs",
    "content": "using System;\nusing Bencodex.Types;\n\nnamespace Libplanet.Action\n{\n    /// <summary>\n    /// Indicates that an action class (i.e., a class implementing\n    /// <see cref=\"IAction\"/>) can be held by transactions and blocks.\n    /// It also gives an action class a <see cref=\"TypeIdentifier\"/> for\n    /// serialization and deserialization.\n    /// </summary>\n    [AttributeUsage(AttributeTargets.Class, AllowMultiple = false)]\n    public class ActionTypeAttribute : Attribute\n    {\n        /// <summary>\n        /// Creates an <see cref=\"ActionTypeAttribute\"/> with a given\n        /// <paramref name=\"typeIdentifier\"/>.\n        /// </summary>\n        /// <param name=\"typeIdentifier\">An action class's unique\n        /// identifier for serialization and deserialization.</param>\n        public ActionTypeAttribute(string typeIdentifier)\n        {\n            TypeIdentifier = new Text(typeIdentifier);\n        }\n\n        public ActionTypeAttribute(int typeIdentifier)\n        {\n            TypeIdentifier = new Integer(typeIdentifier);\n        }\n\n        /// <summary>\n        /// An action class's unique identifier for serialization and\n        /// deserialization.\n        /// </summary>\n        public IValue TypeIdentifier { get; }\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Action/ActionsExtensions.cs",
    "content": "using System.Collections.Generic;\nusing System.Linq;\nusing Bencodex.Types;\n\nnamespace Libplanet.Action\n{\n    public static class ActionsExtensions\n    {\n        public static IEnumerable<IValue> ToPlainValues(this IEnumerable<IAction> actions)\n            => actions.Select(x => x.PlainValue);\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Action/AssemblyInfo.cs",
    "content": "using System.Runtime.CompilerServices;\n\n[assembly: InternalsVisibleTo(\"Libplanet.Tests\")]\n[assembly: InternalsVisibleTo(\"Libplanet.Action.Tests\")]\n[assembly: InternalsVisibleTo(\"Libplanet.Explorer.Tests\")]\n[assembly: InternalsVisibleTo(\"Libplanet.Mocks\")]\n"
  },
  {
    "path": "src/Libplanet.Action/BlockProtocolVersionNotSupportedException.cs",
    "content": "using System;\nusing Libplanet.Types.Blocks;\n\nnamespace Libplanet.Action\n{\n    /// <summary>\n    /// The exception that is thrown when an <see cref=\"IPreEvaluationBlock\"/> with\n    /// a protocol version that is not supported by an implementation of\n    /// <see cref=\"IActionEvaluator\"/> is passed as an argument to\n    /// <see cref=\"IActionEvaluator.Evaluate\"/>.\n    /// </summary>\n    public sealed class BlockProtocolVersionNotSupportedException : Exception\n    {\n        /// <summary>\n        /// Creates a new <see cref=\"BlockProtocolVersionNotSupportedException\"/> object.\n        /// </summary>\n        /// <param name=\"message\">Specifies a <see cref=\"Exception.Message\"/>.</param>\n        /// <param name=\"blockProtocolVersion\">The <see cref=\"Block.ProtocolVersion\"/> of the\n        /// <see cref=\"Block\"/> that <paramref name=\"action\"/> belongs to.</param>\n        public BlockProtocolVersionNotSupportedException(\n            string message,\n            int blockProtocolVersion)\n            : base(message)\n        {\n            BlockProtocolVersion = blockProtocolVersion;\n        }\n\n        /// <summary>\n        /// The <see cref=\"Block.ProtocolVersion\"/> of the <see cref=\"Block\"/> that is\n        /// not supported by an implementation of <see cref=\"IActionEvaluator\"/>.\n        /// </summary>\n        public int BlockProtocolVersion { get; }\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Action/CommittedActionContext.cs",
    "content": "using System.Diagnostics.Contracts;\nusing System.Security.Cryptography;\nusing Libplanet.Common;\nusing Libplanet.Crypto;\nusing Libplanet.Types.Tx;\n\nnamespace Libplanet.Action\n{\n    public class CommittedActionContext : ICommittedActionContext\n    {\n        public CommittedActionContext(IActionContext context)\n            : this(\n                signer: context.Signer,\n                txId: context.TxId,\n                miner: context.Miner,\n                blockIndex: context.BlockIndex,\n                blockProtocolVersion: context.BlockProtocolVersion,\n                previousState: context.PreviousState.Trie.Hash,\n                randomSeed: context.RandomSeed,\n                isPolicyAction: context.IsPolicyAction)\n        {\n        }\n\n        public CommittedActionContext(\n            Address signer,\n            TxId? txId,\n            Address miner,\n            long blockIndex,\n            int blockProtocolVersion,\n            HashDigest<SHA256> previousState,\n            int randomSeed,\n            bool isPolicyAction)\n        {\n            Signer = signer;\n            TxId = txId;\n            Miner = miner;\n            BlockIndex = blockIndex;\n            BlockProtocolVersion = blockProtocolVersion;\n            PreviousState = previousState;\n            RandomSeed = randomSeed;\n            IsPolicyAction = isPolicyAction;\n        }\n\n        /// <inheritdoc cref=\"ICommittedActionContext.Signer\"/>\n        [Pure]\n        public Address Signer { get; }\n\n        /// <inheritdoc cref=\"ICommittedActionContext.TxId\"/>\n        [Pure]\n        public TxId? TxId { get; }\n\n        /// <inheritdoc cref=\"ICommittedActionContext.Miner\"/>\n        [Pure]\n        public Address Miner { get; }\n\n        /// <inheritdoc cref=\"ICommittedActionContext.BlockIndex\"/>\n        [Pure]\n        public long BlockIndex { get; }\n\n        /// <inheritdoc cref=\"ICommittedActionContext.BlockProtocolVersion\"/>\n        [Pure]\n        public int BlockProtocolVersion { get; }\n\n        /// <inheritdoc cref=\"ICommittedActionContext.PreviousState\"/>\n        [Pure]\n        public HashDigest<SHA256> PreviousState { get; }\n\n        /// <inheritdoc cref=\"ICommittedActionContext.RandomSeed\"/>\n        public int RandomSeed { get; }\n\n        /// <inheritdoc cref=\"ICommittedActionContext.IsPolicyAction\"/>\n        [Pure]\n        public bool IsPolicyAction { get; }\n\n        /// <inheritdoc cref=\"ICommittedActionContext.GetRandom\"/>\n        [Pure]\n        public IRandom GetRandom() => new Random(RandomSeed);\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Action/CommittedActionEvaluation.cs",
    "content": "using System;\nusing System.Security.Cryptography;\nusing Bencodex.Types;\nusing Libplanet.Common;\n\nnamespace Libplanet.Action\n{\n    /// <summary>\n    /// A record type to represent an evaluation plan and result of\n    /// a single action.\n    /// </summary>\n    public class CommittedActionEvaluation : ICommittedActionEvaluation\n    {\n        /// <summary>\n        /// Creates an <see cref=\"CommittedActionEvaluation\"/> instance\n        /// with filling properties.\n        /// </summary>\n        /// <param name=\"action\">An action to evaluate.</param>\n        /// <param name=\"inputContext\">An input <see cref=\"IActionContext\"/> to\n        /// evaluate <paramref name=\"action\"/>.</param>\n        /// <param name=\"outputState\">The result states that\n        /// <paramref name=\"action\"/> makes.</param>\n        /// <param name=\"exception\">An exception that has risen during evaluating a given\n        /// <paramref name=\"action\"/>.</param>\n        public CommittedActionEvaluation(\n            IValue action,\n            ICommittedActionContext inputContext,\n            HashDigest<SHA256> outputState,\n            Exception? exception = null)\n        {\n            Action = action;\n            InputContext = inputContext;\n            OutputState = outputState;\n            Exception = exception;\n        }\n\n        /// <summary>\n        /// An action to evaluate.\n        /// </summary>\n        public IValue Action { get; }\n\n        /// <summary>\n        /// An input <see cref=\"ICommittedActionContext\"/> to evaluate\n        /// <see cref=\"Action\"/>.\n        /// </summary>\n        /// <remarks>Its <see cref=\"ICommittedActionContext.Random\"/> property\n        /// is not consumed yet.</remarks>\n        public ICommittedActionContext InputContext { get; }\n\n        /// <summary>\n        /// The result states that <see cref=\"Action\"/> makes.\n        /// </summary>\n        public HashDigest<SHA256> OutputState { get; }\n\n        /// <summary>\n        /// An exception that had risen during evaluation.\n        /// </summary>\n        public Exception? Exception { get; }\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Action/DuplicateActionTypeIdentifierException.cs",
    "content": "using System;\nusing System.Collections.Immutable;\nusing System.Linq;\n\nnamespace Libplanet.Action\n{\n    /// <summary>\n    /// An exception that is thrown when multiple action types are associated with the same\n    /// <see cref=\"ActionTypeAttribute.TypeIdentifier\"/>.\n    /// </summary>\n    /// <remarks>Note this cannot be serialized as it holds a set of <see cref=\"Type\"/> objects\n    /// which are not serializable either.</remarks>\n    public sealed class DuplicateActionTypeIdentifierException : Exception\n    {\n        /// <summary>\n        /// Creates a new <see cref=\"DuplicateActionTypeIdentifierException\"/> instance.\n        /// </summary>\n        /// <param name=\"message\">Specifies an <see cref=\"Exception.Message\"/>.  Note that extra\n        /// informative text will be appended to this.</param>\n        /// <param name=\"typeIdentifier\">The <see cref=\"ActionTypeAttribute.TypeIdentifier\"/> string\n        /// that the <paramref name=\"duplicateActionTypes\"/> are associated with.</param>\n        /// <param name=\"duplicateActionTypes\">The set of multiple action types that are associated\n        /// with the same <paramref name=\"typeIdentifier\"/>.</param>\n        public DuplicateActionTypeIdentifierException(\n            string message,\n            string typeIdentifier,\n            IImmutableSet<Type> duplicateActionTypes\n        )\n            : base($\"{message}\\n\\n{GetExtraMessage(typeIdentifier, duplicateActionTypes)}\")\n        {\n            TypeIdentifier = typeIdentifier;\n            DuplicateActionTypes = duplicateActionTypes;\n        }\n\n        /// <summary>\n        /// The <see cref=\"ActionTypeAttribute.TypeIdentifier\"/> string that\n        /// the <see cref=\"DuplicateActionTypes\"/> are associated with.\n        /// </summary>\n        public string TypeIdentifier { get; }\n\n        /// <summary>\n        /// The set of multiple action types that are associated with the same\n        /// <see cref=\"TypeIdentifier\"/>.\n        /// </summary>\n        public IImmutableSet<Type> DuplicateActionTypes { get; }\n\n        private static string GetExtraMessage(\n            string typeIdentifier,\n            IImmutableSet<Type> duplicateActionTypes)\n        {\n            var types = duplicateActionTypes\n                .Select(t => t.FullName ?? $\"{t.AssemblyQualifiedName ?? string.Empty}.(Unnamed)\")\n                .OrderBy(s => s, StringComparer.InvariantCultureIgnoreCase);\n            return $\"Type ID: {typeIdentifier}\\nAssociated types:\\n  {string.Join(\"\\n  \", types)}\";\n        }\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Action/GasLimitExceededException.cs",
    "content": "using System;\nusing System.Globalization;\n\nnamespace Libplanet.Action\n{\n    public sealed class GasLimitExceededException : Exception\n    {\n        public GasLimitExceededException(long limit, long used)\n            : base($\"Gas usage cannot be exceed limit. Gas limit is \" +\n                $\"{limit.ToString(CultureInfo.InvariantCulture)} but used gas is \" +\n                $\"{used.ToString(CultureInfo.InvariantCulture)}. \" +\n                $\"Please ensure that the gas limit is not exceeded.\")\n        {\n            Limit = limit;\n            Used = used;\n        }\n\n        public long Limit { get; }\n\n        public long Used { get; }\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Action/GasLimitNegativeException.cs",
    "content": "using System;\n\nnamespace Libplanet.Action\n{\n    public class GasLimitNegativeException : Exception\n    {\n        public GasLimitNegativeException()\n            : base($\"Gas Limit cannot be negative. \" +\n                $\"Please set the Gas Limit to a non-negative value.\")\n        {\n        }\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Action/GasMeter.cs",
    "content": "namespace Libplanet.Action\n{\n    internal class GasMeter : IGasMeter\n    {\n        public GasMeter(long gasLimit)\n        {\n            if (gasLimit < 0)\n            {\n                throw new GasLimitNegativeException();\n            }\n\n            GasLimit = gasLimit;\n        }\n\n        public long GasAvailable => GasLimit - GasUsed;\n\n        public long GasLimit { get; private set; }\n\n        public long GasUsed { get; private set; }\n\n        public void UseGas(long gas)\n        {\n            if (gas < 0)\n            {\n                throw new GasUseNegativeException();\n            }\n\n            long newGasUsed = 0;\n            try\n            {\n                newGasUsed = checked(GasUsed + gas);\n            }\n            catch (System.OverflowException)\n            {\n                throw new GasLimitExceededException(GasLimit, GasUsed + gas);\n            }\n\n            if (newGasUsed > GasLimit)\n            {\n                GasUsed = GasLimit;\n                throw new GasLimitExceededException(GasLimit, newGasUsed);\n            }\n\n            GasUsed = newGasUsed;\n        }\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Action/GasTracer.cs",
    "content": "using System;\nusing System.Threading;\nusing Libplanet.Types.Tx;\n\nnamespace Libplanet.Action\n{\n    /// <summary>\n    /// Provides a way to trace the gas usage of an <see cref=\"ITransaction\"/>.\n    /// It will be initialize each transaction.\n    ///\n    /// <see cref=\"GasTracer\"/> is thread-local, so it can be used in a multi-threaded environment.\n    /// </summary>\n    public static class GasTracer\n    {\n        private static readonly AsyncLocal<GasMeter> GasMeter = new AsyncLocal<GasMeter>();\n\n        private static readonly AsyncLocal<bool> IsTrace = new AsyncLocal<bool>();\n\n        private static readonly AsyncLocal<bool> IsTraceCancelled = new AsyncLocal<bool>();\n\n        /// <summary>\n        /// The amount of gas used so far.\n        /// </summary>\n        public static long GasUsed => GasMeterValue.GasUsed;\n\n        /// <summary>\n        /// The amount of gas available.\n        /// </summary>\n        public static long GasAvailable => GasMeterValue.GasAvailable;\n\n        internal static bool IsTxAction { get; set; }\n\n        private static GasMeter GasMeterValue\n            => GasMeter.Value ?? throw new InvalidOperationException(\n                \"GasTracer is not initialized.\");\n\n        /// <summary>\n        /// Using gas by the specified amount.\n        /// </summary>\n        /// <param name=\"gas\">\n        /// The amount of gas to use.\n        /// </param>\n        public static void UseGas(long gas)\n        {\n            if (IsTrace.Value)\n            {\n                GasMeterValue.UseGas(gas);\n                if (IsTraceCancelled.Value)\n                {\n                    throw new InvalidOperationException(\"GasTracing was canceled.\");\n                }\n            }\n        }\n\n        public static void CancelTrace()\n        {\n            if (!IsTxAction)\n            {\n                throw new InvalidOperationException(\"CancelTrace can only be called in TxAction.\");\n            }\n\n            if (IsTraceCancelled.Value)\n            {\n                throw new InvalidOperationException(\"GasTracing is already canceled.\");\n            }\n\n            IsTraceCancelled.Value = true;\n        }\n\n        internal static void Initialize(long gasLimit)\n        {\n            GasMeter.Value = new GasMeter(gasLimit);\n            IsTrace.Value = true;\n            IsTraceCancelled.Value = false;\n        }\n\n        internal static void Release()\n        {\n            IsTrace.Value = false;\n            IsTraceCancelled.Value = false;\n        }\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Action/GasUseNegativeException.cs",
    "content": "using System;\n\nnamespace Libplanet.Action\n{\n    public class GasUseNegativeException : Exception\n    {\n        public GasUseNegativeException()\n            : base($\"Cannot use negative value gas. \" +\n                $\"Please use gas with a non-negative value.\")\n        {\n        }\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Action/IAction.cs",
    "content": "using Bencodex.Types;\nusing Libplanet.Action.State;\n\nnamespace Libplanet.Action\n{\n    /// <summary>\n    /// An in-game action.  Every action should be replayable, because\n    /// multiple nodes in a network should execute an action and get the same\n    /// result.\n    /// <para>A &#x201c;class&#x201d; which implements this interface is\n    /// analogous to a function, and its instance is analogous to a\n    /// <a href=\"https://en.wikipedia.org/wiki/Partial_application\">partial\n    /// function application</a>, in other words, a function with some bound\n    /// arguments.  Those parameters that will be bound at runtime should be\n    /// represented as fields or properties in an action class, and bound\n    /// argument values to these parameters should be received through\n    /// a constructor parameters of that class.</para>\n    /// <para>From a perspective of security, an action class belongs to\n    /// the network protocol, and property values in an action belong to\n    /// a node's will (i.e., a user/player's choice).\n    /// That means if you define an action class it also defines what every\n    /// honest node can do in the network.  Even if a malicious node changes\n    /// their own action code it won't affect other honest nodes in\n    /// the network.</para>\n    /// <para>For example, where honest nodes share the common action\n    /// <c>Heal(Target) => PreviousState[Target] + 1</c>, suppose a malicious\n    /// node <c>m</c> changes their own <c>Heal</c> action code to\n    /// <c>Heal(Target) => PreviousState[Target] + 2</c> (2 instead of 1),\n    /// and then send an action <c>Heal(m)</c>.\n    /// Fortunately, this action does not work as <c>m</c>'s intention,\n    /// because the changed code in itself is not used by other honest nodes,\n    /// so they still increase only 1, not 2.  The effect of that double healing\n    /// is a sort of &#x201c;illusion&#x201d; only visible to the malicious node\n    /// alone.</para>\n    /// <para>In conclusion, action code is a part of the protocol and it works with\n    /// consensus in the network, so only things each node can affect the network\n    /// in general is property values of each action they sign and send,\n    /// not code of an action.</para>\n    /// </summary>\n    /// <example>\n    /// The following example shows how to implement an action of three types\n    /// of in-game logic:\n    /// <code><![CDATA[\n    /// using System;\n    /// using System.Collections.Generic;\n    /// using System.Collections.Immutable;\n    /// using Bencodex.Types;\n    /// using Libplanet;\n    /// using Libplanet.Action;\n    /// public class MyAction : IAction\n    /// {\n    ///     // Declare an enum type to distinguish types of in-game logic.\n    ///     public enum ActType { CreateCharacter, Attack, Heal }\n    ///     // Declare properties (or fields) to store \"bound\" argument values.\n    ///     public ActType Type { get; private set; }\n    ///     public Address TargetAddress { get; private set; }\n    ///     // Action must has a public parameterless constructor.\n    ///     // Usually this is used only by Libplanet's internals.\n    ///     public MyAction() {}\n    ///     // Take argument values to \"bind\" through constructor parameters.\n    ///     public MyAction(ActType type, Address targetAddress)\n    ///     {\n    ///         Type = type;\n    ///         TargetAddress = targetAddress;\n    ///     }\n    ///     // The main game logic belongs to here.  It takes the\n    ///     // previous states through its parameter named context,\n    ///     // and is offered \"bound\" argument values through\n    ///     // its own properties (or fields).\n    ///     IAccountStateDelta IAction.Execute(IActionContext context)\n    ///     {\n    ///         // Gets the state immediately before this action is executed.\n    ///         // ImmutableDictionary<string, uint> is just for example,\n    ///         // As far as it is serializable, you can store any types.\n    ///         // (We recommend to use immutable types though.)\n    ///         var state =\n    ///             context.PreviousState.GetState(TargetAddress);\n    ///         Dictionary dictionary;\n    ///         // This variable purposes to store the state\n    ///         // right after this action finishes.\n    ///         IImmutableDictionary<IKey, IValue> nextState;\n    ///         // Does different things depending on the action's type.\n    ///         // This way is against the common principals of programming\n    ///         // as it is just an example.\n    ///         switch (Type)\n    ///         {\n    ///             case ActType.CreateCharacter:\n    ///                 if (!TargetAddress.Equals(context.Signer))\n    ///                     throw new Exception(\n    ///                         \"TargetAddress of CreateCharacter action \" +\n    ///                         \"only can be the same address to the \" +\n    ///                         \"Transaction.Signer.\");\n    ///                 else if (!(state is null))\n    ///                     throw new Exception(\n    ///                         \"Character was already created.\");\n    ///                 nextState = ImmutableDictionary<IKey, IValue>.Empty\n    ///                     .Add((Text)\"hp\", (Integer)20);\n    ///                 break;\n    ///             case ActType.Attack:\n    ///                 dictionary = (Bencodex.Types.Dictionary)state;\n    ///                 nextState =\n    ///                     dictionary.SetItem(\n    ///                         (Text)\"hp\",\n    ///                         (Integer)Math.Max(\n    ///                             (Integer)dictionary[\"hp\"] - 5,\n    ///                             0)\n    ///                     );\n    ///                 break;\n    ///             case ActType.Heal:\n    ///                 dictionary = (Bencodex.Types.Dictionary)state;\n    ///                 nextState =\n    ///                     dictionary.SetItem(\n    ///                         (Text)\"hp\",\n    ///                         (Integer)Math.Min(\n    ///                             (Integer)dictionary[\"hp\"] + 5,\n    ///                             20)\n    ///                     );\n    ///                 break;\n    ///             default:\n    ///                 throw new Exception(\n    ///                     \"Properties are not properly initialized.\");\n    ///         }\n    ///         // Builds a delta (dirty) from previous to next states, and\n    ///         // returns it.\n    ///         return context.PreviousState.SetState(TargetAddress,\n    ///             (Dictionary)nextState);\n    ///     }\n    ///     // Serializes its \"bound arguments\" so that they are transmitted\n    ///     // over network or stored to the persistent storage.\n    ///     IValue IAction.PlainValue =>\n    ///         new Bencodex.Types.Dictionary(new Dictionary<IKey, IValue>\n    ///         {\n    ///             [(Text)\"type\"] = (Integer)(int)Type,\n    ///             [(Text)\"target_address\"] = (Binary)TargetAddress.ToByteArray(),\n    ///         });\n    ///     // Deserializes \"bound arguments\".  That is, it is inverse\n    ///     // of PlainValue property.\n    ///     void IAction.LoadPlainValue(\n    ///         IValue plainValue)\n    ///     {\n    ///         var dictionary = (Bencodex.Types.Dictionary)plainValue;\n    ///         Type = (ActType)(int)(Integer)dictionary[\"type\"];\n    ///         TargetAddress =\n    ///             new Address(dictionary[\"target_address\"]);\n    ///     }\n    /// }\n    /// ]]></code>\n    /// </example>\n    public interface IAction\n    {\n        /// <summary>\n        /// Serializes values bound to an action, which is held by properties\n        /// (or fields) of an action, so that they can be transmitted over\n        /// network or saved to persistent storage.\n        /// <para>Serialized values are deserialized by\n        /// <see cref=\"LoadPlainValue(IValue)\"/> method later.</para>\n        /// </summary>\n        /// <returns>A Bencodex value which encodes this action's bound values (held\n        /// by properties or fields).\n        /// </returns>\n        /// <seealso cref=\"LoadPlainValue(IValue)\"/>\n        IValue PlainValue { get; }\n\n        /// <summary>\n        /// Deserializes serialized data (i.e., data <see cref=\"PlainValue\"/>\n        /// property made), and then fills this action's properties (or fields)\n        /// with the deserialized values.\n        /// </summary>\n        /// <param name=\"plainValue\">Data (made by <see cref=\"PlainValue\"/>\n        /// property) to be deserialized and assigned to this action's\n        /// properties (or fields).</param>\n        /// <seealso cref=\"PlainValue\"/>\n        void LoadPlainValue(IValue plainValue);\n\n        /// <summary>\n        /// Executes the main game logic of an action.  This should be\n        /// <em>deterministic</em>.\n        /// <para>Through the <paramref name=\"context\"/> object,\n        /// it receives information such as a transaction signer,\n        /// its states immediately before the execution,\n        /// and a deterministic random seed.</para>\n        /// <para>Other &#x201c;bound&#x201d; information resides in the action\n        /// object in itself, as its properties (or fields).</para>\n        /// <para>A returned <see cref=\"IWorld\"/> object functions as\n        /// a delta which shifts from previous states to next states.</para>\n        /// </summary>\n        /// <param name=\"context\">A context object containing addresses that\n        /// signed the transaction, states immediately before the execution,\n        /// and a PRNG object which produces deterministic random numbers.\n        /// See <see cref=\"IActionContext\"/> for details.</param>\n        /// <returns>A map of changed states (so-called \"dirty\").</returns>\n        /// <remarks>This method should be deterministic:\n        /// for structurally (member-wise) equal actions and <see\n        /// cref=\"IActionContext\"/>s, the same result should be returned.\n        /// Side effects should be avoided, because an action's\n        /// <see cref=\"Execute(IActionContext)\"/> method can be called more\n        /// than once, the time it's called is difficult to predict.\n        /// <para>For changing in-memory game states or drawing graphics,\n        /// implement the <see cref=\"Blockchain.Renderers.IRenderer\"/> interface separately and\n        /// attach it to a <see cref=\"Blockchain.BlockChain\"/> instance.</para>\n        /// <para>For randomness, <em>never</em> use <see cref=\"System.Random\"/>\n        /// nor any other PRNGs provided by other than Libplanet.\n        /// Use <see cref=\"IActionContext.Random\"/> instead.\n        /// <see cref=\"IActionContext.Random\"/> guarantees the same action\n        /// has the consistent result for every node in the network.</para>\n        /// <para>Also do not perform I/O operations such as file system access\n        /// or networking.  These bring an action indeterministic.  You maybe\n        /// fine to log messages for debugging purpose, but equivalent messages\n        /// could be logged multiple times.</para>\n        /// <para>Although it might be surprising, <a\n        /// href=\"https://wp.me/p1fTCO-kT\">floating-point arithmetics are\n        /// underspecified so that it can make different results on different\n        /// machines, platforms, runtimes, compilers, and builds</a>.</para>\n        /// <para>Lastly, you need to be aware and keep in mind that there\n        /// is a global state named <see\n        /// cref=\"System.Globalization.CultureInfo.CurrentCulture\"/> on .NET;\n        /// if you format numbers, dates and times, currencies, or other such\n        /// things into strings and parse these strings back these can rely on\n        /// <see cref=\"System.Globalization.CultureInfo.CurrentCulture\"/>,\n        /// so that the same action make different results on two differently\n        /// configured systems like Thai language and French language.\n        /// In order to make these types of conversions deterministic,\n        /// you have to explicitly pass <see\n        /// cref=\"System.Globalization.CultureInfo.InvariantCulture\"/>.</para>\n        /// <para>For more on determinism in general, please read also <a\n        /// href=\"https://tendermint.com/docs/spec/abci/abci.html#determinism\"\n        /// >Tendermint ABCI's docs on determinism</a>.</para>\n        /// <para>Lastly, you can conduct static analysis on your code\n        /// using <a href=\"https://git.io/JTmby\">Libplanet.Analyzers</a>.\n        /// The analyzer can be enabled by adding its NuGet package into\n        /// your project as a dependency.</para>\n        /// </remarks>\n        /// <seealso cref=\"IActionContext\"/>\n        IWorld Execute(IActionContext context);\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Action/IActionContext.cs",
    "content": "using System.Collections.Generic;\nusing System.Diagnostics.Contracts;\nusing Libplanet.Action.State;\nusing Libplanet.Crypto;\nusing Libplanet.Types.Assets;\nusing Libplanet.Types.Blocks;\nusing Libplanet.Types.Evidence;\nusing Libplanet.Types.Tx;\n\nnamespace Libplanet.Action\n{\n    /// <summary>\n    /// Contextual data determined by a transaction and a block.\n    /// Passed to <see cref=\"IAction.Execute(IActionContext)\"/> method.\n    /// </summary>\n    public interface IActionContext\n    {\n        /// <summary>\n        /// The <see cref=\"Transaction.Signer\"/> of the <see cref=\"Transaction\"/> that contains\n        /// the <see cref=\"IAction\"/> to be executed.  If the <see cref=\"IAction\"/> is\n        /// not part of a <see cref=\"Transaction\"/>, e.g. <see cref=\"IBlockPolicy.BlockAction\"/>,\n        /// this is set to <see cref=\"Block.Miner\"/> instead.\n        /// </summary>\n        [Pure]\n        Address Signer { get; }\n\n        /// <summary>\n        /// The <see cref=\"Transaction.Id\"/> of the <see cref=\"Transaction\"/> that contains\n        /// the <see cref=\"IAction\"/>.  If the <see cref=\"IAction\"/> is not part of\n        /// a <see cref=\"Transaction\"/>, e.g. <see cref=\"IBlockPolicy.BlockAction\"/>,\n        /// this is set to <see langword=\"null\"/>.\n        /// </summary>\n        [Pure]\n        TxId? TxId { get; }\n\n        /// <summary>\n        /// The <see cref=\"Block.Miner\"/> of the <see cref=\"Block\"/> that contains\n        /// the <see cref=\"IAction\"/>.\n        /// </summary>\n        [Pure]\n        Address Miner { get; }\n\n        /// <summary>\n        /// The <see cref=\"Block.Index\"/> of the <see cref=\"Block\"/> that contains\n        /// the <see cref=\"IAction\"/>.\n        /// </summary>\n        [Pure]\n        long BlockIndex { get; }\n\n        /// <summary>\n        /// The <see cref=\"Block.ProtocolVersion\"/> of the <see cref=\"Block\"/> that contains\n        /// the <see cref=\"IAction\"/>.\n        /// </summary>\n        [Pure]\n        int BlockProtocolVersion { get; }\n\n        /// <summary>\n        /// The <see cref=\"BlockCommit\"/> about previous <see cref=\"Block\"/>'s vote information.\n        /// <see langword=\"null\"/> if the block is the genesis block.\n        /// </summary>\n        [Pure]\n        BlockCommit? LastCommit { get; }\n\n        /// <summary>\n        /// A null delta of states, which means it represents the states\n        /// before <see cref=\"IAction\"/> executes.\n        /// <para>Although a <see cref=\"IAccount\"/> instance is\n        /// immutable, it has several manipulative methods that returns\n        /// new <see cref=\"IAccount\"/> instances with some \"dirty\"\n        /// states.  These kinds of dirty <see cref=\"IWorld\"/>\n        /// instances can be returned by <see\n        /// cref=\"IAction.Execute(IActionContext)\"/> method.</para>\n        /// </summary>\n        [Pure]\n        IWorld PreviousState { get; }\n\n        /// <summary>\n        /// The random seed to use for pseudorandom number generator.  This value\n        /// is determined by various block properties, the signature of the transaction\n        /// containing the action to execute, and index of the action to execute, which is\n        /// deterministic so that every node can replay the same action and\n        /// then reproduce the same result, while neither a single block miner\n        /// nor a single transaction signer can predict the result and cheat.\n        /// </summary>\n        /// <seealso cref=\"GetRandom\"/>\n        int RandomSeed { get; }\n\n        /// <summary>\n        /// Whether this action is executed as a policy action.\n        /// <see langword=\"false\"/> if it is a user action.\n        /// </summary>\n        [Pure]\n        bool IsPolicyAction { get; }\n\n        /// <summary>\n        /// Max gas price set by the transaction.\n        /// <see langword=\"null\"/> if the action does not belongs to a transaction.\n        /// </summary>\n        [Pure]\n        FungibleAssetValue? MaxGasPrice { get; }\n\n        /// <summary>\n        /// A list of <see cref=\"ITransaction\"/>s that are included in a <see cref=\"Block\"/> as\n        /// the <see cref=\"IAction\"/> to be evaluated.  This information is provided only if\n        /// <see cref=\"IsPolicyAction\"/> is <see langword=\"true\"/>, otherwise returns an empty set.\n        /// </summary>\n        [Pure]\n        IReadOnlyList<ITransaction> Txs { get; }\n\n        /// <summary>\n        /// A list of <see cref=\"EvidenceBase\"/>s that are included in a\n        /// <see cref=\"Block\"/>.\n        /// </summary>\n        [Pure]\n        IReadOnlyList<EvidenceBase> Evidence { get; }\n\n        /// <summary>\n        /// Returns a newly initialized <see cref=\"IRandom\"/> using <see cref=\"RandomSeed\"/>\n        /// as its seed value.\n        /// </summary>\n        /// <returns>A newly initialized <see cref=\"IRandom\"/> using <see cref=\"RandomSeed\"/>\n        /// as its seed value.</returns>\n        [Pure]\n        IRandom GetRandom();\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Action/IActionEvaluation.cs",
    "content": "using System;\nusing Bencodex.Types;\nusing Libplanet.Action.State;\n\nnamespace Libplanet.Action\n{\n    public interface IActionEvaluation\n    {\n        /// <summary>\n        /// An action data to evaluate. When the\n        /// <see cref=\"InputContext\"/>.<see cref=\"IActionContext.IsPolicyAction\"/> is true,\n        /// use <see cref=\"IBlockPolicy.BlockAction\"/> instead of trying deserialization.\n        /// </summary>\n        public IValue Action { get; }\n\n        /// <summary>\n        /// An input <see cref=\"IActionContext\"/> to evaluate\n        /// <see cref=\"Action\"/>.\n        /// </summary>\n        /// <remarks>Its <see cref=\"IActionContext.Random\"/> property\n        /// is not consumed yet.</remarks>\n        public IActionContext InputContext { get; }\n\n        /// <summary>\n        /// The result states that <see cref=\"Action\"/> makes.\n        /// </summary>\n        public IWorld OutputState { get; }\n\n        /// <summary>\n        /// An exception that had risen during evaluation.\n        /// </summary>\n        public Exception? Exception { get; }\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Action/IActionEvaluator.cs",
    "content": "using System.Collections.Generic;\nusing System.Diagnostics.Contracts;\nusing System.Security.Cryptography;\nusing Libplanet.Action.Loader;\nusing Libplanet.Common;\nusing Libplanet.Store;\nusing Libplanet.Types.Blocks;\n\nnamespace Libplanet.Action\n{\n    public interface IActionEvaluator\n    {\n        /// <summary>\n        /// The <see cref=\"IActionLoader\"/> used by this <see cref=\"IActionEvaluator\"/>\n        /// when evaluating <see cref=\"Block\"/>s.\n        /// </summary>\n        [Pure]\n        IActionLoader ActionLoader { get; }\n\n        /// <summary>\n        /// The main entry point for evaluating a <see cref=\"IPreEvaluationBlock\"/>.\n        /// </summary>\n        /// <param name=\"block\">The block to evaluate.</param>\n        /// <param name=\"baseStateRootHash\">The base state to use when evaluating\n        /// <paramref name=\"block\"/>.</param>\n        /// <returns> The result of evaluating every <see cref=\"IAction\"/> related to\n        /// <paramref name=\"block\"/> as an <see cref=\"IReadOnlyList{T}\"/> of\n        /// <see cref=\"ICommittedActionEvaluation\"/>s.</returns>\n        /// <remarks>\n        /// <para>\n        /// This has a side-effect of writing data to internally held <see cref=\"IStateStore\"/>.\n        /// </para>\n        /// <para>\n        /// First evaluates all <see cref=\"IAction\"/>s in\n        /// <see cref=\"IBlockContent.Transactions\"/> of <paramref name=\"block\"/> and appends the\n        /// evaluation of the <see cref=\"IBlockPolicy.BlockAction\"/> held by the instance at\n        /// the end.\n        /// </para>\n        /// </remarks>\n        /// <exception cref=\"BlockProtocolVersionNotSupportedException\">Thrown when\n        /// <paramref name=\"block\"/> has a <see cref=\"IPreEvaluationBlock.ProtocolVersion\"/>\n        /// that is not supported by an implementation of <see cref=\"IActionEvaluator\"/>.\n        /// </exception>\n        [Pure]\n        IReadOnlyList<ICommittedActionEvaluation> Evaluate(\n            IPreEvaluationBlock block,\n            HashDigest<SHA256>? baseStateRootHash);\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Action/IActionTypeLoaderContext.cs",
    "content": "namespace Libplanet.Action\n{\n    /// <summary>\n    /// An interface to provide contextual variables to load action types.\n    /// </summary>\n    public interface IActionTypeLoaderContext\n    {\n        /// <summary>\n        /// A block index.\n        /// </summary>\n        long Index { get; }\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Action/ICommittedActionContext.cs",
    "content": "using System.Diagnostics.Contracts;\nusing System.Security.Cryptography;\nusing Libplanet.Common;\nusing Libplanet.Crypto;\nusing Libplanet.Types.Blocks;\nusing Libplanet.Types.Tx;\n\nnamespace Libplanet.Action\n{\n    /// <summary>\n    /// Contextual data determined by a transaction and a block for rendering.\n    /// </summary>\n    public interface ICommittedActionContext\n    {\n        /// <summary>\n        /// The <see cref=\"Transaction.Signer\"/> of the <see cref=\"Transaction\"/> that contains\n        /// the <see cref=\"IAction\"/> to be executed.  If the <see cref=\"IAction\"/> is\n        /// not part of a <see cref=\"Transaction\"/>, e.g. <see cref=\"IBlockPolicy.BlockAction\"/>,\n        /// this is set to <see cref=\"Block.Miner\"/> instead.\n        /// </summary>\n        [Pure]\n        Address Signer { get; }\n\n        /// <summary>\n        /// The <see cref=\"Transaction.Id\"/> of the <see cref=\"Transaction\"/> that contains\n        /// the <see cref=\"IAction\"/>.  If the <see cref=\"IAction\"/> is not part of\n        /// a <see cref=\"Transaction\"/>, e.g. <see cref=\"IBlockPolicy.BlockAction\"/>,\n        /// this is set to <see langword=\"null\"/>.\n        /// </summary>\n        [Pure]\n        TxId? TxId { get; }\n\n        /// <summary>\n        /// The <see cref=\"Block.Miner\"/> of the <see cref=\"Block\"/> that contains\n        /// the <see cref=\"IAction\"/>.\n        /// </summary>\n        [Pure]\n        Address Miner { get; }\n\n        /// <summary>\n        /// The <see cref=\"Block.Index\"/> of the <see cref=\"Block\"/> that contains\n        /// the <see cref=\"IAction\"/>.\n        /// </summary>\n        [Pure]\n        long BlockIndex { get; }\n\n        /// <summary>\n        /// The <see cref=\"Block.ProtocolVersion\"/> of the <see cref=\"Block\"/> that contains\n        /// the <see cref=\"IAction\"/>.\n        /// </summary>\n        [Pure]\n        int BlockProtocolVersion { get; }\n\n        /// <summary>\n        /// The state root hash of the previous state.\n        /// </summary>\n        [Pure]\n        HashDigest<SHA256> PreviousState { get; }\n\n        /// <summary>\n        /// The random seed to use for pseudorandom number generator.  This value\n        /// is determined by various block properties, the signature of the transaction\n        /// containing the action to execute, and index of the action to execute, which is\n        /// deterministic so that every node can replay the same action and\n        /// then reproduce the same result, while neither a single block miner\n        /// nor a single transaction signer can predict the result and cheat.\n        /// </summary>\n        /// <seealso cref=\"GetRandom\"/>\n        int RandomSeed { get; }\n\n        /// <summary>\n        /// Whether this action is executed as a policy action.\n        /// <see langword=\"false\"/> if it belongs to a transaction.\n        /// </summary>\n        [Pure]\n        bool IsPolicyAction { get; }\n\n        /// <summary>\n        /// Returns a newly initialized <see cref=\"IRandom\"/> using <see cref=\"RandomSeed\"/>\n        /// as its seed value.\n        /// </summary>\n        /// <returns>A newly initialized <see cref=\"IRandom\"/> using <see cref=\"RandomSeed\"/>\n        /// as its seed value.</returns>\n        [Pure]\n        IRandom GetRandom();\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Action/ICommittedActionEvaluation.cs",
    "content": "using System;\nusing System.Security.Cryptography;\nusing Bencodex.Types;\nusing Libplanet.Common;\n\nnamespace Libplanet.Action\n{\n    public interface ICommittedActionEvaluation\n    {\n        /// <summary>\n        /// An action data to evaluate. When the\n        /// <see cref=\"InputContext\"/>.<see cref=\"IActionContext.IsPolicyAction\"/> is true,\n        /// use <see cref=\"IBlockPolicy.BlockAction\"/> instead of trying deserialization.\n        /// </summary>\n        public IValue Action { get; }\n\n        /// <summary>\n        /// An input <see cref=\"IActionContext\"/> to evaluate\n        /// <see cref=\"Action\"/>.\n        /// </summary>\n        /// <remarks>Its <see cref=\"IActionContext.Random\"/> property\n        /// is not consumed yet.</remarks>\n        public ICommittedActionContext InputContext { get; }\n\n        /// <summary>\n        /// The result states that <see cref=\"Action\"/> makes.\n        /// </summary>\n        public HashDigest<SHA256> OutputState { get; }\n\n        /// <summary>\n        /// An exception that had risen during evaluation.\n        /// </summary>\n        public Exception? Exception { get; }\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Action/IGasMeter.cs",
    "content": "namespace Libplanet.Action\n{\n    /// <summary>\n    /// An interface to provide a transition of the gas usage.\n    /// </summary>\n    public interface IGasMeter\n    {\n        /// <summary>\n        /// The available gas of the action.\n        /// </summary>\n        long GasAvailable { get; }\n\n        /// <summary>\n        /// The gas limit of the action.\n        /// </summary>\n        long GasLimit { get; }\n\n        /// <summary>\n        /// The gas used by the action.\n        /// </summary>\n        long GasUsed { get; }\n\n        /// <summary>\n        /// Use gas of the account.\n        /// </summary>\n        /// <param name=\"gas\">\n        /// The gas usage of the action.\n        /// </param>\n        void UseGas(long gas);\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Action/IPolicyActionsRegistry.cs",
    "content": "using System.Collections.Immutable;\n\nnamespace Libplanet.Action\n{\n    public interface IPolicyActionsRegistry\n    {\n        /// <summary>\n        /// An array of <see cref=\"IAction\"/> to execute and be rendered at the beginning\n        /// for every block, if any.</summary>\n        ImmutableArray<IAction> BeginBlockActions\n        {\n            get;\n        }\n\n        /// <summary>\n        /// An array of <see cref=\"IAction\"/> to execute and be rendered at the end\n        /// for every block, if any.</summary>\n        ImmutableArray<IAction> EndBlockActions\n        {\n            get;\n        }\n\n        /// <summary>\n        /// An array of <see cref=\"IAction\"/> to execute and be rendered at the beginning\n        /// for every transaction, if any.</summary>\n        ImmutableArray<IAction> BeginTxActions\n        {\n            get;\n        }\n\n        /// <summary>\n        /// An array of <see cref=\"IAction\"/> to execute and be rendered at the end\n        /// for every transaction, if any.</summary>\n        ImmutableArray<IAction> EndTxActions\n        {\n            get;\n        }\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Action/IRandom.cs",
    "content": "using System;\nusing System.Diagnostics.Contracts;\n\nnamespace Libplanet.Action\n{\n    /// <summary>\n    /// An pseudorandom number generator interface equivalent to\n    /// <see cref=\"System.Random\"/>.\n    /// <para>Although these two types have similar shapes, they are not\n    /// compatible (i.e., disallowed to be casted to each other).</para>\n    /// </summary>\n    public interface IRandom\n    {\n        /// <summary>\n        /// A number used to calculate a starting value for the pseudo-random\n        /// number sequence.\n        /// </summary>\n        [Pure]\n        int Seed { get; }\n\n        /// <summary>\n        /// Gets a non-negative random integer.\n        /// </summary>\n        /// <returns>A 32-bit signed integer that is greater than or equal to\n        /// 0 and less than <see cref=\"int.MaxValue\"/>.</returns>\n        /// <seealso cref=\"System.Random.Next()\"/>\n        int Next();\n\n        /// <summary>\n        /// Gets a non-negative random integer that is less than the specified\n        /// <paramref name=\"upperBound\"/>.\n        /// </summary>\n        /// <param name=\"upperBound\">The exclusive upper bound of the random\n        /// number to be generated.  It must be greater than or equal to 0.\n        /// </param>\n        /// <returns>A 32-bit signed integer that is greater than or equal to\n        /// 0 and less than <paramref name=\"upperBound\"/>; that is, the range of\n        /// return values ordinarily includes 0 but not <paramref\n        /// name=\"upperBound\"/>.  However, if <paramref name=\"upperBound\"/> equals\n        /// to 0, <paramref name=\"upperBound\"/> is returned.</returns>\n        /// <exception cref=\"System.ArgumentOutOfRangeException\">Thrown when\n        /// <paramref name=\"upperBound\"/> is less than 0.</exception>\n        /// <seealso cref=\"System.Random.Next(int)\"/>\n        int Next(int upperBound);\n\n        /// <summary>\n        /// Gets a random integer that is within a specified range.\n        /// </summary>\n        /// <param name=\"lowerBound\">The inclusive lower bound of the random\n        /// number to be generated.</param>\n        /// <param name=\"upperBound\">The exclusive upper bound of the random\n        /// number to be generated.  It must be greater than or equal to\n        /// <paramref name=\"lowerBound\"/>.\n        /// </param>\n        /// <returns>A 32-bit signed integer that is greater than or equal to\n        /// <paramref name=\"lowerBound\"/> and less than <paramref\n        /// name=\"upperBound\"/>; that is, the range of return values ordinarily\n        /// includes <paramref name=\"lowerBound\"/> but not <paramref\n        /// name=\"upperBound\"/>.  If <paramref name=\"upperBound\"/> equals to\n        /// <paramref name=\"lowerBound\"/>, <paramref name=\"lowerBound\"/> is\n        /// returned.</returns>\n        /// <exception cref=\"ArgumentOutOfRangeException\">Thrown when\n        /// <paramref name=\"upperBound\"/> is less than <paramref\n        /// name=\"lowerBound\"/>.</exception>\n        /// <seealso cref=\"System.Random.Next(int, int)\"/>\n        int Next(int lowerBound, int upperBound);\n\n        /// <summary>\n        /// Fills the elements of a specified <see cref=\"byte\"/>s <paramref\n        /// name=\"buffer\"/> with random numbers.\n        /// </summary>\n        /// <param name=\"buffer\">A <see cref=\"byte\"/> array to contain random\n        /// numbers.</param>\n        /// <exception cref=\"ArgumentNullException\">Thrown when <paramref\n        /// name=\"buffer\"/> is <see langword=\"null\"/>.</exception>\n        /// <seealso cref=\"System.Random.NextBytes(byte[])\"/>\n        void NextBytes(byte[] buffer);\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Action/InvalidActionException.cs",
    "content": "using System;\nusing Bencodex.Types;\nusing Libplanet.Action.Loader;\n\nnamespace Libplanet.Action\n{\n    /// <summary>\n    /// The <see cref=\"Exception\"/> that is thrown when an <see cref=\"IValue\"/> that is\n    /// supposedly a serialized <see cref=\"IAction\"/> cannot be deserialized via an\n    /// <see cref=\"IActionLoader\"/>.\n    /// </summary>\n    /// <seealso cref=\"IActionLoader\"/>\n    public sealed class InvalidActionException : Exception\n    {\n        /// <summary>\n        /// Creates a new <see cref=\"InvalidActionException\"/> object.\n        /// </summary>\n        /// <param name=\"message\">Specifies an <see cref=\"Exception.Message\"/>.</param>\n        /// <param name=\"plainValue\">The <see cref=\"IValue\"/> that cannot be loaded\n        /// to an <see cref=\"IAction\"/>.</param>\n        /// <param name=\"innerException\">The <see cref=\"Exception\"/> for\n        /// <see cref=\"Exception.InnerException\"/>.</param>\n        public InvalidActionException(string message, IValue plainValue, Exception innerException)\n            : base(message, innerException)\n        {\n            PlainValue = plainValue;\n        }\n\n        /// <summary>\n        /// The <see cref=\"IValue\"/> that cannot be deserialized to an <see cref=\"IAction\"/>.\n        /// </summary>\n        public IValue PlainValue { get; }\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Action/Libplanet.Action.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <ItemGroup>\n    <PackageReference Include=\"System.Collections.Immutable\" Version=\"1.*\" />\n    <PackageReference Include=\"System.Diagnostics.DiagnosticSource\" Version=\"8.0.0\" />\n    <PackageReference Include=\"System.Text.Json\" Version=\"6.0.*\" />\n    <PackageReference Include=\"Bencodex\" Version=\"0.16.0\" />\n    <PackageReference Include=\"Bencodex.Json\" Version=\"0.16.0\" />\n    <PackageReference Include=\"Planetarium.LruCacheNet\" Version=\"1.2.0\" />\n    <PackageReference Include=\"Serilog\" Version=\"2.8.0\" />\n  </ItemGroup>\n\n  <ItemGroup Condition=\"'$(SkipSonar)' != 'true'\">\n    <PackageReference Remove=\"SonarAnalyzer.CSharp\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <ProjectReference Include=\"..\\Libplanet.Common\\Libplanet.Common.csproj\" />\n    <ProjectReference Include=\"..\\Libplanet.Crypto\\Libplanet.Crypto.csproj\" />\n    <ProjectReference Include=\"..\\Libplanet.Types\\Libplanet.Types.csproj\" />\n    <ProjectReference Include=\"..\\Libplanet.Store\\Libplanet.Store.csproj\" />\n  </ItemGroup>\n\n</Project>\n"
  },
  {
    "path": "src/Libplanet.Action/Loader/AggregateTypedActionLoader.cs",
    "content": "using System;\nusing System.Collections;\nusing System.Collections.Generic;\nusing Bencodex.Types;\nusing Libplanet.Action.Sys;\n\nnamespace Libplanet.Action.Loader\n{\n    public sealed class AggregateTypedActionLoader\n         : IActionLoader, IEnumerable<IActionLoader>\n    {\n        private readonly List<IActionLoader> _actionLoaderList = new List<IActionLoader>();\n\n        public AggregateTypedActionLoader()\n        {\n        }\n\n        public AggregateTypedActionLoader(IActionLoader[] actionLoaders)\n        {\n            _actionLoaderList = new List<IActionLoader>(actionLoaders);\n        }\n\n        public IAction LoadAction(long index, IValue value)\n        {\n            if (Registry.IsSystemAction(value))\n            {\n                return Registry.Deserialize(value);\n            }\n\n            foreach (var item in _actionLoaderList)\n            {\n                try\n                {\n                    return item.LoadAction(index, value);\n                }\n                catch\n                {\n                    // ignored\n                }\n            }\n\n            throw new ArgumentException(\n                message: $\"No action loader found for the given value: {value}\",\n                paramName: nameof(value));\n        }\n\n        public void Add(IActionLoader actionLoader)\n        {\n            _actionLoaderList.Add(actionLoader);\n        }\n\n        IEnumerator<IActionLoader> IEnumerable<IActionLoader>.GetEnumerator()\n            => _actionLoaderList.GetEnumerator();\n\n        IEnumerator IEnumerable.GetEnumerator()\n            => _actionLoaderList.GetEnumerator();\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Action/Loader/AssemblyActionLoader.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Reflection;\nusing Bencodex.Types;\nusing Libplanet.Action.Sys;\n\nnamespace Libplanet.Action.Loader\n{\n    public class AssemblyActionLoader : IActionLoader\n    {\n        private readonly Dictionary<IValue, Type> _types;\n\n        public AssemblyActionLoader(Assembly assembly)\n        {\n            var query = from type in assembly.GetTypes()\n                        where typeof(IAction).IsAssignableFrom(type) == true\n                        let attribute = type.GetCustomAttribute<ActionTypeAttribute>()\n                        where attribute is not null\n                        select (attribute.TypeIdentifier, type);\n\n            _types = query.ToDictionary((item) => item.TypeIdentifier, item => item.type);\n        }\n\n        public IReadOnlyDictionary<IValue, Type> Types => _types;\n\n        public IAction LoadAction(long index, IValue value)\n        {\n            try\n            {\n                if (Registry.IsSystemAction(value))\n                {\n                    return Registry.Deserialize(value);\n                }\n\n                IAction action;\n                if (value is Dictionary pv &&\n                    pv.TryGetValue((Text)\"type_id\", out var rawTypeId) &&\n                    rawTypeId is IValue typeId &&\n                    Types.TryGetValue(typeId, out var actionType))\n                {\n                    action = (IAction)Activator.CreateInstance(actionType)!;\n                    action.LoadPlainValue(pv);\n                }\n                else\n                {\n                    throw new InvalidOperationException(\n                        $\"Failed to instantiate an action from {value} for index {index}\");\n                }\n\n                return action;\n            }\n            catch (Exception e)\n            {\n                throw new InvalidActionException(\n                    $\"Failed to instantiate an action from {value} for index {index}\",\n                    value,\n                    e);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Action/Loader/IActionLoader.cs",
    "content": "using Bencodex.Types;\n\nnamespace Libplanet.Action.Loader\n{\n    /// <summary>\n    /// An interface to load actions branched by block index.\n    /// </summary>\n    public interface IActionLoader\n    {\n        /// <summary>\n        /// Loads a concrete <see cref=\"IAction\"/> from <paramref name=\"value\"/>\n        /// given <paramref name=\"index\"/>.\n        /// </summary>\n        /// <param name=\"index\">The index of a block to use as context for deserializing\n        /// <paramref name=\"value\"/>.</param>\n        /// <param name=\"value\">The <see cref=\"IValue\"/> to deserialize to\n        /// an <see cref=\"IAction\"/>.</param>\n        /// <exception cref=\"InvalidActionException\">Thrown when an <see cref=\"IAction\"/> cannot be\n        /// instantiated with given <paramref name=\"index\"/> and <paramref name=\"value\"/>.\n        /// </exception>\n        /// <returns>An <see cref=\"IAction\"/> instantiated with <paramref name=\"value\"/>.</returns>\n        public IAction LoadAction(long index, IValue value);\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Action/Loader/IndexedActionLoader.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Collections.Immutable;\nusing System.Linq;\nusing Bencodex.Types;\nusing Libplanet.Action.Sys;\n\nnamespace Libplanet.Action.Loader\n{\n    /// <summary>\n    /// An <see cref=\"IActionLoader\"/> implementation for dispatching\n    /// multiple <see cref=\"IActionLoader\"/>s.\n    /// </summary>\n    public class IndexedActionLoader : IActionLoader\n    {\n        private ImmutableArray<(long StartIndex, IActionLoader Loader)> _loaders;\n\n        /// <summary>\n        /// Creates an <see cref=\"IndexedActionLoader\"/> instance.\n        /// </summary>\n        /// <param name=\"loaders\">A list of inner <see cref=\"IActionLoader\"/>s to use.</param>\n        /// <exception cref=\"ArgumentException\">Thrown for any of the following reasons:\n        /// <list type=\"bullet\">\n        ///     <item><description>\n        ///         If <paramref name=\"loaders\"/> is empty.\n        ///     </description></item>\n        ///     <item><description>\n        ///         If <paramref name=\"loaders\"/>'s first starting index is not zero.\n        ///     </description></item>\n        ///     <item><description>\n        ///         If <paramref name=\"loaders\"/>'s starting indices are not strictly increasing.\n        ///     </description></item>\n        /// </list>\n        /// </exception>\n        public IndexedActionLoader(IReadOnlyList<(long StartIndex, IActionLoader Loader)> loaders)\n        {\n            if (loaders.Count == 0)\n            {\n                throw new ArgumentException(\n                    $\"Given {nameof(loaders)} cannot be empty.\", nameof(loaders));\n            }\n            else if (loaders.First().StartIndex != 0)\n            {\n                throw new ArgumentException(\n                    $\"Given {nameof(loaders)} must start with zero starting index: {loaders[0]}\",\n                    nameof(loaders));\n            }\n            else if (\n                loaders\n                    .Zip(loaders.Skip(1), (prev, next) => (prev, next))\n                    .Any(pair => pair.prev.StartIndex >= pair.next.StartIndex))\n            {\n                throw new ArgumentException(\n                    $\"Given {nameof(loaders)}'s starting indices must be strictly increasing.\",\n                    nameof(loaders));\n            }\n\n            _loaders = loaders.ToImmutableArray();\n        }\n\n        /// <inheritdoc cref=\"IActionLoader.LoadAction\"/>\n        public IAction LoadAction(long index, IValue value)\n        {\n            try\n            {\n                if (Registry.IsSystemAction(value))\n                {\n                    return Registry.Deserialize(value);\n                }\n\n                var loaderIndex = _loaders.Count(pair => pair.StartIndex <= index);\n                var loader = _loaders[loaderIndex - 1].Loader;\n                return loader.LoadAction(index, value);\n            }\n            catch (Exception e)\n            {\n                throw new InvalidActionException(\n                    $\"Failed to instantiate an action from {value} for index {index}\",\n                    value,\n                    e);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Action/Loader/SingleActionLoader.cs",
    "content": "using System;\nusing Bencodex.Types;\nusing Libplanet.Action.Sys;\n\nnamespace Libplanet.Action.Loader\n{\n    /// <summary>\n    /// An <see cref=\"IActionLoader\"/> implementation for a single <see cref=\"IAction\"/> type.\n    /// </summary>\n    public class SingleActionLoader : IActionLoader\n    {\n        private Type _type;\n\n        /// <summary>\n        /// Creates a new <see cref=\"SingleActionLoader\"/> instance.\n        /// The <see cref=\"IAction\"/> type to load is restricted to given type\n        /// <paramref name=\"type\"/>, except for those handled by <see cref=\"Registry\"/>\n        /// for system <see cref=\"IAction\"/>s.\n        /// </summary>\n        /// <param name=\"type\">The type of <see cref=\"IAction\"/> to load.  It should match\n        /// the <see cref=\"BlockChain\"/>'s type parameter.</param>\n        /// <exception cref=\"ArgumentException\">Thrown when given type <paramref name=\"type\"/>\n        /// is not a <see langword=\"class\"/> or cannot be assigned to <see cref=\"IAction\"/>.\n        /// </exception>\n        public SingleActionLoader(Type type)\n        {\n            if (!type.IsClass)\n            {\n                throw new ArgumentException(\n                    $\"Given {nameof(type)} must be a class: {type}\", nameof(type));\n            }\n            else if (!typeof(IAction).IsAssignableFrom(type))\n            {\n                throw new ArgumentException(\n                    $\"Given {nameof(type)} must be assignable to {nameof(IAction)}: {type}\",\n                    nameof(type));\n            }\n\n            _type = type;\n        }\n\n        public Type Type => _type;\n\n        /// <inheritdoc cref=\"IActionLoader.LoadAction\"/>.\n        public IAction LoadAction(long index, IValue value)\n        {\n            try\n            {\n                if (Registry.IsSystemAction(value))\n                {\n                    return Registry.Deserialize(value);\n                }\n\n                IAction action = (IAction)Activator.CreateInstance(_type)!;\n                action.LoadPlainValue(value);\n                return action;\n            }\n            catch (Exception e)\n            {\n                throw new InvalidActionException(\n                    $\"Failed to instantiate an action from {value} for index {index}\",\n                    value,\n                    e);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Action/Loader/TypedActionLoader.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Collections.Immutable;\nusing System.Reflection;\nusing Bencodex.Types;\nusing Libplanet.Action.Sys;\n\nnamespace Libplanet.Action.Loader\n{\n    /// <summary>\n    /// An <see cref=\"IActionLoader\"/> implementation for multiple <see cref=\"IAction\"/> types.\n    /// </summary>\n    public class TypedActionLoader : IActionLoader\n    {\n        private IDictionary<IValue, Type> _types;\n\n        /// <summary>\n        /// <para>\n        /// Creates a new <see cref=\"TypedActionLoader\"/> instance with an explicit\n        /// <see cref=\"IValue\"/>s to <see cref=\"Type\"/>s mapping.\n        /// </para>\n        /// <para>\n        /// The mapping can be generated semi-automatically using\n        /// <see cref=\"TypedActionLoader.Create\"/>.\n        /// </para>\n        /// </summary>\n        /// <param name=\"types\">The <see cref=\"IValue\"/>s to <see cref=\"Type\"/>s mapping to use.\n        /// </param>\n        /// <seealso cref=\"TypedActionLoader.Create\"/>\n        public TypedActionLoader(IDictionary<IValue, Type> types)\n        {\n            if (types.Count == 0)\n            {\n                throw new ArgumentException(\n                    $\"Give {nameof(types)} cannot be empty.\", nameof(types));\n            }\n\n            _types = types;\n        }\n\n        public IDictionary<IValue, Type> Types => _types;\n\n        /// <inheritdoc cref=\"IActionLoader.LoadAction\"/>.\n        /// <summary>\n        /// <para>\n        /// Creates a new <see cref=\"TypedActionLoader\"/> instance.\n        /// </para>\n        /// <para>\n        /// The <see cref=\"IAction\"/> type to load is restricted to given\n        /// <paramref name=\"assembly\"/> and <paramref name=\"baseType\"/>,\n        /// except for those handled by <see cref=\"Registry\"/> for system <see cref=\"IAction\"/>s.\n        /// </para>\n        /// <para>\n        /// This automatically searches an <see cref=\"Assembly\"/> with all <see cref=\"IAction\"/>s\n        /// according to the following rule:\n        /// <list type=\"bullet\">\n        ///     <item><description>\n        ///         The <see cref=\"Assembly\"/> to search is <paramref name=\"assembly\"/> if given,\n        ///         or the <see cref=\"Assembly\"/> of <paramref name=\"baseType\"/> if not.\n        ///     </description></item>\n        ///     <item><description>\n        ///         From the <see cref=\"Assembly\"/> determined above, all <see cref=\"IAction\"/>s\n        ///         with <see cref=\"ActionTypeAttribute\"/> attached are collected.\n        ///     </description></item>\n        ///     <item><description>\n        ///         If <paramref name=\"baseType\"/> is provided, only those <see cref=\"IAction\"/>\n        ///         types that are assignable to <paramref name=\"baseType\"/> are selected.\n        ///     </description></item>\n        /// </list>\n        /// </para>\n        /// <para>\n        /// Then a dictionary mapping from <see cref=\"IValue\"/>s to <see cref=\"Type\"/>s created\n        /// from searched <see cref=\"IAction\"/>s and the explicit loader is created by\n        /// passing the map to <see cref=\"TypedActionLoader(IDictionary{IValue, Type})\"/>.\n        /// </para>\n        /// </summary>\n        /// <param name=\"assembly\">The <see cref=\"Assembly\"/> to search <see cref=\"IAction\"/> types.\n        /// </param>\n        /// <param name=\"baseType\">The type of <see cref=\"IAction\"/> to filter.</param>\n        /// <returns>A <see cref=\"TypedActionLoader\"/> created from provided\n        /// <paramref name=\"assembly\"/> and <paramref name=\"baseType\"/>.</returns>\n        /// <exception cref=\"ArgumentException\">Thrown when both <paramref name=\"assembly\"/> and\n        /// <paramref name=\"baseType\"/> are <see langword=\"null\"/>.\n        /// </exception>\n        /// <seealso cref=\"TypedActionLoader(IDictionary{IValue, Type})\"/>\n        public static TypedActionLoader Create(Assembly? assembly = null, Type? baseType = null)\n        {\n            if (assembly is null && baseType is null)\n            {\n                throw new ArgumentException(\n                    $\"At least one of {nameof(assembly)} and {nameof(baseType)} must be non-null.\");\n            }\n\n            assembly = assembly ?? baseType!.Assembly;\n            return new TypedActionLoader(LoadTypes(assembly, baseType));\n        }\n\n        public IAction LoadAction(long index, IValue value)\n        {\n            try\n            {\n                if (Registry.IsSystemAction(value))\n                {\n                    return Registry.Deserialize(value);\n                }\n\n                IAction action;\n                if (value is Dictionary pv &&\n                    pv.TryGetValue((Text)\"type_id\", out IValue rawTypeId) &&\n                    rawTypeId is IValue typeId &&\n                    Types.TryGetValue(typeId, out Type? actionType))\n                {\n                    // NOTE: This is different from how PolymorphicAction<T> handles plain values.\n                    // Actual underlying types are expected to handle (or at least accept)\n                    // a plainvalue *with* \"type_id\" field included.\n                    action = (IAction)Activator.CreateInstance(actionType)!;\n                    action.LoadPlainValue(pv);\n                }\n                else\n                {\n                    throw new InvalidOperationException(\n                        $\"Failed to instantiate an action from {value} for index {index}\");\n                }\n\n                return action;\n            }\n            catch (Exception e)\n            {\n                throw new InvalidActionException(\n                    $\"Failed to instantiate an action from {value} for index {index}\",\n                    value,\n                    e);\n            }\n        }\n\n        private static IDictionary<IValue, Type> LoadTypes(Assembly assembly, Type? baseType)\n        {\n            var types = new Dictionary<IValue, Type>();\n            var actionType = typeof(IAction);\n            foreach (Type type in LoadAllActionTypes(assembly))\n            {\n                if (baseType is { } bType && !bType.IsAssignableFrom(type))\n                {\n                    continue;\n                }\n\n                if (type.GetCustomAttribute<ActionTypeAttribute>()?.TypeIdentifier is { } typeId)\n                {\n                    if (types.TryGetValue(typeId, out Type? existing))\n                    {\n                        if (existing != type)\n                        {\n                            throw new DuplicateActionTypeIdentifierException(\n                                \"Multiple action types are associated with the same type ID.\",\n                                typeId.ToString() ?? \"null\",\n                                ImmutableHashSet.Create(existing, type));\n                        }\n\n                        continue;\n                    }\n\n                    types[typeId] = type;\n                }\n            }\n\n            return types;\n        }\n\n        private static IEnumerable<Type> LoadAllActionTypes(Assembly assembly)\n        {\n            var actionType = typeof(IAction);\n            foreach (Type t in assembly.GetTypes())\n            {\n                if (actionType.IsAssignableFrom(t))\n                {\n                    yield return t;\n                }\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Action/NullAction.cs",
    "content": "using Bencodex.Types;\nusing Libplanet.Action.State;\n\nnamespace Libplanet.Action\n{\n    /// <summary>\n    /// An action implementation which does nothing for filling type parameter taking of\n    /// <see cref=\"IAction\"/>.\n    /// </summary>\n    public class NullAction : IAction\n    {\n        public NullAction()\n        {\n            PlainValue = Null.Value;\n        }\n\n        public IValue PlainValue\n        {\n            get;\n            private set;\n        }\n\n        public void LoadPlainValue(IValue plainValue)\n        {\n            PlainValue = plainValue;\n        }\n\n        public IWorld Execute(IActionContext context)\n        {\n            return context.PreviousState;\n        }\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Action/PolicyActionsRegistry.cs",
    "content": "using System.Collections.Immutable;\nusing Libplanet.Types.Blocks;\nusing Libplanet.Types.Tx;\n\nnamespace Libplanet.Action\n{\n    public class PolicyActionsRegistry : IPolicyActionsRegistry\n    {\n        /// <summary>\n        /// A class containing policy actions to evaluate at each situation.\n        /// </summary>\n        /// <param name=\"beginBlockActions\">A list of block actions to\n        /// evaluate at the beginning for each <see cref=\"IPreEvaluationBlock\"/> that gets\n        /// evaluated.\n        /// Note the order of the returned list determines the execution order.\n        /// </param>\n        /// <param name=\"endBlockActions\">A list of block actions to\n        /// evaluate at the end for each <see cref=\"IPreEvaluationBlock\"/> that gets evaluated.\n        /// Note the order of the returned list determines the execution order.\n        /// </param>\n        /// <param name=\"beginTxActions\">A list of block actions to\n        /// evaluate at the beginning for each <see cref=\"Transaction\"/> that gets evaluated.\n        /// Note the order of the returned list determines the execution order.\n        /// </param>\n        /// <param name=\"endTxActions\">A list of block actions to\n        /// evaluate at the end for each <see cref=\"Transaction\"/> that gets evaluated.\n        /// Note the order of the returned list determines the execution order.\n        /// </param>\n        public PolicyActionsRegistry(\n            ImmutableArray<IAction>? beginBlockActions = null,\n            ImmutableArray<IAction>? endBlockActions = null,\n            ImmutableArray<IAction>? beginTxActions = null,\n            ImmutableArray<IAction>? endTxActions = null)\n        {\n            BeginBlockActions = beginBlockActions ?? ImmutableArray<IAction>.Empty;\n            EndBlockActions = endBlockActions ?? ImmutableArray<IAction>.Empty;\n            BeginTxActions = beginTxActions ?? ImmutableArray<IAction>.Empty;\n            EndTxActions = endTxActions ?? ImmutableArray<IAction>.Empty;\n        }\n\n        /// <summary>\n        /// An array of <see cref=\"IAction\"/> to execute and be rendered at the beginning\n        /// for every block, if any.</summary>\n        public ImmutableArray<IAction> BeginBlockActions { get; }\n\n        /// <summary>\n        /// An array of <see cref=\"IAction\"/> to execute and be rendered at the end\n        /// for every block, if any.</summary>\n        public ImmutableArray<IAction> EndBlockActions { get; }\n\n        /// <summary>\n        /// An array of <see cref=\"IAction\"/> to execute and be rendered at the beginning\n        /// for every transaction, if any.</summary>\n        public ImmutableArray<IAction> BeginTxActions { get; }\n\n        /// <summary>\n        /// An array of <see cref=\"IAction\"/> to execute and be rendered at the end\n        /// for every transaction, if any.</summary>\n        public ImmutableArray<IAction> EndTxActions { get; }\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Action/Random.cs",
    "content": "namespace Libplanet.Action\n{\n    internal class Random : System.Random, IRandom\n    {\n        public Random(int seed)\n            : base(seed)\n        {\n            Seed = seed;\n        }\n\n        public int Seed { get; private set; }\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Action/RandomExtensions.cs",
    "content": "using System;\n\nnamespace Libplanet.Action\n{\n    /// <summary>\n    /// This extension class provides some convenient methods\n    /// to deal with <see cref=\"IRandom\"/>.\n    /// </summary>\n    public static class RandomExtensions\n    {\n        /// <summary>\n        /// Generates a UUID version 4, i.e., a random <see cref=\"Guid\"/>.\n        /// Please refer to <a href=\"https://tools.ietf.org/html/rfc4122#section-4.4\">RFC 4122</a>.\n        /// </summary>\n        /// <param name=\"random\"> <see cref=\"IRandom\"/> to generate\n        /// a random <see cref=\"Guid\"/>.</param>\n        /// <returns> Generated random <see cref=\"Guid\"/>.\n        /// </returns>\n        /// <seealso cref=\"IRandom\"/>\n        public static Guid GenerateRandomGuid(this IRandom random)\n        {\n            var b = new byte[16];\n            random.NextBytes(b);\n\n            // Set the four most significant bits (bits 12 through 15) of the time_hi_and_version\n            // field to the 4-bit version number. V4 is 0 1 0 0.\n            // This modifies b[7] not b[6] because time_hi_and_version is stored as short type\n            // in .NET like below:\n            // (short) ((int) b[7] << 8 | (int) b[6])\n            b[7] = (byte)((b[7] & 0x0f) | 0x40);\n\n            // Set the two most significant bits (bits 7 and 6) of the clock_seq_hi_and_reserved\n            // to one and zero, respectively.\n            b[8] = (byte)((b[8] & 0x3f) | 0x80);\n\n            return new Guid(b);\n        }\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Action/State/Account.cs",
    "content": "using System.Collections.Generic;\nusing System.Diagnostics.Contracts;\nusing Bencodex.Types;\nusing Libplanet.Crypto;\nusing Libplanet.Store.Trie;\nusing static Libplanet.Action.State.KeyConverters;\n\nnamespace Libplanet.Action.State\n{\n    /// <summary>\n    /// An internal implementation of <see cref=\"IAccount\"/>.\n    /// </summary>\n    [Pure]\n    public class Account : IAccount\n    {\n        private readonly IAccountState _state;\n\n        public Account(IAccountState state)\n        {\n            _state = state;\n        }\n\n        /// <inheritdoc cref=\"IAccountState.Trie\"/>\n        public ITrie Trie => _state.Trie;\n\n        /// <inheritdoc cref=\"IAccountState.GetState\"/>\n        [Pure]\n        public IValue? GetState(Address address) => _state.GetState(address);\n\n        /// <inheritdoc cref=\"IAccountState.GetStates\"/>\n        [Pure]\n        public IReadOnlyList<IValue?> GetStates(IReadOnlyList<Address> addresses) =>\n            _state.GetStates(addresses);\n\n        /// <inheritdoc cref=\"IAccount.SetState\"/>\n        [Pure]\n        public IAccount SetState(Address address, IValue state) => UpdateState(address, state);\n\n        /// <inheritdoc cref=\"IAccount.RemoveState\"/>\n        [Pure]\n        public IAccount RemoveState(Address address) => UpdateState(address, null);\n\n        [Pure]\n        private Account UpdateState(\n            Address address,\n            IValue? value) => value is { } v\n                ? new Account(new AccountState(Trie.Set(ToStateKey(address), v)))\n                : new Account(new AccountState(Trie.Remove(ToStateKey(address))));\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Action/State/AccountDiff.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Collections.Immutable;\nusing System.Linq;\nusing System.Security.Cryptography;\nusing Bencodex.Types;\nusing Libplanet.Common;\nusing Libplanet.Crypto;\nusing Libplanet.Store.Trie;\nusing Libplanet.Types.Assets;\n\nnamespace Libplanet.Action.State\n{\n    /// <summary>\n    /// Represents a difference between two <see cref=\"IAccountState\"/>s.\n    /// This is a partial interpretation of a raw difference obtained by <see cref=\"ITrie.Diff\"/>\n    /// from <see cref=\"IAccountState\"/>'s perspective.  Keep in mind of the following properties:\n    /// <list type=\"bullet\">\n    ///     <item><description>\n    ///         Any <see lagnword=\"null\"/> value, which is equivalent to non-existent value in\n    ///         the underlying storage, in the source is <em>ignored</em>.  That is, even if\n    ///         the value in the target and the value in the source are different while\n    ///         the value in the source is <see langword=\"null\"/>, this will not be\n    ///         part of the resulting <see cref=\"AccountDiff\"/>.\n    ///     </description></item>\n    ///     <item><description>\n    ///         This only shows the difference in \"states\" manipulated using\n    ///         <see cref=\"IAccount.SetState\"/> and <see cref=\"IAccount.RemoveState\"/>.  That is,\n    ///         this does care about differences in <see cref=\"FungibleAssetValue\"/>s.\n    ///     </description></item>\n    ///     <item><description>\n    ///         Due to the reason mentioned directly above, the size of <see cref=\"AccountDiff\"/>\n    ///         derived from <see cref=\"ITrie.Diff\"/> may not be the same.  Moreover,\n    ///         an <see cref=\"AccountDiff\"/> being empty <em>does not guarantee</em>\n    ///         that the data represented by <see cref=\"IAccountState\"/>s are the same.\n    ///     </description></item>\n    /// </list>\n    /// </summary>\n    public class AccountDiff\n    {\n        private static readonly int _metadataKeyLength = 0;\n\n        private static readonly int _addressKeyLength = Address.Size * 2;\n\n        private static readonly int _currencyKeyLength = HashDigest<SHA1>.Size * 2;\n\n        private static readonly int _stateKeyLength = _addressKeyLength;\n\n        private static readonly int _fungibleAssetKeyLength =\n            _addressKeyLength + _currencyKeyLength + 2;\n\n        private static readonly int _totalSupplyKeyLength = _currencyKeyLength + 2;\n\n        private static readonly int _validatorSetKeyLength = 3;\n\n        private static readonly ImmutableDictionary<int, byte> _reverseConversionTable =\n            new Dictionary<int, byte>()\n            {\n                [48] = 0,   // '0'\n                [49] = 1,   // '1'\n                [50] = 2,   // '2'\n                [51] = 3,   // '3'\n                [52] = 4,   // '4'\n                [53] = 5,   // '5'\n                [54] = 6,   // '6'\n                [55] = 7,   // '7'\n                [56] = 8,   // '8'\n                [57] = 9,   // '9'\n                [97] = 10,  // 'a'\n                [98] = 11,  // 'b'\n                [99] = 12,  // 'c'\n                [100] = 13, // 'd'\n                [101] = 14, // 'e'\n                [102] = 15, // 'f'\n            }.ToImmutableDictionary();\n\n        private AccountDiff(ImmutableDictionary<Address, (IValue?, IValue)> stateDiff)\n        {\n            StateDiffs = stateDiff;\n        }\n\n        public ImmutableDictionary<Address, (IValue?, IValue)> StateDiffs { get; }\n\n        /// <summary>\n        /// Creates an <see cref=\"AccountDiff\"/> instance from given parameters.\n        /// </summary>\n        /// <param name=\"target\">The <see cref=\"IAccountState\"/> to use as the target.</param>\n        /// <param name=\"source\">The <see cref=\"IAccountState\"/> to use as the source.</param>\n        /// <returns>An <see cref=\"AccountDiff\"/> created from given parameters.</returns>\n        /// <remarks>Note that the ordering of the parameters are flipped compared to\n        /// <see cref=\"ITrie.Diff\"/> for syntactical reasons.</remarks>\n        /// <seealso cref=\"ITrie.Diff\"/>\n        /// <seealso cref=\"Create(ITrie, ITrie)\"/>\n        public static AccountDiff Create(IAccountState target, IAccountState source)\n            => Create(target.Trie, source.Trie);\n\n        /// <summary>\n        /// Creates an <see cref=\"AccountDiff\"/> instance from given parameters.\n        /// </summary>\n        /// <param name=\"target\">The <see cref=\"ITrie\"/> to use as the target.</param>\n        /// <param name=\"source\">The <see cref=\"ITrie\"/> to use as the source.</param>\n        /// <returns>An <see cref=\"AccountDiff\"/> created from given parameters.</returns>\n        /// <exception cref=\"ArgumentException\">Thrown when the diff internally obtained from\n        /// <see cref=\"ITrie.Diff\"/> cannot be properly interpreted.</exception>\n        /// <remarks>Note that the ordering of the parameters are flipped compared to\n        /// <see cref=\"ITrie.Diff\"/> for syntactical reasons.</remarks>\n        /// <seealso cref=\"ITrie.Diff\"/>\n        /// <seealso cref=\"Create(IAccountState, IAccountState)\"/>\n        public static AccountDiff Create(ITrie target, ITrie source)\n        {\n            var rawDiffs = source.Diff(target).ToList();\n\n            Dictionary<Address, (IValue?, IValue)> stateDiffs =\n                new Dictionary<Address, (IValue?, IValue)>();\n\n            foreach (var diff in rawDiffs)\n            {\n                // NOTE: Cannot use switch as some lengths cannot be derived as const.\n                if (diff.Path.Length == _stateKeyLength)\n                {\n                    var sd = ToStateDiff(diff);\n                    stateDiffs[sd.Address] = (sd.TargetValue, sd.SourceValue);\n                }\n                else if (diff.Path.Length == _fungibleAssetKeyLength)\n                {\n                    continue;\n                }\n                else if (diff.Path.Length == _totalSupplyKeyLength)\n                {\n                    continue;\n                }\n                else if (diff.Path.Length == _validatorSetKeyLength)\n                {\n                    continue;\n                }\n                else if (diff.Path.Length == _metadataKeyLength)\n                {\n                    continue;\n                }\n                else\n                {\n                    throw new ArgumentException(\n                        $\"Encountered different values at an invalid location: {diff.Path}\");\n                }\n            }\n\n            return new AccountDiff(stateDiffs.ToImmutableDictionary());\n        }\n\n        internal static (Address Address, IValue? TargetValue, IValue SourceValue)\n            ToStateDiff((KeyBytes Path, IValue? TargetValue, IValue SourceValue) encoded)\n        {\n            return (\n                ToAddress(encoded.Path.ToByteArray()),\n                encoded.TargetValue,\n                encoded.SourceValue);\n        }\n\n        internal static Address FromStateKey(KeyBytes key)\n        {\n            if (key.Length != _stateKeyLength)\n            {\n                throw new ArgumentException(\n                    $\"Given {nameof(key)} must be of length {_stateKeyLength}: {key.Length}\");\n            }\n\n            byte[] buffer = new byte[Address.Size];\n            for (int i = 0; i < buffer.Length; i++)\n            {\n                buffer[i] = Pack(key.ByteArray[i * 2], key.ByteArray[i * 2 + 1]);\n            }\n\n            return new Address(buffer);\n        }\n\n        internal static Address ToAddress(byte[] bytes)\n        {\n            if (bytes.Length != _stateKeyLength)\n            {\n                throw new ArgumentException(\n                    $\"Given {nameof(bytes)} must be of length {_stateKeyLength}: {bytes.Length}\");\n            }\n\n            byte[] buffer = new byte[Address.Size];\n            for (int i = 0; i < buffer.Length; i++)\n            {\n                buffer[i] = Pack(bytes[i * 2], bytes[i * 2 + 1]);\n            }\n\n            return new Address(buffer);\n        }\n\n        // FIXME: Assumes both x and y are less than 16.\n        private static byte Pack(byte x, byte y) =>\n            (byte)((_reverseConversionTable[x] << 4) + _reverseConversionTable[y]);\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Action/State/AccountState.cs",
    "content": "#nullable enable\nusing System.Collections.Generic;\nusing System.Diagnostics;\nusing System.Linq;\nusing Bencodex.Types;\nusing Libplanet.Crypto;\nusing Libplanet.Store.Trie;\nusing Libplanet.Types.Consensus;\nusing static Libplanet.Action.State.KeyConverters;\n\nnamespace Libplanet.Action.State\n{\n    /// <summary>\n    /// A default implementation of <see cref=\"IAccountState\"/> interface.\n    /// </summary>\n    public class AccountState : IAccountState\n    {\n        private readonly ITrie _trie;\n        private readonly ActivitySource _activitySource;\n\n        public AccountState(ITrie trie)\n        {\n            _trie = trie;\n            _activitySource = new ActivitySource(\"Libplanet.Action.State\");\n        }\n\n        /// <inheritdoc cref=\"IAccountState.Trie\"/>\n        public ITrie Trie => _trie;\n\n        /// <inheritdoc cref=\"IAccountState.GetState\"/>\n        public IValue? GetState(Address address)\n        {\n            using Activity? a = _activitySource\n                .StartActivity(ActivityKind.Internal)?\n                .AddTag(\"Address\", address.ToString());\n            return Trie.Get(ToStateKey(address));\n        }\n\n        /// <inheritdoc cref=\"IAccountState.GetStates\"/>\n        public IReadOnlyList<IValue?> GetStates(IReadOnlyList<Address> addresses) =>\n            addresses.Select(address => GetState(address)).ToList();\n\n        /// <inheritdoc cref=\"IAccountState.GetValidatorSet\"/>\n        public ValidatorSet GetValidatorSet()\n        {\n            IValue? value = Trie.Get(ValidatorSetKey);\n            return value is List list\n                ? new ValidatorSet(list)\n                : new ValidatorSet();\n        }\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Action/State/CurrencyAccount.cs",
    "content": "using System;\nusing System.Numerics;\nusing Bencodex.Types;\nusing Libplanet.Crypto;\nusing Libplanet.Store.Trie;\nusing Libplanet.Types.Assets;\nusing Libplanet.Types.Blocks;\n\nnamespace Libplanet.Action.State\n{\n    /// <summary>\n    /// A special \"account\" for managing <see cref=\"Currency\"/> starting with\n    /// <see cref=\"BlockMetadata.CurrencyAccountProtocolVersion\"/>.\n    /// </summary>\n    public sealed class CurrencyAccount\n    {\n        /// <summary>\n        /// The <see cref=\"Address\"/> location within the account where\n        /// the total supply of the currency gets stored.\n        /// </summary>\n        public static readonly Address TotalSupplyAddress =\n            new Address(\"1000000000000000000000000000000000000000\");\n\n        public CurrencyAccount(ITrie trie, int worldVersion, Currency currency)\n        {\n            Trie = trie;\n            WorldVersion = worldVersion;\n            Currency = currency;\n        }\n\n        public ITrie Trie { get; }\n\n        public int WorldVersion { get; }\n\n        public Currency Currency { get; }\n\n        public FungibleAssetValue GetBalance(Address address, Currency currency)\n        {\n            CheckCurrency(currency);\n#pragma warning disable SA1118  // The parameter spans multiple lines\n            return FungibleAssetValue.FromRawValue(\n                Currency,\n                WorldVersion >= BlockMetadata.CurrencyAccountProtocolVersion\n                    ? GetRawBalanceV7(address)\n                    : GetRawBalanceV0(address));\n#pragma warning restore SA1118\n        }\n\n        public FungibleAssetValue GetTotalSupply(Currency currency)\n        {\n            CheckCurrency(currency);\n#pragma warning disable SA1118  // The parameter spans multiple lines\n            return FungibleAssetValue.FromRawValue(\n                Currency,\n                WorldVersion >= BlockMetadata.CurrencyAccountProtocolVersion\n                    ? GetRawTotalSupplyV7()\n                    : GetRawTotalSupplyV0());\n#pragma warning restore SA1118\n        }\n\n        public CurrencyAccount MintAsset(\n            Address recipient,\n            FungibleAssetValue value)\n        {\n            CheckCurrency(value.Currency);\n            if (value.Sign <= 0)\n            {\n                throw new ArgumentOutOfRangeException(\n                    nameof(value),\n                    $\"The amount to mint, burn, or transfer must be greater than zero: {value}\");\n            }\n\n            return WorldVersion >= BlockMetadata.CurrencyAccountProtocolVersion\n                ? MintRawAssetV7(recipient, value.RawValue)\n                : MintRawAssetV0(recipient, value.RawValue);\n        }\n\n        public CurrencyAccount BurnAsset(\n            Address owner,\n            FungibleAssetValue value)\n        {\n            CheckCurrency(value.Currency);\n            if (value.Sign <= 0)\n            {\n                throw new ArgumentOutOfRangeException(\n                    nameof(value),\n                    $\"The amount to mint, burn, or transfer must be greater than zero: {value}\");\n            }\n\n            return WorldVersion >= BlockMetadata.CurrencyAccountProtocolVersion\n                ? BurnRawAssetV7(owner, value.RawValue)\n                : BurnRawAssetV0(owner, value.RawValue);\n        }\n\n        public CurrencyAccount TransferAsset(\n            Address sender,\n            Address recipient,\n            FungibleAssetValue value)\n        {\n            CheckCurrency(value.Currency);\n            if (value.Sign <= 0)\n            {\n                throw new ArgumentOutOfRangeException(\n                    nameof(value),\n                    $\"The amount to mint, burn, or transfer must be greater than zero: {value}\");\n            }\n\n            return WorldVersion >= BlockMetadata.CurrencyAccountProtocolVersion\n                ? TransferRawAssetV7(sender, recipient, value.RawValue)\n                : TransferRawAssetV1(sender, recipient, value.RawValue);\n        }\n\n        [Obsolete(\n            \"Should not be used unless to specifically keep backwards compatibility \" +\n            \"for IActions that's been used when block protocol version was 0.\")]\n        public CurrencyAccount TransferAssetV0(\n            Address sender,\n            Address recipient,\n            FungibleAssetValue value)\n        {\n            CheckCurrency(value.Currency);\n            if (value.Sign <= 0)\n            {\n                throw new ArgumentOutOfRangeException(\n                    nameof(value),\n                    $\"The amount to mint, burn, or transfer must be greater than zero: {value}\");\n            }\n\n            return TransferRawAssetV0(sender, recipient, value.RawValue);\n        }\n\n        public IAccount AsAccount()\n        {\n            return new Account(new AccountState(Trie));\n        }\n\n        private CurrencyAccount MintRawAssetV0(\n            Address recipient,\n            BigInteger rawValue)\n        {\n            CurrencyAccount currencyAccount = this;\n            BigInteger prevBalanceRawValue = currencyAccount.GetRawBalanceV0(recipient);\n            currencyAccount =\n                currencyAccount.WriteRawBalanceV0(recipient, prevBalanceRawValue + rawValue);\n            if (Currency.TotalSupplyTrackable)\n            {\n                BigInteger prevTotalSupplyRawValue = currencyAccount.GetRawTotalSupplyV0();\n                if (Currency.MaximumSupply is { } maximumSupply &&\n                    maximumSupply.RawValue < prevTotalSupplyRawValue + rawValue)\n                {\n                    FungibleAssetValue prevTotalSupply =\n                        FungibleAssetValue.FromRawValue(Currency, prevTotalSupplyRawValue);\n                    FungibleAssetValue value =\n                        FungibleAssetValue.FromRawValue(Currency, rawValue);\n                    throw new SupplyOverflowException(\n                        $\"Cannot mint {value} in addition to \" +\n                        $\"the current total supply of {prevTotalSupply} as it would exceed \" +\n                        $\"the maximum supply {Currency.MaximumSupply}.\",\n                        value);\n                }\n\n                currencyAccount =\n                    currencyAccount.WriteRawTotalSupplyV0(prevTotalSupplyRawValue + rawValue);\n            }\n\n            return currencyAccount;\n        }\n\n        private CurrencyAccount MintRawAssetV7(\n            Address recipient,\n            BigInteger rawValue)\n        {\n            CurrencyAccount currencyAccount = this;\n            BigInteger prevBalanceRawValue = currencyAccount.GetRawBalanceV7(recipient);\n            currencyAccount =\n                currencyAccount.WriteRawBalanceV7(recipient, prevBalanceRawValue + rawValue);\n\n            BigInteger prevTotalSupplyRawValue = currencyAccount.GetRawTotalSupplyV7();\n            if (Currency.MaximumSupply is { } maximumSupply &&\n                maximumSupply.RawValue < prevTotalSupplyRawValue + rawValue)\n            {\n                FungibleAssetValue prevTotalSupply =\n                    FungibleAssetValue.FromRawValue(Currency, prevTotalSupplyRawValue);\n                FungibleAssetValue value =\n                    FungibleAssetValue.FromRawValue(Currency, rawValue);\n                throw new SupplyOverflowException(\n                    $\"Cannot mint {value} in addition to \" +\n                    $\"the current total supply of {prevTotalSupply} as it would exceed \" +\n                    $\"the maximum supply {Currency.MaximumSupply}.\",\n                    prevTotalSupply);\n            }\n\n            currencyAccount =\n                currencyAccount.WriteRawTotalSupplyV7(prevTotalSupplyRawValue + rawValue);\n\n            return currencyAccount;\n        }\n\n        private CurrencyAccount BurnRawAssetV0(\n            Address owner,\n            BigInteger rawValue)\n        {\n            CurrencyAccount currencyAccount = this;\n            BigInteger prevBalanceRawValue = currencyAccount.GetRawBalanceV0(owner);\n            if (prevBalanceRawValue - rawValue < 0)\n            {\n                FungibleAssetValue prevBalance =\n                    FungibleAssetValue.FromRawValue(Currency, prevBalanceRawValue);\n                FungibleAssetValue value = FungibleAssetValue.FromRawValue(Currency, rawValue);\n                throw new InsufficientBalanceException(\n                    $\"Cannot burn or transfer {value} from {owner} as the current balance \" +\n                    $\"of {owner} is {prevBalance}.\",\n                    owner,\n                    prevBalance);\n            }\n\n            currencyAccount =\n                currencyAccount.WriteRawBalanceV0(owner, prevBalanceRawValue - rawValue);\n\n            if (Currency.TotalSupplyTrackable)\n            {\n                BigInteger prevTotalSupply = currencyAccount.GetRawTotalSupplyV0();\n                currencyAccount =\n                    currencyAccount.WriteRawTotalSupplyV0(prevTotalSupply - rawValue);\n            }\n\n            return currencyAccount;\n        }\n\n        private CurrencyAccount BurnRawAssetV7(\n            Address owner,\n            BigInteger rawValue)\n        {\n            CurrencyAccount currencyAccount = this;\n            BigInteger prevBalanceRawValue = currencyAccount.GetRawBalanceV7(owner);\n            if (prevBalanceRawValue - rawValue < 0)\n            {\n                FungibleAssetValue prevBalance =\n                    FungibleAssetValue.FromRawValue(Currency, prevBalanceRawValue);\n                FungibleAssetValue value = FungibleAssetValue.FromRawValue(Currency, rawValue);\n                throw new InsufficientBalanceException(\n                    $\"Cannot burn or transfer {value} from {owner} as the current balance \" +\n                    $\"of {owner} is {prevBalance}.\",\n                    owner,\n                    prevBalance);\n            }\n\n            currencyAccount =\n                currencyAccount.WriteRawBalanceV7(owner, prevBalanceRawValue - rawValue);\n\n            BigInteger prevTotalSupplyRawValue = currencyAccount.GetRawTotalSupplyV7();\n            currencyAccount =\n                currencyAccount.WriteRawTotalSupplyV7(prevTotalSupplyRawValue - rawValue);\n\n            return currencyAccount;\n        }\n\n        private CurrencyAccount TransferRawAssetV7(\n            Address sender,\n            Address recipient,\n            BigInteger rawValue)\n        {\n            CurrencyAccount currencyAccount = this;\n            BigInteger prevSenderBalanceRawValue = currencyAccount.GetRawBalanceV7(sender);\n            if (prevSenderBalanceRawValue - rawValue < 0)\n            {\n                FungibleAssetValue prevSenderBalance =\n                    FungibleAssetValue.FromRawValue(Currency, prevSenderBalanceRawValue);\n                FungibleAssetValue value = FungibleAssetValue.FromRawValue(Currency, rawValue);\n                throw new InsufficientBalanceException(\n                    $\"Cannot burn or transfer {value} from {sender} as the current balance \" +\n                    $\"of {sender} is {prevSenderBalance}.\",\n                    sender,\n                    prevSenderBalance);\n            }\n\n            currencyAccount = currencyAccount.WriteRawBalanceV7(\n                sender,\n                prevSenderBalanceRawValue - rawValue);\n            BigInteger prevRecipientBalanceRawValue = currencyAccount.GetRawBalanceV7(recipient);\n            currencyAccount = currencyAccount.WriteRawBalanceV7(\n                recipient,\n                prevRecipientBalanceRawValue + rawValue);\n            return currencyAccount;\n        }\n\n        private CurrencyAccount TransferRawAssetV1(\n            Address sender,\n            Address recipient,\n            BigInteger rawValue)\n        {\n            CurrencyAccount currencyAccount = this;\n            BigInteger prevSenderBalanceRawValue = currencyAccount.GetRawBalanceV0(sender);\n            if (prevSenderBalanceRawValue - rawValue < 0)\n            {\n                FungibleAssetValue prevSenderBalance =\n                    FungibleAssetValue.FromRawValue(Currency, prevSenderBalanceRawValue);\n                FungibleAssetValue value = FungibleAssetValue.FromRawValue(Currency, rawValue);\n                throw new InsufficientBalanceException(\n                    $\"Cannot burn or transfer {value} from {sender} as the current balance \" +\n                    $\"of {sender} is {prevSenderBalance}.\",\n                    sender,\n                    prevSenderBalance);\n            }\n\n            // NOTE: For backward compatibility with the bugged behavior before\n            // protocol version 1.\n            currencyAccount = currencyAccount.WriteRawBalanceV0(\n                sender,\n                prevSenderBalanceRawValue - rawValue);\n            BigInteger prevRecipientBalanceRawValue =\n                currencyAccount.GetRawBalanceV0(recipient);\n            currencyAccount = currencyAccount.WriteRawBalanceV0(\n                recipient,\n                prevRecipientBalanceRawValue + rawValue);\n            return currencyAccount;\n        }\n\n        private CurrencyAccount TransferRawAssetV0(\n            Address sender,\n            Address recipient,\n            BigInteger rawValue)\n        {\n            CurrencyAccount currencyAccount = this;\n            BigInteger prevSenderBalanceRawValue = currencyAccount.GetRawBalanceV0(sender);\n            if (prevSenderBalanceRawValue - rawValue < 0)\n            {\n                FungibleAssetValue prevSenderBalance =\n                    FungibleAssetValue.FromRawValue(Currency, prevSenderBalanceRawValue);\n                FungibleAssetValue value = FungibleAssetValue.FromRawValue(Currency, rawValue);\n                throw new InsufficientBalanceException(\n                    $\"Cannot burn or transfer {value} from {sender} as the current balance \" +\n                    $\"of {sender} is {prevSenderBalance}.\",\n                    sender,\n                    prevSenderBalance);\n            }\n\n            // NOTE: For backward compatibility with the bugged behavior before\n            // protocol version 1.\n            BigInteger prevRecipientBalanceRawValue =\n                currencyAccount.GetRawBalanceV0(recipient);\n            currencyAccount = currencyAccount.WriteRawBalanceV0(\n                sender,\n                prevSenderBalanceRawValue - rawValue);\n            currencyAccount = currencyAccount.WriteRawBalanceV0(\n                recipient,\n                prevRecipientBalanceRawValue + rawValue);\n            return currencyAccount;\n        }\n\n        private CurrencyAccount WriteRawBalanceV0(Address address, BigInteger rawValue) =>\n            new CurrencyAccount(\n                Trie.Set(\n                    KeyConverters.ToFungibleAssetKey(address, Currency), new Integer(rawValue)),\n                WorldVersion,\n                Currency);\n\n        private CurrencyAccount WriteRawBalanceV7(Address address, BigInteger rawValue) =>\n            new CurrencyAccount(\n                Trie.Set(KeyConverters.ToStateKey(address), new Integer(rawValue)),\n                WorldVersion,\n                Currency);\n\n        private CurrencyAccount WriteRawTotalSupplyV0(BigInteger rawValue) =>\n            new CurrencyAccount(\n                Trie.Set(KeyConverters.ToTotalSupplyKey(Currency), new Integer(rawValue)),\n                WorldVersion,\n                Currency);\n\n        private CurrencyAccount WriteRawTotalSupplyV7(BigInteger rawValue) =>\n            new CurrencyAccount(\n                Trie.Set(\n                    KeyConverters.ToStateKey(CurrencyAccount.TotalSupplyAddress),\n                    new Integer(rawValue)),\n                WorldVersion,\n                Currency);\n\n        private BigInteger GetRawBalanceV0(Address address) =>\n            Trie.Get(\n                KeyConverters.ToFungibleAssetKey(address, Currency)) is Integer i\n                    ? i.Value\n                    : BigInteger.Zero;\n\n        private BigInteger GetRawBalanceV7(Address address) =>\n            Trie.Get(KeyConverters.ToStateKey(address)) is Integer i\n                ? i.Value\n                : BigInteger.Zero;\n\n        private BigInteger GetRawTotalSupplyV0() =>\n            Trie.Get(KeyConverters.ToTotalSupplyKey(Currency)) is Integer i\n                ? i.Value\n                : BigInteger.Zero;\n\n        private BigInteger GetRawTotalSupplyV7() =>\n            Trie.Get(KeyConverters.ToStateKey(TotalSupplyAddress)) is Integer i\n                ? i.Value\n                : BigInteger.Zero;\n\n        private void CheckCurrency(Currency currency)\n        {\n            if (!Currency.Equals(currency))\n            {\n                throw new ArgumentException(\n                    $\"Given currency {currency} should match the account's currency {Currency}.\",\n                    nameof(currency));\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Action/State/CurrencyPermissionException.cs",
    "content": "using System;\nusing Libplanet.Crypto;\nusing Libplanet.Types.Assets;\n\nnamespace Libplanet.Action.State\n{\n    /// <summary>\n    /// The exception that is thrown when a <see cref=\"TransactionSigner\"/> has no rights\n    /// to mint a <see cref=\"Currency\"/> or burn assets of a <see cref=\"Currency\"/>.\n    /// </summary>\n    /// <seealso cref=\"IWorld.MintAsset\"/>\n    /// <seealso cref=\"IWorld.BurnAsset\"/>\n    public sealed class CurrencyPermissionException : Exception\n    {\n        /// <summary>\n        /// Creates a new <see cref=\"CurrencyPermissionException\"/> object.\n        /// </summary>\n        /// <param name=\"message\">Specifies a <see cref=\"Exception.Message\"/>.</param>\n        /// <param name=\"transactionSigner\"> The address of the account who tried to mint or burn\n        /// assets of a <paramref name=\"currency\"/>.  Corresponds to\n        /// the <see cref=\"TransactionSigner\"/> property.</param>\n        /// <param name=\"currency\"> The <see cref=\"Common.Types.Assets.Currency\"/> to be tried\n        /// to be minted or burned by the <paramref name=\"transactionSigner\"/>.  Corresponds to\n        /// the <see cref=\"Currency\"/> property.</param>\n        public CurrencyPermissionException(\n            string? message,\n            Address transactionSigner,\n            Currency currency\n        )\n            : base(message)\n        {\n            TransactionSigner = transactionSigner;\n            Currency = currency;\n        }\n\n        /// <summary>\n        /// The address of the account who tried to mint or burn assets of a <see cref=\"Currency\"/>.\n        /// </summary>\n        public Address TransactionSigner { get; }\n\n        /// <summary>\n        /// The <see cref=\"Common.Types.Assets.Currency\"/> to be tried to be minted or burned by\n        /// the <see cref=\"TransactionSigner\"/>.\n        /// </summary>\n        public Currency Currency { get; }\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Action/State/IAccount.cs",
    "content": "using System.Collections.Generic;\nusing System.Diagnostics.Contracts;\nusing Bencodex.Types;\nusing Libplanet.Crypto;\n\nnamespace Libplanet.Action.State\n{\n    /// <summary>\n    /// An interface to manipulate an account state with\n    /// maintaining <see cref=\"Delta\"/>.\n    /// <para>It is like a map which is virtually initialized such\n    /// that every possible <see cref=\"Address\"/> exists and\n    /// is mapped to <see langword=\"null\"/>.  That means that:</para>\n    /// <list type=\"bullet\">\n    /// <item>\n    /// <description>it does not have length,</description>\n    /// </item>\n    /// <item>\n    /// <description>its index getter never throws\n    /// <see cref=\"KeyNotFoundException\"/>,\n    /// but returns <see langword=\"null\"/> instead, and</description>\n    /// </item>\n    /// <item>\n    /// <description>filling an <see cref=\"Address\"/> with\n    /// <see langword=\"null\"/> state cannot be distinguished from\n    /// the <see cref=\"Address\"/> having never been set to\n    /// any state.</description>\n    /// </item>\n    /// </list>\n    /// </summary>\n    /// <remarks>\n    /// This interface is immutable.  <see cref=\"SetState(Address, IValue)\"/>\n    /// method does not manipulate the instance, but returns a new\n    /// <see cref=\"IAccount\"/> instance with updated states.\n    /// </remarks>\n    public interface IAccount : IAccountState\n    {\n        /// <summary>\n        /// Gets a new instance that the account state of the given\n        /// <paramref name=\"address\"/> is set to the given\n        /// <paramref name=\"state\"/>.\n        /// </summary>\n        /// <param name=\"address\">The <see cref=\"Address\"/> referring\n        /// the account to set its state.</param>\n        /// <param name=\"state\">The new state to fill the account with.</param>\n        /// <returns>A new <see cref=\"IAccount\"/> instance that\n        /// the account state of the given <paramref name=\"address\"/>\n        /// is set to the given <paramref name=\"state\"/>.</returns>\n        /// <remarks>\n        /// This method does not manipulate the instance,\n        /// but returns a new <see cref=\"IAccount\"/> instance\n        /// with updated states instead.\n        /// </remarks>\n        [Pure]\n        IAccount SetState(Address address, IValue state);\n\n        /// <summary>\n        /// Gets a new instance that the account state of the given\n        /// <paramref name=\"address\"/> is removed.\n        /// </summary>\n        /// <param name=\"address\">The <see cref=\"Address\"/> referring\n        /// the account to remove its state.</param>\n        /// <returns>A new <see cref=\"IAccount\"/> instance that\n        /// the account state of the given <paramref name=\"address\"/>\n        /// is removed.</returns>\n        /// <remarks>\n        /// This method does not manipulate the instance,\n        /// but returns a new <see cref=\"IAccount\"/> instance\n        /// with updated states instead.\n        /// </remarks>\n        [Pure]\n        IAccount RemoveState(Address address);\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Action/State/IAccountState.cs",
    "content": "using System.Collections.Generic;\nusing System.Diagnostics.Contracts;\nusing Bencodex.Types;\nusing Libplanet.Crypto;\nusing Libplanet.Store.Trie;\n\nnamespace Libplanet.Action.State\n{\n    /// <summary>\n    /// An interface to fetch account states.\n    /// <para>It is like a readonly map which is virtually initialized such\n    /// that every possible <see cref=\"Address\"/> exists and\n    /// is mapped to <see langword=\"null\"/>.  That means that:</para>\n    /// <list type=\"bullet\">\n    /// <item>\n    /// <description>it does not have length,</description>\n    /// </item>\n    /// <item>\n    /// <description>its index getter never throws\n    /// <see cref=\"KeyNotFoundException\"/>,\n    /// but returns <see langword=\"null\"/> instead, and</description>\n    /// </item>\n    /// </list>\n    /// </summary>\n    public interface IAccountState\n    {\n        /// <summary>\n        /// The <see cref=\"ITrie\"/> of the <see cref=\"IAccountState\"/>.\n        /// </summary>\n        [Pure]\n        public ITrie Trie { get; }\n\n        /// <summary>\n        /// Gets the account state of the given <paramref name=\"address\"/>.\n        /// </summary>\n        /// <param name=\"address\">The <see cref=\"Address\"/> referring\n        /// the account to get its state.</param>\n        /// <returns>The account state of the given <paramref name=\"address\"/>.\n        /// If it has never been set to any state it returns <see langword=\"null\"/>\n        /// instead.</returns>\n        [Pure]\n        IValue? GetState(Address address);\n\n        /// <summary>\n        /// Gets multiple account states associated with the specified <paramref name=\"addresses\"/>\n        /// at once.\n        /// </summary>\n        /// <param name=\"addresses\">The <see cref=\"Address\"/>es associated with states to get.\n        /// </param>\n        /// <returns>The states associated to the specified <paramref name=\"addresses\"/>.\n        /// Associated values are ordered in the same way to the corresponding\n        /// <paramref name=\"addresses\"/>.  Absent states are represented as <see langword=\"null\"/>.\n        /// </returns>\n        [Pure]\n        IReadOnlyList<IValue?> GetStates(IReadOnlyList<Address> addresses);\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Action/State/IBlockChainStates.cs",
    "content": "using System;\nusing System.Security.Cryptography;\nusing Libplanet.Common;\nusing Libplanet.Store;\nusing Libplanet.Store.Trie;\nusing Libplanet.Types.Blocks;\n\nnamespace Libplanet.Action.State\n{\n    /// <summary>\n    /// A minimal interface to get states from a BlockChain.\n    /// <para>Note that BlockChain implements this interface.</para>\n    /// </summary>\n    public interface IBlockChainStates\n    {\n        /// <summary>\n        /// Returns the <see cref=\"IWorldState\"/> in the BlockChain at <paramref name=\"offset\"/>.\n        /// </summary>\n        /// <param name=\"offset\">The <see cref=\"BlockHash\"/> of the <see cref=\"Block\"/> to create\n        /// for which to create an <see cref=\"IWorldState\"/>.</param>\n        /// <returns>\n        /// The <see cref=\"IWorldState\"/> at <paramref name=\"offset\"/>, which is the identical\n        /// to what <see cref=\"Block.StateRootHash\"/> of <paramref name=\"offset\"/> indicates.\n        /// </returns>\n        /// <exception cref=\"ArgumentException\">Thrown when one of the following is true\n        /// for <paramref name=\"offset\"/>.\n        /// <list type=\"bullet\">\n        ///     <item><description>\n        ///         Corresponding <see cref=\"Block\"/> is not found in the <see cref=\"IStore\"/>.\n        ///     </description></item>\n        ///     <item><description>\n        ///         Corresponding <see cref=\"Block\"/> is found but its state root is not found\n        ///         in the <see cref=\"IStateStore\"/>.\n        ///     </description></item>\n        /// </list>\n        /// </exception>\n        /// <seealso cref=\"IWorldState\"/>\n        IWorldState GetWorldState(BlockHash offset);\n\n        /// <summary>\n        /// Returns the <see cref=\"IWorldState\"/> in the BlockChain's state storage\n        /// with <paramref name=\"stateRootHash\"/>.\n        /// </summary>\n        /// <param name=\"stateRootHash\">The state root hash for which to create\n        /// an <see cref=\"IWorldState\"/>.</param>\n        /// <returns>\n        /// The <see cref=\"IWorldState\"/> with <paramref name=\"stateRootHash\"/>.\n        /// If <paramref name=\"stateRootHash\"/> is <see langword=\"null\"/>,\n        /// returns an empty <see cref=\"IWorldState\"/>.\n        /// </returns>\n        /// <exception cref=\"ArgumentException\">Thrown when no <see cref=\"ITrie\"/> with\n        /// <paramref name=\"hash\"/> as its state root hash is found.\n        /// </exception>\n        /// <seealso cref=\"IWorldState\"/>\n        IWorldState GetWorldState(HashDigest<SHA256>? stateRootHash);\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Action/State/IStateStoreExtensions.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Security.Cryptography;\nusing System.Text;\nusing Bencodex.Types;\nusing Libplanet.Common;\nusing Libplanet.Store;\nusing Libplanet.Store.Trie;\nusing Libplanet.Types.Blocks;\n\nnamespace Libplanet.Action.State\n{\n    internal static class IStateStoreExtensions\n    {\n        /// <summary>\n        /// Retrieves the <see cref=\"IWorld\"/> associated with\n        /// given <paramref name=\"stateRootHash\"/>.\n        /// </summary>\n        /// <param name=\"stateStore\">The <see cref=\"IStateStore\"/> to retrieve\n        /// an <see cref=\"IWorld\"/> from.</param>\n        /// <param name=\"stateRootHash\">The state root hash of the <see cref=\"IWorld\"/>\n        /// to retrieve.</param>\n        /// <returns>The <see cref=\"IWorld\"/> associated with\n        /// given <paramref name=\"stateRootHash\"/>.</returns>\n        internal static IWorld GetWorld(\n            this IStateStore stateStore,\n            HashDigest<SHA256>? stateRootHash)\n        {\n            return new World(\n                new WorldBaseState(stateStore.GetStateRoot(stateRootHash), stateStore));\n        }\n\n        /// <summary>\n        /// Commits given <paramref name=\"world\"/> to given <paramref name=\"stateStore\"/>.\n        /// </summary>\n        /// <param name=\"stateStore\">The <see cref=\"IStateStore\"/> to commit\n        /// <paramref name=\"world\"/> to.</param>\n        /// <param name=\"world\">The <see cref=\"IWorld\"/> to commit.</param>\n        /// <returns>The committed <see cref=\"IWorld\"/>.</returns>\n        internal static IWorld CommitWorld(this IStateStore stateStore, IWorld world)\n        {\n            if (world.Version >= BlockMetadata.WorldStateProtocolVersion)\n            {\n                var worldTrie = world.Trie;\n                foreach (var account in world.Delta.Accounts)\n                {\n                    var accountTrie = stateStore.Commit(account.Value.Trie);\n                    worldTrie = worldTrie.Set(\n                        KeyConverters.ToStateKey(account.Key),\n                        new Binary(accountTrie.Hash.ByteArray));\n                }\n\n                return new World(\n                    new WorldBaseState(stateStore.Commit(worldTrie), stateStore));\n            }\n            else\n            {\n                return new World(\n                    new WorldBaseState(\n                        stateStore.Commit(world.GetAccount(ReservedAddresses.LegacyAccount).Trie),\n                        stateStore));\n            }\n        }\n\n        /// <summary>\n        /// Migrates given <paramref name=\"world\"/> to <paramref name=\"targetVersion\"/>.\n        /// </summary>\n        /// <param name=\"stateStore\">The <see cref=\"IStateStore\"/> to commit\n        /// the migrated <see cref=\"IWorld\"/>.</param>\n        /// <param name=\"world\">The <see cref=\"IWorld\"/> to migrate.</param>\n        /// <param name=\"targetVersion\">The target <see cref=\"IWorld\"/> version\n        /// to migrate to.</param>\n        /// <returns>The migrated <see cref=\"IWorld\"/> of <paramref name=\"world\"/> with\n        /// <see cref=\"IWorld.Version\"/> equal to:\n        /// <list type=\"bullet\">\n        ///     <item><description>\n        ///         zero if <paramref name=\"targetVersion\"/> is less than\n        ///         <see cref=\"BlockMetadata.WorldStateProtocolVersion\"/>.\n        ///     </description></item>\n        ///     <item><description>\n        ///         <paramref name=\"targetVersion\"/> if <paramref name=\"targetVersion\"/> is\n        ///         greater than or equal to <see cref=\"BlockMetadata.WorldStateProtocolVersion\"/>.\n        ///     </description></item>\n        /// </list>\n        /// </returns>\n        /// <exception cref=\"ApplicationException\">Thrown when <paramref name=\"targetVersion\"/> is\n        /// lower than the <see cref=\"IWorld.Version\"/> of <paramref name=\"world\"/>.</exception>\n        /// <remarks>\n        /// Migrated <see cref=\"IWorld\"/> is automatically committed before returning.\n        /// </remarks>\n        internal static IWorld MigrateWorld(\n            this IStateStore stateStore,\n            IWorld world,\n            int targetVersion)\n        {\n            if (world.Version > targetVersion)\n            {\n                throw new ApplicationException(\n                    $\"Given {nameof(world)} with version {world.Version} \" +\n                    $\"cannot be migrated to a lower version {targetVersion}.\");\n            }\n\n            // Migrate up to BlockMetadata.WorldStateProtocolVersion\n            // if conditions are met.\n            if (targetVersion >= BlockMetadata.WorldStateProtocolVersion &&\n                world.Version < BlockMetadata.WorldStateProtocolVersion)\n            {\n                var worldTrie = stateStore.GetStateRoot(null);\n                worldTrie = worldTrie.SetMetadata(\n                    new TrieMetadata(BlockMetadata.WorldStateProtocolVersion));\n                worldTrie = worldTrie.Set(\n                    KeyConverters.ToStateKey(ReservedAddresses.LegacyAccount),\n                    new Binary(world.Trie.Hash.ByteArray));\n                worldTrie = stateStore.Commit(worldTrie);\n                world = new World(new WorldBaseState(worldTrie, stateStore));\n            }\n\n            // Migrate up to BlockMetadata.ValidatorSetAccountProtocolVersion\n            // if conditions are met.\n            if (targetVersion >= BlockMetadata.ValidatorSetAccountProtocolVersion &&\n                world.Version < BlockMetadata.ValidatorSetAccountProtocolVersion)\n            {\n                var worldTrie = world.Trie;\n                worldTrie = worldTrie.SetMetadata(\n                    new TrieMetadata(BlockMetadata.ValidatorSetAccountProtocolVersion));\n                worldTrie = stateStore.Commit(worldTrie);\n                world = new World(new WorldBaseState(worldTrie, stateStore));\n\n                var legacyAccountTrie =\n                    world.GetAccount(ReservedAddresses.LegacyAccount).Trie;\n                IValue? rawValidatorSet = legacyAccountTrie.Get(KeyConverters.ValidatorSetKey);\n\n                // Move encoded validator set only if it already exists.\n                if (rawValidatorSet is { } rawValue)\n                {\n                    legacyAccountTrie = legacyAccountTrie.Remove(KeyConverters.ValidatorSetKey);\n                    legacyAccountTrie = stateStore.Commit(legacyAccountTrie);\n\n                    var validatorSetAccountTrie =\n                        world.GetAccount(ReservedAddresses.ValidatorSetAccount).Trie;\n                    validatorSetAccountTrie = validatorSetAccountTrie.Set(\n                        KeyConverters.ToStateKey(ValidatorSetAccount.ValidatorSetAddress),\n                        rawValue);\n                    validatorSetAccountTrie = stateStore.Commit(validatorSetAccountTrie);\n\n                    worldTrie = worldTrie.Set(\n                        KeyConverters.ToStateKey(ReservedAddresses.LegacyAccount),\n                        new Binary(legacyAccountTrie.Hash.ByteArray));\n                    worldTrie = worldTrie.Set(\n                        KeyConverters.ToStateKey(ReservedAddresses.ValidatorSetAccount),\n                        new Binary(validatorSetAccountTrie.Hash.ByteArray));\n                    worldTrie = stateStore.Commit(worldTrie);\n                    world = new World(new WorldBaseState(worldTrie, stateStore));\n                }\n            }\n\n            // Migrate up to BlockMetadata.CurrencyAccountProtocolVersion\n            // if conditions are met.\n            if (targetVersion >= BlockMetadata.CurrencyAccountProtocolVersion &&\n                world.Version < BlockMetadata.CurrencyAccountProtocolVersion)\n            {\n                var worldTrie = world.Trie;\n                worldTrie = worldTrie.SetMetadata(\n                    new TrieMetadata(BlockMetadata.CurrencyAccountProtocolVersion));\n                worldTrie = stateStore.Commit(worldTrie);\n                world = new World(new WorldBaseState(worldTrie, stateStore));\n\n                // Remove all total supply tracking.\n                const int totalSupplyKeyLength = 42;\n                var subRootPath = new KeyBytes(Encoding.ASCII.GetBytes(\"__\"));\n                var legacyAccountTrie =\n                    world.GetAccount(ReservedAddresses.LegacyAccount).Trie;\n                var tempTrie = (MerkleTrie)legacyAccountTrie.Set(subRootPath, Null.Value);\n                foreach (var pair in tempTrie.IterateSubTrieValues(subRootPath))\n                {\n                    if (pair.Path.Length == totalSupplyKeyLength)\n                    {\n                        legacyAccountTrie = legacyAccountTrie.Remove(pair.Path);\n                    }\n                }\n\n                legacyAccountTrie = stateStore.Commit(legacyAccountTrie);\n                worldTrie = worldTrie.Set(\n                    KeyConverters.ToStateKey(ReservedAddresses.LegacyAccount),\n                    new Binary(legacyAccountTrie.Hash.ByteArray));\n                worldTrie = stateStore.Commit(worldTrie);\n                world = new World(new WorldBaseState(worldTrie, stateStore));\n\n                // Remove all fungible assets\n                const int fungibleAssetKeyLength = 82;\n                subRootPath = new KeyBytes(Encoding.ASCII.GetBytes(\"_\"));\n                tempTrie = (MerkleTrie)legacyAccountTrie.Set(subRootPath, Null.Value);\n                byte[] addressBytesBuffer = new byte[40];\n                byte[] currencyBytesBuffer = new byte[40];\n                List<(KeyBytes Address, KeyBytes Currency, Integer Amount)> favs =\n                    new List<(KeyBytes Address, KeyBytes Currency, Integer Amount)>();\n                foreach (var pair in tempTrie.IterateSubTrieValues(subRootPath))\n                {\n                    if (pair.Path.Length == fungibleAssetKeyLength)\n                    {\n                        legacyAccountTrie = legacyAccountTrie.Remove(pair.Path);\n                        pair.Path.ByteArray.CopyTo(1, addressBytesBuffer, 0, 40);\n                        pair.Path.ByteArray.CopyTo(42, currencyBytesBuffer, 0, 40);\n                        favs.Add((\n                            new KeyBytes(addressBytesBuffer),\n                            new KeyBytes(currencyBytesBuffer),\n                            (Integer)pair.Value));\n                    }\n                }\n\n                legacyAccountTrie = stateStore.Commit(legacyAccountTrie);\n                worldTrie = worldTrie.Set(\n                    KeyConverters.ToStateKey(ReservedAddresses.LegacyAccount),\n                    new Binary(legacyAccountTrie.Hash.ByteArray));\n                worldTrie = stateStore.Commit(worldTrie);\n                world = new World(new WorldBaseState(worldTrie, stateStore));\n\n                // Add in fungible assets to new accounts.\n                KeyBytes totalSupplyKeyBytes =\n                    KeyConverters.ToStateKey(CurrencyAccount.TotalSupplyAddress);\n                var grouped = favs.GroupBy(fav => fav.Currency);\n                foreach (var group in grouped)\n                {\n                    var currencyAccountTrie = world.Trie.Get(group.Key) is Binary hash\n                        ? stateStore.GetStateRoot(new HashDigest<SHA256>(hash))\n                        : stateStore.GetStateRoot(null);\n                    foreach (var fav in group)\n                    {\n                        Integer balance = fav.Amount;\n                        Integer prevTotalSupply =\n                            currencyAccountTrie.Get(totalSupplyKeyBytes) is Integer i\n                                ? i\n                                : new Integer(0);\n                        Integer newTotalSupply = new Integer(prevTotalSupply.Value + balance.Value);\n                        currencyAccountTrie =\n                            currencyAccountTrie.Set(\n                                fav.Address,\n                                balance);\n                        currencyAccountTrie =\n                            currencyAccountTrie.Set(\n                                totalSupplyKeyBytes,\n                                newTotalSupply);\n                    }\n\n                    currencyAccountTrie = stateStore.Commit(currencyAccountTrie);\n                    worldTrie = worldTrie.Set(\n                        group.Key,\n                        new Binary(currencyAccountTrie.Hash.ByteArray));\n                    worldTrie = stateStore.Commit(worldTrie);\n                    world = new World(new WorldBaseState(worldTrie, stateStore));\n                }\n            }\n\n            // Migrate up to target version if conditions are met.\n            if (targetVersion >= BlockMetadata.WorldStateProtocolVersion &&\n                world.Version < targetVersion)\n            {\n                var worldTrie = world.Trie;\n                worldTrie = worldTrie.SetMetadata(new TrieMetadata(targetVersion));\n                worldTrie = stateStore.Commit(worldTrie);\n                world = new World(new WorldBaseState(worldTrie, stateStore));\n            }\n\n            return world;\n        }\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Action/State/IWorld.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Diagnostics.Contracts;\nusing Libplanet.Crypto;\n\nnamespace Libplanet.Action.State\n{\n    /// <summary>\n    /// An interface to manipulate an world state with\n    /// maintaining <see cref=\"Delta\"/>.\n    /// <para>It is like a map which is virtually initialized such\n    /// that every possible <see cref=\"Address\"/> exists and\n    /// is mapped to <see langword=\"null\"/>.  That means that:</para>\n    /// <list type=\"bullet\">\n    /// <item>\n    /// <description>it does not have length,</description>\n    /// </item>\n    /// <item>\n    /// <description>its index getter never throws\n    /// <see cref=\"KeyNotFoundException\"/>,\n    /// but returns <see langword=\"null\"/> instead, and</description>\n    /// </item>\n    /// <item>\n    /// <description>filling an <see cref=\"Address\"/> with\n    /// <see langword=\"null\"/> account cannot be distinguished from\n    /// the <see cref=\"Address\"/> having never been set to\n    /// any account.</description>\n    /// </item>\n    /// </list>\n    /// </summary>\n    /// <remarks>\n    /// This interface is immutable.  <see cref=\"SetAccount\"/>\n    /// method does not manipulate the instance, but returns a new\n    /// <see cref=\"IWorld\"/> instance with updated states.\n    /// </remarks>\n    public interface IWorld : IWorldState\n    {\n        /// <summary>\n        /// The <see cref=\"IWorld\"/> representing the delta part of\n        /// this <see cref=\"IWorld\"/>.\n        /// </summary>\n        [Pure]\n        IWorldDelta Delta { get; }\n\n        /// <summary>\n        /// Gets the <see cref=\"IAccount\"/> of the given <paramref name=\"address\"/>.\n        /// </summary>\n        /// <param name=\"address\">The <see cref=\"Address\"/> referring\n        /// the world to get its state.</param>\n        /// <returns>The <see cref=\"IAccount\"/> of the given <paramref name=\"address\"/>.\n        /// If it has never been set to any state it returns <see langword=\"null\"/>\n        /// instead.</returns>\n        [Pure]\n        IAccount GetAccount(Address address);\n\n        /// <summary>\n        /// Creates a new instance of <see cref=\"IWorld\"/> with given <paramref name=\"address\"/>\n        /// set to given <paramref name=\"account\"/>.\n        /// </summary>\n        /// <param name=\"address\">The <see cref=\"Address\"/> for which to set\n        /// given <see cref=\"account\"/> to.</param>\n        /// <param name=\"account\">The new <see cref=\"IAccount\"/> to set to\n        /// given <paramref name=\"address\"/>.</param>\n        /// <returns>A new <see cref=\"IWorld\"/> instance where the account state of given\n        /// <paramref name=\"address\"/> is set to given <paramref name=\"account\"/>.</returns>\n        /// <remarks>\n        /// This method does not manipulate the instance, but returns\n        /// a new <see cref=\"IWorld\"/> instance with an updated world state instead.\n        /// </remarks>\n        /// <exception cref=\"ArgumentException\">\n        /// Thrown when <see cref=\"Legacy\"/> is <see langword=\"true\"/> and\n        /// <paramref name=\"address\"/> is not <see cref=\"ReservedAddresses.LegacyAccount\"/>.\n        /// </exception>\n        [Pure]\n        IWorld SetAccount(Address address, IAccount account);\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Action/State/IWorldDelta.cs",
    "content": "using System.Collections.Immutable;\nusing System.Diagnostics.Contracts;\nusing Libplanet.Crypto;\n\nnamespace Libplanet.Action.State\n{\n    public interface IWorldDelta\n    {\n        /// <summary>\n        /// A dictionary representing changed account states for each <see cref=\"Address\"/>.\n        /// This lasts till new empty delta instance has been made.\n        /// </summary>\n        [Pure]\n        IImmutableDictionary<Address, IAccount> Accounts { get; }\n\n        /// <summary>\n        /// Set account on both of <see cref=\"Accounts\"/> and <see cref=\"Uncommitted\"/>\n        /// dictionaries. If <see cref=\"IAccount\"/> already exists on\n        /// <paramref name=\"address\"/>, update with new <paramref name=\"account\"/>.\n        /// </summary>\n        /// <param name=\"address\"><see cref=\"Address\"/> to set on.</param>\n        /// <param name=\"account\"><see cref=\"IAccount\"/> to set.</param>\n        /// <returns>New <see cref=\"IWorldDelta\"/> that account is properly set.</returns>\n        [Pure]\n        IWorldDelta SetAccount(Address address, IAccount account);\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Action/State/IWorldExtensions.cs",
    "content": "using System;\nusing System.Diagnostics.Contracts;\nusing Libplanet.Crypto;\nusing Libplanet.Types.Assets;\nusing Libplanet.Types.Blocks;\nusing Libplanet.Types.Consensus;\n\nnamespace Libplanet.Action.State\n{\n    public static class IWorldExtensions\n    {\n        /// <summary>\n        /// Queries <paramref name=\"address\"/>'s balance of the <paramref name=\"currency\"/>.\n        /// </summary>\n        /// <param name=\"worldState\">The <see cref=\"IWorldState\"/> to read from.</param>\n        /// <param name=\"address\">The owner address to query.</param>\n        /// <param name=\"currency\">The currency type to query.</param>\n        /// <returns>\n        /// The <paramref name=\"address\"/>'s balance of the <paramref name=\"currency\"/>.\n        /// </returns>\n        [Pure]\n        public static FungibleAssetValue GetBalance(\n            this IWorldState worldState,\n            Address address,\n            Currency currency) =>\n                worldState.GetCurrencyAccount(currency).GetBalance(address, currency);\n\n        /// <summary>\n        /// Mints the fungible asset <paramref name=\"value\"/> (i.e., in-game monetary),\n        /// and give it to the <paramref name=\"recipient\"/>.\n        /// </summary>\n        /// <param name=\"world\">The <see cref=\"IWorld\"/> to manipulate.</param>\n        /// <param name=\"context\">The <see cref=\"IActionContext\"/> of the <see cref=\"IAction\"/>\n        /// executing this method.</param>\n        /// <param name=\"recipient\">The address who receives the minted asset.</param>\n        /// <param name=\"value\">The asset value to mint.</param>\n        /// <returns>A new <see cref=\"IWorld\"/> instance that the given <paramref\n        /// name=\"value\"/> is added to <paramref name=\"recipient\"/>'s balance.</returns>\n        /// <exception cref=\"CurrencyPermissionException\">Thrown when a transaction signer\n        /// (or a miner in case of block actions) is not a member of the <see\n        /// cref=\"FungibleAssetValue.Currency\"/>'s <see cref=\"Currency.Minters\"/>.</exception>\n        /// <exception cref=\"ArgumentOutOfRangeException\">Thrown when the <paramref name=\"value\"/>\n        /// is less than or equal to 0.</exception>\n        /// <exception cref=\"SupplyOverflowException\">Thrown when the sum of the\n        /// <paramref name=\"value\"/> to be minted and the current total supply amount of the\n        /// <see cref=\"FungibleAssetValue.Currency\"/> exceeds the\n        /// <see cref=\"Currency.MaximumSupply\"/>.</exception>\n        [Pure]\n        public static IWorld MintAsset(\n            this IWorld world,\n            IActionContext context,\n            Address recipient,\n            FungibleAssetValue value) => value.Currency.AllowsToMint(context.Signer)\n                ? world.SetCurrencyAccount(\n                    world.GetCurrencyAccount(value.Currency).MintAsset(recipient, value))\n                : throw new CurrencyPermissionException(\n                    $\"Given {nameof(context)}'s signer {context.Signer} does not have \" +\n                    $\"the authority to mint or burn currency {value.Currency}.\",\n                    context.Signer,\n                    value.Currency);\n\n        /// <summary>\n        /// Burns the fungible asset <paramref name=\"value\"/> (i.e., in-game monetary) from\n        /// <paramref name=\"owner\"/>'s balance.\n        /// </summary>\n        /// <param name=\"world\">The <see cref=\"IWorld\"/> to manipulate.</param>\n        /// <param name=\"context\">The <see cref=\"IActionContext\"/> of the <see cref=\"IAction\"/>\n        /// executing this method.</param>\n        /// <param name=\"owner\">The address who owns the fungible asset to burn.</param>\n        /// <param name=\"value\">The fungible asset <paramref name=\"value\"/> to burn.</param>\n        /// <returns>A new <see cref=\"IWorld\"/> instance that the given <paramref\n        /// name=\"value\"/> is subtracted from <paramref name=\"owner\"/>'s balance.</returns>\n        /// <exception cref=\"CurrencyPermissionException\">Thrown when a transaction signer\n        /// (or a miner in case of block actions) is not a member of the <see\n        /// cref=\"FungibleAssetValue.Currency\"/>'s <see cref=\"Currency.Minters\"/>.</exception>\n        /// <exception cref=\"ArgumentOutOfRangeException\">Thrown when the <paramref name=\"value\"/>\n        /// is less than or equal to zero.</exception>\n        /// <exception cref=\"InsufficientBalanceException\">Thrown when the <paramref name=\"owner\"/>\n        /// has insufficient balance than <paramref name=\"value\"/> to burn.</exception>\n        [Pure]\n        public static IWorld BurnAsset(\n            this IWorld world,\n            IActionContext context,\n            Address owner,\n            FungibleAssetValue value) => value.Currency.AllowsToMint(context.Signer)\n                ? world.SetCurrencyAccount(\n                    world.GetCurrencyAccount(value.Currency).BurnAsset(owner, value))\n                : throw new CurrencyPermissionException(\n                    $\"Given {nameof(context)}'s signer {context.Signer} does not have \" +\n                    $\"the authority to mint or burn currency {value.Currency}.\",\n                    context.Signer,\n                    value.Currency);\n\n        /// <summary>\n        /// Transfers the fungible asset <paramref name=\"value\"/> (i.e., in-game monetary)\n        /// from the <paramref name=\"sender\"/> to the <paramref name=\"recipient\"/>.\n        /// </summary>\n        /// <param name=\"world\">The <see cref=\"IWorld\"/> to manipulate.</param>\n        /// <param name=\"context\">The <see cref=\"IActionContext\"/> of the <see cref=\"IAction\"/>\n        /// executing this method.</param>\n        /// <param name=\"sender\">The address who sends the fungible asset to\n        /// the <paramref name=\"recipient\"/>.</param>\n        /// <param name=\"recipient\">The address who receives the fungible asset from\n        /// the <paramref name=\"sender\"/>.</param>\n        /// <param name=\"value\">The asset value to transfer.</param>\n        /// <returns>A new <see cref=\"IWorld\"/> instance that the given <paramref\n        /// name=\"value\"/>  is subtracted from <paramref name=\"sender\"/>'s balance and added to\n        /// <paramref name=\"recipient\"/>'s balance.</returns>\n        /// <exception cref=\"ArgumentOutOfRangeException\">Thrown when the <paramref name=\"value\"/>\n        /// is less than or equal to zero.</exception>\n        /// <exception cref=\"InsufficientBalanceException\">Thrown when the <paramref name=\"sender\"/>\n        /// has insufficient balance than <paramref name=\"value\"/> to transfer.</exception>\n        /// <remarks>\n        /// The behavior is different depending on <paramref name=\"context\"/>'s\n        /// <see cref=\"IActionContext.BlockProtocolVersion\"/>.  There is a bug for version 0\n        /// where this may not act as intended.  Such behavior is left intact for backward\n        /// compatibility.\n        /// </remarks>\n        [Pure]\n        public static IWorld TransferAsset(\n            this IWorld world,\n            IActionContext context,\n            Address sender,\n            Address recipient,\n            FungibleAssetValue value) =>\n                context.BlockProtocolVersion > 0\n                    ? world.SetCurrencyAccount(\n                        world\n                            .GetCurrencyAccount(value.Currency)\n                            .TransferAsset(sender, recipient, value))\n#pragma warning disable CS0618 // Obsolete\n                    : world.SetCurrencyAccount(\n                        world\n                            .GetCurrencyAccount(value.Currency)\n                            .TransferAssetV0(sender, recipient, value));\n#pragma warning restore CS0618\n\n        /// <summary>\n        /// <para>\n        /// Returns the total supply of <paramref name=\"currency\"/>.\n        /// </para>\n        /// <para>\n        /// The total supply of a given <see cref=\"Currency\"/> is <em>determined</em>\n        /// by the following:\n        /// <list type=\"bullet\">\n        ///     <item><description>\n        ///         If <see cref=\"IWorldState.Version\"/> is less than\n        ///         <see cref=\"BlockMetadata.CurrencyAccountProtocolVersion\"/>,\n        ///         it is the amount of total supply for the <see cref=\"Currency\"/> in question\n        ///         if the value of <see cref=\"Currency.TotalSupplyTrackable\"/>\n        ///         is <see langword=\"true\"/>, and zero otherwise.  That is, an untracked\n        ///         <see cref=\"Currency\"/>'s total supply is always considered zero.\n        ///     </description></item>\n        ///     <item><description>\n        ///         If <see cref=\"IWorldState.Version\"/> is greater than or equal to\n        ///         <see cref=\"BlockMetadata.CurrencyAccountProtocolVersion\"/>,\n        ///         it is the amount of total supply for the <see cref=\"Currency\"/> in question\n        ///         regardless of the value of <see cref=\"Currency.TotalSupplyTrackable\"/>.\n        ///     </description></item>\n        /// </list>\n        /// </para>\n        /// </summary>\n        /// <param name=\"worldState\">The <see cref=\"IWorldState\"/> to read from.</param>\n        /// <param name=\"currency\">The currency type to query.</param>\n        /// <returns>The total supply of the <paramref name=\"currency\"/>.\n        /// </returns>\n        [Pure]\n        public static FungibleAssetValue GetTotalSupply(\n            this IWorldState worldState,\n            Currency currency) =>\n                worldState.GetCurrencyAccount(currency).GetTotalSupply(currency);\n\n        /// <summary>\n        /// Returns the validator set.\n        /// </summary>\n        /// <param name=\"worldState\">The <see cref=\"IWorldState\"/> to read from.</param>\n        /// <returns>The validator set of type <see cref=\"ValidatorSet\"/>.\n        /// </returns>\n        [Pure]\n        public static ValidatorSet GetValidatorSet(this IWorldState worldState) =>\n            worldState.GetValidatorSetAccount().GetValidatorSet();\n\n        /// <summary>\n        /// Sets <paramref name=\"validatorSet\"/> to the stored <see cref=\"ValidatorSet\"/>.\n        /// </summary>\n        /// <param name=\"world\">The <see cref=\"IWorld\"/> to manipulate.</param>\n        /// <param name=\"validatorSet\">The <see cref=\"ValidatorSet\"/> instance to write.</param>\n        /// <returns>A new <see cref=\"IWorld\"/> instance with\n        /// <paramref name=\"validator\"/> set.</returns>\n        [Pure]\n        public static IWorld SetValidatorSet(this IWorld world, ValidatorSet validatorSet) =>\n            world.SetValidatorSetAccount(\n                world.GetValidatorSetAccount().SetValidatorSet(validatorSet));\n\n        [Pure]\n        internal static ValidatorSetAccount GetValidatorSetAccount(this IWorldState worldState) =>\n            worldState.Version >= BlockMetadata.ValidatorSetAccountProtocolVersion\n                ? new ValidatorSetAccount(\n                    worldState.GetAccountState(ReservedAddresses.ValidatorSetAccount).Trie,\n                    worldState.Version)\n                : new ValidatorSetAccount(\n                    worldState.GetAccountState(ReservedAddresses.LegacyAccount).Trie,\n                    worldState.Version);\n\n        [Pure]\n        internal static CurrencyAccount GetCurrencyAccount(\n            this IWorldState worldState,\n            Currency currency) =>\n            worldState.Version >= BlockMetadata.CurrencyAccountProtocolVersion\n                ? new CurrencyAccount(\n                    worldState.GetAccountState(new Address(currency.Hash.ByteArray)).Trie,\n                    worldState.Version,\n                    currency)\n                : new CurrencyAccount(\n                    worldState.GetAccountState(ReservedAddresses.LegacyAccount).Trie,\n                    worldState.Version,\n                    currency);\n\n        [Pure]\n        internal static IWorld SetCurrencyAccount(\n            this IWorld world,\n            CurrencyAccount currencyAccount) =>\n                world.Version == currencyAccount.WorldVersion\n                    ? world.Version >= BlockMetadata.CurrencyAccountProtocolVersion\n                        ? world.SetAccount(\n                            new Address(currencyAccount.Currency.Hash.ByteArray),\n                            currencyAccount.AsAccount())\n                        : world.SetAccount(\n                            ReservedAddresses.LegacyAccount,\n                            currencyAccount.AsAccount())\n                    : throw new ArgumentException(\n                        $\"Given {nameof(currencyAccount)} must have the same version as \" +\n                        $\"the version of the world {world.Version}: \" +\n                        $\"{currencyAccount.WorldVersion}\",\n                        nameof(currencyAccount));\n\n        [Pure]\n        internal static IWorld SetValidatorSetAccount(\n            this IWorld world,\n            ValidatorSetAccount validatorSetAccount) =>\n                world.Version == validatorSetAccount.WorldVersion\n                    ? world.Version >= BlockMetadata.ValidatorSetAccountProtocolVersion\n                        ? world.SetAccount(\n                            ReservedAddresses.ValidatorSetAccount,\n                            validatorSetAccount.AsAccount())\n                        : world.SetAccount(\n                            ReservedAddresses.LegacyAccount,\n                            validatorSetAccount.AsAccount())\n                    : throw new ArgumentException(\n                        $\"Given {nameof(validatorSetAccount)} must have the same version as \" +\n                        $\"the version of the world {world.Version}: \" +\n                        $\"{validatorSetAccount.WorldVersion}\",\n                        nameof(validatorSetAccount));\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Action/State/IWorldState.cs",
    "content": "using System.Collections.Generic;\nusing System.Diagnostics.Contracts;\nusing Libplanet.Crypto;\nusing Libplanet.Store.Trie;\nusing Libplanet.Types.Blocks;\n\nnamespace Libplanet.Action.State\n{\n    /// <summary>\n    /// An interface to fetch world states.\n    /// <para>It is like a readonly map which is virtually initialized such\n    /// that every possible <see cref=\"Address\"/> exists and\n    /// is mapped to <see langword=\"null\"/>.  That means that:</para>\n    /// <list type=\"bullet\">\n    /// <item>\n    /// <description>it does not have length,</description>\n    /// </item>\n    /// <item>\n    /// <description>its index getter never throws\n    /// <see cref=\"KeyNotFoundException\"/>,\n    /// but returns <see langword=\"null\"/> instead, and</description>\n    /// </item>\n    /// <item>\n    /// <description>filling an <see cref=\"Address\"/> with\n    /// <see langword=\"null\"/> state cannot be distinguished from\n    /// the <see cref=\"Address\"/> having never been set to\n    /// any state.</description>\n    /// </item>\n    /// </list>\n    /// </summary>\n    public interface IWorldState\n    {\n        /// <summary>\n        /// The <see cref=\"ITrie\"/> of the <see cref=\"IWorldState\"/>.\n        /// </summary>\n        public ITrie Trie { get; }\n\n        /// <summary>\n        /// Whether <see cref=\"IWorldState\"/> is backed by an <see cref=\"ITrie\"/> with\n        /// the legacy data model.  This is <see langword=\"true\"/> if and only if\n        /// <see cref=\"Version\"/> is less than\n        /// <see cref=\"BlockMetadata.WorldStateProtocolVersion\"/>.\n        /// </summary>\n        bool Legacy { get; }\n\n        /// <summary>\n        /// The version of the backend <see cref=\"ITrie\"/> data model.  This should be in sync with\n        /// <see cref=\"IBlockMetadata.ProtocolVersion\"/> of the <see cref=\"IPreEvaluationBlock\"/>\n        /// getting evaluated.  As this was only introduced since\n        /// <see cref=\"BlockMetadata.WorldStateProtocolVersion\"/>, this returns\n        /// zero with any <see cref=\"ITrie\"/> representing an <see cref=\"IWorldState\"/> before\n        /// <see cref=\"BlockMetadata.WorldStateProtocolVersion\"/> or any <see cref=\"ITrie\"/>\n        /// representing an <see cref=\"IAccountState\"/>.\n        /// </summary>\n        /// <seealso cref=\"TrieMetadata.Version\"/>\n        int Version { get; }\n\n        /// <summary>\n        /// Gets the <see cref=\"IAccountState\"/> of the given <paramref name=\"address\"/>.\n        /// </summary>\n        /// <param name=\"address\">The <see cref=\"Address\"/> referring\n        /// the world to get its state.</param>\n        /// <returns>The <see cref=\"IAccountState\"/> of the given <paramref name=\"address\"/>.\n        /// If it has never been set to any state it returns <see langword=\"null\"/>\n        /// instead.</returns>\n        [Pure]\n        IAccountState GetAccountState(Address address);\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Action/State/InsufficientBalanceException.cs",
    "content": "using System;\nusing Libplanet.Crypto;\nusing Libplanet.Types.Assets;\n\nnamespace Libplanet.Action.State\n{\n    /// <summary>\n    /// The exception that is thrown when a sender has less <see cref=\"Balance\"/> than amount to\n    /// transfer or an owner has less <see cref=\"Balance\"/> than amount to burn.\n    /// </summary>\n    /// <seealso cref=\"IWorld.TransferAsset\"/>\n    /// <seealso cref=\"IWorld.BurnAsset\"/>\n    public sealed class InsufficientBalanceException : Exception\n    {\n        /// <summary>\n        /// Creates a new <see cref=\"InsufficientBalanceException\"/> object.\n        /// </summary>\n        /// <param name=\"message\">Specifies a <see cref=\"Exception.Message\"/>.</param>\n        /// <param name=\"address\">The owner of the insufficient <paramref name=\"balance\"/>.\n        /// Corresponds to the <see cref=\"Address\"/> property.</param>\n        /// <param name=\"balance\">The account's current balance.\n        /// Corresponds to the <see cref=\"Balance\"/> property.</param>\n        public InsufficientBalanceException(\n            string? message,\n            Address address,\n            FungibleAssetValue balance\n        )\n            : base(message)\n        {\n            Address = address;\n            Balance = balance;\n        }\n\n        /// <summary>\n        /// The owner of the insufficient <see cref=\"Balance\"/>.\n        /// </summary>\n        public Address Address { get; }\n\n        /// <summary>\n        /// The account's current balance.\n        /// </summary>\n        public FungibleAssetValue Balance { get; }\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Action/State/KeyConverters.cs",
    "content": "using System.Collections.Immutable;\nusing System.Runtime.CompilerServices;\nusing Libplanet.Crypto;\nusing Libplanet.Store.Trie;\nusing Libplanet.Types.Assets;\n\nnamespace Libplanet.Action.State\n{\n    public static class KeyConverters\n    {\n        // \"___\"\n        public static readonly KeyBytes ValidatorSetKey =\n            new KeyBytes(new byte[] { _underScore, _underScore, _underScore });\n\n        private const byte _underScore = 95;  // '_'\n\n        private static readonly byte[] _conversionTable =\n        {\n            48,  // '0'\n            49,  // '1'\n            50,  // '2'\n            51,  // '3'\n            52,  // '4'\n            53,  // '5'\n            54,  // '6'\n            55,  // '7'\n            56,  // '8'\n            57,  // '9'\n            97,  // 'a'\n            98,  // 'b'\n            99,  // 'c'\n            100, // 'd'\n            101, // 'e'\n            102, // 'f'\n        };\n\n        // $\"{ByteUtil.Hex(address.ByteArray)}\"\n        public static KeyBytes ToStateKey(Address address)\n        {\n            var addressBytes = address.ByteArray;\n            byte[] buffer = new byte[addressBytes.Length * 2];\n            for (int i = 0; i < addressBytes.Length; i++)\n            {\n                buffer[i * 2] = _conversionTable[addressBytes[i] >> 4];\n                buffer[i * 2 + 1] = _conversionTable[addressBytes[i] & 0xf];\n            }\n\n            return new KeyBytes(Unsafe.As<byte[], ImmutableArray<byte>>(ref buffer));\n        }\n\n        // $\"_{ByteUtil.Hex(address.ByteArray)}_{ByteUtil.Hex(currency.Hash.ByteArray)}\"\n        public static KeyBytes ToFungibleAssetKey(Address address, Currency currency)\n        {\n            var addressBytes = address.ByteArray;\n            var currencyBytes = currency.Hash.ByteArray;\n            byte[] buffer = new byte[addressBytes.Length * 2 + currencyBytes.Length * 2 + 2];\n\n            buffer[0] = _underScore;\n            for (int i = 0; i < addressBytes.Length; i++)\n            {\n                buffer[1 + i * 2] = _conversionTable[addressBytes[i] >> 4];\n                buffer[1 + i * 2 + 1] = _conversionTable[addressBytes[i] & 0xf];\n            }\n\n            var offset = addressBytes.Length * 2;\n            buffer[offset + 1] = _underScore;\n            for (int i = 0; i < currencyBytes.Length; i++)\n            {\n                buffer[offset + 2 + i * 2] = _conversionTable[currencyBytes[i] >> 4];\n                buffer[offset + 2 + i * 2 + 1] = _conversionTable[currencyBytes[i] & 0xf];\n            }\n\n            return new KeyBytes(Unsafe.As<byte[], ImmutableArray<byte>>(ref buffer));\n        }\n\n        public static KeyBytes ToFungibleAssetKey(\n            (Address Address, Currency Currency) pair) =>\n            ToFungibleAssetKey(pair.Address, pair.Currency);\n\n        // $\"__{ByteUtil.Hex(currency.Hash.ByteArray)}\"\n        public static KeyBytes ToTotalSupplyKey(Currency currency)\n        {\n            var currencyBytes = currency.Hash.ByteArray;\n            byte[] buffer = new byte[currencyBytes.Length * 2 + 2];\n\n            buffer[0] = _underScore;\n            buffer[1] = _underScore;\n\n            for (int i = 0; i < currencyBytes.Length; i++)\n            {\n                buffer[2 + i * 2] = _conversionTable[currencyBytes[i] >> 4];\n                buffer[2 + i * 2 + 1] = _conversionTable[currencyBytes[i] & 0xf];\n            }\n\n            return new KeyBytes(Unsafe.As<byte[], ImmutableArray<byte>>(ref buffer));\n        }\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Action/State/ReservedAddresses.cs",
    "content": "using Libplanet.Crypto;\n\nnamespace Libplanet.Action.State\n{\n    public static class ReservedAddresses\n    {\n        public static readonly Address LegacyAccount =\n            new Address(\"1000000000000000000000000000000000000000\");\n\n        public static readonly Address ValidatorSetAccount =\n            new Address(\"1000000000000000000000000000000000000001\");\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Action/State/SupplyOverflowException.cs",
    "content": "using System;\nusing Libplanet.Types.Assets;\n\nnamespace Libplanet.Action.State\n{\n    /// <summary>\n    /// The exception thrown when a minter tries to mint a currency such that the resulting total\n    /// supply exceed the maximum amount.\n    /// </summary>\n    /// <seealso cref=\"IWorld.MintAsset\"/>\n    public sealed class SupplyOverflowException : Exception\n    {\n        /// <summary>\n        /// Creates a new <see cref=\"SupplyOverflowException\"/> object.\n        /// </summary>\n        /// <param name=\"message\">Specifies a <see cref=\"Exception.Message\"/>.</param>\n        /// <param name=\"amount\">The attempted amount to be minted.\n        /// Corresponds to the <see cref=\"Amount\"/> property.</param>\n        public SupplyOverflowException(\n            string? message,\n            FungibleAssetValue amount\n        )\n            : base(message)\n        {\n            Amount = amount;\n        }\n\n        /// <summary>\n        /// The attempted amount to be minted.\n        /// </summary>\n        public FungibleAssetValue Amount { get; }\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Action/State/ValidatorSetAccount.cs",
    "content": "using Libplanet.Crypto;\nusing Libplanet.Store.Trie;\nusing Libplanet.Types.Blocks;\nusing Libplanet.Types.Consensus;\n\nnamespace Libplanet.Action.State\n{\n    /// <summary>\n    /// A special \"account\" for managing <see cref=\"ValidatorSet\"/> starting with\n    /// <see cref=\"BlockMetadata.ValidatorSetAccountProtocolVersion\"/>.\n    /// </summary>\n    public class ValidatorSetAccount\n    {\n        /// <summary>\n        /// The <see cref=\"Address\"/> location within the account where a\n        /// <see cref=\"ValidatorSet\"/> gets stored.\n        /// </summary>\n        public static readonly Address ValidatorSetAddress =\n            new Address(\"1000000000000000000000000000000000000000\");\n\n        public ValidatorSetAccount(ITrie trie, int worldVersion)\n        {\n            Trie = trie;\n            WorldVersion = worldVersion;\n        }\n\n        public ITrie Trie { get; }\n\n        public int WorldVersion { get; }\n\n        public ValidatorSet GetValidatorSet()\n        {\n            if (WorldVersion >= BlockMetadata.ValidatorSetAccountProtocolVersion)\n            {\n                return Trie.Get(KeyConverters.ToStateKey(ValidatorSetAddress)) is { } value\n                    ? new ValidatorSet(value)\n                    : new ValidatorSet();\n            }\n            else\n            {\n                return Trie.Get(KeyConverters.ValidatorSetKey) is { } value\n                    ? new ValidatorSet(value)\n                    : new ValidatorSet();\n            }\n        }\n\n        public ValidatorSetAccount SetValidatorSet(ValidatorSet validatorSet)\n        {\n            if (WorldVersion >= BlockMetadata.ValidatorSetAccountProtocolVersion)\n            {\n                return new ValidatorSetAccount(\n                    Trie.Set(KeyConverters.ToStateKey(ValidatorSetAddress), validatorSet.Bencoded),\n                    WorldVersion);\n            }\n            else\n            {\n                return new ValidatorSetAccount(\n                    Trie.Set(KeyConverters.ValidatorSetKey, validatorSet.Bencoded),\n                    WorldVersion);\n            }\n        }\n\n        /// <summary>\n        /// Converts to an <see cref=\"IAccount\"/> so it can be set to an <see cref=\"IWorld\"/>\n        /// using <see cref=\"IWorld.SetAccount\"/>.\n        /// </summary>\n        /// <returns>An <see cref=\"IAccount\"/> with <see cref=\"Trie\"/> as its\n        /// underlying <see cref=\"IAccountState.Trie\"/>.</returns>\n        public IAccount AsAccount()\n        {\n            return new Account(new AccountState(Trie));\n        }\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Action/State/World.cs",
    "content": "using System;\nusing System.Diagnostics.Contracts;\nusing Libplanet.Crypto;\nusing Libplanet.Store.Trie;\n\nnamespace Libplanet.Action.State\n{\n    /// <summary>\n    /// An internal implementation of <see cref=\"IWorld\"/>.\n    /// </summary>\n    [Pure]\n    public class World : IWorld\n    {\n        private readonly IWorldState _baseState;\n\n        public World(IWorldState baseState)\n            : this(baseState, new WorldDelta())\n        {\n        }\n\n        private World(IWorldState baseState, IWorldDelta delta)\n        {\n            _baseState = baseState;\n            Delta = delta;\n        }\n\n        /// <inheritdoc cref=\"IWorld.Delta\"/>\n        public IWorldDelta Delta { get; }\n\n        /// <inheritdoc cref=\"IWorldState.Trie\"/>\n        [Pure]\n        public ITrie Trie => _baseState.Trie;\n\n        /// <inheritdoc cref=\"IWorldState.Legacy\"/>\n        [Pure]\n        public bool Legacy => _baseState.Legacy;\n\n        /// <inheritdoc cref=\"IWorldState.Version\"/>\n        [Pure]\n        public int Version => _baseState.Version;\n\n        /// <inheritdoc cref=\"IWorld.GetAccount\"/>\n        [Pure]\n        public IAccount GetAccount(Address address)\n        {\n            return Delta.Accounts.TryGetValue(address, out IAccount? account)\n                ? account\n                : new Account(_baseState.GetAccountState(address));\n        }\n\n        /// <inheritdoc cref=\"IWorldState.GetAccountState\"/>\n        [Pure]\n        public IAccountState GetAccountState(Address address) => GetAccount(address);\n\n        /// <inheritdoc cref=\"IWorld.SetAccount\"/>\n        [Pure]\n        public IWorld SetAccount(Address address, IAccount account)\n        {\n            if (Legacy && !address.Equals(ReservedAddresses.LegacyAccount))\n            {\n                throw new ArgumentException(\n                    $\"Cannot set a non-legacy account ({address}) to a legacy {nameof(IWorld)}.\",\n                    nameof(address));\n            }\n\n            return new World(_baseState, Delta.SetAccount(address, account));\n        }\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Action/State/WorldBaseState.cs",
    "content": "#nullable enable\nusing System.Diagnostics;\nusing System.Security.Cryptography;\nusing Bencodex.Types;\nusing Libplanet.Common;\nusing Libplanet.Crypto;\nusing Libplanet.Store;\nusing Libplanet.Store.Trie;\nusing Libplanet.Types.Blocks;\nusing static Libplanet.Action.State.KeyConverters;\n\nnamespace Libplanet.Action.State\n{\n    /// <summary>\n    /// A default implementation of <see cref=\"IWorldState\"/> interface.\n    /// It acts as root state of <see cref=\"World\"/> recursion.\n    /// </summary>\n    public class WorldBaseState : IWorldState\n    {\n        private readonly IStateStore _stateStore;\n        private readonly ActivitySource _activitySource;\n\n        public WorldBaseState(ITrie trie, IStateStore stateStore)\n        {\n            Trie = trie;\n            _stateStore = stateStore;\n            Version = trie.GetMetadata() is { } value\n                ? value.Version\n                : 0;\n            _activitySource = new ActivitySource(\"Libplanet.Action.WorldBaseState\");\n        }\n\n        /// <inheritdoc cref=\"IWorldState.Trie\"/>\n        public ITrie Trie { get; }\n\n        /// <inheritdoc cref=\"IWorldState.Legacy\"/>\n        public bool Legacy => Version < BlockMetadata.WorldStateProtocolVersion;\n\n        /// <inheritdoc cref=\"IWorldState.Version\"/>\n        public int Version { get; }\n\n        /// <inheritdoc cref=\"IWorldState.GetAccountState\"/>\n        public IAccountState GetAccountState(Address address)\n        {\n            using Activity? a = _activitySource\n                .StartActivity(ActivityKind.Internal)?\n                .AddTag(\"Address\", address.ToString());\n            if (Legacy)\n            {\n                return address.Equals(ReservedAddresses.LegacyAccount)\n                    ? new AccountState(Trie)\n                    : new AccountState(_stateStore.GetStateRoot(null));\n            }\n            else\n            {\n                return Trie.Get(ToStateKey(address)) is Binary accountStateRootHash\n                    ? new AccountState(_stateStore.GetStateRoot(\n                        new HashDigest<SHA256>(accountStateRootHash.ByteArray)))\n                    : new AccountState(_stateStore.GetStateRoot(null));\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Action/State/WorldDelta.cs",
    "content": "using System.Collections.Immutable;\nusing Libplanet.Crypto;\n\nnamespace Libplanet.Action.State\n{\n    public class WorldDelta : IWorldDelta\n    {\n        private readonly IImmutableDictionary<Address, IAccount> _accounts;\n\n        public WorldDelta()\n        {\n            _accounts = ImmutableDictionary<Address, IAccount>.Empty;\n        }\n\n        private WorldDelta(IImmutableDictionary<Address, IAccount> accounts)\n        {\n            _accounts = accounts;\n        }\n\n        /// <inheritdoc cref=\"IWorldDelta.Accounts\"/>\n        public IImmutableDictionary<Address, IAccount> Accounts => _accounts;\n\n        /// <inheritdoc cref=\"IWorldDelta.SetAccount\"/>\n        public IWorldDelta SetAccount(Address address, IAccount account)\n            => new WorldDelta(_accounts.SetItem(address, account));\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Action/Sys/Initialize.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Collections.Immutable;\nusing System.Linq;\nusing System.Reflection;\nusing Bencodex.Types;\nusing Libplanet.Action.State;\nusing Libplanet.Crypto;\nusing Libplanet.Types.Consensus;\n\nnamespace Libplanet.Action.Sys\n{\n    /// <summary>\n    /// A system action that initializes the chain's beginning states.\n    /// </summary>\n    [ActionType(2)]\n    public sealed class Initialize : IAction\n    {\n        public Initialize(\n            ValidatorSet validatorSet,\n            IImmutableDictionary<Address, IValue> states\n        )\n        {\n            ValidatorSet = validatorSet;\n            States = states;\n        }\n\n        public Initialize()\n        {\n            // Used only for deserialization.  See also class Libplanet.Action.Sys.Registry.\n        }\n\n        public IImmutableDictionary<Address, IValue>? States\n        {\n            get;\n            private set;\n        }\n\n        public ValidatorSet? ValidatorSet { get; private set; }\n\n        public IValue TypeId =>\n            this.GetType().GetCustomAttribute<ActionTypeAttribute>()!.TypeIdentifier;\n\n        public IValue PlainValue\n        {\n            get\n            {\n                IValue encodedValidatorSet = ValidatorSet?.Bencoded ?? (IValue)default(Null);\n                IValue encodedStates = States is { } s\n                    ? new Dictionary(\n                        s.Select(\n                            kv => new KeyValuePair<IKey, IValue>(\n                                (Binary)kv.Key.Bencoded,\n                                kv.Value\n                            )\n                        )\n                    )\n                    : (IValue)default(Null);\n\n                return Dictionary.Empty\n                    .Add(\"type_id\", TypeId)\n                    .Add(\"values\", new List(encodedValidatorSet, encodedStates));\n            }\n        }\n\n        public IWorld Execute(IActionContext context)\n        {\n            IWorld world = context.PreviousState;\n\n            if (context.BlockIndex != 0)\n            {\n                throw new InvalidOperationException(\n                    $\"{nameof(Initialize)} action can be executed only genesis block.\"\n                );\n            }\n\n            if (ValidatorSet is { } vs)\n            {\n                var validatorSet = world.GetValidatorSet();\n                foreach (Validator v in vs.Validators)\n                {\n                    validatorSet = validatorSet.Update(v);\n                }\n\n                world = world.SetValidatorSet(validatorSet);\n            }\n\n            IAccount legacyAccount = world.GetAccount(ReservedAddresses.LegacyAccount);\n\n            if (States is { } s)\n            {\n                foreach (KeyValuePair<Address, IValue> kv in s)\n                {\n                    legacyAccount = legacyAccount.SetState(kv.Key, kv.Value);\n                }\n            }\n\n            world = world.SetAccount(ReservedAddresses.LegacyAccount, legacyAccount);\n            return world;\n        }\n\n        public void LoadPlainValue(IValue plainValue)\n        {\n            if (!(plainValue is Dictionary dict))\n            {\n                throw new ArgumentException(\n                    $\"Given {nameof(plainValue)} must be a {nameof(Dictionary)}: \" +\n                    $\"{plainValue.GetType()}\",\n                    nameof(plainValue));\n            }\n\n            if (!dict.TryGetValue((Text)\"type_id\", out IValue typeId))\n            {\n                throw new ArgumentException(\n                    $\"Given {nameof(plainValue)} is missing type id: {plainValue}\",\n                    nameof(plainValue));\n            }\n\n            if (!typeId.Equals(TypeId))\n            {\n                throw new ArgumentException(\n                    $\"Given {nameof(plainValue)} has invalid type id: {plainValue}\",\n                    nameof(plainValue));\n            }\n\n            if (!dict.TryGetValue((Text)\"values\", out IValue values))\n            {\n                throw new ArgumentException(\n                    $\"Given {nameof(plainValue)} is missing values: {plainValue}\",\n                    nameof(plainValue));\n            }\n\n            if (!(values is List valuesList))\n            {\n                throw new ArgumentException(\n                    $\"Given {nameof(plainValue)} has invalid values: {plainValue}\",\n                    nameof(plainValue));\n            }\n\n            ValidatorSet = new ValidatorSet((List)valuesList[0]);\n            States = ((Dictionary)valuesList[1])\n                .Select(kv => new KeyValuePair<Address, IValue>(\n                    new Address(kv.Key), kv.Value))\n                .ToImmutableDictionary();\n        }\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Action/Sys/Registry.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Reflection;\nusing Bencodex.Types;\n\nnamespace Libplanet.Action.Sys\n{\n    public static class Registry\n    {\n        public static readonly Dictionary<IValue, Type> Types;\n\n        static Registry()\n        {\n            var assembly = Assembly.GetExecutingAssembly();\n            Types = assembly\n                .GetTypes()\n                .Where(type => type.Namespace == typeof(Registry).Namespace)\n                .Where(type => type.GetCustomAttribute<ActionTypeAttribute>() is { })\n                .ToDictionary(\n                    type => type.GetCustomAttribute<ActionTypeAttribute>()!.TypeIdentifier,\n                    type => type);\n        }\n\n        public static IAction Deserialize(IValue serialized)\n        {\n            if (!(serialized is Dictionary dict))\n            {\n                throw new ArgumentException(\n                    $\"Given {nameof(serialized)} must be a {nameof(Dictionary)}: \" +\n                    $\"{serialized.GetType()}\",\n                    nameof(serialized));\n            }\n\n            if (!dict.TryGetValue((Text)\"type_id\", out IValue typeIdValue))\n            {\n                throw new ArgumentException(\n                    $\"No type_id field found: {serialized}\", nameof(serialized));\n            }\n\n            if (!dict.TryGetValue((Text)\"values\", out IValue values))\n            {\n                throw new ArgumentException(\n                    $\"No values field found: {serialized}\", nameof(serialized));\n            }\n\n            try\n            {\n                IAction action = Instantiate(typeIdValue);\n                action.LoadPlainValue(dict);\n                return action;\n            }\n            catch (Exception e)\n            {\n                throw new ArgumentException(\n                    $\"Failed to deserialize to a system action: {serialized}\",\n                    nameof(serialized),\n                    e);\n            }\n        }\n\n        public static bool IsSystemAction(IAction action) => Types.ContainsValue(action.GetType());\n\n        public static bool IsSystemAction(IValue value) =>\n            value is Dictionary dict &&\n            dict.TryGetValue(new Text(\"type_id\"), out IValue typeId) &&\n            Types.ContainsKey(typeId);\n\n        private static IAction Instantiate(IValue typeId) =>\n            (IAction)(Activator.CreateInstance(Types[typeId]) ??\n                throw new ArgumentException(\n                    $\"Failed to create an instance for given type id: {typeId}\"));\n\n        private static IValue? GetTypeId(IAction action) =>\n            Types.FirstOrDefault(x => x.Value == action.GetType()).Key;\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Action/Sys/SysActionJsonConverter.cs",
    "content": "using System;\nusing System.Text.Json;\nusing System.Text.Json.Serialization;\nusing Bencodex.Json;\nusing Bencodex.Types;\n\nnamespace Libplanet.Action.Sys\n{\n    internal sealed class SysActionJsonConverter : JsonConverter<IAction>\n    {\n        private static readonly BencodexJsonConverter BencodexJsonConverter\n            = new BencodexJsonConverter();\n\n        public override bool CanConvert(Type typeToConvert) =>\n            typeof(IAction).IsAssignableFrom(typeToConvert);\n\n        public override IAction? Read(\n            ref Utf8JsonReader reader,\n            Type typeToConvert,\n            JsonSerializerOptions options\n        )\n        {\n            IValue? serialized = BencodexJsonConverter.Read(ref reader, typeToConvert, options);\n            if (serialized is Bencodex.Types.Dictionary dict)\n            {\n                return Registry.Deserialize(dict);\n            }\n\n            throw new JsonException(\"Serialized action must be a Bencodex dictionary.\");\n        }\n\n        public override void Write(\n            Utf8JsonWriter writer,\n            IAction value,\n            JsonSerializerOptions options\n        )\n        {\n            BencodexJsonConverter.Write(writer, value.PlainValue, options);\n        }\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Action/UnexpectedlyTerminatedActionException.cs",
    "content": "using System;\nusing System.Security.Cryptography;\nusing Libplanet.Common;\nusing Libplanet.Types.Blocks;\nusing Libplanet.Types.Tx;\n\nnamespace Libplanet.Action\n{\n    /// <summary>\n    /// The exception that is thrown during an <see cref=\"IAction\"/> is being evaluated.\n    /// <para>The actual exception that the <see cref=\"Action\"/> threw\n    /// is stored in the <see cref=\"Exception.InnerException\"/> property.</para>\n    /// </summary>\n    public sealed class UnexpectedlyTerminatedActionException : Exception\n    {\n        /// <summary>\n        /// Creates a new <see cref=\"UnexpectedlyTerminatedActionException\"/> object.\n        /// </summary>\n        /// <param name=\"message\">Specifies a <see cref=\"Exception.Message\"/>.</param>\n        /// <param name=\"preEvaluationHash\">The <see cref=\"Block.PreEvaluationHash\"/> of the\n        /// <see cref=\"Block\"/> that <paramref name=\"action\"/> belongs to.</param>\n        /// <param name=\"blockIndex\">The <see cref=\"Block.Index\"/> of the <see cref=\"Block\"/>\n        /// that <paramref name=\"action\"/> belongs to.</param>\n        /// <param name=\"txid\">The <see cref=\"Transaction.Id\"/> of\n        /// the <see cref=\"Transaction\"/> that <paramref name=\"action\"/> belongs to.\n        /// This can be <see langword=\"null\"/> if <paramref name=\"action\"/> is\n        /// a <see cref=\"IBlockPolicy.BlockAction\"/>.\n        /// </param>\n        /// <param name=\"action\">The <see cref=\"IAction\"/> object which threw an exception.</param>\n        /// <param name=\"previousStateRootHash\">The <see cref=\"ITrie.Hash\"/> of states until\n        /// previous action execution.  This can be <see langword=\"null\"/> if the chain which\n        /// executed the action, was not using <see cref=\"TrieStateStore\"/>.</param>\n        /// <param name=\"innerException\">The actual exception that the <see cref=\"Action\"/> threw.\n        /// </param>\n        public UnexpectedlyTerminatedActionException(\n            string message,\n            HashDigest<SHA256> preEvaluationHash,\n            long blockIndex,\n            TxId? txid,\n            HashDigest<SHA256>? previousStateRootHash,\n            IAction action,\n            Exception innerException\n        )\n            : base(message, innerException)\n        {\n            PreEvaluationHash = preEvaluationHash;\n            BlockIndex = blockIndex;\n            TxId = txid;\n            PreviousStateRootHash = previousStateRootHash;\n            Action = action;\n        }\n\n        /// <summary>\n        /// The <see cref=\"Block.PreEvaluationHash\"/> of the <see cref=\"Block\"/> that\n        /// <see cref=\"Action\"/> belongs to.\n        /// </summary>\n        public HashDigest<SHA256> PreEvaluationHash { get; }\n\n        /// <summary>\n        /// The <see cref=\"Block.Index\"/> of the <see cref=\"Block\"/> that <see cref=\"Action\"/>\n        /// belongs to.\n        /// </summary>\n        public long BlockIndex { get; }\n\n        /// <summary>\n        /// The <see cref=\"Transaction.Id\"/> of the <see cref=\"Transaction\"/> that\n        /// <see cref=\"Action\"/> belongs to.\n        /// This can be <see langword=\"null\"/>\n        /// if <see cref=\"Action\"/> is a <see cref=\"IBlockPolicy.BlockAction\"/>.\n        /// </summary>\n        public TxId? TxId { get; }\n\n        /// <summary>\n        /// The <see cref=\"IAction\"/> object which threw an exception.\n        /// </summary>\n        public IAction Action { get; }\n\n        public HashDigest<SHA256>? PreviousStateRootHash { get; }\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Common/ArrayEqualityComparer.cs",
    "content": "using System;\nusing System.Collections.Generic;\n\nnamespace Libplanet.Common\n{\n    /// <summary>\n    /// An <see cref=\"IEqualityComparer{T}\"/> implementation to compare two arrays of the same\n    /// element type.  This compares the elements in the order of the array.\n    /// <para>The way to compare each element can be customized by specifying\n    /// the <see cref=\"ElementComparer\"/>.</para>\n    /// </summary>\n    /// <typeparam name=\"T\">The element type of the array.</typeparam>\n    public class ArrayEqualityComparer<T> : IEqualityComparer<T[]>\n        where T : IEquatable<T>\n    {\n        /// <summary>\n        /// Creates a new instance of <see cref=\"ArrayEqualityComparer{T}\"/>.\n        /// </summary>\n        /// <param name=\"elementComparer\">Optionally customize the way to compare each element.\n        /// </param>\n        public ArrayEqualityComparer(IEqualityComparer<T>? elementComparer = null)\n        {\n            ElementComparer = elementComparer;\n        }\n\n        /// <summary>\n        /// Optionally customizes the way to compare each element.\n        /// </summary>\n        public IEqualityComparer<T>? ElementComparer { get; }\n\n        /// <inheritdoc cref=\"IEqualityComparer{T}.Equals(T, T)\"/>\n        public bool Equals(T[]? x, T[]? y)\n        {\n            if (x is null && y is null)\n            {\n                return true;\n            }\n            else if (x is null || y is null)\n            {\n                return false;\n            }\n            else if (x.Length != y.Length)\n            {\n                return false;\n            }\n\n            if (ElementComparer is { } comparer)\n            {\n                for (long i = 0L; i < x.LongLength; i++)\n                {\n                    if (!comparer.Equals(x[i], y[i]))\n                    {\n                        return false;\n                    }\n                }\n            }\n            else\n            {\n                for (long i = 0L; i < x.LongLength; i++)\n                {\n                    if (!x[i].Equals(y[i]))\n                    {\n                        return false;\n                    }\n                }\n            }\n\n            return true;\n        }\n\n        /// <inheritdoc cref=\"IEqualityComparer{T}.GetHashCode(T)\"/>\n        public int GetHashCode(T[]? obj)\n        {\n            if (obj is null)\n            {\n                return 0;\n            }\n\n            int hash = 17;\n            if (ElementComparer is { } comparer)\n            {\n                foreach (T el in obj)\n                {\n                    hash = unchecked(hash * 31 + comparer.GetHashCode(el));\n                }\n            }\n            else\n            {\n                foreach (T el in obj)\n                {\n                    hash = unchecked(hash * 31 + el.GetHashCode());\n                }\n            }\n\n            return hash;\n        }\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Common/ByteArrayExtensions.cs",
    "content": "using System;\nusing System.Diagnostics.Contracts;\n\nnamespace Libplanet.Common\n{\n    /// <summary>\n    /// This extension class enables some convenient methods to deal with byte array.\n    /// </summary>\n    public static class ByteArrayExtensions\n    {\n        /// <summary>\n        /// Determines whether the beginning of this byte array instance matches a specified string.\n        /// </summary>\n        /// <param name=\"bytes\">A byte array to check.</param>\n        /// <param name=\"prefix\">The prefix byte array to compare.</param>\n        /// <returns>\n        /// true if <paramref name=\"prefix\"/> matches the beginning of <paramref name=\"bytes\"/>;\n        /// otherwise, false.\n        /// </returns>\n        /// <exception cref=\"ArgumentNullException\">\n        /// <paramref name=\"bytes\"/> or <paramref name=\"prefix\"/> is null.\n        /// </exception>\n        [Pure]\n        public static bool StartsWith(this byte[]? bytes, byte[]? prefix)\n        {\n            if (bytes is null)\n            {\n                throw new ArgumentNullException(nameof(bytes));\n            }\n\n            if (prefix is null)\n            {\n                throw new ArgumentNullException(nameof(prefix));\n            }\n\n            if (prefix.Length > bytes.Length)\n            {\n                return false;\n            }\n\n            for (int i = 0, j = 0; i < bytes.Length && j < prefix.Length; i++, j++)\n            {\n                if (bytes[i] != prefix[j])\n                {\n                    return false;\n                }\n            }\n\n            return true;\n        }\n\n        [Pure]\n        public static int IndexOf(this byte[] bytes, byte[] sub)\n        {\n            // TODO: Make this method public and write the docs.\n            if (bytes.Length < 1)\n            {\n                return sub.Length > 0 ? -1 : 0;\n            }\n            else if (bytes.Length < sub.Length)\n            {\n                return -1;\n            }\n\n            // TODO: We need to optimize this...\n            for (int i = 0; i < bytes.Length; i++)\n            {\n                bool found = true;\n                for (int j = 0; j < sub.Length; j++)\n                {\n                    if (bytes[i + j] != sub[j])\n                    {\n                        found = false;\n                        break;\n                    }\n                }\n\n                if (found)\n                {\n                    return i;\n                }\n            }\n\n            return -1;\n        }\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Common/ByteUtil.cs",
    "content": "using System;\n#if !NETSTANDARD2_0\nusing System.Buffers;\n#endif\nusing System.Collections.Generic;\nusing System.Collections.Immutable;\nusing System.Diagnostics.Contracts;\nusing System.Globalization;\nusing System.Linq;\nusing System.Numerics;\nusing System.Runtime.CompilerServices;\n\nnamespace Libplanet.Common\n{\n    /// <summary>\n    /// Utility methods to deal with <see cref=\"byte\"/> arrays.\n    /// </summary>\n    public static class ByteUtil\n    {\n        private static readonly char[] _hexCharLookup =\n        {\n            '0', '1', '2', '3', '4', '5', '6', '7',\n            '8', '9', 'a', 'b', 'c', 'd', 'e', 'f',\n        };\n\n        /// <summary>\n        /// Converts a hexadecimal string to a mutable <see cref=\"byte\"/> array.\n        /// </summary>\n        /// <param name=\"hex\">A <see cref=\"string\"/> which encodes\n        /// <see cref=\"byte\"/>s in hexadecimal.  Its length must be zero or\n        /// an even number.  It must not be <see langword=\"null\"/>.</param>\n        /// <returns>A <see cref=\"byte\"/> array that the given\n        /// <paramref name=\"hex\"/> string represented in hexadecimal.\n        /// It lengthens the half of the given <paramref name=\"hex\"/> string.\n        /// </returns>\n        /// <exception cref=\"ArgumentOutOfRangeException\">Thrown when the length\n        /// of the given <paramref name=\"hex\"/> string is an odd number.\n        /// </exception>\n        /// <exception cref=\"FormatException\">Thrown when the given\n        /// <paramref name=\"hex\"/> string is not a valid hexadecimal string.\n        /// </exception>\n        /// <seealso cref=\"ParseHexToImmutable(string)\"/>\n        /// <seealso cref=\"Hex(byte[])\"/>\n        [Pure]\n        public static byte[] ParseHex(string hex)\n        {\n            if (hex.Length % 2 > 0)\n            {\n                throw new ArgumentOutOfRangeException(\n                    nameof(hex),\n                    \"A length of a hexadecimal string must be an even number.\"\n                );\n            }\n\n            var bytes = new byte[hex.Length / 2];\n            for (var i = 0; i < hex.Length / 2; i++)\n            {\n                bytes[i] = byte.Parse(\n                    hex.Substring(i * 2, 2), NumberStyles.HexNumber, CultureInfo.InvariantCulture);\n            }\n\n            return bytes;\n        }\n\n        /// <summary>\n        /// Converts a hexadecimal string to an immutable <see cref=\"byte\"/> array.\n        /// </summary>\n        /// <param name=\"hex\">A <see cref=\"string\"/> which encodes <see cref=\"byte\"/>s in\n        /// hexadecimal.  Its length must be zero or an even number.  It must not be\n        /// <see langword=\"null\"/>.</param>\n        /// <returns>A <see cref=\"byte\"/> array that the given <paramref name=\"hex\"/> string\n        /// represented in hexadecimal.</returns>\n        /// <exception cref=\"ArgumentNullException\">Thrown when the given <paramref name=\"hex\"/>\n        /// string is <see langword=\"null\"/>.</exception>\n        /// <exception cref=\"ArgumentOutOfRangeException\">Thrown when the length of the given\n        /// <paramref name=\"hex\"/> string is an odd number.</exception>\n        /// <exception cref=\"FormatException\">Thrown when the given <paramref name=\"hex\"/> string\n        /// is not a valid hexadecimal string.</exception>\n        /// <seealso cref=\"ParseHex(string)\"/>\n        /// <seealso cref=\"Hex(in ImmutableArray{byte})\"/>\n        [Pure]\n        public static ImmutableArray<byte> ParseHexToImmutable(string hex)\n        {\n            byte[] bytes = ParseHex(hex);\n            ImmutableArray<byte> movedImmutableArray =\n                Unsafe.As<byte[], ImmutableArray<byte>>(ref bytes);\n            return movedImmutableArray;\n        }\n\n        /// <summary>\n        /// Renders a hexadecimal string in lowercase from a <see cref=\"byte\"/> array.\n        /// </summary>\n        /// <param name=\"bytes\">A <see cref=\"byte\"/> array to renders\n        /// the corresponding hexadecimal string.\n        /// </param>\n        /// <returns>A hexadecimal string which encodes the given\n        /// <paramref name=\"bytes\"/>.</returns>\n        /// <seealso cref=\"Hex(in ImmutableArray{byte})\"/>\n        /// <seealso cref=\"ParseHex(string)\"/>\n        [Pure]\n        public static string Hex(byte[] bytes)\n        {\n#if NETSTANDARD2_0\n            char[] chars = new char[bytes.Length * 2];\n            for (int i = 0; i < bytes.Length; i++)\n            {\n                chars[i * 2] = _hexCharLookup[bytes[i] >> 4];\n                chars[i * 2 + 1] = _hexCharLookup[bytes[i] & 0xf];\n            }\n\n            return new string(chars);\n#else\n            int length = bytes.Length * 2;\n            char[] chars = ArrayPool<char>.Shared.Rent(length);\n            for (int i = 0; i < bytes.Length; i++)\n            {\n                chars[i * 2] = _hexCharLookup[bytes[i] >> 4];\n                chars[i * 2 + 1] = _hexCharLookup[bytes[i] & 0xf];\n            }\n\n            string result = new string(chars, 0, length);\n            ArrayPool<char>.Shared.Return(chars);\n            return result;\n#endif\n        }\n\n        /// <summary>\n        /// Renders a hexadecimal string in lowercase from a <see cref=\"byte\"/> array.\n        /// </summary>\n        /// <param name=\"bytes\">A <see cref=\"byte\"/> array to renders\n        /// the corresponding hexadecimal string.\n        /// </param>\n        /// <returns>A hexadecimal string which encodes the given\n        /// <paramref name=\"bytes\"/>.</returns>\n        /// <seealso cref=\"Hex(byte[])\"/>\n        /// <seealso cref=\"ParseHexToImmutable(string)\"/>\n        [Pure]\n        public static string Hex(in ImmutableArray<byte> bytes) =>\n            Hex(bytes.IsDefaultOrEmpty ? Array.Empty<byte>() : bytes.ToArray());\n\n        /// <summary>\n        /// Calculates a deterministic hash code from a given\n        /// <paramref name=\"bytes\"/>.  It is mostly used to implement\n        /// <see cref=\"object.GetHashCode()\"/> method.\n        /// </summary>\n        /// <param name=\"bytes\">A <see cref=\"byte\"/> array, which completely\n        /// determines (or encodes) an object, to calculate a hash code.</param>\n        /// <returns>A hash code determined from the given\n        /// <paramref name=\"bytes\"/>.  For equivalent <paramref name=\"bytes\"/>,\n        /// the same hash code is returned.  It must not be <see langword=\"null\"/>.\n        /// </returns>\n        /// <exception cref=\"ArgumentNullException\">Thrown when the given\n        /// <paramref name=\"bytes\"/> is <see langword=\"null\"/>.</exception>\n        [Pure]\n        public static int CalculateHashCode(byte[] bytes)\n        {\n            if (bytes == null)\n            {\n                throw new ArgumentNullException(nameof(bytes));\n            }\n\n            int code = 0;\n            unchecked\n            {\n                foreach (byte b in bytes)\n                {\n                    code = (code * 397) ^ b.GetHashCode();\n                }\n            }\n\n            return code;\n        }\n\n        /// <summary>\n        /// Timing safe comparison of two byte arrays.\n        /// </summary>\n        /// <remarks>In case of two byte arrays do not have the same length, it tries to keep\n        /// the timing dependent on the length of the shorter one.</remarks>\n        /// <param name=\"left\">A byte array.</param>\n        /// <param name=\"right\">Another byte array.</param>\n        /// <returns><see langword=\"true\"/> iff two byte arrays have the exactly same contents.\n        /// </returns>\n        [Pure]\n        public static bool TimingSafelyCompare(IReadOnlyList<byte> left, IReadOnlyList<byte> right)\n        {\n            bool differ = left.Count != right.Count;\n            for (int i = 0, len = Math.Min(left.Count, right.Count); i < len; i++)\n            {\n                differ = differ || (left[i] ^ right[i]) != 0;\n            }\n\n            return !differ;\n        }\n\n        /// <summary>\n        /// Tests if a hash digest is less than the target computed for the given\n        /// <paramref name=\"difficulty\"/>).\n        /// </summary>\n        /// <param name=\"hashDigest\">A hash digest to test.</param>\n        /// <param name=\"difficulty\">The difficulty to compute target number.</param>\n        /// <returns><see langword=\"true\"/> only if a digest is less than the target computed for\n        /// the given <paramref name=\"difficulty\"/>).  If <paramref name=\"difficulty\"/> is <c>0</c>\n        /// it always returns <see langword=\"true\"/>.</returns>\n        [Pure]\n        public static bool Satisfies(IReadOnlyList<byte> hashDigest, long difficulty)\n        {\n            if (difficulty == 0)\n            {\n                return true;\n            }\n            else if (!hashDigest.Any())\n            {\n                return false;\n            }\n\n            var maxTargetBytes = new byte[hashDigest.Count + 1];\n            maxTargetBytes[hashDigest.Count] = 0x01;\n            var maxTarget = new BigInteger(maxTargetBytes);\n            BigInteger target = maxTarget / difficulty;\n\n            var digestArray = new byte[hashDigest.Count + 1];\n            int i = 0;\n            foreach (byte b in hashDigest)\n            {\n                digestArray[i++] = b;\n            }\n\n            // Append zero to convert unsigned BigInteger.  Note that BigInteger(byte[]) assumes\n            // the input bytes are in little-endian order.\n            digestArray[i] = 0;\n\n            var result = new BigInteger(digestArray);\n            return result < target;\n        }\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Common/FixedSizedQueue.cs",
    "content": "using System.Collections.Concurrent;\n\nnamespace Libplanet.Common\n{\n    /// <summary>\n    /// Equivalent to <see cref=\"ConcurrentQueue{T}\"/>, except this does not accept more than\n    /// the specified maximum size.\n    /// </summary>\n    /// <typeparam name=\"T\">Specifies the type of elements in the queue.</typeparam>\n    // This class referenced the implementation of the following.\n    // https://git.io/Jvs1f\n    public class FixedSizedQueue<T> : ConcurrentQueue<T>\n    {\n        /// <summary>\n        /// Simple object for thread synchronization.\n        /// </summary>\n        private readonly object _syncObject = new object();\n\n        /// <summary>\n        /// Creates a new instance of the <see cref=\"FixedSizedQueue{T}\"/>\n        /// with the specified <paramref name=\"size\"/>.\n        /// </summary>\n        /// <param name=\"size\">The maximum size of the <see cref=\"FixedSizedQueue{T}\"/>.</param>\n        public FixedSizedQueue(int size)\n        {\n            Size = size;\n        }\n\n        /// <summary>\n        /// Gets the fixed size of the <see cref=\"FixedSizedQueue{T}\"/>.\n        /// </summary>\n        public int Size { get; }\n\n        /// <summary>\n        /// Adds an object at the end of the <see cref=\"FixedSizedQueue{T}\"/>.\n        /// </summary>\n        /// <param name=\"obj\">The object to add at the\n        /// end of the <see cref=\"FixedSizedQueue{T}\"/>.</param>\n        public new void Enqueue(T obj)\n        {\n            // Add the object to the queue.\n            base.Enqueue(obj);\n\n            lock (_syncObject)\n            {\n                while (Count > Size)\n                {\n                    // Ensure we don't exceed the maximum size.\n                    TryDequeue(out T _);\n                }\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Common/HashDigest.cs",
    "content": "using System;\nusing System.Collections.Immutable;\nusing System.ComponentModel;\nusing System.Diagnostics.CodeAnalysis;\nusing System.Diagnostics.Contracts;\nusing System.Globalization;\nusing System.Linq;\nusing System.Linq.Expressions;\nusing System.Reflection;\n#if NETSTANDARD2_0\nusing System.Runtime.CompilerServices;\n#endif\nusing System.Security.Cryptography;\nusing System.Text.Json;\nusing System.Text.Json.Serialization;\nusing System.Threading;\nusing Bencodex;\nusing Bencodex.Types;\n\nnamespace Libplanet.Common\n{\n    /// <summary>\n    /// A value type to represent digest bytes determined by a\n    /// <see cref=\"HashAlgorithm\"/>.  For more type safety, it takes\n    /// a type parameter <typeparamref name=\"T\"/> of\n    /// <see cref=\"HashAlgorithm\"/>.\n    /// </summary>\n    /// <typeparam name=\"T\">A <see cref=\"HashAlgorithm\"/> which corresponds to\n    /// a digest.  This determines <see cref=\"Size\"/> of a digest.</typeparam>\n    /// <seealso cref=\"HashAlgorithm\"/>\n    [SuppressMessage(\n        \"ReSharper\",\n        \"StaticMemberInGenericType\",\n        Justification = \"Size & DefaultByteArray differ between HashAlgorithm types.\"\n    )]\n    [TypeConverter(typeof(HashDigestTypeConverter))]\n    [JsonConverter(typeof(HashDigestJsonConverter))]\n    public readonly struct HashDigest<T> : IEquatable<HashDigest<T>>, IBencodable\n        where T : HashAlgorithm\n    {\n        /// <summary>\n        /// The fixed, and valid <see cref=\"Array.Length\"/> of\n        /// a <see cref=\"byte\"/> array of every digest.\n        /// <para>This varies depending upon what <see cref=\"HashAlgorithm\"/> is\n        /// used for <typeparamref name=\"T\"/>.  For example, if <typeparamref\n        /// name=\"T\"/> is <see cref=\"SHA1\"/> <see cref=\"Size\"/> is <c>20</c>,\n        /// and if <see cref=\"SHA256\"/> it is <c>32</c>.</para>\n        /// </summary>\n        public static readonly int Size;\n\n        private static readonly ThreadLocal<T> Algorithm;\n        private static readonly ImmutableArray<byte> DefaultByteArray;\n\n        private readonly ImmutableArray<byte> _byteArray;\n\n        static HashDigest()\n        {\n            Type type = typeof(T);\n            MethodInfo method = type.GetMethod(nameof(HashAlgorithm.Create), Array.Empty<Type>())!;\n            MethodCallExpression methodCall = Expression.Call(null, method);\n            var exc = new InvalidCastException($\"Failed to invoke {methodCall} static method.\");\n            Func<T> instantiateAlgorithm = Expression.Lambda<Func<T>>(\n                Expression.Coalesce(methodCall, Expression.Throw(Expression.Constant(exc), type))\n            ).Compile();\n            Algorithm = new ThreadLocal<T>(instantiateAlgorithm);\n            Size = Algorithm.Value!.HashSize / 8;\n            DefaultByteArray = ImmutableArray.CreateRange(Enumerable.Repeat(default(byte), Size));\n        }\n\n        /// <summary>\n        /// Converts a <see cref=\"byte\"/> array into a\n        /// <see cref=\"HashDigest{T}\"/>.\n        /// </summary>\n        /// <param name=\"hashDigest\">A <see cref=\"byte\"/> array that encodes\n        /// a <see cref=\"HashDigest{T}\"/>.  It must not be <see langword=\"null\"/>,\n        /// and its <see cref=\"Array.Length\"/> must be the same to\n        /// <see cref=\"Size\"/>.</param>\n        /// <exception cref=\"ArgumentNullException\">Thrown when the given\n        /// <paramref name=\"hashDigest\"/> is <see langword=\"null\"/>.</exception>\n        /// <exception cref=\"ArgumentOutOfRangeException\">Thrown when the given\n        /// <paramref name=\"hashDigest\"/>'s <see cref=\"Array.Length\"/> is not\n        /// the same to the <see cref=\"Size\"/> the hash algorithm\n        /// (i.e., <typeparamref name=\"T\"/> requires.</exception>\n        public HashDigest(byte[] hashDigest)\n            : this((hashDigest ?? throw new ArgumentNullException(nameof(hashDigest)))\n                .ToImmutableArray())\n        {\n        }\n\n        /// <summary>\n        /// Converts an immutable <see cref=\"byte\"/> array into a <see cref=\"HashDigest{T}\"/>.\n        /// </summary>\n        /// <param name=\"hashDigest\">An immutable <see cref=\"byte\"/> array that encodes\n        /// a <see cref=\"HashDigest{T}\"/>.  It must not be <see langword=\"null\"/>, and its\n        /// <see cref=\"Array.Length\"/> must be the same to <see cref=\"Size\"/>.</param>\n        /// <exception cref=\"ArgumentOutOfRangeException\">Thrown when the given\n        /// <paramref name=\"hashDigest\"/>'s <see cref=\"ImmutableArray{T}.Length\"/> is not\n        /// the same to the <see cref=\"Size\"/> the hash algorithm\n        /// (i.e., <typeparamref name=\"T\"/>) requires.</exception>\n        public HashDigest(in ImmutableArray<byte> hashDigest)\n        {\n            if (hashDigest.Length != Size)\n            {\n                string message =\n                    $\"HashDigest<{typeof(T).Name}> must be {Size} bytes, \" +\n                    $\"but {hashDigest.Length} was given\";\n                throw new ArgumentOutOfRangeException(\n                    nameof(hashDigest),\n                    message\n                );\n            }\n\n            _byteArray = hashDigest;\n        }\n\n        public HashDigest(IValue bencoded)\n            : this(bencoded is Binary binary\n                ? binary\n                : throw new ArgumentException(\n                    $\"Given {nameof(bencoded)} must be of type \" +\n                    $\"{typeof(Binary)}: {bencoded.GetType()}\",\n                    nameof(bencoded)))\n        {\n        }\n\n        private HashDigest(Binary binary)\n            : this(binary.ByteArray)\n        {\n        }\n\n        /// <summary>\n        /// A bare immutable <see cref=\"byte\"/> array of the digest.\n        /// </summary>\n        /// <remarks>It is immutable.  For a mutable array, use\n        /// <see cref=\"ToByteArray()\"/> method instead.</remarks>\n        /// <seealso cref=\"ToByteArray()\"/>\n        public ImmutableArray<byte> ByteArray =>\n            _byteArray.IsDefault ? DefaultByteArray : _byteArray;\n\n        /// <inheritdoc cref=\"IBencodable.Bencoded\"/>\n        public IValue Bencoded => new Binary(ByteArray);\n\n        /// <summary>\n        /// Converts a given hexadecimal representation of a digest into\n        /// a <see cref=\"HashDigest{T}\"/> object.\n        /// <para>This is an inverse function of <see cref=\"ToString()\"/>\n        /// method.</para>\n        /// </summary>\n        /// <param name=\"hexDigest\">A hexadecimal representation of\n        /// a <see cref=\"HashDigest{T}\"/>.</param>\n        /// <returns>A corresponding <see cref=\"HashDigest{T}\"/> value.\n        /// </returns>\n        /// <exception cref=\"ArgumentNullException\">Thrown when the given\n        /// <paramref name=\"hexDigest\"/> is <see langword=\"null\"/>.</exception>\n        /// <exception cref=\"ArgumentOutOfRangeException\">Thrown when the given\n        /// <paramref name=\"hexDigest\"/>'s length is not the double of\n        /// the <see cref=\"Size\"/>, the hash algorithm\n        /// (i.e., <typeparamref name=\"T\"/> requires.</exception>\n        /// <seealso cref=\"ToString()\"/>\n        /// <seealso cref=\"HashDigestExtensions.ToHashDigest{T}(string)\"/>\n        [Pure]\n        public static HashDigest<T> FromString(string hexDigest)\n        {\n            if (hexDigest == null)\n            {\n                throw new ArgumentNullException(nameof(hexDigest));\n            }\n\n            if (hexDigest.Length != Size * 2)\n            {\n                string message =\n                    $\"HashDigest<{typeof(T).Name}> requires {Size * 2} \" +\n                    $\"hexadecimal letters, but {hexDigest.Length} was given\";\n                throw new ArgumentOutOfRangeException(\n                    nameof(hexDigest),\n                    message\n                );\n            }\n\n            return new HashDigest<T>(ByteUtil.ParseHexToImmutable(hexDigest));\n        }\n\n        /// <summary>\n        /// Computes a hash digest of the algorithm <typeparamref name=\"T\"/> from the given\n        /// <paramref name=\"input\"/> bytes.\n        /// </summary>\n        /// <param name=\"input\">The bytes to compute its hash.</param>\n        /// <returns>The hash digest derived from <paramref name=\"input\"/>.</returns>\n        [Pure]\n        public static HashDigest<T> DeriveFrom(byte[] input)\n        {\n#if NETSTANDARD2_0\n            byte[] hash = Algorithm.Value!.ComputeHash(input);\n            ImmutableArray<byte> movedImmutableArray =\n                Unsafe.As<byte[], ImmutableArray<byte>>(ref hash);\n            return new HashDigest<T>(movedImmutableArray);\n#else\n            return DeriveFrom(input.AsSpan());\n#endif\n        }\n\n        /// <summary>\n        /// Computes a hash digest of the algorithm <typeparamref name=\"T\"/> from the given\n        /// <paramref name=\"input\"/> bytes.\n        /// </summary>\n        /// <param name=\"input\">The bytes to compute its hash.</param>\n        /// <returns>The hash digest derived from <paramref name=\"input\"/>.</returns>\n        [Pure]\n        public static HashDigest<T> DeriveFrom(ImmutableArray<byte> input)\n        {\n#if NETSTANDARD2_0\n            byte[] movedArray = Unsafe.As<ImmutableArray<byte>, byte[]>(ref input);\n            return DeriveFrom(movedArray);\n#else\n            return DeriveFrom(input.AsSpan());\n#endif\n        }\n\n        /// <summary>\n        /// Computes a hash digest of the algorithm <typeparamref name=\"T\"/> from the given\n        /// <paramref name=\"input\"/> bytes.\n        /// </summary>\n        /// <param name=\"input\">The bytes to compute its hash.</param>\n        /// <returns>The hash digest derived from <paramref name=\"input\"/>.</returns>\n        [Pure]\n        public static HashDigest<T> DeriveFrom(ReadOnlySpan<byte> input)\n        {\n#if NETSTANDARD2_0\n            var array = new byte[input.Length];\n            for (int i = 0; i < input.Length; i++)\n            {\n                array[i] = input[i];\n            }\n\n            return DeriveFrom(array);\n#else\n            Span<byte> buffer = stackalloc byte[Size];\n            Algorithm.Value!.TryComputeHash(input, buffer, out _);\n            var builder = ImmutableArray.CreateBuilder<byte>(Size);\n            foreach (byte b in buffer)\n            {\n                builder.Add(b);\n            }\n\n            return new HashDigest<T>(builder.MoveToImmutable());\n#endif\n        }\n\n        /// <summary>\n        /// Gets a bare mutable <see cref=\"byte\"/> array of the digest.\n        /// </summary>\n        /// <returns>A new mutable <see cref=\"byte\"/> array of the digest.\n        /// Since a returned array is created every time the method is called,\n        /// any mutations on that array does not affect to the digest object.\n        /// </returns>\n        /// <seealso cref=\"ByteArray\"/>\n        [Pure]\n        public byte[] ToByteArray() =>\n            ByteArray.ToArray();\n\n        /// <summary>\n        /// Gets a hexadecimal representation of a digest.\n        /// <para>This is an inverse function of <see cref=\"FromString\"/>.\n        /// </para>\n        /// </summary>\n        /// <returns>A hexadecimal representation of a digest.</returns>\n        /// <seealso cref=\"FromString(string)\"/>\n        [Pure]\n        public override string ToString()\n        {\n            return ByteUtil.Hex(ToByteArray());\n        }\n\n        /// <inheritdoc cref=\"object.GetHashCode()\"/>\n        [Pure]\n        public override int GetHashCode()\n        {\n            int code = 0;\n            unchecked\n            {\n                foreach (byte b in ByteArray)\n                {\n                    code = (code * 397) ^ b.GetHashCode();\n                }\n            }\n\n            return code;\n        }\n\n        /// <inheritdoc cref=\"IEquatable{T}.Equals(T)\"/>\n        [Pure]\n        public bool Equals(HashDigest<T> other)\n        {\n            for (int i = 0; i < Size; i++)\n            {\n                if (!ByteArray[i].Equals(other.ByteArray[i]))\n                {\n                    return false;\n                }\n            }\n\n            return true;\n        }\n\n        /// <inheritdoc cref=\"object.Equals(object)\"/>\n        [Pure]\n        public override bool Equals(object? obj) =>\n            obj is IEquatable<HashDigest<T>> other && other.Equals(this);\n    }\n\n    /// <summary>\n    /// Augments types to have some shortcut methods dealing with\n    /// <see cref=\"HashDigest{T}\"/> values.\n    /// </summary>\n    public static class HashDigestExtensions\n    {\n        /// <summary>\n        /// Converts a given hexadecimal representation of a digest into\n        /// a <see cref=\"HashDigest{T}\"/> object.\n        /// <para>This is a shortcut of\n        /// <see cref=\"HashDigest{T}.FromString(string)\"/> method.</para>\n        /// <para>This is an inverse function of\n        /// <see cref=\"HashDigest{T}.ToString()\"/> method.</para>\n        /// </summary>\n        /// <param name=\"hexDigest\">A hexadecimal representation of\n        /// a <see cref=\"HashDigest{T}\"/>.</param>\n        /// <typeparam name=\"T\">A <see cref=\"HashAlgorithm\"/> which corresponds\n        /// to a digest.</typeparam>\n        /// <returns>A corresponding <see cref=\"HashDigest{T}\"/> value.\n        /// </returns>\n        /// <exception cref=\"ArgumentNullException\">Thrown when the given\n        /// <paramref name=\"hexDigest\"/> is <see langword=\"null\"/>.</exception>\n        /// <exception cref=\"ArgumentOutOfRangeException\">Thrown when the given\n        /// <paramref name=\"hexDigest\"/>'s length is not the double of\n        /// the <see cref=\"HashDigest{T}.Size\"/>, the hash algorithm\n        /// (i.e., <typeparamref name=\"T\"/> requires.</exception>\n        /// <seealso cref=\"HashDigest{T}.FromString(string)\"/>\n        /// <seealso cref=\"HashDigest{T}.ToString()\"/>\n        public static HashDigest<T> ToHashDigest<T>(this string hexDigest)\n            where T : HashAlgorithm\n        {\n            return HashDigest<T>.FromString(hexDigest);\n        }\n    }\n\n    /// <summary>\n    /// The <see cref=\"TypeConverter\"/> implementation for <see cref=\"HashDigest{T}\"/>.\n    /// </summary>\n    [SuppressMessage(\n        \"StyleCop.CSharp.MaintainabilityRules\",\n        \"SA1402:FileMayOnlyContainASingleClass\",\n        Justification = \"It's okay to have non-public classes together in a single file.\"\n    )]\n    internal class HashDigestTypeConverter : TypeConverter\n    {\n        private readonly MethodInfo _fromString;\n\n        public HashDigestTypeConverter(Type type)\n        {\n            if (!type.IsConstructedGenericType ||\n                type.GetGenericTypeDefinition() != typeof(HashDigest<>) ||\n                type.GetGenericArguments().Length != 1)\n            {\n                throw new ArgumentException(\n                    \"Only usable with a constructed HashDigest<T>.\",\n                    nameof(type));\n            }\n\n            _fromString = type.GetMethod(\n                nameof(HashDigest<SHA1>.FromString),\n                BindingFlags.Public | BindingFlags.Static,\n                Type.DefaultBinder,\n                new[] { typeof(string) },\n                null\n            ) ?? throw new MissingMethodException(\n                $\"Failed to look up the {nameof(HashDigest<SHA1>.FromString)} method\");\n        }\n\n        /// <inheritdoc cref=\"TypeConverter.CanConvertFrom(ITypeDescriptorContext?, Type)\"/>\n        public override bool CanConvertFrom(ITypeDescriptorContext? context, Type sourceType) =>\n            sourceType == typeof(string) || base.CanConvertFrom(context, sourceType);\n\n        /// <inheritdoc\n        /// cref=\"TypeConverter.ConvertFrom(ITypeDescriptorContext?, CultureInfo?, object)\"/>\n        public override object? ConvertFrom(\n            ITypeDescriptorContext? context,\n            CultureInfo? culture,\n            object value\n        )\n        {\n            if (value is string v)\n            {\n                try\n                {\n                    return _fromString.Invoke(null, new[] { v })!;\n                }\n                catch (TargetInvocationException e) when (e.InnerException is { } ie)\n                {\n                    if (ie is ArgumentOutOfRangeException || ie is FormatException)\n                    {\n                        throw new ArgumentException(ie.Message, ie);\n                    }\n\n                    throw ie;\n                }\n            }\n\n            return base.ConvertFrom(context, culture, value);\n        }\n\n        /// <inheritdoc cref=\"TypeConverter.CanConvertTo(ITypeDescriptorContext?, Type?)\"/>\n        public override bool CanConvertTo(ITypeDescriptorContext? context, Type? destinationType) =>\n            destinationType == typeof(string) || base.CanConvertTo(context, destinationType);\n\n        /// <inheritdoc\n        /// cref=\"TypeConverter.ConvertTo(ITypeDescriptorContext?, CultureInfo?, object?, Type)\"/>\n        public override object? ConvertTo(\n            ITypeDescriptorContext? context,\n            CultureInfo? culture,\n            object? value,\n            Type destinationType\n        )\n        {\n            if (value != null &&\n                destinationType == typeof(string) &&\n                value.GetType().IsConstructedGenericType &&\n                value.GetType().GetGenericTypeDefinition() == typeof(HashDigest<>))\n            {\n                return value.ToString()!;\n            }\n\n            return base.ConvertTo(context, culture, value, destinationType);\n        }\n    }\n\n    // NOTE: As JsonConverterAttribute does not take a generic type, we need to make\n    // a JsonConverter<System.Object> instead.\n    [SuppressMessage(\n        \"StyleCop.CSharp.MaintainabilityRules\",\n        \"SA1402:FileMayOnlyContainASingleClass\",\n        Justification = \"It's okay to have non-public classes together in a single file.\"\n    )]\n    internal class HashDigestJsonConverter : JsonConverter<object>\n    {\n        private Type? _queriedType;\n\n        public override bool CanConvert(Type typeToConvert)\n        {\n            if (typeToConvert.IsConstructedGenericType &&\n                typeToConvert.GetGenericTypeDefinition() == typeof(HashDigest<>))\n            {\n                _queriedType = typeToConvert;\n                return true;\n            }\n\n            _queriedType = null;\n            return false;\n        }\n\n        public override object Read(\n            ref Utf8JsonReader reader,\n            Type typeToConvert,\n            JsonSerializerOptions options\n        )\n        {\n            if (typeToConvert == typeof(object) && _queriedType is { } t)\n            {\n                typeToConvert = t;\n            }\n\n            MethodInfo fromString = typeToConvert.GetMethod(\n                \"FromString\",\n                BindingFlags.Public | BindingFlags.Static\n            )!;\n            string? hex = reader.GetString();\n            try\n            {\n                return fromString.Invoke(null, new object?[] { hex })!;\n            }\n            catch (ArgumentException e)\n            {\n                throw new JsonException(e.Message);\n            }\n        }\n\n        public override void Write(\n            Utf8JsonWriter writer,\n            object value,\n            JsonSerializerOptions options\n        ) =>\n            writer.WriteStringValue(value.ToString());\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Common/JsonConverters/BigIntegerJsonConverter.cs",
    "content": "using System;\nusing System.Buffers;\nusing System.Globalization;\nusing System.Numerics;\nusing System.Text;\nusing System.Text.Json;\nusing System.Text.Json.Serialization;\n\nnamespace Libplanet.Common.JsonConverters\n{\n    public sealed class BigIntegerJsonConverter : JsonConverter<BigInteger>\n    {\n        public override BigInteger Read(\n            ref Utf8JsonReader reader,\n            Type typeToConvert,\n            JsonSerializerOptions options)\n        {\n            if (reader.TokenType != JsonTokenType.Number)\n            {\n                throw new JsonException($\"Expected a number, not a {reader.TokenType}\");\n            }\n\n#if NETSTANDARD2_0\n            byte[] bytes;\n            if (reader.HasValueSequence)\n            {\n                bytes = reader.ValueSequence.ToArray();\n            }\n            else\n            {\n                // Don't know why, but the compiler errors out with the following message:\n                //   PC001: ReadOnlySpan<T>.ToArray() isn't supported on Linux, macOS, and Windows\n                // if I try to use ReadOnlySpan<T>.ToArray().  Here's a workaround:\n                ReadOnlySpan<byte> span = reader.ValueSpan;\n                bytes = new byte[span.Length];\n                for (int i = 0; i < span.Length; i++)\n                {\n                    bytes[i] = span[i];\n                }\n            }\n#else\n            ReadOnlySpan<byte> bytes = reader.HasValueSequence\n                ? reader.ValueSequence.ToArray()\n                : reader.ValueSpan;\n#endif\n\n            string digits = Encoding.ASCII.GetString(bytes);\n            return BigInteger.Parse(digits, NumberFormatInfo.InvariantInfo);\n        }\n\n        public override void Write(\n            Utf8JsonWriter writer,\n            BigInteger value,\n            JsonSerializerOptions options\n        ) =>\n            writer.WriteRawValue(value.ToString(NumberFormatInfo.InvariantInfo), false);\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Common/JsonConverters/ByteArrayJsonConverter.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Collections.Immutable;\nusing System.Linq;\nusing System.Text.Json;\nusing System.Text.Json.Serialization;\n\nnamespace Libplanet.Common.JsonConverters\n{\n    public sealed class ByteArrayJsonConverter : JsonConverter<IReadOnlyList<byte>?>\n    {\n        public override bool HandleNull => true;\n\n        public override bool CanConvert(Type typeToConvert) =>\n            typeToConvert == typeof(byte[]) ||\n            typeToConvert == typeof(ImmutableArray<byte>) ||\n            typeToConvert == typeof(ImmutableArray<byte>?);\n\n        public override IReadOnlyList<byte>? Read(\n            ref Utf8JsonReader reader,\n            Type typeToConvert,\n            JsonSerializerOptions options)\n        {\n            var hex = reader.GetString();\n            if (hex is null)\n            {\n                return null;\n            }\n\n            return typeToConvert == typeof(ImmutableArray<byte>)\n                ? ByteUtil.ParseHexToImmutable(hex)\n                : (IReadOnlyList<byte>?)ByteUtil.ParseHex(hex);\n        }\n\n        public override void Write(\n            Utf8JsonWriter writer,\n            IReadOnlyList<byte>? value,\n            JsonSerializerOptions options)\n        {\n            if (value is null)\n            {\n                writer.WriteNullValue();\n            }\n            else\n            {\n                writer.WriteStringValue(ByteUtil.Hex(value is byte[] a ? a : value.ToArray()));\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Common/Libplanet.Common.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <ItemGroup>\n    <PackageReference Include=\"System.Collections.Immutable\" Version=\"1.*\" />\n    <PackageReference Include=\"System.Text.Json\" Version=\"6.0.*\" />\n    <PackageReference Include=\"Bencodex\" Version=\"0.16.0\" />\n  </ItemGroup>\n\n  <ItemGroup Condition=\"'$(SkipSonar)' != 'true'\">\n    <PackageReference Remove=\"SonarAnalyzer.CSharp\" />\n  </ItemGroup>\n\n</Project>\n"
  },
  {
    "path": "src/Libplanet.Common/NameValueCollectionExtensions.cs",
    "content": "using System;\nusing System.Collections.Specialized;\nusing System.Globalization;\nusing static System.Convert;\n\nnamespace Libplanet.Common\n{\n    /// <summary>\n    /// Useful extension methods for <see cref=\"NameValueCollection\"/>.\n    /// </summary>\n    public static class NameValueCollectionExtensions\n    {\n        /// <summary>\n        /// Tries to get the text associated with the specified <paramref name=\"name\"/> as\n        /// given <see cref=\"Enum\"/> type <typeparamref name=\"T\"/> value from the specified\n        /// name-value <paramref name=\"collection\"/>.\n        /// </summary>\n        /// <param name=\"collection\">The <see cref=\"NameValueCollection\"/> that contains the entry\n        /// to find.</param>\n        /// <param name=\"name\">The <see cref=\"string\"/> key of the entry that contains the value to\n        /// find.</param>\n        /// <typeparam name=\"T\">The <see cref=\"Enum\"/> type to parse to.</typeparam>\n        /// <returns>A <typeparamref name=\"T\"/> value converted from the text value associated with\n        /// the specified key <paramref name=\"name\"/> from the <paramref name=\"collection\"/>,\n        /// if found; otherwise, <see langword=\"null\"/>.</returns>\n        /// <exception cref=\"ArgumentException\">Thrown when the value cannot be parsed to type\n        /// <typeparamref name=\"T\"/>.</exception>\n        /// <remarks>This method assumes the <paramref name=\"collection\"/> contains zero or\n        /// one entry for the specified <paramref name=\"name\"/>.</remarks>\n        public static T? GetEnum<T>(this NameValueCollection collection, string name)\n            where T : struct, Enum\n            => collection.Get(name) is { } value\n                ? (T?)(Enum.TryParse(value, out T result) ? result : throw new ArgumentException())\n                : (T?)null;\n\n        /// <summary>\n        /// Tries to get the text associated with the specified <paramref name=\"name\"/> as\n        /// given <see cref=\"Enum\"/> type <typeparamref name=\"T\"/> value from the specified\n        /// name-value <paramref name=\"collection\"/>.\n        /// </summary>\n        /// <param name=\"collection\">The <see cref=\"NameValueCollection\"/> that contains the entry\n        /// to find.</param>\n        /// <param name=\"name\">The <see cref=\"string\"/> key of the entry that contains the value to\n        /// find.</param>\n        /// <param name=\"defaultValue\">Returns this value if the specified key\n        /// <paramref name=\"name\"/> is not found in the <paramref name=\"collection\"/>, or\n        /// the associated value cannot be parsed to type <typeparamref name=\"T\"/>.</param>\n        /// <typeparam name=\"T\">The <see cref=\"Enum\"/> type to parse to.</typeparam>\n        /// <returns>A <typeparamref name=\"T\"/> value converted from the text value associated with\n        /// the specified key <paramref name=\"name\"/> from the <paramref name=\"collection\"/>,\n        /// if found; otherwise, <see langword=\"defaultValue\"/>.</returns>\n        public static T GetEnum<T>(this NameValueCollection collection, string name, T defaultValue)\n            where T : struct, Enum\n        {\n            try\n            {\n                return GetEnum<T>(collection, name) ?? defaultValue;\n            }\n            catch (ArgumentException)\n            {\n                return defaultValue;\n            }\n        }\n\n        /// <summary>\n        /// Tries to get the numeric text associated with the specified <paramref name=\"name\"/> as\n        /// an <see cref=\"int\"/> value from the specified name-value <paramref name=\"collection\"/>.\n        /// </summary>\n        /// <param name=\"collection\">The <see cref=\"NameValueCollection\"/> that contains the entry\n        /// to find.</param>\n        /// <param name=\"name\">The <see cref=\"string\"/> key of the entry that contains the value to\n        /// find.</param>\n        /// <returns>An <see cref=\"int\"/> value converted from the text value associated with\n        /// the specified key <paramref name=\"name\"/> from the <paramref name=\"collection\"/>,\n        /// if found; otherwise, <see langword=\"null\"/>.</returns>\n        /// <exception cref=\"FormatException\">Thrown when the value is not a numeric text.\n        /// </exception>\n        /// <exception cref=\"OverflowException\">Thrown when the value is outside the range of the\n        /// <see cref=\"int\"/> type.</exception>\n        /// <remarks>This method assumes the <paramref name=\"collection\"/> contains zero or\n        /// one entry for the specified <paramref name=\"name\"/>.</remarks>\n        public static int? GetInt32(this NameValueCollection collection, string name) =>\n            collection.Get(name) is { } v ? ToInt32(v, CultureInfo.InvariantCulture) : (int?)null;\n\n        /// <summary>\n        /// Tries to get the numeric text associated with the specified <paramref name=\"name\"/> as\n        /// an <see cref=\"int\"/> value from the specified name-value <paramref name=\"collection\"/>.\n        /// </summary>\n        /// <param name=\"collection\">The <see cref=\"NameValueCollection\"/> that contains the entry\n        /// to find.</param>\n        /// <param name=\"name\">The <see cref=\"string\"/> key of the entry that contains the value to\n        /// find.</param>\n        /// <param name=\"defaultValue\">Returns this value if the specified key\n        /// <paramref name=\"name\"/> is not found in the <paramref name=\"collection\"/>, or\n        /// the associated value is not a numeric text or outside the range of the <see cref=\"int\"/>\n        /// type.</param>\n        /// <returns>An <see cref=\"int\"/> value converted from the text value associated with\n        /// the specified key <paramref name=\"name\"/> from the <paramref name=\"collection\"/>,\n        /// if found; otherwise, <paramref name=\"defaultValue\"/>.</returns>\n        public static int GetInt32(\n            this NameValueCollection collection,\n            string name,\n            int defaultValue)\n        {\n            try\n            {\n                return GetInt32(collection, name) ?? defaultValue;\n            }\n            catch (FormatException)\n            {\n                return defaultValue;\n            }\n            catch (OverflowException)\n            {\n                return defaultValue;\n            }\n        }\n\n        /// <summary>\n        /// Tries to get the numeric text associated with the specified <paramref name=\"name\"/> as\n        /// a <see cref=\"ulong\"/> value from the specified name-value <paramref name=\"collection\"/>.\n        /// </summary>\n        /// <param name=\"collection\">The <see cref=\"NameValueCollection\"/> that contains the entry\n        /// to find.</param>\n        /// <param name=\"name\">The <see cref=\"string\"/> key of the entry that contains the value to\n        /// find.</param>\n        /// <returns>A <see cref=\"ulong\"/> value converted from the text value associated with\n        /// the specified key <paramref name=\"name\"/> from the <paramref name=\"collection\"/>,\n        /// if found; otherwise, <see langword=\"null\"/>.</returns>\n        /// <exception cref=\"FormatException\">Thrown when the value is not a numeric text.\n        /// </exception>\n        /// <exception cref=\"OverflowException\">Thrown when the value is outside the range of the\n        /// <see cref=\"ulong\"/> type.</exception>\n        /// <remarks>This method assumes the <paramref name=\"collection\"/> contains zero or\n        /// one entry for the specified <paramref name=\"name\"/>.</remarks>\n        public static ulong? GetUInt64(this NameValueCollection collection, string name) =>\n            collection.Get(name) is { } v\n                ? ToUInt64(v, CultureInfo.InvariantCulture)\n                : (ulong?)null;\n\n        /// <summary>\n        /// Tries to get the numeric text associated with the specified <paramref name=\"name\"/> as\n        /// a <see cref=\"ulong\"/> value from the specified name-value <paramref name=\"collection\"/>.\n        /// </summary>\n        /// <param name=\"collection\">The <see cref=\"NameValueCollection\"/> that contains the entry\n        /// to find.</param>\n        /// <param name=\"name\">The <see cref=\"string\"/> key of the entry that contains the value to\n        /// find.</param>\n        /// <param name=\"defaultValue\">Returns this value if the specified key\n        /// <paramref name=\"name\"/> is not found in the <paramref name=\"collection\"/>, or\n        /// the associated value is not a numeric text or outside the range of\n        /// the <see cref=\"ulong\"/> type.</param>\n        /// <returns>An <see cref=\"int\"/> value converted from the text value associated with\n        /// the specified key <paramref name=\"name\"/> from the <paramref name=\"collection\"/>,\n        /// if found; otherwise, <paramref name=\"defaultValue\"/>.</returns>\n        public static ulong GetUInt64(\n            this NameValueCollection collection,\n            string name,\n            ulong defaultValue)\n        {\n            try\n            {\n                return GetUInt64(collection, name) ?? defaultValue;\n            }\n            catch (FormatException)\n            {\n                return defaultValue;\n            }\n            catch (OverflowException)\n            {\n                return defaultValue;\n            }\n        }\n\n        /// <summary>\n        /// Tries to get the boolean text associated with the specified <paramref name=\"name\"/> as\n        /// a <see cref=\"bool\"/> value from the specified name-value <paramref name=\"collection\"/>.\n        /// <para>Supported keywords are: <see langword=\"true\"/>, <see langword=\"false\"/>,\n        /// <c>yes</c>, <c>no</c>, <c>on</c>, <c>off</c>, <c>t</c>, <c>f</c>, <c>y</c>, <c>n</c>,\n        /// <c>1</c>, <c>0</c> (all case-insensitive).</para>\n        /// </summary>\n        /// <param name=\"collection\">The <see cref=\"NameValueCollection\"/> that contains the entry\n        /// to find.</param>\n        /// <param name=\"name\">The <see cref=\"string\"/> key of the entry that contains the value to\n        /// find.</param>\n        /// <param name=\"defaultValue\">Returns this value if the specified key\n        /// <paramref name=\"name\"/> is not found in the <paramref name=\"collection\"/>, or\n        /// the associated value is not a valid boolean text.  Configured as <see langword=\"false\"/>\n        /// by default.</param>\n        /// <returns>A <see cref=\"bool\"/> value converted from the text value associated with\n        /// the specified key <paramref name=\"name\"/> from the <paramref name=\"collection\"/>,\n        /// if found; otherwise, <paramref name=\"defaultValue\"/>.</returns>\n        public static bool GetBoolean(\n            this NameValueCollection collection,\n            string name,\n            bool defaultValue = false)\n        {\n            return collection.Get(name)?.ToLowerInvariant() switch\n            {\n                \"0\" => false,\n                \"1\" => true,\n                \"n\" => false,\n                \"y\" => true,\n                \"no\" => false,\n                \"yes\" => true,\n                \"f\" => false,\n                \"t\" => true,\n                \"false\" => false,\n                \"true\" => true,\n                \"off\" => false,\n                \"on\" => true,\n                _ => defaultValue,\n            };\n        }\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Common/TimeSpanExtensions.cs",
    "content": "using System;\n\nnamespace Libplanet.Common\n{\n    public static class TimeSpanExtensions\n    {\n        public static TimeSpan Multiply(this TimeSpan timeSpan, double factor)\n        {\n            // This code is borrowed from the official .NET implementation:\n            //   https://bit.ly/38zW6eq\n            // We can remove these copy-and-pasted lines in the future when Libplanet drops\n            // .NET Standard 2.0 support and becomes to support .NET Standard 2.1 or higher.\n            if (double.IsNaN(factor))\n            {\n                const string Arg_CannotBeNaN =\n                    nameof(TimeSpan) + \" does not accept floating point Not-a-Number values.\";\n                throw new ArgumentException(Arg_CannotBeNaN, nameof(factor));\n            }\n\n            // Rounding to the nearest tick is as close to the result we would have with unlimited\n            // precision as possible, and so likely to have the least potential to surprise.\n            double ticks = Math.Round(timeSpan.Ticks * factor);\n            return IntervalFromDoubleTicks(ticks);\n        }\n\n        public static TimeSpan Divide(this TimeSpan timeSpan, double divisor)\n        {\n            // This code is borrowed from the official .NET implementation:\n            //   https://bit.ly/3wtFmxA\n            // We can remove these copy-and-pasted lines in the future when Libplanet drops\n            // .NET Standard 2.0 support and becomes to support .NET Standard 2.1 or higher.\n            if (double.IsNaN(divisor))\n            {\n                const string Arg_CannotBeNaN =\n                    nameof(TimeSpan) + \" does not accept floating point Not-a-Number values.\";\n                throw new ArgumentException(Arg_CannotBeNaN, nameof(divisor));\n            }\n\n            double ticks = Math.Round(timeSpan.Ticks / divisor);\n            return IntervalFromDoubleTicks(ticks);\n        }\n\n        private static TimeSpan IntervalFromDoubleTicks(double ticks)\n        {\n            // This code is borrowed from the official .NET implementation:\n            //   https://bit.ly/3FLAvMx\n            // We can remove these copy-and-pasted lines in the future when Libplanet drops\n            // .NET Standard 2.0 support and becomes to support .NET Standard 2.1 or higher.\n            if (ticks > long.MaxValue || ticks < long.MinValue || double.IsNaN(ticks))\n            {\n                const string Overflow_TimeSpanTooLong =\n                    nameof(TimeSpan) + \" overflowed because the duration is too long.\";\n                throw new OverflowException(Overflow_TimeSpanTooLong);\n            }\n\n            return ticks.Equals(long.MaxValue)\n                ? TimeSpan.MaxValue\n                : new TimeSpan((long)ticks);\n        }\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Crypto/Address.cs",
    "content": "using System;\nusing System.Collections.Immutable;\nusing System.ComponentModel;\nusing System.Diagnostics.CodeAnalysis;\nusing System.Diagnostics.Contracts;\nusing System.Globalization;\nusing System.Linq;\nusing System.Text;\nusing System.Text.Json;\nusing System.Text.Json.Serialization;\nusing Bencodex;\nusing Bencodex.Types;\nusing Libplanet.Common;\nusing Org.BouncyCastle.Crypto.Digests;\n\nnamespace Libplanet.Crypto\n{\n    /// <summary>\n    /// An identifier of 20 bytes (or 40 letters in hexadecimal, commonly with\n    /// a prefix <c>0x</c>) that refers to a unique account.\n    /// <para>It is derived from the corresponding <see cref=\"PublicKey\"/>\n    /// of an account, but as a derivation loses information, it is always\n    /// unidirectional.</para>\n    /// <para>The address derivation from a public key is as follows:</para>\n    /// <list type=\"number\">\n    /// <item><description>Calculates the Keccak-256, which is a previous form\n    /// of SHA-3 before NIST standardized it and does not follow\n    /// <a href=\"http://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.202.pdf\"\n    /// >FIPS-202</a>, of the corresponding <see cref=\"PublicKey\"/>.\n    /// </description></item>\n    /// <item><description>Takes only the last 20 bytes of the calculated\n    /// Keccak-256 hash.</description></item>\n    /// <item><description>When the address needs to be shown to end users,\n    /// displays these 20 bytes in hexadecimal, with a prefix <c>0x</c>.\n    /// </description></item>\n    /// </list>\n    /// <para>Since the scheme of the address derivation and the <see\n    /// cref=\"PrivateKey\"/>/<see cref=\"PublicKey\"/> is the same to\n    /// <a href=\"https://www.ethereum.org/\">Ethereum</a>, Ethereum addresses\n    /// can be used by Libplanet-backed games/apps too.</para>\n    /// </summary>\n    /// <remarks>Every <see cref=\"Address\"/> value is immutable.</remarks>\n    /// <seealso cref=\"PublicKey\"/>\n    [TypeConverter(typeof(AddressTypeConverter))]\n    [JsonConverter(typeof(AddressJsonConverter))]\n    public readonly struct Address\n        : IEquatable<Address>, IComparable<Address>, IComparable, IBencodable\n    {\n        /// <summary>\n        /// The <see cref=\"byte\"/>s size that each <see cref=\"Address\"/> takes.\n        /// <para>It is 20 <see cref=\"byte\"/>s.</para>\n        /// </summary>\n        public const int Size = 20;\n\n        private static readonly Codec _codec = new Codec();\n\n        private static readonly ImmutableArray<byte> _defaultByteArray =\n            ImmutableArray.Create<byte>(new byte[Size]);\n\n        private readonly ImmutableArray<byte> _byteArray;\n\n        /// <summary>\n        /// Creates an <see cref=\"Address\"/> instance from the given immutable <see\n        /// cref=\"byte\"/> array (i.e., <paramref name=\"address\"/>).\n        /// </summary>\n        /// <param name=\"address\">An immutable array of 20 <see cref=\"byte\"/>s which\n        /// represents an <see cref=\"Address\"/>.</param>\n        /// <exception cref=\"ArgumentException\">Thrown when the given <paramref\n        /// name=\"address\"/> array did not lengthen 20 bytes.</exception>\n        /// <remarks>A valid <see cref=\"byte\"/> array which represents an\n        /// <see cref=\"Address\"/> can be gotten using <see cref=\"ToByteArray()\"\n        /// /> method.</remarks>\n        /// <seealso cref=\"ByteArray\"/>\n        public Address(in ImmutableArray<byte> address)\n        {\n            if (address.Length != Size)\n            {\n                throw new ArgumentException(\n                    $\"Given {nameof(address)} must be 20 bytes\", nameof(address));\n            }\n\n            _byteArray = address;\n        }\n\n        /// <summary>\n        /// Creates an <see cref=\"Address\"/> instance from the given <see\n        /// cref=\"byte\"/> array (i.e., <paramref name=\"address\"/>).\n        /// </summary>\n        /// <param name=\"address\">An array of 20 <see cref=\"byte\"/>s which\n        /// represents an <see cref=\"Address\"/>.</param>\n        /// <exception cref=\"ArgumentException\">Thrown when the given <paramref\n        /// name=\"address\"/> array did not lengthen 20 bytes.</exception>\n        /// <remarks>A valid <see cref=\"byte\"/> array which represents an\n        /// <see cref=\"Address\"/> can be gotten using <see cref=\"ToByteArray()\"\n        /// /> method.</remarks>\n        /// <seealso cref=\"ToByteArray()\"/>\n        public Address(byte[] address)\n            : this(address.ToImmutableArray())\n        {\n        }\n\n        /// <summary>\n        /// Derives the corresponding <see cref=\"Address\"/> from a <see\n        /// cref=\"PublicKey\"/>.\n        /// <para>Note that there is an equivalent extension method\n        /// <see cref=\"AddressExtensions.ToAddress(PublicKey)\"/>, which enables\n        /// a code like <c>publicKey.Address</c> instead of\n        /// <c>new Address(publicKey)</c>, for convenience.</para>\n        /// </summary>\n        /// <param name=\"publicKey\">A <see cref=\"PublicKey\"/> to derive\n        /// the corresponding <see cref=\"Address\"/> from.</param>\n        /// <seealso cref=\"AddressExtensions.ToAddress(PublicKey)\"/>\n        public Address(PublicKey publicKey)\n            : this(DeriveAddress(publicKey))\n        {\n        }\n\n        /// <summary>\n        /// Derives the corresponding <see cref=\"Address\"/> from a hexadecimal\n        /// address string.\n        /// </summary>\n        /// <exception cref=\"ArgumentException\">Thrown when given <paramref name=\"hex\"/>\n        /// is neither 40 chars long nor 42 chars long with 0x prefix.</exception>\n        /// <exception cref=\"ArgumentException\">Thrown when given <paramref name=\"hex\"/>\n        /// is mixed-case and the checksum is invalid.</exception>\n        /// <exception cref=\"ArgumentException\">Thrown when given <paramref name=\"hex\"/>\n        /// does not consist of ASCII characters.</exception>\n        /// <param name=\"hex\">A 40 characters or included 0x prefix hexadecimal\n        /// address string to derive the corresponding <see cref=\"Address\"/> from.\n        /// The string should be all lower-case or mixed-case which follows <a\n        /// href=\"https://github.com/ethereum/EIPs/blob/master/EIPS/eip-55.md\"\n        /// >EIP 55</a>.</param>\n        public Address(string hex)\n            : this(DeriveAddress(hex))\n        {\n        }\n\n        /// <summary>\n        /// Creates an <see cref=\"Address\"/> instance from given <paramref name=\"bencoded\"/>.\n        /// </summary>\n        /// <param name=\"bencoded\">A Bencodex <see cref=\"Binary\"/> of 20 <see cref=\"byte\"/>s which\n        /// represents an <see cref=\"Address\"/>.\n        /// </param>\n        /// <exception cref=\"ArgumentException\">Thrown when given <paramref name=\"bencoded\"/>\n        /// is not of type <see cref=\"Binary\"/>.</exception>\n        /// <seealso cref=\"Address(in ImmutableArray{byte})\"/>\n        public Address(IValue bencoded)\n            : this(bencoded is Binary binary\n                ? binary\n                : throw new ArgumentException(\n                    $\"Given {nameof(bencoded)} must be of type \" +\n                    $\"{typeof(Binary)}: {bencoded.GetType()}\",\n                    nameof(bencoded)))\n        {\n        }\n\n        private Address(Binary bencoded)\n            : this(bencoded.ByteArray)\n        {\n        }\n\n        /// <summary>\n        /// An immutable array of 20 <see cref=\"byte\"/>s that represent this\n        /// <see cref=\"Address\"/>.\n        /// </summary>\n        /// <remarks>This is immutable.  For a mutable array, call <see\n        /// cref=\"ToByteArray()\"/> method.</remarks>\n        /// <seealso cref=\"ToByteArray()\"/>\n        public ImmutableArray<byte> ByteArray => _byteArray.IsDefault\n            ? _defaultByteArray\n            : _byteArray;\n\n        /// <inheritdoc/>\n        public IValue Bencoded => new Binary(ByteArray);\n\n        public static bool operator ==(Address left, Address right) => left.Equals(right);\n\n        public static bool operator !=(Address left, Address right) => !left.Equals(right);\n\n        public bool Equals(Address other) => ByteArray.SequenceEqual(other.ByteArray);\n\n        public override bool Equals(object? obj) => obj is Address other && Equals(other);\n\n        public override int GetHashCode() => ByteUtil.CalculateHashCode(ToByteArray());\n\n        /// <summary>\n        /// Gets a mutable array of 20 <see cref=\"byte\"/>s that represent\n        /// this <see cref=\"Address\"/>.\n        /// </summary>\n        /// <returns>A new mutable array which represents this\n        /// <see cref=\"Address\"/>.  Since it is created every time the method\n        /// is called, any mutation on that does not affect internal states of\n        /// this <see cref=\"Address\"/>.</returns>\n        /// <seealso cref=\"ByteArray\"/>\n        /// <seealso cref=\"Address(byte[])\"/>\n        [Pure]\n        public byte[] ToByteArray() => ByteArray.ToArray();\n\n        /// <summary>\n        /// Gets a mixed-case hexadecimal string of 40 letters that represent\n        /// this <see cref=\"Address\"/>. The returned hexadecimal string follows\n        /// <a\n        /// href=\"https://github.com/ethereum/EIPs/blob/master/EIPS/eip-55.md\"\n        /// >EIP 55</a>.\n        /// </summary>\n        /// <example>A returned string looks like\n        /// <c>87Ae4774E20963fd6caC967CF47aDCF880C3e89B</c>.</example>\n        /// <returns>A hexadecimal string of 40 letters that represent\n        /// this <see cref=\"Address\"/>.  Note that it does not start with\n        /// a prefix.</returns>\n        /// <remarks>As the returned string has no prefix, for\n        /// <c>0x</c>-prefixed hexadecimal, call <see cref=\"ToString()\"/>\n        /// method instead.</remarks>\n        /// <seealso cref=\"ToString()\"/>\n        [Pure]\n        public string ToHex() => ToChecksumAddress(ByteUtil.Hex(ToByteArray()));\n\n        /// <summary>\n        /// Gets a <c>0x</c>-prefixed mixed-case hexadecimal string of\n        /// 42 letters that represent this <see cref=\"Address\"/>. The returned\n        /// hexadecimal string follows\n        /// <a\n        /// href=\"https://github.com/ethereum/EIPs/blob/master/EIPS/eip-55.md\"\n        /// >EIP 55</a>.\n        /// </summary>\n        /// <example>A returned string looks like\n        /// <c>0x87Ae4774E20963fd6caC967CF47aDCF880C3e89B</c>.</example>\n        /// <returns>A <c>0x</c>-hexadecimal string of 42 letters that represent\n        /// this <see cref=\"Address\"/>.</returns>\n        /// <remarks>As the returned string is <c>0x</c>-prefixed, for\n        /// hexadecimal without prefix, call <see cref=\"ToHex()\"/> method\n        /// instead.</remarks>\n        /// <seealso cref=\"ToHex()\"/>\n        [Pure]\n        public override string ToString() => $\"0x{ToHex()}\";\n\n        /// <inheritdoc cref=\"IComparable{T}.CompareTo(T)\"/>\n        public int CompareTo(Address other)\n        {\n            ImmutableArray<byte> self = ByteArray, operand = other.ByteArray;\n\n            for (int i = 0; i < Size; i++)\n            {\n                int cmp = ((IComparable<byte>)self[i]).CompareTo(operand[i]);\n                if (cmp != 0)\n                {\n                    return cmp;\n                }\n            }\n\n            return 0;\n        }\n\n        /// <inheritdoc cref=\"IComparable.CompareTo(object)\"/>\n        public int CompareTo(object? obj) => obj is Address other\n            ? this.CompareTo(other)\n            : throw new ArgumentException(\n                $\"Argument {nameof(obj)} is not an ${nameof(Address)}.\", nameof(obj));\n\n        private static string ToChecksumAddress(string hex)\n        {\n            byte[] bytes = Encoding.ASCII.GetBytes(hex);\n            byte[] hash = CalculateHash(bytes);\n            string hashHex = ByteUtil.Hex(hash);\n            string address = string.Empty;\n\n            for (var i = 0; i < hex.Length; i++)\n            {\n                char c = hex[i];\n                address += (hashHex[i] >= '8') ? char.ToUpper(c, CultureInfo.InvariantCulture) : c;\n            }\n\n            return address;\n        }\n\n        private static byte[] CalculateHash(byte[] value)\n        {\n            var digest = new KeccakDigest(256);\n            var output = new byte[digest.GetDigestSize()];\n            digest.BlockUpdate(value, 0, value.Length);\n            digest.DoFinal(output, 0);\n            return output;\n        }\n\n        private static ImmutableArray<byte> DeriveAddress(PublicKey key)\n        {\n            byte[] hashPayload = key.Format(false).Skip(1).ToArray();\n            var output = CalculateHash(hashPayload);\n\n            return output.Skip(output.Length - Size).ToImmutableArray();\n        }\n\n        private static ImmutableArray<byte> DeriveAddress(string hex)\n        {\n            if (hex.Length != 40 && hex.Length != 42)\n            {\n                throw new ArgumentException(\n                    $\"Address hex must be either 42 chars or 40 chars, \" +\n                    $\"but given {nameof(hex)} is of length {hex.Length}: {hex}\",\n                    nameof(hex));\n            }\n\n            if (hex.Length == 42)\n            {\n                if (hex.StartsWith(\"0x\"))\n                {\n                    hex = hex.Substring(2);\n                }\n                else\n                {\n                    throw new ArgumentException(\n                        $\"Address hex of length 42 chars must start with \\\"0x\\\" prefix: {hex}\",\n                        nameof(hex));\n                }\n            }\n\n            if (hex.ToLower(CultureInfo.InvariantCulture) != hex &&\n                ToChecksumAddress(hex.ToLower(CultureInfo.InvariantCulture)) != hex)\n            {\n                throw new ArgumentException(\"Address checksum is invalid\", nameof(hex));\n            }\n\n            try\n            {\n                return ByteUtil.ParseHexToImmutable(hex);\n            }\n            catch (FormatException fe)\n            {\n                throw new ArgumentException(\n                    \"Address hex must only consist of ASCII characters\", fe);\n            }\n        }\n    }\n\n    /// <summary>\n    /// The <see cref=\"TypeConverter\"/> implementation for <see cref=\"Address\"/>.\n    /// </summary>\n    [SuppressMessage(\n        \"StyleCop.CSharp.MaintainabilityRules\",\n        \"SA1402:FileMayOnlyContainASingleClass\",\n        Justification = \"It's okay to have non-public classes together in a single file.\"\n    )]\n    internal class AddressTypeConverter : TypeConverter\n    {\n        /// <inheritdoc cref=\"TypeConverter.CanConvertFrom(ITypeDescriptorContext?, Type)\"/>\n        public override bool CanConvertFrom(ITypeDescriptorContext? context, Type sourceType) =>\n            sourceType == typeof(string) || base.CanConvertFrom(context, sourceType);\n\n        /// <inheritdoc\n        /// cref=\"TypeConverter.ConvertFrom(ITypeDescriptorContext?, CultureInfo?, object)\"/>\n        public override object? ConvertFrom(\n            ITypeDescriptorContext? context,\n            CultureInfo? culture,\n            object value\n        ) =>\n            value is string v ? new Address(v) : base.ConvertFrom(context, culture, value);\n\n        /// <inheritdoc cref=\"TypeConverter.CanConvertTo(ITypeDescriptorContext?, Type?)\"/>\n        public override bool CanConvertTo(ITypeDescriptorContext? context, Type? destinationType) =>\n            destinationType == typeof(string) || base.CanConvertTo(context, destinationType);\n\n        /// <inheritdoc\n        /// cref=\"TypeConverter.ConvertTo(ITypeDescriptorContext?, CultureInfo?, object?, Type)\"/>\n        public override object? ConvertTo(\n            ITypeDescriptorContext? context,\n            CultureInfo? culture,\n            object? value,\n            Type destinationType\n        ) =>\n            value is Address address && destinationType == typeof(string)\n                ? address.ToHex()\n                : base.ConvertTo(context, culture, value, destinationType);\n    }\n\n    [SuppressMessage(\n        \"StyleCop.CSharp.MaintainabilityRules\",\n        \"SA1402:FileMayOnlyContainASingleClass\",\n        Justification = \"It's okay to have non-public classes together in a single file.\"\n    )]\n    internal class AddressJsonConverter : JsonConverter<Address>\n    {\n        public override Address Read(\n            ref Utf8JsonReader reader,\n            Type typeToConvert,\n            JsonSerializerOptions options\n        )\n        {\n            string hex = reader.GetString() ?? throw new JsonException(\"Expected a string.\");\n            try\n            {\n                return new Address(hex);\n            }\n            catch (ArgumentException e)\n            {\n                throw new JsonException(e.Message);\n            }\n        }\n\n        public override void Write(\n            Utf8JsonWriter writer,\n            Address value,\n            JsonSerializerOptions options\n        ) =>\n            writer.WriteStringValue(value.ToHex());\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Crypto/CryptoConfig.cs",
    "content": "using System.Security.Cryptography;\n\nnamespace Libplanet.Crypto\n{\n    /// <summary>\n    /// Libplanet cryptography configuration information.\n    /// </summary>\n    public static class CryptoConfig\n    {\n        private static ICryptoBackend<SHA256>? _cryptoBackend;\n\n        /// <summary>\n        /// Global cryptography backend to sign and verify messages.\n        /// </summary>\n        public static ICryptoBackend<SHA256> CryptoBackend\n        {\n            get => _cryptoBackend ??= new DefaultCryptoBackend<SHA256>();\n            set => _cryptoBackend = value;\n        }\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Crypto/DefaultCryptoBackend.cs",
    "content": "using System.IO;\nusing System.Security.Cryptography;\nusing Libplanet.Common;\nusing Org.BouncyCastle.Asn1;\nusing Org.BouncyCastle.Crypto.Digests;\nusing Org.BouncyCastle.Crypto.Signers;\nusing Org.BouncyCastle.Math;\n\nnamespace Libplanet.Crypto\n{\n    public class DefaultCryptoBackend<T> : ICryptoBackend<T>\n        where T : HashAlgorithm\n    {\n        public byte[] Sign(HashDigest<T> messageHash, PrivateKey privateKey)\n        {\n            var h = new Sha256Digest();\n            var kCalculator = new HMacDsaKCalculator(h);\n            var signer = new ECDsaSigner(kCalculator);\n            signer.Init(true, privateKey.KeyParam);\n            BigInteger[] rs = signer.GenerateSignature(messageHash.ToByteArray());\n            var r = rs[0];\n            var s = rs[1];\n\n            BigInteger otherS = privateKey.KeyParam.Parameters.N.Subtract(s);\n            if (s.CompareTo(otherS) == 1)\n            {\n                s = otherS;\n            }\n\n            using var bos = new MemoryStream(72);\n            using (var seq = new DerSequenceGenerator(bos))\n            {\n                seq.AddObject(new DerInteger(r));\n                seq.AddObject(new DerInteger(s));\n            }\n\n            return bos.ToArray();\n        }\n\n        public bool Verify(\n            HashDigest<T> messageHash,\n            byte[] signature,\n            PublicKey publicKey)\n        {\n            try\n            {\n                Asn1Sequence asn1Sequence = (Asn1Sequence)Asn1Object.FromByteArray(signature);\n\n                var rs = new[]\n                {\n                    ((DerInteger)asn1Sequence[0]).Value,\n                    ((DerInteger)asn1Sequence[1]).Value,\n                };\n                var verifier = new ECDsaSigner();\n                verifier.Init(false, publicKey.KeyParam);\n\n                return verifier.VerifySignature(messageHash.ToByteArray(), rs[0], rs[1]);\n            }\n            catch (IOException)\n            {\n                return false;\n            }\n            catch (Asn1ParsingException)\n            {\n                return false;\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Crypto/GenerateKeyParamTriesExceedException.cs",
    "content": "using System;\n\nnamespace Libplanet.Crypto\n{\n    public class GenerateKeyParamTriesExceedException : Exception\n    {\n        public GenerateKeyParamTriesExceedException()\n        {\n        }\n\n        public GenerateKeyParamTriesExceedException(string message)\n          : base(message)\n        {\n        }\n\n        public GenerateKeyParamTriesExceedException(string message, Exception innerException)\n          : base(message, innerException)\n        {\n        }\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Crypto/ICryptoBackend.cs",
    "content": "using System;\nusing System.Security.Cryptography;\nusing Libplanet.Common;\n\nnamespace Libplanet.Crypto\n{\n    /// <summary>\n    /// Cryptography backend interface.\n    /// </summary>\n    /// <typeparam name=\"T\">A <see cref=\"HashAlgorithm\"/> which corresponds to a digest.</typeparam>\n    /// <seealso cref=\"HashAlgorithm\"/>\n    public interface ICryptoBackend<T>\n        where T : HashAlgorithm\n    {\n        /// <summary>\n        /// Creates a signature from <paramref name=\"messageHash\"/> with the corresponding\n        /// <paramref name=\"privateKey\"/>.\n        /// </summary>\n        /// <param name=\"messageHash\">A 32 bytes message hash digest hashed with SHA256 to sign.\n        /// </param>\n        /// <param name=\"privateKey\"><see cref=\"PrivateKey\"/> to sign\n        /// <paramref name=\"messageHash\"/>.\n        /// </param>\n        /// <returns> Created a signature from <paramref name=\"messageHash\"/> with the corresponding\n        /// <paramref name=\"privateKey\"/>.\n        /// </returns>\n        byte[] Sign(HashDigest<T> messageHash, PrivateKey privateKey);\n\n        /// <summary>\n        /// Verifies whether a <paramref name=\"signature\"/> was created from\n        /// a <paramref name=\"messageHash\"/> with the corresponding <see cref=\"PrivateKey\"/>.\n        /// </summary>\n        /// <param name=\"messageHash\">A 32 bytes message hash digest hashed with SHA256.</param>\n        /// <param name=\"signature\">A signature that was created from the\n        /// <paramref name=\"messageHash\"/>.</param>\n        /// <param name=\"publicKey\"><see cref=\"PublicKey\"/> used for verification.</param>\n        /// <returns><see langword=\"true\"/> if the <paramref name=\"signature\"/> was created\n        /// from the <paramref name=\"messageHash\"/> with the corresponding\n        /// <see cref=\"PrivateKey\"/>. Otherwise <see langword=\"false\"/>.</returns>\n        /// <exception cref=\"Exception\">If any exception is thrown, the given\n        /// <paramref name=\"signature\"/> is considered as invalid.</exception>\n        bool Verify(\n            HashDigest<T> messageHash,\n            byte[] signature,\n            PublicKey publicKey);\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Crypto/InvalidCiphertextException.cs",
    "content": "using System;\n\nnamespace Libplanet.Crypto\n{\n    public class InvalidCiphertextException : Exception\n    {\n        public InvalidCiphertextException()\n        {\n        }\n\n        public InvalidCiphertextException(string message)\n            : base(message)\n        {\n        }\n\n        public InvalidCiphertextException(\n            string message, Exception innerException)\n            : base(message, innerException)\n        {\n        }\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Crypto/Libplanet.Crypto.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <ItemGroup>\n    <PackageReference Include=\"System.Collections.Immutable\" Version=\"1.*\" />\n    <PackageReference Include=\"System.Text.Json\" Version=\"6.0.*\" />\n    <PackageReference Include=\"Bencodex\" Version=\"0.16.0\" />\n    <PackageReference Include=\"BouncyCastle.Cryptography\" Version=\"2.4.0\" />\n  </ItemGroup>\n\n  <ItemGroup Condition=\"'$(SkipSonar)' != 'true'\">\n    <PackageReference Remove=\"SonarAnalyzer.CSharp\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <ProjectReference Include=\"..\\Libplanet.Common\\Libplanet.Common.csproj\" />\n  </ItemGroup>\n\n</Project>\n"
  },
  {
    "path": "src/Libplanet.Crypto/PrivateKey.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Collections.Immutable;\nusing System.Diagnostics.Contracts;\nusing System.Linq;\nusing System.Runtime.CompilerServices;\nusing System.Security.Cryptography;\nusing Libplanet.Common;\nusing Org.BouncyCastle.Asn1.Sec;\nusing Org.BouncyCastle.Asn1.X9;\nusing Org.BouncyCastle.Crypto.Digests;\nusing Org.BouncyCastle.Crypto.Generators;\nusing Org.BouncyCastle.Crypto.Parameters;\nusing Org.BouncyCastle.Math;\nusing Org.BouncyCastle.Math.EC;\nusing Org.BouncyCastle.Security;\nusing ECPoint = Org.BouncyCastle.Math.EC.ECPoint;\n\nnamespace Libplanet.Crypto\n{\n    /// <summary>\n    /// A secret part of a key pair involved in\n    /// <a href=\"https://en.wikipedia.org/wiki/ECDSA\">ECDSA</a>, the digital\n    /// signature algorithm on which the Libplanet is based.  It can be used to\n    /// create signatures, which can be verified with the corresponding\n    /// <see cref=\"Crypto.PublicKey\"/>, as well as to decrypt\n    /// messages which were encrypted with the corresponding\n    /// <see cref=\"Crypto.PublicKey\"/>.\n    /// <para>Note that it uses <a href=\"https://en.bitcoin.it/wiki/Secp256k1\"\n    /// >secp256k1</a> as the parameters of the elliptic curve, which is\n    /// the same to <a href=\"https://bitcoin.org/\">Bitcoin</a> and\n    /// <a href=\"https://www.ethereum.org/\">Ethereum</a>.\n    /// It means private keys generated for Bitcoin/Ethereum can be used by\n    /// Libplanet-backed games/apps too.</para>\n    /// </summary>\n    /// <remarks>\n    /// These (and any derived representations, e.g., <see cref=\"ByteArray\"/>)\n    /// must be kept secret, if they are exposed, an attacker will be able to\n    /// forge signatures.\n    /// <para>Every <see cref=\"PrivateKey\"/> object is immutable.</para>\n    /// </remarks>\n    /// <seealso cref=\"Crypto.PublicKey\"/>\n    public class PrivateKey : IEquatable<PrivateKey>\n    {\n        private const int KeyByteSize = 32;\n        private PublicKey? _publicKey;\n\n        /// <summary>\n        /// Generates a new unique <see cref=\"PrivateKey\"/> instance.\n        /// It can be analogous to creating a new account in a degree.\n        /// </summary>\n        public PrivateKey()\n            : this(GenerateKeyParam())\n        {\n        }\n\n        /// <summary>\n        /// Creates a <see cref=\"PrivateKey\"/> instance from the given <see cref=\"byte\"/>s (i.e.,\n        /// <paramref name=\"privateKey\"/>), which encodes a valid\n        /// <a href=\"https://en.wikipedia.org/wiki/ECDSA\">ECDSA</a> private key.\n        /// </summary>\n        /// <param name=\"privateKey\">A valid <see cref=\"byte\"/>s that encodes an ECDSA private key.\n        /// </param>\n        /// <exception cref=\"ArgumentOutOfRangeException\">Thrown when the given\n        /// <paramref name=\"privateKey\"/> is too short or too long.</exception>\n        /// <remarks>A valid <see cref=\"byte\"/> array for a <see cref=\"PrivateKey\"/> can be encoded\n        /// using <see cref=\"ByteArray\"/> property.</remarks>\n        /// <seealso cref=\"ByteArray\"/>\n        public PrivateKey(IReadOnlyList<byte> privateKey)\n            : this(privateKey is byte[] ba ? ba : privateKey.ToArray(), informedConsent: true)\n        {\n            if (privateKey.Count != KeyByteSize)\n            {\n                throw new ArgumentOutOfRangeException(\n                    nameof(privateKey),\n                    $\"The key must be {KeyByteSize} bytes.\"\n                );\n            }\n        }\n\n        /// <summary>\n        /// Creates a <see cref=\"PrivateKey\"/> instance from the given hexadecimal\n        /// <see cref=\"string\"/> (i.e.,<paramref name=\"hex\"/>).\n        /// </summary>\n        /// <param name=\"hex\">A hexadecimal string of a private key's\n        /// <see cref=\"ByteArray\"/>.</param>\n        /// <exception cref=\"ArgumentNullException\">Thrown when the given <paramref name=\"hex\"/>\n        /// string is <see langword=\"null\"/>.</exception>\n        /// <exception cref=\"ArgumentOutOfRangeException\">Thrown when the length of the given\n        /// <paramref name=\"hex\"/> string is too short or too long.</exception>\n        /// <exception cref=\"FormatException\">Thrown when the given <paramref name=\"hex\"/> string is\n        /// not a valid hexadecimal string.</exception>\n        public PrivateKey(string hex)\n            : this(unverifiedKey: GenerateBytesFromHexString(hex), informedConsent: true)\n        {\n        }\n\n        public PrivateKey(byte[] unverifiedKey, bool informedConsent)\n            : this(GenerateKeyFromBytes(unverifiedKey))\n        {\n            // The `informedConsent` parameter mainly purposes to prevent this overload from\n            // being chosen instead of PrivatKey(IReadOnly<byte>) by mistake.\n            if (!informedConsent)\n            {\n                throw new ArgumentException(\n                    nameof(informedConsent),\n                    \"The caller should ensure the key is valid and safe enough.\"\n                );\n            }\n        }\n\n        private PrivateKey(ECPrivateKeyParameters keyParam)\n        {\n            KeyParam = keyParam;\n        }\n\n        /// <summary>\n        /// The corresponding <see cref=\"Crypto.PublicKey\"/> of\n        /// this private key.\n        /// </summary>\n        public PublicKey PublicKey\n        {\n            get\n            {\n                if (_publicKey is null)\n                {\n                    ECDomainParameters ecParams = GetECParameters();\n                    ECPoint q = ecParams.G.Multiply(KeyParam.D);\n                    var kp = new ECPublicKeyParameters(\"ECDSA\", q, ecParams);\n                    _publicKey = new PublicKey(kp);\n                }\n\n                return _publicKey;\n            }\n        }\n\n        /// <summary>\n        /// The corresponding <see cref=\"Crypto.Address\"/> derived from a <see cref=\"PrivateKey\"/>.\n        /// This is the same as the one derived from <see cref=\"PublicKey\"/>.\n        /// </summary>\n        public Address Address => new Address(PublicKey);\n\n        /// <summary>\n        /// An encoded <see cref=\"byte\"/> array representation.\n        /// </summary>\n        /// <remarks>\n        /// An encoded <see cref=\"byte\"/> array representation can be recovered to a <see\n        /// cref=\"PrivateKey\"/> instance again using <see cref=\"PrivateKey(IReadOnlyList{byte})\"/>\n        /// constructor.\n        /// <para>As like <see cref=\"PrivateKey\"/> instances, it also must be kept secret.\n        /// In practice, this must not be sent over the network, and be securely stored in the file\n        /// system.  If you just want to store the in-memory private key in the persistent storage,\n        /// use <see cref=\"KeyStore.ProtectedPrivateKey\"/> or <see cref=\"KeyStore.Web3KeyStore\"/>.\n        /// </para>\n        /// <para>To get a mutable array instead of immutable one, use <see cref=\"ToByteArray()\"/>\n        /// method instead.</para>\n        /// </remarks>\n        /// <seealso cref=\"ToByteArray()\"/>\n        /// <seealso cref=\"PrivateKey(IReadOnlyList{byte})\"/>\n        [Pure]\n        public ImmutableArray<byte> ByteArray => ToByteArray().ToImmutableArray();\n\n        internal ECPrivateKeyParameters KeyParam { get; }\n\n        public static bool operator ==(PrivateKey left, PrivateKey right) => left.Equals(right);\n\n        public static bool operator !=(PrivateKey left, PrivateKey right) => !left.Equals(right);\n\n        /// <summary>\n        /// Creates a <see cref=\"PrivateKey\"/> instance from hexadecimal string of bytes.\n        /// </summary>\n        /// <param name=\"hex\">A hexadecimal string of a private key's\n        /// <see cref=\"ByteArray\"/>.</param>\n        /// <returns>A created <see cref=\"PrivateKey\"/> instance.</returns>\n        /// <exception cref=\"ArgumentNullException\">Thrown when the given <paramref name=\"hex\"/>\n        /// string is <see langword=\"null\"/>.</exception>\n        /// <exception cref=\"ArgumentOutOfRangeException\">Thrown when the length of the given\n        /// <paramref name=\"hex\"/> string is too short or too long.</exception>\n        /// <exception cref=\"FormatException\">Thrown when the given <paramref name=\"hex\"/> string is\n        /// not a valid hexadecimal string.</exception>\n        [Pure]\n        public static PrivateKey FromString(string hex)\n        {\n            return new PrivateKey(\n                unverifiedKey: GenerateBytesFromHexString(hex),\n                informedConsent: true\n            );\n        }\n\n        public bool Equals(PrivateKey? other) => KeyParam.Equals(other?.KeyParam);\n\n        public override bool Equals(object? obj) => obj is PrivateKey other && Equals(other);\n\n        public override int GetHashCode() =>\n            unchecked(ByteUtil.CalculateHashCode(ToByteArray()) * 397 ^\n                      KeyParam.GetHashCode());\n\n        /// <summary>\n        /// Creates a signature from the given <paramref name=\"message\"/>.\n        /// <para>\n        /// A created signature can be verified by the corresponding\n        /// <see cref=\"PublicKey\"/>.\n        /// </para>\n        /// <para>\n        /// Signatures can be created by only the <see cref=\"PrivateKey\"/>\n        /// which corresponds a <see cref=\"PublicKey\"/> to verify these\n        /// signatures.\n        /// </para>\n        /// <para>\n        /// To sum up, a signature is used to guarantee:\n        /// </para>\n        /// <list type=\"bullet\">\n        /// <item><description>that the <paramref name=\"message\"/> was created\n        /// by someone possessing the corresponding <see cref=\"PrivateKey\"/>,\n        /// </description></item>\n        /// <item><description>that the possessor cannot deny having sent the\n        /// <paramref name=\"message\"/>, and</description></item>\n        /// <item><description>that the <paramref name=\"message\"/> was not\n        /// forged in the middle of transit.</description></item>\n        /// </list>\n        /// </summary>\n        /// <param name=\"message\">A message <see cref=\"byte\"/>s to sign.</param>\n        /// <returns>A signature that proves the authenticity of the <paramref name=\"message\"/>.\n        /// It can be verified using <see cref=\"Crypto.PublicKey.Verify\"/> method.\n        /// </returns>\n        /// <seealso cref=\"Crypto.PublicKey.Verify\"/>\n        public byte[] Sign(byte[] message)\n        {\n            HashDigest<SHA256> hashed = HashDigest<SHA256>.DeriveFrom(message);\n            return CryptoConfig.CryptoBackend.Sign(hashed, this);\n        }\n\n        /// <summary>\n        /// Creates a signature from the given <paramref name=\"message\"/>.\n        /// <para>A created signature can be verified by the corresponding <see cref=\"PublicKey\"/>.\n        /// </para>\n        /// <para>Signatures can be created by only the <see cref=\"PrivateKey\"/> which corresponds\n        /// a <see cref=\"PublicKey\"/> to verify these signatures.</para>\n        /// <para>To sum up, a signature is used to guarantee:</para>\n        /// <list type=\"bullet\">\n        /// <item><description>that the <paramref name=\"message\"/> was created by someone possessing\n        /// the corresponding <see cref=\"PrivateKey\"/>,</description></item>\n        /// <item><description>that the possessor cannot deny having sent the\n        /// <paramref name=\"message\"/>, and</description></item>\n        /// <item><description>that the <paramref name=\"message\"/> was not forged in the middle of\n        /// transit.</description></item>\n        /// </list>\n        /// </summary>\n        /// <param name=\"message\">A message <see cref=\"byte\"/>s to sign.</param>\n        /// <returns>A signature that proves the authenticity of the <paramref name=\"message\"/>.\n        /// It can be verified using <see cref=\"Crypto.PublicKey.Verify\"/> method.\n        /// </returns>\n        /// <seealso cref=\"Crypto.PublicKey.Verify\"/>\n        public ImmutableArray<byte> Sign(ImmutableArray<byte> message)\n        {\n            HashDigest<SHA256> hashed = HashDigest<SHA256>.DeriveFrom(message);\n            byte[] sig = CryptoConfig.CryptoBackend.Sign(hashed, this);\n            return Unsafe.As<byte[], ImmutableArray<byte>>(ref sig);\n        }\n\n        /// <summary>\n        /// Decrypts a <paramref name=\"ciphertext\"/> which was encrypted with the corresponding\n        /// <see cref=\"PublicKey\"/> to the original plain text.\n        /// </summary>\n        /// <param name=\"ciphertext\">The encrypted message.</param>\n        /// <returns>The decrypted original message.</returns>\n        /// <exception cref=\"InvalidCiphertextException\">Thrown when the given\n        /// <paramref name=\"ciphertext\"/> is invalid.</exception>\n        /// <remarks>\n        /// Although the parameter name <paramref name=\"ciphertext\"/> has the\n        /// word &#x201c;text&#x201d;, both a <paramref name=\"ciphertext\"/> and a returned message\n        /// are <see cref=\"byte\"/>s, not Unicode <see cref=\"string\"/>s.\n        /// </remarks>\n        /// <seealso cref=\"Crypto.PublicKey.Encrypt(byte[])\"/>\n        [Pure]\n        public byte[] Decrypt(byte[] ciphertext)\n        {\n            PublicKey pubKey = new PublicKey(ciphertext.Take(33).ToArray());\n            SymmetricKey aes = ExchangeKey(pubKey);\n\n            return aes.Decrypt(ciphertext, 33);\n        }\n\n        /// <summary>\n        /// Decrypts a <paramref name=\"ciphertext\"/> which was encrypted with the corresponding\n        /// <see cref=\"PublicKey\"/> to the original plain text.\n        /// </summary>\n        /// <param name=\"ciphertext\">The encrypted message.</param>\n        /// <returns>The decrypted original message.</returns>\n        /// <exception cref=\"InvalidCiphertextException\">Thrown when the given\n        /// <paramref name=\"ciphertext\"/> is invalid.</exception>\n        /// <remarks>\n        /// Although the parameter name <paramref name=\"ciphertext\"/> has the\n        /// word &#x201c;text&#x201d;, both a <paramref name=\"ciphertext\"/> and a returned message\n        /// are <see cref=\"byte\"/>s, not Unicode <see cref=\"string\"/>s.\n        /// </remarks>\n        /// <seealso cref=\"Crypto.PublicKey.Encrypt(ImmutableArray{byte})\"/>\n        [Pure]\n        public ImmutableArray<byte> Decrypt(ImmutableArray<byte> ciphertext) =>\n            Decrypt(ciphertext.ToBuilder().ToArray()).ToImmutableArray();\n\n        /// <summary>\n        /// Securely exchange a <see cref=\"SymmetricKey\"/> with a peer's\n        /// <see cref=\"PublicKey\"/>.\n        /// Two parties can agree on a (new, unique, and typically temporal)\n        /// key without revealing to any eavesdropping party what key has been\n        /// agreed upon.\n        /// <para>Technically it is <a href=\"https://en.wikipedia.org/wiki/ECDH\"\n        /// >ECDH</a>, a <a\n        /// href=\"https://en.wikipedia.org/wiki/DH_key_exchange\"\n        /// >Diffie&#x2013;Hellman key exchange</a> of elliptic-curve version.\n        /// </para>\n        /// </summary>\n        /// <param name=\"publicKey\">The <see cref=\"PublicKey\"/> possessed by\n        /// a peer to whom exchange a private key with.</param>\n        /// <returns>An exchanged (agreed) <see cref=\"SymmetricKey\"/>.\n        /// Note that it is not an elliptic-curve private key, but an <a\n        /// href=\"https://en.wikipedia.org/wiki/Advanced_Encryption_Standard\"\n        /// >AES</a> key.</returns>\n        [Pure]\n        public SymmetricKey ExchangeKey(PublicKey publicKey)\n        {\n            ECPoint p = CalculatePoint(publicKey.KeyParam);\n            BigInteger x = p.AffineXCoord.ToBigInteger();\n            BigInteger y = p.AffineYCoord.ToBigInteger();\n\n            byte[] xbuf = x.ToByteArrayUnsigned();\n            var ybuf = new byte[] { (byte)(y.TestBit(0) ? 0x03 : 0x02) };\n\n            var hash = new Sha256Digest();\n            var result = new byte[hash.GetDigestSize()];\n\n            hash.BlockUpdate(ybuf, 0, ybuf.Length);\n            hash.BlockUpdate(xbuf, 0, xbuf.Length);\n            hash.DoFinal(result, 0);\n\n            return new SymmetricKey(result);\n        }\n\n        /// <summary>\n        /// Encodes the private key into a corresponding mutable <see cref=\"byte\"/> array\n        /// representation.\n        /// </summary>\n        /// <returns>An encoded <see cref=\"byte\"/> array representation.  It guarantees that\n        /// returned arrays are never reused, and mutating on them does not affect\n        /// <see cref=\"PrivateKey\"/> instance's internal states.</returns>\n        /// <remarks>\n        /// An encoded <see cref=\"byte\"/> array representation can be recovered to a <see\n        /// cref=\"PrivateKey\"/> instance again using <see cref=\"PrivateKey(IReadOnlyList{byte})\"/>\n        /// constructor.\n        /// <para>As like <see cref=\"PrivateKey\"/> instances, it also must be kept secret.\n        /// In practice, this must not be sent over the network, and be securely stored in the file\n        /// system.  If you just want to store the in-memory private key in the persistent storage,\n        /// use <see cref=\"KeyStore.ProtectedPrivateKey\"/> or <see cref=\"KeyStore.Web3KeyStore\"/>.\n        /// </para>\n        /// <para>To get an immutable array instead of mutable one, use <see cref=\"ByteArray\"/>\n        /// property.</para>\n        /// </remarks>\n        /// <seealso cref=\"ByteArray\"/>\n        /// <seealso cref=\"PrivateKey(IReadOnlyList{byte})\"/>\n        [Pure]\n        public byte[] ToByteArray() =>\n            KeyParam.D.ToByteArrayUnsigned();\n\n        internal static ECDomainParameters GetECParameters()\n        {\n            return GetECParameters(\"secp256k1\");\n        }\n\n        private static ECDomainParameters GetECParameters(string name)\n        {\n            X9ECParameters ps = SecNamedCurves.GetByName(name);\n            return new ECDomainParameters(ps.Curve, ps.G, ps.N, ps.H);\n        }\n\n        private static ECPrivateKeyParameters GenerateKeyParam()\n        {\n            var gen = new ECKeyPairGenerator();\n            var secureRandom = new SecureRandom();\n            ECDomainParameters ecParams = GetECParameters();\n            var keyGenParam =\n                new ECKeyGenerationParameters(ecParams, secureRandom);\n            gen.Init(keyGenParam);\n\n            const int maxTries = 3000;\n            int tries = 0;\n            ECPrivateKeyParameters result;\n\n            while (tries < maxTries)\n            {\n                result = (ECPrivateKeyParameters)gen.GenerateKeyPair().Private;\n                if (result.D.ToByteArrayUnsigned().Length == KeyByteSize)\n                {\n                    return result;\n                }\n\n                tries++;\n            }\n\n            throw new GenerateKeyParamTriesExceedException(\n                \"Can't find appropriate parameter for private key\" +\n                $\"(maxTries: {maxTries})\"\n            );\n        }\n\n        private static ECPrivateKeyParameters GenerateKeyFromBytes(byte[] privateKey)\n        {\n            if (privateKey.All(b => b.Equals(0x00)))\n            {\n                throw new ArgumentException(\"Every bytes in Private key is zero value.\");\n            }\n\n            var param = new ECPrivateKeyParameters(\n                \"ECDSA\",\n                new BigInteger(1, privateKey),\n                GetECParameters()\n            );\n\n            // For sanity check.\n#pragma warning disable SA1312, S1481\n            var _ = new PrivateKey(param).PublicKey;\n#pragma warning restore SA1312, S1481\n            return param;\n        }\n\n        private static byte[] GenerateBytesFromHexString(string hex)\n        {\n            byte[] bytes = ByteUtil.ParseHex(hex);\n            if (bytes.Length != KeyByteSize)\n            {\n                throw new ArgumentOutOfRangeException(\n                    nameof(hex),\n                    $\"Expected {KeyByteSize * 2} hexadecimal digits.\"\n                );\n            }\n\n            return bytes;\n        }\n\n        private ECPoint CalculatePoint(ECPublicKeyParameters pubKeyParams)\n        {\n            ECDomainParameters dp = KeyParam.Parameters;\n            if (!dp.Equals(pubKeyParams.Parameters))\n            {\n                throw new InvalidOperationException(\n                    \"ECDH public key has wrong domain parameters\"\n                );\n            }\n\n            BigInteger d = KeyParam.D;\n\n            ECPoint q = dp.Curve.DecodePoint(pubKeyParams.Q.GetEncoded(true));\n            if (q.IsInfinity)\n            {\n                throw new InvalidOperationException(\n                    \"Infinity is not a valid public key for ECDH\"\n                );\n            }\n\n            BigInteger h = dp.H;\n            if (!h.Equals(BigInteger.One))\n            {\n                d = dp.H.ModInverse(dp.N).Multiply(d).Mod(dp.N);\n                q = ECAlgorithms.ReferenceMultiply(q, h);\n            }\n\n            ECPoint p = q.Multiply(d).Normalize();\n            if (p.IsInfinity)\n            {\n                throw new InvalidOperationException(\n                    \"Infinity is not a valid agreement value for ECDH\"\n                );\n            }\n\n            return p;\n        }\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Crypto/PublicKey.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Collections.Immutable;\nusing System.ComponentModel;\nusing System.Diagnostics.CodeAnalysis;\nusing System.Diagnostics.Contracts;\nusing System.Globalization;\nusing System.Linq;\nusing System.Security.Cryptography;\nusing System.Text.Json;\nusing System.Text.Json.Serialization;\nusing Libplanet.Common;\nusing Org.BouncyCastle.Crypto.Parameters;\n\nnamespace Libplanet.Crypto\n{\n    /// <summary>\n    /// A public part of a key pair involved in\n    /// <a href=\"https://en.wikipedia.org/wiki/ECDSA\">ECDSA</a>, the digital\n    /// signature algorithm on which the Libplanet is based.\n    /// It can be used to verify signatures created with the corresponding\n    /// <see cref=\"PrivateKey\"/> and to encrypt messages for someone\n    /// possessing the corresponding <see cref=\"PrivateKey\"/>.\n    /// This can be distributed publicly, hence the name.\n    /// <para>Note that it uses <a href=\"https://en.bitcoin.it/wiki/Secp256k1\"\n    /// >secp256k1</a> as the parameters of the elliptic curve, which is same to\n    /// <a href=\"https://bitcoin.org/\">Bitcoin</a> and\n    /// <a href=\"https://www.ethereum.org/\">Ethereum</a>.\n    /// It means public keys generated for Bitcoin/Ethereum can be used by\n    /// Libplanet-backed games/apps too.</para>\n    /// </summary>\n    /// <remarks>Every <see cref=\"PublicKey\"/> object is immutable.</remarks>\n    /// <seealso cref=\"PrivateKey\"/>\n    /// <seealso cref=\"Address\"/>\n    [TypeConverter(typeof(PublicKeyTypeConverter))]\n    [JsonConverter(typeof(PublicKeyJsonConverter))]\n    public class PublicKey : IEquatable<PublicKey>\n    {\n        /// <summary>\n        /// Creates a <see cref=\"PublicKey\"/> instance from the given\n        /// <see cref=\"byte\"/> array (i.e., <paramref name=\"publicKey\"/>),\n        /// which encodes a valid <a href=\"https://en.wikipedia.org/wiki/ECDSA\">\n        /// ECDSA</a> public key.\n        /// </summary>\n        /// <param name=\"publicKey\">A valid <see cref=\"byte\"/> array that\n        /// encodes an ECDSA public key.  It can be either compressed or\n        /// not.</param>\n        /// <remarks>A valid <see cref=\"byte\"/> array for\n        /// a <see cref=\"PublicKey\"/> can be encoded using\n        /// <see cref=\"Format(bool)\"/> method.\n        /// </remarks>\n        /// <seealso cref=\"Format(bool)\"/>\n        public PublicKey(IReadOnlyList<byte> publicKey)\n            : this(GetECPublicKeyParameters(publicKey is byte[] ba ? ba : publicKey.ToArray()))\n        {\n        }\n\n        internal PublicKey(ECPublicKeyParameters keyParam)\n        {\n            KeyParam = keyParam;\n        }\n\n        /// <summary>\n        /// The corresponding <see cref=\"Crypto.Address\"/> derived from a <see cref=\"PublicKey\"/>.\n        /// </summary>\n        public Address Address => new Address(this);\n\n        internal ECPublicKeyParameters KeyParam { get; }\n\n        public static bool operator ==(PublicKey left, PublicKey right) => left.Equals(right);\n\n        public static bool operator !=(PublicKey left, PublicKey right) => !left.Equals(right);\n\n        /// <summary>\n        /// Creates a <see cref=\"PublicKey\"/> instance from its hexadecimal representation.\n        /// </summary>\n        /// <param name=\"hex\">The hexadecimal representation of the public key to load.\n        /// Case insensitive, and accepts either compressed or uncompressed.</param>\n        /// <returns>The parsed <see cref=\"PublicKey\"/>.</returns>\n        /// <exception cref=\"ArgumentOutOfRangeException\">Thrown when the length of the given\n        /// <paramref name=\"hex\"/> string is an odd number.</exception>\n        /// <exception cref=\"FormatException\">Thrown when the given <paramref name=\"hex\"/> string\n        /// is not a valid hexadecimal string.</exception>\n        /// <seealso cref=\"ToHex(bool)\"/>\n        public static PublicKey FromHex(string hex) =>\n            new PublicKey(ByteUtil.ParseHex(hex));\n\n        public bool Equals(PublicKey? other) => KeyParam.Equals(other?.KeyParam);\n\n        public override bool Equals(object? obj) => obj is PublicKey other && Equals(other);\n\n        public override int GetHashCode() => KeyParam.GetHashCode();\n\n        /// <summary>\n        /// Encodes this public key into a mutable <see cref=\"byte\"/> array representation.\n        /// <para>To get an immutable one, use <see cref=\"ToImmutableArray(bool)\"/> method\n        /// instead.</para>\n        /// </summary>\n        /// <param name=\"compress\">Returns a short length representation if it is\n        /// <see langword=\"true\"/>.  This option does not lose any information.</param>\n        /// <returns>An encoded mutable <see cref=\"byte\"/> array representation.  It can be\n        /// recovered to a <see cref=\"PublicKey\"/> instance again using\n        /// <see cref=\"PublicKey(IReadOnlyList{byte})\"/> constructor whether it is compressed\n        /// or not.</returns>\n        /// <seealso cref=\"ToImmutableArray(bool)\"/>\n        /// <seealso cref=\"PublicKey(IReadOnlyList{byte})\"/>\n        [Pure]\n        public byte[] Format(bool compress) =>\n            KeyParam.Q.GetEncoded(compress);\n\n        /// <summary>\n        /// Encodes this public key into a immutable <see cref=\"byte\"/> array representation.\n        /// <para>To get an mutable one, use <see cref=\"Format(bool)\"/> method instead.</para>\n        /// </summary>\n        /// <param name=\"compress\">Returns a short length representation if it is\n        /// <see langword=\"true\"/>.  This option does not lose any information.</param>\n        /// <returns>An encoded immutable <see cref=\"byte\"/> array representation.  It can be\n        /// recovered to a <see cref=\"PublicKey\"/> instance again using\n        /// <see cref=\"PublicKey(IReadOnlyList{byte})\"/> constructor whether it is compressed\n        /// or not.</returns>\n        /// <seealso cref=\"Format(bool)\"/>\n        /// <seealso cref=\"PublicKey(IReadOnlyList{byte})\"/>\n        [Pure]\n        public ImmutableArray<byte> ToImmutableArray(bool compress) =>\n            Format(compress).ToImmutableArray();\n\n        /// <summary>\n        /// Encrypts a plaintext <paramref name=\"message\"/> to a ciphertext, which can be decrypted\n        /// with the corresponding <see cref=\"PrivateKey\"/>.\n        /// </summary>\n        /// <param name=\"message\">A binary data to encrypt.</param>\n        /// <returns>\n        /// A ciphertext that was encrypted from the original <paramref name=\"message\"/>.\n        /// This can be decrypted with the corresponding <see cref=\"PrivateKey\" />.\n        /// </returns>\n        /// <remarks>Although the word &#x201c;ciphertext&#x201d; has the word &#x201c;text&#x201d;,\n        /// a returned ciphertext is not a Unicode <see cref=\"string\"/>, but a mutable\n        /// <see cref=\"byte\"/> array.</remarks>\n        /// <seealso cref=\"PrivateKey.Decrypt(byte[])\"/>\n        public byte[] Encrypt(byte[] message)\n        {\n            PrivateKey disposablePrivateKey = new PrivateKey();\n            SymmetricKey aes = disposablePrivateKey.ExchangeKey(this);\n\n            return aes.Encrypt(\n                message,\n                disposablePrivateKey.PublicKey.Format(true)\n            );\n        }\n\n        /// <summary>\n        /// Encrypts a plaintext <paramref name=\"message\"/> to a ciphertext, which can be decrypted\n        /// with the corresponding <see cref=\"PrivateKey\"/>.\n        /// </summary>\n        /// <param name=\"message\">A binary data to encrypt.</param>\n        /// <returns>\n        /// A ciphertext that was encrypted from the original <paramref name=\"message\"/>.\n        /// This can be decrypted with the corresponding <see cref=\"PrivateKey\" />.\n        /// </returns>\n        /// <remarks>Although the word &#x201c;ciphertext&#x201d; has the word &#x201c;text&#x201d;,\n        /// a returned ciphertext is not a Unicode <see cref=\"string\"/>, but a mutable\n        /// <see cref=\"byte\"/> array.</remarks>\n        /// <seealso cref=\"PrivateKey.Decrypt(ImmutableArray{byte})\"/>\n        public ImmutableArray<byte> Encrypt(ImmutableArray<byte> message) =>\n            Encrypt(message.ToBuilder().ToArray()).ToImmutableArray();\n\n        /// <summary>\n        /// Verifies whether a <paramref name=\"signature\"/> proves authenticity of\n        /// <paramref name=\"message\"/> with the corresponding <see cref=\"PrivateKey\"/>.\n        /// </summary>\n        /// <param name=\"message\">A original plaintext message that the <paramref name=\"signature\"/>\n        /// tries to prove its authenticity.  I.e., an argument data passed to\n        /// <see cref=\"PrivateKey.Sign(byte[])\"/> or <see\n        /// cref=\"PrivateKey.Sign(ImmutableArray{byte})\" /> methods.</param>\n        /// <param name=\"signature\">A signature which tries to authenticity of\n        /// <paramref name=\"message\"/>.  I.e., a data that <see cref=\"PrivateKey.Sign(byte[])\"/> or\n        /// <see cref=\"PrivateKey.Sign(ImmutableArray{byte})\"/> methods returned.</param>\n        /// <returns><see langword=\"true\"/> if the <paramref name=\"signature\"/> proves authenticity\n        /// of the <paramref name=\"message\"/> with the corresponding <see cref=\"PrivateKey\"/>.\n        /// Otherwise <see langword=\"false\"/>.</returns>\n        [Pure]\n        public bool Verify(IReadOnlyList<byte> message, IReadOnlyList<byte> signature)\n        {\n            if (message == null)\n            {\n                throw new ArgumentNullException(nameof(message));\n            }\n\n            if (signature == null)\n            {\n                throw new ArgumentNullException(nameof(signature));\n            }\n\n            if (signature is ImmutableArray<byte> i ? i.IsDefaultOrEmpty : !signature.Any())\n            {\n                return false;\n            }\n\n            try\n            {\n                HashDigest<SHA256> hashed = message switch\n                {\n                    byte[] ma => HashDigest<SHA256>.DeriveFrom(ma),\n                    ImmutableArray<byte> im => HashDigest<SHA256>.DeriveFrom(im),\n                    _ => HashDigest<SHA256>.DeriveFrom(message.ToArray()),\n                };\n                return CryptoConfig.CryptoBackend.Verify(\n                    hashed,\n                    signature is byte[] ba ? ba : signature.ToArray(),\n                    publicKey: this\n                );\n            }\n            catch (Exception)\n            {\n                return false;\n            }\n        }\n\n        /// <summary>\n        /// Gets the public key's hexadecimal representation in compressed form.\n        /// </summary>\n        /// <param name=\"compress\">Returns a short length representation if it is\n        /// <see langword=\"true\"/>.  This option does not lose any information.</param>\n        /// <returns>The hexadecimal string of the public key's compressed bytes.</returns>\n        /// <seealso cref=\"FromHex(string)\"/>\n        public string ToHex(bool compress) => ByteUtil.Hex(Format(compress));\n\n        /// <inheritdoc cref=\"object.ToString()\"/>\n        public override string ToString() => ToHex(true);\n\n        private static ECPublicKeyParameters GetECPublicKeyParameters(byte[] bs)\n        {\n            var ecParams = PrivateKey.GetECParameters();\n            return new ECPublicKeyParameters(\n                \"ECDSA\",\n                ecParams.Curve.DecodePoint(bs),\n                ecParams\n            );\n        }\n    }\n\n    /// <summary>\n    /// The <see cref=\"TypeConverter\"/> implementation for <see cref=\"PublicKey\"/>.\n    /// </summary>\n    [SuppressMessage(\n        \"StyleCop.CSharp.MaintainabilityRules\",\n        \"SA1402:FileMayOnlyContainASingleClass\",\n        Justification = \"It's okay to have non-public classes together in a single file.\"\n    )]\n    internal class PublicKeyTypeConverter : TypeConverter\n    {\n        /// <inheritdoc cref=\"TypeConverter.CanConvertFrom(ITypeDescriptorContext?, Type)\"/>\n        public override bool CanConvertFrom(ITypeDescriptorContext? context, Type sourceType) =>\n            sourceType == typeof(string) || base.CanConvertFrom(context, sourceType);\n\n        /// <inheritdoc\n        /// cref=\"TypeConverter.ConvertFrom(ITypeDescriptorContext?, CultureInfo?, object)\"/>\n        public override object? ConvertFrom(\n            ITypeDescriptorContext? context,\n            CultureInfo? culture,\n            object value\n        )\n        {\n            if (value is string v)\n            {\n                try\n                {\n                    return PublicKey.FromHex(v);\n                }\n                catch (Exception e) when (e is ArgumentException || e is FormatException)\n                {\n                    throw new ArgumentException(e.Message, e);\n                }\n            }\n\n            return base.ConvertFrom(context, culture, value);\n        }\n\n        /// <inheritdoc cref=\"TypeConverter.CanConvertTo(ITypeDescriptorContext?, Type?)\"/>\n        public override bool CanConvertTo(ITypeDescriptorContext? context, Type? destinationType) =>\n            destinationType == typeof(string) || base.CanConvertTo(context, destinationType);\n\n        /// <inheritdoc\n        /// cref=\"TypeConverter.ConvertTo(ITypeDescriptorContext?, CultureInfo?, object?, Type)\"/>\n        public override object? ConvertTo(\n            ITypeDescriptorContext? context,\n            CultureInfo? culture,\n            object? value,\n            Type destinationType\n        ) =>\n            value is PublicKey key && destinationType == typeof(string)\n                ? key.ToHex(true)\n                : base.ConvertTo(context, culture, value, destinationType);\n    }\n\n    [SuppressMessage(\n        \"StyleCop.CSharp.MaintainabilityRules\",\n        \"SA1402:FileMayOnlyContainASingleClass\",\n        Justification = \"It's okay to have non-public classes together in a single file.\"\n    )]\n    internal class PublicKeyJsonConverter : JsonConverter<PublicKey>\n    {\n        public override PublicKey Read(\n            ref Utf8JsonReader reader,\n            Type typeToConvert,\n            JsonSerializerOptions options\n        )\n        {\n            string? hex = reader.GetString();\n            try\n            {\n                return PublicKey.FromHex(hex!);\n            }\n            catch (Exception e) when (e is ArgumentException || e is FormatException)\n            {\n                throw new JsonException(e.Message);\n            }\n        }\n\n        public override void Write(\n            Utf8JsonWriter writer,\n            PublicKey value,\n            JsonSerializerOptions options\n        ) =>\n            writer.WriteStringValue(value.ToHex(true));\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Crypto/SymmetricKey.cs",
    "content": "using System;\nusing System.Collections.Immutable;\nusing System.Diagnostics.Contracts;\nusing System.IO;\nusing System.Linq;\nusing Libplanet.Common;\nusing Org.BouncyCastle.Crypto;\nusing Org.BouncyCastle.Crypto.Engines;\nusing Org.BouncyCastle.Crypto.Modes;\nusing Org.BouncyCastle.Crypto.Parameters;\nusing Org.BouncyCastle.Security;\n\nnamespace Libplanet.Crypto\n{\n    /// <summary>\n    /// An <a href=\"https://en.wikipedia.org/wiki/Advanced_Encryption_Standard\"\n    /// >AES</a>-<a href=\"https://en.wikipedia.org/wiki/Galois/Counter_Mode\"\n    /// >GCM</a> <a href=\"https://en.wikipedia.org/wiki/Symmetric-key_algorithm\"\n    /// >symmetric key</a>.  Unlike <see cref=\"PrivateKey\"/> and\n    /// <see cref=\"PublicKey\"/> that are involved in an asymmetric key\n    /// cryptography, it uses the same <see cref=\"SymmetricKey\"/> for both\n    /// encrypting a plaintext and decrypting a ciphertext.\n    /// </summary>\n    public class SymmetricKey : IEquatable<SymmetricKey>\n    {\n        private const int KeyBitSize = 256;\n        private const int MacBitSize = 128;\n        private const int NonceBitSize = 128;\n\n        private readonly SecureRandom _secureRandom;\n\n        private readonly byte[] _key;\n\n        /// <summary>\n        /// Creates a <see cref=\"SymmetricKey\"/> instance from the given\n        /// <see cref=\"byte\"/> array (i.e., <paramref name=\"key\"/>),\n        /// which encodes a valid <a\n        /// href=\"https://en.wikipedia.org/wiki/Advanced_Encryption_Standard\"\n        /// >AES</a>-<a href=\"https://en.wikipedia.org/wiki/Galois/Counter_Mode\"\n        /// >GCM</a> <a\n        /// href=\"https://en.wikipedia.org/wiki/Symmetric-key_algorithm\"\n        /// >symmetric key</a>.\n        /// </summary>\n        /// <param name=\"key\">A valid <see cref=\"byte\"/> array that\n        /// encodes an AES-GCM symmetric key.\n        /// </param>\n        /// <remarks>A valid <see cref=\"byte\"/> array for\n        /// a <see cref=\"SymmetricKey\"/> can be encoded using\n        /// <see cref=\"ToByteArray()\"/> method.\n        /// </remarks>\n        /// <seealso cref=\"ToByteArray()\"/>\n        public SymmetricKey(byte[] key)\n        {\n            _secureRandom = new SecureRandom();\n\n            if (key == null || key.Length != KeyBitSize / 8)\n            {\n                throw new ArgumentException(\n                    $\"Key needs to be {KeyBitSize} bit!\",\n                    nameof(key));\n            }\n\n            _key = key;\n        }\n\n        /// <summary>\n        /// An immutable <see cref=\"byte\"/> array encoding of this key.\n        /// </summary>\n        /// <remarks>This is immutable.  For a mutable array, call\n        /// <see cref=\"ToByteArray()\"/> method.</remarks>\n        /// <seealso cref=\"ToByteArray()\"/>\n        [Pure]\n        public ImmutableArray<byte> ByteArray => _key.ToImmutableArray();\n\n        public static bool operator ==(SymmetricKey left, SymmetricKey right) => left.Equals(right);\n\n        public static bool operator !=(SymmetricKey left, SymmetricKey right) =>\n            !left.Equals(right);\n\n        public bool Equals(SymmetricKey? other)\n        {\n            if (other is null)\n            {\n                return false;\n            }\n\n            if (ReferenceEquals(this, other))\n            {\n                return true;\n            }\n\n            return ByteArray.SequenceEqual(other.ByteArray);\n        }\n\n        public override bool Equals(object? obj) => obj is SymmetricKey other && Equals(other);\n\n        public override int GetHashCode() => ByteUtil.CalculateHashCode(ToByteArray());\n\n        /// <summary>\n        /// Converts a plain <paramref name=\"message\"/> to a ciphertext\n        /// which can be decrypted with the same key.\n        /// </summary>\n        /// <param name=\"message\">A binary data to be encrypted.</param>\n        /// <param name=\"nonSecret\">An extra data not to be encrypted, but\n        /// to be just transmitted as is.  The default value is <see langword=\"null\"/>,\n        /// which means empty.</param>\n        /// <returns>\n        /// A ciphertext that was encrypted from the <paramref name=\"message\"/>\n        /// and can be decrypted with the same key.\n        /// (Although the word &#x201c;ciphertext&#x201d; has the word\n        /// &#x201c;text&#x201d;, a returned ciphertext is not a Unicode\n        /// <see cref=\"string\"/>, but a <see cref=\"byte\"/> array.)\n        /// </returns>\n        /// <seealso cref=\"Decrypt(byte[], int)\"/>\n        [Pure]\n        public byte[] Encrypt(byte[] message, byte[]? nonSecret = null)\n        {\n            var nonce = new byte[NonceBitSize / 8];\n            _secureRandom.NextBytes(nonce, 0, nonce.Length);\n\n            nonSecret = nonSecret ?? new byte[] { };\n\n            var cipher = new GcmBlockCipher(new AesEngine());\n            var parameters = new AeadParameters(\n                new KeyParameter(_key), MacBitSize, nonce, nonSecret\n            );\n            cipher.Init(true, parameters);\n\n            var cipherText = new byte[cipher.GetOutputSize(message.Length)];\n            int len =\n                cipher.ProcessBytes(message, 0, message.Length, cipherText, 0);\n            cipher.DoFinal(cipherText, len);\n\n            using var combinedStream = new MemoryStream();\n            using (var binaryWriter = new BinaryWriter(combinedStream))\n            {\n                binaryWriter.Write(nonSecret);\n                binaryWriter.Write(nonce);\n                binaryWriter.Write(cipherText);\n            }\n\n            return combinedStream.ToArray();\n        }\n\n        /// <summary>\n        /// Converts a <paramref name=\"ciphertext\"/> which was encrypted with\n        /// the same key to the plain message.\n        /// </summary>\n        /// <param name=\"ciphertext\">The encrypted data.</param>\n        /// <param name=\"nonSecretLength\">The length of <c>nonSecret</c> data.\n        /// (See also <see cref=\"Encrypt(byte[], byte[])\"/> method's the second\n        /// parameter, which is optional.)  <c>0</c> by default.</param>\n        /// <returns>The plain data the <paramref name=\"ciphertext\"/> encrypted.\n        /// It returns <see langword=\"null\"/> if the <paramref name=\"ciphertext\"/> is\n        /// invalid (this behavior will be eventually changed in the future to\n        /// throw an exception instead).</returns>\n        /// <remarks>\n        /// Although the parameter name <paramref name=\"ciphertext\"/> has the\n        /// word &#x201c;text&#x201d;, both a <paramref name=\"ciphertext\"/>\n        /// and a returned message are a <see cref=\"byte\"/> string,\n        /// not a Unicode <see cref=\"string\"/>.\n        /// </remarks>\n        /// <seealso cref=\"Encrypt(byte[], byte[])\"/>\n        [Pure]\n        public byte[] Decrypt(byte[] ciphertext, int nonSecretLength = 0)\n        {\n            if (ciphertext == null || ciphertext.Length == 0)\n            {\n                throw new ArgumentException(\n                    \"Encrypted Message Required!\",\n                    nameof(ciphertext));\n            }\n\n            using var cipherStream = new MemoryStream(ciphertext);\n            using var cipherReader = new BinaryReader(cipherStream);\n            byte[] nonSecretPayload = cipherReader.ReadBytes(\n                nonSecretLength\n            );\n            byte[] nonce = cipherReader.ReadBytes(NonceBitSize / 8);\n\n            var cipher = new GcmBlockCipher(new AesEngine());\n            var parameters = new AeadParameters(\n                new KeyParameter(_key),\n                MacBitSize,\n                nonce,\n                nonSecretPayload);\n            cipher.Init(false, parameters);\n\n            byte[] cipherText = cipherReader.ReadBytes(\n                ciphertext.Length - nonSecretLength - nonce.Length\n            );\n            var plainText =\n                new byte[cipher.GetOutputSize(cipherText.Length)];\n\n            try\n            {\n                int len = cipher.ProcessBytes(\n                    cipherText, 0, cipherText.Length, plainText, 0\n                );\n                cipher.DoFinal(plainText, len);\n                return plainText;\n            }\n            catch (InvalidCipherTextException)\n            {\n                throw new InvalidCiphertextException(\n                    \"The ciphertext is invalid. \" +\n                    \"Ciphertext may not have been encrypted with \" +\n                    \"the corresponding public key\");\n            }\n        }\n\n        /// <summary>\n        /// Gets a mutable <see cref=\"byte\"/> array which encodes this key.\n        /// </summary>\n        /// <returns>A new mutable <see cref=\"byte\"/> array which encodes this\n        /// key.  Since it is created every time the method is called, any\n        /// mutation on that does not affect this <see cref=\"SymmetricKey\"/>\n        /// object.</returns>\n        /// <seealso cref=\"ByteArray\"/>\n        /// <seealso cref=\"SymmetricKey(byte[])\"/>\n        [Pure]\n        public byte[] ToByteArray() => ByteArray.ToArray();\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Crypto.Secp256k1/Libplanet.Crypto.Secp256k1.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <PropertyGroup>\n    <LangVersion>10</LangVersion>\n    <TreatWarningsAsErrors>true</TreatWarningsAsErrors>\n    <NoWarn>$(NoWarn);NU5104</NoWarn>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <PackageReference Include=\"Secp256k1.Net\" Version=\"1.0.0-alpha\" />\n    <PackageReference Include=\"Secp256k1.Native\" Version=\"0.1.24-alpha\" />\n  </ItemGroup>\n\n  <ItemGroup Condition=\"'$(SkipSonar)' != 'true'\">\n    <PackageReference Remove=\"SonarAnalyzer.CSharp\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <ProjectReference Include=\"..\\Libplanet\\Libplanet.csproj\" />\n  </ItemGroup>\n</Project>\n"
  },
  {
    "path": "src/Libplanet.Crypto.Secp256k1/Secp256k1CryptoBackend.cs",
    "content": "using Libplanet.Common;\nusing Libplanet.Crypto;\n\nnamespace Libplanet.Crypto.Secp256k1;\n\nusing System.Diagnostics.CodeAnalysis;\nusing System.Linq;\nusing System.Security.Cryptography;\nusing Libplanet;\nusing Secp256k1Net;\nusing Libplanet.Crypto;\n\n[SuppressMessage(\n    \"Minor Code Smell\",\n    \"S101:Types should be named in PascalCase\",\n    Justification = \"Term \\\"secp256k1\\\" is a single word.\")]\npublic class Secp256k1CryptoBackend<T> : ICryptoBackend<T>\n    where T : HashAlgorithm\n{\n    private readonly Secp256k1 _instance = new Secp256k1();\n    private readonly object _instanceLock = new object();\n\n    public byte[] Sign(HashDigest<T> messageHash, PrivateKey privateKey)\n    {\n        lock (_instanceLock)\n        {\n            var secp256K1Signature = new byte[Secp256k1.SIGNATURE_LENGTH];\n            var privateKeyBytes = new byte[Secp256k1.PRIVKEY_LENGTH];\n\n            privateKey.ByteArray.CopyTo(\n                privateKeyBytes,\n                Secp256k1.PRIVKEY_LENGTH - privateKey.ByteArray.Length);\n\n            _instance.Sign(\n                secp256K1Signature,\n                messageHash.ToByteArray(),\n                privateKeyBytes);\n\n            var signature = new byte[Secp256k1.SERIALIZED_DER_SIGNATURE_MAX_SIZE];\n            _instance.SignatureSerializeDer(\n                signature,\n                secp256K1Signature,\n                out int signatureLength);\n\n            return signature.Take(signatureLength).ToArray();\n        }\n    }\n\n    public bool Verify(\n        HashDigest<T> messageHash,\n        byte[] signature,\n        PublicKey publicKey)\n    {\n        lock (_instanceLock)\n        {\n            var secp256K1Signature = new byte[64];\n            _instance.SignatureParseDer(secp256K1Signature, signature);\n\n            byte[] secp256K1PublicKey = new byte[64];\n            byte[] serializedPublicKey = publicKey.Format(false);\n            _instance.PublicKeyParse(secp256K1PublicKey, serializedPublicKey);\n\n            return _instance.Verify(\n                secp256K1Signature,\n                messageHash.ToByteArray(),\n                secp256K1PublicKey);\n        }\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Net/ActionExecutionState.cs",
    "content": "using System;\nusing Libplanet.Types.Blocks;\n\nnamespace Libplanet.Net\n{\n    /// <summary>\n    /// Indicates a progress of executing block actions.\n    /// </summary>\n    [Obsolete(\"This is no longer compatible with the current preloading scheme.\")]\n    public class ActionExecutionState : BlockSyncState, IEquatable<ActionExecutionState>\n    {\n        /// <summary>\n        /// Total number of blocks to execute in the current batch.\n        /// </summary>\n        public int TotalBlockCount { get; internal set; }\n\n        /// <summary>\n        /// The number of currently executed blocks.\n        /// </summary>\n        public int ExecutedBlockCount { get; internal set; }\n\n        /// <summary>\n        /// The hash digest of the block just executed.\n        /// </summary>\n        public BlockHash ExecutedBlockHash { get; internal set; }\n\n        /// <inheritdoc />\n        public override int CurrentPhase => 5;\n\n        public static bool operator ==(ActionExecutionState left, ActionExecutionState right) =>\n            left.Equals(right);\n\n        public static bool operator !=(ActionExecutionState left, ActionExecutionState right) =>\n            !left.Equals(right);\n\n        public bool Equals(ActionExecutionState? other)\n        {\n            if (other is null)\n            {\n                return false;\n            }\n\n            if (ReferenceEquals(this, other))\n            {\n                return true;\n            }\n\n            return base.Equals(other) &&\n                   TotalBlockCount == other.TotalBlockCount &&\n                   ExecutedBlockCount == other.ExecutedBlockCount &&\n                   ExecutedBlockHash.Equals(other.ExecutedBlockHash);\n        }\n\n        public override bool Equals(object? obj) =>\n            obj is ActionExecutionState other && Equals(other);\n\n        public override int GetHashCode() => HashCode.Combine(\n                base.GetHashCode(),\n                TotalBlockCount,\n                ExecutedBlockCount,\n                ExecutedBlockHash);\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Net/AppProtocolVersion.cs",
    "content": "using System;\nusing System.Collections.Immutable;\nusing System.Diagnostics.Contracts;\nusing System.Globalization;\nusing System.Linq;\nusing Bencodex;\nusing Bencodex.Types;\nusing Libplanet.Common;\nusing Libplanet.Crypto;\nusing NetMQ;\n\nnamespace Libplanet.Net\n{\n    /// <summary>\n    /// A <em>claim</em> of a version.\n    /// <para>Every peer in network shows others their <see cref=\"AppProtocolVersion\"/> information.\n    /// As every peer can change its software by itself, this <see cref=\"AppProtocolVersion\"/>\n    /// is theoretically arbitrary, hence a &#x201c;claim.&#x201d; (i.e., no authority).</para>\n    /// <para>In order to verify who claimed a version, every <see cref=\"AppProtocolVersion\"/>\n    /// has its <see cref=\"Signature\"/> which is made by its <see cref=\"Signer\"/>.\n    /// <see cref=\"Verify(PublicKey)\"/> method purposes to determine whether an information\n    /// is claimed by its corresponding <see cref=\"Signer\"/> in fact.</para>\n    /// </summary>\n    public readonly struct AppProtocolVersion : IEquatable<AppProtocolVersion>\n    {\n        /// <summary>\n        /// The version number.  This does not have to be increased by only 1, but can be more\n        /// than that.\n        /// </summary>\n        public readonly int Version;\n\n        /// <summary>\n        /// Optional extra data about the version.  This can be used for any purpose\n        /// by apps, such as a URL to download the software.\n        /// </summary>\n        public readonly IValue? Extra;\n\n        /// <summary>\n        /// A signer who claims presence of a version.\n        /// </summary>\n        public readonly Address Signer;\n\n        private static readonly Codec _codec = new Codec();\n\n        private readonly ImmutableArray<byte> _signature;\n\n        /// <summary>\n        /// Initializes an <see cref=\"AppProtocolVersion\"/> value with field values.\n        /// </summary>\n        /// <param name=\"version\">Sets the <see cref=\"Version\"/>.</param>\n        /// <param name=\"extra\">Sets the <see cref=\"Extra\"/>.</param>\n        /// <param name=\"signature\">Sets the <see cref=\"Signature\"/>.</param>\n        /// <param name=\"signer\">Gets the <see cref=\"Signer\"/>.</param>\n        public AppProtocolVersion(\n            int version,\n            IValue? extra,\n            ImmutableArray<byte> signature,\n            Address signer\n        )\n        {\n            Version = version;\n            Extra = extra;\n            _signature = signature;\n            Signer = signer;\n        }\n\n        /// <summary>\n        /// A signature which verifies <seealso cref=\"Signer\"/>'s claim of a version.\n        /// </summary>\n        public ImmutableArray<byte> Signature =>\n            _signature.IsDefault ? ImmutableArray<byte>.Empty : _signature;\n\n        /// <summary>\n        /// A token string which serializes an <see cref=\"AppProtocolVersion\"/>.\n        /// <para>As this is designed to be easy to copy and paste, the format consists of only\n        /// printable characters in the ASCII character set.</para>\n        /// <para>A token can be deserialized into an <see cref=\"AppProtocolVersion\"/> through\n        /// <see cref=\"FromToken(string)\"/> method.</para>\n        /// </summary>\n        /// <seealso cref=\"FromToken(string)\"/>\n        [Pure]\n        public string Token\n        {\n            get\n            {\n                string sig = Convert.ToBase64String(\n                    Signature.ToArray(),\n                    Base64FormattingOptions.None\n                ).Replace('/', '.');\n                var prefix =\n                    $\"{Version.ToString(CultureInfo.InvariantCulture)}/{Signer.ToHex()}/{sig}\";\n                if (Extra is null)\n                {\n                    return prefix;\n                }\n\n                string extra = Convert.ToBase64String(\n                    _codec.Encode(Extra),\n                    Base64FormattingOptions.None\n                ).Replace('/', '.');\n                return $\"{prefix}/{extra}\";\n            }\n        }\n\n        [Pure]\n        public static bool operator ==(AppProtocolVersion left, AppProtocolVersion right) =>\n            left.Equals(right);\n\n        [Pure]\n        public static bool operator !=(AppProtocolVersion left, AppProtocolVersion right) =>\n            !(left == right);\n\n        /// <summary>\n        /// Claim a <paramref name=\"version\"/> with <paramref name=\"extra\"/> data and sign it\n        /// using the given private key.\n        /// </summary>\n        /// <param name=\"signer\">A private key to sign the claim.</param>\n        /// <param name=\"version\">A version to claim.</param>\n        /// <param name=\"extra\">Extra data to claim.</param>\n        /// <returns>A signed version claim.</returns>\n        /// <exception cref=\"ArgumentNullException\">Thrown when <paramref name=\"signer\"/> is\n        /// <see langword=\"null\"/>.</exception>\n        public static AppProtocolVersion Sign(PrivateKey signer, int version, IValue? extra = null)\n        {\n            if (signer is null)\n            {\n                throw new ArgumentNullException(nameof(signer));\n            }\n\n            return new AppProtocolVersion(\n                version,\n                extra,\n                ImmutableArray.Create(signer.Sign(GetMessage(version, extra))),\n                new Address(signer.PublicKey)\n            );\n        }\n\n        /// <summary>\n        /// Deserializes a <see cref=\"Token\"/> into an <see cref=\"AppProtocolVersion\"/> object.\n        /// </summary>\n        /// <param name=\"token\">A <see cref=\"Token\"/> string.</param>\n        /// <returns>A deserialized <see cref=\"AppProtocolVersion\"/> object.</returns>\n        /// <exception cref=\"ArgumentNullException\">Thrown when <see langword=\"null\"/> is passed to\n        /// <paramref name=\"token\"/>.</exception>\n        /// <exception cref=\"FormatException\">Thrown when the given <paramref name=\"token\"/>'s\n        /// format is invalid.  The detailed reason is in the message.</exception>\n        /// <seealso cref=\"Token\"/>\n        public static AppProtocolVersion FromToken(string token)\n        {\n            if (token is null)\n            {\n                throw new ArgumentNullException(nameof(token));\n            }\n\n            int pos, pos2;\n            pos = token.IndexOf('/');\n            if (pos < 0)\n            {\n                throw new FormatException($\"Failed to find the first field delimiter: {token}\");\n            }\n\n            int version;\n            try\n            {\n                version = int.Parse(token.Substring(0, pos), CultureInfo.InvariantCulture);\n            }\n            catch (Exception e) when (e is OverflowException || e is FormatException)\n            {\n                throw new FormatException($\"Failed to parse a version number: {token}\", e);\n            }\n\n            pos++;\n            pos2 = token.IndexOf('/', pos);\n            if (pos2 < 0)\n            {\n                throw new FormatException($\"Failed to find the second field delimiter: {token}\");\n            }\n\n            Address signer;\n            try\n            {\n                signer = new Address(token.Substring(pos, pos2 - pos));\n            }\n            catch (ArgumentException e)\n            {\n                throw new FormatException($\"Failed to parse a signer address: {token}\", e);\n            }\n\n            pos2++;\n            pos = token.IndexOf('/', pos2);\n            string sigEncoded = pos < 0 ? token.Substring(pos2) : token.Substring(pos2, pos - pos2);\n\n            ImmutableArray<byte> sig;\n            try\n            {\n                sig = ImmutableArray.Create(Convert.FromBase64String(sigEncoded.Replace('.', '/')));\n            }\n            catch (FormatException e)\n            {\n                throw new FormatException($\"Failed to parse a signature: {token}\", e);\n            }\n\n            IValue? extra = null;\n            if (pos >= 0)\n            {\n                pos++;\n                string extraEncoded = token.Substring(pos);\n                byte[] extraBytes = Convert.FromBase64String(extraEncoded.Replace('.', '/'));\n                try\n                {\n                    extra = _codec.Decode(extraBytes);\n                }\n                catch (DecodingException e)\n                {\n                    throw new FormatException(\n                        $\"Failed to parse extra data (offset = {pos}): {token}\", e);\n                }\n            }\n\n            return new AppProtocolVersion(version, extra, sig, signer);\n        }\n\n        /// <summary>\n        /// Verifies whether the claim is certainly signed by the <see cref=\"Signer\"/>.\n        /// </summary>\n        /// <param name=\"publicKey\">A public key of the <see cref=\"Signer\"/>.</param>\n        /// <returns><see langword=\"true\"/> if and only if the given <paramref name=\"publicKey\"/> is\n        /// <see cref=\"Signer\"/>'s and the <see cref=\"Signature\"/> is certainly signed by\n        /// the <see cref=\"Signer\"/>.</returns>\n        [Pure]\n        public bool Verify(PublicKey publicKey) =>\n            Signer.Equals(new Address(publicKey)) &&\n            publicKey.Verify(GetMessage(Version, Extra), Signature.ToBuilder().ToArray());\n\n        /// <inheritdoc/>\n        [Pure]\n        public bool Equals(AppProtocolVersion other) =>\n            /* The reason why we need to check other fields than the Signature is that\n            this struct in itself does not guarantee its Signature is derived from\n            other field values.  A value of this struct can represent an invalid claim. */\n            Version == other.Version &&\n            Signer.Equals(other.Signer) &&\n            Equals(Extra, other.Extra) &&\n            Signature.SequenceEqual(other.Signature);\n\n        /// <inheritdoc/>\n        [Pure]\n        public override bool Equals(object? obj) =>\n            obj is AppProtocolVersion other && Equals(other);\n\n        /// <inheritdoc/>\n        [Pure]\n        public override int GetHashCode()\n        {\n            int hash = 17;\n            unchecked\n            {\n                hash *= 31 + Version.GetHashCode();\n                hash *= 31 + (Extra is null ? 0 : Extra.GetHashCode());\n                hash *= 31 + ByteUtil.CalculateHashCode(Signature.ToArray());\n                hash *= 31 + Signer.GetHashCode();\n            }\n\n            return hash;\n        }\n\n        /// <inheritdoc/>\n        [Pure]\n        public override string ToString() => string.Format(\n            CultureInfo.InvariantCulture,\n            Extra is null ? \"{0}\" : \"{0} ({1})\",\n            Version,\n            Extra\n        );\n\n        /// <summary>\n        /// Gets a deterministic message to sign.\n        /// </summary>\n        /// <returns>A deterministic message to sign.</returns>\n        [Pure]\n        private static byte[] GetMessage(int version, IValue? extra)\n        {\n            byte[] msg = NetworkOrderBitsConverter.GetBytes(version);\n            if (!(extra is null))\n            {\n                byte[] extraBytes = _codec.Encode(extra);\n                int versionLength = msg.Length;\n                Array.Resize(ref msg, versionLength + extraBytes.Length);\n                extraBytes.CopyTo(msg, versionLength);\n            }\n\n            return msg;\n        }\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Net/AssemblyInfo.cs",
    "content": "using System.Runtime.CompilerServices;\n\n[assembly: InternalsVisibleTo(\"Libplanet.Benchmarks\")]\n[assembly: InternalsVisibleTo(\"Libplanet.Net.Tests\")]\n"
  },
  {
    "path": "src/Libplanet.Net/AsyncDelegate.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Threading.Tasks;\n\nnamespace Libplanet.Net\n{\n    public class AsyncDelegate<T>\n    {\n        private IEnumerable<Func<T, Task>> _functions;\n\n        public AsyncDelegate()\n        {\n            _functions = new List<Func<T, Task>>();\n        }\n\n        public void Register(Func<T, Task> func)\n        {\n#pragma warning disable PC002\n            // Usage of a .NET Standard API that isn’t available on the .NET Framework 4.6.1\n#if NETFRAMEWORK && !NET48 && !NET472 && !NET471\n            _functions = _functions.Concat(new[] { func });\n#else\n            _functions = _functions.Append(func);\n#endif\n#pragma warning restore PC002\n        }\n\n        public void Unregister(Func<T, Task> func)\n        {\n            _functions = _functions.Where(f => !f.Equals(func));\n        }\n\n        public async Task InvokeAsync(T arg)\n        {\n            IEnumerable<Task> tasks = _functions.Select(f => f(arg));\n            await Task.WhenAll(tasks).ConfigureAwait(false);\n        }\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Net/BlockCandidateTable.cs",
    "content": "using System;\nusing System.Collections.Concurrent;\nusing System.Collections.Generic;\nusing System.Linq;\nusing Libplanet.Blockchain;\nusing Libplanet.Types.Blocks;\nusing Serilog;\n\nnamespace Libplanet.Net\n{\n    /// <summary>\n    /// <para>\n    /// A class for storing downloaded <see cref=\"Block\"/>s as <see cref=\"Dictionary{K, V}\"/>.\n    /// A <see cref=\"BlockHeader\"/> is used as a key for storing downloading context.\n    /// </para>\n    /// <para>\n    /// This is designed to be exception free.\n    /// </para>\n    /// </summary>\n    public class BlockCandidateTable\n    {\n        private readonly ILogger _logger;\n        private readonly ConcurrentDictionary<BlockHeader, Branch> _table;\n\n        public BlockCandidateTable()\n        {\n            _logger = Log\n                .ForContext<BlockCandidateTable>()\n                .ForContext(\"Source\", nameof(BlockCandidateTable));\n            _table = new ConcurrentDictionary<BlockHeader, Branch>();\n        }\n\n        public long Count\n        {\n            get => _table.Count;\n        }\n\n        /// <summary>\n        /// <para>\n        /// Adds given <paramref name=\"branch\"/> to the table.\n        /// </para>\n        /// <para>\n        /// The internal table is only updated if it does not already contain\n        /// <paramref name=\"blockHeader\"/> as its key.\n        /// </para>\n        /// </summary>\n        /// <param name=\"blockHeader\">The header of the <see cref=\"BlockChain\"/>'s\n        /// tip at the time of downloading the blocks.</param>\n        /// <param name=\"branch\">The list of downloaded <see cref=\"Block\"/>s and\n        /// its <see cref=\"BlockCommit\"/>s.</param>\n        public void Add(BlockHeader blockHeader, Branch branch)\n        {\n            if (_table.ContainsKey(blockHeader))\n            {\n                var root = branch.Blocks.First().Item1;\n                var tip = branch.Blocks.Last().Item1;\n                _logger.Debug(\n                    \"Given branch with root #{RootIndex} {RootHash} and \" +\n                    \"tip #{TipIndex} {TipHash} will not be added as the table already contains \" +\n                    \"blockheader #{Index} {BlockHash} as its key\",\n                    root.Index,\n                    root.Hash,\n                    tip.Index,\n                    tip.Hash,\n                    blockHeader.Index,\n                    blockHeader.Hash);\n                return;\n            }\n\n            _table.TryAdd(blockHeader, branch);\n            _logger\n                .ForContext(\"Tag\", \"Metric\")\n                .ForContext(\"Subtag\", \"CandidateTableCount\")\n                .Information(\n                    \"There are {Count} branches in {ClassName}\",\n                    _table.Count,\n                    nameof(BlockCandidateTable));\n        }\n\n        /// <summary>\n        /// Get the <see cref=\"Block\"/>s which are in the table by <see cref=\"BlockHeader\"/>.\n        /// </summary>\n        /// <param name=\"thisRoundTip\">Canonical <see cref=\"BlockChain\"/>'s\n        /// tip of this round.</param>\n        /// <returns>A <see cref=\"List{T}\"/> of <see cref=\"Block\"/>s with associated\n        /// <see cref=\"BlockCommit\"/>s by\n        /// <paramref name=\"thisRoundTip\"/> if found, otherwise <see langword=\"null\"/>.\n        /// The result is guaranteed to be non-empty and consecutive sorted by\n        /// <see cref=\"Block.Index\"/>.\n        /// </returns>\n        /// <seealso cref=\"Add\"/>\n        public Branch? GetCurrentRoundCandidate(\n            BlockHeader thisRoundTip)\n        {\n            return _table.TryGetValue(thisRoundTip, out var branch)\n                ? branch\n                : null;\n        }\n\n        public bool TryRemove(BlockHeader header)\n        {\n            return _table.TryRemove(header, out _);\n        }\n\n        public void Cleanup(Func<IBlockExcerpt, bool> predicate)\n        {\n            foreach (var blockHeader in _table.Keys)\n            {\n                if (!predicate(blockHeader))\n                {\n                    TryRemove(blockHeader);\n                }\n            }\n\n            _logger\n                .ForContext(\"Tag\", \"Metric\")\n                .ForContext(\"Subtag\", \"CandidateTableCount\")\n                .Information(\n                    \"There are {Count} branches in {ClassName}\",\n                    _table.Count,\n                    nameof(BlockCandidateTable));\n        }\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Net/BlockDemand.cs",
    "content": "using System;\nusing Libplanet.Types.Blocks;\n\nnamespace Libplanet.Net\n{\n    /// <summary>\n    /// Struct represents <see cref=\"Swarm\"/>'s block demand status.\n    /// </summary>\n    public readonly struct BlockDemand : IBlockExcerpt\n    {\n        /// <summary>\n        /// The <see cref=\"IBlockExcerpt\"/> of the block to request.\n        /// </summary>\n        public readonly IBlockExcerpt BlockExcerpt;\n\n        /// <summary>\n        /// The <see cref=\"BoundPeer\"/> to request block hash from.\n        /// </summary>\n        public readonly BoundPeer Peer;\n\n        /// <summary>\n        /// The <see cref=\"DateTimeOffset\"/> when\n        /// the corresponding block information was received.\n        /// </summary>\n        public readonly DateTimeOffset Timestamp;\n\n        public BlockDemand(IBlockExcerpt blockExcerpt, BoundPeer peer, DateTimeOffset timestamp)\n        {\n            BlockExcerpt = blockExcerpt;\n            Peer = peer;\n            Timestamp = timestamp;\n        }\n\n        /// <inheritdoc cref=\"IBlockExcerpt.ProtocolVersion\"/>\n        public int ProtocolVersion => BlockExcerpt.ProtocolVersion;\n\n        /// <inheritdoc cref=\"IBlockExcerpt.Index\"/>\n        public long Index => BlockExcerpt.Index;\n\n        /// <inheritdoc cref=\"IBlockExcerpt.Hash\"/>\n        public BlockHash Hash => BlockExcerpt.Hash;\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Net/BlockDemandTable.cs",
    "content": "using System;\nusing System.Collections.Concurrent;\nusing System.Collections.Generic;\nusing System.Linq;\nusing Libplanet.Blockchain;\nusing Libplanet.Types.Blocks;\nusing Serilog;\n\nnamespace Libplanet.Net\n{\n    public class BlockDemandTable\n    {\n        private readonly TimeSpan _blockDemandLifespan;\n        private readonly ConcurrentDictionary<BoundPeer, BlockDemand> _blockDemands;\n\n        public BlockDemandTable(TimeSpan blockDemandLifespan)\n        {\n            _blockDemandLifespan = blockDemandLifespan;\n            _blockDemands = new ConcurrentDictionary<BoundPeer, BlockDemand>();\n        }\n\n        public IDictionary<BoundPeer, BlockDemand> Demands =>\n            _blockDemands.ToDictionary(pair => pair.Key, pair => pair.Value);\n\n        public bool Any() => _blockDemands.Any();\n\n        public void Add(\n            BlockChain blockChain,\n            Func<IBlockExcerpt, bool> predicate,\n            BlockDemand demand)\n        {\n            if (IsDemandNeeded(blockChain, predicate, demand))\n            {\n                _blockDemands[demand.Peer] = demand;\n                Log.Debug(\n                    \"BlockDemand #{Index} {BlockHash} from peer {Peer} updated\",\n                    demand.Index,\n                    demand.Hash,\n                    demand.Peer);\n            }\n            else\n            {\n                Log.Debug(\n                    \"BlockDemand #{Index} {BlockHash} from peer {Peer} ignored\",\n                    demand.Index,\n                    demand.Hash,\n                    demand.Peer);\n            }\n        }\n\n        public void Remove(BoundPeer peer)\n        {\n            _blockDemands.TryRemove(peer, out _);\n        }\n\n        public void Cleanup(\n            BlockChain blockChain,\n            Func<IBlockExcerpt, bool> predicate)\n        {\n            foreach (var demand in _blockDemands.Values)\n            {\n                if (!predicate(demand) || IsDemandStale(demand))\n                {\n                    _blockDemands.TryRemove(demand.Peer, out _);\n                }\n            }\n\n            Log.Verbose(\"Successfully cleaned up demands\");\n        }\n\n        private bool IsDemandNeeded(\n            BlockChain blockChain,\n            Func<IBlockExcerpt, bool> predicate,\n            BlockDemand demand)\n        {\n            BlockDemand? oldDemand = _blockDemands.ContainsKey(demand.Peer)\n                ? _blockDemands[demand.Peer]\n                : (BlockDemand?)null;\n\n            bool needed;\n            if (IsDemandStale(demand))\n            {\n                needed = false;\n            }\n            else if (predicate(demand))\n            {\n                if (oldDemand is { } old)\n                {\n                    needed = IsDemandStale(old) || old.Index < demand.Index;\n                }\n                else\n                {\n                    needed = true;\n                }\n            }\n            else\n            {\n                needed = false;\n            }\n\n            Log.Verbose(\n                \"Determining if a demand is actually needed: {Need}\\n\" +\n                \"Peer: {Peer}\\n\" +\n                \"Demand: {Demand}\\n\" +\n                \"Tip: {Tip}\\n\" +\n                \"Old Demand: {OldDemand}\",\n                needed,\n                demand.Peer,\n                demand.ToExcerptString(),\n                blockChain.Tip.ToExcerptString(),\n                oldDemand?.ToExcerptString());\n            return needed;\n        }\n\n        private bool IsDemandStale(BlockDemand demand)\n        {\n            return demand.Timestamp + _blockDemandLifespan < DateTimeOffset.UtcNow;\n        }\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Net/BlockDownloadState.cs",
    "content": "using System;\nusing Libplanet.Types.Blocks;\n\nnamespace Libplanet.Net\n{\n    /// <summary>\n    /// Indicates a progress of downloading blocks.\n    /// </summary>\n    [Obsolete(\"This is no longer compatible with the current preloading scheme.\")]\n    public class BlockDownloadState : BlockSyncState, IEquatable<BlockDownloadState>\n    {\n        /// <summary>\n        /// Total number of blocks to receive in the current batch.\n        /// </summary>\n        public long TotalBlockCount { get; internal set; }\n\n        /// <summary>\n        /// The number of currently received blocks.\n        /// </summary>\n        public long ReceivedBlockCount { get; internal set; }\n\n        /// <summary>\n        /// The hash digest of the block just received.\n        /// </summary>\n        public BlockHash ReceivedBlockHash { get; internal set; }\n\n        /// <inheritdoc />\n        public override int CurrentPhase => 2;\n\n        /// <summary>\n        /// The peer which sent the block.\n        /// </summary>\n        public BoundPeer? SourcePeer { get; internal set; }\n\n        public static bool operator ==(BlockDownloadState left, BlockDownloadState right) =>\n            left.Equals(right);\n\n        public static bool operator !=(BlockDownloadState left, BlockDownloadState right) =>\n            !left.Equals(right);\n\n        public bool Equals(BlockDownloadState? other)\n        {\n            if (other is null)\n            {\n                return false;\n            }\n\n            if (ReferenceEquals(this, other))\n            {\n                return true;\n            }\n\n            return base.Equals(other) &&\n                   TotalBlockCount == other.TotalBlockCount &&\n                   ReceivedBlockCount == other.ReceivedBlockCount &&\n                   ReceivedBlockHash.Equals(other.ReceivedBlockHash) &&\n                   ((SourcePeer is null && other.SourcePeer is null) ||\n                    (SourcePeer is { } p1 && other.SourcePeer is { } p2 && p1.Equals(p2)));\n        }\n\n        public override bool Equals(object? obj) =>\n            obj is BlockDownloadState other && Equals(other);\n\n        public override int GetHashCode() => HashCode.Combine(\n                base.GetHashCode(),\n                TotalBlockCount,\n                ReceivedBlockCount,\n                ReceivedBlockHash,\n                SourcePeer);\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Net/BlockHashDownloadState.cs",
    "content": "using System;\n\nnamespace Libplanet.Net\n{\n    /// <summary>\n    /// Indicates a progress of downloading block hashes.\n    /// </summary>\n    [Obsolete(\"This is no longer compatible with the current preloading scheme.\")]\n    public class BlockHashDownloadState : BlockSyncState, IEquatable<BlockHashDownloadState>\n    {\n        /// <summary>\n        /// The estimated number of block hashes to receive in the current batch.\n        /// </summary>\n        public long EstimatedTotalBlockHashCount { get; internal set; }\n\n        /// <summary>\n        /// The number of currently received block hashes.\n        /// </summary>\n        public long ReceivedBlockHashCount { get; internal set; }\n\n        /// <summary>\n        /// The peer which sent the block hashes.\n        /// </summary>\n        public BoundPeer? SourcePeer { get; internal set; }\n\n        /// <inheritdoc />\n        public override int CurrentPhase => 1;\n\n        public static bool operator ==(BlockHashDownloadState left, BlockHashDownloadState right) =>\n            left.Equals(right);\n\n        public static bool operator !=(BlockHashDownloadState left, BlockHashDownloadState right) =>\n            !left.Equals(right);\n\n        public bool Equals(BlockHashDownloadState? other)\n        {\n            if (other is null)\n            {\n                return false;\n            }\n\n            if (ReferenceEquals(this, other))\n            {\n                return true;\n            }\n\n            return base.Equals(other) &&\n                   EstimatedTotalBlockHashCount == other.EstimatedTotalBlockHashCount &&\n                   ReceivedBlockHashCount == other.ReceivedBlockHashCount &&\n                   ((SourcePeer is null && other.SourcePeer is null) ||\n                    (SourcePeer is { } p1 && other.SourcePeer is { } p2 && p1.Equals(p2)));\n        }\n\n        public override bool Equals(object? obj) =>\n            obj is BlockHashDownloadState other && Equals(other);\n\n        public override int GetHashCode() => HashCode.Combine(\n                base.GetHashCode(),\n                EstimatedTotalBlockHashCount,\n                ReceivedBlockHashCount,\n                SourcePeer);\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Net/BlockSyncState.cs",
    "content": "using System;\n\nnamespace Libplanet.Net\n{\n    // <summary>\n    // Indicates a progress of preloading things from the network.\n    // </summary>\n    public abstract class BlockSyncState : IEquatable<BlockSyncState>\n    {\n        /// <summary>\n        /// The number of total phases.\n        /// </summary>\n        public const int TotalPhase = 5;\n\n        /// <summary>\n        /// The current phase.\n        /// </summary>\n        public abstract int CurrentPhase { get; }\n\n        public static bool operator ==(BlockSyncState left, BlockSyncState right) =>\n            left.Equals(right);\n\n        public static bool operator !=(BlockSyncState left, BlockSyncState right) =>\n            !left.Equals(right);\n\n        public bool Equals(BlockSyncState? other)\n        {\n            if (other is null)\n            {\n                return false;\n            }\n\n            if (ReferenceEquals(this, other))\n            {\n                return true;\n            }\n\n            return CurrentPhase == other.CurrentPhase;\n        }\n\n        public override bool Equals(object? obj) => obj is BlockSyncState other && Equals(other);\n\n        public override int GetHashCode() => CurrentPhase;\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Net/BlockVerificationState.cs",
    "content": "using System;\nusing Libplanet.Types.Blocks;\n\nnamespace Libplanet.Net\n{\n    /// <summary>\n    /// Indicates a progress of verifying blocks.\n    /// </summary>\n    [Obsolete(\"This is no longer compatible with the current preloading scheme.\")]\n    public class BlockVerificationState : BlockSyncState, IEquatable<BlockVerificationState>\n    {\n        /// <summary>\n        /// Total number of blocks to verify in the current batch.\n        /// </summary>\n        public long TotalBlockCount { get; internal set; }\n\n        /// <summary>\n        /// The number of blocks that completed verification.\n        /// </summary>\n        public long VerifiedBlockCount { get; internal set; }\n\n        /// <summary>\n        /// The hash digest of the block just verified.\n        /// </summary>\n        public BlockHash VerifiedBlockHash { get; internal set; }\n\n        /// <inheritdoc />\n        public override int CurrentPhase => 3;\n\n        public static bool operator ==(BlockVerificationState left, BlockVerificationState right) =>\n            left.Equals(right);\n\n        public static bool operator !=(BlockVerificationState left, BlockVerificationState right) =>\n            !left.Equals(right);\n\n        public bool Equals(BlockVerificationState? other)\n        {\n            if (other is null)\n            {\n                return false;\n            }\n\n            if (ReferenceEquals(this, other))\n            {\n                return true;\n            }\n\n            return base.Equals(other) &&\n                   TotalBlockCount == other.TotalBlockCount &&\n                   VerifiedBlockCount == other.VerifiedBlockCount &&\n                   VerifiedBlockHash.Equals(other.VerifiedBlockHash);\n        }\n\n        public override bool Equals(object? obj) =>\n            obj is BlockVerificationState other && Equals(other);\n\n        public override int GetHashCode() => HashCode.Combine(\n            base.GetHashCode(),\n            TotalBlockCount,\n            VerifiedBlockCount,\n            VerifiedBlockHash);\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Net/BoundPeer.cs",
    "content": "using System;\nusing System.Diagnostics.Contracts;\nusing System.Globalization;\nusing System.Net;\nusing Bencodex;\nusing Bencodex.Types;\nusing Destructurama.Attributed;\nusing Libplanet.Crypto;\n\nnamespace Libplanet.Net\n{\n    public sealed class BoundPeer : IEquatable<BoundPeer>, IBencodable\n    {\n        private static readonly byte[] PublicKeyKey = { 0x70 }; // 'p'\n        private static readonly byte[] EndPointHostKey = { 0x68 }; // 'h'\n        private static readonly byte[] EndPointPortKey = { 0x65 }; // 'e'\n        private static readonly byte[] PublicIpAddressKey = { 0x50 }; // 'P'\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"BoundPeer\"/> class.\n        /// </summary>\n        /// <param name=\"publicKey\">A <see cref=\"PublicKey\"/> of the\n        /// <see cref=\"BoundPeer\"/>.</param>\n        /// <param name=\"endPoint\">A <see cref=\"DnsEndPoint\"/> consisting of the\n        /// host and port of the <see cref=\"BoundPeer\"/>.</param>\n        public BoundPeer(\n            PublicKey publicKey,\n            DnsEndPoint endPoint)\n            : this(publicKey, endPoint, null)\n        {\n        }\n\n        public BoundPeer(Bencodex.Types.IValue bencoded)\n            : this(bencoded is Bencodex.Types.Dictionary dict\n                ? dict\n                : throw new ArgumentException(\n                    $\"Given {nameof(bencoded)} must be of type \" +\n                    $\"{typeof(Bencodex.Types.Dictionary)}: {bencoded.GetType()}\",\n                    nameof(bencoded)))\n        {\n        }\n\n        internal BoundPeer(\n            PublicKey publicKey,\n            DnsEndPoint endPoint,\n            IPAddress? publicIPAddress)\n        {\n            if (Uri.CheckHostName(endPoint.Host) == UriHostNameType.Unknown)\n            {\n                throw new ArgumentException(\n                    $\"Given {nameof(endPoint)} has unknown host name type: {endPoint.Host}\",\n                    nameof(endPoint));\n            }\n\n            PublicKey = publicKey;\n            EndPoint = endPoint;\n            PublicIPAddress = publicIPAddress;\n        }\n\n        private BoundPeer(Bencodex.Types.Dictionary bencoded)\n            : this(\n                new PublicKey(((Binary)bencoded[PublicKeyKey]).ByteArray),\n                new DnsEndPoint(\n                    (Text)bencoded[EndPointHostKey], (Integer)bencoded[EndPointPortKey]),\n                bencoded[PublicIpAddressKey] is Text text ? IPAddress.Parse(text) : null)\n        {\n        }\n\n        /// <summary>\n        /// The corresponding <see cref=\"Libplanet.Crypto.PublicKey\"/> of\n        /// this peer.\n        /// </summary>\n        [LogAsScalar]\n        [Pure]\n        public PublicKey PublicKey { get; }\n\n        /// <summary>The peer's address which is derived from\n        /// its <see cref=\"PublicKey\"/>.\n        /// </summary>\n        /// <seealso cref=\"PublicKey\"/>\n        [LogAsScalar]\n        [Pure]\n        public Address Address => new Address(PublicKey);\n\n        /// <summary>\n        /// The corresponding <see cref=\"DnsEndPoint\"/> of this peer.\n        /// </summary>\n        [LogAsScalar]\n        [Pure]\n        public DnsEndPoint EndPoint { get; }\n\n        [LogAsScalar]\n        [Pure]\n        public IPAddress? PublicIPAddress { get; }\n\n        public string PeerString => $\"{PublicKey},{EndPoint.Host},{EndPoint.Port}\";\n\n        /// <inheritdoc/>\n        [Pure]\n        public Bencodex.Types.IValue Bencoded =>\n            Bencodex.Types.Dictionary.Empty\n                .Add(PublicKeyKey, PublicKey.Format(true))\n                .Add(EndPointHostKey, EndPoint.Host)\n                .Add(EndPointPortKey, EndPoint.Port)\n                .Add(\n                    PublicIpAddressKey,\n                    PublicIPAddress is IPAddress ip ? (IValue)(Text)ip.ToString() : Null.Value);\n\n        public static bool operator ==(BoundPeer left, BoundPeer right) => left.Equals(right);\n\n        public static bool operator !=(BoundPeer left, BoundPeer right) => !left.Equals(right);\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"BoundPeer\"/> class from\n        /// comma-separated string.</summary>\n        /// <param name=\"peerInfo\">A comma-separated string have format {pubkey},{host},{port}.\n        /// </param>\n        /// <returns>A <see cref=\"BoundPeer\"/> from given data.</returns>\n        /// <exception cref=\"ArgumentException\">Thrown when the given peerInfo is invalid.\n        /// </exception>\n        public static BoundPeer ParsePeer(string peerInfo)\n        {\n            string[] tokens = peerInfo.Split(',');\n            if (tokens.Length != 3)\n            {\n                throw new ArgumentException(\n                    $\"'{peerInfo}', should have format <pubkey>,<host>,<port>\",\n                    nameof(peerInfo)\n                );\n            }\n\n            if (!(tokens[0].Length == 130 || tokens[0].Length == 66))\n            {\n                throw new ArgumentException(\n                    $\"'{peerInfo}', a length of public key must be 130 or 66 in hexadecimal,\" +\n                    $\" but the length of given public key '{tokens[0]}' doesn't.\",\n                    nameof(peerInfo)\n                );\n            }\n\n            try\n            {\n                var pubKey = PublicKey.FromHex(tokens[0]);\n                var host = tokens[1];\n                var port = int.Parse(tokens[2], CultureInfo.InvariantCulture);\n\n                // FIXME: It might be better to make Peer.AppProtocolVersion property nullable...\n                return new BoundPeer(\n                    pubKey,\n                    new DnsEndPoint(host, port));\n            }\n            catch (Exception e)\n            {\n                throw new ArgumentException(\n                    $\"{nameof(peerInfo)} seems invalid. [{peerInfo}]\",\n                    nameof(peerInfo),\n                    innerException: e\n                );\n            }\n        }\n\n        public bool Equals(BoundPeer? other)\n        {\n            if (other is null)\n            {\n                return false;\n            }\n\n            if (ReferenceEquals(this, other))\n            {\n                return true;\n            }\n\n            return PublicKey.Equals(other.PublicKey) &&\n                (PublicIPAddress?.Equals(other.PublicIPAddress) ?? other.PublicIPAddress is null) &&\n                EndPoint.Equals(other.EndPoint);\n        }\n\n        public override bool Equals(object? obj) => obj is BoundPeer other && Equals(other);\n\n        public override int GetHashCode() => HashCode.Combine(\n            HashCode.Combine(PublicKey.GetHashCode(), PublicIPAddress?.GetHashCode()), EndPoint);\n\n        /// <inheritdoc/>\n        public override string ToString()\n        {\n            return $\"{Address}.{EndPoint}.{PublicIPAddress}\";\n        }\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Net/Consensus/ConsensusContext.Event.cs",
    "content": "using System;\nusing Libplanet.Net.Messages;\n\nnamespace Libplanet.Net.Consensus\n{\n    public partial class ConsensusContext\n    {\n        /// <summary>\n        /// An event that is invoked when a <see cref=\"ConsensusMsg\"/> is published.\n        /// </summary>\n        internal event EventHandler<(long Height, ConsensusMsg Message)>? MessagePublished;\n\n        /// <inheritdoc cref=\"Context.ExceptionOccurred\"/>\n        internal event EventHandler<(long Height, Exception)>? ExceptionOccurred;\n\n        /// <inheritdoc cref=\"Context.TimeoutProcessed\"/>\n        internal event EventHandler<(long Height, int Round, ConsensusStep Step)>? TimeoutProcessed;\n\n        /// <inheritdoc cref=\"Context.StateChanged\"/>\n        internal event EventHandler<Context.ContextState>? StateChanged;\n\n        /// <inheritdoc cref=\"Context.MessageConsumed\"/>\n        internal event EventHandler<(long Height, ConsensusMsg Message)>? MessageConsumed;\n\n        /// <inheritdoc cref=\"Context.MutationConsumed\"/>\n        internal event EventHandler<(long Height, System.Action)>? MutationConsumed;\n\n        private void AttachEventHandlers(Context context)\n        {\n            // NOTE: Events for testing and debugging.\n            context.ExceptionOccurred += (sender, exception) =>\n                ExceptionOccurred?.Invoke(this, (context.Height, exception));\n            context.TimeoutProcessed += (sender, eventArgs) =>\n                TimeoutProcessed?.Invoke(this, (context.Height, eventArgs.Round, eventArgs.Step));\n            context.StateChanged += (sender, eventArgs) =>\n                StateChanged?.Invoke(this, eventArgs);\n            context.MessageConsumed += (sender, message) =>\n                MessageConsumed?.Invoke(this, (context.Height, message));\n            context.MutationConsumed += (sender, action) =>\n                MutationConsumed?.Invoke(this, (context.Height, action));\n\n            // NOTE: Events for consensus logic.\n            context.HeightStarted += (sender, height) =>\n                _consensusMessageCommunicator.OnStartHeight(height);\n            context.RoundStarted += (sender, round) =>\n                _consensusMessageCommunicator.OnStartRound(round);\n            context.MessageToPublish += (sender, message) =>\n            {\n                _consensusMessageCommunicator.PublishMessage(message);\n                MessagePublished?.Invoke(this, (context.Height, message));\n            };\n        }\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Net/Consensus/ConsensusContext.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing Libplanet.Action.State;\nusing Libplanet.Blockchain;\nusing Libplanet.Consensus;\nusing Libplanet.Crypto;\nusing Libplanet.Net.Messages;\nusing Libplanet.Types.Blocks;\nusing Libplanet.Types.Consensus;\nusing Libplanet.Types.Evidence;\nusing Serilog;\n\nnamespace Libplanet.Net.Consensus\n{\n    /// <summary>\n    /// <para>\n    /// A class that maintains a collection of <see cref=\"Context\"/>s.\n    /// </para>\n    /// <para>\n    /// Internally, multiple <see cref=\"Context\"/>s may be managed at any given time.\n    /// In particular, a <see cref=\"Context\"/> with its <see cref=\"Context.Height\"/> that\n    /// is greater than <see cref=\"Height\"/> may be created preemptively to hold\n    /// <see cref=\"ConsensusMsg\"/>s to be processed at later time.  Furthermore,\n    /// it is guaranteed that no <see cref=\"Context\"/> with its <see cref=\"Context.Height\"/>\n    /// less than <see cref=\"Height\"/>, as any such <see cref=\"Context\"/> is disposed\n    /// when <see cref=\"Height\"/> is updated.\n    /// </para>\n    /// </summary>\n    public partial class ConsensusContext : IDisposable\n    {\n        private readonly object _contextLock;\n        private readonly ContextOption _contextOption;\n        private readonly IConsensusMessageCommunicator _consensusMessageCommunicator;\n        private readonly BlockChain _blockChain;\n        private readonly PrivateKey _privateKey;\n        private readonly TimeSpan _newHeightDelay;\n        private readonly ILogger _logger;\n        private readonly HashSet<ConsensusMsg> _pendingMessages;\n        private readonly EvidenceExceptionCollector _evidenceCollector\n            = new EvidenceExceptionCollector();\n\n        private Context _currentContext;\n        private CancellationTokenSource? _newHeightCts;\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"ConsensusContext\"/> class.\n        /// </summary>\n        /// <param name=\"consensusMessageCommunicator\">A communicator for receiving\n        /// <see cref=\"ConsensusMsg\"/> from or publishing to other validators.</param>\n        /// <param name=\"blockChain\">A blockchain that will be committed, which\n        /// will be voted by consensus, and used for proposing a block.\n        /// </param>\n        /// <param name=\"privateKey\">A <see cref=\"PrivateKey\"/> for signing message and blocks.\n        /// </param>\n        /// <param name=\"newHeightDelay\">A time delay in starting the consensus for the next height\n        /// block. <seealso cref=\"OnTipChanged\"/>\n        /// </param>\n        /// <param name=\"contextOption\">A <see cref=\"ContextOption\"/> for\n        /// configuring a timeout or delay for each <see cref=\"Step\"/>.</param>\n        public ConsensusContext(\n            IConsensusMessageCommunicator consensusMessageCommunicator,\n            BlockChain blockChain,\n            PrivateKey privateKey,\n            TimeSpan newHeightDelay,\n            ContextOption contextOption)\n        {\n            _consensusMessageCommunicator = consensusMessageCommunicator;\n            _blockChain = blockChain;\n            _privateKey = privateKey;\n            Running = false;\n            _newHeightDelay = newHeightDelay;\n\n            _contextOption = contextOption;\n            _currentContext = CreateContext(\n                _blockChain.Tip.Index + 1,\n                _blockChain.GetBlockCommit(_blockChain.Tip.Index));\n            AttachEventHandlers(_currentContext);\n            _pendingMessages = new HashSet<ConsensusMsg>();\n\n            _logger = Log\n                .ForContext(\"Tag\", \"Consensus\")\n                .ForContext(\"SubTag\", \"ConsensusContext\")\n                .ForContext<ConsensusContext>()\n                .ForContext(\"Source\", nameof(ConsensusContext));\n\n            _blockChain.TipChanged += OnTipChanged;\n            _contextLock = new object();\n        }\n\n        /// <summary>\n        /// A value shwoing whether a <see cref=\"ConsensusContext\"/> is in a running state or not.\n        /// This determines whether internally handled <see cref=\"Context\"/> gets started or not.\n        /// </summary>\n        public bool Running { get; private set; }\n\n        /// <summary>\n        /// <para>\n        /// The height of the current viewing <see cref=\"Context\"/>.\n        /// </para>\n        /// <para>\n        /// This value can only be increased by calling <see cref=\"NewHeight\"/>.\n        /// </para>\n        /// </summary>\n        /// <returns>The height of the current viewing <see cref=\"Context\"/>.</returns>\n        /// <seealso cref=\"NewHeight\"/>\n        /// <seealso cref=\"OnTipChanged\"/>\n        public long Height => CurrentContext.Height;\n\n        /// <summary>\n        /// A current round of <see cref=\"Context\"/> in current <see cref=\"Height\"/>.\n        /// </summary>\n        /// <returns>If there is <see cref=\"Context\"/> for <see cref=\"Height\"/> returns the round\n        /// of current <see cref=\"Context\"/>, or otherwise returns -1.\n        /// </returns>\n        public long Round => CurrentContext.Round;\n\n        /// <summary>\n        /// The current step of <see cref=\"Context\"/> in current <see cref=\"Height\"/>.\n        /// </summary>\n        /// <returns>If there is <see cref=\"Context\"/> for <see cref=\"Height\"/> returns the step\n        /// of current <see cref=\"Context\"/>.\n        /// </returns>\n        public ConsensusStep Step => CurrentContext.Step;\n\n        internal Context CurrentContext\n        {\n            get\n            {\n                lock (_contextLock)\n                {\n                    return _currentContext;\n                }\n            }\n        }\n\n        /// <summary>\n        /// Switches <see cref=\"Running\"/> to <see langword=\"true\"/> and also starts\n        /// the current highest <see cref=\"Context\"/>, if any.\n        /// </summary>\n        /// <exception cref=\"InvalidOperationException\">Thrown when\n        /// <see cref=\"Running\"/> is already <see langword=\"true\"/>.</exception>\n        public void Start()\n        {\n            if (Running)\n            {\n                throw new InvalidOperationException(\n                    $\"Can only start {nameof(ConsensusContext)} if {nameof(Running)} is {false}.\");\n            }\n            else\n            {\n                lock (_contextLock)\n                {\n                    Running = true;\n                    _currentContext.Start();\n                }\n            }\n        }\n\n        /// <inheritdoc cref=\"IDisposable.Dispose\"/>\n        public void Dispose()\n        {\n            _newHeightCts?.Cancel();\n            lock (_contextLock)\n            {\n                _currentContext.Dispose();\n            }\n\n            _blockChain.TipChanged -= OnTipChanged;\n        }\n\n        /// <summary>\n        /// Starts a new <see cref=\"Context\"/> for given <paramref name=\"height\"/>.\n        /// </summary>\n        /// <param name=\"height\">The height of a new <see cref=\"Context\"/> to start.</param>\n        /// <exception cref=\"InvalidHeightIncreasingException\">Thrown when given\n        /// <paramref name=\"height\"/> is less than or equal to <see cref=\"Height\"/>.</exception>\n        /// <exception cref=\"NullReferenceException\">Thrown when <see cref=\"BlockChain\"/> does\n        /// not have the appropriate next state root hash ready for given <paramref name=\"height\"/>.\n        /// </exception>\n        /// <remarks>The method is only called with a delay\n        /// when <see cref=\"BlockChain.TipChanged\"/> is triggered.\n        /// </remarks>\n        public void NewHeight(long height)\n        {\n            lock (_contextLock)\n            {\n                _logger.Information(\n                    \"Invoked {FName}() for new height #{NewHeight} from old height #{OldHeight}\",\n                    nameof(NewHeight),\n                    height,\n                    Height);\n\n                if (height <= Height)\n                {\n                    throw new InvalidHeightIncreasingException(\n                        $\"Given new height #{height} must be greater than \" +\n                        $\"the current height #{Height}.\");\n                }\n\n                BlockCommit? lastCommit = null;\n                if (_currentContext.Height == height - 1 &&\n                    _currentContext.GetBlockCommit() is { } prevCommit)\n                {\n                    lastCommit = prevCommit;\n                    _logger.Debug(\n                        \"Retrieved block commit for Height #{Height} from previous context\",\n                        lastCommit.Height);\n                }\n\n                if (lastCommit is null &&\n                    _blockChain.GetBlockCommit(height - 1) is { } storedCommit)\n                {\n                    lastCommit = storedCommit;\n                    _logger.Debug(\n                        \"Retrieved stored block commit for Height #{Height} from blockchain\",\n                        lastCommit.Height);\n                }\n\n                _logger.Debug(\n                    \"LastCommit for height #{Height} is {LastCommit}\",\n                    height,\n                    lastCommit);\n\n                _currentContext.Dispose();\n                _logger.Information(\n                    \"Start consensus for height #{Height} with last commit {LastCommit}\",\n                    height,\n                    lastCommit);\n                _currentContext = CreateContext(height, lastCommit);\n                AttachEventHandlers(_currentContext);\n\n                foreach (var message in _pendingMessages)\n                {\n                    if (message.Height == height)\n                    {\n                        _currentContext.ProduceMessage(message);\n                    }\n                }\n\n                _pendingMessages.RemoveWhere(message => message.Height <= height);\n                if (Running)\n                {\n                    _currentContext.Start();\n                }\n            }\n        }\n\n        /// <summary>\n        /// <para>\n        /// Handles a received <see cref=\"ConsensusMsg\"/> by either dispatching it to the right\n        /// <see cref=\"Context\"/> or discarding it.\n        /// </para>\n        /// <para>\n        /// In particular, this discards <paramref name=\"consensusMessage\"/> with\n        /// <see cref=\"ConsensusMsg.Height\"/> less than <see cref=\"Height\"/>.  Otherwise,\n        /// given <paramref name=\"consensusMessage\"/> is passed on to a <see cref=\"Context\"/>\n        /// with <see cref=\"Context.Height\"/> the same as <see cref=\"ConsensusMsg.Height\"/> of\n        /// <paramref name=\"consensusMessage\"/>.  If there is no such <see cref=\"Context\"/>,\n        /// then a new <see cref=\"Context\"/> is created for the dispatch.\n        /// </para>\n        /// </summary>\n        /// <param name=\"consensusMessage\">The <see cref=\"ConsensusMsg\"/> received from\n        /// any validator.\n        /// </param>\n        /// <returns>\n        /// <see langword=\"true\"/> if <paramref name=\"consensusMessage\"/> is dispatched to\n        /// a <see cref=\"Context\"/>, <see langword=\"false\"/> otherwise.\n        /// </returns>\n        public bool HandleMessage(ConsensusMsg consensusMessage)\n        {\n            long height = consensusMessage.Height;\n            if (height < Height)\n            {\n                _logger.Debug(\n                    \"Discarding a received message as its height #{MessageHeight} \" +\n                    \"is lower than the current context's height #{ContextHeight}\",\n                    height,\n                    Height);\n                return false;\n            }\n\n            lock (_contextLock)\n            {\n                if (_currentContext.Height == height)\n                {\n                    _currentContext.ProduceMessage(consensusMessage);\n                }\n                else\n                {\n                    _pendingMessages.Add(consensusMessage);\n                }\n\n                return true;\n            }\n        }\n\n        /// <summary>\n        /// Handles a received <see cref=\"Maj23\"/> and return message to fetch.\n        /// </summary>\n        /// <param name=\"maj23\">The <see cref=\"Maj23\"/> received from any validator.\n        /// </param>\n        /// <returns>\n        /// An <see cref=\"IEnumerable{ConsensusMsg}\"/> to reply back.\n        /// </returns>\n        /// <remarks>This method does not update state of the context.</remarks>\n        public VoteSetBits? HandleMaj23(Maj23 maj23)\n        {\n            long height = maj23.Height;\n            if (height < Height)\n            {\n                _logger.Debug(\n                    \"Ignore a received VoteSetBits as its height \" +\n                    \"#{Height} is lower than the current context's height #{ContextHeight}\",\n                    height,\n                    Height);\n            }\n            else\n            {\n                lock (_contextLock)\n                {\n                    if (_currentContext.Height == height)\n                    {\n                        return _currentContext.AddMaj23(maj23);\n                    }\n                }\n            }\n\n            return null;\n        }\n\n        /// <summary>\n        /// Handles a received <see cref=\"VoteSetBits\"/> and return message to fetch.\n        /// </summary>\n        /// <param name=\"voteSetBits\">The <see cref=\"VoteSetBits\"/> received from any validator.\n        /// </param>\n        /// <returns>\n        /// An <see cref=\"IEnumerable{ConsensusMsg}\"/> to reply back.\n        /// </returns>\n        /// <remarks>This method does not update state of the context.</remarks>\n        public IEnumerable<ConsensusMsg> HandleVoteSetBits(VoteSetBits voteSetBits)\n        {\n            long height = voteSetBits.Height;\n            if (height < Height)\n            {\n                _logger.Debug(\n                    \"Ignore a received VoteSetBits as its height \" +\n                    \"#{Height} is lower than the current context's height #{ContextHeight}\",\n                    height,\n                    Height);\n            }\n            else\n            {\n                lock (_contextLock)\n                {\n                    if (_currentContext.Height == height)\n                    {\n                        // NOTE: Should check if collected messages have same BlockHash with\n                        // VoteSetBit's BlockHash?\n                        return _currentContext.GetVoteSetBitsResponse(voteSetBits);\n                    }\n                }\n            }\n\n            return Array.Empty<ConsensusMsg>();\n        }\n\n        public Proposal? HandleProposalClaim(ProposalClaim proposalClaim)\n        {\n            long height = proposalClaim.Height;\n            int round = proposalClaim.Round;\n            if (height != Height)\n            {\n                _logger.Debug(\n                    \"Ignore a received ProposalClaim as its height \" +\n                    \"#{Height} does not match with the current context's height #{ContextHeight}\",\n                    height,\n                    Height);\n            }\n            else if (round != Round)\n            {\n                _logger.Debug(\n                    \"Ignore a received ProposalClaim as its round \" +\n                    \"#{Round} does not match with the current context's round #{ContextRound}\",\n                    round,\n                    Round);\n            }\n            else\n            {\n                lock (_contextLock)\n                {\n                    if (_currentContext.Height == height)\n                    {\n                        // NOTE: Should check if collected messages have same BlockHash with\n                        // VoteSetBit's BlockHash?\n                        return _currentContext.Proposal;\n                    }\n                }\n            }\n\n            return null;\n        }\n\n        /// <summary>\n        /// Returns the summary for <see cref=\"ConsensusContext\"/>.\n        /// </summary>\n        /// <returns>Returns the current height <see cref=\"Context\"/>. if there's no instance of\n        /// <see cref=\"Context\"/> for current height, returns \"No context\".\n        /// </returns>\n        public override string ToString()\n        {\n            lock (_contextLock)\n            {\n                return _currentContext.ToString();\n            }\n        }\n\n        /// <summary>\n        /// A handler for <see cref=\"BlockChain.TipChanged\"/> event that calls\n        /// <see cref=\"NewHeight\"/>.  Starting a new height will be delayed for\n        /// <see cref=\"_newHeightDelay\"/> in order to collect remaining delayed votes\n        /// and stabilize the consensus process by waiting for Global Stabilization Time.\n        /// </summary>\n        /// <param name=\"sender\">The source object instance for <see cref=\"EventHandler\"/>.\n        /// </param>\n        /// <param name=\"e\">The event arguments given by <see cref=\"BlockChain.TipChanged\"/>\n        /// as a tuple of the old tip and the new tip.\n        /// </param>\n        private void OnTipChanged(object? sender, (Block _, Block NewTip) e)\n        {\n            // TODO: Should set delay by using GST.\n            _newHeightCts?.Cancel();\n            _newHeightCts?.Dispose();\n            _newHeightCts = new CancellationTokenSource();\n            Task.Run(\n                async () =>\n                {\n                    await Task.Delay(_newHeightDelay, _newHeightCts.Token);\n\n                    // Delay further until evaluation is ready.\n                    while (_blockChain.GetNextStateRootHash(e.NewTip.Index) is null)\n                    {\n                        // FIXME: Maybe interval should be adjustable?\n                        await Task.Delay(100, _newHeightCts.Token);\n                    }\n\n                    if (!_newHeightCts.IsCancellationRequested)\n                    {\n                        try\n                        {\n                            HandleEvidenceExceptions();\n                            AddEvidenceToBlockChain(e.NewTip);\n                            NewHeight(e.NewTip.Index + 1);\n                        }\n                        catch (Exception exc)\n                        {\n                            _logger.Error(\n                                exc,\n                                \"Unexpected exception occurred during {FName}()\",\n                                nameof(NewHeight));\n                        }\n                    }\n                    else\n                    {\n                        _logger.Error(\n                            \"Did not invoke {FName}() for height \" +\n                            \"#{Height} because cancellation is requested\",\n                            nameof(NewHeight),\n                            e.NewTip.Index + 1);\n                    }\n                },\n                _newHeightCts.Token);\n        }\n\n        /// <summary>\n        /// Create new context of height of the given <paramref name=\"height\"/>\n        /// and attach event handlers to it, and return the created context.\n        /// </summary>\n        /// <param name=\"height\">The height of the context to create.</param>\n        /// <param name=\"lastCommit\">The block commit of the previous <see cref=\"Block\"/>.</param>\n        /// <exception cref=\"NullReferenceException\">Thrown when <see cref=\"BlockChain\"/> does\n        /// not have the appropriate next state root hash ready for given <paramref name=\"height\"/>.\n        /// </exception>\n        private Context CreateContext(long height, BlockCommit? lastCommit)\n        {\n            var nextStateRootHash = _blockChain.GetNextStateRootHash(height - 1) ??\n                throw new NullReferenceException(\n                    $\"Could not find the next state root hash for index {height - 1}\");\n            ValidatorSet validatorSet = _blockChain\n                .GetWorldState(nextStateRootHash)\n                .GetValidatorSet();\n\n            Context context = new Context(\n                _blockChain,\n                height,\n                lastCommit,\n                _privateKey,\n                validatorSet,\n                contextOption: _contextOption);\n            return context;\n        }\n\n        private void HandleEvidenceExceptions()\n        {\n            var evidenceExceptions = _currentContext.CollectEvidenceExceptions();\n            _evidenceCollector.AddRange(evidenceExceptions);\n        }\n\n        private void AddEvidenceToBlockChain(Block tip)\n        {\n            var height = tip.Index;\n            var evidenceExceptions\n                = _evidenceCollector.Flush().Where(item => item.Height <= height).ToArray();\n            foreach (var evidenceException in evidenceExceptions)\n            {\n                try\n                {\n                    var validatorSet = _blockChain.GetValidatorSet(evidenceException.Height);\n                    var evidenceContext = new EvidenceContext(validatorSet);\n                    var evidence = evidenceException.CreateEvidence(evidenceContext);\n                    _blockChain.AddEvidence(evidence);\n                }\n                catch (Exception e)\n                {\n                    _logger.Error(\n                        exception: e,\n                        messageTemplate: \"Unexpected exception occurred during {FName}()\",\n                        propertyValue: nameof(BlockChain.AddEvidence));\n                }\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Net/Consensus/ConsensusReactor.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Collections.Immutable;\nusing System.Linq;\nusing System.Text.Json;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing Libplanet.Blockchain;\nusing Libplanet.Consensus;\nusing Libplanet.Crypto;\nusing Libplanet.Net.Messages;\nusing Libplanet.Net.Transports;\nusing Serilog;\n\nnamespace Libplanet.Net.Consensus\n{\n    /// <summary>\n    /// A manager class for starting network and joining into consensus.\n    /// <seealso cref=\"ConsensusContext\"/>\n    /// </summary>\n    public class ConsensusReactor : IReactor\n    {\n        private readonly Gossip _gossip;\n        private readonly ConsensusContext _consensusContext;\n        private readonly BlockChain _blockChain;\n        private readonly ILogger _logger;\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"ConsensusReactor\"/> class.\n        /// </summary>\n        /// <param name=\"consensusTransport\">An <see cref=\"ITransport\"/> for sending the\n        /// <see cref=\"ConsensusMsg\"/>s to validators.</param>\n        /// <param name=\"blockChain\">A blockchain that will be committed, which\n        /// will be voted by consensus, and used for proposing a block.\n        /// </param>\n        /// <param name=\"privateKey\">A <see cref=\"PrivateKey\"/> for using in signing a block,\n        /// message.\n        /// </param>\n        /// <param name=\"validatorPeers\">A list of validator's <see cref=\"BoundPeer\"/>, including\n        /// itself.\n        /// </param>\n        /// <param name=\"seedPeers\">A list of seed's <see cref=\"BoundPeer\"/>.</param>\n        /// <param name=\"newHeightDelay\">A time delay in starting the consensus for the next height\n        /// block.\n        /// </param>\n        /// <param name=\"contextOption\">A <see cref=\"ContextOption\"/> for\n        /// configuring a timeout for each <see cref=\"ConsensusStep\"/>.</param>\n        public ConsensusReactor(\n            ITransport consensusTransport,\n            BlockChain blockChain,\n            PrivateKey privateKey,\n            ImmutableList<BoundPeer> validatorPeers,\n            ImmutableList<BoundPeer> seedPeers,\n            TimeSpan newHeightDelay,\n            ContextOption contextOption)\n        {\n            validatorPeers ??= ImmutableList<BoundPeer>.Empty;\n            seedPeers ??= ImmutableList<BoundPeer>.Empty;\n\n            GossipConsensusMessageCommunicator consensusMessageHandler =\n                new GossipConsensusMessageCommunicator(\n                    consensusTransport,\n                    validatorPeers.ToImmutableArray(),\n                    seedPeers.ToImmutableArray(),\n                    ProcessMessage);\n            _gossip = consensusMessageHandler.Gossip;\n            _blockChain = blockChain;\n\n            _consensusContext = new ConsensusContext(\n                consensusMessageHandler,\n                blockChain,\n                privateKey,\n                newHeightDelay,\n                contextOption);\n\n            _logger = Log\n                .ForContext(\"Tag\", \"Consensus\")\n                .ForContext(\"SubTag\", \"Reactor\")\n                .ForContext<ConsensusReactor>()\n                .ForContext(\"Source\", nameof(ConsensusReactor));\n        }\n\n        /// <summary>\n        /// Whether this <see cref=\"ConsensusReactor\"/> is running.\n        /// </summary>\n        public bool Running => _gossip.Running;\n\n        /// <summary>\n        /// The index of block that <see cref=\"ConsensusContext\"/> is watching. The value can be\n        /// changed by starting a consensus or appending a block.\n        /// </summary>\n        public long Height => _consensusContext.Height;\n\n        /// <summary>\n        /// An <see cref=\"IEnumerable{BoundPeer}\"/> of the validators.\n        /// </summary>\n        public IReadOnlyList<BoundPeer> Validators => _gossip.Peers.ToList().AsReadOnly();\n\n        // FIXME: This should be exposed in a better way.\n        internal ConsensusContext ConsensusContext => _consensusContext;\n\n        /// <summary>\n        /// <inheritdoc cref=\"IDisposable.Dispose()\"/>\n        /// </summary>\n        public void Dispose()\n        {\n            _gossip.Dispose();\n            _consensusContext.Dispose();\n        }\n\n        /// <summary>\n        /// Starts the instance and joins into consensus.\n        /// </summary>\n        /// <param name=\"cancellationToken\">A cancellation token used to propagate notification\n        /// that this operation should be canceled.</param>\n        /// <returns>Returns the <see cref=\"ITransport.StartAsync\"/>.</returns>\n        public async Task StartAsync(CancellationToken cancellationToken)\n        {\n            Task task = _gossip.StartAsync(cancellationToken);\n            await _gossip.WaitForRunningAsync();\n            _consensusContext.Start();\n            await task;\n        }\n\n        /// <summary>\n        /// Stops the instance and consensus.\n        /// </summary>\n        /// <param name=\"cancellationToken\">A cancellation Token.</param>\n        /// <returns>Returns the <see cref=\"ITransport.StopAsync\"/>.</returns>\n        public async Task StopAsync(CancellationToken cancellationToken)\n        {\n            _consensusContext.Dispose();\n            await _gossip.StopAsync(TimeSpan.FromMilliseconds(10), cancellationToken);\n        }\n\n        /// <summary>\n        /// Returns a summary of current consensus status in JSON-formatted string.\n        /// </summary>\n        /// <returns>Returns a summary in JSON-formatted string.\n        /// </returns>\n        public override string ToString()\n        {\n            var dict =\n                JsonSerializer.Deserialize<Dictionary<string, object>>(\n                    _consensusContext.ToString()) ?? new Dictionary<string, object>();\n            dict[\"peer\"] = _gossip.AsPeer.ToString();\n\n            return JsonSerializer.Serialize(dict);\n        }\n\n        /// <summary>\n        /// A handler for received <see cref=\"Message\"/>s.\n        /// </summary>\n        /// <param name=\"content\">A message to process.</param>\n        private void ProcessMessage(MessageContent content)\n        {\n            switch (content)\n            {\n                case ConsensusVoteSetBitsMsg voteSetBits:\n                    // Note: ConsensusVoteSetBitsMsg will not be stored to context's message log.\n                    var messages = _consensusContext.HandleVoteSetBits(voteSetBits.VoteSetBits);\n                    try\n                    {\n                        var sender = _gossip.Peers.First(\n                            peer => peer.PublicKey.Equals(voteSetBits.ValidatorPublicKey));\n                        foreach (var msg in messages)\n                        {\n                            _gossip.PublishMessage(msg, new[] { sender });\n                        }\n                    }\n                    catch (InvalidOperationException)\n                    {\n                        _logger.Debug(\n                            \"Cannot respond received ConsensusVoteSetBitsMsg message\" +\n                            \" {Message} since there is no corresponding peer in the table\",\n                            voteSetBits);\n                    }\n\n                    break;\n\n                case ConsensusMaj23Msg maj23Msg:\n                    try\n                    {\n                        VoteSetBits? voteSetBits = _consensusContext.HandleMaj23(maj23Msg.Maj23);\n                        if (voteSetBits is null)\n                        {\n                            break;\n                        }\n\n                        var sender = _gossip.Peers.First(\n                            peer => peer.PublicKey.Equals(maj23Msg.ValidatorPublicKey));\n                        _gossip.PublishMessage(\n                            new ConsensusVoteSetBitsMsg(voteSetBits),\n                            new[] { sender });\n                    }\n                    catch (InvalidOperationException)\n                    {\n                        _logger.Debug(\n                            \"Cannot respond received ConsensusMaj23Msg message \" +\n                            \"{Message} since there is no corresponding peer in the table\",\n                            maj23Msg);\n                    }\n\n                    break;\n\n                case ConsensusProposalClaimMsg proposalClaimMsg:\n                    try\n                    {\n                        Proposal? proposal = _consensusContext.HandleProposalClaim(\n                            proposalClaimMsg.ProposalClaim);\n                        if (proposal is { } proposalNotNull)\n                        {\n                            var reply = new ConsensusProposalMsg(proposalNotNull);\n                            var sender = _gossip.Peers.First(\n                                peer => peer.PublicKey.Equals(proposalClaimMsg.ValidatorPublicKey));\n\n                            _gossip.PublishMessage(reply, new[] { sender });\n                        }\n                    }\n                    catch (InvalidOperationException)\n                    {\n                        _logger.Debug(\n                            \"Cannot respond received ConsensusProposalClaimMsg message \" +\n                            \"{Message} since there is no corresponding peer in the table\",\n                            proposalClaimMsg);\n                    }\n\n                    break;\n\n                case ConsensusMsg consensusMsg:\n                    _consensusContext.HandleMessage(consensusMsg);\n                    break;\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Net/Consensus/ConsensusReactorOption.cs",
    "content": "using System;\nusing System.Collections.Immutable;\nusing Libplanet.Crypto;\nusing Libplanet.Net.Messages;\nusing Libplanet.Net.Transports;\n\nnamespace Libplanet.Net.Consensus\n{\n    /// <summary>\n    /// An option struct for initializing <see cref=\"ConsensusReactor\"/>.\n    /// </summary>\n    public struct ConsensusReactorOption\n    {\n        /// <summary>\n        /// A port number that is used for exchanging <see cref=\"ConsensusMsg\"/>.\n        /// </summary>\n        public int ConsensusPort { get; set; }\n\n        /// <summary>\n        /// A number of <see cref=\"ITransport\"/>'s worker.\n        /// </summary>\n        public int ConsensusWorkers { get; set; }\n\n        /// <summary>\n        /// A <see cref=\"PrivateKey\"/> for signing block and message.\n        /// </summary>\n        public PrivateKey ConsensusPrivateKey { get; set; }\n\n        /// <summary>\n        /// A list of seeds.\n        /// </summary>\n        public ImmutableList<BoundPeer> SeedPeers { get; set; }\n\n        /// <summary>\n        /// A list of validators.\n        /// </summary>\n        public ImmutableList<BoundPeer> ConsensusPeers { get; set; }\n\n        /// <summary>\n        /// A time delay in starting the consensus for the next height block.\n        /// </summary>\n        public TimeSpan TargetBlockInterval { get; set; }\n\n        /// <summary>\n        /// A timeout and delay value for used in <see cref=\"Context\"/> in milliseconds.\n        /// </summary>\n        public ContextOption ContextOption { get; set; }\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Net/Consensus/ConsensusStep.cs",
    "content": "namespace Libplanet.Net.Consensus\n{\n    public enum ConsensusStep\n    {\n        /// <summary>\n        /// Initial Step.\n        /// </summary>\n        Default,\n\n        /// <summary>\n        /// Proposing Step.\n        /// </summary>\n        Propose,\n\n        /// <summary>\n        /// Voting Step.\n        /// </summary>\n        PreVote,\n\n        /// <summary>\n        /// Commit voting step.\n        /// </summary>\n        PreCommit,\n\n        /// <summary>\n        /// Commit end step.\n        /// </summary>\n        EndCommit,\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Net/Consensus/Context.Async.cs",
    "content": "using System;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing Libplanet.Net.Messages;\nusing Libplanet.Types.Blocks;\nusing Libplanet.Types.Evidence;\n\nnamespace Libplanet.Net.Consensus\n{\n    public partial class Context\n    {\n        /// <summary>\n        /// Starts round #0 of consensus for <see cref=\"Height\"/>.\n        /// </summary>\n        /// <exception cref=\"InvalidOperationException\">Thrown when <see cref=\"Step\"/>\n        /// is not <see cref=\"ConsensusStep.Default\"/>.</exception>\n        public void Start()\n        {\n            if (Step != ConsensusStep.Default)\n            {\n                throw new InvalidOperationException(\n                    $\"Context cannot be started unless its state is {ConsensusStep.Default} \" +\n                    $\"but its current step is {Step}\");\n            }\n\n            _logger.Information(\n                \"Starting context for height #{Height}\",\n                Height);\n            HeightStarted?.Invoke(this, Height);\n            ProduceMutation(() => StartRound(0));\n\n            // FIXME: Exceptions inside tasks should be handled properly.\n            _ = MessageConsumerTask(_cancellationTokenSource.Token);\n            _ = MutationConsumerTask(_cancellationTokenSource.Token);\n        }\n\n        /// <summary>\n        /// Consumes every <see cref=\"ConsensusMsg\"/> in the message queue.\n        /// </summary>\n        /// <param name=\"cancellationToken\">A cancellation token for reading\n        /// <see cref=\"ConsensusMsg\"/>s from the message queue.</param>\n        /// <returns>An awaitable task without value.</returns>\n        internal async Task MessageConsumerTask(CancellationToken cancellationToken)\n        {\n            while (true)\n            {\n                try\n                {\n                    await ConsumeMessage(cancellationToken);\n                }\n                catch (OperationCanceledException oce)\n                {\n                    _logger.Debug(oce, \"Cancellation was requested\");\n                    ExceptionOccurred?.Invoke(this, oce);\n                    throw;\n                }\n                catch (Exception e)\n                {\n                    _logger.Error(\n                        e,\n                        \"Unexpected exception occurred during {FName}\",\n                        nameof(ConsumeMessage));\n                    ExceptionOccurred?.Invoke(this, e);\n                    throw;\n                }\n            }\n        }\n\n        /// <summary>\n        /// Consumes every <see cref=\"System.Action\"/> in the mutation queue.\n        /// </summary>\n        /// <param name=\"cancellationToken\">A cancellation token for reading\n        /// <see cref=\"System.Action\"/>s from the mutation queue.</param>\n        /// <returns>An awaitable task without value.</returns>\n        internal async Task MutationConsumerTask(CancellationToken cancellationToken)\n        {\n            while (true)\n            {\n                try\n                {\n                    await ConsumeMutation(cancellationToken);\n                }\n                catch (OperationCanceledException oce)\n                {\n                    _logger.Debug(oce, \"Cancellation was requested\");\n                    ExceptionOccurred?.Invoke(this, oce);\n                    throw;\n                }\n                catch (EvidenceException e)\n                {\n                    _evidenceCollector.Add(e);\n                }\n                catch (Exception e)\n                {\n                    _logger.Error(\n                        e,\n                        \"Unexpected exception occurred during {FName}\",\n                        nameof(ConsumeMutation));\n                    ExceptionOccurred?.Invoke(this, e);\n                    throw;\n                }\n            }\n        }\n\n        /// <summary>\n        /// Adds <paramref name=\"message\"/> to the message queue.\n        /// </summary>\n        /// <param name=\"message\">A <see cref=\"ConsensusMsg\"/> to be processed.</param>\n        internal void ProduceMessage(ConsensusMsg message)\n        {\n            _messageRequests.Writer.WriteAsync(message);\n        }\n\n        /// <summary>\n        /// Adds a mutating <see cref=\"System.Action\"/> to the mutation queue.\n        /// </summary>\n        /// <param name=\"mutation\">A <see cref=\"System.Action\"/> to be processed.</param>\n        private void ProduceMutation(System.Action mutation)\n        {\n            _mutationRequests.Writer.WriteAsync(mutation);\n        }\n\n        private async Task ConsumeMessage(CancellationToken cancellationToken)\n        {\n            ConsensusMsg message = await _messageRequests.Reader.ReadAsync(cancellationToken);\n            ProduceMutation(() =>\n            {\n                if (AddMessage(message))\n                {\n                    ProcessHeightOrRoundUponRules(message);\n                }\n            });\n\n            MessageConsumed?.Invoke(this, message);\n        }\n\n        private async Task ConsumeMutation(CancellationToken cancellationToken)\n        {\n            System.Action mutation = await _mutationRequests.Reader.ReadAsync(cancellationToken);\n            var prevState = new ContextState(\n                _heightVoteSet.Count,\n                Height,\n                Round,\n                Step,\n                Proposal?.BlockHash);\n            mutation();\n            var nextState = new ContextState(\n                _heightVoteSet.Count,\n                Height,\n                Round,\n                Step,\n                Proposal?.BlockHash);\n            while (!prevState.Equals(nextState))\n            {\n                _logger.Information(\n                    \"State (Proposal, VoteCount, Round, Step) \" +\n                    \"changed from \" +\n                    \"({PrevProposal}, {PrevVoteCount}, {PrevRound}, {PrevStep}) to \" +\n                    \"({NextProposal}, {NextVoteCount}, {NextRound}, {NextStep})\",\n                    prevState.Proposal?.ToString() ?? \"Null\",\n                    prevState.VoteCount,\n                    prevState.Round,\n                    prevState.Step,\n                    nextState.Proposal?.ToString() ?? \"Null\",\n                    nextState.VoteCount,\n                    nextState.Round,\n                    nextState.Step);\n                StateChanged?.Invoke(this, nextState);\n                prevState = new ContextState(\n                    _heightVoteSet.Count,\n                    Height,\n                    Round,\n                    Step,\n                    Proposal?.BlockHash);\n                ProcessGenericUponRules();\n                nextState = new ContextState(\n                    _heightVoteSet.Count,\n                    Height,\n                    Round,\n                    Step,\n                    Proposal?.BlockHash);\n            }\n\n            MutationConsumed?.Invoke(this, mutation);\n        }\n\n        private void AppendBlock(Block block)\n        {\n            _ = Task.Run(() => _blockChain.Append(block, GetBlockCommit()));\n        }\n\n        private async Task EnterPreCommitWait(int round, BlockHash hash)\n        {\n            if (!_preCommitWaitFlags.Add(round))\n            {\n                return;\n            }\n\n            if (_contextOption.EnterPreCommitDelay > 0)\n            {\n                await Task.Delay(\n                    _contextOption.EnterPreCommitDelay,\n                    _cancellationTokenSource.Token);\n            }\n\n            ProduceMutation(() => EnterPreCommit(round, hash));\n        }\n\n        private async Task EnterEndCommitWait(int round)\n        {\n            if (!_endCommitWaitFlags.Add(round))\n            {\n                return;\n            }\n\n            if (_contextOption.EnterEndCommitDelay > 0)\n            {\n                await Task.Delay(\n                    _contextOption.EnterEndCommitDelay,\n                    _cancellationTokenSource.Token);\n            }\n\n            ProduceMutation(() => EnterEndCommit(round));\n        }\n\n        /// <summary>\n        /// Schedules <see cref=\"ProcessTimeoutPropose\"/> to be queued after\n        /// <see cref=\"TimeoutPropose\"/> amount of time.\n        /// </summary>\n        /// <param name=\"round\">A round that the timeout task is scheduled for.</param>\n        private async Task OnTimeoutPropose(int round)\n        {\n            TimeSpan timeout = TimeoutPropose(round);\n            await Task.Delay(timeout, _cancellationTokenSource.Token);\n            _logger.Information(\n                \"TimeoutPropose has occurred in {Timeout}. {Info}\",\n                timeout,\n                ToString());\n            ProduceMutation(() => ProcessTimeoutPropose(round));\n        }\n\n        /// <summary>\n        /// Schedules <see cref=\"ProcessTimeoutPreVote\"/> to be queued after\n        /// <see cref=\"TimeoutPreVote\"/> amount of time.\n        /// </summary>\n        /// <param name=\"round\">A round that the timeout task is scheduled for.</param>\n        private async Task OnTimeoutPreVote(int round)\n        {\n            if (_preCommitTimeoutFlags.Contains(round) || !_preVoteTimeoutFlags.Add(round))\n            {\n                return;\n            }\n\n            TimeSpan timeout = TimeoutPreVote(round);\n            _logger.Debug(\n                \"PreVote step in round {Round} is scheduled to be timed out after {Timeout} \" +\n                \"because 2/3+ PreVotes are collected for the round. (context: {Context})\",\n                round,\n                timeout,\n                ToString());\n            await Task.Delay(timeout, _cancellationTokenSource.Token);\n            _logger.Information(\n                \"TimeoutPreVote has occurred in {Timeout}. {Info}\",\n                timeout,\n                ToString());\n            ProduceMutation(() => ProcessTimeoutPreVote(round));\n        }\n\n        /// <summary>\n        /// Schedules <see cref=\"ProcessTimeoutPreCommit\"/> to be queued after\n        /// <see cref=\"TimeoutPreCommit\"/> amount of time.\n        /// </summary>\n        /// <param name=\"round\">The round that the timeout task is scheduled for.</param>\n        private async Task OnTimeoutPreCommit(int round)\n        {\n            if (!_preCommitTimeoutFlags.Add(round))\n            {\n                return;\n            }\n\n            TimeSpan timeout = TimeoutPreCommit(round);\n            _logger.Debug(\n                \"PreCommit step in round {Round} is scheduled to be timed out in {Timeout} \" +\n                \"because 2/3+ PreCommits are collected for the round. (context: {Context})\",\n                round,\n                timeout,\n                ToString());\n            await Task.Delay(timeout, _cancellationTokenSource.Token);\n            _logger.Information(\n                \"TimeoutPreCommit has occurred in {Timeout}. {Info}\",\n                timeout,\n                ToString());\n            ProduceMutation(() => ProcessTimeoutPreCommit(round));\n        }\n\n        internal struct ContextState : IEquatable<ContextState>\n        {\n            public ContextState(\n                int voteCount,\n                long height,\n                int round,\n                ConsensusStep step,\n                BlockHash? proposal)\n            {\n                VoteCount = voteCount;\n                Height = height;\n                Round = round;\n                Step = step;\n                Proposal = proposal;\n            }\n\n            public int VoteCount { get; }\n\n            public long Height { get; }\n\n            public int Round { get; }\n\n            public ConsensusStep Step { get; }\n\n            public BlockHash? Proposal { get; }\n\n            public bool Equals(ContextState other)\n            {\n                return VoteCount == other.VoteCount &&\n                       Round == other.Round &&\n                       Step == other.Step &&\n                       Proposal.Equals(other.Proposal);\n            }\n\n            public override bool Equals(object? obj)\n            {\n                return obj is ContextState other && Equals(other);\n            }\n\n            public override int GetHashCode()\n            {\n                return HashCode.Combine(VoteCount, Round, (int)Step, Proposal.GetHashCode());\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Net/Consensus/Context.Event.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing Libplanet.Net.Messages;\nusing Libplanet.Types.Consensus;\n\nnamespace Libplanet.Net.Consensus\n{\n    public partial class Context\n    {\n        /// <summary>\n        /// An event that is invoked when <see cref=\"Context\"/> starts via <see cref=\"Start\"/>.\n        /// </summary>\n        internal event EventHandler<long>? HeightStarted;\n\n        /// <summary>\n        /// An event that is invoked when <see cref=\"Context\"/> starts a new round\n        /// via <see cref=\"StartRound\"/>.\n        /// </summary>\n        internal event EventHandler<int>? RoundStarted;\n\n        /// <summary>\n        /// An event that is invoked when a <see cref=\"ConsensusMsg\"/> needs to be published.\n        /// </summary>\n        internal event EventHandler<ConsensusMsg>? MessageToPublish;\n\n        /// <summary>\n        /// An event that is invoked when an <see cref=\"Exception\"/> is thrown.\n        /// </summary>\n        internal event EventHandler<Exception>? ExceptionOccurred;\n\n        /// <summary>\n        /// An event that invoked when any timeout triggered mutation is processed.\n        /// This is conditionally triggered when internal countdown timer has reached zero,\n        /// i.e. when certain conditions are met.\n        /// </summary>\n        internal event EventHandler<(int Round, ConsensusStep Step)>? TimeoutProcessed;\n\n        /// <summary>\n        /// An event that is invoked when the message log size, <see cref=\"Round\"/>,\n        /// and/or <see cref=\"ConsensusStep\"/> is changed.\n        /// </summary>\n        internal event EventHandler<ContextState>? StateChanged;\n\n        /// <summary>\n        /// An event that is invoked when a queued <see cref=\"ConsensusMsg\"/> is consumed.\n        /// </summary>\n        /// <remarks>\n        /// This only indicates that a <see cref=\"ConsensusMsg\"/> has been dequeued from\n        /// internal queue.  This only creates an <see cref=\"System.Action\"/> to be consumed\n        /// by a <see cref=\"MutationConsumerTask\"/> and may or may not result in a state change\n        /// further down the line.\n        /// </remarks>\n        internal event EventHandler<ConsensusMsg>? MessageConsumed;\n\n        /// <summary>\n        /// An event that is invoked when a queued <see cref=\"System.Action\"/> is consumed.\n        /// </summary>\n        internal event EventHandler<System.Action>? MutationConsumed;\n\n        /// <summary>\n        /// An event that is invoked when the <see cref=\"HeightVoteSet\"/> is modified.\n        /// </summary>\n        internal event EventHandler<(int Round, VoteFlag Flag, IEnumerable<Vote> Votes)>?\n            VoteSetModified;\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Net/Consensus/Context.Mutate.cs",
    "content": "using System;\nusing Libplanet.Consensus;\nusing Libplanet.Net.Messages;\nusing Libplanet.Types.Blocks;\nusing Libplanet.Types.Consensus;\n\nnamespace Libplanet.Net.Consensus\n{\n    // NOTE: All methods that can potentially mutate a Context is placed here.\n    // Each mutation must be run synchronously either through MutationConsumerTask\n    // or as a part of another mutation.  All methods are made intentionally private and\n    // Exception free, i.e. any exception that is not thrown explicitly is unintentional and\n    // unexpected.\n    public partial class Context\n    {\n        /// <summary>\n        /// Starts a new round.\n        /// </summary>\n        /// <param name=\"round\">The round to start.</param>\n        private void StartRound(int round)\n        {\n            _logger.Information(\n                \"Starting round {NewRound} (was {PrevRound}). (context: {Context})\",\n                round,\n                Round,\n                ToString());\n\n            Round = round;\n            RoundStarted?.Invoke(this, Round);\n            _heightVoteSet.SetRound(round);\n\n            Proposal = null;\n            Step = ConsensusStep.Propose;\n            if (_validatorSet.GetProposer(Height, Round).PublicKey == _privateKey.PublicKey)\n            {\n                _logger.Information(\n                    \"Starting round {NewRound} and is a proposer.\",\n                    round,\n                    ToString());\n                if ((_validValue ?? GetValue()) is Block proposalValue)\n                {\n                    Proposal proposal = new ProposalMetadata(\n                        Height,\n                        Round,\n                        DateTimeOffset.UtcNow,\n                        _privateKey.PublicKey,\n                        _codec.Encode(proposalValue.MarshalBlock()),\n                        _validRound).Sign(_privateKey);\n\n                    PublishMessage(new ConsensusProposalMsg(proposal));\n                }\n                else\n                {\n                    _logger.Information(\n                        \"Failed to propose a block for round {Round}.\",\n                        round);\n                    _ = OnTimeoutPropose(Round);\n                }\n            }\n            else\n            {\n                _logger.Information(\n                    \"Starting round {NewRound} and is not a proposer.\",\n                    round);\n                _ = OnTimeoutPropose(Round);\n            }\n        }\n\n        /// <summary>\n        /// Validates given <paramref name=\"message\"/> and add it to the message log.\n        /// </summary>\n        /// <param name=\"message\">A <see cref=\"ConsensusMsg\"/> to be added.\n        /// </param>\n        /// <remarks>\n        /// If an invalid <see cref=\"ConsensusMsg\"/> is given, this method throws\n        /// an <see cref=\"InvalidConsensusMessageException\"/> and handles it <em>internally</em>\n        /// while invoking <see cref=\"ExceptionOccurred\"/> event.\n        /// An <see cref=\"InvalidConsensusMessageException\"/> can be thrown when\n        /// the internal <see cref=\"HeightVoteSet\"/> does not accept it, i.e.\n        /// <see cref=\"HeightVoteSet.AddVote\"/> returns <see langword=\"false\"/>.\n        /// </remarks>\n        /// <seealso cref=\"HeightVoteSet.AddVote\"/>\n        private bool AddMessage(ConsensusMsg message)\n        {\n            try\n            {\n                if (message.Height != Height)\n                {\n                    throw new InvalidConsensusMessageException(\n                        $\"Given message's height {message.Height} is invalid\",\n                        message);\n                }\n\n                if (!_validatorSet.ContainsPublicKey(message.ValidatorPublicKey))\n                {\n                    throw new InvalidConsensusMessageException(\n                        $\"Given message's validator {message.ValidatorPublicKey} is invalid\",\n                        message);\n                }\n\n                if (message is ConsensusProposalMsg proposal)\n                {\n                    AddProposal(proposal.Proposal);\n                }\n\n                if (message is ConsensusVoteMsg voteMsg)\n                {\n                    switch (voteMsg)\n                    {\n                        case ConsensusPreVoteMsg preVote:\n                        {\n                            _heightVoteSet.AddVote(preVote.PreVote);\n                            var args = (preVote.Round, VoteFlag.PreVote,\n                                _heightVoteSet.PreVotes(preVote.Round).GetAllVotes());\n                            VoteSetModified?.Invoke(this, args);\n                            break;\n                        }\n\n                        case ConsensusPreCommitMsg preCommit:\n                        {\n                            _heightVoteSet.AddVote(preCommit.PreCommit);\n                            var args = (preCommit.Round, VoteFlag.PreCommit,\n                                _heightVoteSet.PreCommits(preCommit.Round).GetAllVotes());\n                            VoteSetModified?.Invoke(this, args);\n                            break;\n                        }\n                    }\n\n                    _logger.Debug(\n                        \"{FName}: Message: {Message} => Height: {Height}, Round: {Round}, \" +\n                        \"Validator Address: {VAddress}, \" +\n                        \"Hash: {BlockHash}. (context: {Context})\",\n                        nameof(AddMessage),\n                        voteMsg,\n                        voteMsg.Height,\n                        voteMsg.Round,\n                        voteMsg.ValidatorPublicKey.Address,\n                        voteMsg.BlockHash,\n                        ToString());\n                    return true;\n                }\n\n                return false;\n            }\n            catch (InvalidProposalException ipe)\n            {\n                var icme = new InvalidConsensusMessageException(\n                    ipe.Message,\n                    message);\n                var msg = $\"Failed to add invalid message {message} to the \" +\n                          $\"{nameof(HeightVoteSet)}\";\n                _logger.Error(icme, msg);\n                ExceptionOccurred?.Invoke(this, icme);\n                return false;\n            }\n            catch (InvalidVoteException ive)\n            {\n                var icme = new InvalidConsensusMessageException(\n                    ive.Message,\n                    message);\n                var msg = $\"Failed to add invalid message {message} to the \" +\n                          $\"{nameof(HeightVoteSet)}\";\n                _logger.Error(icme, msg);\n                ExceptionOccurred?.Invoke(this, icme);\n                return false;\n            }\n            catch (InvalidConsensusMessageException icme)\n            {\n                var msg = $\"Failed to add invalid message {message} to the \" +\n                          $\"{nameof(HeightVoteSet)}\";\n                _logger.Error(icme, msg);\n                ExceptionOccurred?.Invoke(this, icme);\n                return false;\n            }\n        }\n\n        private void AddProposal(Proposal proposal)\n        {\n            if (!_validatorSet.GetProposer(Height, Round)\n                    .PublicKey.Equals(proposal.ValidatorPublicKey))\n            {\n                throw new InvalidProposalException(\n                    $\"Given proposal's proposer {proposal.ValidatorPublicKey} is not the \" +\n                    $\"proposer for the current height {Height} and round {Round}\",\n                    proposal);\n            }\n\n            if (proposal.Round != Round)\n            {\n                throw new InvalidProposalException(\n                    $\"Given proposal's round {proposal.Round} does not match\" +\n                    $\" with the current round {Round}\",\n                    proposal);\n            }\n\n            // Should check if +2/3 votes already collected and the proposal does not match\n            if (_heightVoteSet.PreVotes(Round).TwoThirdsMajority(out var preVoteMaj23) &&\n                !proposal.BlockHash.Equals(preVoteMaj23))\n            {\n                throw new InvalidProposalException(\n                    $\"Given proposal's block hash {proposal.BlockHash} does not match\" +\n                    $\" with the collected +2/3 preVotes' block hash {preVoteMaj23}\",\n                    proposal);\n            }\n\n            if (_heightVoteSet.PreCommits(Round).TwoThirdsMajority(out var preCommitMaj23) &&\n                !proposal.BlockHash.Equals(preCommitMaj23))\n            {\n                throw new InvalidProposalException(\n                    $\"Given proposal's block hash {proposal.BlockHash} does not match\" +\n                    $\" with the collected +2/3 preCommits' block hash {preCommitMaj23}\",\n                    proposal);\n            }\n\n            if (Proposal is null)\n            {\n                Proposal = proposal;\n                _logger.Debug(\"Proposal {BlockHash} is set\", proposal.BlockHash);\n            }\n            else\n            {\n                throw new InvalidProposalException(\n                    $\"Proposal already exists for height {Height} and round {Round}\",\n                    proposal);\n            }\n        }\n\n        /// <summary>\n        /// Checks the current state to mutate <see cref=\"ConsensusStep\"/> and/or schedule timeouts.\n        /// </summary>\n        private void ProcessGenericUponRules()\n        {\n            if (Step == ConsensusStep.Default || Step == ConsensusStep.EndCommit)\n            {\n                _logger.Debug(\"Operation will not run in {Step} step\", Step);\n                return;\n            }\n\n            (Block Block, int ValidRound)? propose = GetProposal();\n            if (propose is { } p1 &&\n                p1.ValidRound == -1 &&\n                Step == ConsensusStep.Propose)\n            {\n                _logger.Debug(\n                    \"Entering PreVote step due to proposal message with \" +\n                    \"valid round -1. (context: {Context})\",\n                    ToString());\n\n                if (IsValid(p1.Block) && (_lockedRound == -1 || _lockedValue == p1.Block))\n                {\n                    EnterPreVote(Round, p1.Block.Hash);\n                }\n                else\n                {\n                    EnterPreVote(Round, default);\n                }\n            }\n\n            if (propose is { } p2 &&\n                p2.ValidRound >= 0 &&\n                p2.ValidRound < Round &&\n                _heightVoteSet.PreVotes(p2.ValidRound).TwoThirdsMajority(out BlockHash hash1) &&\n                hash1.Equals(p2.Block.Hash) &&\n                Step == ConsensusStep.Propose)\n            {\n                _logger.Debug(\n                    \"Entering PreVote step due to proposal message and have collected \" +\n                    \"2/3+ PreVote for valid round {ValidRound}. (context: {Context})\",\n                    p2.ValidRound,\n                    ToString());\n\n                if (IsValid(p2.Block) &&\n                    (_lockedRound <= p2.ValidRound || _lockedValue == p2.Block))\n                {\n                    EnterPreVote(Round, p2.Block.Hash);\n                }\n                else\n                {\n                    EnterPreVote(Round, default);\n                }\n            }\n\n            if (_heightVoteSet.PreVotes(Round).HasTwoThirdsAny() && Step == ConsensusStep.PreVote)\n            {\n                _ = OnTimeoutPreVote(Round);\n            }\n\n            if (propose is { } p3 &&\n                _heightVoteSet.PreVotes(Round).TwoThirdsMajority(out BlockHash hash2) &&\n                hash2.Equals(p3.Block.Hash) &&\n                IsValid(p3.Block) &&\n                (Step == ConsensusStep.PreVote || Step == ConsensusStep.PreCommit) &&\n                !_hasTwoThirdsPreVoteFlags.Contains(Round))\n            {\n                _logger.Debug(\n                    \"2/3+ PreVotes for the current round {Round} have collected. \" +\n                    \"(context: {Context})\",\n                    Round,\n                    ToString());\n                _hasTwoThirdsPreVoteFlags.Add(Round);\n                if (Step == ConsensusStep.PreVote)\n                {\n                    _logger.Debug(\n                        \"Schedule to enter PreCommit step due to proposal message and have \" +\n                        \"collected 2/3+ PreVote for current round {Round}. (context: {Context})\",\n                        Round,\n                        ToString());\n                    _lockedValue = p3.Block;\n                    _lockedRound = Round;\n                    _ = EnterPreCommitWait(Round, p3.Block.Hash);\n\n                    // Maybe need to broadcast periodically?\n                    PublishMessage(\n                        new ConsensusMaj23Msg(\n                            MakeMaj23(Round, p3.Block.Hash, VoteFlag.PreVote)));\n                }\n\n                _validValue = p3.Block;\n                _validRound = Round;\n            }\n\n            if (_heightVoteSet.PreVotes(Round).TwoThirdsMajority(out BlockHash hash3) &&\n                Step == ConsensusStep.PreVote)\n            {\n                if (hash3.Equals(default))\n                {\n                    _logger.Debug(\n                        \"PreCommit nil for the round {Round} because 2/3+ PreVotes \" +\n                        \"were collected. (context: {Context})\",\n                        Round,\n                        ToString());\n                    _ = EnterPreCommitWait(Round, default);\n                }\n                else if (Proposal is { } proposal && !proposal.BlockHash.Equals(hash3))\n                {\n                    // +2/3 votes were collected and is not equal to proposal's,\n                    // remove invalid proposal.\n                    _logger.Debug(\n                        \"Remove invalid proposal {Proposal} because 2/3+ PreVotes \" +\n                        \"for hash {BlockHash} were collected. (context: {Context})\",\n                        Round,\n                        hash3,\n                        ToString());\n                    Proposal = null;\n                    PublishMessage(\n                        new ConsensusProposalClaimMsg(\n                            new ProposalClaimMetadata(\n                                Height,\n                                Round,\n                                hash3,\n                                DateTimeOffset.UtcNow,\n                                _privateKey.PublicKey).Sign(_privateKey)));\n                }\n            }\n\n            if (_heightVoteSet.PreCommits(Round).HasTwoThirdsAny())\n            {\n                _ = OnTimeoutPreCommit(Round);\n            }\n        }\n\n        /// <summary>\n        /// Checks the current state to mutate <see cref=\"Round\"/> or to terminate\n        /// by setting <see cref=\"ConsensusStep\"/> to <see cref=\"ConsensusStep.EndCommit\"/>.\n        /// </summary>\n        /// <param name=\"message\">The <see cref=\"ConsensusMsg\"/> to process.\n        /// Although this is not strictly needed, this is used for optimization.</param>\n        private void ProcessHeightOrRoundUponRules(ConsensusMsg message)\n        {\n            if (Step == ConsensusStep.Default || Step == ConsensusStep.EndCommit)\n            {\n                _logger.Debug(\"Operation will not run in {Step} step\", Step);\n                return;\n            }\n\n            int round = message.Round;\n            if ((message is ConsensusProposalMsg || message is ConsensusPreCommitMsg) &&\n                GetProposal() is(Block block4, _) &&\n                _heightVoteSet.PreCommits(Round).TwoThirdsMajority(out BlockHash hash) &&\n                block4.Hash.Equals(hash) &&\n                IsValid(block4))\n            {\n                _decision = block4;\n                _committedRound = round;\n\n                // Maybe need to broadcast periodically?\n                PublishMessage(\n                    new ConsensusMaj23Msg(\n                        MakeMaj23(round, block4.Hash, VoteFlag.PreCommit)));\n                _ = EnterEndCommitWait(Round);\n                return;\n            }\n\n            // NOTE: +1/3 prevote received, skip round\n            // FIXME: Tendermint uses +2/3, should be fixed?\n            if (round > Round &&\n                _heightVoteSet.PreVotes(round).HasOneThirdsAny())\n            {\n                _logger.Debug(\n                    \"1/3+ validators from round {Round} > current round {CurrentRound}. \" +\n                    \"(context: {Context})\",\n                    round,\n                    Round,\n                    ToString());\n                StartRound(round);\n                return;\n            }\n        }\n\n        private void EnterPreVote(int round, BlockHash hash)\n        {\n            if (Round != round || Step >= ConsensusStep.PreVote)\n            {\n                // Round and step mismatch\n                return;\n            }\n\n            Step = ConsensusStep.PreVote;\n            PublishMessage(\n                new ConsensusPreVoteMsg(MakeVote(round, hash, VoteFlag.PreVote)));\n        }\n\n        private void EnterPreCommit(int round, BlockHash hash)\n        {\n            if (Round != round || Step >= ConsensusStep.PreCommit)\n            {\n                // Round and step mismatch\n                return;\n            }\n\n            _logger.Debug(\n                \"Entering PreCommit step current round {Round}. (context: {Context})\",\n                Round,\n                ToString());\n            Step = ConsensusStep.PreCommit;\n            PublishMessage(\n                new ConsensusPreCommitMsg(MakeVote(round, hash, VoteFlag.PreCommit)));\n        }\n\n        private void EnterEndCommit(int round)\n        {\n            if (Round != round ||\n                Step == ConsensusStep.Default ||\n                Step == ConsensusStep.EndCommit)\n            {\n                // Round and step mismatch\n                return;\n            }\n\n            Step = ConsensusStep.EndCommit;\n            if (_decision is not { } block)\n            {\n                StartRound(Round + 1);\n                return;\n            }\n\n            try\n            {\n                _logger.Information(\n                    \"Committing block #{Index} {Hash} (context: {Context})\",\n                    block.Index,\n                    block.Hash,\n                    ToString());\n\n                IsValid(block);\n                AppendBlock(block);\n            }\n            catch (Exception e)\n            {\n                _logger.Error(\n                    e,\n                    \"Failed to commit block #{Index} {Hash}\",\n                    block.Index,\n                    block.Hash);\n                ExceptionOccurred?.Invoke(this, e);\n                return;\n            }\n\n            _logger.Information(\n                \"Committed block #{Index} {Hash}\",\n                block.Index,\n                block.Hash);\n        }\n\n        /// <summary>\n        /// A timeout mutation to run if no <see cref=\"ConsensusProposalMsg\"/> is received in\n        /// <see cref=\"TimeoutPropose\"/> and is still in <see cref=\"ConsensusStep.Propose\"/> step.\n        /// </summary>\n        /// <param name=\"round\">A round that the timeout task is scheduled for.</param>\n        private void ProcessTimeoutPropose(int round)\n        {\n            if (round == Round && Step == ConsensusStep.Propose)\n            {\n                EnterPreVote(round, default);\n                TimeoutProcessed?.Invoke(this, (round, ConsensusStep.Propose));\n            }\n        }\n\n        /// <summary>\n        /// A timeout mutation to run if +2/3 <see cref=\"ConsensusPreVoteMsg\"/>s were received but\n        /// is still in <paramref name=\"round\"/> round and <see cref=\"ConsensusStep.PreVote\"/> step\n        /// after <see cref=\"TimeoutPreVote\"/>.\n        /// </summary>\n        /// <param name=\"round\">A round that the timeout task is scheduled for.</param>\n        private void ProcessTimeoutPreVote(int round)\n        {\n            if (round == Round && Step == ConsensusStep.PreVote)\n            {\n                EnterPreCommit(round, default);\n                TimeoutProcessed?.Invoke(this, (round, ConsensusStep.PreVote));\n            }\n        }\n\n        /// <summary>\n        /// A timeout mutation to run if +2/3 <see cref=\"ConsensusPreCommitMsg\"/>s were received but\n        /// is still in <paramref name=\"round\"/> round and <see cref=\"ConsensusStep.PreCommit\"/>\n        /// step after <see cref=\"TimeoutPreCommit\"/>.\n        /// </summary>\n        /// <param name=\"round\">A round that the timeout task is scheduled for.</param>\n        private void ProcessTimeoutPreCommit(int round)\n        {\n            if (Step == ConsensusStep.Default || Step == ConsensusStep.EndCommit)\n            {\n                _logger.Debug(\"Operation will not run in {Step} step\", Step);\n                return;\n            }\n\n            if (round == Round)\n            {\n                EnterEndCommit(round);\n                TimeoutProcessed?.Invoke(this, (round, ConsensusStep.PreCommit));\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Net/Consensus/Context.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Text.Json;\nusing System.Threading;\nusing System.Threading.Channels;\nusing Bencodex;\nusing Bencodex.Types;\nusing Caching;\nusing Libplanet.Action;\nusing Libplanet.Blockchain;\nusing Libplanet.Consensus;\nusing Libplanet.Crypto;\nusing Libplanet.Net.Messages;\nusing Libplanet.Types.Blocks;\nusing Libplanet.Types.Consensus;\nusing Libplanet.Types.Evidence;\nusing Libplanet.Types.Tx;\nusing Serilog;\n\nnamespace Libplanet.Net.Consensus\n{\n    /// <summary>\n    /// A state machine class of PBFT consensus algorithm. The state machine is responsible for\n    /// proposing, validating, voting a block and committing the voted block to the blockchain.\n    /// There are five states:\n    /// <list type=\"bullet\">\n    ///     <item>\n    ///         <see cref=\"ConsensusStep.Default\"/> which is the initial state when\n    ///         the <see cref=\"Start\"/> is not called (i.e., round has not been started).\n    ///     </item>\n    ///     <item>\n    ///         <see cref=\"ConsensusStep.Propose\"/>, which is the state when\n    ///         the round has been started and waiting for the block proposal. If a validator is a\n    ///         proposer of the round, it will propose a block to the other validators and to\n    ///         itself.\n    ///     </item>\n    ///     <item>\n    ///         <see cref=\"ConsensusStep.PreVote\"/>, which is the state when a block\n    ///         proposal for a round has been received. While translating to this step, state\n    ///         machine votes for the block whether block is valid or not, and waiting for any +2/3\n    ///         votes from other validators.\n    ///     </item>\n    ///     <item>\n    ///         <see cref=\"ConsensusStep.PreCommit\"/>, which is the state received\n    ///         any +2/3 votes in <see cref=\"ConsensusStep.PreVote\"/>. While\n    ///         translating to this step, state machine votes for whether the block should be\n    ///         committed or not, and waiting for any +2/3 committing votes from other validators.\n    ///         If <see cref=\"ConsensusStep.PreCommit\"/>\n    ///         receives +2/3 commit votes with NIL, starts new round <see cref=\"StartRound\"/> and\n    ///         moves step to <see cref=\"ConsensusStep.Propose\"/>.\n    ///     </item>\n    ///     <item>\n    ///         <see cref=\"ConsensusStep.EndCommit\"/>, which is the state represents\n    ///         committing vote has been received from other validators. Block will be committed\n    ///         to the blockchain and consensus for this height is stopped. (responsibility of next\n    ///         height handling is at <see cref=\"ConsensusContext\"/>).\n    ///     </item>\n    ///     <item>\n    ///         In the above states, <see cref=\"ConsensusStep.Propose\"/>, If\n    ///         receiving proposal fails in <see cref=\"TimeoutPropose\"/>, then step is moved to\n    ///         <see cref=\"ConsensusStep.PreVote\"/> and vote NIL.\n    ///     </item>\n    ///     <item>\n    ///         Similar to Propose, <see cref=\"ConsensusStep.PreVote\"/> and\n    ///         <see cref=\"ConsensusStep.PreCommit\"/> also wait for\n    ///         <see cref=\"TimeoutPreVote\"/> or <see cref=\"TimeoutPreCommit\"/> respectively,\n    ///         if +2/3 vote received but neither NIL nor Block is not +2/3. If still +2/3 vote is\n    ///         not received neither NIL nor Block after timeout runs out, then move to next step\n    ///         and vote NIL.\n    ///     </item>\n    /// </list>\n    /// Validators are bonding/bonded nodes that participate in the consensus.\n    /// </summary>\n    /// <remarks>\n    /// A <see cref=\"Context\"/> represents a consensus of a single height and its multiple\n    /// rounds.\n    /// </remarks>\n    public partial class Context : IDisposable\n    {\n        private readonly ContextOption _contextOption;\n\n        private readonly BlockChain _blockChain;\n        private readonly Codec _codec;\n        private readonly ValidatorSet _validatorSet;\n        private readonly Channel<ConsensusMsg> _messageRequests;\n        private readonly Channel<System.Action> _mutationRequests;\n        private readonly HeightVoteSet _heightVoteSet;\n        private readonly PrivateKey _privateKey;\n        private readonly HashSet<int> _hasTwoThirdsPreVoteFlags;\n        private readonly HashSet<int> _preVoteTimeoutFlags;\n        private readonly HashSet<int> _preCommitTimeoutFlags;\n        private readonly HashSet<int> _preCommitWaitFlags;\n        private readonly HashSet<int> _endCommitWaitFlags;\n        private readonly EvidenceExceptionCollector _evidenceCollector\n            = new EvidenceExceptionCollector();\n\n        private readonly CancellationTokenSource _cancellationTokenSource;\n\n        private readonly ILogger _logger;\n        private readonly LRUCache<BlockHash, bool> _blockValidationCache;\n\n        private Proposal? _proposal;\n        private Block? _proposalBlock;\n        private Block? _lockedValue;\n        private int _lockedRound;\n        private Block? _validValue;\n        private int _validRound;\n        private Block? _decision;\n        private int _committedRound;\n        private BlockCommit? _lastCommit;\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"Context\"/> class.\n        /// </summary>\n        /// <param name=\"blockChain\">A blockchain that will be committed, which\n        /// will be voted by consensus, and used for proposing a block.\n        /// </param>\n        /// <param name=\"height\">A target <see cref=\"Context.Height\"/> of the consensus state.\n        /// </param>\n        /// <param name=\"lastCommit\">The last commit for the previous <see cref=\"Block\"/>.</param>\n        /// <param name=\"privateKey\">A private key for signing a block and message.\n        /// <seealso cref=\"GetValue\"/>\n        /// <seealso cref=\"ProcessGenericUponRules\"/>\n        /// <seealso cref=\"MakeVote\"/>\n        /// </param>\n        /// <param name=\"validators\">The <see cref=\"ValidatorSet\"/> for\n        /// given <paramref name=\"height\"/>.</param>\n        /// <param name=\"contextOption\">A <see cref=\"ContextOption\"/> for\n        /// configuring a timeout and delay for each <see cref=\"ConsensusStep\"/>.</param>\n        public Context(\n            BlockChain blockChain,\n            long height,\n            BlockCommit? lastCommit,\n            PrivateKey privateKey,\n            ValidatorSet validators,\n            ContextOption contextOption)\n            : this(\n                blockChain,\n                height,\n                lastCommit,\n                privateKey,\n                validators,\n                ConsensusStep.Default,\n                -1,\n                128,\n                contextOption)\n        {\n        }\n\n        private Context(\n            BlockChain blockChain,\n            long height,\n            BlockCommit? lastCommit,\n            PrivateKey privateKey,\n            ValidatorSet validators,\n            ConsensusStep consensusStep,\n            int round = -1,\n            int cacheSize = 128,\n            ContextOption? contextOption = null)\n        {\n            if (height < 1)\n            {\n                throw new ArgumentException(\n                    $\"Given {nameof(height)} must be positive: {height}\", nameof(height));\n            }\n\n            _logger = Log\n                .ForContext(\"Tag\", \"Consensus\")\n                .ForContext(\"SubTag\", \"Context\")\n                .ForContext<Context>()\n                .ForContext(\"Source\", nameof(Context));\n\n            _privateKey = privateKey;\n            Height = height;\n            Round = round;\n            Step = consensusStep;\n            _lastCommit = lastCommit;\n            _lockedValue = null;\n            _lockedRound = -1;\n            _validValue = null;\n            _validRound = -1;\n            _decision = null;\n            _committedRound = -1;\n            _blockChain = blockChain;\n            _codec = new Codec();\n            _messageRequests = Channel.CreateUnbounded<ConsensusMsg>();\n            _mutationRequests = Channel.CreateUnbounded<System.Action>();\n            _heightVoteSet = new HeightVoteSet(height, validators);\n            _hasTwoThirdsPreVoteFlags = new HashSet<int>();\n            _preVoteTimeoutFlags = new HashSet<int>();\n            _preCommitTimeoutFlags = new HashSet<int>();\n            _preCommitWaitFlags = new HashSet<int>();\n            _endCommitWaitFlags = new HashSet<int>();\n            _validatorSet = validators;\n            _cancellationTokenSource = new CancellationTokenSource();\n            _blockValidationCache =\n                new LRUCache<BlockHash, bool>(cacheSize, Math.Max(cacheSize / 64, 8));\n\n            _contextOption = contextOption ?? new ContextOption();\n\n            _logger.Information(\n                \"Created Context for height #{Height}, round #{Round}\",\n                Height,\n                Round);\n        }\n\n        /// <summary>\n        /// A target height of this consensus state. This is also a block index now in consensus.\n        /// </summary>\n        public long Height { get; }\n\n        /// <summary>\n        /// A round represents of this consensus state.\n        /// </summary>\n        public int Round { get; private set; }\n\n        /// <summary>\n        /// A step represents of this consensus state. See <see cref=\"Context\"/> for more detail.\n        /// </summary>\n        public ConsensusStep Step { get; private set; }\n\n        public Proposal? Proposal\n        {\n            get => _proposal;\n            private set\n            {\n                if (value is { } p)\n                {\n                    _proposal = p;\n                    _proposalBlock =\n                        BlockMarshaler.UnmarshalBlock((Dictionary)_codec.Decode(p.MarshaledBlock));\n                }\n                else\n                {\n                    _proposal = null;\n                    _proposalBlock = null;\n                }\n            }\n        }\n\n        /// <inheritdoc cref=\"IDisposable.Dispose()\"/>\n        public void Dispose()\n        {\n            _cancellationTokenSource.Cancel();\n            _messageRequests.Writer.TryComplete();\n            _mutationRequests.Writer.TryComplete();\n        }\n\n        /// <summary>\n        /// Returns a <see cref=\"BlockCommit\"/> if the context is committed.\n        /// </summary>\n        /// <returns>Returns <see cref=\"BlockCommit\"/> if the context is committed\n        /// otherwise returns <see langword=\"null\"/>.\n        /// </returns>\n        public BlockCommit? GetBlockCommit()\n        {\n            try\n            {\n                var blockCommit = _heightVoteSet.PreCommits(Round)?.ToBlockCommit();\n                _logger.Debug(\n                    \"{FName}: CommittedRound: {CommittedRound}, Decision: {Decision}, \" +\n                    \"BlockCommit: {BlockCommit}\",\n                    nameof(GetBlockCommit),\n                    _committedRound,\n                    _decision,\n                    blockCommit);\n                return blockCommit;\n            }\n            catch (KeyNotFoundException)\n            {\n                return null;\n            }\n        }\n\n        public VoteSetBits GetVoteSetBits(int round, BlockHash blockHash, VoteFlag flag)\n        {\n            // If executed in correct manner (called by Maj23),\n            // _heightVoteSet.PreVotes(round) on below cannot throw KeyNotFoundException,\n            // since RoundVoteSet has been already created on SetPeerMaj23.\n            bool[] voteBits = flag switch\n            {\n                VoteFlag.PreVote => _heightVoteSet.PreVotes(round).BitArrayByBlockHash(blockHash),\n                VoteFlag.PreCommit\n                    => _heightVoteSet.PreCommits(round).BitArrayByBlockHash(blockHash),\n                _ => throw new ArgumentException(\n                    \"VoteFlag should be either PreVote or PreCommit.\",\n                    nameof(flag)),\n            };\n\n            return new VoteSetBitsMetadata(\n                Height,\n                round,\n                blockHash,\n                DateTimeOffset.UtcNow,\n                _privateKey.PublicKey,\n                flag,\n                voteBits).Sign(_privateKey);\n        }\n\n        /// <summary>\n        /// Add a <see cref=\"ConsensusMsg\"/> to the context.\n        /// </summary>\n        /// <param name=\"maj23\">A <see cref=\"ConsensusMsg\"/> to add.</param>\n        /// <returns>A <see cref=\"VoteSetBits\"/> if given <paramref name=\"maj23\"/> is valid and\n        /// required.</returns>\n        public VoteSetBits? AddMaj23(Maj23 maj23)\n        {\n            try\n            {\n                if (_heightVoteSet.SetPeerMaj23(maj23))\n                {\n                    var voteSetBits = GetVoteSetBits(maj23.Round, maj23.BlockHash, maj23.Flag);\n                    return voteSetBits.VoteBits.All(b => b) ? null : voteSetBits;\n                }\n\n                return null;\n            }\n            catch (InvalidMaj23Exception ime)\n            {\n                var msg = $\"Failed to add invalid maj23 {ime} to the \" +\n                          $\"{nameof(HeightVoteSet)}\";\n                _logger.Error(ime, msg);\n                ExceptionOccurred?.Invoke(this, ime);\n                return null;\n            }\n        }\n\n        public IEnumerable<ConsensusMsg> GetVoteSetBitsResponse(VoteSetBits voteSetBits)\n        {\n            IEnumerable<Vote> votes;\n            try\n            {\n                votes = voteSetBits.Flag switch\n                {\n                    VoteFlag.PreVote =>\n                    _heightVoteSet.PreVotes(voteSetBits.Round).MappedList().Where(\n                        (vote, index)\n                        => !voteSetBits.VoteBits[index]\n                        && vote is { }\n                        && vote.Flag == VoteFlag.PreVote).Select(vote => vote!),\n                    VoteFlag.PreCommit =>\n                    _heightVoteSet.PreCommits(voteSetBits.Round).MappedList().Where(\n                        (vote, index)\n                        => !voteSetBits.VoteBits[index]\n                        && vote is { }\n                        && vote.Flag == VoteFlag.PreCommit).Select(vote => vote!),\n                    _ => throw new ArgumentException(\n                        \"VoteFlag should be PreVote or PreCommit.\",\n                        nameof(voteSetBits.Flag)),\n                };\n            }\n            catch (KeyNotFoundException)\n            {\n                votes = Array.Empty<Vote>();\n            }\n\n            return from vote in votes\n                   select vote.Flag switch\n                   {\n                       VoteFlag.PreVote => (ConsensusMsg)new ConsensusPreVoteMsg(vote),\n                       VoteFlag.PreCommit => (ConsensusMsg)new ConsensusPreCommitMsg(vote),\n                       _ => throw new ArgumentException(\n                           \"VoteFlag should be PreVote or PreCommit.\",\n                           nameof(vote.Flag)),\n                   };\n        }\n\n        /// <summary>\n        /// Returns the summary of context in JSON-formatted string.\n        /// </summary>\n        /// <returns>Returns a JSON-formatted string of context state.</returns>\n        public override string ToString()\n        {\n            var dict = new Dictionary<string, object>\n            {\n                { \"node_id\", _privateKey.Address.ToString() },\n                { \"number_of_validators\", _validatorSet.TotalCount },\n                { \"height\", Height },\n                { \"round\", Round },\n                { \"step\", Step.ToString() },\n                { \"proposal\", Proposal?.ToString() ?? \"null\" },\n                { \"locked_value\", _lockedValue?.Hash.ToString() ?? \"null\" },\n                { \"locked_round\", _lockedRound },\n                { \"valid_value\", _validValue?.Hash.ToString() ?? \"null\" },\n                { \"valid_round\", _validRound },\n            };\n            return JsonSerializer.Serialize(dict);\n        }\n\n        /// <summary>\n        /// Collects <see cref=\"EvidenceException\"/>s that are occurred during the consensus.\n        /// </summary>\n        /// <returns>A list of <see cref=\"EvidenceException\"/>s.</returns>\n        public EvidenceException[] CollectEvidenceExceptions() => _evidenceCollector.Flush();\n\n        /// <summary>\n        /// Gets the timeout of <see cref=\"ConsensusStep.PreVote\"/> with the given\n        /// round.\n        /// </summary>\n        /// <param name=\"round\">A round to get the timeout.</param>\n        /// <returns>A duration in <see cref=\"TimeSpan\"/>.</returns>\n        private TimeSpan TimeoutPreVote(long round)\n        {\n            return TimeSpan.FromMilliseconds(\n                _contextOption.PreVoteTimeoutBase +\n                round * _contextOption.PreVoteTimeoutDelta);\n        }\n\n        /// <summary>\n        /// Gets the timeout of <see cref=\"ConsensusStep.PreCommit\"/> with the given\n        /// round.\n        /// </summary>\n        /// <param name=\"round\">A round to get the timeout.</param>\n        /// <returns>A duration in <see cref=\"TimeSpan\"/>.</returns>\n        private TimeSpan TimeoutPreCommit(long round)\n        {\n            return TimeSpan.FromMilliseconds(\n                _contextOption.PreCommitTimeoutBase +\n                round * _contextOption.PreCommitTimeoutDelta);\n        }\n\n        /// <summary>\n        /// Gets the timeout of <see cref=\"ConsensusStep.Propose\"/> with the given\n        /// round.\n        /// </summary>\n        /// <param name=\"round\">A round to get the timeout.</param>\n        /// <returns>A duration in <see cref=\"TimeSpan\"/>.</returns>\n        private TimeSpan TimeoutPropose(long round)\n        {\n            return TimeSpan.FromMilliseconds(\n                _contextOption.ProposeTimeoutBase +\n                round * _contextOption.ProposeTimeoutDelta);\n        }\n\n        /// <summary>\n        /// Creates a new <see cref=\"Block\"/> to propose.\n        /// </summary>\n        /// <returns>A new <see cref=\"Block\"/> if successfully proposed,\n        /// otherwise <see langword=\"null\"/>.</returns>\n        private Block? GetValue()\n        {\n            try\n            {\n                var evidence = _blockChain.GetPendingEvidence();\n                Block block = _blockChain.ProposeBlock(_privateKey, _lastCommit, evidence);\n                _blockChain.Store.PutBlock(block);\n                return block;\n            }\n            catch (Exception e)\n            {\n                _logger.Error(\n                    e,\n                    \"Could not propose a block for height {Height} and round {Round}\",\n                    Height,\n                    Round);\n                ExceptionOccurred?.Invoke(this, e);\n                return null;\n            }\n        }\n\n        /// <summary>\n        /// Publish <see cref=\"ConsensusMsg\"/> to validators.\n        /// </summary>\n        /// <param name=\"message\">A <see cref=\"ConsensusMsg\"/> to publish.</param>\n        /// <remarks><see cref=\"ConsensusMsg\"/> should be published to itself.</remarks>\n        private void PublishMessage(ConsensusMsg message) =>\n            MessageToPublish?.Invoke(this, message);\n\n        /// <summary>\n        /// Validates the given block.\n        /// </summary>\n        /// <param name=\"block\">A <see cref=\"Block\"/> to validate.</param>\n        /// <returns><see langword=\"true\"/> if block is valid, otherwise <see langword=\"false\"/>.\n        /// </returns>\n        private bool IsValid(Block block)\n        {\n            if (_blockValidationCache.TryGet(block.Hash, out var isValid))\n            {\n                return isValid;\n            }\n            else\n            {\n                // Need to get txs from store, lock?\n                // TODO: Remove ChainId, enhancing lock management.\n                _blockChain._rwlock.EnterUpgradeableReadLock();\n\n                if (block.Index != Height)\n                {\n                    _blockValidationCache.AddReplace(block.Hash, false);\n                    return false;\n                }\n\n                try\n                {\n                    _blockChain.ValidateBlock(block);\n                    _blockChain.ValidateBlockNonces(\n                        block.Transactions\n                            .Select(tx => tx.Signer)\n                            .Distinct()\n                            .ToDictionary(\n                                signer => signer,\n                                signer => _blockChain.Store.GetTxNonce(\n                                    _blockChain.Id, signer)),\n                        block);\n\n                    if (_blockChain.Policy.ValidateNextBlock(\n                        _blockChain, block) is { } bpve)\n                    {\n                        throw bpve;\n                    }\n\n                    foreach (var tx in block.Transactions)\n                    {\n                        if (_blockChain.Policy.ValidateNextBlockTx(\n                            _blockChain, tx) is { } txve)\n                        {\n                            throw txve;\n                        }\n                    }\n\n                    _blockChain.ValidateBlockStateRootHash(block);\n                }\n                catch (Exception e) when (\n                    e is InvalidBlockException ||\n                    e is InvalidTxException ||\n                    e is InvalidActionException)\n                {\n                    _logger.Debug(\n                        e,\n                        \"Block #{Index} {Hash} is invalid\",\n                        block.Index,\n                        block.Hash);\n                    _blockValidationCache.AddReplace(block.Hash, false);\n                    return false;\n                }\n                finally\n                {\n                    _blockChain._rwlock.ExitUpgradeableReadLock();\n                }\n\n                _blockValidationCache.AddReplace(block.Hash, true);\n                return true;\n            }\n        }\n\n        /// <summary>\n        /// Creates a signed <see cref=\"Vote\"/> for a <see cref=\"ConsensusPreVoteMsg\"/> or\n        /// a <see cref=\"ConsensusPreCommitMsg\"/>.\n        /// </summary>\n        /// <param name=\"round\">Current context round.</param>\n        /// <param name=\"hash\">Current context locked <see cref=\"BlockHash\"/>.</param>\n        /// <param name=\"flag\"><see cref=\"VoteFlag\"/> of <see cref=\"Vote\"/> to create.\n        /// Set to <see cref=\"VoteFlag.PreVote\"/> if message is <see cref=\"ConsensusPreVoteMsg\"/>.\n        /// If message is <see cref=\"ConsensusPreCommitMsg\"/>, Set to\n        /// <see cref=\"VoteFlag.PreCommit\"/>.</param>\n        /// <returns>Returns a signed <see cref=\"Vote\"/> with consensus private key.</returns>\n        /// <exception cref=\"ArgumentException\">If <paramref name=\"flag\"/> is either\n        /// <see cref=\"VoteFlag.Null\"/> or <see cref=\"VoteFlag.Unknown\"/>.</exception>\n        private Vote MakeVote(int round, BlockHash hash, VoteFlag flag)\n        {\n            if (flag == VoteFlag.Null || flag == VoteFlag.Unknown)\n            {\n                throw new ArgumentException(\n                    $\"{nameof(flag)} must be either {VoteFlag.PreVote} or {VoteFlag.PreCommit}\" +\n                    $\"to create a valid signed vote.\");\n            }\n\n            return new VoteMetadata(\n                Height,\n                round,\n                hash,\n                DateTimeOffset.UtcNow,\n                _privateKey.PublicKey,\n                _validatorSet.GetValidator(_privateKey.PublicKey).Power,\n                flag).Sign(_privateKey);\n        }\n\n        /// <summary>\n        /// Creates a signed <see cref=\"Maj23\"/> for a <see cref=\"ConsensusMaj23Msg\"/>.\n        /// </summary>\n        /// <param name=\"round\">Current context round.</param>\n        /// <param name=\"hash\">Current context locked <see cref=\"BlockHash\"/>.</param>\n        /// <param name=\"flag\"><see cref=\"VoteFlag\"/> of <see cref=\"Maj23\"/> to create.\n        /// Set to <see cref=\"VoteFlag.PreVote\"/> if +2/3 <see cref=\"ConsensusPreVoteMsg\"/>\n        /// messages that votes to the same block with proposal are collected.\n        /// If +2/3 <see cref=\"ConsensusPreCommitMsg\"/> messages that votes to the same block\n        /// with proposal are collected, Set to <see cref=\"VoteFlag.PreCommit\"/>.</param>\n        /// <returns>Returns a signed <see cref=\"Maj23\"/> with consensus private key.</returns>\n        /// <exception cref=\"ArgumentException\">If <paramref name=\"flag\"/> is either\n        /// <see cref=\"VoteFlag.Null\"/> or <see cref=\"VoteFlag.Unknown\"/>.</exception>\n        private Maj23 MakeMaj23(int round, BlockHash hash, VoteFlag flag)\n        {\n            if (flag == VoteFlag.Null || flag == VoteFlag.Unknown)\n            {\n                throw new ArgumentException(\n                    $\"{nameof(flag)} must be either {VoteFlag.PreVote} or {VoteFlag.PreCommit}\" +\n                    $\"to create a valid signed maj23.\");\n            }\n\n            return new Maj23Metadata(\n                Height,\n                round,\n                hash,\n                DateTimeOffset.UtcNow,\n                _privateKey.PublicKey,\n                flag).Sign(_privateKey);\n        }\n\n        /// <summary>\n        /// Gets the proposed block and valid round of the given round.\n        /// </summary>\n        /// <returns>Returns a tuple of proposer and valid round.  If proposal for the round\n        /// does not exist, returns <see langword=\"null\"/> instead.\n        /// </returns>\n        private (Block, int)? GetProposal() =>\n            Proposal is { } p && _proposalBlock is { } b ? (b, p.ValidRound) : null;\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Net/Consensus/ContextOption.cs",
    "content": "using System;\n\nnamespace Libplanet.Net.Consensus\n{\n    /// <summary>\n    /// An options class to configure <see cref=\"Context\"/> timeout and delay\n    /// for each <see cref=\"ConsensusStep\"/> in milliseconds.\n    /// </summary>\n    public class ContextOption\n    {\n        public ContextOption(\n            int proposeTimeoutBase = 8_000,\n            int preVoteTimeoutBase = 1_000,\n            int preCommitTimeoutBase = 1_000,\n            int proposeTimeoutDelta = 4_000,\n            int preVoteTimeoutDelta = 500,\n            int preCommitTimeoutDelta = 500,\n            int enterPreVoteDelay = 0,\n            int enterPreCommitDelay = 0,\n            int enterEndCommitDelay = 0)\n        {\n            if (proposeTimeoutBase <= 0)\n            {\n                throw new ArgumentOutOfRangeException(\n                    nameof(proposeTimeoutBase),\n                    \"ProposeTimeoutBase must be greater than 0.\");\n            }\n\n            ProposeTimeoutBase = proposeTimeoutBase;\n\n            if (preVoteTimeoutBase <= 0)\n            {\n                throw new ArgumentOutOfRangeException(\n                    nameof(preVoteTimeoutBase),\n                    \"PreVoteTimeoutBase must be greater than 0.\");\n            }\n\n            PreVoteTimeoutBase = preVoteTimeoutBase;\n\n            if (preCommitTimeoutBase <= 0)\n            {\n                throw new ArgumentOutOfRangeException(\n                    nameof(preCommitTimeoutBase),\n                    \"PreCommitTimeoutBase must be greater than 0.\");\n            }\n\n            PreCommitTimeoutBase = preCommitTimeoutBase;\n\n            if (proposeTimeoutDelta <= 0)\n            {\n                throw new ArgumentOutOfRangeException(\n                    nameof(proposeTimeoutDelta),\n                    \"ProposeTimeoutDelta must be greater than 0.\");\n            }\n\n            ProposeTimeoutDelta = proposeTimeoutDelta;\n\n            if (preVoteTimeoutDelta <= 0)\n            {\n                throw new ArgumentOutOfRangeException(\n                    nameof(preVoteTimeoutDelta),\n                    \"PreVoteTimeoutDelta must be greater than 0.\");\n            }\n\n            PreVoteTimeoutDelta = preVoteTimeoutDelta;\n\n            if (preCommitTimeoutDelta <= 0)\n            {\n                throw new ArgumentOutOfRangeException(\n                    nameof(preCommitTimeoutDelta),\n                    \"PreCommitTimeoutDelta must be greater than 0.\");\n            }\n\n            PreCommitTimeoutDelta = preCommitTimeoutDelta;\n\n            if (enterPreVoteDelay < 0)\n            {\n                throw new ArgumentOutOfRangeException(\n                    nameof(enterPreVoteDelay),\n                    \"EnterPreVoteDelay must be greater than or equal to 0.\");\n            }\n\n            EnterPreVoteDelay = enterPreVoteDelay;\n\n            if (enterPreCommitDelay < 0)\n            {\n                throw new ArgumentOutOfRangeException(\n                    nameof(enterPreCommitDelay),\n                    \"EnterPreCommitDelay must be greater than or equal to 0.\");\n            }\n\n            EnterPreCommitDelay = enterPreCommitDelay;\n\n            if (enterEndCommitDelay < 0)\n            {\n                throw new ArgumentOutOfRangeException(\n                    nameof(enterEndCommitDelay),\n                    \"EnterEndCommitDelay must be greater than or equal to 0.\");\n            }\n\n            EnterEndCommitDelay = enterEndCommitDelay;\n        }\n\n        public int ProposeTimeoutBase { get; }\n\n        public int PreVoteTimeoutBase { get; }\n\n        public int PreCommitTimeoutBase { get; }\n\n        public int ProposeTimeoutDelta { get; }\n\n        public int PreVoteTimeoutDelta { get; }\n\n        public int PreCommitTimeoutDelta { get; }\n\n        public int EnterPreVoteDelay { get; }\n\n        public int EnterPreCommitDelay { get; }\n\n        public int EnterEndCommitDelay { get; }\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Net/Consensus/EvidenceExceptionCollector.cs",
    "content": "using System.Collections.Generic;\nusing Libplanet.Blockchain;\nusing Libplanet.Types.Evidence;\n\nnamespace Libplanet.Net.Consensus\n{\n    /// <summary>\n    /// Collects <see cref=\"EvidenceException\"/>s to be occurred during the consensus process.\n    /// <para>The collected exceptions are added to the Pending pool using the\n    /// <see cref=\"BlockChain.AddEvidence\" /> method after the blockchain's tip changes.</para>\n    /// </summary>\n    internal sealed class EvidenceExceptionCollector\n    {\n        private readonly List<EvidenceException> _exceptionList\n            = new List<EvidenceException>();\n\n        /// <summary>\n        /// Adds an <see cref=\"EvidenceException\"/> to the <see cref=\"EvidenceExceptionCollector\"/>.\n        /// </summary>\n        /// <param name=\"exception\">Indicates an <see cref=\"EvidenceException\"/> that includes\n        /// the infraction information.</param>\n        public void Add(EvidenceException exception)\n        {\n            _exceptionList.Add(exception);\n        }\n\n        /// <summary>\n        /// Adds multiple <see cref=\"EvidenceException\"/>s to the\n        /// <see cref=\"EvidenceExceptionCollector\"/>.\n        /// </summary>\n        /// <param name=\"exceptions\">Indicates an array of <see cref=\"EvidenceException\"/>s\n        /// that include the infraction information.</param>\n        public void AddRange(EvidenceException[] exceptions)\n        {\n            _exceptionList.AddRange(exceptions);\n        }\n\n        /// <summary>\n        /// Flushes all the collected <see cref=\"EvidenceException\"/>s and returns them.\n        /// </summary>\n        /// <returns>\n        /// A list of <see cref=\"EvidenceException\"/>s that have been collected so far.\n        /// </returns>\n        public EvidenceException[] Flush()\n        {\n            var evidenceExceptions = _exceptionList.ToArray();\n            _exceptionList.Clear();\n            return evidenceExceptions;\n        }\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Net/Consensus/Gossip.cs",
    "content": "using System;\nusing System.Collections.Concurrent;\nusing System.Collections.Generic;\nusing System.Collections.Immutable;\nusing System.Linq;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing Dasync.Collections;\nusing Libplanet.Net.Messages;\nusing Libplanet.Net.Protocols;\nusing Libplanet.Net.Transports;\nusing Serilog;\n\nnamespace Libplanet.Net.Consensus\n{\n    /// <summary>\n    /// A class gossips messages into network. Peers will be stored and managed by Kademlia DHT.\n    /// </summary>\n    public class Gossip : IDisposable\n    {\n        private const int DLazy = 6;\n        private readonly TimeSpan _rebuildTableInterval = TimeSpan.FromMinutes(1);\n        private readonly TimeSpan _refreshTableInterval = TimeSpan.FromSeconds(10);\n        private readonly TimeSpan _refreshLifespan = TimeSpan.FromSeconds(60);\n        private readonly TimeSpan _heartbeatInterval = TimeSpan.FromSeconds(1);\n        private readonly ITransport _transport;\n        private readonly MessageCache _cache;\n        private readonly Action<Message> _validateMessageToReceive;\n        private readonly Action<MessageContent> _validateMessageToSend;\n        private readonly Action<MessageContent> _processMessage;\n        private readonly IEnumerable<BoundPeer> _seeds;\n        private readonly ILogger _logger;\n\n        private TaskCompletionSource<object?> _runningEvent;\n        private CancellationTokenSource? _cancellationTokenSource;\n        private RoutingTable _table;\n        private HashSet<BoundPeer> _denySet;\n        private IProtocol _protocol;\n        private ConcurrentDictionary<BoundPeer, HashSet<MessageId>> _haveDict;\n\n        /// <summary>\n        /// Creates a <see cref=\"Gossip\"/> instance.\n        /// </summary>\n        /// <param name=\"transport\">\n        /// An <see cref=\"ITransport\"/> used for communicating messages.</param>\n        /// <param name=\"peers\">A list of <see cref=\"BoundPeer\"/> composing network.</param>\n        /// <param name=\"seeds\">A list of <see cref=\"BoundPeer\"/> for lookup network.</param>\n        /// <param name=\"validateMessageToReceive\">Action to be called to validate\n        /// a received message to add. Validates on <see cref=\"HandleMessageAsync\"/>.</param>\n        /// <param name=\"validateMessageToSend\">Action to be called to validate a new message\n        /// to send. Validates on <see cref=\"HandleWantAsync\"/>.</param>\n        /// <param name=\"processMessage\">Action to be called when receiving a new message.</param>\n        public Gossip(\n            ITransport transport,\n            ImmutableArray<BoundPeer> peers,\n            ImmutableArray<BoundPeer> seeds,\n            Action<Message> validateMessageToReceive,\n            Action<MessageContent> validateMessageToSend,\n            Action<MessageContent> processMessage)\n        {\n            _transport = transport;\n            _cache = new MessageCache();\n            _validateMessageToReceive = validateMessageToReceive;\n            _validateMessageToSend = validateMessageToSend;\n            _processMessage = processMessage;\n            _table = new RoutingTable(transport.AsPeer.Address);\n\n            // FIXME: Dumb way to add peer.\n            foreach (BoundPeer peer in peers.Where(p => p.Address != transport.AsPeer.Address))\n            {\n                _table.AddPeer(peer);\n            }\n\n            _protocol = new KademliaProtocol(_table, _transport, transport.AsPeer.Address);\n            _seeds = seeds;\n\n            _runningEvent = new TaskCompletionSource<object?>();\n            _haveDict = new ConcurrentDictionary<BoundPeer, HashSet<MessageId>>();\n            _denySet = new HashSet<BoundPeer>();\n            Running = false;\n\n            _logger = Log\n                .ForContext(\"Tag\", \"Consensus\")\n                .ForContext(\"SubTag\", \"Gossip\")\n                .ForContext<Gossip>()\n                .ForContext(\"Source\", nameof(Gossip));\n        }\n\n        /// <summary>\n        /// Whether this <see cref=\"Gossip\"/> instance is running.\n        /// </summary>\n        /// <value>Gets the value indicates whether the instance is running.</value>\n        public bool Running\n        {\n            get => _runningEvent.Task.Status == TaskStatus.RanToCompletion;\n\n            private set\n            {\n                if (value)\n                {\n                    _runningEvent.TrySetResult(null);\n                }\n                else\n                {\n                    _runningEvent = new TaskCompletionSource<object?>();\n                }\n            }\n        }\n\n        /// <summary>\n        /// <see cref=\"BoundPeer\"/> representation of transport used in <see cref=\"Gossip\"/>.\n        /// </summary>\n        public BoundPeer AsPeer => _transport.AsPeer;\n\n        /// <summary>\n        /// The list of <see cref=\"BoundPeer\"/>s in the <see cref=\"Gossip\"/>'s table.\n        /// </summary>\n        public IEnumerable<BoundPeer> Peers => _table.Peers;\n\n        /// <summary>\n        /// The list of <see cref=\"BoundPeer\"/>s written in <see cref=\"_denySet\"/>.\n        /// </summary>\n        public IEnumerable<BoundPeer> DeniedPeers => _denySet.ToList();\n\n        /// <summary>\n        /// Start the <see cref=\"Gossip\"/> instance.\n        /// </summary>\n        /// <param name=\"ctx\">A cancellation token used to propagate notification\n        /// that this operation should be canceled.</param>\n        /// <returns>An awaitable task without value.</returns>\n        public async Task StartAsync(CancellationToken ctx)\n        {\n            _cancellationTokenSource = CancellationTokenSource.CreateLinkedTokenSource(ctx);\n            Task transportTask = _transport.StartAsync(ctx);\n            await _transport.WaitForRunningAsync();\n            try\n            {\n                await _protocol.BootstrapAsync(_seeds, TimeSpan.FromSeconds(1), 3, ctx);\n            }\n            catch (PeerDiscoveryException pde)\n            {\n                _logger.Error(\n                    pde,\n                    \"Peer discovery exception occurred during {FName}.\",\n                    nameof(StartAsync));\n            }\n\n            _transport.ProcessMessageHandler.Register(\n                HandleMessageAsync(_cancellationTokenSource.Token));\n            _logger.Debug(\"All peers are alive. Starting gossip...\");\n            Running = true;\n            await Task.WhenAny(\n                transportTask,\n                RefreshTableAsync(_cancellationTokenSource.Token),\n                RebuildTableAsync(_cancellationTokenSource.Token),\n                HeartbeatTask(_cancellationTokenSource.Token));\n        }\n\n        /// <summary>\n        /// Stop the <see cref=\"Gossip\"/> instance.\n        /// </summary>\n        /// <param name=\"waitFor\">\n        /// The <see cref=\"TimeSpan\"/> of delay before actual stopping.</param>\n        /// <param name=\"ctx\">A cancellation token used to propagate notification\n        /// that this operation should be canceled.</param>\n        /// <returns>An awaitable task without value.</returns>\n        public async Task StopAsync(TimeSpan waitFor, CancellationToken ctx)\n        {\n            _cancellationTokenSource?.Cancel();\n            await _transport.StopAsync(waitFor, ctx);\n        }\n\n        /// <summary>\n        /// Clear message cache.\n        /// </summary>\n        public void ClearCache()\n        {\n            _cache.Clear();\n        }\n\n        /// <inheritdoc/>\n        public void Dispose()\n        {\n            _cancellationTokenSource?.Cancel();\n            _cancellationTokenSource?.Dispose();\n            _cache.Clear();\n            _transport.Dispose();\n        }\n\n        /// <summary>\n        /// Waits until this <see cref=\"Gossip\"/> instance gets started to run.\n        /// </summary>\n        /// <returns>A <see cref=\"Task\"/> completed when <see cref=\"Gossip.Running\"/>\n        /// property becomes <see langword=\"true\"/>.</returns>\n        public Task WaitForRunningAsync() => _runningEvent.Task;\n\n        /// <summary>\n        /// Publish given <see cref=\"MessageContent\"/> to peers.\n        /// </summary>\n        /// <param name=\"content\">A <see cref=\"MessageContent\"/> instance to publish.</param>\n        public void PublishMessage(MessageContent content) => PublishMessage(\n            content,\n            PeersToBroadcast(_table.Peers, DLazy));\n\n        /// <summary>\n        /// Publish given <see cref=\"MessageContent\"/> to given <paramref name=\"targetPeers\"/>.\n        /// </summary>\n        /// <param name=\"content\">A <see cref=\"MessageContent\"/> instance to publish.</param>\n        /// <param name=\"targetPeers\"><see cref=\"BoundPeer\"/>s to publish to.</param>\n        public void PublishMessage(MessageContent content, IEnumerable<BoundPeer> targetPeers)\n        {\n            AddMessage(content);\n            _transport.BroadcastMessage(targetPeers, content);\n        }\n\n        /// <summary>\n        /// Process a <see cref=\"MessageContent\"/> and add it to the gossip.\n        /// </summary>\n        /// <param name=\"content\">A <see cref=\"MessageContent\"/> instance to\n        /// process and gossip.</param>\n        public void AddMessage(MessageContent content)\n        {\n            try\n            {\n                _cache.Put(content);\n            }\n            catch (ArgumentException)\n            {\n                _logger.Verbose(\n                    \"Message of content {Content} with id {Id} seen recently, ignored\",\n                    content,\n                    content.Id);\n                return;\n            }\n            catch (Exception)\n            {\n                return;\n            }\n\n            try\n            {\n                _processMessage(content);\n            }\n            catch (Exception)\n            {\n                // ignored\n            }\n        }\n\n        /// <summary>\n        /// Adds multiple <see cref=\"MessageContent\"/>s in parallel.\n        /// <seealso cref=\"AddMessage(MessageContent)\"/>\n        /// </summary>\n        /// <param name=\"contents\">\n        /// An enumerable <see cref=\"MessageContent\"/> instance to process and gossip.</param>\n        public void AddMessages(IEnumerable<MessageContent> contents)\n        {\n            contents.AsParallel().ForAll(AddMessage);\n        }\n\n        /// <summary>\n        /// Adds <paramref name=\"peer\"/> to the <see cref=\"_denySet\"/> to reject\n        /// <see cref=\"Message\"/>s from.\n        /// </summary>\n        /// <param name=\"peer\"><see cref=\"BoundPeer\"/> to deny.</param>\n        public void DenyPeer(BoundPeer peer)\n        {\n            _denySet.Add(peer);\n        }\n\n        /// <summary>\n        /// Remove <paramref name=\"peer\"/> frin the <see cref=\"_denySet\"/> to allow\n        /// <see cref=\"Message\"/>s from.\n        /// </summary>\n        /// <param name=\"peer\"><see cref=\"BoundPeer\"/> to allow.</param>\n        public void AllowPeer(BoundPeer peer)\n        {\n            _denySet.Remove(peer);\n        }\n\n        /// <summary>\n        /// Clear <see cref=\"_denySet\"/> to allow all <see cref=\"BoundPeer\"/>.\n        /// </summary>\n        public void ClearDenySet()\n        {\n            _denySet.Clear();\n        }\n\n        /// <summary>\n        /// Selects <paramref name=\"count\"/> <see cref=\"BoundPeer\"/>s from <paramref name=\"peers\"/>.\n        /// </summary>\n        /// <param name=\"peers\">A <see cref=\"BoundPeer\"/> pool.</param>\n        /// <param name=\"count\">Number of <see cref=\"BoundPeer\"/> to choose.</param>\n        /// <returns>\n        /// An enumerable <see cref=\"BoundPeer\"/>'s of length <paramref name=\"count\"/>.</returns>\n        private IEnumerable<BoundPeer> PeersToBroadcast(\n            IEnumerable<BoundPeer> peers,\n            int count)\n        {\n            var rnd = new Random();\n            return peers\n                .Where(x => !_seeds.Contains(x))\n                .OrderBy(x => rnd.Next())\n                .Take(count);\n        }\n\n        /// <summary>\n        /// Handle a message received from <see cref=\"ITransport.ProcessMessageHandler\"/>.\n        /// </summary>\n        /// <param name=\"ctx\">A cancellation token used to propagate notification\n        /// that this operation should be canceled.</param>\n        /// <returns>A function with parameter of <see cref=\"Message\"/>\n        /// and return <see cref=\"Task\"/>.</returns>\n        private Func<Message, Task> HandleMessageAsync(CancellationToken ctx) => async msg =>\n        {\n            _logger.Verbose(\"HandleMessage: {Message}\", msg);\n\n            if (_denySet.Contains(msg.Remote))\n            {\n                _logger.Verbose(\"Message from denied peer, rejecting: {Message}\", msg);\n                await ReplyMessagePongAsync(msg, ctx);\n                return;\n            }\n\n            try\n            {\n                _validateMessageToReceive(msg);\n            }\n            catch (Exception e)\n            {\n                _logger.Error(\n                    \"Invalid message, rejecting: {Message}, {Exception}\", msg, e.Message);\n                return;\n            }\n\n            switch (msg.Content)\n            {\n                case PingMsg _:\n                case FindNeighborsMsg _:\n                    // Ignore protocol related messages, Kadmelia Protocol will handle it.\n                    break;\n                case HaveMessage _:\n                    await HandleHaveAsync(msg, ctx);\n                    break;\n                case WantMessage _:\n                    await HandleWantAsync(msg, ctx);\n                    break;\n                default:\n                    await ReplyMessagePongAsync(msg, ctx);\n                    AddMessage(msg.Content);\n                    break;\n            }\n        };\n\n        /// <summary>\n        /// A lifecycle task which will run in every <see cref=\"_heartbeatInterval\"/>.\n        /// </summary>\n        /// <param name=\"ctx\">A cancellation token used to propagate notification\n        /// that this operation should be canceled.</param>\n        /// <returns>An awaitable task without value.</returns>\n        private async Task HeartbeatTask(CancellationToken ctx)\n        {\n            while (!ctx.IsCancellationRequested)\n            {\n                _logger.Debug(\"{FName}() has invoked.\", nameof(HeartbeatTask));\n                MessageId[] ids = _cache.GetGossipIds();\n                if (ids.Any())\n                {\n                    _transport.BroadcastMessage(\n                        PeersToBroadcast(_table.Peers, DLazy),\n                        new HaveMessage(ids));\n                }\n\n                _ = SendWantAsync(ctx);\n                await Task.Delay(_heartbeatInterval, ctx);\n            }\n        }\n\n        /// <summary>\n        /// A function handling <see cref=\"HaveMessage\"/>.\n        /// <seealso cref=\"HandleMessageAsync\"/>\n        /// </summary>\n        /// <param name=\"msg\">Target <see cref=\"HaveMessage\"/>.</param>\n        /// <param name=\"ctx\">A cancellation token used to propagate notification\n        /// that this operation should be canceled.</param>\n        /// <returns>An awaitable task without value.</returns>\n        private async Task HandleHaveAsync(Message msg, CancellationToken ctx)\n        {\n            var haveMessage = (HaveMessage)msg.Content;\n\n            await ReplyMessagePongAsync(msg, ctx);\n            MessageId[] idsToGet = _cache.DiffFrom(haveMessage.Ids);\n            _logger.Verbose(\n                \"Handle HaveMessage. {Total}/{Count} messages to get.\",\n                haveMessage.Ids.Count(),\n                idsToGet.Length);\n            if (!idsToGet.Any())\n            {\n                return;\n            }\n\n            _logger.Verbose(\"Ids to receive: {Ids}\", idsToGet);\n            if (!_haveDict.ContainsKey(msg.Remote))\n            {\n                _haveDict.TryAdd(msg.Remote, new HashSet<MessageId>(idsToGet));\n            }\n            else\n            {\n                List<MessageId> list = _haveDict[msg.Remote].ToList();\n                list.AddRange(idsToGet.Where(id => !list.Contains(id)));\n                _haveDict[msg.Remote] = new HashSet<MessageId>(list);\n            }\n        }\n\n        private async Task SendWantAsync(CancellationToken ctx)\n        {\n            // TODO: To optimize WantMessage count to minimum, should remove duplications.\n            var copy = _haveDict.ToDictionary(pair => pair.Key, pair => pair.Value.ToArray());\n            _haveDict = new ConcurrentDictionary<BoundPeer, HashSet<MessageId>>();\n            var optimized = new Dictionary<BoundPeer, MessageId[]>();\n            while (copy.Any())\n            {\n                var longest = copy.OrderBy(pair => pair.Value.Length).Last();\n                optimized.Add(longest.Key, longest.Value);\n                copy.Remove(longest.Key);\n                var removeCandidate = new List<BoundPeer>();\n                foreach (var pair in copy)\n                {\n                    var clean = pair.Value.Where(id => !longest.Value.Contains(id)).ToArray();\n                    if (clean.Any())\n                    {\n                        copy[pair.Key] = clean;\n                    }\n                    else\n                    {\n                        removeCandidate.Add(pair.Key);\n                    }\n                }\n\n                foreach (var peer in removeCandidate)\n                {\n                    copy.Remove(peer);\n                }\n            }\n\n            await optimized.ParallelForEachAsync(\n                async pair =>\n                {\n                    MessageId[] idsToGet = pair.Value;\n                    var want = new WantMessage(idsToGet);\n                    Message[] replies = (await _transport.SendMessageAsync(\n                        pair.Key,\n                        want,\n                        TimeSpan.FromSeconds(1),\n                        idsToGet.Length,\n                        true,\n                        ctx)).ToArray();\n                    _logger.Verbose(\n                        \"Received {Expected}/{Count} messages. Messages: {@Messages}, Ids: {Ids}\",\n                        idsToGet.Length,\n                        replies.Length,\n                        replies,\n                        replies.Select(m => m.Content.Id).ToArray());\n                    replies.AsParallel().ForAll(\n                        r =>\n                        {\n                            try\n                            {\n                                _validateMessageToReceive(r);\n                                AddMessage(r.Content);\n                            }\n                            catch (Exception e)\n                            {\n                                _logger.Error(\n                                    \"Invalid message, rejecting: {Message}, {Exception}\",\n                                    r,\n                                    e.Message);\n                            }\n                        });\n                },\n                ctx);\n        }\n\n        /// <summary>\n        /// A function handling <see cref=\"WantMessage\"/>.\n        /// <seealso cref=\"HandleMessageAsync\"/>\n        /// </summary>\n        /// <param name=\"msg\">Target <see cref=\"WantMessage\"/>.</param>\n        /// <param name=\"ctx\">A cancellation token used to propagate notification\n        /// that this operation should be canceled.</param>\n        /// <returns>An awaitable task without value.</returns>\n        private async Task HandleWantAsync(Message msg, CancellationToken ctx)\n        {\n            // FIXME: Message may have been discarded.\n            var wantMessage = (WantMessage)msg.Content;\n            MessageContent[] contents = wantMessage.Ids.Select(id => _cache.Get(id)).ToArray();\n            MessageId[] ids = contents.Select(c => c.Id).ToArray();\n\n            _logger.Debug(\n                \"WantMessage: Requests are: {Idr}, Ids are: {Id}, Messages are: {Messages}\",\n                wantMessage.Ids,\n                ids,\n                contents.Select(content => (content.Type, content.Id)));\n\n            await contents.ParallelForEachAsync(\n                async c =>\n                {\n                    try\n                    {\n                        _validateMessageToSend(c);\n                        await _transport.ReplyMessageAsync(c, msg.Identity, ctx);\n                    }\n                    catch (Exception e)\n                    {\n                        _logger.Error(\n                            \"Invalid message, rejecting: {Message}, {Exception}\", msg, e.Message);\n                    }\n                }, ctx);\n\n            var id = msg is { Identity: null } ? \"unknown\" : new Guid(msg.Identity).ToString();\n            _logger.Debug(\"Finished replying WantMessage. {RequestId}\", id);\n        }\n\n        /// <summary>\n        /// A lifecycle task which will run in every <see cref=\"_rebuildTableInterval\"/> for\n        /// refreshing peer table from seed peer.\n        /// </summary>\n        /// <param name=\"ctx\">A cancellation token used to propagate notification\n        /// that this operation should be canceled.</param>\n        /// <returns>An awaitable task without value.</returns>\n        private async Task RebuildTableAsync(CancellationToken ctx)\n        {\n            _logger.Debug(\n                \"{FName}: Updating the peer table from seed for every {Time} milliseconds...\",\n                nameof(RebuildTableAsync),\n                _rebuildTableInterval.TotalMilliseconds);\n\n            while (!ctx.IsCancellationRequested)\n            {\n                await Task.Delay(_rebuildTableInterval, ctx);\n                _logger.Debug(\n                    \"{FName}: Updating peer table from seed(s) {Seeds}...\",\n                    nameof(RebuildTableAsync),\n                    _seeds.Select(s => s.Address.ToHex()));\n                try\n                {\n                    await _protocol.BootstrapAsync(\n                        _seeds,\n                        TimeSpan.FromSeconds(1),\n                        Kademlia.MaxDepth,\n                        ctx);\n                }\n                catch (Exception e)\n                {\n                    _logger.Error(\n                        e,\n                        \"Peer discovery exception occurred during {FName}.\",\n                        nameof(RebuildTableAsync));\n                }\n            }\n        }\n\n        /// <summary>\n        /// Periodically checks whether peers in table is alive.\n        /// </summary>\n        /// <param name=\"ctx\">\n        /// A cancellation token used to propagate notification that this\n        /// operation should be canceled.</param>\n        private async Task RefreshTableAsync(CancellationToken ctx)\n        {\n            while (!ctx.IsCancellationRequested)\n            {\n                try\n                {\n                    await _protocol.RefreshTableAsync(_refreshLifespan, ctx);\n                    await _protocol.CheckReplacementCacheAsync(ctx);\n                    await Task.Delay(_refreshTableInterval, ctx);\n                }\n                catch (OperationCanceledException e)\n                {\n                    _logger.Warning(e, $\"{nameof(RefreshTableAsync)}() is cancelled.\");\n                    throw;\n                }\n                catch (Exception e)\n                {\n                    var msg = \"Unexpected exception occurred during \" +\n                              $\"{nameof(RefreshTableAsync)}(): {{0}}\";\n                    _logger.Warning(e, msg, e);\n                }\n            }\n        }\n\n        /// <summary>\n        /// Replies a <see cref=\"PongMsg\"/> of received <paramref name=\"message\"/>.\n        /// </summary>\n        /// <param name=\"message\">A message to replies.</param>\n        /// <param name=\"ctx\">A cancellation token used to propagate notification\n        /// that this operation should be canceled.</param>\n        /// <returns>An awaitable task without value.</returns>\n        private async Task ReplyMessagePongAsync(Message message, CancellationToken ctx)\n        {\n            await _transport.ReplyMessageAsync(new PongMsg(), message.Identity, ctx);\n        }\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Net/Consensus/GossipConsensusMessageCommunicator.cs",
    "content": "using System;\nusing System.Collections.Concurrent;\nusing System.Collections.Immutable;\nusing Libplanet.Net.Messages;\nusing Libplanet.Net.Transports;\nusing Serilog;\n\nnamespace Libplanet.Net.Consensus\n{\n    /// <summary>\n    /// An <see cref=\"IConsensusMessageCommunicator\"/> implementation using <see cref=\"Gossip\"/>.\n    /// </summary>\n    public class GossipConsensusMessageCommunicator : IConsensusMessageCommunicator\n    {\n        private readonly ILogger _logger;\n        private long _height;\n        private int _round;\n        private ConcurrentDictionary<BoundPeer, ImmutableHashSet<int>> _peerCatchupRounds;\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"GossipConsensusMessageCommunicator\"/>\n        /// class.\n        /// </summary>\n        /// <param name=\"consensusTransport\">An <see cref=\"ITransport\"/> for sending the\n        /// <see cref=\"ConsensusMsg\"/>s to validators.</param>\n        /// <param name=\"validatorPeers\">A list of validator's <see cref=\"BoundPeer\"/>,\n        /// including itself.\n        /// </param>\n        /// <param name=\"seedPeers\">A list of seed's <see cref=\"BoundPeer\"/>.</param>\n        /// <param name=\"processMessage\">Action to be called when receiving a new\n        /// <see cref=\"ConsensusMsg\"/>.</param>\n        public GossipConsensusMessageCommunicator(\n            ITransport consensusTransport,\n            ImmutableArray<BoundPeer> validatorPeers,\n            ImmutableArray<BoundPeer> seedPeers,\n            Action<MessageContent> processMessage)\n        {\n            Gossip = new Gossip(\n                consensusTransport,\n                validatorPeers,\n                seedPeers,\n                ValidateMessageToReceive,\n                ValidateMessageToSend,\n                processMessage);\n            _height = 0;\n            _round = 0;\n            _peerCatchupRounds\n                = new ConcurrentDictionary<BoundPeer, ImmutableHashSet<int>>();\n\n            _logger = Log\n                .ForContext(\"Tag\", \"Consensus\")\n                .ForContext(\"SubTag\", \"ConsensusMessageCommunicator\")\n                .ForContext<GossipConsensusMessageCommunicator>()\n                .ForContext(\"Source\", nameof(GossipConsensusMessageCommunicator));\n        }\n\n        /// <summary>\n        /// <see cref=\"Gossip\"/> of <see cref=\"GossipConsensusMessageCommunicator\"/>.\n        /// </summary>\n        internal Gossip Gossip { get; }\n\n        /// <inheritdoc/>\n        public void PublishMessage(ConsensusMsg message)\n            => Gossip.PublishMessage(message);\n\n        /// <inheritdoc/>\n        public void OnStartHeight(long height)\n        {\n            _height = height;\n            _peerCatchupRounds.Clear();\n            Gossip.ClearDenySet();\n        }\n\n        /// <inheritdoc/>\n        public void OnStartRound(int round)\n        {\n            _round = round;\n            Gossip.ClearCache();\n        }\n\n        /// <summary>\n        /// Message validator to be called on <see cref=\"Gossip.HandleMessageAsync\"/>.\n        /// This will be set as parameter of <see cref=\"Gossip\"/>, and will validate\n        /// <see cref=\"Message\"/>s before it's added to the <see cref=\"Gossip._cache\"/>.\n        /// </summary>\n        /// <param name=\"message\"><see cref=\"Message\"/> to validate.</param>\n        private void ValidateMessageToReceive(Message message)\n        {\n            if (message.Content is ConsensusVoteMsg voteMsg)\n            {\n                FilterDifferentHeightVote(voteMsg);\n                FilterHigherRoundVoteSpam(voteMsg, message.Remote);\n            }\n        }\n\n        /// <summary>\n        /// Message content validator to be called on <see cref=\"Gossip.HandleWantAsync\"/>.\n        /// This will be set as parameter of <see cref=\"Gossip\"/>, and will validate\n        /// <see cref=\"Message\"/>s before respond to peer's <see cref=\"WantMessage\"/>.\n        /// </summary>\n        /// <param name=\"content\"><see cref=\"MessageContent\"/> to validate.</param>\n        private void ValidateMessageToSend(MessageContent content)\n        {\n            if (content is ConsensusVoteMsg voteMsg)\n            {\n                if (voteMsg.Height != _height)\n                {\n                    throw new InvalidConsensusMessageException(\n                        $\"Cannot send vote of height different from context's\", voteMsg);\n                }\n\n                if (voteMsg.Round > _round)\n                {\n                    throw new InvalidConsensusMessageException(\n                        $\"Cannot send vote of round higher than context's\", voteMsg);\n                }\n            }\n        }\n\n        /// <summary>\n        /// Filter logic for different height <see cref=\"ConsensusVoteMsg\"/>s.\n        /// </summary>\n        /// <param name=\"voteMsg\"><see cref=\"ConsensusVoteMsg\"/> to filter.</param>\n        private void FilterDifferentHeightVote(ConsensusVoteMsg voteMsg)\n        {\n            if (voteMsg.Height != _height)\n            {\n                throw new InvalidConsensusMessageException(\n                    $\"Filtered vote from different height: {voteMsg.Height}\",\n                    voteMsg);\n            }\n        }\n\n        /// <summary>\n        /// Spam filter logic for higher round <see cref=\"ConsensusVoteMsg\"/>s.\n        /// </summary>\n        /// <param name=\"voteMsg\"><see cref=\"ConsensusVoteMsg\"/> to filter.</param>\n        /// <param name=\"peer\"><see cref=\"BoundPeer\"/> who sent <paramref name=\"voteMsg\"/>.\n        /// </param>\n        private void FilterHigherRoundVoteSpam(ConsensusVoteMsg voteMsg, BoundPeer peer)\n        {\n            if (voteMsg.Height == _height &&\n                voteMsg.Round > _round)\n            {\n                _peerCatchupRounds.AddOrUpdate(\n                    peer,\n                    ImmutableHashSet.Create<int>(voteMsg.Round),\n                    (peer, set) => set.Add(voteMsg.Round));\n\n                if (_peerCatchupRounds.TryGetValue(peer, out var set) && set.Count > 2)\n                {\n                    Gossip.DenyPeer(peer);\n                    throw new InvalidConsensusMessageException(\n                        $\"Add {peer} to deny set, since repetitively found higher rounds: \" +\n                        $\"{string.Join(\", \", _peerCatchupRounds[peer])}\",\n                        voteMsg);\n                }\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Net/Consensus/HeightVoteSet.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing Libplanet.Consensus;\nusing Libplanet.Crypto;\nusing Libplanet.Types.Blocks;\nusing Libplanet.Types.Consensus;\nusing Serilog;\n\nnamespace Libplanet.Net.Consensus\n{\n    public class HeightVoteSet\n    {\n        private readonly ILogger _logger;\n        private readonly object _lock;\n        private long _height;\n        private ValidatorSet _validatorSet;\n        private Dictionary<int, RoundVoteSet> _roundVoteSets;\n        private int _round;\n\n        public HeightVoteSet(long height, ValidatorSet validatorSet)\n        {\n            _logger = Log\n                .ForContext(\"Tag\", \"Consensus\")\n                .ForContext(\"SubTag\", \"Context\")\n                .ForContext<HeightVoteSet>()\n                .ForContext(\"Source\", nameof(HeightVoteSet));\n            _lock = new object();\n            lock (_lock)\n            {\n                _height = height;\n                _validatorSet = validatorSet;\n                _roundVoteSets = new Dictionary<int, RoundVoteSet>();\n            }\n\n            Reset(height, validatorSet);\n        }\n\n        public int Count => _roundVoteSets.Values.Sum(v => v.Count);\n\n        public void Reset(long height, ValidatorSet validatorSet)\n        {\n            lock (_lock)\n            {\n                _height = height;\n                _validatorSet = validatorSet;\n                _roundVoteSets = new Dictionary<int, RoundVoteSet>();\n\n                AddRound(0);\n                _round = 0;\n            }\n        }\n\n        public long Height()\n        {\n            lock (_lock)\n            {\n                return _height;\n            }\n        }\n\n        public int Round()\n        {\n            lock (_lock)\n            {\n                return _round;\n            }\n        }\n\n        // Create more RoundVoteSets up to round.\n        public void SetRound(int round)\n        {\n            lock (_lock)\n            {\n                var newRound = _round + 1;\n                if (_round != 0 && (round < newRound))\n                {\n                    throw new ArgumentException(\"Round must increase\");\n                }\n\n                for (int r = newRound; r <= round; r++)\n                {\n                    if (_roundVoteSets.ContainsKey(r))\n                    {\n                        continue; // Already exists because peerCatchupRounds.\n                    }\n\n                    AddRound(r);\n                }\n\n                _round = round;\n            }\n        }\n\n        public void AddRound(int round)\n        {\n            if (_roundVoteSets.ContainsKey(round))\n            {\n                throw new ArgumentException($\"Add round for an existing round: {round}\");\n            }\n\n            _logger.Debug(\"Adding round {Round}\", round);\n            VoteSet preVotes = new VoteSet(_height, round, VoteFlag.PreVote, _validatorSet);\n            VoteSet preCommits = new VoteSet(_height, round, VoteFlag.PreCommit, _validatorSet);\n            _roundVoteSets[round] = new RoundVoteSet(preVotes, preCommits);\n        }\n\n        // Duplicate votes return added=false, err=nil.\n        // By convention, peerID is \"\" if origin is self.\n        public void AddVote(Vote vote)\n        {\n            lock (_lock)\n            {\n                if (vote.Height != _height)\n                {\n                    throw new InvalidVoteException(\n                        \"Height of vote is different from current HeightVoteSet\",\n                        vote);\n                }\n\n                PublicKey validatorKey = vote.ValidatorPublicKey;\n\n                if (validatorKey is null)\n                {\n                    throw new InvalidVoteException(\"ValidatorKey of the vote cannot be null\", vote);\n                }\n\n                if (!_validatorSet.ContainsPublicKey(validatorKey))\n                {\n                    throw new InvalidVoteException(\n                        \"ValidatorKey of the vote is not in the validator set\",\n                        vote);\n                }\n\n                if (vote.ValidatorPower is not { } power)\n                {\n                    const string msg = \"ValidatorPower of the vote cannot be null\";\n                    throw new InvalidVoteException(msg, vote);\n                }\n                else if (_validatorSet.GetValidator(validatorKey).Power != power)\n                {\n                    const string msg = \"ValidatorPower of the vote is given and the value is \" +\n                                       \"not the same with the one in the validator set\";\n                    throw new InvalidVoteException(msg, vote);\n                }\n\n                if (!vote.Flag.Equals(VoteFlag.PreVote) &&\n                    !vote.Flag.Equals(VoteFlag.PreCommit))\n                {\n                    throw new InvalidVoteException(\n                        $\"VoteFlag should be either {VoteFlag.PreVote} or {VoteFlag.PreCommit}\",\n                        vote);\n                }\n\n                if (!vote.Verify())\n                {\n                    throw new InvalidVoteException(\n                        \"Received vote's signature is invalid\",\n                        vote);\n                }\n\n                VoteSet voteSet;\n                try\n                {\n                    voteSet = GetVoteSet(vote.Round, vote.Flag);\n                }\n                catch (KeyNotFoundException)\n                {\n                    AddRound(vote.Round);\n                    voteSet = GetVoteSet(vote.Round, vote.Flag);\n                }\n\n                voteSet.AddVote(vote);\n            }\n        }\n\n        public VoteSet PreVotes(int round)\n        {\n            lock (_lock)\n            {\n                return GetVoteSet(round, VoteFlag.PreVote);\n            }\n        }\n\n        public VoteSet PreCommits(int round)\n        {\n            lock (_lock)\n            {\n                return GetVoteSet(round, VoteFlag.PreCommit);\n            }\n        }\n\n        // Last round and block hash that has +2/3 prevotes for a particular block or nil.\n        // Returns -1 if no such round exists.\n        public (int, BlockHash) POLInfo()\n        {\n            lock (_lock)\n            {\n                for (int r = _round; r >= 0; r--)\n                {\n                    try\n                    {\n                        VoteSet voteSet = GetVoteSet(r, VoteFlag.PreVote);\n                        bool exists = voteSet.TwoThirdsMajority(out BlockHash polBlockHash);\n                        if (exists)\n                        {\n                            return (r, polBlockHash);\n                        }\n                    }\n                    catch (KeyNotFoundException)\n                    {\n                        continue;\n                    }\n                }\n\n                return (-1, default(BlockHash));\n            }\n        }\n\n        /// <summary>\n        /// Gets a <see cref=\"VoteSet\"/> for given round and flag.\n        /// </summary>\n        /// <param name=\"round\">A round of the <see cref=\"VoteSet\"/> to get.</param>\n        /// <param name=\"voteFlag\">A vote flag of the <see cref=\"VoteSet\"/> to get.</param>\n        /// <returns>A <see cref=\"VoteSet\"/> for given round and flag.</returns>\n        /// <exception cref=\"KeyNotFoundException\">Thrown when <see cref=\"VoteSet\"/> for\n        /// given round does not exist.\n        /// </exception>\n        /// <exception cref=\"ArgumentException\">Thrown when given <paramref name=\"voteFlag\"/>\n        /// is not either <see cref=\"VoteFlag.PreVote\"/> or <see cref=\"VoteFlag.PreCommit\"/>.\n        /// </exception>\n        /// <exception cref=\"KeyNotFoundException\">Thrown when there's no <see cref=\"RoundVoteSet\"/>\n        /// exists for given <paramref name=\"round\"/>.\n        /// </exception>\n        public VoteSet GetVoteSet(int round, VoteFlag voteFlag)\n        {\n            RoundVoteSet roundVoteSet = _roundVoteSets[round];\n            return voteFlag switch\n            {\n                VoteFlag.PreVote => roundVoteSet.PreVotes,\n                VoteFlag.PreCommit => roundVoteSet.PreCommits,\n                _ => throw new ArgumentException($\"Unexpected vote type: {voteFlag}\"),\n            };\n        }\n\n        // If a peer claims that it has 2/3 majority for given blockKey, call this.\n        // NOTE: if there are too many peers, or too much peer churn,\n        // this can cause memory issues.\n        // TODO: implement ability to remove peers too\n        public bool SetPeerMaj23(Maj23 maj23)\n        {\n            lock (_lock)\n            {\n                if (!maj23.Flag.Equals(VoteFlag.PreVote) &&\n                    !maj23.Flag.Equals(VoteFlag.PreCommit))\n                {\n                    throw new InvalidMaj23Exception(\n                        $\"Maj23 must have either {VoteFlag.PreVote} or {VoteFlag.PreCommit} \" +\n                        $\"(Actual: {maj23.Flag})\",\n                        maj23);\n                }\n\n                VoteSet voteSet;\n                try\n                {\n                    voteSet = GetVoteSet(maj23.Round, maj23.Flag);\n                }\n                catch (KeyNotFoundException)\n                {\n                    AddRound(maj23.Round);\n                    voteSet = GetVoteSet(maj23.Round, maj23.Flag);\n                }\n\n                return voteSet.SetPeerMaj23(maj23);\n            }\n        }\n\n        internal class RoundVoteSet\n        {\n            public RoundVoteSet(VoteSet preVotes, VoteSet preCommits)\n            {\n                PreVotes = preVotes;\n                PreCommits = preCommits;\n            }\n\n            public VoteSet PreVotes { get; set; }\n\n            public VoteSet PreCommits { get; set; }\n\n            public int Count => PreVotes.TotalCount + PreCommits.TotalCount;\n        }\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Net/Consensus/IConsensusMessageCommunicator.cs",
    "content": "using Libplanet.Net.Messages;\n\nnamespace Libplanet.Net.Consensus\n{\n    /// <summary>\n    /// Interface for communicating <see cref=\"ConsensusMsg\"/>s with peers.\n    /// </summary>\n    public interface IConsensusMessageCommunicator\n    {\n        /// <summary>\n        /// Publish given <paramref name=\"message\"/> to peers.\n        /// </summary>\n        /// <param name=\"message\"><see cref=\"ConsensusMsg\"/> to publish.</param>\n        public void PublishMessage(ConsensusMsg message);\n\n        /// <summary>\n        /// Method that will be called on the\n        /// <see cref=\"Context.Start\"/> call.\n        /// </summary>\n        /// <param name=\"height\"><see cref=\"Context.Height\"/>\n        /// to trigger this method.</param>\n        public void OnStartHeight(long height);\n\n        /// <summary>\n        /// Method that will be called on the\n        /// <see cref=\"Context.StartRound(int)\"/> call.\n        /// </summary>\n        /// <param name=\"round\"><see cref=\"Context.Round\"/>\n        /// to trigger this method.</param>\n        public void OnStartRound(int round);\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Net/Consensus/IReactor.cs",
    "content": "using System;\nusing System.Threading;\nusing System.Threading.Tasks;\n\nnamespace Libplanet.Net.Consensus\n{\n    /// <summary>\n    /// A interface of consensus reactors.\n    /// </summary>\n    public interface IReactor : IDisposable\n    {\n        /// <summary>\n        /// Starts a reactor.\n        /// </summary>\n        /// <param name=\"cancellationToken\">A cancellation token used to propagate notification\n        /// that this operation should be canceled.</param>\n        /// <returns>A awaitable tasks from reactor for starting.</returns>\n        public Task StartAsync(CancellationToken cancellationToken);\n\n        /// <summary>\n        /// Stops a reactor.\n        /// </summary>\n        /// <param name=\"cancellationToken\">A cancellation token used to propagate notification\n        /// that this operation should be canceled.</param>\n        /// <returns>A awaitable tasks from reactor for stopping.</returns>\n        public Task StopAsync(CancellationToken cancellationToken);\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Net/Consensus/InvalidConsensusMessageException.cs",
    "content": "using System;\nusing Libplanet.Net.Messages;\n\nnamespace Libplanet.Net.Consensus\n{\n    /// <summary>\n    /// An exception thrown when a received <see cref=\"ConsensusMsg\"/> is invalid.  In particular,\n    /// this is thrown pre-emptively before a <see cref=\"ConsensusMsg\"/> is processed, i.e.\n    /// does not change the state of a <see cref=\"Context\"/> in a meaningful way.\n    /// </summary>\n    public class InvalidConsensusMessageException : InvalidMessageContentException\n    {\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"InvalidConsensusMessageException\"/> class.\n        /// </summary>\n        /// <param name=\"message\">The error message that explains the reason for the exception.\n        /// </param>\n        /// <param name=\"receivedMessage\">The <see cref=\"ConsensusMsg\"/> that caused this exception.\n        /// </param>\n        /// <param name=\"innerException\">The exception that is the cause of the current exception.\n        /// </param>\n        public InvalidConsensusMessageException(\n            string message,\n            MessageContent receivedMessage,\n            Exception innerException)\n            : base(message, receivedMessage, innerException)\n        {\n        }\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"InvalidConsensusMessageException\"/> class.\n        /// </summary>\n        /// <param name=\"message\">The error message that explains the reason for the exception.\n        /// </param>\n        /// <param name=\"receivedMessage\">The <see cref=\"ConsensusMsg\"/> that caused this exception.\n        /// </param>\n        public InvalidConsensusMessageException(string message, MessageContent receivedMessage)\n            : base(message, receivedMessage)\n        {\n        }\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Net/Consensus/InvalidHeightIncreasingException.cs",
    "content": "using System;\nusing Libplanet.Blockchain;\n\nnamespace Libplanet.Net.Consensus\n{\n    /// <summary>\n    /// An exception thrown when a <see cref=\"ConsensusContext.NewHeight\"/> has called with\n    /// height is not the index of <see cref=\"BlockChain.Tip\"/> + 1.\n    /// </summary>\n    public class InvalidHeightIncreasingException : Exception\n    {\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"InvalidHeightIncreasingException\"/> class.\n        /// </summary>\n        /// <param name=\"message\">The error message that explains the reason for the exception.\n        /// </param>\n        public InvalidHeightIncreasingException(string message)\n            : base(message)\n        {\n        }\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Net/Consensus/InvalidMaj23Exception.cs",
    "content": "using System;\nusing Libplanet.Consensus;\n\nnamespace Libplanet.Net.Consensus\n{\n    /// <summary>\n    /// An exception thrown when a received <see cref=\"Maj23\"/> is invalid.  In particular,\n    /// this is thrown pre-emptively before a <see cref=\"Maj23\"/> is processed, i.e.\n    /// does not change the state of a <see cref=\"Context\"/> in a meaningful way.\n    /// </summary>\n    public class InvalidMaj23Exception : Exception\n    {\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"InvalidMaj23Exception\"/> class.\n        /// </summary>\n        /// <param name=\"message\">The error message that explains the reason for the exception.\n        /// </param>\n        /// <param name=\"maj23\">The <see cref=\"Maj23\"/> that caused this exception.\n        /// </param>\n        /// <param name=\"innerException\">The exception that is the cause of the current exception.\n        /// </param>\n        public InvalidMaj23Exception(\n            string message,\n            Maj23 maj23,\n            Exception innerException)\n            : base(message, innerException)\n        {\n            Maj23 = maj23;\n        }\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"InvalidMaj23Exception\"/> class.\n        /// </summary>\n        /// <param name=\"message\">The error message that explains the reason for the exception.\n        /// </param>\n        /// <param name=\"maj23\">The <see cref=\"Maj23\"/> that caused this exception.\n        /// </param>\n        public InvalidMaj23Exception(string message, Maj23 maj23)\n            : base(message)\n        {\n            Maj23 = maj23;\n        }\n\n        public Maj23 Maj23 { get; }\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Net/Consensus/InvalidProposalException.cs",
    "content": "using System;\nusing Libplanet.Consensus;\n\nnamespace Libplanet.Net.Consensus\n{\n    /// <summary>\n    /// An exception thrown when a received <see cref=\"Proposal\"/> is invalid.  In particular,\n    /// this is thrown pre-emptively before a <see cref=\"Proposal\"/> is processed, i.e.\n    /// does not change the state of a <see cref=\"Context\"/> in a meaningful way.\n    /// </summary>\n    public class InvalidProposalException : Exception\n    {\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"InvalidProposalException\"/> class.\n        /// </summary>\n        /// <param name=\"message\">The error message that explains the reason for the exception.\n        /// </param>\n        /// <param name=\"proposal\">The <see cref=\"Proposal\"/> that caused this exception.\n        /// </param>\n        /// <param name=\"innerException\">The exception that is the cause of the current exception.\n        /// </param>\n        public InvalidProposalException(\n            string message,\n            Proposal proposal,\n            Exception innerException)\n            : base(message, innerException)\n        {\n            Proposal = proposal;\n        }\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"InvalidProposalException\"/> class.\n        /// </summary>\n        /// <param name=\"message\">The error message that explains the reason for the exception.\n        /// </param>\n        /// <param name=\"proposal\">The <see cref=\"Proposal\"/> that caused this exception.\n        /// </param>\n        public InvalidProposalException(string message, Proposal proposal)\n            : base(message)\n        {\n            Proposal = proposal;\n        }\n\n        public Proposal Proposal { get; }\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Net/Consensus/InvalidVoteException.cs",
    "content": "using System;\nusing Libplanet.Types.Consensus;\n\nnamespace Libplanet.Net.Consensus\n{\n    /// <summary>\n    /// An exception thrown when a received <see cref=\"Vote\"/> is invalid.  In particular,\n    /// this is thrown pre-emptively before a <see cref=\"Vote\"/> is processed, i.e.\n    /// does not change the state of a <see cref=\"Context\"/> in a meaningful way.\n    /// </summary>\n    public class InvalidVoteException : Exception\n    {\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"InvalidVoteException\"/> class.\n        /// </summary>\n        /// <param name=\"message\">The error message that explains the reason for the exception.\n        /// </param>\n        /// <param name=\"vote\">The <see cref=\"Vote\"/> that caused this exception.\n        /// </param>\n        /// <param name=\"innerException\">The exception that is the cause of the current exception.\n        /// </param>\n        public InvalidVoteException(\n            string message,\n            Vote vote,\n            Exception innerException)\n            : base(message, innerException)\n        {\n            Vote = vote;\n        }\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"InvalidVoteException\"/> class.\n        /// </summary>\n        /// <param name=\"message\">The error message that explains the reason for the exception.\n        /// </param>\n        /// <param name=\"vote\">The <see cref=\"Vote\"/> that caused this exception.\n        /// </param>\n        public InvalidVoteException(string message, Vote vote)\n            : base(message)\n        {\n            Vote = vote;\n        }\n\n        public Vote Vote { get; }\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Net/Consensus/MessageCache.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Diagnostics.Contracts;\nusing System.Linq;\nusing Libplanet.Net.Messages;\n\nnamespace Libplanet.Net.Consensus\n{\n    /// <summary>\n    /// Cache object that stores recently seen <see cref=\"Message\"/>s.\n    /// </summary>\n    public class MessageCache\n    {\n        private readonly object _lock;\n        private readonly Dictionary<MessageId, MessageContent> _messages;\n\n        /// <summary>\n        /// Create a message cache instance that stores\n        /// recently seen <see cref=\"Message\"/>s for gossip.\n        /// </summary>\n        public MessageCache()\n        {\n            _lock = new object();\n            _messages = new Dictionary<MessageId, MessageContent>();\n        }\n\n        /// <summary>\n        /// Puts the <paramref name=\"message\"/> into message cache.\n        /// </summary>\n        /// <param name=\"message\">A <see cref=\"Message\"/> to cache.</param>\n        /// <exception cref=\"ArgumentException\">\n        /// Thrown when a <see cref=\"Message\"/> with the same id already exists.</exception>\n        public void Put(MessageContent message)\n        {\n            lock (_lock)\n            {\n                try\n                {\n                    MessageId id = message.Id;\n                    _messages.Add(id, message);\n                }\n                catch (ArgumentException)\n                {\n                    throw new ArgumentException(\n                        \"A message with the same id already exists.\",\n                        nameof(message));\n                }\n            }\n        }\n\n        /// <summary>\n        /// Gets copied value of the message with <paramref name=\"id\"/>\n        /// if it exists in the message cache.\n        /// </summary>\n        /// <param name=\"id\">A <see cref=\"MessageId\"/> of the <see cref=\"Message\"/> to get.</param>\n        /// <returns>A message with id <paramref name=\"id\"/>.</returns>\n        /// <exception cref=\"KeyNotFoundException\">Thrown when a <see cref=\"Message\"/> of id\n        /// <paramref name=\"id\"/> does not exist in the message cache.</exception>\n        [Pure]\n        public MessageContent Get(MessageId id)\n        {\n            lock (_lock)\n            {\n                if (_messages.TryGetValue(id, out MessageContent? msg))\n                {\n                    // FIXME: This is a workaround for preventing any message modification in\n                    // message dictionary.\n                    return NetMQMessageCodec.CreateMessage(msg.Type, msg.DataFrames.ToArray());\n                }\n\n                throw new KeyNotFoundException($\"A message of id {id} does not exist.\");\n            }\n        }\n\n        /// <summary>\n        /// Gets the array of <see cref=\"MessageId\"/> of set difference\n        /// <paramref name=\"ids\"/> - <see cref=\"_messages\"/>.\n        /// </summary>\n        /// <param name=\"ids\"><see cref=\"MessageId\"/>s of the <see cref=\"Message\"/>s\n        /// to calculate difference from.</param>\n        /// <returns>Result of set difference operation.</returns>\n        [Pure]\n        public MessageId[] DiffFrom(IEnumerable<MessageId> ids)\n        {\n            lock (_lock)\n            {\n                return ids.Where(id => !_messages.TryGetValue(id, out _)).ToArray();\n            }\n        }\n\n        /// <summary>\n        /// Selects at maximum <c>gossip</c> messages used for gossiping.\n        /// </summary>\n        /// <returns>A list of message ids to gossip.</returns>\n        [Pure]\n        public MessageId[] GetGossipIds()\n        {\n            lock (_lock)\n            {\n                return _messages.Keys.ToArray();\n            }\n        }\n\n        /// <summary>\n        /// Clears <see cref=\"_messages\"/>.\n        /// </summary>\n        public void Clear()\n        {\n            lock (_lock)\n            {\n                _messages.Clear();\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Net/Consensus/VoteSet.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Collections.Immutable;\nusing System.Linq;\nusing System.Numerics;\nusing Libplanet.Consensus;\nusing Libplanet.Crypto;\nusing Libplanet.Types.Blocks;\nusing Libplanet.Types.Consensus;\nusing Libplanet.Types.Evidence;\nusing Serilog;\n\nnamespace Libplanet.Net.Consensus\n{\n    public class VoteSet\n    {\n        private readonly ILogger _logger;\n        private readonly long _height;\n        private readonly int _round;\n        private readonly VoteFlag _voteType;\n        private readonly ValidatorSet _validatorSet;\n        private readonly object _lock;\n        private readonly Dictionary<PublicKey, Vote> _votes; // Primary votes to share\n        private readonly Dictionary<BlockHash, BlockVotes> _votesByBlock;\n        private readonly Dictionary<PublicKey, BlockHash> _peerMaj23s;\n        private BlockHash? _maj23; // First 2/3 majority seen\n\n        public VoteSet(\n            long height,\n            int round,\n            VoteFlag voteType,\n            ValidatorSet validatorSet)\n        {\n            _logger = Log\n                .ForContext(\"Tag\", \"Consensus\")\n                .ForContext(\"SubTag\", \"Context\")\n                .ForContext<VoteSet>()\n                .ForContext(\"Source\", nameof(VoteSet));\n            _height = height;\n            _round = round;\n            _voteType = voteType;\n            _validatorSet = validatorSet;\n            _lock = new object();\n            _votes = new Dictionary<PublicKey, Vote>();\n            _votesByBlock = new Dictionary<BlockHash, BlockVotes>();\n            _peerMaj23s = new Dictionary<PublicKey, BlockHash>();\n        }\n\n        public IEnumerable<Validator> Validators => _validatorSet.Validators;\n\n        public BigInteger Sum => _validatorSet.GetValidatorsPower(\n            _votes.Values.Select(vote => vote.ValidatorPublicKey).ToList());\n\n        /// <summary>\n        /// Count of the canonical <see cref=\"Vote\"/>s.\n        /// </summary>\n        public int Count => _votes.Count;\n\n        /// <summary>\n        /// Count of the all <see cref=\"Vote\"/>s.\n        /// </summary>\n        public int TotalCount => _votesByBlock.Values.Sum(votes => votes.Votes.Count);\n\n        /// <summary>\n        /// Predicate indicates where the <see cref=\"VoteSet\"/> have collected a vote with\n        /// given <paramref name=\"publicKey\"/> and <paramref name=\"blockHash\"/>.\n        /// </summary>\n        /// <param name=\"publicKey\">A <see cref=\"PublicKey\"/> of the <see cref=\"Vote\"/>.</param>\n        /// <param name=\"blockHash\">A <see cref=\"BlockHash\"/> of the <see cref=\"Vote\"/>.</param>\n        /// <returns> <see langword=\"true\"/> when a vote with given params exits,\n        /// else <see langword=\"false\"/>.\n        /// </returns>\n        public bool Contains(PublicKey publicKey, BlockHash blockHash)\n        {\n            return _votes.Values.Any(\n                vote => vote.ValidatorPublicKey.Equals(publicKey)\n                && vote.BlockHash.Equals(blockHash));\n        }\n\n        /// <summary>\n        /// Gets a <see cref=\"Vote\"/> signed by <paramref name=\"publicKey\"/> and of hash\n        /// <paramref name=\"blockHash\"/>.\n        /// </summary>\n        /// <param name=\"publicKey\">A <see cref=\"PublicKey\"/> of the <see cref=\"Vote\"/>.</param>\n        /// <param name=\"blockHash\">A <see cref=\"BlockHash\"/> of the <see cref=\"Vote\"/>.</param>\n        /// <returns>A <see cref=\"Vote\"/> signed by <paramref name=\"publicKey\"/> and of hash\n        /// <paramref name=\"blockHash\"/> if exists. Else, <see langword=\"null\"/>.</returns>\n        public Vote? GetVote(PublicKey publicKey, BlockHash blockHash)\n        {\n            Vote vote;\n            try\n            {\n                vote = _votes[publicKey];\n                if (vote.BlockHash.Equals(blockHash))\n                {\n                    return vote;\n                }\n            }\n            catch (KeyNotFoundException)\n            {\n            }\n\n            try\n            {\n                return _votesByBlock[blockHash].Votes[publicKey];\n            }\n            catch (KeyNotFoundException)\n            {\n            }\n\n            return null;\n        }\n\n        /// <summary>\n        /// Gets all collected <see cref=\"Vote\"/>s that voted to block with hash\n        /// <paramref name=\"blockHash\"/>.\n        /// </summary>\n        /// <param name=\"blockHash\">\n        /// <see cref=\"BlockHash\"/> of the <see cref=\"Vote\"/>s to collect.</param>\n        /// <returns><see cref=\"IEnumerable{T}\"/> of <see cref=\"Vote\"/>.</returns>\n        public IEnumerable<Vote> GetVotes(BlockHash blockHash) =>\n            _votesByBlock[blockHash].Votes.Values;\n\n        /// <summary>\n        /// Gets all collected <see cref=\"Vote\"/>s.\n        /// </summary>\n        /// <returns><see cref=\"IEnumerable{T}\"/> of <see cref=\"Vote\"/>.</returns>\n        public IEnumerable<Vote> GetAllVotes()\n        {\n            var list = new List<Vote>();\n            foreach (var votes in _votesByBlock.Values)\n            {\n                list.AddRange(votes.Votes.Values);\n            }\n\n            return list;\n        }\n\n        /// <summary>\n        /// If a peer claims that it has 2/3 majority for given <see cref=\"BlockHash\"/>,\n        /// modify state by calling this method.\n        /// </summary>\n        /// <param name=\"maj23\">A <see cref=\"Maj23\"/> received by other validator.</param>\n        /// <returns><see langword=\"true\"/> when given <paramref name=\"maj23\"/> actually modified\n        /// state of the <see cref=\"VoteSet\"/>, else <see langword=\"false\"/>.</returns>\n        /// <exception cref=\"InvalidMaj23Exception\">\n        /// Thrown when given <paramref name=\"maj23\"/> has conflicting <see cref=\"BlockHash\"/>.\n        /// </exception>\n        /// <remarks>if there are too many peers, or too much peer churn,\n        /// this can cause memory issues.</remarks>\n        public bool SetPeerMaj23(Maj23 maj23)\n        {\n            // TODO: implement ability to remove peers too\n            lock (_lock)\n            {\n                PublicKey publicKey = maj23.ValidatorPublicKey;\n                BlockHash blockHash = maj23.BlockHash;\n\n                // Make sure peer hasn't already told us something.\n                if (_peerMaj23s.ContainsKey(publicKey))\n                {\n                    BlockHash hash = _peerMaj23s[publicKey];\n                    if (hash.Equals(blockHash))\n                    {\n                        return false;\n                    }\n\n                    throw new InvalidMaj23Exception(\n                        $\"Received conflicting BlockHash from peer {publicKey} \" +\n                        $\"(Expected: {hash}, Actual: {blockHash})\",\n                        maj23);\n                }\n\n                _peerMaj23s[publicKey] = blockHash;\n\n                if (!_votesByBlock.ContainsKey(blockHash))\n                {\n                    _votesByBlock[blockHash] = new BlockVotes(blockHash);\n                }\n\n                BlockVotes votesByBlock = _votesByBlock[blockHash];\n                if (votesByBlock.PeerMaj23)\n                {\n                    return false;\n                }\n                else\n                {\n                    votesByBlock.PeerMaj23 = true;\n                    return true;\n                }\n            }\n        }\n\n        public bool[] BitArray()\n        {\n            lock (_lock)\n            {\n                return _validatorSet.Validators.Select(validator =>\n                     _votes.ContainsKey(validator.PublicKey)).ToArray();\n            }\n        }\n\n        public bool[] BitArrayByBlockHash(BlockHash blockHash)\n        {\n            lock (_lock)\n            {\n                if (_votesByBlock.ContainsKey(blockHash))\n                {\n                    return _validatorSet.Validators.Select(validator =>\n                        _votesByBlock[blockHash].Votes.ContainsKey(validator.PublicKey)).ToArray();\n                }\n\n                return _validatorSet.Validators.Select(_ => false).ToArray();\n            }\n        }\n\n        /// <summary>\n        /// Returns a copy of the list of <see cref=\"Vote\"/>s stored by the <see cref=\"VoteSet\"/>.\n        /// </summary>\n        /// <returns>\n        /// A copy of the list of <see cref=\"Vote\"/>s stored by the <see cref=\"VoteSet\"/>.\n        /// </returns>\n        public List<Vote> List()\n            => _votes.Values.OrderBy(vote => vote.ValidatorPublicKey.Address).ToList();\n\n        /// <summary>\n        /// Returns a copy of the list of <see cref=\"Vote\"/>s stored by the <see cref=\"VoteSet\"/>.\n        /// If failed to collect <see cref=\"Vote\"/> from certain peer,\n        /// fill it with nil <see cref=\"Vote\"/>.\n        /// </summary>\n        /// <returns>\n        /// A copy of the list of <see cref=\"Vote\"/>s stored by the <see cref=\"VoteSet\"/>.\n        /// If failed to collect <see cref=\"Vote\"/> from certain peer,\n        /// fill it with nil <see cref=\"Vote\"/>.\n        /// </returns>\n        /// <exception cref=\"NullReferenceException\">\n        /// Thrown when there are no +2/3 majority <see cref=\"Vote\"/>s.</exception>\n        public List<Vote> MappedList()\n        {\n            if (_maj23 is { } maj23NotNull)\n            {\n                return _votesByBlock[maj23NotNull].MappedList(_height, _round, _validatorSet);\n            }\n\n            throw new NullReferenceException();\n        }\n\n        /// <summary>\n        /// Gets the <see cref=\"Vote\"/> signed by given <paramref name=\"publicKey\"/>.\n        /// If given validator has conflicting votes, returns \"canonical\" <see cref=\"Vote\"/>.\n        /// </summary>\n        /// <param name=\"publicKey\">\n        /// A <see cref=\"PublicKey\"/> of the validator signed <see cref=\"Vote\"/>.</param>\n        /// <returns>A <see cref=\"Vote\"/> signed by given <paramref name=\"publicKey\"/>.</returns>\n        /// <exception cref=\"KeyNotFoundException\">Thrown when there's no <see cref=\"Vote\"/>\n        /// signed by given <paramref name=\"publicKey\"/>.</exception>\n        public Vote GetByPublicKey(PublicKey publicKey)\n        {\n            lock (_lock)\n            {\n                if (_votes.ContainsKey(publicKey))\n                {\n                    return _votes[publicKey];\n                }\n\n                throw new KeyNotFoundException(nameof(publicKey));\n            }\n        }\n\n        /// <summary>If there is a +2/3 majority for certain <see cref=\"BlockHash\"/>,\n        /// return <see langword=\"true\"/>. Else, return <see langword=\"false\"/>.</summary>\n        /// <returns><see langword=\"true\"/> if +2/3 majority exists,\n        /// else <see langword=\"false\"/>.</returns>\n        public bool HasTwoThirdsMajority()\n        {\n            lock (_lock)\n            {\n                return !(_maj23 is null);\n            }\n        }\n\n        /// <summary>\n        /// A predicate indicates whether the <see cref=\"VoteSet\"/> collected +2/3 majority commits.\n        /// </summary>\n        /// <returns><see langword=\"true\"/> if the <see cref=\"VoteSet\"/> collected +2/3 majority\n        /// commits, else <see langword=\"false\"/>.</returns>\n        public bool IsCommit()\n        {\n            if (_voteType != VoteFlag.PreCommit)\n            {\n                return false;\n            }\n\n            return HasTwoThirdsMajority();\n        }\n\n        /// <summary>If there is a +1/3 majority for any <see cref=\"BlockHash\"/>,\n        /// return <see langword=\"true\"/>. Else, return <see langword=\"false\"/>.</summary>\n        /// <returns><see langword=\"true\"/> if +1/3 majority exists,\n        /// else <see langword=\"false\"/>.</returns>\n        public bool HasOneThirdsAny()\n        {\n            lock (_lock)\n            {\n                return Sum > _validatorSet.OneThirdPower;\n            }\n        }\n\n        /// <summary>If there is a +2/3 majority for any <see cref=\"BlockHash\"/>,\n        /// return <see langword=\"true\"/>. Else, return <see langword=\"false\"/>.</summary>\n        /// <returns><see langword=\"true\"/> if +2/3 majority exists,\n        /// else <see langword=\"false\"/>.</returns>\n        public bool HasTwoThirdsAny()\n        {\n            lock (_lock)\n            {\n                return Sum > _validatorSet.TwoThirdsPower;\n            }\n        }\n\n        /// <summary>\n        /// Predicate which returns <see langword=\"true\"/> when collected all <see cref=\"Vote\"/>s.\n        /// Else, return <see langword=\"false\"/>.\n        /// </summary>\n        /// <returns><see langword=\"true\"/> when collected all <see cref=\"Vote\"/>s.\n        /// Else, <see langword=\"false\"/>.</returns>\n        public bool HasAll()\n        {\n            lock (_lock)\n            {\n                return Sum == _validatorSet.TotalPower;\n            }\n        }\n\n        /// <summary>If there is a +2/3 majority for certain <see cref=\"BlockHash\"/>,\n        /// return <see cref=\"BlockHash\"/> and <see langword=\"true\"/>.\n        /// Else, return the <see langword=\"default\"/> <see cref=\"BlockHash\"/> and\n        /// <see langword=\"false\"/>.</summary>\n        /// <param name=\"blockHash\"><see cref=\"BlockHash\"/> of the +2/3 majority vote.\n        /// If not exists, it will have <see langword=\"default\"/>.</param>\n        /// <returns><see langword=\"true\"/> if +2/3 majority exists,\n        /// else <see langword=\"false\"/>.</returns>\n        public bool TwoThirdsMajority(out BlockHash blockHash)\n        {\n            lock (_lock)\n            {\n                if (_maj23 is { } maj23)\n                {\n                    blockHash = maj23;\n                    return true;\n                }\n\n                blockHash = default;\n                return false;\n            }\n        }\n\n        /// <summary>\n        /// Create a <see cref=\"BlockCommit\"/> instance if <see cref=\"VoteSet\"/> has +2/3 majority\n        /// commits.\n        /// </summary>\n        /// <returns>A <see cref=\"BlockCommit\"/> instance made by collected commits. If failed\n        /// to collect +2/3 majority commits, return <see langword=\"null\"/>.</returns>\n        public BlockCommit? ToBlockCommit()\n        {\n            if (!IsCommit())\n            {\n                _logger.Information(\"Failed to create block commit since no +2/3 votes collected\");\n                return null;\n            }\n\n            return new BlockCommit(\n                _height, _round, _maj23!.Value, MappedList().ToImmutableArray());\n        }\n\n        internal void AddVote(Vote vote)\n        {\n            if (vote.Round != _round ||\n                vote.Flag != _voteType)\n            {\n                throw new InvalidVoteException(\n                    \"Round, flag of the vote mismatches\",\n                    vote);\n            }\n\n            PublicKey validatorKey = vote.ValidatorPublicKey;\n            BlockHash blockHash = vote.BlockHash;\n\n            Vote? conflicting = null;\n            _logger.Debug(\"Adding verified vote {Vote}\", vote);\n\n            // Already exists in voteSet.votes?\n            if (_votes.ContainsKey(validatorKey))\n            {\n                var existing = _votes[validatorKey];\n                if (existing.BlockHash.Equals(vote.BlockHash))\n                {\n                    throw new InvalidVoteException(\n                        $\"{nameof(AddVote)}() does not expect duplicate votes\",\n                        vote);\n                }\n                else\n                {\n                    conflicting = existing;\n                }\n\n                // Replace vote if blockKey matches voteSet.maj23.\n                if (_maj23 is { } maj23NotNull && maj23NotNull.Equals(blockHash))\n                {\n                    _votes[validatorKey] = vote;\n                }\n\n                // Otherwise don't add it to voteSet.votes\n            }\n            else\n            {\n                // Add to voteSet.votes and incr .sum\n                _votes[validatorKey] = vote;\n            }\n\n            if (_votesByBlock.ContainsKey(blockHash))\n            {\n                if (!(conflicting is null) && !_votesByBlock[blockHash].PeerMaj23)\n                {\n                    // There's a conflict and no peer claims that this block is special.\n                    throw new InvalidVoteException(\n                        \"There's a conflict and no peer claims that this block is special\",\n                        vote);\n                }\n\n                // We'll add the vote in a bit.\n            }\n            else\n            {\n                // .votesByBlock doesn't exist...\n                if (!(conflicting is null))\n                {\n                    // ... and there's a conflicting vote.\n                    // We're not even tracking this blockKey, so just forget it.\n                    throw new DuplicateVoteException(\n                        message: \"There's a conflicting vote\",\n                        voteRef: conflicting,\n                        voteDup: vote);\n                }\n\n                // ... and there's no conflicting vote.\n                // Start tracking this blockKey\n                _votesByBlock[blockHash] = new BlockVotes(blockHash);\n\n                // We'll add the vote in a bit.\n            }\n\n            BlockVotes votesByBlock = _votesByBlock[blockHash];\n\n            // Before adding to votesByBlock, see if we'll exceed quorum\n            BigInteger origSum = votesByBlock.Sum;\n            BigInteger quorum = _validatorSet.TwoThirdsPower + 1;\n\n            // Add vote to votesByBlock\n            votesByBlock.AddVerifiedVote(vote, _validatorSet.GetValidator(validatorKey).Power);\n\n            // If we just crossed the quorum threshold and have 2/3 majority...\n            if (origSum < quorum && quorum <= votesByBlock.Sum && _maj23 is null)\n            {\n                _maj23 = vote.BlockHash;\n\n                // And also copy votes over to voteSet.votes\n                foreach (var pair in votesByBlock.Votes)\n                {\n                    _votes[pair.Key] = pair.Value;\n                }\n            }\n        }\n\n        internal class BlockVotes\n        {\n            public BlockVotes(BlockHash blockHash)\n            {\n                BlockHash = blockHash;\n                PeerMaj23 = false;\n                Votes = new Dictionary<PublicKey, Vote>();\n                Sum = BigInteger.Zero;\n            }\n\n            public BlockHash BlockHash { get; }\n\n            public bool PeerMaj23 { get; set; }\n\n            public Dictionary<PublicKey, Vote> Votes { get; set; }\n\n            public BigInteger Sum { get; set; }\n\n            public void AddVerifiedVote(Vote vote, BigInteger power)\n            {\n                if (Votes.ContainsKey(vote.ValidatorPublicKey))\n                {\n                    return;\n                }\n\n                Votes[vote.ValidatorPublicKey] = vote;\n                Sum += power;\n            }\n\n            public List<Vote> MappedList(long height, int round, ValidatorSet validatorSet) =>\n                validatorSet.PublicKeys.Select(\n                    key => Votes.ContainsKey(key)\n                        ? Votes[key]\n                        : new VoteMetadata(\n                            height,\n                            round,\n                            BlockHash,\n                            DateTimeOffset.UtcNow,\n                            key,\n                            validatorSet.GetValidator(key).Power,\n                            VoteFlag.Null).Sign(null))\n                    .ToList();\n        }\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Net/DifferentAppProtocolVersionEncountered.cs",
    "content": "namespace Libplanet.Net\n{\n    /// <summary>\n    /// A delegate to call back when a <see cref=\"Swarm\"/> encounters\n    /// a peer with a different <see cref=\"AppProtocolVersion\"/> signed by\n    /// a trusted signer in the network.\n    /// </summary>\n    /// <param name=\"peer\">The encountered <see cref=\"BoundPeer\"/> with\n    /// a different <see cref=\"AppProtocolVersion\"/>.\n    /// </param>\n    /// <param name=\"peerVersion\">The encountered different <see cref=\"AppProtocolVersion\"/>.\n    /// </param>\n    /// <param name=\"localVersion\">The currently running application's\n    /// <see cref=\"AppProtocolVersion\"/>.</param>\n    public delegate void DifferentAppProtocolVersionEncountered(\n        BoundPeer peer,\n        AppProtocolVersion peerVersion,\n        AppProtocolVersion localVersion\n    );\n}\n"
  },
  {
    "path": "src/Libplanet.Net/EvidenceCompletion.cs",
    "content": "using System;\nusing System.Collections.Concurrent;\nusing System.Collections.Generic;\nusing System.Diagnostics;\nusing System.Linq;\nusing System.Threading;\nusing System.Threading.Channels;\nusing System.Threading.Tasks;\nusing Libplanet.Blockchain;\nusing Libplanet.Types.Evidence;\nusing Nito.AsyncEx;\nusing Serilog;\n\nnamespace Libplanet.Net\n{\n    public class EvidenceCompletion<TPeer> : IDisposable\n        where TPeer : notnull\n    {\n        private readonly CancellationTokenSource _cancellationTokenSource;\n        private readonly BlockChain _blockChain;\n        private readonly EvidenceFetcher _evidenceFetcher;\n        private readonly EvidenceBroadcaster _evidenceBroadcaster;\n        private readonly ILogger _logger;\n        private readonly ConcurrentDictionary<TPeer, EvidenceFetchJob> _evidenceFetchJobs;\n\n        private bool _disposed;\n\n        public EvidenceCompletion(\n            BlockChain blockChain,\n            EvidenceFetcher evidenceFetcher,\n            EvidenceBroadcaster evidenceBroadcaster)\n        {\n            _cancellationTokenSource = new CancellationTokenSource();\n            _blockChain = blockChain;\n            _evidenceFetcher = evidenceFetcher;\n            _evidenceBroadcaster = evidenceBroadcaster;\n            _evidenceFetchJobs = new ConcurrentDictionary<TPeer, EvidenceFetchJob>();\n            EvidenceReceived = new AsyncAutoResetEvent();\n\n            _logger = Log\n                .ForContext<EvidenceCompletion<TPeer>>()\n                .ForContext(\"Source\", nameof(EvidenceCompletion<TPeer>));\n        }\n\n        public delegate IAsyncEnumerable<EvidenceBase> EvidenceFetcher(\n            TPeer peer,\n            IEnumerable<EvidenceId> evidenceIds,\n            CancellationToken cancellationToken\n        );\n\n        public delegate void EvidenceBroadcaster(TPeer except, IEnumerable<EvidenceBase> evidence);\n\n        internal AsyncAutoResetEvent EvidenceReceived { get; }\n\n        public void Dispose()\n        {\n            if (!_disposed)\n            {\n                _cancellationTokenSource.Cancel();\n                _disposed = true;\n            }\n        }\n\n        public void Demand(TPeer peer, EvidenceId evidenceId) => Demand(peer, new[] { evidenceId });\n\n        public void Demand(TPeer peer, IEnumerable<EvidenceId> evidenceIds)\n        {\n            if (_disposed)\n            {\n                throw new ObjectDisposedException(nameof(EvidenceCompletion<TPeer>));\n            }\n\n            HashSet<EvidenceId> required = GetRequiredEvidenceIds(evidenceIds);\n\n            _logger.Information(\n                \"There are {RequiredCount} unaware transactions to receive out of {Count} \",\n                required.Count,\n                evidenceIds.Count());\n\n            if (!required.Any())\n            {\n                return;\n            }\n\n            do\n            {\n                EvidenceFetchJob evidenceFetchJob = _evidenceFetchJobs.GetOrAdd(\n                    peer,\n                    peerAsKey => EvidenceFetchJob.RunAfter(\n                        peerAsKey,\n                        _evidenceFetcher,\n                        TimeSpan.FromSeconds(1),\n                        (task) =>\n                        {\n                            if (task.IsCompleted &&\n                                !task.IsFaulted &&\n                                !task.IsCanceled &&\n                                task.Result is ISet<EvidenceBase> evidence)\n                            {\n                                ProcessFetchedEvidenceIds(evidence, peerAsKey);\n                            }\n\n                            _evidenceFetchJobs.TryRemove(peer, out _);\n                        },\n                        _cancellationTokenSource.Token\n                    )\n                );\n\n                if (evidenceFetchJob.TryAdd(required, out HashSet<EvidenceId> rest))\n                {\n                    break;\n                }\n\n                required = rest;\n                _evidenceFetchJobs.TryRemove(peer, out _);\n            }\n            while (true);\n        }\n\n        private void ProcessFetchedEvidenceIds(ISet<EvidenceBase> evidence, TPeer peer)\n        {\n            try\n            {\n                var policyCompatEvidence = new HashSet<EvidenceBase>(\n                    evidence.Where(\n                        evidence =>\n                        {\n                            return true;\n                        }));\n\n                var pendingEvidence = new List<EvidenceBase>();\n                foreach (var ev in policyCompatEvidence)\n                {\n                    try\n                    {\n                        _blockChain.AddEvidence(ev);\n                        pendingEvidence.Add(ev);\n                    }\n                    catch (Exception e)\n                    {\n                        const string message =\n                            \"Received transaction from {Peer} with id {EvidenceId} \" +\n                            \"will not be added since it is invalid\";\n                        _logger.Error(e, message, peer, ev.Id);\n                    }\n                }\n\n                // To maintain the consistency of the unit tests.\n                if (policyCompatEvidence.Any())\n                {\n                    EvidenceReceived.Set();\n                }\n\n                if (pendingEvidence.Any())\n                {\n                    _logger.Information(\n                        \"Staged {StagedEvidenceCount} out of {EvidenceCount} evidence from {Peer}\",\n                        pendingEvidence.Count,\n                        evidence.Count,\n                        peer);\n\n                    _evidenceBroadcaster(peer, pendingEvidence);\n                }\n                else\n                {\n                    _logger.Information(\n                        \"No transaction has been staged among received {EvidenceCount} from {Peer}\",\n                        evidence.Count,\n                        peer\n                    );\n                }\n            }\n            catch (Exception e)\n            {\n                _logger.Error(\n                    e,\n                    \"An error occurred during {MethodName}() from {Peer}\",\n                    nameof(ProcessFetchedEvidenceIds),\n                    peer);\n                throw;\n            }\n            finally\n            {\n                _logger.Debug(\n                    \"End of {MethodName}() from {Peer}\",\n                    nameof(ProcessFetchedEvidenceIds),\n                    peer);\n            }\n        }\n\n        private HashSet<EvidenceId> GetRequiredEvidenceIds(IEnumerable<EvidenceId> ids)\n        {\n            return new HashSet<EvidenceId>(ids);\n        }\n\n        private class EvidenceFetchJob\n        {\n            private readonly EvidenceFetcher _evidenceFetcher;\n            private readonly Channel<EvidenceId> _evidenceIds;\n            private readonly TPeer _peer;\n            private readonly ILogger _logger;\n            private readonly ReaderWriterLockSlim _evidenceIdsWriterLock;\n\n            private EvidenceFetchJob(EvidenceFetcher evidenceFetcher, TPeer peer)\n            {\n                _evidenceFetcher = evidenceFetcher;\n                _peer = peer;\n                _evidenceIds = Channel.CreateUnbounded<EvidenceId>(\n                    new UnboundedChannelOptions\n                    {\n                        SingleReader = true,\n                    }\n                );\n                _evidenceIdsWriterLock = new ReaderWriterLockSlim();\n\n                _logger = Log\n                    .ForContext<EvidenceFetchJob>()\n                    .ForContext(\"Source\", nameof(EvidenceFetchJob));\n            }\n\n            public static EvidenceFetchJob RunAfter(\n                TPeer peer,\n                EvidenceFetcher evidenceFetcher,\n                TimeSpan waitFor,\n                Action<Task<ISet<EvidenceBase>>> continuation,\n                CancellationToken cancellationToken)\n            {\n                var task = new EvidenceFetchJob(evidenceFetcher, peer);\n                _ = task.RequestAsync(waitFor, cancellationToken).ContinueWith(continuation);\n                return task;\n            }\n\n            public bool TryAdd(IEnumerable<EvidenceId> evidenceIds, out HashSet<EvidenceId> rest)\n            {\n                rest = new HashSet<EvidenceId>(evidenceIds);\n                _evidenceIdsWriterLock.EnterReadLock();\n                try\n                {\n                    foreach (EvidenceId evidenceId in evidenceIds)\n                    {\n                        _evidenceIds.Writer.WriteAsync(evidenceId);\n                        rest.Remove(evidenceId);\n                    }\n\n                    return true;\n                }\n                catch (ChannelClosedException)\n                {\n                    return false;\n                }\n                finally\n                {\n                    _evidenceIdsWriterLock.ExitReadLock();\n                }\n            }\n\n            private async Task<ISet<EvidenceBase>> RequestAsync(\n                TimeSpan waitFor,\n                CancellationToken cancellationToken\n            )\n            {\n                _ = Task.Run(async () =>\n                {\n                    await Task.Delay(waitFor);\n                    _evidenceIdsWriterLock.EnterWriteLock();\n                    try\n                    {\n                        _evidenceIds.Writer.TryComplete();\n                    }\n                    finally\n                    {\n                        _evidenceIdsWriterLock.ExitWriteLock();\n                    }\n                });\n\n                try\n                {\n                    var evidenceIds = new HashSet<EvidenceId>();\n\n                    while (await _evidenceIds.Reader.WaitToReadAsync(cancellationToken))\n                    {\n                        while (_evidenceIds.Reader.TryRead(out EvidenceId evidenceId))\n                        {\n                            evidenceIds.Add(evidenceId);\n                        }\n                    }\n\n                    _logger.Debug(\n                        \"Start to run _evidenceFetcher from {Peer}. (count: {Count})\",\n                        _peer,\n                        evidenceIds.Count);\n                    var stopWatch = new Stopwatch();\n                    stopWatch.Start();\n                    var evidence = new HashSet<EvidenceBase>(\n                        await _evidenceFetcher(\n                                _peer,\n                                evidenceIds,\n                                cancellationToken)\n                            .ToListAsync(cancellationToken)\n                            .AsTask());\n                    _logger.Debug(\n                        \"End of _evidenceFetcher from {Peer}. (received: {Count}); \" +\n                        \"Time taken: {Elapsed}\",\n                        _peer,\n                        evidence.Count,\n                        stopWatch.Elapsed);\n\n                    return evidence;\n                }\n                catch (Exception e)\n                {\n                    _logger.Error(\n                        e,\n                        \"An error occurred during {MethodName}() from {Peer}\",\n                        nameof(RequestAsync),\n                        _peer);\n                    throw;\n                }\n                finally\n                {\n                    _logger.Debug(\n                        \"End of {MethodName}() from {Peer}\",\n                        nameof(RequestAsync),\n                        _peer);\n                }\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Net/IceServer.cs",
    "content": "using System;\nusing System.Linq;\nusing Libplanet.Stun;\n\nnamespace Libplanet.Net\n{\n    public class IceServer : IIceServer\n    {\n        public IceServer(string url)\n            : this(new Uri(url))\n        {\n        }\n\n        /// <summary>\n        /// Creates an instance by parsing given <paramref name=\"url\"/>.\n        /// </summary>\n        /// <param name=\"url\">The <see cref=\"Uri\"/> to parse.</param>\n        /// <exception cref=\"ArgumentException\">Thrown when <see cref=\"Uri.Scheme\"/> is\n        /// not <c>\"turn\"</c> for <paramref name=\"url\"/>.</exception>\n        public IceServer(Uri url)\n        {\n            if (url.Scheme != \"turn\")\n            {\n                throw new ArgumentException($\"{url} is not a valid TURN url.\");\n            }\n\n#pragma warning disable S1121, S3358, SA1316\n            Url = url;\n            Func<string, string, bool, char, (string, string, bool)> parser =\n                (username, credential, colonFound, c) =>\n                    c == ':'\n                        ? colonFound\n                            ? (username, credential, !colonFound)\n                            : throw new ArgumentException(\n                                $\"Uri.UserInfo '{url.UserInfo}' have to contain single colon \" +\n                                \"as a delimiter between username and credential.\")\n                        : colonFound\n                            ? (username += c, credential, colonFound)\n                            : (username, credential += c, colonFound);\n            (string username, string credential, bool colonFound) seed =\n                (string.Empty, string.Empty, true);\n            (Username, Credential, _) = url.UserInfo\n                .Aggregate(seed, (prev, c) => parser(\n                    prev.username, prev.credential, prev.colonFound, c));\n#pragma warning restore S1121, S3358, SA1316\n        }\n\n        public Uri Url { get; }\n\n        public string Username { get; }\n\n        public string Credential { get; }\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Net/InvalidMessageContentException.cs",
    "content": "using System;\nusing Libplanet.Net.Messages;\n\nnamespace Libplanet.Net\n{\n    public class InvalidMessageContentException : Exception\n    {\n        internal InvalidMessageContentException(\n            string message,\n            MessageContent content,\n            Exception innerException\n        )\n            : base(message, innerException)\n        {\n            Content = content;\n        }\n\n        internal InvalidMessageContentException(string message, MessageContent content)\n            : base(message)\n        {\n            Content = content;\n        }\n\n        internal MessageContent Content { get; }\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Net/InvalidStateTargetException.cs",
    "content": "using System;\n\nnamespace Libplanet.Net\n{\n    public class InvalidStateTargetException : SwarmException\n    {\n        public InvalidStateTargetException()\n        {\n        }\n\n        public InvalidStateTargetException(string message)\n            : base(message)\n        {\n        }\n\n        public InvalidStateTargetException(string message, Exception innerException)\n            : base(message, innerException)\n        {\n        }\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Net/Libplanet.Net.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <PropertyGroup>\n    <Title>P2P implementation for Libplanet</Title>\n    <Description>A peer-to-peer networking layer based on Libplanet.</Description>\n  </PropertyGroup>\n\n  <PropertyGroup>\n    <ProduceReferenceAssembly>true</ProduceReferenceAssembly>\n    <GenerateDocumentationFile>true</GenerateDocumentationFile>\n    <TreatWarningsAsErrors>true</TreatWarningsAsErrors>\n    <NoWarn>$(NoWarn);S4035;CS0660;CS0661;S3875;CS1591;NU5104;MEN001</NoWarn>\n    <!-- FIXME: S4035 and CS1591 should be turned on eventually. -->\n  </PropertyGroup>\n\n  <ItemGroup>\n    <PackageReference Include=\"AsyncEnumerator\" Version=\"4.0.2\" />\n    <PackageReference Include=\"Destructurama.Attributed\" Version=\"2.0.0\" />\n    <PackageReference Include=\"Microsoft.Extensions.Caching.Memory\" Version=\"5.0.0\" />\n    <PackageReference Include=\"Planetarium.NetMQ\" Version=\"4.0.0.261-planetarium\" />\n    <PackageReference Include=\"System.Diagnostics.DiagnosticSource\" Version=\"8.0.0\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <ProjectReference Include=\"..\\Libplanet\\Libplanet.csproj\" />\n    <ProjectReference Include=\"..\\Libplanet.Stun\\Libplanet.Stun.csproj\" />\n  </ItemGroup>\n</Project>\n"
  },
  {
    "path": "src/Libplanet.Net/Messages/BlockHashesMsg.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing Destructurama.Attributed;\nusing Libplanet.Types.Blocks;\n\nnamespace Libplanet.Net.Messages\n{\n    internal class BlockHashesMsg : MessageContent\n    {\n        public BlockHashesMsg(IEnumerable<BlockHash> hashes)\n        {\n            Hashes = hashes.ToList();\n        }\n\n        public BlockHashesMsg(byte[][] dataFrames)\n        {\n            int hashCount = BitConverter.ToInt32(dataFrames[0], 0);\n            var hashes = new List<BlockHash>(hashCount);\n            if (hashCount > 0)\n            {\n                for (int i = 1, end = hashCount + 1; i < end; i++)\n                {\n                    hashes.Add(new BlockHash(dataFrames[i]));\n                }\n            }\n\n            Hashes = hashes;\n        }\n\n        /// <summary>\n        /// The continuous block hashes, from the lowest index to the highest index.\n        /// </summary>\n        [LogAsScalar]\n        public IEnumerable<BlockHash> Hashes { get; }\n\n        public override MessageType Type => MessageType.BlockHashes;\n\n        public override IEnumerable<byte[]> DataFrames\n        {\n            get\n            {\n                var frames = new List<byte[]>();\n                frames.Add(BitConverter.GetBytes(Hashes.Count()));\n                frames.AddRange(Hashes.Select(hash => hash.ToByteArray()));\n                return frames;\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Net/Messages/BlockHeaderMsg.cs",
    "content": "using System.Collections.Generic;\nusing Bencodex;\nusing Libplanet.Types.Blocks;\n\nnamespace Libplanet.Net.Messages\n{\n    internal class BlockHeaderMsg : MessageContent\n    {\n        private static readonly Codec Codec = new Codec();\n\n        public BlockHeaderMsg(BlockHash genesisHash, BlockHeader header)\n        {\n            GenesisHash = genesisHash;\n            HeaderDictionary = header.MarshalBlockHeader();\n        }\n\n        public BlockHeaderMsg(byte[][] dataFrames)\n        {\n            GenesisHash = new BlockHash(dataFrames[0]);\n            HeaderDictionary = (Bencodex.Types.Dictionary)Codec.Decode(dataFrames[1]);\n        }\n\n        public BlockHash GenesisHash { get; }\n\n        public Bencodex.Types.Dictionary HeaderDictionary { get; }\n\n        public long HeaderIndex => BlockMarshaler.UnmarshalBlockMetadataIndex(HeaderDictionary);\n\n        public BlockHash HeaderHash => BlockMarshaler.UnmarshalBlockHeaderHash(HeaderDictionary);\n\n        public override MessageType Type => MessageType.BlockHeaderMessage;\n\n        public override IEnumerable<byte[]> DataFrames => new[]\n        {\n            GenesisHash.ToByteArray(),\n            Codec.Encode(HeaderDictionary),\n        };\n\n        public BlockHeader GetHeader()\n        {\n            return BlockMarshaler.UnmarshalBlockHeader(HeaderDictionary);\n        }\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Net/Messages/BlocksMsg.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing Libplanet.Types.Blocks;\n\nnamespace Libplanet.Net.Messages\n{\n    internal class BlocksMsg : MessageContent\n    {\n        /// <summary>\n        /// Creates an instance of <see cref=\"BlocksMsg\"/> with given <paramref name=\"payloads\"/>.\n        /// </summary>\n        /// <param name=\"payloads\">The payload for this <see cref=\"Message\"/>.  The length\n        /// should be twice the length of <see cref=\"Block\"/>s to send where even indices are\n        /// encoded <see cref=\"Block\"/>s and odd indices are encoded <see cref=\"BlockCommit\"/>s.\n        /// </param>\n        /// <exception cref=\"ArgumentException\">Thrown when the length of\n        /// <paramref name=\"payloads\"/> is not even.</exception>\n        public BlocksMsg(IEnumerable<byte[]> payloads)\n        {\n            var count = payloads.Count();\n            if (count % 2 != 0)\n            {\n                throw new ArgumentException(\n                    $\"Given {nameof(payloads)} must be of even length: {count}\");\n            }\n\n            Payloads = payloads.ToList();\n        }\n\n        public BlocksMsg(byte[][] dataFrames)\n        {\n            var count = BitConverter.ToInt32(dataFrames.First(), 0);\n            if (count % 2 != 0)\n            {\n                throw new ArgumentException(\n                    $\"Given {nameof(dataFrames)} must be of even length: {count}\");\n            }\n\n            Payloads = dataFrames.Skip(1).Take(count).ToList();\n        }\n\n        /// <summary>\n        /// A <see cref=\"List{T}\"/> of <see langword=\"byte\"/> arrays representing the payload\n        /// of this <see cref=\"Message\"/>.  Even indices are encoded <see cref=\"Block\"/>s\n        /// and odd indices are encoded <see cref=\"BlockCommit\"/>s.\n        /// </summary>\n        /// <remarks>\n        /// This is guaranteed to be of even length.\n        /// </remarks>\n        public List<byte[]> Payloads { get; }\n\n        public override MessageType Type => MessageType.Blocks;\n\n        public override IEnumerable<byte[]> DataFrames\n        {\n            get\n            {\n                var frames = new List<byte[]>();\n                frames.Add(BitConverter.GetBytes(Payloads.Count));\n                frames.AddRange(Payloads);\n                return frames;\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Net/Messages/ChainStatusMsg.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing Destructurama.Attributed;\nusing Libplanet.Types.Blocks;\n\nnamespace Libplanet.Net.Messages\n{\n    internal class ChainStatusMsg : MessageContent, IBlockExcerpt\n    {\n        public ChainStatusMsg(\n            int protocolVersion,\n            BlockHash genesisHash,\n            long tipIndex,\n            BlockHash tipHash)\n        {\n            ProtocolVersion = protocolVersion;\n            GenesisHash = genesisHash;\n            TipIndex = tipIndex;\n            TipHash = tipHash;\n        }\n\n        public ChainStatusMsg(byte[][] dataFrames)\n        {\n            ProtocolVersion = BitConverter.ToInt32(dataFrames[0], 0);\n            GenesisHash = new BlockHash(dataFrames[1]);\n            TipIndex = BitConverter.ToInt64(dataFrames[2], 0);\n            TipHash = new BlockHash(dataFrames[3]);\n        }\n\n        public int ProtocolVersion { get; }\n\n        [LogAsScalar]\n        public BlockHash GenesisHash { get; }\n\n        public long TipIndex { get; }\n\n        [LogAsScalar]\n        public BlockHash TipHash { get; }\n\n        long IBlockExcerpt.Index => TipIndex;\n\n        [LogAsScalar]\n        BlockHash IBlockExcerpt.Hash => TipHash;\n\n        public override MessageType Type => MessageType.ChainStatus;\n\n        public override IEnumerable<byte[]> DataFrames => new[]\n        {\n            BitConverter.GetBytes(ProtocolVersion),\n            GenesisHash.ToByteArray(),\n            BitConverter.GetBytes(TipIndex),\n            TipHash.ToByteArray(),\n        };\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Net/Messages/ConsensusMaj23Msg.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing Libplanet.Consensus;\n\nnamespace Libplanet.Net.Messages\n{\n    /// <summary>\n    /// A message class for claiming that the peer has +2/3 votes.\n    /// </summary>\n    public class ConsensusMaj23Msg : ConsensusMsg\n    {\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"ConsensusMaj23Msg\"/> class.\n        /// </summary>\n        /// <param name=\"maj23\">A <see cref=\"Maj23\"/> of given height and round.</param>\n        public ConsensusMaj23Msg(Maj23 maj23)\n            : base(maj23.ValidatorPublicKey, maj23.Height, maj23.Round)\n        {\n            Maj23 = maj23;\n        }\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"ConsensusMaj23Msg\"/> class\n        /// with marshalled message.\n        /// </summary>\n        /// <param name=\"dataframes\">A marshalled message.</param>\n        public ConsensusMaj23Msg(byte[][] dataframes)\n            : this(maj23: new Maj23(dataframes[0]))\n        {\n        }\n\n        /// <summary>\n        /// A <see cref=\"Maj23\"/> of the message.\n        /// </summary>\n        public Maj23 Maj23 { get; }\n\n        /// <inheritdoc cref=\"MessageContent.DataFrames\"/>\n        public override IEnumerable<byte[]> DataFrames =>\n            new List<byte[]> { Maj23.ToByteArray() };\n\n        /// <inheritdoc cref=\"MessageContent.MessageType\"/>\n        public override MessageType Type => MessageType.ConsensusMaj23Msg;\n\n        /// <inheritdoc cref=\"ConsensusMsg.Equals(ConsensusMsg?)\"/>\n        public override bool Equals(ConsensusMsg? other)\n        {\n            return other is ConsensusMaj23Msg message &&\n                   message.Maj23.Equals(Maj23);\n        }\n\n        /// <inheritdoc cref=\"ConsensusMsg.Equals(object?)\"/>\n        public override bool Equals(object? obj)\n        {\n            return obj is ConsensusMaj23Msg other && Equals(other);\n        }\n\n        /// <inheritdoc cref=\"ConsensusMsg.GetHashCode\"/>\n        public override int GetHashCode()\n        {\n            return HashCode.Combine(Type, Maj23);\n        }\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Net/Messages/ConsensusMsg.cs",
    "content": "using System;\nusing Libplanet.Crypto;\nusing Libplanet.Net.Consensus;\n\nnamespace Libplanet.Net.Messages\n{\n    /// <summary>\n    /// A abstract base class message for consensus.\n    /// </summary>\n    public abstract class ConsensusMsg : MessageContent, IEquatable<ConsensusMsg>\n    {\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"ConsensusMsg\"/> class.\n        /// </summary>\n        /// <param name=\"validatorPublicKey\">\n        /// A <see cref=\"PublicKey\"/> of the validator who made this message.</param>\n        /// <param name=\"height\">A <see cref=\"Context.Height\"/> the message is for.</param>\n        /// <param name=\"round\">A <see cref=\"Context.Round\"/> the message is written for.</param>\n        protected ConsensusMsg(\n            PublicKey validatorPublicKey,\n            long height,\n            int round)\n        {\n            ValidatorPublicKey = validatorPublicKey;\n            Round = round;\n            Height = height;\n        }\n\n        /// <summary>\n        /// A <see cref=\"PublicKey\"/> of the validator who made this message.\n        /// </summary>\n        public PublicKey ValidatorPublicKey { get; }\n\n        /// <summary>\n        /// A <see cref=\"Context.Height\"/> the message is written for.\n        /// </summary>\n        public long Height { get; }\n\n        /// <summary>\n        /// A <see cref=\"Context.Round\"/> the message is written for.\n        /// </summary>\n        public int Round { get; }\n\n        /// <summary>\n        /// Indicates whether the current <see cref=\"ConsensusMsg\"/>\n        /// is equal to another <see cref=\"ConsensusMsg\"/>.\n        /// </summary>\n        /// <param name=\"other\">An <see cref=\"ConsensusMsg\"/> to compare with this\n        /// <see cref=\"ConsensusMsg\"/>.</param>\n        /// <returns>\n        /// true if the current <see cref=\"ConsensusMsg\"/> is equal to the other parameter;\n        /// otherwise, false.\n        /// </returns>\n        public abstract bool Equals(ConsensusMsg? other);\n\n        /// <inheritdoc cref=\"IEquatable{T}.Equals(T)\"/>\n        public abstract override bool Equals(object? obj);\n\n        /// <inheritdoc cref=\"object.GetHashCode\"/>\n        public abstract override int GetHashCode();\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Net/Messages/ConsensusPreCommitMsg.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing Libplanet.Net.Consensus;\nusing Libplanet.Types.Consensus;\n\nnamespace Libplanet.Net.Messages\n{\n    /// <summary>\n    /// A message class for <see cref=\"ConsensusStep.PreCommit\"/>.\n    /// </summary>\n    public class ConsensusPreCommitMsg : ConsensusVoteMsg\n    {\n        private static Bencodex.Codec _codec = new Bencodex.Codec();\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"ConsensusPreCommitMsg\"/> class.\n        /// </summary>\n        /// <param name=\"vote\">The <see cref=\"Vote\"/> for <see cref=\"ConsensusStep.PreCommit\"/>\n        /// to attach.\n        /// </param>\n        /// <exception cref=\"ArgumentException\">Thrown when given <paramref name=\"vote\"/>'s\n        /// <see cref=\"Vote.Flag\"/> is not <see cref=\"VoteFlag.PreCommit\"/>.</exception>\n        public ConsensusPreCommitMsg(Vote vote)\n            : base(vote.ValidatorPublicKey, vote.Height, vote.Round, vote.BlockHash, vote.Flag)\n        {\n            if (vote.Flag != VoteFlag.PreCommit)\n            {\n                throw new ArgumentException(\n                    $\"Given {nameof(vote)}'s flag must be {VoteFlag.PreCommit}.\", nameof(vote));\n            }\n\n            PreCommit = vote;\n        }\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"ConsensusPreCommitMsg\"/> class\n        /// with marshalled message.\n        /// </summary>\n        /// <param name=\"dataframes\">A marshalled message.</param>\n        public ConsensusPreCommitMsg(byte[][] dataframes)\n            : this(new Vote(_codec.Decode(dataframes[0])))\n        {\n        }\n\n        /// <summary>\n        /// A <see cref=\"Vote\"/> for <see cref=\"ConsensusStep.PreCommit\"/>.  This will always\n        /// have its <see cref=\"Vote.Flag\"/> set to <see cref=\"VoteFlag.PreCommit\"/>.\n        /// </summary>\n        public Vote PreCommit { get; }\n\n        /// <inheritdoc cref=\"MessageContent.DataFrames\"/>\n        public override IEnumerable<byte[]> DataFrames =>\n            new List<byte[]> { _codec.Encode(PreCommit.Bencoded) };\n\n        /// <inheritdoc cref=\"MessageContent.MessageType\"/>\n        public override MessageType Type => MessageType.ConsensusCommit;\n\n        /// <inheritdoc/>\n        public override bool Equals(ConsensusMsg? other)\n        {\n            return other is ConsensusPreCommitMsg message &&\n                PreCommit.Equals(message.PreCommit);\n        }\n\n        /// <inheritdoc/>\n        public override bool Equals(object? obj)\n        {\n            return obj is ConsensusMsg other && Equals(other);\n        }\n\n        /// <inheritdoc/>\n        public override int GetHashCode()\n        {\n            return HashCode.Combine(Type, PreCommit);\n        }\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Net/Messages/ConsensusPreVoteMsg.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing Libplanet.Net.Consensus;\nusing Libplanet.Types.Consensus;\n\nnamespace Libplanet.Net.Messages\n{\n    /// <summary>\n    /// A message class for <see cref=\"ConsensusStep.PreVote\"/>.\n    /// </summary>\n    public class ConsensusPreVoteMsg : ConsensusVoteMsg\n    {\n        private static Bencodex.Codec _codec = new Bencodex.Codec();\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"ConsensusPreVoteMsg\"/> class.\n        /// </summary>\n        /// <param name=\"vote\">The <see cref=\"Vote\"/> for <see cref=\"ConsensusStep.PreVote\"/>\n        /// to attach.\n        /// </param>\n        /// <exception cref=\"ArgumentException\">Thrown when given <paramref name=\"vote\"/>'s\n        /// <see cref=\"Vote.Flag\"/> is not <see cref=\"VoteFlag.PreVote\"/>.</exception>\n        public ConsensusPreVoteMsg(Vote vote)\n            : base(vote.ValidatorPublicKey, vote.Height, vote.Round, vote.BlockHash, vote.Flag)\n        {\n            if (vote.Flag != VoteFlag.PreVote)\n            {\n                throw new ArgumentException(\n                    $\"Given {nameof(vote)}'s flag must be {VoteFlag.PreVote}.\", nameof(vote));\n            }\n\n            PreVote = vote;\n        }\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"ConsensusPreVoteMsg\"/> class\n        /// with marshalled message.\n        /// </summary>\n        /// <param name=\"dataframes\">A marshalled message.</param>\n        public ConsensusPreVoteMsg(byte[][] dataframes)\n            : this(new Vote(_codec.Decode(dataframes[0])))\n        {\n        }\n\n        /// <summary>\n        /// A <see cref=\"Vote\"/> for <see cref=\"ConsensusStep.PreVote\"/>.  This will always\n        /// have its <see cref=\"Vote.Flag\"/> set to <see cref=\"VoteFlag.PreVote\"/>.\n        /// </summary>\n        public Vote PreVote { get; }\n\n        /// <inheritdoc cref=\"MessageContent.DataFrames\"/>\n        public override IEnumerable<byte[]> DataFrames =>\n            new List<byte[]> { _codec.Encode(PreVote.Bencoded) };\n\n        /// <inheritdoc cref=\"MessageContent.MessageType\"/>\n        public override MessageType Type => MessageType.ConsensusVote;\n\n        /// <inheritdoc/>\n        public override bool Equals(ConsensusMsg? other)\n        {\n            return other is ConsensusPreVoteMsg message &&\n                PreVote.Equals(message.PreVote);\n        }\n\n        /// <inheritdoc/>\n        public override bool Equals(object? obj)\n        {\n            return obj is ConsensusMsg other && Equals(other);\n        }\n\n        /// <inheritdoc/>\n        public override int GetHashCode()\n        {\n            return HashCode.Combine(Type, PreVote);\n        }\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Net/Messages/ConsensusProposalClaimMsg.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing Libplanet.Consensus;\nusing Libplanet.Types.Blocks;\n\nnamespace Libplanet.Net.Messages\n{\n    /// <summary>\n    /// A message class for claiming a <see cref=\"Proposal\"/>.\n    /// </summary>\n    public class ConsensusProposalClaimMsg : ConsensusMsg\n    {\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"ConsensusProposalClaimMsg\"/> class.\n        /// </summary>\n        /// <param name=\"proposalClaim\">A <see cref=\"ProposalClaim\"/> of given height,\n        /// round and <see cref=\"BlockHash\"/>.</param>\n        public ConsensusProposalClaimMsg(ProposalClaim proposalClaim)\n            : base(proposalClaim.ValidatorPublicKey, proposalClaim.Height, proposalClaim.Round)\n        {\n            ProposalClaim = proposalClaim;\n        }\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"ConsensusProposalClaimMsg\"/> class\n        /// with marshalled message.\n        /// </summary>\n        /// <param name=\"dataframes\">A marshalled message.</param>\n        public ConsensusProposalClaimMsg(byte[][] dataframes)\n            : this(new ProposalClaim(dataframes[0]))\n        {\n        }\n\n        /// <summary>\n        /// A <see cref=\"ProposalClaim\"/> of the message.\n        /// </summary>\n        public ProposalClaim ProposalClaim { get; }\n\n        /// <inheritdoc cref=\"MessageContent.DataFrames\"/>\n        public override IEnumerable<byte[]> DataFrames =>\n            new List<byte[]> { ProposalClaim.ToByteArray() };\n\n        /// <inheritdoc cref=\"MessageContent.MessageType\"/>\n        public override MessageType Type => MessageType.ConsensusProposalClaimMsg;\n\n        /// <inheritdoc cref=\"ConsensusMsg.Equals(ConsensusMsg?)\"/>\n        public override bool Equals(ConsensusMsg? other)\n        {\n            return other is ConsensusProposalClaimMsg message &&\n                   message.ProposalClaim.Equals(ProposalClaim);\n        }\n\n        /// <inheritdoc cref=\"ConsensusMsg.Equals(object?)\"/>\n        public override bool Equals(object? obj)\n        {\n            return obj is ConsensusMsg other && Equals(other);\n        }\n\n        /// <inheritdoc cref=\"ConsensusMsg.GetHashCode\"/>\n        public override int GetHashCode()\n        {\n            return HashCode.Combine(Type, ProposalClaim);\n        }\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Net/Messages/ConsensusProposalMsg.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing Libplanet.Consensus;\nusing Libplanet.Net.Consensus;\nusing Libplanet.Types.Blocks;\n\nnamespace Libplanet.Net.Messages\n{\n    /// <summary>\n    /// A message class for <see cref=\"ConsensusStep.Propose\"/>.\n    /// </summary>\n    public class ConsensusProposalMsg : ConsensusMsg\n    {\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"ConsensusProposalMsg\"/> class.\n        /// </summary>\n        /// <param name=\"proposal\">A <see cref=\"Proposal\"/> of given height and round.</param>\n        public ConsensusProposalMsg(\n            Proposal proposal)\n            : base(proposal.ValidatorPublicKey, proposal.Height, proposal.Round)\n        {\n            Proposal = proposal;\n            BlockHash = proposal.BlockHash;\n        }\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"ConsensusProposalMsg\"/> class\n        /// with marshalled message.\n        /// </summary>\n        /// <param name=\"dataframes\">A marshalled message.</param>\n        public ConsensusProposalMsg(byte[][] dataframes)\n            : this(proposal: new Proposal(dataframes[0]))\n        {\n        }\n\n        /// <summary>\n        /// A <see cref=\"Proposal\"/> of the message.\n        /// </summary>\n        public Proposal Proposal { get; }\n\n        /// <summary>\n        /// A <see cref=\"BlockHash\"/> the message is written for.\n        /// </summary>\n        public BlockHash BlockHash { get; }\n\n        /// <inheritdoc cref=\"MessageContent.DataFrames\"/>\n        public override IEnumerable<byte[]> DataFrames =>\n            new List<byte[]> { Proposal.ToByteArray() };\n\n        /// <inheritdoc cref=\"MessageContent.MessageType\"/>\n        public override MessageType Type => MessageType.ConsensusProposal;\n\n        /// <inheritdoc/>\n        public override bool Equals(ConsensusMsg? other)\n        {\n            return other is ConsensusProposalMsg message &&\n                   message.Proposal.Equals(Proposal);\n        }\n\n        /// <inheritdoc/>\n        public override bool Equals(object? obj)\n        {\n            return obj is ConsensusMsg other && Equals(other);\n        }\n\n        /// <inheritdoc/>\n        public override int GetHashCode()\n        {\n            return HashCode.Combine(Type, Proposal);\n        }\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Net/Messages/ConsensusVoteMsg.cs",
    "content": "using Libplanet.Crypto;\nusing Libplanet.Net.Consensus;\nusing Libplanet.Types.Blocks;\nusing Libplanet.Types.Consensus;\n\nnamespace Libplanet.Net.Messages\n{\n    /// <summary>\n    /// A abstract base class message for consensus.\n    /// </summary>\n    public abstract class ConsensusVoteMsg : ConsensusMsg\n    {\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"ConsensusMsg\"/> class.\n        /// </summary>\n        /// <param name=\"validatorPublicKey\">\n        /// A <see cref=\"PublicKey\"/> of the validator who made this message.</param>\n        /// <param name=\"height\">A <see cref=\"Context.Height\"/> the message is for.</param>\n        /// <param name=\"round\">A <see cref=\"Context.Round\"/> the message is written for.</param>\n        /// <param name=\"blockHash\">A <see cref=\"BlockHash\"/> the message is written for.</param>\n        /// <param name=\"flag\">A <see cref=\"VoteFlag\"/>.</param>\n        protected ConsensusVoteMsg(\n            PublicKey validatorPublicKey,\n            long height,\n            int round,\n            BlockHash blockHash,\n            VoteFlag flag)\n            : base(validatorPublicKey, height, round)\n        {\n            BlockHash = blockHash;\n            Flag = flag;\n        }\n\n        /// <summary>\n        /// A <see cref=\"BlockHash\"/> the message is written for.\n        /// </summary>\n        public BlockHash BlockHash { get; }\n\n        /// <summary>\n        /// A <see cref=\"VoteFlag\"/> of message's vote.\n        /// </summary>\n        public VoteFlag Flag { get; }\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Net/Messages/ConsensusVoteSetBitsMsg.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing Libplanet.Consensus;\nusing Libplanet.Types.Blocks;\nusing Libplanet.Types.Consensus;\n\nnamespace Libplanet.Net.Messages\n{\n    /// <summary>\n    /// A message class for requesting lacking <see cref=\"Vote\"/>s\n    /// by sending the <see cref=\"Vote\"/>s that the peer has.\n    /// </summary>\n    public class ConsensusVoteSetBitsMsg : ConsensusMsg\n    {\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"ConsensusVoteSetBitsMsg\"/> class.\n        /// </summary>\n        /// <param name=\"voteSetBits\">A <see cref=\"VoteSetBits\"/> of given height and round.</param>\n        public ConsensusVoteSetBitsMsg(VoteSetBits voteSetBits)\n            : base(\n                voteSetBits.ValidatorPublicKey,\n                voteSetBits.Height,\n                voteSetBits.Round)\n        {\n            VoteSetBits = voteSetBits;\n            BlockHash = voteSetBits.BlockHash;\n        }\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"ConsensusVoteSetBitsMsg\"/> class\n        /// with marshalled message.\n        /// </summary>\n        /// <param name=\"dataframes\">A marshalled message.</param>\n        public ConsensusVoteSetBitsMsg(byte[][] dataframes)\n            : this(voteSetBits: new VoteSetBits(dataframes[0]))\n        {\n        }\n\n        /// <summary>\n        /// A <see cref=\"VoteSetBits\"/> of the message.\n        /// </summary>\n        public VoteSetBits VoteSetBits { get; }\n\n        /// <summary>\n        /// A <see cref=\"BlockHash\"/> of the message.\n        /// </summary>\n        public BlockHash BlockHash { get; }\n\n        /// <inheritdoc cref=\"MessageContent.DataFrames\"/>\n        public override IEnumerable<byte[]> DataFrames =>\n            new List<byte[]> { VoteSetBits.ToByteArray() };\n\n        /// <inheritdoc cref=\"MessageContent.MessageType\"/>\n        public override MessageType Type => MessageType.ConsensusVoteSetBitsMsg;\n\n        /// <inheritdoc cref=\"ConsensusMsg.Equals(ConsensusMsg?)\"/>\n        public override bool Equals(ConsensusMsg? other)\n        {\n            return other is ConsensusVoteSetBitsMsg message &&\n                   message.VoteSetBits.Equals(VoteSetBits);\n        }\n\n        /// <inheritdoc cref=\"ConsensusMsg.Equals(object?)\"/>\n        public override bool Equals(object? obj)\n        {\n            return obj is ConsensusVoteSetBitsMsg other && Equals(other);\n        }\n\n        /// <inheritdoc cref=\"ConsensusMsg.GetHashCode\"/>\n        public override int GetHashCode()\n        {\n            return HashCode.Combine(Type, VoteSetBits);\n        }\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Net/Messages/DifferentVersionMsg.cs",
    "content": "using System.Collections.Generic;\n\nnamespace Libplanet.Net.Messages\n{\n    /// <summary>\n    /// A reply to any messages with different <see cref=\"AppProtocolVersion\"/>.\n    /// Contains the expected and actual <see cref=\"AppProtocolVersion\"/>\n    /// value of the message.\n    /// </summary>\n    public class DifferentVersionMsg : MessageContent\n    {\n        public override MessageType Type => MessageType.DifferentVersion;\n\n        public override IEnumerable<byte[]> DataFrames => new byte[][] { };\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Net/Messages/EvidenceIdsMsg.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing Libplanet.Types.Evidence;\n\nnamespace Libplanet.Net.Messages\n{\n    internal class EvidenceIdsMsg : MessageContent\n    {\n        public EvidenceIdsMsg(IEnumerable<EvidenceId> evidenceIds)\n        {\n            Ids = evidenceIds;\n        }\n\n        public EvidenceIdsMsg(byte[][] dataFrames)\n        {\n            int txCount = BitConverter.ToInt32(dataFrames[0], 0);\n            Ids = dataFrames\n                .Skip(1).Take(txCount)\n                .Select(ba => new EvidenceId(ba))\n                .ToList();\n        }\n\n        public IEnumerable<EvidenceId> Ids { get; }\n\n        public override MessageType Type => MessageType.EvidenceIds;\n\n        public override IEnumerable<byte[]> DataFrames\n        {\n            get\n            {\n                var frames = new List<byte[]>();\n                frames.Add(BitConverter.GetBytes(Ids.Count()));\n                frames.AddRange(Ids.Select(id => id.ToByteArray()));\n                return frames;\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Net/Messages/EvidenceMsg.cs",
    "content": "using System.Collections.Generic;\n\nnamespace Libplanet.Net.Messages\n{\n    internal class EvidenceMsg : MessageContent\n    {\n        public EvidenceMsg(byte[] payload)\n        {\n            Payload = payload;\n        }\n\n        public EvidenceMsg(byte[][] dataFrames)\n        {\n            Payload = dataFrames[0];\n        }\n\n        public byte[] Payload { get; }\n\n        public override MessageType Type => MessageType.Evidence;\n\n        public override IEnumerable<byte[]> DataFrames => new[] { Payload, };\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Net/Messages/FindNeighborsMsg.cs",
    "content": "using System.Collections.Generic;\nusing Libplanet.Crypto;\n\nnamespace Libplanet.Net.Messages\n{\n    /// <summary>\n    /// Message containing request for nearby peers.\n    /// </summary>\n    /// <seealso cref=\"NeighborsMsg\"/>\n    public class FindNeighborsMsg : MessageContent\n    {\n        // TODO: This message may request exact peer instead of its neighbors.\n        public FindNeighborsMsg(Address target)\n        {\n            Target = target;\n        }\n\n        public FindNeighborsMsg(byte[][] dataFrames)\n        {\n            Target = new Address(dataFrames[0]);\n        }\n\n        public Address Target { get; }\n\n        public override MessageType Type => MessageType.FindNeighbors;\n\n        public override IEnumerable<byte[]> DataFrames => new[]\n        {\n            Target.ToByteArray(),\n        };\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Net/Messages/GetBlockHashesMsg.cs",
    "content": "using System.Collections.Generic;\nusing Libplanet.Blockchain;\nusing Libplanet.Types.Blocks;\n\nnamespace Libplanet.Net.Messages\n{\n    internal class GetBlockHashesMsg : MessageContent\n    {\n        public GetBlockHashesMsg(BlockLocator locator)\n        {\n            Locator = locator;\n        }\n\n        public GetBlockHashesMsg(byte[][] dataFrames)\n        {\n            Locator = new BlockLocator(new BlockHash(dataFrames[0]));\n        }\n\n        public BlockLocator Locator { get; }\n\n        public override MessageType Type => MessageType.GetBlockHashes;\n\n        public override IEnumerable<byte[]> DataFrames\n        {\n            get\n            {\n                var frames = new List<byte[]>();\n                frames.Add(Locator.Hash.ToByteArray());\n                return frames;\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Net/Messages/GetBlocksMsg.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing Libplanet.Types.Blocks;\n\nnamespace Libplanet.Net.Messages\n{\n    internal class GetBlocksMsg : MessageContent\n    {\n        public GetBlocksMsg(IEnumerable<BlockHash> hashes, int chunkSize = 100)\n        {\n            if (chunkSize <= 0)\n            {\n                throw new ArgumentOutOfRangeException(\n                    nameof(chunkSize),\n                    \"Chunk size must be greater than 0.\");\n            }\n\n            BlockHashes = hashes;\n            ChunkSize = chunkSize;\n        }\n\n        public GetBlocksMsg(byte[][] dataFrames)\n        {\n            int hashCount = BitConverter.ToInt32(dataFrames[0], 0);\n            BlockHashes = dataFrames\n                .Skip(1).Take(hashCount)\n                .Select(ba => new BlockHash(ba))\n                .ToList();\n            ChunkSize = BitConverter.ToInt32(dataFrames[1 + hashCount], 0);\n        }\n\n        public IEnumerable<BlockHash> BlockHashes { get; }\n\n        public int ChunkSize { get; }\n\n        public override MessageType Type => MessageType.GetBlocks;\n\n        public override IEnumerable<byte[]> DataFrames\n        {\n            get\n            {\n                var frames = new List<byte[]>();\n                frames.Add(BitConverter.GetBytes(BlockHashes.Count()));\n                frames.AddRange(BlockHashes.Select(hash => hash.ToByteArray()));\n                frames.Add(BitConverter.GetBytes(ChunkSize));\n                return frames;\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Net/Messages/GetChainStatusMsg.cs",
    "content": "using System.Collections.Generic;\n\nnamespace Libplanet.Net.Messages\n{\n    internal class GetChainStatusMsg : MessageContent\n    {\n        public override MessageType Type => MessageType.GetChainStatus;\n\n        public override IEnumerable<byte[]> DataFrames => new byte[][] { };\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Net/Messages/GetEvidenceMsg.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing Libplanet.Types.Evidence;\n\nnamespace Libplanet.Net.Messages\n{\n    internal class GetEvidenceMsg : MessageContent\n    {\n        public GetEvidenceMsg(IEnumerable<EvidenceId> evidenceIds)\n        {\n            EvidenceIds = evidenceIds;\n        }\n\n        public GetEvidenceMsg(byte[][] dataFrames)\n        {\n            int txCount = BitConverter.ToInt32(dataFrames[0], 0);\n            EvidenceIds = dataFrames\n                .Skip(1).Take(txCount)\n                .Select(ba => new EvidenceId(ba))\n                .ToList();\n        }\n\n        public IEnumerable<EvidenceId> EvidenceIds { get; }\n\n        public override MessageType Type => MessageType.GetEvidence;\n\n        public override IEnumerable<byte[]> DataFrames\n        {\n            get\n            {\n                var frames = new List<byte[]>();\n                frames.Add(BitConverter.GetBytes(EvidenceIds.Count()));\n                frames.AddRange(EvidenceIds.Select(id => id.ToByteArray()));\n                return frames;\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Net/Messages/GetTxsMsg.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing Libplanet.Types.Tx;\n\nnamespace Libplanet.Net.Messages\n{\n    internal class GetTxsMsg : MessageContent\n    {\n        public GetTxsMsg(IEnumerable<TxId> txIds)\n        {\n            TxIds = txIds;\n        }\n\n        public GetTxsMsg(byte[][] dataFrames)\n        {\n            int txCount = BitConverter.ToInt32(dataFrames[0], 0);\n            TxIds = dataFrames\n                .Skip(1).Take(txCount)\n                .Select(ba => new TxId(ba))\n                .ToList();\n        }\n\n        public IEnumerable<TxId> TxIds { get; }\n\n        public override MessageType Type => MessageType.GetTxs;\n\n        public override IEnumerable<byte[]> DataFrames\n        {\n            get\n            {\n                var frames = new List<byte[]>();\n                frames.Add(BitConverter.GetBytes(TxIds.Count()));\n                frames.AddRange(TxIds.Select(id => id.ToByteArray()));\n                return frames;\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Net/Messages/HaveMessage.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Linq;\n\nnamespace Libplanet.Net.Messages\n{\n    /// <summary>\n    /// List of message IDs that the peer seen recently.\n    /// </summary>\n    /// <seealso cref=\"WantMessage\"/>\n    public class HaveMessage : MessageContent\n    {\n        public HaveMessage(MessageId[] messageIds)\n        {\n            Ids = messageIds;\n        }\n\n        public HaveMessage(byte[][] dataFrames)\n        {\n            int msgCount = BitConverter.ToInt32(dataFrames[0], 0);\n            Ids = dataFrames\n                .Skip(1).Take(msgCount)\n                .Select(ba => new MessageId(ba))\n                .ToList();\n        }\n\n        public IEnumerable<MessageId> Ids { get; }\n\n        public override MessageType Type => MessageType.HaveMessage;\n\n        public override IEnumerable<byte[]> DataFrames\n        {\n            get\n            {\n                var frames = new List<byte[]>();\n                frames.Add(BitConverter.GetBytes(Ids.Count()));\n                frames.AddRange(Ids.Select(id => id.ToByteArray()));\n                return frames;\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Net/Messages/IMessageCodec.cs",
    "content": "using System;\nusing Libplanet.Crypto;\nusing Libplanet.Net.Transports;\n\nnamespace Libplanet.Net.Messages\n{\n    public interface IMessageCodec<T>\n    {\n        /// <summary>\n        /// Encodes the message to <see typeref=\"T\"/>-typed instance with given\n        /// <paramref name=\"privateKey\"/> for signing.\n        /// </summary>\n        /// <param name=\"message\">The message to encode.</param>\n        /// <param name=\"privateKey\">The <see cref=\"PrivateKey\"/> to sign the encoded message.\n        /// </param>\n        /// <returns>A <see typeref=\"T\"/> containing the signed <see cref=\"MessageContent\"/>.\n        /// </returns>\n        /// <exception cref=\"InvalidCredentialException\">Thrown when <paramref name=\"privateKey\"/>'s\n        /// <see cref=\"PublicKey\"/> does not match that of <paramref name=\"message.Remote\"/>.\n        /// </exception>\n        T Encode(Message message, PrivateKey privateKey);\n\n        /// <summary>\n        /// Decodes given <see typeref=\"T\"/>-typed <paramref name=\"encoded\"/> into\n        /// <see cref=\"Message\"/> and checks its validity.\n        /// <seealso cref=\"Encode\"/>\n        /// </summary>\n        /// <param name=\"encoded\">A <see typeref=\"T\"/>-typed instance to parse.</param>\n        /// <param name=\"reply\">A flag to express whether the target is a reply of other message.\n        /// </param>\n        /// <returns>A <see cref=\"Message\"/> parsed from <paramref name=\"encoded\"/>.</returns>\n        /// <exception cref=\"ArgumentException\">Thrown when empty <paramref name=\"encoded\"/>\n        /// is given.</exception>\n        /// <exception cref=\"InvalidMessageSignatureException\">Thrown when the signer of\n        /// <paramref name=\"encoded\"/> is invalid.</exception>\n        Message Decode(\n            T encoded,\n            bool reply);\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Net/Messages/Message.cs",
    "content": "using System;\n\nnamespace Libplanet.Net.Messages\n{\n    public class Message\n    {\n        public Message(\n            MessageContent content,\n            AppProtocolVersion version,\n            BoundPeer remote,\n            DateTimeOffset timestamp,\n            byte[]? identity)\n        {\n            Content = content;\n            Version = version;\n            Remote = remote;\n            Timestamp = timestamp;\n            Identity = identity;\n        }\n\n        /// <summary>\n        /// The body of the message that contains the message type and data.\n        /// </summary>\n        public MessageContent Content { get; }\n\n        /// <summary>\n        /// The <see cref=\"AppProtocolVersion\"/> of sender of the <see cref=\"Message\"/>.\n        /// </summary>\n        public AppProtocolVersion Version { get; }\n\n        /// <summary>\n        /// The <see cref=\"BoundPeer\"/> representation of sender of the given <see cref=\"Message\"/>.\n        /// </summary>\n        public BoundPeer Remote { get; }\n\n        /// <summary>\n        /// The <see cref=\"DateTimeOffset\"/> of the <see cref=\"Message\"/>.\n        /// </summary>\n        public DateTimeOffset Timestamp { get; }\n\n        /// <summary>\n        /// The byte array identifies the message to match between\n        /// message and its respond used in <see cref=\"NetMQ\"/>.\n        /// </summary>\n        public byte[]? Identity { get; }\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Net/Messages/MessageContent.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Diagnostics.Contracts;\nusing System.Security.Cryptography;\nusing Destructurama.Attributed;\nusing Libplanet.Net.Transports;\nusing Libplanet.Types.Blocks;\n\nnamespace Libplanet.Net.Messages\n{\n    /// <summary>\n    /// Serves as the base class for messages used in <see cref=\"ITransport\"/>.\n    /// </summary>\n    public abstract class MessageContent\n    {\n        /// <summary>\n        /// <c>Enum</c> represents the type of the <see cref=\"MessageContent\"/>.\n        /// </summary>\n        public enum MessageType : byte\n        {\n            /// <summary>\n            /// Check message to determine peer is alive.\n            /// </summary>\n            Ping = 0x01,\n\n            /// <summary>\n            /// A reply to <see cref=\"Ping\"/>.\n            /// </summary>\n            Pong = 0x14,\n\n            /// <summary>\n            /// Request to query block hashes.\n            /// </summary>\n            GetBlockHashes = 0x032,\n\n            /// <summary>\n            /// Inventory to transfer transactions.\n            /// </summary>\n            TxIds = 0x31,\n\n            /// <summary>\n            /// Request to query blocks.\n            /// </summary>\n            GetBlocks = 0x07,\n\n            /// <summary>\n            /// Request to query transactions.\n            /// </summary>\n            GetTxs = 0x08,\n\n            /// <summary>\n            /// Message containing serialized blocks.\n            /// </summary>\n            Blocks = 0x0a,\n\n            /// <summary>\n            /// Message containing serialized transaction.\n            /// </summary>\n            Tx = 0x10,\n\n            /// <summary>\n            /// Message containing request for nearby peers.\n            /// </summary>\n            FindNeighbors = 0x11,\n\n            /// <summary>\n            /// Message containing nearby peers.\n            /// </summary>\n            Neighbors = 0x12,\n\n            /// <summary>\n            /// Message containing a single <see cref=\"BlockHeader\"/>.\n            /// </summary>\n            BlockHeaderMessage = 0x0c,\n\n            /// <summary>\n            /// Message containing demand block hashes with their index numbers.\n            /// </summary>\n            BlockHashes = 0x33,\n\n            /// <summary>\n            /// Request current chain status of the peer.\n            /// </summary>\n            GetChainStatus = 0x20,\n\n            /// <summary>\n            /// A reply to <see cref=\"GetChainStatus\"/>.\n            /// Contains the chain status of the peer at the moment.\n            /// </summary>\n            ChainStatus = 0x25,\n\n            /// <summary>\n            /// A reply to any messages with different <see cref=\"AppProtocolVersion\"/>.\n            /// Contains the expected and actual <see cref=\"AppProtocolVersion\"/>\n            /// value of the message.\n            /// </summary>\n            DifferentVersion = 0x30,\n\n            /// <summary>\n            /// List of message IDs that the peer seen recently.\n            /// </summary>\n            HaveMessage = 0x43,\n\n            /// <summary>\n            /// List of message IDs that the peer want to have.\n            /// </summary>\n            WantMessage = 0x44,\n\n            /// <summary>\n            /// Consensus proposal message.\n            /// </summary>\n            ConsensusProposal = 0x50,\n\n            /// <summary>\n            /// Consensus vote message.\n            /// </summary>\n            ConsensusVote = 0x51,\n\n            /// <summary>\n            /// Consensus commit message.\n            /// </summary>\n            ConsensusCommit = 0x52,\n\n            /// <summary>\n            /// Consensus message that informs other peer that the peer has a vote of majority 2/3.\n            /// </summary>\n            ConsensusMaj23Msg = 0x53,\n\n            /// <summary>\n            /// Consensus message that informs vote sets that the peer have to other peer.\n            /// </summary>\n            ConsensusVoteSetBitsMsg = 0x54,\n\n            /// <summary>\n            /// Consensus message that informs vote sets that the peer received new maj23 block.\n            /// </summary>\n            ConsensusProposalClaimMsg = 0x55,\n\n            /// <summary>\n            /// Inventory to transfer evidence.\n            /// </summary>\n            EvidenceIds = 0x56,\n\n            /// <summary>\n            /// Request to query evidence.\n            /// </summary>\n            GetEvidence = 0x57,\n\n            /// <summary>\n            /// Message containing serialized evidence.\n            /// </summary>\n            Evidence = 0x58,\n        }\n\n        /// <summary>\n        /// The type of the message.\n        /// </summary>\n        public abstract MessageType Type { get; }\n\n        /// <summary>\n        /// The body of the message.\n        /// </summary>\n        public abstract IEnumerable<byte[]> DataFrames { get; }\n\n        /// <summary>\n        /// A bytearray representing SHA-256 digest of <see cref=\"MessageContent\"/>.\n        /// </summary>\n        /// <returns>A mutable <see cref=\"byte\"/> array representing\n        /// SHA-256 digest of <see cref=\"Message\"/>.\n        /// </returns>\n        [Pure]\n        [NotLogged]\n        public MessageId Id\n        {\n            get\n            {\n                var bytes = new List<byte>();\n                bytes.AddRange(BitConverter.GetBytes((int)Type));\n                foreach (byte[] ba in DataFrames)\n                {\n                    bytes.AddRange(ba);\n                }\n\n                SHA256 sha256 = SHA256.Create();\n                byte[] digest = sha256.ComputeHash(bytes.ToArray());\n                return new MessageId(digest);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Net/Messages/MessageId.cs",
    "content": "using System;\nusing System.Collections.Immutable;\nusing System.Diagnostics.Contracts;\nusing System.Linq;\nusing Libplanet.Common;\n\nnamespace Libplanet.Net.Messages\n{\n    /// <summary>\n    /// <see cref=\"MessageId\"/>, abbreviation of message identifier,\n    /// is a SHA-256 digest derived from a <see cref=\"Message\"/>'s\n    /// content.\n    /// <para>As it is a SHA-256 digest, it consists of 32 <see cref=\"byte\"/>s,\n    /// and 64 characters in hexadecimal.\n    /// (See also <see cref=\"Size\"/> constant.)</para>\n    /// </summary>\n    /// <seealso cref=\"MessageContent.Id\"/>\n    public struct MessageId : IComparable<MessageId>, IComparable\n    {\n        /// <summary>\n        /// The <see cref=\"byte\"/>s size that each <see cref=\"MessageId\"/> takes.\n        /// <para>As a message ID is a SHA-256 digest, it is 32 <see cref=\"byte\"/>s.\n        /// </para>\n        /// </summary>\n        public const int Size = 32;\n\n        private ImmutableArray<byte> _byteArray;\n\n        /// <summary>\n        /// Converts a <see cref=\"byte\"/> array into a <see cref=\"MessageId\"/>.\n        /// </summary>\n        /// <param name=\"messageId\">A <see cref=\"byte\"/> array that encodes\n        /// a <see cref=\"MessageId\"/>.  It must not be <see langword=\"null\"/>,\n        /// and its <see cref=\"Array.Length\"/> must be the same to\n        /// <see cref=\"Size\"/>.</param>\n        /// <exception cref=\"ArgumentOutOfRangeException\">Thrown when the given\n        /// <paramref name=\"messageId\"/>'s <see cref=\"Array.Length\"/> is not\n        /// the same to the required <see cref=\"Size\"/>.</exception>\n        public MessageId(byte[] messageId)\n        {\n            if (messageId.Length != Size)\n            {\n                throw new ArgumentOutOfRangeException(\n                    nameof(messageId),\n                    $\"{nameof(MessageId)} must be {Size} bytes.\"\n                );\n            }\n\n            _byteArray = messageId.ToImmutableArray();\n        }\n\n        /// <summary>\n        /// A bare immutable <see cref=\"byte\"/> array of\n        /// this <see cref=\"MessageId\"/>.\n        /// </summary>\n        /// <remarks>It is immutable.  For a mutable array, use\n        /// <see cref=\"ToByteArray()\"/> method instead.</remarks>\n        /// <seealso cref=\"ToByteArray()\"/>\n        public ImmutableArray<byte> ByteArray\n        {\n            get\n            {\n                if (_byteArray.IsDefault)\n                {\n                    _byteArray = new byte[Size].ToImmutableArray();\n                }\n\n                return _byteArray;\n            }\n        }\n\n        public static bool operator ==(MessageId left, MessageId right) => left.Equals(right);\n\n        public static bool operator !=(MessageId left, MessageId right) => !left.Equals(right);\n\n        /// <summary>\n        /// Creates a <see cref=\"MessageId\"/> value from a <paramref name=\"hex\"/> string.\n        /// </summary>\n        /// <param name=\"hex\">A hexadecimal string which encodes a <see cref=\"MessageId\"/>.\n        /// This has to contain 64 hexadecimal digits and must not be <see langword=\"null\"/>\n        /// This is usually made by <see cref=\"ToHex()\"/> method.</param>\n        /// <returns>A corresponding <see cref=\"MessageId\"/> value.</returns>\n        /// <exception cref=\"ArgumentNullException\">Thrown when the given <paramref name=\"hex\"/>\n        /// string is <see langword=\"null\"/>.</exception>\n        /// <exception cref=\"ArgumentOutOfRangeException\">Thrown when the given\n        /// <paramref name=\"hex\"/> is shorter or longer than 64 characters.</exception>\n        /// <exception cref=\"FormatException\">Thrown when the given <paramref name=\"hex\"/> string is\n        /// not a valid hexadecimal string.</exception>\n        /// <seealso cref=\"ToHex()\"/>\n        public static MessageId FromHex(string hex)\n        {\n            if (hex is null)\n            {\n                throw new ArgumentNullException(nameof(hex));\n            }\n\n            byte[] bytes = ByteUtil.ParseHex(hex);\n            try\n            {\n                return new MessageId(bytes);\n            }\n            catch (ArgumentOutOfRangeException)\n            {\n                throw new ArgumentOutOfRangeException(\n                    nameof(hex),\n                    $\"Expected {Size * 2} characters, but {hex.Length} characters given.\"\n                );\n            }\n        }\n\n        public bool Equals(MessageId other) => ByteArray.SequenceEqual(other.ByteArray);\n\n        public override bool Equals(object? obj) => obj is MessageId other && Equals(other);\n\n        public override int GetHashCode() => ByteUtil.CalculateHashCode(ToByteArray());\n\n        /// <summary>\n        /// Gets a bare mutable <see cref=\"byte\"/> array of\n        /// this <see cref=\"MessageId\"/>.\n        /// </summary>\n        /// <returns>A new mutable <see cref=\"byte\"/> array of\n        /// this <see cref=\"MessageId\"/>.\n        /// Since a returned array is created every time the method is called,\n        /// any mutations on that array does not affect to\n        /// the <see cref=\"MessageId\"/> object.\n        /// </returns>\n        /// <seealso cref=\"ByteArray\"/>\n        [Pure]\n        public byte[] ToByteArray() => ByteArray.ToArray();\n\n        /// <summary>\n        /// Gets a hexadecimal form of a <see cref=\"MessageId\"/>.\n        /// </summary>\n        /// <returns>64 hexadecimal characters.</returns>\n        [Pure]\n        public string ToHex() => ByteUtil.Hex(ToByteArray());\n\n        /// <summary>\n        /// Gets a <see cref=\"MessageId\"/>'s representative string.\n        /// </summary>\n        /// <returns>A string which represents this <see cref=\"MessageId\"/>.\n        /// </returns>\n        [Pure]\n        public override string ToString() => ToHex();\n\n        /// <inheritdoc cref=\"IComparable{T}.CompareTo(T)\"/>\n        public int CompareTo(MessageId other)\n        {\n            for (int i = 0; i < Size; ++i)\n            {\n                int cmp = ByteArray[i].CompareTo(other.ByteArray[i]);\n                if (cmp != 0)\n                {\n                    return cmp;\n                }\n            }\n\n            return 0;\n        }\n\n        /// <inheritdoc cref=\"IComparable.CompareTo(object)\"/>\n        public int CompareTo(object? obj)\n        {\n            if (obj is MessageId other)\n            {\n                return ((IComparable<MessageId>)this).CompareTo(other);\n            }\n\n            if (obj is null)\n            {\n                throw new ArgumentNullException(nameof(obj));\n            }\n\n            throw new ArgumentException(nameof(obj));\n        }\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Net/Messages/MessageValidator.cs",
    "content": "using System;\nusing System.Collections.Immutable;\nusing System.Globalization;\nusing System.Linq;\nusing Libplanet.Common;\nusing Libplanet.Crypto;\nusing Libplanet.Net.Options;\nusing Libplanet.Net.Transports;\n\nnamespace Libplanet.Net.Messages\n{\n    /// <summary>\n    /// A helper class for an <see cref=\"IMessageCodec{T}\"/> to validate\n    /// a decoded <see cref=\"Message\"/>.\n    /// </summary>\n    public class MessageValidator\n    {\n        private const string TimestampFormat = \"yyyy-MM-ddTHH:mm:ss.ffffffZ\";\n        private readonly AppProtocolVersionOptions _appProtocolVersionOptions;\n\n        internal MessageValidator(\n            AppProtocolVersionOptions appProtocolVersionOptions,\n            TimeSpan? messageTimestampBuffer)\n        {\n            _appProtocolVersionOptions = appProtocolVersionOptions;\n            MessageTimestampBuffer = messageTimestampBuffer;\n        }\n\n        /// <summary>\n        /// <para>\n        /// The local <see cref=\"AppProtocolVersion\"/> used for\n        /// <see cref=\"IMessageCodec{T}.Encode\"/> and <see cref=\"IMessageCodec{T}.Decode\"/> methods.\n        /// </para>\n        /// <para>\n        /// In particular, this is used in the following cases:\n        /// <list type=\"bullet\">\n        ///     <item><description>\n        ///         When encoding, this value is attached to the encoded output.\n        ///     </description></item>\n        ///     <item><description>\n        ///         When decoding, the encoded message's <see cref=\"AppProtocolVersion\"/> must\n        ///         match this value.\n        ///     </description></item>\n        /// </list>\n        /// </para>\n        /// </summary>\n        public AppProtocolVersion Apv => _appProtocolVersionOptions.AppProtocolVersion;\n\n        /// <summary>\n        /// <para>\n        /// An <see cref=\"IImmutableSet{T}\"/> of <see cref=\"Address\"/>es to trust as a signer\n        /// when a different <see cref=\"AppProtocolVersion\"/> is encountered.\n        /// </para>\n        /// <para>\n        /// Whether to trust an unknown <see cref=\"AppProtocolVersion\"/>, i.e.\n        /// an <see cref=\"AppProtocolVersion\"/> that is different\n        /// from <see cref=\"Apv\"/>.  An <see cref=\"AppProtocolVersion\"/> is trusted if it is signed\n        /// by one of the signers in the set.  In particular, if the set is empty,\n        /// no <see cref=\"AppProtocolVersion\"/> is trusted.\n        /// </para>\n        /// </summary>\n        public IImmutableSet<PublicKey> TrustedApvSigners =>\n            _appProtocolVersionOptions.TrustedAppProtocolVersionSigners;\n\n        /// <summary>\n        /// A callback method that gets invoked when a an <see cref=\"AppProtocolVersion\"/>\n        /// by a <em>trusted</em> signer that is different from <see cref=\"Apv\"/> is encountered.\n        /// </summary>\n        /// <remarks>\n        /// If <see langword=\"null\"/>, no action is taken.\n        /// </remarks>\n        public DifferentAppProtocolVersionEncountered DifferentApvEncountered =>\n            _appProtocolVersionOptions.DifferentAppProtocolVersionEncountered;\n\n        /// <summary>\n        /// <para>\n        /// The <see cref=\"TimeSpan\"/> to use as a buffer when decoding <see cref=\"Message\"/>s.\n        /// </para>\n        /// <para>\n        /// Whether a decoded <see cref=\"Message\"/> is valid or not depends on this value:\n        /// <list type=\"bullet\">\n        ///     <item><description>\n        ///         If <see langword=\"null\"/>, there is no restriction\n        ///         on <see cref=\"Message.Timestamp\"/> for received <see cref=\"Message\"/>s.\n        ///     </description></item>\n        ///     <item><description>\n        ///         If not <see langword=\"null\"/>, the absolute difference between the timestamp of\n        ///         a received <see cref=\"Message\"/> and current time should be less than\n        ///         this value.\n        ///     </description></item>\n        /// </list>\n        /// </para>\n        /// </summary>\n        public TimeSpan? MessageTimestampBuffer { get; }\n\n        /// <summary>\n        /// Validates an <see cref=\"AppProtocolVersion\"/> against <see cref=\"Apv\"/>.\n        /// Any <see cref=\"AppProtocolVersion\"/> that is different from <see cref=\"Apv\"/> is\n        /// considered invalid and an <see cref=\"DifferentAppProtocolVersionException\"/> will be\n        /// thrown.\n        /// </summary>\n        /// <param name=\"message\">The <see cref=\"Message\"/> to validate.</param>\n        /// <remarks>\n        /// If <see cref=\"Message.Version\"/> of <paramref name=\"message\"/> is not valid but\n        /// is signed by a trusted signer, then <see cref=\"DifferentApvEncountered\"/> is called.\n        /// </remarks>\n        /// <exception cref=\"NullReferenceException\">Thrown when <see cref=\"Message.Remote\"/> is\n        /// <see langword=\"null\"/> for <paramref name=\"message\"/>.</exception>\n        /// <exception cref=\"DifferentAppProtocolVersionException\">Thrown when\n        /// local version does not match with given <paramref name=\"message\"/>'s\n        /// <see cref=\"Message.Version\"/>.</exception>\n        /// <seealso cref=\"Apv\"/>\n        /// <seealso cref=\"TrustedApvSigners\"/>\n        /// <seealso cref=\"DifferentApvEncountered\"/>\n        public void ValidateAppProtocolVersion(Message message) =>\n            ValidateAppProtocolVersion(Apv, TrustedApvSigners, DifferentApvEncountered, message);\n\n        /// <summary>\n        /// Validates a <see cref=\"DateTimeOffset\"/> timestamp against current timestamp.\n        /// </summary>\n        /// <param name=\"message\">The <see cref=\"Message\"/> to validate.</param>\n        /// <exception cref=\"InvalidMessageTimestampException\">Thrown when the timestamp of\n        /// <paramref name=\"message\"/> is invalid.</exception>\n        /// <seealso cref=\"MessageTimestampBuffer\"/>.\n        public void ValidateTimestamp(Message message) =>\n            ValidateTimestamp(MessageTimestampBuffer, DateTimeOffset.UtcNow, message.Timestamp);\n\n        private static void ValidateAppProtocolVersion(\n            AppProtocolVersion appProtocolVersion,\n            IImmutableSet<PublicKey> trustedAppProtocolVersionSigners,\n            DifferentAppProtocolVersionEncountered differentAppProtocolVersionEncountered,\n            Message message)\n        {\n            if (message.Version.Equals(appProtocolVersion))\n            {\n                return;\n            }\n\n            bool trusted = !trustedAppProtocolVersionSigners.All(\n                publicKey => !message.Version.Verify(publicKey));\n\n            if (trusted)\n            {\n                differentAppProtocolVersionEncountered(\n                    message.Remote, message.Version, appProtocolVersion);\n            }\n\n            if (!trusted || !message.Version.Version.Equals(appProtocolVersion.Version))\n            {\n                throw new DifferentAppProtocolVersionException(\n                    $\"The APV of a received message is invalid:\\n\" +\n                    $\"Expected: APV {appProtocolVersion} with \" +\n                    $\"signature {ByteUtil.Hex(appProtocolVersion.Signature)} by \" +\n                    $\"signer {appProtocolVersion.Signer}\\n\" +\n                    $\"Actual: APV {message.Version} with \" +\n                    $\"signature: {ByteUtil.Hex(message.Version.Signature)} by \" +\n                    $\"signer: {message.Version.Signer}\\n\" +\n                    $\"Signed by a trusted signer: {trusted}\",\n                    appProtocolVersion,\n                    message.Version,\n                    trusted);\n            }\n        }\n\n        private static void ValidateTimestamp(\n            TimeSpan? timestampBuffer,\n            DateTimeOffset currentTimestamp,\n            DateTimeOffset messageTimestamp)\n        {\n            if (timestampBuffer is TimeSpan buffer &&\n                (currentTimestamp - messageTimestamp).Duration() > buffer)\n            {\n                var cultureInfo = CultureInfo.InvariantCulture;\n                throw new InvalidMessageTimestampException(\n                    $\"The timestamp of a received message is invalid:\\n\" +\n                    $\"Message timestamp buffer: {buffer}\\n\" +\n                    $\"Current timestamp: \" +\n                    $\"{currentTimestamp.ToString(TimestampFormat, cultureInfo)}\\n\" +\n                    $\"Message timestamp: \" +\n                    $\"{messageTimestamp.ToString(TimestampFormat, cultureInfo)}\",\n                    messageTimestamp,\n                    buffer,\n                    currentTimestamp);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Net/Messages/NeighborsMsg.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Collections.Immutable;\nusing System.Linq;\nusing Bencodex;\nusing Destructurama.Attributed;\n\nnamespace Libplanet.Net.Messages\n{\n    /// <summary>\n    /// Message containing nearby peers. A reply to <see cref=\"FindNeighborsMsg\"/>.\n    /// </summary>\n    /// <seealso cref=\"FindNeighborsMsg\"/>\n    public class NeighborsMsg : MessageContent\n    {\n        private static readonly Codec Codec = new Codec();\n\n        public NeighborsMsg(IEnumerable<BoundPeer> found)\n        {\n            Found = found.ToImmutableList();\n        }\n\n        public NeighborsMsg(byte[][] dataFrames)\n        {\n            var codec = new Codec();\n            int foundCount = BitConverter.ToInt32(dataFrames[0], 0);\n            Found = dataFrames.Skip(1).Take(foundCount)\n                .Select(ba => new BoundPeer(codec.Decode(ba)))\n                .ToImmutableList();\n        }\n\n        [LogAsScalar]\n        public IImmutableList<BoundPeer> Found { get; }\n\n        public override MessageType Type => MessageType.Neighbors;\n\n        public override IEnumerable<byte[]> DataFrames\n        {\n            get\n            {\n                var frames = new List<byte[]>();\n                frames.Add(BitConverter.GetBytes(Found.Count));\n                frames.AddRange(Found.Select(boundPeer => Codec.Encode(boundPeer.Bencoded)));\n                return frames;\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Net/Messages/NetMQMessageCodec.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing Bencodex;\nusing Libplanet.Crypto;\nusing Libplanet.Net.Transports;\nusing NetMQ;\n\nnamespace Libplanet.Net.Messages\n{\n    public class NetMQMessageCodec : IMessageCodec<NetMQMessage>\n    {\n        public static readonly int CommonFrames =\n            Enum.GetValues(typeof(MessageFrame)).Length;\n\n        private readonly Codec _codec;\n\n        /// <summary>\n        /// Creates a <see cref=\"NetMQMessageCodec\"/> instance.\n        /// </summary>\n        public NetMQMessageCodec()\n        {\n            _codec = new Codec();\n        }\n\n        public enum MessageFrame\n        {\n            /// <summary>\n            /// Frame containing <see cref=\"AppProtocolVersion\"/>.\n            /// </summary>\n            Version = 0,\n\n            /// <summary>\n            /// Frame containing the type of the message.\n            /// </summary>\n            Type = 1,\n\n            /// <summary>\n            /// Frame containing the sender <see cref=\"BoundPeer\"/> of the<see cref=\"Message\"/>.\n            /// </summary>\n            Peer = 2,\n\n            /// <summary>\n            /// Frame containing the datetime when the <see cref=\"Message\"/> is created.\n            /// </summary>\n            Timestamp = 3,\n\n            /// <summary>\n            /// Frame containing signature of the <see cref=\"Message\"/>.\n            /// </summary>\n            Sign = 4,\n        }\n\n        /// <inheritdoc cref=\"IMessageCodec{T}.Encode\"/>\n        public NetMQMessage Encode(\n            Message message,\n            PrivateKey privateKey)\n        {\n            if (!privateKey.PublicKey.Equals(message.Remote.PublicKey))\n            {\n                throw new InvalidCredentialException(\n                    $\"An invalid private key was provided: the provided private key's \" +\n                    $\"expected public key is {message.Remote.PublicKey} \" +\n                    $\"but its actual public key is {privateKey.PublicKey}.\",\n                    message.Remote.PublicKey,\n                    privateKey.PublicKey);\n            }\n\n            var netMqMessage = new NetMQMessage();\n\n            // Write body (by concrete class)\n            foreach (byte[] frame in message.Content.DataFrames)\n            {\n                netMqMessage.Append(frame);\n            }\n\n            // Write headers. (inverse order, version-type-peer-timestamp)\n            netMqMessage.Push(message.Timestamp.Ticks);\n            netMqMessage.Push(_codec.Encode(message.Remote.Bencoded));\n            netMqMessage.Push((int)message.Content.Type);\n            netMqMessage.Push(message.Version.Token);\n\n            // Make and insert signature\n            byte[] signature = privateKey.Sign(netMqMessage.ToByteArray());\n            List<NetMQFrame> frames = netMqMessage.ToList();\n            frames.Insert((int)MessageFrame.Sign, new NetMQFrame(signature));\n            netMqMessage = new NetMQMessage(frames);\n\n            if (message.Identity is { })\n            {\n                netMqMessage.Push(message.Identity);\n            }\n\n            return netMqMessage;\n        }\n\n        /// <inheritdoc cref=\"IMessageCodec{T}.Decode\"/>\n        public Message Decode(NetMQMessage encoded, bool reply)\n        {\n            if (encoded.FrameCount == 0)\n            {\n                throw new ArgumentException(\"Can't parse empty NetMQMessage.\");\n            }\n\n            // (reply == true)            [version, type, peer, timestamp, sign, frames...]\n            // (reply == false) [identity, version, type, peer, timestamp, sign, frames...]\n            NetMQFrame[] remains = reply ? encoded.ToArray() : encoded.Skip(1).ToArray();\n\n            var versionToken = remains[(int)MessageFrame.Version].ConvertToString();\n\n            AppProtocolVersion version = AppProtocolVersion.FromToken(versionToken);\n            var dictionary = _codec.Decode(remains[(int)MessageFrame.Peer].ToByteArray());\n            var remote = new BoundPeer(dictionary);\n\n            var type =\n                (MessageContent.MessageType)remains[(int)MessageFrame.Type].ConvertToInt32();\n            var ticks = remains[(int)MessageFrame.Timestamp].ConvertToInt64();\n            var timestamp = new DateTimeOffset(ticks, TimeSpan.Zero);\n\n            byte[] signature = remains[(int)MessageFrame.Sign].ToByteArray();\n\n            NetMQFrame[] body = remains.Skip(CommonFrames).ToArray();\n\n            MessageContent content = CreateMessage(\n                type,\n                body.Select(frame => frame.ToByteArray()).ToArray());\n\n            var headerWithoutSign = new[]\n            {\n                remains[(int)MessageFrame.Version],\n                remains[(int)MessageFrame.Type],\n                remains[(int)MessageFrame.Peer],\n                remains[(int)MessageFrame.Timestamp],\n            };\n\n            var messageToVerify = headerWithoutSign.Concat(body).ToByteArray();\n            if (!remote.PublicKey.Verify(messageToVerify, signature))\n            {\n                throw new InvalidMessageSignatureException(\n                    \"The signature of an encoded message is invalid.\",\n                    remote,\n                    remote.PublicKey,\n                    messageToVerify,\n                    signature);\n            }\n\n            byte[]? identity = reply ? null : encoded[0].Buffer.ToArray();\n\n            return new Message(content, version, remote, timestamp, identity);\n        }\n\n        internal static MessageContent CreateMessage(\n            MessageContent.MessageType type,\n            byte[][] dataframes)\n        {\n            switch (type)\n            {\n                case MessageContent.MessageType.Ping:\n                    return new PingMsg();\n                case MessageContent.MessageType.Pong:\n                    return new PongMsg();\n                case MessageContent.MessageType.GetBlockHashes:\n                    return new GetBlockHashesMsg(dataframes);\n                case MessageContent.MessageType.TxIds:\n                    return new TxIdsMsg(dataframes);\n                case MessageContent.MessageType.EvidenceIds:\n                    return new EvidenceIdsMsg(dataframes);\n                case MessageContent.MessageType.GetBlocks:\n                    return new GetBlocksMsg(dataframes);\n                case MessageContent.MessageType.GetTxs:\n                    return new GetTxsMsg(dataframes);\n                case MessageContent.MessageType.GetEvidence:\n                    return new GetEvidenceMsg(dataframes);\n                case MessageContent.MessageType.Blocks:\n                    return new BlocksMsg(dataframes);\n                case MessageContent.MessageType.Tx:\n                    return new TxMsg(dataframes);\n                case MessageContent.MessageType.Evidence:\n                    return new EvidenceMsg(dataframes);\n                case MessageContent.MessageType.FindNeighbors:\n                    return new FindNeighborsMsg(dataframes);\n                case MessageContent.MessageType.Neighbors:\n                    return new NeighborsMsg(dataframes);\n                case MessageContent.MessageType.BlockHeaderMessage:\n                    return new BlockHeaderMsg(dataframes);\n                case MessageContent.MessageType.BlockHashes:\n                    return new BlockHashesMsg(dataframes);\n                case MessageContent.MessageType.GetChainStatus:\n                    return new GetChainStatusMsg();\n                case MessageContent.MessageType.ChainStatus:\n                    return new ChainStatusMsg(dataframes);\n                case MessageContent.MessageType.DifferentVersion:\n                    return new DifferentVersionMsg();\n                case MessageContent.MessageType.HaveMessage:\n                    return new HaveMessage(dataframes);\n                case MessageContent.MessageType.WantMessage:\n                    return new WantMessage(dataframes);\n                case MessageContent.MessageType.ConsensusProposal:\n                    return new ConsensusProposalMsg(dataframes);\n                case MessageContent.MessageType.ConsensusVote:\n                    return new ConsensusPreVoteMsg(dataframes);\n                case MessageContent.MessageType.ConsensusCommit:\n                    return new ConsensusPreCommitMsg(dataframes);\n                case MessageContent.MessageType.ConsensusMaj23Msg:\n                    return new ConsensusMaj23Msg(dataframes);\n                case MessageContent.MessageType.ConsensusVoteSetBitsMsg:\n                    return new ConsensusVoteSetBitsMsg(dataframes);\n                case MessageContent.MessageType.ConsensusProposalClaimMsg:\n                    return new ConsensusProposalClaimMsg(dataframes);\n                default:\n                    throw new InvalidCastException($\"Given type {type} is not a valid message.\");\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Net/Messages/PingMsg.cs",
    "content": "using System.Collections.Generic;\n\nnamespace Libplanet.Net.Messages\n{\n    /// <summary>\n    /// Check message to determine peer is alive.\n    /// </summary>\n    /// <seealso cref=\"PongMsg\"/>\n    public class PingMsg : MessageContent\n    {\n        public override MessageType Type => MessageType.Ping;\n\n        public override IEnumerable<byte[]> DataFrames => new byte[][] { };\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Net/Messages/PongMsg.cs",
    "content": "using System.Collections.Generic;\n\nnamespace Libplanet.Net.Messages\n{\n    /// <summary>\n    /// A reply to <see cref=\"PingMsg\"/>.\n    /// </summary>\n    /// <seealso cref=\"PingMsg\"/>\n    public class PongMsg : MessageContent\n    {\n        public override MessageType Type => MessageType.Pong;\n\n        public override IEnumerable<byte[]> DataFrames => new byte[][] { };\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Net/Messages/TxIdsMsg.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing Libplanet.Types.Tx;\n\nnamespace Libplanet.Net.Messages\n{\n    internal class TxIdsMsg : MessageContent\n    {\n        public TxIdsMsg(IEnumerable<TxId> txIds)\n        {\n            Ids = txIds;\n        }\n\n        public TxIdsMsg(byte[][] dataFrames)\n        {\n            int txCount = BitConverter.ToInt32(dataFrames[0], 0);\n            Ids = dataFrames\n                .Skip(1).Take(txCount)\n                .Select(ba => new TxId(ba))\n                .ToList();\n        }\n\n        public IEnumerable<TxId> Ids { get; }\n\n        public override MessageType Type => MessageType.TxIds;\n\n        public override IEnumerable<byte[]> DataFrames\n        {\n            get\n            {\n                var frames = new List<byte[]>();\n                frames.Add(BitConverter.GetBytes(Ids.Count()));\n                frames.AddRange(Ids.Select(id => id.ToByteArray()));\n                return frames;\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Net/Messages/TxMsg.cs",
    "content": "using System.Collections.Generic;\n\nnamespace Libplanet.Net.Messages\n{\n    internal class TxMsg : MessageContent\n    {\n        public TxMsg(byte[] payload)\n        {\n            Payload = payload;\n        }\n\n        public TxMsg(byte[][] dataFrames)\n        {\n            Payload = dataFrames[0];\n        }\n\n        public byte[] Payload { get; }\n\n        public override MessageType Type => MessageType.Tx;\n\n        public override IEnumerable<byte[]> DataFrames => new[] { Payload, };\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Net/Messages/WantMessage.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Linq;\n\nnamespace Libplanet.Net.Messages\n{\n    /// <summary>\n    /// List of message IDs that the peer want to have.\n    /// </summary>\n    /// <seealso cref=\"HaveMessage\"/>\n    public class WantMessage : MessageContent\n    {\n        public WantMessage(MessageId[] messageIds)\n        {\n            Ids = messageIds;\n        }\n\n        public WantMessage(byte[][] dataFrames)\n        {\n            int msgCount = BitConverter.ToInt32(dataFrames[0], 0);\n            Ids = dataFrames\n                .Skip(1).Take(msgCount)\n                .Select(ba => new MessageId(ba))\n                .ToList();\n        }\n\n        public IEnumerable<MessageId> Ids { get; }\n\n        public override MessageType Type => MessageType.WantMessage;\n\n        public override IEnumerable<byte[]> DataFrames\n        {\n            get\n            {\n                var frames = new List<byte[]>();\n                frames.Add(BitConverter.GetBytes(Ids.Count()));\n                frames.AddRange(Ids.Select(id => id.ToByteArray()));\n                return frames;\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Net/NetMQFrameExtensions.cs",
    "content": "using System.Collections.Generic;\nusing System.IO;\nusing System.Security.Cryptography;\nusing Libplanet.Common;\nusing Libplanet.Types.Blocks;\nusing Libplanet.Types.Tx;\nusing NetMQ;\n\nnamespace Libplanet.Net\n{\n    internal static class NetMQFrameExtensions\n    {\n        public static HashDigest<T> ConvertToHashDigest<T>(\n            this NetMQFrame frame)\n            where T : HashAlgorithm\n        {\n            return new HashDigest<T>(frame.ToByteArray());\n        }\n\n        public static BlockHash ConvertToBlockHash(this NetMQFrame frame) =>\n            new BlockHash(frame.ToByteArray());\n\n        public static TxId ConvertToTxId(this NetMQFrame frame)\n        {\n            return new TxId(frame.ToByteArray());\n        }\n\n        public static byte[] ToByteArray(this IEnumerable<NetMQFrame> frames)\n        {\n            using var stream = new MemoryStream();\n            foreach (NetMQFrame frame in frames)\n            {\n                byte[] bytes = frame.ToByteArray();\n                stream.Write(bytes, 0, bytes.Length);\n            }\n\n            return stream.ToArray();\n        }\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Net/NoSwarmContextException.cs",
    "content": "using System;\n\nnamespace Libplanet.Net\n{\n    public class NoSwarmContextException : SwarmException\n    {\n        public NoSwarmContextException()\n        {\n        }\n\n        public NoSwarmContextException(string message)\n            : base(message)\n        {\n        }\n\n        public NoSwarmContextException(string message, Exception innerException)\n            : base(message, innerException)\n        {\n        }\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Net/NullableSemaphore.cs",
    "content": "using System;\nusing System.Threading;\nusing System.Threading.Tasks;\n\nnamespace Libplanet.Net\n{\n    internal class NullableSemaphore : IDisposable\n    {\n        private readonly SemaphoreSlim? _sema;\n\n        public NullableSemaphore(int maxCount)\n        {\n            _sema = maxCount > 0\n                ? new SemaphoreSlim(maxCount, maxCount)\n                : null;\n        }\n\n        public void Dispose()\n        {\n            _sema?.Dispose();\n        }\n\n        public async Task<bool> WaitAsync(TimeSpan timeout, CancellationToken cancellationToken)\n        {\n            if (_sema is { } sema)\n            {\n                return await sema.WaitAsync(timeout, cancellationToken).ConfigureAwait(false);\n            }\n\n            return true;\n        }\n\n        public int Release()\n        {\n            if (_sema is { } sema)\n            {\n                return sema.Release();\n            }\n\n            return -1;\n        }\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Net/Options/AppProtocolVersionOptions.cs",
    "content": "using System.Collections.Immutable;\nusing Libplanet.Crypto;\nusing Libplanet.Net.Messages;\n\nnamespace Libplanet.Net.Options\n{\n    /// <summary>\n    /// Various options for a <see cref=\"Swarm\"/>'s\n    /// <see cref=\"Net.AppProtocolVersion\"/>.\n    /// </summary>\n    public class AppProtocolVersionOptions\n    {\n        /// <summary>\n        /// The application protocol version to comply.\n        /// </summary>\n        public AppProtocolVersion AppProtocolVersion { get; set; } = default;\n\n        /// <summary>\n        /// The set of <see cref=\"PublicKey\"/>s to trust when a node encounters\n        /// a <see cref=\"Message\"/> with an <see cref=\"Net.AppProtocolVersion\"/> that is different\n        /// from <see cref=\"AppProtocolVersion\"/>.  Any <see cref=\"Message\"/> with an untrusted\n        /// <see cref=\"Net.AppProtocolVersion\"/> is ignored by the node.  Set to an\n        /// empty set of <see cref=\"PublicKey\"/>s by default, i.e. not to trust any\n        /// <see cref=\"Message\"/> with a different <see cref=\"Net.AppProtocolVersion\"/>.\n        /// </summary>\n        public IImmutableSet<PublicKey> TrustedAppProtocolVersionSigners { get; set; } =\n            ImmutableHashSet<PublicKey>.Empty;\n\n        /// <summary>\n        /// The callback triggered when a node encounters\n        /// an <see cref=\"Net.AppProtocolVersion\"/> that is different from\n        /// <see cref=\"AppProtocolVersion\"/> that is signed by\n        /// a <em>trusted party</em>, that is, one of\n        /// <see cref=\"TrustedAppProtocolVersionSigners\"/>.  Does nothing by default.\n        /// </summary>\n        public DifferentAppProtocolVersionEncountered\n            DifferentAppProtocolVersionEncountered { get; set; } =\n                (peer, peerVersion, localVersion) => { };\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Net/Options/BootstrapOptions.cs",
    "content": "using System;\nusing System.Collections.Immutable;\nusing Libplanet.Net.Messages;\nusing Libplanet.Net.Protocols;\nusing Libplanet.Net.Transports;\n\nnamespace Libplanet.Net.Options\n{\n    public class BootstrapOptions\n    {\n        public const int DefaultDialTimeout = 15;\n\n        /// <summary>\n        /// Determines how long an <see cref=\"ITransport\"/> should wait before timimg out\n        /// when dialing peers for either <see cref=\"PongMsg\"/>, <see cref=\"NeighborsMsg\"/>,\n        /// or <see cref=\"ChainStatusMsg\"/> during a bootstrapping phase.  Generally, a more relaxed\n        /// <see cref=\"TimeSpan\"/> is used compared to <see cref=\"TimeoutOptions.DialTimeout\"/>.\n        /// Set to <see cref=\"DefaultDialTimeout\"/> seconds by default.\n        /// </summary>\n        /// <seealso cref=\"TimeoutOptions.DialTimeout\"/>\n        public TimeSpan DialTimeout { get; set; }\n            = TimeSpan.FromSeconds(DefaultDialTimeout);\n\n        /// <summary>\n        /// The list of seed peers to connect to.\n        /// </summary>\n        public ImmutableList<BoundPeer> SeedPeers { get; set; } = ImmutableList<BoundPeer>.Empty;\n\n        /// <summary>\n        /// Determines the depth of the search when discovering neighbors for the local node.\n        /// </summary>\n        public int SearchDepth { get; set; } = Kademlia.MaxDepth;\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Net/Options/HostOptions.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Collections.Immutable;\nusing System.Linq;\n\nnamespace Libplanet.Net.Options\n{\n    /// <summary>\n    /// Various options for determining <see cref=\"Swarm\"/>'s <see cref=\"BoundPeer\"/> identity.\n    /// </summary>\n    public class HostOptions\n    {\n        public HostOptions(\n            string? host,\n            IEnumerable<IceServer> iceServers,\n            int port = 0)\n        {\n            if (port < 0)\n            {\n                throw new ArgumentException($\"Given {nameof(port)} cannot be negative: {port}\");\n            }\n            else if (!(host is { } ^ iceServers.Any()))\n            {\n                throw new ArgumentException(\n                    $\"Either {nameof(host)} must be null or {nameof(iceServers)} must be empty.\");\n            }\n\n            Host = host;\n            IceServers = iceServers.ToImmutableList();\n            Port = port;\n        }\n\n        /// <summary>\n        /// The hostname to be a part of a public endpoint that peers may use when\n        /// they connect to this node.  This is set to <see langword=\"null\"/> when\n        /// a non-empty <see cref=\"IceServers\"/> is provided.\n        /// </summary>\n        public string? Host { get; }\n\n        /// <summary>\n        /// The set of\n        /// <a href=\"https://en.wikipedia.org/wiki/Interactive_Connectivity_Establishment\">ICE</a>\n        /// servers to use for TURN/STUN to traverse NAT.  This is empty when <see cref=\"Host\"/>\n        /// is provided.\n        /// </summary>\n        public IReadOnlyList<IceServer> IceServers { get; }\n\n        /// <summary>\n        /// The port number to use for the host.  If set to zero, a free port will be assigned.\n        /// </summary>\n        public int Port { get; }\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Net/Options/PreloadOptions.cs",
    "content": "using System;\nusing Libplanet.Net.Messages;\nusing Libplanet.Net.Transports;\n\nnamespace Libplanet.Net.Options\n{\n    public class PreloadOptions\n    {\n        public const int DefaultDialTimeout = 5;\n        public const long DefaultTipDeltaThreshold = 25L;\n\n        /// <summary>\n        /// Determines how long an <see cref=\"ITransport\"/> should wait before timimg out\n        /// when dialing peers for either <see cref=\"PongMsg\"/>, <see cref=\"NeighborsMsg\"/>,\n        /// or <see cref=\"ChainStatusMsg\"/> during a preloading phase.  Generally, a more relaxed\n        /// <see cref=\"TimeSpan\"/> is used compared to <see cref=\"TimeoutOptions.DialTimeout\"/>.\n        /// Set to <see cref=\"DefaultDialTimeout\"/> seconds by default.\n        /// </summary>\n        /// <seealso cref=\"TimeoutOptions.DialTimeout\"/>\n        public TimeSpan DialTimeout { get; set; }\n            = TimeSpan.FromSeconds(DefaultDialTimeout);\n\n        /// <summary>\n        /// Determines when to stop preloading. Preloading is considered complete when\n        /// the delta between the local node's tip index and the best known tip\n        /// index is less than or equal to this value.  Set to\n        /// <see cref=\"DefaultTipDeltaThreshold\"/> by default. </summary>\n        public long TipDeltaThreshold { get; set; } = DefaultTipDeltaThreshold;\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Net/Options/SwarmOptions.cs",
    "content": "using System;\nusing System.Collections.Immutable;\nusing Libplanet.Blockchain;\nusing Libplanet.Net.Messages;\nusing Libplanet.Net.Protocols;\nusing Libplanet.Net.Transports;\nusing Libplanet.Types.Tx;\n\nnamespace Libplanet.Net.Options\n{\n    public class SwarmOptions\n    {\n        /// <summary>\n        /// The lifespan of block demand.\n        /// </summary>\n        public TimeSpan BlockDemandLifespan { get; set; } = TimeSpan.FromMinutes(1);\n\n        /// <summary>\n        /// The amount of difference in <see cref=\"TimeSpan\"/> allowed from current local time for\n        /// a received <see cref=\"Message\"/>.\n        /// </summary>\n        public TimeSpan? MessageTimestampBuffer { get; set; } = TimeSpan.FromSeconds(60);\n\n        /// <summary>\n        /// The frequency of <see cref=\"IProtocol.RefreshTableAsync\" />.\n        /// </summary>\n        public TimeSpan RefreshPeriod { get; set; } = TimeSpan.FromSeconds(10);\n\n        /// <summary>\n        /// The lifespan of <see cref=\"BoundPeer\"/> in routing table.\n        /// <seealso cref=\"IProtocol.RefreshTableAsync\" />\n        /// </summary>\n        public TimeSpan RefreshLifespan { get; set; } = TimeSpan.FromSeconds(60);\n\n        /// <summary>\n        /// The list of <see cref=\"BoundPeer\"/>s to keep in routing table permanently.\n        /// The <see cref=\"BoundPeer\"/>s in the list will be maintained periodically within\n        /// <see cref=\"StaticPeersMaintainPeriod\"/>.\n        /// </summary>\n        public IImmutableSet<BoundPeer> StaticPeers { get; set; } =\n            ImmutableHashSet<BoundPeer>.Empty;\n\n        /// <summary>\n        /// The period of <c>Task</c> maintains static peer.\n        /// </summary>\n        /// <seealso cref=\"StaticPeers\"/>\n        public TimeSpan StaticPeersMaintainPeriod { get; set; } = TimeSpan.FromSeconds(10);\n\n        /// <summary>\n        /// The minimum number to select from routing table when broadcast messages.\n        /// It is 10 by default.\n        /// </summary>\n        public int MinimumBroadcastTarget { get; set; } = 10;\n\n        /// <summary>\n        /// Determines how often <see cref=\"Swarm\"/> broadcasts <see cref=\"BlockHeaderMsg\"/>\n        /// to its peers.\n        /// </summary>\n        /// <remarks>\n        /// Broadcasts are also made whenever <see cref=\"BlockChain.Tip\"/> changes in addition\n        /// to regular broadcasts determined by this option.\n        /// </remarks>\n        public TimeSpan BlockBroadcastInterval { get; set; }\n            = TimeSpan.FromMilliseconds(15_000);\n\n        /// <summary>\n        /// Determines how often <see cref=\"Swarm\"/> broadcasts <see cref=\"TxIdsMsg\"/>\n        /// to its peers.\n        /// </summary>\n        /// <remarks>\n        /// Broadcasts are also made whenever <see cref=\"Transaction\"/> is staged in addition\n        /// to regular broadcasts determined by this option.\n        /// </remarks>\n        public TimeSpan TxBroadcastInterval { get; set; }\n            = TimeSpan.FromMilliseconds(5_000);\n\n        /// <summary>\n        /// The number of buckets of the Kademlia based routing table.\n        /// </summary>\n        /// <seealso cref=\"RoutingTable\"/>\n        public int TableSize { get; set; } = Kademlia.TableSize;\n\n        /// <summary>\n        /// The size of each bucket of the Kademlia based routing table.\n        /// </summary>\n        /// <seealso cref=\"RoutingTable\"/>\n        public int BucketSize { get; set; } = Kademlia.BucketSize;\n\n        /// <summary>\n        /// The maximum number of peers to poll blocks.\n        /// </summary>\n        public int MaximumPollPeers { get; set; } = int.MaxValue;\n\n        /// <summary>\n        /// The lifespan of the <see cref=\"BlockChain.Tip\"/>.  When the tip has not been updated\n        /// for the configured lifespan, <see cref=\"Swarm\"/> pulls new blocks from neighbor\n        /// peers.\n        /// </summary>\n        public TimeSpan TipLifespan { get; set; } = TimeSpan.FromSeconds(60);\n\n        /// <summary>\n        /// Various options for the default bootstrap behavior of <see cref=\"Swarm\"/>.\n        /// </summary>\n        public BootstrapOptions BootstrapOptions { get; set; } = new BootstrapOptions();\n\n        /// <summary>\n        /// Various options for the default preload behavior of <see cref=\"Swarm\"/>.\n        /// </summary>\n        public PreloadOptions PreloadOptions { get; set; } = new PreloadOptions();\n\n        /// <summary>\n        /// Various timeout options for sending and receiving <see cref=\"Message\"/>s through\n        /// an <see cref=\"ITransport\"/>.\n        /// </summary>\n        public TimeoutOptions TimeoutOptions { get; set; } = new TimeoutOptions();\n\n        /// <summary>\n        /// Various task spawning regulations for handling received <see cref=\"Message\"/>s\n        /// through an <see cref=\"ITransport\"/>.\n        /// </summary>\n        public TaskRegulationOptions TaskRegulationOptions { get; set; } =\n            new TaskRegulationOptions();\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Net/Options/TaskRegulationOptions.cs",
    "content": "using Libplanet.Net.Messages;\n\nnamespace Libplanet.Net.Options\n{\n    public class TaskRegulationOptions\n    {\n        /// <summary>\n        /// Max limit to spawn a task that handles <see cref=\"GetBlocksMsg\"/> message.\n        /// If 0 is given, task spawning is not limited.\n        /// Set to 0 by default.\n        /// </summary>\n        public int MaxTransferBlocksTaskCount { get; set; } = 0;\n\n        /// <summary>\n        /// Max limit to spawn a task that handles <see cref=\"GetTxsMsg\"/> message.\n        /// If 0 is given, task spawning is not limited.\n        /// Set to 0 by default.\n        /// </summary>\n        public int MaxTransferTxsTaskCount { get; set; } = 0;\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Net/Options/TimeoutOptions.cs",
    "content": "using System;\nusing Libplanet.Net.Messages;\nusing Libplanet.Net.Transports;\nusing Libplanet.Types.Blocks;\nusing Libplanet.Types.Tx;\n\nnamespace Libplanet.Net.Options\n{\n    /// <summary>\n    /// Various timeout options for sending and receiving <see cref=\"Message\"/>s through\n    /// an <see cref=\"ITransport\"/>. Each timeout determines how long an <see cref=\"ITransport\"/>\n    /// should wait for all expected responses to arrive before giving up after sending\n    /// a <see cref=\"Message\"/>.\n    /// </summary>\n    public class TimeoutOptions\n    {\n        public const int DefaultMaxTimeout = 150;\n        public const int DefaultDialTimeout = 1;\n        public const int DefaultGetBlockHashesTimeout = 30;\n        public const int DefaultGetBlocksBaseTimeout = 15;\n        public const int DefaultGetBlocksPerBlockHashTimeout = 1;\n        public const int DefaultGetTxsBaseTimeout = 3;\n        public const int DefaultGetTxsPerTxIdTimeout = 1;\n\n        /// <summary>\n        /// The maximum timeout used in <see cref=\"Swarm\"/>. This is a hard limit for\n        /// all <see cref=\"Message\"/>s.  Set to <see cref=\"DefaultMaxTimeout\"/> seconds\n        /// by default.\n        /// </summary>\n        public TimeSpan MaxTimeout { get; set; }\n            = TimeSpan.FromSeconds(DefaultMaxTimeout);\n\n        /// <summary>\n        /// Determines how long an <see cref=\"ITransport\"/> should wait before timing out\n        /// when dialing peers for either <see cref=\"PongMsg\"/>, <see cref=\"NeighborsMsg\"/>,\n        /// or <see cref=\"ChainStatusMsg\"/> for a long running process.\n        /// Set to <see cref=\"DefaultDialTimeout\"/> seconds by default.\n        /// </summary>\n        /// <seealso cref=\"BootstrapOptions.DialTimeout\"/>\n        /// <seealso cref=\"PreloadOptions.DialTimeout\"/>\n        public TimeSpan DialTimeout { get; set; }\n            = TimeSpan.FromSeconds(DefaultDialTimeout);\n\n        /// <summary>\n        /// The timeout used when sending a request with <see cref=\"GetBlockHashesMsg\"/>\n        /// to receive a <see cref=\"BlockHashesMsg\"/> message.\n        /// Set to <see cref=\"DefaultGetBlockHashesTimeout\"/> seconds by default.\n        /// </summary>\n        public TimeSpan GetBlockHashesTimeout { get; set; }\n            = TimeSpan.FromSeconds(DefaultGetBlockHashesTimeout);\n\n        /// <summary>\n        /// The base timeout used when sending a request with <see cref=\"GetBlocksMsg\"/>\n        /// to receive <see cref=\"BlocksMsg\"/> messages.\n        /// Set to <see cref=\"DefaultGetBlocksBaseTimeout\"/> seconds by default.\n        /// </summary>\n        /// <seealso cref=\"GetBlocksPerBlockHashTimeout\"/>\n        public TimeSpan GetBlocksBaseTimeout { get; set; }\n            = TimeSpan.FromSeconds(DefaultGetBlocksBaseTimeout);\n\n        /// <summary>\n        /// The additional amount to wait for each <see cref=\"BlockHash\"/> in\n        /// <see cref=\"GetBlocksMsg\"/> to receive <see cref=\"BlocksMsg\"/> messages.\n        /// Set to <see cref=\"DefaultGetBlocksPerBlockHashTimeout\"/> seconds by default.\n        /// </summary>\n        /// <seealso cref=\"GetBlocksBaseTimeout\"/>\n        public TimeSpan GetBlocksPerBlockHashTimeout { get; set; }\n            = TimeSpan.FromSeconds(DefaultGetBlocksPerBlockHashTimeout);\n\n        /// <summary>\n        /// The base timeout used when sending a request with <see cref=\"GetTxsMsg\"/>\n        /// to receive <see cref=\"Transaction\"/> messages.\n        /// Set to <see cref=\"DefaultGetTxsBaseTimeout\"/> seconds by default.\n        /// </summary>\n        /// <seealso cref=\"GetTxsPerTxIdTimeout\"/>\n        public TimeSpan GetTxsBaseTimeout { get; set; }\n            = TimeSpan.FromSeconds(DefaultGetTxsBaseTimeout);\n\n        /// <summary>\n        /// The additional amount to wait for each <see cref=\"TxId\"/> in <see cref=\"GetTxsMsg\"/>\n        /// to receive <see cref=\"Transaction\"/> messages.\n        /// Set to <see cref=\"DefaultGetTxsPerTxIdTimeout\"/> seconds by default.\n        /// </summary>\n        /// <seealso cref=\"GetTxsBaseTimeout\"/>\n        public TimeSpan GetTxsPerTxIdTimeout { get; set; }\n            = TimeSpan.FromSeconds(DefaultGetTxsPerTxIdTimeout);\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Net/PeerChainState.cs",
    "content": "namespace Libplanet.Net\n{\n    /// <summary>\n    /// The blockchain state of <see cref=\"BoundPeer\"/>.\n    /// </summary>\n    public readonly struct PeerChainState\n    {\n        public PeerChainState(BoundPeer peer, long tipIndex)\n        {\n            Peer = peer;\n            TipIndex = tipIndex;\n        }\n\n        /// <summary>\n        /// The peer with chain.\n        /// </summary>\n        public BoundPeer Peer { get; }\n\n        /// <summary>\n        /// The blockchain tip of the <see cref=\"BoundPeer\"/>.\n        /// </summary>\n        public long TipIndex { get; }\n\n        /// <inheritdoc />\n        public override string ToString()\n        {\n            return $\"{Peer}, {TipIndex}\";\n        }\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Net/PeerNotFoundException.cs",
    "content": "using System;\n\nnamespace Libplanet.Net\n{\n    public class PeerNotFoundException : SwarmException\n    {\n        public PeerNotFoundException()\n        {\n        }\n\n        public PeerNotFoundException(string message)\n            : base(message)\n        {\n        }\n\n        public PeerNotFoundException(string message, Exception innerException)\n            : base(message, innerException)\n        {\n        }\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Net/PeerState.cs",
    "content": "using System;\n\nnamespace Libplanet.Net\n{\n    /// <summary>\n    /// Represents a <see cref=\"BoundPeer\"/>'s state in the routing table.\n    /// </summary>\n    public class PeerState\n    {\n        internal PeerState(BoundPeer peer, DateTimeOffset lastUpdated)\n        {\n            Peer = peer;\n            LastUpdated = lastUpdated;\n            LastChecked = null;\n            Latency = null;\n        }\n\n        /// <summary>\n        /// <see cref=\"BoundPeer\"/> of the state.\n        /// </summary>\n        public BoundPeer Peer { get; set; }\n\n        /// <summary>\n        /// Last time messages were exchanged.\n        /// </summary>\n        public DateTimeOffset LastUpdated { get; internal set; }\n\n        /// <summary>\n        /// Last time the peer was verified.\n        /// </summary>\n        public DateTimeOffset? LastChecked { get; internal set; }\n\n        /// <summary>\n        /// Delay of verification in milliseconds.\n        /// </summary>\n        public TimeSpan? Latency { get; internal set; }\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Net/Protocols/IProtocol.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing Libplanet.Net.Messages;\n\nnamespace Libplanet.Net.Protocols\n{\n    /// <summary>\n    /// An interface of protocol to discover peers from the distributed network.\n    /// </summary>\n    public interface IProtocol\n    {\n        /// <summary>\n        /// Conducts peer discovery for given <paramref name=\"bootstrapPeers\"/>.\n        /// </summary>\n        /// <param name=\"bootstrapPeers\">A <see cref=\"IEnumerable{T}\"/> of <see cref=\"BoundPeer\"/>s\n        /// to bootstrap.</param>\n        /// <param name=\"dialTimeout\">The timeout used when waiting a reply for either\n        /// <see cref=\"PingMsg\"/> or <see cref=\"FindNeighborsMsg\"/>.\n        /// If <see langword=\"null\"/> is given, the task never halts by itself\n        /// even no any response was given from the target seed.</param>\n        /// <param name=\"depth\">Recursive operation depth to search peers from network.</param>\n        /// <param name=\"cancellationToken\">\n        /// A cancellation token used to propagate notification that this\n        /// operation should be canceled.</param>\n        /// <returns>An awaitable task without value.</returns>\n        Task BootstrapAsync(\n            IEnumerable<BoundPeer> bootstrapPeers,\n            TimeSpan? dialTimeout,\n            int depth,\n            CancellationToken cancellationToken);\n\n        /// <summary>\n        /// Tries to add given <paramref name=\"peers\"/> to routing table\n        /// by sending <see cref=\"PingMsg\"/>.\n        /// </summary>\n        /// <param name=\"peers\">The peers to add.</param>\n        /// <param name=\"timeout\">A timeout of waiting for the reply of <see cref=\"PingMsg\"/>\n        /// message sent to <paramref name=\"peers\"/>.\n        /// If <see langword=\"null\"/> is given, task never halts by itself\n        /// even the target peer gives no any response.</param>\n        /// <param name=\"cancellationToken\">\n        /// A cancellation token used to propagate notification that this\n        /// operation should be canceled.</param>\n        /// <returns>An awaitable task without value.</returns>\n        Task AddPeersAsync(\n            IEnumerable<BoundPeer> peers,\n            TimeSpan? timeout,\n            CancellationToken cancellationToken);\n\n        /// <summary>\n        /// Checks whether <see cref=\"BoundPeer\"/>s in <see cref=\"RoutingTable\"/> is online by\n        /// sending <see cref=\"PingMsg\"/>.\n        /// </summary>\n        /// <param name=\"maxAge\">Maximum age of peer to validate.</param>\n        /// <param name=\"cancellationToken\">A cancellation token used to propagate notification\n        /// that this operation should be canceled.</param>\n        /// <returns>An awaitable task without value.</returns>\n        Task RefreshTableAsync(TimeSpan maxAge, CancellationToken cancellationToken);\n\n        /// <summary>\n        /// Reconstructs network connection between peers on network.\n        /// </summary>\n        /// <param name=\"depth\">Recursive operation depth to search peers from network.</param>\n        /// <param name=\"cancellationToken\">A cancellation token used to propagate notification\n        /// that this operation should be canceled.</param>\n        /// <returns>An awaitable task without value.</returns>\n        Task RebuildConnectionAsync(int depth, CancellationToken cancellationToken);\n\n        /// <summary>\n        /// Checks the <see cref=\"KBucket\"/> in the <see cref=\"RoutingTable\"/> and if\n        /// there is an empty <see cref=\"KBucket\"/>, fill it with <see cref=\"BoundPeer\"/>s\n        /// in the <see cref=\"KBucket.ReplacementCache\"/>.\n        /// </summary>\n        /// <param name=\"cancellationToken\">A cancellation token used to propagate notification\n        /// that this operation should be canceled.</param>\n        /// <returns>An awaitable task without value.</returns>\n        Task CheckReplacementCacheAsync(CancellationToken cancellationToken);\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Net/Protocols/IRoutingTable.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing Libplanet.Crypto;\n\nnamespace Libplanet.Net.Protocols\n{\n    public interface IRoutingTable\n    {\n        /// <summary>\n        /// The number of peers in the table.\n        /// </summary>\n        int Count { get; }\n\n        /// <summary>\n        /// An <see cref=\"IReadOnlyList{T}\"/> of peers in the table.\n        /// </summary>\n        IReadOnlyList<BoundPeer> Peers { get; }\n\n        /// <summary>\n        /// Adds the <paramref name=\"peer\"/> to the table.\n        /// </summary>\n        /// <param name=\"peer\">The <see cref=\"BoundPeer\"/> to add.</param>\n        /// <exception cref=\"ArgumentException\">Thrown when <paramref name=\"peer\"/>'s\n        /// <see cref=\"Address\"/> is equal to the <see cref=\"Address\"/> of self.</exception>\n        void AddPeer(BoundPeer peer);\n\n        /// <summary>\n        /// Removes the <paramref name=\"peer\"/> to the table.\n        /// </summary>\n        /// <param name=\"peer\">The <see cref=\"BoundPeer\"/> to remove.</param>\n        /// <returns><see langword=\"true\"/> if the <paramref name=\"peer\"/> is successfully\n        /// removed from <see cref=\"IRoutingTable\"/>.</returns>\n        /// <exception cref=\"ArgumentException\">Thrown when <paramref name=\"peer\"/>'s\n        /// <see cref=\"Address\"/> is equal to the <see cref=\"Address\"/> of self.</exception>\n        bool RemovePeer(BoundPeer peer);\n\n        /// <summary>\n        /// Determines whether the <see cref=\"IRoutingTable\"/> contains the specified key.\n        /// </summary>\n        /// <param name=\"peer\">Key to locate in the <see cref=\"IRoutingTable\"/>.</param>\n        /// <returns><see langword=\"true\"/> if the <see cref=\"IRoutingTable\" /> contains\n        /// an element with the specified key; otherwise, <see langword=\"false\"/>.</returns>\n        bool Contains(BoundPeer peer);\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Net/Protocols/KBucket.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing Libplanet.Crypto;\nusing Serilog;\n\nnamespace Libplanet.Net.Protocols\n{\n    internal class KBucket\n    {\n        private readonly int _size;\n        private readonly Random _random;\n        private readonly KBucketDictionary _peerStates;\n        private readonly KBucketDictionary _replacementCache;\n        private readonly ILogger _logger;\n\n        public KBucket(int size, Random random, ILogger logger)\n        {\n            if (size <= 0)\n            {\n                throw new ArgumentOutOfRangeException(\n                    nameof(size),\n                    $\"The value of {nameof(size)} must be positive.\");\n            }\n\n            _size = size;\n            _random = random;\n            _logger = logger;\n            _peerStates = new KBucketDictionary(_size, false, logger);\n            _replacementCache = new KBucketDictionary(_size, true, logger);\n        }\n\n        public int Count => _peerStates.Count;\n\n        public bool IsEmpty => _peerStates.Count == 0;\n\n        public bool IsFull => _peerStates.Count >= _size;\n\n        /// <summary>\n        /// The <see cref=\"PeerState\"/> used most recently. If the bucket is empty,\n        /// this is <see langword=\"null\"/>.\n        /// </summary>\n        public PeerState? Head => _peerStates.Head;\n\n        /// <summary>\n        /// The <see cref=\"PeerState\"/> used longest time ago. If the bucket is empty,\n        /// this is <see langword=\"null\"/>.\n        /// </summary>\n        public PeerState? Tail => _peerStates.Tail;\n\n        public IEnumerable<BoundPeer> Peers => _peerStates.Peers;\n\n        public IEnumerable<PeerState> PeerStates => _peerStates.PeerStates;\n\n        // replacement candidate stored in this cache when\n        // the bucket is full and least recently used peer responds.\n        public KBucketDictionary ReplacementCache => _replacementCache;\n\n        public void AddPeer(BoundPeer peer, DateTimeOffset updated)\n        {\n            if (!_peerStates.AddOrUpdate(peer, new PeerState(peer, updated)))\n            {\n                ReplacementCache.AddOrUpdate(peer, new PeerState(peer, updated));\n            }\n        }\n\n        /// <summary>\n        /// Checks whether the bucket contains given <paramref name=\"peer\"/>.\n        /// </summary>\n        /// <param name=\"peer\">The <see cref=\"BoundPeer\"/> to check.</param>\n        /// <returns><see langword=\"true\"/> if the bucket contains <paramref name=\"peer\"/>,\n        /// <see langword=\"false\"/> otherwise.</returns>\n        public bool Contains(BoundPeer peer)\n        {\n            return _peerStates.Contains(peer.Address);\n        }\n\n        /// <summary>\n        /// Empties the bucket.\n        /// </summary>\n        public void Clear()\n        {\n            _peerStates.Clear();\n        }\n\n        /// <summary>\n        /// Removes given <paramref name=\"peer\"/> from the bucket.\n        /// </summary>\n        /// <param name=\"peer\">The <see cref=\"BoundPeer\"/> to remove.</param>\n        /// <returns>\n        /// <see langword=\"true\"/> if <paramref name=\"peer\"/> was removed,\n        /// <see langword=\"false\"/> otherwise.</returns>\n        public bool RemovePeer(BoundPeer peer)\n        {\n            if (_peerStates.Remove(peer.Address))\n            {\n                _logger.Verbose(\"Removed peer {Peer} from bucket\", peer);\n                return true;\n            }\n            else\n            {\n                _logger.Verbose(\"Failed to remove peer {Peer} from bucket\", peer);\n                return false;\n            }\n        }\n\n        /// <summary>\n        /// Selects a random <see cref=\"BoundPeer\"/> in the bucket excluding\n        /// <paramref name=\"except\"/>.\n        /// </summary>\n        /// <param name=\"except\">The <see cref=\"BoundPeer\"/> to exclude when selecting.</param>\n        /// <returns>\n        /// A randomly selected <see cref=\"BoundPeer\"/> in the bucket excluding\n        /// <paramref name=\"except\"/>. If no <see cref=\"BoundPeer\"/> can be selected,\n        /// <see langword=\"null\"/> is returned.\n        /// </returns>\n        public BoundPeer? GetRandomPeer(Address? except = null)\n        {\n            List<BoundPeer> peers = _peerStates.Peers\n                .Where(p => (!(except is Address e) || !p.Address.Equals(e)))\n                .ToList();\n            return peers.Count > 0 ? peers[_random.Next(peers.Count)] : null;\n        }\n\n        public void Check(BoundPeer peer, DateTimeOffset start, DateTimeOffset end)\n        {\n            if (_peerStates.Get(peer.Address) is PeerState peerState)\n            {\n                peerState.LastChecked = start;\n                peerState.Latency = end - start;\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Net/Protocols/KBucketDictionary.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Threading;\nusing Libplanet.Crypto;\nusing Serilog;\n\nnamespace Libplanet.Net.Protocols\n{\n    /// <summary>\n    /// <para>\n    /// An internal dictionary with a size limit used for <see cref=\"KBucket\"/>s.\n    /// </para>\n    /// <para>\n    /// Purposely designed with the following features:\n    /// <list type=\"bullet\">\n    ///     <item><description>\n    ///         Fixed maximum size.\n    ///     </description></item>\n    ///     <item><description>\n    ///         Exception free.\n    ///     </description></item>\n    ///     <item><description>\n    ///         Enforced concurrency.\n    ///     </description></item>\n    /// </list>\n    /// </para>\n    /// </summary>\n    internal class KBucketDictionary\n    {\n        private readonly ReaderWriterLockSlim _lock;\n        private readonly int _size;\n        private readonly bool _replace;\n        private readonly ILogger _logger;\n        private Dictionary<Address, PeerState> _dictionary;\n\n        /// <summary>\n        /// Creates an instance with a size limit given by <paramref name=\"size\"/>.\n        /// </summary>\n        /// <param name=\"size\">The maximum number of elements the dictionary can hold.</param>\n        /// <param name=\"replace\">Whether to replace the oldest <see cref=\"PeerState\"/>,\n        /// i.e. <see cref=\"Tail\"/>, if the dictionary is already full.</param>\n        /// <param name=\"logger\">The <see cref=\"ILogger\"/> to write log messages to.</param>\n        /// <exception cref=\"ArgumentOutOfRangeException\">Thrown when <paramref name=\"size\"/>\n        /// is not positive..</exception>\n        public KBucketDictionary(int size, bool replace, ILogger logger)\n        {\n            if (size <= 0)\n            {\n                throw new ArgumentOutOfRangeException(\n                    nameof(size),\n                    $\"The value of {nameof(size)} must be positive.\");\n            }\n\n            _lock = new ReaderWriterLockSlim(LockRecursionPolicy.SupportsRecursion);\n            _size = size;\n            _replace = replace;\n            _dictionary = new Dictionary<Address, PeerState>();\n            _logger = logger;\n        }\n\n        public List<BoundPeer> Peers\n        {\n            get\n            {\n                return PeerStates.Select(peerState => peerState.Peer).ToList();\n            }\n        }\n\n        public List<PeerState> PeerStates\n        {\n            get\n            {\n                _lock.EnterReadLock();\n                try\n                {\n                    return _dictionary.Values.ToList();\n                }\n                finally\n                {\n                    _lock.ExitReadLock();\n                }\n            }\n        }\n\n        public int Count\n        {\n            get\n            {\n                _lock.EnterReadLock();\n                try\n                {\n                    return _dictionary.Count;\n                }\n                finally\n                {\n                    _lock.ExitReadLock();\n                }\n            }\n        }\n\n        /// <summary>\n        /// The <see cref=\"PeerState\"/> updated most recently. <see langword=\"null\"/>\n        /// if the dictionary is empty.\n        /// </summary>\n        public PeerState? Head\n        {\n            get\n            {\n                _lock.EnterReadLock();\n                try\n                {\n#pragma warning disable S3358   // Extract this nested ternary operation.\n                    return _dictionary.Values.Count > 0\n                        ? _dictionary.Values.Aggregate((candidate, ps) =>\n                            candidate.LastUpdated < ps.LastUpdated ? ps : candidate)\n                        : null;\n#pragma warning restore S3358\n                }\n                finally\n                {\n                    _lock.ExitReadLock();\n                }\n            }\n        }\n\n        /// <summary>\n        /// The <see cref=\"PeerState\"/> updated least recently. <see langword=\"null\"/>\n        /// if the dictionary is empty.\n        /// </summary>\n        public PeerState? Tail\n        {\n            get\n            {\n                _lock.EnterReadLock();\n                try\n                {\n#pragma warning disable S3358   // Extract this nested ternary operation.\n                    return _dictionary.Values.Count > 0\n                        ? _dictionary.Values.Aggregate((candidate, ps) =>\n                            candidate.LastUpdated > ps.LastUpdated ? ps : candidate)\n                        : null;\n#pragma warning restore S3358\n                }\n                finally\n                {\n                    _lock.ExitReadLock();\n                }\n            }\n        }\n\n        /// <summary>\n        /// Retrieves the <see cref=\"BoundPeer\"/> associated with <paramref name=\"peer\"/>'s\n        /// <see cref=\"Address\"/>.\n        /// </summary>\n        /// <param name=\"peer\">The <see cref=\"BoundPeer\"/> to check.</param>\n        /// <returns>The <see cref=\"BoundPeer\"/> with its address equal to\n        /// that of the <paramref name=\"peer\"/>'s. <see langword=\"null\"/> if not found.</returns>\n        public PeerState? Get(BoundPeer peer)\n        {\n            return Get(peer.Address);\n        }\n\n        /// <summary>\n        /// Retrievees the <see cref=\"BoundPeer\"/> associated with <paramref name=\"address\"/>.\n        /// </summary>\n        /// <param name=\"address\">The <see cref=\"Address\"/> to check.</param>\n        /// <returns>The <see cref=\"BoundPeer\"/> with its address equal to\n        /// that of <paramref name=\"address\"/>. <see langword=\"null\"/> if not found.</returns>\n        public PeerState? Get(Address address)\n        {\n            _lock.EnterReadLock();\n            try\n            {\n                if (_dictionary.ContainsKey(address))\n                {\n                    return _dictionary[address];\n                }\n                else\n                {\n                    return null;\n                }\n            }\n            finally\n            {\n                _lock.ExitReadLock();\n            }\n        }\n\n        /// <summary>\n        /// Checks if the dictionary contains <paramref name=\"peer\"/>'s <see cref=\"Address\"/>\n        /// as a key.\n        /// </summary>\n        /// <param name=\"peer\">The <see cref=\"BoundPeer\"/> to check.</param>\n        /// <returns><see langword=\"true\"/> if the <paramref name=\"peer\"/>'s\n        /// <see cref=\"Address\"/> exists, <see langword=\"false\"/> otherwise.</returns>\n        public bool Contains(BoundPeer peer)\n        {\n            return Contains(peer.Address);\n        }\n\n        /// <summary>\n        /// Checks if the dictionary contains <paramref name=\"address\"/> as a key.\n        /// </summary>\n        /// <param name=\"address\">The <see cref=\"Address\"/> to check.</param>\n        /// <returns><see langword=\"true\"/> if <paramref name=\"address\"/> exists,\n        /// <see langword=\"false\"/> otherwise.</returns>\n        public bool Contains(Address address)\n        {\n            _lock.EnterReadLock();\n            try\n            {\n                return _dictionary.ContainsKey(address);\n            }\n            finally\n            {\n                _lock.ExitReadLock();\n            }\n        }\n\n        /// <summary>\n        /// Adds or updates the dictionary with <paramref name=\"peer\"/>.\n        /// </summary>\n        /// <param name=\"peer\">The <see cref=\"BoundPeer\"/> to add or update.</param>\n        /// <returns><see langword=\"true\"/> if <paramref name=\"peer\"/> was either added or updated,\n        /// <see langword=\"false\"/> otherwise.</returns>\n        /// <seealso cref=\"AddOrUpdate(BoundPeer, PeerState)\"/>.\n        public bool AddOrUpdate(BoundPeer peer)\n        {\n            return AddOrUpdate(peer, new PeerState(peer, DateTimeOffset.UtcNow));\n        }\n\n        /// <summary>\n        /// Adds or updates the dictionary with a key/value pair.\n        /// </summary>\n        /// <param name=\"peer\">The <see cref=\"BoundPeer\"/> to add or update.</param>\n        /// <param name=\"peerState\">The <see cref=\"PeerState\"/> to use as a value.</param>\n        /// <returns><see langword=\"true\"/> if <paramref name=\"peer\"/> was either added or updated,\n        /// <see langword=\"false\"/> otherwise.</returns>\n        /// <seealso cref=\"AddOrUpdate(Address, PeerState)\"/>.\n        public bool AddOrUpdate(BoundPeer peer, PeerState peerState)\n        {\n            return AddOrUpdate(peer.Address, peerState);\n        }\n\n        /// <summary>\n        /// <para>\n        /// Adds or updates the dictionary with a key/value pair.\n        /// </para>\n        /// <para>\n        /// Internal logic is as follows:\n        /// <list type=\"bullet\">\n        ///     <item><description>\n        ///         If <paramref name=\"address\"/> is found, update its value\n        ///         with <paramref name=\"peerState\"/>.\n        ///     </description></item>\n        ///     <item><description>\n        ///         Else, if the dictionary is not full, i.e. has not reached its limit in size,\n        ///         add <paramref name=\"address\"/> and <paramref name=\"peerState\"/> as\n        ///         a key/value pair.\n        ///     </description></item>\n        ///     <item><description>\n        ///         Else, if the dictionary is full and replace option is set to\n        ///         <see langword=\"true\"/>, replace the oldest <see cref=\"PeerState\"/>, i.e.\n        ///         <see cref=\"Tail\"/>, with <paramref name=\"peerState\"/>.\n        ///     </description></item>\n        ///     <item><description>\n        ///         Else, ignore.\n        ///     </description></item>\n        /// </list>\n        /// </para>\n        /// </summary>\n        /// <param name=\"address\">The <see cref=\"Address\"/> to use as a key.</param>\n        /// <param name=\"peerState\">The <see cref=\"PeerState\"/> to use as a value.</param>\n        /// <returns><see langword=\"true\"/> if the key/value pair was either added or updated,\n        /// <see langword=\"false\"/> otherwise.</returns>\n        /// <remarks>\n        /// This returns <see langword=\"false\"/> only if all following conditions are met:\n        /// <list type=\"bullet\">\n        ///     <item><description>\n        ///         The dictionary does not contain <paramref name=\"address\"/> as a key.\n        ///     </description></item>\n        ///     <item><description>\n        ///         The dictionary is already full.\n        ///     </description></item>\n        ///     <item><description>\n        ///         The replacement option is set to <see langword=\"false\"/> for\n        ///         this <see cref=\"KBucketDictionary\"/> instance.\n        ///     </description></item>\n        /// </list>\n        /// </remarks>\n        public bool AddOrUpdate(Address address, PeerState peerState)\n        {\n            _lock.EnterWriteLock();\n            try\n            {\n                if (_dictionary.ContainsKey(address))\n                {\n                    _dictionary[address] = peerState;\n                    _logger.Verbose(\n                        \"{Address} found in the dictionary; updating its state...\",\n                        address);\n                    return true;\n                }\n                else\n                {\n                    if (_dictionary.Count < _size)\n                    {\n                        _dictionary[address] = peerState;\n                        _logger.Verbose(\n                            \"Added {Address} to the dictionary\", address);\n                        return true;\n                    }\n                    else\n                    {\n                        if (_replace)\n                        {\n                            // Tail is never null since the dictionary size is always positive.\n                            _dictionary.Remove(Tail!.Peer.Address);\n                            _dictionary[address] = peerState;\n                            return true;\n                        }\n                        else\n                        {\n                            _logger.Verbose(\n                                \"Cannot add {Address}; \" +\n                                \"the dictionary size is already at its limit of {Size}\",\n                                address,\n                                _size);\n                            return false;\n                        }\n                    }\n                }\n            }\n            finally\n            {\n                _lock.ExitWriteLock();\n            }\n        }\n\n        /// <summary>\n        /// Removes <paramref name=\"peer\"/> from the dictionary.\n        /// </summary>\n        /// <param name=\"peer\">The <see cref=\"BoundPeer\"/> to remove.</param>\n        /// <returns><see langword=\"true\"/> if <paramref name=\"peer\"/> was successfully removed,\n        /// <see langword=\"false\"/> otherwise.</returns>\n        public bool Remove(BoundPeer peer)\n        {\n            return Remove(peer.Address);\n        }\n\n        /// <summary>\n        /// Removes <paramref name=\"address\"/> from the dictionary.\n        /// </summary>\n        /// <param name=\"address\">The <see cref=\"Address\"/> to remove.</param>\n        /// <returns><see langword=\"true\"/> if <paramref name=\"address\"/> was successfully removed,\n        /// <see langword=\"false\"/> otherwise.</returns>\n        public bool Remove(Address address)\n        {\n            _lock.EnterWriteLock();\n            try\n            {\n                return _dictionary.Remove(address);\n            }\n            finally\n            {\n                _lock.ExitWriteLock();\n            }\n        }\n\n        /// <summary>\n        /// Empties the dictionary.\n        /// </summary>\n        public void Clear()\n        {\n            _lock.EnterWriteLock();\n            try\n            {\n                _dictionary = new Dictionary<Address, PeerState>();\n            }\n            finally\n            {\n                _lock.ExitWriteLock();\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Net/Protocols/Kademlia.cs",
    "content": "using System.Collections.Generic;\nusing System.Collections.Immutable;\nusing System.Linq;\nusing Libplanet.Crypto;\n\nnamespace Libplanet.Net.Protocols\n{\n    /// <summary>\n    /// Commonly used constants and static functions for Kademlia distributed hash table.\n    /// </summary>\n    public static class Kademlia\n    {\n        /// <summary>\n        /// The size of a single bucket.\n        /// </summary>\n        public const int BucketSize = 16;\n\n        /// <summary>\n        /// The number of buckets in the table.\n        /// </summary>\n        public const int TableSize = Address.Size * 8;\n\n        /// <summary>\n        /// The number of concurrency in peer discovery.\n        /// </summary>\n        public const int FindConcurrency = 3;\n\n        /// <summary>\n        /// Depth of the peer discovery operation.\n        /// </summary>\n        public const int MaxDepth = 3;\n\n        /// <summary>\n        /// Calculates the difference between two <see cref=\"Address\"/>es.\n        /// </summary>\n        /// <param name=\"left\">The first <see cref=\"Address\"/>.</param>\n        /// <param name=\"right\">The second <see cref=\"Address\"/>.</param>\n        /// <returns>The difference between the two <see cref=\"Address\"/>es given.</returns>\n        public static Address CalculateDifference(Address left, Address right)\n        {\n            byte[] dba = Enumerable.Zip(\n                left.ByteArray, right.ByteArray, (l, r) => (byte)(l ^ r)).ToArray();\n            return new Address(dba);\n        }\n\n        /// <summary>\n        /// Calculates the length of the common prefix between two <see cref=\"Address\"/>es\n        /// by finding the index of the first non-zero bit of the xor between the two.\n        /// </summary>\n        /// <param name=\"left\">The first element to calculate the common prefix length.</param>\n        /// <param name=\"right\">The second element to calculate the common prefix length.</param>\n        /// <returns>The length of the common prefix between <paramref name=\"left\"/> and\n        /// <paramref name=\"right\"/>.</returns>\n        public static int CommonPrefixLength(Address left, Address right)\n        {\n            ImmutableArray<byte> bytes = CalculateDifference(left, right).ByteArray;\n            int length = 0;\n\n            foreach (byte b in bytes)\n            {\n                int mask = 1 << 7;\n                while (mask != 0)\n                {\n                    if ((mask & b) != 0)\n                    {\n                        return length;\n                    }\n\n                    length++;\n                    mask >>= 1;\n                }\n            }\n\n            return length;\n        }\n\n        /// <summary>\n        /// Calculates the distance between two <see cref=\"Address\"/>es.\n        /// </summary>\n        /// <param name=\"left\">The first <see cref=\"Address\"/>.</param>\n        /// <param name=\"right\">The second <see cref=\"Address\"/>.</param>\n        /// <returns>The distance between the two <see cref=\"Address\"/>es given.</returns>\n        public static int CalculateDistance(Address left, Address right)\n        {\n            return Address.Size * 8 - CommonPrefixLength(left, right);\n        }\n\n        /// <summary>\n        /// Sorts a list of <see cref=\"BoundPeer\"/>s with respect to\n        /// the distance from <paramref name=\"target\"/> in ascending order.\n        /// </summary>\n        /// <param name=\"peers\">The <see cref=\"IEnumerable{T}\"/> of <see cref=\"BoundPeer\"/>s\n        /// to sort.</param>\n        /// <param name=\"target\">The <see cref=\"Address\"/> to calculate the distance of\n        /// each element in <paramref name=\"peers\"/>.</param>\n        /// <returns>>An <see cref=\"IEnumerable{T}\"/> whose elements are sorted\n        /// according to the distance with <paramref name=\"target\"/>.</returns>\n        public static IEnumerable<BoundPeer> SortByDistance(\n            IEnumerable<BoundPeer> peers,\n            Address target)\n        {\n            return peers.OrderBy(peer => CalculateDistance(target, peer.Address));\n        }\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Net/Protocols/KademliaProtocol.cs",
    "content": "using System;\nusing System.Collections.Concurrent;\nusing System.Collections.Generic;\nusing System.Collections.Immutable;\nusing System.Linq;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing Dasync.Collections;\nusing Libplanet.Crypto;\nusing Libplanet.Net.Messages;\nusing Libplanet.Net.Transports;\nusing Serilog;\nusing Random = System.Random;\n\nnamespace Libplanet.Net.Protocols\n{\n    /// <summary>\n    /// A Kademlia based peer discovery protocol.\n    /// </summary>\n    public class KademliaProtocol : IProtocol\n    {\n        private readonly TimeSpan _requestTimeout;\n        private readonly ITransport _transport;\n        private readonly Address _address;\n        private readonly Random _random;\n        private readonly RoutingTable _table;\n        private readonly int _findConcurrency;\n        private readonly ILogger _logger;\n\n        /// <summary>\n        /// Creates a <see cref=\"KademliaProtocol\"/> instance.\n        /// </summary>\n        /// <param name=\"table\">\n        /// The <see cref=\"RoutingTable\"/> where <see cref=\"BoundPeer\"/>s are stored.</param>\n        /// <param name=\"transport\"><see cref=\"ITransport\"/> to process messages.</param>\n        /// <param name=\"address\">The <see cref=\"Address\"/> of the <see cref=\"BoundPeer\"/>\n        /// to be the reference point.</param>\n        /// <param name=\"findConcurrency\">The number of concurrency in peer discovery.</param>\n        /// <param name=\"requestTimeout\">\n        /// A timeout of waiting for the reply of messages.  If it's omitted\n        /// or <see langword=\"null\"/> is given, will automatically be set to 5 seconds.</param>\n        public KademliaProtocol(\n            RoutingTable table,\n            ITransport transport,\n            Address address,\n            int findConcurrency = Kademlia.FindConcurrency,\n            TimeSpan? requestTimeout = null)\n        {\n            _transport = transport;\n            _logger = Log.ForContext<KademliaProtocol>();\n\n            _address = address;\n            _random = new System.Random();\n            _findConcurrency = findConcurrency;\n            _table = table;\n            _requestTimeout = requestTimeout ?? TimeSpan.FromMilliseconds(5000);\n            _transport.ProcessMessageHandler.Register(ProcessMessageHandler);\n        }\n\n        /// <inheritdoc />\n        // FIXME: Currently bootstrap is done until it finds closest peer, but it should halt\n        // when found neighbor's count is reached 2*k.\n        public async Task BootstrapAsync(\n            IEnumerable<BoundPeer> bootstrapPeers,\n            TimeSpan? dialTimeout,\n            int depth,\n            CancellationToken cancellationToken)\n        {\n            var findPeerTasks = new List<Task>();\n            var history = new ConcurrentBag<BoundPeer>();\n            var dialHistory = new ConcurrentBag<BoundPeer>();\n\n            if (!bootstrapPeers.Any())\n            {\n                throw new PeerDiscoveryException(\n                    \"No seeds are provided.  If it is intended you should conditionally invoke \" +\n                    $\"{nameof(BootstrapAsync)}() only when there are seed peers.\"\n                );\n            }\n\n            foreach (BoundPeer peer in bootstrapPeers.Where(peer => !peer.Address.Equals(_address)))\n            {\n                // Guarantees at least one connection (seed peer)\n                try\n                {\n                    await PingAsync(peer, dialTimeout, cancellationToken)\n                        .ConfigureAwait(false);\n                    findPeerTasks.Add(\n                        FindPeerAsync(\n                            history,\n                            dialHistory,\n                            _address,\n                            peer,\n                            depth,\n                            dialTimeout,\n                            cancellationToken));\n                }\n                catch (PingTimeoutException)\n                {\n                    _logger.Warning(\"A timeout exception occurred connecting to seed peer\");\n                    RemovePeer(peer);\n                }\n                catch (Exception e)\n                {\n                    _logger.Error(\n                        e, \"An unexpected exception occurred connecting to seed peer\");\n                }\n            }\n\n            if (!_table.Peers.Any())\n            {\n                throw new PeerDiscoveryException(\"All seeds are unreachable.\");\n            }\n\n            if (findPeerTasks.Count == 0)\n            {\n                throw new PeerDiscoveryException(\"Bootstrap failed.\");\n            }\n\n            try\n            {\n                await Task.WhenAll(findPeerTasks).ConfigureAwait(false);\n            }\n            catch (Exception e)\n            {\n                var msg = $\"An unexpected exception occurred during {nameof(BootstrapAsync)}()\";\n                _logger.Error(e, msg);\n                throw;\n            }\n        }\n\n        /// <inheritdoc />\n        public async Task AddPeersAsync(\n            IEnumerable<BoundPeer> peers,\n            TimeSpan? timeout,\n            CancellationToken cancellationToken)\n        {\n            try\n            {\n                var tasks = new List<Task>();\n                foreach (BoundPeer peer in peers)\n                {\n                    tasks.Add(PingAsync(\n                        peer,\n                        timeout: timeout,\n                        cancellationToken: cancellationToken));\n                }\n\n                _logger.Verbose(\"Trying to ping {PeerCount} peers\", tasks.Count);\n                await Task.WhenAll(tasks).ConfigureAwait(false);\n                _logger.Verbose(\"Update complete\");\n            }\n            catch (PingTimeoutException e)\n            {\n                _logger.Debug(e, \"Ping timed out\");\n            }\n            catch (TaskCanceledException e)\n            {\n                _logger.Debug(\n                    e, \"Task cancelled during {MethodName}()\", nameof(AddPeersAsync));\n            }\n            catch (Exception e)\n            {\n                _logger.Error(\n                    e,\n                    \"Unexpected exception occurred during {MethodName}()\",\n                    nameof(AddPeersAsync));\n                throw;\n            }\n        }\n\n        /// <inheritdoc />\n        public async Task RefreshTableAsync(TimeSpan maxAge, CancellationToken cancellationToken)\n        {\n            // TODO: Add timeout parameter for this method\n            try\n            {\n                IReadOnlyList<BoundPeer> peers = _table.PeersToRefresh(maxAge);\n                _logger.Verbose(\n                    \"Refreshing {CandidateCount} peers out of {PeerCount} peers...\",\n                    peers.Count,\n                    _table.Peers.Count);\n\n                await peers.ParallelForEachAsync(\n                    async peer =>\n                    {\n                        try\n                        {\n                            await ValidateAsync(peer, _requestTimeout, cancellationToken);\n                        }\n                        catch (TimeoutException)\n                        {\n                            _logger.Debug(\"Can't validate peer: {Peer}\", peer);\n                        }\n                    },\n                    cancellationToken\n                );\n                cancellationToken.ThrowIfCancellationRequested();\n            }\n            catch (TimeoutException)\n            {\n            }\n        }\n\n        /// <summary>\n        /// Refreshes all peers in routing table.\n        /// </summary>\n        /// <param name=\"timeout\">A timeout of waiting for the reply of messages.\n        /// If <see langword=\"null\"/> is given, the task never halts by itself\n        /// even no any response was given from the target peer.</param>\n        /// <param name=\"cancellationToken\">\n        /// A cancellation token used to propagate notification that this\n        /// operation should be canceled.</param>\n        /// <returns>An awaitable task without value.</returns>\n        public async Task CheckAllPeersAsync(TimeSpan? timeout, CancellationToken cancellationToken)\n        {\n            try\n            {\n                _logger.Verbose(\"Start to validate all peers: ({Count})\", _table.Peers.Count);\n                foreach (var peer in _table.Peers)\n                {\n                    await ValidateAsync(peer, timeout ?? _requestTimeout, cancellationToken)\n                        .ConfigureAwait(false);\n                }\n            }\n            catch (TimeoutException e)\n            {\n                _logger.Error(e, \"Timeout occurred checking some peers\");\n            }\n        }\n\n        /// <inheritdoc />\n        public async Task RebuildConnectionAsync(int depth, CancellationToken cancellationToken)\n        {\n            _logger.Verbose(\"Rebuilding connection...\");\n            var buffer = new byte[20];\n            var tasks = new List<Task>();\n            var history = new ConcurrentBag<BoundPeer>();\n            var dialHistory = new ConcurrentBag<BoundPeer>();\n            for (int i = 0; i < _findConcurrency; i++)\n            {\n                _random.NextBytes(buffer);\n                tasks.Add(FindPeerAsync(\n                    history,\n                    dialHistory,\n                    new Address(buffer),\n                    null,\n                    depth,\n                    _requestTimeout,\n                    cancellationToken));\n            }\n\n            tasks.Add(\n                FindPeerAsync(\n                    history,\n                    dialHistory,\n                    _address,\n                    null,\n                    depth,\n                    _requestTimeout,\n                    cancellationToken));\n            try\n            {\n                await Task.WhenAll(tasks).ConfigureAwait(false);\n            }\n            catch (TimeoutException)\n            {\n            }\n        }\n\n        /// <inheritdoc />\n        public async Task CheckReplacementCacheAsync(CancellationToken cancellationToken)\n        {\n            _logger.Verbose(\"Checking replacement cache\");\n            foreach (IEnumerable<BoundPeer> cache in _table.CachesToCheck)\n            {\n                foreach (BoundPeer replacement in cache)\n                {\n                    try\n                    {\n                        _logger.Verbose(\"Check peer {Peer}\", replacement);\n\n                        _table.RemoveCache(replacement);\n                        await PingAsync(replacement, _requestTimeout, cancellationToken)\n                            .ConfigureAwait(false);\n                    }\n                    catch (PingTimeoutException)\n                    {\n                        _logger.Verbose(\n                            \"Removed stale peer {Peer} from replacement cache\",\n                            replacement);\n                    }\n                }\n            }\n\n            _logger.Verbose(\"Replacement cache checked\");\n        }\n\n        /// <summary>\n        /// Use <see cref=\"FindNeighborsMsg\"/> messages to find a <see cref=\"BoundPeer\"/> with\n        /// <see cref=\"Address\"/> of <paramref name=\"target\"/>.\n        /// </summary>\n        /// <param name=\"target\">The <see cref=\"Address\"/> to find.</param>\n        /// <param name=\"depth\">Target depth of recursive operation.</param>\n        /// <param name=\"timeout\"><see cref=\"TimeSpan\"/> for waiting reply of\n        /// <see cref=\"FindNeighborsMsg\"/>.</param>\n        /// <param name=\"cancellationToken\">A cancellation token used to propagate notification\n        /// that this operation should be canceled.</param>\n        /// <returns>A <see cref=\"BoundPeer\"/> with <paramref name=\"target\"/> as its\n        /// <see cref=\"Address\"/> if found.  Otherwise, <see langword=\"null\"/>.</returns>\n        public async Task<BoundPeer?> FindSpecificPeerAsync(\n            Address target,\n            int depth,\n            TimeSpan? timeout,\n            CancellationToken cancellationToken)\n        {\n            _logger.Verbose(\n                \"{MethodName}() with {Target}. (depth: {Depth})\",\n                nameof(FindSpecificPeerAsync),\n                target,\n                depth);\n\n            if (_table.GetPeer(target) is BoundPeer boundPeer)\n            {\n                try\n                {\n                    await PingAsync(boundPeer, _requestTimeout, cancellationToken)\n                        .ConfigureAwait(false);\n                }\n                catch (PingTimeoutException)\n                {\n                    var msg =\n                        \"{BoundPeer}, a target peer, is in the routing table does not respond\";\n                    _logger.Verbose(msg, boundPeer);\n                    RemovePeer(boundPeer);\n                    return null;\n                }\n\n                _logger.Verbose(\n                    \"{BoundPeer}, a target peer, is in the routing table\",\n                    boundPeer);\n                return boundPeer;\n            }\n\n            HashSet<BoundPeer> history = new HashSet<BoundPeer>();\n            Queue<Tuple<BoundPeer, int>> peersToFind = new Queue<Tuple<BoundPeer, int>>();\n            foreach (BoundPeer peer in _table.Neighbors(target, _findConcurrency, false))\n            {\n                peersToFind.Enqueue(new Tuple<BoundPeer, int>(peer, 0));\n            }\n\n            while (peersToFind.Any())\n            {\n                cancellationToken.ThrowIfCancellationRequested();\n\n                peersToFind.Dequeue().Deconstruct(out BoundPeer viaPeer, out int curDepth);\n                _logger.Debug(\"ViaPeer: {Peer}, curDepth: {curDepth}\", viaPeer, curDepth);\n                if (depth != -1 && curDepth >= depth)\n                {\n                    continue;\n                }\n\n                history.Add(viaPeer);\n                IEnumerable<BoundPeer> foundPeers =\n                    await GetNeighbors(viaPeer, target, timeout, cancellationToken)\n                    .ConfigureAwait(false);\n                IEnumerable<BoundPeer> filteredPeers = foundPeers\n                    .Where(peer =>\n                        !history.Contains(peer) &&\n                        !peersToFind.Any(t => t.Item1.Equals(peer)) &&\n                        !peer.Address.Equals(_address))\n                    .Take(_findConcurrency);\n                int count = 0;\n                foreach (var found in filteredPeers)\n                {\n                    try\n                    {\n                        await PingAsync(found, _requestTimeout, cancellationToken)\n                            .ConfigureAwait(false);\n                        if (found.Address.Equals(target))\n                        {\n                            return found;\n                        }\n\n                        peersToFind.Enqueue(new Tuple<BoundPeer, int>(found, curDepth + 1));\n\n                        if (count++ >= _findConcurrency)\n                        {\n                            break;\n                        }\n                    }\n                    catch (TaskCanceledException)\n                    {\n                        throw new TaskCanceledException(\n                            $\"Task is cancelled during {nameof(FindSpecificPeerAsync)}()\");\n                    }\n                    catch (PingTimeoutException)\n                    {\n                        // Ignore peer not responding\n                    }\n                    finally\n                    {\n                        history.Add(found);\n                    }\n                }\n            }\n\n            return null;\n        }\n\n        internal async Task PingAsync(\n            BoundPeer peer,\n            TimeSpan? timeout,\n            CancellationToken cancellationToken)\n        {\n            if (cancellationToken.IsCancellationRequested)\n            {\n                return;\n            }\n\n            try\n            {\n                _logger.Verbose(\"Trying to ping async to {Peer}\", peer);\n                Message reply = await _transport.SendMessageAsync(\n                    peer,\n                    new PingMsg(),\n                    timeout,\n                    cancellationToken\n                ).ConfigureAwait(false);\n                if (!(reply.Content is PongMsg pong))\n                {\n                    throw new InvalidMessageContentException(\n                        $\"Expected pong, but received {reply.Content.Type}.\", reply.Content);\n                }\n                else if (reply.Remote.Address.Equals(_address))\n                {\n                    throw new InvalidMessageContentException(\"Cannot receive pong from self\", pong);\n                }\n\n                AddPeer(peer);\n            }\n            catch (CommunicationFailException)\n            {\n                throw new PingTimeoutException(\n                    $\"Failed to send Ping to {peer}.\",\n                    peer);\n            }\n        }\n\n        private async Task ProcessMessageHandler(Message message)\n        {\n            switch (message.Content)\n            {\n                case PingMsg ping:\n                {\n                    await ReceivePingAsync(message).ConfigureAwait(false);\n                    break;\n                }\n\n                case FindNeighborsMsg findNeighbors:\n                {\n                    await ReceiveFindPeerAsync(message).ConfigureAwait(false);\n                    break;\n                }\n            }\n\n            // Kademlia protocol registers handle of ITransport with the services\n            // (e.g., Swarm, ConsensusReactor) to receive the heartbeat messages.\n            // For AsyncDelegate<T> Task.WhenAll(), this will yield the handler\n            // to the other services before entering to synchronous AddPeer().\n            await Task.Yield();\n\n            AddPeer(message.Remote);\n        }\n\n        /// <summary>\n        /// Validate peer by send <see cref=\"PingMsg\"/> to <paramref name=\"peer\"/>. If target peer\n        /// does not responds, remove it from the table.\n        /// </summary>\n        /// <param name=\"peer\">A <see cref=\"BoundPeer\"/> to validate.</param>\n        /// <param name=\"timeout\">Timeout for waiting reply of <see cref=\"PingMsg\"/>.</param>\n        /// <param name=\"cancellationToken\">A cancellation token used to propagate notification\n        /// that this operation should be canceled.</param>\n        /// <returns>An awaitable task without value.</returns>\n        /// <exception cref=\"TimeoutException\">\n        /// Thrown when validation fails in given <paramref name=\"timeout\"/>.\n        /// </exception>\n        private async Task ValidateAsync(\n            BoundPeer peer,\n            TimeSpan timeout,\n            CancellationToken cancellationToken = default)\n        {\n            try\n            {\n                _logger.Verbose(\"Starting to validate peer {Peer}...\", peer);\n                DateTimeOffset check = DateTimeOffset.UtcNow;\n                await PingAsync(peer, timeout, cancellationToken).ConfigureAwait(false);\n                _table.Check(peer, check, DateTimeOffset.UtcNow);\n            }\n            catch (PingTimeoutException)\n            {\n                _logger.Verbose(\"Removing invalid peer {Peer}...\", peer);\n                RemovePeer(peer);\n                throw new TimeoutException($\"Timeout occurred during {nameof(ValidateAsync)}\");\n            }\n        }\n\n        private void AddPeer(BoundPeer peer)\n        {\n            _logger.Verbose(\"Trying to add {Peer}...\", peer);\n            _table.AddPeer(peer);\n        }\n\n        private void RemovePeer(BoundPeer peer)\n        {\n            _logger.Verbose(\"Trying to remove {Peer}...\", peer);\n            _table.RemovePeer(peer);\n        }\n\n        /// <summary>\n        /// Send <see cref=\"FindNeighborsMsg\"/> messages to <paramref name=\"viaPeer\"/>\n        /// to find <see cref=\"BoundPeer\"/>s near <paramref name=\"target\"/>.\n        /// </summary>\n        /// <param name=\"history\">The <see cref=\"BoundPeer\"/> that searched.</param>\n        /// <param name=\"dialHistory\">The <see cref=\"BoundPeer\"/> that ping was sent.</param>\n        /// <param name=\"target\">The <see cref=\"Address\"/> to find.</param>\n        /// <param name=\"viaPeer\">The target <see cref=\"BoundPeer\"/>\n        /// to send <see cref=\"FindNeighborsMsg\"/> message.\n        /// If null, selects 3 <see cref=\"BoundPeer\"/>s from <see cref=\"RoutingTable\"/> of\n        /// self.</param>\n        /// <param name=\"depth\">Target depth of recursive operation.</param>\n        /// <param name=\"timeout\"><see cref=\"TimeSpan\"/> for waiting reply of\n        /// <see cref=\"FindNeighborsMsg\"/>.</param>\n        /// <param name=\"cancellationToken\">A cancellation token used to propagate notification\n        /// that this operation should be canceled.</param>\n        /// <returns>An awaitable task without value.</returns>\n        private async Task FindPeerAsync(\n            ConcurrentBag<BoundPeer> history,\n            ConcurrentBag<BoundPeer> dialHistory,\n            Address target,\n            BoundPeer? viaPeer,\n            int depth,\n            TimeSpan? timeout,\n            CancellationToken cancellationToken)\n        {\n            _logger.Verbose(\n                \"{MethodName}() with {Target} to {Peer}. (depth: {Depth})\",\n                nameof(FindPeerAsync),\n                target,\n                viaPeer,\n                depth);\n            if (depth == 0)\n            {\n                return;\n            }\n\n            IEnumerable<BoundPeer> found;\n            if (viaPeer is null)\n            {\n                found = await QueryNeighborsAsync(history, target, timeout, cancellationToken)\n                    .ConfigureAwait(false);\n            }\n            else\n            {\n                found = await GetNeighbors(viaPeer, target, timeout, cancellationToken)\n                    .ConfigureAwait(false);\n                history.Add(viaPeer);\n            }\n\n            // In ethereum's devp2p, GetNeighbors request will exclude peer with address of\n            // target. But our implementation contains target itself for FindSpecificPeerAsync(),\n            // so it should be excluded in here.\n            found = found.Where(peer => !peer.Address.Equals(target));\n            await ProcessFoundAsync(\n                history,\n                dialHistory,\n                found,\n                target,\n                depth,\n                timeout,\n                cancellationToken).ConfigureAwait(false);\n        }\n\n        private async Task<IEnumerable<BoundPeer>> QueryNeighborsAsync(\n            ConcurrentBag<BoundPeer> history,\n            Address target,\n            TimeSpan? timeout,\n            CancellationToken cancellationToken)\n        {\n            List<BoundPeer> neighbors = _table.Neighbors(target, _table.BucketSize, false).ToList();\n            var found = new List<BoundPeer>();\n            int count = Math.Min(neighbors.Count, _findConcurrency);\n            for (var i = 0; i < count; i++)\n            {\n                var peers =\n                    await GetNeighbors(neighbors[i], target, timeout, cancellationToken)\n                    .ConfigureAwait(false);\n                history.Add(neighbors[i]);\n                found.AddRange(peers.Where(peer => !found.Contains(peer)));\n            }\n\n            return found;\n        }\n\n        private async Task<IEnumerable<BoundPeer>> GetNeighbors(\n            BoundPeer peer,\n            Address target,\n            TimeSpan? timeout,\n            CancellationToken cancellationToken)\n        {\n            var findPeer = new FindNeighborsMsg(target);\n            try\n            {\n                Message reply = await _transport.SendMessageAsync(\n                    peer,\n                    findPeer,\n                    timeout,\n                    cancellationToken\n                ).ConfigureAwait(false);\n                if (!(reply.Content is NeighborsMsg neighbors))\n                {\n                    throw new InvalidMessageContentException(\n                        $\"Reply to {nameof(Messages.FindNeighborsMsg)} is invalid.\",\n                        reply.Content);\n                }\n\n                return neighbors.Found;\n            }\n            catch (CommunicationFailException cfe)\n            {\n                _logger.Debug(cfe, \"Failed to get neighbors from {Peer}\", target);\n                RemovePeer(peer);\n                return ImmutableArray<BoundPeer>.Empty;\n            }\n        }\n\n        // Send pong back to remote\n        private async Task ReceivePingAsync(Message message)\n        {\n            var ping = (PingMsg)message.Content;\n            if (message.Remote.Address.Equals(_address))\n            {\n                throw new InvalidMessageContentException(\"Cannot receive ping from self.\", ping);\n            }\n\n            var pong = new PongMsg();\n\n            await _transport.ReplyMessageAsync(pong, message.Identity, default)\n                .ConfigureAwait(false);\n        }\n\n        /// <summary>\n        /// Process <see cref=\"BoundPeer\"/>s that is replied by sending\n        /// <see cref=\"FindNeighborsMsg\"/> request.\n        /// </summary>\n        /// <param name=\"history\"><see cref=\"BoundPeer\"/>s that already searched.</param>\n        /// <param name=\"dialHistory\"><see cref=\"BoundPeer\"/>s that ping sent.</param>\n        /// <param name=\"found\"><see cref=\"BoundPeer\"/>s that found.</param>\n        /// <param name=\"target\">The target <see cref=\"Address\"/> to search.</param>\n        /// <param name=\"depth\">Target depth of recursive operation. If -1 is given,\n        /// it runs until the closest peer is found.</param>\n        /// <param name=\"timeout\"><see cref=\"TimeSpan\"/> for next depth's\n        /// <see cref=\"FindPeerAsync\"/> operation.</param>\n        /// <param name=\"cancellationToken\">A cancellation token used to propagate notification\n        /// that this operation should be canceled.</param>\n        /// <returns>An awaitable task without value.</returns>\n        /// <exception cref=\"TimeoutException\">Thrown when all peers that found are\n        /// not online.</exception>\n        private async Task ProcessFoundAsync(\n            ConcurrentBag<BoundPeer> history,\n            ConcurrentBag<BoundPeer> dialHistory,\n            IEnumerable<BoundPeer> found,\n            Address target,\n            int depth,\n            TimeSpan? timeout,\n            CancellationToken cancellationToken)\n        {\n            List<BoundPeer> peers = found.Where(\n                peer =>\n                    !peer.Address.Equals(_address) &&\n                    !_table.Contains(peer) &&\n                    !history.Contains(peer)).ToList();\n\n            if (peers.Count == 0)\n            {\n                _logger.Verbose(\"No any neighbor received\");\n                return;\n            }\n\n            peers = Kademlia.SortByDistance(peers, target).ToList();\n\n            IReadOnlyList<BoundPeer> closestCandidate =\n                _table.Neighbors(target, _table.BucketSize, false);\n\n            List<Task> tasks = peers\n                .Where(peer => !dialHistory.Contains(peer))\n                .Select(\n                    peer =>\n                    {\n                        dialHistory.Add(peer);\n                        return PingAsync(peer, _requestTimeout, cancellationToken);\n                    }\n                ).ToList();\n            Task aggregateTask = Task.WhenAll(tasks);\n            try\n            {\n                await aggregateTask.ConfigureAwait(false);\n            }\n            catch (Exception)\n            {\n                AggregateException aggregateException = aggregateTask.Exception!;\n                foreach (Exception e in aggregateException.InnerExceptions)\n                {\n                    if (e is PingTimeoutException pte)\n                    {\n                        peers.Remove(pte.Target);\n                    }\n                }\n\n                _logger.Warning(\n                    aggregateException,\n                    \"Some responses from neighbors found unexpectedly terminated\");\n            }\n\n            var findPeerTasks = new List<Task>();\n            BoundPeer? closestKnownPeer = closestCandidate.FirstOrDefault();\n            var count = 0;\n            foreach (var peer in peers)\n            {\n                if (closestKnownPeer is { } ckp &&\n                   string.CompareOrdinal(\n                       Kademlia.CalculateDifference(peer.Address, target).ToHex(),\n                       Kademlia.CalculateDifference(ckp.Address, target).ToHex()\n                   ) >= 1)\n                {\n                    break;\n                }\n\n                if (history.Contains(peer))\n                {\n                    continue;\n                }\n\n                findPeerTasks.Add(FindPeerAsync(\n                    history,\n                    dialHistory,\n                    target,\n                    peer,\n                    depth == -1 ? depth : depth - 1,\n                    timeout,\n                    cancellationToken));\n                if (count++ >= _findConcurrency)\n                {\n                    break;\n                }\n            }\n\n            try\n            {\n                await Task.WhenAll(findPeerTasks).ConfigureAwait(false);\n            }\n            catch (Exception e)\n            {\n                _logger.Error(\n                    e,\n                    \"Some FindPeer tasks were unexpectedly terminated\");\n            }\n        }\n\n        // FIXME: this method is not safe from amplification attack\n        // maybe ping/pong/ping/pong is required\n        private async Task ReceiveFindPeerAsync(Message message)\n        {\n            var findNeighbors = (FindNeighborsMsg)message.Content;\n            IEnumerable<BoundPeer> found =\n                _table.Neighbors(findNeighbors.Target, _table.BucketSize, true);\n\n            var neighbors = new NeighborsMsg(found);\n\n            await _transport.ReplyMessageAsync(neighbors, message.Identity, default)\n                .ConfigureAwait(false);\n        }\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Net/Protocols/PeerDiscoveryException.cs",
    "content": "using System;\n\nnamespace Libplanet.Net.Protocols\n{\n    public class PeerDiscoveryException : SwarmException\n    {\n        public PeerDiscoveryException()\n        {\n        }\n\n        public PeerDiscoveryException(string message)\n            : base(message)\n        {\n        }\n\n        public PeerDiscoveryException(string message, Exception innerException)\n            : base(message, innerException)\n        {\n        }\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Net/Protocols/PingTimeoutException.cs",
    "content": "using System;\n\nnamespace Libplanet.Net.Protocols\n{\n    public class PingTimeoutException : TimeoutException\n    {\n        public PingTimeoutException(BoundPeer target)\n            : base()\n        {\n            Target = target;\n        }\n\n        public PingTimeoutException(string message, BoundPeer target)\n            : base(message)\n        {\n            Target = target;\n        }\n\n        public PingTimeoutException(string message, BoundPeer target, Exception innerException)\n            : base(message, innerException)\n        {\n            Target = target;\n        }\n\n        public BoundPeer Target { get; private set; }\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Net/Protocols/RoutingTable.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Collections.Immutable;\nusing System.Linq;\nusing Libplanet.Crypto;\nusing Serilog;\n\nnamespace Libplanet.Net.Protocols\n{\n    /// <summary>\n    /// Kademlia distributed hash table.\n    /// </summary>\n    public class RoutingTable : IRoutingTable\n    {\n        private readonly Address _address;\n        private readonly KBucket[] _buckets;\n\n        private readonly ILogger _logger;\n\n        /// <summary>\n        /// Creates a Kademlia distributed hash table instance.\n        /// </summary>\n        /// <param name=\"address\"><see cref=\"Address\"/> of this peer.</param>\n        /// <param name=\"tableSize\">The number of buckets in the table.</param>\n        /// <param name=\"bucketSize\">The size of a single bucket.</param>\n        /// <exception cref=\"ArgumentOutOfRangeException\">\n        /// Thrown when <paramref name=\"tableSize\"/> or <paramref name=\"bucketSize\"/> is\n        /// less then or equal to 0.</exception>\n        public RoutingTable(\n            Address address,\n            int tableSize = Kademlia.TableSize,\n            int bucketSize = Kademlia.BucketSize)\n        {\n            if (tableSize <= 0)\n            {\n                throw new ArgumentOutOfRangeException(\n                    nameof(tableSize),\n                    $\"The value of {nameof(tableSize)} must be positive.\");\n            }\n            else if (bucketSize <= 0)\n            {\n                throw new ArgumentOutOfRangeException(\n                    nameof(bucketSize),\n                    $\"The value of {nameof(bucketSize)} must be positive.\");\n            }\n\n            _address = address;\n            TableSize = tableSize;\n            BucketSize = bucketSize;\n            _logger = Log\n                .ForContext<RoutingTable>()\n                .ForContext(\"Source\", nameof(RoutingTable));\n\n            var random = new Random();\n            _buckets = new KBucket[TableSize];\n            for (int i = 0; i < TableSize; i++)\n            {\n                _buckets[i] = new KBucket(BucketSize, random, _logger);\n            }\n        }\n\n        /// <summary>\n        /// The number of buckets in the table.\n        /// </summary>\n        public int TableSize { get; }\n\n        /// <summary>\n        /// The size of a single bucket.\n        /// </summary>\n        public int BucketSize { get; }\n\n        /// <inheritdoc />\n        public int Count => _buckets.Sum(bucket => bucket.Count);\n\n        /// <inheritdoc />\n        public IReadOnlyList<BoundPeer> Peers =>\n            NonEmptyBuckets.SelectMany(bucket => bucket.Peers).ToImmutableArray();\n\n        /// <summary>\n        /// An <see cref=\"IReadOnlyList{T}\"/> of <see cref=\"PeerState\"/> of peers in the table.\n        /// </summary>\n        public IReadOnlyList<PeerState> PeerStates =>\n            NonEmptyBuckets.SelectMany(bucket => bucket.PeerStates).ToImmutableArray();\n\n        internal IReadOnlyList<IReadOnlyList<BoundPeer>> CachesToCheck\n        {\n            get\n            {\n                return NonFullBuckets.Select(\n                    bucket => bucket.ReplacementCache.PeerStates\n                        .OrderBy(peerState => peerState.LastUpdated)\n                        .Select(peerState => peerState.Peer)\n                        .ToArray()\n                ).ToArray();\n            }\n        }\n\n        internal IReadOnlyList<KBucket> NonFullBuckets\n        {\n            get\n            {\n                return _buckets.Where(bucket => !bucket.IsFull).ToArray();\n            }\n        }\n\n        internal IReadOnlyList<KBucket> NonEmptyBuckets\n        {\n            get\n            {\n                return _buckets.Where(bucket => !bucket.IsEmpty).ToArray();\n            }\n        }\n\n        /// <inheritdoc />\n        public void AddPeer(BoundPeer peer) => AddPeer(peer, DateTimeOffset.UtcNow);\n\n        /// <inheritdoc />\n        public bool RemovePeer(BoundPeer peer)\n        {\n            if (peer.Address.Equals(_address))\n            {\n                throw new ArgumentException(\n                    \"A node is disallowed to remove itself from its routing table.\",\n                    nameof(peer)\n                );\n            }\n\n            _logger.Debug(\"Removing peer {Peer} from the routing table\", peer);\n            return BucketOf(peer).RemovePeer(peer);\n        }\n\n        /// <inheritdoc />\n        public bool Contains(BoundPeer peer)\n        {\n            return BucketOf(peer).Contains(peer);\n        }\n\n        /// <summary>\n        /// Finds a <seealso cref=\"BoundPeer\"/> whose <see cref=\"Address\"/> matches with\n        /// the given <paramref name=\"addr\"/> if it exits.\n        /// </summary>\n        /// <param name=\"addr\">The <see cref=\"Address\"/> to search.</param>\n        /// <returns>A <see cref=\"BoundPeer\"/> whose <see cref=\"Address\"/> matches\n        /// the given <paramref name=\"addr\"/>.</returns>\n        public BoundPeer? GetPeer(Address addr) =>\n            Peers.FirstOrDefault(peer => peer.Address.Equals(addr));\n\n        /// <summary>\n        /// Removes all peers in the table. This method does not affect static peers.\n        /// </summary>\n        public void Clear()\n        {\n            foreach (KBucket bucket in _buckets)\n            {\n                bucket.Clear();\n            }\n        }\n\n        /// <summary>\n        /// Returns <paramref name=\"k\"/> nearest peers to given parameter peer from routing table.\n        /// Return value is already sorted with respect to target.\n        /// </summary>\n        /// <param name=\"target\"><see cref=\"BoundPeer\"/> to look up.</param>\n        /// <param name=\"k\">Number of peers to return.</param>\n        /// <param name=\"includeTarget\">A boolean value indicates to include a peer with\n        /// <see cref=\"Address\"/> of <paramref name=\"target\"/> in return value or not.</param>\n        /// <returns>An enumerable of <see cref=\"BoundPeer\"/>.</returns>\n        public IReadOnlyList<BoundPeer> Neighbors(BoundPeer target, int k, bool includeTarget)\n            => Neighbors(target.Address, k, includeTarget);\n\n        /// <summary>\n        /// Returns at most 2 * <paramref name=\"k\"/> (2 * <paramref name=\"k\"/> + 1 if\n        /// <paramref name=\"includeTarget\"/> is <see langword=\"true\"/>) nearest peers to given\n        /// parameter peer from routing table. Return value is sorted with respect to target.\n        /// <seealso cref=\"Kademlia.SortByDistance(IEnumerable{BoundPeer}, Address)\"/>\n        /// </summary>\n        /// <param name=\"target\"><see cref=\"Address\"/> to look up.</param>\n        /// <param name=\"k\">Number of peers to return.</param>\n        /// <param name=\"includeTarget\">A boolean value indicates to include a peer with\n        /// <see cref=\"Address\"/> of <paramref name=\"target\"/> in return value or not.</param>\n        /// <returns>An enumerable of <see cref=\"BoundPeer\"/>.</returns>\n        public IReadOnlyList<BoundPeer> Neighbors(Address target, int k, bool includeTarget)\n        {\n            // TODO: Should include static peers?\n            var sorted = _buckets\n                .Where(b => !b.IsEmpty)\n                .SelectMany(b => b.Peers)\n                .ToList();\n\n            sorted = Kademlia.SortByDistance(sorted, target).ToList();\n\n            // Select maximum k * 2 peers excluding the target itself.\n            bool containsTarget = sorted.Any(peer => peer.Address.Equals(target));\n            int maxCount = (includeTarget && containsTarget) ? k * 2 + 1 : k * 2;\n\n            IEnumerable<BoundPeer> peers = includeTarget\n                ? sorted\n                : sorted.Where(peer => !peer.Address.Equals(target));\n\n            return peers.Take(maxCount).ToArray();\n        }\n\n        /// <summary>\n        /// Marks <paramref name=\"peer\"/> checked and refreshes last checked time of the peer.\n        /// </summary>\n        /// <param name=\"peer\">The <see cref=\"BoundPeer\"/> to check.</param>\n        /// <param name=\"start\"><see cref=\"DateTimeOffset\"/> at the beginning of the check.</param>\n        /// <param name=\"end\"><see cref=\"DateTimeOffset\"/> at the end of the check.</param>\n        /// <exception cref=\"ArgumentNullException\">\n        /// Thrown when <paramref name=\"peer\"/> is <see langword=\"null\"/>.</exception>\n        public void Check(BoundPeer peer, DateTimeOffset start, DateTimeOffset end)\n            => BucketOf(peer).Check(peer, start, end);\n\n        internal void AddPeer(BoundPeer peer, DateTimeOffset updated)\n        {\n            if (peer.Address.Equals(_address))\n            {\n                throw new ArgumentException(\n                    \"A node is disallowed to add itself to its routing table.\",\n                    nameof(peer));\n            }\n\n            _logger.Debug(\"Adding peer {Peer} to the routing table...\", peer);\n            BucketOf(peer).AddPeer(peer, updated);\n        }\n\n        internal IReadOnlyList<BoundPeer> PeersToBroadcast(Address? except, int min = 10)\n        {\n            List<BoundPeer> peers = NonEmptyBuckets\n                .Select(bucket => bucket.GetRandomPeer(except))\n                .OfType<BoundPeer>()\n                .ToList();\n            int count = peers.Count;\n            if (count < min)\n            {\n                peers.AddRange(Peers\n                    .Where(peer =>\n                        !peers.Contains(peer) &&\n                            (!(except is Address e) || !peer.Address.Equals(e)))\n                    .Take(min - count));\n            }\n\n            return peers;\n        }\n\n        internal IReadOnlyList<BoundPeer> PeersToRefresh(TimeSpan maxAge) => NonEmptyBuckets\n            .Where(bucket =>\n                bucket.Tail is PeerState peerState &&\n                    peerState.LastUpdated + maxAge < DateTimeOffset.UtcNow)\n            .Select(bucket => bucket.Tail!.Peer)\n            .ToList();\n\n        internal bool RemoveCache(BoundPeer peer)\n        {\n            KBucket bucket = BucketOf(peer);\n            return bucket.ReplacementCache.Remove(peer);\n        }\n\n        internal KBucket BucketOf(BoundPeer peer)\n        {\n            int index = GetBucketIndexOf(peer.Address);\n            return BucketOf(index);\n        }\n\n        internal KBucket BucketOf(int level)\n        {\n            return _buckets[level];\n        }\n\n        internal int GetBucketIndexOf(Address addr)\n        {\n            int plength = Kademlia.CommonPrefixLength(addr, _address);\n            return Math.Min(plength, TableSize - 1);\n        }\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Net/StateDownloadState.cs",
    "content": "namespace Libplanet.Net\n{\n    /// <summary>\n    /// Indicates a progress of downloading states.\n    /// </summary>\n    public class StateDownloadState : BlockSyncState\n    {\n        /// <summary>\n        /// Total number of messages to receive in the current batch.\n        /// </summary>\n        public int TotalIterationCount { get; internal set; }\n\n        /// <summary>\n        /// The number of received messages until now.\n        /// </summary>\n        public int ReceivedIterationCount { get; internal set; }\n\n        /// <inheritdoc />\n        public override int CurrentPhase => 4;\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Net/Swarm.BlockCandidate.cs",
    "content": "#nullable disable\nusing System;\nusing System.Collections.Concurrent;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing Libplanet.Blockchain;\nusing Libplanet.Types.Blocks;\n\nnamespace Libplanet.Net\n{\n    public partial class Swarm\n    {\n        private readonly ConcurrentDictionary<BoundPeer, int> _processBlockDemandSessions;\n\n        private async Task ConsumeBlockCandidates(\n            TimeSpan? checkInterval = null,\n            bool render = true,\n            CancellationToken cancellationToken = default)\n        {\n            while (!cancellationToken.IsCancellationRequested)\n            {\n                if (BlockCandidateTable.Count > 0)\n                {\n                    BlockHeader tipHeader = BlockChain.Tip.Header;\n                    if (BlockCandidateTable.GetCurrentRoundCandidate(tipHeader) is { } branch)\n                    {\n                        var root = branch.Blocks.First();\n                        var tip = branch.Blocks.Last();\n                        _logger.Information(\n                            \"Consuming branch with root #{RootIndex} {RootHash} \" +\n                            \"and tip #{TipIndex} {TipHash}\",\n                            root.Item1.Index,\n                            root.Item1.Hash,\n                            tip.Item1.Index,\n                            tip.Item1.Hash);\n                        _ = BlockCandidateProcess(\n                            branch,\n                            render,\n                            cancellationToken);\n                        BlockAppended.Set();\n                    }\n                }\n                else if (checkInterval is { } interval)\n                {\n                    await Task.Delay(interval, cancellationToken);\n                    continue;\n                }\n                else\n                {\n                    break;\n                }\n\n                BlockCandidateTable.Cleanup(IsBlockNeeded);\n            }\n        }\n\n        private bool BlockCandidateProcess(\n            Branch candidate,\n            bool render,\n            CancellationToken cancellationToken)\n        {\n            try\n            {\n                FillBlocksAsyncStarted.Set();\n                _logger.Debug(\n                    \"{MethodName}() starts to append; current tip is #{Index} {Hash}\",\n                    nameof(BlockCandidateProcess),\n                    BlockChain.Tip.Index,\n                    BlockChain.Tip.Hash);\n                AppendBranch(\n                    blockChain: BlockChain,\n                    candidate: candidate,\n                    render: render,\n                    cancellationToken: cancellationToken);\n                ProcessFillBlocksFinished.Set();\n                _logger.Debug(\n                    \"{MethodName}() finished appending blocks; current tip is #{Index} {Hash}\",\n                    nameof(BlockCandidateProcess),\n                    BlockChain.Tip.Index,\n                    BlockChain.Tip.Hash);\n                return true;\n            }\n            catch (Exception e)\n            {\n                _logger.Error(\n                    e,\n                    \"{MethodName}() has failed to append blocks\",\n                    nameof(BlockCandidateProcess));\n                FillBlocksAsyncFailed.Set();\n                return false;\n            }\n        }\n\n        private void AppendBranch(\n            BlockChain blockChain,\n            Branch candidate,\n            bool render,\n            CancellationToken cancellationToken = default)\n        {\n            Block oldTip = blockChain.Tip;\n            Block branchpoint = oldTip;\n            List<(Block, BlockCommit)> blocks = ExtractBlocksToAppend(branchpoint, candidate);\n\n            if (!blocks.Any())\n            {\n                _logger.Debug(\n                    \"There are no blocks to append to block {BlockHash}\",\n                    branchpoint.Hash);\n            }\n\n            try\n            {\n                long verifiedBlockCount = 0;\n\n                foreach (var (block, commit) in blocks)\n                {\n                    cancellationToken.ThrowIfCancellationRequested();\n                    if (block.ProtocolVersion < BlockMetadata.SlothProtocolVersion)\n                    {\n                        blockChain.AppendStateRootHashPreceded(block, commit, render: render);\n                    }\n                    else\n                    {\n                        blockChain.Append(block, commit, render: render);\n                    }\n\n                    verifiedBlockCount++;\n                }\n            }\n            catch (Exception e)\n            {\n                const string dbgMsg = \"An exception occurred while appending a block\";\n                _logger.Error(e, dbgMsg);\n                throw;\n            }\n        }\n\n        private List<(Block, BlockCommit)> ExtractBlocksToAppend(Block branchpoint, Branch branch)\n        {\n            var trimmed = new List<(Block, BlockCommit)>();\n            bool matchFound = false;\n            foreach (var pair in branch.Blocks)\n            {\n                if (matchFound)\n                {\n                    trimmed.Add(pair);\n                }\n                else\n                {\n                    matchFound = branchpoint.Hash.Equals(pair.Item1.Hash);\n                }\n            }\n\n            return trimmed;\n        }\n\n        private async Task<bool> ProcessBlockDemandAsync(\n            BlockDemand demand,\n            CancellationToken cancellationToken)\n        {\n            BoundPeer peer = demand.Peer;\n\n            if (_processBlockDemandSessions.ContainsKey(peer))\n            {\n                // Another task has spawned for the peer.\n                return false;\n            }\n\n            var sessionRandom = new Random();\n\n            int sessionId = sessionRandom.Next();\n\n            if (demand.Index <= BlockChain.Tip.Index)\n            {\n                return false;\n            }\n\n            _logger.Debug(\n                \"{SessionId}: Downloading blocks from {Peer}; started \" +\n                \"to fetch the block #{BlockIndex} {BlockHash} at {MethodName}()\",\n                sessionId,\n                peer,\n                demand.Index,\n                demand.Hash,\n                nameof(ProcessBlockDemandAsync));\n\n            try\n            {\n                _processBlockDemandSessions.TryAdd(peer, sessionId);\n                var result = await BlockCandidateDownload(\n                    peer: peer,\n                    blockChain: BlockChain,\n                    logSessionId: sessionId,\n                    cancellationToken: cancellationToken);\n\n                BlockReceived.Set();\n                return result;\n            }\n            catch (TimeoutException)\n            {\n                _logger.Debug(\n                    \"{SessionId}: Timeout occurred during {MethodName}() from {Peer}\",\n                    sessionId,\n                    nameof(ProcessBlockDemandAsync),\n                    peer);\n                return false;\n            }\n            catch (InvalidBlockIndexException)\n            {\n                const string msg =\n                    \"{SessionId}: {Peer} sent an invalid block index\";\n                _logger.Debug(msg, sessionId, peer);\n                return false;\n            }\n            catch (InvalidBlockHashException)\n            {\n                const string msg =\n                    \"{SessionId}: {Peer} sent an invalid block hash\";\n                _logger.Debug(msg, sessionId, peer);\n                return false;\n            }\n            catch (InvalidBlockException)\n            {\n                const string msg =\n                    \"{SessionId}: {Peer} sent an invalid block\";\n                _logger.Debug(msg, sessionId, peer);\n                return false;\n            }\n            catch (Exception e)\n            {\n                const string msg =\n                    \"{SessionId}: Unexpected exception occurred during \" +\n                    nameof(ProcessBlockDemandAsync) + \"() from {Peer}\";\n                _logger.Error(e, msg, sessionId, peer);\n                return false;\n            }\n            finally\n            {\n                // Maybe demand table can be cleaned up here, but it will be eventually\n                // cleaned up in FillBlocksAsync()\n                _processBlockDemandSessions.TryRemove(peer, out _);\n            }\n        }\n\n        private async Task<bool> BlockCandidateDownload(\n            BoundPeer peer,\n            BlockChain blockChain,\n            int logSessionId,\n            CancellationToken cancellationToken)\n        {\n            BlockLocator locator = blockChain.GetBlockLocator();\n            Block tip = blockChain.Tip;\n\n            List<BlockHash> hashes = await GetBlockHashes(\n                peer: peer,\n                locator: locator,\n                cancellationToken: cancellationToken);\n\n            if (!hashes.Any())\n            {\n                FillBlocksAsyncFailed.Set();\n                return false;\n            }\n\n            IAsyncEnumerable<(Block, BlockCommit)> blocksAsync = GetBlocksAsync(\n                peer,\n                hashes,\n                cancellationToken);\n            try\n            {\n                var branch = new Branch(await blocksAsync.ToArrayAsync(cancellationToken));\n                BlockCandidateTable.Add(tip.Header, branch);\n                return true;\n            }\n            catch (ArgumentException ae)\n            {\n                _logger.Error(\n                    ae,\n                    \"An unexpected exception occurred during {FName}\",\n                    nameof(BlockCandidateDownload));\n                return false;\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Net/Swarm.BlockSync.cs",
    "content": "#nullable disable\nusing System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing Libplanet.Blockchain;\nusing Libplanet.Types.Blocks;\nusing Nito.AsyncEx;\n\nnamespace Libplanet.Net\n{\n    public partial class Swarm\n    {\n        /// <summary>\n        /// Information of <see cref=\"Swarm\"/>'s demand for new blocks.\n        /// It is empty when the <see cref=\"Swarm\"/> does not have any block to demand.\n        /// <seealso cref=\"BlockDemandTable\"/>\n        /// </summary>\n        public BlockDemandTable BlockDemandTable { get; private set; }\n\n        /// <summary>\n        /// This is a table of waiting <see cref=\"Block\"/>s\n        /// to enter the <see cref=\"BlockChain\"/>.\n        /// <seealso cref=\"BlockCandidateTable\"/>\n        /// </summary>\n        public BlockCandidateTable BlockCandidateTable { get; private set; }\n\n        internal AsyncAutoResetEvent FillBlocksAsyncStarted { get; } = new AsyncAutoResetEvent();\n\n        internal AsyncAutoResetEvent FillBlocksAsyncFailed { get; } = new AsyncAutoResetEvent();\n\n        internal AsyncAutoResetEvent ProcessFillBlocksFinished { get; } = new AsyncAutoResetEvent();\n\n        /// <summary>\n        /// Fill blocks from the <see cref=\"BoundPeer\"/>s in the\n        /// <see cref=\"Swarm.RoutingTable\"/>.\n        /// </summary>\n        /// <param name=\"timeout\">\n        /// The timeout value for the request to get the tip of the block.\n        /// </param>\n        /// <param name=\"maximumPollPeers\">The maximum targets to send request to.</param>\n        /// <param name=\"cancellationToken\">\n        /// A cancellation token used to propagate notification that this\n        /// operation should be canceled.</param>\n        /// <returns>An awaitable task without value.</returns>\n        internal async Task PullBlocksAsync(\n            TimeSpan? timeout,\n            int maximumPollPeers,\n            CancellationToken cancellationToken)\n        {\n            if (maximumPollPeers <= 0)\n            {\n                return;\n            }\n\n            List<(BoundPeer, IBlockExcerpt)> peersWithBlockExcerpt =\n                await GetPeersWithExcerpts(\n                    timeout, maximumPollPeers, cancellationToken);\n            await PullBlocksAsync(peersWithBlockExcerpt, cancellationToken);\n        }\n\n        private async Task PullBlocksAsync(\n            List<(BoundPeer, IBlockExcerpt)> peersWithBlockExcerpt,\n            CancellationToken cancellationToken)\n        {\n            if (!peersWithBlockExcerpt.Any())\n            {\n                _logger.Verbose(\"No any excerpts to process\");\n                return;\n            }\n\n            long totalBlocksToDownload = 0L;\n            Block tempTip = BlockChain.Tip;\n            var blocks = new List<(Block, BlockCommit)>();\n\n            try\n            {\n                // NOTE: demandBlockHashes is always non-empty.\n                (var peer, var demandBlockHashes) = await GetDemandBlockHashes(\n                    BlockChain,\n                    peersWithBlockExcerpt,\n                    cancellationToken);\n                totalBlocksToDownload = demandBlockHashes.Count;\n\n                _logger.Verbose(\n                    \"Enqueue {BlockHashes} to demands queue...\",\n                    demandBlockHashes);\n\n                var downloadedBlocks = GetBlocksAsync(\n                    peer,\n                    demandBlockHashes,\n                    cancellationToken);\n\n                await foreach (\n                    (Block block, BlockCommit commit) in\n                        downloadedBlocks.WithCancellation(cancellationToken))\n                {\n                    _logger.Verbose(\n                        \"Got block #{BlockIndex} {BlockHash} from {Peer}\",\n                        block.Index,\n                        block.Hash,\n                        peer);\n                    cancellationToken.ThrowIfCancellationRequested();\n                    blocks.Add((block, commit));\n                }\n            }\n            catch (Exception e)\n            {\n                var msg =\n                    $\"Unexpected exception occurred during {nameof(PullBlocksAsync)}()\";\n                _logger.Error(e, msg);\n                FillBlocksAsyncFailed.Set();\n            }\n            finally\n            {\n                if (totalBlocksToDownload > 0)\n                {\n                    try\n                    {\n                        var branch = new Branch(blocks);\n                        BlockCandidateTable.Add(BlockChain.Tip.Header, branch);\n                        BlockReceived.Set();\n                    }\n                    catch (ArgumentException ae)\n                    {\n                        _logger.Error(\n                            ae,\n                            \"An Unexpected exception occurred during {FName}\",\n                            nameof(PullBlocksAsync));\n                    }\n                }\n\n                ProcessFillBlocksFinished.Set();\n                _logger.Debug(\"{MethodName}() has finished\", nameof(PullBlocksAsync));\n            }\n        }\n\n        private async Task FillBlocksAsync(\n            CancellationToken cancellationToken\n        )\n        {\n            var checkInterval = TimeSpan.FromMilliseconds(100);\n            while (!cancellationToken.IsCancellationRequested)\n            {\n                if (BlockDemandTable.Any())\n                {\n                    _logger.Debug(\n                        \"{MethodName}() blockDemand count: {BlockDemandCount}\",\n                        nameof(FillBlocksAsync),\n                        BlockDemandTable.Demands.Count);\n                    foreach (var blockDemand in BlockDemandTable.Demands.Values)\n                    {\n                        BlockDemandTable.Remove(blockDemand.Peer);\n                        _ = ProcessBlockDemandAsync(\n                            blockDemand,\n                            cancellationToken);\n                    }\n                }\n                else\n                {\n                    await Task.Delay(checkInterval, cancellationToken);\n                    continue;\n                }\n\n                BlockDemandTable.Cleanup(BlockChain, IsBlockNeeded);\n            }\n\n            _logger.Debug(\"{MethodName}() has finished\", nameof(FillBlocksAsync));\n        }\n\n        private async Task PollBlocksAsync(\n            TimeSpan timeout,\n            TimeSpan tipLifespan,\n            int maximumPollPeers,\n            CancellationToken cancellationToken\n        )\n        {\n            IBlockExcerpt lastTip = BlockChain.Tip;\n            DateTimeOffset lastUpdated = DateTimeOffset.UtcNow;\n            while (!cancellationToken.IsCancellationRequested)\n            {\n                if (!lastTip.Hash.Equals(BlockChain.Tip.Hash))\n                {\n                    lastUpdated = DateTimeOffset.UtcNow;\n                    lastTip = BlockChain.Tip;\n                }\n                else if (lastUpdated + tipLifespan < DateTimeOffset.UtcNow)\n                {\n                    _logger.Debug(\n                        \"Tip #{TipIndex} {TipHash} has expired (last updated: {LastUpdated}); \" +\n                        \"pulling blocks from neighbor peers...\",\n                        lastTip.Index,\n                        lastTip.Hash,\n                        lastUpdated\n                    );\n                    await PullBlocksAsync(\n                        timeout, maximumPollPeers, cancellationToken);\n                }\n\n                await Task.Delay(1000, cancellationToken);\n            }\n        }\n\n        private void OnBlockChainTipChanged(object sender, (Block OldTip, Block NewTip) e)\n        {\n            if (Running)\n            {\n                BroadcastBlock(e.NewTip);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Net/Swarm.Evidence.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Runtime.CompilerServices;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing Libplanet.Blockchain;\nusing Libplanet.Crypto;\nusing Libplanet.Net.Messages;\nusing Libplanet.Net.Transports;\nusing Libplanet.Types.Evidence;\nusing Libplanet.Types.Tx;\n#if NETSTANDARD2_0\nusing Libplanet.Common;\n#endif\n\nnamespace Libplanet.Net\n{\n    public partial class Swarm\n    {\n        public void BroadcastEvidence(IEnumerable<EvidenceBase> evidence)\n        {\n            BroadcastEvidence(null, evidence);\n        }\n\n        internal async IAsyncEnumerable<EvidenceBase> GetEvidenceAsync(\n            BoundPeer peer,\n            IEnumerable<EvidenceId> evidenceIds,\n            [EnumeratorCancellation] CancellationToken cancellationToken)\n        {\n            var evidenceIdsAsArray = evidenceIds as EvidenceId[] ?? evidenceIds.ToArray();\n            var request = new GetEvidenceMsg(evidenceIdsAsArray);\n            int evidenceCount = evidenceIdsAsArray.Count();\n\n            _logger.Debug(\"Required evidence count: {Count}\", evidenceCount);\n\n            var evidenceRecvTimeout = Options.TimeoutOptions.GetTxsBaseTimeout\n                + Options.TimeoutOptions.GetTxsPerTxIdTimeout.Multiply(evidenceCount);\n            if (evidenceRecvTimeout > Options.TimeoutOptions.MaxTimeout)\n            {\n                evidenceRecvTimeout = Options.TimeoutOptions.MaxTimeout;\n            }\n\n            IEnumerable<Message> replies;\n            try\n            {\n                replies = await Transport.SendMessageAsync(\n                    peer,\n                    request,\n                    evidenceRecvTimeout,\n                    evidenceCount,\n                    true,\n                    cancellationToken\n                ).ConfigureAwait(false);\n            }\n            catch (CommunicationFailException e) when (e.InnerException is TimeoutException)\n            {\n                yield break;\n            }\n\n            foreach (Message message in replies)\n            {\n                if (message.Content is EvidenceMsg parsed)\n                {\n                    EvidenceBase evidence = EvidenceBase.Deserialize(parsed.Payload);\n                    yield return evidence;\n                }\n                else\n                {\n                    string errorMessage =\n                        $\"Expected {nameof(Transaction)} messages as response of \" +\n                        $\"the {nameof(GetEvidenceMsg)} message, but got a \" +\n                        $\"{message.GetType().Name} \" +\n                        $\"message instead: {message}\";\n                    throw new InvalidMessageContentException(errorMessage, message.Content);\n                }\n            }\n        }\n\n        private void BroadcastEvidence(BoundPeer? except, IEnumerable<EvidenceBase> evidence)\n        {\n            List<EvidenceId> evidenceIds = evidence.Select(evidence => evidence.Id).ToList();\n            _logger.Information(\"Broadcasting {Count} evidenceIds...\", evidenceIds.Count);\n            BroadcastEvidenceIds(except?.Address, evidenceIds);\n        }\n\n        private async Task BroadcastEvidenceAsync(\n            TimeSpan broadcastTxInterval,\n            CancellationToken cancellationToken)\n        {\n            while (!cancellationToken.IsCancellationRequested)\n            {\n                try\n                {\n                    await Task.Delay(broadcastTxInterval, cancellationToken);\n\n                    await Task.Run(\n                        () =>\n                        {\n                            List<EvidenceId> evidenceIds = BlockChain\n                                .GetPendingEvidence()\n                                .Select(item => item.Id)\n                                .ToList();\n\n                            if (evidenceIds.Any())\n                            {\n                                _logger.Debug(\n                                    \"Broadcasting {EvidenceCount} pending evidence...\",\n                                    evidenceIds.Count);\n                                BroadcastEvidenceIds(null, evidenceIds);\n                            }\n                        }, cancellationToken);\n                }\n                catch (OperationCanceledException e)\n                {\n                    _logger.Warning(e, \"{MethodName}() was canceled\", nameof(BroadcastTxAsync));\n                    throw;\n                }\n                catch (Exception e)\n                {\n                    _logger.Error(\n                        e,\n                        \"An unexpected exception occurred during {MethodName}()\",\n                        nameof(BroadcastTxAsync));\n                }\n            }\n        }\n\n        private void BroadcastEvidenceIds(Address? except, IEnumerable<EvidenceId> evidenceIds)\n        {\n            var message = new EvidenceIdsMsg(evidenceIds);\n            BroadcastMessage(except, message);\n        }\n\n        private async Task TransferEvidenceAsync(Message message)\n        {\n            if (!await _transferEvidenceSemaphore.WaitAsync(TimeSpan.Zero, _cancellationToken))\n            {\n                _logger.Debug(\n                    \"Message {Message} is dropped due to task limit {Limit}\",\n                    message,\n                    Options.TaskRegulationOptions.MaxTransferTxsTaskCount);\n                return;\n            }\n\n            try\n            {\n                var getEvidenceMsg = (GetEvidenceMsg)message.Content;\n                foreach (EvidenceId txid in getEvidenceMsg.EvidenceIds)\n                {\n                    try\n                    {\n                        EvidenceBase? ev = BlockChain.GetPendingEvidence(txid);\n\n                        if (ev is null)\n                        {\n                            continue;\n                        }\n\n                        MessageContent response = new EvidenceMsg(ev.Serialize());\n                        await Transport.ReplyMessageAsync(response, message.Identity, default);\n                    }\n                    catch (KeyNotFoundException)\n                    {\n                        _logger.Warning(\"Requested TxId {TxId} does not exist\", txid);\n                    }\n                }\n            }\n            finally\n            {\n                int count = _transferEvidenceSemaphore.Release();\n                if (count >= 0)\n                {\n                    _logger.Debug(\n                        \"{Count}/{Limit} tasks are remaining for handling {FName}\",\n                        count,\n                        Options.TaskRegulationOptions.MaxTransferTxsTaskCount,\n                        nameof(TransferEvidenceAsync));\n                }\n            }\n        }\n\n        private void ProcessEvidenceIds(Message message)\n        {\n            var evidenceIdsMsg = (EvidenceIdsMsg)message.Content;\n            _logger.Information(\n                \"Received a {MessageType} message with {EvidenceIdCount} evidenceIds\",\n                nameof(EvidenceIdsMsg),\n                evidenceIdsMsg.Ids.Count()\n            );\n\n            EvidenceCompletion.Demand(message.Remote, evidenceIdsMsg.Ids);\n        }\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Net/Swarm.MessageHandlers.cs",
    "content": "#nullable disable\nusing System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Threading.Tasks;\nusing Libplanet.Net.Messages;\nusing Libplanet.Types.Blocks;\nusing Libplanet.Types.Tx;\n\nnamespace Libplanet.Net\n{\n    public partial class Swarm\n    {\n        private readonly NullableSemaphore _transferBlocksSemaphore;\n        private readonly NullableSemaphore _transferTxsSemaphore;\n        private readonly NullableSemaphore _transferEvidenceSemaphore;\n\n        private Task ProcessMessageHandlerAsync(Message message)\n        {\n            switch (message.Content)\n            {\n                case PingMsg _:\n                case FindNeighborsMsg _:\n                    return Task.CompletedTask;\n\n                case GetChainStatusMsg getChainStatus:\n                {\n                    _logger.Debug(\n                        \"Received a {MessageType} message\",\n                        nameof(GetChainStatusMsg));\n\n                    // This is based on the assumption that genesis block always exists.\n                    Block tip = BlockChain.Tip;\n                    var chainStatus = new ChainStatusMsg(\n                        tip.ProtocolVersion,\n                        BlockChain.Genesis.Hash,\n                        tip.Index,\n                        tip.Hash\n                    );\n\n                    return Transport.ReplyMessageAsync(\n                        chainStatus,\n                        message.Identity,\n                        default);\n                }\n\n                case GetBlockHashesMsg getBlockHashes:\n                {\n                    _logger.Debug(\n                        \"Received a {MessageType} message locator [{LocatorHead}]\",\n                        nameof(GetBlockHashesMsg),\n                        getBlockHashes.Locator.Hash);\n                    IReadOnlyList<BlockHash> hashes = BlockChain.FindNextHashes(\n                        getBlockHashes.Locator,\n                        FindNextHashesChunkSize);\n                    _logger.Debug(\n                        \"Found {HashCount} hashes after the branchpoint \" +\n                        \"with locator [{LocatorHead}]\",\n                        hashes.Count,\n                        getBlockHashes.Locator.Hash);\n                    var reply = new BlockHashesMsg(hashes);\n\n                    return Transport.ReplyMessageAsync(reply, message.Identity, default);\n                }\n\n                case GetBlocksMsg getBlocksMsg:\n                    return TransferBlocksAsync(message);\n\n                case GetTxsMsg getTxs:\n                    return TransferTxsAsync(message);\n\n                case GetEvidenceMsg getTxs:\n                    return TransferEvidenceAsync(message);\n\n                case TxIdsMsg txIds:\n                    ProcessTxIds(message);\n                    return Transport.ReplyMessageAsync(\n                        new PongMsg(),\n                        message.Identity,\n                        default\n                    );\n\n                case EvidenceIdsMsg evidenceIds:\n                    ProcessEvidenceIds(message);\n                    return Transport.ReplyMessageAsync(\n                        new PongMsg(),\n                        message.Identity,\n                        default\n                    );\n\n                case BlockHashesMsg _:\n                    _logger.Error(\n                        \"{MessageType} messages are only for IBD\",\n                        nameof(BlockHashesMsg));\n                    return Task.CompletedTask;\n\n                case BlockHeaderMsg blockHeader:\n                    ProcessBlockHeader(message);\n                    return Transport.ReplyMessageAsync(\n                        new PongMsg(),\n                        message.Identity,\n                        default\n                    );\n\n                default:\n                    throw new InvalidMessageContentException(\n                        $\"Failed to handle message: {message.Content}\",\n                        message.Content\n                    );\n            }\n        }\n\n        private void ProcessBlockHeader(Message message)\n        {\n            var blockHeaderMsg = (BlockHeaderMsg)message.Content;\n            if (!blockHeaderMsg.GenesisHash.Equals(BlockChain.Genesis.Hash))\n            {\n                _logger.Debug(\n                    \"{MessageType} message was sent from a peer {Peer} with \" +\n                    \"a different genesis block {Hash}\",\n                    nameof(BlockHeaderMsg),\n                    message.Remote,\n                    blockHeaderMsg.GenesisHash\n                );\n                return;\n            }\n\n            BlockHeaderReceived.Set();\n            BlockHeader header;\n            try\n            {\n                header = blockHeaderMsg.GetHeader();\n            }\n            catch (InvalidBlockException ibe)\n            {\n                _logger.Debug(\n                    ibe,\n                    \"Received header #{BlockIndex} {BlockHash} is invalid\",\n                    blockHeaderMsg.HeaderHash,\n                    blockHeaderMsg.HeaderIndex\n                );\n                return;\n            }\n\n            try\n            {\n                header.ValidateTimestamp();\n            }\n            catch (InvalidBlockTimestampException e)\n            {\n                _logger.Debug(\n                    e,\n                    \"Received header #{BlockIndex} {BlockHash} has invalid timestamp: {Timestamp}\",\n                    header.Index,\n                    header.Hash,\n                    header.Timestamp\n                );\n                return;\n            }\n\n            bool needed = IsBlockNeeded(header);\n            _logger.Information(\n                \"Received \" + nameof(BlockHeader) + \" #{ReceivedIndex} {ReceivedHash}\",\n                header.Index,\n                header.Hash);\n\n            if (needed)\n            {\n                _logger.Information(\n                    \"Adding received header #{BlockIndex} {BlockHash} from peer {Peer} to \" +\n                    nameof(BlockDemandTable) + \"...\",\n                    header.Index,\n                    header.Hash,\n                    message.Remote);\n                BlockDemandTable.Add(\n                    BlockChain,\n                    IsBlockNeeded,\n                    new BlockDemand(header, message.Remote, DateTimeOffset.UtcNow));\n                return;\n            }\n            else\n            {\n                _logger.Information(\n                    \"Discarding received header #{ReceivedIndex} {ReceivedHash} from peer {Peer} \" +\n                    \"as it is not needed for the current chain with tip #{TipIndex} {TipHash}\",\n                    header.Index,\n                    header.Hash,\n                    message.Remote,\n                    BlockChain.Tip.Index,\n                    BlockChain.Tip.Hash);\n                return;\n            }\n        }\n\n        private async Task TransferTxsAsync(Message message)\n        {\n            if (!await _transferTxsSemaphore.WaitAsync(TimeSpan.Zero, _cancellationToken))\n            {\n                _logger.Debug(\n                    \"Message {Message} is dropped due to task limit {Limit}\",\n                    message,\n                    Options.TaskRegulationOptions.MaxTransferTxsTaskCount);\n                return;\n            }\n\n            try\n            {\n                var getTxsMsg = (GetTxsMsg)message.Content;\n                foreach (TxId txid in getTxsMsg.TxIds)\n                {\n                    try\n                    {\n                        Transaction tx = BlockChain.GetTransaction(txid);\n\n                        if (tx is null)\n                        {\n                            continue;\n                        }\n\n                        MessageContent response = new TxMsg(tx.Serialize());\n                        await Transport.ReplyMessageAsync(response, message.Identity, default);\n                    }\n                    catch (KeyNotFoundException)\n                    {\n                        _logger.Warning(\"Requested TxId {TxId} does not exist\", txid);\n                    }\n                }\n            }\n            finally\n            {\n                int count = _transferTxsSemaphore.Release();\n                if (count >= 0)\n                {\n                    _logger.Debug(\n                        \"{Count}/{Limit} tasks are remaining for handling {FName}\",\n                        count,\n                        Options.TaskRegulationOptions.MaxTransferTxsTaskCount,\n                        nameof(TransferTxsAsync));\n                }\n            }\n        }\n\n        private void ProcessTxIds(Message message)\n        {\n            var txIdsMsg = (TxIdsMsg)message.Content;\n            _logger.Information(\n                \"Received a {MessageType} message with {TxIdCount} txIds\",\n                nameof(TxIdsMsg),\n                txIdsMsg.Ids.Count()\n            );\n\n            TxCompletion.Demand(message.Remote, txIdsMsg.Ids);\n        }\n\n        private async Task TransferBlocksAsync(Message message)\n        {\n            if (!await _transferBlocksSemaphore.WaitAsync(TimeSpan.Zero, _cancellationToken))\n            {\n                _logger.Debug(\n                    \"Message {Message} is dropped due to task limit {Limit}\",\n                    message,\n                    Options.TaskRegulationOptions.MaxTransferBlocksTaskCount);\n                return;\n            }\n\n            try\n            {\n                var blocksMsg = (GetBlocksMsg)message.Content;\n                string reqId = !(message.Identity is null) && message.Identity.Length == 16\n                    ? new Guid(message.Identity).ToString()\n                    : \"unknown\";\n                _logger.Verbose(\n                    \"Preparing a {MessageType} message to reply to {Identity}...\",\n                    nameof(Messages.BlocksMsg),\n                    reqId);\n\n                var payloads = new List<byte[]>();\n\n                List<BlockHash> hashes = blocksMsg.BlockHashes.ToList();\n                int count = 0;\n                int total = hashes.Count;\n                const string logMsg =\n                    \"Fetching block {Index}/{Total} {Hash} to include in \" +\n                    \"a reply to {Identity}...\";\n                foreach (BlockHash hash in hashes)\n                {\n                    _logger.Verbose(logMsg, count, total, hash, reqId);\n                    if (_store.GetBlock(hash) is { } block)\n                    {\n                        byte[] blockPayload = Codec.Encode(block.MarshalBlock());\n                        payloads.Add(blockPayload);\n                        byte[] commitPayload = BlockChain.GetBlockCommit(block.Hash) is { } commit\n                            ? Codec.Encode(commit.Bencoded)\n                            : Array.Empty<byte>();\n                        payloads.Add(commitPayload);\n                        count++;\n                    }\n\n                    if (payloads.Count / 2 == blocksMsg.ChunkSize)\n                    {\n                        var response = new BlocksMsg(payloads);\n                        _logger.Verbose(\n                            \"Enqueuing a blocks reply (...{Count}/{Total})...\",\n                            count,\n                            total\n                        );\n                        await Transport.ReplyMessageAsync(response, message.Identity, default);\n                        payloads.Clear();\n                    }\n                }\n\n                if (payloads.Any())\n                {\n                    var response = new BlocksMsg(payloads);\n                    _logger.Verbose(\n                        \"Enqueuing a blocks reply (...{Count}/{Total}) to {Identity}...\",\n                        count,\n                        total,\n                        reqId);\n                    await Transport.ReplyMessageAsync(response, message.Identity, default);\n                }\n\n                if (count == 0)\n                {\n                    var response = new BlocksMsg(payloads);\n                    _logger.Verbose(\n                        \"Enqueuing a blocks reply (...{Index}/{Total}) to {Identity}...\",\n                        count,\n                        total,\n                        reqId);\n                    await Transport.ReplyMessageAsync(response, message.Identity, default);\n                }\n\n                _logger.Debug(\"{Count} blocks were transferred to {Identity}\", count, reqId);\n            }\n            finally\n            {\n                int count = _transferBlocksSemaphore.Release();\n                if (count >= 0)\n                {\n                    _logger.Debug(\n                        \"{Count}/{Limit} tasks are remaining for handling {FName}\",\n                        count,\n                        Options.TaskRegulationOptions.MaxTransferBlocksTaskCount,\n                        nameof(TransferBlocksAsync));\n                }\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Net/Swarm.cs",
    "content": "#nullable disable\nusing System;\nusing System.Collections.Concurrent;\nusing System.Collections.Generic;\nusing System.Collections.Immutable;\nusing System.Linq;\nusing System.Net;\nusing System.Runtime.CompilerServices;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing Bencodex;\nusing Libplanet.Action;\nusing Libplanet.Blockchain;\n#if NETSTANDARD2_0\nusing Libplanet.Common;\n#endif\nusing Libplanet.Crypto;\nusing Libplanet.Net.Consensus;\nusing Libplanet.Net.Messages;\nusing Libplanet.Net.Options;\nusing Libplanet.Net.Protocols;\nusing Libplanet.Net.Transports;\nusing Libplanet.Store;\nusing Libplanet.Types.Blocks;\nusing Libplanet.Types.Tx;\nusing Nito.AsyncEx;\nusing Serilog;\n\nnamespace Libplanet.Net\n{\n    public partial class Swarm : IDisposable\n    {\n        private const int InitialBlockDownloadWindow = 100;\n        private static readonly Codec Codec = new Codec();\n\n        private readonly PrivateKey _privateKey;\n\n        private readonly AsyncLock _runningMutex;\n\n        private readonly ILogger _logger;\n        private readonly IStore _store;\n        private readonly ConsensusReactor _consensusReactor;\n\n        private CancellationTokenSource _workerCancellationTokenSource;\n        private CancellationToken _cancellationToken;\n\n        private bool _disposed;\n\n        /// <summary>\n        /// Creates a <see cref=\"Swarm\"/>.  This constructor in only itself does not start\n        /// any communication with the network.\n        /// </summary>\n        /// <param name=\"blockChain\">A blockchain to publicize on the network.</param>\n        /// <param name=\"privateKey\">A private key to sign messages.  The public part of\n        /// this key become a part of its end address for being pointed by peers.</param>\n        /// <param name=\"transport\">The <see cref=\"ITransport\"/> to use for\n        /// network communication in block synchronization.</param>\n        /// <param name=\"options\">Options for <see cref=\"Swarm\"/>.</param>\n        /// <param name=\"consensusTransport\">The <see cref=\"ITransport\"/> to use for\n        /// network communication in consensus.\n        /// If null is given, the node cannot join block consensus.\n        /// </param>\n        /// <param name=\"consensusOption\"><see cref=\"ConsensusReactorOption\"/> for\n        /// initialize <see cref=\"ConsensusReactor\"/>.</param>\n        public Swarm(\n            BlockChain blockChain,\n            PrivateKey privateKey,\n            ITransport transport,\n            SwarmOptions options = null,\n            ITransport consensusTransport = null,\n            ConsensusReactorOption? consensusOption = null)\n        {\n            BlockChain = blockChain ?? throw new ArgumentNullException(nameof(blockChain));\n            _store = BlockChain.Store;\n            _privateKey = privateKey ?? throw new ArgumentNullException(nameof(privateKey));\n            LastSeenTimestamps =\n                new ConcurrentDictionary<BoundPeer, DateTimeOffset>();\n            BlockHeaderReceived = new AsyncAutoResetEvent();\n            BlockAppended = new AsyncAutoResetEvent();\n            BlockReceived = new AsyncAutoResetEvent();\n\n            _runningMutex = new AsyncLock();\n\n            string loggerId = _privateKey.Address.ToHex();\n            _logger = Log\n                .ForContext<Swarm>()\n                .ForContext(\"Source\", nameof(Swarm))\n                .ForContext(\"SwarmId\", loggerId);\n\n            Options = options ?? new SwarmOptions();\n            TxCompletion = new TxCompletion<BoundPeer>(BlockChain, GetTxsAsync, BroadcastTxs);\n            EvidenceCompletion =\n                new EvidenceCompletion<BoundPeer>(\n                    BlockChain, GetEvidenceAsync, BroadcastEvidence);\n            RoutingTable = new RoutingTable(Address, Options.TableSize, Options.BucketSize);\n\n            // FIXME: after the initialization of NetMQTransport is fully converted to asynchronous\n            // code, the portion initializing the swarm in Agent.cs in NineChronicles should be\n            // fixed. for context, refer to\n            // https://github.com/planetarium/libplanet/discussions/2303.\n            Transport = transport;\n            _processBlockDemandSessions = new ConcurrentDictionary<BoundPeer, int>();\n            Transport.ProcessMessageHandler.Register(ProcessMessageHandlerAsync);\n            PeerDiscovery = new KademliaProtocol(RoutingTable, Transport, Address);\n            BlockDemandTable = new BlockDemandTable(Options.BlockDemandLifespan);\n            BlockCandidateTable = new BlockCandidateTable();\n\n            // Regulate heavy tasks. Treat negative value as 0.\n            var taskRegulationOptions = Options.TaskRegulationOptions;\n            _transferBlocksSemaphore =\n                new NullableSemaphore(taskRegulationOptions.MaxTransferBlocksTaskCount);\n            _transferTxsSemaphore =\n                new NullableSemaphore(taskRegulationOptions.MaxTransferTxsTaskCount);\n            _transferEvidenceSemaphore =\n                new NullableSemaphore(taskRegulationOptions.MaxTransferTxsTaskCount);\n\n            // Initialize consensus reactor.\n            if (consensusTransport is { } && consensusOption is { } consensusReactorOption)\n            {\n                _consensusReactor = new ConsensusReactor(\n                    consensusTransport,\n                    BlockChain,\n                    consensusReactorOption.ConsensusPrivateKey,\n                    consensusReactorOption.ConsensusPeers,\n                    consensusReactorOption.SeedPeers,\n                    consensusReactorOption.TargetBlockInterval,\n                    consensusReactorOption.ContextOption);\n            }\n        }\n\n        ~Swarm()\n        {\n            // FIXME If possible, we should stop Swarm appropriately here.\n            if (Running)\n            {\n                _logger.Warning(\n                    \"Swarm is scheduled to destruct, but Transport progress is still running\"\n                );\n            }\n        }\n\n        public bool Running => Transport?.Running ?? false;\n\n        public bool ConsensusRunning => _consensusReactor?.Running ?? false;\n\n        public DnsEndPoint EndPoint => AsPeer is BoundPeer boundPeer ? boundPeer.EndPoint : null;\n\n        public Address Address => _privateKey.Address;\n\n        public BoundPeer AsPeer => Transport?.AsPeer;\n\n        /// <summary>\n        /// The last time when any message was arrived.\n        /// It can be <see langword=\"null\"/> if no message has been arrived yet.\n        /// </summary>\n        public DateTimeOffset? LastMessageTimestamp =>\n            Running ? Transport.LastMessageTimestamp : (DateTimeOffset?)null;\n\n        public IDictionary<BoundPeer, DateTimeOffset> LastSeenTimestamps { get; private set; }\n\n        public IReadOnlyList<BoundPeer> Peers => RoutingTable.Peers;\n\n        /// <summary>\n        /// Returns list of the validators that consensus has in its routing table.\n        /// If the node is not joining consensus, returns <c>null</c>.\n        /// </summary>\n        public IReadOnlyList<BoundPeer> Validators => _consensusReactor?.Validators;\n\n        /// <summary>\n        /// The <see cref=\"BlockChain\"/> instance this <see cref=\"Swarm\"/> instance\n        /// synchronizes with.\n        /// </summary>\n        public BlockChain BlockChain { get; private set; }\n\n        /// <inheritdoc cref=\"AppProtocolVersionOptions.TrustedAppProtocolVersionSigners\"/>\n        public IImmutableSet<PublicKey> TrustedAppProtocolVersionSigners =>\n            Transport.TrustedAppProtocolVersionSigners;\n\n        /// <inheritdoc cref=\"AppProtocolVersionOptions.AppProtocolVersion\"/>\n        public AppProtocolVersion AppProtocolVersion =>\n            Transport.AppProtocolVersion;\n\n        internal RoutingTable RoutingTable { get; }\n\n        internal IProtocol PeerDiscovery { get; }\n\n        internal ITransport Transport { get; }\n\n        internal TxCompletion<BoundPeer> TxCompletion { get; }\n\n        internal EvidenceCompletion<BoundPeer> EvidenceCompletion { get; }\n\n        internal AsyncAutoResetEvent TxReceived => TxCompletion?.TxReceived;\n\n        internal AsyncAutoResetEvent EvidenceReceived => EvidenceCompletion?.EvidenceReceived;\n\n        internal AsyncAutoResetEvent BlockHeaderReceived { get; }\n\n        internal AsyncAutoResetEvent BlockReceived { get; }\n\n        // FIXME: Should have a unit test.\n        internal AsyncAutoResetEvent BlockAppended { get; }\n\n        // FIXME: We need some sort of configuration method for it.\n        internal int FindNextHashesChunkSize { get; set; } = 500;\n\n        internal AsyncAutoResetEvent BlockDownloadStarted { get; } = new AsyncAutoResetEvent();\n\n        internal SwarmOptions Options { get; }\n\n        // FIXME: This should be exposed in a better way.\n        internal ConsensusReactor ConsensusReactor => _consensusReactor;\n\n        /// <summary>\n        /// Waits until this <see cref=\"Swarm\"/> instance gets started to run.\n        /// </summary>\n        /// <seealso cref=\"ITransport.WaitForRunningAsync()\"/>\n        /// <returns>A <see cref=\"Task\"/> completed when <see cref=\"ITransport.Running\"/>\n        /// property becomes <see langword=\"true\"/>.</returns>\n        public Task WaitForRunningAsync() => Transport?.WaitForRunningAsync();\n\n        public void Dispose()\n        {\n            if (!_disposed)\n            {\n                _workerCancellationTokenSource?.Cancel();\n                TxCompletion?.Dispose();\n                Transport?.Dispose();\n                _consensusReactor?.Dispose();\n                _workerCancellationTokenSource?.Dispose();\n                _disposed = true;\n            }\n        }\n\n        public async Task StopAsync(\n            CancellationToken cancellationToken = default\n        )\n        {\n            await StopAsync(TimeSpan.FromSeconds(1), cancellationToken);\n        }\n\n        public async Task StopAsync(\n            TimeSpan waitFor,\n            CancellationToken cancellationToken = default\n        )\n        {\n            _logger.Debug(\"Stopping watching \" + nameof(BlockChain) + \" for tip changes...\");\n            BlockChain.TipChanged -= OnBlockChainTipChanged;\n\n            _logger.Debug($\"Stopping {nameof(Swarm)}...\");\n            using (await _runningMutex.LockAsync())\n            {\n                await Transport.StopAsync(waitFor, cancellationToken);\n                if (_consensusReactor is { })\n                {\n                    await _consensusReactor.StopAsync(cancellationToken);\n                }\n            }\n\n            BlockDemandTable = new BlockDemandTable(Options.BlockDemandLifespan);\n            BlockCandidateTable = new BlockCandidateTable();\n            _logger.Debug($\"{nameof(Swarm)} stopped\");\n        }\n\n        /// <summary>\n        /// Starts to periodically synchronize the <see cref=\"BlockChain\"/>.\n        /// </summary>\n        /// <param name=\"cancellationToken\">\n        /// A cancellation token used to propagate notification that this\n        /// operation should be canceled.\n        /// </param>\n        /// <returns>An awaitable task without value.</returns>\n        /// <exception cref=\"SwarmException\">Thrown when this <see cref=\"Swarm\"/> instance is\n        /// already <see cref=\"Running\"/>.</exception>\n        /// <remarks>If the <see cref=\"BlockChain\"/> has no blocks at all or there are long behind\n        /// blocks to caught in the network this method could lead to unexpected behaviors, because\n        /// this tries to render <em>all</em> actions in the behind blocks so that there are\n        /// a lot of calls to methods of <see cref=\"BlockChain.Renderers\"/> in a short\n        /// period of time.  This can lead a game startup slow.  If you want to omit rendering of\n        /// these actions in the behind blocks use\n        /// <see cref=\"PreloadAsync(IProgress{BlockSyncState}, CancellationToken)\"/>\n        /// method too.</remarks>\n        public async Task StartAsync(CancellationToken cancellationToken = default)\n        {\n            await StartAsync(\n                Options.TimeoutOptions.DialTimeout,\n                Options.BlockBroadcastInterval,\n                Options.TxBroadcastInterval,\n                cancellationToken);\n        }\n\n        /// <summary>\n        /// Starts to periodically synchronize the <see cref=\"BlockChain\"/>.\n        /// </summary>\n        /// <param name=\"dialTimeout\">\n        /// When the <see cref=\"Swarm\"/> tries to dial each peer in <see cref=\"Peers\"/>,\n        /// the dial-up is cancelled after this timeout, and it tries another peer.\n        /// If <see langword=\"null\"/> is given it never gives up dial-ups.\n        /// </param>\n        /// <param name=\"broadcastBlockInterval\">Time interval between each broadcast of\n        /// chain tip.</param>\n        /// <param name=\"broadcastTxInterval\">Time interval between each broadcast of staged\n        /// transactions.</param>\n        /// <param name=\"cancellationToken\">\n        /// A cancellation token used to propagate notification that this\n        /// operation should be canceled.\n        /// </param>\n        /// <returns>An awaitable task without value.</returns>\n        /// <exception cref=\"SwarmException\">Thrown when this <see cref=\"Swarm\"/> instance is\n        /// already <see cref=\"Running\"/>.</exception>\n        /// <remarks>If the <see cref=\"BlockChain\"/> has no blocks at all or there are long behind\n        /// blocks to caught in the network this method could lead to unexpected behaviors, because\n        /// this tries to render <em>all</em> actions in the behind blocks so that there are\n        /// a lot of calls to methods of <see cref=\"BlockChain.Renderers\"/> in a short\n        /// period of time.  This can lead a game startup slow.  If you want to omit rendering of\n        /// these actions in the behind blocks use\n        /// <see cref=\"PreloadAsync(IProgress{BlockSyncState}, CancellationToken)\"/>\n        /// method too.</remarks>\n        public async Task StartAsync(\n            TimeSpan dialTimeout,\n            TimeSpan broadcastBlockInterval,\n            TimeSpan broadcastTxInterval,\n            CancellationToken cancellationToken = default)\n        {\n            Task<Task> runner;\n            using (await _runningMutex.LockAsync().ConfigureAwait(false))\n            {\n                _workerCancellationTokenSource = new CancellationTokenSource();\n                _cancellationToken = CancellationTokenSource.CreateLinkedTokenSource(\n                    _workerCancellationTokenSource.Token, cancellationToken\n                ).Token;\n\n                if (Transport.Running)\n                {\n                    throw new SwarmException(\"Swarm is already running.\");\n                }\n\n                _logger.Debug(\"Starting swarm...\");\n                _logger.Debug(\"Peer information : {Peer}\", AsPeer);\n\n                _logger.Debug(\"Watching the \" + nameof(BlockChain) + \" for tip changes...\");\n                BlockChain.TipChanged += OnBlockChainTipChanged;\n\n                var tasks = new List<Func<Task>>\n                {\n                    () => Transport.StartAsync(_cancellationToken),\n                    () => BroadcastBlockAsync(broadcastBlockInterval, _cancellationToken),\n                    () => BroadcastTxAsync(broadcastTxInterval, _cancellationToken),\n                    () => FillBlocksAsync(_cancellationToken),\n                    () => PollBlocksAsync(\n                        dialTimeout,\n                        Options.TipLifespan,\n                        Options.MaximumPollPeers,\n                        _cancellationToken\n                    ),\n                    () => ConsumeBlockCandidates(\n                        TimeSpan.FromMilliseconds(10), true, _cancellationToken),\n                    () => RefreshTableAsync(\n                        Options.RefreshPeriod,\n                        Options.RefreshLifespan,\n                        _cancellationToken),\n                    () => RebuildConnectionAsync(TimeSpan.FromMinutes(30), _cancellationToken),\n                    () => BroadcastEvidenceAsync(broadcastTxInterval, _cancellationToken),\n                };\n\n                if (_consensusReactor is { })\n                {\n                    tasks.Add(() => _consensusReactor.StartAsync(_cancellationToken));\n                }\n\n                if (Options.StaticPeers.Any())\n                {\n                    tasks.Add(\n                        () => MaintainStaticPeerAsync(\n                            Options.StaticPeersMaintainPeriod,\n                            _cancellationToken\n                        )\n                    );\n                }\n\n                runner = Task.WhenAny(tasks.Select(CreateLongRunningTask));\n                await Transport.WaitForRunningAsync().ConfigureAwait(false);\n            }\n\n            try\n            {\n                _logger.Debug(\"Swarm started\");\n                await await runner;\n            }\n            catch (OperationCanceledException e)\n            {\n                _logger.Warning(e, \"{MethodName}() is canceled\", nameof(StartAsync));\n                throw;\n            }\n            catch (Exception e)\n            {\n                _logger.Error(\n                    e,\n                    \"An unexpected exception occurred during {MethodName}()\",\n                    nameof(StartAsync));\n                throw;\n            }\n        }\n\n        /// <summary>\n        /// Join to the peer-to-peer network using seed peers.\n        /// </summary>\n        /// <param name=\"cancellationToken\">A cancellation token used to propagate notification\n        /// that this operation should be canceled.</param>\n        /// <returns>An awaitable task without value.</returns>\n        /// <exception cref=\"SwarmException\">Thrown when this <see cref=\"Swarm\"/> instance is\n        /// not <see cref=\"Running\"/>.</exception>\n        public async Task BootstrapAsync(CancellationToken cancellationToken = default)\n        {\n            await BootstrapAsync(\n                seedPeers: Options.BootstrapOptions.SeedPeers,\n                dialTimeout: Options.BootstrapOptions.DialTimeout,\n                searchDepth: Options.BootstrapOptions.SearchDepth,\n                cancellationToken: cancellationToken)\n                .ConfigureAwait(false);\n        }\n\n        /// <summary>\n        /// Join to the peer-to-peer network using seed peers.\n        /// </summary>\n        /// <param name=\"seedPeers\">List of seed peers.</param>\n        /// <param name=\"dialTimeout\">Timeout for connecting to peers.</param>\n        /// <param name=\"searchDepth\">Maximum recursion depth when finding neighbors of\n        /// current <see cref=\"BoundPeer\"/> from seed peers.</param>\n        /// <param name=\"cancellationToken\">A cancellation token used to propagate notification\n        /// that this operation should be canceled.</param>\n        /// <returns>An awaitable task without value.</returns>\n        /// <exception cref=\"SwarmException\">Thrown when this <see cref=\"Swarm\"/> instance is\n        /// not <see cref=\"Running\"/>.</exception>\n        public async Task BootstrapAsync(\n            IEnumerable<BoundPeer> seedPeers,\n            TimeSpan? dialTimeout,\n            int searchDepth,\n            CancellationToken cancellationToken = default)\n        {\n            if (seedPeers is null)\n            {\n                throw new ArgumentNullException(nameof(seedPeers));\n            }\n\n            IReadOnlyList<BoundPeer> peersBeforeBootstrap = RoutingTable.Peers;\n\n            await PeerDiscovery.BootstrapAsync(\n                seedPeers,\n                dialTimeout,\n                searchDepth,\n                cancellationToken).ConfigureAwait(false);\n\n            if (!Transport.Running)\n            {\n                // Mark added peers as stale if bootstrap is called before transport is running\n                // FIXME: Peers added before bootstrap might be updated.\n                foreach (BoundPeer peer in RoutingTable.Peers.Except(peersBeforeBootstrap))\n                {\n                    RoutingTable.AddPeer(peer, DateTimeOffset.MinValue);\n                }\n            }\n        }\n\n        /// <summary>\n        /// Broadcasts the given block to peers.\n        /// <para>The message is immediately broadcasted, and it is done if the same block has\n        /// already been broadcasted before.</para>\n        /// </summary>\n        /// <param name=\"block\">The block to broadcast to peers.</param>\n        /// <remarks>It does not have to be called manually, because <see cref=\"Swarm\"/> in\n        /// itself watches <see cref=\"BlockChain\"/> for <see cref=\"BlockChain.Tip\"/> changes and\n        /// immediately broadcasts updates if anything changes.</remarks>\n        public void BroadcastBlock(Block block)\n        {\n            BroadcastBlock(null, block);\n        }\n\n        public void BroadcastTxs(IEnumerable<Transaction> txs)\n        {\n            BroadcastTxs(null, txs);\n        }\n\n        /// <summary>\n        /// Gets the <see cref=\"PeerChainState\"/> of the connected <see cref=\"Peers\"/>.\n        /// </summary>\n        /// <param name=\"dialTimeout\">\n        /// When the <see cref=\"Swarm\"/> tries to dial each peer in <see cref=\"Peers\"/>,\n        /// the dial-up is cancelled after this timeout, and it tries another peer.\n        /// If <see langword=\"null\"/> is given it never gives up dial-ups.\n        /// </param>\n        /// <param name=\"cancellationToken\">\n        /// A cancellation token used to propagate notification that this\n        /// operation should be canceled.\n        /// </param>\n        /// <returns><see cref=\"PeerChainState\"/> of the connected <see cref=\"Peers\"/>.</returns>\n        public async Task<IEnumerable<PeerChainState>> GetPeerChainStateAsync(\n            TimeSpan? dialTimeout,\n            CancellationToken cancellationToken\n        )\n        {\n            // FIXME: It would be better if it returns IAsyncEnumerable<PeerChainState> instead.\n            return (await DialExistingPeers(dialTimeout, int.MaxValue, cancellationToken))\n                .Select(pp =>\n                    new PeerChainState(\n                        pp.Item1,\n                        pp.Item2?.TipIndex ?? -1));\n        }\n\n        /// <summary>\n        /// Preemptively downloads blocks from registered <see cref=\"BoundPeer\"/>s.\n        /// </summary>\n        /// <param name=\"progress\">\n        /// An instance that receives progress updates for block downloads.\n        /// </param>\n        /// <param name=\"cancellationToken\">\n        /// A cancellation token used to propagate notification that this\n        /// operation should be canceled.\n        /// </param>\n        /// <returns>\n        /// A task without value.\n        /// You only can <c>await</c> until the method is completed.\n        /// </returns>\n        /// <remarks>This does not render downloaded <see cref=\"IAction\"/>s, but fills states only.\n        /// </remarks>\n        /// <exception cref=\"AggregateException\">Thrown when the given the block downloading is\n        /// failed.</exception>\n        public async Task PreloadAsync(\n            IProgress<BlockSyncState> progress = null,\n            CancellationToken cancellationToken = default)\n        {\n            await PreloadAsync(\n                Options.PreloadOptions.DialTimeout,\n                Options.PreloadOptions.TipDeltaThreshold,\n                progress,\n                cancellationToken);\n        }\n\n        /// <summary>\n        /// Preemptively downloads blocks from registered <see cref=\"BoundPeer\"/>s.\n        /// </summary>\n        /// <param name=\"dialTimeout\">\n        /// When the <see cref=\"Swarm\"/> tries to dial each peer in <see cref=\"Peers\"/>,\n        /// the dial-up is cancelled after this timeout, and it tries another peer.\n        /// If <see langword=\"null\"/> is given it never gives up dial-ups.\n        /// </param>\n        /// <param name=\"tipDeltaThreshold\">The threshold of the difference between the topmost tip\n        /// among peers and the local tip.  If the local tip is still behind the topmost tip among\n        /// peers by more than this threshold after a preloading is once done, the preloading\n        /// is repeated.</param>\n        /// <param name=\"progress\">\n        /// An instance that receives progress updates for block downloads.\n        /// </param>\n        /// <param name=\"cancellationToken\">\n        /// A cancellation token used to propagate notification that this\n        /// operation should be canceled.\n        /// </param>\n        /// <returns>\n        /// A task without value.\n        /// You only can <c>await</c> until the method is completed.\n        /// </returns>\n        /// <remarks>This does not render downloaded <see cref=\"IAction\"/>s, but fills states only.\n        /// </remarks>\n        /// <exception cref=\"AggregateException\">Thrown when the given the block downloading is\n        /// failed.</exception>\n        public async Task PreloadAsync(\n            TimeSpan? dialTimeout,\n            long tipDeltaThreshold,\n            IProgress<BlockSyncState> progress = null,\n            CancellationToken cancellationToken = default)\n        {\n            using CancellationTokenRegistration ctr = cancellationToken.Register(() =>\n                _logger.Information(\"Preloading is requested to be cancelled\")\n            );\n\n            _logger.Debug(\n                \"Tip before preloading: #{TipIndex} {TipHash}\",\n                BlockChain.Tip.Index,\n                BlockChain.Tip.Hash\n            );\n\n            // FIXME: Currently `IProgress<PreloadState>` can be rewinded to the previous stage\n            // as it starts from the first stage when it's still not close enough to the topmost\n            // tip in the network.\n            for (int i = 0; !cancellationToken.IsCancellationRequested; i++)\n            {\n                _logger.Information(\n                    \"Fetching excerpts from {PeersCount} peers...\",\n                    Peers.Count);\n                var peersWithExcerpts = await GetPeersWithExcerpts(\n                    dialTimeout, int.MaxValue, cancellationToken);\n\n                if (!peersWithExcerpts.Any())\n                {\n                    _logger.Information(\"There are no appropriate peers for preloading\");\n                    break;\n                }\n                else\n                {\n                    _logger.Information(\n                        \"Fetched {PeersWithExcerptsCount} excerpts from {PeersCount} peers\",\n                        peersWithExcerpts.Count,\n                        Peers.Count);\n                }\n\n                Block localTip = BlockChain.Tip;\n                IBlockExcerpt topmostTip = peersWithExcerpts\n                    .Select(pair => pair.Item2)\n                    .Aggregate((prev, next) => prev.Index > next.Index ? prev : next);\n                if (topmostTip.Index - (i > 0 ? tipDeltaThreshold : 0L) <= localTip.Index)\n                {\n                    const string msg =\n                        \"As the local tip (#{LocalTipIndex} {LocalTipHash}) is close enough to \" +\n                        \"the topmost tip in the network (#{TopmostTipIndex} {TopmostTipHash}), \" +\n                        \"preloading is no longer needed\";\n                    _logger.Information(\n                        msg,\n                        localTip.Index,\n                        localTip.Hash,\n                        topmostTip.Index,\n                        topmostTip.Hash\n                    );\n                    break;\n                }\n                else\n                {\n                    const string msg =\n                        \"As the local tip (#{LocalTipIndex} {LocalTipHash}) is still not close \" +\n                        \"enough to the topmost tip in the network \" +\n                        \"(#{TopmostTipIndex} {TopmostTipHash}), preload one more time...\";\n                    _logger.Information(\n                        msg,\n                        localTip.Index,\n                        localTip.Hash,\n                        topmostTip.Index,\n                        topmostTip.Hash\n                    );\n                }\n\n                _logger.Information(\"Preloading (trial #{Trial}) started...\", i + 1);\n\n                BlockCandidateTable.Cleanup((_) => true);\n                await PullBlocksAsync(\n                    peersWithExcerpts,\n                    cancellationToken);\n\n                await ConsumeBlockCandidates(\n                    render: false,\n                    cancellationToken: cancellationToken);\n            }\n\n            cancellationToken.ThrowIfCancellationRequested();\n        }\n\n        /// <summary>\n        /// Use <see cref=\"FindNeighborsMsg\"/> messages to find a <see cref=\"BoundPeer\"/> with\n        /// <see cref=\"Address\"/> of <paramref name=\"target\"/>.\n        /// </summary>\n        /// <param name=\"target\">The <see cref=\"Address\"/> to find.</param>\n        /// <param name=\"depth\">Target depth of recursive operation. If -1 is given,\n        /// will recursive until the closest <see cref=\"BoundPeer\"/> to the\n        /// <paramref name=\"target\"/> is found.</param>\n        /// <param name=\"timeout\">\n        /// <see cref=\"TimeSpan\"/> for waiting reply of <see cref=\"FindNeighborsMsg\"/>.\n        /// If <see langword=\"null\"/> is given, <see cref=\"TimeoutException\"/> will not be thrown.\n        /// </param>\n        /// <param name=\"cancellationToken\">A cancellation token used to propagate notification\n        /// that this operation should be canceled.</param>\n        /// <returns>\n        /// A <see cref=\"BoundPeer\"/> with <see cref=\"Address\"/> of <paramref name=\"target\"/>.\n        /// Returns <see langword=\"null\"/> if the peer with address does not exist.\n        /// </returns>\n        public async Task<BoundPeer> FindSpecificPeerAsync(\n            Address target,\n            int depth = 3,\n            TimeSpan? timeout = null,\n            CancellationToken cancellationToken = default)\n        {\n            KademliaProtocol kademliaProtocol = (KademliaProtocol)PeerDiscovery;\n            return await kademliaProtocol.FindSpecificPeerAsync(\n                target,\n                depth,\n                timeout,\n                cancellationToken);\n        }\n\n        /// <summary>\n        /// Validates all <see cref=\"BoundPeer\"/>s in the routing table by sending a simple message.\n        /// </summary>\n        /// <param name=\"timeout\">Timeout for this operation. If it is set to\n        /// <see langword=\"null\"/>, wait infinitely until the requested operation is finished.\n        /// </param>\n        /// <param name=\"cancellationToken\">A cancellation token used to propagate notification\n        /// that this operation should be canceled.</param>\n        /// <returns>An awaitable task without value.</returns>\n        public async Task CheckAllPeersAsync(\n            TimeSpan? timeout = null,\n            CancellationToken cancellationToken = default)\n        {\n            using CancellationTokenSource cts = CancellationTokenSource\n                .CreateLinkedTokenSource(cancellationToken, _cancellationToken);\n            cancellationToken = cts.Token;\n\n            KademliaProtocol kademliaProtocol = (KademliaProtocol)PeerDiscovery;\n            await kademliaProtocol.CheckAllPeersAsync(timeout, cancellationToken);\n        }\n\n        /// <summary>\n        /// Adds <paramref name=\"peers\"/> to routing table by sending a simple message.\n        /// </summary>\n        /// <param name=\"peers\">A list of peers to add.</param>\n        /// <param name=\"timeout\">Timeout for this operation. If it is set to\n        /// <see langword=\"null\"/>, wait infinitely until the requested operation is finished.\n        /// </param>\n        /// <param name=\"cancellationToken\">A cancellation token used to propagate notification\n        /// that this operation should be canceled.</param>\n        /// <returns>An awaitable task without value.</returns>\n        public Task AddPeersAsync(\n            IEnumerable<BoundPeer> peers,\n            TimeSpan? timeout,\n            CancellationToken cancellationToken = default)\n        {\n            if (Transport is null)\n            {\n                throw new ArgumentNullException(nameof(Transport));\n            }\n\n            if (cancellationToken == default)\n            {\n                cancellationToken = _cancellationToken;\n            }\n\n            return PeerDiscovery.AddPeersAsync(peers, timeout, cancellationToken);\n        }\n\n        // FIXME: This would be better if it's merged with GetDemandBlockHashes\n        internal async Task<List<BlockHash>> GetBlockHashes(\n            BoundPeer peer,\n            BlockLocator locator,\n            CancellationToken cancellationToken = default)\n        {\n            var request = new GetBlockHashesMsg(locator);\n\n            const string sendMsg =\n                \"Sending a {MessageType} message with locator [{LocatorHead}]\";\n            _logger.Debug(\n                sendMsg,\n                nameof(GetBlockHashesMsg),\n                locator.Hash);\n\n            Message parsedMessage;\n            try\n            {\n                parsedMessage = await Transport.SendMessageAsync(\n                    peer,\n                    request,\n                    timeout: Options.TimeoutOptions.GetBlockHashesTimeout,\n                    cancellationToken: cancellationToken).ConfigureAwait(false);\n            }\n            catch (CommunicationFailException)\n            {\n                _logger.Debug(\n                    \"Failed to get a response for \" + nameof(GetBlockHashesMsg) +\n                    \" due to a communication failure\");\n                return new List<BlockHash>();\n            }\n\n            if (parsedMessage.Content is BlockHashesMsg blockHashes)\n            {\n                if (blockHashes.Hashes.Any())\n                {\n                    if (locator.Hash.Equals(blockHashes.Hashes.First()))\n                    {\n                        List<BlockHash> hashes = blockHashes.Hashes.ToList();\n                        _logger.Debug(\n                            \"Received a \" + nameof(BlockHashesMsg) + \" with {Length} hashes\",\n                            hashes.Count);\n                        return hashes;\n                    }\n                    else\n                    {\n                        const string msg =\n                            \"Received a \" + nameof(BlockHashesMsg) + \" but its \" +\n                            \"first hash {ActualBlockHash} does not match \" +\n                            \"the locator hash {ExpectedBlockHash}\";\n                        _logger.Debug(msg, blockHashes.Hashes.First(), locator.Hash);\n                        return new List<BlockHash>();\n                    }\n                }\n                else\n                {\n                    const string msg =\n                        \"Received a \" + nameof(BlockHashesMsg) + \" with zero hashes\";\n                    _logger.Debug(msg);\n                    return new List<BlockHash>();\n                }\n            }\n            else\n            {\n                _logger.Debug(\n                    \"A response for \" + nameof(GetBlockHashesMsg) +\n                    \" is expected to be {ExpectedType}: {ReceivedType}\",\n                    nameof(BlockHashesMsg),\n                    parsedMessage.GetType());\n                return new List<BlockHash>();\n            }\n        }\n\n        /// <summary>\n        /// Download <see cref=\"Block\"/>s corresponding to <paramref name=\"blockHashes\"/>\n        /// from <paramref name=\"peer\"/>.\n        /// </summary>\n        /// <param name=\"peer\">A <see cref=\"BoundPeer\"/> to request <see cref=\"Block\"/>s from.\n        /// </param>\n        /// <param name=\"blockHashes\">A <see cref=\"List{T}\"/> of <see cref=\"BlockHash\"/>es\n        /// of <see cref=\"Block\"/>s to be downloaded from <paramref name=\"peer\"/>.</param>\n        /// <param name=\"cancellationToken\">A cancellation token used to propagate notification\n        /// that this operation should be canceled.</param>\n        /// <returns>An <see cref=\"IAsyncEnumerable{T}\"/> of <see cref=\"Block\"/> and\n        /// <see cref=\"BlockCommit\"/> pairs corresponding to <paramref name=\"blockHashes\"/>.\n        /// Returned <see cref=\"Block\"/>s are guaranteed to correspond to the initial part of\n        /// <paramref name=\"blockHashes\"/>, including the empty list and the full list in order.\n        /// </returns>\n        /// <exception cref=\"InvalidMessageContentException\">Thrown when\n        /// a message other than <see cref=\"BlocksMsg\"/> is received while\n        /// trying to get <see cref=\"Block\"/>s from <paramref name=\"peer\"/>.</exception>\n        internal async IAsyncEnumerable<(Block, BlockCommit)> GetBlocksAsync(\n            BoundPeer peer,\n            List<BlockHash> blockHashes,\n            [EnumeratorCancellation] CancellationToken cancellationToken\n        )\n        {\n            _logger.Information(\n                \"Trying to download {BlockHashesCount} block(s) from {Peer}...\",\n                blockHashes.Count,\n                peer);\n\n            var request = new GetBlocksMsg(blockHashes);\n            int hashCount = blockHashes.Count;\n\n            if (hashCount < 1)\n            {\n                yield break;\n            }\n\n            TimeSpan blockRecvTimeout = Options.TimeoutOptions.GetBlocksBaseTimeout\n                + Options.TimeoutOptions.GetBlocksPerBlockHashTimeout.Multiply(hashCount);\n            if (blockRecvTimeout > Options.TimeoutOptions.MaxTimeout)\n            {\n                blockRecvTimeout = Options.TimeoutOptions.MaxTimeout;\n            }\n\n            IEnumerable<Message> replies;\n            try\n            {\n                replies = await Transport.SendMessageAsync(\n                    peer,\n                    request,\n                    blockRecvTimeout,\n                    ((hashCount - 1) / request.ChunkSize) + 1,\n                    false,\n                    cancellationToken\n                ).ConfigureAwait(false);\n            }\n            catch (CommunicationFailException e) when (e.InnerException is TimeoutException)\n            {\n                yield break;\n            }\n\n            _logger.Debug(\"Received replies from {Peer}\", peer);\n            int count = 0;\n\n            foreach (Message message in replies)\n            {\n                cancellationToken.ThrowIfCancellationRequested();\n\n                if (message.Content is BlocksMsg blockMessage)\n                {\n                    List<byte[]> payloads = blockMessage.Payloads;\n                    _logger.Information(\n                        \"Received {Count} blocks from {Peer}\",\n                        payloads.Count,\n                        message.Remote);\n                    for (int i = 0; i < payloads.Count; i += 2)\n                    {\n                        cancellationToken.ThrowIfCancellationRequested();\n                        byte[] blockPayload = payloads[i];\n                        byte[] commitPayload = payloads[i + 1];\n                        Block block = BlockMarshaler.UnmarshalBlock(\n                            (Bencodex.Types.Dictionary)Codec.Decode(blockPayload));\n                        BlockCommit commit = commitPayload.Length == 0\n                            ? null\n                            : new BlockCommit(Codec.Decode(commitPayload));\n\n                        if (count < blockHashes.Count)\n                        {\n                            if (blockHashes[count].Equals(block.Hash))\n                            {\n                                yield return (block, commit);\n                                count++;\n                            }\n                            else\n                            {\n                                _logger.Debug(\n                                    \"Expected a block with hash {ExpectedBlockHash} but \" +\n                                    \"received a block with hash {ActualBlockHash}\",\n                                    blockHashes[count],\n                                    block.Hash);\n                                yield break;\n                            }\n                        }\n                        else\n                        {\n                            _logger.Debug(\n                                \"Expected to receive {BlockCount} blocks but \" +\n                                \"received more blocks than expected\",\n                                blockHashes.Count);\n                            yield break;\n                        }\n                    }\n                }\n                else\n                {\n                    string errorMessage =\n                        $\"Expected a {nameof(BlocksMsg)} message as a response of \" +\n                        $\"the {nameof(GetBlocksMsg)} message, but got a {message.GetType().Name} \" +\n                        $\"message instead: {message}\";\n                    throw new InvalidMessageContentException(errorMessage, message.Content);\n                }\n            }\n\n            _logger.Information(\"Downloaded {Count} block(s) from {Peer}\", count, peer);\n        }\n\n        internal async IAsyncEnumerable<Transaction> GetTxsAsync(\n            BoundPeer peer,\n            IEnumerable<TxId> txIds,\n            [EnumeratorCancellation] CancellationToken cancellationToken)\n        {\n            var txIdsAsArray = txIds as TxId[] ?? txIds.ToArray();\n            var request = new GetTxsMsg(txIdsAsArray);\n            int txCount = txIdsAsArray.Count();\n\n            _logger.Debug(\"Required tx count: {Count}\", txCount);\n\n            var txRecvTimeout = Options.TimeoutOptions.GetTxsBaseTimeout\n                + Options.TimeoutOptions.GetTxsPerTxIdTimeout.Multiply(txCount);\n            if (txRecvTimeout > Options.TimeoutOptions.MaxTimeout)\n            {\n                txRecvTimeout = Options.TimeoutOptions.MaxTimeout;\n            }\n\n            IEnumerable<Message> replies;\n            try\n            {\n                replies = await Transport.SendMessageAsync(\n                    peer,\n                    request,\n                    txRecvTimeout,\n                    txCount,\n                    true,\n                    cancellationToken\n                ).ConfigureAwait(false);\n            }\n            catch (CommunicationFailException e) when (e.InnerException is TimeoutException)\n            {\n                yield break;\n            }\n\n            foreach (Message message in replies)\n            {\n                if (message.Content is TxMsg parsed)\n                {\n                    Transaction tx = Transaction.Deserialize(parsed.Payload);\n                    yield return tx;\n                }\n                else\n                {\n                    string errorMessage =\n                        $\"Expected {nameof(Transaction)} messages as response of \" +\n                        $\"the {nameof(GetTxsMsg)} message, but got a {message.GetType().Name} \" +\n                        $\"message instead: {message}\";\n                    throw new InvalidMessageContentException(errorMessage, message.Content);\n                }\n            }\n        }\n\n        /// <summary>\n        /// Gets all <see cref=\"BlockHash\"/>es for <see cref=\"Block\"/>s needed to be downloaded\n        /// by querying <see cref=\"BoundPeer\"/>s.\n        /// </summary>\n        /// <param name=\"blockChain\">The <see cref=\"BlockChain\"/> to use as a reference\n        /// for generating a <see cref=\"BlockLocator\"/> when querying.  This may not necessarily\n        /// be <see cref=\"BlockChain\"/>, the canonical <see cref=\"BlockChain\"/> instance held\n        /// by this <see cref=\"Swarm\"/> instance.</param>\n        /// <param name=\"peersWithExcerpts\">The <see cref=\"List{T}\"/> of <see cref=\"BoundPeer\"/>s\n        /// to query with their tips known.</param>\n        /// <param name=\"cancellationToken\">The cancellation token that should be used to propagate\n        /// a notification that this operation should be canceled.</param>\n        /// <returns>An <see cref=\"List{T}\"/> of <see cref=\"BlockHash\"/>es together with\n        /// its source <see cref=\"BoundPeer\"/>.  This is guaranteed to always return a non-empty\n        /// <see cref=\"List{T}\"/> unless an <see cref=\"Exception\"/> is thrown.</returns>\n        /// <exception cref=\"AggregateException\">Thrown when failed to download\n        /// <see cref=\"BlockHash\"/>es from a <see cref=\"BoundPeer\"/>.</exception>\n        /// <remarks>\n        /// <para>\n        /// This method uses the tip information for each <see cref=\"BoundPeer\"/> provided with\n        /// <paramref name=\"peersWithExcerpts\"/> whether to make a query in the first place.\n        /// </para>\n        /// <para>\n        /// Returned list of tuples is simply the first successful query result from a\n        /// <see cref=\"BoundPeer\"/> among <paramref name=\"peersWithExcerpts\"/>.\n        /// </para>\n        /// <para>\n        /// This implicitly assumes returned <see cref=\"BlockHashesMsg\"/> is properly\n        /// indexed with a valid branching <see cref=\"BlockHash\"/> as its first element and\n        /// skips it when constructing the result as it is not necessary to download.\n        /// As such, returned result is simply a \"dump\" of possible <see cref=\"BlockHash\"/>es\n        /// to download.\n        /// </para>\n        /// </remarks>\n        internal async Task<(BoundPeer, List<BlockHash>)> GetDemandBlockHashes(\n            BlockChain blockChain,\n            IList<(BoundPeer, IBlockExcerpt)> peersWithExcerpts,\n            CancellationToken cancellationToken = default)\n        {\n            var exceptions = new List<Exception>();\n            foreach ((BoundPeer peer, IBlockExcerpt excerpt) in peersWithExcerpts)\n            {\n                if (!IsBlockNeeded(excerpt))\n                {\n                    _logger.Verbose(\n                        \"Skip peer {Peer} because its block excerpt is not needed\",\n                        Peers);\n                    continue;\n                }\n\n                try\n                {\n                    List<BlockHash> downloadedHashes = await GetDemandBlockHashesFromPeer(\n                        blockChain,\n                        peer,\n                        excerpt,\n                        cancellationToken);\n                    if (downloadedHashes.Any())\n                    {\n                        return (peer, downloadedHashes);\n                    }\n                    else\n                    {\n                        continue;\n                    }\n                }\n                catch (Exception e)\n                {\n                    const string message =\n                        \"Failed to fetch demand block hashes from {Peer}; \" +\n                        \"retry with another peer...\";\n                    _logger.Debug(e, message, peer);\n                    exceptions.Add(e);\n                    continue;\n                }\n            }\n\n            BoundPeer[] peers = peersWithExcerpts.Select(p => p.Item1).ToArray();\n            _logger.Warning(\n                \"Failed to fetch demand block hashes from peers: {Peers}\",\n                peers);\n            throw new AggregateException(\n                \"Failed to fetch demand block hashes from peers: \" +\n                string.Join(\", \", peers.Select(p => p.ToString())),\n                exceptions);\n        }\n\n        internal async Task<List<BlockHash>> GetDemandBlockHashesFromPeer(\n            BlockChain blockChain,\n            BoundPeer peer,\n            IBlockExcerpt excerpt,\n            CancellationToken cancellationToken = default)\n        {\n            BlockLocator locator = blockChain.GetBlockLocator();\n            long peerIndex = excerpt.Index;\n            var downloaded = new List<BlockHash>();\n\n            try\n            {\n                _logger.Verbose(\n                    \"Request block hashes to {Peer} (height: {PeerHeight}) using \" +\n                    \"locator [{LocatorHead}]\",\n                    peer,\n                    peerIndex,\n                    locator.Hash);\n\n                List<BlockHash> blockHashes = await GetBlockHashes(\n                    peer: peer,\n                    locator: locator,\n                    cancellationToken: cancellationToken);\n\n                foreach (var blockHash in blockHashes)\n                {\n                    _logger.Verbose(\n                        \"Received a block hash from {Peer}: {BlockHash}\",\n                        peer,\n                        blockHash);\n                    downloaded.Add(blockHash);\n                }\n\n                return downloaded;\n            }\n            catch (Exception e)\n            {\n                _logger.Error(\n                    e,\n                    \"Failed to fetch demand block hashes from {Peer}\",\n                    peer);\n                throw new Exception(\"Failed\");\n            }\n        }\n\n        private void BroadcastBlock(Address? except, Block block)\n        {\n            _logger.Information(\n                \"Trying to broadcast block #{Index} {Hash}...\",\n                block.Index,\n                block.Hash);\n            var message = new BlockHeaderMsg(BlockChain.Genesis.Hash, block.Header);\n            BroadcastMessage(except, message);\n        }\n\n        private void BroadcastTxs(BoundPeer except, IEnumerable<Transaction> txs)\n        {\n            List<TxId> txIds = txs.Select(tx => tx.Id).ToList();\n            _logger.Information(\"Broadcasting {Count} txIds...\", txIds.Count);\n            BroadcastTxIds(except?.Address, txIds);\n        }\n\n        private void BroadcastMessage(Address? except, MessageContent message)\n        {\n            Transport.BroadcastMessage(\n                RoutingTable.PeersToBroadcast(except, Options.MinimumBroadcastTarget),\n                message);\n        }\n\n        /// <summary>\n        /// Gets <see cref=\"IBlockExcerpt\"/>es from randomly selected <see cref=\"BoundPeer\"/>s\n        /// from <see cref=\"Peers\"/> with each <see cref=\"IBlockExcerpt\"/> tied to\n        /// its originating <see cref=\"BoundPeer\"/>.\n        /// </summary>\n        /// <param name=\"dialTimeout\">Timeout for each dialing operation to\n        /// a <see cref=\"BoundPeer\"/> in <see cref=\"Peers\"/>.  Not having a timeout limit\n        /// is equivalent to setting this value to <see langword=\"null\"/>.</param>\n        /// <param name=\"maxPeersToDial\">Maximum number of <see cref=\"BoundPeer\"/>s to dial.</param>\n        /// <param name=\"cancellationToken\">A cancellation token used to propagate notification\n        /// that this operation should be canceled.</param>\n        /// <returns>An awaitable task with a <see cref=\"List{T}\"/> of tuples\n        /// of <see cref=\"BoundPeer\"/> and <see cref=\"IBlockExcerpt\"/> ordered randomly.</returns>\n        private async Task<List<(BoundPeer, IBlockExcerpt)>> GetPeersWithExcerpts(\n            TimeSpan? dialTimeout,\n            int maxPeersToDial,\n            CancellationToken cancellationToken)\n        {\n            Random random = new Random();\n            Block tip = BlockChain.Tip;\n            BlockHash genesisHash = BlockChain.Genesis.Hash;\n            return (await DialExistingPeers(dialTimeout, maxPeersToDial, cancellationToken))\n                .Where(\n                    pair => pair.Item2 is { } chainStatus &&\n                        genesisHash.Equals(chainStatus.GenesisHash) &&\n                        chainStatus.TipIndex > tip.Index)\n                .Select(pair => (pair.Item1, (IBlockExcerpt)pair.Item2))\n                .OrderBy(_ => random.Next())\n                .ToList();\n        }\n\n        /// <summary>\n        /// Gets <see cref=\"ChainStatusMsg\"/>es from randomly selected <see cref=\"BoundPeer\"/>s\n        /// from <see cref=\"Peers\"/> with each <see cref=\"ChainStatusMsg\"/> tied to\n        /// its originating <see cref=\"BoundPeer\"/>.\n        /// </summary>\n        /// <param name=\"dialTimeout\">Timeout for each dialing operation to\n        /// a <see cref=\"BoundPeer\"/> in <see cref=\"Peers\"/>.  Not having a timeout limit\n        /// is equivalent to setting this value to <see langword=\"null\"/>.</param>\n        /// <param name=\"maxPeersToDial\">Maximum number of <see cref=\"BoundPeer\"/>s to dial.</param>\n        /// <param name=\"cancellationToken\">A cancellation token used to propagate notification\n        /// that this operation should be canceled.</param>\n        /// <returns>An awaitable task with an <see cref=\"Array\"/> of tuples\n        /// of <see cref=\"BoundPeer\"/> and <see cref=\"ChainStatusMsg\"/> where\n        /// <see cref=\"ChainStatusMsg\"/> can be <see langword=\"null\"/> if dialing fails for\n        /// a selected <see cref=\"BoundPeer\"/>.</returns>\n        private Task<(BoundPeer, ChainStatusMsg)[]> DialExistingPeers(\n            TimeSpan? dialTimeout,\n            int maxPeersToDial,\n            CancellationToken cancellationToken)\n        {\n            // FIXME: It would be better if it returns IAsyncEnumerable<(BoundPeer, ChainStatus)>\n            // instead.\n            void LogException(BoundPeer peer, Task<Message> task)\n            {\n                switch (task.Exception?.InnerException)\n                {\n                    case CommunicationFailException cfe:\n                        _logger.Debug(\n                            cfe,\n                            \"Failed to dial {Peer}\",\n                            peer);\n                        break;\n                    case Exception e:\n                        _logger.Error(\n                            e, \"An unexpected exception occurred while dialing {Peer}\", peer);\n                        break;\n                    default:\n                        break;\n                }\n            }\n\n            var rnd = new System.Random();\n            IEnumerable<Task<(BoundPeer, ChainStatusMsg)>> tasks = Peers.OrderBy(_ => rnd.Next())\n                .Take(maxPeersToDial)\n                .Select(\n                    peer => Transport.SendMessageAsync(\n                        peer,\n                        new GetChainStatusMsg(),\n                        dialTimeout,\n                        cancellationToken\n                    ).ContinueWith<(BoundPeer, ChainStatusMsg)>(\n                        task =>\n                        {\n                            if (task.IsFaulted || task.IsCanceled ||\n                                !(task.Result.Content is ChainStatusMsg chainStatus))\n                            {\n                                // Log and mark to skip\n                                LogException(peer, task);\n                                return (peer, null);\n                            }\n                            else\n                            {\n                                return (peer, chainStatus);\n                            }\n                        },\n                        cancellationToken\n                    )\n                );\n\n            return Task.WhenAll(tasks).ContinueWith(\n                task =>\n                {\n                    if (task.IsFaulted)\n                    {\n                        throw task.Exception;\n                    }\n\n                    return task.Result.ToArray();\n                },\n                cancellationToken\n            );\n        }\n\n        private async Task BroadcastBlockAsync(\n            TimeSpan broadcastBlockInterval,\n            CancellationToken cancellationToken)\n        {\n            const string fname = nameof(BroadcastBlockAsync);\n            while (!cancellationToken.IsCancellationRequested)\n            {\n                try\n                {\n                    await Task.Delay(broadcastBlockInterval, cancellationToken);\n                    BroadcastBlock(BlockChain.Tip);\n                }\n                catch (OperationCanceledException e)\n                {\n                    _logger.Warning(e, \"{MethodName}() was canceled\", fname);\n                    throw;\n                }\n                catch (Exception e)\n                {\n                    _logger.Error(\n                        e, \"An unexpected exception occurred during {MethodName}()\", fname);\n                }\n            }\n        }\n\n        private async Task BroadcastTxAsync(\n            TimeSpan broadcastTxInterval,\n            CancellationToken cancellationToken)\n        {\n            while (!cancellationToken.IsCancellationRequested)\n            {\n                try\n                {\n                    await Task.Delay(broadcastTxInterval, cancellationToken);\n\n                    await Task.Run(\n                        () =>\n                        {\n                            List<TxId> txIds = BlockChain\n                                .GetStagedTransactionIds()\n                                .ToList();\n\n                            if (txIds.Any())\n                            {\n                                _logger.Debug(\n                                    \"Broadcasting {TxCount} staged transactions...\",\n                                    txIds.Count);\n                                BroadcastTxIds(null, txIds);\n                            }\n                        }, cancellationToken);\n                }\n                catch (OperationCanceledException e)\n                {\n                    _logger.Warning(e, \"{MethodName}() was canceled\", nameof(BroadcastTxAsync));\n                    throw;\n                }\n                catch (Exception e)\n                {\n                    _logger.Error(\n                        e,\n                        \"An unexpected exception occurred during {MethodName}()\",\n                        nameof(BroadcastTxAsync));\n                }\n            }\n        }\n\n        private void BroadcastTxIds(Address? except, IEnumerable<TxId> txIds)\n        {\n            var message = new TxIdsMsg(txIds);\n            BroadcastMessage(except, message);\n        }\n\n        /// <summary>\n        /// Checks if the corresponding <see cref=\"Block\"/> to a given\n        /// <see cref=\"IBlockExcerpt\"/> is needed for <see cref=\"BlockChain\"/>.\n        /// </summary>\n        /// <param name=\"target\">The <see cref=\"IBlockExcerpt\"/> to compare to the current\n        /// <see cref=\"BlockChain.Tip\"/> of <see cref=\"BlockChain\"/>.</param>\n        /// <returns><see langword=\"true\"/> if the corresponding <see cref=\"Block\"/> to\n        /// <paramref name=\"target\"/> is needed, otherwise, <see langword=\"false\"/>.</returns>\n        private bool IsBlockNeeded(IBlockExcerpt target)\n        {\n            return target.Index > BlockChain.Tip.Index;\n        }\n\n        private async Task RefreshTableAsync(\n            TimeSpan period,\n            TimeSpan maxAge,\n            CancellationToken cancellationToken)\n        {\n            while (!cancellationToken.IsCancellationRequested)\n            {\n                try\n                {\n                    await PeerDiscovery.RefreshTableAsync(maxAge, cancellationToken);\n                    await PeerDiscovery.CheckReplacementCacheAsync(cancellationToken);\n                    await Task.Delay(period, cancellationToken);\n                }\n                catch (OperationCanceledException e)\n                {\n                    _logger.Warning(e, \"{MethodName}() was cancelled\", nameof(RefreshTableAsync));\n                    throw;\n                }\n                catch (Exception e)\n                {\n                    _logger.Warning(\n                        e,\n                        \"An unexpected exception occurred during {MethodName}()\",\n                        nameof(RefreshTableAsync));\n                }\n            }\n        }\n\n        private async Task RebuildConnectionAsync(\n            TimeSpan period,\n            CancellationToken cancellationToken)\n        {\n            while (!cancellationToken.IsCancellationRequested)\n            {\n                try\n                {\n                    await Task.Delay(period, cancellationToken);\n                    await PeerDiscovery.RebuildConnectionAsync(\n                        Kademlia.MaxDepth,\n                        cancellationToken);\n                }\n                catch (OperationCanceledException e)\n                {\n                    _logger.Warning(e, $\"{nameof(RebuildConnectionAsync)}() is cancelled\");\n                    throw;\n                }\n                catch (Exception e)\n                {\n                    _logger.Warning(\n                        e,\n                        \"Unexpected exception occurred during {MethodName}()\",\n                        nameof(RebuildConnectionAsync));\n                }\n            }\n        }\n\n        private async Task MaintainStaticPeerAsync(\n            TimeSpan period,\n            CancellationToken cancellationToken)\n        {\n            TimeSpan timeout = TimeSpan.FromSeconds(3);\n            while (!cancellationToken.IsCancellationRequested)\n            {\n                var tasks = Options.StaticPeers\n                    .Where(peer => !RoutingTable.Contains(peer))\n                    .Select(async peer =>\n                    {\n                        try\n                        {\n                            await AddPeersAsync(new[] { peer }, timeout, cancellationToken);\n                        }\n                        catch (TimeoutException)\n                        {\n                        }\n                    });\n                await Task.WhenAll(tasks);\n                await Task.Delay(period, cancellationToken);\n            }\n        }\n\n        private async Task CreateLongRunningTask(Func<Task> f)\n        {\n            using var thread = new AsyncContextThread();\n            await thread.Factory.Run(f).WaitAsync(_cancellationToken);\n        }\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Net/SwarmException.cs",
    "content": "using System;\n\nnamespace Libplanet.Net\n{\n    public class SwarmException : Exception\n    {\n        public SwarmException()\n        {\n        }\n\n        public SwarmException(string message)\n            : base(message)\n        {\n        }\n\n        public SwarmException(string message, Exception innerException)\n            : base(message, innerException)\n        {\n        }\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Net/Transports/BoundPeerExtensions.cs",
    "content": "#nullable disable\nusing System;\nusing System.Linq;\nusing System.Net;\nusing System.Net.Sockets;\nusing System.Threading.Tasks;\nusing Libplanet.Crypto;\nusing Libplanet.Net.Messages;\nusing NetMQ;\nusing NetMQ.Sockets;\n\nnamespace Libplanet.Net.Transports\n{\n    /// <summary>\n    /// This extension class activates transport-oriented methods on <see cref=\"BoundPeer\"/>.\n    /// </summary>\n    /// <seealso cref=\"BoundPeer\"/>\n    public static class BoundPeerExtensions\n    {\n        /// <summary>\n        /// Queries <see cref=\"AppProtocolVersion\"/> of given <see cref=\"BoundPeer\"/>\n        /// specialized for NetMQ based transport.\n        /// </summary>\n        /// <param name=\"peer\">The <see cref=\"BoundPeer\"/> to query\n        /// <see cref=\"AppProtocolVersion\"/>.</param>\n        /// <param name=\"timeout\">Timeout value for request.</param>\n        /// <returns><see cref=\"AppProtocolVersion\"/> of given peer. </returns>\n        public static AppProtocolVersion QueryAppProtocolVersionNetMQ(\n            this BoundPeer peer,\n            TimeSpan? timeout = null\n        )\n        {\n            using var dealerSocket = new DealerSocket(ToNetMQAddress(peer));\n            var privateKey = new PrivateKey();\n            var ping = new PingMsg();\n            var netMQMessageCodec = new NetMQMessageCodec();\n            NetMQMessage request = netMQMessageCodec.Encode(\n                new Message(\n                    ping,\n                    default,\n                    new BoundPeer(privateKey.PublicKey, new DnsEndPoint(\"0.0.0.0\", 0)),\n                    DateTimeOffset.UtcNow,\n                    null),\n                privateKey);\n\n            TimeSpan timeoutNotNull = timeout ?? TimeSpan.FromSeconds(5);\n            try\n            {\n                if (dealerSocket.TrySendMultipartMessage(timeoutNotNull, request))\n                {\n                    var response = new NetMQMessage();\n                    if (dealerSocket.TryReceiveMultipartMessage(timeoutNotNull, ref response))\n                    {\n                        return AppProtocolVersion.FromToken(response.First.ConvertToString());\n                    }\n                }\n            }\n            catch (TerminatingException)\n            {\n                throw new TimeoutException($\"Peer didn't respond.\");\n            }\n\n            throw new TimeoutException(\n                $\"Peer[{peer}] didn't respond within the specified time[{timeout}].\"\n            );\n        }\n\n        internal static string ToNetMQAddress(this BoundPeer peer)\n        {\n            return $\"tcp://{peer.EndPoint.Host}:{peer.EndPoint.Port}\";\n        }\n\n        /// <summary>\n        /// Get IPv4 TCP address <see cref=\"string\"/> of given <see cref=\"BoundPeer\"/>\n        /// to be used on NetMQ transport.\n        /// </summary>\n        /// <param name=\"peer\">The <see cref=\"BoundPeer\"/> to get TCP NetMQ address.</param>\n        /// <returns>IPv4 TCP address <see cref=\"string\"/> of given <paramref name=\"peer\"/>.\n        /// </returns>\n        /// <exception cref=\"TransportException\">Thrown if failed to resolve address for given peer.\n        /// </exception>\n        internal static async Task<string> ResolveNetMQAddressAsync(this BoundPeer peer)\n        {\n            string addr = peer.EndPoint.Host;\n\n            IPAddress[] addresses = await Dns.GetHostAddressesAsync(addr).ConfigureAwait(false);\n\n            // FIXME IPs are restricted with IPv4 for now, and have to be fixed later on.\n            string ipv4 = addresses.FirstOrDefault(\n                addr => addr.AddressFamily is AddressFamily.InterNetwork)?.ToString()\n                ?? throw new TransportException($\"Failed to resolve for {addr}\");\n            int port = peer.EndPoint.Port;\n\n            return $\"tcp://{ipv4}:{port}\";\n        }\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Net/Transports/CommunicationFailException.cs",
    "content": "using System;\nusing Libplanet.Net.Messages;\n\nnamespace Libplanet.Net.Transports\n{\n    /// <summary>\n    /// An <see cref=\"Exception\"/> thrown when fail to complete a sending and receiving messages\n    /// cycle via <see cref=\"ITransport\"/> for one of the expected reasons such as normal timeout,\n    /// receiving an invalid reply, etc.\n    /// </summary>\n    public class CommunicationFailException : Exception\n    {\n        public CommunicationFailException(\n            string message,\n            MessageContent.MessageType messageType,\n            BoundPeer peer)\n            : base(message)\n        {\n            Peer = peer;\n            MessageType = messageType;\n        }\n\n        public CommunicationFailException(\n            string message,\n            MessageContent.MessageType messageType,\n            BoundPeer peer,\n            Exception innerException)\n            : base(message, innerException)\n        {\n            Peer = peer;\n            MessageType = messageType;\n        }\n\n        public BoundPeer Peer { get; }\n\n        public MessageContent.MessageType MessageType { get; }\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Net/Transports/DifferentAppProtocolVersionException.cs",
    "content": "using System;\nusing Libplanet.Net.Messages;\n\nnamespace Libplanet.Net.Transports\n{\n    /// <summary>\n    /// The exception that is thrown when the version of the\n    /// <see cref=\"Message\"/> that <see cref=\"Swarm\"/> received\n    /// is different.\n    /// </summary>\n    public class DifferentAppProtocolVersionException : Exception\n    {\n        /// <summary>\n        /// Initializes a new instance of the\n        /// <see cref=\"DifferentAppProtocolVersionException\"/> class.\n        /// </summary>\n        /// <param name=\"message\">Specifies an <see cref=\"Exception.Message\"/>.</param>\n        /// <param name=\"expectedAppProtocolVersion\">The protocol version of\n        /// the local <see cref=\"Swarm\"/>.</param>\n        /// <param name=\"actualAppProtocolVersion\">The protocol version of the\n        /// <see cref=\"BoundPeer\"/> that the local <see cref=\"Swarm\"/> is trying to connect\n        /// to.</param>\n        /// <param name=\"trusted\">Whether <paramref name=\"actualAppProtocolVersion\"/>\n        /// is signed by a trusted signer.</param>\n        public DifferentAppProtocolVersionException(\n            string message,\n            AppProtocolVersion expectedAppProtocolVersion,\n            AppProtocolVersion actualAppProtocolVersion,\n            bool trusted)\n            : base(message)\n        {\n            ExpectedApv = expectedAppProtocolVersion;\n            ActualApv = actualAppProtocolVersion;\n            Trusted = trusted;\n        }\n\n        /// <summary>\n        /// The protocol version of the current <see cref=\"Swarm\"/>.\n        /// </summary>\n        public AppProtocolVersion ExpectedApv { get; }\n\n        /// <summary>\n        /// The protocol version of the <see cref=\"BoundPeer\"/> that the\n        /// <see cref=\"Swarm\" /> is trying to connect to.\n        /// </summary>\n        public AppProtocolVersion ActualApv { get; }\n\n        /// <summary>\n        /// Whether <see cref=\"ActualApv\"/> is signed by a trusted signer.\n        /// </summary>\n        public bool Trusted { get; }\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Net/Transports/ITransport.cs",
    "content": "#nullable disable\nusing System;\nusing System.Collections.Generic;\nusing System.Collections.Immutable;\nusing System.Diagnostics.Contracts;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing Libplanet.Crypto;\nusing Libplanet.Net.Messages;\nusing Libplanet.Net.Options;\n\nnamespace Libplanet.Net.Transports\n{\n    /// <summary>\n    /// An interface to handle peer-to-peer networking, including <see cref=\"Message\"/> exchange\n    /// and <see cref=\"BoundPeer\"/> managing.\n    /// </summary>\n    /// <remarks>\n    /// An instance of a transport implementing <see cref=\"ITransport\"/> should always be able to\n    /// send requests and receive replies.\n    /// </remarks>\n    public interface ITransport : IDisposable\n    {\n        /// <summary>\n        /// The list of tasks invoked when a message that is not\n        /// a reply is received.\n        /// </summary>\n        AsyncDelegate<Message> ProcessMessageHandler { get; }\n\n        /// <summary>\n        /// The <em>current</em> <see cref=\"BoundPeer\"/> representation of <see cref=\"ITransport\"/>.\n        /// </summary>\n        /// <remarks>\n        /// This creates a new instance of <see cref=\"BoundPeer\"/> on the fly and can be different\n        /// at different points of time depending on implementation, as <see cref=\"ITransport\"/>\n        /// may account for changing endpoint.\n        /// </remarks>\n        BoundPeer AsPeer { get; }\n\n        /// <summary>\n        /// The <see cref=\"DateTimeOffset\"/> of the last message received.\n        /// </summary>\n        [Pure]\n        DateTimeOffset? LastMessageTimestamp { get; }\n\n        /// <summary>\n        /// <para>\n        /// Whether this <see cref=\"ITransport\"/> instance is running.\n        /// </para>\n        /// <para>\n        /// When the value is <see langword=\"true\"/>, the <see cref=\"ITransport\"/> can receive\n        /// outside requests.  When the value is <see langword=\"false\"/>,\n        /// the <see cref=\"ITransport\"/> stops receiving outside requests.\n        /// </para>\n        /// </summary>\n        /// <value>The value indicating whether the instance is running.</value>\n        [Pure]\n        bool Running { get; }\n\n        /// <inheritdoc cref=\"AppProtocolVersionOptions.AppProtocolVersion\"/>\n        AppProtocolVersion AppProtocolVersion { get; }\n\n        /// <inheritdoc cref=\"AppProtocolVersionOptions.TrustedAppProtocolVersionSigners\"/>\n        public IImmutableSet<PublicKey> TrustedAppProtocolVersionSigners { get; }\n\n        /// <inheritdoc cref=\"AppProtocolVersionOptions.DifferentAppProtocolVersionEncountered\"/>\n        public DifferentAppProtocolVersionEncountered\n            DifferentAppProtocolVersionEncountered { get; }\n\n        /// <summary>\n        /// Starts running a transport layer as to put it in a <see cref=\"Running\"/> state.\n        /// </summary>\n        /// <param name=\"cancellationToken\">The cancellation token to propagate a notification\n        /// that this operation should be canceled.</param>\n        /// <returns>An awaitable <see cref=\"Task\"/> without a value.</returns>\n        /// <exception cref=\"ObjectDisposedException\">Thrown when the instance is already disposed.\n        /// </exception>\n        Task StartAsync(CancellationToken cancellationToken = default);\n\n        /// <summary>\n        /// Stops running a transport layer as to put it in a not <see cref=\"Running\"/> state.\n        /// </summary>\n        /// <param name=\"waitFor\">The <see cref=\"TimeSpan\"/> to delay before actual stopping.\n        /// </param>\n        /// <param name=\"cancellationToken\">The cancellation token to propagate a notification\n        /// that this operation should be canceled.</param>\n        /// <returns>An awaitable <see cref=\"Task\"/> without a value.</returns>\n        /// <exception cref=\"ObjectDisposedException\">Thrown when the instance is already disposed.\n        /// </exception>\n        Task StopAsync(TimeSpan waitFor, CancellationToken cancellationToken = default);\n\n        /// <summary>\n        /// Waits until this <see cref=\"ITransport\"/> instance gets started to run.\n        /// </summary>\n        /// <returns>A <see cref=\"Task\"/> completed when <see cref=\"ITransport.Running\"/>\n        /// property becomes <see langword=\"true\"/>.</returns>\n        Task WaitForRunningAsync();\n\n        /// <summary>\n        /// Sends a <see cref=\"MessageContent\"/> to a given <see cref=\"BoundPeer\"/>\n        /// and waits for its single reply.\n        /// </summary>\n        /// <param name=\"peer\">The <see cref=\"BoundPeer\"/> to send message to.</param>\n        /// <param name=\"content\">The <see cref=\"MessageContent\"/> to send.</param>\n        /// <param name=\"timeout\">A timeout of waiting for the reply of the message.</param>\n        /// <param name=\"cancellationToken\">\n        /// A cancellation token used to propagate notification that this\n        /// operation should be canceled.</param>\n        /// <returns>The replies of the <paramref name=\"content\"/>\n        /// sent by <paramref name=\"peer\"/>.</returns>\n        /// <exception cref=\"CommunicationFailException\">Thrown when fail send or receive\n        /// a <see cref=\"Message\"/>.</exception>\n        /// <exception cref=\"ObjectDisposedException\">Thrown when <see cref=\"ITransport\"/> instance\n        /// is already disposed.</exception>\n        Task<Message> SendMessageAsync(\n            BoundPeer peer,\n            MessageContent content,\n            TimeSpan? timeout,\n            CancellationToken cancellationToken);\n\n        /// <summary>\n        /// Sends a <see cref=\"MessageContent\"/> to a given <see cref=\"BoundPeer\"/>\n        /// and waits for its multiple replies.\n        /// </summary>\n        /// <param name=\"peer\">The <see cref=\"BoundPeer\"/> to send message to.</param>\n        /// <param name=\"content\">The <see cref=\"MessageContent\"/> to send.</param>\n        /// <param name=\"timeout\">A timeout of waiting for the reply of the message.</param>\n        /// <param name=\"expectedResponses\">The number of expected replies for the message.</param>\n        /// <param name=\"returnWhenTimeout\">Determines the behavior when failed to receive\n        /// <paramref name=\"expectedResponses\"/> messages and timeout occurred.</param>\n        /// <param name=\"cancellationToken\">\n        /// A cancellation token used to propagate notification that this\n        /// operation should be canceled.</param>\n        /// <returns>The replies of the <paramref name=\"content\"/>\n        /// sent by <paramref name=\"peer\"/>.</returns>\n        /// <exception cref=\"CommunicationFailException\">Thrown when fail send or receive\n        /// a <see cref=\"Message\"/>.</exception>\n        /// <exception cref=\"ObjectDisposedException\">Thrown when <see cref=\"ITransport\"/> instance\n        /// is already disposed.</exception>\n        Task<IEnumerable<Message>> SendMessageAsync(\n            BoundPeer peer,\n            MessageContent content,\n            TimeSpan? timeout,\n            int expectedResponses,\n            bool returnWhenTimeout,\n            CancellationToken cancellationToken);\n\n        /// <summary>\n        /// Broadcasts a <see cref=\"MessageContent\"/> to peers selected from the routing table.\n        /// </summary>\n        /// <param name=\"peers\">The <see cref=\"BoundPeer\"/>s to broadcast the\n        /// <paramref name=\"content\"/>.</param>\n        /// <param name=\"content\">A <see cref=\"MessageContent\"/> to broadcast.</param>\n        /// <exception cref=\"ObjectDisposedException\">Thrown when <see cref=\"ITransport\"/> instance\n        /// is already disposed.</exception>\n        void BroadcastMessage(IEnumerable<BoundPeer> peers, MessageContent content);\n\n        /// <summary>\n        /// Sends a <see cref=\"MessageContent\"/> as a reply.\n        /// </summary>\n        /// <param name=\"content\">The <see cref=\"MessageContent\"/> to send as a reply.</param>\n        /// <param name=\"identity\">The byte array that represents identification of the\n        /// <see cref=\"MessageContent\"/> to respond.</param>\n        /// <param name=\"cancellationToken\">\n        /// A cancellation token used to propagate notification that this\n        /// operation should be canceled.</param>\n        /// <returns>An awaitable task without value.</returns>\n        /// <exception cref=\"ObjectDisposedException\">\n        /// Thrown when <see cref=\"ITransport\"/> instance is already disposed.</exception>\n        Task ReplyMessageAsync(\n            MessageContent content,\n            byte[] identity,\n            CancellationToken cancellationToken);\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Net/Transports/InvalidCredentialException.cs",
    "content": "using System;\nusing Libplanet.Crypto;\nusing Libplanet.Net.Messages;\n\nnamespace Libplanet.Net.Transports\n{\n    /// <summary>\n    /// An <see cref=\"Exception\"/> that is thrown when a provided credential is invalid\n    /// when signing an encoded <see cref=\"Message\"/>.\n    /// </summary>\n    public class InvalidCredentialException : Exception\n    {\n        internal InvalidCredentialException(\n            string message,\n            PublicKey expected,\n            PublicKey actual)\n            : base(message)\n        {\n            Expected = expected;\n            Actual = actual;\n        }\n\n        public PublicKey Expected { get; private set; }\n\n        public PublicKey Actual { get; private set; }\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Net/Transports/InvalidMessageSignatureException.cs",
    "content": "using System;\nusing Libplanet.Crypto;\nusing Libplanet.Net.Messages;\n\nnamespace Libplanet.Net.Transports\n{\n    /// <summary>\n    /// An exception that is thrown when the signature of an encoded <see cref=\"Message\"/> is\n    /// invalid.\n    /// </summary>\n    public class InvalidMessageSignatureException : Exception\n    {\n        internal InvalidMessageSignatureException(\n            string message,\n            BoundPeer peer,\n            PublicKey publicKey,\n            byte[] messageToVerify,\n            byte[] signature)\n            : base(message)\n        {\n            Peer = peer;\n            PublicKey = publicKey;\n            MessageToVerify = messageToVerify;\n            Signature = signature;\n        }\n\n        public BoundPeer Peer { get; }\n\n        public PublicKey PublicKey { get; }\n\n        public byte[] MessageToVerify { get; }\n\n        public byte[] Signature { get; }\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Net/Transports/InvalidMessageTimestampException.cs",
    "content": "using System;\nusing Libplanet.Net.Messages;\n\nnamespace Libplanet.Net.Transports\n{\n    /// <summary>\n    /// An exception that is thrown when the timestamp of an encoded <see cref=\"Message\"/> is\n    /// invalid.\n    /// </summary>\n    public class InvalidMessageTimestampException : Exception\n    {\n        internal InvalidMessageTimestampException(\n            string message,\n            DateTimeOffset createdOffset,\n            TimeSpan? buffer,\n            DateTimeOffset currentOffset)\n            : base(message)\n        {\n            CreatedOffset = createdOffset;\n            Buffer = buffer;\n            CurrentOffset = currentOffset;\n        }\n\n        internal DateTimeOffset CreatedOffset { get; private set; }\n\n        internal TimeSpan? Buffer { get; private set; }\n\n        internal DateTimeOffset CurrentOffset { get; private set; }\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Net/Transports/NetMQTransport.cs",
    "content": "#nullable enable\nusing System;\nusing System.Collections.Generic;\nusing System.Collections.Immutable;\nusing System.Diagnostics;\nusing System.Linq;\nusing System.Net;\nusing System.Threading;\nusing System.Threading.Channels;\nusing System.Threading.Tasks;\nusing AsyncIO;\nusing Dasync.Collections;\nusing Libplanet.Crypto;\nusing Libplanet.Net.Messages;\nusing Libplanet.Net.Options;\nusing Libplanet.Stun;\nusing NetMQ;\nusing NetMQ.Sockets;\nusing Nito.AsyncEx;\nusing Nito.AsyncEx.Synchronous;\nusing Serilog;\n\nnamespace Libplanet.Net.Transports\n{\n    /// <summary>\n    /// Implementation of <see cref=\"ITransport\"/> interface using NetMQ.\n    /// </summary>\n    public class NetMQTransport : ITransport\n    {\n        private readonly PrivateKey _privateKey;\n        private readonly ILogger _logger;\n        private readonly AppProtocolVersionOptions _appProtocolVersionOptions;\n        private readonly HostOptions _hostOptions;\n        private readonly MessageValidator _messageValidator;\n        private readonly NetMQMessageCodec _messageCodec;\n        private readonly Channel<MessageRequest> _requests;\n        private readonly Task _runtimeProcessor;\n        private readonly AsyncManualResetEvent _runningEvent;\n        private readonly ActivitySource _activitySource;\n\n        private NetMQQueue<(AsyncManualResetEvent, Message)>? _replyQueue;\n\n        private RouterSocket? _router;\n        private NetMQPoller? _routerPoller;\n        private TurnClient? _turnClient;\n        private DnsEndPoint? _hostEndPoint;\n\n        private CancellationTokenSource _runtimeCancellationTokenSource;\n        private CancellationTokenSource _turnCancellationTokenSource;\n\n        // Used only for logging.\n        private long _requestCount;\n        private long _socketCount;\n        private bool _disposed = false;\n\n        static NetMQTransport()\n        {\n            NetMQConfig.ThreadPoolSize = 3;\n            ForceDotNet.Force();\n        }\n\n        /// <summary>\n        /// Creates a <see cref=\"NetMQTransport\"/> instance.\n        /// </summary>\n        /// <param name=\"privateKey\"><see cref=\"PrivateKey\"/> of the transport layer.</param>\n        /// <param name=\"appProtocolVersionOptions\">The <see cref=\"AppProtocolVersionOptions\"/>\n        /// to use when handling an <see cref=\"AppProtocolVersion\"/> attached to\n        /// a <see cref=\"Message\"/>.</param>\n        /// <param name=\"hostOptions\">The <see cref=\"HostOptions\"/> to use when binding\n        /// to the network.</param>\n        /// <param name=\"messageTimestampBuffer\">The amount in <see cref=\"TimeSpan\"/>\n        /// that is allowed for the timestamp of a <see cref=\"Message\"/> to differ from\n        /// the current time of a local node.  Every <see cref=\"Message\"/> with its timestamp\n        /// differing greater than <paramref name=\"messageTimestampBuffer\"/> will be ignored.\n        /// If <see langword=\"null\"/>, any timestamp is accepted.</param>\n        private NetMQTransport(\n            PrivateKey privateKey,\n            AppProtocolVersionOptions appProtocolVersionOptions,\n            HostOptions hostOptions,\n            TimeSpan? messageTimestampBuffer = null)\n        {\n            _logger = Log\n                .ForContext<NetMQTransport>()\n                .ForContext(\"Source\", nameof(NetMQTransport));\n\n            _socketCount = 0;\n            _privateKey = privateKey;\n            _hostOptions = hostOptions;\n            _appProtocolVersionOptions = appProtocolVersionOptions;\n            _messageValidator = new MessageValidator(\n                _appProtocolVersionOptions, messageTimestampBuffer);\n            _messageCodec = new NetMQMessageCodec();\n\n            _requests = Channel.CreateUnbounded<MessageRequest>();\n            _runtimeCancellationTokenSource = new CancellationTokenSource();\n            _turnCancellationTokenSource = new CancellationTokenSource();\n            _activitySource = new ActivitySource(\"Libplanet.Net.Transports.NetMQTransport\");\n            _requestCount = 0;\n            CancellationToken runtimeCt = _runtimeCancellationTokenSource.Token;\n            _runtimeProcessor = Task.Factory.StartNew(\n                () =>\n                {\n                    // Ignore NetMQ related exceptions during NetMQRuntime.Dispose() to stabilize\n                    // tests\n                    try\n                    {\n                        using var runtime = new NetMQRuntime();\n                        runtime.Run(ProcessRuntime(runtimeCt));\n                    }\n                    catch (Exception e)\n                        when (e is NetMQException || e is ObjectDisposedException)\n                    {\n                        _logger.Error(\n                            e,\n                            \"An exception has occurred while running {TaskName}\",\n                            nameof(_runtimeProcessor));\n                    }\n                },\n                runtimeCt,\n                TaskCreationOptions.DenyChildAttach | TaskCreationOptions.LongRunning,\n                TaskScheduler.Default\n            );\n\n            _runningEvent = new AsyncManualResetEvent();\n            ProcessMessageHandler = new AsyncDelegate<Message>();\n        }\n\n        /// <inheritdoc/>\n        public AsyncDelegate<Message> ProcessMessageHandler { get; }\n\n        /// <inheritdoc/>\n        public BoundPeer AsPeer => _turnClient is TurnClient turnClient\n            ? new BoundPeer(_privateKey.PublicKey, turnClient.EndPoint, turnClient.PublicAddress)\n            : new BoundPeer(_privateKey.PublicKey, _hostEndPoint!);\n\n        /// <inheritdoc/>\n        public DateTimeOffset? LastMessageTimestamp { get; private set; }\n\n        /// <inheritdoc/>\n        public bool Running => _routerPoller?.IsRunning ?? false;\n\n        /// <inheritdoc/>\n        public AppProtocolVersion AppProtocolVersion =>\n            _appProtocolVersionOptions.AppProtocolVersion;\n\n        /// <inheritdoc/>\n        public IImmutableSet<PublicKey> TrustedAppProtocolVersionSigners =>\n            _appProtocolVersionOptions.TrustedAppProtocolVersionSigners;\n\n        /// <inheritdoc/>\n        public DifferentAppProtocolVersionEncountered DifferentAppProtocolVersionEncountered =>\n            _appProtocolVersionOptions.DifferentAppProtocolVersionEncountered;\n\n        /// <summary>\n        /// Creates an initialized <see cref=\"NetMQTransport\"/> instance.\n        /// </summary>\n        /// <param name=\"privateKey\"><see cref=\"PrivateKey\"/> of the transport layer.</param>\n        /// <param name=\"appProtocolVersionOptions\">The <see cref=\"AppProtocolVersionOptions\"/>\n        /// to use when handling an <see cref=\"AppProtocolVersion\"/> attached to\n        /// a <see cref=\"Message\"/>.</param>\n        /// <param name=\"hostOptions\">The <see cref=\"HostOptions\"/> to use when binding\n        /// to the network.</param>\n        /// <param name=\"messageTimestampBuffer\">The amount in <see cref=\"TimeSpan\"/>\n        /// that is allowed for the timestamp of a <see cref=\"Message\"/> to differ from\n        /// the current time of a local node.  Every <see cref=\"Message\"/> with its timestamp\n        /// differing greater than <paramref name=\"messageTimestampBuffer\"/> will be ignored.\n        /// If <see langword=\"null\"/>, any timestamp is accepted.</param>\n        /// <returns>\n        /// An awaitable <see cref=\"Task\"/> returning a <see cref=\"NetMQTransport\"/>\n        /// when awaited that is ready to send request <see cref=\"Message\"/>s and\n        /// receive reply <see cref=\"Message\"/>s.\n        /// </returns>\n        public static async Task<NetMQTransport> Create(\n            PrivateKey privateKey,\n            AppProtocolVersionOptions appProtocolVersionOptions,\n            HostOptions hostOptions,\n            TimeSpan? messageTimestampBuffer = null)\n        {\n            var transport = new NetMQTransport(\n                privateKey,\n                appProtocolVersionOptions,\n                hostOptions,\n                messageTimestampBuffer);\n            await transport.Initialize();\n            return transport;\n        }\n\n        /// <inheritdoc/>\n        public async Task StartAsync(CancellationToken cancellationToken = default)\n        {\n            if (_disposed)\n            {\n                throw new ObjectDisposedException(nameof(NetMQTransport));\n            }\n\n            if (Running)\n            {\n                throw new TransportException(\"Transport is already running.\");\n            }\n\n            _runtimeCancellationTokenSource =\n                CancellationTokenSource.CreateLinkedTokenSource(cancellationToken);\n            _turnCancellationTokenSource =\n                CancellationTokenSource.CreateLinkedTokenSource(cancellationToken);\n\n            _replyQueue = new NetMQQueue<(AsyncManualResetEvent, Message)>();\n            _routerPoller = new NetMQPoller { _router!, _replyQueue };\n\n            _router!.ReceiveReady += ReceiveMessage!;\n            _replyQueue.ReceiveReady += DoReply!;\n\n            Task pollerTask = RunPoller(_routerPoller!);\n            new Task(async () =>\n            {\n                while (!_routerPoller.IsRunning)\n                {\n                    await Task.Yield();\n                }\n\n                _runningEvent.Set();\n            }).Start(_routerPoller);\n\n            await pollerTask.ConfigureAwait(false);\n        }\n\n        /// <inheritdoc/>\n        public async Task StopAsync(\n            TimeSpan waitFor,\n            CancellationToken cancellationToken = default\n        )\n        {\n            if (_disposed)\n            {\n                throw new ObjectDisposedException(nameof(NetMQTransport));\n            }\n\n            if (Running)\n            {\n                await Task.Delay(waitFor, cancellationToken);\n\n                _replyQueue!.ReceiveReady -= DoReply!;\n                _router!.ReceiveReady -= ReceiveMessage!;\n\n                if (_routerPoller!.IsRunning)\n                {\n                    _routerPoller.Stop();\n                }\n\n                _replyQueue.Dispose();\n\n                _runtimeCancellationTokenSource.Cancel();\n                _runningEvent.Reset();\n            }\n        }\n\n        /// <inheritdoc/>\n        public void Dispose()\n        {\n            if (Running)\n            {\n                StopAsync(TimeSpan.Zero).WaitWithoutException();\n            }\n\n            if (!_disposed)\n            {\n                _requests.Writer.TryComplete();\n                _runtimeCancellationTokenSource.Cancel();\n                _turnCancellationTokenSource.Cancel();\n                _runtimeProcessor.WaitWithoutException();\n\n                _runtimeCancellationTokenSource.Dispose();\n                _turnCancellationTokenSource.Dispose();\n\n                if (_router is { } router && !router.IsDisposed)\n                {\n                    // We omitted _router.Unbind() with intention due to hangs.\n                    // See also: https://github.com/planetarium/libplanet/pull/2311\n                    _router.Dispose();\n                    _turnClient?.Dispose();\n                }\n\n                _routerPoller?.Dispose();\n\n                _disposed = true;\n            }\n        }\n\n        /// <inheritdoc/>\n        public Task WaitForRunningAsync() => _runningEvent.WaitAsync();\n\n        /// <inheritdoc/>\n        public async Task<Message> SendMessageAsync(\n            BoundPeer peer,\n            MessageContent content,\n            TimeSpan? timeout,\n            CancellationToken cancellationToken)\n        {\n            IEnumerable<Message> replies =\n                await SendMessageAsync(\n                    peer,\n                    content,\n                    timeout,\n                    1,\n                    false,\n                    cancellationToken).ConfigureAwait(false);\n            Message reply = replies.First();\n\n            return reply;\n        }\n\n        /// <inheritdoc/>\n        public async Task<IEnumerable<Message>> SendMessageAsync(\n            BoundPeer peer,\n            MessageContent content,\n            TimeSpan? timeout,\n            int expectedResponses,\n            bool returnWhenTimeout,\n            CancellationToken cancellationToken\n        )\n        {\n            if (_disposed)\n            {\n                throw new ObjectDisposedException(nameof(NetMQTransport));\n            }\n\n            using Activity? a = _activitySource\n                .StartActivity(ActivityKind.Producer)?\n                .AddTag(\"Message\", content.Type)\n                .AddTag(\"Peer\", peer.PeerString);\n\n            using var timerCts = new CancellationTokenSource();\n            if (timeout is { } timeoutNotNull)\n            {\n                timerCts.CancelAfter(timeoutNotNull);\n            }\n\n            using CancellationTokenSource linkedCts =\n                CancellationTokenSource.CreateLinkedTokenSource(\n                    _runtimeCancellationTokenSource.Token,\n                    cancellationToken,\n                    timerCts.Token\n                );\n            CancellationToken linkedCt = linkedCts.Token;\n\n            Guid reqId = Guid.NewGuid();\n            var replies = new List<Message>();\n\n            Channel<NetMQMessage> channel = Channel.CreateUnbounded<NetMQMessage>();\n\n            try\n            {\n                var req = new MessageRequest(\n                    reqId,\n                    new Message(\n                        content,\n                        _appProtocolVersionOptions.AppProtocolVersion,\n                        AsPeer,\n                        DateTimeOffset.UtcNow,\n                        null),\n                    peer,\n                    expectedResponses,\n                    channel,\n                    linkedCt);\n                Interlocked.Increment(ref _requestCount);\n                await _requests.Writer.WriteAsync(\n                    req,\n                    linkedCt).ConfigureAwait(false);\n                _logger.Verbose(\n                    \"Enqueued a request {RequestId} to the peer {Peer}: {@Message}; \" +\n                    \"{LeftRequests} left\",\n                    reqId,\n                    peer,\n                    content,\n                    Interlocked.Read(ref _requestCount)\n                );\n\n                foreach (var i in Enumerable.Range(0, expectedResponses))\n                {\n                    NetMQMessage raw = await channel.Reader\n                        .ReadAsync(linkedCt)\n                        .ConfigureAwait(false);\n                    Message reply = _messageCodec.Decode(raw, true);\n\n                    _logger.Information(\n                        \"Received {Reply} as a reply to request {Request} {RequestId} from {Peer}\",\n                        reply.Content.Type,\n                        content.Type,\n                        req.Id,\n                        reply.Remote);\n                    try\n                    {\n                        _messageValidator.ValidateTimestamp(reply);\n                        _messageValidator.ValidateAppProtocolVersion(reply);\n                    }\n                    catch (InvalidMessageTimestampException imte)\n                    {\n                        const string imteMsge =\n                            \"Received reply {Reply} from {Peer} to request {Request} \" +\n                            \"{RequestId} has an invalid timestamp\";\n                        _logger.Warning(\n                            imte,\n                            imteMsge,\n                            reply.Content.Type,\n                            reply.Remote,\n                            content.Type,\n                            req.Id);\n                        channel.Writer.Complete(imte);\n                    }\n                    catch (DifferentAppProtocolVersionException dapve)\n                    {\n                        const string dapveMsg =\n                            \"Received reply {Reply} from {Peer} to request {Request} \" +\n                            \"{RequestId} has an invalid APV\";\n                        _logger.Warning(\n                            dapve,\n                            dapveMsg,\n                            reply.Content.Type,\n                            reply.Remote,\n                            content.Type,\n                            req.Id);\n                        channel.Writer.Complete(dapve);\n                    }\n\n                    replies.Add(reply);\n                }\n\n                _logger.Information(\n                    \"Received {ReplyMessageCount} reply messages to {Message} {RequestId}\" +\n                    \"from {Peer}: {ReplyMessages}\",\n                    replies.Count,\n                    content.Type,\n                    reqId,\n                    peer,\n                    replies.Select(reply => reply.Content.Type));\n                a?.SetStatus(ActivityStatusCode.Ok);\n                return replies;\n            }\n            catch (OperationCanceledException oce) when (timerCts.IsCancellationRequested)\n            {\n                if (returnWhenTimeout)\n                {\n                    return replies;\n                }\n\n                a?.SetStatus(ActivityStatusCode.Error);\n                a?.AddTag(\"Exception\", nameof(TimeoutException));\n                throw WrapCommunicationFailException(\n                    new TimeoutException(\n                        $\"The operation was canceled due to timeout {timeout!.ToString()}.\",\n                        oce\n                    ),\n                    peer,\n                    content\n                );\n            }\n            catch (OperationCanceledException oce2)\n            {\n                const string dbgMsg =\n                    \"{MethodName}() was cancelled while waiting for a reply to \" +\n                    \"{Content} {RequestId} from {Peer}\";\n                _logger.Debug(\n                    oce2, dbgMsg, nameof(SendMessageAsync), content, reqId, peer);\n\n                a?.SetStatus(ActivityStatusCode.Error);\n                a?.AddTag(\"Exception\", nameof(TaskCanceledException));\n\n                // Wrapping to match the previous behavior of `SendMessageAsync()`.\n                throw new TaskCanceledException(dbgMsg, oce2);\n            }\n            catch (ChannelClosedException ce)\n            {\n                a?.SetStatus(ActivityStatusCode.Error);\n                a?.AddTag(\"Exception\", nameof(ChannelClosedException));\n                throw WrapCommunicationFailException(ce.InnerException ?? ce, peer, content);\n            }\n            catch (Exception e)\n            {\n                const string errMsg =\n                    \"{MethodName}() encountered an unexpected exception while waiting for \" +\n                    \"a reply to {Content} {RequestId} from {Peer}\";\n                _logger.Error(\n                    e, errMsg, nameof(SendMessageAsync), content, reqId, peer.Address);\n                a?.SetStatus(ActivityStatusCode.Error);\n                a?.AddTag(\"Exception\", e.GetType().ToString());\n                throw;\n            }\n            finally\n            {\n                channel.Writer.TryComplete();\n            }\n        }\n\n        /// <inheritdoc/>\n        public void BroadcastMessage(IEnumerable<BoundPeer> peers, MessageContent content)\n        {\n            if (_disposed)\n            {\n                throw new ObjectDisposedException(nameof(NetMQTransport));\n            }\n\n            CancellationToken ct = _runtimeCancellationTokenSource.Token;\n            List<BoundPeer> boundPeers = peers.ToList();\n            Task.Run(\n                async () =>\n                {\n                    using Activity? a = _activitySource\n                        .StartActivity(ActivityKind.Producer)?\n                        .AddTag(\"Message\", content.Type)\n                        .AddTag(\"Peers\", boundPeers.Select(x => x.PeerString));\n                    await boundPeers.ParallelForEachAsync(\n                        peer => SendMessageAsync(peer, content, TimeSpan.FromSeconds(1), ct),\n                        ct\n                    );\n\n                    a?.SetStatus(ActivityStatusCode.Ok);\n                },\n                ct\n            );\n\n            _logger.Debug(\n                \"Broadcasting message {Message} as {AsPeer} to {PeerCount} peers\",\n                content,\n                AsPeer,\n                boundPeers.Count\n            );\n        }\n\n        /// <inheritdoc/>\n        public async Task ReplyMessageAsync(\n            MessageContent content,\n            byte[] identity,\n            CancellationToken cancellationToken)\n        {\n            if (_disposed)\n            {\n                throw new ObjectDisposedException(nameof(NetMQTransport));\n            }\n\n            string reqId = !(identity is null) && identity.Length == 16\n                ? new Guid(identity).ToString()\n                : \"unknown\";\n            _logger.Debug(\"Reply {Content} to {Identity}...\", content, reqId);\n\n            var ev = new AsyncManualResetEvent();\n            _replyQueue!.Enqueue(\n                (\n                    ev,\n                    new Message(\n                        content,\n                        _appProtocolVersionOptions.AppProtocolVersion,\n                        AsPeer,\n                        DateTimeOffset.UtcNow,\n                        identity)\n                )\n            );\n\n            await ev.WaitAsync(cancellationToken);\n        }\n\n        /// <summary>\n        /// Initializes a <see cref=\"NetMQTransport\"/> as to make it ready to\n        /// send request <see cref=\"MessageContent\"/>s and receive reply <see cref=\"Message\"/>s.\n        /// </summary>\n        /// <param name=\"cancellationToken\">The cancellation token to propagate a notification\n        /// that this operation should be canceled.</param>\n        /// <returns>An awaitable <see cref=\"Task\"/> without value.</returns>\n        private async Task Initialize(CancellationToken cancellationToken = default)\n        {\n            _router = new RouterSocket();\n            _router.Options.RouterHandover = true;\n            int listenPort = 0;\n\n            if (_hostOptions.Port == 0)\n            {\n                listenPort = _router.BindRandomPort(\"tcp://*\");\n            }\n            else\n            {\n                listenPort = _hostOptions.Port;\n                _router.Bind($\"tcp://*:{listenPort}\");\n            }\n\n            _logger.Information(\"Listening on {Port}...\", listenPort);\n\n            if (_hostOptions.Host is { } host)\n            {\n                _hostEndPoint = new DnsEndPoint(host, listenPort);\n            }\n            else\n            {\n                _turnClient = await TurnClient.Create(_hostOptions.IceServers, cancellationToken);\n                await _turnClient.StartAsync(listenPort, cancellationToken);\n                if (!_turnClient.BehindNAT)\n                {\n                    _hostEndPoint = new DnsEndPoint(\n                        _turnClient.PublicAddress.ToString(), listenPort);\n                }\n            }\n        }\n\n        private void ReceiveMessage(object? sender, NetMQSocketEventArgs e)\n        {\n            try\n            {\n                var raw = new NetMQMessage();\n\n                // execution limit to avoid starvation.\n                for (var i = 0; i < 1_000; i++)\n                {\n                    if (!e.Socket.TryReceiveMultipartMessage(TimeSpan.Zero, ref raw))\n                    {\n                        break;\n                    }\n\n                    _logger.Verbose(\n                        \"A raw message [frame count: {0}] has received\",\n                        raw.FrameCount\n                    );\n\n                    if (_runtimeCancellationTokenSource.IsCancellationRequested)\n                    {\n                        return;\n                    }\n\n                    LastMessageTimestamp = DateTimeOffset.UtcNow;\n\n                    // Duplicate received message before distributing.\n                    var copied = new NetMQMessage(raw.Select(f => f.Duplicate()));\n\n                    Task.Factory.StartNew(\n                        async () =>\n                        {\n                            try\n                            {\n                                Message message = _messageCodec.Decode(\n                                    copied,\n                                    false);\n                                string reqId = copied[0].Buffer.Length == 16 ?\n                                    new Guid(copied[0].ToByteArray()).ToString() : \"unknown\";\n                                _logger\n                                    .ForContext(\"Tag\", \"Metric\")\n                                    .ForContext(\"Subtag\", \"InboundMessageReport\")\n                                    .Information(\n                                        \"Received Request {RequestId} {Message} from {Peer}\",\n                                        reqId,\n                                        message,\n                                        message.Remote);\n                                try\n                                {\n                                    _messageValidator.ValidateTimestamp(message);\n                                    _messageValidator.ValidateAppProtocolVersion(message);\n                                    await ProcessMessageHandler.InvokeAsync(message);\n                                }\n                                catch (InvalidMessageTimestampException imte)\n                                {\n                                    const string logMsg =\n                                        \"Received {RequestId} {Content} from \" +\n                                        \"{Peer} has an invalid timestamp {Timestamp}\";\n                                    _logger.Debug(\n                                        imte,\n                                        logMsg,\n                                        reqId,\n                                        message.Content,\n                                        message.Remote,\n                                        message.Timestamp);\n                                }\n                                catch (DifferentAppProtocolVersionException dapve)\n                                {\n                                    const string logMsg =\n                                        \"Received Request {RequestId} {Content} \" +\n                                        \"from {Peer} has an invalid APV {Apv}\";\n                                    _logger.Debug(\n                                        dapve,\n                                        logMsg,\n                                        reqId,\n                                        message.Content,\n                                        message.Remote,\n                                        message.Version);\n                                    var diffVersion = new DifferentVersionMsg();\n                                    _logger.Debug(\n                                        \"Replying to Request {RequestId} {Peer} with {Reply}\",\n                                        reqId,\n                                        message.Remote,\n                                        diffVersion);\n                                    await ReplyMessageAsync(\n                                        diffVersion,\n                                        message.Identity ?? Array.Empty<byte>(),\n                                        _runtimeCancellationTokenSource.Token\n                                    );\n                                }\n                            }\n                            catch (InvalidMessageContentException ex)\n                            {\n                                _logger.Error(ex, \"Could not parse NetMQMessage properly; ignore\");\n                            }\n                            catch (Exception exc)\n                            {\n                                _logger.Error(\n                                    exc,\n                                    \"Something went wrong during message processing\");\n                            }\n                        },\n                        CancellationToken.None,\n                        TaskCreationOptions.HideScheduler | TaskCreationOptions.DenyChildAttach,\n                        TaskScheduler.Default\n                    ).Unwrap();\n                }\n            }\n            catch (Exception ex)\n            {\n                _logger.Error(\n                    ex,\n                    \"An unexpected exception occurred during {MethodName}()\",\n                    nameof(ReceiveMessage));\n            }\n        }\n\n        private void DoReply(\n            object? sender,\n            NetMQQueueEventArgs<(AsyncManualResetEvent, Message)> e\n        )\n        {\n            (AsyncManualResetEvent ev, Message message) = e.Queue.Dequeue();\n            string reqId = message.Identity is { } identity && identity.Length == 16\n                ? new Guid(identity).ToString()\n                : \"unknown\";\n\n            // FIXME The current timeout value(1 sec) is arbitrary.\n            // We should make this configurable or fix it to an unneeded structure.\n            NetMQMessage netMQMessage = _messageCodec.Encode(message, _privateKey);\n            if (_router!.TrySendMultipartMessage(TimeSpan.FromSeconds(1), netMQMessage))\n            {\n                _logger.Debug(\n                    \"{Message} as a reply to {Identity} sent\", message.Content.Type, reqId);\n            }\n            else\n            {\n                _logger.Debug(\n                    \"Failed to send {Message} as a reply to {Identity}\",\n                    message.Content.Type,\n                    reqId);\n            }\n\n            ev.Set();\n        }\n\n        private async Task ProcessRuntime(CancellationToken cancellationToken)\n        {\n            const string waitMsg = \"Waiting for a new request...\";\n            ChannelReader<MessageRequest> reader = _requests.Reader;\n#if NETCOREAPP3_0 || NETCOREAPP3_1 || NET\n            _logger.Verbose(waitMsg);\n            await foreach (MessageRequest req in reader.ReadAllAsync(cancellationToken))\n            {\n#else\n            while (true)\n            {\n                cancellationToken.ThrowIfCancellationRequested();\n                _logger.Verbose(waitMsg);\n                MessageRequest req = await reader.ReadAsync(cancellationToken);\n#endif\n                long left = Interlocked.Decrement(ref _requestCount);\n                _logger.Debug(\n                    \"Request {Message} {RequestId} taken for processing; {Count} requests left\",\n                    req.Message.Content.Type,\n                    req.Id,\n                    left);\n\n                _ = SynchronizationContext.Current.PostAsync(\n                    () => ProcessRequest(req, req.CancellationToken)\n                );\n\n#if NETCOREAPP3_0 || NETCOREAPP3_1 || NET\n                _logger.Verbose(waitMsg);\n#endif\n            }\n        }\n\n        private async Task ProcessRequest(MessageRequest req, CancellationToken cancellationToken)\n        {\n            Stopwatch stopwatch = new Stopwatch();\n            stopwatch.Start();\n\n            _logger.Debug(\n                \"Request {Message} {RequestId} is ready to be processed in {TimeSpan}\",\n                req.Message.Content.Type,\n                req.Id,\n                DateTimeOffset.UtcNow - req.Message.Timestamp);\n\n            Channel<NetMQMessage> channel = req.Channel;\n\n            _logger.Debug(\n                \"Trying to send request {Message} {RequestId} to {Peer}\",\n                req.Message.Content.Type,\n                req.Id,\n                req.Peer\n            );\n            int receivedCount = 0;\n            long? incrementedSocketCount = null;\n\n            // Normal OperationCanceledException initiated from outside should bubble up.\n            try\n            {\n                cancellationToken.ThrowIfCancellationRequested();\n\n                using var dealer = new DealerSocket();\n                dealer.Options.DisableTimeWait = true;\n                dealer.Options.Identity = req.Id.ToByteArray();\n                try\n                {\n                    _logger.Debug(\n                        \"Trying to connect to {Peer} for request {Message} {RequestId}\",\n                        req.Peer,\n                        req.Message.Content.Type,\n                        req.Id);\n                    dealer.Connect(await req.Peer.ResolveNetMQAddressAsync());\n                    incrementedSocketCount = Interlocked.Increment(ref _socketCount);\n                    _logger\n                        .ForContext(\"Tag\", \"Metric\")\n                        .ForContext(\"Subtag\", \"SocketCount\")\n                        .Debug(\n                            \"{SocketCount} sockets open for processing request \" +\n                            \"{Message} {RequestId}\",\n                            incrementedSocketCount,\n                            req.Message.Content.Type,\n                            req.Id);\n                }\n                catch (NetMQException nme)\n                {\n                    const string logMsg =\n                        \"{SocketCount} sockets open for processing requests; \" +\n                        \"failed to create an additional socket for request {Message} {RequestId}\";\n                    _logger\n                        .ForContext(\"Tag\", \"Metric\")\n                        .ForContext(\"Subtag\", \"SocketCount\")\n                        .Debug(\n                            nme,\n                            logMsg,\n                            Interlocked.Read(ref _socketCount),\n                            req.Message.Content.Type,\n                            req.Id);\n                    throw;\n                }\n\n                var netMQMessage = _messageCodec.Encode(\n                    req.Message,\n                    _privateKey);\n                if (dealer.TrySendMultipartMessage(netMQMessage))\n                {\n                    _logger.Debug(\n                        \"Request {RequestId} {Message} sent to {Peer}\",\n                        req.Id,\n                        req.Message.Content.Type,\n                        req.Peer);\n                }\n                else\n                {\n                    _logger.Debug(\n                        \"Failed to send {RequestId} {Message} to {Peer}\",\n                        req.Id,\n                        req.Message.Content.Type,\n                        req.Peer);\n\n                    throw new SendMessageFailException(\n                        $\"Failed to send {req.Message.Content.Type} to {req.Peer}.\",\n                        req.Peer);\n                }\n\n                foreach (var i in Enumerable.Range(0, req.ExpectedResponses))\n                {\n                    NetMQMessage raw = await dealer.ReceiveMultipartMessageAsync(\n                        cancellationToken: cancellationToken\n                    );\n\n                    _logger.Verbose(\n                        \"Received a raw message with {FrameCount} frames as a reply to \" +\n                        \"request {RequestId} from {Peer}\",\n                        raw.FrameCount,\n                        req.Id,\n                        req.Peer\n                    );\n                    await channel.Writer.WriteAsync(raw, cancellationToken);\n                    receivedCount += 1;\n                }\n\n                channel.Writer.Complete();\n            }\n            catch (Exception e)\n            {\n                _logger.Error(\n                    e,\n                    \"Failed to process {Message} {RequestId}; discarding it\",\n                    req.Message.Content.Type,\n                    req.Id);\n                channel.Writer.TryComplete(e);\n            }\n            finally\n            {\n                if (req.ExpectedResponses == 0)\n                {\n                    // FIXME: Temporary fix to wait for a message to be sent.\n                    await Task.Delay(1000);\n                }\n\n                if (incrementedSocketCount is { })\n                {\n                    Interlocked.Decrement(ref _socketCount);\n                }\n\n                _logger\n                    .ForContext(\"Tag\", \"Metric\")\n                    .ForContext(\"Subtag\", \"OutboundMessageReport\")\n                    .Information(\n                        \"Request {RequestId} {Message} \" +\n                        \"processed in {DurationMs} ms with {ReceivedCount} replies received \" +\n                        \"out of {ExpectedCount} expected replies\",\n                        req.Id,\n                        req.Message.Content.Type,\n                        stopwatch.ElapsedMilliseconds,\n                        receivedCount,\n                        req.ExpectedResponses);\n            }\n        }\n\n        private async Task RunPoller(NetMQPoller poller)\n        {\n            TaskCreationOptions taskCreationOptions =\n                TaskCreationOptions.DenyChildAttach |\n                TaskCreationOptions.LongRunning |\n                TaskCreationOptions.HideScheduler;\n            await Task.Factory.StartNew(\n                () =>\n                {\n                    // Ignore NetMQ related exceptions during NetMQPoller.Run() to stabilize\n                    // tests.\n                    try\n                    {\n                        poller.Run();\n                    }\n                    catch (TerminatingException)\n                    {\n                        _logger.Error(\"TerminatingException occurred during poller.Run()\");\n                    }\n                    catch (ObjectDisposedException)\n                    {\n                        _logger.Error(\n                            \"ObjectDisposedException occurred during poller.Run()\");\n                    }\n                    catch (Exception e)\n                    {\n                        _logger.Error(\n                            e, \"An unexpected exception occurred during poller.Run()\");\n                    }\n                },\n                CancellationToken.None,\n                taskCreationOptions,\n                TaskScheduler.Default\n            );\n        }\n\n        private CommunicationFailException WrapCommunicationFailException(\n            Exception innerException,\n            BoundPeer peer,\n            MessageContent message\n        )\n        {\n            return new CommunicationFailException(\n                $\"Failed to send and receive replies from {peer} for request {message}.\",\n                message.Type,\n                peer,\n                innerException\n            );\n        }\n\n        private class MessageRequest\n        {\n            public MessageRequest(\n                in Guid id,\n                Message message,\n                BoundPeer peer,\n                in int expectedResponses,\n                Channel<NetMQMessage> channel,\n                CancellationToken cancellationToken)\n            {\n                Id = id;\n                Message = message;\n                Peer = peer;\n                ExpectedResponses = expectedResponses;\n                Channel = channel;\n                CancellationToken = cancellationToken;\n            }\n\n            public Guid Id { get; }\n\n            public Message Message { get; }\n\n            public BoundPeer Peer { get; }\n\n            public int ExpectedResponses { get; }\n\n            public Channel<NetMQMessage> Channel { get; }\n\n            public CancellationToken CancellationToken { get; }\n        }\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Net/Transports/SendMessageFailException.cs",
    "content": "using System;\nusing Libplanet.Net.Messages;\n\nnamespace Libplanet.Net.Transports\n{\n    /// <summary>\n    /// An <see cref=\"Exception\"/> thrown when fail to send a <see cref=\"Message\"/>.\n    /// </summary>\n    public class SendMessageFailException : Exception\n    {\n        internal SendMessageFailException(string message, BoundPeer peer)\n            : base(message)\n        {\n            Peer = peer;\n        }\n\n        internal SendMessageFailException(string message, BoundPeer peer, Exception innerException)\n            : base(message, innerException)\n        {\n            Peer = peer;\n        }\n\n        public BoundPeer Peer { get; }\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Net/Transports/TransportException.cs",
    "content": "using System;\n\nnamespace Libplanet.Net.Transports\n{\n    public class TransportException : Exception\n    {\n        public TransportException()\n        {\n        }\n\n        public TransportException(string message)\n            : base(message)\n        {\n        }\n\n        public TransportException(string message, Exception innerException)\n            : base(message, innerException)\n        {\n        }\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Net/TxCompletion.cs",
    "content": "using System;\nusing System.Collections.Concurrent;\nusing System.Collections.Generic;\nusing System.Diagnostics;\nusing System.Linq;\nusing System.Threading;\nusing System.Threading.Channels;\nusing System.Threading.Tasks;\nusing Libplanet.Blockchain;\nusing Libplanet.Types.Tx;\nusing Nito.AsyncEx;\nusing Serilog;\n\nnamespace Libplanet.Net\n{\n    public class TxCompletion<TPeer> : IDisposable\n        where TPeer : notnull\n    {\n        private readonly CancellationTokenSource _cancellationTokenSource;\n        private readonly BlockChain _blockChain;\n        private readonly TxFetcher _txFetcher;\n        private readonly TxBroadcaster _txBroadcaster;\n        private readonly ILogger _logger;\n        private readonly ConcurrentDictionary<TPeer, TxFetchJob> _txFetchJobs;\n\n        private bool _disposed;\n\n        public TxCompletion(\n            BlockChain blockChain,\n            TxFetcher txFetcher,\n            TxBroadcaster txBroadcaster)\n        {\n            _cancellationTokenSource = new CancellationTokenSource();\n            _blockChain = blockChain;\n            _txFetcher = txFetcher;\n            _txBroadcaster = txBroadcaster;\n            _txFetchJobs = new ConcurrentDictionary<TPeer, TxFetchJob>();\n            TxReceived = new AsyncAutoResetEvent();\n\n            _logger = Log\n                .ForContext<TxCompletion<TPeer>>()\n                .ForContext(\"Source\", nameof(TxCompletion<TPeer>));\n        }\n\n        public delegate IAsyncEnumerable<Transaction> TxFetcher(\n            TPeer peer,\n            IEnumerable<TxId> txIds,\n            CancellationToken cancellationToken\n        );\n\n        public delegate void TxBroadcaster(TPeer except, IEnumerable<Transaction> txs);\n\n        internal AsyncAutoResetEvent TxReceived { get; }\n\n        public void Dispose()\n        {\n            if (!_disposed)\n            {\n                _cancellationTokenSource.Cancel();\n                _disposed = true;\n            }\n        }\n\n        public void Demand(TPeer peer, TxId txId) => Demand(peer, new[] { txId });\n\n        public void Demand(TPeer peer, IEnumerable<TxId> txIds)\n        {\n            if (_disposed)\n            {\n                throw new ObjectDisposedException(nameof(TxCompletion<TPeer>));\n            }\n\n            HashSet<TxId> required = GetRequiredTxIds(txIds);\n\n            _logger.Information(\n                \"There are {RequiredCount} unaware transactions to receive out of {Count} TxIds\",\n                required.Count,\n                txIds.Count());\n\n            if (!required.Any())\n            {\n                return;\n            }\n\n            do\n            {\n                TxFetchJob txFetchJob = _txFetchJobs.GetOrAdd(\n                    peer,\n                    peerAsKey => TxFetchJob.RunAfter(\n                        peerAsKey,\n                        _txFetcher,\n                        TimeSpan.FromSeconds(1),\n                        (task) =>\n                        {\n                            if (task.IsCompleted &&\n                                !task.IsFaulted &&\n                                !task.IsCanceled &&\n                                task.Result is ISet<Transaction> txs)\n                            {\n                                ProcessFetchedTxIds(txs, peerAsKey);\n                            }\n\n                            _txFetchJobs.TryRemove(peer, out _);\n                        },\n                        _cancellationTokenSource.Token\n                    )\n                );\n\n                if (txFetchJob.TryAdd(required, out HashSet<TxId> rest))\n                {\n                    break;\n                }\n\n                required = rest;\n                _txFetchJobs.TryRemove(peer, out _);\n            }\n            while (true);\n        }\n\n        private void ProcessFetchedTxIds(ISet<Transaction> txs, TPeer peer)\n        {\n            try\n            {\n                var policyCompatTxs = new HashSet<Transaction>(\n                    txs.Where(\n                        tx =>\n                        {\n                            if (_blockChain.Policy.ValidateNextBlockTx(\n                                    _blockChain,\n                                    tx) is { } tpve)\n                            {\n                                const string message =\n                                    \"Received transaction {TxId} from {Peer} will not be \" +\n                                    \"staged since it does not follow policy\";\n                                _logger.Debug(\n                                    tpve,\n                                    message,\n                                    tx.Id,\n                                    peer);\n                                _blockChain.StagePolicy.Ignore(_blockChain, tx.Id);\n                                return false;\n                            }\n                            else\n                            {\n                                return true;\n                            }\n                        }));\n\n                var stagedTxs = new List<Transaction>();\n                foreach (var tx in policyCompatTxs)\n                {\n                    try\n                    {\n                        if (_blockChain.StageTransaction(tx))\n                        {\n                            stagedTxs.Add(tx);\n                        }\n                    }\n                    catch (InvalidTxException ite)\n                    {\n                        const string msg = \"Received transaction from {Peer} with id {TxId} \" +\n                                  \"will not be staged since it is invalid\";\n                        _logger.Error(ite, msg, peer, tx.Id);\n                    }\n                }\n\n                // To maintain the consistency of the unit tests.\n                if (policyCompatTxs.Any())\n                {\n                    TxReceived.Set();\n                }\n\n                if (stagedTxs.Any())\n                {\n                    _logger.Information(\n                        \"Staged {StagedTxCount} out of {TxCount} txs from {Peer}\",\n                        stagedTxs.Count,\n                        txs.Count,\n                        peer);\n\n                    _txBroadcaster(peer, stagedTxs);\n                }\n                else\n                {\n                    _logger.Information(\n                        \"No transaction has been staged among received {TxCount} from {Peer}\",\n                        txs.Count,\n                        peer\n                    );\n                }\n            }\n            catch (Exception e)\n            {\n                _logger.Error(\n                    e,\n                    \"An error occurred during {MethodName}() from {Peer}\",\n                    nameof(ProcessFetchedTxIds),\n                    peer);\n                throw;\n            }\n            finally\n            {\n                _logger.Debug(\n                    \"End of {MethodName}() from {Peer}\",\n                    nameof(ProcessFetchedTxIds),\n                    peer);\n            }\n        }\n\n        private HashSet<TxId> GetRequiredTxIds(IEnumerable<TxId> ids)\n        {\n            return new HashSet<TxId>(ids\n                .Where(txId =>\n                    !_blockChain.StagePolicy.Ignores(_blockChain, txId)\n                        && _blockChain.StagePolicy.Get(_blockChain, txId, filtered: false) is null\n                        && _blockChain.Store.GetTransaction(txId) is null));\n        }\n\n        private class TxFetchJob\n        {\n            private readonly TxFetcher _txFetcher;\n            private readonly Channel<TxId> _txIds;\n            private readonly TPeer _peer;\n            private readonly ILogger _logger;\n            private readonly ReaderWriterLockSlim _txIdsWriterLock;\n\n            private TxFetchJob(TxFetcher txFetcher, TPeer peer)\n            {\n                _txFetcher = txFetcher;\n                _peer = peer;\n                _txIds = Channel.CreateUnbounded<TxId>(\n                    new UnboundedChannelOptions\n                    {\n                        SingleReader = true,\n                    }\n                );\n                _txIdsWriterLock = new ReaderWriterLockSlim();\n\n                _logger = Log\n                    .ForContext<TxFetchJob>()\n                    .ForContext(\"Source\", nameof(TxFetchJob));\n            }\n\n            public static TxFetchJob RunAfter(\n                TPeer peer,\n                TxFetcher txFetcher,\n                TimeSpan waitFor,\n                Action<Task<ISet<Transaction>>> continuation,\n                CancellationToken cancellationToken)\n            {\n                var task = new TxFetchJob(txFetcher, peer);\n                _ = task.RequestAsync(waitFor, cancellationToken).ContinueWith(continuation);\n                return task;\n            }\n\n            public bool TryAdd(IEnumerable<TxId> txIds, out HashSet<TxId> rest)\n            {\n                rest = new HashSet<TxId>(txIds);\n                _txIdsWriterLock.EnterReadLock();\n                try\n                {\n                    foreach (TxId txId in txIds)\n                    {\n                        _txIds.Writer.WriteAsync(txId);\n                        rest.Remove(txId);\n                    }\n\n                    return true;\n                }\n                catch (ChannelClosedException)\n                {\n                    return false;\n                }\n                finally\n                {\n                    _txIdsWriterLock.ExitReadLock();\n                }\n            }\n\n            private async Task<ISet<Transaction>> RequestAsync(\n                TimeSpan waitFor,\n                CancellationToken cancellationToken\n            )\n            {\n                _ = Task.Run(async () =>\n                {\n                    await Task.Delay(waitFor);\n                    _txIdsWriterLock.EnterWriteLock();\n                    try\n                    {\n                        _txIds.Writer.TryComplete();\n                    }\n                    finally\n                    {\n                        _txIdsWriterLock.ExitWriteLock();\n                    }\n                });\n\n                try\n                {\n                    var txIds = new HashSet<TxId>();\n\n                    while (await _txIds.Reader.WaitToReadAsync(cancellationToken))\n                    {\n                        while (_txIds.Reader.TryRead(out TxId txId))\n                        {\n                            txIds.Add(txId);\n                        }\n                    }\n\n                    _logger.Debug(\n                        \"Start to run _txFetcher from {Peer}. (count: {Count})\",\n                        _peer,\n                        txIds.Count);\n                    var stopWatch = new Stopwatch();\n                    stopWatch.Start();\n                    var txs = new HashSet<Transaction>(\n                        await _txFetcher(\n                                _peer,\n                                txIds,\n                                cancellationToken)\n                            .ToListAsync(cancellationToken)\n                            .AsTask());\n                    _logger.Debug(\n                        \"End of _txFetcher from {Peer}. (received: {Count}); \" +\n                        \"Time taken: {Elapsed}\",\n                        _peer,\n                        txs.Count,\n                        stopWatch.Elapsed);\n\n                    return txs;\n                }\n                catch (Exception e)\n                {\n                    _logger.Error(\n                        e,\n                        \"An error occurred during {MethodName}() from {Peer}\",\n                        nameof(RequestAsync),\n                        _peer);\n                    throw;\n                }\n                finally\n                {\n                    _logger.Debug(\n                        \"End of {MethodName}() from {Peer}\",\n                        nameof(RequestAsync),\n                        _peer);\n                }\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.RocksDBStore/Libplanet.RocksDBStore.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <PropertyGroup>\n    <Summary>A Libplanet.IStore implementation using RocksDB</Summary>\n    <Description>A Libplanet.IStore implementation using RocksDB</Description>\n  </PropertyGroup>\n\n  <PropertyGroup>\n    <Nullable>enable</Nullable>\n    <TreatWarningsAsErrors>true</TreatWarningsAsErrors>\n    <NoWarn>$(NoWarn);NU5104</NoWarn>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <PackageReference Include=\"RocksDB\" Version=\"8.5.3.42578\" />\n    <PackageReference Include=\"Serilog\" Version=\"2.8.0\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <ProjectReference Include=\"..\\Libplanet\\Libplanet.csproj\" />\n    <ProjectReference Include=\"..\\Libplanet.Store\\Libplanet.Store.csproj\" />\n    <!-- FIXME: We should specify the version range when the following NuGet issue\n    is addressed: <https://github.com/NuGet/Home/issues/5556>. -->\n  </ItemGroup>\n\n</Project>\n"
  },
  {
    "path": "src/Libplanet.RocksDBStore/RocksDBInstanceType.cs",
    "content": "namespace Libplanet.RocksDBStore\n{\n    /// <summary>\n    /// Represent <see cref=\"RocksDbSharp.RocksDb\"/>'s instance type.\n    /// <see cref=\"RocksDbSharp.RocksDb\"/> can be instantiated as primary, read-only, or secondary.\n    /// Please refer a <a\n    /// href=\"https://github.com/facebook/rocksdb/wiki/Read-only-and-Secondary-instances\">\n    /// RocksDB's document</a> for more details.\n    /// </summary>\n    public enum RocksDBInstanceType\n    {\n        /// <summary>\n        /// Primary instance.\n        /// </summary>\n        Primary,\n\n        /// <summary>\n        /// ReadOnly instance.\n        /// </summary>\n        ReadOnly,\n\n        /// <summary>\n        /// Secondary instance.\n        /// </summary>\n        Secondary,\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.RocksDBStore/RocksDBKeyValueStore.cs",
    "content": "using System.Collections.Generic;\nusing Libplanet.Store.Trie;\nusing RocksDbSharp;\n\nnamespace Libplanet.RocksDBStore\n{\n    /// <summary>\n    /// The <a href=\"https://rocksdb.org/\">RocksDB</a> <see cref=\"IKeyValueStore\"/> implementation.\n    /// This stores data in the RocksDB.\n    /// <para><see cref=\"RocksDBStore\"/> and <see cref=\"RocksDBKeyValueStore\"/>-backed\n    /// <see cref=\"TrieStateStore\"/> can be instantiated from a URI with <c>rocksdb+file:</c> scheme\n    /// using <see cref=\"StoreLoaderAttribute.LoadStore(Uri)\"/>, e.g.:</para>\n    /// <list type=\"bullet\">\n    /// <item><description><c>rocksdb+file:///var/data/planet/</c></description></item>\n    /// <item><description><c>rocksdb+file:///c:/Users/john/AppData/Local/planet/</c></description>\n    /// </item>\n    /// </list>\n    /// <para>The following query string parameters are supported:</para>\n    /// <list type=\"table\">\n    /// <item>\n    /// <term><c>block-cache</c></term>\n    /// <description>Corresponds to\n    /// <see cref=\"RocksDBStore(string, int, int, ulong?, ulong?, ulong?, int, int, int)\"/>'s\n    /// <c>blockCacheSize</c> parameter.  512 by default.</description>\n    /// </item>\n    /// <item>\n    /// <term><c>tx-cache</c></term>\n    /// <description>Corresponds to\n    /// <see cref=\"RocksDBStore(string, int, int, ulong?, ulong?, ulong?, int, int, int)\"/>'s\n    /// <c>txCacheSize</c> parameter.  1024 by default.</description>\n    /// </item>\n    /// <item>\n    /// <term><c>max-total-wal-size</c></term>\n    /// <description>Corresponds to RocksDB's <c>max_total_wal_size</c> option.</description>\n    /// </item>\n    /// <item>\n    /// <term><c>keep-log-file-num</c></term>\n    /// <description>Corresponds to RocksDB's <c>keep_log_file_num</c> option.</description>\n    /// </item>\n    /// <item>\n    /// <term><c>max_log_file_size</c></term>\n    /// <description>Corresponds to RocksDB's <c>max_log_file_size</c> option.</description>\n    /// </item>\n    /// <item>\n    /// <term><c>tx-epoch-unit-secs</c></term>\n    /// <description>Corresponds to\n    /// <see cref=\"RocksDBStore(string, int, int, ulong?, ulong?, ulong?, int, int, int)\"/>'s\n    /// <c>txEpochUnitSeconds</c> parameter.  86400 by default.</description>\n    /// </item>\n    /// <item>\n    /// <term><c>block-epoch-unit-secs</c></term>\n    /// <description>Corresponds to\n    /// <see cref=\"RocksDBStore(string, int, int, ulong?, ulong?, ulong?, int, int, int)\"/>'s\n    /// <c>blockEpochUnitSeconds</c> parameter.  86400 by default.</description>\n    /// </item>\n    /// <item>\n    /// <term><c>connection-cache</c></term>\n    /// <description>Corresponds to\n    /// <see cref=\"RocksDBStore(string, int, int, ulong?, ulong?, ulong?, int, int, int)\"/>'s\n    /// <c>dbConnectionCacheSize</c> parameter.  100 by default.</description>\n    /// </item>\n    /// <item>\n    /// <term><c>states-dir</c></term>\n    /// <description>Corresponds to <see cref=\"RocksDBKeyValueStore(string)\"/>'s <c>path</c>\n    /// parameter.  It is relative to the URI path, and defaults to <c>states</c>.</description>\n    /// </item>\n    /// </list>\n    /// </summary>\n    public class RocksDBKeyValueStore : IKeyValueStore\n    {\n        private readonly RocksDb _keyValueDb;\n        private bool _disposed = false;\n\n        /// <summary>\n        /// Creates a new <see cref=\"RocksDBKeyValueStore\"/>.\n        /// </summary>\n        /// <param name=\"path\">The path of the storage file will be saved.</param>\n        /// <param name=\"type\">Determines the instance type of the internal <see cref=\"RocksDb\"/>\n        /// instances.  <see cref=\"RocksDBInstanceType.Primary\"/> by default.</param>\n        /// <param name=\"options\">The <see cref=\"DbOptions\"/> for <see cref=\"RocksDb\"/>.</param>\n        public RocksDBKeyValueStore(\n            string path,\n            RocksDBInstanceType type = RocksDBInstanceType.Primary,\n            DbOptions? options = null)\n        {\n            options ??= new DbOptions()\n                .SetCreateIfMissing()\n                .SetSoftPendingCompactionBytesLimit(1000000000000)\n                .SetHardPendingCompactionBytesLimit(1038176821042);\n\n            _keyValueDb = RocksDBUtils.OpenRocksDb(options, path, type: type);\n            Type = type;\n        }\n\n        public RocksDBInstanceType Type { get; }\n\n        /// <inheritdoc/>\n        public byte[] Get(in KeyBytes key) => _keyValueDb.Get(key.ToByteArray())\n            ?? throw new KeyNotFoundException($\"No such key: ${key}.\");\n\n        /// <inheritdoc/>\n        public void Set(in KeyBytes key, byte[] value)\n        {\n            _keyValueDb.Put(key.ToByteArray(), value);\n        }\n\n        /// <inheritdoc/>\n        public void Set(IDictionary<KeyBytes, byte[]> values)\n        {\n            using var writeBatch = new WriteBatch();\n\n            foreach (KeyValuePair<KeyBytes, byte[]> kv in values)\n            {\n                writeBatch.Put(kv.Key.ToByteArray(), kv.Value);\n            }\n\n            _keyValueDb.Write(writeBatch);\n        }\n\n        /// <inheritdoc/>\n        public void Delete(in KeyBytes key)\n        {\n            _keyValueDb.Remove(key.ToByteArray());\n        }\n\n        /// <inheritdoc cref=\"IKeyValueStore.Delete(IEnumerable{KeyBytes})\"/>\n        public void Delete(IEnumerable<KeyBytes> keys)\n        {\n            foreach (KeyBytes key in keys)\n            {\n                _keyValueDb.Remove(key.ToByteArray());\n            }\n        }\n\n        /// <inheritdoc cref=\"System.IDisposable.Dispose()\"/>\n        public void Dispose()\n        {\n            if (!_disposed)\n            {\n                _keyValueDb.Dispose();\n                _disposed = true;\n            }\n        }\n\n        /// <inheritdoc/>\n        public bool Exists(in KeyBytes key) =>\n            _keyValueDb.Get(key.ToByteArray()) is { };\n\n        /// <inheritdoc/>\n        public IEnumerable<KeyBytes> ListKeys()\n        {\n            using Iterator it = _keyValueDb.NewIterator();\n            for (it.SeekToFirst(); it.Valid(); it.Next())\n            {\n                yield return new KeyBytes(it.Key());\n            }\n        }\n\n        public void TryCatchUpWithPrimary()\n        {\n            _keyValueDb.TryCatchUpWithPrimary();\n        }\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.RocksDBStore/RocksDBStore.Prune.cs",
    "content": "#nullable disable\nusing System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing Libplanet.Common;\nusing Libplanet.Store;\nusing Libplanet.Types.Blocks;\nusing RocksDbSharp;\n\nnamespace Libplanet.RocksDBStore\n{\n    public partial class RocksDBStore : BaseStore\n    {\n        /// <inheritdoc cref=\"IStore.PruneOutdatedChains\"/>\n        public override void PruneOutdatedChains(bool noopWithoutCanon = false)\n        {\n            if (!(GetCanonicalChainId() is { } ccid))\n            {\n                if (noopWithoutCanon)\n                {\n                    return;\n                }\n\n                throw new InvalidOperationException(\"Canonical chain ID is not assigned.\");\n            }\n\n            using var batch = new WriteBatch();\n\n            // Copy indexes from previous chains.\n            // TxNonce is not copied because it is copied during .ForkTxNonces().\n            long index = 0;\n            foreach (var hash in IterateIndexesForPrune(ccid))\n            {\n                batch.Put(\n                    IndexKey(ccid, RocksDBStoreBitConverter.GetBytes(index)),\n                    hash.ToByteArray());\n\n                if (batch.Count() > 10000)\n                {\n                    _chainDb.Write(batch);\n                    batch.Clear();\n                }\n\n                index++;\n            }\n\n            _chainDb.Write(batch);\n            batch.Clear();\n\n            batch.Delete(PreviousChainIdKey(ccid));\n            batch.Delete(PreviousChainIndexKey(ccid));\n            batch.Delete(DeletedChainKey(ccid));\n            _chainDb.Write(batch);\n            batch.Clear();\n\n            int guidLength = ccid.ToByteArray().Length;\n            using Iterator it = _chainDb.NewIterator();\n            for (it.SeekToFirst();\n                 it.Valid();\n                 it.Next())\n            {\n                if (it.Key().StartsWith(CanonicalChainIdIdKey))\n                {\n                    continue;\n                }\n\n                try\n                {\n                    var id = new Guid(it.Key().Skip(1).Take(guidLength).ToArray());\n                    if (id.Equals(ccid))\n                    {\n                        continue;\n                    }\n\n                    batch.Delete(it.Key());\n                }\n                catch (Exception)\n                {\n                    // Key is corrupted, delete.\n                    batch.Delete(it.Key());\n                }\n\n                if (batch.Count() > 10000)\n                {\n                    _chainDb.Write(batch);\n                    batch.Clear();\n                }\n            }\n\n            _chainDb.Write(batch);\n            batch.Clear();\n        }\n\n        private IEnumerable<BlockHash> IterateIndexesForPrune(Guid chainId)\n        {\n            Stack<(Guid Id, long Count)> chainInfos =\n                new Stack<(Guid Id, long Count)>();\n\n            chainInfos.Push((chainId, CountIndex(chainId)));\n            while (GetPreviousChainInfo(chainInfos.Peek().Id) is { } chainInfo)\n            {\n                chainInfos.Push(chainInfo);\n            }\n\n            List<BlockHash> hashes = new List<BlockHash>();\n\n            while (chainInfos.Count > 0)\n            {\n                var chainInfo = chainInfos.Pop();\n\n                foreach ((BlockHash hash, int i) in\n                    IterateIndexesInnerForPrune(chainInfo.Id).Select((hash, i) => (hash, i)))\n                {\n                    if (i == 0)\n                    {\n                        BlockDigest digest = GetBlockDigest(hash) ??\n                            throw new InvalidOperationException(\n                                $\"Could not find a block corresponding to {hash} in storage.\");\n\n                        // NOTE: This means there is a gap between two chain ids.\n                        if (digest.Index > hashes.Count)\n                        {\n                            throw new InvalidOperationException(\n                                $\"Next block is expected to be of index #{hashes.Count} but \" +\n                                $\"got #{digest.Index} {digest.Hash}.\");\n                        }\n\n                        // NOTE: This means there is an overlap between two chain ids.\n                        // The newer one should overwrite the old.\n                        if (digest.Index < hashes.Count)\n                        {\n                            // NOTE: Make sure it can be overwritten by checking continuity.\n                            if (digest.PreviousHash is { } previousHash)\n                            {\n                                BlockHash targetHash = hashes[(int)digest.Index - 1];\n                                if (!previousHash.Equals(targetHash))\n                                {\n                                    throw new InvalidOperationException(\n                                        $\"The previous hash {previousHash} of a retrieved \" +\n                                        $\"block #{digest.Index} {digest.Hash} \" +\n                                        $\"does not match the one iterated so far {targetHash}\");\n                                }\n                            }\n\n                            // NOTE: Truncate the iterated list so far.\n                            _logger.Debug(\n                                \"Truncating hashes iterated so far from \" +\n                                \"{IteratedCount} to {TargetCount}\",\n                                hashes.Count,\n                                digest.Index);\n                            hashes.RemoveRange(\n                                (int)digest.Index, (int)(hashes.Count - digest.Index));\n                        }\n                    }\n\n                    // NOTE: We assume non-first hashes are sequential for a chain id.\n                    hashes.Add(hash);\n                }\n            }\n\n            BlockHash lastHash = hashes.Last();\n            BlockDigest lastDigest = GetBlockDigest(lastHash) ??\n                throw new InvalidOperationException(\n                    $\"Could not find a block corresponding to {lastHash} in storage.\");\n\n            if (lastDigest.Index != hashes.Count - 1)\n            {\n                throw new InvalidOperationException(\n                    $\"The last iterated block is #{lastDigest.Index} {lastDigest.Hash} when \" +\n                    $\"its expected index is {hashes.Count}\");\n            }\n\n            return hashes;\n        }\n\n        private IEnumerable<BlockHash> IterateIndexesInnerForPrune(Guid chainId)\n        {\n            byte[] prefix = Concat(IndexKeyPrefix, chainId.ToByteArray());\n            foreach (Iterator it in IterateDb(_chainDb, prefix))\n            {\n                byte[] value = it.Value();\n                yield return new BlockHash(value);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.RocksDBStore/RocksDBStore.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Collections.Immutable;\nusing System.Collections.Specialized;\nusing System.IO;\nusing System.Linq;\nusing System.Security.Cryptography;\nusing System.Threading;\nusing System.Web;\nusing Bencodex;\nusing Libplanet.Common;\nusing Libplanet.Crypto;\nusing Libplanet.Store;\nusing Libplanet.Types.Blocks;\nusing Libplanet.Types.Evidence;\nusing Libplanet.Types.Tx;\nusing LruCacheNet;\nusing RocksDbSharp;\nusing Serilog;\n\nnamespace Libplanet.RocksDBStore\n{\n    /// <summary>\n    /// The <a href=\"https://rocksdb.org/\">RocksDB</a> <see cref=\"IStore\"/> implementation,\n    /// which is more production-ready than <see cref=\"DefaultStore\"/>.\n    /// This stores data in the RocksDB with multiple partitions under the hood.\n    /// <para><see cref=\"RocksDBStore\"/> and <see cref=\"RocksDBKeyValueStore\"/>-backed\n    /// <see cref=\"TrieStateStore\"/> can be instantiated from a URI with <c>rocksdb+file:</c> scheme\n    /// using <see cref=\"StoreLoaderAttribute.LoadStore(Uri)\"/>, e.g.:</para>\n    /// <list type=\"bullet\">\n    /// <item><description><c>rocksdb+file:///var/data/planet/</c></description></item>\n    /// <item><description><c>rocksdb+file:///c:/Users/john/AppData/Local/planet/</c></description>\n    /// </item>\n    /// </list>\n    /// <para>The following query string parameters are supported:</para>\n    /// <list type=\"table\">\n    /// <item>\n    /// <term><c>block-cache</c></term>\n    /// <description>Corresponds to\n    /// <see cref=\"RocksDBStore(string, int, int, ulong?, ulong?, ulong?, int, int, int)\"/>'s\n    /// <c>blockCacheSize</c> parameter.  512 by default.</description>\n    /// </item>\n    /// <item>\n    /// <term><c>tx-cache</c></term>\n    /// <description>Corresponds to\n    /// <see cref=\"RocksDBStore(string, int, int, ulong?, ulong?, ulong?, int, int, int)\"/>'s\n    /// <c>txCacheSize</c> parameter.  1024 by default.</description>\n    /// </item>\n    /// <item>\n    /// <term><c>max-total-wal-size</c></term>\n    /// <description>Corresponds to RocksDB's <c>max_total_wal_size</c> option.</description>\n    /// </item>\n    /// <item>\n    /// <term><c>keep-log-file-num</c></term>\n    /// <description>Corresponds to RocksDB's <c>keep_log_file_num</c> option.</description>\n    /// </item>\n    /// <item>\n    /// <term><c>max_log_file_size</c></term>\n    /// <description>Corresponds to RocksDB's <c>max_log_file_size</c> option.</description>\n    /// </item>\n    /// <item>\n    /// <term><c>tx-epoch-unit-secs</c></term>\n    /// <description>Corresponds to\n    /// <see cref=\"RocksDBStore(string, int, int, ulong?, ulong?, ulong?, int, int, int)\"/>'s\n    /// <c>txEpochUnitSeconds</c> parameter.  86400 by default.</description>\n    /// </item>\n    /// <item>\n    /// <term><c>block-epoch-unit-secs</c></term>\n    /// <description>Corresponds to\n    /// <see cref=\"RocksDBStore(string, int, int, ulong?, ulong?, ulong?, int, int, int)\"/>'s\n    /// <c>blockEpochUnitSeconds</c> parameter.  86400 by default.</description>\n    /// </item>\n    /// <item>\n    /// <term><c>connection-cache</c></term>\n    /// <description>Corresponds to\n    /// <see cref=\"RocksDBStore(string, int, int, ulong?, ulong?, ulong?, int, int, int)\"/>'s\n    /// <c>dbConnectionCacheSize</c> parameter.  100 by default.</description>\n    /// </item>\n    /// <item>\n    /// <term><c>states-dir</c></term>\n    /// <description>Corresponds to <see cref=\"RocksDBKeyValueStore(string)\"/>'s <c>path</c>\n    /// parameter.  It is relative to the URI path, and defaults to <c>states</c>.</description>\n    /// </item>\n    /// </list>\n    /// </summary>\n    /// <seealso cref=\"IStore\"/>\n    public partial class RocksDBStore : BaseStore\n    {\n        private const string BlockDbRootPathName = \"block\";\n        private const string BlockIndexDbName = \"blockindex\";\n        private const string BlockPerceptionDbName = \"blockpercept\";\n        private const string TxDbRootPathName = \"tx\";\n        private const string TxIndexDbName = \"txindex\";\n        private const string TxExecutionDbName = \"txexec\";\n        private const string TxIdBlockHashIndexDbName = \"txbindex\";\n        private const string ChainDbName = \"chain\";\n        private const string StatesKvPathDefault = \"states\";\n        private const string BlockCommitDbName = \"blockcommit\";\n        private const string NextStateRootHashDbName = \"nextstateroothash\";\n        private const string PendingEvidenceDbName = \"evidencep\";\n        private const string CommittedEvidenceDbName = \"evidencec\";\n        private const int ForkWriteBatchSize = 100000;\n\n        private static readonly byte[] IndexKeyPrefix = { (byte)'I' };\n        private static readonly byte[] BlockKeyPrefix = { (byte)'B' };\n        private static readonly byte[] TxKeyPrefix = { (byte)'T' };\n        private static readonly byte[] TxNonceKeyPrefix = { (byte)'N' };\n        private static readonly byte[] TxExecutionKeyPrefix = { (byte)'e' };\n        private static readonly byte[] TxIdBlockHashIndexPrefix = { (byte)'i' };\n        private static readonly byte[] IndexCountKeyPrefix = { (byte)'c' };\n        private static readonly byte[] CanonicalChainIdIdKey = { (byte)'C' };\n        private static readonly byte[] PreviousChainIdKeyPrefix = { (byte)'P' };\n        private static readonly byte[] PreviousChainIndexKeyPrefix = { (byte)'p' };\n        private static readonly byte[] ForkedChainsKeyPrefix = { (byte)'f' };\n        private static readonly byte[] DeletedKeyPrefix = { (byte)'d' };\n        private static readonly byte[] ChainIdKeyPrefix = { (byte)'h' };\n        private static readonly byte[] ChainBlockCommitKeyPrefix = { (byte)'M' };\n        private static readonly byte[] BlockCommitKeyPrefix = { (byte)'m' };\n        private static readonly byte[] NextStateRootHashKeyPrefix = { (byte)'s' };\n        private static readonly byte[] PendingEvidenceKeyPrefix = { (byte)'v' };\n        private static readonly byte[] CommittedEvidenceKeyPrefix = { (byte)'V' };\n\n        private static readonly Codec Codec = new Codec();\n\n        private readonly ILogger _logger;\n\n        private readonly LruCache<TxId, object> _txCache;\n        private readonly LruCache<BlockHash, BlockDigest> _blockCache;\n        private readonly LruCache<EvidenceId, EvidenceBase> _evidenceCache;\n\n        private readonly DbOptions _options;\n        private readonly ColumnFamilyOptions _colOptions;\n        private readonly string _path;\n        private readonly RocksDBInstanceType _instanceType;\n        private readonly int _txEpochUnitSeconds;\n        private readonly int _blockEpochUnitSeconds;\n\n        private readonly RocksDb _blockIndexDb;\n        private readonly RocksDb _blockPerceptionDb;\n        private readonly LruCache<string, RocksDb> _blockDbCache;\n        private readonly RocksDb _txIndexDb;\n        private readonly LruCache<string, RocksDb> _txDbCache;\n        private readonly RocksDb _txExecutionDb;\n        private readonly RocksDb _txIdBlockHashIndexDb;\n        private readonly RocksDb _chainDb;\n        private readonly RocksDb _blockCommitDb;\n        private readonly RocksDb _nextStateRootHashDb;\n        private readonly RocksDb _pendingEvidenceDb;\n        private readonly RocksDb _committedEvidenceDb;\n\n        private readonly ReaderWriterLockSlim _rwTxLock;\n        private readonly ReaderWriterLockSlim _rwBlockLock;\n        private readonly ReaderWriterLockSlim _rwBlockCommitLock;\n        private readonly ReaderWriterLockSlim _rwNextStateRootHashLock;\n        private readonly ReaderWriterLockSlim _rwEvidenceLock;\n        private bool _disposed = false;\n        private object _chainForkDeleteLock = new object();\n        private LruCache<Guid, LruCache<(int, int?), List<BlockHash>>> _indexCache;\n\n        /// <summary>\n        /// Creates a new <seealso cref=\"RocksDBStore\"/>.\n        /// </summary>\n        /// <param name=\"path\">The path of the directory where the storage files will be saved.\n        /// </param>\n        /// <param name=\"blockCacheSize\">The capacity of the block cache.</param>\n        /// <param name=\"txCacheSize\">The capacity of the transaction cache.</param>\n        /// <param name=\"evidenceCacheSize\">The capacity of the evidence cache.</param>\n        /// <param name=\"maxTotalWalSize\">The number to configure <c>max_total_wal_size</c> RocksDB\n        /// option.</param>\n        /// <param name=\"keepLogFileNum\">The number to configure <c>keep_log_file_num</c> RocksDB\n        /// option.</param>\n        /// <param name=\"maxLogFileSize\">The number to configure <c>max_log_file_size</c>\n        /// RocksDB option.</param>\n        /// <param name=\"txEpochUnitSeconds\">The interval between epochs of DB partitions containing\n        /// transactions.  86,400 seconds by default.</param>\n        /// <param name=\"blockEpochUnitSeconds\">The interval between epochs of DB partitions\n        /// containing blocks.  86,400 seconds by default.</param>\n        /// <param name=\"dbConnectionCacheSize\">The capacity of the block and transaction\n        /// RocksDB connection cache. 100 by default.</param>\n        /// <param name=\"type\">Determines the instance type of the internal <see cref=\"RocksDb\"/>\n        /// instances.  <see cref=\"RocksDBInstanceType.Primary\"/> by default.</param>\n        public RocksDBStore(\n            string path,\n            int blockCacheSize = 512,\n            int txCacheSize = 1024,\n            int evidenceCacheSize = 1024,\n            ulong? maxTotalWalSize = null,\n            ulong? keepLogFileNum = null,\n            ulong? maxLogFileSize = null,\n            int txEpochUnitSeconds = 86400,\n            int blockEpochUnitSeconds = 86400,\n            int dbConnectionCacheSize = 100,\n            RocksDBInstanceType type = RocksDBInstanceType.Primary\n        )\n        {\n            _logger = Log.ForContext<RocksDBStore>();\n\n            if (path is null)\n            {\n                throw new ArgumentNullException(nameof(path));\n            }\n\n            path = Path.GetFullPath(path);\n\n            if (!Directory.Exists(path))\n            {\n                Directory.CreateDirectory(path);\n            }\n\n            _txCache = new LruCache<TxId, object>(capacity: txCacheSize);\n            _blockCache = new LruCache<BlockHash, BlockDigest>(capacity: blockCacheSize);\n            _evidenceCache = new LruCache<EvidenceId, EvidenceBase>(capacity: evidenceCacheSize);\n            _indexCache = new LruCache<Guid, LruCache<(int, int?), List<BlockHash>>>(64);\n\n            _path = path;\n            _instanceType = type;\n            _txEpochUnitSeconds = txEpochUnitSeconds > 0\n                ? txEpochUnitSeconds\n                : throw new ArgumentException(\n                    \"It must be greater than 0.\",\n                    nameof(txEpochUnitSeconds));\n            _blockEpochUnitSeconds = blockEpochUnitSeconds > 0\n                ? blockEpochUnitSeconds\n                : throw new ArgumentException(\n                    \"It must be greater than 0.\",\n                    nameof(blockEpochUnitSeconds));\n            _options = new DbOptions()\n                .SetCreateIfMissing();\n            _colOptions = new ColumnFamilyOptions();\n\n            if (maxTotalWalSize is ulong maxTotalWalSizeValue)\n            {\n                _options = _options.SetMaxTotalWalSize(maxTotalWalSizeValue);\n                _colOptions = _colOptions.SetMaxTotalWalSize(maxTotalWalSizeValue);\n            }\n\n            if (keepLogFileNum is ulong keepLogFileNumValue)\n            {\n                _options = _options.SetKeepLogFileNum(keepLogFileNumValue);\n                _colOptions = _colOptions.SetKeepLogFileNum(keepLogFileNumValue);\n            }\n\n            if (maxLogFileSize is ulong maxLogFileSizeValue)\n            {\n                _options = _options.SetMaxLogFileSize(maxLogFileSizeValue);\n                _colOptions = _colOptions.SetMaxLogFileSize(maxLogFileSizeValue);\n            }\n\n            _blockIndexDb = RocksDBUtils.OpenRocksDb(\n                _options, BlockDbPath(BlockIndexDbName), type: _instanceType);\n            _blockPerceptionDb =\n                RocksDBUtils.OpenRocksDb(\n                    _options, RocksDbPath(BlockPerceptionDbName), type: _instanceType);\n            _txIndexDb = RocksDBUtils.OpenRocksDb(\n                _options, TxDbPath(TxIndexDbName), type: _instanceType);\n            _txExecutionDb =\n                RocksDBUtils.OpenRocksDb(\n                    _options, RocksDbPath(TxExecutionDbName), type: _instanceType);\n            _txIdBlockHashIndexDb =\n                RocksDBUtils.OpenRocksDb(\n                    _options, RocksDbPath(TxIdBlockHashIndexDbName), type: _instanceType);\n            _blockCommitDb =\n                RocksDBUtils.OpenRocksDb(\n                    _options, RocksDbPath(BlockCommitDbName), type: _instanceType);\n            _nextStateRootHashDb =\n                RocksDBUtils.OpenRocksDb(\n                    _options, RocksDbPath(NextStateRootHashDbName), type: _instanceType);\n            _pendingEvidenceDb =\n                RocksDBUtils.OpenRocksDb(_options, RocksDbPath(PendingEvidenceDbName));\n            _committedEvidenceDb =\n                RocksDBUtils.OpenRocksDb(_options, RocksDbPath(CommittedEvidenceDbName));\n\n            // When opening a DB in a read-write mode, you need to specify all Column Families that\n            // currently exist in a DB. https://github.com/facebook/rocksdb/wiki/Column-Families\n            var chainDbColumnFamilies = GetColumnFamilies(_options, ChainDbName);\n            _chainDb = RocksDBUtils.OpenRocksDb(\n                _options, RocksDbPath(ChainDbName), chainDbColumnFamilies, _instanceType);\n\n            _rwTxLock = new ReaderWriterLockSlim(LockRecursionPolicy.SupportsRecursion);\n            _rwBlockLock = new ReaderWriterLockSlim(LockRecursionPolicy.SupportsRecursion);\n            _rwBlockCommitLock = new ReaderWriterLockSlim(LockRecursionPolicy.SupportsRecursion);\n            _rwNextStateRootHashLock =\n                new ReaderWriterLockSlim(LockRecursionPolicy.SupportsRecursion);\n            _rwEvidenceLock = new ReaderWriterLockSlim(LockRecursionPolicy.SupportsRecursion);\n\n            _blockDbCache = new LruCache<string, RocksDb>(dbConnectionCacheSize);\n            _blockDbCache.SetPreRemoveDataMethod(db =>\n            {\n                db.Dispose();\n                return true;\n            });\n            _txDbCache = new LruCache<string, RocksDb>(dbConnectionCacheSize);\n            _txDbCache.SetPreRemoveDataMethod(db =>\n            {\n                db.Dispose();\n                return true;\n            });\n        }\n\n        public static bool MigrateChainDBFromColumnFamilies(string path)\n        {\n            var opt = new DbOptions();\n            var colOpt = new ColumnFamilyOptions();\n            opt.SetCreateIfMissing();\n            List<string> cfns = RocksDb.ListColumnFamilies(opt, path).ToList();\n            var cfs = new ColumnFamilies();\n            foreach (string name in cfns)\n            {\n                cfs.Add(name, colOpt);\n            }\n\n            RocksDb db = RocksDb.Open(opt, path, cfs);\n            if (cfs.Count() == 1 && IterateDb(db, ChainIdKeyPrefix).Any())\n            {\n                // Already migrated.\n                db.Dispose();\n                return false;\n            }\n\n            var tmpDbPath = Path.GetDirectoryName(path) + \".tmp\";\n            RocksDb newDb = RocksDb.Open(opt, tmpDbPath);\n            var ccid = new Guid(db.Get(CanonicalChainIdIdKey));\n            newDb.Put(CanonicalChainIdIdKey, ccid.ToByteArray());\n            ColumnFamilyHandle ccf = db.GetColumnFamily(ccid.ToString());\n            var batch = new WriteBatch();\n\n            // Migrate chain indexes\n            (ColumnFamilyHandle, long)? PreviousColumnFamily(ColumnFamilyHandle cfh)\n            {\n                byte[] cid = db.Get(PreviousChainIdKeyPrefix, cfh);\n\n                if (cid is null)\n                {\n                    return null;\n                }\n                else\n                {\n                    return (\n                        db.GetColumnFamily(new Guid(cid).ToString()),\n                        RocksDBStoreBitConverter.ToInt64(db.Get(PreviousChainIndexKeyPrefix, cfh))\n                    );\n                }\n            }\n\n            void CopyIndexes(ColumnFamilyHandle cfh, long? limit)\n            {\n                Iterator it = db.NewIterator(cfh);\n                for (\n                    it.Seek(IndexKeyPrefix);\n                    it.Valid() && it.Key().StartsWith(IndexKeyPrefix);\n                    it.Next()\n                )\n                {\n                    byte[] indexBytes = it.Key().Skip(1).ToArray();\n                    long index = RocksDBStoreBitConverter.ToInt64(indexBytes);\n                    if (index > limit)\n                    {\n                        continue;\n                    }\n\n                    batch.Put(IndexKey(ccid, indexBytes), it.Value());\n\n                    if (batch.Count() > 10000)\n                    {\n                        newDb.Write(batch);\n                        batch.Clear();\n                    }\n                }\n            }\n\n            CopyIndexes(ccf, null);\n            var cfInfo = PreviousColumnFamily(ccf);\n            while (cfInfo is { } cfInfoNotNull)\n            {\n                ColumnFamilyHandle cf = cfInfoNotNull.Item1;\n                long cfi = cfInfoNotNull.Item2;\n\n                CopyIndexes(cf, cfi);\n\n                cfInfo = PreviousColumnFamily(cf);\n            }\n\n            newDb.Write(batch);\n            batch.Clear();\n\n            // Migrate total count & chain ID\n            long prevCount = RocksDBStoreBitConverter.ToInt64(\n                db.Get(IndexCountKeyPrefix, ccf)\n            );\n            newDb.Put(\n                IndexCountKey(ccid),\n                RocksDBStoreBitConverter.GetBytes(prevCount)\n            );\n            newDb.Put(ChainIdKey(ccid), ccid.ToByteArray());\n\n            // Migrate tx nonces\n            Iterator it = db.NewIterator(ccf);\n            for (\n                it.Seek(TxNonceKeyPrefix);\n                it.Valid() && it.Key().StartsWith(TxNonceKeyPrefix);\n                it.Next()\n            )\n            {\n                batch.Put(TxNonceKey(ccid, it.Key().Skip(1).ToArray()), it.Value());\n            }\n\n            newDb.Write(batch);\n            batch.Dispose();\n\n            // Remove column families\n            db.Dispose();\n            newDb.Dispose();\n            Directory.Delete(path, true);\n            Directory.Move(tmpDbPath, path);\n\n            return true;\n        }\n\n        /// <inheritdoc/>\n        public override IEnumerable<Guid> ListChainIds()\n        {\n            foreach (var it in IterateDb(_chainDb, ChainIdKeyPrefix))\n            {\n                var guid = new Guid(it.Value());\n                if (IsDeletionMarked(guid) && HasFork(guid))\n                {\n                    continue;\n                }\n\n                yield return guid;\n            }\n        }\n\n        /// <inheritdoc/>\n        public override void DeleteChainId(Guid chainId)\n        {\n            _indexCache.Remove(chainId);\n            if (HasFork(chainId))\n            {\n                _chainDb.Put(DeletedChainKey(chainId), Array.Empty<byte>());\n\n                // We need only chain indexes, not tx nonces at this time because they already had\n                // been copied on .ForkTxNonces().\n                // FIXME: We should remove this code after adjusting .ForkTxNonces().\n                using var batch = new WriteBatch();\n                byte[] prefix = TxNonceKey(chainId);\n                foreach (Iterator k in IterateDb(_chainDb, prefix))\n                {\n                    batch.Delete(k.Key());\n                }\n\n                _chainDb.Write(batch);\n                return;\n            }\n\n            _logger.Debug($\"Deleting chainID: {chainId}\");\n            Guid? prevChain = GetPreviousChainInfo(chainId)?.Item1;\n\n            string cfName = chainId.ToString();\n            try\n            {\n                using var batch = new WriteBatch();\n                foreach (Iterator it in IterateDb(_chainDb, IndexKey(chainId)))\n                {\n                    batch.Delete(it.Key());\n                }\n\n                foreach (Iterator it in IterateDb(_chainDb, TxNonceKey(chainId)))\n                {\n                    batch.Delete(it.Key());\n                }\n\n                batch.Delete(DeletedChainKey(chainId));\n                batch.Delete(PreviousChainIdKey(chainId));\n                batch.Delete(PreviousChainIndexKey(chainId));\n                batch.Delete(IndexCountKey(chainId));\n                batch.Delete(ChainIdKey(chainId));\n\n                _chainDb.Write(batch);\n\n                if (prevChain is { } prevChainNotNull)\n                {\n                    lock (_chainForkDeleteLock)\n                    {\n                        if (HasFork(prevChainNotNull))\n                        {\n                            RemoveFork(prevChainNotNull, chainId);\n\n                            if (IsDeletionMarked(prevChainNotNull))\n                            {\n                                DeleteChainId(prevChainNotNull);\n                            }\n                        }\n                    }\n                }\n            }\n            catch (KeyNotFoundException)\n            {\n                // Do nothing according to the specification: DeleteChainId() should be idempotent.\n                _logger.Debug($\"No such chain ID in _chainDb: {cfName}\", cfName);\n            }\n            catch (Exception e)\n            {\n                LogUnexpectedException(nameof(DeleteChainId), e);\n                throw;\n            }\n        }\n\n        /// <inheritdoc />\n        public override Guid? GetCanonicalChainId()\n        {\n            try\n            {\n                byte[] bytes = _chainDb.Get(CanonicalChainIdIdKey);\n\n                return bytes is null\n                    ? (Guid?)null\n                    : new Guid(bytes);\n            }\n            catch (Exception e)\n            {\n                LogUnexpectedException(nameof(GetCanonicalChainId), e);\n            }\n\n            return (Guid?)null;\n        }\n\n        /// <inheritdoc />\n        public override void SetCanonicalChainId(Guid chainId)\n        {\n            try\n            {\n                byte[] bytes = chainId.ToByteArray();\n                _chainDb.Put(CanonicalChainIdIdKey, bytes);\n            }\n            catch (Exception e)\n            {\n                LogUnexpectedException(nameof(SetCanonicalChainId), e);\n                throw;\n            }\n        }\n\n        /// <inheritdoc/>\n        public override long CountIndex(Guid chainId)\n        {\n            try\n            {\n                byte[] bytes = _chainDb.Get(IndexCountKey(chainId));\n                return bytes is null\n                    ? 0\n                    : RocksDBStoreBitConverter.ToInt64(bytes);\n            }\n            catch (Exception e)\n            {\n                LogUnexpectedException(nameof(CountIndex), e);\n            }\n\n            return 0;\n        }\n\n        /// <inheritdoc cref=\"BaseStore.IterateIndexes(Guid, int, int?)\"/>\n        public override IEnumerable<BlockHash> IterateIndexes(Guid chainId, int offset, int? limit)\n        {\n            if (_indexCache.TryGetValue(chainId, out LruCache<(int, int?), List<BlockHash>> ic) &&\n                ic.TryGetValue((offset, limit), out List<BlockHash> cached))\n            {\n                return cached;\n            }\n\n            List<BlockHash> indexes = IterateIndexes(chainId, offset, limit, false).ToList();\n\n            if (ic is null)\n            {\n                _indexCache[chainId] = ic = new LruCache<(int, int?), List<BlockHash>>();\n            }\n\n            ic[(offset, limit)] = indexes;\n            return indexes;\n        }\n\n        /// <inheritdoc cref=\"BaseStore.IndexBlockHash(Guid, long)\"/>\n        public override BlockHash? IndexBlockHash(Guid chainId, long index)\n        {\n            try\n            {\n                if (index < 0)\n                {\n                    index += CountIndex(chainId);\n\n                    if (index < 0)\n                    {\n                        return null;\n                    }\n                }\n\n                if (IsDeletionMarked(chainId))\n                {\n                    return null;\n                }\n\n                (Guid ChainId, long Index)? prevChainInfo = GetPreviousChainInfo(chainId);\n                while (prevChainInfo is { } infoNotNull && infoNotNull.Index >= index)\n                {\n                    chainId = infoNotNull.ChainId;\n                    prevChainInfo = GetPreviousChainInfo(chainId);\n                }\n\n                byte[] indexBytes = RocksDBStoreBitConverter.GetBytes(index);\n                byte[] bytes = _chainDb.Get(IndexKey(chainId, indexBytes));\n                return bytes is null ? (BlockHash?)null : new BlockHash(bytes);\n            }\n            catch (Exception e)\n            {\n                LogUnexpectedException(nameof(IndexBlockHash), e);\n                return null;\n            }\n        }\n\n        /// <inheritdoc cref=\"BaseStore.AppendIndex(Guid, BlockHash)\"/>\n        public override long AppendIndex(Guid chainId, BlockHash hash)\n        {\n            long index = CountIndex(chainId);\n            try\n            {\n                byte[] indexBytes = RocksDBStoreBitConverter.GetBytes(index);\n\n                byte[] key = IndexKey(chainId, indexBytes);\n\n                using var writeBatch = new WriteBatch();\n\n                writeBatch.Put(key, hash.ToByteArray());\n                writeBatch.Put(\n                    IndexCountKey(chainId),\n                    RocksDBStoreBitConverter.GetBytes(index + 1)\n                );\n                writeBatch.Put(ChainIdKey(chainId), chainId.ToByteArray());\n\n                _chainDb.Write(writeBatch);\n            }\n            catch (Exception e)\n            {\n                LogUnexpectedException(nameof(AppendIndex), e);\n                throw;\n            }\n\n            _indexCache.Remove(chainId);\n\n            return index;\n        }\n\n        /// <inheritdoc cref=\"BaseStore.ForkBlockIndexes(Guid, Guid, BlockHash)\"/>\n        public override void ForkBlockIndexes(\n            Guid sourceChainId,\n            Guid destinationChainId,\n            BlockHash branchpoint\n        )\n        {\n            BlockHash[] bottoms = IterateIndexes(sourceChainId, 0, 1, true).ToArray();\n            BlockHash? genesisHash = bottoms.Any() ? bottoms[0] : (BlockHash?)null;\n\n            if (genesisHash is null || branchpoint.Equals(genesisHash))\n            {\n                return;\n            }\n\n            using var batch = new WriteBatch();\n            foreach (Iterator k in IterateDb(_chainDb, IndexKey(destinationChainId)))\n            {\n                batch.Delete(k.Key());\n            }\n\n            if (!(GetBlockIndex(branchpoint) is { } bpIndex))\n            {\n                return;\n            }\n\n            _chainDb.Write(batch);\n\n            // Do fork from previous chain instead current if it's available and same as current.\n            if (GetPreviousChainInfo(sourceChainId) is { } chainInfo &&\n                chainInfo.Item2 == bpIndex)\n            {\n                ForkBlockIndexes(chainInfo.Item1, destinationChainId, branchpoint);\n                return;\n            }\n\n            _chainDb.Put(PreviousChainIdKey(destinationChainId), sourceChainId.ToByteArray());\n            _chainDb.Put(\n                PreviousChainIndexKey(destinationChainId),\n                RocksDBStoreBitConverter.GetBytes(bpIndex)\n            );\n            _chainDb.Put(\n                IndexCountKey(destinationChainId),\n                RocksDBStoreBitConverter.GetBytes(bpIndex + 1)\n            );\n\n            _chainDb.Put(ChainIdKey(destinationChainId), destinationChainId.ToByteArray());\n            AddFork(sourceChainId, destinationChainId);\n        }\n\n        /// <inheritdoc/>\n        public override Transaction? GetTransaction(TxId txid)\n        {\n            if (_txCache.TryGetValue(txid, out object cachedTx))\n            {\n                return (Transaction)cachedTx;\n            }\n\n            byte[] key = TxKey(txid);\n            if (!(_txIndexDb.Get(key) is byte[] txDbNameBytes))\n            {\n                return null;\n            }\n\n            string txDbName = RocksDBStoreBitConverter.GetString(txDbNameBytes);\n            _rwTxLock.EnterReadLock();\n            try\n            {\n                RocksDb txDb;\n                lock (_txDbCache)\n                {\n                    if (!_txDbCache.TryGetValue(txDbName, out txDb))\n                    {\n                        txDb = RocksDBUtils.OpenRocksDb(\n                            _options, TxDbPath(txDbName), type: _instanceType);\n                        _txDbCache.AddOrUpdate(txDbName, txDb);\n                    }\n                }\n\n                byte[] txBytes = txDb.Get(key);\n\n                Transaction tx =\n                    TxMarshaler.DeserializeTransactionWithoutVerification(txBytes);\n                _txCache.AddOrUpdate(txid, tx);\n                return tx;\n            }\n            catch (Exception e)\n            {\n                LogUnexpectedException(nameof(GetTransaction), e);\n                return null;\n            }\n            finally\n            {\n                _rwTxLock.ExitReadLock();\n            }\n        }\n\n        /// <inheritdoc/>\n        public override void PutTransaction(Transaction tx)\n        {\n            if (_txCache.ContainsKey(tx.Id))\n            {\n                return;\n            }\n\n            byte[] key = TxKey(tx.Id);\n            if (!(_txIndexDb.Get(key) is null))\n            {\n                return;\n            }\n\n            long timestamp = tx.Timestamp.ToUnixTimeSeconds();\n            string txDbName = $\"epoch{timestamp / _txEpochUnitSeconds}\";\n            _rwTxLock.EnterWriteLock();\n            try\n            {\n                RocksDb txDb;\n                lock (_txDbCache)\n                {\n                    if (!_txDbCache.TryGetValue(txDbName, out txDb))\n                    {\n                        txDb = RocksDBUtils.OpenRocksDb(\n                            _options, TxDbPath(txDbName), type: _instanceType);\n                        _txDbCache.AddOrUpdate(txDbName, txDb);\n                    }\n                }\n\n                txDb.Put(key, tx.Serialize());\n                _txIndexDb.Put(key, RocksDBStoreBitConverter.GetBytes(txDbName));\n                _txCache.AddOrUpdate(tx.Id, tx);\n            }\n            catch (Exception e)\n            {\n                LogUnexpectedException(nameof(PutTransaction), e);\n                throw;\n            }\n            finally\n            {\n                _rwTxLock.ExitWriteLock();\n            }\n        }\n\n        /// <inheritdoc/>\n        public override bool ContainsTransaction(TxId txId)\n        {\n            try\n            {\n                if (_txCache.ContainsKey(txId))\n                {\n                    return true;\n                }\n\n                byte[] key = TxKey(txId);\n\n                return !(_txIndexDb.Get(key) is null);\n            }\n            catch (Exception e)\n            {\n                LogUnexpectedException(nameof(ContainsTransaction), e);\n            }\n\n            return false;\n        }\n\n        /// <inheritdoc cref=\"BaseStore.IterateBlockHashes()\"/>\n        public override IEnumerable<BlockHash> IterateBlockHashes()\n        {\n            byte[] prefix = BlockKeyPrefix;\n\n            foreach (Iterator it in IterateDb(_blockIndexDb, prefix))\n            {\n                byte[] key = it.Key();\n                byte[] hashBytes = key.Skip(prefix.Length).ToArray();\n                yield return new BlockHash(hashBytes);\n            }\n        }\n\n        /// <inheritdoc cref=\"BaseStore.GetBlockDigest(BlockHash)\"/>\n        public override BlockDigest? GetBlockDigest(BlockHash blockHash)\n        {\n            if (_blockCache.TryGetValue(blockHash, out BlockDigest cachedDigest))\n            {\n                return cachedDigest;\n            }\n\n            byte[] key = BlockKey(blockHash);\n            if (!(_blockIndexDb.Get(key) is byte[] blockDbNameBytes))\n            {\n                return null;\n            }\n\n            _rwBlockLock.EnterReadLock();\n            try\n            {\n                string blockDbName = RocksDBStoreBitConverter.GetString(blockDbNameBytes);\n                RocksDb blockDb;\n                lock (_blockDbCache)\n                {\n                    if (!_blockDbCache.TryGetValue(blockDbName, out blockDb))\n                    {\n                        blockDb = RocksDBUtils.OpenRocksDb(\n                            _options, BlockDbPath(blockDbName), type: _instanceType);\n                        _blockDbCache.AddOrUpdate(blockDbName, blockDb);\n                    }\n                }\n\n                if (!(blockDb.Get(key) is byte[] blockBytes))\n                {\n                    return null;\n                }\n\n                BlockDigest blockDigest = BlockDigest.Deserialize(blockBytes);\n\n                _blockCache.AddOrUpdate(blockHash, blockDigest);\n                return blockDigest;\n            }\n            catch (Exception e)\n            {\n                LogUnexpectedException(nameof(GetBlockDigest), e);\n            }\n            finally\n            {\n                _rwBlockLock.ExitReadLock();\n            }\n\n            return null;\n        }\n\n        /// <inheritdoc/>\n        public override void PutBlock(Block block)\n        {\n            if (_blockCache.ContainsKey(block.Hash))\n            {\n                return;\n            }\n\n            byte[] key = BlockKey(block.Hash);\n\n            if (!(_blockIndexDb.Get(key) is null))\n            {\n                return;\n            }\n\n            long timestamp = block.Timestamp.ToUnixTimeSeconds();\n\n            foreach (Transaction tx in block.Transactions)\n            {\n                PutTransaction(tx);\n            }\n\n            _rwBlockLock.EnterWriteLock();\n            try\n            {\n                string blockDbName = $\"epoch{timestamp / _blockEpochUnitSeconds}\";\n                RocksDb blockDb;\n                lock (_blockDbCache)\n                {\n                    if (!_blockDbCache.TryGetValue(blockDbName, out blockDb))\n                    {\n                        blockDb = RocksDBUtils.OpenRocksDb(\n                            _options, BlockDbPath(blockDbName), type: _instanceType);\n                        _blockDbCache.AddOrUpdate(blockDbName, blockDb);\n                    }\n                }\n\n                BlockDigest digest = BlockDigest.FromBlock(block);\n                byte[] value = digest.Serialize();\n                blockDb.Put(key, value);\n                _blockIndexDb.Put(key, RocksDBStoreBitConverter.GetBytes(blockDbName));\n                _blockCache.AddOrUpdate(block.Hash, digest);\n            }\n            catch (Exception e)\n            {\n                LogUnexpectedException(nameof(PutBlock), e);\n                throw;\n            }\n            finally\n            {\n                _rwBlockLock.ExitWriteLock();\n            }\n        }\n\n        /// <inheritdoc cref=\"BaseStore.DeleteBlock(BlockHash)\"/>\n        public override bool DeleteBlock(BlockHash blockHash)\n        {\n            byte[] key = BlockKey(blockHash);\n\n            if (!(_blockIndexDb.Get(key) is byte[] blockDbNameByte))\n            {\n                return false;\n            }\n\n            _rwBlockLock.EnterWriteLock();\n            try\n            {\n                string blockDbName = RocksDBStoreBitConverter.GetString(blockDbNameByte);\n                RocksDb blockDb;\n                lock (_blockDbCache)\n                {\n                    if (!_blockDbCache.TryGetValue(blockDbName, out blockDb))\n                    {\n                        blockDb = RocksDBUtils.OpenRocksDb(\n                            _options, BlockDbPath(blockDbName), type: _instanceType);\n                        _blockDbCache.AddOrUpdate(blockDbName, blockDb);\n                    }\n                }\n\n                _blockCache.Remove(blockHash);\n                _blockIndexDb.Remove(key);\n                blockDb.Remove(key);\n                return true;\n            }\n            catch (Exception e)\n            {\n                LogUnexpectedException(nameof(DeleteBlock), e);\n                throw;\n            }\n            finally\n            {\n                _rwBlockLock.ExitWriteLock();\n            }\n        }\n\n        /// <inheritdoc cref=\"BaseStore.ContainsBlock(BlockHash)\"/>\n        public override bool ContainsBlock(BlockHash blockHash)\n        {\n            try\n            {\n                if (_blockCache.ContainsKey(blockHash))\n                {\n                    return true;\n                }\n\n                byte[] key = BlockKey(blockHash);\n\n                return !(_blockIndexDb.Get(key) is null);\n            }\n            catch (Exception e)\n            {\n                LogUnexpectedException(nameof(ContainsBlock), e);\n            }\n\n            return false;\n        }\n\n        /// <inheritdoc cref=\"BaseStore.PutTxIdBlockHashIndex(TxId, BlockHash)\"/>\n        public override void PutTxIdBlockHashIndex(TxId txId, BlockHash blockHash)\n        {\n            _txIdBlockHashIndexDb.Put(\n                TxIdBlockHashIndexKey(txId, blockHash),\n                blockHash.ToByteArray()\n                );\n        }\n\n        /// <inheritdoc cref=\"BaseStore.DeleteTxIdBlockHashIndex(TxId, BlockHash)\"/>\n        public override void DeleteTxIdBlockHashIndex(TxId txId, BlockHash blockHash)\n        {\n            _txIdBlockHashIndexDb.Remove(\n                TxIdBlockHashIndexKey(txId, blockHash)\n            );\n        }\n\n        /// <inheritdoc cref=\"BaseStore.IterateTxIdBlockHashIndex(TxId)\"/>\n        public override IEnumerable<BlockHash> IterateTxIdBlockHashIndex(TxId txId)\n        {\n            var prefix = TxIdBlockHashIndexTxIdKey(txId);\n            foreach (var it in IterateDb(_txIdBlockHashIndexDb, prefix))\n            {\n                yield return new BlockHash(it.Value());\n            }\n        }\n\n        /// <inheritdoc cref=\"BaseStore.PutTxExecution\"/>\n        public override void PutTxExecution(TxExecution txExecution) =>\n            _txExecutionDb.Put(\n                TxExecutionKey(txExecution),\n                Codec.Encode(SerializeTxExecution(txExecution))\n            );\n\n        /// <inheritdoc cref=\"BaseStore.GetTxExecution(BlockHash, TxId)\"/>\n        public override TxExecution? GetTxExecution(BlockHash blockHash, TxId txid)\n        {\n            byte[] key = TxExecutionKey(blockHash, txid);\n            if (_txExecutionDb.Get(key) is { } bytes)\n            {\n                return DeserializeTxExecution(blockHash, txid, Codec.Decode(bytes), _logger);\n            }\n\n            return null;\n        }\n\n        /// <inheritdoc/>\n        public override IEnumerable<KeyValuePair<Address, long>> ListTxNonces(Guid chainId)\n        {\n            byte[] prefix = TxNonceKey(chainId);\n            foreach (Iterator it in IterateDb(_chainDb, prefix))\n            {\n                byte[] addressBytes = it.Key()\n                    .Skip(prefix.Length)\n                    .ToArray();\n                var address = new Address(addressBytes);\n                long nonce = RocksDBStoreBitConverter.ToInt64(it.Value());\n                yield return new KeyValuePair<Address, long>(address, nonce);\n            }\n        }\n\n        /// <inheritdoc/>\n        public override long GetTxNonce(Guid chainId, Address address)\n        {\n            try\n            {\n                byte[] key = TxNonceKey(chainId, address);\n                byte[] bytes = _chainDb.Get(key);\n                return bytes is null\n                    ? 0\n                    : RocksDBStoreBitConverter.ToInt64(bytes);\n            }\n            catch (Exception e)\n            {\n                LogUnexpectedException(nameof(GetTxNonce), e);\n            }\n\n            return 0;\n        }\n\n        /// <inheritdoc/>\n        public override void IncreaseTxNonce(Guid chainId, Address signer, long delta = 1)\n        {\n            try\n            {\n                long nextNonce = GetTxNonce(chainId, signer) + delta;\n\n                byte[] key = TxNonceKey(chainId, signer);\n                byte[] bytes = RocksDBStoreBitConverter.GetBytes(nextNonce);\n\n                _chainDb.Put(key, bytes);\n                _chainDb.Put(ChainIdKey(chainId), chainId.ToByteArray());\n            }\n            catch (Exception e)\n            {\n                LogUnexpectedException(nameof(IncreaseTxNonce), e);\n                throw;\n            }\n        }\n\n        /// <inheritdoc/>\n        public override long CountBlocks()\n        {\n            return IterateBlockHashes().LongCount();\n        }\n\n        public override void Dispose()\n        {\n            try\n            {\n                if (!_disposed)\n                {\n                    _chainDb?.Dispose();\n                    _txIndexDb?.Dispose();\n                    _blockIndexDb?.Dispose();\n                    _blockPerceptionDb?.Dispose();\n                    _txExecutionDb?.Dispose();\n                    _txIdBlockHashIndexDb?.Dispose();\n                    foreach (var db in _txDbCache.Values)\n                    {\n                        db.Dispose();\n                    }\n\n                    _txDbCache.Clear();\n                    _blockCommitDb?.Dispose();\n                    _nextStateRootHashDb?.Dispose();\n                    _pendingEvidenceDb?.Dispose();\n                    _committedEvidenceDb?.Dispose();\n\n                    foreach (var db in _blockDbCache.Values)\n                    {\n                        db.Dispose();\n                    }\n\n                    _blockDbCache.Clear();\n                    _disposed = true;\n                }\n            }\n            catch (Exception e)\n            {\n                LogUnexpectedException(nameof(Dispose), e);\n            }\n        }\n\n        /// <inheritdoc/>\n        public override void ForkTxNonces(Guid sourceChainId, Guid destinationChainId)\n        {\n            var writeBatch = new WriteBatch();\n            bool exist = false;\n            try\n            {\n                byte[] prefix = TxNonceKey(sourceChainId);\n                foreach (Iterator it in IterateDb(_chainDb, prefix))\n                {\n                    exist = true;\n                    Address address = new Address(it.Key().Skip(prefix.Length).ToArray());\n                    writeBatch.Put(TxNonceKey(destinationChainId, address), it.Value());\n                    if (writeBatch.Count() >= ForkWriteBatchSize)\n                    {\n                        _chainDb.Write(writeBatch);\n                        writeBatch.Dispose();\n                        writeBatch = new WriteBatch();\n                    }\n                }\n            }\n            catch (Exception e)\n            {\n                LogUnexpectedException(nameof(ForkTxNonces), e);\n                throw;\n            }\n            finally\n            {\n                if (exist)\n                {\n                    _chainDb.Write(writeBatch);\n                    writeBatch.Dispose();\n                }\n            }\n        }\n\n        /// <inheritdoc />\n        public override BlockCommit? GetChainBlockCommit(Guid chainId)\n        {\n            try\n            {\n                byte[] key = ChainBlockCommitKey(chainId);\n                byte[] bytes = _chainDb.Get(key);\n                if (bytes is null)\n                {\n                    return null;\n                }\n\n                return new BlockCommit(Codec.Decode(bytes));\n            }\n            catch (Exception e)\n            {\n                LogUnexpectedException(nameof(GetChainBlockCommit), e);\n            }\n\n            return null;\n        }\n\n        public override void PutChainBlockCommit(Guid chainId, BlockCommit blockCommit)\n        {\n            try\n            {\n                byte[] key = ChainBlockCommitKey(chainId);\n                byte[] bytes = Codec.Encode(blockCommit.Bencoded);\n\n                _chainDb.Put(key, bytes);\n                _chainDb.Put(ChainIdKey(chainId), chainId.ToByteArray());\n            }\n            catch (Exception e)\n            {\n                LogUnexpectedException(nameof(PutChainBlockCommit), e);\n            }\n        }\n\n        public override BlockCommit? GetBlockCommit(BlockHash blockHash)\n        {\n            _rwBlockCommitLock.EnterReadLock();\n\n            try\n            {\n                byte[] key = BlockCommitKey(blockHash);\n                byte[] bytes = _blockCommitDb.Get(key);\n                if (bytes is null)\n                {\n                    return null;\n                }\n\n                return new BlockCommit(Codec.Decode(bytes));\n            }\n            catch (Exception e)\n            {\n                LogUnexpectedException(nameof(GetBlockCommit), e);\n            }\n            finally\n            {\n                _rwBlockCommitLock.ExitReadLock();\n            }\n\n            return null;\n        }\n\n        /// <inheritdoc />\n        public override void PutBlockCommit(BlockCommit blockCommit)\n        {\n            byte[] key = BlockCommitKey(blockCommit.BlockHash);\n\n            if (_blockCommitDb.Get(key) is { })\n            {\n                return;\n            }\n\n            _rwBlockCommitLock.EnterWriteLock();\n            try\n            {\n                byte[] value = Codec.Encode(blockCommit.Bencoded);\n                _blockCommitDb.Put(key, value);\n            }\n            catch (Exception e)\n            {\n                LogUnexpectedException(nameof(PutBlockCommit), e);\n                throw;\n            }\n            finally\n            {\n                _rwBlockCommitLock.ExitWriteLock();\n            }\n        }\n\n        /// <inheritdoc />\n        public override void DeleteBlockCommit(BlockHash blockHash)\n        {\n            byte[] key = BlockCommitKey(blockHash);\n\n            if (!(_blockCommitDb.Get(key) is { }))\n            {\n                return;\n            }\n\n            _rwBlockCommitLock.EnterWriteLock();\n            try\n            {\n                _blockCommitDb.Remove(key);\n            }\n            catch (Exception e)\n            {\n                LogUnexpectedException(nameof(DeleteBlockCommit), e);\n                throw;\n            }\n            finally\n            {\n                _rwBlockCommitLock.ExitWriteLock();\n            }\n        }\n\n        /// <inheritdoc />\n        public override IEnumerable<BlockHash> GetBlockCommitHashes()\n        {\n            try\n            {\n                IEnumerable<Iterator> iterators = IterateDb(_blockCommitDb, Array.Empty<byte>());\n\n                // FIXME: Somehow key value comes with 0x76 prefix at the first index of\n                // byte array.\n                IEnumerable<BlockHash> hashes = iterators\n                    .Select(x => new BlockHash(x.Key().Skip(1).ToArray()))\n                    .ToArray();\n                return hashes;\n            }\n            catch (Exception e)\n            {\n                LogUnexpectedException(nameof(PutBlockCommit), e);\n                throw;\n            }\n        }\n\n        /// <inheritdoc />\n        public override HashDigest<SHA256>? GetNextStateRootHash(BlockHash blockHash)\n        {\n            _rwNextStateRootHashLock.EnterReadLock();\n\n            try\n            {\n                byte[] key = NextStateRootHashKey(blockHash);\n                byte[] bytes = _nextStateRootHashDb.Get(key);\n                if (bytes is null)\n                {\n                    return null;\n                }\n\n                return new HashDigest<SHA256>(bytes);\n            }\n            catch (Exception e)\n            {\n                LogUnexpectedException(nameof(GetNextStateRootHash), e);\n            }\n            finally\n            {\n                _rwNextStateRootHashLock.ExitReadLock();\n            }\n\n            return null;\n        }\n\n        /// <inheritdoc />\n        public override void PutNextStateRootHash(\n            BlockHash blockHash, HashDigest<SHA256> nextStateRootHash)\n        {\n            byte[] key = NextStateRootHashKey(blockHash);\n\n            if (_nextStateRootHashDb.Get(key) is { })\n            {\n                return;\n            }\n\n            _rwNextStateRootHashLock.EnterWriteLock();\n            try\n            {\n                _nextStateRootHashDb.Put(key, nextStateRootHash.ToByteArray());\n            }\n            catch (Exception e)\n            {\n                LogUnexpectedException(nameof(PutNextStateRootHash), e);\n                throw;\n            }\n            finally\n            {\n                _rwNextStateRootHashLock.ExitWriteLock();\n            }\n        }\n\n        /// <inheritdoc />\n        public override void DeleteNextStateRootHash(BlockHash blockHash)\n        {\n            byte[] key = NextStateRootHashKey(blockHash);\n\n            if (!(_nextStateRootHashDb.Get(key) is { }))\n            {\n                return;\n            }\n\n            _rwNextStateRootHashLock.EnterWriteLock();\n            try\n            {\n                _nextStateRootHashDb.Remove(key);\n            }\n            catch (Exception e)\n            {\n                LogUnexpectedException(nameof(DeleteNextStateRootHash), e);\n                throw;\n            }\n            finally\n            {\n                _rwNextStateRootHashLock.ExitWriteLock();\n            }\n        }\n\n        /// <inheritdoc/>\n        public override IEnumerable<EvidenceId> IteratePendingEvidenceIds()\n        {\n            foreach (Iterator it in IterateDb(_pendingEvidenceDb, PendingEvidenceKeyPrefix))\n            {\n                byte[] key = it.Key();\n                byte[] idBytes = key.Skip(PendingEvidenceKeyPrefix.Length).ToArray();\n                yield return new EvidenceId(idBytes);\n            }\n        }\n\n        /// <inheritdoc/>\n        public override EvidenceBase? GetPendingEvidence(EvidenceId evidenceId)\n        {\n            _rwEvidenceLock.EnterReadLock();\n\n            try\n            {\n                byte[] key = PendingEvidenceKey(evidenceId);\n                byte[] bytes = _pendingEvidenceDb.Get(key);\n                if (bytes is null)\n                {\n                    return null;\n                }\n\n                return EvidenceBase.Decode(Codec.Decode(bytes));\n            }\n            catch (Exception e)\n            {\n                LogUnexpectedException(nameof(GetPendingEvidence), e);\n            }\n            finally\n            {\n                _rwEvidenceLock.ExitReadLock();\n            }\n\n            return null;\n        }\n\n        /// <inheritdoc/>\n        public override void PutPendingEvidence(EvidenceBase evidence)\n        {\n            if (_evidenceCache.ContainsKey(evidence.Id))\n            {\n                return;\n            }\n\n            byte[] key = PendingEvidenceKey(evidence.Id);\n\n            if (_pendingEvidenceDb.Get(key) is { })\n            {\n                return;\n            }\n\n            _rwEvidenceLock.EnterWriteLock();\n            try\n            {\n                byte[] value = Codec.Encode(EvidenceBase.Bencode(evidence));\n                _pendingEvidenceDb.Put(key, value);\n            }\n            catch (Exception e)\n            {\n                LogUnexpectedException(nameof(PutPendingEvidence), e);\n                throw;\n            }\n            finally\n            {\n                _rwEvidenceLock.ExitWriteLock();\n            }\n        }\n\n        /// <inheritdoc/>\n        public override void DeletePendingEvidence(EvidenceId evidenceId)\n        {\n            byte[] key = PendingEvidenceKey(evidenceId);\n\n            if (!(_pendingEvidenceDb.Get(key) is { }))\n            {\n                return;\n            }\n\n            _rwEvidenceLock.EnterWriteLock();\n            try\n            {\n                _pendingEvidenceDb.Remove(key);\n            }\n            catch (Exception e)\n            {\n                LogUnexpectedException(nameof(DeletePendingEvidence), e);\n                throw;\n            }\n            finally\n            {\n                _rwEvidenceLock.ExitWriteLock();\n            }\n        }\n\n        /// <inheritdoc/>\n        public override bool ContainsPendingEvidence(EvidenceId evidenceId)\n        {\n            return _pendingEvidenceDb.Get(PendingEvidenceKey(evidenceId)) is { };\n        }\n\n        /// <inheritdoc/>\n        public override EvidenceBase? GetCommittedEvidence(EvidenceId evidenceId)\n        {\n            if (_evidenceCache.TryGetValue(evidenceId, out EvidenceBase cachedEvidence))\n            {\n                return cachedEvidence;\n            }\n\n            _rwEvidenceLock.EnterReadLock();\n\n            try\n            {\n                byte[] key = CommittedEvidenceKey(evidenceId);\n                byte[] bytes = _committedEvidenceDb.Get(key);\n                if (bytes is null)\n                {\n                    return null;\n                }\n\n                return EvidenceBase.Decode(Codec.Decode(bytes));\n            }\n            catch (Exception e)\n            {\n                LogUnexpectedException(nameof(GetCommittedEvidence), e);\n            }\n            finally\n            {\n                _rwEvidenceLock.ExitReadLock();\n            }\n\n            return null;\n        }\n\n        /// <inheritdoc/>\n        public override void PutCommittedEvidence(EvidenceBase evidence)\n        {\n            if (_evidenceCache.ContainsKey(evidence.Id))\n            {\n                return;\n            }\n\n            byte[] key = CommittedEvidenceKey(evidence.Id);\n\n            if (_committedEvidenceDb.Get(key) is { })\n            {\n                return;\n            }\n\n            _rwEvidenceLock.EnterWriteLock();\n            try\n            {\n                byte[] value = Codec.Encode(EvidenceBase.Bencode(evidence));\n                _committedEvidenceDb.Put(key, value);\n                _evidenceCache.AddOrUpdate(evidence.Id, evidence);\n            }\n            catch (Exception e)\n            {\n                LogUnexpectedException(nameof(PutCommittedEvidence), e);\n                throw;\n            }\n            finally\n            {\n                _rwEvidenceLock.ExitWriteLock();\n            }\n        }\n\n        /// <inheritdoc/>\n        public override void DeleteCommittedEvidence(EvidenceId evidenceId)\n        {\n            _evidenceCache.Remove(evidenceId);\n\n            byte[] key = CommittedEvidenceKey(evidenceId);\n\n            if (!(_committedEvidenceDb.Get(key) is { }))\n            {\n                return;\n            }\n\n            _rwEvidenceLock.EnterWriteLock();\n            try\n            {\n                _committedEvidenceDb.Remove(key);\n            }\n            catch (Exception e)\n            {\n                LogUnexpectedException(nameof(DeletePendingEvidence), e);\n                throw;\n            }\n            finally\n            {\n                _rwEvidenceLock.ExitWriteLock();\n            }\n        }\n\n        /// <inheritdoc/>\n        public override bool ContainsCommittedEvidence(EvidenceId evidenceId)\n        {\n            if (_evidenceCache.ContainsKey(evidenceId))\n            {\n                return true;\n            }\n\n            return _committedEvidenceDb.Get(CommittedEvidenceKey(evidenceId)) is { };\n        }\n\n        [StoreLoader(\"rocksdb+file\")]\n        private static (IStore Store, IStateStore StateStore) Loader(Uri storeUri)\n        {\n            NameValueCollection query = HttpUtility.ParseQueryString(storeUri.Query);\n            int blockCacheSize = query.GetInt32(\"block-cache\", 512);\n            int txCacheSize = query.GetInt32(\"tx-cache\", 1024);\n            int evidenceCacheSize = query.GetInt32(\"evidence-cache\", 1024);\n            ulong? maxTotalWalSize = query.GetUInt64(\"max-total-wal-size\");\n            ulong? keepLogFileNum = query.GetUInt64(\"keep-log-file-num\");\n            ulong? maxLogFileSize = query.GetUInt64(\"max-log-file-size\");\n            int txEpochUnitSeconds = query.GetInt32(\"tx-epoch-unit-secs\", 86400);\n            int blockEpochUnitSeconds = query.GetInt32(\"block-epoch-unit-secs\", 86400);\n            int dbConnectionCacheSize = query.GetInt32(\"connection-cache\", 100);\n            RocksDBInstanceType instanceType = query.GetEnum<RocksDBInstanceType>(\n                \"instance-type\", RocksDBInstanceType.Primary);\n\n            string statesKvPath = query.Get(\"states-dir\") ?? StatesKvPathDefault;\n            var store = new RocksDBStore(\n                storeUri.LocalPath,\n                blockCacheSize,\n                txCacheSize,\n                evidenceCacheSize,\n                maxTotalWalSize,\n                keepLogFileNum,\n                maxLogFileSize,\n                txEpochUnitSeconds,\n                blockEpochUnitSeconds,\n                dbConnectionCacheSize,\n                instanceType);\n            string statesDirPath = Path.Combine(storeUri.LocalPath, statesKvPath);\n            var stateStore = new TrieStateStore(\n                new RocksDBKeyValueStore(\n                    statesDirPath,\n                    instanceType));\n            return (store, stateStore);\n        }\n\n        private static byte[] DeletedChainKey(Guid chainId) =>\n            Concat(DeletedKeyPrefix, chainId.ToByteArray());\n\n        private static byte[] PreviousChainIndexKey(Guid chainId) =>\n            Concat(PreviousChainIndexKeyPrefix, chainId.ToByteArray());\n\n        private static byte[] PreviousChainIdKey(Guid chainId) =>\n            Concat(PreviousChainIdKeyPrefix, chainId.ToByteArray());\n\n        private static byte[] IndexKey(Guid chainId) =>\n            Concat(IndexKeyPrefix, chainId.ToByteArray());\n\n        private static byte[] IndexKey(Guid chainId, byte[] indexBytes) =>\n            Concat(IndexKeyPrefix, chainId.ToByteArray(), indexBytes);\n\n        private static byte[] IndexCountKey(Guid chainId) =>\n            Concat(IndexCountKeyPrefix, chainId.ToByteArray());\n\n        private static byte[] ChainIdKey(Guid chainId) =>\n            Concat(ChainIdKeyPrefix, chainId.ToByteArray());\n\n        private static byte[] BlockKey(in BlockHash blockHash) =>\n            Concat(BlockKeyPrefix, blockHash.ByteArray);\n\n        private static byte[] TxKey(in TxId txId) =>\n            Concat(TxKeyPrefix, txId.ByteArray);\n\n        private static byte[] TxNonceKey(Guid chainId) =>\n            Concat(TxNonceKeyPrefix, chainId.ToByteArray());\n\n        private static byte[] TxNonceKey(Guid chainId, Address address) =>\n            Concat(TxNonceKeyPrefix, chainId.ToByteArray(), address.ByteArray);\n\n        private static byte[] TxNonceKey(Guid chainId, byte[] addressBytes) =>\n            Concat(TxNonceKeyPrefix, chainId.ToByteArray(), addressBytes);\n\n        private static byte[] TxExecutionKey(in BlockHash blockHash, in TxId txId) =>\n\n            // As BlockHash is not fixed size, place TxId first.\n            Concat(TxExecutionKeyPrefix, txId.ByteArray, blockHash.ByteArray);\n\n        private static byte[] TxExecutionKey(TxExecution txExecution) =>\n            Concat(\n                TxExecutionKeyPrefix, txExecution.TxId.ByteArray, txExecution.BlockHash.ByteArray);\n\n        private static byte[] TxIdBlockHashIndexKey(in TxId txId, in BlockHash blockHash) =>\n            Concat(TxIdBlockHashIndexPrefix, txId.ByteArray, blockHash.ByteArray);\n\n        private static byte[] TxIdBlockHashIndexTxIdKey(in TxId txId) =>\n            Concat(TxIdBlockHashIndexPrefix, txId.ByteArray);\n\n        private static byte[] ForkedChainsKey(Guid chainId, Guid forkedChainId) =>\n            Concat(ForkedChainsKeyPrefix, chainId.ToByteArray(), forkedChainId.ToByteArray());\n\n        private static byte[] ChainBlockCommitKey(Guid chainId) =>\n            Concat(ChainBlockCommitKeyPrefix, chainId.ToByteArray());\n\n        private static byte[] BlockCommitKey(in BlockHash blockHash) =>\n            Concat(BlockCommitKeyPrefix, blockHash.ByteArray);\n\n        private static byte[] NextStateRootHashKey(in BlockHash blockHash) =>\n            Concat(NextStateRootHashKeyPrefix, blockHash.ByteArray);\n\n        private static byte[] Concat(byte[] first, byte[] second)\n        {\n            byte[] result = new byte[first.Length + second.Length];\n            first.CopyTo(result, 0);\n            second.CopyTo(result, first.Length);\n            return result;\n        }\n\n        private static byte[] Concat(byte[] first, ImmutableArray<byte> second)\n        {\n            byte[] result = new byte[first.Length + second.Length];\n            first.CopyTo(result, 0);\n            second.CopyTo(result, first.Length);\n            return result;\n        }\n\n        private static byte[] Concat(byte[] first, byte[] second, byte[] third)\n        {\n            byte[] result = new byte[first.Length + second.Length + third.Length];\n            first.CopyTo(result, 0);\n            second.CopyTo(result, first.Length);\n            third.CopyTo(result, first.Length + second.Length);\n            return result;\n        }\n\n        private static byte[] Concat(\n            byte[] first,\n            byte[] second,\n            ImmutableArray<byte> third)\n        {\n            byte[] result = new byte[first.Length + second.Length + third.Length];\n            first.CopyTo(result, 0);\n            second.CopyTo(result, first.Length);\n            third.CopyTo(result, first.Length + second.Length);\n            return result;\n        }\n\n        private static byte[] Concat(\n            byte[] first,\n            ImmutableArray<byte> second,\n            ImmutableArray<byte> third)\n        {\n            byte[] result = new byte[first.Length + second.Length + third.Length];\n            first.CopyTo(result, 0);\n            second.CopyTo(result, first.Length);\n            third.CopyTo(result, first.Length + second.Length);\n            return result;\n        }\n\n        private static byte[] PendingEvidenceKey(in EvidenceId evidenceId) =>\n            PendingEvidenceKeyPrefix.Concat(evidenceId.ByteArray).ToArray();\n\n        private static byte[] CommittedEvidenceKey(in EvidenceId evidenceId) =>\n            CommittedEvidenceKeyPrefix.Concat(evidenceId.ByteArray).ToArray();\n\n        private static IEnumerable<Iterator> IterateDb(RocksDb db, byte[] prefix)\n        {\n            using Iterator it = db.NewIterator();\n            for (it.Seek(prefix); it.Valid() && it.Key().StartsWith(prefix); it.Next())\n            {\n                yield return it;\n            }\n        }\n\n        private ColumnFamilies GetColumnFamilies(DbOptions options, string dbName)\n        {\n            var dbPath = Path.Combine(_path, dbName);\n            var columnFamilies = new ColumnFamilies();\n            List<string> listColumnFamilies;\n\n            try\n            {\n                listColumnFamilies = RocksDb.ListColumnFamilies(options, dbPath).ToList();\n            }\n            catch (RocksDbException)\n            {\n                listColumnFamilies = new List<string>();\n            }\n\n            foreach (string name in listColumnFamilies)\n            {\n                columnFamilies.Add(name, _colOptions);\n            }\n\n            return columnFamilies;\n        }\n\n        private string TxDbPath(string dbName) =>\n            Path.Combine(RocksDbPath(TxDbRootPathName), dbName);\n\n        private string BlockDbPath(string dbName) =>\n            Path.Combine(RocksDbPath(BlockDbRootPathName), dbName);\n\n        private string RocksDbPath(string dbName) => Path.Combine(_path, dbName);\n\n        private void LogUnexpectedException(string methodName, Exception e)\n        {\n            _logger.Error(e, \"An unexpected exception occurred on {MethodName}()\", methodName);\n        }\n\n        private (Guid, long)? GetPreviousChainInfo(Guid chainId)\n        {\n            if (_chainDb.Get(PreviousChainIdKey(chainId)) is { } prevChainId &&\n                _chainDb.Get(PreviousChainIndexKey(chainId)) is { } prevChainIndex)\n            {\n                return (new Guid(prevChainId), RocksDBStoreBitConverter.ToInt64(prevChainIndex));\n            }\n\n            return null;\n        }\n\n        private IEnumerable<BlockHash> IterateIndexes(\n            Guid chainId,\n            long offset,\n            long? limit,\n            bool includeDeleted\n        )\n        {\n            long count = 0;\n            Stack<(Guid, long)> chainInfos = new Stack<(Guid, long)>();\n\n            if (!includeDeleted && IsDeletionMarked(chainId))\n            {\n                yield break;\n            }\n\n            chainInfos.Push((chainId, CountIndex(chainId)));\n\n            while (true)\n            {\n                if (chainInfos.Peek().Item2 > offset &&\n                    GetPreviousChainInfo(chainInfos.Peek().Item1) is { } chainInfo)\n                {\n                    chainInfos.Push(chainInfo);\n                }\n                else\n                {\n                    break;\n                }\n            }\n\n            long previousChainTipIndex;\n\n            // Adjust offset if it skipped some previous chains.\n            (offset, previousChainTipIndex) =\n                GetPreviousChainInfo(chainInfos.Peek().Item1) is { } cinfo\n                    ? (Math.Max(0, offset - cinfo.Item2 - 1), cinfo.Item2)\n                    : (offset, 0);\n\n            while (chainInfos.Count > 0)\n            {\n                (Guid, long) chainInfo = chainInfos.Pop();\n                (Guid cid, long chainTipIndex) = chainInfo;\n\n                // Include genesis block.\n                long expectedCount = chainTipIndex - previousChainTipIndex +\n                                     (GetPreviousChainInfo(cid) is null ? 1 : 0);\n\n                foreach (BlockHash hash in IterateIndexesInner(cid, expectedCount))\n                {\n                    if (offset > 0)\n                    {\n                        offset -= 1;\n                        continue;\n                    }\n\n                    if (count >= limit)\n                    {\n                        yield break;\n                    }\n\n                    yield return hash;\n                    count += 1;\n                }\n\n                previousChainTipIndex = chainTipIndex;\n            }\n        }\n\n        private IEnumerable<BlockHash> IterateIndexesInner(Guid chainId, long expectedCount)\n        {\n            long count = 0;\n            byte[] prefix = Concat(IndexKeyPrefix, chainId.ToByteArray());\n            foreach (Iterator it in IterateDb(_chainDb, prefix))\n            {\n                if (count >= expectedCount)\n                {\n                    yield break;\n                }\n\n                byte[] value = it.Value();\n                yield return new BlockHash(value);\n                count += 1;\n            }\n        }\n\n        private void AddFork(Guid chainId, Guid forkedChainId)\n        {\n            _chainDb.Put(ForkedChainsKey(chainId, forkedChainId), Array.Empty<byte>());\n        }\n\n        private void RemoveFork(Guid chainId, Guid forkedChainId)\n        {\n            _chainDb.Remove(ForkedChainsKey(chainId, forkedChainId));\n        }\n\n        private bool HasFork(Guid chainId)\n        {\n            byte[] prefix = Concat(ForkedChainsKeyPrefix, chainId.ToByteArray());\n            return IterateDb(_chainDb, prefix).Any();\n        }\n\n        private bool IsDeletionMarked(Guid chainId)\n            => _chainDb.Get(DeletedChainKey(chainId)) is { };\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.RocksDBStore/RocksDBStoreBitConverter.cs",
    "content": "using System;\nusing System.Text;\n\nnamespace Libplanet.RocksDBStore\n{\n    /// <summary>\n    /// Collection of wrapper methods to convert to byte-arrays from various types to store\n    /// <see cref=\"RocksDBStore\"/>.  Every integer data is converted to Big-endian, or\n    /// \"Network Byte Order\" to order index lexicographically.\n    /// </summary>\n    internal static class RocksDBStoreBitConverter\n    {\n        /// <summary>\n        /// Get <c>long</c> representation of the <paramref name=\"value\"/>.\n        /// </summary>\n        /// <param name=\"value\">The Big-endian byte-array value to convert to <c>long</c>.</param>\n        /// <returns>The <c>long</c> representation of the <paramref name=\"value\"/>.</returns>\n        public static long ToInt64(byte[] value)\n        {\n            byte[] bytes = new byte[sizeof(long)];\n            value.CopyTo(bytes, 0);\n\n            // Use Big-endian to order index lexicographically.\n            if (BitConverter.IsLittleEndian)\n            {\n                Array.Reverse(bytes);\n            }\n\n            return BitConverter.ToInt64(bytes, 0);\n        }\n\n        /// <summary>\n        /// Get <c>string</c> representation of the <paramref name=\"value\"/>.\n        /// </summary>\n        /// <param name=\"value\">The byte-array value to convert to <c>string</c>.</param>\n        /// <returns>The <c>string</c> representation of the <paramref name=\"value\"/>.</returns>\n        public static string GetString(byte[] value)\n        {\n            return Encoding.UTF8.GetString(value);\n        }\n\n        /// <summary>\n        /// Get Big-endian byte-array representation of the <paramref name=\"value\"/>.\n        /// </summary>\n        /// <param name=\"value\">The <c>long</c> value to convert to byte-array.</param>\n        /// <returns>The Big-endian byte-array representation of the <paramref name=\"value\"/>.\n        /// </returns>\n        public static byte[] GetBytes(long value)\n        {\n            byte[] bytes = BitConverter.GetBytes(value);\n\n            // Use Big-endian to order index lexicographically.\n            if (BitConverter.IsLittleEndian)\n            {\n                Array.Reverse(bytes);\n            }\n\n            return bytes;\n        }\n\n        /// <summary>\n        /// Get encoded byte-array representation of the <paramref name=\"value\"/>.\n        /// </summary>\n        /// <param name=\"value\">The <c>string</c> to convert to byte-array.</param>\n        /// <returns>The encoded representation of the <paramref name=\"value\"/>.</returns>\n        public static byte[] GetBytes(string value)\n        {\n            return Encoding.UTF8.GetBytes(value);\n        }\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.RocksDBStore/RocksDBUtils.cs",
    "content": "using System;\nusing System.IO;\nusing RocksDbSharp;\n\nnamespace Libplanet.RocksDBStore\n{\n    internal static class RocksDBUtils\n    {\n        internal static RocksDb OpenRocksDb(\n            DbOptions options,\n            string dbPath,\n            ColumnFamilies? columnFamilies = null,\n            RocksDBInstanceType type = RocksDBInstanceType.Primary)\n        {\n            if (!Directory.Exists(dbPath))\n            {\n                Directory.CreateDirectory(dbPath);\n            }\n\n            return type switch\n            {\n                RocksDBInstanceType.Primary => columnFamilies is null\n                    ? RocksDb.Open(options, dbPath) : RocksDb.Open(options, dbPath, columnFamilies),\n                RocksDBInstanceType.ReadOnly => columnFamilies is null\n                    ? RocksDb.OpenReadOnly(options, dbPath, false)\n                    : RocksDb.OpenReadOnly(options, dbPath, columnFamilies, false),\n                RocksDBInstanceType.Secondary => columnFamilies is null\n                    ? RocksDb.OpenAsSecondary(options, dbPath, CreateSecondaryPath(dbPath))\n                    : RocksDb.OpenAsSecondary(\n                        options,\n                        dbPath,\n                        CreateSecondaryPath(dbPath),\n                        columnFamilies),\n                _ => throw new ArgumentOutOfRangeException(nameof(type), type, null),\n            };\n        }\n\n        private static string CreateSecondaryPath(string dbPath)\n        {\n            string secondaryPath = Path.Combine(dbPath, $\"SECONDARY-{Guid.NewGuid()}\");\n            if (!Directory.Exists(secondaryPath))\n            {\n                Directory.CreateDirectory(secondaryPath);\n            }\n\n            return secondaryPath;\n        }\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Store/AssemblyInfo.cs",
    "content": "using System.Runtime.CompilerServices;\n\n[assembly: InternalsVisibleTo(\"Libplanet.Extensions.Cocona.Tests\")]\n[assembly: InternalsVisibleTo(\"Libplanet.Tests\")]\n"
  },
  {
    "path": "src/Libplanet.Store/BaseStore.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Collections.Immutable;\nusing System.Linq;\nusing System.Numerics;\nusing System.Security.Cryptography;\nusing Bencodex.Types;\nusing Libplanet.Common;\nusing Libplanet.Crypto;\nusing Libplanet.Types.Assets;\nusing Libplanet.Types.Blocks;\nusing Libplanet.Types.Evidence;\nusing Libplanet.Types.Tx;\nusing Serilog;\nusing FAV = Libplanet.Types.Assets.FungibleAssetValue;\n\nnamespace Libplanet.Store\n{\n    /// <summary>\n    /// Common code for several <see cref=\"IStore\"/> implementations.\n    /// </summary>\n    public abstract class BaseStore : IStore\n    {\n        /// <inheritdoc/>\n        public abstract IEnumerable<Guid> ListChainIds();\n\n        /// <inheritdoc/>\n        public abstract Guid? GetCanonicalChainId();\n\n        /// <inheritdoc/>\n        public abstract void SetCanonicalChainId(Guid chainId);\n\n        public abstract long CountIndex(Guid chainId);\n\n        /// <inheritdoc/>\n        public abstract IEnumerable<BlockHash> IterateIndexes(Guid chainId, int offset, int? limit);\n\n        /// <inheritdoc/>\n        public abstract BlockHash? IndexBlockHash(Guid chainId, long index);\n\n        /// <inheritdoc/>\n        public abstract long AppendIndex(Guid chainId, BlockHash hash);\n\n        /// <inheritdoc/>\n        public abstract void ForkBlockIndexes(\n            Guid sourceChainId,\n            Guid destinationChainId,\n            BlockHash branchpoint\n        );\n\n        public abstract Transaction? GetTransaction(TxId txid);\n\n        public abstract void PutTransaction(Transaction tx);\n\n        /// <inheritdoc/>\n        public abstract IEnumerable<BlockHash> IterateBlockHashes();\n\n        /// <inheritdoc/>\n        public Block? GetBlock(BlockHash blockHash)\n        {\n            if (GetBlockDigest(blockHash) is BlockDigest blockDigest)\n            {\n                BlockHeader header = blockDigest.GetHeader();\n                TxId[] txids = blockDigest.TxIds\n                                .Select(bytes => new TxId(bytes.ToArray()))\n                                .OrderBy(txid => txid)\n                                .ToArray();\n                Transaction[] txs = txids.Select(txid => GetTransaction(txid))\n                                         .OfType<Transaction>()\n                                         .ToArray();\n                var evidenceIds = blockDigest.EvidenceIds\n                                             .Select(bytes => new EvidenceId(bytes.ToArray()))\n                                             .OrderBy(evidenceId => evidenceId)\n                                             .ToArray();\n                var evidence = evidenceIds.Select(evidenceId => GetCommittedEvidence(evidenceId))\n                                           .OfType<EvidenceBase>()\n                                           .ToArray();\n\n                if (txids.Length != txs.Length)\n                {\n                    TxId[] missingTxIds = txids.Except(txs.Select(tx => tx.Id)).ToArray();\n                    throw new InvalidOperationException(\n                        $\"Failed to find {missingTxIds.Length} tx(s) (out of {txs.Length}) \" +\n                        $\"at block {blockHash}:\\n\" + string.Join(\"\\n  \", missingTxIds));\n                }\n\n                if (evidenceIds.Length != evidence.Length)\n                {\n                    var missingEvidenceIds = evidenceIds.Except(evidence.Select(tx => tx.Id))\n                                                         .ToArray();\n                    throw new InvalidOperationException(\n                        $\"Failed to find {missingEvidenceIds.Length} evidence(s) \" +\n                        $\"(out of {evidence.Length}) \" +\n                        $\"at block {blockHash}:\\n\" + string.Join(\"\\n  \", missingEvidenceIds));\n                }\n\n                return new Block(header, txs, evidence);\n            }\n\n            return null;\n        }\n\n        /// <inheritdoc/>\n        public long? GetBlockIndex(BlockHash blockHash)\n        {\n            return GetBlockDigest(blockHash)?.Index;\n        }\n\n        /// <inheritdoc/>\n        public abstract BlockDigest? GetBlockDigest(BlockHash blockHash);\n\n        /// <inheritdoc/>\n        public abstract void PutBlock(Block block);\n\n        /// <inheritdoc/>\n        public abstract bool DeleteBlock(BlockHash blockHash);\n\n        /// <inheritdoc/>\n        public abstract bool ContainsBlock(BlockHash blockHash);\n\n        /// <inheritdoc/>\n        public abstract void PutTxExecution(TxExecution txExecution);\n\n        /// <inheritdoc/>\n        public abstract TxExecution? GetTxExecution(BlockHash blockHash, TxId txid);\n\n        /// <inheritdoc/>\n        public abstract void PutTxIdBlockHashIndex(TxId txId, BlockHash blockHash);\n\n        public BlockHash? GetFirstTxIdBlockHashIndex(TxId txId)\n        {\n            BlockHash? blockHash;\n            try\n            {\n                blockHash = IterateTxIdBlockHashIndex(txId).First();\n            }\n            catch (InvalidOperationException)\n            {\n                blockHash = null;\n            }\n\n            return blockHash;\n        }\n\n        /// <inheritdoc/>\n        public abstract IEnumerable<BlockHash> IterateTxIdBlockHashIndex(TxId txId);\n\n        /// <inheritdoc/>\n        public abstract void DeleteTxIdBlockHashIndex(TxId txId, BlockHash blockHash);\n\n        /// <inheritdoc/>\n        public abstract IEnumerable<KeyValuePair<Address, long>> ListTxNonces(Guid chainId);\n\n        /// <inheritdoc/>\n        public abstract long GetTxNonce(Guid chainId, Address address);\n\n        /// <inheritdoc/>\n        public abstract void IncreaseTxNonce(Guid chainId, Address signer, long delta = 1);\n\n        public virtual long CountBlocks()\n        {\n            return IterateBlockHashes().LongCount();\n        }\n\n        /// <inheritdoc/>\n        public abstract bool ContainsTransaction(TxId txId);\n\n        /// <inheritdoc/>\n        public abstract void DeleteChainId(Guid chainId);\n\n        /// <inheritdoc/>\n        public abstract void Dispose();\n\n        /// <inheritdoc/>\n        public abstract void ForkTxNonces(Guid sourceChainId, Guid destinationChainId);\n\n        /// <inheritdoc/>\n        public abstract void PruneOutdatedChains(bool noopWithoutCanon = false);\n\n        /// <inheritdoc/>\n        public abstract BlockCommit? GetChainBlockCommit(Guid chainId);\n\n        /// <inheritdoc/>\n        public abstract void PutChainBlockCommit(Guid chainId, BlockCommit blockCommit);\n\n        /// <inheritdoc/>\n        public abstract BlockCommit? GetBlockCommit(BlockHash blockHash);\n\n        /// <inheritdoc/>\n        public abstract void PutBlockCommit(BlockCommit blockCommit);\n\n        /// <inheritdoc/>\n        public abstract void DeleteBlockCommit(BlockHash blockHash);\n\n        /// <inheritdoc/>\n        public abstract IEnumerable<BlockHash> GetBlockCommitHashes();\n\n        /// <inheritdoc/>\n        public abstract HashDigest<SHA256>? GetNextStateRootHash(BlockHash blockHash);\n\n        /// <inheritdoc/>\n        public abstract void PutNextStateRootHash(\n            BlockHash blockHash, HashDigest<SHA256> nextStateRootHash);\n\n        /// <inheritdoc/>\n        public abstract void DeleteNextStateRootHash(BlockHash blockHash);\n\n        /// <inheritdoc/>\n        public abstract IEnumerable<EvidenceId> IteratePendingEvidenceIds();\n\n        /// <inheritdoc/>\n        public abstract EvidenceBase? GetPendingEvidence(EvidenceId evidenceId);\n\n        /// <inheritdoc/>\n        public abstract EvidenceBase? GetCommittedEvidence(EvidenceId evidenceId);\n\n        /// <inheritdoc/>\n        public abstract void PutPendingEvidence(EvidenceBase evidence);\n\n        /// <inheritdoc/>\n        public abstract void PutCommittedEvidence(EvidenceBase evidence);\n\n        /// <inheritdoc/>\n        public abstract void DeletePendingEvidence(EvidenceId evidenceId);\n\n        /// <inheritdoc/>\n        public abstract void DeleteCommittedEvidence(EvidenceId evidenceId);\n\n        /// <inheritdoc/>\n        public abstract bool ContainsPendingEvidence(EvidenceId evidenceId);\n\n        /// <inheritdoc/>\n        public abstract bool ContainsCommittedEvidence(EvidenceId evidenceId);\n\n        protected static IValue SerializeTxExecution(TxExecution txExecution)\n        {\n            return txExecution.ToBencodex();\n        }\n\n        protected static TxExecution? DeserializeTxExecution(\n            BlockHash blockHash,\n            TxId txid,\n            IValue decoded,\n            ILogger logger\n        )\n        {\n            if (!(decoded is Bencodex.Types.Dictionary d))\n            {\n                const string msg = nameof(TxExecution) +\n                    \" must be serialized as a Bencodex dictionary, not {ActualValue}\";\n                logger?.Error(msg, decoded.Inspect());\n                return null;\n            }\n\n            try\n            {\n                return new TxExecution(blockHash, txid, d);\n            }\n            catch (Exception e)\n            {\n                const string msg =\n                    \"Uncaught exception during deserializing a \" + nameof(TxExecution);\n                logger?.Error(e, msg);\n                return null;\n            }\n        }\n\n        private static Bencodex.Types.Dictionary SerializeGroupedFAVs(\n            IImmutableDictionary<Address, IImmutableDictionary<Currency, FAV>> balanceDelta\n        ) =>\n            new Dictionary(\n                balanceDelta.Select(pair =>\n                    new KeyValuePair<IKey, IValue>(\n                        new Binary(pair.Key.ByteArray),\n                        SerializeFAVs(pair.Value)\n                    )\n                )\n            );\n\n        private static IImmutableDictionary<Address, IImmutableDictionary<Currency, FAV>>\n        DeserializeGroupedFAVs(Bencodex.Types.Dictionary serialized) =>\n            serialized.ToImmutableDictionary(\n                kv => new Address((IValue)kv.Key),\n                kv => DeserializeFAVs((List)kv.Value)\n            );\n\n        private static Bencodex.Types.List SerializeLogs(\n            List<IReadOnlyList<string>> logs\n        ) =>\n            new List(logs.Select(l => new List(l.Select(x => (Text)x))));\n\n        private static List<IReadOnlyList<string>> DeserializeLogs(\n            Bencodex.Types.List serialized) =>\n            serialized\n                .Cast<List>()\n                .Select(l => (IReadOnlyList<string>)l.Select(e => (string)(Text)e).ToList())\n                .ToList();\n\n        private static Bencodex.Types.List SerializeFAVs(\n            IImmutableDictionary<Currency, FAV> favs\n        ) =>\n            new List(\n                favs.Select(\n                    kv => List.Empty.Add(kv.Key.Serialize()).Add(kv.Value.RawValue)\n                )\n            );\n\n        private static IImmutableDictionary<Currency, FAV> DeserializeFAVs(\n            List serialized\n        ) =>\n            serialized.Select(pList =>\n            {\n                var pair = (List)pList;\n                var currency = new Currency(pair[0]);\n                BigInteger rawValue = (Bencodex.Types.Integer)pair[1];\n                return new KeyValuePair<Currency, FAV>(\n                    currency,\n                    FAV.FromRawValue(currency, rawValue)\n                );\n            }).ToImmutableDictionary();\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Store/BlockDigest.cs",
    "content": "using System;\nusing System.Collections.Immutable;\nusing System.Linq;\nusing System.Security.Cryptography;\nusing Bencodex;\nusing Bencodex.Types;\nusing Libplanet.Common;\nusing Libplanet.Crypto;\nusing Libplanet.Types.Blocks;\nusing Libplanet.Types.Evidence;\nusing Libplanet.Types.Tx;\n\nnamespace Libplanet.Store\n{\n    /// <summary>\n    /// Class that store uses to save blocks. This contains:\n    /// <see cref=\"BlockHeader\"/>, and list of <see cref=\"TxId\"/>s.\n    /// </summary>\n    public readonly struct BlockDigest : IBlockMetadata, IBlockExcerpt\n    {\n        private static readonly Binary HeaderKey = new Binary(new byte[] { 0x48 });         // 'H'\n\n        private static readonly Binary TransactionIdsKey = new Binary(new byte[] { 0x54 }); // 'T'\n        private static readonly Binary EvidenceIdsKey = new Binary(new byte[] { 0x56 });    // 'V'\n\n        private readonly BlockMetadata _metadata;\n        private readonly HashDigest<SHA256> _preEvaluationHash;\n\n        /// <summary>\n        /// Creates <see cref=\"BlockDigest\"/> instance from <see cref=\"BlockHeader\"/> and\n        /// <see cref=\"Transaction\"/> ids the <see cref=\"Block\"/> has.\n        /// </summary>\n        /// <param name=\"header\"><see cref=\"BlockHeader\"/> of the <see cref=\"Block\"/>.</param>\n        /// <param name=\"txIds\"><see cref=\"Transaction\"/> ids the <see cref=\"Block\"/> has.\n        /// </param>\n        /// <param name=\"evidenceIds\"><see cref=\"EvidenceBase\"/> ids the <see cref=\"Block\"/> has.\n        /// </param>\n        public BlockDigest(\n            BlockHeader header,\n            ImmutableArray<ImmutableArray<byte>> txIds,\n            ImmutableArray<ImmutableArray<byte>> evidenceIds)\n        {\n            _metadata = header.Header.Metadata;\n            _preEvaluationHash = header.PreEvaluationHash;\n            StateRootHash = header.StateRootHash;\n            Signature = header.Signature;\n            Hash = header.Hash;\n            TxIds = txIds;\n            EvidenceIds = evidenceIds;\n        }\n\n        /// <summary>\n        /// Creates <see cref=\"BlockDigest\"/> instance from\n        /// <see cref=\"Bencodex.Types.Dictionary\"/> representation of the <see cref=\"Block\"/>.\n        /// </summary>\n        /// <param name=\"dict\">\n        /// <see cref=\"Bencodex.Types.Dictionary\"/> representation of the <see cref=\"Block\"/>.\n        /// </param>\n        public BlockDigest(Bencodex.Types.Dictionary dict)\n        {\n            var headerDict = (Dictionary)dict[HeaderKey];\n            _metadata = BlockMarshaler.UnmarshalBlockMetadata(headerDict);\n            _preEvaluationHash = BlockMarshaler.UnmarshalPreEvaluationHash(headerDict);\n            StateRootHash = BlockMarshaler.UnmarshalBlockHeaderStateRootHash(headerDict);\n            Signature = BlockMarshaler.UnmarshalBlockHeaderSignature(headerDict);\n            Hash = BlockMarshaler.UnmarshalBlockHeaderHash(headerDict);\n            TxIds = dict.ContainsKey((Binary)TransactionIdsKey)\n                ? ((List)dict[TransactionIdsKey])\n                    .Select(txId => ((Binary)txId).ByteArray).ToImmutableArray()\n                : ImmutableArray<ImmutableArray<byte>>.Empty;\n            EvidenceIds = dict.ContainsKey(EvidenceIdsKey)\n                ? ((List)dict[EvidenceIdsKey])\n                    .Select(evId => ((Binary)evId).ByteArray).ToImmutableArray()\n                : ImmutableArray<ImmutableArray<byte>>.Empty;\n        }\n\n        /// <inheritdoc cref=\"IBlockMetadata.ProtocolVersion\"/>\n        public int ProtocolVersion => _metadata.ProtocolVersion;\n\n        /// <inheritdoc cref=\"IBlockMetadata.Index\"/>\n        public long Index => _metadata.Index;\n\n        /// <inheritdoc cref=\"IBlockMetadata.Timestamp\"/>\n        public System.DateTimeOffset Timestamp => _metadata.Timestamp;\n\n        /// <inheritdoc cref=\"IBlockMetadata.Miner\"/>\n        public Address Miner => _metadata.Miner;\n\n        /// <inheritdoc cref=\"IBlockMetadata.PublicKey\"/>\n        public PublicKey? PublicKey => _metadata.PublicKey;\n\n        /// <inheritdoc cref=\"IBlockMetadata.PreviousHash\"/>\n        public BlockHash? PreviousHash => _metadata.PreviousHash;\n\n        /// <inheritdoc cref=\"IBlockMetadata.TxHash\"/>\n        public HashDigest<SHA256>? TxHash => _metadata.TxHash;\n\n        /// <inheritdoc cref=\"IBlockMetadata.LastCommit\"/>\n        public BlockCommit? LastCommit => _metadata.LastCommit;\n\n        /// <inheritdoc cref=\"IBlockMetadata.EvidenceHash\"/>\n        public HashDigest<SHA256>? EvidenceHash => _metadata.EvidenceHash;\n\n        /// <summary>\n        /// The block hash.\n        /// </summary>\n        public BlockHash Hash { get; }\n\n        /// <summary>\n        /// The state root hash.\n        /// </summary>\n        public HashDigest<SHA256> StateRootHash { get; }\n\n        /// <summary>\n        /// The block signature.\n        /// </summary>\n        public ImmutableArray<byte>? Signature { get; }\n\n        /// <summary>\n        /// The <see cref=\"Transaction.Id\"/>s of <see cref=\"Transaction\"/>s in\n        /// a <see cref=\"Block\"/>.  This is <em>not</em> necessarily ordered by\n        /// <see cref=\"Transaction.Id\"/>.\n        /// </summary>\n        public ImmutableArray<ImmutableArray<byte>> TxIds { get; }\n\n        /// <summary>\n        /// The <see cref=\"Evidence.Id\"/>s of <see cref=\"EvidenceBase\"/>s in\n        /// a <see cref=\"Block\"/>.  This is <em>not</em> necessarily ordered by\n        /// <see cref=\"Evidence.Id\"/>.\n        /// </summary>\n        public ImmutableArray<ImmutableArray<byte>> EvidenceIds { get; }\n\n        /// <summary>\n        /// Gets <see cref=\"BlockDigest\"/> representation of the <see cref=\"Block\"/>.\n        /// </summary>\n        /// <param name=\"block\">The block instance to get its digest.</param>\n        /// <returns><see cref=\"BlockDigest\"/> representation of the <see cref=\"Block\"/>.\n        /// </returns>\n        public static BlockDigest FromBlock(Block block)\n        {\n            return new BlockDigest(\n                header: block.Header,\n                txIds: block.Transactions\n                    .Select(tx => tx.Id.ByteArray)\n                    .ToImmutableArray(),\n                evidenceIds: block.Evidence\n                    .Select(ev => ev.Id.ByteArray)\n                    .ToImmutableArray()\n            );\n        }\n\n        /// <summary>\n        /// Gets <see cref=\"BlockDigest\"/> instance from serialized <paramref name=\"bytes\"/>.\n        /// </summary>\n        /// <param name=\"bytes\">Serialized <see cref=\"BlockDigest\"/>.</param>\n        /// <returns>Deserialized <see cref=\"BlockDigest\"/>.</returns>\n        /// <exception cref=\"ArgumentNullException\">Thrown when the passed <paramref name=\"bytes\"/>\n        /// is <see langword=\"null\"/>.</exception>\n        /// <exception cref=\"DecodingException\">Thrown when decoded value is not\n        /// <see cref=\"Bencodex.Types.Dictionary\"/> type.</exception>\n        public static BlockDigest Deserialize(byte[] bytes)\n        {\n            if (!(bytes is byte[] bytesArray))\n            {\n                throw new ArgumentNullException(nameof(bytes));\n            }\n\n            IValue value = new Codec().Decode(bytesArray);\n            if (!(value is Bencodex.Types.Dictionary dict))\n            {\n                throw new DecodingException(\n                    $\"Expected {typeof(Bencodex.Types.Dictionary)} but \" +\n                    $\"{value.GetType()}\");\n            }\n\n            return new BlockDigest(dict);\n        }\n\n        /// <summary>\n        /// Gets serialized byte array of the <see cref=\"BlockDigest\"/>.\n        /// </summary>\n        /// <returns>Serialized byte array of <see cref=\"BlockDigest\"/>.</returns>\n        public byte[] Serialize()\n        {\n            return new Codec().Encode(ToBencodex());\n        }\n\n        /// <summary>\n        /// Gets the block header.\n        /// </summary>\n        /// <returns>The block header.</returns>\n        public BlockHeader GetHeader()\n        {\n            var preEvalHeader = new PreEvaluationBlockHeader(_metadata, _preEvaluationHash);\n            return new BlockHeader(preEvalHeader, StateRootHash, Signature, Hash);\n        }\n\n        /// <summary>\n        /// Gets <see cref=\"Bencodex.Types.Dictionary\"/> representation of\n        /// <see cref=\"BlockDigest\"/>.\n        /// </summary>\n        /// <returns><see cref=\"Bencodex.Types.Dictionary\"/> representation of\n        /// <see cref=\"BlockDigest\"/>.</returns>\n        public Bencodex.Types.Dictionary ToBencodex()\n        {\n            var preEvalHeaderDict = BlockMarshaler.MarshalPreEvaluationBlockHeader(\n                BlockMarshaler.MarshalBlockMetadata(_metadata),\n                _preEvaluationHash);\n            Dictionary headerDict = BlockMarshaler.MarshalBlockHeader(\n                preEvalHeaderDict,\n                StateRootHash,\n                Signature,\n                Hash\n            );\n            var dict = Bencodex.Types.Dictionary.Empty.Add(HeaderKey, headerDict);\n\n            if (TxIds.Any())\n            {\n                dict = dict.Add(\n                    TransactionIdsKey,\n                    new List(TxIds.Select(txId => txId.ToArray())));\n            }\n\n            if (EvidenceIds.Any())\n            {\n                dict = dict.Add(\n                    EvidenceIdsKey,\n                    new List(EvidenceIds.Select(evId => evId.ToArray())));\n            }\n\n            return dict;\n        }\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Store/BlockSet.cs",
    "content": "using System;\nusing System.Collections;\nusing System.Collections.Generic;\nusing System.Linq;\nusing BitFaster.Caching;\nusing BitFaster.Caching.Lru;\nusing Caching;\nusing Libplanet.Types.Blocks;\n\nnamespace Libplanet.Store\n{\n    public class BlockSet : IReadOnlyDictionary<BlockHash, Block>\n    {\n        private readonly IStore _store;\n        private readonly ICache<BlockHash, Block> _cache;\n\n        public BlockSet(IStore store, int cacheSize = 4096)\n        {\n            _store = store;\n            _cache = new ConcurrentLruBuilder<BlockHash, Block>()\n                .WithCapacity(cacheSize)\n                .Build();\n        }\n\n        public IEnumerable<BlockHash> Keys =>\n            _store.IterateBlockHashes().ToList();\n\n        public IEnumerable<Block> Values =>\n            _store.IterateBlockHashes()\n                .Select(GetBlock)\n                .Where(block => block is { })\n                .Select(block => block!)\n                .ToList();\n\n        public int Count => (int)_store.CountBlocks();\n\n        public bool IsReadOnly => false;\n\n        public Block this[BlockHash key]\n        {\n            get\n            {\n                Block? block = GetBlock(key);\n                if (block is null)\n                {\n                    throw new KeyNotFoundException(\n                        $\"The given hash[{key}] was not found in this set.\"\n                    );\n                }\n\n                if (block.ProtocolVersion < BlockMetadata.PBFTProtocolVersion)\n                {\n                    // Skip verifying BlockHash of PoW blocks due to change of the block structure.\n                    // If verification is required, use older version of LibPlanet(<0.43).\n                }\n                else if (!block.Hash.Equals(key))\n                {\n                    throw new InvalidBlockHashException(\n                        $\"The given hash[{key}] was not equal to actual[{block.Hash}].\");\n                }\n\n                return block;\n            }\n\n            set\n            {\n                if (!value.Hash.Equals(key))\n                {\n                    throw new InvalidBlockHashException(\n                        $\"{value}.hash does not match to {key}\");\n                }\n\n                value.ValidateTimestamp();\n                _store.PutBlock(value);\n                _cache.AddOrUpdate(value.Hash, value);\n            }\n        }\n\n        public bool Contains(KeyValuePair<BlockHash, Block> item) =>\n            _store.ContainsBlock(item.Key);\n\n        public bool ContainsKey(BlockHash key) =>\n            _store.ContainsBlock(key);\n\n        public bool Remove(BlockHash key)\n        {\n            bool deleted = _store.DeleteBlock(key);\n\n            _cache.TryRemove(key);\n\n            return deleted;\n        }\n\n        public void Add(BlockHash key, Block value)\n        {\n            this[key] = value;\n        }\n\n        public bool TryGetValue(BlockHash key, out Block value)\n        {\n            try\n            {\n                value = this[key];\n                return true;\n            }\n            catch (KeyNotFoundException)\n            {\n                value = default!;\n                return false;\n            }\n        }\n\n        public void Add(KeyValuePair<BlockHash, Block> item) => Add(item.Key, item.Value);\n\n        public void Clear()\n        {\n            foreach (BlockHash key in Keys)\n            {\n                Remove(key);\n            }\n        }\n\n        public void CopyTo(KeyValuePair<BlockHash, Block>[] array, int arrayIndex)\n        {\n            if (array == null)\n            {\n                throw new ArgumentNullException(nameof(array));\n            }\n\n            if (arrayIndex < 0)\n            {\n                throw new ArgumentOutOfRangeException(nameof(arrayIndex));\n            }\n\n            if (Count > array.Length + arrayIndex)\n            {\n                throw new ArgumentException();\n            }\n\n            foreach (KeyValuePair<BlockHash, Block> kv in this)\n            {\n                array[arrayIndex++] = kv;\n            }\n        }\n\n        public bool Remove(KeyValuePair<BlockHash, Block> item) => Remove(item.Key);\n\n        public IEnumerator<KeyValuePair<BlockHash, Block>> GetEnumerator()\n        {\n            foreach (var key in Keys)\n            {\n                yield return new KeyValuePair<BlockHash, Block>(key, this[key]);\n            }\n        }\n\n        IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();\n\n        private Block? GetBlock(BlockHash key)\n        {\n            if (_cache.TryGet(key, out Block cached))\n            {\n                if (_store.ContainsBlock(key))\n                {\n                    return cached;\n                }\n                else\n                {\n                    // The cached block had been deleted on _store...\n                    _cache.TryRemove(key);\n                }\n            }\n\n            Block? fetched = _store.GetBlock(key);\n            if (fetched is { })\n            {\n                _cache.AddOrUpdate(key, fetched);\n            }\n\n            return fetched;\n        }\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Store/DataModel.Decode.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Collections.Immutable;\nusing System.Linq;\nusing System.Numerics;\nusing Libplanet.Crypto;\nusing BTypes = Bencodex.Types;\n\nnamespace Libplanet.Store\n{\n    public abstract partial class DataModel\n    {\n        private static object DecodeFromIValue(BTypes.IValue value, Type type)\n        {\n            switch (value)\n            {\n                case BTypes.Null _:\n                    throw new NotSupportedException($\"Null value is not supported: {value}\");\n                case BTypes.Boolean b:\n                    return b.Value;\n                case BTypes.Integer i when type == typeof(int):\n                    return (int)i.Value;\n                case BTypes.Integer l when type == typeof(long):\n                    return (long)l.Value;\n                case BTypes.Integer bigInteger when type == typeof(BigInteger):\n                    return bigInteger.Value;\n                case BTypes.Binary bytes when type == typeof(ImmutableArray<byte>):\n                    return bytes.ByteArray;\n                case BTypes.Binary guid when type == typeof(Guid):\n                    return new Guid(guid.ToByteArray());\n                case BTypes.Binary bytes when type == typeof(Address):\n                    return new Address(bytes.ByteArray);\n                case BTypes.Text s when type == typeof(string):\n                    return s.Value;\n                case BTypes.Dictionary dm when\n                    type.IsSubclassOf(typeof(DataModel)):\n                    object instance = Activator.CreateInstance(type, dm)\n                        ?? throw new NullReferenceException(\n                            $\"Failed to decode {value} to target type {type}\");\n                    return instance;\n                case BTypes.List list:\n                    return DecodeFromListIValue(list, type);\n                case BTypes.Dictionary dict:\n                    return DecodeFromDictionaryIValue(dict, type);\n                default:\n                    throw new ArgumentException($\"Failed to decode {value} to target type {type}\");\n            }\n        }\n\n#pragma warning disable MEN002 // Lines too long.\n        private static object DecodeFromListIValue(BTypes.List list, Type type)\n        {\n            if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(ImmutableList<>))\n            {\n                Type[] genericTypes = type.GetGenericArguments();\n                Type genericType = genericTypes[0];\n\n                IEnumerable<object> tempList = list\n                    .Select(x => DecodeFromIValue(x, genericType));\n\n                switch (tempList)\n                {\n                    case IEnumerable<object> listBool when genericType == typeof(bool):\n                        return listBool.Select(x => (bool)x).ToImmutableList();\n                    case IEnumerable<object> listInt when genericType == typeof(int):\n                        return listInt.Select(x => (int)x).ToImmutableList();\n                    case IEnumerable<object> listLong when genericType == typeof(long):\n                        return listLong.Select(x => (long)x).ToImmutableList();\n                    case IEnumerable<object> listBigInteger when genericType == typeof(BigInteger):\n                        return listBigInteger.Select(x => (BigInteger)x).ToImmutableList();\n                    case IEnumerable<object> listBytes when genericType == typeof(ImmutableArray<byte>):\n                        return listBytes.Select(x => (ImmutableArray<byte>)x).ToImmutableList();\n                    case IEnumerable<object> listGuid when genericType == typeof(Guid):\n                        return listGuid.Select(x => (Guid)x).ToImmutableList();\n                    case IEnumerable<object> listAddress when genericType == typeof(Address):\n                        return listAddress.Select(x => (Address)x).ToImmutableList();\n                    case IEnumerable<object> listString when genericType == typeof(string):\n                        return listString.Select(x => (string)x).ToImmutableList();\n                    default:\n                        throw new ArgumentException(\n                            $\"Invalid generic type {genericType} encountered.\");\n                }\n            }\n            else\n            {\n                throw new ArgumentException(\n                    $\"Invalid target property type {type} encountered.\");\n            }\n        }\n#pragma warning restore MEN002\n\n#pragma warning disable MEN002, MEN003 // Lines too long; method too long.\n        private static object DecodeFromDictionaryIValue(BTypes.Dictionary dict, Type type)\n        {\n            if (type.IsGenericType &&\n                type.GetGenericTypeDefinition() == typeof(ImmutableDictionary<,>))\n            {\n                Type[] genericTypes = type.GetGenericArguments();\n                Type keyType = genericTypes[0];\n                Type valueType = genericTypes[1];\n\n                IEnumerable<KeyValuePair<object, object>> tempDict = dict.Select(\n                    kv => new KeyValuePair<object, object>(\n                        DecodeFromIValue(kv.Key, keyType),\n                        DecodeFromIValue(kv.Value, valueType)));\n\n                switch (tempDict)\n                {\n                    // ImmutabeArray<byte> type keys.\n                    case IEnumerable<KeyValuePair<object, object>> bytesBoolDict\n                        when keyType == typeof(ImmutableArray<byte>) && valueType == typeof(bool):\n                        return bytesBoolDict\n                            .Select(kv => new KeyValuePair<ImmutableArray<byte>, bool>(\n                                (ImmutableArray<byte>)kv.Key, (bool)kv.Value))\n                            .ToImmutableDictionary();\n                    case IEnumerable<KeyValuePair<object, object>> bytesIntDict\n                        when keyType == typeof(ImmutableArray<byte>) && valueType == typeof(int):\n                        return bytesIntDict\n                            .Select(kv => new KeyValuePair<ImmutableArray<byte>, int>(\n                                (ImmutableArray<byte>)kv.Key, (int)kv.Value))\n                            .ToImmutableDictionary();\n                    case IEnumerable<KeyValuePair<object, object>> bytesLongDict\n                        when keyType == typeof(ImmutableArray<byte>) && valueType == typeof(long):\n                        return bytesLongDict\n                            .Select(kv => new KeyValuePair<ImmutableArray<byte>, long>(\n                                (ImmutableArray<byte>)kv.Key, (long)kv.Value))\n                            .ToImmutableDictionary();\n                    case IEnumerable<KeyValuePair<object, object>> bytesBigIntegerDict\n                        when keyType == typeof(ImmutableArray<byte>) && valueType == typeof(BigInteger):\n                        return bytesBigIntegerDict\n                            .Select(kv => new KeyValuePair<ImmutableArray<byte>, BigInteger>(\n                                (ImmutableArray<byte>)kv.Key, (BigInteger)kv.Value))\n                            .ToImmutableDictionary();\n                    case IEnumerable<KeyValuePair<object, object>> bytesBytesDict\n                        when keyType == typeof(ImmutableArray<byte>) && valueType == typeof(ImmutableArray<byte>):\n                        return bytesBytesDict\n                            .Select(kv => new KeyValuePair<ImmutableArray<byte>, ImmutableArray<byte>>(\n                                (ImmutableArray<byte>)kv.Key, (ImmutableArray<byte>)kv.Value))\n                            .ToImmutableDictionary();\n                    case IEnumerable<KeyValuePair<object, object>> bytesGuidDict\n                        when keyType == typeof(ImmutableArray<byte>) && valueType == typeof(Guid):\n                        return bytesGuidDict\n                            .Select(kv => new KeyValuePair<ImmutableArray<byte>, Guid>(\n                                (ImmutableArray<byte>)kv.Key, (Guid)kv.Value))\n                            .ToImmutableDictionary();\n                    case IEnumerable<KeyValuePair<object, object>> bytesAddressDict\n                        when keyType == typeof(ImmutableArray<byte>) && valueType == typeof(Address):\n                        return bytesAddressDict\n                            .Select(kv => new KeyValuePair<ImmutableArray<byte>, Address>(\n                                (ImmutableArray<byte>)kv.Key, (Address)kv.Value))\n                            .ToImmutableDictionary();\n                    case IEnumerable<KeyValuePair<object, object>> bytesStringDict\n                        when keyType == typeof(ImmutableArray<byte>) && valueType == typeof(string):\n                        return bytesStringDict\n                            .Select(kv => new KeyValuePair<ImmutableArray<byte>, string>(\n                                (ImmutableArray<byte>)kv.Key, (string)kv.Value))\n                            .ToImmutableDictionary();\n\n                    // Guid type keys.\n                    case IEnumerable<KeyValuePair<object, object>> guidBoolDict\n                        when keyType == typeof(Guid) && valueType == typeof(bool):\n                        return guidBoolDict\n                            .Select(kv => new KeyValuePair<Guid, bool>(\n                                (Guid)kv.Key, (bool)kv.Value))\n                            .ToImmutableDictionary();\n                    case IEnumerable<KeyValuePair<object, object>> guidIntDict\n                        when keyType == typeof(Guid) && valueType == typeof(int):\n                        return guidIntDict\n                            .Select(kv => new KeyValuePair<Guid, int>(\n                                (Guid)kv.Key, (int)kv.Value))\n                            .ToImmutableDictionary();\n                    case IEnumerable<KeyValuePair<object, object>> guidLongDict\n                        when keyType == typeof(Guid) && valueType == typeof(long):\n                        return guidLongDict\n                            .Select(kv => new KeyValuePair<Guid, long>(\n                                (Guid)kv.Key, (long)kv.Value))\n                            .ToImmutableDictionary();\n                    case IEnumerable<KeyValuePair<object, object>> guidBigIntegerDict\n                        when keyType == typeof(Guid) && valueType == typeof(BigInteger):\n                        return guidBigIntegerDict\n                            .Select(kv => new KeyValuePair<Guid, BigInteger>(\n                                (Guid)kv.Key, (BigInteger)kv.Value))\n                            .ToImmutableDictionary();\n                    case IEnumerable<KeyValuePair<object, object>> guidBytesDict\n                        when keyType == typeof(Guid) && valueType == typeof(ImmutableArray<byte>):\n                        return guidBytesDict\n                            .Select(kv => new KeyValuePair<Guid, ImmutableArray<byte>>(\n                                (Guid)kv.Key, (ImmutableArray<byte>)kv.Value))\n                            .ToImmutableDictionary();\n                    case IEnumerable<KeyValuePair<object, object>> guidGuidDict\n                        when keyType == typeof(Guid) && valueType == typeof(Guid):\n                        return guidGuidDict\n                            .Select(kv => new KeyValuePair<Guid, Guid>(\n                                (Guid)kv.Key, (Guid)kv.Value))\n                            .ToImmutableDictionary();\n                    case IEnumerable<KeyValuePair<object, object>> guidAddressDict\n                        when keyType == typeof(Guid) && valueType == typeof(Address):\n                        return guidAddressDict\n                            .Select(kv => new KeyValuePair<Guid, Address>(\n                                (Guid)kv.Key, (Address)kv.Value))\n                            .ToImmutableDictionary();\n                    case IEnumerable<KeyValuePair<object, object>> guidStringDict\n                        when keyType == typeof(Guid) && valueType == typeof(string):\n                        return guidStringDict\n                            .Select(kv => new KeyValuePair<Guid, string>(\n                                (Guid)kv.Key, (string)kv.Value))\n                            .ToImmutableDictionary();\n\n                    // Address type keys.\n                    case IEnumerable<KeyValuePair<object, object>> addressBoolDict\n                        when keyType == typeof(Address) && valueType == typeof(bool):\n                        return addressBoolDict\n                            .Select(kv => new KeyValuePair<Address, bool>(\n                                (Address)kv.Key, (bool)kv.Value))\n                            .ToImmutableDictionary();\n                    case IEnumerable<KeyValuePair<object, object>> addressIntDict\n                        when keyType == typeof(Address) && valueType == typeof(int):\n                        return addressIntDict\n                            .Select(kv => new KeyValuePair<Address, int>(\n                                (Address)kv.Key, (int)kv.Value))\n                            .ToImmutableDictionary();\n                    case IEnumerable<KeyValuePair<object, object>> addressLongDict\n                        when keyType == typeof(Address) && valueType == typeof(long):\n                        return addressLongDict\n                            .Select(kv => new KeyValuePair<Address, long>(\n                                (Address)kv.Key, (long)kv.Value))\n                            .ToImmutableDictionary();\n                    case IEnumerable<KeyValuePair<object, object>> addressBigIntegerDict\n                        when keyType == typeof(Address) && valueType == typeof(BigInteger):\n                        return addressBigIntegerDict\n                            .Select(kv => new KeyValuePair<Address, BigInteger>(\n                                (Address)kv.Key, (BigInteger)kv.Value))\n                            .ToImmutableDictionary();\n                    case IEnumerable<KeyValuePair<object, object>> addressBytesDict\n                        when keyType == typeof(Address) && valueType == typeof(ImmutableArray<byte>):\n                        return addressBytesDict\n                            .Select(kv => new KeyValuePair<Address, ImmutableArray<byte>>(\n                                (Address)kv.Key, (ImmutableArray<byte>)kv.Value))\n                            .ToImmutableDictionary();\n                    case IEnumerable<KeyValuePair<object, object>> addressGuidDict\n                        when keyType == typeof(Address) && valueType == typeof(Guid):\n                        return addressGuidDict\n                            .Select(kv => new KeyValuePair<Address, Guid>(\n                                (Address)kv.Key, (Guid)kv.Value))\n                            .ToImmutableDictionary();\n                    case IEnumerable<KeyValuePair<object, object>> addressAddressDict\n                        when keyType == typeof(Address) && valueType == typeof(Address):\n                        return addressAddressDict\n                            .Select(kv => new KeyValuePair<Address, Address>(\n                                (Address)kv.Key, (Address)kv.Value))\n                            .ToImmutableDictionary();\n                    case IEnumerable<KeyValuePair<object, object>> addressStringDict\n                        when keyType == typeof(Address) && valueType == typeof(string):\n                        return addressStringDict\n                            .Select(kv => new KeyValuePair<Address, string>(\n                                (Address)kv.Key, (string)kv.Value))\n                            .ToImmutableDictionary();\n\n                    // string type keys.\n                    case IEnumerable<KeyValuePair<object, object>> stringBoolDict\n                        when keyType == typeof(string) && valueType == typeof(bool):\n                        return stringBoolDict\n                            .Select(kv => new KeyValuePair<string, bool>(\n                                (string)kv.Key, (bool)kv.Value))\n                            .ToImmutableDictionary();\n                    case IEnumerable<KeyValuePair<object, object>> stringIntDict\n                        when keyType == typeof(string) && valueType == typeof(int):\n                        return stringIntDict\n                            .Select(kv => new KeyValuePair<string, int>(\n                                (string)kv.Key, (int)kv.Value))\n                            .ToImmutableDictionary();\n                    case IEnumerable<KeyValuePair<object, object>> stringLongDict\n                        when keyType == typeof(string) && valueType == typeof(long):\n                        return stringLongDict\n                            .Select(kv => new KeyValuePair<string, long>(\n                                (string)kv.Key, (long)kv.Value))\n                            .ToImmutableDictionary();\n                    case IEnumerable<KeyValuePair<object, object>> stringBigIntegerDict\n                        when keyType == typeof(string) && valueType == typeof(BigInteger):\n                        return stringBigIntegerDict\n                            .Select(kv => new KeyValuePair<string, BigInteger>(\n                                (string)kv.Key, (BigInteger)kv.Value))\n                            .ToImmutableDictionary();\n                    case IEnumerable<KeyValuePair<object, object>> stringBytesDict\n                        when keyType == typeof(string) && valueType == typeof(ImmutableArray<byte>):\n                        return stringBytesDict\n                            .Select(kv => new KeyValuePair<string, ImmutableArray<byte>>(\n                                (string)kv.Key, (ImmutableArray<byte>)kv.Value))\n                            .ToImmutableDictionary();\n                    case IEnumerable<KeyValuePair<object, object>> stringGuidDict\n                        when keyType == typeof(string) && valueType == typeof(Guid):\n                        return stringGuidDict\n                            .Select(kv => new KeyValuePair<string, Guid>(\n                                (string)kv.Key, (Guid)kv.Value))\n                            .ToImmutableDictionary();\n                    case IEnumerable<KeyValuePair<object, object>> stringAddressDict\n                        when keyType == typeof(string) && valueType == typeof(Address):\n                        return stringAddressDict\n                            .Select(kv => new KeyValuePair<string, Address>(\n                                (string)kv.Key, (Address)kv.Value))\n                            .ToImmutableDictionary();\n                    case IEnumerable<KeyValuePair<object, object>> stringStringDict\n                        when keyType == typeof(string) && valueType == typeof(string):\n                        return stringStringDict\n                            .Select(kv => new KeyValuePair<string, string>(\n                                (string)kv.Key, (string)kv.Value))\n                            .ToImmutableDictionary();\n                    default:\n                        throw new ArgumentException(\n                            $\"Invalid key {keyType} type and/or value {valueType} type encountered.\");\n                }\n            }\n            else\n            {\n                throw new ArgumentException(\n                    $\"Invalid target property type {type} encountered.\");\n            }\n        }\n#pragma warning restore MEN002, MEN003\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Store/DataModel.Encode.cs",
    "content": "using System;\nusing System.Collections;\nusing System.Collections.Generic;\nusing System.Collections.Immutable;\nusing System.Linq;\nusing System.Numerics;\nusing System.Reflection;\nusing Libplanet.Crypto;\nusing BTypes = Bencodex.Types;\n\nnamespace Libplanet.Store\n{\n    public abstract partial class DataModel\n    {\n        private static BTypes.IKey EncodeToIKey(object? key)\n        {\n            switch (key)\n            {\n                // NOTE: Check for null is only here for better readability.\n                case null:\n                    throw new NullReferenceException(\n                        $\"Argument {nameof(key)} cannot be null\");\n                case ImmutableArray<byte> bytes:\n                    return new BTypes.Binary(bytes);\n                case Guid guid:\n                    return new BTypes.Binary(guid.ToByteArray());\n                case Address address:\n                    return new BTypes.Binary(address.ByteArray);\n                case string s:\n                    return new BTypes.Text(s);\n                default:\n                    throw new ArgumentException(\n                        $\"Invalid type encountered for {nameof(key)}: {key}\");\n            }\n        }\n\n        private static BTypes.IValue EncodeToIValue(object? value)\n        {\n            switch (value)\n            {\n                case null:\n                    throw new NotSupportedException($\"Null value is not supported\");\n                case bool b:\n                    return new BTypes.Boolean(b);\n                case int i:\n                    return new BTypes.Integer(i);\n                case long l:\n                    return new BTypes.Integer(l);\n                case BigInteger bigInteger:\n                    return new BTypes.Integer(bigInteger);\n                case ImmutableArray<byte> bytes:\n                    return new BTypes.Binary(bytes);\n                case Guid guid:\n                    return new BTypes.Binary(guid.ToByteArray());\n                case Address address:\n                    return new BTypes.Binary(address.ByteArray);\n                case string s:\n                    return new BTypes.Text(s);\n                case DataModel dm:\n                    return dm.Encode();\n                case IList list:\n                    return EncodeToListIValue(list);\n                case IDictionary dict:\n                    return EncodeToDictionaryIValue(dict);\n                default:\n                    throw new ArgumentException(\n                        $\"Invalid type encountered for {nameof(value)}: {value}\");\n            }\n        }\n\n        private static BTypes.List EncodeToListIValue(IList list)\n        {\n            Type type = list.GetType();\n            if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(ImmutableList<>))\n            {\n                Type[] genericTypes = type.GetGenericArguments();\n                Type genericType = genericTypes[0];\n                if (genericType.IsGenericType &&\n                    (genericType.GetGenericTypeDefinition() == typeof(ImmutableList<>) ||\n                        genericType.GetGenericTypeDefinition() == typeof(ImmutableDictionary<,>)))\n                {\n                    throw new NotSupportedException($\"Nested collection is not supported: {type}\");\n                }\n                else if (genericType == typeof(bool?)\n                    || genericType == typeof(int?)\n                    || genericType == typeof(long?)\n                    || genericType == typeof(BigInteger?)\n                    || genericType == typeof(ImmutableArray<byte>?)\n                    || genericType == typeof(Guid?)\n                    || genericType == typeof(Address?))\n                {\n                    throw new NotSupportedException(\n                        $\"Nullable value type is not supported: {genericType}\");\n                }\n                else if (genericType == typeof(bool)\n                    || genericType == typeof(int)\n                    || genericType == typeof(long)\n                    || genericType == typeof(BigInteger)\n                    || genericType == typeof(ImmutableArray<byte>)\n                    || genericType == typeof(Guid)\n                    || genericType == typeof(Address)\n                    || genericType == typeof(string))\n                {\n                    return new BTypes.List(\n                        list.Cast<object>().Select(x => EncodeToIValue(x)));\n                }\n                else\n                {\n                        throw new ArgumentException(\n                            $\"Invalid value type {genericType} encountered \" +\n                            $\"for {nameof(list)}: {list}\");\n                }\n            }\n            else\n            {\n                throw new ArgumentException(\n                    $\"Invalid type encountered for {nameof(list)}: {list}\");\n            }\n        }\n\n        private static BTypes.Dictionary EncodeToDictionaryIValue(IDictionary dict)\n        {\n            Type type = dict.GetType();\n            if (type.IsGenericType &&\n                type.GetGenericTypeDefinition() == typeof(ImmutableDictionary<,>))\n            {\n                Type[] genericTypes = dict.GetType().GetGenericArguments();\n                Type keyType = genericTypes[0];\n                Type valueType = genericTypes[1];\n                if (keyType == typeof(string)\n                    || keyType == typeof(ImmutableArray<byte>)\n                    || keyType == typeof(Guid)\n                    || keyType == typeof(Address))\n                {\n                    if (valueType.IsGenericType &&\n                        (valueType.GetGenericTypeDefinition() == typeof(ImmutableList<>) ||\n                            valueType.GetGenericTypeDefinition() == typeof(ImmutableDictionary<,>)))\n                    {\n                        throw new NotSupportedException(\n                            $\"Nested collection is not supported: {type}\");\n                    }\n                    else if (\n                        keyType == typeof(ImmutableArray<byte>?)\n                        || keyType == typeof(Guid?)\n                        || keyType == typeof(Address?))\n                    {\n                        throw new NotSupportedException(\n                            $\"Nullable value type is not supported: {keyType}\");\n                    }\n                    else if (valueType == typeof(bool?)\n                        || valueType == typeof(int?)\n                        || valueType == typeof(long?)\n                        || valueType == typeof(BigInteger?)\n                        || valueType == typeof(ImmutableArray<byte>?)\n                        || valueType == typeof(Guid?)\n                        || valueType == typeof(Address?))\n                    {\n                        throw new NotSupportedException(\n                            $\"Nullable value type is not supported: {valueType}\");\n                    }\n                    else if (valueType == typeof(bool)\n                        || valueType == typeof(int)\n                        || valueType == typeof(long)\n                        || valueType == typeof(BigInteger)\n                        || valueType == typeof(ImmutableArray<byte>)\n                        || valueType == typeof(Guid)\n                        || valueType == typeof(Address)\n                        || valueType == typeof(string))\n                    {\n                        return new BTypes.Dictionary(dict\n                            .Cast<object>()\n                            .Select(kv =>\n                                {\n                                    PropertyInfo[] properties = kv.GetType().GetProperties();\n                                    object? key = properties[0].GetValue(kv);\n                                    object? value = properties[1].GetValue(kv);\n                                    return new KeyValuePair<BTypes.IKey, BTypes.IValue>(\n                                        EncodeToIKey(key), EncodeToIValue(value));\n                                }));\n                    }\n                    else\n                    {\n                        throw new ArgumentException(\n                            $\"Invalid value type {valueType} encountered \" +\n                            $\"for {nameof(dict)}: {dict}\");\n                    }\n                }\n                else\n                {\n                    throw new ArgumentException(\n                        $\"Invalid key type {keyType} encountered for {nameof(dict)}: {dict}\");\n                }\n            }\n            else\n            {\n                throw new ArgumentException(\n                    $\"Invalid type encountered for {nameof(dict)}: {dict}\");\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Store/DataModel.cs",
    "content": "using System;\nusing System.Collections.Immutable;\nusing System.Diagnostics.Contracts;\nusing System.Numerics;\nusing System.Reflection;\nusing Libplanet.Crypto;\nusing BTypes = Bencodex.Types;\n\nnamespace Libplanet.Store\n{\n    /// <summary>\n    /// <para>\n    /// A <c>class</c> representing an abstract data model that can be easily\n    /// encoded and decoded to and from a <see cref=\"BTypes.Dictionary\"/>.\n    /// </para>\n    /// <para>\n    /// Inheriting this class and simply declaring properties allows an instance of the child class\n    /// to encode its data into a <see cref=\"BTypes.Dictionary\"/> where the encoded\n    /// <see cref=\"BTypes.Dictionary\"/> has the concrete class'es each property name as its key and\n    /// the each corresponding property value as its value.\n    /// </para>\n    /// <para>\n    /// However, there are certain restrictions that apply when using this <c>class</c>:\n    /// <list type=\"bullet\">\n    ///     <item><description>\n    ///         The complete list of allowed property types are as follows:\n    ///         <list type=\"bullet\">\n    ///             <item><description>\n    ///                 Primitive types: <c>bool</c>, <c>int</c>, <c>long</c>, <c>BigInteger</c>,\n    ///                 <c><![CDATA[ImmutableArray<byte>]]></c>, <c>Guid</c>, <c>Address</c>,\n    ///                 and <c>string</c>.\n    ///             </description></item>\n    ///             <item><description>\n    ///                 Special types: Any type inherited from <see cref=\"DataModel\"/>.\n    ///             </description></item>\n    ///             <item><description>\n    ///                 Collective types:\n    ///                 <list type=\"bullet\">\n    ///                     <item><description>\n    ///                         <see cref=\"ImmutableList{T}\"/> where <c>T</c> is a primitive type.\n    ///                     </description></item>\n    ///                     <item><description>\n    ///                         <see cref=\"ImmutableDictionary{TKey,TValue}\"/> where\n    ///                         <list type=\"bullet\">\n    ///                             <item><description>\n    ///                                 <c>TKey</c> is one of\n    ///                                 <c><![CDATA[ImmutableArray<byte>]]></c>, <c>Address</c>,\n    ///                                 <c>Guid</c>, and <c>string</c>.\n    ///                             </description></item>\n    ///                             <item><description>\n    ///                                 <c>TValue</c> is a primitive type.\n    ///                             </description></item>\n    ///                         </list>\n    ///                     </description></item>\n    ///                 </list>\n    ///             </description></item>\n    ///         </list>\n    ///     </description></item>\n    ///     <item><description>\n    ///         Value types are not allowed to be declared as <c>nullable</c>, not even as\n    ///         a generic type parameter.  That is, types such as <c>bool?</c>, <c>Address?</c>,\n    ///         and <c><![CDATA[ImmutableList<int?>]]></c>are not allowed.\n    ///     </description></item>\n    ///     <item><description>\n    ///         Reference types are not allowed to be assigned <see langword=\"null\"/>.  This will\n    ///         result in an <see cref=\"Exception\"/> when <see cref=\"Encode\"/> is called.\n    ///     </description></item>\n    ///     <item><description>\n    ///         Trying to assign <see langword=\"null\"/> to any property or to a part of\n    ///         a collection will result in an <see cref=\"Exception\"/> when\n    ///         <see cref=\"DataModel(BTypes.Dictionary)\"/> is called.\n    ///     </description></item>\n    /// </list>\n    /// </para>\n    /// </summary>\n    /// <example>\n    /// The following example shows how this class can be used:\n    /// <code><![CDATA[\n    /// public class CharacterData : DataModel\n    /// {\n    ///     /// <summary>\n    ///     /// Name of the character.\n    ///     /// </summary>\n    ///     public string Name { get; private set; }\n    ///\n    ///     /// <summary>\n    ///     /// Current level of the character.\n    ///     /// </summary>\n    ///     public int Level { get; private set; }\n    ///\n    ///     /// <summary>\n    ///     /// Inventory of the character.\n    ///     /// </summary>\n    ///     public InventoryData Inv { get; private set; }\n    ///\n    ///     public CharacterData(string name, int level, InventoryData inv)\n    ///         : base()\n    ///     {\n    ///         Name = name;\n    ///         Level = level;\n    ///         Inv = inv;\n    ///     }\n    ///\n    ///     public CharacterData(Bencodex.Types.Dictionary encoded)\n    ///         : base(encoded)\n    ///     {\n    ///     }\n    /// }\n    ///\n    /// public class InventoryData : DataModel\n    /// {\n    ///     /// <summary>\n    ///     /// The amount of gold in the inventory.\n    ///     /// </summary>\n    ///     public int Gold { get; private set; }\n    ///\n    ///     public InventoryData(int gold)\n    ///         : base()\n    ///     {\n    ///         Gold = gold;\n    ///     }\n    ///\n    ///     public InventoryData(Bencodex.Types.Dictionary encoded)\n    ///         : base(encoded)\n    ///     {\n    ///     }\n    /// }\n    /// ]]></code>\n    /// Then the concrete model defined above can be used as shown below:\n    /// <code><![CDATA[\n    /// CharacterData characterData = new CharacterData(\"John\", 5, new InventoryData(100));\n    /// Bencodex.Types.Dictionary encoded = characterData.Encode()\n    /// ]]></code>\n    /// This would result in <c>encoded</c> in a following format:\n    /// <code><![CDATA[\n    /// Bencodex.Types.Dictionary {\n    ///   \"Name\": \"John\",\n    ///   \"Level\": 5,\n    ///   \"Inv\": {\n    ///       \"Gold\": 100,\n    ///   },\n    /// }\n    /// ]]></code>\n    /// To decode this back into an instance, simply use it as shown below:\n    /// <code><![CDATA[\n    /// CharacterData decoded = new CharacterData(encoded);\n    /// ]]></code>\n    /// Then <c>decoded.Name</c>, <c>decoded.Level</c>, and <c>decoded.Inv.Gold</c> will have\n    /// values <c>\"John\"</c>, <c>5</c>, and <c>100</c> respectively.\n    /// </example>\n    /// <remarks>\n    /// There are certain caveats for using this class:\n    /// <list type=\"bullet\">\n    ///     <item><description>\n    ///         Encoded data type is fixed to <see cref=\"BTypes.Dictionary\"/>.  As each\n    ///         property name is encoded into <see cref=\"BTypes.Text\"/> as a key, it is\n    ///         advisable to give short names for properties.  For example, <c>int HP</c> is better\n    ///         than <c>int HealthPoint</c> to reduce storage size and/or network traffic.\n    ///         As seen in the example above, actively use documented properties instead.\n    ///     </description></item>\n    ///     <item><description>\n    ///         Property type of <see cref=\"ImmutableDictionary{TKey,TValue}\"/> is inefficient\n    ///         to encode and decode.  Additional caution is needed when declaring\n    ///         <see cref=\"ImmutableDictionary{TKey,TValue}\"/> property type.\n    ///     </description></item>\n    ///     <item><description>\n    ///         As supported types are limited, in particular, nullable types and nested\n    ///         collection types not being allowed, if a custom data model that isn't supported\n    ///         by this class is needed, manual implementation of encoding and decoding\n    ///         should be done separately.\n    ///     </description></item>\n    /// </list>\n    /// </remarks>\n    public abstract partial class DataModel\n    {\n        private PropertyInfo[]? _propertyInfos = null;\n\n        protected DataModel()\n        {\n        }\n\n        /// <summary>\n        /// Decodes a <see cref=\"BTypes.Dictionary\"/> data into an instance.\n        /// </summary>\n        /// <param name=\"encoded\">The <see cref=\"BTypes.Dictionary\"/> instance to decode.</param>\n        /// <returns>A decoded instance from <paramref name=\"encoded\"/>.</returns>\n        /// <exception cref=\"NotSupportedException\">Thrown when <see langword=\"null\"/> value is\n        /// encountered while decoding.</exception>\n        /// <exception cref=\"ArgumentException\">Thrown when invalid encoded type is encountered.\n        /// </exception>\n        /// <exception cref=\"NullReferenceException\">Thrown when <paramref name=\"encoded\"/> is\n        /// <see langword=\"null\"/> or <see langword=\"null\"/> reference is returned by inner\n        /// instantiation.</exception>\n        protected DataModel(BTypes.Dictionary encoded)\n        {\n            if (encoded is BTypes.Dictionary e)\n            {\n                foreach (PropertyInfo property in PropertyInfos)\n                {\n                    Type type = property.PropertyType;\n                    BTypes.IValue value = e[property.Name];\n\n                    if (type == typeof(bool?)\n                        || type == typeof(int?)\n                        || type == typeof(long?)\n                        || type == typeof(BigInteger?)\n                        || type == typeof(ImmutableArray<byte>?)\n                        || type == typeof(Guid?)\n                        || type == typeof(Address?))\n                    {\n                        throw new NotSupportedException(\n                            $\"Nullable value type is not supported: {type}\");\n                    }\n                    else\n                    {\n                        property.SetValue(this, DecodeFromIValue(value, type));\n                    }\n                }\n            }\n            else\n            {\n                throw new NullReferenceException($\"Argument {nameof(encoded)} cannot be null.\");\n            }\n        }\n\n        /// <summary>\n        /// Cached property info for performance.\n        /// </summary>\n        private PropertyInfo[] PropertyInfos => _propertyInfos\n            ?? (_propertyInfos = this.GetType().GetProperties());\n\n        /// <summary>\n        /// Encodes an instance into a <see cref=\"BTypes.Dictionary\"/>.\n        /// </summary>\n        /// <returns>An encoded <see cref=\"BTypes.Dictionary\"/> instance.</returns>\n        /// <exception cref=\"NotSupportedException\">Thrown when <c>nullable</c> value type property\n        /// or <see langword=\"null\"/> value inside a reference type is encountered.</exception>\n        /// <exception cref=\"ArgumentException\">Thrown when an unknown invalid property type is\n        /// encountered.</exception>\n        [Pure]\n        public BTypes.Dictionary Encode()\n        {\n            BTypes.Dictionary result = BTypes.Dictionary.Empty;\n            foreach (PropertyInfo property in PropertyInfos)\n            {\n                Type type = property.PropertyType;\n                if (type == typeof(bool?)\n                    || type == typeof(int?)\n                    || type == typeof(long?)\n                    || type == typeof(BigInteger?)\n                    || type == typeof(ImmutableArray<byte>?)\n                    || type == typeof(Guid?)\n                    || type == typeof(Address?))\n                {\n                    throw new NotSupportedException(\n                        $\"Nullable value type is not supported: {type}\");\n                }\n\n                // NOTE: Additional IValue casting is needed for this to work.\n                object? value = property.GetValue(this, null);\n                result = result.Add(property.Name, EncodeToIValue(value));\n            }\n\n            return result;\n        }\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Store/DefaultStore.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Collections.Specialized;\nusing System.IO;\nusing System.Linq;\nusing System.Runtime.InteropServices;\nusing System.Security.Cryptography;\nusing System.Web;\nusing Bencodex;\nusing Bencodex.Types;\nusing Libplanet.Common;\nusing Libplanet.Crypto;\nusing Libplanet.Store.Trie;\nusing Libplanet.Types.Blocks;\nusing Libplanet.Types.Evidence;\nusing Libplanet.Types.Tx;\nusing LiteDB;\nusing LruCacheNet;\nusing Serilog;\nusing Zio;\nusing Zio.FileSystems;\nusing FileMode = LiteDB.FileMode;\n\nnamespace Libplanet.Store\n{\n    /// <summary>\n    /// The default built-in <see cref=\"IStore\"/> implementation.  This stores data in\n    /// the file system or in memory.  It also uses <a href=\"https://www.litedb.org/\">LiteDB</a>\n    /// for some complex indices.\n    /// <para><see cref=\"DefaultStore\"/> and <see cref=\"DefaultKeyValueStore\"/>-backed\n    /// <see cref=\"TrieStateStore\"/> can be instantiated from a URI with <c>default+file:</c> scheme\n    /// using <see cref=\"StoreLoaderAttribute.LoadStore(Uri)\"/>, e.g.:</para>\n    /// <list type=\"bullet\">\n    /// <item><description><c>default+file:///var/data/planet/</c></description></item>\n    /// <item><description><c>default+file:///c:/Users/john/AppData/Local/planet/</c></description>\n    /// </item>\n    /// </list>\n    /// <para>The following query string parameters are supported:</para>\n    /// <list type=\"table\">\n    /// <item>\n    /// <term><c>journal</c></term>\n    /// <description><see langword=\"true\"/> (default) or <see langword=\"false\"/>.  Corresponds to\n    /// <see cref=\"DefaultStore(string, bool, int, int, int, int, bool, bool)\"/>'s <c>journal</c>\n    /// parameter.</description>\n    /// </item>\n    /// <item>\n    /// <term><c>index-cache</c></term>\n    /// <description>Corresponds to\n    /// <see cref=\"DefaultStore(string,bool,int,int,int,int,bool,bool)\"/>'s\n    /// <c>indexCacheSize</c> parameter.  50000 by default.</description>\n    /// </item>\n    /// <item>\n    /// <term><c>block-cache</c></term>\n    /// <description>Corresponds to\n    /// <see cref=\"DefaultStore(string,bool,int,int,int,int,bool,bool)\"/>'s\n    /// <c>blockCacheSize</c> parameter.  512 by default.</description>\n    /// </item>\n    /// <item>\n    /// <term><c>tx-cache</c></term>\n    /// <description>Corresponds to\n    /// <see cref=\"DefaultStore(string,bool,int,int,int,int,bool,bool)\"/>'s\n    /// <c>txCacheSize</c> parameter.  1024 by default.</description>\n    /// </item>\n    /// <item>\n    /// <term><c>flush</c></term>\n    /// <description><see langword=\"true\"/> (default) or <see langword=\"false\"/>.  Corresponds to\n    /// <see cref=\"DefaultStore(string, bool, int, int, int, int, bool, bool)\"/>'s <c>flush</c>\n    /// parameter.</description>\n    /// </item>\n    /// <item>\n    /// <term><c>readonly</c></term>\n    /// <description><see langword=\"true\"/> or <see langword=\"false\"/> (default).  Corresponds to\n    /// <see cref=\"DefaultStore(string, bool, int, int, int, int, bool, bool)\"/>'s <c>readOnly</c>\n    /// parameter.</description>\n    /// </item>\n    /// <item>\n    /// <term><c>states-dir</c></term>\n    /// <description>Corresponds to <see cref=\"DefaultKeyValueStore(string)\"/>'s <c>path</c>\n    /// parameter.  It is relative to the URI path, and defaults to <c>states</c>.</description>\n    /// </item>\n    /// </list>\n    /// </summary>\n    /// <seealso cref=\"IStore\"/>\n    public class DefaultStore : BaseStore\n    {\n        private const string IndexColPrefix = \"index_\";\n        private const string TxNonceIdPrefix = \"nonce_\";\n        private const string CommitColPrefix = \"commit_\";\n        private const string StatesKvPathDefault = \"states\";\n\n        private static readonly UPath TxRootPath = UPath.Root / \"tx\";\n        private static readonly UPath BlockRootPath = UPath.Root / \"block\";\n        private static readonly UPath TxExecutionRootPath = UPath.Root / \"txexec\";\n        private static readonly UPath TxIdBlockHashRootPath = UPath.Root / \"txbindex\";\n        private static readonly UPath BlockPerceptionRootPath = UPath.Root / \"blockpercept\";\n        private static readonly UPath BlockCommitRootPath = UPath.Root / \"blockcommit\";\n        private static readonly UPath NextStateRootHashRootPath = UPath.Root / \"nextstateroothash\";\n        private static readonly UPath PendingEvidenceRootPath = UPath.Root / \"evidencep\";\n        private static readonly UPath CommittedEvidenceRootPath = UPath.Root / \"evidencec\";\n        private static readonly Codec Codec = new Codec();\n\n        private readonly ILogger _logger;\n\n        private readonly IFileSystem _root;\n        private readonly SubFileSystem _txs;\n        private readonly SubFileSystem _blocks;\n        private readonly SubFileSystem _txExecutions;\n        private readonly SubFileSystem _txIdBlockHashIndex;\n        private readonly SubFileSystem _blockPerceptions;\n        private readonly SubFileSystem _blockCommits;\n        private readonly SubFileSystem _nextStateRootHashes;\n        private readonly SubFileSystem _pendingEvidence;\n        private readonly SubFileSystem _committedEvidence;\n        private readonly LruCache<TxId, object> _txCache;\n        private readonly LruCache<BlockHash, BlockDigest> _blockCache;\n        private readonly LruCache<EvidenceId, EvidenceBase> _evidenceCache;\n\n        private readonly LiteDatabase _db;\n\n        private bool _disposed = false;\n\n        /// <summary>\n        /// Creates a new <seealso cref=\"DefaultStore\"/>.\n        /// </summary>\n        /// <param name=\"path\">The path of the directory where the storage files will be saved.\n        /// If the path is <see langword=\"null\"/>, the database is created in memory.</param>\n        /// <param name=\"journal\">\n        /// Enables or disables double write check to ensure durability.\n        /// </param>\n        /// <param name=\"indexCacheSize\">Max number of pages in the index cache.</param>\n        /// <param name=\"blockCacheSize\">The capacity of the block cache.</param>\n        /// <param name=\"txCacheSize\">The capacity of the transaction cache.</param>\n        /// <param name=\"evidenceCacheSize\">The capacity of the evidence cache.</param>\n        /// <param name=\"flush\">Writes data direct to disk avoiding OS cache.  Turned on by default.\n        /// </param>\n        /// <param name=\"readOnly\">Opens database readonly mode. Turned off by default.</param>\n        public DefaultStore(\n            string path,\n            bool journal = true,\n            int indexCacheSize = 50000,\n            int blockCacheSize = 512,\n            int txCacheSize = 1024,\n            int evidenceCacheSize = 1024,\n            bool flush = true,\n            bool readOnly = false\n        )\n        {\n            _logger = Log.ForContext<DefaultStore>();\n\n            if (path is null)\n            {\n                _root = new MemoryFileSystem();\n                _db = new LiteDatabase(new MemoryStream(), disposeStream: true);\n            }\n            else\n            {\n                path = Path.GetFullPath(path);\n\n                if (!Directory.Exists(path))\n                {\n                    Directory.CreateDirectory(path);\n                }\n\n                var pfs = new PhysicalFileSystem();\n                _root = new SubFileSystem(\n                    pfs,\n                    pfs.ConvertPathFromInternal(path),\n                    owned: true\n                );\n\n                var connectionString = new ConnectionString\n                {\n                    Filename = Path.Combine(path, \"index.ldb\"),\n                    Journal = journal,\n                    CacheSize = indexCacheSize,\n                    Flush = flush,\n                };\n\n                if (readOnly)\n                {\n                    connectionString.Mode = FileMode.ReadOnly;\n                }\n                else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX) &&\n                    Type.GetType(\"Mono.Runtime\") is null)\n                {\n                    // macOS + .NETCore doesn't support shared lock.\n                    connectionString.Mode = FileMode.Exclusive;\n                }\n\n                _db = new LiteDatabase(connectionString);\n            }\n\n            lock (_db.Mapper)\n            {\n                _db.Mapper.RegisterType(\n                    hash => hash.ToByteArray(),\n                    b => new BlockHash(b));\n                _db.Mapper.RegisterType(\n                    hash => hash.ToByteArray(),\n                    b => new HashDigest<SHA256>(b));\n                _db.Mapper.RegisterType(\n                    txid => txid.ToByteArray(),\n                    b => new TxId(b));\n                _db.Mapper.RegisterType(\n                    address => address.ToByteArray(),\n                    b => new Address(b.AsBinary));\n                _db.Mapper.RegisterType(\n                    commit => Codec.Encode(commit.Bencoded),\n                    b => new BlockCommit(Codec.Decode(b)));\n                _db.Mapper.RegisterType(\n                    evidence => Codec.Encode(evidence.Bencoded),\n                    b => new EvidenceId(Codec.Decode(b)));\n            }\n\n            _root.CreateDirectory(TxRootPath);\n            _txs = new SubFileSystem(_root, TxRootPath, owned: false);\n            _root.CreateDirectory(BlockRootPath);\n            _blocks = new SubFileSystem(_root, BlockRootPath, owned: false);\n            _root.CreateDirectory(TxExecutionRootPath);\n            _txExecutions = new SubFileSystem(_root, TxExecutionRootPath, owned: false);\n            _root.CreateDirectory(TxIdBlockHashRootPath);\n            _txIdBlockHashIndex = new SubFileSystem(_root, TxIdBlockHashRootPath, owned: false);\n            _root.CreateDirectory(BlockPerceptionRootPath);\n            _blockPerceptions = new SubFileSystem(_root, BlockPerceptionRootPath, owned: false);\n            _root.CreateDirectory(BlockCommitRootPath);\n            _blockCommits = new SubFileSystem(_root, BlockCommitRootPath, owned: false);\n            _root.CreateDirectory(NextStateRootHashRootPath);\n            _nextStateRootHashes =\n                new SubFileSystem(_root, NextStateRootHashRootPath, owned: false);\n            _root.CreateDirectory(PendingEvidenceRootPath);\n            _pendingEvidence = new SubFileSystem(_root, PendingEvidenceRootPath, owned: false);\n            _root.CreateDirectory(CommittedEvidenceRootPath);\n            _committedEvidence = new SubFileSystem(_root, CommittedEvidenceRootPath, owned: false);\n\n            _txCache = new LruCache<TxId, object>(capacity: txCacheSize);\n            _blockCache = new LruCache<BlockHash, BlockDigest>(capacity: blockCacheSize);\n            _evidenceCache = new LruCache<EvidenceId, EvidenceBase>(\n                capacity: evidenceCacheSize);\n        }\n\n        /// <inheritdoc/>\n        public override IEnumerable<Guid> ListChainIds()\n        {\n            return _db.GetCollectionNames()\n                .Where(name => name.StartsWith(IndexColPrefix))\n                .Select(name => ParseChainId(name.Substring(IndexColPrefix.Length)));\n        }\n\n        /// <inheritdoc/>\n        public override void DeleteChainId(Guid chainId)\n        {\n            _db.DropCollection(IndexCollection(chainId).Name);\n            _db.DropCollection(TxNonceCollection(chainId).Name);\n            _db.DropCollection(CommitCollection(chainId).Name);\n        }\n\n        /// <inheritdoc />\n        public override Guid? GetCanonicalChainId()\n        {\n            LiteCollection<BsonDocument> collection = _db.GetCollection<BsonDocument>(\"canon\");\n            var docId = new BsonValue(\"canon\");\n            BsonDocument doc = collection.FindById(docId);\n            if (doc is null)\n            {\n                return null;\n            }\n\n            return doc.TryGetValue(\"chainId\", out BsonValue ns)\n                ? new Guid(ns.AsBinary)\n                : (Guid?)null;\n        }\n\n        /// <inheritdoc />\n        public override void SetCanonicalChainId(Guid chainId)\n        {\n            LiteCollection<BsonDocument> collection = _db.GetCollection<BsonDocument>(\"canon\");\n            var docId = new BsonValue(\"canon\");\n            byte[] idBytes = chainId.ToByteArray();\n            collection.Upsert(docId, new BsonDocument() { [\"chainId\"] = new BsonValue(idBytes) });\n        }\n\n        /// <inheritdoc/>\n        public override long CountIndex(Guid chainId)\n        {\n            return IndexCollection(chainId).Count();\n        }\n\n        /// <inheritdoc cref=\"BaseStore.IterateIndexes(Guid, int, int?)\"/>\n        public override IEnumerable<BlockHash> IterateIndexes(Guid chainId, int offset, int? limit)\n        {\n            return IndexCollection(chainId)\n                .Find(Query.All(), offset, limit ?? int.MaxValue)\n                .Select(i => i.Hash);\n        }\n\n        /// <inheritdoc cref=\"BaseStore.IndexBlockHash(Guid, long)\"/>\n        public override BlockHash? IndexBlockHash(Guid chainId, long index)\n        {\n            if (index < 0)\n            {\n                index += CountIndex(chainId);\n\n                if (index < 0)\n                {\n                    return null;\n                }\n            }\n\n            HashDoc doc = IndexCollection(chainId).FindById(index + 1);\n            BlockHash? hash = doc is { } d ? d.Hash : (BlockHash?)null;\n            return hash;\n        }\n\n        /// <inheritdoc cref=\"BaseStore.AppendIndex(Guid, BlockHash)\"/>\n        public override long AppendIndex(Guid chainId, BlockHash hash)\n        {\n            return IndexCollection(chainId).Insert(new HashDoc { Hash = hash }) - 1;\n        }\n\n        /// <inheritdoc cref=\"BaseStore.ForkBlockIndexes(Guid, Guid, BlockHash)\"/>\n        public override void ForkBlockIndexes(\n            Guid sourceChainId,\n            Guid destinationChainId,\n            BlockHash branchpoint)\n        {\n            LiteCollection<HashDoc> srcColl = IndexCollection(sourceChainId);\n            LiteCollection<HashDoc> destColl = IndexCollection(destinationChainId);\n\n            BlockHash? genesisHash = IterateIndexes(sourceChainId, 0, 1)\n                .Cast<BlockHash?>()\n                .FirstOrDefault();\n\n            if (genesisHash is null || branchpoint.Equals(genesisHash))\n            {\n                return;\n            }\n\n            destColl.Delete(Query.All());\n            destColl.InsertBulk(srcColl.FindAll().TakeWhile(i => !i.Hash.Equals(branchpoint)));\n\n            AppendIndex(destinationChainId, branchpoint);\n        }\n\n        /// <inheritdoc/>\n        public override Transaction? GetTransaction(TxId txid)\n        {\n            if (_txCache.TryGetValue(txid, out object cachedTx))\n            {\n                return (Transaction)cachedTx;\n            }\n\n            UPath path = TxPath(txid);\n            if (!_txs.FileExists(path))\n            {\n                return null;\n            }\n\n            byte[] bytes;\n            try\n            {\n                bytes = _txs.ReadAllBytes(path);\n            }\n            catch (FileNotFoundException)\n            {\n                return null;\n            }\n\n            IValue txNode = Codec.Decode(bytes);\n            if (txNode is Bencodex.Types.Dictionary dict)\n            {\n                Transaction tx = TxMarshaler.UnmarshalTransactionWithoutVerification(dict);\n                _txCache.AddOrUpdate(txid, tx);\n                return tx;\n            }\n\n            throw new DecodingException(\n                $\"Expected {typeof(Dictionary).FullName}, but {txNode.GetType().Name} is given\"\n            );\n        }\n\n        /// <inheritdoc/>\n        public override void PutTransaction(Transaction tx)\n        {\n            if (_txCache.ContainsKey(tx.Id))\n            {\n                return;\n            }\n\n            WriteContentAddressableFile(_txs, TxPath(tx.Id), tx.Serialize());\n            _txCache.AddOrUpdate(tx.Id, tx);\n        }\n\n        /// <inheritdoc/>\n        public override bool ContainsTransaction(TxId txId)\n        {\n            if (_txCache.ContainsKey(txId))\n            {\n                return true;\n            }\n\n            return _txs.FileExists(TxPath(txId));\n        }\n\n        /// <inheritdoc cref=\"BaseStore.IterateBlockHashes()\"/>\n        public override IEnumerable<BlockHash> IterateBlockHashes()\n        {\n            foreach (UPath path in _blocks.EnumerateDirectories(UPath.Root))\n            {\n                string upper = path.GetName();\n                if (upper.Length != 2)\n                {\n                    continue;\n                }\n\n                foreach (UPath subPath in _blocks.EnumerateFiles(path))\n                {\n                    string lower = subPath.GetName();\n                    string name = upper + lower;\n                    BlockHash blockHash;\n                    try\n                    {\n                        blockHash = BlockHash.FromString(name);\n                    }\n                    catch (Exception)\n                    {\n                        // Skip if a filename does not match to the format.\n                        continue;\n                    }\n\n                    yield return blockHash;\n                }\n            }\n        }\n\n        /// <inheritdoc cref=\"BaseStore.GetBlockDigest(BlockHash)\"/>\n        public override BlockDigest? GetBlockDigest(BlockHash blockHash)\n        {\n            if (_blockCache.TryGetValue(blockHash, out BlockDigest cachedDigest))\n            {\n                return cachedDigest;\n            }\n\n            UPath path = BlockPath(blockHash);\n            if (!_blocks.FileExists(path))\n            {\n                return null;\n            }\n\n            BlockDigest blockDigest;\n            try\n            {\n                blockDigest = BlockDigest.Deserialize(_blocks.ReadAllBytes(path));\n            }\n            catch (FileNotFoundException)\n            {\n                return null;\n            }\n\n            _blockCache.AddOrUpdate(blockHash, blockDigest);\n            return blockDigest;\n        }\n\n        /// <inheritdoc/>\n        public override void PutBlock(Block block)\n        {\n            if (_blockCache.ContainsKey(block.Hash))\n            {\n                return;\n            }\n\n            UPath path = BlockPath(block.Hash);\n            if (_blocks.FileExists(path))\n            {\n                return;\n            }\n\n            foreach (Transaction tx in block.Transactions)\n            {\n                PutTransaction(tx);\n            }\n\n            BlockDigest digest = BlockDigest.FromBlock(block);\n            WriteContentAddressableFile(_blocks, path, digest.Serialize());\n            _blockCache.AddOrUpdate(block.Hash, digest);\n        }\n\n        /// <inheritdoc cref=\"BaseStore.DeleteBlock(BlockHash)\"/>\n        public override bool DeleteBlock(BlockHash blockHash)\n        {\n            var path = BlockPath(blockHash);\n            if (_blocks.FileExists(path))\n            {\n                _blocks.DeleteFile(path);\n                _blockCache.Remove(blockHash);\n                return true;\n            }\n\n            return false;\n        }\n\n        /// <inheritdoc cref=\"BaseStore.ContainsBlock(BlockHash)\"/>\n        public override bool ContainsBlock(BlockHash blockHash)\n        {\n            if (_blockCache.ContainsKey(blockHash))\n            {\n                return true;\n            }\n\n            UPath blockPath = BlockPath(blockHash);\n            return _blocks.FileExists(blockPath);\n        }\n\n        /// <inheritdoc cref=\"BaseStore.PutTxExecution\"/>\n        public override void PutTxExecution(TxExecution txExecution)\n        {\n            UPath path = TxExecutionPath(txExecution);\n            UPath dirPath = path.GetDirectory();\n            CreateDirectoryRecursively(_txExecutions, dirPath);\n            using Stream f =\n                _txExecutions.OpenFile(path, System.IO.FileMode.Create, FileAccess.Write);\n            Codec.Encode(SerializeTxExecution(txExecution), f);\n        }\n\n        /// <inheritdoc cref=\"BaseStore.GetTxExecution(BlockHash, TxId)\"/>\n        public override TxExecution? GetTxExecution(BlockHash blockHash, TxId txid)\n        {\n            UPath path = TxExecutionPath(blockHash, txid);\n            if (_txExecutions.FileExists(path))\n            {\n                IValue decoded;\n                using (Stream f = _txExecutions.OpenFile(\n                    path, System.IO.FileMode.Open, FileAccess.Read))\n                {\n                    try\n                    {\n                        decoded = Codec.Decode(f);\n                    }\n                    catch (DecodingException e)\n                    {\n                        const string msg =\n                            \"Uncaught exception during \" + nameof(GetTxExecution);\n                        _logger.Error(e, msg);\n                        return null;\n                    }\n                }\n\n                return DeserializeTxExecution(blockHash, txid, decoded, _logger);\n            }\n\n            return null;\n        }\n\n        /// <inheritdoc cref=\"BaseStore.PutTxIdBlockHashIndex(TxId, BlockHash)\"/>\n        public override void PutTxIdBlockHashIndex(TxId txId, BlockHash blockHash)\n        {\n            var path = TxIdBlockHashIndexPath(txId, blockHash);\n            var dirPath = path.GetDirectory();\n            CreateDirectoryRecursively(_txIdBlockHashIndex, dirPath);\n            _txIdBlockHashIndex.WriteAllBytes(path, blockHash.ToByteArray());\n        }\n\n        public override IEnumerable<BlockHash> IterateTxIdBlockHashIndex(TxId txId)\n        {\n            var txPath = TxPath(txId);\n            if (!_txIdBlockHashIndex.DirectoryExists(txPath))\n            {\n                yield break;\n            }\n\n            foreach (var path in _txIdBlockHashIndex.EnumerateFiles(txPath))\n            {\n                yield return new BlockHash(ByteUtil.ParseHex(path.GetName()));\n            }\n        }\n\n        /// <inheritdoc cref=\"BaseStore.DeleteTxIdBlockHashIndex(TxId, BlockHash)\"/>\n        public override void DeleteTxIdBlockHashIndex(TxId txId, BlockHash blockHash)\n        {\n            var path = TxIdBlockHashIndexPath(txId, blockHash);\n            if (_txIdBlockHashIndex.FileExists(path))\n            {\n                _txIdBlockHashIndex.DeleteFile(path);\n            }\n        }\n\n        /// <inheritdoc/>\n        public override IEnumerable<KeyValuePair<Address, long>> ListTxNonces(Guid chainId)\n        {\n            LiteCollection<BsonDocument> collection = TxNonceCollection(chainId);\n            foreach (BsonDocument doc in collection.FindAll())\n            {\n                if (doc.TryGetValue(\"_id\", out BsonValue id) && id.IsBinary)\n                {\n                    var address = new Address(id.AsBinary);\n                    if (doc.TryGetValue(\"v\", out BsonValue v) && v.IsInt64 && v.AsInt64 > 0)\n                    {\n                        yield return new KeyValuePair<Address, long>(address, v.AsInt64);\n                    }\n                }\n            }\n        }\n\n        /// <inheritdoc/>\n        public override long GetTxNonce(Guid chainId, Address address)\n        {\n            LiteCollection<BsonDocument> collection = TxNonceCollection(chainId);\n            var docId = new BsonValue(address.ToByteArray());\n            BsonDocument doc = collection.FindById(docId);\n\n            if (doc is null)\n            {\n                return 0;\n            }\n\n            return doc.TryGetValue(\"v\", out BsonValue v) ? v.AsInt64 : 0;\n        }\n\n        /// <inheritdoc/>\n        public override void IncreaseTxNonce(Guid chainId, Address signer, long delta = 1)\n        {\n            long nextNonce = GetTxNonce(chainId, signer) + delta;\n            LiteCollection<BsonDocument> collection = TxNonceCollection(chainId);\n            var docId = new BsonValue(signer.ToByteArray());\n            collection.Upsert(docId, new BsonDocument() { [\"v\"] = new BsonValue(nextNonce) });\n        }\n\n        /// <inheritdoc/>\n        public override void ForkTxNonces(Guid sourceChainId, Guid destinationChainId)\n        {\n            LiteCollection<BsonDocument> srcColl = TxNonceCollection(sourceChainId);\n            LiteCollection<BsonDocument> destColl = TxNonceCollection(destinationChainId);\n            destColl.InsertBulk(srcColl.FindAll());\n        }\n\n        /// <inheritdoc/>\n        public override void PruneOutdatedChains(bool noopWithoutCanon = false)\n        {\n            if (!(GetCanonicalChainId() is { } ccid))\n            {\n                if (noopWithoutCanon)\n                {\n                    return;\n                }\n\n                throw new InvalidOperationException(\"Canonical chain ID is not assigned.\");\n            }\n\n            Guid[] chainIds = ListChainIds().ToArray();\n            foreach (Guid id in chainIds.Where(id => !id.Equals(ccid)))\n            {\n                DeleteChainId(id);\n            }\n        }\n\n        /// <inheritdoc />\n        public override BlockCommit? GetChainBlockCommit(Guid chainId)\n        {\n            LiteCollection<BsonDocument> collection = CommitCollection(chainId);\n            var docId = new BsonValue(\"c\");\n            BsonDocument doc = collection.FindById(docId);\n            return doc is { } d && d.TryGetValue(\"v\", out BsonValue v)\n                ? new BlockCommit(Codec.Decode(v))\n                : null;\n        }\n\n        /// <inheritdoc />\n        public override void PutChainBlockCommit(Guid chainId, BlockCommit blockCommit)\n        {\n            LiteCollection<BsonDocument> collection = CommitCollection(chainId);\n            var docId = new BsonValue(\"c\");\n            BsonDocument doc = collection.FindById(docId);\n            collection.Upsert(\n                docId,\n                new BsonDocument() { [\"v\"] = new BsonValue(Codec.Encode(blockCommit.Bencoded)) });\n        }\n\n        public override BlockCommit? GetBlockCommit(BlockHash blockHash)\n        {\n            UPath path = BlockCommitPath(blockHash);\n            if (!_blockCommits.FileExists(path))\n            {\n                return null;\n            }\n\n            byte[] bytes;\n            try\n            {\n                bytes = _blockCommits.ReadAllBytes(path);\n            }\n            catch (FileNotFoundException)\n            {\n                return null;\n            }\n\n            BlockCommit blockCommit = new BlockCommit(Codec.Decode(bytes));\n            return blockCommit;\n        }\n\n        /// <inheritdoc />\n        public override void PutBlockCommit(BlockCommit blockCommit)\n        {\n            UPath path = BlockCommitPath(blockCommit.BlockHash);\n            if (_blockCommits.FileExists(path))\n            {\n                return;\n            }\n\n            WriteContentAddressableFile(_blockCommits, path, Codec.Encode(blockCommit.Bencoded));\n        }\n\n        /// <inheritdoc />\n        public override void DeleteBlockCommit(BlockHash blockHash)\n        {\n            UPath path = BlockCommitPath(blockHash);\n            if (!_blockCommits.FileExists(path))\n            {\n                return;\n            }\n\n            _blockCommits.DeleteFile(path);\n        }\n\n        /// <inheritdoc/>\n        public override IEnumerable<BlockHash> GetBlockCommitHashes()\n        {\n            var hashes = new List<BlockHash>();\n\n            foreach (UPath path in _blockCommits.EnumerateFiles(UPath.Root))\n            {\n                if (path.FullName.Split('/').LastOrDefault() is { } name)\n                {\n                    hashes.Add(new BlockHash(ByteUtil.ParseHex(name)));\n                }\n                else\n                {\n                    throw new InvalidOperationException(\"Failed to get the block hash.\");\n                }\n            }\n\n            return hashes.AsEnumerable();\n        }\n\n        /// <inheritdoc/>\n        public override HashDigest<SHA256>? GetNextStateRootHash(BlockHash blockHash)\n        {\n            UPath path = NextStateRootHashPath(blockHash);\n            if (!_nextStateRootHashes.FileExists(path))\n            {\n                return null;\n            }\n\n            byte[] bytes;\n            try\n            {\n                bytes = _nextStateRootHashes.ReadAllBytes(path);\n            }\n            catch (FileNotFoundException)\n            {\n                return null;\n            }\n\n            HashDigest<SHA256> nextStateRootHash = new HashDigest<SHA256>(bytes);\n            return nextStateRootHash;\n        }\n\n        /// <inheritdoc/>\n        public override void PutNextStateRootHash(\n            BlockHash blockHash, HashDigest<SHA256> nextStateRootHash)\n        {\n            UPath path = NextStateRootHashPath(blockHash);\n            if (_nextStateRootHashes.FileExists(path))\n            {\n                return;\n            }\n\n            WriteContentAddressableFile(\n                _nextStateRootHashes, path, nextStateRootHash.ToByteArray());\n        }\n\n        /// <inheritdoc />\n        public override void DeleteNextStateRootHash(BlockHash blockHash)\n        {\n            UPath path = NextStateRootHashPath(blockHash);\n            if (!_nextStateRootHashes.FileExists(path))\n            {\n                return;\n            }\n\n            _nextStateRootHashes.DeleteFile(path);\n        }\n\n        /// <inheritdoc/>\n        public override IEnumerable<EvidenceId> IteratePendingEvidenceIds()\n        {\n            foreach (UPath path in _pendingEvidence.EnumerateFiles(UPath.Root))\n            {\n                EvidenceId evidenceId;\n                try\n                {\n                    var name = path.FullName.Split('/').LastOrDefault() ?? string.Empty;\n                    evidenceId = EvidenceId.Parse(name);\n                }\n                catch (Exception)\n                {\n                    // Skip if a filename does not match to the format.\n                    continue;\n                }\n\n                yield return evidenceId;\n            }\n        }\n\n        /// <inheritdoc/>\n        public override EvidenceBase? GetPendingEvidence(EvidenceId evidenceId)\n        {\n            UPath path = PendingEvidencePath(evidenceId);\n            if (!_pendingEvidence.FileExists(path))\n            {\n                return null;\n            }\n\n            byte[] bytes;\n            try\n            {\n                bytes = _pendingEvidence.ReadAllBytes(path);\n            }\n            catch (FileNotFoundException)\n            {\n                return null;\n            }\n\n            try\n            {\n                EvidenceBase evidence = EvidenceBase.Decode(Codec.Decode(bytes));\n                return evidence;\n            }\n            catch\n            {\n                return null;\n            }\n        }\n\n        /// <inheritdoc/>\n        public override void PutPendingEvidence(EvidenceBase evidence)\n        {\n            if (_evidenceCache.ContainsKey(evidence.Id))\n            {\n                return;\n            }\n\n            if (_pendingEvidence.FileExists(PendingEvidencePath(evidence.Id)))\n            {\n                return;\n            }\n\n            WriteContentAddressableFile(\n                _pendingEvidence,\n                PendingEvidencePath(evidence.Id),\n                Codec.Encode(EvidenceBase.Bencode(evidence)));\n        }\n\n        /// <inheritdoc/>\n        public override void DeletePendingEvidence(EvidenceId evidenceId)\n        {\n            UPath path = PendingEvidencePath(evidenceId);\n            if (!_pendingEvidence.FileExists(path))\n            {\n                return;\n            }\n\n            _pendingEvidence.DeleteFile(path);\n        }\n\n        /// <inheritdoc/>\n        public override bool ContainsPendingEvidence(EvidenceId evidenceId)\n        {\n            return _pendingEvidence.FileExists(PendingEvidencePath(evidenceId));\n        }\n\n        /// <inheritdoc/>\n        public override EvidenceBase? GetCommittedEvidence(EvidenceId evidenceId)\n        {\n            if (_evidenceCache.TryGetValue(evidenceId, out EvidenceBase cachedEvidence))\n            {\n                return cachedEvidence;\n            }\n\n            UPath path = CommittedEvidencePath(evidenceId);\n            if (!_committedEvidence.FileExists(path))\n            {\n                return null;\n            }\n\n            byte[] bytes;\n            try\n            {\n                bytes = _committedEvidence.ReadAllBytes(path);\n            }\n            catch (FileNotFoundException)\n            {\n                return null;\n            }\n\n            try\n            {\n                EvidenceBase evidence = EvidenceBase.Decode(Codec.Decode(bytes));\n                return evidence;\n            }\n            catch\n            {\n                return null;\n            }\n        }\n\n        /// <inheritdoc/>\n        public override void PutCommittedEvidence(EvidenceBase evidence)\n        {\n            if (_evidenceCache.ContainsKey(evidence.Id))\n            {\n                return;\n            }\n\n            if (_committedEvidence.FileExists(CommittedEvidencePath(evidence.Id)))\n            {\n                return;\n            }\n\n            WriteContentAddressableFile(\n                _committedEvidence,\n                CommittedEvidencePath(evidence.Id),\n                Codec.Encode(EvidenceBase.Bencode(evidence)));\n\n            _evidenceCache.AddOrUpdate(evidence.Id, evidence);\n        }\n\n        /// <inheritdoc/>\n        public override void DeleteCommittedEvidence(EvidenceId evidenceId)\n        {\n            _evidenceCache.Remove(evidenceId);\n\n            UPath path = CommittedEvidencePath(evidenceId);\n            if (!_committedEvidence.FileExists(path))\n            {\n                return;\n            }\n\n            _committedEvidence.DeleteFile(path);\n        }\n\n        /// <inheritdoc/>\n        public override bool ContainsCommittedEvidence(EvidenceId evidenceId)\n        {\n            if (_evidenceCache.ContainsKey(evidenceId))\n            {\n                return true;\n            }\n\n            return _committedEvidence.FileExists(CommittedEvidencePath(evidenceId));\n        }\n\n        /// <inheritdoc/>\n        public override long CountBlocks()\n        {\n            // FIXME: This implementation is too inefficient.  Fortunately, this method seems\n            // unused (except for unit tests).  If this is never used why should we maintain\n            // this?  This is basically only for making BlockSet<T> class to implement\n            // IDictionary<HashDigest<SHA256>, Block>.Count property, which is never used either.\n            // We'd better to refactor all such things so that unnecessary APIs are gone away.\n            return IterateBlockHashes().LongCount();\n        }\n\n        public override void Dispose()\n        {\n            if (!_disposed)\n            {\n                _db?.Dispose();\n                _root.Dispose();\n                _disposed = true;\n            }\n        }\n\n        internal static Guid ParseChainId(string chainIdString) =>\n            new Guid(ByteUtil.ParseHex(chainIdString));\n\n        internal static string FormatChainId(Guid chainId) =>\n            ByteUtil.Hex(chainId.ToByteArray());\n\n        [StoreLoader(\"default+file\")]\n        private static (IStore Store, IStateStore StateStore) Loader(Uri storeUri)\n        {\n            NameValueCollection query = HttpUtility.ParseQueryString(storeUri.Query);\n            bool journal = query.GetBoolean(\"journal\", true);\n            int indexCacheSize = query.GetInt32(\"index-cache\", 50000);\n            int blockCacheSize = query.GetInt32(\"block-cache\", 512);\n            int txCacheSize = query.GetInt32(\"tx-cache\", 1024);\n            int evidenceCacheSize = query.GetInt32(\"evidence-cache\", 1024);\n            bool flush = query.GetBoolean(\"flush\", true);\n            bool readOnly = query.GetBoolean(\"readonly\");\n            string statesKvPath = query.Get(\"states-dir\") ?? StatesKvPathDefault;\n            var store = new DefaultStore(\n                storeUri.LocalPath,\n                journal,\n                indexCacheSize,\n                blockCacheSize,\n                txCacheSize,\n                evidenceCacheSize,\n                flush,\n                readOnly);\n            var stateStore = new TrieStateStore(\n                new DefaultKeyValueStore(Path.Combine(storeUri.LocalPath, statesKvPath)));\n            return (store, stateStore);\n        }\n\n        private static void CreateDirectoryRecursively(IFileSystem fs, UPath path)\n        {\n            if (!fs.DirectoryExists(path))\n            {\n                CreateDirectoryRecursively(fs, path.GetDirectory());\n                fs.CreateDirectory(path);\n            }\n        }\n\n        private void WriteContentAddressableFile(IFileSystem fs, UPath path, byte[] contents)\n        {\n            UPath dirPath = path.GetDirectory();\n            CreateDirectoryRecursively(fs, dirPath);\n\n            // Assuming the filename is content-addressable, so that if there is\n            // already the file of the same name the content is the same as well.\n            if (fs.FileExists(path))\n            {\n                return;\n            }\n\n            // For atomicity, writes bytes into an intermediate temp file,\n            // and then renames it to the final destination.\n            UPath tmpPath = dirPath / $\".{Guid.NewGuid():N}.tmp\";\n            try\n            {\n                fs.WriteAllBytes(tmpPath, contents);\n                try\n                {\n                    fs.MoveFile(tmpPath, path);\n                }\n                catch (IOException)\n                {\n                    if (!fs.FileExists(path) ||\n                        fs.GetFileLength(path) != contents.LongLength)\n                    {\n                        throw;\n                    }\n                }\n            }\n            finally\n            {\n                if (fs.FileExists(tmpPath))\n                {\n                    fs.DeleteFile(tmpPath);\n                }\n            }\n        }\n\n        private UPath BlockPath(in BlockHash blockHash)\n        {\n            string idHex = ByteUtil.Hex(blockHash.ByteArray);\n            if (idHex.Length < 3)\n            {\n                throw new ArgumentException(\n                    $\"Too short block hash: \\\"{idHex}\\\".\",\n                    nameof(blockHash)\n                );\n            }\n\n            return UPath.Root / idHex.Substring(0, 2) / idHex.Substring(2);\n        }\n\n        private UPath TxPath(in TxId txid)\n        {\n            string idHex = txid.ToHex();\n            return UPath.Root / idHex.Substring(0, 2) / idHex.Substring(2);\n        }\n\n        private UPath BlockCommitPath(in BlockHash blockHash)\n        {\n            return UPath.Combine(UPath.Root, blockHash.ToString());\n        }\n\n        private UPath NextStateRootHashPath(in BlockHash blockHash)\n        {\n            return UPath.Root / blockHash.ToString();\n        }\n\n        private UPath PendingEvidencePath(in EvidenceId evidenceId)\n        {\n            return UPath.Combine(UPath.Root, evidenceId.ToString());\n        }\n\n        private UPath CommittedEvidencePath(in EvidenceId evidenceId)\n        {\n            return UPath.Combine(UPath.Root, evidenceId.ToString());\n        }\n\n        private UPath TxExecutionPath(in BlockHash blockHash, in TxId txid) =>\n            BlockPath(blockHash) / txid.ToHex();\n\n        private UPath TxExecutionPath(TxExecution txExecution) =>\n            TxExecutionPath(txExecution.BlockHash, txExecution.TxId);\n\n        private UPath TxIdBlockHashIndexPath(in TxId txid, in BlockHash blockHash) =>\n            TxPath(txid) / blockHash.ToString();\n\n        private LiteCollection<HashDoc> IndexCollection(in Guid chainId) =>\n            _db.GetCollection<HashDoc>($\"{IndexColPrefix}{FormatChainId(chainId)}\");\n\n        private LiteCollection<BsonDocument> TxNonceCollection(Guid chainId) =>\n            _db.GetCollection<BsonDocument>($\"{TxNonceIdPrefix}{FormatChainId(chainId)}\");\n\n        private LiteCollection<BsonDocument> CommitCollection(in Guid chainId) =>\n            _db.GetCollection<BsonDocument>($\"{CommitColPrefix}{FormatChainId(chainId)}\");\n\n        private class HashDoc\n        {\n            public long Id { get; set; }\n\n            public BlockHash Hash { get; set; }\n        }\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Store/HashNodeCache.cs",
    "content": "using System;\nusing System.Security.Cryptography;\nusing Bencodex.Types;\nusing BitFaster.Caching;\nusing BitFaster.Caching.Lru;\nusing Libplanet.Common;\nusing Libplanet.Store.Trie;\n\nnamespace Libplanet.Store\n{\n    /// <summary>\n    /// A class used for internally caching hashed nodes of <see cref=\"MerkleTrie\"/>s.\n    /// </summary>\n    public class HashNodeCache\n    {\n        // FIXME: Tuned to 9c mainnet.  Should be refactored to accept cache size as an argument.\n        private const int _cacheSize = 524_288;\n\n        private ICache<HashDigest<SHA256>, IValue> _cache;\n\n        internal HashNodeCache()\n        {\n            _cache = new ConcurrentLruBuilder<HashDigest<SHA256>, IValue>()\n                .WithMetrics()\n                .WithExpireAfterAccess(TimeSpan.FromMinutes(10))\n                .WithCapacity(_cacheSize)\n                .Build();\n        }\n\n        public bool TryGetValue(HashDigest<SHA256> hash, out IValue? value)\n        {\n            return _cache.TryGet(hash, out value);\n        }\n\n        public void AddOrUpdate(HashDigest<SHA256> hash, IValue value)\n        {\n            _cache.AddOrUpdate(hash, value);\n        }\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Store/IStateStore.cs",
    "content": "using System;\nusing System.Collections.Immutable;\nusing System.Security.Cryptography;\nusing Libplanet.Common;\nusing Libplanet.Store.Trie;\nusing Libplanet.Store.Trie.Nodes;\n\nnamespace Libplanet.Store\n{\n    /// <summary>\n    /// An interface to store states.\n    /// </summary>\n    public interface IStateStore : IDisposable\n    {\n        /// <summary>\n        /// Gets the state root trie of the <paramref name=\"stateRootHash\"/> from the state store.\n        /// </summary>\n        /// <param name=\"stateRootHash\">The state root hash of the state root trie to get.\n        /// If <see langword=\"null\"/> is passed the empty state root trie is returned.</param>\n        /// <returns>The state root trie of the <paramref name=\"stateRootHash\"/>.\n        /// If <see langword=\"null\"/> is passed the empty state root trie is returned.</returns>\n        ITrie GetStateRoot(HashDigest<SHA256>? stateRootHash);\n\n        /// <summary>\n        /// Commits given <paramref name=\"trie\"/> to storage.\n        /// Returned <see cref=\"ITrie\"/> must be identical to the one obtained from\n        /// <see cref=\"GetStateRoot\"/> with resulting <see cref=\"ITrie\"/>'s\n        /// <see cref=\"ITrie.Hash\"/>.\n        /// </summary>\n        /// <param name=\"trie\">The <see cref=\"ITrie\"/> to commit.</param>\n        /// <returns>The committed <see cref=\"ITrie\"/>.  The committed <see cref=\"ITrie\"/>'s\n        /// <see cref=\"ITrie.Root\"/> is guaranteed to be either <see langword=\"null\"/>\n        /// or a <see cref=\"HashNode\"/>.</returns>\n        /// <remarks>\n        /// Given <paramref name=\"trie\"/> must have originated from the same instance\n        /// (or with an instance with the same reference to an <see cref=\"IKeyValueStore\"/>).\n        /// Otherwise, this is not guaranteed to work properly.\n        /// </remarks>\n        /// <seealso cref=\"GetStateRoot\"/>\n        ITrie Commit(ITrie trie);\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Store/IStore.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Security.Cryptography;\nusing Libplanet.Common;\nusing Libplanet.Crypto;\nusing Libplanet.Types.Blocks;\nusing Libplanet.Types.Evidence;\nusing Libplanet.Types.Tx;\n\nnamespace Libplanet.Store\n{\n    public interface IStore : IDisposable\n    {\n        /// <summary>\n        /// Lists chain IDs containing at least a single block.\n        /// </summary>\n        /// <returns>Chain IDs with at least a single block.</returns>\n        IEnumerable<Guid> ListChainIds();\n\n        /// <summary>\n        /// Deletes an index, tx nonces, and state references in the given\n        /// <paramref name=\"chainId\"/>.\n        /// It also deletes chain itself.  If there is no such <paramref name=\"chainId\"/> it\n        /// does nothing.\n        /// </summary>\n        /// <param name=\"chainId\">The ID of chain to delete.</param>\n        /// <remarks>This does not delete blocks or transactions that belong to the index of\n        /// the <paramref name=\"chainId\"/>, but only the index, tx nonces, and state references.\n        /// </remarks>\n        void DeleteChainId(Guid chainId);\n\n        /// <summary>\n        /// Gets the ID of the current canonical chain.\n        /// </summary>\n        /// <returns>The ID of the current canonical chain.  Maybe <see langword=\"null\"/>.</returns>\n        /// <seealso cref=\"SetCanonicalChainId(Guid)\"/>\n        Guid? GetCanonicalChainId();\n\n        /// <summary>\n        /// Sets the canonical chain.\n        /// </summary>\n        /// <param name=\"chainId\">The ID of a new canonical chain.</param>\n        /// <seealso cref=\"GetCanonicalChainId()\"/>\n        void SetCanonicalChainId(Guid chainId);\n\n        long CountIndex(Guid chainId);\n\n        /// <summary>\n        /// Lists all block hashes in <paramref name=\"chainId\"/>.\n        /// </summary>\n        /// <param name=\"chainId\">The chain ID of the index that contains block hashes to\n        /// iterate.</param>\n        /// <param name=\"offset\">The starting point to return block hashes.</param>\n        /// <param name=\"limit\">The maximum number of block hashes to get.</param>\n        /// <returns>Block hashes in the index of the <paramref name=\"chainId\"/>, in ascending\n        /// order; the genesis block goes first, and the tip block goes last.</returns>\n        IEnumerable<BlockHash> IterateIndexes(Guid chainId, int offset = 0, int? limit = null);\n\n        /// <summary>\n        /// Determines the block hash by its <paramref name=\"index\"/>.\n        /// </summary>\n        /// <param name=\"chainId\">The chain ID of the index that contains the block.</param>\n        /// <param name=\"index\">The index of the block to query its hash.  Negative indices mean\n        /// the offset from the end.  For example, -1 means the topmost block.</param>\n        /// <returns>The block hash of the index in the chain.  If there is no such index,\n        /// it returns <see langword=\"null\"/>.</returns>\n        BlockHash? IndexBlockHash(Guid chainId, long index);\n\n        /// <summary>\n        /// Appends a block to a chain.\n        /// </summary>\n        /// <param name=\"chainId\">The ID of a chain to append a block to.</param>\n        /// <param name=\"hash\">The hash of a block to append.  Assumes the block is already put\n        /// into the store.</param>\n        /// <returns>The index of the appended block.</returns>\n        long AppendIndex(Guid chainId, BlockHash hash);\n\n        /// <summary>\n        /// Forks block indexes from\n        /// <paramref name=\"sourceChainId\"/> to\n        /// <paramref name=\"destinationChainId\"/>.\n        /// </summary>\n        /// <param name=\"sourceChainId\">The chain ID of block indexes to\n        /// fork.</param>\n        /// <param name=\"destinationChainId\">The chain ID of destination\n        /// block indexes.</param>\n        /// <param name=\"branchpoint\">The branchpoint <see cref=\"Block\"/> to fork.</param>\n        /// <seealso cref=\"IterateIndexes(Guid, int, int?)\"/>\n        /// <seealso cref=\"AppendIndex(Guid, BlockHash)\"/>\n        void ForkBlockIndexes(Guid sourceChainId, Guid destinationChainId, BlockHash branchpoint);\n\n        Transaction? GetTransaction(TxId txid);\n\n        /// <summary>\n        /// Puts a given <see cref=\"Transaction\"/> to the store.  If the same transaction\n        /// already exists in the store it does nothing.\n        /// </summary>\n        /// <param name=\"tx\">A transaction to put into the store.</param>\n        void PutTransaction(Transaction tx);\n\n        /// <summary>\n        /// Lists all block hashes in the store, regardless of their belonging chains.\n        /// </summary>\n        /// <returns>All block hashes in the store.</returns>\n        IEnumerable<BlockHash> IterateBlockHashes();\n\n        /// <summary>\n        /// Gets the corresponding stored <see cref=\"Block\"/> to the given\n        /// <paramref name=\"blockHash\"/>.\n        /// </summary>\n        /// <param name=\"blockHash\"><see cref=\"Block.Hash\"/> to find.</param>\n        /// <returns>A found block, or <see langword=\"null\"/> if no block having such\n        /// <paramref name=\"blockHash\"/> is stored.</returns>\n        Block? GetBlock(BlockHash blockHash);\n\n        /// <summary>\n        /// Gets a stored block's <see cref=\"Block.Index\"/> by its <see cref=\"Block.Hash\"/>.\n        /// </summary>\n        /// <param name=\"blockHash\"><see cref=\"Block.Hash\"/> to find.</param>\n        /// <remarks>\n        /// It provides only limited information, but can be called without any type parameter\n        /// unlike <see cref=\"GetBlock\"/>.\n        /// </remarks>\n        /// <returns>A found block's <see cref=\"Block.Index\"/>, or <see langword=\"null\"/> if\n        /// no block having such <paramref name=\"blockHash\"/> is stored.</returns>\n        long? GetBlockIndex(BlockHash blockHash);\n\n        /// <summary>\n        /// Gets the corresponding stored <see cref=\"BlockDigest\"/> to the given\n        /// <paramref name=\"blockHash\"/>.\n        /// </summary>\n        /// <param name=\"blockHash\"><see cref=\"Block.Hash\"/> to find.</param>\n        /// <returns>A found <see cref=\"BlockDigest\"/>, or <see langword=\"null\"/> if no block\n        /// having such <paramref name=\"blockHash\"/> is stored.</returns>\n        BlockDigest? GetBlockDigest(BlockHash blockHash);\n\n        /// <summary>\n        /// Puts the given <paramref name=\"block\"/> in to the store.\n        /// If the same block already exists in the store it does nothing.\n        /// </summary>\n        /// <param name=\"block\">A <see cref=\"Block\"/> to put into the store.\n        /// </param>\n        void PutBlock(Block block);\n\n        /// <summary>\n        /// Removes a block from the store.\n        /// </summary>\n        /// <param name=\"blockHash\">The hash of a block to remove.</param>\n        /// <returns><see langword=\"false\"/> if such block does not exist. Otherwise\n        /// <see langword=\"true\"/>.</returns>\n        bool DeleteBlock(BlockHash blockHash);\n\n        /// <summary>\n        /// Determines whether the <see cref=\"IStore\"/> contains <see cref=\"Block\"/>\n        /// the specified <paramref name=\"blockHash\"/>.\n        /// </summary>\n        /// <param name=\"blockHash\">The <see cref=\"HashDigest{T}\"/> of the <see cref=\"Block\"/> to\n        /// check if it is in the <see cref=\"IStore\"/>.</param>\n        /// <returns>\n        /// <see langword=\"true\"/> if the <see cref=\"IStore\"/> contains <see cref=\"Block\"/> with\n        /// the specified <paramref name=\"blockHash\"/>; otherwise, <see langword=\"false\"/>.\n        /// </returns>\n        bool ContainsBlock(BlockHash blockHash);\n\n        /// <summary>\n        /// Records the given <paramref name=\"txExecution\"/>.\n        /// </summary>\n        /// <remarks>If there is already the record for the same <see cref=\"TxExecution.BlockHash\"/>\n        /// and <see cref=\"TxExecution.TxId\"/>, the record is silently overwritten.</remarks>\n        /// <param name=\"txExecution\">The transaction execution summary to record.\n        /// Must not be <see langword=\"null\"/>.</param>\n        /// <exception cref=\"ArgumentNullException\">Thrown when <paramref name=\"txExecution\"/> is\n        /// <see langword=\"null\"/>.</exception>\n        /// <seealso cref=\"GetTxExecution(BlockHash, TxId)\"/>\n        void PutTxExecution(TxExecution txExecution);\n\n        /// <summary>\n        /// Retrieves the recorded transaction execution summary.\n        /// </summary>\n        /// <param name=\"blockHash\">The <see cref=\"Block.Hash\"/> of the recorded transaction\n        /// execution to retrieve.</param>\n        /// <param name=\"txid\">The <see cref=\"Transaction.Id\"/> of the recorded transaction\n        /// execution to retrieve.</param>\n        /// <returns>The recorded transaction execution summary.  If it has been never recorded\n        /// <see langword=\"null\"/> is returned instead.</returns>\n        /// <seealso cref=\"PutTxExecution\"/>\n        TxExecution? GetTxExecution(BlockHash blockHash, TxId txid);\n\n        /// <summary>\n        /// Records a index for given pair <paramref name=\"txId\"/> and <paramref name=\"blockHash\"/>.\n        /// If there exist a record for <paramref name=\"txId\"/> already,\n        /// it overwrites the record silently.\n        /// </summary>\n        /// <param name=\"txId\">The <see cref=\"TxId\"/> of the <see cref=\"Transaction\"/>.</param>\n        /// <param name=\"blockHash\">The <see cref=\"BlockHash\"/> of the <see cref=\"Block\"/>.\n        /// </param>\n        void PutTxIdBlockHashIndex(TxId txId, BlockHash blockHash);\n\n        /// <summary>\n        /// Retrieves the <see cref=\"BlockHash\"/> indexed by the <paramref name=\"txId\"/>.\n        /// </summary>\n        /// <param name=\"txId\">The <see cref=\"TxId\"/> of the <see cref=\"Transaction\"/>.</param>\n        /// <returns><see cref=\"BlockHash\"/> if the index exists. Otherwise\n        /// <see langword=\"null\"/>.</returns>\n        BlockHash? GetFirstTxIdBlockHashIndex(TxId txId);\n\n        /// <summary>\n        /// Retrieves <see cref=\"BlockHash\"/>es indexed by the <paramref name=\"txId\"/>.\n        /// </summary>\n        /// <param name=\"txId\">The <see cref=\"TxId\"/> of the <see cref=\"Transaction\"/>.</param>\n        /// <returns><see cref=\"BlockHash\"/>es if the index exists.</returns>\n        IEnumerable<BlockHash> IterateTxIdBlockHashIndex(TxId txId);\n\n        /// <summary>\n        /// Deletes the index for the <paramref name=\"txId\"/> and <paramref name=\"blockHash\"/>.\n        /// </summary>\n        /// <param name=\"txId\">The <see cref=\"TxId\"/> of the <see cref=\"Transaction\"/>.</param>\n        /// <param name=\"blockHash\">The <see cref=\"BlockHash\"/>\n        /// of the <see cref=\"Block\"/>.</param>.\n        void DeleteTxIdBlockHashIndex(TxId txId, BlockHash blockHash);\n\n        /// <summary>\n        /// Lists all <see cref=\"Address\"/>es that have ever signed <see cref=\"Transaction\"/>,\n        /// and their corresponding <see cref=\"Transaction\"/> nonces.\n        /// </summary>\n        /// <param name=\"chainId\">The ID of the chain to list <see cref=\"Address\"/>es and their\n        /// <see cref=\"Transaction\"/> nonces.</param>\n        /// <returns>Pairs of an <see cref=\"Address\"/> and its tx nonce.  All nonces are greater\n        /// than 0.  (If there are underlying entries having zero nonces these must be hidden.)\n        /// </returns>\n        /// <seealso cref=\"GetTxNonce(Guid, Address)\"/>\n        IEnumerable<KeyValuePair<Address, long>> ListTxNonces(Guid chainId);\n\n        /// <summary>\n        /// Gets <see cref=\"Transaction\"/> nonce of the\n        /// <paramref name=\"address\"/>.\n        /// </summary>\n        /// <param name=\"chainId\">The ID of the chain to get <see cref=\"Transaction\"/> nonce.\n        /// </param>\n        /// <param name=\"address\">The <see cref=\"Address\"/> to get\n        /// <see cref=\"Transaction\"/> nonce.\n        /// </param>\n        /// <returns>A <see cref=\"Transaction\"/> nonce. If there is no\n        /// previous <see cref=\"Transaction\"/>, return 0.</returns>\n        /// <seealso cref=\"IncreaseTxNonce(Guid, Address, long)\"/>\n        long GetTxNonce(Guid chainId, Address address);\n\n        /// <summary>\n        /// Increases (or decreases if a negative <paramref name=\"delta\"/> is given)\n        /// the tx nonce counter for <paramref name=\"signer\"/>.\n        /// </summary>\n        /// <param name=\"chainId\">The ID of the chain to increase\n        /// <see cref=\"Transaction\"/> nonce.</param>\n        /// <param name=\"signer\">The address of the account to increase tx nonce.</param>\n        /// <param name=\"delta\">How many to increase the counter.  A negative number decreases\n        /// the counter.  1 by default.</param>\n        /// <seealso cref=\"GetTxNonce(Guid, Address)\"/>\n        void IncreaseTxNonce(Guid chainId, Address signer, long delta = 1);\n\n        /// <summary>\n        /// Determines whether the <see cref=\"IStore\"/> contains <see cref=\"Transaction\"/>\n        /// the specified <paramref name=\"txId\"/>.\n        /// </summary>\n        /// <param name=\"txId\">The <see cref=\"TxId\"/> of the <see cref=\"Transaction\"/>\n        /// to check if it is in the <see cref=\"IStore\"/>.</param>\n        /// <returns>\n        /// <see langword=\"true\"/> if the <see cref=\"IStore\"/> contains <see cref=\"Transaction\"/>\n        /// with the specified <paramref name=\"txId\"/>; otherwise, <see langword=\"false\"/>.\n        /// </returns>\n        bool ContainsTransaction(TxId txId);\n\n        long CountBlocks();\n\n        /// <summary>\n        /// Forks <see cref=\"Transaction\"/> <see cref=\"Transaction.Nonce\"/>s from\n        /// <paramref name=\"sourceChainId\"/> to\n        /// <paramref name=\"destinationChainId\"/>.\n        /// </summary>\n        /// <param name=\"sourceChainId\">The chain <see cref=\"BlockChain.Id\"/> of\n        /// <see cref=\"Transaction\"/> <see cref=\"Transaction.Nonce\"/>s to fork.</param>\n        /// <param name=\"destinationChainId\">The chain <see cref=\"BlockChain.Id\"/> of destination\n        /// <see cref=\"Transaction\"/> <see cref=\"Transaction.Nonce\"/>s.</param>\n        void ForkTxNonces(Guid sourceChainId, Guid destinationChainId);\n\n        /// <summary>\n        /// Delete all non-canonical chains.\n        /// </summary>\n        /// <param name=\"noopWithoutCanon\">\n        /// Flag to determine whether the function throws exception\n        /// when the canonical chain is not assigned.  <see langword=\"false\"/> by default.\n        /// If it set to <see langword=\"true\"/>, does not throw exception when\n        /// there is no canonical chain.\n        /// Otherwise, throws <see cref=\"InvalidOperationException\"/> when\n        /// there is no canonical chain.\n        /// </param>\n        /// <exception cref=\"InvalidOperationException\">\n        /// Thrown for any of the following reasons:\n        /// <list type=\"bullet\">\n        ///     <item><description>\n        ///         Thrown when there is no canonical chain and <paramref name=\"noopWithoutCanon\"/>\n        ///         is false.\n        ///     </description></item>\n        ///     <item><description>\n        ///         A <see cref=\"BlockHash\"/> for a non-existent <see cref=\"Block\"/> is encountered\n        ///         while iterating.\n        ///     </description></item>\n        ///     <item><description>\n        ///         If the chain in question is found to be \"un-prunable\" due to data corruption.\n        ///     </description></item>\n        /// </list>\n        /// </exception>\n        /// <remarks>\n        /// If an <see cref=\"InvalidOperationException\"/> is thrown, this results in\n        /// no-op for the <see cref=\"IStore\"/>.\n        /// </remarks>\n        void PruneOutdatedChains(bool noopWithoutCanon = false);\n\n        /// <summary>\n        /// Gets a <see cref=\"BlockCommit\"/> associated with a <see cref=\"BlockChain\"/>\n        /// with <paramref name=\"chainId\"/> as its <see cref=\"BlockChain.Id\"/>.\n        /// </summary>\n        /// <param name=\"chainId\">The <see cref=\"BlockChain.Id\"/> of\n        /// the <see cref=\"BlockChain\"/> to retrieve <see cref=\"BlockCommit\"/>.</param>\n        /// <returns>Returns <see cref=\"BlockCommit\"/> if given <paramref name=\"chainId\"/> is\n        /// stored and available, otherwise returns <see langword=\"null\"/>.</returns>\n        BlockCommit? GetChainBlockCommit(Guid chainId);\n\n        /// <summary>\n        /// Puts a <see cref=\"BlockCommit\"/> associated with a <see cref=\"BlockChain\"/>\n        /// with <paramref name=\"chainId\"/> as its <see cref=\"BlockChain.Id\"/>.\n        /// The given <see cref=\"BlockCommit\"/> should have the same <see cref=\"BlockHash\"/>\n        /// as the <see cref=\"BlockChain.Tip\"/>.\n        /// </summary>\n        /// <param name=\"chainId\">The <see cref=\"BlockChain.Id\"/> of\n        /// the <see cref=\"BlockChain\"/> to store <see cref=\"BlockCommit\"/>.</param>\n        /// <param name=\"blockCommit\">The <see cref=\"BlockCommit\"/> to store.</param>\n        void PutChainBlockCommit(Guid chainId, BlockCommit blockCommit);\n\n        /// <summary>\n        /// Gets the <see cref=\"BlockCommit\"/> for given <paramref name=\"blockHash\"/> from\n        /// the store.\n        /// </summary>\n        /// <param name=\"blockHash\">The <see cref=\"BlockHash\"/> of a <see cref=\"BlockCommit\"/>\n        /// to retrieve.</param>\n        /// <returns>Returns <see cref=\"BlockCommit\"/> if given <paramref name=\"blockHash\"/> is\n        /// stored and available, otherwise returns <see langword=\"null\"/>.</returns>\n        BlockCommit? GetBlockCommit(BlockHash blockHash);\n\n        /// <summary>\n        /// Puts a <see cref=\"BlockCommit\"/> to the store.\n        /// </summary>\n        /// <param name=\"blockCommit\">A <see cref=\"BlockCommit\"/> to store.</param>\n        void PutBlockCommit(BlockCommit blockCommit);\n\n        /// <summary>\n        /// Deletes a <see cref=\"BlockCommit\"/> of given height from store.\n        /// </summary>\n        /// <param name=\"blockHash\">The <see cref=\"BlockHash\"/> of a <see cref=\"BlockCommit\"/>\n        /// to delete.</param>\n        void DeleteBlockCommit(BlockHash blockHash);\n\n        /// <summary>\n        /// Gets every <see cref=\"BlockHash\"/>es of <see cref=\"BlockCommit\"/>s from store.\n        /// </summary>\n        /// <returns>Returns an <see cref=\"IEnumerable{T}\"/> of <see cref=\"BlockHash\"/>es\n        /// of all <see cref=\"BlockCommit\"/>s.</returns>\n        IEnumerable<BlockHash> GetBlockCommitHashes();\n\n        /// <summary>\n        /// Gets every <see cref=\"EvidenceId\"/>s of pending <see cref=\"EvidenceBase\"/>s\n        /// from the store.\n        /// </summary>\n        /// <returns>Returns an <see cref=\"IEnumerable{T}\"/> of <see cref=\"EvidenceId\"/>s\n        /// of all pending <see cref=\"EvidenceBase\"/>s.</returns>\n        IEnumerable<EvidenceId> IteratePendingEvidenceIds();\n\n        /// <summary>\n        /// Gets every pending <see cref=\"EvidenceBase\"/> of given <paramref name=\"evidenceId\"/>\n        /// from the store.\n        /// </summary>\n        /// <param name=\"evidenceId\">The <see cref=\"EvidenceId\"/> of a pending\n        /// <see cref=\"EvidenceBase\"/> to retrieve.</param>\n        /// <returns>Returns <see cref=\"EvidenceBase\"/> if given <paramref name=\"evidenceId\"/> is\n        /// stored, pending and available, otherwise returns <see langword=\"null\"/>.</returns>\n        EvidenceBase? GetPendingEvidence(EvidenceId evidenceId);\n\n        /// <summary>\n        /// Gets every committed <see cref=\"EvidenceBase\"/> of given <paramref name=\"evidenceId\"/>\n        /// from the store.\n        /// </summary>\n        /// <param name=\"evidenceId\">The <see cref=\"EvidenceId\"/> of a committed\n        /// <see cref=\"EvidenceBase\"/> to retrieve.</param>\n        /// <returns>Returns <see cref=\"EvidenceBase\"/> if given <paramref name=\"evidenceId\"/> is\n        /// stored, committed and available, otherwise returns <see langword=\"null\"/>.</returns>\n        EvidenceBase? GetCommittedEvidence(EvidenceId evidenceId);\n\n        /// <summary>\n        /// Puts a <see cref=\"EvidenceBase\"/> to the store as pending evidence.\n        /// </summary>\n        /// <param name=\"evidence\">A pending <see cref=\"EvidenceBase\"/> to store.</param>\n        void PutPendingEvidence(EvidenceBase evidence);\n\n        /// <summary>\n        /// Puts a <see cref=\"EvidenceBase\"/> to the store as committed evidence.\n        /// </summary>\n        /// <param name=\"evidence\">A committed <see cref=\"EvidenceBase\"/> to store.</param>\n        void PutCommittedEvidence(EvidenceBase evidence);\n\n        /// <summary>\n        /// Deletes a pending <see cref=\"EvidenceBase\"/> of given <paramref name=\"evidenceId\"/>\n        /// from the store.\n        /// </summary>\n        /// <param name=\"evidenceId\">The <see cref=\"EvidenceId\"/> of a pending\n        /// <see cref=\"EvidenceBase\"/>\n        /// to delete.</param>\n        void DeletePendingEvidence(EvidenceId evidenceId);\n\n        /// <summary>\n        /// Deletes a committed <see cref=\"EvidenceBase\"/> of given <paramref name=\"evidenceId\"/>\n        /// from the store.\n        /// </summary>\n        /// <param name=\"evidenceId\">The <see cref=\"EvidenceId\"/> of a committed\n        /// <see cref=\"EvidenceBase\"/>\n        /// to delete.</param>\n        void DeleteCommittedEvidence(EvidenceId evidenceId);\n\n        /// <summary>\n        /// Determines whether the <see cref=\"IStore\"/> contains <see cref=\"EvidenceBase\"/>\n        /// the specified <paramref name=\"evidenceId\"/> as pending.\n        /// </summary>\n        /// <param name=\"evidenceId\">The <see cref=\"EvidenceId\"/> of the <see cref=\"EvidenceBase\"/>\n        /// to check if it is in the <see cref=\"IStore\"/> and pending.</param>\n        /// <returns>\n        /// <see langword=\"true\"/> if the <see cref=\"IStore\"/> contains <see cref=\"EvidenceBase\"/>\n        /// with the specified <paramref name=\"evidenceId\"/> as pending; otherwise,\n        /// <see langword=\"false\"/>.\n        /// </returns>\n        bool ContainsPendingEvidence(EvidenceId evidenceId);\n\n        /// <summary>\n        /// Determines whether the <see cref=\"IStore\"/> contains <see cref=\"EvidenceBase\"/>\n        /// the specified <paramref name=\"evidenceId\"/> as committed.\n        /// </summary>\n        /// <param name=\"evidenceId\">The <see cref=\"EvidenceId\"/> of the <see cref=\"EvidenceBase\"/>\n        /// to check if it is in the <see cref=\"IStore\"/> and committed.</param>\n        /// <returns>\n        /// <see langword=\"true\"/> if the <see cref=\"IStore\"/> contains <see cref=\"EvidenceBase\"/>\n        /// with the specified <paramref name=\"evidenceId\"/> as committed; otherwise,\n        /// <see langword=\"false\"/>.\n        /// </returns>\n        bool ContainsCommittedEvidence(EvidenceId evidenceId);\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Store/Libplanet.Store.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <PropertyGroup>\n    <NoWarn>$(NoWarn);NU1904</NoWarn>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <PackageReference Include=\"BitFaster.Caching\" Version=\"2.5.2\" />\n    <PackageReference Include=\"System.Collections.Immutable\" Version=\"1.*\" />\n    <PackageReference Include=\"Bencodex\" Version=\"0.16.0\" />\n    <PackageReference Include=\"Caching.dll\" Version=\"1.4.0.1\" />\n    <PackageReference Include=\"ImmutableTrie\" Version=\"1.0.0-alpha\" />\n    <PackageReference Include=\"LiteDB\" Version=\"4.1.4\" />\n    <PackageReference Include=\"Planetarium.LruCacheNet\" Version=\"1.2.0\" />\n    <PackageReference Include=\"Serilog\" Version=\"2.8.0\" />\n    <PackageReference Include=\"Zio\" Version=\"0.7.4\" />\n  </ItemGroup>\n\n  <ItemGroup Condition=\"'$(SkipSonar)' != 'true'\">\n    <PackageReference Remove=\"SonarAnalyzer.CSharp\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <ProjectReference Include=\"..\\Libplanet.Common\\Libplanet.Common.csproj\" />\n    <ProjectReference Include=\"..\\Libplanet.Crypto\\Libplanet.Crypto.csproj\" />\n    <ProjectReference Include=\"..\\Libplanet.Types\\Libplanet.Types.csproj\" />\n  </ItemGroup>\n\n</Project>\n"
  },
  {
    "path": "src/Libplanet.Store/MemoryStore.cs",
    "content": "using System;\nusing System.Collections.Concurrent;\nusing System.Collections.Generic;\nusing System.Collections.Immutable;\nusing System.Collections.Specialized;\nusing System.Linq;\nusing System.Security.Cryptography;\nusing System.Web;\nusing ImmutableTrie;\nusing Libplanet.Common;\nusing Libplanet.Crypto;\nusing Libplanet.Store.Trie;\nusing Libplanet.Types.Blocks;\nusing Libplanet.Types.Evidence;\nusing Libplanet.Types.Tx;\n\nnamespace Libplanet.Store\n{\n    /// <summary>\n    /// Volatile in-memory store.\n    /// <para>It is useful for storing temporal small chains, e.g., fixtures for unit tests of\n    /// game logic.</para>\n    /// <para><see cref=\"MemoryStore\"/> and <see cref=\"MemoryKeyValueStore\"/>-backed\n    /// <see cref=\"TrieStateStore\"/> can be instantiated from a URI with <c>memory:</c> scheme\n    /// using <see cref=\"StoreLoaderAttribute.LoadStore(Uri)\"/>, e.g.:</para>\n    /// <list type=\"bullet\">\n    /// <item><description><c>memory:</c></description></item>\n    /// </list>\n    /// </summary>\n    public sealed class MemoryStore : IStore\n    {\n        private readonly ConcurrentDictionary<Guid, ImmutableTrieList<BlockHash>> _indices =\n            new ConcurrentDictionary<Guid, ImmutableTrieList<BlockHash>>();\n\n        private readonly ConcurrentDictionary<BlockHash, BlockDigest> _blocks =\n            new ConcurrentDictionary<BlockHash, BlockDigest>();\n\n        private readonly ConcurrentDictionary<BlockHash, DateTimeOffset> _blockPerceivedTimes =\n            new ConcurrentDictionary<BlockHash, DateTimeOffset>();\n\n        private readonly ConcurrentDictionary<TxId, Transaction> _txs =\n            new ConcurrentDictionary<TxId, Transaction>();\n\n        private readonly ConcurrentDictionary<Guid, ConcurrentDictionary<Address, long>> _txNonces =\n            new ConcurrentDictionary<Guid, ConcurrentDictionary<Address, long>>();\n\n        private readonly ConcurrentDictionary<(BlockHash, TxId), TxExecution> _txExecutions =\n            new ConcurrentDictionary<(BlockHash, TxId), TxExecution>();\n\n        private readonly ConcurrentDictionary<TxId, ImmutableHashSet<BlockHash>> _txBlockIndices =\n            new ConcurrentDictionary<TxId, ImmutableHashSet<BlockHash>>();\n\n        private readonly ConcurrentDictionary<BlockHash, BlockCommit> _blockCommits =\n            new ConcurrentDictionary<BlockHash, BlockCommit>();\n\n        private readonly ConcurrentDictionary<BlockHash, HashDigest<SHA256>> _nextStateRootHashes =\n            new ConcurrentDictionary<BlockHash, HashDigest<SHA256>>();\n\n        private readonly ConcurrentDictionary<Guid, BlockCommit> _chainCommits =\n            new ConcurrentDictionary<Guid, BlockCommit>();\n\n        private readonly ConcurrentDictionary<EvidenceId, EvidenceBase> _pendingEvidence =\n            new ConcurrentDictionary<EvidenceId, EvidenceBase>();\n\n        private readonly ConcurrentDictionary<EvidenceId, EvidenceBase> _committedEvidence\n            = new ConcurrentDictionary<EvidenceId, EvidenceBase>();\n\n        private Guid? _canonicalChainId;\n\n        void IDisposable.Dispose()\n        {\n            // Method intentionally left empty.\n        }\n\n        IEnumerable<Guid> IStore.ListChainIds() =>\n            _indices.Keys;\n\n        void IStore.DeleteChainId(Guid chainId)\n        {\n            _indices.TryRemove(chainId, out _);\n            _txNonces.TryRemove(chainId, out _);\n        }\n\n        Guid? IStore.GetCanonicalChainId() =>\n            _canonicalChainId;\n\n        void IStore.SetCanonicalChainId(Guid chainId) =>\n            _canonicalChainId = chainId;\n\n        long IStore.CountIndex(Guid chainId) =>\n            _indices.TryGetValue(chainId, out ImmutableTrieList<BlockHash>? index)\n            ? index.Count\n            : 0;\n\n        IEnumerable<BlockHash> IStore.IterateIndexes(Guid chainId, int offset, int? limit)\n        {\n            if (_indices.TryGetValue(chainId, out var list))\n            {\n                IEnumerable<BlockHash> index = list.Skip(offset);\n                return limit is { } l ? index.Take(l) : index;\n            }\n\n            return Enumerable.Empty<BlockHash>();\n        }\n\n        BlockHash? IStore.IndexBlockHash(Guid chainId, long index)\n        {\n            if (_indices.TryGetValue(chainId, out var list))\n            {\n                if (index < 0)\n                {\n                    index += list.Count;\n                }\n\n                if (index < list.Count && index >= 0)\n                {\n                    return list[(int)index];\n                }\n            }\n\n            return null;\n        }\n\n        long IStore.AppendIndex(Guid chainId, BlockHash hash)\n        {\n            ImmutableTrieList<BlockHash> list = _indices.AddOrUpdate(\n                chainId,\n                _ => ImmutableTrieList.Create(hash),\n                (_, list) => list.Add(hash)\n            );\n            _txNonces.GetOrAdd(chainId, _ => new ConcurrentDictionary<Address, long>());\n\n            return list.Count - 1;\n        }\n\n        public void ForkBlockIndexes(\n            Guid sourceChainId,\n            Guid destinationChainId,\n            BlockHash branchpoint\n        )\n        {\n            if (_indices.TryGetValue(sourceChainId, out ImmutableTrieList<BlockHash>? source))\n            {\n                int bpIndex = source.FindIndex(branchpoint.Equals);\n                _indices[destinationChainId] = source.GetRange(0, bpIndex + 1);\n            }\n        }\n\n        Transaction? IStore.GetTransaction(TxId txid) =>\n            _txs.TryGetValue(txid, out Transaction? untyped) && untyped is Transaction tx\n                ? tx\n                : null;\n\n        void IStore.PutTransaction(Transaction tx) =>\n            _txs[tx.Id] = tx;\n\n        IEnumerable<BlockHash> IStore.IterateBlockHashes() =>\n            _blocks.Keys;\n\n        Block? IStore.GetBlock(BlockHash blockHash)\n        {\n            if (!_blocks.TryGetValue(blockHash, out BlockDigest digest))\n            {\n                return null;\n            }\n\n            BlockHeader header = digest.GetHeader();\n            ImmutableArray<TxId> txids = digest.TxIds\n                .Select(b => new TxId(b.ToBuilder().ToArray()))\n                .ToImmutableArray();\n            IEnumerable<Transaction> txs = txids.Select(txid => _txs[txid]);\n            ImmutableArray<EvidenceId> evidenceIds = digest.EvidenceIds\n                .Select(b => new EvidenceId(b.ToBuilder().ToArray()))\n                .ToImmutableArray();\n            IEnumerable<EvidenceBase> evidence\n                = evidenceIds.Select(evId => _committedEvidence[evId]);\n            return new Block(header, txs, evidence);\n        }\n\n        long? IStore.GetBlockIndex(BlockHash blockHash) =>\n            _blocks.TryGetValue(blockHash, out BlockDigest digest) ? digest.Index : (long?)null;\n\n        BlockDigest? IStore.GetBlockDigest(BlockHash blockHash) =>\n            _blocks.TryGetValue(blockHash, out BlockDigest digest) ? digest : (BlockDigest?)null;\n\n        void IStore.PutBlock(Block block)\n        {\n            IReadOnlyList<Transaction> txs = block.Transactions;\n            foreach (Transaction tx in txs)\n            {\n                _txs[tx.Id] = tx;\n            }\n\n            var evidence = block.Evidence;\n            foreach (var ev in evidence)\n            {\n                _committedEvidence[ev.Id] = ev;\n            }\n\n            _blocks[block.Hash] = new BlockDigest(\n                block.Header,\n                txs.Select(tx => tx.Id.ByteArray).ToImmutableArray(),\n                evidence.Select(ev => ev.Id.ByteArray).ToImmutableArray()\n            );\n        }\n\n        bool IStore.DeleteBlock(BlockHash blockHash) =>\n            _blocks.TryRemove(blockHash, out _);\n\n        bool IStore.ContainsBlock(BlockHash blockHash) =>\n            _blocks.ContainsKey(blockHash);\n\n        void IStore.PutTxExecution(TxExecution txExecution) =>\n            _txExecutions[(txExecution.BlockHash, txExecution.TxId)] = txExecution;\n\n        TxExecution? IStore.GetTxExecution(BlockHash blockHash, TxId txid) =>\n            _txExecutions.TryGetValue((blockHash, txid), out TxExecution? e) ? e : null;\n\n        void IStore.PutTxIdBlockHashIndex(TxId txId, BlockHash blockHash) =>\n            _txBlockIndices.AddOrUpdate(\n                txId,\n                _ => ImmutableHashSet.Create(blockHash),\n                (_, set) => set.Add(blockHash)\n            );\n\n        BlockHash? IStore.GetFirstTxIdBlockHashIndex(TxId txId) =>\n            _txBlockIndices.TryGetValue(txId, out ImmutableHashSet<BlockHash>? set) && set.Any()\n                ? set.First()\n                : (BlockHash?)null;\n\n        IEnumerable<BlockHash> IStore.IterateTxIdBlockHashIndex(TxId txId) =>\n            _txBlockIndices.TryGetValue(txId, out ImmutableHashSet<BlockHash>? set)\n                ? set\n                : Enumerable.Empty<BlockHash>();\n\n        void IStore.DeleteTxIdBlockHashIndex(TxId txId, BlockHash blockHash)\n        {\n            while (_txBlockIndices.TryGetValue(txId, out ImmutableHashSet<BlockHash>? set) &&\n                   set.Contains(blockHash))\n            {\n                var removed = set.Remove(blockHash);\n                _txBlockIndices.TryUpdate(txId, removed, set);\n            }\n        }\n\n        IEnumerable<KeyValuePair<Address, long>> IStore.ListTxNonces(Guid chainId) =>\n            _txNonces.TryGetValue(chainId, out ConcurrentDictionary<Address, long>? dict)\n                ? dict\n                : Enumerable.Empty<KeyValuePair<Address, long>>();\n\n        long IStore.GetTxNonce(Guid chainId, Address address) =>\n            _txNonces.TryGetValue(chainId, out ConcurrentDictionary<Address, long>? dict) &&\n            dict.TryGetValue(address, out long nonce)\n                ? nonce\n                : 0;\n\n        void IStore.IncreaseTxNonce(Guid chainId, Address signer, long delta)\n        {\n            ConcurrentDictionary<Address, long> dict =\n                _txNonces.GetOrAdd(chainId, _ => new ConcurrentDictionary<Address, long>());\n            dict.AddOrUpdate(signer, _ => delta, (_, nonce) => nonce + delta);\n        }\n\n        bool IStore.ContainsTransaction(TxId txId) =>\n            _txs.ContainsKey(txId);\n\n        long IStore.CountBlocks() =>\n            _blocks.Count;\n\n        void IStore.ForkTxNonces(Guid sourceChainId, Guid destinationChainId)\n        {\n            if (_txNonces.TryGetValue(sourceChainId, out ConcurrentDictionary<Address, long>? dict))\n            {\n                _txNonces[destinationChainId] = new ConcurrentDictionary<Address, long>(dict);\n            }\n        }\n\n        void IStore.PruneOutdatedChains(bool noopWithoutCanon)\n        {\n            if (!(_canonicalChainId is { } ccid))\n            {\n                if (noopWithoutCanon)\n                {\n                    return;\n                }\n\n                throw new InvalidOperationException(\"Canonical chain ID is not assigned.\");\n            }\n\n            foreach (Guid id in _indices.Keys.Where(id => !id.Equals(ccid)))\n            {\n                ((IStore)this).DeleteChainId(id);\n            }\n        }\n\n        /// <inheritdoc />\n        public BlockCommit? GetChainBlockCommit(Guid chainId) =>\n            _chainCommits.TryGetValue(chainId, out BlockCommit? commit)\n                ? commit\n                : null;\n\n        /// <inheritdoc />\n        public void PutChainBlockCommit(Guid chainId, BlockCommit blockCommit) =>\n            _chainCommits[chainId] = blockCommit;\n\n        public BlockCommit? GetBlockCommit(BlockHash blockHash) =>\n            _blockCommits.TryGetValue(blockHash, out var commit)\n                ? commit\n                : null;\n\n        /// <inheritdoc />\n        public void PutBlockCommit(BlockCommit blockCommit) =>\n            _blockCommits[blockCommit.BlockHash] = blockCommit;\n\n        /// <inheritdoc />\n        public void DeleteBlockCommit(BlockHash blockHash) =>\n            _blockCommits.TryRemove(blockHash, out _);\n\n        /// <inheritdoc />\n        public IEnumerable<BlockHash> GetBlockCommitHashes()\n            => _blockCommits.Keys;\n\n        /// <inheritdoc/>\n        public IEnumerable<EvidenceId> IteratePendingEvidenceIds()\n            => _pendingEvidence.Keys;\n\n        /// <inheritdoc/>\n        public EvidenceBase? GetPendingEvidence(EvidenceId evidenceId)\n            => _pendingEvidence.TryGetValue(evidenceId, out var evidence)\n            ? evidence\n            : null;\n\n        /// <inheritdoc/>\n        public void PutPendingEvidence(EvidenceBase evidence)\n            => _pendingEvidence[evidence.Id] = evidence;\n\n        /// <inheritdoc/>\n        public void DeletePendingEvidence(EvidenceId evidenceId)\n            => _pendingEvidence.TryRemove(evidenceId, out _);\n\n        /// <inheritdoc/>\n        public bool ContainsPendingEvidence(EvidenceId evidenceId)\n            => _pendingEvidence.ContainsKey(evidenceId);\n\n        /// <inheritdoc/>\n        public EvidenceBase? GetCommittedEvidence(EvidenceId evidenceId)\n            => _committedEvidence.TryGetValue(evidenceId, out var evidence)\n            ? evidence\n            : null;\n\n        /// <inheritdoc/>\n        public void PutCommittedEvidence(EvidenceBase evidence)\n            => _committedEvidence[evidence.Id] = evidence;\n\n        /// <inheritdoc/>\n        public void DeleteCommittedEvidence(EvidenceId evidenceId)\n            => _committedEvidence.TryRemove(evidenceId, out _);\n\n        /// <inheritdoc/>\n        public bool ContainsCommittedEvidence(EvidenceId evidenceId)\n            => _committedEvidence.ContainsKey(evidenceId);\n\n        [StoreLoader(\"memory\")]\n        private static (IStore Store, IStateStore StateStore) Loader(Uri storeUri)\n        {\n            NameValueCollection query = HttpUtility.ParseQueryString(storeUri.Query);\n            var store = new MemoryStore();\n            var stateStore = new TrieStateStore(new MemoryKeyValueStore());\n            return (store, stateStore);\n        }\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Store/StoreExtensions.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Security.Cryptography;\nusing Libplanet.Common;\nusing Libplanet.Crypto;\nusing Libplanet.Types.Blocks;\n\nnamespace Libplanet.Store\n{\n    /// <summary>\n    /// Convenient extension methods for <see cref=\"IStore\"/>.\n    /// </summary>\n    public static class StoreExtensions\n    {\n        /// <summary>\n        /// Makes a store, <paramref name=\"to\"/>, logically (but not necessarily physically)\n        /// identical to another store, <paramref name=\"from\"/>.  As this copies the contents\n        /// of the store, instead of its physicall data, this can be used for migrating\n        /// between two different types of <see cref=\"IStore\"/> implementations.\n        /// </summary>\n        /// <param name=\"from\">The store containing the source contents.</param>\n        /// <param name=\"to\">The store to contain the copied contents. Expected to be empty.</param>\n        /// <exception cref=\"ArgumentException\">Thrown when the store passed through\n        /// <paramref name=\"to\"/> is not empty.</exception>\n        public static void Copy(this IStore from, IStore to)\n        {\n            // TODO: take a IProgress<> so that a caller can be aware the progress of cloning.\n            if (to.ListChainIds().Any())\n            {\n                throw new ArgumentException(\"The destination store has to be empty.\", nameof(to));\n            }\n\n            foreach (Guid chainId in from.ListChainIds().ToArray())\n            {\n                foreach (BlockHash blockHash in from.IterateIndexes(chainId))\n                {\n                    Block block = from.GetBlock(blockHash)\n                        ?? throw new InvalidOperationException(\n                            $\"Could not find block with block hash {blockHash} in store.\");\n\n                    to.PutBlock(block);\n                    to.AppendIndex(chainId, blockHash);\n                }\n\n                foreach (KeyValuePair<Address, long> kv in from.ListTxNonces(chainId))\n                {\n                    to.IncreaseTxNonce(chainId, kv.Key, kv.Value);\n                }\n            }\n\n            if (from.GetCanonicalChainId() is Guid canonId)\n            {\n                to.SetCanonicalChainId(canonId);\n            }\n        }\n\n        /// <summary>\n        /// Gets the <see cref=\"Block.StateRootHash\"/> of the given <paramref name=\"blockHash\"/>.\n        /// </summary>\n        /// <param name=\"store\">The store that blocks are stored.</param>\n        /// <param name=\"blockHash\">The hash of the block to get the state root hash of.\n        /// This can be <see langword=\"null\"/>.</param>\n        /// <returns>The state root hash of the block associated with <paramref name=\"blockHash\"/>\n        /// if found or <see langword=\"null\"/> if <paramref name=\"blockHash\"/> is itself\n        /// <see langword=\"null\"/>.</returns>\n        /// <exception cref=\"ArgumentException\">Thrown when <paramref name=\"blockHash\"/> is\n        /// not <see langword=\"null\"/> but the corresponding block is not found in store.\n        /// </exception>\n        public static HashDigest<SHA256>? GetStateRootHash(\n            this IStore store,\n            BlockHash? blockHash\n        ) =>\n            blockHash is { } hash\n                ? store.GetBlockDigest(hash) is BlockDigest digest\n                    ? digest.StateRootHash\n                    : throw new ArgumentException(\n                        $\"Given {nameof(blockHash)} was not found in storage: {hash}\")\n                : (HashDigest<SHA256>?)null;\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Store/StoreLoader.cs",
    "content": "using System;\n\nnamespace Libplanet.Store\n{\n    /// <summary>\n    /// A function that parses a URI and returns a pair of <see cref=\"IStore\"/> and\n    /// <see cref=\"IStateStore\"/>.\n    /// </summary>\n    /// <param name=\"storeUri\">A URI referring to a store.</param>\n    /// <returns>A pair of loaded <see cref=\"IStore\"/> and <see cref=\"IStateStore\"/> instances.\n    /// </returns>\n    public delegate (IStore Store, IStateStore StateStore) StoreLoader(Uri storeUri);\n}\n"
  },
  {
    "path": "src/Libplanet.Store/StoreLoaderAttribute.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Globalization;\nusing System.IO;\nusing System.Linq;\nusing System.Reflection;\n\nnamespace Libplanet.Store\n{\n    /// <summary>\n    /// Registers a static method as a store loader.  The method must comply with\n    /// <see cref=\"StoreLoader\"/> delegate.\n    /// </summary>\n    /// <example>\n    /// <para>With the below code, <c>SampleStore</c> and <c>SampleStateStore</c>-backed\n    /// <see cref=\"TrieStateStore\"/> can be instantiated from a URI like\n    /// <c>sample:///home/foo/bar?cache=512</c>:</para>\n    /// <code><![CDATA[\n    /// [StoreLoader(\"sample\")]\n    /// private static (IStore Store, IStateStore StateStore) Loader(Uri storeUri)\n    /// {\n    ///     NameValueCollection query = HttpUtility.ParseQueryString(storeUri.Query);\n    ///     int cache = query.GetInt32(\"cache\", 128);\n    ///     var store = new SampleStore(storeUri.LocalPath, cache);\n    ///     var stateStore = new SampleStateStore(storeUri.LocalPath, cache);\n    ///     return (store, stateStore);\n    /// }\n    /// ]]></code>\n    /// </example>\n    [AttributeUsage(AttributeTargets.Method, AllowMultiple = true)]\n    public class StoreLoaderAttribute : Attribute\n    {\n        /// <summary>\n        /// Instniates a new <see cref=\"StoreLoaderAttribute\"/> with the specified\n        /// <paramref name=\"uriScheme\"/>.\n        /// </summary>\n        /// <param name=\"uriScheme\">The URI scheme to associate with the attributed store loader\n        /// method.</param>\n        public StoreLoaderAttribute(string uriScheme)\n        {\n            UriScheme = uriScheme.ToLowerInvariant();\n        }\n\n        /// <summary>\n        /// The URI scheme to associate with the attributed store loader method.\n        /// </summary>\n        public string UriScheme { get; }\n\n        /// <summary>\n        /// Loads a pair of <see cref=\"IStore\"/> and <see cref=\"IStateStore\"/> from the specified\n        /// <paramref name=\"storeUri\"/>.\n        /// </summary>\n        /// <param name=\"storeUri\">A URI referring to a store.</param>\n        /// <returns>A pair of loaded <see cref=\"IStore\"/> and <see cref=\"IStateStore\"/>.</returns>\n        public static (IStore Store, IStateStore StateStore)? LoadStore(Uri storeUri)\n        {\n            const BindingFlags flags =\n                BindingFlags.Public |\n                BindingFlags.NonPublic |\n                BindingFlags.Static |\n                (BindingFlags)0x2000000;  // BindingFlags.DoNotWrapExceptions\n            return ((IStore, IStateStore)?)FindStoreLoader(storeUri.Scheme)?.Invoke(\n                null,\n                flags,\n                null,\n                new object[] { storeUri },\n                CultureInfo.CurrentCulture\n            );\n        }\n\n        /// <summary>\n        /// Lists all registered store loaders.\n        /// </summary>\n        /// <returns>Pairs of registered URI scheme and declaring type.</returns>\n        public static IEnumerable<(string UriScheme, Type DeclaringType)> ListStoreLoaders() =>\n            ListStoreLoaderMethods().SelectMany(pair =>\n                pair.Loader.DeclaringType is { } declType\n                    ? new[] { (pair.UriScheme, declType) }\n                    : Enumerable.Empty<(string, Type)>());\n\n        private static IEnumerable<(string UriScheme, MethodInfo Loader)> ListStoreLoaderMethods()\n        {\n            var paramType = typeof(Uri);\n            var retType = typeof((IStore, IStateStore));\n            return AppDomain.CurrentDomain.GetAssemblies()\n                .SelectMany(a =>\n                {\n                    try\n                    {\n                        return a.GetTypes();\n                    }\n                    catch (Exception e)\n                        when (e is TypeLoadException ||\n                              e is ReflectionTypeLoadException ||\n                              e is FileNotFoundException)\n                    {\n                        return Enumerable.Empty<Type>();\n                    }\n                })\n                .SelectMany(t =>\n                {\n                    try\n                    {\n                        return t.GetMethods(BindingFlags.Static |\n                            BindingFlags.NonPublic | BindingFlags.Public);\n                    }\n                    catch (Exception e)\n                        when (e is TypeLoadException ||\n                              e is ReflectionTypeLoadException ||\n                              e is FileNotFoundException)\n                    {\n                        return Enumerable.Empty<MethodInfo>();\n                    }\n                })\n                .Where(m =>\n                {\n                    try\n                    {\n                        ParameterInfo[] parameters = m.GetParameters();\n                        return parameters.Length == 1 &&\n                               paramType.IsAssignableFrom(parameters[0].ParameterType) &&\n                               retType.IsAssignableFrom(m.ReturnType);\n                    }\n                    catch (Exception e)\n                        when (e is TypeLoadException ||\n                              e is ReflectionTypeLoadException ||\n                              e is FileNotFoundException)\n                    {\n                        return false;\n                    }\n                })\n                .SelectMany(m =>\n                {\n                    return m.GetCustomAttributes<StoreLoaderAttribute>()\n                        .Select(attr => (attr.UriScheme, m));\n                });\n        }\n\n        private static MethodInfo? FindStoreLoader(string uriScheme) =>\n            ListStoreLoaderMethods()\n                .Cast<(string, MethodInfo)?>()\n                .FirstOrDefault(pair =>\n                    pair?.Item1?.Equals(uriScheme, StringComparison.InvariantCulture) == true)\n                ?.Item2;\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Store/Trie/CacheableKeyValueStore.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing LruCacheNet;\n\nnamespace Libplanet.Store.Trie\n{\n    /// <summary>\n    /// The proxy class to cache <see cref=\"IKeyValueStore\"/> operations.\n    /// </summary>\n    public class CacheableKeyValueStore : IKeyValueStore\n    {\n        private readonly IKeyValueStore _keyValueStore;\n        private readonly LruCache<KeyBytes, byte[]> _cache;\n\n        /// <summary>\n        /// Creates a new <see cref=\"CacheableKeyValueStore\"/>.\n        /// </summary>\n        /// <param name=\"keyValueStore\">An <see cref=\"IKeyValueStore\"/> implementation to do real\n        /// operations via <see cref=\"CacheableKeyValueStore\"/>.</param>\n        /// <param name=\"cacheSize\">The capacity of the values cache.</param>\n        public CacheableKeyValueStore(IKeyValueStore keyValueStore, int cacheSize = 100)\n        {\n            _keyValueStore = keyValueStore;\n            _cache = new LruCache<KeyBytes, byte[]>(cacheSize);\n        }\n\n        /// <inheritdoc/>\n        public byte[] Get(in KeyBytes key)\n        {\n            if (_cache.TryGetValue(key, out byte[]? value) && value is { } v)\n            {\n                return v;\n            }\n\n            if (_keyValueStore.Get(key) is { } bytes)\n            {\n                _cache[key] = bytes;\n                return bytes;\n            }\n\n            throw new KeyNotFoundException($\"No such key: ${key}.\");\n        }\n\n        /// <inheritdoc/>\n        public void Set(in KeyBytes key, byte[] value)\n        {\n            _keyValueStore.Set(key, value);\n            _cache[key] = value;\n        }\n\n        public void Set(IDictionary<KeyBytes, byte[]> values)\n        {\n            _keyValueStore.Set(values);\n        }\n\n        /// <inheritdoc/>\n        public void Delete(in KeyBytes key)\n        {\n            _keyValueStore.Delete(key);\n            _cache.Remove(key);\n        }\n\n        /// <inheritdoc cref=\"IKeyValueStore.Delete(IEnumerable{KeyBytes})\"/>\n        public void Delete(IEnumerable<KeyBytes> keys)\n        {\n            _keyValueStore.Delete(keys);\n            foreach (KeyBytes key in keys)\n            {\n                _cache.Remove(key);\n            }\n        }\n\n        /// <inheritdoc/>\n        public bool Exists(in KeyBytes key)\n        {\n            return _cache.ContainsKey(key) || _keyValueStore.Exists(key);\n        }\n\n        /// <inheritdoc/>\n        public IEnumerable<KeyBytes> ListKeys() => _keyValueStore.ListKeys();\n\n        /// <inheritdoc cref=\"IDisposable.Dispose()\"/>\n        public void Dispose()\n        {\n            _keyValueStore?.Dispose();\n        }\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Store/Trie/DefaultKeyValueStore.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.IO;\nusing System.Linq;\nusing Zio;\nusing Zio.FileSystems;\n\nnamespace Libplanet.Store.Trie\n{\n    /// <summary>\n    /// The default built-in <see cref=\"IKeyValueStore\"/> implementation. This stores data in\n    /// the file system or in memory.\n    /// <para><see cref=\"DefaultStore\"/> and <see cref=\"DefaultKeyValueStore\"/>-backed\n    /// <see cref=\"TrieStateStore\"/> can be instantiated from a URI with <c>default+file:</c> scheme\n    /// using <see cref=\"StoreLoaderAttribute.LoadStore(Uri)\"/>, e.g.:</para>\n    /// <list type=\"bullet\">\n    /// <item><description><c>default+file:///var/data/planet/</c></description></item>\n    /// <item><description><c>default+file:///c:/Users/john/AppData/Local/planet/</c></description>\n    /// </item>\n    /// </list>\n    /// <para>The following query string parameters are supported:</para>\n    /// <list type=\"table\">\n    /// <item>\n    /// <term><c>journal</c></term>\n    /// <description><see langword=\"true\"/> (default) or <see langword=\"false\"/>.  Corresponds to\n    /// <see cref=\"DefaultStore(string, bool, int, int, int, int, bool, bool)\"/>'s <c>journal</c>\n    /// parameter.</description>\n    /// </item>\n    /// <item>\n    /// <term><c>index-cache</c></term>\n    /// <description>Corresponds to\n    /// <see cref=\"DefaultStore(string,bool,int,int,int,int,bool,bool)\"/>'s\n    /// <c>indexCacheSize</c> parameter.  50000 by default.</description>\n    /// </item>\n    /// <item>\n    /// <term><c>block-cache</c></term>\n    /// <description>Corresponds to\n    /// <see cref=\"DefaultStore(string,bool,int,int,int,int,bool,bool)\"/>'s\n    /// <c>blockCacheSize</c> parameter.  512 by default.</description>\n    /// </item>\n    /// <item>\n    /// <term><c>tx-cache</c></term>\n    /// <description>Corresponds to\n    /// <see cref=\"DefaultStore(string,bool,int,int,int,int,bool,bool)\"/>'s\n    /// <c>txCacheSize</c> parameter.  1024 by default.</description>\n    /// </item>\n    /// <item>\n    /// <term><c>flush</c></term>\n    /// <description><see langword=\"true\"/> (default) or <see langword=\"false\"/>.  Corresponds to\n    /// <see cref=\"DefaultStore(string, bool, int, int, int, int, bool, bool)\"/>'s <c>flush</c>\n    /// parameter.</description>\n    /// </item>\n    /// <item>\n    /// <term><c>readonly</c></term>\n    /// <description><see langword=\"true\"/> or <see langword=\"false\"/> (default).  Corresponds to\n    /// <see cref=\"DefaultStore(string, bool, int, int, int, int, bool, bool)\"/>'s <c>readOnly</c>\n    /// parameter.</description>\n    /// </item>\n    /// <item>\n    /// <term><c>states-dir</c></term>\n    /// <description>Corresponds to <see cref=\"DefaultKeyValueStore(string)\"/>'s <c>path</c>\n    /// parameter.  It is relative to the URI path, and defaults to <c>states</c>.</description>\n    /// </item>\n    /// </list>\n    /// </summary>\n    public class DefaultKeyValueStore : IKeyValueStore\n    {\n        private readonly IFileSystem _root;\n\n        /// <summary>\n        /// Creates a new <see cref=\"DefaultKeyValueStore\"/>.\n        /// </summary>\n        /// <param name=\"path\">The path of the directory where the storage files will be saved.\n        /// If the path is <see langword=\"null\"/>, the database is created in memory.</param>\n        public DefaultKeyValueStore(string? path)\n        {\n            if (path is null)\n            {\n                _root = new MemoryFileSystem();\n            }\n            else\n            {\n                path = Path.GetFullPath(path);\n                if (!Directory.Exists(path))\n                {\n                    Directory.CreateDirectory(path);\n                }\n\n                var pfs = new PhysicalFileSystem();\n                _root = new SubFileSystem(\n                    pfs,\n                    pfs.ConvertPathFromInternal(path),\n                    owned: true\n                );\n            }\n        }\n\n        /// <inheritdoc/>\n        public byte[] Get(in KeyBytes key)\n        {\n            var path = DataPath(key);\n            return _root.FileExists(path)\n                ? _root.ReadAllBytes(path)\n                : throw new KeyNotFoundException($\"No such key: {key}.\");\n        }\n\n        /// <inheritdoc/>\n        public void Set(in KeyBytes key, byte[] value)\n        {\n            var path = DataPath(key);\n            _root.WriteAllBytes(path, value);\n        }\n\n        public void Set(IDictionary<KeyBytes, byte[]> values)\n        {\n            foreach (KeyValuePair<KeyBytes, byte[]> kv in values)\n            {\n                Set(kv.Key, kv.Value);\n            }\n        }\n\n        /// <inheritdoc/>\n        public void Delete(in KeyBytes key)\n        {\n            var path = DataPath(key);\n            if (_root.FileExists(path))\n            {\n                _root.DeleteFile(path);\n            }\n        }\n\n        /// <inheritdoc cref=\"IKeyValueStore.Delete(IEnumerable{KeyBytes})\"/>\n        public void Delete(IEnumerable<KeyBytes> keys)\n        {\n            foreach (KeyBytes key in keys)\n            {\n                Delete(key);\n            }\n        }\n\n        public void Dispose()\n        {\n            _root.Dispose();\n        }\n\n        /// <inheritdoc/>\n        public bool Exists(in KeyBytes key)\n            => _root.FileExists(DataPath(key));\n\n        /// <inheritdoc/>\n        public IEnumerable<KeyBytes> ListKeys() =>\n            _root.EnumerateFiles(UPath.Root)\n                .Select(path => KeyBytes.FromHex(path.GetName()));\n\n        private UPath DataPath(in KeyBytes key) =>\n            UPath.Root / key.Hex;\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Store/Trie/IKeyValueStore.cs",
    "content": "using System;\nusing System.Collections.Generic;\n\nnamespace Libplanet.Store.Trie\n{\n    /// <summary>\n    /// An interface to access key-value store.\n    /// </summary>\n    public interface IKeyValueStore : IDisposable\n    {\n        /// <summary>\n        /// Gets the value associated with the specified key.\n        /// </summary>\n        /// <param name=\"key\">The key whose value to get.</param>\n        /// <returns>The value associated with the specified key.</returns>\n        /// <exception cref=\"KeyNotFoundException\">Thrown when the key is not found.</exception>\n        public byte[] Get(in KeyBytes key);\n\n        /// <summary>\n        /// Sets the value to the key.  If the key already exists, the value is overwritten.\n        /// </summary>\n        /// <param name=\"key\">The key of the value to set.</param>\n        /// <param name=\"value\">The value to set.</param>\n        public void Set(in KeyBytes key, byte[] value);\n\n        /// <summary>\n        /// Sets all values in the given dictionary.\n        /// </summary>\n        /// <param name=\"values\">A values to set.</param>\n        public void Set(IDictionary<KeyBytes, byte[]> values);\n\n        /// <summary>\n        /// Deletes the given key.  If the key does not exist, nothing happens.\n        /// </summary>\n        /// <param name=\"key\">A key to delete.</param>\n        public void Delete(in KeyBytes key);\n\n        /// <summary>\n        /// Delete multiple <paramref name=\"keys\"/> at once.\n        /// </summary>\n        /// <param name=\"keys\">Keys to delete.  The order of keys does not matter.\n        /// Non-existent keys are ignored.</param>\n        public void Delete(IEnumerable<KeyBytes> keys);\n\n        /// <summary>\n        /// Checks whether the given key exists in the store.\n        /// </summary>\n        /// <param name=\"key\">A key to check.</param>\n        /// <returns><see langword=\"true\"/> if the key exists; otherwise, <see langword=\"false\"/>.\n        /// </returns>\n        public bool Exists(in KeyBytes key);\n\n        /// <summary>\n        /// Lists all keys that have been stored in the storage.\n        /// </summary>\n        /// <returns>All keys in an arbitrary order.  The order might be vary for each call.\n        /// </returns>\n        public IEnumerable<KeyBytes> ListKeys();\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Store/Trie/ITrie.cs",
    "content": "using System.Collections.Generic;\nusing System.Security.Cryptography;\nusing Bencodex.Types;\nusing Libplanet.Common;\nusing Libplanet.Store.Trie.Nodes;\n\nnamespace Libplanet.Store.Trie\n{\n    /// <summary>\n    /// An interface for <see href=\"https://en.wikipedia.org/wiki/Merkle_tree\">Merkle Tree</see>.\n    /// </summary>\n    /// <seealso cref=\"MerkleTrie\"/>\n    public interface ITrie\n    {\n        /// <summary>\n        /// The root of the <see cref=\"ITrie\"/>.  This is <see langword=\"null\"/> if and only if\n        /// the <see cref=\"ITrie\"/> is empty.  That is, this is never a \"hashed node\" of a\n        /// <see langword=\"null\"/> root.\n        /// </summary>\n        /// <seealso cref=\"Hash\"/>\n        INode? Root { get; }\n\n        /// <summary>\n        /// The state root hash of the trie.\n        /// </summary>\n        /// <remarks>\n        /// If <see cref=\"Root\"/> is <see langword=\"null\"/>, this still gives a unique\n        /// <see cref=\"HashDigest{SHA256}\"/> value corresponding to <see langword=\"null\"/>\n        /// that is <em>never recorded</em>.\n        /// </remarks>\n        /// <seealso cref=\"Root\"/>\n        HashDigest<SHA256> Hash { get; }\n\n        /// <summary>\n        /// Whether <see cref=\"Root\"/> is recorded in the store.\n        /// </summary>\n        /// <remarks>A <see cref=\"Root\"/> that is <see langword=\"null\"/> is always considered\n        /// as recorded.\n        /// </remarks>\n        bool Recorded { get; }\n\n        /// <summary>\n        /// Stores the <paramref name=\"value\"/> at the path corresponding to\n        /// given <paramref name=\"key\"/> <em>in memory</em>.\n        /// </summary>\n        /// <param name=\"key\">The unique key to associate with the <paramref name=\"value\"/>.</param>\n        /// <param name=\"value\">The value to store.</param>\n        /// <exception cref=\"System.ArgumentNullException\">Thrown when the given\n        /// <paramref name=\"value\"/> is <see langword=\"null\"/>.</exception>\n        /// <returns>Returns new updated <see cref=\"ITrie\"/>.</returns>\n        /// <remarks>\n        /// This <em>should not</em> actually write anything to storage.\n        /// Stored <paramref name=\"value\"/> is actually written to storage when\n        /// <see cref=\"IStateStore.Commit\"/> is called.\n        /// </remarks>\n        /// <seealso cref=\"IStateStore.Commit\"/>\n        ITrie Set(in KeyBytes key, IValue value);\n\n        /// <summary>\n        /// Removes the value at the path corresponding to given <paramref name=\"key\"/>\n        /// <em>in memory</em>.  If there is no <see cref=\"IValue\"/> at <paramref name=\"key\"/>,\n        /// this does nothing.\n        /// </summary>\n        /// <param name=\"key\">The unique key to associate with the <paramref name=\"value\"/>.</param>\n        /// <returns>Returns new updated <see cref=\"ITrie\"/>.</returns>\n        /// <remarks>\n        /// This <em>should not</em> actually remove anything from storage.\n        /// The removal of the value at the marked path given by <paramref name=\"key\"/> is actually\n        /// recorded to storage when <see cref=\"IStateStore.Commit\"/> is called.\n        /// Regardless, there is actually no removal of any value from storage even when\n        /// <see cref=\"IStateStore.Commit\"/> is called.\n        /// </remarks>\n        /// <seealso cref=\"IStateStore.Commit\"/>\n        ITrie Remove(in KeyBytes key);\n\n        /// <summary>\n        /// Gets the values stored with <paramref name=\"key\"/> in <see cref=\"Set\"/>.\n        /// </summary>\n        /// <param name=\"key\">The key used in <see cref=\"Set\"/> to store a value.</param>\n        /// <returns>The value associated to the specified <paramref name=\"key\"/>.  Absent\n        /// value is represented as <see langword=\"null\"/>.</returns>\n        public IValue? Get(KeyBytes key);\n\n        /// <summary>\n        /// Gets the values stored with <paramref name=\"keys\"/> in <see cref=\"Set\"/>.\n        /// </summary>\n        /// <param name=\"keys\">The keys used in <see cref=\"Set\"/> to store a value.</param>\n        /// <returns>The values associated to the specified <paramref name=\"keys\"/>.  The associated\n        /// values are ordered in the same way to the corresponding <paramref name=\"keys\"/>.  Absent\n        /// values are represented as <see langword=\"null\"/>.</returns>\n        IReadOnlyList<IValue?> Get(IReadOnlyList<KeyBytes> keys);\n\n        /// <summary>\n        /// Gets the first node encountered at <paramref name=\"nibbles\"/> when traversing down\n        /// from <see cref=\"Root\"/>.\n        /// </summary>\n        /// <param name=\"nibbles\">The path to check.</param>\n        /// <returns>A node at <paramref name=\"nibbles\"/>, if any.\n        /// Otherwise <see langword=\"null\"/>.</returns>\n        /// <exception cref=\"InvalidTrieNodeException\">Thrown when an unknown type\n        /// of <see cref=\"INode\"/> is encountered while traversing to the given path.</exception>\n        /// <remarks>\n        /// <para>\n        /// There may be more than one <see cref=\"INode\"/> at <paramref name=\"nibbles\"/>.\n        /// For instance, a <see cref=\"FullNode\"/>, a <see cref=\"ValueNode\"/> as the value of the\n        /// aforementioned <see cref=\"FullNode\"/>, and up to two additional <see cref=\"HashNode\"/>s\n        /// is possible.\n        /// </para>\n        /// <para>\n        /// As such, for two equivalent <see cref=\"ITrie\"/>s, <see cref=\"Trie\"/>s that\n        /// <em>would have the same committed <see cref=\"Hash\"/>es</em>, this may return different\n        /// types of <see cref=\"INode\"/> depending on the actual underlying \"structure\".\n        /// However, returned <see cref=\"INode\"/>s for such <see cref=\"ITrie\"/>s are\n        /// equivalent as sub-<see cref=\"ITrie\"/>s.\n        /// </para>\n        /// </remarks>\n        INode? GetNode(Nibbles nibbles);\n\n        /// <summary>\n        /// Iterates and every stored <see cref=\"IValue\"/> along with its respective\n        /// path in <see cref=\"KeyBytes\"/>.\n        /// </summary>\n        /// <returns>An <see cref=\"IEnumerable{T}\"/> of all <see cref=\"IValue\"/>s\n        /// in no particular order.</returns>\n        /// <remarks>\n        /// This is a very heavy operation.\n        /// </remarks>\n        IEnumerable<(KeyBytes Path, IValue Value)> IterateValues();\n\n        /// <summary>\n        /// Iterates and every stored <see cref=\"INode\"/> along with its respective\n        /// path in <see cref=\"Nibbles\"/>.\n        /// </summary>\n        /// <returns>An <see cref=\"IEnumerable{T}\"/> of all <see cref=\"INode\"/>s\n        /// in no particular order.</returns>\n        /// <remarks>\n        /// This is a very heavy operation.\n        /// </remarks>\n        IEnumerable<(Nibbles Path, INode Node)> IterateNodes();\n\n        /// <summary>\n        /// Lists every non-<see langword=\"null\"/> <see cref=\"IValue\"/> that is different\n        /// from the one stored in <paramref name=\"other\"/> given any <see cref=\"KeyBytes\"/> path.\n        /// </summary>\n        /// <param name=\"other\">The other <see cref=\"MerkleTrie\"/> to compare to.</param>\n        /// <returns>A list of tuples where each tuple consists of the path where\n        /// the difference occurred, the \"old\" value from <paramref name=\"other\"/> and\n        /// the current \"new\" value.</returns>\n        /// <exception cref=\"InvalidTrieNodeException\">Thrown when the method fails\n        /// to traverse the <see cref=\"ITrie\"/>.</exception>\n        /// <remarks>\n        /// This operation has the following properties:\n        /// <list type=\"bullet\">\n        ///     <item><description>\n        ///         This operation is non-symmetric.  That is, in general,\n        ///         <c>trieA.Diff(trieB)</c> and <c>trieB.Diff(trieA)</c> are not the same.\n        ///     </description></item>\n        ///     <item><description>\n        ///         Values existing in <paramref name=\"other\"/> but not in the source instance,\n        ///         considered as <see langword=\"null\"/> in the source, are not included in the\n        ///         result.\n        ///     </description></item>\n        /// </list>\n        /// </remarks>\n        IEnumerable<(KeyBytes Path, IValue? TargetValue, IValue SourceValue)> Diff(ITrie other);\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Store/Trie/InvalidTrieNodeException.cs",
    "content": "using System;\n\nnamespace Libplanet.Store.Trie\n{\n    public class InvalidTrieNodeException : Exception\n    {\n        public InvalidTrieNodeException(string message, Exception innerException)\n            : base(message, innerException)\n        {\n        }\n\n        public InvalidTrieNodeException(string message)\n            : base(message)\n        {\n        }\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Store/Trie/KeyBytes.cs",
    "content": "using System;\nusing System.Collections.Immutable;\nusing System.Linq;\nusing System.Runtime.CompilerServices;\nusing System.Text;\nusing Libplanet.Common;\n\nnamespace Libplanet.Store.Trie\n{\n    /// <summary>\n    /// Wraps a byte array and provides equality comparison and hash code calculation.  Designed\n    /// to be used as a key in dictionaries.\n    /// </summary>\n    public readonly struct KeyBytes : IEquatable<KeyBytes>\n    {\n        /// <summary>\n        /// The default <see cref=\"System.Text.Encoding\"/>, which is <see cref=\"Encoding.UTF8\"/>,\n        /// to use when creating an instance from a <see langword=\"string\"/>.\n        /// </summary>\n        public static readonly Encoding Encoding = Encoding.UTF8;\n\n        private readonly ImmutableArray<byte> _byteArray;\n\n        /// <summary>\n        /// Creates a new <see cref=\"KeyBytes\"/> instance from the given byte array.\n        /// </summary>\n        /// <param name=\"bytes\">A mutable byte array to wrap.</param>\n        public KeyBytes(params byte[] bytes)\n            : this(ImmutableArray.Create(bytes))\n        {\n        }\n\n        /// <summary>\n        /// Creates a new <see cref=\"KeyBytes\"/> instance from the given byte array.\n        /// </summary>\n        /// <param name=\"bytes\">An immutable byte array to wrap.</param>\n        public KeyBytes(in ImmutableArray<byte> bytes)\n        {\n            _byteArray = bytes;\n        }\n\n        /// <summary>\n        /// Creates a new <seealso cref=\"KeyBytes\"/> instance from given\n        /// <paramref name=\"str\"/> with <see cref=\"Encoding\"/>.\n        /// </summary>\n        /// <param name=\"str\">The key <see langword=\"string\"/> to encode into bytes.</param>\n        public KeyBytes(string str)\n            : this(str, Encoding)\n        {\n        }\n\n        /// <summary>\n        /// Creates a new <seealso cref=\"KeyBytes\"/> instance from given <paramref name=\"str\"/>\n        /// with <paramref name=\"encoding\"/>.\n        /// </summary>\n        /// <param name=\"str\">The key <see langword=\"string\"/> to encode into bytes.</param>\n        /// <param name=\"encoding\">The <see cref=\"System.Text.Encoding\"/> to be used for\n        /// <paramref name=\"str\"/>.</param>\n        private KeyBytes(string str, Encoding encoding)\n        {\n            byte[] neverReusedBuffer = encoding.GetBytes(str);\n            ImmutableArray<byte> movedImmutable =\n                Unsafe.As<byte[], ImmutableArray<byte>>(ref neverReusedBuffer);\n            _byteArray = movedImmutable;\n        }\n\n        /// <summary>\n        /// The length of the byte array.\n        /// </summary>\n        public int Length => _byteArray.IsDefault ? 0 : ByteArray.Length;\n\n        /// <summary>\n        /// The immutable array of bytes.\n        /// </summary>\n        public ImmutableArray<byte> ByteArray => _byteArray.IsDefault\n            ? ImmutableArray<byte>.Empty\n            : _byteArray;\n\n        /// <summary>\n        /// The hexadecimal string representation of the byte array.\n        /// </summary>\n        public string Hex => _byteArray.IsDefaultOrEmpty\n            ? string.Empty\n            : ByteUtil.Hex(_byteArray);\n\n        /// <summary>\n        /// Compares two <see cref=\"KeyBytes\"/> values.\n        /// </summary>\n        /// <param name=\"left\">An operand.</param>\n        /// <param name=\"right\">Another operand.</param>\n        /// <returns><see langword=\"true\"/> if two values equal; otherwise <see langword=\"false\"/>.\n        /// </returns>\n        public static bool operator ==(KeyBytes left, KeyBytes right) => left.Equals(right);\n\n        /// <summary>\n        /// Compares two <see cref=\"KeyBytes\"/> values.\n        /// </summary>\n        /// <param name=\"left\">An operand.</param>\n        /// <param name=\"right\">Another operand.</param>\n        /// <returns><see langword=\"false\"/> if two values equal; otherwise <see langword=\"true\"/>.\n        /// </returns>\n        public static bool operator !=(KeyBytes left, KeyBytes right) => !left.Equals(right);\n\n        /// <summary>\n        /// Parses the given hexadecimal string as bytes and returns a new <see cref=\"KeyBytes\"/>\n        /// instance.\n        /// </summary>\n        /// <param name=\"hex\">A hexadecimal string which encodes bytes.</param>\n        /// <returns>A new <see cref=\"KeyBytes\"/> instance.</returns>\n        /// <exception cref=\"ArgumentNullException\">Thrown when the given <paramref name=\"hex\"/>\n        /// string is <see langword=\"null\"/>.</exception>\n        /// <exception cref=\"ArgumentOutOfRangeException\">Thrown when the length of the given\n        /// <paramref name=\"hex\"/> string is an odd number.</exception>\n        /// <exception cref=\"FormatException\">Thrown when the given <paramref name=\"hex\"/> string is\n        /// not a valid hexadecimal string.</exception>\n        public static KeyBytes FromHex(string hex) =>\n            new KeyBytes(ByteUtil.ParseHexToImmutable(hex));\n\n        /// <summary>\n        /// Converts to a mutable byte array.\n        /// </summary>\n        /// <returns>A new copy of mutable byte array.</returns>\n        public byte[] ToByteArray() => ByteArray.IsDefault\n            ? Array.Empty<byte>()\n            : ByteArray.ToArray();\n\n        /// <inheritdoc cref=\"IEquatable{T}.Equals(T)\"/>\n        public bool Equals(KeyBytes other) => ByteArray.SequenceEqual(other.ByteArray);\n\n        /// <inheritdoc cref=\"object.Equals(object?)\"/>\n        public override bool Equals(object? obj) => obj is KeyBytes other && Equals(other);\n\n        /// <inheritdoc cref=\"object.GetHashCode()\"/>\n        public override int GetHashCode()\n        {\n            int hash = 17;\n            if (!_byteArray.IsDefaultOrEmpty)\n            {\n                foreach (byte b in _byteArray)\n                {\n                    hash = unchecked(hash * (31 + b));\n                }\n            }\n\n            return hash;\n        }\n\n        /// <inheritdoc cref=\"object.ToString()\"/>\n        public override string ToString()\n        {\n            string hex = Length > 0 ? $\" {ByteUtil.Hex(_byteArray)}\" : string.Empty;\n            return $\"{nameof(KeyBytes)} ({Length} B){hex}\";\n        }\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Store/Trie/MemoryKeyValueStore.cs",
    "content": "using System;\nusing System.Collections.Concurrent;\nusing System.Collections.Generic;\n\nnamespace Libplanet.Store.Trie\n{\n    /// <summary>\n    /// Volatile in-memory key-value store.\n    /// <para>It is useful for storing temporal small chains, e.g., fixtures for unit tests of\n    /// game logic.</para>\n    /// <para><see cref=\"MemoryStore\"/> and <see cref=\"MemoryKeyValueStore\"/>-backed\n    /// <see cref=\"TrieStateStore\"/> can be instantiated from a URI with <c>memory:</c> scheme\n    /// using <see cref=\"StoreLoaderAttribute.LoadStore(Uri)\"/>, e.g.:</para>\n    /// <list type=\"bullet\">\n    /// <item><description><c>memory:</c></description></item>\n    /// </list>\n    /// </summary>\n    public sealed class MemoryKeyValueStore : IKeyValueStore\n    {\n        private readonly ConcurrentDictionary<KeyBytes, byte[]> _dictionary =\n            new ConcurrentDictionary<KeyBytes, byte[]>();\n\n        /// <inheritdoc/>\n        byte[] IKeyValueStore.Get(in KeyBytes key) =>\n            _dictionary[key];\n\n        /// <inheritdoc/>\n        void IKeyValueStore.Set(in KeyBytes key, byte[] value) =>\n            _dictionary[key] = value;\n\n        /// <inheritdoc cref=\"IKeyValueStore.Set(IDictionary{KeyBytes, byte[]})\"/>\n        void IKeyValueStore.Set(IDictionary<KeyBytes, byte[]> values)\n        {\n            foreach (KeyValuePair<KeyBytes, byte[]> kv in values)\n            {\n                _dictionary[kv.Key] = kv.Value;\n            }\n        }\n\n        /// <inheritdoc/>\n        void IKeyValueStore.Delete(in KeyBytes key) =>\n            _dictionary.TryRemove(key, out _);\n\n        /// <inheritdoc cref=\"IKeyValueStore.Delete(IEnumerable{KeyBytes})\"/>\n        public void Delete(IEnumerable<KeyBytes> keys)\n        {\n            foreach (KeyBytes key in keys)\n            {\n                _dictionary.TryRemove(key, out _);\n            }\n        }\n\n        /// <inheritdoc/>\n        bool IKeyValueStore.Exists(in KeyBytes key) =>\n            _dictionary.ContainsKey(key);\n\n        /// <inheritdoc cref=\"IDisposable.Dispose()\"/>\n        void IDisposable.Dispose()\n        {\n            // Method intentionally left empty.\n        }\n\n        IEnumerable<KeyBytes> IKeyValueStore.ListKeys() =>\n            _dictionary.Keys;\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Store/Trie/MerkleTrie.Diff.cs",
    "content": "using System.Collections.Generic;\nusing System.Collections.Immutable;\nusing System.Linq;\nusing Bencodex.Types;\nusing Libplanet.Store.Trie.Nodes;\n\nnamespace Libplanet.Store.Trie\n{\n    public partial class MerkleTrie : ITrie\n    {\n        /// <inheritdoc cref=\"ITrie.Diff\"/>\n        public IEnumerable<(KeyBytes Path, IValue? TargetValue, IValue SourceValue)>\n            Diff(ITrie other)\n        {\n            if (Root is null)\n            {\n                yield break;\n            }\n\n            var queue = new Queue<(INode, Nibbles)>();\n            queue.Enqueue((Root, new Nibbles(ImmutableArray<byte>.Empty)));\n\n            while (queue.Count > 0)\n            {\n                (INode node, Nibbles path) = queue.Dequeue();\n                INode? target = other.GetNode(path);\n\n                if (target is { } targetNode)\n                {\n                    switch (node)\n                    {\n                        case HashNode hn:\n                            // NOTE: If source node is a hashed node, check if the target node\n                            // is also a hashed node and is the same.  Otherwise queue\n                            // the unhashed version.\n                            if (targetNode is HashNode targetHashNode && hn.Equals(targetHashNode))\n                            {\n                                continue;\n                            }\n                            else\n                            {\n                                queue.Enqueue((UnhashNode(hn), path));\n                                continue;\n                            }\n\n                        default:\n                            // Try comparing unhashed version of both.\n                            switch (node)\n                            {\n                                case ValueNode valueNode:\n                                    IValue? targetValue = ValueAtNodeRoot(targetNode);\n                                    if (targetValue is { } tv && valueNode.Value.Equals(tv))\n                                    {\n                                        continue;\n                                    }\n                                    else\n                                    {\n                                        yield return\n                                            (path.ToKeyBytes(), targetValue, valueNode.Value);\n                                        continue;\n                                    }\n\n                                case ShortNode shortNode:\n                                    queue.Enqueue((shortNode.Value, path.AddRange(shortNode.Key)));\n                                    continue;\n\n                                case FullNode fullNode:\n                                    foreach (\n                                        int i in Enumerable.Range(0, FullNode.ChildrenCount - 1))\n                                    {\n                                        if (fullNode.Children[i] is { } child)\n                                        {\n                                            queue.Enqueue((child, path.Add((byte)i)));\n                                        }\n                                    }\n\n                                    if (fullNode.Children[FullNode.ChildrenCount - 1] is { } value)\n                                    {\n                                        queue.Enqueue((value, path));\n                                    }\n\n                                    continue;\n\n                                default:\n                                    throw new InvalidTrieNodeException(\n                                        $\"Unknown node type encountered at {path.Hex}: \" +\n                                        $\"{node.GetType()}\");\n                            }\n                    }\n                }\n                else\n                {\n                    // NOTE: Target node being null at given path does not mean\n                    // there will not be a node at the end of an extended path.\n                    // Hence, we need to iterate rest of the source node.\n                    switch (node)\n                    {\n                        case HashNode hashNode:\n                            queue.Enqueue((UnhashNode(hashNode), path));\n                            continue;\n\n                        case ValueNode valueNode:\n                            yield return (path.ToKeyBytes(), null, valueNode.Value);\n                            continue;\n\n                        case ShortNode shortNode:\n                            queue.Enqueue((shortNode.Value, path.AddRange(shortNode.Key)));\n                            continue;\n\n                        case FullNode fullNode:\n                            foreach (int i in Enumerable.Range(0, FullNode.ChildrenCount - 1))\n                            {\n                                if (fullNode.Children[i] is { } c)\n                                {\n                                    queue.Enqueue((c, path.Add((byte)i)));\n                                }\n                            }\n\n                            if (fullNode.Children[FullNode.ChildrenCount - 1] is { } v)\n                            {\n                                queue.Enqueue((v, path));\n                            }\n\n                            continue;\n\n                        default:\n                            throw new InvalidTrieNodeException(\n                                $\"Unknown node type encountered at {path.Hex}: {node.GetType()}\");\n                    }\n                }\n            }\n        }\n\n        /// <summary>\n        /// Returns the value at the root of <paramref name=\"node\"/>.\n        /// Note that only <see cref=\"ValueNode\"/>s and <see cref=\"FullNode\"/>s are allowed to\n        /// have a value at its root.  If <paramref name=\"node\"/> is a <see cref=\"HashNode\"/>,\n        /// its unhashed version is checked.\n        /// </summary>\n        /// <param name=\"node\">The <see cref=\"INode\"/> to check.</param>\n        /// <returns>The value associated with the root of <paramref name=\"node\"/>.\n        /// If no such value exists, then <see langword=\"null\"/>.</returns>\n        private IValue? ValueAtNodeRoot(INode node)\n        {\n            switch (node)\n            {\n                case HashNode hashNode:\n                    return ValueAtNodeRoot(UnhashNode(hashNode));\n                case ValueNode valueNode:\n                    return valueNode.Value;\n                case FullNode fullNode:\n                    return fullNode.Value is ValueNode vn\n                        ? vn.Value\n                        : null;\n                default:\n                    return null;\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Store/Trie/MerkleTrie.Insert.cs",
    "content": "using System;\nusing Libplanet.Store.Trie.Nodes;\n\nnamespace Libplanet.Store.Trie\n{\n    public partial class MerkleTrie\n    {\n        private INode Insert(\n            INode? node,\n            in PathCursor cursor,\n            ValueNode value,\n            bool allowNull)\n        {\n            switch (node)\n            {\n                case HashNode hashNode:\n                    return InsertToHashNode(hashNode, cursor, value, allowNull);\n\n                case null:\n                    return allowNull\n                        ? InsertToNullNode(cursor, value)\n                        : throw new NullReferenceException(\n                            $\"Given {nameof(node)} is not allowed to be null\");\n\n                case ValueNode valueNode:\n                    return InsertToValueNode(valueNode, cursor, value);\n\n                case ShortNode shortNode:\n                    return InsertToShortNode(shortNode, cursor, value);\n\n                case FullNode fullNode:\n                    return InsertToFullNode(fullNode, cursor, value);\n\n                default:\n                    throw new InvalidTrieNodeException(\n                        $\"Unsupported node value: {node.ToBencodex().Inspect()}\");\n            }\n        }\n\n        // Note: Should not be called on short node or full node's value.\n        private INode InsertToNullNode(PathCursor cursor, ValueNode value)\n        {\n            if (cursor.RemainingAnyNibbles)\n            {\n                return new ShortNode(cursor.GetRemainingNibbles(), value);\n            }\n            else\n            {\n                return value;\n            }\n        }\n\n        // Note: Should not be called on full node's value.\n        private INode InsertToValueNode(ValueNode valueNode, PathCursor cursor, ValueNode value)\n        {\n            if (cursor.RemainingAnyNibbles)\n            {\n                return FullNode.Empty\n                    .SetChild(FullNode.ChildrenCount - 1, valueNode)\n                    .SetChild(cursor.NextNibble, InsertToNullNode(cursor.Next(1), value));\n            }\n            else\n            {\n                // Overwrite existing value\n                return value;\n            }\n        }\n\n        private INode InsertToShortNode(ShortNode shortNode, in PathCursor cursor, ValueNode value)\n        {\n            // Two cases are possible:\n            // - common prefix length == short node's key length: insert directly into short node's\n            //   value\n            // - common prefix length < short node's key length: branch off and handle remaining\n            //   short node and remaining path\n            //   - in this case, a full node is created at current cursor + common prefix nibbles\n            Nibbles commonNibbles = cursor.GetCommonStartingNibbles(shortNode.Key);\n            PathCursor nextCursor = cursor.Next(commonNibbles.Length);\n\n            if (commonNibbles.Length == shortNode.Key.Length)\n            {\n                return new ShortNode(\n                    shortNode.Key,\n                    Insert(shortNode.Value, nextCursor, value, false));\n            }\n            else\n            {\n                FullNode fullNode = FullNode.Empty;\n                byte newChildIndex = shortNode.Key[commonNibbles.Length];\n                Nibbles newShortNodeKey = shortNode.Key.Skip(commonNibbles.Length + 1);\n\n                // Handles modified short node.\n                fullNode = newShortNodeKey.Length > 0\n                    ? fullNode.SetChild(\n                        newChildIndex,\n                        new ShortNode(newShortNodeKey, shortNode.Value))\n                    : fullNode.SetChild(newChildIndex, shortNode.Value);\n\n                // Handles value node.\n                // Assumes next cursor nibble (including non-remaining case)\n                // does not conflict with short node above.\n                fullNode = nextCursor.RemainingNibbleLength > 0\n                    ? fullNode.SetChild(\n                        nextCursor.NextNibble,\n                        InsertToNullNode(nextCursor.Next(1), value))\n                    : fullNode.SetChild(\n                        FullNode.ChildrenCount - 1,\n                        value);\n\n                // Full node is created at the branching point and may not be at the original root.\n                if (commonNibbles.Length == 0)\n                {\n                    return fullNode;\n                }\n                else\n                {\n                    return new ShortNode(\n                        commonNibbles,\n                        fullNode);\n                }\n            }\n        }\n\n        private INode InsertToFullNode(FullNode fullNode, PathCursor cursor, ValueNode value)\n        {\n            if (cursor.RemainingAnyNibbles)\n            {\n                byte nextNibble = cursor.NextNibble;\n                return fullNode.SetChild(\n                    nextNibble,\n                    Insert(fullNode.Children[nextNibble], cursor.Next(1), value, true));\n            }\n            else\n            {\n                // Overwrite existing value\n                return fullNode.SetChild(FullNode.ChildrenCount - 1, value);\n            }\n        }\n\n        private INode InsertToHashNode(\n            HashNode hashNode,\n            PathCursor cursor,\n            ValueNode value,\n            bool allowNull)\n        {\n            INode unhashedNode = UnhashNode(hashNode);\n            return Insert(unhashedNode, cursor, value, allowNull);\n        }\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Store/Trie/MerkleTrie.Path.cs",
    "content": "using Bencodex.Types;\nusing Libplanet.Store.Trie.Nodes;\n\nnamespace Libplanet.Store.Trie\n{\n    public partial class MerkleTrie\n    {\n        private IValue? ResolveToValue(INode? node, in PathCursor cursor) =>\n            node switch\n            {\n                null => null,\n                ValueNode valueNode => !cursor.RemainingAnyNibbles\n                    ? valueNode.Value\n                    : null,\n                ShortNode shortNode => cursor.RemainingNibblesStartWith(shortNode.Key)\n                    ? ResolveToValue(shortNode.Value, cursor.Next(shortNode.Key.Length))\n                    : null,\n                FullNode fullNode => cursor.RemainingAnyNibbles\n                    ? ResolveToValue(\n                        fullNode.Children[cursor.NextNibble],\n                        cursor.Next(1))\n                    : ResolveToValue(\n                        fullNode.Value,\n                        cursor),\n                HashNode hashNode => ResolveToValue(UnhashNode(hashNode), cursor),\n                _ => throw new InvalidTrieNodeException(\n                    $\"Invalid node value: {node.ToBencodex().Inspect()}\"),\n            };\n\n        private INode? ResolveToNode(INode? node, in PathCursor cursor)\n        {\n            if (cursor.RemainingAnyNibbles)\n            {\n                switch (node)\n                {\n                    case null:\n                    case ValueNode _:\n                        return null;\n                    case ShortNode shortNode:\n                        return cursor.RemainingNibblesStartWith(shortNode.Key)\n                            ? ResolveToNode(shortNode.Value, cursor.Next(shortNode.Key.Length))\n                            : null;\n                    case FullNode fullNode:\n                        return ResolveToNode(fullNode.Children[cursor.NextNibble], cursor.Next(1));\n                    case HashNode hashNode:\n                        return ResolveToNode(UnhashNode(hashNode), cursor);\n                    default:\n                        throw new InvalidTrieNodeException(\n                            $\"An unknown type of node was encountered \" +\n                            $\"at {cursor.GetConsumedNibbles().Hex}: {node.GetType()}\");\n                }\n            }\n            else\n            {\n                return node;\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Store/Trie/MerkleTrie.Proof.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Collections.Immutable;\nusing System.Security.Cryptography;\nusing Bencodex.Types;\nusing Libplanet.Common;\nusing Libplanet.Store.Trie.Nodes;\n\nnamespace Libplanet.Store.Trie\n{\n    public partial class MerkleTrie\n    {\n        /// <summary>\n        /// Checks whether given <paramref name=\"proof\"/> is a valid proof\n        /// for given <paramref name=\"key\"/> and <paramref name=\"value\"/> against\n        /// given <paramref name=\"stateRootHash\"/>.\n        /// </summary>\n        /// <param name=\"stateRootHash\">A known <see cref=\"ITrie.Hash\"/> of a <see cref=\"ITrie\"/>\n        /// to check <paramref name=\"proof\"/> against.</param>\n        /// <param name=\"proof\">An <see cref=\"IReadOnlyList{T}\"/> of <see cref=\"INode\"/>s\n        /// that acts as a proof of existence for <paramref name=\"value\"/>\n        /// at <paramref name=\"key\"/>.</param>\n        /// <param name=\"key\">The path in <see cref=\"KeyBytes\"/> to validate.</param>\n        /// <param name=\"value\">The <see cref=\"IValue\"/> to search.</param>\n        /// <returns><see langword=\"true\"/> if <paramref name=\"proof\"/> is valid,\n        /// <see langword=\"false\"/> otherwise.</returns>\n        public static bool ValidateProof(\n            HashDigest<SHA256> stateRootHash,\n            IReadOnlyList<INode> proof,\n            KeyBytes key,\n            IValue value)\n        {\n            HashDigest<SHA256> targetHash = stateRootHash;\n            PathCursor cursor = new PathCursor(key);\n            for (int i = 0; i < proof.Count; i++)\n            {\n                INode proofNode = proof[i];\n                bool first = i == 0;\n                bool last = i == proof.Count - 1;\n\n                // A proof node cannot be a HashNode.\n                if (proofNode is HashNode)\n                {\n                    return false;\n                }\n\n                if (!CheckProofNodeHash(targetHash, proofNode, first))\n                {\n                    return false;\n                }\n\n                var resolved = ResolveToNextCandidateNode(proofNode, cursor);\n                if (resolved is { } r)\n                {\n                    switch (r.NextNode)\n                    {\n                        case HashNode hashNode:\n                            if (!last)\n                            {\n                                cursor = r.NextCursor;\n                                targetHash = hashNode.HashDigest;\n                                continue;\n                            }\n                            else\n                            {\n                                return false;\n                            }\n\n                        case ValueNode valueNode:\n                            if (last)\n                            {\n                                return r.NextCursor.Offset == r.NextCursor.Length &&\n                                    valueNode.Value.Equals(value);\n                            }\n                            else\n                            {\n                                return false;\n                            }\n\n                        default:\n                            // NOTE: Should never be reached. Non-null resolved next node is\n                            // expected to be either HashNode or ValueNode.\n                            return false;\n                    }\n                }\n                else\n                {\n                    return false;\n                }\n            }\n\n            return false;\n        }\n\n        /// <summary>\n        /// Generates a proof of existence for <paramref name=\"value\"/> at <paramref name=\"key\"/>.\n        /// </summary>\n        /// <param name=\"key\">The path in <see cref=\"KeyBytes\"/> to search.</param>\n        /// <param name=\"value\">The <see cref=\"IValue\"/> to search.</param>\n        /// <returns>An <see cref=\"IReadOnlyList{T}\"/> of <see cref=\"INode\"/>s\n        /// that can prove <paramref name=\"key\"/> and <paramref name=\"value\"/> pair exists or not\n        /// given an <see cref=\"ITrie\"/>'s <see cref=\"ITrie.Hash\"/>.\n        /// </returns>\n        /// <exception cref=\"InvalidOperationException\">Thrown when either\n        /// <see cref=\"Recorded\"/> is <see langword=\"false\"/> or\n        /// <see cref=\"Root\"/> is <see langword=\"null\"/>.</exception>\n        /// <exception cref=\"ArgumentException\">Thrown when the given <paramref name=\"key\"/>\n        /// and <paramref name=\"value\"/> pair is invalid, i.e. not a key value pair\n        /// found in this <see cref=\"ITrie\"/>.</exception>\n        /// <remarks>\n        /// In order to generate a valid proof, both a valid <paramref name=\"key\"/> and\n        /// a valid <paramref name=\"value\"/> must be known beforehand.\n        /// </remarks>\n        public IReadOnlyList<INode> GenerateProof(KeyBytes key, IValue value)\n        {\n            if (!Recorded)\n            {\n                throw new InvalidOperationException(\n                    $\"A proof can only be retrieved from a recorded {nameof(ITrie)}\");\n            }\n\n            INode root = Root ??\n                throw new InvalidOperationException(\n                    $\"A proof can only be retrieved from a non-null {nameof(Root)}\");\n\n            // NOTE: Should never be thrown. A recorded non-null root must always be a HashNode.\n            INode hashNode = root is HashNode h\n                ? h\n                : throw new InvalidOperationException(\n                    $\"Encountered an unexpected node type {root.GetType()}\");\n\n            List<INode> proof = new List<INode>();\n            PathCursor cursor = new PathCursor(key);\n\n            while (hashNode is HashNode currentHashNode)\n            {\n                INode unhashedNode = UnhashNode(currentHashNode);\n                proof.Add(unhashedNode);\n                var resolved = ResolveToNextCandidateNode(unhashedNode, cursor);\n\n                if (resolved is { } r)\n                {\n                    switch (r.NextNode)\n                    {\n                        case HashNode _:\n                            hashNode = r.NextNode;\n                            cursor = r.NextCursor;\n                            continue;\n\n                        case ValueNode nextValueNode:\n                            if (r.NextCursor.Offset == r.NextCursor.Length)\n                            {\n                                return nextValueNode.Value.Equals(value)\n                                    ? proof.ToImmutableList()\n                                    : throw new ArgumentException(\n                                        $\"Given value {value} does not match \" +\n                                        $\"the actual value {nextValueNode.Value}\" +\n                                        $\"found at given key {key}\",\n                                        nameof(value));\n                            }\n                            else\n                            {\n                                throw new ArgumentException(\n                                    $\"Given key {key} could not be fully resolved due to \" +\n                                    $\"prematurely encountering a {nameof(ValueNode)}\",\n                                    nameof(key));\n                            }\n\n                        default:\n                            // NOTE: Should never be thrown. Non-null resolved next node is\n                            // expected to be either HashNode or ValueNode.\n                            throw new ArgumentException(\"Failed to get a proof.\");\n                    }\n                }\n                else\n                {\n                    throw new ArgumentException(\n                        $\"Given key {key} could not be properly resolved.\",\n                        nameof(key));\n                }\n            }\n\n            // NOTE: Should never be thrown.\n            throw new ArgumentException(\"Something went wrong.\");\n        }\n\n        private static bool CheckProofNodeHash(\n            HashDigest<SHA256> targetHash,\n            INode proofNode,\n            bool first)\n        {\n            IValue bencoded = proofNode.ToBencodex();\n            byte[] bytes = _codec.Encode(bencoded);\n\n            // Only the first node in the proof is allowed to be have an encoding\n            // length less than SHA256's size.\n            if (!first && bytes.Length <= HashDigest<SHA256>.Size)\n            {\n                return false;\n            }\n\n            return targetHash.Equals(HashDigest<SHA256>.DeriveFrom(bytes));\n        }\n\n        private static (INode NextNode, PathCursor NextCursor)? ResolveToNextCandidateNode(\n            INode node,\n            PathCursor cursor)\n        {\n            switch (node)\n            {\n                // This operates under an assumption that the initial non-recursive\n                // call to this method will not be called with a HashNode.\n                case HashNode hashNode:\n                    return (hashNode, cursor);\n\n                case ValueNode valueNode:\n                    return (valueNode, cursor);\n\n                case ShortNode shortNode:\n                    if (cursor.RemainingNibblesStartWith(shortNode.Key))\n                    {\n                        return ResolveToNextCandidateNode(\n                            shortNode.Value, cursor.Next(shortNode.Key.Length));\n                    }\n                    else\n                    {\n                        return null;\n                    }\n\n                case FullNode fullNode:\n                    if (cursor.Offset == cursor.Length)\n                    {\n                        // Note: FullNode.Value is either null, a HashNode, or a ValueNode.\n                        if (fullNode.Value is INode n)\n                        {\n                            return (n, cursor);\n                        }\n                        else\n                        {\n                            return null;\n                        }\n                    }\n                    else\n                    {\n                        INode? nextNode = fullNode.Children[cursor.NextNibble];\n                        if (nextNode is INode n)\n                        {\n                            return ResolveToNextCandidateNode(n, cursor.Next(1));\n                        }\n                        else\n                        {\n                            return null;\n                        }\n                    }\n\n                default:\n                    // NOTE: Should never be thrown.\n                    throw new ArgumentException(\n                        $\"Encountered an unexpected node type {node.GetType()}\");\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Store/Trie/MerkleTrie.Remove.cs",
    "content": "using System;\nusing System.Collections.Immutable;\nusing System.Linq;\nusing Libplanet.Store.Trie.Nodes;\n\nnamespace Libplanet.Store.Trie\n{\n    public partial class MerkleTrie\n    {\n        private INode? RemoveFromRoot(in PathCursor cursor)\n        {\n            if (Root is null)\n            {\n                return Root;\n            }\n            else\n            {\n                return Remove(Root, cursor);\n            }\n        }\n\n        private INode? Remove(INode node, in PathCursor cursor)\n        {\n            switch (node)\n            {\n                case HashNode hashNode:\n                    return RemoveFromHashNode(hashNode, cursor);\n                case ValueNode valueNode:\n                    return RemoveFromValueNode(valueNode, cursor);\n                case ShortNode shortNode:\n                    return RemoveFromShortNode(shortNode, cursor);\n                case FullNode fullNode:\n                    return RemoveFromFullNode(fullNode, cursor);\n                default:\n                    throw new InvalidOperationException();\n            }\n        }\n\n        private INode? RemoveFromHashNode(HashNode hashNode, PathCursor cursor) =>\n            Remove(UnhashNode(hashNode), cursor);\n\n        private INode? RemoveFromValueNode(ValueNode valueNode, PathCursor cursor) =>\n            cursor.RemainingAnyNibbles\n                ? valueNode\n                : null;\n\n        private INode? RemoveFromShortNode(ShortNode shortNode, PathCursor cursor)\n        {\n            // Two cases are possible:\n            // - common prefix length == short node's key length: remove directly from short node's\n            //   value\n            // - common prefix length < short node's key length: do nothing since it is\n            //   trying to remove value from a non-existent path\n            Nibbles commonNibbles = cursor.GetCommonStartingNibbles(shortNode.Key);\n            PathCursor nextCursor = cursor.Next(commonNibbles.Length);\n\n            if (commonNibbles.Length == shortNode.Key.Length)\n            {\n                INode? processedValue = Remove(shortNode.Value, nextCursor);\n                if (processedValue is { } node)\n                {\n                    switch (node)\n                    {\n                        case HashNode _:\n                            throw new ArgumentException();\n                        case ValueNode vn:\n                            return new ShortNode(shortNode.Key, vn);\n                        case FullNode fn:\n                            return new ShortNode(shortNode.Key, fn);\n                        case ShortNode sn:\n                            return new ShortNode(shortNode.Key.AddRange(sn.Key), sn.Value);\n                        default:\n                            throw new InvalidTrieNodeException(\n                                $\"Unsupported node value: {node.ToBencodex().Inspect()}\");\n                    }\n                }\n                else\n                {\n                    return null;\n                }\n            }\n            else\n            {\n                return shortNode;\n            }\n        }\n\n        private INode RemoveFromFullNode(FullNode fullNode, PathCursor cursor)\n        {\n            if (cursor.RemainingAnyNibbles)\n            {\n                byte nextNibble = cursor.NextNibble;\n                if (fullNode.Children[nextNibble] is { } child)\n                {\n                    INode? processedChild = Remove(child, cursor.Next(1));\n                    return processedChild is { } node\n                        ? fullNode.SetChild(\n                            nextNibble,\n                            node)\n                        : ReduceFullNode(fullNode.RemoveChild(nextNibble));\n                }\n                else\n                {\n                    return fullNode;\n                }\n            }\n            else\n            {\n                return ReduceFullNode(fullNode.RemoveChild(FullNode.ChildrenCount - 1));\n            }\n        }\n\n        private INode ReduceFullNode(FullNode fullNode)\n        {\n            (INode, int)[] childrenWithIndices = fullNode.Children\n                .Select((child, i) => (child, i))\n                .Where(pair => pair.child is INode)\n                .ToArray()!;\n            int childrenCount = childrenWithIndices.Length;\n            if (childrenCount == 0)\n            {\n                throw new ArgumentException(\n                    $\"Given {nameof(fullNode)} must have at least 1 child: {childrenCount}\");\n            }\n            else if (childrenCount == 1)\n            {\n                // Possible cases:\n                // - If only the value remains, it is equivalent to a value node.\n                // - If only nibble + child remains:\n                //   - If the child is a short node, combine with a nibble to make\n                //     a \"longer\" short node.\n                //   - If the child is either a value node or a full node, return a short node\n                //     with the nibble as its key.\n                (INode child, int index) = childrenWithIndices.Single();\n                child = child is HashNode hn ? UnhashNode(hn) : child;\n                return index == FullNode.ChildrenCount - 1\n                    ? child\n                    : child is ShortNode sn\n                        ? new ShortNode(\n                            new Nibbles(new byte[] { (byte)index }.ToImmutableArray())\n                                .AddRange(sn.Key),\n                            sn.Value)\n                        : new ShortNode(\n                            new Nibbles(new byte[] { (byte)index }.ToImmutableArray()),\n                            child);\n            }\n            else\n            {\n                return fullNode;\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Store/Trie/MerkleTrie.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Collections.Immutable;\nusing System.Linq;\nusing System.Security.Cryptography;\nusing Bencodex;\nusing Bencodex.Types;\nusing Libplanet.Common;\nusing Libplanet.Store.Trie.Nodes;\n\nnamespace Libplanet.Store.Trie\n{\n    /// <summary>\n    /// An <see cref=\"ITrie\"/> implementation implemented\n    /// <see href=\"https://eth.wiki/fundamentals/patricia-tree\">Merkle Patricia Trie</see>.\n    /// </summary>\n    // TODO: implement 'logs' for debugging.\n    public partial class MerkleTrie : ITrie\n    {\n        public static readonly HashDigest<SHA256> EmptyRootHash;\n\n        private static readonly Codec _codec;\n\n        private readonly HashNodeCache _cache;\n\n        static MerkleTrie()\n        {\n            _codec = new Codec();\n            var bxNull = _codec.Encode(Null.Value);\n            EmptyRootHash = HashDigest<SHA256>.DeriveFrom(bxNull);\n        }\n\n        /// <summary>\n        /// An <see cref=\"ITrie\"/> implementation.\n        /// </summary>\n        /// <param name=\"keyValueStore\">The <see cref=\"IKeyValueStore\"/> storage to store\n        /// nodes.</param>\n        /// <param name=\"rootHash\">The root <see cref=\"ITrie.Hash\"/> of\n        /// <see cref=\"MerkleTrie\"/>.</param>\n        /// <param name=\"cache\">The <see cref=\"HashNodeCache\"/> to use as cache.</param>\n        public MerkleTrie(\n            IKeyValueStore keyValueStore,\n            HashDigest<SHA256> rootHash,\n            HashNodeCache? cache = null)\n            : this(keyValueStore, new HashNode(rootHash), cache)\n        {\n        }\n\n        /// <summary>\n        /// An <see cref=\"ITrie\"/> implementation.\n        /// </summary>\n        /// <param name=\"keyValueStore\">The <see cref=\"IKeyValueStore\"/> storage to store\n        /// nodes.</param>\n        /// <param name=\"root\">The root node of <see cref=\"MerkleTrie\"/>.  If it is\n        /// <see langword=\"null\"/>, it will be treated like empty trie.</param>\n        /// <param name=\"cache\">The <see cref=\"HashNodeCache\"/> to use as cache.</param>\n        public MerkleTrie(\n            IKeyValueStore keyValueStore,\n            INode? root = null,\n            HashNodeCache? cache = null)\n        {\n            // FIXME: It might be a good idea to have something like IReadOnlyKeyValueStore.\n            KeyValueStore = keyValueStore;\n            Root = root is HashNode hashNode && hashNode.HashDigest.Equals(EmptyRootHash)\n                ? null\n                : root;\n            _cache = cache ?? new HashNodeCache();\n        }\n\n        /// <inheritdoc cref=\"ITrie.Root\"/>\n        public INode? Root { get; }\n\n        /// <inheritdoc cref=\"ITrie.Hash\"/>\n        public HashDigest<SHA256> Hash => Root?.Hash() ?? EmptyRootHash;\n\n        /// <inheritdoc cref=\"ITrie.Recorded\"/>\n        public bool Recorded => Root is null || KeyValueStore.Exists(new KeyBytes(Hash.ByteArray));\n\n        private IKeyValueStore KeyValueStore { get; }\n\n        /// <inheritdoc cref=\"ITrie.Set\"/>\n        public ITrie Set(in KeyBytes key, IValue value)\n        {\n            if (value is null)\n            {\n                throw new ArgumentNullException(nameof(value));\n            }\n\n            INode newRootNode = Insert(\n                Root,\n                new PathCursor(key),\n                new ValueNode(value),\n                true);\n\n            return new MerkleTrie(KeyValueStore, newRootNode, _cache);\n        }\n\n        /// <inheritdoc cref=\"ITrie.Remove\"/>\n        public ITrie Remove(in KeyBytes key)\n        {\n            INode? newRootNode = RemoveFromRoot(new PathCursor(key));\n            return new MerkleTrie(KeyValueStore, newRootNode, _cache);\n        }\n\n        /// <inheritdoc cref=\"ITrie.Get(KeyBytes)\"/>\n        public IValue? Get(KeyBytes key) => ResolveToValue(Root, new PathCursor(key));\n\n        /// <inheritdoc cref=\"ITrie.Get(IReadOnlyList{KeyBytes})\"/>\n        public IReadOnlyList<IValue?> Get(IReadOnlyList<KeyBytes> keys)\n        {\n            const int parallelThreshold = 4;\n            return keys.Count <= parallelThreshold\n                ? keys.Select(key => Get(key)).ToArray()\n                : keys.AsParallel().Select(key => Get(key)).ToArray();\n        }\n\n        /// <inheritdoc cref=\"ITrie.GetNode(Nibbles)\"/>\n        public INode? GetNode(Nibbles nibbles) => ResolveToNode(Root, new PathCursor(nibbles));\n\n        /// <inheritdoc cref=\"ITrie.IterateValues\"/>\n        public IEnumerable<(KeyBytes Path, IValue Value)> IterateValues()\n        {\n            foreach ((var path, var node) in IterateNodes())\n            {\n                if (node is ValueNode valueNode)\n                {\n                    yield return (path.ToKeyBytes(), valueNode.Value);\n                }\n            }\n        }\n\n        /// <inheritdoc cref=\"ITrie.IterateNodes\"/>\n        public IEnumerable<(Nibbles Path, INode Node)> IterateNodes() =>\n            IterateSubTrieNodes(new KeyBytes(ImmutableArray<byte>.Empty));\n\n        /// <summary>\n        /// Iterates all values that can be reached from a sub-<see cref=\"ITrie\"/> with\n        /// <see cref=\"INode\"/> at <paramref name=\"rootPath\"/> as its root.\n        /// </summary>\n        /// <param name=\"rootPath\">The <see cref=\"KeyBytes\"/> path of an <see cref=\"INode\"/>\n        /// to use as the root of traversal.</param>\n        /// <returns>All <see cref=\"IValue\"/>s together with its <em>full</em>\n        /// <see cref=\"KeyBytes\"/> paths.</returns>\n        /// <remarks>\n        /// This requires an <see cref=\"INode\"/> to exist at <paramref name=\"rootPath\"/>.\n        /// As such, this does not necessarily return all <see cref=\"INode\"/> with paths starting\n        /// with <paramref name=\"rootPath\"/>.  In particular, if there doesn't exist\n        /// an <see cref=\"INode\"/> at <paramref name=\"rootPath\"/>, this returns nothing.\n        /// </remarks>\n        public IEnumerable<(KeyBytes Path, IValue Value)> IterateSubTrieValues(KeyBytes rootPath)\n        {\n            foreach ((var path, var node) in IterateSubTrieNodes(rootPath))\n            {\n                if (node is ValueNode valueNode)\n                {\n                    yield return (path.ToKeyBytes(), valueNode.Value);\n                }\n            }\n        }\n\n        /// <summary>\n        /// Iterates all sub-nodes from a sub-<see cref=\"ITrie\"/> with <see cref=\"INode\"/> at\n        /// <paramref name=\"rootPath\"/> as its root.\n        /// </summary>\n        /// <param name=\"rootPath\">The <see cref=\"KeyBytes\"/> path of an <see cref=\"INode\"/>\n        /// to use as the root of traversal.</param>\n        /// <returns>All <see cref=\"INode\"/>s together with its <em>full</em>\n        /// <see cref=\"Nibbles\"/> paths.</returns>\n        /// <remarks>\n        /// This requires an <see cref=\"INode\"/> to exist at <paramref name=\"rootPath\"/>.\n        /// As such, this does not necessarily return all <see cref=\"INode\"/> with paths starting\n        /// with <paramref name=\"rootPath\"/>.  In particular, if there doesn't exist\n        /// an <see cref=\"INode\"/> at <paramref name=\"rootPath\"/>, this returns nothing.\n        /// </remarks>\n        public IEnumerable<(Nibbles Path, INode Node)> IterateSubTrieNodes(KeyBytes rootPath)\n        {\n            Nibbles rootPrefix = Nibbles.FromKeyBytes(rootPath);\n            INode? root = GetNode(rootPrefix);\n            if (root is { } node)\n            {\n                foreach (var pair in IterateNodes(rootPrefix, node))\n                {\n                    yield return pair;\n                }\n            }\n            else\n            {\n                yield break;\n            }\n        }\n\n        /// <summary>\n        /// Iterates over <see cref=\"KeyBytes\"/> and <see cref=\"byte[]\"/> pairs stored\n        /// necessary to fully represent this <see cref=\"ITrie\"/>.\n        /// </summary>\n        /// <returns>An <see cref=\"IEnumerable\"/> of all <see cref=\"KeyBytes\"/> and\n        /// <see cref=\"byte[]\"/> pairs stored necessary to fully represent\n        /// this <see cref=\"ITrie\"/>.</returns>\n        /// <exception cref=\"NullReferenceException\">Thrown when a <see cref=\"HashNode\"/>\n        /// is encountered that can't be decoded into an <see cref=\"INode\"/>.</exception>\n        internal IEnumerable<(KeyBytes Key, byte[] Value)> IterateKeyValuePairs()\n        {\n            if (Root is null)\n            {\n                yield break;\n            }\n\n            var stack = new Stack<INode>();\n            stack.Push(Root);\n\n            while (stack.Count > 0)\n            {\n                INode node = stack.Pop();\n                if (node is HashNode poppedHashNode)\n                {\n                    var storedKey = new KeyBytes(poppedHashNode.HashDigest.ByteArray);\n                    var storedValue = KeyValueStore.Get(storedKey);\n                    var intermediateEncoding = _codec.Decode(storedValue);\n                    stack.Push(\n                        NodeDecoder.Decode(\n                            intermediateEncoding,\n                            NodeDecoder.HashEmbeddedNodeType) ??\n                            throw new NullReferenceException());\n                    yield return (storedKey, storedValue);\n                    continue;\n                }\n\n                switch (node)\n                {\n                    case FullNode fullNode:\n                        foreach (int index in Enumerable.Range(0, FullNode.ChildrenCount - 1))\n                        {\n                            INode? child = fullNode.Children[index];\n                            if (child is HashNode childHashNode)\n                            {\n                                stack.Push(childHashNode);\n                            }\n                        }\n\n                        if (fullNode.Value is HashNode fullNodeValueHashNode)\n                        {\n                            stack.Push(fullNodeValueHashNode);\n                        }\n\n                        break;\n\n                    case ShortNode shortNode:\n                        if (shortNode.Value is HashNode shortNodeValueHashNode)\n                        {\n                            stack.Push(shortNodeValueHashNode);\n                        }\n\n                        break;\n\n                    case ValueNode _:\n                        break;\n\n                    case HashNode _:\n                        throw new InvalidOperationException();\n                }\n            }\n        }\n\n        private IEnumerable<(Nibbles Path, INode Node)> IterateNodes(\n            Nibbles rootPrefix,\n            INode root)\n        {\n            var stack = new Stack<(Nibbles, INode)>();\n            stack.Push((rootPrefix, root));\n\n            while (stack.Count > 0)\n            {\n                (Nibbles path, INode node) = stack.Pop();\n                yield return (path, node);\n                switch (node)\n                {\n                    case FullNode fullNode:\n                        foreach (int index in Enumerable.Range(0, FullNode.ChildrenCount - 1))\n                        {\n                            INode? child = fullNode.Children[index];\n                            if (!(child is null))\n                            {\n                                stack.Push((path.Add((byte)index), child));\n                            }\n                        }\n\n                        if (!(fullNode.Value is null))\n                        {\n                            stack.Push((path, fullNode.Value));\n                        }\n\n                        break;\n\n                    case ShortNode shortNode:\n                        if (!(shortNode.Value is null))\n                        {\n                            stack.Push((path.AddRange(shortNode.Key), shortNode.Value));\n                        }\n\n                        break;\n\n                    case HashNode hashNode:\n                        stack.Push((path, UnhashNode(hashNode)));\n                        break;\n                }\n            }\n        }\n\n        /// <summary>\n        /// Gets the concrete inner node corresponding to <paramref name=\"hashNode\"/> from storage.\n        /// </summary>\n        /// <param name=\"hashNode\">The <see cref=\"HashNode\"/> to un-hash and retrieve\n        /// the inner node from.</param>\n        /// <returns>The node corresponding to <paramref name=\"hashNode\"/>.</returns>\n        /// <exception cref=\"KeyNotFoundException\">Thrown when <paramref name=\"hashNode\"/>'s\n        /// <see cref=\"HashNode.HashDigest\"/> is not found in storage.</exception>\n        /// <remarks>\n        /// As <see langword=\"null\"/> is never hashed, this is never <see langword=\"null\"/>.\n        /// Specifically, hashing of <see langword=\"null\"/> never happens.\n        /// Calling of this method is explicitly bypassed for an empty <see cref=\"ITrie\"/>.\n        /// </remarks>\n        private INode UnhashNode(HashNode hashNode)\n        {\n            IValue intermediateEncoding;\n            if (_cache.TryGetValue(hashNode.HashDigest, out var value))\n            {\n                intermediateEncoding = value!;\n            }\n            else\n            {\n                intermediateEncoding =\n                    _codec.Decode(KeyValueStore.Get(new KeyBytes(hashNode.HashDigest.ByteArray)));\n                _cache.AddOrUpdate(hashNode.HashDigest, intermediateEncoding);\n            }\n\n            return NodeDecoder.Decode(intermediateEncoding, NodeDecoder.HashEmbeddedNodeType) ??\n                throw new NullReferenceException();\n        }\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Store/Trie/Nibbles.cs",
    "content": "using System;\nusing System.Collections.Immutable;\nusing System.Diagnostics.Contracts;\nusing System.Linq;\n\nnamespace Libplanet.Store.Trie\n{\n    public readonly struct Nibbles : IEquatable<Nibbles>\n    {\n        public static readonly Nibbles Empty = new Nibbles(ImmutableArray<byte>.Empty);\n\n        private static readonly char[] _hexCharLookup =\n        {\n            '0', '1', '2', '3', '4', '5', '6', '7',\n            '8', '9', 'a', 'b', 'c', 'd', 'e', 'f',\n        };\n\n        private readonly ImmutableArray<byte> _bytes;\n\n        /// <summary>\n        /// Creates an instance of <see cref=\"Nibbles\"/> from a sequence of nibbles.\n        /// </summary>\n        /// <param name=\"nibbles\">The list of nibbles with each nibble assigned to\n        /// a <see langword=\"byte\"/>, i.e., each element is assumed to be less than 16.</param>\n        /// <remarks>\n        /// For performance reasons, this does not actually check whether <paramref name=\"nibbles\"/>\n        /// is a valid sequence of nibbles, i.e. each element with value less than 16.\n        /// </remarks>\n        internal Nibbles(in ImmutableArray<byte> nibbles)\n        {\n            _bytes = nibbles;\n        }\n\n        /// <summary>\n        /// A list of <see langword=\"byte\"/>s representing raw nibbles where each nibble\n        /// is assigned to a <see langword=\"byte\"/>.\n        /// </summary>\n        [Pure]\n        public ImmutableArray<byte> ByteArray => _bytes.IsDefaultOrEmpty\n            ? ImmutableArray<byte>.Empty\n            : _bytes;\n\n        [Pure]\n        public int Length => ByteArray.Length;\n\n        /// <summary>\n        /// The hex representation of the <see cref=\"Nibbles\"/>.  Unlike most other\n        /// hex representations, returned <see langword=\"string\"/> is of the same length as\n        /// <see cref=\"ByteArray\"/> and can be of odd length.\n        /// </summary>\n        [Pure]\n        public string Hex\n        {\n            get\n            {\n                char[] chars = new char[Length];\n                for (int i = 0; i < Length; i++)\n                {\n                    chars[i] = _hexCharLookup[ByteArray[i]];\n                }\n\n                return new string(chars);\n            }\n        }\n\n        public byte this[int index] => ByteArray[index];\n\n        public static Nibbles FromHex(string hex)\n        {\n            byte[] bytes = new byte[hex.Length];\n            for (var i = 0; i < hex.Length; i++)\n            {\n                bytes[i] = (byte)System.Uri.FromHex(hex[i]);\n            }\n\n            return new Nibbles(bytes.ToImmutableArray());\n        }\n\n        public static Nibbles FromKeyBytes(in KeyBytes keyBytes)\n        {\n            var builder = ImmutableArray.CreateBuilder<byte>(keyBytes.ByteArray.Length * 2);\n            for (int i = 0; i < keyBytes.ByteArray.Length; i++)\n            {\n                builder.Add((byte)(keyBytes.ByteArray[i] >> 4));\n                builder.Add((byte)(keyBytes.ByteArray[i] & 0x0f));\n            }\n\n            return new Nibbles(builder.ToImmutable());\n        }\n\n        public Nibbles Add(byte b)\n        {\n            return new Nibbles(ByteArray.Add(b));\n        }\n\n        public Nibbles AddRange(in ImmutableArray<byte> nibbles)\n        {\n            return new Nibbles(ByteArray.AddRange(nibbles));\n        }\n\n        public Nibbles AddRange(in Nibbles nibbles)\n        {\n            return new Nibbles(ByteArray.AddRange(nibbles.ByteArray));\n        }\n\n        public Nibbles Take(int count) => count <= Length\n            ? new Nibbles(ByteArray.Take(count).ToImmutableArray())\n            : throw new ArgumentOutOfRangeException(\n                nameof(count),\n                $\"Given {nameof(count)} must be less than or equal to {Length}: {count}\");\n\n        public Nibbles Skip(int count) => count <= Length\n            ? new Nibbles(ByteArray.Skip(count).ToImmutableArray())\n            : throw new ArgumentOutOfRangeException(\n                nameof(count),\n                $\"Given {nameof(count)} must be less than or equal to {Length}: {count}\");\n\n        /// <summary>\n        /// Gets a <see cref=\"KeyBytes\"/> representing compressed nibbles where\n        /// each pair of nibbles is compacted into a <see langword=\"byte\"/>.\n        /// </summary>\n        /// <returns>\n        /// A <see cref=\"KeyBytes\"/> representing compacted nibbles.\n        /// </returns>\n        /// <exception cref=\"InvalidOperationException\">Thrown when <see cref=\"Length\"/> is odd.\n        /// </exception>\n        [Pure]\n        public KeyBytes ToKeyBytes()\n        {\n            if (Length % 2 != 0)\n            {\n                throw new InvalidOperationException(\n                    $\"The length must be even in order to convert \" +\n                    $\"to a {nameof(KeyBytes)}: {Length}\");\n            }\n\n            int byteLength = Length / 2;\n            var builder = ImmutableArray.CreateBuilder<byte>(byteLength);\n            for (int i = 0; i < Length; i += 2)\n            {\n                builder.Add((byte)(ByteArray[i] << 4 | ByteArray[i + 1]));\n            }\n\n            return new KeyBytes(builder.ToImmutable());\n        }\n\n        public bool Equals(Nibbles other)\n        {\n#if NETSTANDARD2_0_OR_GREATER\n            if (ReferenceEquals(this, other))\n            {\n                return true;\n            }\n#endif // NETSTANDARD2_0_OR_GREATER\n\n            return other is { } nibbles && ByteArray.SequenceEqual(nibbles.ByteArray);\n        }\n\n        public override bool Equals(object? obj) =>\n            obj is Nibbles other && Equals(other);\n\n        public override int GetHashCode()\n        {\n            int code = 0;\n            unchecked\n            {\n                foreach (byte b in ByteArray)\n                {\n                    code = (code * 397) ^ b.GetHashCode();\n                }\n            }\n\n            return code;\n        }\n\n        public override string ToString()\n        {\n            return Hex;\n        }\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Store/Trie/Nodes/FullNode.cs",
    "content": "using System;\nusing System.Collections.Immutable;\nusing System.Linq;\nusing Bencodex.Types;\n\nnamespace Libplanet.Store.Trie.Nodes\n{\n    public sealed class FullNode : INode, IEquatable<FullNode>\n    {\n        // Children 0x10 + Value 0x01\n        public const byte ChildrenCount = 0x11;\n\n        public static readonly FullNode Empty =\n            new FullNode(new INode?[ChildrenCount].ToImmutableArray());\n\n        public FullNode(ImmutableArray<INode?> children)\n        {\n            if (children.Length != ChildrenCount)\n            {\n                throw new InvalidTrieNodeException(\n                    $\"The number of {nameof(FullNode)}'s children should be {ChildrenCount}.\");\n            }\n\n            Children = children;\n            Value = children[ChildrenCount - 1];\n        }\n\n        public ImmutableArray<INode?> Children { get; }\n\n        public INode? Value { get; }\n\n        public FullNode SetChild(int index, INode childNode)\n        {\n            return new FullNode(Children.SetItem(index, childNode));\n        }\n\n        public FullNode RemoveChild(int index)\n        {\n            return new FullNode(Children.SetItem(index, null));\n        }\n\n        /// <inheritdoc cref=\"IEquatable{T}.Equals\"/>\n        public bool Equals(FullNode? other)\n        {\n            if (ReferenceEquals(this, other))\n            {\n                return true;\n            }\n\n            return other is { } node &&\n                Children.Select((n, i) => (n, i)).Where(pair => pair.n is { }).SequenceEqual(\n                    node.Children.Select((n, i) => (n, i)).Where(pair => pair.n is { }));\n        }\n\n        public override bool Equals(object? obj) =>\n            obj is FullNode other && Equals(other);\n\n        public override int GetHashCode() => Children.GetHashCode();\n\n        /// <inheritdoc cref=\"INode.ToBencodex()\"/>\n        public IValue ToBencodex() =>\n            new List(Children.Select(child => child?.ToBencodex() ?? Null.Value));\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Store/Trie/Nodes/HashNode.cs",
    "content": "using System;\nusing System.Security.Cryptography;\nusing Bencodex.Types;\nusing Libplanet.Common;\n\nnamespace Libplanet.Store.Trie.Nodes\n{\n    /// <summary>\n    /// <see cref=\"HashDigest{T}\"/>'s wrapper class, used in <see cref=\"ITrie\"/> interface.\n    /// </summary>\n    public class HashNode : INode, IEquatable<HashNode>\n    {\n        public HashNode(HashDigest<SHA256> hashDigest)\n        {\n            HashDigest = hashDigest;\n        }\n\n        public HashDigest<SHA256> HashDigest { get; }\n\n        public static bool operator ==(HashNode left, HashNode right) => left.Equals(right);\n\n        public static bool operator !=(HashNode left, HashNode right) => !left.Equals(right);\n\n        /// <inheritdoc cref=\"IEquatable{T}.Equals\"/>\n        public bool Equals(HashNode? other) =>\n            other is { } node && HashDigest.Equals(node.HashDigest);\n\n        public override bool Equals(object? obj) => obj is HashNode other && Equals(other);\n\n        /// <inheritdoc cref=\"INode.ToBencodex()\"/>\n        public IValue ToBencodex() => HashDigest.Bencoded;\n\n        public override int GetHashCode() => HashDigest.GetHashCode();\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Store/Trie/Nodes/INode.cs",
    "content": "using Bencodex.Types;\n\nnamespace Libplanet.Store.Trie.Nodes\n{\n    /// <summary>\n    /// A constituent unit of <see cref=\"MerkleTrie\"/>.\n    /// </summary>\n    /// <seealso cref=\"FullNode\"/>\n    /// <seealso cref=\"ShortNode\"/>\n    /// <seealso cref=\"ValueNode\"/>\n    /// <seealso cref=\"HashNode\"/>\n    public interface INode\n    {\n        IValue ToBencodex();\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Store/Trie/Nodes/INodeExtensions.cs",
    "content": "using System.Security.Cryptography;\nusing Bencodex;\nusing Libplanet.Common;\n\nnamespace Libplanet.Store.Trie.Nodes\n{\n    // FIXME: As it's not an interface, it should be renamed to NodeExtensions.\n    internal static class INodeExtensions\n    {\n        private static readonly Codec Codec = new Codec();\n\n        internal static HashDigest<SHA256> Hash(this INode node)\n        {\n            return node is HashNode hashNode\n                ? hashNode.HashDigest\n                : HashDigest<SHA256>.DeriveFrom(Codec.Encode(node.ToBencodex()));\n        }\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Store/Trie/Nodes/NodeDecoder.cs",
    "content": "using System;\nusing System.Collections.Immutable;\nusing System.Linq;\nusing System.Security.Cryptography;\nusing Bencodex.Types;\nusing Libplanet.Common;\n\nnamespace Libplanet.Store.Trie.Nodes\n{\n    public static class NodeDecoder\n    {\n        public const NodeType AnyNodeType =\n            NodeType.Null | NodeType.Value | NodeType.Short | NodeType.Full | NodeType.Hash;\n\n        public const NodeType FullValueNodeType =\n            NodeType.Null | NodeType.Value | NodeType.Hash;\n\n        public const NodeType FullChildNodeType =\n            NodeType.Null | NodeType.Value | NodeType.Short | NodeType.Full | NodeType.Hash;\n\n        public const NodeType ShortValueNodeType =\n            NodeType.Value | NodeType.Short | NodeType.Full | NodeType.Hash;\n\n        public const NodeType HashEmbeddedNodeType =\n            NodeType.Value | NodeType.Short | NodeType.Full;\n\n        [Flags]\n        public enum NodeType : short\n        {\n            /// <summary>\n            /// A null node represented as <see langword=\"null\"/>.\n            /// </summary>\n            Null = 1,\n\n            /// <summary>\n            /// A <see cref=ValueNode\"/>.\n            /// </summary>\n            Value = 2,\n\n            /// <summary>\n            /// A <see cref=\"ShortNode\"/>.\n            /// </summary>\n            Short = 4,\n\n            /// <summary>\n            /// A <see cref=\"FullNode\"/>.\n            /// </summary>\n            Full = 8,\n\n            /// <summary>\n            /// A <see cref=\"HashNode\"/>.\n            /// </summary>\n            Hash = 16,\n        }\n\n        public static INode? Decode(IValue value, NodeType allowed)\n        {\n            if (value is List list)\n            {\n                if (list.Count == FullNode.ChildrenCount)\n                {\n                    return (allowed & NodeType.Full) == NodeType.Full\n                        ? DecodeFull(list)\n                        : throw new InvalidTrieNodeException(\n                            $\"Can't decode a node from value {value.Inspect()}\");\n                }\n                else if (list.Count == 2)\n                {\n                    if (list[0] is Binary)\n                    {\n                        return (allowed & NodeType.Short) == NodeType.Short\n                            ? DecodeShort(list)\n                            : throw new InvalidTrieNodeException(\n                                $\"Can't decode a node from value {value.Inspect()}\");\n                    }\n                    else if (list[0] is Null)\n                    {\n                        return (allowed & NodeType.Value) == NodeType.Value\n                            ? DecodeValue(list)\n                            : throw new InvalidTrieNodeException(\n                                $\"Can't decode a node from value {value.Inspect()}\");\n                    }\n                    else\n                    {\n                        throw new InvalidTrieNodeException(\n                                $\"Can't decode a node from value {value.Inspect()}\");\n                    }\n                }\n                else\n                {\n                    throw new InvalidTrieNodeException(\n                        $\"Can't decode a node from the bencodex value: {value.Inspect()}\");\n                }\n            }\n            else if (value is Binary binary)\n            {\n                return (allowed & NodeType.Hash) == NodeType.Hash\n                    ? DecodeHash(binary)\n                    : throw new InvalidTrieNodeException(\n                        $\"Can't decode a node from value {value.Inspect()}\");\n            }\n            else if (value is Null)\n            {\n                return (allowed & NodeType.Null) == NodeType.Null\n                    ? (INode?)null\n                    : throw new InvalidTrieNodeException(\n                        $\"Can't decode a node from value {value.Inspect()}\");\n            }\n            else\n            {\n                throw new InvalidTrieNodeException(\n                    $\"Can't decode a node from value {value.Inspect()}\");\n            }\n        }\n\n        // The length and the first element are already checked.\n        private static ValueNode DecodeValue(List list)\n        {\n            return new ValueNode(list[1]);\n        }\n\n        // The length and the first element are already checked.\n        private static ShortNode DecodeShort(List list)\n        {\n            // FIXME: This assumes encoded binary is a valid sequence of nibbles.\n            INode value = Decode(list[1], ShortValueNodeType) ??\n                throw new NullReferenceException(\n                    $\"Failed to decode a {nameof(ShortNode)} from given {nameof(list)}: {list}\");\n            return new ShortNode(\n                new Nibbles(((Binary)list[0]).ByteArray), value);\n        }\n\n        // The length is already checked.\n        private static FullNode DecodeFull(List list)\n        {\n            return new FullNode(list\n                .Select((child, i) => i < FullNode.ChildrenCount - 1\n                    ? Decode(child, FullChildNodeType)\n                    : Decode(child, FullValueNodeType))\n                .ToImmutableArray());\n        }\n\n        private static HashNode DecodeHash(Binary binary)\n        {\n            return new HashNode(new HashDigest<SHA256>(binary.ByteArray));\n        }\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Store/Trie/Nodes/ShortNode.cs",
    "content": "using System;\nusing Bencodex.Types;\n\nnamespace Libplanet.Store.Trie.Nodes\n{\n    public sealed class ShortNode : INode, IEquatable<ShortNode>\n    {\n        public ShortNode(in Nibbles nibbles, INode value)\n        {\n            Key = nibbles.Length > 0\n                ? nibbles\n                : throw new ArgumentException(\n                    $\"Given {nameof(nibbles)} cannot be empty.\", nameof(nibbles));\n            Value = value is ShortNode\n                ? throw new ArgumentException(\n                    $\"Given {nameof(value)} cannot be a {nameof(ShortNode)}.\", nameof(value))\n                : value;\n        }\n\n        public Nibbles Key { get; }\n\n        /// <summary>\n        /// Represents an <see cref=\"INode\"/> at the end of a <see cref=\"ShortNode\"/>.\n        /// It can be a <see cref=\"ValueNode\"/>, a <see cref=\"FullNode\"/>,\n        /// or a <see cref=\"HashNode\"/> of either a <see cref=\"ValueNode\"/>\n        /// or a <see cref=\"FullNode\"/>.  That is, this can be neither a <see cref=\"ShortNode\"/>\n        /// nor a <see cref=\"HashNode\"/> of a <see cref=\"ShortNode\"/>.\n        /// </summary>\n        public INode Value { get; }\n\n        /// <inheritdoc cref=\"IEquatable{T}.Equals\"/>\n        public bool Equals(ShortNode? other)\n        {\n            if (ReferenceEquals(this, other))\n            {\n                return true;\n            }\n\n            return other is { } node &&\n                Key.Equals(node.Key) &&\n                Value.Equals(node.Value);\n        }\n\n        /// <inheritdoc cref=\"object.Equals\"/>\n        public override bool Equals(object? obj) =>\n            obj is ShortNode other && Equals(other);\n\n        public override int GetHashCode()\n        {\n            unchecked\n            {\n                return (Key.GetHashCode() * 397) ^ Value.GetHashCode();\n            }\n        }\n\n        /// <inheritdoc cref=\"INode.ToBencodex()\"/>\n        public IValue ToBencodex() =>\n            new List(new Binary(Key.ByteArray), Value.ToBencodex());\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Store/Trie/Nodes/ValueNode.cs",
    "content": "using System;\nusing Bencodex.Types;\n\nnamespace Libplanet.Store.Trie.Nodes\n{\n    /// <summary>\n    /// Wrapper class.\n    /// </summary>\n    public class ValueNode : INode, IEquatable<ValueNode>\n    {\n        public ValueNode(IValue value)\n        {\n            Value = value;\n        }\n\n        public IValue Value { get; }\n\n        public static bool operator ==(ValueNode left, ValueNode right) => left.Equals(right);\n\n        public static bool operator !=(ValueNode left, ValueNode right) => !left.Equals(right);\n\n        /// <inheritdoc cref=\"IEquatable{T}.Equals\"/>\n        public bool Equals(ValueNode? other)\n        {\n            if (ReferenceEquals(this, other))\n            {\n                return true;\n            }\n\n            return other is { } node && Value.Equals(node.Value);\n        }\n\n        public override bool Equals(object? obj) => obj is ValueNode other && Equals(other);\n\n        /// <inheritdoc cref=\"INode.ToBencodex()\"/>\n        public IValue ToBencodex() => new List(Null.Value, Value);\n\n        public override int GetHashCode() => Value.GetHashCode();\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Store/Trie/PathCursor.cs",
    "content": "using System;\nusing System.Collections.Immutable;\nusing System.Diagnostics.Contracts;\nusing System.Security.Cryptography;\nusing Libplanet.Common;\n\nnamespace Libplanet.Store.Trie\n{\n    public readonly struct PathCursor\n    {\n        public readonly Nibbles Nibbles;\n\n        public readonly int Length;\n\n        public readonly int Offset;\n\n        public PathCursor(in KeyBytes keyBytes)\n            : this(Nibbles.FromKeyBytes(keyBytes), 0)\n        {\n        }\n\n        /// <summary>\n        /// Creates a <see cref=\"PathCursor\"/> from <paramref name=\"nibbles\"/>.\n        /// </summary>\n        /// <param name=\"nibbles\">The <see cref=\"Nibbles\"/> from which to derive\n        /// a <see cref=\"PathCursor\"/>.</param>\n        public PathCursor(in Nibbles nibbles)\n            : this(nibbles, 0)\n        {\n        }\n\n        private PathCursor(in Nibbles nibbles, int offset)\n        {\n            if (offset < 0 || offset > nibbles.Length)\n            {\n                throw new ArgumentOutOfRangeException(nameof(offset));\n            }\n\n            Nibbles = nibbles;\n            Offset = offset;\n            Length = nibbles.Length;\n        }\n\n        [Pure]\n        public readonly int RemainingNibbleLength => Length - Offset;\n\n        [Pure]\n        public readonly bool RemainingAnyNibbles => Length > Offset;\n\n        [Pure]\n        public readonly byte NextNibble => Nibbles[Offset];\n\n        [Pure]\n        public Nibbles GetConsumedNibbles() => Nibbles.Take(Offset);\n\n        [Pure]\n        public Nibbles GetRemainingNibbles() => Nibbles.Skip(Offset);\n\n        [Pure]\n        public PathCursor Next(int offset) => offset < 0\n            ? throw new ArgumentOutOfRangeException(nameof(offset))\n            : new PathCursor(Nibbles, Offset + offset);\n\n        [Pure]\n        public bool RemainingNibblesStartWith(in Nibbles nibbles)\n        {\n            if (RemainingNibbleLength < nibbles.Length)\n            {\n                return false;\n            }\n\n            int i = 0;\n            for (; i < nibbles.Length; i++)\n            {\n                int offset = Offset + i;\n                if (Nibbles[offset] != nibbles[i])\n                {\n                    return false;\n                }\n            }\n\n            return true;\n        }\n\n        /// <summary>\n        /// Counts the number of common starting nibbles from the remaining path.\n        /// </summary>\n        /// <param name=\"nibbles\">The list of nibbles to compare.</param>\n        /// <returns>The number of common starting nibbles from the remaining path.\n        [Pure]\n        public int CountCommonStartingNibbles(in Nibbles nibbles)\n        {\n            int i = 0;\n            for (; i < Math.Min(RemainingNibbleLength, nibbles.Length); i++)\n            {\n                int offset = Offset + i;\n                if (Nibbles[offset] != nibbles[i])\n                {\n                    return i;\n                }\n            }\n\n            return i;\n        }\n\n        [Pure]\n        public Nibbles GetCommonStartingNibbles(in Nibbles nibbles)\n        {\n            var builder = ImmutableArray.CreateBuilder<byte>();\n\n            int i = 0;\n            for (; i < Math.Min(RemainingNibbleLength, nibbles.Length); i++)\n            {\n                int offset = Offset + i;\n                if (Nibbles[offset] != nibbles[i])\n                {\n                    return new Nibbles(builder.ToImmutable());\n                }\n                else\n                {\n                    builder.Add(Nibbles[offset]);\n                }\n            }\n\n            return new Nibbles(builder.ToImmutable());\n        }\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Store/Trie/TrieExtensions.cs",
    "content": "using System;\nusing Bencodex.Types;\n\nnamespace Libplanet.Store.Trie\n{\n    public static class TrieExtensions\n    {\n        public static readonly KeyBytes MetadataKey = new KeyBytes(Array.Empty<byte>());\n\n        public static TrieMetadata? GetMetadata(this ITrie trie)\n        {\n            if (trie.Get(MetadataKey) is { } value)\n            {\n                return new TrieMetadata(value);\n            }\n\n            return null;\n        }\n\n        public static ITrie SetMetadata(this ITrie trie, TrieMetadata metadata)\n        {\n            return trie.Set(MetadataKey, metadata.Bencoded);\n        }\n\n        public static ITrie SetMetadata(this ITrie trie, IValue encoded)\n        {\n            return trie.Set(MetadataKey, encoded);\n        }\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Store/Trie/TrieMetadata.cs",
    "content": "using System;\nusing Bencodex;\nusing Bencodex.Types;\nusing Libplanet.Types.Blocks;\n\nnamespace Libplanet.Store.Trie\n{\n    /// <summary>\n    /// <para>\n    /// A metadata object to be injected to an <see cref=\"ITrie\"/> to identify\n    /// and validate the data model.  The is to be injected at the root of\n    /// an <see cref=\"ITrie\"/> with the zero byte array path.\n    /// </para>\n    /// <para>\n    /// <see cref=\"Version\"/> represents under which <see cref=\"IBlockMetadata.ProtocolVersion\"/>\n    /// the <see cref=\"ITrie\"/> is to be interpreted.\n    /// </para>\n    /// <para>\n    /// This is newly introduced since <see cref=\"BlockMetadata.WorldStateProtocolVersion\"/> and\n    /// every <see cref=\"ITrie\"/> handled prior to\n    /// <see cref=\"BlockMetadata.WorldStateProtocolVersion\"/> lacks this data.\n    /// </para>\n    /// </summary>\n    /// <remarks>\n    /// Due to some backward compatibility constraints, and in particular an empty\n    /// <see cref=\"Block\"/> being allowed with no state transition, an <see cref=\"ITrie\"/>\n    /// associated with the <see cref=\"Block.StateRootHash\"/> of a <see cref=\"Block\"/> with\n    /// <see cref=\"IBlockMetadata.ProtocolVersion\"/> is <em>not guaranteed</em> to have\n    /// the same <see cref=Version\"/> as the <see cref=\"Block\"/>'s\n    /// <see cref=\"IBlockMetadata.ProtocolVersion\"/>.\n    /// </remarks>\n    public class TrieMetadata : IBencodable\n    {\n        /// <summary>\n        /// Creates a <see cref=\"TrieMetadata\"/> instance.\n        /// </summary>\n        /// <param name=\"version\">The version of the <see cref=\"TrieMetadata\"/> to create.\n        /// This must equal to the version of <see cref=\"IPreEvaluationBlock\"/> that is\n        /// under evaluation.</param>\n        /// <exception cref=\"ArgumentException\">Thrown when either <paramref name=\"version\"/>\n        /// is less than <see cref=\"BlockMetadata.WorldStateProtocolVersion\"/> or\n        /// greater than <see cref=\"BlockMetadata.CurrentProtocolVersion\"/>.</exception>\n        public TrieMetadata(int version)\n        {\n            if (version < BlockMetadata.WorldStateProtocolVersion ||\n                version > BlockMetadata.CurrentProtocolVersion)\n            {\n                throw new ArgumentException(\n                    $\"Given {nameof(version)} cannot be less than \" +\n                    $\"{BlockMetadata.WorldStateProtocolVersion} or greater than \" +\n                    $\"{BlockMetadata.CurrentProtocolVersion}: {version}\",\n                    nameof(version));\n            }\n\n            Version = version;\n        }\n\n        public TrieMetadata(IValue bencoded)\n            : this(bencoded is List list\n                ? list\n                : throw new ArgumentException(\n                    $\"Given {nameof(bencoded)} must be of type \" +\n                    $\"{typeof(Binary)}: {bencoded.GetType()}\",\n                    nameof(bencoded)))\n        {\n        }\n\n        private TrieMetadata(List list)\n            : this((int)((Integer)list[0]).Value)\n        {\n        }\n\n        public int Version { get; }\n\n        public IValue Bencoded => new List(new Integer(Version));\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Store/TrieStateStore.Commit.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Collections.Immutable;\nusing System.Linq;\nusing System.Security.Cryptography;\nusing Bencodex;\nusing Bencodex.Types;\nusing Libplanet.Common;\nusing Libplanet.Store.Trie;\nusing Libplanet.Store.Trie.Nodes;\n\nnamespace Libplanet.Store\n{\n    public partial class TrieStateStore\n    {\n        private static readonly Codec _codec = new Codec();\n\n        /// <inheritdoc cref=\"IStateStore.Commit\"/>\n        public ITrie Commit(ITrie trie)\n        {\n            // FIXME: StateKeyValueStore used might not be the same as\n            // the one referenced by the argument trie.  Some kind of sanity check\n            // would be nice, if possible.\n            INode? root = trie.Root;\n            if (root is null)\n            {\n                return trie;\n            }\n            else\n            {\n                var writeBatch = new WriteBatch(StateKeyValueStore, 4096);\n                INode newRoot = Commit(root, writeBatch, _cache);\n\n                // It assumes embedded node if it's not HashNode.\n                if (!(newRoot is HashNode))\n                {\n                    IValue bencoded = newRoot.ToBencodex();\n                    byte[] serialized = _codec.Encode(bencoded);\n                    HashDigest<SHA256> hashDigest = HashDigest<SHA256>.DeriveFrom(serialized);\n\n                    writeBatch.Add(new KeyBytes(hashDigest.ByteArray), serialized);\n                    newRoot = new HashNode(hashDigest);\n                }\n\n                writeBatch.Flush();\n\n                return new MerkleTrie(StateKeyValueStore, newRoot, _cache);\n            }\n        }\n\n        private static INode Commit(INode node, WriteBatch writeBatch, HashNodeCache cache)\n        {\n            switch (node)\n            {\n                // NOTE: If it is a hashed node, it has been recorded already.\n                case HashNode _:\n                    return node;\n\n                case FullNode fullNode:\n                    return CommitFullNode(fullNode, writeBatch, cache);\n\n                case ShortNode shortNode:\n                    return CommitShortNode(shortNode, writeBatch, cache);\n\n                case ValueNode valueNode:\n                    return CommitValueNode(valueNode, writeBatch, cache);\n\n                default:\n                    throw new NotSupportedException(\"Not supported node came.\");\n            }\n        }\n\n        private static INode CommitFullNode(\n            FullNode fullNode, WriteBatch writeBatch, HashNodeCache cache)\n        {\n            var virtualChildren = fullNode.Children\n                .Select(c => c is null ? null : Commit(c, writeBatch, cache))\n                .ToImmutableArray();\n\n            fullNode = new FullNode(virtualChildren);\n            IValue encoded = fullNode.ToBencodex();\n\n            if (encoded.EncodingLength <= HashDigest<SHA256>.Size)\n            {\n                return fullNode;\n            }\n\n            return Write(fullNode.ToBencodex(), writeBatch, cache);\n        }\n\n        private static INode CommitShortNode(\n            ShortNode shortNode, WriteBatch writeBatch, HashNodeCache cache)\n        {\n            // FIXME: Assumes value is not null.\n            var committedValueNode = Commit(shortNode.Value!, writeBatch, cache);\n            shortNode = new ShortNode(shortNode.Key, committedValueNode);\n            IValue encoded = shortNode.ToBencodex();\n            if (encoded.EncodingLength <= HashDigest<SHA256>.Size)\n            {\n                return shortNode;\n            }\n\n            return Write(encoded, writeBatch, cache);\n        }\n\n        private static INode CommitValueNode(\n            ValueNode valueNode, WriteBatch writeBatch, HashNodeCache cache)\n        {\n            IValue encoded = valueNode.ToBencodex();\n            var nodeSize = encoded.EncodingLength;\n            if (nodeSize <= HashDigest<SHA256>.Size)\n            {\n                return valueNode;\n            }\n\n            return Write(encoded, writeBatch, cache);\n        }\n\n        /// <summary>\n        /// Writes <paramref name=\"bencodedNode\"/> to storage as an embedded <see cref=\"INode\"/>.\n        /// </summary>\n        /// <param name=\"bencodedNode\">The <see cref=\"IValue\"/> representation of\n        /// an <see cref=\"INode\"/> to embed.</param>\n        /// <param name=\"writeBatch\">A batched writer to use for performance reasons.</param>\n        /// <returns>A <see cref=\"HashNode\"/> already written to storage with\n        /// <paramref name=\"bencodedNode\"/> embedded inside.</returns>\n        /// <param name=\"cache\">A <see cref=\"HashNodeCache\"/> to cache nodes.</param>\n        private static HashNode Write(\n            IValue bencodedNode, WriteBatch writeBatch, HashNodeCache cache)\n        {\n            byte[] serialized = _codec.Encode(bencodedNode);\n            var nodeHash = HashDigest<SHA256>.DeriveFrom(serialized);\n            cache.AddOrUpdate(nodeHash, bencodedNode);\n            writeBatch.Add(new KeyBytes(nodeHash.ByteArray), serialized);\n            return new HashNode(nodeHash);\n        }\n\n        private class WriteBatch\n        {\n            private readonly IKeyValueStore _store;\n            private readonly int _batchSize;\n            private readonly Dictionary<KeyBytes, byte[]> _batch;\n\n            public WriteBatch(IKeyValueStore store, int batchSize)\n            {\n                _store = store;\n                _batchSize = batchSize;\n                _batch = new Dictionary<KeyBytes, byte[]>(_batchSize);\n            }\n\n            public bool ContainsKey(KeyBytes key) => _batch.ContainsKey(key);\n\n            public void Add(KeyBytes key, byte[] value)\n            {\n                _batch[key] = value;\n\n                if (_batch.Count == _batchSize)\n                {\n                    Flush();\n                }\n            }\n\n            public void Flush()\n            {\n                _store.Set(_batch);\n                _batch.Clear();\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Store/TrieStateStore.cs",
    "content": "using System;\nusing System.Collections.Immutable;\nusing System.Diagnostics;\nusing System.Security.Cryptography;\nusing Libplanet.Common;\nusing Libplanet.Store.Trie;\nusing Libplanet.Store.Trie.Nodes;\nusing Serilog;\n\nnamespace Libplanet.Store\n{\n    /// <summary>\n    /// An <see cref=\"IStateStore\"/> implementation. It stores states with <see cref=\"MerkleTrie\"/>.\n    /// </summary>\n    public partial class TrieStateStore : IStateStore\n    {\n        private readonly ILogger _logger;\n        private readonly HashNodeCache _cache;\n        private bool _disposed = false;\n\n        /// <summary>\n        /// Creates a new <see cref=\"TrieStateStore\"/>.\n        /// </summary>\n        /// <param name=\"stateKeyValueStore\">The storage to store states. It used by\n        /// <see cref=\"MerkleTrie\"/> in internal.</param>\n        public TrieStateStore(IKeyValueStore stateKeyValueStore)\n        {\n            StateKeyValueStore = stateKeyValueStore;\n            _cache = new HashNodeCache();\n            _logger = Log.ForContext<TrieStateStore>();\n        }\n\n        public IKeyValueStore StateKeyValueStore { get; }\n\n        /// <summary>\n        /// <para>\n        /// Copies states under state root hashes of given <paramref name=\"stateRootHashes\"/>\n        /// to <paramref name=\"targetStateStore\"/>.\n        /// </para>\n        /// <para>\n        /// Under the hood, this not only copies states directly associated\n        /// with <paramref name=\"stateRootHashes\"/>, but also automatically copies states\n        /// that are not directly associated with <paramref name=\"stateRootHashes\"/>\n        /// but associated with \"subtries\" with references stored in <see cref=\"ITrie\"/>s\n        /// of <paramref name=\"stateRootHashes\"/>.\n        /// </para>\n        /// </summary>\n        /// <param name=\"stateRootHashes\">The state root hashes of states to copy.</param>\n        /// <param name=\"targetStateStore\">The target state store to copy state root hashes.</param>\n        /// <exception cref=\"ArgumentException\">Thrown when a state root cannot be found for\n        /// any of given <paramref name=\"stateRootHashes\"/>.</exception>\n        public void CopyStates(\n            IImmutableSet<HashDigest<SHA256>> stateRootHashes, TrieStateStore targetStateStore)\n        {\n            IKeyValueStore targetKeyValueStore = targetStateStore.StateKeyValueStore;\n            var stopwatch = new Stopwatch();\n            long count = 0;\n            _logger.Verbose(\"Started {MethodName}()\", nameof(CopyStates));\n            stopwatch.Start();\n\n            foreach (HashDigest<SHA256> stateRootHash in stateRootHashes)\n            {\n                var stateTrie = (MerkleTrie)GetStateRoot(stateRootHash);\n                if (!stateTrie.Recorded)\n                {\n                    throw new ArgumentException(\n                        $\"Failed to find a state root for given state root hash {stateRootHash}.\");\n                }\n\n                foreach (var (key, value) in stateTrie.IterateKeyValuePairs())\n                {\n                    targetKeyValueStore.Set(key, value);\n                    count++;\n                }\n\n                // FIXME: Probably not the right place to implement this.\n                // It'd be better to have it in Libplanet.Action.State.\n                if (stateTrie.Get(new KeyBytes(Array.Empty<byte>())) is { } metadata)\n                {\n                    foreach (var (path, hash) in stateTrie.IterateValues())\n                    {\n                        // Ignore metadata\n                        if (path.Length > 0)\n                        {\n                            HashDigest<SHA256> accountStateRootHash = new HashDigest<SHA256>(hash);\n                            MerkleTrie accountStateTrie =\n                                (MerkleTrie)GetStateRoot(accountStateRootHash);\n                            if (!accountStateTrie.Recorded)\n                            {\n                                throw new ArgumentException(\n                                    $\"Failed to find a state root for given \" +\n                                    $\"state root hash {accountStateRootHash}.\");\n                            }\n\n                            foreach (var (key, value) in accountStateTrie.IterateKeyValuePairs())\n                            {\n                                targetKeyValueStore.Set(key, value);\n                                count++;\n                            }\n                        }\n                    }\n                }\n            }\n\n            stopwatch.Stop();\n            _logger.Debug(\n                \"Finished copying all states with {Count} key value pairs \" +\n                \"in {ElapsedMilliseconds} ms\",\n                count,\n                stopwatch.ElapsedMilliseconds);\n            _logger.Verbose(\"Finished {MethodName}()\", nameof(CopyStates));\n        }\n\n        /// <inheritdoc cref=\"IStateStore.GetStateRoot(HashDigest{SHA256}?, bool)\"/>\n        public ITrie GetStateRoot(HashDigest<SHA256>? stateRootHash) =>\n            new MerkleTrie(\n                StateKeyValueStore,\n                stateRootHash is { } h2 ? new HashNode(h2) : null,\n                _cache);\n\n        /// <inheritdoc cref=\"System.IDisposable.Dispose()\"/>\n        public void Dispose()\n        {\n            if (!_disposed)\n            {\n                StateKeyValueStore?.Dispose();\n                _disposed = true;\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Store.Remote/Client/RemoteKeyValueStore.cs",
    "content": "using Google.Protobuf;\nusing Grpc.Core;\nusing Libplanet.Store.Remote.Extensions;\nusing Libplanet.Store.Remote.Server;\nusing Libplanet.Store.Trie;\n\nnamespace Libplanet.Store.Remote.Client\n{\n    /// <summary>\n    /// The <a href=\"https://grpc.io/\">gRPC</a> client for\n    /// <see cref=\"IKeyValueStore\"/>. This class is a thin wrapper around the\n    /// <see cref=\"KeyValueStore.KeyValueStoreClient\"/> generated by <c>protoc</c>.\n    ///\n    /// <para> <see cref=\"RemoteKeyValueStore\"/> needs to be used with the\n    /// <see cref=\"RemoteKeyValueService\"/>.\n    /// The <see cref=\"RemoteKeyValueService\"/> should be hosted on a remote server or\n    /// a local process, and the <see cref=\"RemoteKeyValueStore\"/> should be used on a client.\n    /// </para>\n    /// </summary>\n    public sealed class RemoteKeyValueStore : IKeyValueStore\n    {\n        private readonly KeyValueStore.KeyValueStoreClient _client;\n\n        /// <summary>\n        /// Creates a new instance of <see cref=\"RemoteKeyValueStore\"/>.\n        /// </summary>\n        /// <param name=\"client\">\n        /// The <see cref=\"KeyValueStore.KeyValueStoreClient\"/> to use for communication.\n        /// </param>\n        public RemoteKeyValueStore(KeyValueStore.KeyValueStoreClient client)\n        {\n            _client = client;\n        }\n\n        /// <inheritdoc/>\n        public void Dispose()\n        {\n            // Do nothing.\n        }\n\n        /// <inheritdoc/>\n        public byte[] Get(in KeyBytes key)\n        {\n            KeyValueStoreValue value;\n            try\n            {\n                value = _client.GetValue(new GetValueRequest\n                {\n                    Key = key.ToKeyValueStoreKey(),\n                });\n            }\n            catch (RpcException e) when (e.StatusCode == StatusCode.NotFound)\n            {\n                throw new KeyNotFoundException();\n            }\n\n            return value.Data.ToByteArray();\n        }\n\n        /// <inheritdoc/>\n        public void Set(in KeyBytes key, byte[] value) =>\n            _client.SetValue(new SetValueRequest\n            {\n                Item = new KeyValueStorePair\n                {\n                    Key = key.ToKeyValueStoreKey(),\n                    Value = ByteString.CopyFrom(value).ToKeyValueStoreValue(),\n                },\n            });\n\n        /// <inheritdoc/>\n        public void Set(IDictionary<KeyBytes, byte[]> values) =>\n            _client.SetValues(new SetValuesRequest\n            {\n                Items =\n                {\n                    values.Select(kv =>\n                        new KeyValueStorePair\n                        {\n                            Key = kv.Key.ToKeyValueStoreKey(),\n                            Value = ByteString.CopyFrom(kv.Value).ToKeyValueStoreValue(),\n                        }),\n                },\n            });\n\n        /// <inheritdoc/>\n        public void Delete(in KeyBytes key) =>\n            _client.DeleteValue(new DeleteValueRequest\n            {\n                Key = key.ToKeyValueStoreKey(),\n            });\n\n        /// <inheritdoc/>\n        public void Delete(IEnumerable<KeyBytes> keys) =>\n            _client.DeleteValues(new DeleteValuesRequest\n            {\n                Keys = { keys.Select(KeyBytesExtensions.ToKeyValueStoreKey) },\n            });\n\n        /// <inheritdoc/>\n        public bool Exists(in KeyBytes key) =>\n            _client.ExistsKey(new ExistsKeyRequest\n            {\n                Key = key.ToKeyValueStoreKey(),\n            }).Exists;\n\n        /// <inheritdoc/>\n        public IEnumerable<KeyBytes> ListKeys() =>\n            _client\n                .ListKeys(new ListKeysRequest())\n                .Keys\n                .Select(kv => kv.ToKeyBytes());\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Store.Remote/Extensions/ByteStringExtensions.cs",
    "content": "using Google.Protobuf;\n\nnamespace Libplanet.Store.Remote.Extensions\n{\n    public static class ByteStringExtensions\n    {\n        public static KeyValueStoreValue ToKeyValueStoreValue(this ByteString @this) =>\n            new KeyValueStoreValue\n            {\n                Data = @this,\n            };\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Store.Remote/Extensions/KeyBytesExtensions.cs",
    "content": "using Google.Protobuf;\nusing Libplanet.Store.Trie;\n\nnamespace Libplanet.Store.Remote.Extensions\n{\n    public static class KeyBytesExtensions\n    {\n        public static ByteString ToByteString(this KeyBytes @this) =>\n            ByteString.CopyFrom(@this.ToByteArray());\n\n        public static KeyValueStoreKey ToKeyValueStoreKey(this KeyBytes @this) =>\n            new KeyValueStoreKey { Data = @this.ToByteString() };\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Store.Remote/Extensions/ProtoMessageExtensions.cs",
    "content": "using Libplanet.Store.Trie;\n\nnamespace Libplanet.Store.Remote.Extensions\n{\n    public static class ProtoMessageExtensions\n    {\n        public static KeyBytes ToKeyBytes(this KeyValueStoreKey @this) =>\n            new KeyBytes(@this.Data.ToByteArray());\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Store.Remote/Libplanet.Store.Remote.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <PropertyGroup>\n    <TargetFrameworks Condition=\"'$(_IsPacking)'=='true'\">net8.0</TargetFrameworks>\n    <LangVersion>10</LangVersion>\n    <ImplicitUsings>enable</ImplicitUsings>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <PackageReference Include=\"Grpc.AspNetCore\" Version=\"2.61.0\" />\n    <PackageReference Remove=\"StyleCop.Analyzers\" />\n  </ItemGroup>\n\n  <ItemGroup Condition=\"'$(SkipSonar)' != 'true'\">\n    <PackageReference Remove=\"SonarAnalyzer.CSharp\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <Protobuf Include=\"**/*.proto\" GrpcServices=\"Both\"/>\n    <ProjectReference Include=\"..\\Libplanet.Store\\Libplanet.Store.csproj\" />\n  </ItemGroup>\n\n</Project>\n"
  },
  {
    "path": "src/Libplanet.Store.Remote/Protos/Requests/key_value_requests.proto",
    "content": "syntax = \"proto3\";\n\nimport \"Protos/Types/pair.proto\";\n\npackage libplanet.rpc.v1;\n\noption csharp_namespace = \"Libplanet.Store.Remote\";\n\n\nmessage GetValueRequest {\n    KeyValueStoreKey key = 1;\n}\n\nmessage SetValueRequest {\n    KeyValueStorePair item = 1;\n}\n\nmessage SetValuesRequest {\n    repeated KeyValueStorePair items = 1;\n}\n\nmessage DeleteValueRequest {\n    KeyValueStoreKey key = 1;\n}\n\nmessage DeleteValuesRequest {\n    repeated KeyValueStoreKey keys = 1;\n}\n\nmessage ExistsKeyRequest {\n    KeyValueStoreKey key = 1;\n}\n\nmessage ListKeysRequest {\n}\n"
  },
  {
    "path": "src/Libplanet.Store.Remote/Protos/Responses/key_value_responses.proto",
    "content": "syntax = \"proto3\";\n\nimport \"Protos/Types/pair.proto\";\n\noption csharp_namespace = \"Libplanet.Store.Remote\";\n\npackage libplanet.rpc.v1;\n\nmessage SetValuesResponse {\n    repeated KeyValueStorePair pairs = 1;\n}\n\nmessage ExistsKeyResponse {\n  bool exists = 1;\n}\n\nmessage ListKeysResponse {\n  repeated KeyValueStoreKey keys = 1;\n}\n"
  },
  {
    "path": "src/Libplanet.Store.Remote/Protos/Types/pair.proto",
    "content": "syntax = \"proto3\";\n\npackage libplanet.rpc.v1;\n\noption csharp_namespace = \"Libplanet.Store.Remote\";\n\nmessage KeyValueStorePair {\n    KeyValueStoreKey key = 1;\n    KeyValueStoreValue value = 2;\n}\n\nmessage KeyValueStoreKey {\n    bytes data = 1;\n}\n\nmessage KeyValueStoreValue {\n    bytes data = 1;\n}\n"
  },
  {
    "path": "src/Libplanet.Store.Remote/Protos/kvstore.proto",
    "content": "syntax = \"proto3\";\n\nimport \"Protos/Responses/key_value_responses.proto\";\nimport \"Protos/Requests/key_value_requests.proto\";\nimport \"Protos/Types/pair.proto\";\nimport \"google/protobuf/empty.proto\";\n\npackage libplanet.rpc.v1;\n\noption csharp_namespace = \"Libplanet.Store.Remote\";\n\nservice KeyValueStore {\n  rpc GetValue(GetValueRequest) returns (KeyValueStoreValue) {\n  }\n\n  rpc SetValue(SetValueRequest) returns (KeyValueStoreValue) {\n  }\n\n  rpc SetValues(SetValuesRequest) returns (SetValuesResponse) {\n  }\n\n  rpc DeleteValue(DeleteValueRequest) returns (google.protobuf.Empty) {\n  }\n\n  rpc DeleteValues(DeleteValuesRequest) returns (google.protobuf.Empty) {\n  }\n\n  rpc ExistsKey(ExistsKeyRequest) returns (ExistsKeyResponse) {\n  }\n\n  rpc ListKeys(ListKeysRequest) returns (ListKeysResponse) {\n  }\n}\n"
  },
  {
    "path": "src/Libplanet.Store.Remote/README.md",
    "content": "Libplanet.Store.Remote\n======================\nA remote store service for Libplanet.\n\n# Table of Contents\n- [RemoteKeyValueStore](#remotekeyvaluestore)\n    * [Usage](#usage)\n        + [Server](#server)\n        + [Client](#client)\n\n# RemoteKeyValueStore\n## Usage\n### Server\nFirst, we need to make a server project.\n\n```csharp\nusing Libplanet.Store.Remote.Server;\nusing Libplanet.Store.Trie;\n\nvar builder = WebApplication.CreateBuilder(args);\n\n// Add services to the container.\nbuilder.Services.AddGrpc();\nbuilder.Services.AddSingleton<IKeyValueStore, MemoryKeyValueStore>();\n\n// If use `RocksDBStore`, try this:\n// builder.Services.AddSingleton<IKeyValueStore>(_ => new RocksDBKeyValueStore(\"path/to/rocksdb\"));\n\nvar app = builder.Build();\n\n// Configure the HTTP request pipeline.\napp.MapGrpcService<RemoteKeyValueService>();\napp.MapGet(\"/\", () => \"Communication with gRPC endpoints must be made through a gRPC client. To learn how to create a client, visit: https://go.microsoft.com/fwlink/?linkid=2086909\");\n\napp.Run();\n```\n\nThen you can test with any other gRPC client tool.\n\n![GRPC localhost:5239/libplanet.rpc.v1.KeyValueStore/Get is return some value](https://github.com/planetarium/libplanet/assets/16367497/e2692856-6971-41f0-a5a3-5536cc7cc64b)\n\n### Client\nJust use any project if you want to use the remote store.\n\nAsync example:\n```csharp\nusing Libplanet.Store.Remote.Client;\nusing Libplanet.Store.Trie;\n\nvar channel = GrpcChannel.ForAddress(\"https://localhost:5239\");\nvar client = new RemoteKeyValueStoreClient(channel);\n\nawait client\n        .SetAsync(new KeyBytes(1, 2, 3), new byte[] { 1, 2, 3, 4, 5 })\n        .ConfigureAwait(false);\n\nbyte[] value = await client\n        .GetAsync(new KeyBytes(1, 2, 3))\n        .ConfigureAwait(false);\n```\n\nSync example:\n```csharp\nusing Libplanet.Store.Remote.Client;\nusing Libplanet.Store.Trie;\n\nvar channel = GrpcChannel.ForAddress(\"https://localhost:5239\");\nvar client = new RemoteKeyValueStoreClient(channel);\n\nclient.Set(new KeyBytes(1, 2, 3), new byte[] { 1, 2, 3, 4, 5 });\n\nbyte[] value = client.Get(new KeyBytes(1, 2, 3));\n```\n"
  },
  {
    "path": "src/Libplanet.Store.Remote/Server/RemoteKeyValueService.cs",
    "content": "using Google.Protobuf;\nusing Google.Protobuf.Collections;\nusing Google.Protobuf.WellKnownTypes;\nusing Grpc.Core;\nusing Libplanet.Store.Remote.Extensions;\nusing Libplanet.Store.Trie;\nusing ILogger = Serilog.ILogger;\n\nnamespace Libplanet.Store.Remote.Server\n{\n    public class RemoteKeyValueService : KeyValueStore.KeyValueStoreBase\n    {\n        private readonly ILogger _logger;\n        private readonly IKeyValueStore _baseStore;\n\n        public RemoteKeyValueService(\n            ILogger logger,\n            IKeyValueStore baseStore)\n        {\n            _logger = logger;\n            _baseStore = baseStore;\n        }\n\n        public override Task<KeyValueStoreValue> GetValue(\n            GetValueRequest request,\n            ServerCallContext context)\n        {\n            var key = new KeyBytes(request.Key.Data.ToByteArray());\n            byte[] value;\n            try\n            {\n                value = _baseStore.Get(key);\n\n            }\n            catch (KeyNotFoundException e)\n            {\n                _logger.Error(e, \"Get: {Key}\", key);\n                throw new RpcException(new Status(StatusCode.NotFound, e.Message));\n            }\n\n            _logger.Verbose(\"Get: {Key} => {Value}\", key, value);\n            return Task.FromResult(new KeyValueStoreValue { Data = ByteString.CopyFrom(value) });\n        }\n\n        public override Task<KeyValueStoreValue> SetValue(\n            SetValueRequest request,\n            ServerCallContext context)\n        {\n            var key = new KeyBytes(request.Item.Key.Data.ToByteArray());\n            byte[] value = request.Item.Value.Data.ToByteArray();\n\n            try\n            {\n                _baseStore.Set(key, value);\n            }\n            catch (Exception e)\n            {\n                _logger.Error(e, \"Set: {Key} <= {Value}\", key, ByteString.CopyFrom(value));\n                throw new RpcException(new Status(StatusCode.Internal, e.Message));\n            }\n\n            _logger.Verbose(\"Set: {Key} <= {Value}\", key, ByteString.CopyFrom(value));\n            return Task.FromResult(new KeyValueStoreValue { Data = ByteString.CopyFrom(value) });\n        }\n\n        public override Task<SetValuesResponse> SetValues(\n            SetValuesRequest request,\n            ServerCallContext context)\n        {\n            RepeatedField<KeyValueStorePair>? items = request.Items;\n            if (items == null)\n            {\n                return Task.FromResult(new SetValuesResponse());\n            }\n\n            var dict = items\n                .ToDictionary(\n                    pair => new KeyBytes(pair.Key.Data.ToByteArray()),\n                    pair => pair.Value.Data.ToByteArray());\n\n            try\n            {\n                _baseStore.Set(dict);\n            }\n            catch (Exception e)\n            {\n                _logger.Error(e, \"SetValues: {Count}\", items.Count);\n                throw new RpcException(new Status(StatusCode.Internal, e.Message));\n            }\n\n            _logger.Verbose(\"SetValues: {Count}\", items.Count);\n            return Task.FromResult(new SetValuesResponse());\n        }\n\n        public override Task<Empty> DeleteValue(\n            DeleteValueRequest request,\n            ServerCallContext context)\n        {\n            var key = new KeyBytes(request.Key.Data.ToByteArray());\n            try\n            {\n                _baseStore.Delete(key);\n            }\n            catch (Exception e)\n            {\n                _logger.Error(e, \"Delete: {Key}\", key);\n                throw new RpcException(new Status(StatusCode.Internal, e.Message));\n            }\n\n            _logger.Verbose(\"Delete: {Key}\", key);\n            return Task.FromResult(new Empty());\n        }\n\n        public override Task<Empty> DeleteValues(\n            DeleteValuesRequest request,\n            ServerCallContext context)\n        {\n            RepeatedField<KeyValueStoreKey>? keys = request.Keys;\n            if (keys == null)\n            {\n                return Task.FromResult(new Empty());\n            }\n\n            IEnumerable<KeyBytes> keyBytes = keys\n                .Select(k => new KeyBytes(k.Data.ToByteArray()));\n            try\n            {\n                _baseStore.Delete(keyBytes);\n            }\n            catch (Exception e)\n            {\n                _logger.Error(e, \"DeleteValues: {Count}\", keys.Count);\n                throw new RpcException(new Status(StatusCode.Internal, e.Message));\n            }\n\n            _logger.Verbose(\"DeleteValues: {Count}\", keys.Count);\n            return Task.FromResult(new Empty());\n        }\n\n        public override Task<ExistsKeyResponse> ExistsKey(\n            ExistsKeyRequest request,\n            ServerCallContext context)\n        {\n            var key = new KeyBytes(request.Key.Data.ToByteArray());\n            bool exists;\n            try\n            {\n                exists = _baseStore.Exists(key);\n            }\n            catch (Exception e)\n            {\n                _logger.Error(e, \"Exists: {Key}\", key);\n                throw new RpcException(new Status(StatusCode.Internal, e.Message));\n            }\n\n            _logger.Verbose(\"Exists: {Key} => {Exists}\", key, exists);\n            return Task.FromResult(new ExistsKeyResponse { Exists = exists });\n        }\n\n        public override Task<ListKeysResponse> ListKeys(\n            ListKeysRequest request,\n            ServerCallContext context)\n        {\n            IEnumerable<KeyBytes> keys = _baseStore.ListKeys();\n            var response = new ListKeysResponse();\n            response.Keys.AddRange(\n                keys\n                    .Select(KeyBytesExtensions.ToByteString)\n                    .Select(key => new KeyValueStoreKey{ Data = key }));\n            _logger.Verbose(\"ListKeys: {Count}\", response.Keys.Count);\n            return Task.FromResult(response);\n        }\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Store.Remote/Server/Startup.cs",
    "content": "using Libplanet.Store.Remote.Client;\nusing Libplanet.Store.Trie;\nusing Microsoft.AspNetCore.Builder;\nusing Microsoft.AspNetCore.Hosting;\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.Hosting;\n\nnamespace Libplanet.Store.Remote.Server\n{\n    public class Startup\n    {\n        public void ConfigureServices(IServiceCollection services)\n        {\n            if(services.Any(service => service.ServiceType == typeof(IKeyValueStore)))\n            {\n                services.AddSingleton<IKeyValueStore, RemoteKeyValueStore>();\n            }\n\n            services.AddGrpc(o => o.EnableDetailedErrors = true);\n        }\n\n        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)\n        {\n            if (env.IsDevelopment())\n            {\n                app.UseDeveloperExceptionPage();\n            }\n\n            app.UseRouting();\n\n            app.UseEndpoints(endpoints =>\n            {\n                endpoints.MapGrpcService<RemoteKeyValueService>();\n            });\n        }\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Stun/AssemblyInfo.cs",
    "content": "using System.Runtime.CompilerServices;\n\n[assembly: InternalsVisibleTo(\"Libplanet.Stun.Tests\")]\n"
  },
  {
    "path": "src/Libplanet.Stun/IIceServer.cs",
    "content": "using System;\n\nnamespace Libplanet.Stun\n{\n    public interface IIceServer\n    {\n        public Uri Url { get; }\n\n        public string Username { get; }\n\n        public string Credential { get; }\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Stun/IceServerException.cs",
    "content": "using System;\n\nnamespace Libplanet.Stun\n{\n    public class IceServerException : Exception\n    {\n        public IceServerException(string message)\n            : base(message)\n        {\n        }\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Stun/Libplanet.Stun.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <PropertyGroup>\n    <Summary>A STUN/TURN client implementation for Libplanet.</Summary>\n    <Description>A STUN/TURN client implementation for Libplanet.</Description>\n  </PropertyGroup>\n\n  <PropertyGroup>\n    <TreatWarningsAsErrors>true</TreatWarningsAsErrors>\n    <NoWarn>$(NoWarn);MEN001</NoWarn>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <PackageReference Include=\"Serilog\" Version=\"2.8.0\" />\n    <PackageReference Include=\"Nito.AsyncEx\" Version=\"5.0.0\" />\n  </ItemGroup>\n\n</Project>\n"
  },
  {
    "path": "src/Libplanet.Stun/Stun/Attributes/Attribute.cs",
    "content": "#nullable disable\nusing System.IO;\n\nnamespace Libplanet.Stun.Attributes\n{\n    public abstract class Attribute\n    {\n        /// <summary>\n        /// Enum values that correspond to <see cref=\"Attribute\"/> subclasses.\n        /// </summary>\n        /// <remarks>\n        /// See also\n        /// <a href=\"https://www.iana.org/assignments/stun-parameters/stun-parameters.xhtml\">\n        /// IANA STUN Attributes</a>.\n        /// </remarks>\n        public enum AttributeType : ushort\n        {\n            /// <summary>\n            /// An <see cref=\"Attribute\"/> used for message integrity, identifies a combination\n            /// of username and password.\n            /// </summary>\n            /// <remarks>\n            /// See also <a href=\"https://tools.ietf.org/html/rfc5389#section-15.3\">RFC 5389</a>.\n            /// </remarks>\n            Username = 0x0006,\n\n            /// <summary>\n            /// An <see cref=\"Attribute\"/> which contains an HMAC-SHA1 of the STUN message.\n            /// </summary>\n            /// <remarks>\n            /// See also <a href=\"https://tools.ietf.org/html/rfc5389#section-15.4\">RFC 5389</a>.\n            /// </remarks>\n            MessageIntegrity = 0x0008,\n\n            /// <summary>\n            /// An <see cref=\"Attribute\"/> which contains a numeric error code value in range of\n            /// 300 to 699 and a textual reason phrase encoded in UTF-8.\n            /// </summary>\n            /// <remarks>\n            /// See also <a href=\"https://tools.ietf.org/html/rfc5389#section-15.6\">RFC 5389</a>.\n            /// </remarks>\n            ErrorCode = 0x0009,\n\n            /// <summary>\n            /// An <see cref=\"Attribute\"/> which specifies the address and port of the peer as seen\n            /// from the TURN server, obfuscated through the XOR function.\n            /// </summary>\n            /// <remarks>\n            /// See also <a href=\"https://tools.ietf.org/html/rfc5766#section-14.3\">RFC 5766</a>.\n            /// </remarks>\n            XorPeerAddress = 0x0012,\n\n            /// <summary>\n            /// An <see cref=\"Attribute\"/> which contains an unquoted realm-value, UTF-8 encoded\n            /// sequence of less than 128 characters. If this attribute presences in a request,\n            /// there was used long-term credentials for authentication. And it is to wish the\n            /// client to use long-term credentials for authentication if there is this attribute\n            /// in certain error-response.\n            /// </summary>\n            /// <remarks>\n            /// See also <a href=\"https://tools.ietf.org/html/rfc5389#section-15.7\">RFC 5389</a>.\n            /// </remarks>\n            Realm = 0x0014,\n\n            /// <summary>\n            /// An <see cref=\"Attribute\"/> which contains a sequence of qdtext of quoted-pair and\n            /// protects replay attacks.\n            /// </summary>\n            /// <remarks>\n            /// See also <a href=\"https://tools.ietf.org/html/rfc5389#section-15.8\">RFC 5389</a>.\n            /// </remarks>\n            Nonce = 0x0015,\n\n            /// <summary>\n            /// An <see cref=\"Attribute\"/> in allocate-responses, which specifies the address and\n            /// port than the server allocated to the client, obfuscated through the XOR function.\n            /// </summary>\n            /// <remarks>\n            /// See also <a href=\"https://tools.ietf.org/html/rfc5766#section-14.5\">RFC 5766</a>.\n            /// </remarks>\n            XorRelayedAddress = 0x0016,\n\n            /// <summary>\n            /// An <see cref=\"Attribute\"/> used by the client to request a specific transport\n            /// protocol for the allocated transport address.\n            /// </summary>\n            /// <remarks>\n            /// See also <a href=\"https://tools.ietf.org/html/rfc5766#section-14.7\">RFC 5766</a>.\n            /// </remarks>\n            RequestedTransport = 0x0019,\n\n            /// <summary>\n            /// An <see cref=\"Attribute\"/> which indicates a reflexive transport address obfuscated\n            /// through the XOR function.\n            /// </summary>\n            /// <remarks>\n            /// See also <a href=\"https://tools.ietf.org/html/rfc5389#section-15.2\">RFC 5389</a>.\n            /// </remarks>\n            XorMappedAddress = 0x0020,\n\n            /// <summary>\n            /// An <see cref=\"Attribute\"/> which uniquely identifies a peer data connection.\n            /// </summary>\n            /// <remarks>\n            /// See also <a href=\"https://tools.ietf.org/html/rfc6062#section-6.2.1\">RFC 6062</a>.\n            /// </remarks>\n            ConnectionId = 0x002a,\n\n            /// <summary>\n            /// An <see cref=\"Attribute\"/> which represents the duration for which the server will\n            /// maintain an allocation in the absence of a refresh.\n            /// </summary>\n            /// <remarks>\n            /// See also <a href=\"https://tools.ietf.org/html/rfc5766#section-14.2\">RFC 5766</a>.\n            /// </remarks>\n            Lifetime = 0x000d,\n\n            /// <summary>\n            /// An <see cref=\"Attribute\"/> which contains a textual description of the software\n            /// being used by the agent sending the message. It should include manufacturer and\n            /// version number. Also it has no impact on operation of the protocol, and serves only\n            /// as a tool for diagnostic and debugging purposes.\n            /// </summary>\n            /// <remarks>\n            /// See also <a href=\"https://tools.ietf.org/html/rfc5389#section-15.10\">RFC 5389</a>.\n            /// </remarks>\n            Software = 0x8022,\n\n            /// <summary>\n            /// An <see cref=\"Attribute\"/> may be present in all STUN messages.\n            /// It has the value computed as the CRC-32 of the STUN message.\n            /// Also it aids in distinguishing STUN packets from packets of other protocols.\n            /// </summary>\n            /// <remarks>\n            /// See also <a href=\"https://tools.ietf.org/html/rfc5389#section-15.5\">RFC 5389</a>.\n            /// </remarks>\n            Fingerprint = 0x8028,\n        }\n\n        public abstract AttributeType Type { get; }\n\n        public byte[] ToByteArray(byte[] transactionId = null)\n        {\n            var payload = EncodePayload(transactionId);\n            using var ms = new MemoryStream();\n            ms.Write(((ushort)Type).ToBytes(), 0, 2);\n            ms.Write(((ushort)payload.Length).ToBytes(), 0, 2);\n            ms.Write(payload, 0, payload.Length);\n\n            // Fill padding\n            while (ms.Position % 4 != 0)\n            {\n                ms.WriteByte(0x00);\n            }\n\n            return ms.ToArray();\n        }\n\n        protected abstract byte[] EncodePayload(byte[] transactionId);\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Stun/Stun/Attributes/ConnectionId.cs",
    "content": "#nullable disable\n\nnamespace Libplanet.Stun.Attributes\n{\n    public class ConnectionId : Attribute\n    {\n        public ConnectionId(byte[] value)\n        {\n            Value = value;\n        }\n\n        public override AttributeType Type => AttributeType.ConnectionId;\n\n        public byte[] Value { get; }\n\n        protected override byte[] EncodePayload(byte[] transactionId)\n        {\n            return Value;\n        }\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Stun/Stun/Attributes/ErrorCode.cs",
    "content": "#nullable disable\nusing System.IO;\nusing System.Text;\n\nnamespace Libplanet.Stun.Attributes\n{\n    public class ErrorCode : Attribute\n    {\n        public ErrorCode(int code, string reason)\n        {\n            Code = code;\n            Reason = reason;\n        }\n\n        public override AttributeType Type => AttributeType.ErrorCode;\n\n        public int Code { get; }\n\n        public string Reason { get; }\n\n        internal static ErrorCode Parse(byte[] payload)\n        {\n            byte @class = payload[2];\n            byte code = payload[3];\n            string reason = Encoding.ASCII.GetString(\n                payload, 4, payload.Length - 4);\n\n            return new ErrorCode(@class * 100 + code, reason);\n        }\n\n        protected override byte[] EncodePayload(byte[] transactionId)\n        {\n            using var ms = new MemoryStream();\n            ms.WriteByte(0x00);\n            ms.WriteByte(0x00);\n            ms.WriteByte((byte)(Code / 100));\n            ms.WriteByte((byte)(Code % 100));\n\n            var reason = Encoding.ASCII.GetBytes(Reason);\n            ms.Write(reason, 0, reason.Length);\n\n            return ms.ToArray();\n        }\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Stun/Stun/Attributes/Fingerprint.cs",
    "content": "#nullable disable\n\nnamespace Libplanet.Stun.Attributes\n{\n    public class Fingerprint : Attribute\n    {\n        private readonly uint _checksum;\n\n        public Fingerprint(uint checksum)\n        {\n            _checksum = checksum;\n        }\n\n        public override AttributeType Type => AttributeType.Fingerprint;\n\n        public static Fingerprint FromMessage(byte[] message)\n        {\n            return new Fingerprint(Crc32.Calculate(message) ^ 0x5354554e);\n        }\n\n        internal static Attribute Parse(byte[] payload)\n        {\n            return new Fingerprint(payload.ToUInt());\n        }\n\n        protected override byte[] EncodePayload(byte[] transactionId)\n        {\n            return _checksum.ToBytes();\n        }\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Stun/Stun/Attributes/InvalidStunAddressException.cs",
    "content": "using System;\n\nnamespace Libplanet.Stun.Attributes\n{\n    public class InvalidStunAddressException : Exception\n    {\n        public InvalidStunAddressException(string message)\n            : base(message)\n        {\n        }\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Stun/Stun/Attributes/Lifetime.cs",
    "content": "#nullable disable\n\nnamespace Libplanet.Stun.Attributes\n{\n    public class Lifetime : Attribute\n    {\n        public Lifetime(int value)\n        {\n            Value = value;\n        }\n\n        public override AttributeType Type => AttributeType.Lifetime;\n\n        public int Value { get; }\n\n        protected override byte[] EncodePayload(byte[] transactionId)\n        {\n            return ((uint)Value).ToBytes();\n        }\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Stun/Stun/Attributes/MessageIntegrity.cs",
    "content": "#nullable disable\nusing System.Security.Cryptography;\nusing System.Text;\n\nnamespace Libplanet.Stun.Attributes\n{\n    public class MessageIntegrity : Attribute\n    {\n        public MessageIntegrity(byte[] value)\n        {\n            Value = value;\n        }\n\n        public override AttributeType Type => AttributeType.MessageIntegrity;\n\n        public byte[] Value { get; }\n\n        public static MessageIntegrity Calculate(\n            string username,\n            string password,\n            string realm,\n            byte[] msg)\n        {\n            byte[] key = Encoding.ASCII.GetBytes(\n                $\"{username}:{realm}:{password}\"\n            );\n            using MD5 md5 = MD5.Create();\n            byte[] hmacKey = md5.ComputeHash(key);\n            using var hmac = new HMACSHA1(hmacKey);\n            return new MessageIntegrity(hmac.ComputeHash(msg));\n        }\n\n        protected override byte[] EncodePayload(byte[] transactionId)\n        {\n            return Value;\n        }\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Stun/Stun/Attributes/Nonce.cs",
    "content": "#nullable disable\n\nnamespace Libplanet.Stun.Attributes\n{\n    public class Nonce : Attribute\n    {\n        public Nonce(byte[] value)\n        {\n            Value = value;\n        }\n\n        public override AttributeType Type => AttributeType.Nonce;\n\n        public byte[] Value { get; }\n\n        internal static Nonce Parse(byte[] value)\n        {\n            return new Nonce(value);\n        }\n\n        protected override byte[] EncodePayload(byte[] transactionId)\n        {\n            return Value;\n        }\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Stun/Stun/Attributes/Realm.cs",
    "content": "#nullable disable\nusing System.Text;\n\nnamespace Libplanet.Stun.Attributes\n{\n    public class Realm : Attribute\n    {\n        public Realm(string value)\n        {\n            Value = value;\n        }\n\n        public override AttributeType Type => AttributeType.Realm;\n\n        public string Value { get; }\n\n        internal static Realm Parse(byte[] payload)\n        {\n            return new Realm(Encoding.ASCII.GetString(payload));\n        }\n\n        protected override byte[] EncodePayload(byte[] transactionId)\n        {\n            return Encoding.ASCII.GetBytes(Value);\n        }\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Stun/Stun/Attributes/RequestedTransport.cs",
    "content": "#nullable disable\n\nnamespace Libplanet.Stun.Attributes\n{\n    public class RequestedTransport : Attribute\n    {\n        private readonly TransportType _transportType;\n\n        public RequestedTransport(TransportType transportType)\n        {\n            _transportType = transportType;\n        }\n\n        public enum TransportType : byte\n        {\n            #pragma warning disable SA1602\n            TCP = 0x06,\n            #pragma warning restore SA1602\n        }\n\n        public override AttributeType Type => AttributeType.RequestedTransport;\n\n        protected override byte[] EncodePayload(byte[] transactionId)\n        {\n            return new byte[] { (byte)_transportType, 0x00, 0x00, 0x00 };\n        }\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Stun/Stun/Attributes/Software.cs",
    "content": "#nullable disable\nusing System.Text;\n\nnamespace Libplanet.Stun.Attributes\n{\n    public class Software : Attribute\n    {\n        public Software(string value)\n        {\n            Value = value;\n        }\n\n        public override AttributeType Type => AttributeType.Software;\n\n        public string Value { get; }\n\n        internal static Software Parse(byte[] payload)\n        {\n            return new Software(Encoding.ASCII.GetString(payload));\n        }\n\n        protected override byte[] EncodePayload(byte[] transactionId)\n        {\n            return Encoding.ASCII.GetBytes(Value);\n        }\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Stun/Stun/Attributes/StunAddressExtensions.cs",
    "content": "#nullable disable\nusing System;\nusing System.IO;\nusing System.Linq;\nusing System.Net;\nusing System.Net.Sockets;\nusing Libplanet.Stun.Messages;\n\nnamespace Libplanet.Stun.Attributes\n{\n    internal static class StunAddressExtensions\n    {\n        private enum StunAf : byte\n        {\n            IpV4 = 0x01,\n            IpV6 = 0x02,\n        }\n\n        public static byte[] EncodeStunAddress(\n            this IPEndPoint endpoint, byte[] transactionId\n        )\n        {\n            uint cookie = StunMessage.MagicCookie.ToUInt();\n            bool inTransaction = transactionId != null;\n\n            ushort port = inTransaction\n                ? (ushort)(endpoint.Port ^ (cookie >> 16))\n                : (ushort)endpoint.Port;\n            byte[] portBytes = port.ToBytes();\n\n            byte[] addrBytes;\n            switch (endpoint.AddressFamily)\n            {\n                case AddressFamily.InterNetwork:\n                    addrBytes = inTransaction\n                        ? (endpoint.Address.GetAddressBytes().ToUInt() ^ cookie)\n                        .ToBytes()\n                        : endpoint.Address.GetAddressBytes().ToUInt().ToBytes();\n                    break;\n\n                case AddressFamily.InterNetworkV6:\n                    if (transactionId is null)\n                    {\n                        throw new ArgumentNullException(nameof(transactionId));\n                    }\n\n                    addrBytes = new byte[16];\n                    Buffer.BlockCopy(\n                        StunMessage.MagicCookie,\n                        0,\n                        addrBytes,\n                        0,\n                        4);\n                    Buffer.BlockCopy(\n                        transactionId,\n                        0,\n                        addrBytes,\n                        4,\n                        12);\n\n                    foreach (var index in Enumerable.Range(0, 16))\n                    {\n                        addrBytes[index] ^=\n                            endpoint.Address.GetAddressBytes()[index];\n                    }\n\n                    break;\n\n                default:\n                    throw new NotSupportedException();\n            }\n\n            using var ms = new MemoryStream();\n            ms.WriteByte(0x00);\n            if (endpoint.AddressFamily == AddressFamily.InterNetwork)\n            {\n                ms.WriteByte((byte)StunAf.IpV4);\n                ms.Write(portBytes, 0, 2);\n                ms.Write(addrBytes, 0, 4);\n            }\n            else if (endpoint.AddressFamily == AddressFamily.InterNetworkV6)\n            {\n                ms.WriteByte((byte)StunAf.IpV6);\n                ms.Write(portBytes, 0, 2);\n                ms.Write(addrBytes, 0, 16);\n            }\n            else\n            {\n                throw new NotSupportedException();\n            }\n\n            return ms.ToArray();\n        }\n\n        public static IPEndPoint DecodeStunAddress(\n            this byte[] encoded, byte[] transactionId\n        )\n        {\n            uint cookie = StunMessage.MagicCookie.ToUInt();\n            bool inTransaction = transactionId != null;\n\n            using var ms = new MemoryStream(encoded);\n            ms.ReadByte();\n\n            StunAf family = (StunAf)ms.ReadByte();\n            var portBytes = new byte[2];\n            ms.Read(portBytes, 0, 2);\n\n            int port = inTransaction\n                ? (int)(portBytes.ToUShort() ^ (cookie >> 16))\n                : portBytes.ToUShort();\n\n            byte[] addrBytes = null;\n            switch (family)\n            {\n                case StunAf.IpV4:\n                    addrBytes = new byte[4];\n                    ms.Read(addrBytes, 0, 4);\n\n                    uint addr = inTransaction\n                        ? addrBytes.ToUInt() ^ cookie\n                        : addrBytes.ToUInt();\n                    addrBytes = addr.ToBytes();\n                    break;\n\n                case StunAf.IpV6:\n                    addrBytes = new byte[16];\n                    ms.Read(addrBytes, 0, 16);\n\n                    foreach (var index in\n                        Enumerable.Range(0, 16))\n                    {\n                        addrBytes[index] ^= index < 4\n                            ? StunMessage.MagicCookie[index]\n                            : transactionId[index - 4];\n                    }\n\n                    break;\n\n                default:\n                    throw new InvalidStunAddressException(\n                        $\"Unknown address family {family}.\");\n            }\n\n            return new IPEndPoint(\n                new IPAddress(addrBytes),\n                port);\n        }\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Stun/Stun/Attributes/Username.cs",
    "content": "#nullable disable\nusing System.Text;\n\nnamespace Libplanet.Stun.Attributes\n{\n    public class Username : Attribute\n    {\n        private readonly string _value;\n\n        public Username(string value)\n        {\n            _value = value;\n        }\n\n        public override AttributeType Type => AttributeType.Username;\n\n        protected override byte[] EncodePayload(byte[] transactionId)\n        {\n            return Encoding.ASCII.GetBytes(_value);\n        }\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Stun/Stun/Attributes/XorMappedAddress.cs",
    "content": "#nullable disable\nusing System.Net;\n\nnamespace Libplanet.Stun.Attributes\n{\n    public class XorMappedAddress : Attribute\n    {\n        public XorMappedAddress(IPEndPoint endPoint)\n        {\n            EndPoint = endPoint;\n        }\n\n        public override AttributeType Type => AttributeType.XorMappedAddress;\n\n        public IPEndPoint EndPoint { get; }\n\n        public static XorMappedAddress Parse(\n            byte[] bytes, byte[] transactionId)\n        {\n            return new XorMappedAddress(\n                bytes.DecodeStunAddress(transactionId));\n        }\n\n        protected override byte[] EncodePayload(byte[] transactionId)\n        {\n            return EndPoint.EncodeStunAddress(transactionId);\n        }\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Stun/Stun/Attributes/XorPeerAddress.cs",
    "content": "#nullable disable\nusing System.Net;\n\nnamespace Libplanet.Stun.Attributes\n{\n    public class XorPeerAddress : Attribute\n    {\n        public XorPeerAddress(IPEndPoint endPoint)\n        {\n            EndPoint = endPoint;\n        }\n\n        public override AttributeType Type => AttributeType.XorPeerAddress;\n\n        public IPEndPoint EndPoint { get; }\n\n        public static XorPeerAddress Parse(\n            byte[] bytes, byte[] transactionId)\n        {\n            return new XorPeerAddress(\n                bytes.DecodeStunAddress(transactionId));\n        }\n\n        protected override byte[] EncodePayload(byte[] transactionId)\n        {\n            return EndPoint.EncodeStunAddress(transactionId);\n        }\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Stun/Stun/Attributes/XorRelayedAddress.cs",
    "content": "#nullable disable\nusing System.Net;\n\nnamespace Libplanet.Stun.Attributes\n{\n    public class XorRelayedAddress : Attribute\n    {\n        public XorRelayedAddress(IPEndPoint endPoint)\n        {\n            EndPoint = endPoint;\n        }\n\n        public override AttributeType Type => AttributeType.XorRelayedAddress;\n\n        public IPEndPoint EndPoint { get; }\n\n        public static XorRelayedAddress Parse(\n            byte[] bytes, byte[] transactionId)\n        {\n            return new XorRelayedAddress(\n                bytes.DecodeStunAddress(transactionId));\n        }\n\n        protected override byte[] EncodePayload(byte[] transactionId)\n        {\n            return EndPoint.EncodeStunAddress(transactionId);\n        }\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Stun/Stun/BytesConvertExtensions.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Linq;\n\nnamespace Libplanet.Stun\n{\n    internal static class BytesConvertExtensions\n    {\n        public static byte[] ToBytes(this ushort value)\n        {\n            var rv = new byte[sizeof(ushort)];\n\n            rv[0] = (byte)((0xff00 & value) >> 8);\n            rv[1] = (byte)(0x00ff & value);\n\n            return rv;\n        }\n\n        public static byte[] ToBytes(this uint value)\n        {\n            var rv = new byte[sizeof(uint)];\n\n            rv[0] = (byte)((0xff000000 & value) >> 24);\n            rv[1] = (byte)((0x00ff0000 & value) >> 16);\n            rv[2] = (byte)((0x0000ff00 & value) >> 8);\n            rv[3] = (byte)(0x000000ff & value);\n\n            return rv;\n        }\n\n        public static ushort ToUShort(this IEnumerable<byte> bytes)\n        {\n            byte[] bs = bytes.ToArray();\n\n            if (bs.Length != sizeof(ushort))\n            {\n                throw new ArgumentOutOfRangeException(nameof(bytes));\n            }\n\n            ushort rv = bs[0];\n            rv = (ushort)(rv << 8);\n            rv |= bs[1];\n\n            return rv;\n        }\n\n        public static uint ToUInt(this IEnumerable<byte> bytes)\n        {\n            byte[] bs = bytes.ToArray();\n\n            if (bs.Length != sizeof(uint))\n            {\n                throw new ArgumentOutOfRangeException(nameof(bytes));\n            }\n\n            uint rv = bs[0];\n            rv = rv << 8;\n            rv |= bs[1];\n            rv = rv << 8;\n            rv |= bs[2];\n            rv = rv << 8;\n            rv |= bs[3];\n\n            return rv;\n        }\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Stun/Stun/Crc32.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Linq;\n\nnamespace Libplanet.Stun\n{\n    public static class Crc32\n    {\n        private const uint _generator = 0xEDB88320;\n        private static readonly uint[] _checksumTable;\n\n        static Crc32()\n        {\n            _checksumTable = Enumerable.Range(0, 256).Select(\n                i =>\n                {\n                    var tableEntry = (uint)i;\n                    for (int j = 0; j < 8; ++j)\n                    {\n                        tableEntry = ((tableEntry & 1) != 0)\n                        ? (_generator ^ (tableEntry >> 1))\n                        : (tableEntry >> 1);\n                    }\n\n                    return tableEntry;\n                }).ToArray();\n        }\n\n        public static uint Calculate(IEnumerable<byte> bytes)\n        {\n            return ~bytes.Aggregate(\n                0xFFFFFFFF,\n                (register, current) =>\n                {\n                    var index = (register & 0xFF) ^ Convert.ToByte(current);\n                    return _checksumTable[index] ^ (register >> 8);\n                });\n        }\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Stun/Stun/IStunContext.cs",
    "content": "#nullable disable\n\nnamespace Libplanet.Stun\n{\n    public interface IStunContext\n    {\n        string Username { get; }\n\n        string Password { get; }\n\n        string Realm { get; }\n\n        byte[] Nonce { get; }\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Stun/Stun/Messages/AllocateErrorResponse.cs",
    "content": "#nullable disable\nusing Libplanet.Stun.Attributes;\n\nnamespace Libplanet.Stun.Messages\n{\n    public class AllocateErrorResponse : StunMessage\n    {\n        public override MessageClass Class => MessageClass.ErrorResponse;\n\n        public override MessageMethod Method => MessageMethod.Allocate;\n\n        public int ErrorCode\n        {\n            get\n            {\n                ErrorCode attr = GetAttribute<ErrorCode>();\n                return attr.Code;\n            }\n        }\n\n        public string Reason\n        {\n            get\n            {\n                ErrorCode attr = GetAttribute<ErrorCode>();\n                return attr?.Reason;\n            }\n        }\n\n        public byte[] Nonce\n        {\n            get\n            {\n                Attributes.Nonce attr = GetAttribute<Attributes.Nonce>();\n                return attr?.Value;\n            }\n        }\n\n        public string Realm\n        {\n            get\n            {\n                Realm attr = GetAttribute<Realm>();\n                return attr?.Value;\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Stun/Stun/Messages/AllocateRequest.cs",
    "content": "#nullable disable\nusing System.Collections.Generic;\nusing Libplanet.Stun.Attributes;\n\nnamespace Libplanet.Stun.Messages\n{\n    public class AllocateRequest : StunMessage\n    {\n        public AllocateRequest(int lifetime)\n        {\n            Attributes = new List<Attribute>()\n            {\n                // Assume only TCP as relay protocol.\n                new RequestedTransport(RequestedTransport.TransportType.TCP),\n                new Lifetime(lifetime),\n            };\n        }\n\n        public override MessageMethod Method => MessageMethod.Allocate;\n\n        public override MessageClass Class => MessageClass.Request;\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Stun/Stun/Messages/AllocateSuccessResponse.cs",
    "content": "#nullable disable\nusing System.Net;\nusing Libplanet.Stun.Attributes;\n\nnamespace Libplanet.Stun.Messages\n{\n    public class AllocateSuccessResponse : StunMessage\n    {\n        public override MessageClass Class => MessageClass.SuccessResponse;\n\n        public override MessageMethod Method => MessageMethod.Allocate;\n\n        public IPEndPoint RelayedEndPoint\n        {\n            get\n            {\n                return GetAttribute<XorRelayedAddress>()?.EndPoint;\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Stun/Stun/Messages/BindingRequest.cs",
    "content": "#nullable disable\nusing System.Collections.Generic;\nusing Libplanet.Stun.Attributes;\n\nnamespace Libplanet.Stun.Messages\n{\n    public class BindingRequest : StunMessage\n    {\n        public BindingRequest()\n        {\n            Attributes = new List<Attribute>();\n        }\n\n        public override MessageClass Class => MessageClass.Request;\n\n        public override MessageMethod Method => MessageMethod.Binding;\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Stun/Stun/Messages/BindingSuccessResponse.cs",
    "content": "#nullable disable\nusing System.Net;\nusing Libplanet.Stun.Attributes;\n\nnamespace Libplanet.Stun.Messages\n{\n    public class BindingSuccessResponse : StunMessage\n    {\n        public override MessageClass Class => MessageClass.SuccessResponse;\n\n        public override MessageMethod Method => MessageMethod.Binding;\n\n        public IPEndPoint MappedAddress\n        {\n            get\n            {\n                return GetAttribute<XorMappedAddress>()?.EndPoint;\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Stun/Stun/Messages/ConnectRequest.cs",
    "content": "#nullable disable\nusing System.Collections.Generic;\nusing System.Net;\nusing Libplanet.Stun.Attributes;\n\nnamespace Libplanet.Stun.Messages\n{\n    public class ConnectRequest : StunMessage\n    {\n        public ConnectRequest(IPEndPoint peerEndPoint)\n        {\n            Attributes = new List<Attribute>()\n            {\n                new XorPeerAddress(peerEndPoint),\n            };\n        }\n\n        public override MessageClass Class => MessageClass.Request;\n\n        public override MessageMethod Method => MessageMethod.Connect;\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Stun/Stun/Messages/ConnectSuccessResponse.cs",
    "content": "#nullable disable\n\nnamespace Libplanet.Stun.Messages\n{\n    public class ConnectSuccessResponse : StunMessage\n    {\n        public override MessageClass Class => MessageClass.SuccessResponse;\n\n        public override MessageMethod Method => MessageMethod.Connect;\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Stun/Stun/Messages/ConnectionAttempt.cs",
    "content": "#nullable disable\nusing Libplanet.Stun.Attributes;\n\nnamespace Libplanet.Stun.Messages\n{\n    public class ConnectionAttempt : StunMessage\n    {\n        public override MessageClass Class => MessageClass.Indication;\n\n        public override MessageMethod Method =>\n            MessageMethod.ConnectionAttempt;\n\n        public byte[] ConnectionId\n        {\n            get\n            {\n                return GetAttribute<ConnectionId>()?.Value;\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Stun/Stun/Messages/ConnectionBindRequest.cs",
    "content": "#nullable disable\nusing System.Collections.Generic;\nusing Libplanet.Stun.Attributes;\n\nnamespace Libplanet.Stun.Messages\n{\n    public class ConnectionBindRequest : StunMessage\n    {\n        public ConnectionBindRequest(byte[] connectionId)\n        {\n            Attributes = new List<Attribute>()\n            {\n                new ConnectionId(connectionId),\n            };\n        }\n\n        public override MessageClass Class => MessageClass.Request;\n\n        public override MessageMethod Method => MessageMethod.ConnectionBind;\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Stun/Stun/Messages/ConnectionBindSuccessResponse.cs",
    "content": "#nullable disable\n\nnamespace Libplanet.Stun.Messages\n{\n    public class ConnectionBindSuccessResponse : StunMessage\n    {\n        public override MessageClass Class => MessageClass.SuccessResponse;\n\n        public override MessageMethod Method => MessageMethod.ConnectionBind;\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Stun/Stun/Messages/CreatePermissionErrorResponse.cs",
    "content": "#nullable disable\n\nnamespace Libplanet.Stun.Messages\n{\n    public class CreatePermissionErrorResponse : StunMessage\n    {\n        public override MessageClass Class => MessageClass.ErrorResponse;\n\n        public override MessageMethod Method => MessageMethod.CreatePermission;\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Stun/Stun/Messages/CreatePermissionRequest.cs",
    "content": "#nullable disable\nusing System.Collections.Generic;\nusing System.Net;\nusing Libplanet.Stun.Attributes;\n\nnamespace Libplanet.Stun.Messages\n{\n    public class CreatePermissionRequest : StunMessage\n    {\n        public CreatePermissionRequest(IPEndPoint peerEndPoint)\n        {\n            Attributes = new List<Attribute>()\n            {\n                new XorPeerAddress(peerEndPoint),\n            };\n        }\n\n        public override MessageClass Class => MessageClass.Request;\n\n        public override MessageMethod Method => MessageMethod.CreatePermission;\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Stun/Stun/Messages/CreatePermissionSuccessResponse.cs",
    "content": "#nullable disable\n\nnamespace Libplanet.Stun.Messages\n{\n    public class CreatePermissionSuccessResponse : StunMessage\n    {\n        public override MessageClass Class => MessageClass.SuccessResponse;\n\n        public override MessageMethod Method => MessageMethod.CreatePermission;\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Stun/Stun/Messages/RefreshErrorResponse.cs",
    "content": "#nullable disable\nusing Libplanet.Stun.Attributes;\n\nnamespace Libplanet.Stun.Messages\n{\n    public class RefreshErrorResponse : StunMessage\n    {\n        public override MessageClass Class => MessageClass.ErrorResponse;\n\n        public override MessageMethod Method => MessageMethod.Refresh;\n\n        public int ErrorCode\n        {\n            get\n            {\n                ErrorCode attr = GetAttribute<ErrorCode>();\n                return attr.Code;\n            }\n        }\n\n        public byte[] Nonce\n        {\n            get\n            {\n                Nonce attr = GetAttribute<Nonce>();\n                return attr.Value;\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Stun/Stun/Messages/RefreshRequest.cs",
    "content": "#nullable disable\nusing System.Collections.Generic;\nusing Libplanet.Stun.Attributes;\n\nnamespace Libplanet.Stun.Messages\n{\n    public class RefreshRequest : StunMessage\n    {\n        public RefreshRequest(int lifetime)\n        {\n            Attributes = new List<Attribute>()\n            {\n                new Lifetime(lifetime),\n            };\n        }\n\n        public override MessageClass Class => MessageClass.Request;\n\n        public override MessageMethod Method => MessageMethod.Refresh;\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Stun/Stun/Messages/RefreshSuccessResponse.cs",
    "content": "#nullable disable\nusing Libplanet.Stun.Attributes;\n\nnamespace Libplanet.Stun.Messages\n{\n    public class RefreshSuccessResponse : StunMessage\n    {\n        public override MessageClass Class => MessageClass.SuccessResponse;\n\n        public override MessageMethod Method => MessageMethod.Refresh;\n\n        public int Lifetime => GetAttribute<Lifetime>().Value;\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Stun/Stun/Messages/StunMessage.cs",
    "content": "#nullable disable\nusing System.Collections.Generic;\nusing System.IO;\nusing System.Linq;\nusing System.Security.Cryptography;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing Libplanet.Stun.Attributes;\n\nnamespace Libplanet.Stun.Messages\n{\n    public abstract class StunMessage\n    {\n        private const int HeaderBytes = 20;\n        private const int MessageIntegrityBytes = 24;\n        private const int FingerprintBytes = 8;\n\n        protected StunMessage()\n        {\n            var transactionId = new byte[12];\n#if NETSTANDARD2_0_OR_GREATER\n            using var rng = new RNGCryptoServiceProvider();\n#elif NET6_0_OR_GREATER || NETCOREAPP3_1_OR_GREATER\n            using var rng = RandomNumberGenerator.Create();\n#endif\n            rng.GetBytes(transactionId);\n            TransactionId = transactionId;\n        }\n\n        // TODO Should document following STUN / TURN RFC\n        // https://www.iana.org/assignments/stun-parameters/stun-parameters.xhtml\n#pragma warning disable SA1602\n        public enum MessageClass : byte\n        {\n            Request = 0x0,\n            Indication = 0x1,\n            SuccessResponse = 0x2,\n            ErrorResponse = 0x3,\n        }\n\n        public enum MessageMethod : ushort\n        {\n            Binding = 0x001,\n            Allocate = 0x003,\n            Refresh = 0x004,\n            Send = 0x006,\n            Data = 0x007,\n            CreatePermission = 0x008,\n            ChannelBind = 0x009,\n            Connect = 0x00a,\n            ConnectionBind = 0x00b,\n            ConnectionAttempt = 0x00c,\n        }\n#pragma warning restore SA1602\n\n        /// <summary>\n        /// A <see cref=\"MessageClass\"/> of STUN packet.\n        /// </summary>\n        public abstract MessageClass Class { get; }\n\n        /// <summary>\n        /// A <see cref=\"MessageMethod\"/> of STUN packet.\n        /// </summary>\n        public abstract MessageMethod Method { get; }\n\n        /// <summary>\n        /// A 96-bit length identifier, used to uniquely identify STUN transactions.\n        /// </summary>\n        public byte[] TransactionId { get; internal set; }\n\n        /// <summary>\n        /// A fixed value to distinguish STUN packets from packets of another protocol.\n        /// </summary>\n        /// <remarks>It should be always 0x2112A442 in network byte order.</remarks>\n        internal static byte[] MagicCookie => new byte[]\n        {\n            0x21, 0x12, 0xa4, 0x42,\n        };\n\n        /// <summary>\n        /// A list of <see cref=\"Attribute\"/> of STUN packet.\n        /// </summary>\n        protected IEnumerable<Attribute> Attributes { get; set; }\n\n        /// <summary>\n        /// Parses <see cref=\"StunMessage\"/> from <paramref name=\"stream\"/>.\n        /// </summary>\n        /// <param name=\"stream\">A view of a sequence of STUN packet's bytes.</param>\n        /// <param name=\"cancellationToken\">\n        /// A cancellation token used to propagate notification that this\n        /// operation should be canceled.\n        /// </param>\n        /// <returns>A <see cref=\"StunMessage\"/> derived on\n        /// bytes read from <paramref name=\"stream\"/>.\n        /// </returns>\n        public static async Task<StunMessage> ParseAsync(\n            Stream stream,\n            CancellationToken cancellationToken = default)\n        {\n            var header = new byte[20];\n            await stream.ReadAsync(header, 0, 20, cancellationToken);\n\n            MessageMethod method = ParseMethod(header[0], header[1]);\n            MessageClass @class = ParseClass(header[0], header[1]);\n\n            var length = new byte[2];\n            System.Array.Copy(header, 2, length, 0, 2);\n\n            var transactionId = new byte[12];\n            System.Array.Copy(header, 8, transactionId, 0, 12);\n\n            var body = new byte[length.ToUShort()];\n            await stream.ReadAsync(body, 0, body.Length, cancellationToken);\n            IEnumerable<Attribute> attributes = ParseAttributes(\n                body,\n                transactionId\n            );\n\n            StunMessage rv = null;\n            rv = @class switch\n            {\n                MessageClass.SuccessResponse => method switch\n                {\n                    MessageMethod.Allocate => new AllocateSuccessResponse(),\n                    MessageMethod.Connect => new ConnectSuccessResponse(),\n                    MessageMethod.ConnectionBind => new ConnectionBindSuccessResponse(),\n                    MessageMethod.Binding => new BindingSuccessResponse(),\n                    MessageMethod.CreatePermission => new CreatePermissionSuccessResponse(),\n                    MessageMethod.Refresh => new RefreshSuccessResponse(),\n                    _ => rv,\n                },\n                MessageClass.ErrorResponse => method switch\n                {\n                    MessageMethod.Allocate => new AllocateErrorResponse(),\n                    MessageMethod.CreatePermission => new CreatePermissionErrorResponse(),\n                    MessageMethod.Refresh => new RefreshErrorResponse(),\n                    _ => rv,\n                },\n                MessageClass.Indication => method switch\n                {\n                    MessageMethod.ConnectionAttempt => new ConnectionAttempt(),\n                    _ => rv,\n                },\n                _ => rv,\n            };\n\n            if (rv is null)\n            {\n                throw new TurnClientException(\"Parsed result is null.\");\n            }\n\n            rv.TransactionId = transactionId;\n            rv.Attributes = attributes;\n\n            return rv;\n        }\n\n        public byte[] Encode(IStunContext ctx)\n        {\n            bool useMessageIntegrity =\n                !string.IsNullOrEmpty(ctx?.Username) &&\n                !string.IsNullOrEmpty(ctx?.Password) &&\n                !string.IsNullOrEmpty(ctx?.Realm);\n\n            var c = (ushort)Class;\n            var m = (ushort)Method;\n            int type =\n                (m & 0x0f80) << 2 |\n                (m & 0x0070) << 1 |\n                (m & 0x000f) << 0 |\n                (c & 0x2) << 7 |\n                (c & 0x1) << 4;\n\n            using var ms = new MemoryStream();\n            List<Attribute> attrs = Attributes.ToList();\n\n            if (!string.IsNullOrEmpty(ctx?.Username))\n            {\n                attrs.Add(new Username(ctx.Username));\n            }\n\n            if (ctx?.Nonce != null)\n            {\n                attrs.Add(new Attributes.Nonce(ctx.Nonce));\n            }\n\n            if (!string.IsNullOrEmpty(ctx?.Realm))\n            {\n                attrs.Add(new Realm(ctx.Realm));\n            }\n\n            byte[] encodedAttrs;\n            using (var ams = new MemoryStream())\n            {\n                foreach (Attribute attr in attrs)\n                {\n                    byte[] asBytes = attr.ToByteArray(TransactionId);\n                    ams.Write(asBytes, 0, asBytes.Length);\n                }\n\n                encodedAttrs = ams.ToArray();\n            }\n\n            // 8 bytes for Fingerprint\n            var messageLength =\n                (ushort)(encodedAttrs.Length + FingerprintBytes);\n\n            if (useMessageIntegrity)\n            {\n                messageLength += MessageIntegrityBytes;\n            }\n\n            ms.Write(((ushort)type).ToBytes(), 0, 2);\n            ms.Write(messageLength.ToBytes(), 0, 2);\n            ms.Write(MagicCookie, 0, MagicCookie.Length);\n            ms.Write(TransactionId, 0, TransactionId.Length);\n            ms.Write(encodedAttrs, 0, encodedAttrs.Length);\n\n            if (useMessageIntegrity)\n            {\n                var lengthWithoutFingerprint =\n                    (ushort)(messageLength - FingerprintBytes);\n                byte[] toCalc = ms.ToArray();\n                lengthWithoutFingerprint.ToBytes().CopyTo(toCalc, 2);\n\n                MessageIntegrity mi =\n                    MessageIntegrity.Calculate(\n                        ctx?.Username,\n                        ctx?.Password,\n                        ctx?.Realm,\n                        toCalc);\n                ms.Write(mi.ToByteArray(), 0, MessageIntegrityBytes);\n            }\n\n            Fingerprint fingerprint = Fingerprint.FromMessage(\n                ms.ToArray()\n            );\n            ms.Write(fingerprint.ToByteArray(), 0, FingerprintBytes);\n\n            return ms.ToArray();\n        }\n\n        internal static IEnumerable<Attribute> ParseAttributes(\n            IEnumerable<byte> bytes,\n            byte[] transactionId = null\n        )\n        {\n            while (bytes.Any())\n            {\n                var type = (Attribute.AttributeType)bytes.Take(2).ToUShort();\n                ushort length = bytes.Skip(2).Take(2).ToUShort();\n                byte[] payload = bytes.Skip(4).Take(length).ToArray();\n\n                Attribute attr = type switch\n                {\n                    Attribute.AttributeType.ErrorCode => ErrorCode.Parse(payload),\n                    Attribute.AttributeType.Realm => Realm.Parse(payload),\n                    Attribute.AttributeType.Nonce => Stun.Attributes.Nonce.Parse(payload),\n                    Attribute.AttributeType.Software => Software.Parse(payload),\n                    Attribute.AttributeType.Fingerprint => Fingerprint.Parse(payload),\n                    Attribute.AttributeType.XorMappedAddress =>\n                        XorMappedAddress.Parse(payload, transactionId),\n                    Attribute.AttributeType.XorRelayedAddress =>\n                        XorRelayedAddress.Parse(payload, transactionId),\n                    Attribute.AttributeType.ConnectionId => new ConnectionId(payload),\n                    Attribute.AttributeType.Lifetime => new Lifetime((int)payload.ToUInt()),\n                    _ => null,\n                };\n\n                if (!(attr is null))\n                {\n                    yield return attr;\n                }\n\n                // Detect padding\n                var padBytes = (ushort)((4 + length) % 4);\n                if (padBytes > 0)\n                {\n                    length += padBytes;\n                }\n\n                bytes = bytes.Skip(4 + length);\n            }\n        }\n\n        internal static MessageClass ParseClass(byte high, byte low)\n        {\n            ushort type = high;\n            type = (ushort)(type << 8);\n            type |= low;\n\n            return (MessageClass)((type >> 7 | type >> 4) & 0x3);\n        }\n\n        internal static MessageMethod ParseMethod(byte high, byte low)\n        {\n            ushort type = high;\n            type = (ushort)(type << 8);\n            type |= low;\n\n            return (MessageMethod)(\n                (type & 0x3e00) >> 2 | (type & 0x00e0) >> 1 | (type & 0x000f));\n        }\n\n        protected T GetAttribute<T>()\n            where T : Attribute\n        {\n            foreach (Attribute attr in Attributes)\n            {\n                if (attr is T asT)\n                {\n                    return asT;\n                }\n            }\n\n            return null;\n        }\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Stun/Stun/TurnClient.cs",
    "content": "#nullable disable\nusing System;\nusing System.Collections.Concurrent;\nusing System.Collections.Generic;\nusing System.IO;\nusing System.Linq;\nusing System.Net;\nusing System.Net.Sockets;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing Libplanet.Stun.Messages;\nusing Nito.AsyncEx;\nusing Serilog;\n\nnamespace Libplanet.Stun\n{\n    public class TurnClient : IStunContext, IDisposable\n    {\n        public const int TurnDefaultPort = 3478;\n        private const int ConnectableProbeLength = 2;\n        private const int AllocateRetry = 5;\n        private const int ProxyCount = 16;\n\n        // TURN Permission lifetime was defined in RFC 5766\n        // see also https://tools.ietf.org/html/rfc5766#section-8\n        private static readonly TimeSpan TurnAllocationLifetime = TimeSpan.FromSeconds(777);\n        private readonly string _host;\n        private readonly int _port;\n        private readonly IList<TcpClient> _relayedClients;\n        private readonly IDictionary<byte[], TaskCompletionSource<StunMessage>>\n            _responses;\n\n        private readonly AsyncProducerConsumerQueue<ConnectionAttempt> _connectionAttempts;\n        private readonly ILogger _logger;\n\n        private TcpClient _control;\n        private Task _processMessage;\n        private CancellationTokenSource _turnTaskCts;\n        private List<Task> _turnTasks;\n\n        internal TurnClient(\n            string host,\n            string username,\n            string password,\n            int port = TurnDefaultPort)\n        {\n            _host = host;\n            _port = port;\n            Username = username;\n            Password = password;\n\n            _relayedClients = new List<TcpClient>();\n            _connectionAttempts =\n                new AsyncProducerConsumerQueue<ConnectionAttempt>();\n            _responses =\n                new ConcurrentDictionary<byte[], TaskCompletionSource<StunMessage>>(\n                    new ByteArrayComparer());\n\n            _turnTaskCts = new CancellationTokenSource();\n            _logger = Log.ForContext<TurnClient>();\n        }\n\n        public string Username { get; }\n\n        public string Password { get; }\n\n        public string Realm { get; private set; }\n\n        public byte[] Nonce { get; private set; }\n\n        public IPAddress PublicAddress { get; private set; }\n\n        public DnsEndPoint EndPoint { get; private set; }\n\n        public bool BehindNAT { get; private set; }\n\n        /// <summary>\n        /// Creates a <see cref=\"TurnClient\"/> that is connectable to one of\n        /// the <see cref=\"IceServer\"/>s given.\n        /// </summary>\n        /// <remarks>\n        /// This is a blocking operation with a non-negligible amount of execution time as\n        /// each <see cref=\"IceServer\"/> in <paramref name=\"iceServers\"/> is checked over\n        /// the network to see if it can be connected to.\n        /// </remarks>\n        /// <param name=\"iceServers\">The list of <see cref=\"IIceServer\"/>s to check.</param>\n        /// <param name=\"cancellationToken\">A cancellation token used to propagate notification\n        /// that this operation should be canceled.</param>\n        /// <returns>An awaitable <see cref=\"Task\"/> that returns <see cref=\"TurnClient\"/>\n        /// pointing to a connectable <see cref=\"IIceServer\"/>.</returns>\n        /// <exception cref=\"IceServerException\">Thrown when no <see cref=\"TurnClient\"/> can\n        /// be created that can connect to any <see cref=\"IIceServer\"/> among\n        /// <paramref name=\"iceServers\"/>.</exception>\n        public static async Task<TurnClient> Create(\n            IEnumerable<IIceServer> iceServers,\n            CancellationToken cancellationToken = default)\n        {\n            foreach (IIceServer server in iceServers)\n            {\n                Uri url = server.Url;\n                int port = url.IsDefaultPort\n                    ? TurnClient.TurnDefaultPort\n                    : url.Port;\n                TurnClient turnClient = new TurnClient(\n                    url.Host,\n                    server.Username,\n                    server.Credential,\n                    port);\n\n                if (await turnClient.IsConnectable(cancellationToken: cancellationToken))\n                {\n                    Log.Debug(\"TURN client created: {Host}:{Port}\", url.Host, url.Port);\n                    return turnClient;\n                }\n            }\n\n            throw new IceServerException(\"Could not find a suitable ICE server.\");\n        }\n\n        public async Task InitializeTurnAsync(CancellationToken cancellationToken)\n        {\n            _control = new TcpClient();\n            await _control.ConnectAsync(_host, _port);\n            _processMessage = ProcessMessage(_turnTaskCts.Token);\n\n            BehindNAT = await IsBehindNAT(cancellationToken);\n            PublicAddress = (await GetMappedAddressAsync(cancellationToken)).Address;\n\n            IPEndPoint ep = await AllocateRequestAsync(TurnAllocationLifetime, cancellationToken);\n            EndPoint = new DnsEndPoint(ep.Address.ToString(), ep.Port);\n        }\n\n        public async Task StartAsync(int listenPort, CancellationToken cancellationToken)\n        {\n            await InitializeTurnAsync(cancellationToken);\n            _ = ReconnectTurn(listenPort, cancellationToken);\n        }\n\n        public async Task ReconnectTurn(int listenPort, CancellationToken cancellationToken)\n        {\n            while (!cancellationToken.IsCancellationRequested)\n            {\n                try\n                {\n                    if (BehindNAT)\n                    {\n                        _turnTasks = BindMultipleProxies(\n                            listenPort, ProxyCount, _turnTaskCts.Token);\n                        _turnTasks.Add(RefreshAllocate(_turnTaskCts.Token));\n                    }\n\n                    _turnTasks.Add(_processMessage);\n\n                    await Task.WhenAny(_turnTasks);\n                }\n                catch (Exception e)\n                {\n                    _logger.Error(\n                        e, $\"An unexpected exception occurred during {nameof(StartAsync)}()\");\n                }\n                finally\n                {\n                    _logger.Debug(\"TURN tasks cancelled. Re-initializing TURN...\");\n                    ClearSession();\n                    _turnTaskCts = new CancellationTokenSource();\n\n                    try\n                    {\n                        await InitializeTurnAsync(cancellationToken);\n                    }\n                    catch (Exception e)\n                    {\n                        _logger.Error(e, \"Failed to initialize due to an error; retry...\");\n                        await Task.Delay(1000, cancellationToken);\n                    }\n                }\n            }\n        }\n\n        public async Task<IPEndPoint> AllocateRequestAsync(\n            TimeSpan lifetime,\n            CancellationToken cancellationToken = default)\n        {\n            NetworkStream stream = _control.GetStream();\n            StunMessage response;\n            int retry = 0;\n            do\n            {\n                var request = new AllocateRequest((int)lifetime.TotalSeconds);\n                await SendMessageAsync(stream, request, cancellationToken);\n                response = await ReceiveMessageAsync(request.TransactionId, cancellationToken);\n\n                if (response is AllocateErrorResponse allocError)\n                {\n                    Realm = allocError.Realm;\n                    Nonce = allocError.Nonce;\n                }\n\n                retry += 1;\n            }\n            while (response is AllocateErrorResponse && retry < AllocateRetry);\n\n            if (response is AllocateSuccessResponse allocOk)\n            {\n                return allocOk.RelayedEndPoint;\n            }\n            else\n            {\n                throw new TurnClientException(\"Allocate failed.\", response);\n            }\n        }\n\n        public async Task CreatePermissionAsync(\n            IPEndPoint peerAddress,\n            CancellationToken cancellationToken = default)\n        {\n            NetworkStream stream = _control.GetStream();\n            var request = new CreatePermissionRequest(peerAddress);\n            await SendMessageAsync(stream, request, cancellationToken);\n            StunMessage response = await ReceiveMessageAsync(\n                request.TransactionId,\n                cancellationToken);\n\n            if (response is CreatePermissionErrorResponse)\n            {\n                throw new TurnClientException(\n                    \"CreatePermission failed.\",\n                    response);\n            }\n        }\n\n        public async Task<NetworkStream> AcceptRelayedStreamAsync(\n            CancellationToken cancellationToken = default)\n        {\n            while (true)\n            {\n                ConnectionAttempt attempt =\n                    await _connectionAttempts.DequeueAsync(cancellationToken);\n\n                byte[] id = attempt.ConnectionId;\n                var bindRequest = new ConnectionBindRequest(id);\n                var relayedClient = new TcpClient(_host, _port);\n                _relayedClients.Add(relayedClient);\n                NetworkStream relayedStream = relayedClient.GetStream();\n\n                try\n                {\n                    await SendMessageAsync(relayedStream, bindRequest, cancellationToken);\n                    StunMessage bindResponse =\n                        await StunMessage.ParseAsync(relayedStream, cancellationToken);\n\n                    if (bindResponse is ConnectionBindSuccessResponse)\n                    {\n                        return relayedStream;\n                    }\n\n                    throw new TurnClientException(\"ConnectionBind failed.\", bindResponse);\n                }\n                catch (IOException e)\n                {\n                    _logger.Warning(\n                        e,\n                        \"The connection seems to disconnect before parsing; ignored\"\n                    );\n                }\n            }\n        }\n\n        public async Task<IPEndPoint> GetMappedAddressAsync(\n            CancellationToken cancellationToken = default)\n        {\n            NetworkStream stream = _control.GetStream();\n            var request = new BindingRequest();\n            await SendMessageAsync(stream, request, cancellationToken);\n            StunMessage response = await ReceiveMessageAsync(\n                request.TransactionId,\n                cancellationToken);\n\n            if (response is BindingSuccessResponse success)\n            {\n                _logger.Debug($\"Mapped address: {success.MappedAddress}\");\n                return success.MappedAddress;\n            }\n\n            throw new TurnClientException(\n                \"BindingRequest failed.\",\n                response);\n        }\n\n        public async Task<TimeSpan> RefreshAllocationAsync(\n            TimeSpan lifetime,\n            CancellationToken cancellationToken = default)\n        {\n            NetworkStream stream = _control.GetStream();\n            var request = new RefreshRequest((int)lifetime.TotalSeconds);\n            await SendMessageAsync(stream, request, cancellationToken);\n\n            StunMessage response = await ReceiveMessageAsync(\n                request.TransactionId,\n                cancellationToken);\n            if (response is RefreshSuccessResponse success)\n            {\n                return TimeSpan.FromSeconds(success.Lifetime);\n            }\n            else if (\n                response is RefreshErrorResponse error &&\n                error.ErrorCode == 438)\n            {\n                // Retry refreshing when stale nonce error(438) occurred.\n                Nonce = error.Nonce;\n                return await RefreshAllocationAsync(lifetime);\n            }\n\n            throw new TurnClientException(\"RefreshRequest failed.\", response);\n        }\n\n        public async Task<bool> IsBehindNAT(\n            CancellationToken cancellationToken = default)\n        {\n            IPEndPoint mapped = await GetMappedAddressAsync(cancellationToken);\n            return !_control.Client.LocalEndPoint.Equals(mapped);\n        }\n\n        public void Dispose()\n        {\n            _logger.Debug($\"Disposing {nameof(TurnClient)}...\");\n            ClearSession();\n            _logger.Debug($\"{nameof(TurnClient)} is disposed\");\n        }\n\n        private async Task<bool> IsConnectable(\n            CancellationToken cancellationToken = default)\n        {\n            using var cts = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken);\n            try\n            {\n                using var client = new TcpClient();\n#pragma warning disable PC001 // API not supported on all platforms\n                client.Connect(_host, _port);\n#pragma warning restore PC001 // API not supported on all platforms\n                NetworkStream stream = client.GetStream();\n\n                var request = new BindingRequest();\n                byte[] asBytes = request.Encode(this);\n                cts.CancelAfter(TimeSpan.FromSeconds(ConnectableProbeLength));\n                await stream.WriteAsync(asBytes, 0, asBytes.Length, cts.Token);\n                await StunMessage.ParseAsync(stream, cts.Token);\n                return true;\n            }\n            catch (Exception)\n            {\n                return false;\n            }\n        }\n\n        private List<Task> BindMultipleProxies(\n            int listenPort,\n            int count,\n            CancellationToken cancellationToken = default)\n        {\n            return Enumerable.Range(1, count)\n                .Select(x => BindProxies(listenPort, cancellationToken))\n                .ToList();\n        }\n\n        private async Task BindProxies(\n            int listenPort,\n            CancellationToken cancellationToken = default)\n        {\n            while (!cancellationToken.IsCancellationRequested)\n            {\n                var tcpClient = new TcpClient();\n#pragma warning disable PC001  // API not supported on all platforms\n                tcpClient.Connect(new IPEndPoint(IPAddress.Loopback, listenPort));\n#pragma warning restore PC001\n                NetworkStream localStream = tcpClient.GetStream();\n                NetworkStream turnStream = await AcceptRelayedStreamAsync(cancellationToken);\n#pragma warning disable CS4014\n\n                const int bufferSize = 8042;\n                Task.WhenAny(\n                    turnStream.CopyToAsync(localStream, bufferSize, cancellationToken),\n                    localStream.CopyToAsync(turnStream, bufferSize, cancellationToken)\n                ).ContinueWith(\n                    t =>\n                    {\n                        turnStream.Dispose();\n                        localStream.Dispose();\n                        tcpClient.Dispose();\n                    },\n                    cancellationToken\n                );\n#pragma warning restore CS4014\n            }\n        }\n\n        private async Task RefreshAllocate(CancellationToken cancellationToken)\n        {\n            TimeSpan lifetime = TurnAllocationLifetime;\n            while (!cancellationToken.IsCancellationRequested)\n            {\n                try\n                {\n                    await Task.Delay(lifetime - TimeSpan.FromMinutes(1), cancellationToken);\n                    _logger.Debug(\"Refreshing TURN allocation...\");\n                    lifetime = await RefreshAllocationAsync(lifetime);\n                    cancellationToken.ThrowIfCancellationRequested();\n                }\n                catch (OperationCanceledException e)\n                {\n                    _logger.Warning(e, \"{MethodName}() was cancelled\", nameof(RefreshAllocate));\n                    throw;\n                }\n                catch (Exception e)\n                {\n                    _logger.Error(\n                        e,\n                        $\"An unexpected exception occurred during {nameof(RefreshAllocate)}()\");\n                }\n            }\n        }\n\n        private async Task SendMessageAsync(\n            NetworkStream stream,\n            StunMessage message,\n            CancellationToken cancellationToken)\n        {\n            var tcs = new TaskCompletionSource<StunMessage>();\n            _responses[message.TransactionId] = tcs;\n            var asBytes = message.Encode(this);\n            await stream.WriteAsync(\n                asBytes,\n                0,\n                asBytes.Length,\n                cancellationToken);\n        }\n\n        private async Task ProcessMessage(CancellationToken cancellationToken)\n        {\n            while (!cancellationToken.IsCancellationRequested && _control.Connected)\n            {\n                try\n                {\n                    NetworkStream stream = _control.GetStream();\n                    StunMessage message;\n                    message = await StunMessage.ParseAsync(stream, cancellationToken);\n                    _logger.Debug(\"Parsed \" + nameof(StunMessage) + \": {Message}\", message);\n\n                    if (message is ConnectionAttempt attempt)\n                    {\n                        await _connectionAttempts.EnqueueAsync(attempt, cancellationToken);\n                    }\n                    else if (_responses.TryGetValue(\n                        message.TransactionId,\n                        out TaskCompletionSource<StunMessage> tcs))\n                    {\n                        // tcs may be already canceled.\n                        tcs.TrySetResult(message);\n                    }\n                }\n                catch (TurnClientException e)\n                {\n                    _logger.Error(e, \"Failed to parse \" + nameof(StunMessage));\n                    ClearResponses();\n                    break;\n                }\n                catch (Exception e)\n                {\n                    _logger.Error(\n                        e,\n                        $\"An unexpected exception occurred during {nameof(ProcessMessage)}()\");\n                }\n            }\n\n            _logger.Debug($\"{nameof(ProcessMessage)} is ended. Connected: {_control.Connected}\");\n        }\n\n        private async Task<StunMessage> ReceiveMessageAsync(\n            byte[] transactionId,\n            CancellationToken cancellationToken)\n        {\n            TaskCompletionSource<StunMessage> tcs = _responses[transactionId];\n            using CancellationTokenRegistration ctr =\n                cancellationToken.Register(() => tcs.TrySetCanceled());\n            StunMessage response = await tcs.Task;\n            _responses.Remove(transactionId);\n\n            return response;\n        }\n\n        private void ClearSession()\n        {\n            _control?.Dispose();\n            _turnTaskCts.Cancel();\n            _turnTaskCts.Dispose();\n            _turnTasks.Clear();\n            ClearResponses();\n\n            foreach (TcpClient relays in _relayedClients)\n            {\n                relays.Dispose();\n            }\n        }\n\n        private void ClearResponses()\n        {\n            foreach (TaskCompletionSource<StunMessage> tcs in _responses.Values)\n            {\n                tcs.TrySetCanceled();\n            }\n\n            _responses.Clear();\n        }\n\n        private class ByteArrayComparer : IEqualityComparer<byte[]>\n        {\n            public bool Equals(byte[] x, byte[] y)\n            {\n                if (x == null || y == null)\n                {\n                    return x == y;\n                }\n\n                return x.SequenceEqual(y);\n            }\n\n            public int GetHashCode(byte[] obj)\n            {\n                if (obj == null)\n                {\n                    throw new ArgumentNullException(nameof(obj));\n                }\n\n                return obj.Sum(b => b);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Stun/Stun/TurnClientException.cs",
    "content": "using System;\nusing Libplanet.Stun.Messages;\n\nnamespace Libplanet.Stun\n{\n    public class TurnClientException : Exception\n    {\n        public TurnClientException(string message, StunMessage? response = null)\n            : base(message)\n        {\n            Response = response;\n        }\n\n        public StunMessage? Response { get; }\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Types/AssemblyInfo.cs",
    "content": "using System.Runtime.CompilerServices;\n\n[assembly: InternalsVisibleTo(\"Libplanet.Tests\")]\n[assembly: InternalsVisibleTo(\"Libplanet.Explorer.Tests\")]\n"
  },
  {
    "path": "src/Libplanet.Types/Assets/Currency.cs",
    "content": "using System;\nusing System.Collections.Immutable;\nusing System.Diagnostics.CodeAnalysis;\nusing System.Diagnostics.Contracts;\nusing System.IO;\nusing System.Linq;\nusing System.Numerics;\nusing System.Security.Cryptography;\nusing System.Text.Json;\nusing System.Text.Json.Serialization;\nusing Bencodex;\nusing Bencodex.Types;\nusing Libplanet.Common;\nusing Libplanet.Crypto;\n\nnamespace Libplanet.Types.Assets\n{\n    /// <summary>\n    /// Represents a currency type.  Every single value of <see cref=\"Currency\"/> defines\n    /// a distinct currency type.  To draw a parallel with real world monetary,\n    /// each <see cref=\"Currency\"/> value represents such currencies as USD (US Dollar) or\n    /// EUR (Euro), <em>not values</em> like $100 or €100.\n    /// </summary>\n    /// <example>\n    /// Here is how US Dollar can be represented using <see cref=\"Currency\"/>:\n    /// <code>\n    /// var USMint = new PrivateKey();\n    /// var USD = Currency.Uncapped(ticker: \"USD\", decimalPlaces: 2, minter: USMint.Address);\n    /// var twentyThreeBucks = 23 * USD;\n    /// // Or alternatively: USD * 23;\n    /// // Or explicitly: new FungibleAssetValue(USD, 23, 0)\n    /// </code>\n    /// </example>\n    /// <remarks>There are two types of <see cref=\"Currency\">Currencies</see>: capped and uncapped.\n    /// Capped currencies have a hard limit on the maximum minted amount, and uncapped currencies\n    /// do not have the said limit. To define a <see cref=\"Currency\"/> you may call either of the\n    /// following.\n    /// <list type=\"bullet\">\n    /// <item><see\n    /// cref=\"Capped(string,byte,ValueTuple{BigInteger, BigInteger},IImmutableSet{Address}?)\"/>\n    /// </item>\n    /// <item><see cref=\"Capped(string,byte,ValueTuple{BigInteger, BigInteger},Address)\"/></item>\n    /// <item><see cref=\"Uncapped(string,byte,IImmutableSet{Address}?)\"/></item>\n    /// <item><see cref=\"Uncapped(string,byte,Address)\"/></item>\n    /// </list>\n    /// </remarks>\n    /// <seealso cref=\"FungibleAssetValue\"/>\n    public readonly struct Currency : IEquatable<Currency>\n    {\n        /// <summary>\n        /// The ticker symbol, e.g., <c>&quot;USD&quot;</c>.\n        /// </summary>\n        [JsonInclude]\n        public readonly string Ticker;\n\n        /// <summary>\n        /// The number of digits to treat as <a\n        /// href=\"https://w.wiki/ZXv#Treatment_of_minor_currency_units_(the_%22exponent%22)\">minor\n        /// units (i.e., exponent)</a>.\n        /// </summary>\n        [JsonInclude]\n        public readonly byte DecimalPlaces;\n\n        /// <summary>\n        /// The <see cref=\"Address\"/>es who can mint the currency.\n        /// If this is <see langword=\"null\"/> <em>anyone</em> can mint the currency.\n        /// </summary>\n        /// <remarks>\n        /// Unlike <see langword=\"null\"/>, an empty set means <em>no one</em> can mint the currency.\n        /// </remarks>\n        /// <seealso cref=\"Libplanet.Action.State.IAccount.MintAsset\"/>\n        [JsonInclude]\n        public readonly IImmutableSet<Address>? Minters;\n\n        /// <summary>\n        /// The deterministic hash derived from other fields.\n        /// </summary>\n        [JsonInclude]\n        public readonly HashDigest<SHA1> Hash;\n\n        /// <summary>\n        /// Whether the total supply of this instance of <see cref=\"Currency\"/> is trackable.\n        /// </summary>\n        [JsonInclude]\n        public readonly bool TotalSupplyTrackable;\n\n        private readonly (BigInteger Major, BigInteger Minor)? _maximumSupply;\n\n        /// <summary>\n        /// Deserializes a <see cref=\"Currency\"/> type from a Bencodex value.\n        /// </summary>\n        /// <param name=\"serialized\">The Bencodex value serialized by <see cref=\"Serialize()\"/>\n        /// method.</param>\n        /// <seealso cref=\"Serialize()\"/>\n        public Currency(IValue serialized)\n        {\n            BigInteger? maximumSupplyMajor = null, maximumSupplyMinor = null;\n\n            if (!(serialized is Dictionary d))\n            {\n                throw new ArgumentException(\"Expected a Bencodex dictionary.\", nameof(serialized));\n            }\n\n            if (!(d.ContainsKey(\"ticker\") && d[\"ticker\"] is Text ticker))\n            {\n                throw new ArgumentException(\n                    \"Expected a text field named \\\"ticker\\\".\",\n                    nameof(serialized)\n                );\n            }\n\n            byte? nullableDecimals = null;\n            if (d.ContainsKey(\"decimals\") && d[\"decimals\"] is Integer decimals)\n            {\n                nullableDecimals = (byte)(long)decimals;\n            }\n\n            if (d.ContainsKey(\"decimalPlaces\") && d[\"decimalPlaces\"] is Binary decimalPlacesBinary)\n            {\n                nullableDecimals = decimalPlacesBinary.ByteArray[0];\n            }\n\n            if (!(nullableDecimals is { } decimalPlaces))\n            {\n                throw new ArgumentException(\n                    \"Expected a byte field named \\\"decimalPlaces\\\" or \\\"decimals\\\".\",\n                    nameof(serialized)\n                );\n            }\n\n            if (!d.ContainsKey(\"minters\") ||\n                !(d[\"minters\"] is { } minters) ||\n                !(minters is Null || minters is List))\n            {\n                throw new ArgumentException(\n                    \"Expected a nullable list field named \\\"minters\\\".\",\n                    nameof(serialized)\n                );\n            }\n\n            TotalSupplyTrackable = false;\n            if (d.ContainsKey(\"totalSupplyTrackable\"))\n            {\n                if (d[\"totalSupplyTrackable\"] is Bencodex.Types.Boolean totalSupplyTrackable\n                    && totalSupplyTrackable)\n                {\n                    TotalSupplyTrackable = totalSupplyTrackable;\n                }\n                else\n                {\n                    throw new ArgumentException(\n                        \"Field \\\"totalSupplyTrackable\\\" must have a boolean value of true\"\n                        + \" if it exists.\",\n                        nameof(serialized));\n                }\n            }\n\n            if (d.ContainsKey(\"maximumSupplyMajor\"))\n            {\n                if (d[\"maximumSupplyMajor\"] is Integer maximumSupplyMajorValue\n                    && maximumSupplyMajorValue >= 0)\n                {\n                    maximumSupplyMajor = maximumSupplyMajorValue.Value;\n                }\n                else\n                {\n                    throw new ArgumentException(\n                        \"Field \\\"maximumSupplyMajor\\\" must be of non-negative integer type\"\n                        + \" if it exists.\",\n                        nameof(serialized)\n                    );\n                }\n            }\n\n            if (d.ContainsKey(\"maximumSupplyMinor\"))\n            {\n                if (d[\"maximumSupplyMinor\"] is Integer maximumSupplyMinorValue\n                    && maximumSupplyMinorValue >= 0)\n                {\n                    maximumSupplyMinor = maximumSupplyMinorValue.Value;\n                }\n                else\n                {\n                    throw new ArgumentException(\n                        \"Field \\\"maximumSupplyMinor\\\" must be of non-negative integer type\"\n                        + \" if it exists.\",\n                        nameof(serialized)\n                    );\n                }\n            }\n\n            if (maximumSupplyMajor is { } && maximumSupplyMinor is { })\n            {\n                if (!TotalSupplyTrackable)\n                {\n                    throw new ArgumentException(\n                        $\"Maximum supply is not available for legacy untracked currencies.\",\n                        nameof(serialized));\n                }\n\n                _maximumSupply = (maximumSupplyMajor.Value, maximumSupplyMinor.Value);\n            }\n            else if (maximumSupplyMajor is null && maximumSupplyMinor is null)\n            {\n                _maximumSupply = null;\n            }\n            else\n            {\n                throw new ArgumentException(\n                    \"Both \\\"maximumSupplyMajor\\\" and \\\"maximumSupplyMinor\\\" must be \"\n                    + \" omitted or be non-negative integers.\",\n                    nameof(serialized)\n                );\n            }\n\n            Ticker = ticker;\n            DecimalPlaces = decimalPlaces;\n\n            if (_maximumSupply is var (_, minor) && minor > 0 &&\n                Math.Floor(BigInteger.Log10(minor)) >= DecimalPlaces)\n            {\n                var msg = $\"The given minor unit {minor} of the maximum supply value is too\"\n                          + $\" big for the given decimal places {DecimalPlaces}.\";\n                throw new ArgumentException(msg, nameof(minor));\n            }\n\n            if (minters is List l)\n            {\n                Minters = l.Select(\n                    m => m is Binary b\n                        ? new Address(b.ByteArray)\n                        : throw new ArgumentException(\n                            \"Expected \\\"minters\\\" to be a list of binary arrays.\",\n                            nameof(serialized))\n                ).ToImmutableHashSet();\n            }\n            else\n            {\n                Minters = null;\n            }\n\n            Hash = GetHash(Minters, Ticker, DecimalPlaces, _maximumSupply, TotalSupplyTrackable);\n        }\n\n        /// <summary>\n        /// An internal constructor for JSON deserialization.  Do not use this directly.\n        /// </summary>\n        [JsonConstructor]\n        [Obsolete]\n#pragma warning disable SA1611\n        public Currency(\n            HashDigest<SHA1> hash,\n            string ticker,\n            byte decimalPlaces,\n            IImmutableSet<Address>? minters,\n            bool totalSupplyTrackable,\n            FungibleAssetValue? maximumSupply\n        )\n#pragma warning restore SA1611\n#pragma warning disable SA1118\n            : this(\n                ticker,\n                decimalPlaces,\n                maximumSupply is { } v\n                    ? (v.MajorUnit, v.MinorUnit)\n                    : ((BigInteger, BigInteger)?)null,\n                minters\n            )\n#pragma warning restore SA1118\n        {\n            TotalSupplyTrackable = totalSupplyTrackable;\n            HashDigest<SHA1> expectedHash = GetHash(\n                Minters, Ticker, DecimalPlaces, _maximumSupply, TotalSupplyTrackable);\n            if (!expectedHash.Equals(hash))\n            {\n                var msg = $\"Invalid currency hash; expected {expectedHash}, but got {hash}. \" +\n                      \"This probably means the given data is inconsistent with the given hash.\\n\" +\n                      $\"  ticker: {Ticker}\\n  decimalPlaces: {decimalPlaces}\\n\" +\n                      $\"  minters: {(Minters is { } m ? string.Join(\", \", m) : \"N/A\")}\\n\" +\n                      $\"  totalSupplyTrackable: {TotalSupplyTrackable}\\n\" +\n                      $\"  maximumSupply: {MaximumSupply?.ToString() ?? \"N/A\"}\";\n                throw new JsonException(msg);\n            }\n\n            Hash = hash;\n        }\n\n        /// <summary>\n        /// Private implementation to create a capped instance of <see cref=\"Currency\"/> or\n        /// a deserialized instance.\n        /// </summary>\n        /// <param name=\"ticker\">The ticker symbol, e.g., <c>&quot;USD&quot;</c>.</param>\n        /// <param name=\"decimalPlaces\">The number of digits to treat as <a\n        /// href=\"https://w.wiki/ZXv#Treatment_of_minor_currency_units_(the_%22exponent%22)\">minor\n        /// units (i.e., exponent)</a>.</param>\n        /// <param name=\"maximumSupply\">The uppermost quantity of currency allowed to exist. For\n        /// example, a <paramref name=\"maximumSupply\"/> parameter of <c>(123, 45)</c> means that the\n        /// token of the currency can be minted up to <c>123.45</c>. See also\n        /// <see cref=\"MaximumSupply\"/> field which corresponds to this.</param>\n        /// <param name=\"minters\">The <see cref=\"Address\"/>es who can mint the currency.\n        /// See also <see cref=\"Minters\"/> field which corresponds to this.</param>\n        /// <exception cref=\"ArgumentException\">Thrown when the given <paramref name=\"ticker\"/>\n        /// is an empty string, or when either the Major or the Minor values of\n        /// <paramref name=\"maximumSupply\"/> is a negative number, or when the given Minor unit for\n        /// the <paramref name=\"maximumSupply\"/> is too big for the given\n        /// <paramref name=\"decimalPlaces\"/>.</exception>\n        private Currency(\n            string ticker,\n            byte decimalPlaces,\n            (BigInteger Major, BigInteger Minor)? maximumSupply,\n            IImmutableSet<Address>? minters)\n            : this(ticker, decimalPlaces, minters, true)\n        {\n            if (maximumSupply is var (major, minor))\n            {\n                if (major < 0 || minor < 0)\n                {\n                    var msg = $\"Both the major ({major}) and minor ({minor}) units of\"\n                              + $\" {nameof(maximumSupply)} must not be a negative number.\";\n                    throw new ArgumentException(msg, nameof(maximumSupply));\n                }\n\n                if (minor > 0 && Math.Floor(BigInteger.Log10(minor)) >= decimalPlaces)\n                {\n                    var msg = $\"The given minor unit {minor} of the maximum supply value is too\"\n                              + $\" big for the given decimal places {decimalPlaces}.\";\n                    throw new ArgumentException(msg, nameof(minor));\n                }\n\n                _maximumSupply = maximumSupply;\n            }\n\n            Hash = GetHash(Minters, Ticker, DecimalPlaces, _maximumSupply, TotalSupplyTrackable);\n        }\n\n        /// <summary>\n        /// Private implementation to create a general instance of <see cref=\"Currency\"/>.\n        /// </summary>\n        /// <param name=\"ticker\">The ticker symbol, e.g., <c>&quot;USD&quot;</c>.</param>\n        /// <param name=\"decimalPlaces\">The number of digits to treat as <a\n        /// href=\"https://w.wiki/ZXv#Treatment_of_minor_currency_units_(the_%22exponent%22)\">minor\n        /// units (i.e., exponent)</a>.</param>\n        /// <param name=\"minters\">The <see cref=\"Address\"/>es who can mint the currency.\n        /// See also <see cref=\"Minters\"/> field which corresponds to this.</param>\n        /// <param name=\"totalSupplyTrackable\">A feature flag whether this instance of\n        /// <see cref=\"Currency\"/> supports total supply tracking. Legacy behavior is characterized\n        /// with a value of false.</param>\n        /// <exception cref=\"ArgumentException\">Thrown when the given <paramref name=\"ticker\"/>\n        /// is an empty string.</exception>\n        private Currency(\n            string ticker,\n            byte decimalPlaces,\n            IImmutableSet<Address>? minters,\n            bool totalSupplyTrackable)\n        {\n            ticker = ticker.Trim();\n\n            if (string.IsNullOrEmpty(ticker))\n            {\n                throw new ArgumentException(\n                    \"Currency ticker symbol cannot be empty.\",\n                    nameof(ticker)\n                );\n            }\n\n            Ticker = ticker;\n            Minters = minters;\n            DecimalPlaces = decimalPlaces;\n            _maximumSupply = null;\n            TotalSupplyTrackable = totalSupplyTrackable;\n            Hash = GetHash(Minters, Ticker, DecimalPlaces, _maximumSupply, TotalSupplyTrackable);\n        }\n\n        /// <summary>\n        /// The uppermost quantity of currency allowed to exist.\n        /// <see langword=\"null\"/> means unlimited supply.\n        /// </summary>\n        [JsonConverter(typeof(MaximumSupplyJsonConverter))]\n        public FungibleAssetValue? MaximumSupply =>\n            _maximumSupply.HasValue\n                ? new FungibleAssetValue(\n                    this,\n                    _maximumSupply.Value.Major,\n                    _maximumSupply.Value.Minor\n                    )\n                : (FungibleAssetValue?)null;\n\n        /// <summary>\n        /// Gets a fungible asset value with the given <paramref name=\"quantity\"/> of the\n        /// specified <paramref name=\"currency\"/>.\n        /// </summary>\n        /// <param name=\"currency\">The currency to get a value.</param>\n        /// <param name=\"quantity\">The major unit of the fungible asset value,\n        /// i.e., digits <em>before</em> the decimal separator.</param>\n        /// <returns>A fungible asset value with the given <paramref name=\"quantity\"/> of the\n        /// specified <paramref name=\"currency\"/>.</returns>\n        /// <remarks>This cannot specify <see cref=\"FungibleAssetValue.MinorUnit\"/> but only\n        /// <see cref=\"FungibleAssetValue.MajorUnit\"/>.  For more precision, directly use <see\n        /// cref=\"FungibleAssetValue\"/>'s constructors instead.</remarks>\n        [Pure]\n        public static FungibleAssetValue operator *(Currency currency, BigInteger quantity) =>\n            new FungibleAssetValue(currency, majorUnit: quantity, minorUnit: 0);\n\n        /// <summary>\n        /// Gets a fungible asset value with the given <paramref name=\"quantity\"/> of the\n        /// specified <paramref name=\"currency\"/>.\n        /// </summary>\n        /// <param name=\"quantity\">The major unit of the fungible asset value,\n        /// i.e., digits <em>before</em> the decimal separator.</param>\n        /// <param name=\"currency\">The currency to get a value.</param>\n        /// <returns>A fungible asset value with the given <paramref name=\"quantity\"/> of the\n        /// specified <paramref name=\"currency\"/>.</returns>\n        /// <remarks>This cannot specify <see cref=\"FungibleAssetValue.MinorUnit\"/> but only\n        /// <see cref=\"FungibleAssetValue.MajorUnit\"/>.  For more precision, directly use <see\n        /// cref=\"FungibleAssetValue\"/>'s constructors instead.</remarks>\n        [Pure]\n        public static FungibleAssetValue operator *(BigInteger quantity, Currency currency) =>\n            new FungibleAssetValue(currency, majorUnit: quantity, minorUnit: 0);\n\n        /// <summary>\n        /// Define a <see cref=\"Currency\"/> with a maximum supply limit.\n        /// </summary>\n        /// <param name=\"ticker\">The ticker symbol, e.g., <c>&quot;USD&quot;</c>.</param>\n        /// <param name=\"decimalPlaces\">The number of digits to treat as <a\n        /// href=\"https://w.wiki/ZXv#Treatment_of_minor_currency_units_(the_%22exponent%22)\">minor\n        /// units (i.e., exponent)</a>.</param>\n        /// <param name=\"maximumSupply\">The uppermost quantity of currency allowed to exist. For\n        /// example, the <paramref name=\"maximumSupply\"/> parameter in <c>Currency.Capped(\"ABC\", 2,\n        /// (123, 45), ...)</c> means that the token <c>ABC</c> can be minted up to <c>123.45 ABC\n        /// </c>. See also <see cref=\"MaximumSupply\"/> field which corresponds to this.</param>\n        /// <param name=\"minters\">The <see cref=\"Address\"/>es who can mint the currency.\n        /// See also <see cref=\"Minters\"/> field which corresponds to this.</param>\n        /// <returns>An instance of <see cref=\"Currency\"/> with a maximum supply limit.</returns>\n        /// <exception cref=\"ArgumentException\">Thrown when the given <paramref name=\"ticker\"/>\n        /// is an empty string, or when either the Major or the Minor values of\n        /// <paramref name=\"maximumSupply\"/> is a negative number, or when the given Minor unit for\n        /// the <paramref name=\"maximumSupply\"/> is too big for the given\n        /// <paramref name=\"decimalPlaces\"/>.</exception>\n        public static Currency Capped(\n            string ticker,\n            byte decimalPlaces,\n            (BigInteger Major, BigInteger Minor) maximumSupply,\n            IImmutableSet<Address>? minters) =>\n            new Currency(ticker, decimalPlaces, maximumSupply, minters);\n\n        /// <summary>\n        /// Define a <see cref=\"Currency\"/> with a maximum supply limit.\n        /// </summary>\n        /// <param name=\"ticker\">The ticker symbol, e.g., <c>&quot;USD&quot;</c>.</param>\n        /// <param name=\"decimalPlaces\">The number of digits to treat as <a\n        /// href=\"https://w.wiki/ZXv#Treatment_of_minor_currency_units_(the_%22exponent%22)\">minor\n        /// units (i.e., exponent)</a>.</param>\n        /// <param name=\"maximumSupply\">The uppermost quantity of currency allowed to exist. For\n        /// example, the <paramref name=\"maximumSupply\"/> parameter in <c>Currency.Capped(\"ABC\", 2,\n        /// (123, 45), ...)</c> means that the token <c>ABC</c> can be minted up to <c>123.45 ABC\n        /// </c>. See also <see cref=\"MaximumSupply\"/> field which corresponds to this.</param>\n        /// <param name=\"minter\">The address who can mint the currency.  To specify multiple\n        /// minters, use the <see\n        /// cref=\"Capped(string,byte,ValueTuple{BigInteger,BigInteger},IImmutableSet{Address}?)\"/>\n        /// See also <see cref=\"Minters\"/> field which corresponds to this.</param>\n        /// <returns>An instance of <see cref=\"Currency\"/> with a maximum supply limit.</returns>\n        /// <seealso\n        /// cref=\"Capped(string,byte,ValueTuple{BigInteger,BigInteger},IImmutableSet{Address}?)\"/>\n        /// <exception cref=\"ArgumentException\">Thrown when the given <paramref name=\"ticker\"/>\n        /// is an empty string, or when either the Major or the Minor values of\n        /// <paramref name=\"maximumSupply\"/> is a negative number, or when the given Minor unit for\n        /// the <paramref name=\"maximumSupply\"/> is too big for the given\n        /// <paramref name=\"decimalPlaces\"/>.</exception>\n        public static Currency Capped(\n            string ticker,\n            byte decimalPlaces,\n            (BigInteger Major, BigInteger Minor) maximumSupply,\n            Address minter) =>\n            Capped(ticker, decimalPlaces, maximumSupply, ImmutableHashSet.Create(minter));\n\n        /// <summary>\n        /// Define a <see cref=\"Currency\"/> without a maximum supply limit.\n        /// </summary>\n        /// <param name=\"ticker\">The ticker symbol, e.g., <c>&quot;USD&quot;</c>.</param>\n        /// <param name=\"decimalPlaces\">The number of digits to treat as <a\n        /// href=\"https://w.wiki/ZXv#Treatment_of_minor_currency_units_(the_%22exponent%22)\">minor\n        /// units (i.e., exponent)</a>.</param>\n        /// <param name=\"minters\">The <see cref=\"Address\"/>es who can mint the currency.\n        /// See also <see cref=\"Minters\"/> field which corresponds to this.</param>\n        /// <returns>An instance of <see cref=\"Currency\"/> without a maximum supply limit.</returns>\n        /// <exception cref=\"ArgumentException\">Thrown when the given <paramref name=\"ticker\"/>\n        /// is an empty string.</exception>\n        public static Currency Uncapped(\n            string ticker,\n            byte decimalPlaces,\n            IImmutableSet<Address>? minters) =>\n            new Currency(ticker, decimalPlaces, minters, true);\n\n        /// <summary>\n        /// Define a <see cref=\"Currency\"/> without a maximum supply limit.\n        /// </summary>\n        /// <param name=\"ticker\">The ticker symbol, e.g., <c>&quot;USD&quot;</c>.</param>\n        /// <param name=\"decimalPlaces\">The number of digits to treat as <a\n        /// href=\"https://w.wiki/ZXv#Treatment_of_minor_currency_units_(the_%22exponent%22)\">minor\n        /// units (i.e., exponent)</a>.</param>\n        /// <param name=\"minter\">The address who can mint the currency.  To specify multiple\n        /// minters, use the <see cref=\"Uncapped(string,byte,IImmutableSet{Address}?)\"/>\n        /// See also <see cref=\"Minters\"/> field which corresponds to this.</param>\n        /// <returns>An instance of <see cref=\"Currency\"/> without a maximum supply limit.</returns>\n        /// <seealso cref=\"Uncapped(string,byte,IImmutableSet{Address}?)\"/>\n        /// <exception cref=\"ArgumentException\">Thrown when the given <paramref name=\"ticker\"/>\n        /// is an empty string.</exception>\n        public static Currency Uncapped(\n            string ticker,\n            byte decimalPlaces,\n            Address minter) =>\n            Uncapped(ticker, decimalPlaces, ImmutableHashSet.Create(minter));\n\n        /// <summary>\n        /// <b>OBSOLETE! DO NOT USE.</b><br/><br/>(unless you are upgrading your project from an old\n        /// version of Libplanet that did not support total supply tracking for\n        /// <see cref=\"Currency\">Currencies</see> and had a legacy <see cref=\"Currency\"/> defined.)\n        /// <br/><br/>Define a legacy <see cref=\"Currency\"/> without total supply tracking, which is\n        /// internally compatible with the legacy version.\n        /// </summary>\n        /// <param name=\"ticker\">The ticker symbol, e.g., <c>&quot;USD&quot;</c>.</param>\n        /// <param name=\"decimalPlaces\">The number of digits to treat as <a\n        /// href=\"https://w.wiki/ZXv#Treatment_of_minor_currency_units_(the_%22exponent%22)\">minor\n        /// units (i.e., exponent)</a>.</param>\n        /// <param name=\"minters\">The <see cref=\"Address\"/>es who can mint the currency.\n        /// See also <see cref=\"Minters\"/> field which corresponds to this.</param>\n        /// <returns>An instance of legacy <see cref=\"Currency\"/> without total supply tracking.\n        /// </returns>\n        /// <exception cref=\"ArgumentException\">Thrown when the given <paramref name=\"ticker\"/>\n        /// is an empty string.</exception>\n        [Obsolete(\"Obsolete! Use Currency.Capped() or Currency.Uncapped() for new currencies.\")]\n        public static Currency Legacy(\n            string ticker,\n            byte decimalPlaces,\n            IImmutableSet<Address>? minters) =>\n            new Currency(ticker, decimalPlaces, minters, false);\n\n        /// <summary>\n        /// <b>OBSOLETE! DO NOT USE.</b><br/><br/>(unless you are upgrading your project from an old\n        /// version of Libplanet that did not support total supply tracking for\n        /// <see cref=\"Currency\">Currencies</see> and had a legacy <see cref=\"Currency\"/> defined.)\n        /// <br/><br/>Define a legacy <see cref=\"Currency\"/> without total supply tracking, which is\n        /// internally compatible with the legacy version.\n        /// </summary>\n        /// <param name=\"ticker\">The ticker symbol, e.g., <c>&quot;USD&quot;</c>.</param>\n        /// <param name=\"decimalPlaces\">The number of digits to treat as <a\n        /// href=\"https://w.wiki/ZXv#Treatment_of_minor_currency_units_(the_%22exponent%22)\">minor\n        /// units (i.e., exponent)</a>.</param>\n        /// <param name=\"minter\">The address who can mint the currency.  To specify multiple\n        /// minters, use the <see cref=\"Legacy(string,byte,IImmutableSet{Address}?)\"/>\n        /// See also <see cref=\"Minters\"/> field which corresponds to this.</param>\n        /// <returns>An instance of legacy <see cref=\"Currency\"/> without total supply tracking.\n        /// </returns>\n        /// <seealso cref=\"Legacy(string,byte,IImmutableSet{Address}?)\"/>\n        /// <exception cref=\"ArgumentException\">Thrown when the given <paramref name=\"ticker\"/>\n        /// is an empty string.</exception>\n        [Obsolete(\"Obsolete! Use Currency.Capped() or Currency.Uncapped() for new currencies.\")]\n        public static Currency Legacy(\n            string ticker,\n            byte decimalPlaces,\n            Address minter) =>\n            Legacy(ticker, decimalPlaces, ImmutableHashSet.Create(minter));\n\n        /// <summary>\n        /// Returns <see langword=\"true\"/> if and only if\n        /// the given <paramref name=\"address\"/> is allowed\n        /// to mint or burn assets of this currency.\n        /// </summary>\n        /// <param name=\"address\">The account address to test.</param>\n        /// <returns><see langword=\"true\"/> if and only if\n        /// the given <paramref name=\"address\"/> is allowed to\n        /// mint or burn assets of this currency.</returns>\n        [Pure]\n        public bool AllowsToMint(Address address) => Minters is null || Minters.Contains(address);\n\n        /// <inheritdoc cref=\"object.ToString()\"/>\n        [Pure]\n        public override string ToString() => $\"{Ticker} ({Hash})\";\n\n        /// <inheritdoc cref=\"object.GetHashCode()\"/>\n        [Pure]\n        public override int GetHashCode() => Hash.GetHashCode();\n\n        /// <inheritdoc cref=\"object.Equals(object?)\"/>\n        [Pure]\n        public override bool Equals(object? obj) =>\n            obj is IEquatable<Currency> other && other.Equals(this);\n\n        /// <inheritdoc cref=\"IEquatable{T}.Equals(T)\"/>\n        [Pure]\n        public bool Equals(Currency other) =>\n            Hash.Equals(other.Hash);\n\n        /// <summary>\n        /// Serializes the currency into a Bencodex value.\n        /// </summary>\n        /// <returns>The serialized Bencodex value.</returns>\n        [Pure]\n        public IValue Serialize()\n        {\n            IValue minters = Minters is IImmutableSet<Address> m\n                ? new Bencodex.Types.List(m.Select<Address, IValue>(a => a.Bencoded))\n                : (IValue)Null.Value;\n            var serialized = Bencodex.Types.Dictionary.Empty\n                .Add(\"ticker\", Ticker)\n                .Add(\"minters\", minters)\n                .Add(\"decimalPlaces\", new[] { DecimalPlaces });\n            if (TotalSupplyTrackable)\n            {\n                serialized = serialized.Add(\"totalSupplyTrackable\", true);\n                if (MaximumSupply is { } maximumSupply)\n                {\n                    serialized = serialized.Add(\n                        \"maximumSupplyMajor\",\n                        (IValue)new Integer(maximumSupply.MajorUnit)\n                    ).Add(\n                        \"maximumSupplyMinor\",\n                        (IValue)new Integer(maximumSupply.MinorUnit));\n                }\n            }\n\n            return serialized;\n        }\n\n        private static SHA1 GetSHA1()\n        {\n#if NETSTANDARD2_0_OR_GREATER || NETCOREAPP3_1\n            try\n            {\n                return new SHA1CryptoServiceProvider();\n            }\n            catch (PlatformNotSupportedException)\n            {\n                return new SHA1Managed();\n            }\n#elif NET6_0_OR_GREATER\n            return SHA1.Create();\n#endif\n        }\n\n        // NOTE: This uses a different serialization scheme from\n        // Serialize() due to backward compatibility issues.\n        private static HashDigest<SHA1> GetHash(\n            IImmutableSet<Address>? minters,\n            string ticker,\n            byte decimalPlaces,\n            (BigInteger Major, BigInteger Minor)? maximumSupply,\n            bool totalSupplyTrackable\n        )\n        {\n            using var buffer = new MemoryStream();\n            using var sha1 = GetSHA1();\n            using var stream = new CryptoStream(buffer, sha1, CryptoStreamMode.Write);\n            var codec = new Codec();\n            IValue mintersValue = minters is ImmutableHashSet<Address> a\n                ? new List(a.OrderBy(m => m).Select(m => m.Bencoded))\n                : (IValue)Null.Value;\n            var serialized = Dictionary.Empty\n                .Add(\"ticker\", ticker)\n                .Add(\"decimals\", (int)decimalPlaces)\n                .Add(\"minters\", mintersValue);\n\n            if (maximumSupply is var (major, minor))\n            {\n                serialized = serialized.Add(\"maximumSupplyMajor\", new Integer(major))\n                    .Add(\"maximumSupplyMinor\", new Integer(minor));\n            }\n\n            if (totalSupplyTrackable)\n            {\n                serialized = serialized.Add(\"totalSupplyTrackable\", true);\n            }\n\n            codec.Encode(serialized, stream);\n            stream.FlushFinalBlock();\n            if (sha1.Hash is { } hash)\n            {\n                return new HashDigest<SHA1>(sha1.Hash);\n            }\n\n            throw new InvalidOperationException(\"Failed to compute the hash.\");\n        }\n    }\n\n    [SuppressMessage(\n        \"StyleCop.CSharp.MaintainabilityRules\",\n        \"SA1402:FileMayOnlyContainASingleClass\",\n        Justification = \"It's okay to have non-public classes together in a single file.\"\n    )]\n    internal class MaximumSupplyJsonConverter : JsonConverter<FungibleAssetValue>\n    {\n        public override FungibleAssetValue Read(\n            ref Utf8JsonReader reader,\n            Type typeToConvert,\n            JsonSerializerOptions options\n        )\n        {\n            string? quantityString = reader.GetString();\n            if (!(quantityString is { } qs))\n            {\n                throw new JsonException(\"MaximumSupply must be a string.\");\n            }\n\n            int periodPos = qs.IndexOf('.');\n            byte decimalPlaces = periodPos < 0 ? (byte)0 : (byte)(qs.Length - periodPos - 1);\n            var fakeCurrency = Currency.Uncapped(\"FAKE\", decimalPlaces, null);\n            return FungibleAssetValue.Parse(fakeCurrency, qs);\n        }\n\n        public override void Write(\n            Utf8JsonWriter writer,\n            FungibleAssetValue value,\n            JsonSerializerOptions options\n        ) =>\n            writer.WriteStringValue(\n                value.GetQuantityString() + (value.MinorUnit.IsZero ? \".0\" : string.Empty)\n            );\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Types/Assets/FungibleAssetValue.cs",
    "content": "using System;\nusing System.Diagnostics.CodeAnalysis;\nusing System.Diagnostics.Contracts;\nusing System.Globalization;\nusing System.Linq;\nusing System.Numerics;\nusing System.Text.Json;\nusing System.Text.Json.Serialization;\nusing Bencodex.Types;\n\nnamespace Libplanet.Types.Assets\n{\n    /// <summary>\n    /// Holds a fungible asset value which holds its <see cref=\"Currency\"/> together.\n    /// </summary>\n    /// <remarks>\n    /// It behaves like numbers except for division operator (<c>/</c>) to prevent to forget\n    /// to handle its remainder; use <see cref=\"DivRem(FungibleAssetValue)\"/> and <see\n    /// cref=\"DivRem(BigInteger)\"/> methods instead.\n    /// </remarks>\n    [JsonConverter(typeof(FungibleAssetValueJsonConverter))]\n    public readonly struct FungibleAssetValue :\n        IEquatable<FungibleAssetValue>,\n        IComparable<FungibleAssetValue>,\n        IComparable\n    {\n        /// <summary>\n        /// The currency of the fungible asset.\n        /// </summary>\n        public readonly Currency Currency;\n\n        /// <summary>\n        /// The internal representation of the fungible asset.\n        /// </summary>\n        /// <remarks>\n        /// Since this is an internal representation, this does not guarantee forward compatibility.\n        /// Therefore, do not depend on this value for permanent uses but only for volatile data.\n        /// </remarks>\n        /// <seealso cref=\"FromRawValue\"/>\n        public readonly BigInteger RawValue;\n\n        public FungibleAssetValue(IValue value)\n        {\n            if (!(value is Bencodex.Types.List list))\n            {\n                throw new ArgumentException(\n                    $\"The given value is not a list: {value}\",\n                    nameof(value)\n                );\n            }\n\n            Currency = new Currency(list[0]);\n            RawValue = (Bencodex.Types.Integer)list[1];\n        }\n\n        /// <summary>\n        /// Creates a zero value of the <paramref name=\"currency\"/>.\n        /// </summary>\n        /// <param name=\"currency\">The currency to create a zero value.</param>\n        public FungibleAssetValue(Currency currency)\n            : this(currency, BigInteger.Zero)\n        {\n        }\n\n        /// <summary>\n        /// Creates a value of the <paramref name=\"currency\"/> from the given\n        /// <paramref name=\"majorUnit\"/> and <paramref name=\"minorUnit\"/>.\n        /// </summary>\n        /// <param name=\"currency\">The currency to create a value.</param>\n        /// <param name=\"majorUnit\">The major unit of the fungible asset value,\n        /// i.e., digits <em>before</em> the decimal separator.</param>\n        /// <param name=\"minorUnit\">The minor unit of the fungible asset value,\n        /// i.e., digits <em>after</em> the decimal separator.</param>\n        /// <exception cref=\"ArgumentException\">Thrown when the negativity sign is ambiguous\n        /// (e.g., both units have signs) or too big for the <paramref name=\"currency\"/>.\n        /// </exception>\n        /// <seealso cref=\"Currency.DecimalPlaces\"/>\n        public FungibleAssetValue(Currency currency, BigInteger majorUnit, BigInteger minorUnit)\n            : this(\n                currency,\n                majorUnit.IsZero ? minorUnit.Sign : majorUnit.Sign,\n                BigInteger.Abs(majorUnit),\n                BigInteger.Abs(minorUnit)\n            )\n        {\n            if (!majorUnit.IsZero && minorUnit < BigInteger.Zero)\n            {\n                throw new ArgumentException(\n                    \"Unless the major unit is zero, the minor unit cannot be negative.\",\n                    nameof(minorUnit)\n                );\n            }\n        }\n\n        /// <summary>\n        /// Creates a value of the <paramref name=\"currency\"/> from the given <paramref\n        /// name=\"sign\"/>, <paramref name=\"majorUnit\"/> and <paramref name=\"minorUnit\"/>.\n        /// </summary>\n        /// <param name=\"currency\">The currency to create a value.</param>\n        /// <param name=\"sign\">Indicates the sign (negative, positive, or zero) of the value.\n        /// <c>-1</c> indicates negative, <c>1</c> indicates positive, and <c>0</c> indicates\n        /// zero.</param>\n        /// <param name=\"majorUnit\">The major unit of the fungible asset value,\n        /// i.e., digits <em>before</em> the decimal separator.  Must not be negative.</param>\n        /// <param name=\"minorUnit\">The minor unit of the fungible asset value,\n        /// i.e., digits <em>after</em> the decimal separator.  Must not be negative.</param>\n        /// <exception cref=\"ArgumentException\">Thrown when the <paramref name=\"sign\"/> is not\n        /// one of <c>1</c>, <c>0</c>, and <c>-1</c>, or <paramref name=\"majorUnit\"/> or\n        /// <paramref name=\"minorUnit\"/> is negative.\n        /// </exception>\n        /// <seealso cref=\"Currency.DecimalPlaces\"/>\n        public FungibleAssetValue(\n            Currency currency,\n            int sign,\n            BigInteger majorUnit,\n            BigInteger minorUnit\n        )\n            : this(\n                currency,\n                sign * (majorUnit * BigInteger.Pow(10, currency.DecimalPlaces) + minorUnit)\n            )\n        {\n            if (sign > 1 || sign < -1)\n            {\n                throw new ArgumentException(\"The sign must be 1, 0, or -1.\", nameof(sign));\n            }\n            else if (sign == 0 && !majorUnit.IsZero)\n            {\n                throw new ArgumentException(\n                    \"If the sign is zero, the major unit must be also zero.\",\n                    nameof(majorUnit)\n                );\n            }\n            else if (sign == 0 && !minorUnit.IsZero)\n            {\n                throw new ArgumentException(\n                    \"If the sign is zero, the minor unit must be also zero.\",\n                    nameof(minorUnit)\n                );\n            }\n            else if (majorUnit < 0)\n            {\n                throw new ArgumentException(\n                    \"The major unit must not be negative.\",\n                    nameof(majorUnit)\n                );\n            }\n            else if (minorUnit < 0)\n            {\n                throw new ArgumentException(\n                    \"The minor unit must not be negative.\",\n                    nameof(minorUnit)\n                );\n            }\n            else if (minorUnit > 0 &&\n                     (int)Math.Floor(BigInteger.Log10(minorUnit) + 1) > currency.DecimalPlaces)\n            {\n                string msg =\n                    $\"Since the currency {currency} allows upto {currency.DecimalPlaces} \" +\n                    $\"decimal places, the given minor unit {minorUnit} is too big.\";\n                throw new ArgumentException(msg, nameof(minorUnit));\n            }\n        }\n\n        /// <summary>\n        /// Creates a value of the <paramref name=\"currency\"/> with the specified <paramref\n        /// name=\"rawValue\"/>.\n        /// </summary>\n        /// <param name=\"currency\">The currency to create a value.</param>\n        /// <param name=\"rawValue\">The raw quantity of the value to create.</param>\n        internal FungibleAssetValue(Currency currency, BigInteger rawValue)\n        {\n            Currency = currency;\n            RawValue = rawValue;\n        }\n\n        /// <summary>\n        /// Gets a number that indicates the sign (negative, positive, or zero) of the value.\n        /// </summary>\n        /// <value>\n        /// A number that indicates the sign of the fungible asset value, as shown in the following\n        /// table:\n        /// <list type=\"table\">\n        /// <listheader><term>Number</term><description>Description</description></listheader>\n        /// <item><term>-1</term><description>The value is negative.</description></item>\n        /// <item><term>0</term><description>The value is zero.</description></item>\n        /// <item><term>1</term><description>The value is positive.</description></item>\n        /// </list>\n        /// </value>\n        [Pure]\n        public int Sign\n        {\n            get\n            {\n                if (RawValue < 0)\n                {\n                    return -1;\n                }\n\n                if (RawValue == 0)\n                {\n                    return 0;\n                }\n\n                return 1;\n            }\n        }\n\n        /// <summary>\n        /// The major unit of the fungible asset value, i.e., digits <em>before</em> the decimal\n        /// separator, in absolute value.\n        /// </summary>\n        /// <remarks>It is absolute value, which lacks <see cref=\"Sign\"/>.</remarks>\n        /// <seealso cref=\"Currency.DecimalPlaces\"/>\n        [Pure]\n        public BigInteger MajorUnit =>\n            BigInteger.Abs(RawValue) / BigInteger.Pow(10, Currency.DecimalPlaces);\n\n        /// <summary>\n        /// The minor unit of the fungible asset value, i.e., digits <em>after</em> the decimal\n        /// separator, in absolute value.\n        /// </summary>\n        /// <remarks>It is absolute value, which lacks <see cref=\"Sign\"/>.</remarks>\n        /// <seealso cref=\"Currency.DecimalPlaces\"/>\n        [Pure]\n        public BigInteger MinorUnit =>\n            BigInteger.Abs(RawValue) % BigInteger.Pow(10, Currency.DecimalPlaces);\n\n        /// <summary>\n        /// Tests if two values are equal.\n        /// </summary>\n        /// <param name=\"obj\">A value.</param>\n        /// <param name=\"other\">Another value.</param>\n        /// <returns><see langword=\"true\"/> if two values are equal.\n        /// Otherwise <see langword=\"false\"/>.</returns>\n        [Pure]\n        public static bool operator ==(FungibleAssetValue obj, FungibleAssetValue other) =>\n            obj.Equals(other);\n\n        /// <summary>\n        /// Tests if two values are unequal.\n        /// </summary>\n        /// <param name=\"obj\">A value.</param>\n        /// <param name=\"other\">Another value.</param>\n        /// <returns><see langword=\"false\"/> if two values are equal.\n        /// Otherwise <see langword=\"true\"/>.</returns>\n        [Pure]\n        public static bool operator !=(FungibleAssetValue obj, FungibleAssetValue other) =>\n            !(obj == other);\n\n        /// <summary>\n        /// Tests if the left operand (<paramref name=\"obj\"/>) is less than the right operand\n        /// (<paramref name=\"other\"/>).\n        /// </summary>\n        /// <param name=\"obj\">The left operand to compare.</param>\n        /// <param name=\"other\">The right operand to compare.</param>\n        /// <returns><see langword=\"true\"/>\n        /// if the left operand (<paramref name=\"obj\"/>) is less than the right\n        /// operand (<paramref name=\"other\"/>).  Otherwise (even if two operands are equal)\n        /// <see langword=\"false\"/>.</returns>\n        [Pure]\n        public static bool operator <(FungibleAssetValue obj, FungibleAssetValue other) =>\n            obj.CompareTo(other) < 0;\n\n        /// <summary>\n        /// Tests if the left operand (<paramref name=\"obj\"/>) is less than or equal to the right\n        /// operand (<paramref name=\"other\"/>).\n        /// </summary>\n        /// <param name=\"obj\">The left operand to compare.</param>\n        /// <param name=\"other\">The right operand to compare.</param>\n        /// <returns><see langword=\"true\"/>\n        /// if the left operand (<paramref name=\"obj\"/>) is less than or equal\n        /// to the right operand (<paramref name=\"other\"/>).  Otherwise <see langword=\"false\"/>.\n        /// </returns>\n        [Pure]\n        public static bool operator <=(FungibleAssetValue obj, FungibleAssetValue other) =>\n            obj.CompareTo(other) <= 0;\n\n        /// <summary>\n        /// Tests if the left operand (<paramref name=\"obj\"/>) is greater than the right operand\n        /// (<paramref name=\"other\"/>).\n        /// </summary>\n        /// <param name=\"obj\">The left operand to compare.</param>\n        /// <param name=\"other\">The right operand to compare.</param>\n        /// <returns><see langword=\"true\"/>\n        /// if the left operand (<paramref name=\"obj\"/>) is greater than\n        /// the right operand (<paramref name=\"other\"/>).  Otherwise (even if two operands are\n        /// equal) <see langword=\"false\"/>.</returns>\n        [Pure]\n        public static bool operator >(FungibleAssetValue obj, FungibleAssetValue other) =>\n            other < obj;\n\n        /// <summary>\n        /// Tests if the left operand (<paramref name=\"obj\"/>) is greater than or equal to the right\n        /// operand (<paramref name=\"other\"/>).\n        /// </summary>\n        /// <param name=\"obj\">The left operand to compare.</param>\n        /// <param name=\"other\">The right operand to compare.</param>\n        /// <returns><see langword=\"true\"/>\n        /// if the left operand (<paramref name=\"obj\"/>) is greater than or\n        /// equal to the right operand (<paramref name=\"other\"/>).\n        /// Otherwise <see langword=\"false\"/>.</returns>\n        [Pure]\n        public static bool operator >=(FungibleAssetValue obj, FungibleAssetValue other) =>\n            other <= obj;\n\n        /// <summary>\n        /// Negates a <paramref name=\"value\"/>.\n        /// <para>Adds a negative sign to the <paramref name=\"value\"/> if it's positive.\n        /// Removes a negative sign from the <paramref name=\"value\"/> if it's already negative.\n        /// Does nothing if the <paramref name=\"value\"/> is zero.</para>\n        /// </summary>\n        /// <param name=\"value\">A value to negate.</param>\n        /// <returns>A negated <paramref name=\"value\"/>.</returns>\n        [Pure]\n        public static FungibleAssetValue operator -(FungibleAssetValue value) =>\n            new FungibleAssetValue(value.Currency, -value.RawValue);\n\n        /// <summary>\n        /// Adds two values and returns the result.\n        /// </summary>\n        /// <param name=\"left\">The first value to add.</param>\n        /// <param name=\"right\">The second value to add.</param>\n        /// <returns>The sum of <paramref name=\"left\"/> and <paramref name=\"right\"/>.</returns>\n        /// <exception cref=\"ArgumentException\">Thrown when two values do not have the same\n        /// <see cref=\"Currency\"/>.</exception>\n        [Pure]\n        public static FungibleAssetValue operator +(\n            FungibleAssetValue left,\n            FungibleAssetValue right\n        ) => left.Currency.Equals(right.Currency)\n            ? new FungibleAssetValue(left.Currency, left.RawValue + right.RawValue)\n            : throw new ArgumentException(\n                \"Unable to add heterogeneous currencies: \" +\n                $\"{left.Currency} \\u2260 {right.Currency}.\",\n                nameof(right));\n\n        /// <summary>\n        /// Subtracts the <paramref name=\"right\"/> value from the <paramref name=\"left\"/> value.\n        /// </summary>\n        /// <param name=\"left\">The value to subtract from (the minuend).</param>\n        /// <param name=\"right\">The value to subtract (the subtrahend).</param>\n        /// <returns>The result of subtracting <paramref name=\"right\"/> from\n        /// <paramref name=\"left\"/>.</returns>\n        /// <exception cref=\"ArgumentException\">Thrown when two values do not have the same\n        /// <see cref=\"Currency\"/>.</exception>\n        [Pure]\n        public static FungibleAssetValue operator -(\n            FungibleAssetValue left,\n            FungibleAssetValue right\n        ) => left.Currency.Equals(right.Currency)\n            ? new FungibleAssetValue(left.Currency, left.RawValue - right.RawValue)\n            : throw new ArgumentException(\n                \"Unable to subtract heterogeneous currencies: \" +\n                $\"{left.Currency} \\u2260 {right.Currency}.\",\n                nameof(right));\n\n        /// <summary>\n        /// Multiplies <paramref name=\"right\"/> times the <paramref name=\"left\"/> value.\n        /// </summary>\n        /// <param name=\"left\">The value to multiply.</param>\n        /// <param name=\"right\">The times to multiply.</param>\n        /// <returns>The multiplied value.</returns>\n        [Pure]\n        public static FungibleAssetValue operator *(FungibleAssetValue left, BigInteger right) =>\n            new FungibleAssetValue(left.Currency, left.RawValue * right);\n\n        /// <summary>\n        /// Multiplies <paramref name=\"left\"/> times the <paramref name=\"right\"/> value.\n        /// </summary>\n        /// <param name=\"left\">The times to multiply.</param>\n        /// <param name=\"right\">The value to multiply.</param>\n        /// <returns>The multiplied value.</returns>\n        [Pure]\n        public static FungibleAssetValue operator *(BigInteger left, FungibleAssetValue right) =>\n            new FungibleAssetValue(right.Currency, left * right.RawValue);\n\n        /// <summary>\n        /// Divides the value (<paramref name=\"dividend\"/>) by <paramref name=\"divisor\"/>,\n        /// and returns the remainder.\n        /// </summary>\n        /// <param name=\"dividend\">The value to be divided.</param>\n        /// <param name=\"divisor\">The number to divide by.</param>\n        /// <returns>The remainder after dividing <paramref name=\"dividend\"/>\n        /// by <paramref name=\"divisor\"/>.</returns>\n        /// <exception cref=\"DivideByZeroException\">Thrown when the <paramref name=\"divisor\"/> is\n        /// <c>0</c> (zero).</exception>\n        [Pure]\n        public static FungibleAssetValue operator %(FungibleAssetValue dividend, BigInteger divisor)\n            => new FungibleAssetValue(dividend.Currency, dividend.RawValue % divisor);\n\n        /// <summary>\n        /// Divides the value (<paramref name=\"dividend\"/>) by <paramref name=\"divisor\"/>,\n        /// and returns the remainder.\n        /// </summary>\n        /// <param name=\"dividend\">The value to be divided.</param>\n        /// <param name=\"divisor\">The value to divide by.</param>\n        /// <returns>The remainder after dividing <paramref name=\"dividend\"/>\n        /// by <paramref name=\"divisor\"/>.</returns>\n        /// <exception cref=\"ArgumentException\">Thrown when two values do not have the same\n        /// <see cref=\"Currency\"/>.</exception>\n        /// <exception cref=\"DivideByZeroException\">Thrown when the <paramref name=\"divisor\"/> is\n        /// zero.</exception>\n        [Pure]\n        public static FungibleAssetValue operator %(\n            FungibleAssetValue dividend,\n            FungibleAssetValue divisor)\n        {\n            if (!dividend.Currency.Equals(divisor.Currency))\n            {\n                throw new ArgumentException(\n                    \"Cannot be divided by a heterogeneous currency: \" +\n                    $\"{dividend.Currency} \\u2260 {divisor.Currency}.\"\n                );\n            }\n\n            return new FungibleAssetValue(dividend.Currency, dividend.RawValue % divisor.RawValue);\n        }\n\n        /// <summary>\n        /// Parses a numeric string and returns a corresponding <see cref=\"FungibleAssetValue\"/>.\n        /// </summary>\n        /// <param name=\"currency\">The currency of the value to parse.</param>\n        /// <param name=\"value\">A numeric string to parse.  Can consist of digits, plus (+),\n        /// minus (-), and decimal separator (.).</param>\n        /// <returns>The parsed asset value.</returns>\n        /// <exception cref=\"FormatException\">Thrown when the given <paramref name=\"value\"/> is not\n        /// a valid numeric string.</exception>\n        public static FungibleAssetValue Parse(Currency currency, string value)\n        {\n            int sign = 1;\n            if (value[0] == '-' || value[0] == '+')\n            {\n                sign = value[0] == '-' ? -1 : 1;\n                value = value.Remove(0, 1);\n            }\n\n            if (value.IndexOfAny(new[] { '+', '-' }) >= 0)\n            {\n                const string msg =\n                    \"Plus (+) or minus (-) sign can be appeared only at first and cannot be \" +\n                    \"more than one.\";\n                throw new FormatException(msg);\n            }\n\n            string[] parts = value.Split(new[] { '.' }, count: 2);\n            bool minorExist = parts.Length > 1;\n            if (minorExist && parts[1].IndexOf('.') >= 0)\n            {\n                throw new FormatException(\n                    \"The decimal separator (.) cannot be appeared more than once.\"\n                );\n            }\n            else if (!parts[0].All(char.IsDigit) || (minorExist && !parts[1].All(char.IsDigit)))\n            {\n                const string msg =\n                    \"The value string must consist of digits, decimal separator (.), plus (+), \" +\n                    \"and minus(-).\";\n                throw new FormatException(msg);\n            }\n            else if (minorExist && parts[1].Length > currency.DecimalPlaces)\n            {\n                throw new FormatException(\n                    $\"The currency {currency} does not allow more than {currency.DecimalPlaces} \" +\n                    (currency.DecimalPlaces == 1 ? \"decimal place\" : \"decimal places\")\n                );\n            }\n\n            BigInteger major = BigInteger.Parse(parts[0], CultureInfo.InvariantCulture);\n            BigInteger minor = minorExist\n                ? BigInteger.Parse(parts[1], CultureInfo.InvariantCulture) * BigInteger.Pow(\n                    10,\n                    currency.DecimalPlaces - parts[1].Length)\n                : 0;\n            return new FungibleAssetValue(currency, sign, major, minor);\n        }\n\n        /// <summary>\n        /// Restores a value from a <paramref name=\"rawValue\"/> of a <paramref name=\"currency\"/>.\n        /// </summary>\n        /// <param name=\"currency\">The currency to create a value.</param>\n        /// <param name=\"rawValue\">The <see cref=\"RawValue\"/> to restore.</param>\n        /// <returns>The value restored from the given <paramref name=\"rawValue\"/>.</returns>\n        /// <seealso cref=\"RawValue\"/>\n        public static FungibleAssetValue FromRawValue(Currency currency, BigInteger rawValue) =>\n            new FungibleAssetValue(currency, rawValue: rawValue);\n\n        /// <summary>\n        /// Divides the value by <paramref name=\"divisor\"/>, returns the quotient, and returns\n        /// the <paramref name=\"remainder\"/> in an output parameter.\n        /// </summary>\n        /// <param name=\"divisor\">The number to divide by.</param>\n        /// <param name=\"remainder\">When this method returns (without any exception), the remainder\n        /// after dividing the value by <paramref name=\"divisor\"/>.  This parameter is passed\n        /// uninitialized.</param>\n        /// <returns>The quotient of the division.</returns>\n        /// <exception cref=\"DivideByZeroException\">Thrown when the <paramref name=\"divisor\"/> is\n        /// <c>0</c> (zero).</exception>\n        [Pure]\n        public FungibleAssetValue DivRem(BigInteger divisor, out FungibleAssetValue remainder)\n        {\n            BigInteger q = BigInteger.DivRem(RawValue, divisor, out BigInteger rem);\n            remainder = new FungibleAssetValue(Currency, rem);\n            return new FungibleAssetValue(Currency, q);\n        }\n\n        /// <summary>\n        /// Divides the value by <paramref name=\"divisor\"/>, returns the quotient, and returns\n        /// the <paramref name=\"remainder\"/> in an output parameter.\n        /// </summary>\n        /// <param name=\"divisor\">The value to divide by.</param>\n        /// <param name=\"remainder\">When this method returns (without any exception), the remainder\n        /// after dividing the value by <paramref name=\"divisor\"/>.  This parameter is passed\n        /// uninitialized.</param>\n        /// <returns>The quotient of the division.</returns>\n        /// <exception cref=\"ArgumentException\">Thrown when two values do not have the same\n        /// <see cref=\"Currency\"/>.</exception>\n        /// <exception cref=\"DivideByZeroException\">Thrown when the <paramref name=\"divisor\"/> is\n        /// zero.</exception>\n        [Pure]\n        public BigInteger DivRem(FungibleAssetValue divisor, out FungibleAssetValue remainder)\n        {\n            if (!Currency.Equals(divisor.Currency))\n            {\n                throw new ArgumentException(\n                    \"Cannot be divided by a heterogeneous currency: \" +\n                    $\"{Currency} \\u2260 {divisor.Currency}.\"\n                );\n            }\n\n            BigInteger d = BigInteger.DivRem(RawValue, divisor.RawValue, out BigInteger rem);\n            remainder = new FungibleAssetValue(Currency, rem);\n            return d;\n        }\n\n        /// <summary>\n        /// Divides the value by <paramref name=\"divisor\"/>, and returns a pair of the quotient\n        /// and the remainder.\n        /// </summary>\n        /// <param name=\"divisor\">The number to divide by.</param>\n        /// <returns>A tuple of the <c>Quotient</c> and <c>Remainder</c> of the division.</returns>\n        /// <exception cref=\"DivideByZeroException\">Thrown when the <paramref name=\"divisor\"/> is\n        /// <c>0</c> (zero).</exception>\n        [Pure]\n        public (FungibleAssetValue Quotient, FungibleAssetValue Remainder)\n        DivRem(BigInteger divisor) =>\n            (DivRem(divisor, out FungibleAssetValue remainder), remainder);\n\n        /// <summary>\n        /// Divides the value by <paramref name=\"divisor\"/>, and returns a pair of the quotient\n        /// and the remainder.\n        /// </summary>\n        /// <param name=\"divisor\">The value to divide by.</param>\n        /// <returns>A tuple of the <c>Quotient</c> and <c>Remainder</c> of the division.</returns>\n        /// <exception cref=\"ArgumentException\">Thrown when two values do not have the same\n        /// <see cref=\"Currency\"/>.</exception>\n        /// <exception cref=\"DivideByZeroException\">Thrown when the <paramref name=\"divisor\"/> is\n        /// zero.</exception>\n        [Pure]\n        public (BigInteger Quotient, FungibleAssetValue Remainder)\n        DivRem(FungibleAssetValue divisor) =>\n            (DivRem(divisor, out FungibleAssetValue remainder), remainder);\n\n        /// <summary>\n        /// Gets the absolute value.\n        /// <para>Removes the negative sign if it's negative.  Otherwise does nothing.</para>\n        /// </summary>\n        /// <returns>Its absolute value.</returns>\n        [Pure]\n        public FungibleAssetValue Abs()\n            => new FungibleAssetValue(Currency, BigInteger.Abs(RawValue));\n\n        /// <summary>\n        /// Gets the value quantity without its <see cref=\"Currency\"/> in <see cref=\"string\"/>.\n        /// </summary>\n        /// <param name=\"minorUnit\">Whether to show all possible decimal places even\n        /// if they are zeros.</param>\n        /// <returns>A quantity string in decimal system.  Consists of an optional sign (minus),\n        /// digits and an optional decimal separator (period).</returns>\n        [Pure]\n        public string GetQuantityString(bool minorUnit = false)\n        {\n            var signedString = Sign < 0 ? \"-\" : string.Empty;\n            var endCharsToTrim = minorUnit ? ' ' : '0';\n            return minorUnit || MinorUnit > 0\n                ? string.Format(\n                CultureInfo.InvariantCulture,\n                \"{0}{1}.{2:d\" + Currency.DecimalPlaces.ToString(CultureInfo.InvariantCulture) + \"}\",\n                signedString,\n                MajorUnit,\n                MinorUnit\n                ).TrimEnd(endCharsToTrim)\n                : (MajorUnit * Sign).ToString(CultureInfo.InvariantCulture);\n        }\n\n        /// <inheritdoc cref=\"IEquatable{T}.Equals(T)\"/>\n        [Pure]\n        public bool Equals(FungibleAssetValue other) =>\n            Currency.Equals(other.Currency) && RawValue.Equals(other.RawValue);\n\n        /// <inheritdoc cref=\"object.Equals(object)\"/>\n        [Pure]\n        public override bool Equals(object? obj) =>\n            obj is FungibleAssetValue other && Equals(other);\n\n        /// <inheritdoc cref=\"object.GetHashCode()\"/>\n        [Pure]\n        public override int GetHashCode() =>\n            unchecked((Currency.GetHashCode() * 397) ^ RawValue.GetHashCode());\n\n        /// <inheritdoc cref=\"IComparable.CompareTo(object)\"/>\n        [Pure]\n        public int CompareTo(object? obj) => obj is FungibleAssetValue o\n            ? CompareTo(o)\n            : throw new ArgumentException(\n                $\"Unable to compare with other than {nameof(FungibleAssetValue)}\",\n                nameof(obj));\n\n        /// <inheritdoc cref=\"IComparable{T}.CompareTo(T)\"/>\n        [Pure]\n        public int CompareTo(FungibleAssetValue other) => Currency.Equals(other.Currency)\n            ? RawValue.CompareTo(other.RawValue)\n            : throw new ArgumentException(\n                $\"Unable to compare heterogeneous currencies: {Currency} \\u2260 {other.Currency}.\",\n                nameof(other));\n\n        /// <inheritdoc cref=\"object.ToString()\"/>\n        [Pure]\n        public override string ToString() =>\n            $\"{GetQuantityString()} {Currency.Ticker}\";\n\n        public IValue Serialize() => Bencodex.Types.List.Empty\n                .Add(Currency.Serialize())\n                .Add((Bencodex.Types.Integer)RawValue);\n    }\n\n    [SuppressMessage(\n        \"StyleCop.CSharp.MaintainabilityRules\",\n        \"SA1402:FileMayOnlyContainASingleClass\",\n        Justification = \"It's okay to have non-public classes together in a single file.\"\n    )]\n    internal class FungibleAssetValueJsonConverter : JsonConverter<FungibleAssetValue>\n    {\n        public override FungibleAssetValue Read(\n            ref Utf8JsonReader reader,\n            Type typeToConvert,\n            JsonSerializerOptions options\n        )\n        {\n            if (reader.TokenType != JsonTokenType.StartObject)\n            {\n                throw new JsonException(\n                    $\"Expected an object representation of {nameof(FungibleAssetValue)}.\"\n                );\n            }\n\n            reader.Read();\n\n            string quantityFieldName =\n                options.PropertyNamingPolicy?.ConvertName(\"Quantity\") ?? \"Quantity\";\n            string currencyFieldName =\n                options.PropertyNamingPolicy?.ConvertName(\"Currency\") ?? \"Currency\";\n            string? quantityString = null;\n            Currency? currency = null;\n\n            while (reader.TokenType != JsonTokenType.EndObject &&\n                   (quantityString is null || currency is null))\n            {\n                if (quantityString is { } && currency is { })\n                {\n                    throw new JsonException($\"Unexpected token: {reader.TokenType}.\");\n                }\n\n                if (!(reader.GetString() is { } propName))\n                {\n                    throw new JsonException(\"Expected a field name.\");\n                }\n\n                reader.Read();\n                switch (propName.ToLowerInvariant())\n                {\n                    case \"quantity\":\n                        if (options.PropertyNameCaseInsensitive || propName == quantityFieldName)\n                        {\n                            quantityString = reader.GetString();\n                            reader.Read();\n                            if (quantityString is null)\n                            {\n                                throw new JsonException(\"Expected a string value.\");\n                            }\n                        }\n\n                        break;\n\n                    case \"currency\":\n                        if (options.PropertyNameCaseInsensitive || propName == currencyFieldName)\n                        {\n                            currency = JsonSerializer.Deserialize<Currency>(ref reader, options);\n                            if (currency is null)\n                            {\n                                throw new JsonException(\n                                    $\"Expected an object representation of {nameof(Currency)}.\");\n                            }\n                        }\n\n                        break;\n\n                    default:\n                        throw new JsonException($\"Unexpected field name: {propName}.\");\n                }\n            }\n\n            if (reader.TokenType != JsonTokenType.EndObject)\n            {\n                throw new JsonException($\"Unexpected token: {reader.TokenType}.\");\n            }\n\n            reader.Read();\n\n            if (!(quantityString is { } q))\n            {\n                throw new JsonException($\"Missing field: \\\"{quantityFieldName}\\\".\");\n            }\n\n            if (!(currency is { } c))\n            {\n                throw new JsonException($\"Missing field: \\\"{currencyFieldName}\\\".\");\n            }\n\n            return FungibleAssetValue.Parse(c, q);\n        }\n\n        public override void Write(\n            Utf8JsonWriter writer,\n            FungibleAssetValue value,\n            JsonSerializerOptions options\n        )\n        {\n            writer.WriteStartObject();\n            writer.WriteString(\n                options.PropertyNamingPolicy?.ConvertName(\"Quantity\") ?? \"Quantity\",\n                value.GetQuantityString()\n            );\n            writer.WritePropertyName(\n                options.PropertyNamingPolicy?.ConvertName(\"Currency\") ?? \"Currency\");\n            JsonSerializer.Serialize(writer, value.Currency, options);\n            writer.WriteEndObject();\n        }\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Types/Blocks/Block.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Collections.Immutable;\nusing System.Security.Cryptography;\nusing System.Text.Json.Serialization;\nusing Libplanet.Common;\nusing Libplanet.Common.JsonConverters;\nusing Libplanet.Crypto;\nusing Libplanet.Types.Evidence;\nusing Libplanet.Types.Tx;\n\nnamespace Libplanet.Types.Blocks\n{\n    /// <summary>\n    /// The complete block including all block contents and action evaluation.\n    /// </summary>\n    public sealed class Block : IPreEvaluationBlock, IBlockHeader, IEquatable<Block>\n    {\n        /// <summary>\n        /// The latest protocol version.\n        /// </summary>\n        public const int CurrentProtocolVersion = BlockMetadata.CurrentProtocolVersion;\n\n        private readonly BlockHeader _header;\n        private readonly PreEvaluationBlock _preEvaluationBlock;\n\n        /// <summary>\n        /// Creates a <see cref=\"Block\"/> instance by combining a block <paramref name=\"header\"/>\n        /// and <paramref name=\"transactions\"/>.\n        /// </summary>\n        /// <param name=\"header\">The block header.</param>\n        /// <param name=\"transactions\">The transactions to include.</param>\n        /// <param name=\"evidence\">The evidence to include.</param>\n        /// <exception cref=\"InvalidBlockProtocolVersionException\">Thrown when\n        /// the <paramref name=\"header\"/>'s <see cref=\"IBlockMetadata.ProtocolVersion\"/>\n        /// is less than 0, or greater than <see cref=\"BlockMetadata.CurrentProtocolVersion\"/>,\n        /// the latest known protocol version.</exception>\n        /// <exception cref=\"InvalidBlockIndexException\">Thrown when the <paramref name=\"header\"/>\n        /// has a negative <see cref=\"IBlockMetadata.Index\"/>.</exception>\n        /// <exception cref=\"InvalidTxSignatureException\">Thrown when any tx signature is invalid or\n        /// not signed by its signer.</exception>\n        /// <exception cref=\"InvalidTxNonceException\">Thrown when the same tx nonce is used by\n        /// a signer twice or more, or a tx nonce is used without its previous nonce by a signer.\n        /// Note that this validates only a block's intrinsic integrity between its transactions,\n        /// but does not guarantee integrity between blocks.  Such validation needs to be conducted\n        /// by <see cref=\"Blockchain.BlockChain\"/>.</exception>\n        /// <exception cref=\"InvalidTxGenesisHashException\">Thrown when transactions to set have\n        /// inconsistent genesis hashes.</exception>\n        /// <exception cref=\"InvalidBlockTxHashException\">Thrown when the given block\n        /// <paramref name=\"header\"/>'s <see cref=\"IBlockMetadata.TxHash\"/> is not consistent with\n        /// its <paramref name=\"transactions\"/>.</exception>\n        /// <exception cref=\"InvalidBlockPreEvaluationHashException\">Thrown when the given\n        /// <paramref name=\"header\"/> has an invalid\n        /// <see cref=\"IPreEvaluationBlockHeader.PreEvaluationHash\"/>.</exception>\n        public Block(\n            IBlockHeader header,\n            IEnumerable<Transaction> transactions,\n            IEnumerable<EvidenceBase> evidence)\n            : this(\n                new PreEvaluationBlock(header, transactions, evidence),\n                (header.StateRootHash, header.Signature, header.Hash))\n        {\n        }\n\n        /// <summary>\n        /// Creates a <see cref=\"Block\"/> instance by combining\n        /// a <paramref name=\"preEvaluationBlock\"/>, its corresponding\n        /// <paramref name=\"proof.StateRootHash\"/>, valid <paramref name=\"proof.Signature\"/>,\n        /// and correctly derived <paramref name=\"proof.Hash\"/>.\n        /// </summary>\n        /// <param name=\"preEvaluationBlock\">A pre-evaluation block.</param>\n        /// <param name=\"proof\">A triple of the state root hash, the block signature,\n        /// and the block hash.</param>\n        public Block(\n            PreEvaluationBlock preEvaluationBlock,\n            (\n                HashDigest<SHA256> StateRootHash,\n                ImmutableArray<byte>? Signature,\n                BlockHash Hash\n            ) proof\n        )\n        {\n            _header = new BlockHeader(preEvaluationBlock.Header, proof);\n            _preEvaluationBlock = preEvaluationBlock;\n        }\n\n        /// <summary>\n        /// The <see cref=\"BlockHeader\"/> of the block.\n        /// </summary>\n        [JsonIgnore]\n        public BlockHeader Header => _header;\n\n        /// <inheritdoc cref=\"IBlockMetadata.ProtocolVersion\"/>\n        public int ProtocolVersion => _preEvaluationBlock.ProtocolVersion;\n\n        /// <inheritdoc cref=\"IBlockExcerpt.Hash\"/>\n        public BlockHash Hash => Header.Hash;\n\n        /// <inheritdoc cref=\"IBlockHeader.Signature\"/>\n        [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]\n        [JsonConverter(typeof(ByteArrayJsonConverter))]\n        public ImmutableArray<byte>? Signature => Header.Signature;\n\n        /// <inheritdoc cref=\"IPreEvaluationBlockHeader.PreEvaluationHash\"/>\n        public HashDigest<SHA256> PreEvaluationHash => _preEvaluationBlock.PreEvaluationHash;\n\n        /// <inheritdoc cref=\"IBlockHeader.StateRootHash\"/>\n        public HashDigest<SHA256> StateRootHash => Header.StateRootHash;\n\n        /// <inheritdoc cref=\"IBlockMetadata.Index\"/>\n        public long Index => _preEvaluationBlock.Index;\n\n        /// <inheritdoc cref=\"IBlockMetadata.Miner\"/>\n        public Address Miner => _preEvaluationBlock.Miner;\n\n        /// <inheritdoc cref=\"IBlockMetadata.PublicKey\"/>\n        public PublicKey? PublicKey => _preEvaluationBlock.PublicKey;\n\n        /// <inheritdoc cref=\"IBlockMetadata.PreviousHash\"/>\n        public BlockHash? PreviousHash => _preEvaluationBlock.PreviousHash;\n\n        /// <inheritdoc cref=\"IBlockMetadata.Timestamp\"/>\n        public DateTimeOffset Timestamp => _preEvaluationBlock.Timestamp;\n\n        /// <inheritdoc cref=\"IBlockMetadata.TxHash\"/>\n        public HashDigest<SHA256>? TxHash => _preEvaluationBlock.TxHash;\n\n        /// <inheritdoc cref=\"IBlockMetadata.LastCommit\"/>\n        public BlockCommit? LastCommit => _preEvaluationBlock.LastCommit;\n\n        /// <inheritdoc cref=\"IBlockMetadata.EvidenceHash\"/>\n        public HashDigest<SHA256>? EvidenceHash => _preEvaluationBlock.EvidenceHash;\n\n        /// <inheritdoc cref=\"IBlockContent.Evidence\"/>\n        public IReadOnlyList<EvidenceBase> Evidence => _preEvaluationBlock.Evidence;\n\n        /// <inheritdoc cref=\"IBlockContent.Transactions\"/>\n        public IReadOnlyList<Transaction> Transactions => _preEvaluationBlock.Transactions;\n\n        /// <inheritdoc cref=\"IBlockContent.Transactions\"/>\n        IReadOnlyList<ITransaction> IBlockContent.Transactions => _preEvaluationBlock.Transactions;\n\n        /// <summary>\n        /// Equivalent to <see cref=\"IEquatable{T}.Equals(T)\"/>.\n        /// </summary>\n        /// <param name=\"left\">A block.</param>\n        /// <param name=\"right\">Another block.</param>\n        /// <returns><see langword=\"true\"/> if two blocks are equal.\n        /// Otherwise <see langword=\"false\"/>.</returns>\n        public static bool operator ==(Block? left, Block? right) =>\n            Equals(left, right);\n\n        /// <summary>\n        /// Negation of <see cref=\"IEquatable{T}.Equals(T)\"/>.\n        /// </summary>\n        /// <param name=\"left\">A block.</param>\n        /// <param name=\"right\">Another block.</param>\n        /// <returns><see langword=\"true\"/> if two blocks are different.\n        /// Otherwise <see langword=\"false\"/>.</returns>\n        public static bool operator !=(Block? left, Block? right) =>\n            !Equals(left, right);\n\n        /// <inheritdoc cref=\"IEquatable{T}.Equals(T)\"/>\n        public bool Equals(Block? other)\n        {\n            if (other is null)\n            {\n                return false;\n            }\n\n            return ReferenceEquals(this, other) || Hash.Equals(other.Hash);\n        }\n\n        /// <inheritdoc cref=\"object.Equals(object?)\"/>\n        public override bool Equals(object? obj) =>\n            obj is Block other && Equals(other);\n\n        /// <inheritdoc cref=\"object.GetHashCode()\"/>\n        public override int GetHashCode() =>\n            unchecked((17 * 31 + Hash.GetHashCode()) * 31);\n\n        /// <inheritdoc cref=\"object.ToString()\"/>\n        public override string ToString() =>\n            Hash.ToString();\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Types/Blocks/BlockCommit.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Collections.Immutable;\nusing System.Diagnostics.CodeAnalysis;\nusing System.Diagnostics.Contracts;\nusing System.Globalization;\nusing System.Linq;\nusing System.Security.Cryptography;\nusing System.Text.Json;\nusing System.Text.Json.Serialization;\nusing Bencodex;\nusing Bencodex.Types;\nusing Libplanet.Common;\nusing Libplanet.Types.Consensus;\n\nnamespace Libplanet.Types.Blocks\n{\n    public sealed class BlockCommit : IEquatable<BlockCommit>, IBencodable\n    {\n        private static readonly Binary HeightKey = new Binary(new byte[] { 0x48 });    // 'H'\n        private static readonly Binary RoundKey = new Binary(new byte[] { 0x52 });     // 'R'\n        private static readonly Binary BlockHashKey = new Binary(new byte[] { 0x68 }); // 'h'\n        private static readonly Binary VotesKey = new Binary(new byte[] { 0x56 });     // 'V'\n\n        private static Codec _codec = new Codec();\n\n        /// <summary>\n        /// Creates an instance of <see cref=\"BlockCommit\"/> given a set of <see cref=\"Vote\"/>s.\n        /// </summary>\n        /// <param name=\"height\">The <see cref=\"Block.Index\"/> of the last committed\n        /// <see cref=\"Block\"/>.</param>\n        /// <param name=\"round\">The round in which a consensus was reached.</param>\n        /// <param name=\"blockHash\">The <see cref=\"Block.Hash\"/> of the last committed\n        /// <see cref=\"Block\"/>.</param>\n        /// <param name=\"votes\">The set of <see cref=\"Vote\"/>s as a proof for the commit\n        /// of the last <see cref=\"Block\"/>.</param>\n        /// <exception cref=\"ArgumentOutOfRangeException\">Thrown when either\n        /// <paramref name=\"height\"/> or <paramref name=\"round\"/> is negative.</exception>\n        /// <exception cref=\"ArgumentException\">Thrown for any of the following reasons:\n        /// <list type=\"bullet\">\n        /// <item><description>\n        ///     Given <paramref name=\"votes\"/> is empty.\n        /// </description></item>\n        /// <item><description>\n        ///     Any one of <see cref=\"Vote\"/> of <paramref name=\"votes\"/> has a different\n        ///     <see cref=\"Vote.Height\"/> from <paramref name=\"height\"/>.\n        /// </description></item>\n        /// <item><description>\n        ///     Any one of <see cref=\"Vote\"/> of <paramref name=\"votes\"/> has a different\n        ///     <see cref=\"Vote.Round\"/> from <paramref name=\"round\"/>.\n        /// </description></item>\n        /// <item><description>\n        ///     Any one of <see cref=\"Vote\"/> of <paramref name=\"votes\"/> has a different\n        ///     <see cref=\"Vote.BlockHash\"/> from <paramref name=\"blockHash\"/>.\n        /// </description></item>\n        /// <item><description>\n        ///     Any one of <see cref=\"Vote\"/> of <paramref name=\"votes\"/> has\n        ///     <see cref=\"Vote.Flag\"/> that is neither <see cref=\"VoteFlag.Null\"/>\n        ///     nor <see cref=\"VoteFlag.PreCommit\"/>.\n        /// </description></item>\n        /// <item><description>\n        ///     The number of <see cref=\"Vote\"/>s with <see cref=\"Vote.Flag\"/> set as\n        ///     <see cref=\"VoteFlag.PreCommit\"/> does not exceed 2/3 of the total number of\n        ///     <see cref=\"Vote\"/>s in <paramref name=\"votes\"/>\n        /// </description></item>\n        /// </list>\n        /// </exception>\n        public BlockCommit(\n            long height,\n            int round,\n            BlockHash blockHash,\n            ImmutableArray<Vote> votes)\n        {\n            // TODO: Implement separate exception for each case.\n            // TODO: Optimize by using flags to allow single iterating through votes.\n            if (height < 0)\n            {\n                throw new ArgumentOutOfRangeException(\n                    nameof(height),\n                    $\"Height must be non-negative: {height}\");\n            }\n            else if (round < 0)\n            {\n                throw new ArgumentOutOfRangeException(\n                    nameof(round),\n                    $\"Round must be non-negative: {round}\");\n            }\n            else if (votes.IsDefaultOrEmpty)\n            {\n                throw new ArgumentException(\"Empty set of votes is not allowed.\", nameof(votes));\n            }\n            else if (votes.Any(vote =>\n                vote.Height != height ||\n                vote.Round != round ||\n                !blockHash.Equals(vote.BlockHash) ||\n                (vote.Flag != VoteFlag.Null && vote.Flag != VoteFlag.PreCommit) ||\n                (vote.Flag == VoteFlag.PreCommit && !vote.Verify())))\n            {\n                throw new ArgumentException(\n                    $\"Every vote must have the same height as {height}, the same round \" +\n                    $\"as {round}, the same hash as {blockHash}, and must have flag value of \" +\n                    $\"either {VoteFlag.Null} or {VoteFlag.PreCommit}, \" +\n                    $\"and must be signed if the vote's flag is {VoteFlag.PreCommit}.\",\n                    nameof(votes));\n            }\n\n            Height = height;\n            Round = round;\n            BlockHash = blockHash;\n            Votes = votes;\n        }\n\n        public BlockCommit(Bencodex.Types.IValue bencoded)\n            : this(bencoded is Bencodex.Types.Dictionary dict\n                ? dict\n                : throw new ArgumentException(\n                    $\"Given {nameof(bencoded)} must be of type \" +\n                    $\"{typeof(Bencodex.Types.Dictionary)}: {bencoded.GetType()}\",\n                    nameof(bencoded)))\n        {\n        }\n\n        [SuppressMessage(\n            \"StyleCop.CSharp.ReadabilityRules\",\n            \"SA1118:ParameterMustNotSpanMultipleLines\",\n            Justification =\n                \"Multiple lines are Vote decoding. Redirect Bencodex value to public \" +\n                \"constructor for checking not allowed values.\")]\n        private BlockCommit(Bencodex.Types.Dictionary bencoded)\n            : this(\n                (Integer)bencoded[HeightKey],\n                (Integer)bencoded[RoundKey],\n                new BlockHash(bencoded[BlockHashKey]),\n                bencoded.ContainsKey(VotesKey)\n                    ? ((List)bencoded[VotesKey])\n                        .Select(vote => new Vote(vote))\n                        .ToImmutableArray()\n                    : ImmutableArray<Vote>.Empty)\n        {\n        }\n\n        public long Height { get; }\n\n        public int Round { get; }\n\n        public BlockHash BlockHash { get; }\n\n        public ImmutableArray<Vote> Votes { get; }\n\n        [JsonIgnore]\n        public Bencodex.Types.IValue Bencoded\n        {\n            get\n            {\n                var dict = Bencodex.Types.Dictionary.Empty\n                    .Add(HeightKey, Height)\n                    .Add(RoundKey, Round)\n                    .Add(BlockHashKey, BlockHash.ByteArray);\n\n                if (!Votes.IsEmpty)\n                {\n                    dict = dict.Add(VotesKey, new List(Votes.Select(x => x.Bencoded)));\n                }\n\n                return dict;\n            }\n        }\n\n        public bool Equals(BlockCommit? other)\n        {\n            return other is BlockCommit commit &&\n                Height == commit.Height &&\n                Round == commit.Round &&\n                BlockHash.Equals(commit.BlockHash) &&\n                Votes.SequenceEqual(commit.Votes);\n        }\n\n        /// <inheritdoc/>\n        public override bool Equals(object? obj)\n        {\n            return obj is BlockCommit other && Equals(other);\n        }\n\n        public override int GetHashCode()\n        {\n            return HashCode.Combine(Height, Round, BlockHash, Votes);\n        }\n\n        /// <summary>\n        /// Gets a <see cref=\"SHA256\"/> digested <see cref=\"BlockCommit\"/> hash value.\n        /// </summary>\n        /// <returns>Returns a <see cref=\"SHA256\"/> digested <see cref=\"BlockCommit\"/>.</returns>\n        public HashDigest<SHA256> ToHash() =>\n            HashDigest<SHA256>.DeriveFrom(_codec.Encode(Bencoded));\n\n        /// <inheritdoc/>\n        [Pure]\n        public override string ToString()\n        {\n            var dict = new Dictionary<string, object>\n            {\n                { \"block_hash\", BlockHash.ToString() },\n                { \"height\", Height },\n                { \"round\", Round },\n                {\n                    \"votes\",\n                    Votes.Select(\n                        v => new Dictionary<string, object>\n                        {\n                            { \"validator_public_key\", v.ValidatorPublicKey.ToString() },\n                            { \"flag\", v.Flag },\n                            { \"timestamp\", v.Timestamp.ToString(CultureInfo.InvariantCulture) },\n                        })\n                },\n            };\n            return JsonSerializer.Serialize(dict);\n        }\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Types/Blocks/BlockContent.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Collections.Immutable;\nusing System.Security.Cryptography;\nusing Libplanet.Common;\nusing Libplanet.Crypto;\nusing Libplanet.Types.Evidence;\nusing Libplanet.Types.Tx;\n\nnamespace Libplanet.Types.Blocks\n{\n    /// <summary>\n    /// A block content without any proofs like nonce or hash.  This represents contents of a\n    /// block that is not yet mined.\n    /// </summary>\n    /// <remarks>Unlike other model types like <see cref=\"Block\"/> or\n    /// <see cref=\"Transaction\"/>, this type is mutable.</remarks>\n    public sealed class BlockContent : IBlockContent\n    {\n        private readonly BlockMetadata _blockMetadata;\n        private readonly IReadOnlyList<Transaction> _transactions;\n        private readonly IReadOnlyList<EvidenceBase> _evidence;\n\n        /// <summary>\n        /// Creates a new <see cref=\"BlockContent\"/> instance filled with given\n        /// <paramref name=\"metadata\"/> and <paramref name=\"transactions\"/>.\n        /// </summary>\n        /// <remarks>\n        /// This creates a new instance of <see cref=\"BlockMetadata\"/> to check the validity\n        /// of <paramref name=\"metadata\"/>, hence throws any <see cref=\"Exception\"/>s that may\n        /// arise from a <see cref=\"BlockMetadata\"/>'s constructor in addition to the ones\n        /// explicitly listed below.\n        /// </remarks>\n        /// <param name=\"metadata\">The <see cref=\"IBlockMetadata\"/> to copy.</param>\n        /// <param name=\"transactions\">The transactions to include in the block.</param>\n        /// <param name=\"evidence\">The evidence to include in the block.</param>\n        /// <exception cref=\"InvalidTxSignatureException\">Thrown when any tx signature is invalid or\n        /// not signed by its signer.</exception>\n        /// <exception cref=\"InvalidTxNonceException\">Thrown when the same tx nonce is used by\n        /// a signer twice or more, or a tx nonce is used without its previous nonce by a signer.\n        /// Note that this validates only a block's intrinsic integrity between its transactions,\n        /// but does not guarantee integrity between blocks.  Such validation needs to be conducted\n        /// by <see cref=\"Blockchain.BlockChain\"/>.</exception>\n        /// <exception cref=\"InvalidTxGenesisHashException\">Thrown when transactions to set have\n        /// inconsistent genesis hashes.</exception>\n        /// <exception cref=\"InvalidBlockTxHashException\">Thrown when the given\n        /// <paramref name=\"metadata\"/>'s <see cref=\"IBlockMetadata.TxHash\"/> is inconsistent with\n        /// <paramref name=\"transactions\"/>.</exception>\n        /// <seealso cref=\"BlockMetadata\"/>\n        public BlockContent(\n            IBlockMetadata metadata,\n            IEnumerable<Transaction> transactions,\n            IEnumerable<EvidenceBase> evidence)\n            : this(new BlockMetadata(metadata), transactions, evidence)\n        {\n        }\n\n        /// <summary>\n        /// Creates a new <see cref=\"BlockContent\"/> instance with given\n        /// <paramref name=\"metadata\"/> and without any <see cref=\"Transaction\"/>s.\n        /// </summary>\n        /// <param name=\"metadata\">The <see cref=\"BlockMetadata\"/> to include in the block.</param>\n        /// <exception cref=\"InvalidBlockTxHashException\">Thrown when the given\n        /// <paramref name=\"metadata\"/>'s <see cref=\"IBlockMetadata.TxHash\"/> is not\n        /// <see lagnword=\"null\"/>.</exception>\n        public BlockContent(\n            BlockMetadata metadata)\n            : this(metadata, new List<Transaction>(), new List<EvidenceBase>())\n        {\n        }\n\n        /// <summary>\n        /// Creates a new <see cref=\"BlockContent\"/> instance with given\n        /// <paramref name=\"metadata\"/> and <paramref name=\"transactions\"/>.\n        /// </summary>\n        /// <param name=\"metadata\">The <see cref=\"BlockMetadata\"/> to include in the block.</param>\n        /// <param name=\"transactions\">The transactions to include in the block.</param>\n        /// <param name=\"evidence\">The evidence to include in the block.</param>\n        /// <exception cref=\"InvalidBlockTxHashException\">Thrown when the given\n        /// <paramref name=\"metadata\"/>'s <see cref=\"IBlockMetadata.TxHash\"/> is inconsistent with\n        /// <paramref name=\"transactions\"/>.</exception>\n        /// <exception cref=\"InvalidTxSignatureException\">Thrown when any tx signature is invalid\n        /// or not signed by its signer.</exception>\n        /// <exception cref=\"InvalidTxNonceException\">Thrown when the same tx nonce is used by\n        /// a signer twice or more, or a tx nonce is used without its previous nonce by a signer.\n        /// Note that this validates only a block's intrinsic integrity between its transactions,\n        /// but does not guarantee integrity between blocks.  Such validation needs to be conducted\n        /// by <see cref=\"Blockchain.BlockChain\"/>.</exception>\n        /// <exception cref=\"InvalidTxGenesisHashException\">Thrown when transactions to set have\n        /// inconsistent genesis hashes.</exception>\n        /// <exception cref=\"ArgumentException\">Thrown when <paramref name=\"transactions\"/> is\n        /// not ordered by <see cref=\"Transaction.Id\"/>s.</exception>\n        public BlockContent(\n            BlockMetadata metadata,\n            IEnumerable<Transaction> transactions,\n            IEnumerable<EvidenceBase> evidence)\n        {\n            // Check if TxHash provided by metadata is valid.\n            HashDigest<SHA256>? derivedTxHash = DeriveTxHash(transactions);\n            if (!((metadata.TxHash is { } a && derivedTxHash is { } b && a.Equals(b)) ||\n                (metadata.TxHash is null && derivedTxHash is null)))\n            {\n                throw new InvalidBlockTxHashException(\n                    $\"The block #{metadata.Index}'s {nameof(metadata.TxHash)} is invalid.\",\n                    metadata.TxHash,\n                    derivedTxHash);\n            }\n\n            // Check if transactions are ordered with valid nonces.\n            transactions.ValidateTxNonces(metadata.Index);\n            TxId? prevId = null;\n            foreach (Transaction tx in transactions)\n            {\n                if (prevId is { } prev && prev.CompareTo(tx.Id) > 0)\n                {\n                    throw new ArgumentException(\n                        $\"Transactions must be ordered by their {nameof(Transaction.Id)}s.\",\n                        nameof(transactions));\n                }\n\n                prevId = tx.Id;\n            }\n\n            ValidateEvidence(metadata, evidence);\n\n            _blockMetadata = metadata;\n            _transactions = transactions.ToImmutableList();\n            _evidence = evidence.ToImmutableList();\n        }\n\n        /// <summary>\n        /// Internal <see cref=\"BlockMetadata\"/>.\n        /// </summary>\n        public BlockMetadata Metadata => _blockMetadata;\n\n        /// <inheritdoc cref=\"IBlockMetadata.ProtocolVersion\"/>\n        public int ProtocolVersion => _blockMetadata.ProtocolVersion;\n\n        /// <inheritdoc cref=\"IBlockMetadata.Index\"/>\n        public long Index => _blockMetadata.Index;\n\n        /// <inheritdoc cref=\"IBlockMetadata.Timestamp\"/>\n        public DateTimeOffset Timestamp => _blockMetadata.Timestamp;\n\n        /// <inheritdoc cref=\"IBlockMetadata.Miner\"/>\n        public Address Miner => _blockMetadata.Miner;\n\n        /// <inheritdoc cref=\"IBlockMetadata.PublicKey\"/>\n        public PublicKey? PublicKey => _blockMetadata.PublicKey;\n\n        /// <inheritdoc cref=\"IBlockMetadata.PreviousHash\"/>\n        public BlockHash? PreviousHash => _blockMetadata.PreviousHash;\n\n        /// <inheritdoc cref=\"IBlockMetadata.TxHash\"/>\n        public HashDigest<SHA256>? TxHash => _blockMetadata.TxHash;\n\n        /// <inheritdoc cref=\"IBlockMetadata.LastCommit\"/>\n        public BlockCommit? LastCommit => _blockMetadata.LastCommit;\n\n        /// <inheritdoc cref=\"IBlockMetadata.EvidenceHash\"/>\n        public HashDigest<SHA256>? EvidenceHash => _blockMetadata.EvidenceHash;\n\n        /// <inheritdoc cref=\"IBlockMetadata.EvidenceHash\"/>\n        public IReadOnlyList<EvidenceBase> Evidence => _evidence;\n\n        /// <summary>\n        /// Transactions belonging to the block.\n        /// </summary>\n        /// <remarks>This is always ordered by <see cref=\"Transaction.Id\"/>.</remarks>\n        public IReadOnlyList<Transaction> Transactions => _transactions;\n\n        IReadOnlyList<ITransaction> IBlockContent.Transactions => _transactions;\n\n        /// <summary>\n        /// Derives <see cref=\"IBlockMetadata.TxHash\"/> from given <paramref name=\"transactions\"/>.\n        /// </summary>\n        /// <param name=\"transactions\">The transactions to derive\n        /// <see cref=\"IBlockMetadata.TxHash\"/> from.  This must be ordered by\n        /// <see cref=\"Transaction.Id\"/>.</param>\n        /// <returns>The derived <see cref=\"IBlockMetadata.TxHash\"/>.</returns>\n        /// <exception cref=\"ArgumentException\">Thrown when the <paramref name=\"transactions\"/> are\n        /// not ordered by their <see cref=\"Transaction.Id\"/>s.</exception>\n        public static HashDigest<SHA256>? DeriveTxHash(IEnumerable<Transaction> transactions)\n        {\n            TxId? prevId = null;\n            SHA256 hasher = SHA256.Create();\n\n            // Bencodex lists look like: l...e\n            hasher.TransformBlock(new byte[] { 0x6c }, 0, 1, null, 0);  // \"l\"\n            foreach (Transaction tx in transactions)\n            {\n                if (prevId is { } prev && prev.CompareTo(tx.Id) > 0)\n                {\n                    throw new ArgumentException(\n                        $\"Transactions must be ordered by their {nameof(Transaction.Id)}s.\",\n                        nameof(transactions)\n                    );\n                }\n\n                byte[] payload = tx.Serialize();\n                hasher.TransformBlock(payload, 0, payload.Length, null, 0);\n                prevId = tx.Id;\n            }\n\n            if (prevId is null)\n            {\n                return null;\n            }\n\n            hasher.TransformFinalBlock(new byte[] { 0x65 }, 0, 1);  // \"e\"\n            if (hasher.Hash is { } hash)\n            {\n                return new HashDigest<SHA256>(hash);\n            }\n\n            return null;\n        }\n\n        public static HashDigest<SHA256>? DeriveEvidenceHash(IEnumerable<EvidenceBase> evidence)\n        {\n            EvidenceId? prevId = null;\n            SHA256 hasher = SHA256.Create();\n\n            // Bencodex lists look like: l...e\n            hasher.TransformBlock(new byte[] { 0x6c }, 0, 1, null, 0);  // \"l\"\n            foreach (EvidenceBase ev in evidence)\n            {\n                if (prevId is { } prev && prev.CompareTo(ev.Id) > 0)\n                {\n                    throw new ArgumentException(\n                        $\"Transactions must be ordered by their {nameof(Transaction.Id)}s.\",\n                        nameof(evidence)\n                    );\n                }\n\n                byte[] payload = ev.Serialize();\n                hasher.TransformBlock(payload, 0, payload.Length, null, 0);\n                prevId = ev.Id;\n            }\n\n            if (prevId is null)\n            {\n                return null;\n            }\n\n            hasher.TransformFinalBlock(new byte[] { 0x65 }, 0, 1);  // \"e\"\n            if (hasher.Hash is { } hash)\n            {\n                return new HashDigest<SHA256>(hash);\n            }\n\n            return null;\n        }\n\n        public PreEvaluationBlock Propose() =>\n            new PreEvaluationBlock(\n                this,\n                _blockMetadata.DerivePreEvaluationHash());\n\n        private static void ValidateEvidence(\n            BlockMetadata metadata,\n            IEnumerable<EvidenceBase> evidence)\n        {\n            // Check if EvidenceHash provided by metadata is valid.\n            HashDigest<SHA256>? evidenceHash = metadata.EvidenceHash;\n            HashDigest<SHA256>? derivedEvidenceHash = DeriveEvidenceHash(evidence);\n            if (!((evidenceHash is { } e1 && derivedEvidenceHash is { } e2 && e1.Equals(e2)) ||\n                (evidenceHash is null && derivedEvidenceHash is null)))\n            {\n                throw new InvalidBlockEvidenceHashException(\n                    $\"The block #{metadata.Index}'s {nameof(metadata.EvidenceHash)} is invalid.\",\n                    metadata.EvidenceHash,\n                    derivedEvidenceHash);\n            }\n\n            // Check if transactions are ordered with valid nonces.\n            EvidenceId? evidenceId = null;\n            foreach (EvidenceBase ev in evidence)\n            {\n                if (evidenceId is { } prev && prev.CompareTo(ev.Id) > 0)\n                {\n                    throw new ArgumentException(\n                        $\"Evidence must be ordered by their {nameof(EvidenceBase.Id)}s.\",\n                        nameof(ev));\n                }\n\n                evidenceId = ev.Id;\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Types/Blocks/BlockExcerptExtensions.cs",
    "content": "namespace Libplanet.Types.Blocks\n{\n    /// <summary>\n    /// The extension methods for <see cref=\"IBlockExcerpt\"/>.\n    /// </summary>\n    public static class BlockExcerptExtensions\n    {\n        /// <summary>\n        /// Shows <see cref=\"IBlockExcerpt\"/> instance's members as a string.\n        /// </summary>\n        /// <param name=\"excerpt\">An excerpt object to show.</param>\n        /// <returns>Extracted members as a string.</returns>\n        public static string ToExcerptString(this IBlockExcerpt excerpt)\n        {\n            return\n                $\"{excerpt.GetType().Name} {{\" +\n                $\" {nameof(excerpt.ProtocolVersion)} = {excerpt.ProtocolVersion},\" +\n                $\" {nameof(excerpt.Index)} = {excerpt.Index},\" +\n                $\" {nameof(excerpt.Hash)} = {excerpt.Hash},\" +\n                \" }\";\n        }\n\n        public static bool ExcerptEquals(this IBlockExcerpt excerpt, IBlockExcerpt other)\n        {\n            return excerpt.ProtocolVersion.Equals(other.ProtocolVersion)\n                && excerpt.Index.Equals(other.Index)\n                && excerpt.Hash.Equals(other.Hash);\n        }\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Types/Blocks/BlockHash.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Collections.Immutable;\nusing System.Diagnostics.CodeAnalysis;\nusing System.Diagnostics.Contracts;\nusing System.Linq;\nusing System.Security.Cryptography;\nusing System.Text.Json;\nusing System.Text.Json.Serialization;\nusing Bencodex;\nusing Libplanet.Common;\n\nnamespace Libplanet.Types.Blocks\n{\n    /// <summary>\n    /// A value type to represent SHA-256 digest of <see cref=\"Block\"/> data.\n    /// </summary>\n    /// <seealso cref=\"Block.Hash\"/>\n    [JsonConverter(typeof(BlockHashJsonConverter))]\n    public readonly struct BlockHash :\n        IEquatable<BlockHash>, IComparable<BlockHash>, IComparable, IBencodable\n    {\n        /// <summary>\n        /// The size of bytes that each <see cref=\"BlockHash\"/> consists of.\n        /// </summary>\n        public const int Size = 32;\n\n        private static readonly ImmutableArray<byte> _defaultByteArray =\n            new byte[32].ToImmutableArray();\n\n        private readonly ImmutableArray<byte> _byteArray;\n\n        /// <summary>\n        /// Converts an immutable <see cref=\"byte\"/> array into a <see cref=\"BlockHash\"/>.\n        /// </summary>\n        /// <param name=\"blockHash\">An immutable <see cref=\"byte\"/> array that encodes\n        /// a SHA-256 digest of a <see cref=\"Block\"/>.</param>\n        /// <exception cref=\"ArgumentOutOfRangeException\">Thrown when the given\n        /// <paramref name=\"blockHash\"/>'s <see cref=\"ImmutableArray{T}.Length\"/> is not 32.\n        /// </exception>\n        public BlockHash(in ImmutableArray<byte> blockHash)\n        {\n            if (blockHash.Length != Size)\n            {\n                string message =\n                    $\"{nameof(BlockHash)} must be {Size} bytes, but {blockHash.Length} was given.\";\n                throw new ArgumentOutOfRangeException(nameof(blockHash), message);\n            }\n\n            _byteArray = blockHash;\n        }\n\n        /// <summary>\n        /// Converts a <see cref=\"byte\"/> array into a <see cref=\"BlockHash\"/>.\n        /// </summary>\n        /// <param name=\"blockHash\">A <see cref=\"byte\"/> array that encodes\n        /// a <see cref=\"BlockHash\"/>.</param>\n        /// <exception cref=\"ArgumentNullException\">Thrown when the given\n        /// <paramref name=\"blockHash\"/> is <see langword=\"null\"/>.</exception>\n        /// <exception cref=\"ArgumentOutOfRangeException\">Thrown when the given\n        /// <paramref name=\"blockHash\"/>'s <see cref=\"ImmutableArray{T}.Length\"/> is not 32.\n        /// </exception>\n        public BlockHash(byte[] blockHash)\n            : this(blockHash.ToImmutableArray())\n        {\n        }\n\n        public BlockHash(Bencodex.Types.IValue bencoded)\n            : this(bencoded is Bencodex.Types.Binary binary\n                ? binary\n                : throw new ArgumentException(\n                    $\"Given {nameof(bencoded)} must be of type \" +\n                    $\"{typeof(Bencodex.Types.Dictionary)}: {bencoded.GetType()}\",\n                    nameof(bencoded)))\n        {\n        }\n\n        private BlockHash(Bencodex.Types.Binary bencoded)\n            : this(bencoded.ByteArray)\n        {\n        }\n\n        /// <summary>\n        /// A bare immutable <see cref=\"byte\"/> array of the block hash.\n        /// </summary>\n        /// <remarks>It is immutable.  For a mutable array, use <see cref=\"ToByteArray()\"/> method\n        /// instead.</remarks>\n        /// <seealso cref=\"ToByteArray()\"/>\n        public ImmutableArray<byte> ByteArray =>\n            _byteArray.IsDefault ? _defaultByteArray : _byteArray;\n\n        /// <inheritdoc/>\n        public Bencodex.Types.IValue Bencoded => new Bencodex.Types.Binary(ByteArray);\n\n        /// <summary>\n        /// Converts a given hexadecimal representation of a block hash into\n        /// a <see cref=\"BlockHash\"/> value.\n        /// <para>This is an inverse function of <see cref=\"ToString()\"/> method.</para>\n        /// </summary>\n        /// <param name=\"hex\">A hexadecimal representation of a <see cref=\"BlockHash\"/>.</param>\n        /// <returns>A corresponding <see cref=\"BlockHash\"/> value.</returns>\n        /// <exception cref=\"ArgumentNullException\">Thrown when the given <paramref name=\"hex\"/> is\n        /// <see langword=\"null\"/>.</exception>\n        /// <exception cref=\"ArgumentOutOfRangeException\">Thrown when the length of the given\n        /// <paramref name=\"hex\"/> string is an odd number.</exception>\n        /// <exception cref=\"FormatException\">Thrown when the given <paramref name=\"hex\"/> string\n        /// is not a valid hexadecimal string.</exception>\n        /// <exception cref=\"ArgumentOutOfRangeException\">Thrown when the given\n        /// <paramref name=\"hex\"/>'s length is not 64.</exception>\n        /// <seealso cref=\"ToString()\"/>\n        [Pure]\n        public static BlockHash FromString(string hex) =>\n            new BlockHash(\n                ByteUtil.ParseHexToImmutable(hex ?? throw new ArgumentNullException(nameof(hex)))\n            );\n\n        /// <summary>\n        /// Converts a given <see cref=\"HashDigest{SHA256}\"/> into a <see cref=\"BlockHash\"/> value.\n        /// </summary>\n        /// <param name=\"hashDigest\">A SHA-256 digest.</param>\n        /// <returns>A block hash corresponding to the <paramref name=\"hashDigest\"/>.</returns>\n        [Pure]\n        public static BlockHash FromHashDigest(HashDigest<SHA256> hashDigest)\n            => new BlockHash(hashDigest.ByteArray);\n\n        /// <summary>\n        /// Computes a SHA-256 digest from the given <paramref name=\"blockBytes\"/>.\n        /// </summary>\n        /// <param name=\"blockBytes\">The bytes serializing a block to compute its hash.</param>\n        /// <returns>The SHA-256 hash digest derived from <paramref name=\"blockBytes\"/>.</returns>\n        [Pure]\n        public static BlockHash DeriveFrom(IReadOnlyList<byte> blockBytes)\n        {\n            SHA256 sha256 = SHA256.Create();\n            byte[] digest = sha256.ComputeHash(blockBytes is byte[] b ? b : blockBytes.ToArray());\n            return new BlockHash(digest);\n        }\n\n        /// <summary>\n        /// Gets a bare mutable <see cref=\"byte\"/> array of the block hash.\n        /// </summary>\n        /// <returns>A new mutable <see cref=\"byte\"/> array of the block hash.\n        /// Since a returned array is created every time the method is called,\n        /// any mutations on that array does not affect to the block hash object.\n        /// </returns>\n        /// <seealso cref=\"ByteArray\"/>\n        [Pure]\n        public byte[] ToByteArray() => ByteArray.ToArray();\n\n        /// <inheritdoc cref=\"IEquatable{T}.Equals(T)\"/>\n        [Pure]\n        public bool Equals(BlockHash other)\n        {\n            if (_byteArray.IsDefaultOrEmpty && other._byteArray.IsDefaultOrEmpty)\n            {\n                return true;\n            }\n            else if (ByteArray.Length != other.ByteArray.Length)\n            {\n                return false;\n            }\n\n            for (int i = 0; i < ByteArray.Length; i++)\n            {\n                if (!ByteArray[i].Equals(other.ByteArray[i]))\n                {\n                    return false;\n                }\n            }\n\n            return true;\n        }\n\n        /// <inheritdoc cref=\"object.Equals(object)\"/>\n        [Pure]\n        public override bool Equals(object? obj) =>\n            obj is BlockHash h && Equals(h);\n\n        /// <inheritdoc cref=\"object.GetHashCode()\"/>\n        [Pure]\n        public override int GetHashCode()\n        {\n            int code = 0;\n            unchecked\n            {\n                foreach (byte b in ByteArray)\n                {\n                    code = (code * 397) ^ b.GetHashCode();\n                }\n            }\n\n            return code;\n        }\n\n        /// <inheritdoc cref=\"IComparable{T}.CompareTo(T)\"/>\n        public int CompareTo(BlockHash other)\n        {\n            ImmutableArray<byte> self = ByteArray, operand = other.ByteArray;\n\n            for (int i = 0; i < Size; i++)\n            {\n                int cmp = ((IComparable<byte>)self[i]).CompareTo(operand[i]);\n                if (cmp != 0)\n                {\n                    return cmp;\n                }\n            }\n\n            return 0;\n        }\n\n        /// <inheritdoc cref=\"IComparable.CompareTo(object)\"/>\n        public int CompareTo(object? obj) => obj is BlockHash other\n            ? this.CompareTo(other)\n            : throw new ArgumentException(\n                $\"Argument {nameof(obj)} is not an ${nameof(BlockHash)}.\", nameof(obj));\n\n        /// <inheritdoc cref=\"object.ToString()\"/>\n        [Pure]\n        public override string ToString() =>\n            ByteUtil.Hex(ToByteArray());\n    }\n\n    [SuppressMessage(\n        \"StyleCop.CSharp.MaintainabilityRules\",\n        \"SA1402:FileMayOnlyContainASingleClass\",\n        Justification = \"It's okay to have non-public classes together in a single file.\"\n    )]\n    internal class BlockHashJsonConverter : JsonConverter<BlockHash>\n    {\n        public override BlockHash Read(\n            ref Utf8JsonReader reader,\n            Type typeToConvert,\n            JsonSerializerOptions options\n        )\n        {\n            string? hex = reader.GetString();\n            try\n            {\n                return BlockHash.FromString(hex!);\n            }\n            catch (ArgumentException e)\n            {\n                throw new JsonException(e.Message);\n            }\n        }\n\n        public override void Write(\n            Utf8JsonWriter writer,\n            BlockHash value,\n            JsonSerializerOptions options\n        ) =>\n            writer.WriteStringValue(ByteUtil.Hex(value.ByteArray));\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Types/Blocks/BlockHeader.cs",
    "content": "using System;\nusing System.Collections.Immutable;\nusing System.Security.Cryptography;\nusing Libplanet.Common;\nusing Libplanet.Crypto;\n\nnamespace Libplanet.Types.Blocks\n{\n    /// <summary>\n    /// Block header containing information about <see cref=\"Block\"/>s except transactions.\n    /// </summary>\n    public sealed class BlockHeader : IBlockHeader\n    {\n        private readonly PreEvaluationBlockHeader _preEvaluationBlockHeader;\n        private readonly HashDigest<SHA256> _stateRootHash;\n        private readonly ImmutableArray<byte>? _signature;\n        private readonly BlockHash _hash;\n\n        /// <summary>\n        /// Creates a <see cref=\"BlockHeader\"/> by copying the fields of another\n        /// block <paramref name=\"header\"/>.\n        /// </summary>\n        /// <remarks>\n        /// <para>\n        /// As <paramref name=\"header\"/> needn't be an actual <see cref=\"BlockHeader\"/>\n        /// instance, but simply any object implementing <see cref=\"IBlockHeader\"/>\n        /// interface, it can't be trusted to satisfy all the constraints for a valid\n        /// <see cref=\"BlockHeader\"/> instance.  As such, conditions are checked again\n        /// whilst creating a copy.  This is a relatively heavy operation, so must be used\n        /// sparingly.\n        /// </para>\n        /// <para>\n        /// In particular, this creates a new instance of\n        /// <see cref=\"PreEvaluationBlockHeader\"/> with data extracted from\n        /// <paramref name=\"header\"/>.  Thus any <see cref=\"Exception\"/>s that can be thrown from a\n        /// <see cref=\"PreEvaluationBlockHeader\"/>'s constructors may also be thrown\n        /// in addition to the ones explicitly listed below.\n        /// </para>\n        /// </remarks>\n        /// <param name=\"header\">The block header to copy.</param>\n        /// <exception cref=\"InvalidBlockSignatureException\">Thrown if\n        /// <paramref name=\"header.Signature\"/> is invalid.</exception>\n        /// <exception cref=\"InvalidBlockHashException\">Thrown when <paramref name=\"header.Hash\"/>\n        /// is inconsistent with other arguments.</exception>\n        /// <seealso cref=\"PreEvaluationBlockHeader\"/>\n        public BlockHeader(IBlockHeader header)\n            : this(\n                new PreEvaluationBlockHeader(header),\n                (header.StateRootHash, header.Signature, header.Hash))\n        {\n        }\n\n        /// <summary>\n        /// Creates a <see cref=\"BlockHeader\"/> instance from the given\n        /// <paramref name=\"preEvaluationBlockHeader\"/> and <paramref name=\"stateRootHash\"/>.\n        /// It also checks the sanity of the given <paramref name=\"hash\"/>.\n        /// </summary>\n        /// <param name=\"preEvaluationBlockHeader\">The pre-evaluation block header.</param>\n        /// <param name=\"stateRootHash\">The state root hash.</param>\n        /// <param name=\"signature\">The block signature.</param>\n        /// <param name=\"hash\">The block hash to check.</param>\n        /// <exception cref=\"InvalidBlockSignatureException\">Thrown when\n        /// the <paramref name=\"signature\"/> signature is invalid.</exception>\n        /// <exception cref=\"InvalidBlockHashException\">Thrown when the given block\n        /// <paramref name=\"hash\"/> is consistent with other arguments.</exception>\n        public BlockHeader(\n            PreEvaluationBlockHeader preEvaluationBlockHeader,\n            HashDigest<SHA256> stateRootHash,\n            ImmutableArray<byte>? signature,\n            BlockHash hash)\n            : this(\n                preEvaluationBlockHeader,\n                (stateRootHash, signature, hash))\n        {\n        }\n\n        /// <summary>\n        /// Creates a <see cref=\"BlockHeader\"/> instance with its\n        /// <paramref name=\"preEvaluationBlockHeader\"/> and <paramref name=\"proof\"/>.\n        /// </summary>\n        /// <param name=\"preEvaluationBlockHeader\">The pre-evaluation block header.</param>\n        /// <param name=\"proof\">A triple of the state root hash, the block signature, and the block\n        /// hash which is probably considered as to be derived from\n        /// the <paramref name=\"preEvaluationBlockHeader\"/> and the state root hash.</param>\n        /// <exception cref=\"InvalidBlockSignatureException\">Thrown if\n        /// <paramref name=\"proof.Signature\"/> signature is invalid.</exception>\n        /// <exception cref=\"InvalidBlockHashException\">Thrown when <paramref name=\"proof.Hash\"/>\n        /// is inconsistent with other arguments.</exception>\n        public BlockHeader(\n            PreEvaluationBlockHeader preEvaluationBlockHeader,\n            (\n                HashDigest<SHA256> StateRootHash,\n                ImmutableArray<byte>? Signature,\n                BlockHash Hash\n            ) proof\n        )\n        {\n            BlockHash expectedHash =\n                preEvaluationBlockHeader.DeriveBlockHash(proof.StateRootHash, proof.Signature);\n            if (preEvaluationBlockHeader.ProtocolVersion < BlockMetadata.PBFTProtocolVersion)\n            {\n                // Skip verifying signature for PoW blocks due to change of the block structure.\n                // If verification is required, use older version of LibPlanet(<0.43).\n            }\n            else if (\n                !preEvaluationBlockHeader.VerifySignature(proof.Signature, proof.StateRootHash))\n            {\n                long idx = preEvaluationBlockHeader.Index;\n                string msg = preEvaluationBlockHeader.ProtocolVersion >=\n                    BlockMetadata.SignatureProtocolVersion\n                        ? $\"The block #{idx} #{proof.Hash}'s signature is invalid.\"\n                        : $\"The block #{idx} #{proof.Hash} cannot be signed as its \" +\n                          $\"protocol version is less than \" +\n                          $\"{BlockMetadata.SignatureProtocolVersion}: \" +\n                          $\"{preEvaluationBlockHeader.ProtocolVersion}.\";\n                throw new InvalidBlockSignatureException(\n                    msg,\n                    preEvaluationBlockHeader.PublicKey,\n                    proof.Signature);\n            }\n            else if (!proof.Hash.Equals(expectedHash))\n            {\n                throw new InvalidBlockHashException(\n                    $\"The block #{preEvaluationBlockHeader.Index} {proof.Hash} has \" +\n                    $\"an invalid hash; expected: {expectedHash}.\");\n            }\n\n            _preEvaluationBlockHeader = preEvaluationBlockHeader;\n            _stateRootHash = proof.StateRootHash;\n            _signature = proof.Signature;\n            _hash = proof.Hash;\n        }\n\n        /// <summary>\n        /// Internal <see cref=\"PreEvaluationBlockHeader\"/>.\n        /// </summary>\n        public PreEvaluationBlockHeader Header => _preEvaluationBlockHeader;\n\n        /// <inheritdoc cref=\"IBlockMetadata.ProtocolVersion\"/>\n        public int ProtocolVersion => _preEvaluationBlockHeader.ProtocolVersion;\n\n        /// <inheritdoc cref=\"IBlockMetadata.Index\"/>\n        public long Index => _preEvaluationBlockHeader.Index;\n\n        /// <inheritdoc cref=\"IBlockMetadata.Timestamp\"/>\n        public DateTimeOffset Timestamp => _preEvaluationBlockHeader.Timestamp;\n\n        /// <inheritdoc cref=\"IBlockMetadata.Miner\"/>\n        public Address Miner => _preEvaluationBlockHeader.Miner;\n\n        /// <inheritdoc cref=\"IBlockMetadata.PublicKey\"/>\n        public PublicKey? PublicKey => _preEvaluationBlockHeader.PublicKey;\n\n        /// <inheritdoc cref=\"IBlockMetadata.PreviousHash\"/>\n        public BlockHash? PreviousHash => _preEvaluationBlockHeader.PreviousHash;\n\n        /// <inheritdoc cref=\"IBlockMetadata.TxHash\"/>\n        public HashDigest<SHA256>? TxHash => _preEvaluationBlockHeader.TxHash;\n\n        /// <inheritdoc cref=\"IBlockMetadata.LastCommit\"/>\n        public BlockCommit? LastCommit => _preEvaluationBlockHeader.LastCommit;\n\n        /// <inheritdoc cref=\"IBlockMetadata.EvidenceHash\"/>\n        public HashDigest<SHA256>? EvidenceHash => _preEvaluationBlockHeader.EvidenceHash;\n\n        /// <inheritdoc cref=\"IPreEvaluationBlockHeader.PreEvaluationHash\"/>\n        public HashDigest<SHA256> PreEvaluationHash =>\n            _preEvaluationBlockHeader.PreEvaluationHash;\n\n        /// <inheritdoc cref=\"IBlockHeader.StateRootHash\"/>\n        public HashDigest<SHA256> StateRootHash => _stateRootHash;\n\n        /// <inheritdoc cref=\"IBlockHeader.Signature\"/>\n        public ImmutableArray<byte>? Signature => _signature;\n\n        /// <inheritdoc cref=\"IBlockExcerpt.Hash\"/>\n        public BlockHash Hash => _hash;\n\n        /// <inheritdoc cref=\"object.ToString()\"/>\n        public override string ToString() =>\n            $\"#{Index} {Hash}\";\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Types/Blocks/BlockMarshaler.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Collections.Immutable;\nusing System.Globalization;\nusing System.Linq;\nusing System.Security.Cryptography;\nusing Bencodex.Types;\nusing Libplanet.Common;\nusing Libplanet.Crypto;\nusing Libplanet.Types.Evidence;\nusing Libplanet.Types.Tx;\n\nnamespace Libplanet.Types.Blocks\n{\n    /// <summary>\n    /// Marshaling and unmarshalling block data.\n    /// </summary>\n    public static class BlockMarshaler\n    {\n        private const string TimestampFormat = \"yyyy-MM-ddTHH:mm:ss.ffffffZ\";\n\n        // Block fields:\n        private static readonly Binary HeaderKey = new Binary(new byte[] { 0x48 }); // 'H'\n        private static readonly Binary TransactionsKey = new Binary(new byte[] { 0x54 }); // 'T'\n        private static readonly Binary EvidenceKey = new Binary(new byte[] { 0x56 }); // 'V'\n\n        // Header fields:\n        private static readonly Binary ProtocolVersionKey = new Binary(0x00);\n        private static readonly Binary IndexKey = new Binary(0x69); // 'i'\n        private static readonly Binary TimestampKey = new Binary(0x74); // 't'\n        private static readonly Binary DifficultyKey = new Binary(0x64); // 'd'; legacy, unused\n        private static readonly Binary TotalDifficultyKey = new Binary(0x54); // 'T'; legacy, unused\n        private static readonly Binary NonceKey = new Binary(0x6e); // 'n'; legacy, unused\n        private static readonly Binary MinerKey = new Binary(0x6d); // 'm'\n        private static readonly Binary PublicKeyKey = new Binary(0x50); // 'P'\n        private static readonly Binary PreviousHashKey = new Binary(0x70); // 'p'\n        private static readonly Binary TxHashKey = new Binary(0x78); // 'x'\n        private static readonly Binary HashKey = new Binary(0x68); // 'h'\n        private static readonly Binary StateRootHashKey = new Binary(0x73); // 's'\n        private static readonly Binary SignatureKey = new Binary(0x53); // 'S'\n        private static readonly Binary PreEvaluationHashKey = new Binary(0x63); // 'c'\n        private static readonly Binary LastCommitKey = new Binary(0x43); // 'C'\n\n        private static readonly Binary EvidenceHashKey =\n            new Binary(new byte[] { 0x76 }); // 'v'\n\n        public static Dictionary MarshalBlockMetadata(IBlockMetadata metadata)\n        {\n            string timestamp =\n                metadata.Timestamp.ToString(TimestampFormat, CultureInfo.InvariantCulture);\n            Dictionary dict = Dictionary.Empty\n                .Add(IndexKey, metadata.Index)\n                .Add(TimestampKey, timestamp);\n\n            if (metadata.ProtocolVersion != 0)\n            {\n                dict = dict.Add(ProtocolVersionKey, metadata.ProtocolVersion);\n            }\n\n            if (metadata.PreviousHash is { } prev)\n            {\n                dict = dict.Add(PreviousHashKey, prev.ByteArray);\n            }\n\n            if (metadata.TxHash is { } th)\n            {\n                dict = dict.Add(TxHashKey, th.Bencoded);\n            }\n\n            dict = metadata.PublicKey is { } pubKey\n                ? dict.Add(PublicKeyKey, pubKey.Format(compress: true))\n                : dict.Add(MinerKey, metadata.Miner.Bencoded);\n\n            if (metadata.LastCommit is { } commit)\n            {\n                dict = dict.Add(LastCommitKey, commit.Bencoded);\n            }\n\n            if (metadata.EvidenceHash is { } evidenceHash)\n            {\n                dict = dict.Add(EvidenceHashKey, evidenceHash.ByteArray);\n            }\n\n            return dict;\n        }\n\n        public static Dictionary MarshalPreEvaluationBlockHeader(\n            Dictionary marshaledMetadata,\n            HashDigest<SHA256> preEvaluationHash\n        )\n        {\n            Dictionary dict = marshaledMetadata;\n            dict = dict.Add(PreEvaluationHashKey, preEvaluationHash.Bencoded);\n            return dict;\n        }\n\n        public static Dictionary MarshalPreEvaluationBlockHeader(IPreEvaluationBlockHeader header)\n        {\n            return MarshalPreEvaluationBlockHeader(\n                MarshalBlockMetadata(header),\n                header.PreEvaluationHash\n            );\n        }\n\n        public static Dictionary MarshalBlockHeader(\n            Dictionary marshaledPreEvaluatedBlockHeader,\n            HashDigest<SHA256> stateRootHash,\n            ImmutableArray<byte>? signature,\n            BlockHash hash\n        )\n        {\n            Dictionary dict = marshaledPreEvaluatedBlockHeader\n                .Add(StateRootHashKey, stateRootHash.Bencoded)\n                .Add(HashKey, hash.Bencoded);\n            if (signature is { } sig)\n            {\n                dict = dict.Add(SignatureKey, sig);\n            }\n\n            return dict;\n        }\n\n        public static Dictionary MarshalBlockHeader(this IBlockHeader header) =>\n            MarshalBlockHeader(\n                MarshalPreEvaluationBlockHeader(header),\n                header.StateRootHash,\n                header.Signature,\n                header.Hash\n            );\n\n        public static List MarshalTransactions(this IReadOnlyList<Transaction> txs) =>\n            new List(txs.Select(tx => MarshalTransaction(tx)).Cast<IValue>());\n\n        public static Binary MarshalTransaction(this Transaction tx) => new Binary(tx.Serialize());\n\n        public static List MarshalEvidence(this IReadOnlyList<EvidenceBase> evidence) =>\n            new List(evidence.Select(ev => MarshalEvidence(ev)).Cast<IValue>());\n\n        public static Binary MarshalEvidence(this EvidenceBase evidence)\n            => new Binary(evidence.Serialize());\n\n        public static Dictionary MarshalBlock(\n            Dictionary marshaledBlockHeader,\n            List marshaledTransactions,\n            List marshaledEvidence\n        )\n        {\n            Dictionary dict = Dictionary.Empty\n                .Add(HeaderKey, marshaledBlockHeader);\n            if (marshaledTransactions.Any())\n            {\n                dict = dict.Add(TransactionsKey, marshaledTransactions);\n            }\n\n            if (marshaledEvidence.Any())\n            {\n                dict = dict.Add(EvidenceKey, marshaledEvidence);\n            }\n\n            return dict;\n        }\n\n        public static Dictionary MarshalBlock(this Block block) =>\n            MarshalBlock(\n                MarshalBlockHeader(block.Header),\n                MarshalTransactions(block.Transactions),\n                MarshalEvidence(block.Evidence));\n\n        public static long UnmarshalBlockMetadataIndex(Dictionary marshaledMetadata) =>\n            (Integer)marshaledMetadata[IndexKey];\n\n        public static BlockMetadata UnmarshalBlockMetadata(Dictionary marshaled)\n        {\n            Address miner;\n            PublicKey? publicKey = null;\n            if (marshaled.ContainsKey(PublicKeyKey))\n            {\n                publicKey = new PublicKey(((Binary)marshaled[PublicKeyKey]).ByteArray);\n                miner = publicKey.Address;\n            }\n            else\n            {\n                miner = new Address(marshaled[MinerKey]);\n            }\n\n#pragma warning disable SA1118 // The parameter spans multiple lines\n            return new BlockMetadata(\n                protocolVersion: marshaled.ContainsKey(ProtocolVersionKey)\n                    ? (int)(Integer)marshaled[ProtocolVersionKey]\n                    : 0,\n                index: UnmarshalBlockMetadataIndex(marshaled),\n                timestamp: DateTimeOffset.ParseExact(\n                    (Text)marshaled[TimestampKey],\n                    TimestampFormat,\n                    CultureInfo.InvariantCulture),\n                miner: miner,\n                publicKey: publicKey,\n                previousHash: marshaled.TryGetValue(PreviousHashKey, out IValue phv)\n                    ? new BlockHash(phv)\n                    : (BlockHash?)null,\n                txHash: marshaled.TryGetValue(TxHashKey, out IValue thv)\n                    ? new HashDigest<SHA256>(thv)\n                    : (HashDigest<SHA256>?)null,\n                lastCommit: marshaled.ContainsKey(LastCommitKey)\n                    ? new BlockCommit(marshaled[LastCommitKey])\n                    : (BlockCommit?)null,\n                evidenceHash: marshaled.TryGetValue(EvidenceHashKey, out IValue ehv)\n                    ? new HashDigest<SHA256>(ehv)\n                    : (HashDigest<SHA256>?)null);\n#pragma warning restore SA1118\n        }\n\n        public static HashDigest<SHA256> UnmarshalPreEvaluationHash(Dictionary marshaled) =>\n            new HashDigest<SHA256>(marshaled[PreEvaluationHashKey]);\n\n        public static PreEvaluationBlockHeader UnmarshalPreEvaluationBlockHeader(\n            Dictionary marshaled)\n        {\n            return new PreEvaluationBlockHeader(\n                    metadata: UnmarshalBlockMetadata(marshaled),\n                    preEvaluationHash: UnmarshalPreEvaluationHash(marshaled));\n        }\n\n        public static BlockHash UnmarshalBlockHash(Dictionary marshaledBlock)\n        {\n            Dictionary blockHeader = (Dictionary)marshaledBlock[HeaderKey];\n            return UnmarshalBlockHeaderHash(blockHeader);\n        }\n\n        public static BlockHash UnmarshalBlockHeaderHash(Dictionary marshaledBlockHeader) =>\n            new BlockHash(marshaledBlockHeader[HashKey]);\n\n        public static HashDigest<SHA256> UnmarshalBlockHeaderStateRootHash(\n            Dictionary marshaledBlockHeader\n        ) =>\n            new HashDigest<SHA256>(marshaledBlockHeader[StateRootHashKey]);\n\n        public static ImmutableArray<byte>? UnmarshalBlockHeaderSignature(\n            Dictionary marshaledBlockHeader\n        ) =>\n            marshaledBlockHeader.ContainsKey(SignatureKey)\n                ? ((Binary)marshaledBlockHeader[SignatureKey]).ByteArray\n                : (ImmutableArray<byte>?)null;\n\n        public static BlockHeader UnmarshalBlockHeader(Dictionary marshaled)\n        {\n            PreEvaluationBlockHeader preEvalHeader = UnmarshalPreEvaluationBlockHeader(marshaled);\n            HashDigest<SHA256> stateRootHash = UnmarshalBlockHeaderStateRootHash(marshaled);\n            ImmutableArray<byte>? sig = UnmarshalBlockHeaderSignature(marshaled);\n            BlockHash hash = UnmarshalBlockHeaderHash(marshaled);\n            return new BlockHeader(preEvalHeader, (stateRootHash, sig, hash));\n        }\n\n        public static IReadOnlyList<Transaction> UnmarshalTransactions(List marshaled) =>\n            marshaled\n                .Select(tx => Transaction.Deserialize(((Binary)tx).ToByteArray()))\n                .ToImmutableArray();\n\n        public static IReadOnlyList<Transaction> UnmarshalBlockTransactions(\n            Dictionary marshaledBlock) =>\n            marshaledBlock.ContainsKey(TransactionsKey)\n                ? UnmarshalTransactions((List)marshaledBlock[TransactionsKey])\n                : ImmutableArray<Transaction>.Empty;\n\n        public static IReadOnlyList<EvidenceBase> UnmarshalEvidence(List marshaled) =>\n            marshaled\n                .Select(ev => EvidenceBase.Deserialize(((Binary)ev).ToByteArray()))\n                .ToImmutableArray();\n\n        public static IReadOnlyList<EvidenceBase> UnmarshalBlockEvidence(\n            Dictionary marshaledBlock) =>\n            marshaledBlock.ContainsKey(EvidenceKey)\n                ? UnmarshalEvidence((List)marshaledBlock[EvidenceKey])\n                : ImmutableArray<EvidenceBase>.Empty;\n\n        public static Block UnmarshalBlock(Dictionary marshaled)\n        {\n            BlockHeader header = UnmarshalBlockHeader((Dictionary)marshaled[HeaderKey]);\n            IReadOnlyList<Transaction> txs = UnmarshalBlockTransactions(marshaled);\n            IReadOnlyList<EvidenceBase> evidence = UnmarshalBlockEvidence(marshaled);\n            return new Block(header, txs, evidence);\n        }\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Types/Blocks/BlockMetadata.cs",
    "content": "using System;\nusing System.Collections.Immutable;\nusing System.Globalization;\nusing System.Security.Cryptography;\nusing Bencodex;\nusing Libplanet.Common;\nusing Libplanet.Crypto;\nusing Libplanet.Types.Assets;\nusing Libplanet.Types.Evidence;\nusing Libplanet.Types.Tx;\n\nnamespace Libplanet.Types.Blocks\n{\n    /// <summary>\n    /// A block metadata without transactions or any proof hash.  This represents\n    /// metadata of a block that is not yet mined nor proven.\n    /// <para>To represent a block content including its metadata and transactions, use\n    /// <see cref=\"BlockContent\"/>.</para>\n    /// </summary>\n    /// <seealso cref=\"BlockContent\"/>\n    public class BlockMetadata : IBlockMetadata\n    {\n        /// <summary>\n        /// The latest protocol version.\n        /// </summary>\n        public const int CurrentProtocolVersion = 9;\n\n        /// <summary>\n        /// <para>\n        /// The starting protocol version where a bug in transferring asset was fixed.\n        /// Prior to this version, it was possible to duplicate\n        /// <see cref=\"FungibleAssetValue\"/>.\n        /// </para>\n        /// <para>\n        /// Also, <see cref=\"Block.ProtocolVersion\"/> was added.\n        /// </para>\n        /// </summary>\n        public const int TransferFixProtocolVersion = 1;\n\n        /// <summary>\n        /// <para>\n        /// The starting protocol version where <see cref=\"IBlockHeader.Signature\"/> was added.\n        /// Prior to this version, <see cref=\"Block\"/>s had no signature.\n        /// </para>\n        /// <para>\n        /// In its serialized form, <see cref=\"Block.Miner\"/> was removed and\n        /// <see cref=\"Block.PublicKey\"/> together with <see cref=\"Block.Signature\"/> were added.\n        /// </para>\n        /// </summary>\n        public const int SignatureProtocolVersion = 2;\n\n        /// <summary>\n        /// The starting protocol version where a more secure <see cref=\"Transaction\"/> shuffling\n        /// scheme is used.\n        /// </summary>\n        public const int TransactionOrderingFixProtocolVersion = 3;\n\n        /// <summary>\n        /// The starting protocol version where PBFT validation is used instead of\n        /// PoW validation.  Prior to this version, PoW validation is used.\n        /// </summary>\n        public const int PBFTProtocolVersion = 4;\n\n        /// <summary>\n        /// The starting protocol version where the world state model is used instead of\n        /// the legacy state model.  Prior to this version, the legacy state model is used.\n        /// </summary>\n        public const int WorldStateProtocolVersion = 5;\n\n        /// <summary>\n        /// The starting protocol version where the validator set is stored in a separate\n        /// account instead of the legacy account.  Prior to this version, the validator set is\n        /// stored in the legacy account.\n        /// </summary>\n        public const int ValidatorSetAccountProtocolVersion = 6;\n\n        /// <summary>\n        /// The starting protocol version where fungible assets are stored in resepctive\n        /// currency accounts instead of the legacy account.  Prior to this version,\n        /// all fungible assets are stored in the legacy account.\n        /// Moreover, starting with this version, every total supply of each currency is trackable\n        /// regardless of <see cref=\"Currency.TotalSupplyTrackable\"/>.\n        /// </summary>\n        public const int CurrencyAccountProtocolVersion = 7;\n\n        /// <summary>\n        /// The starting protocol version where <see cref=\"Block.StateRootHash\"/> is\n        /// postponed by one blocks.\n        /// Meaning of <see cref=\"Block.StateRootHash\"/> has been changed from\n        /// the result state reference of <see cref=\"Block.Transactions\"/> to state reference\n        /// before <see cref=\"Block.Transactions\"/> were executed.\n        /// </summary>\n        public const int SlothProtocolVersion = 8;\n\n        /// <summary>\n        /// The starting protocol version where evidence of the consensus process is detected and\n        /// stored.\n        /// In the consensus process, evidence of double signing is stored, and in the application\n        /// layer, you can define and use custom evidence.\n        /// </summary>\n        public const int EvidenceProtocolVersion = 9;\n\n        private const string TimestampFormat = \"yyyy-MM-ddTHH:mm:ss.ffffffZ\";\n        private static readonly Codec Codec = new Codec();\n\n        /// <summary>\n        /// Creates a <see cref=\"BlockMetadata\"/> by copying the fields of another block\n        /// <paramref name=\"metadata\"/>.\n        /// </summary>\n        /// <remarks>\n        /// <para>\n        /// As <paramref name=\"metadata\"/> needn't be an actual <see cref=\"BlockMetadata\"/>\n        /// instance, but simply any object implementing <see cref=\"IBlockMetadata\"/> interface,\n        /// it can't be trusted to satisfy all the constraints for a valid\n        /// <see cref=\"BlockMetadata\"/> instance.  As such, conditions are checked again whilst\n        /// creating a copy.  This is a relatively heavy operation, so must be used sparingly.\n        /// </para>\n        /// <para>\n        /// This gets redirected to\n        /// <see cref=\"BlockMetadata(int, long, DateTimeOffset, Address, PublicKey?, BlockHash?,\n        /// HashDigest{SHA256}?, BlockCommit?, ImmutableArray{EvidenceBase}?)\"/>.  Refer to the\n        /// aforementioned constructor to see the full list of <see cref=\"Exception\"/>s\n        /// that may be thrown.\n        /// </para>\n        /// </remarks>\n        /// <param name=\"metadata\">The source block metadata to copy.  This needn't be\n        /// an actual <see cref=\"BlockMetadata\"/> instance, but can be any object which\n        /// implements <see cref=\"IBlockMetadata\"/>.</param>\n        /// <seealso cref=\"BlockMetadata(int, long, DateTimeOffset, Address,\n        /// PublicKey?, BlockHash?, HashDigest{SHA256}?, BlockCommit?, HashDigest{SHA256}?)\"/>\n        public BlockMetadata(IBlockMetadata metadata)\n            : this(\n                protocolVersion: metadata.ProtocolVersion,\n                index: metadata.Index,\n                timestamp: metadata.Timestamp,\n                miner: metadata.Miner,\n                publicKey: metadata.PublicKey,\n                previousHash: metadata.PreviousHash,\n                txHash: metadata.TxHash,\n                lastCommit: metadata.LastCommit,\n                evidenceHash: metadata.EvidenceHash)\n        {\n        }\n\n        /// <summary>\n        /// Creates a <see cref=\"BlockMetadata\"/> with\n        /// <see cref=\"BlockMetadata.CurrentProtocolVersion\"/> as its\n        /// <see cref=\"IBlockMetadata.ProtocolVersion\"/>.\n        /// </summary>\n        /// <param name=\"index\">Goes to <see cref=\"IBlockMetadata.Index\"/>.</param>\n        /// <param name=\"timestamp\">Goes to <see cref=\"IBlockMetadata.Timestamp\"/>.</param>\n        /// <param name=\"publicKey\">Goes to <see cref=\"IBlockMetadata.PublicKey\"/>.</param>\n        /// <param name=\"previousHash\">Goes to <see cref=\"IBlockMetadata.PreviousHash\"/>.</param>\n        /// <param name=\"txHash\">Goes to <see cref=\"IBlockMetadata.TxHash\"/>.</param>\n        /// <param name=\"lastCommit\">Goes to <see cref=\"IBlockMetadata.LastCommit\"/>.</param>\n        /// <param name=\"evidenceHash\">Goes to <see cref=\"IBlockMetadata.EvidenceHash\"/>.</param>\n        /// <seealso cref=\"BlockMetadata(int, long, DateTimeOffset, Address,\n        /// PublicKey?, BlockHash?, HashDigest{SHA256}?, BlockCommit?, HashDigest{SHA256}?)\"/>\n        public BlockMetadata(\n            long index,\n            DateTimeOffset timestamp,\n            PublicKey publicKey,\n            BlockHash? previousHash,\n            HashDigest<SHA256>? txHash,\n            BlockCommit? lastCommit,\n            HashDigest<SHA256>? evidenceHash)\n            : this(\n                protocolVersion: CurrentProtocolVersion,\n                index: index,\n                timestamp: timestamp,\n                miner: publicKey.Address,\n                publicKey: publicKey,\n                previousHash: previousHash,\n                txHash: txHash,\n                lastCommit: lastCommit,\n                evidenceHash: evidenceHash)\n        {\n        }\n\n        /// <summary>\n        /// Creates a <see cref=\"BlockMetadata\"/> by manually filling in the fields for\n        /// <see cref=\"BlockMetadata\"/>.  All other public constructors are redirected to this one.\n        /// </summary>\n        /// <remarks>\n        /// Except for debugging and/or testing purposes, this shouldn't be called directly.\n        /// </remarks>\n        /// <param name=\"protocolVersion\">Goes to <see cref=\"IBlockMetadata.ProtocolVersion\"/>.\n        /// </param>\n        /// <param name=\"index\">Goes to <see cref=\"IBlockMetadata.Index\"/>.</param>\n        /// <param name=\"timestamp\">Goes to <see cref=\"IBlockMetadata.Timestamp\"/>.</param>\n        /// <param name=\"miner\">Goes to <see cref=\"IBlockMetadata.Miner\"/>.</param>\n        /// <param name=\"publicKey\">Goes to <see cref=\"IBlockMetadata.PublicKey\"/>.</param>\n        /// <param name=\"previousHash\">Goes to <see cref=\"IBlockMetadata.PreviousHash\"/>.</param>\n        /// <param name=\"txHash\">Goes to <see cref=\"IBlockMetadata.TxHash\"/>.</param>\n        /// <param name=\"lastCommit\">Goes to <see cref=\"IBlockMetadata.LastCommit\"/>.</param>\n        /// <param name=\"evidenceHash\">Goes to <see cref=\"IBlockMetadata.EvidenceHash\"/>.</param>\n        /// <exception cref=\"InvalidBlockProtocolVersionException\">Thrown when\n        /// <paramref name=\"protocolVersion\"/> is less than zero or greater than\n        /// <see cref=\"CurrentProtocolVersion\"/>, the latest known protocol version.</exception>\n        /// <exception cref=\"InvalidBlockIndexException\">Thrown when <paramref name=\"index\"/> is\n        /// less than zero.</exception>\n        /// <exception cref=\"InvalidBlockPublicKeyException\">Thrown when any of the following\n        /// conditions isn't satisfied:\n        /// <list type=\"bullet\">\n        ///   <item><description>If <paramref name=\"protocolVersion\"/> >= 2,\n        ///   <paramref name=\"miner\"/> should match the derived address of\n        ///   <paramref name=\"publicKey\"/>.</description></item>\n        ///   <item><description>Otherwise, <paramref name=\"publicKey\"/> must be\n        ///   <see langword=\"null\"/>.</description></item>\n        /// </list>\n        /// </exception>\n        /// <exception cref=\"InvalidBlockPreviousHashException\">Thrown when\n        /// <paramref name=\"previousHash\"/> is not null while <paramref name=\"index\"/> is zero\n        /// or <paramref name=\"previousHash\"/> is null while <paramref name=\"index\"/> is nonzero.\n        /// </exception>\n        public BlockMetadata(\n            int protocolVersion,\n            long index,\n            DateTimeOffset timestamp,\n            Address miner,\n            PublicKey? publicKey,\n            BlockHash? previousHash,\n            HashDigest<SHA256>? txHash,\n            BlockCommit? lastCommit,\n            HashDigest<SHA256>? evidenceHash)\n        {\n            // Protocol version validity check.\n            if (protocolVersion < 0)\n            {\n                throw new InvalidBlockProtocolVersionException(\n                    $\"A block's protocol version cannot be less than zero: {protocolVersion}.\",\n                    protocolVersion);\n            }\n            else if (protocolVersion > CurrentProtocolVersion)\n            {\n                throw new InvalidBlockProtocolVersionException(\n                    \"A block's protocol version cannot be greater than \" +\n                    $\"{CurrentProtocolVersion}: {protocolVersion}.\",\n                    protocolVersion);\n            }\n            else\n            {\n                ProtocolVersion = protocolVersion;\n            }\n\n            // Index validity check.\n            Index = index < 0L\n                ? throw new InvalidBlockIndexException(\n                    $\"A negative index is not allowed: {index}.\")\n                : index;\n\n            // FIXME: Transaction timestamps do not convert to universal time.\n            Timestamp = timestamp.ToUniversalTime();\n\n            // Public key and miner validity checks.\n            if (protocolVersion >= 2)\n            {\n                PublicKey = publicKey is { } p\n                    ? p\n                    : throw new InvalidBlockPublicKeyException(\n                        $\"Argument {nameof(publicKey)} cannot be null for \" +\n                        $\"{nameof(protocolVersion)} >= 2.\",\n                        publicKey);\n                Miner = miner == p.Address\n                    ? miner\n                    : throw new InvalidBlockPublicKeyException(\n                        $\"Argument {nameof(miner)} should match the derived address of \" +\n                        $\"{nameof(publicKey)} for {nameof(protocolVersion)} >= 2.\",\n                        publicKey);\n            }\n            else\n            {\n                PublicKey = publicKey is null\n                    ? (PublicKey?)null\n                    : throw new InvalidBlockPublicKeyException(\n                        $\"Argument {nameof(publicKey)} should be null for \" +\n                        $\"{nameof(protocolVersion)} < 2.\",\n                        publicKey);\n                Miner = miner;\n            }\n\n            // Previous hash validity checks.\n            if (index == 0 ^ previousHash is null)\n            {\n                throw new InvalidBlockPreviousHashException(\n                    $\"{nameof(previousHash)} can be null if and only if {nameof(index)} is 0.\");\n            }\n            else\n            {\n                PreviousHash = previousHash;\n            }\n\n            // LastCommit checks.\n            if (lastCommit is { } commit)\n            {\n                if (commit.Height != index - 1)\n                {\n                    throw new InvalidBlockLastCommitException(\n                        $\"The lastcommit height {commit.Height} of block #{index} \" +\n                        $\"should match the previous block's index {index - 1}.\");\n                }\n                else if (!commit.BlockHash.Equals(previousHash))\n                {\n                    throw new InvalidBlockLastCommitException(\n                        $\"The lastcommit blockhash {commit.BlockHash} of block #{index} \" +\n                        $\"should match the previous block's hash {previousHash}.\");\n                }\n            }\n\n            TxHash = txHash;\n            LastCommit = lastCommit;\n            EvidenceHash = evidenceHash;\n        }\n\n        /// <inheritdoc cref=\"IBlockMetadata.ProtocolVersion\"/>\n        public int ProtocolVersion { get; }\n\n        /// <inheritdoc cref=\"IBlockMetadata.Index\"/>\n        public long Index { get; }\n\n        /// <inheritdoc cref=\"IBlockMetadata.Timestamp\"/>\n        public DateTimeOffset Timestamp { get; }\n\n        /// <inheritdoc cref=\"IBlockMetadata.Miner\"/>\n        public Address Miner { get; }\n\n        /// <inheritdoc cref=\"IBlockMetadata.PublicKey\"/>\n        public PublicKey? PublicKey { get; }\n\n        /// <inheritdoc cref=\"IBlockMetadata.PreviousHash\"/>\n        public BlockHash? PreviousHash { get; }\n\n        /// <inheritdoc cref=\"IBlockMetadata.TxHash\"/>\n        public HashDigest<SHA256>? TxHash { get; private set; }\n\n        public BlockCommit? LastCommit { get; set; }\n\n        public HashDigest<SHA256>? EvidenceHash { get; private set; }\n\n        /// <summary>\n        /// Serializes data of a possible candidate shifted from it into a Bencodex dictionary.\n        /// </summary>\n        /// <returns>The serialized block content in a Bencodex dictionary.</returns>\n        public Bencodex.Types.Dictionary MakeCandidateData()\n        {\n            var dict = Bencodex.Types.Dictionary.Empty\n                .Add(\"index\", Index)\n                .Add(\"timestamp\", Timestamp.ToString(TimestampFormat, CultureInfo.InvariantCulture))\n                .Add(\"nonce\", ImmutableArray<byte>.Empty);  // For backward-compatibility.\n\n            if (ProtocolVersion != 0)\n            {\n                dict = dict.Add(\"protocol_version\", ProtocolVersion);\n            }\n\n            if (PreviousHash is { } prevHash)\n            {\n                dict = dict.Add(\"previous_hash\", prevHash.ByteArray);\n            }\n\n            if (TxHash is { } txHash)\n            {\n                dict = dict.Add(\"transaction_fingerprint\", txHash.ByteArray);\n            }\n\n            if (LastCommit is { } lastCommit)\n            {\n                dict = dict.Add(\"last_commit\", lastCommit.ToHash().ByteArray);\n            }\n\n            if (EvidenceHash is { } evidenceHash)\n            {\n                dict = dict.Add(\"evidence_hash\", evidenceHash.ByteArray);\n            }\n\n            // As blocks hadn't been signed before ProtocolVersion <= 1, the PublicKey property\n            // is nullable type-wise.  Blocks with ProtocolVersion <= 1 had a `reward_beneficiary`\n            // field, which referred to the Miner address.  On the other hand, blocks with\n            // ProtocolVersion >= 2 have a `public_key` field instead.  (As Miner addresses can be\n            // derived from PublicKeys, we don't need to include both at a time.)  The PublicKey\n            // property in this class guarantees that its ProtocolVersion is <= 1 when it is null\n            // and its ProtocolVersion is >= 2 when it is not null:\n            dict = PublicKey is { } pubKey && ProtocolVersion >= 2\n                ? dict.Add(\"public_key\", pubKey.Format(compress: true)) // ProtocolVersion >= 2\n                : dict.Add(\"reward_beneficiary\", Miner.Bencoded); /////// ProtocolVersion <= 1\n\n            return dict;\n        }\n\n        /// <summary>\n        /// Derives a hash digest from the block metadata.\n        /// </summary>\n        /// <returns>A pre-evaluation block hash.</returns>\n        public HashDigest<SHA256> DerivePreEvaluationHash() =>\n            HashDigest<SHA256>.DeriveFrom(Codec.Encode(MakeCandidateData()));\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Types/Blocks/BlockPolicyViolationException.cs",
    "content": "using System;\n\nnamespace Libplanet.Types.Blocks\n{\n    /// <summary>\n    /// An exception <em>returned</em> when a <see cref=\"Block\"/> violates\n    /// a <see cref=\"IBlockPolicy\"/>.\n    /// </summary>\n    public class BlockPolicyViolationException : InvalidBlockException\n    {\n        /// <summary>\n        /// Creates a new <see cref=\"BlockPolicyViolationException\"/> instance.\n        /// </summary>\n        /// <param name=\"message\">A description for the reason of violation\n        /// given by an implementation of <see cref=\"IBlockPolicy\"/>.\n        /// </param>\n        public BlockPolicyViolationException(string message)\n            : base(message)\n        {\n        }\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Types/Blocks/IBlockContent.cs",
    "content": "using System.Collections.Generic;\nusing Libplanet.Types.Evidence;\nusing Libplanet.Types.Tx;\n\nnamespace Libplanet.Types.Blocks\n{\n    /// <summary>\n    /// A common interface for blocks that do not have any proofs, but have their metadata and\n    /// containing <see cref=\"Transactions\"/>.\n    /// </summary>\n    /// <remarks>This is always ordered by <see cref=\"Transaction.Id\"/>.</remarks>\n    public interface IBlockContent : IBlockMetadata\n    {\n        /// <summary>\n        /// Transactions belonging to the block.\n        /// </summary>\n        IReadOnlyList<ITransaction> Transactions { get; }\n\n        IReadOnlyList<EvidenceBase> Evidence { get; }\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Types/Blocks/IBlockExcerpt.cs",
    "content": "namespace Libplanet.Types.Blocks\n{\n    /// <summary>\n    /// The very essential metadata extracted from a block.  This purposes to determine\n    /// the canonical chain.\n    /// </summary>\n    public interface IBlockExcerpt\n    {\n        /// <summary>\n        /// A block's protocol version.\n        /// </summary>\n        /// <seealso cref=\"Block.ProtocolVersion\"/>\n        public int ProtocolVersion { get; }\n\n        /// <summary>\n        /// A block's index (height).\n        /// </summary>\n        /// <seealso cref=\"Block.Index\"/>\n        public long Index { get; }\n\n        /// <summary>\n        /// A block's hash.\n        /// </summary>\n        /// <summary>\n        /// The hash digest derived from the whole contents of the block including\n        /// <see cref=\"IBlockHeader.StateRootHash\"/>, which is determined by evaluating transactions\n        /// and a <see cref=\"Blockchain.Policies.IBlockPolicy.BlockAction\"/> (if exists).\n        /// <para>This is used for block's unique identifier.</para>\n        /// </summary>\n        /// <seealso cref=\"IPreEvaluationBlockHeader.PreEvaluationHash\"/>\n        /// <seealso cref=\"IBlockHeader.StateRootHash\"/>\n        /// <seealso cref=\"Block.Hash\"/>\n        public BlockHash Hash { get; }\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Types/Blocks/IBlockHeader.cs",
    "content": "using System.Collections.Immutable;\nusing System.Security.Cryptography;\nusing Libplanet.Common;\nusing Libplanet.Crypto;\n\nnamespace Libplanet.Types.Blocks\n{\n    /// <summary>\n    /// A common interface for blocks that have <see cref=\"StateRootHash\"/>es, but no transactions.\n    /// </summary>\n    public interface IBlockHeader : IPreEvaluationBlockHeader, IBlockExcerpt\n    {\n        /// <summary>\n        /// The <see cref=\"ITrie.Hash\"/> of the resulting states after evaluating transactions and\n        /// a <see cref=\"Blockchain.Policies.IBlockPolicy.BlockAction\"/> (if exists).\n        /// </summary>\n        /// <seealso cref=\"ITrie.Hash\"/>\n        HashDigest<SHA256> StateRootHash { get; }\n\n        /// <summary>\n        /// <para>\n        /// The digital signature of the whole block content (except for\n        /// <see cref=\"IBlockExcerpt.Hash\"/>, which is derived from the signature and other\n        /// contents).  This is made by the <see cref=\"IBlockMetadata.Miner\"/>'s\n        /// <see cref=\"PrivateKey\"/>.\n        /// </para>\n        /// <para>\n        /// As the block signature is introduced since\n        /// <see cref=\"BlockMetadata.SignatureProtocolVersion\"/>, it is\n        /// <see langword=\"null\"/> for blocks with earlier protocol versions than\n        /// <see cref=\"BlockMetadata.SignatureProtocolVersion\"/>.  Although\n        /// the property is type-wise, the block signature is mandatory since\n        /// <see cref=\"BlockMetadata.SignatureProtocolVersion\"/>.\n        /// </para>\n        /// </summary>\n        ImmutableArray<byte>? Signature { get; }\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Types/Blocks/IBlockMetadata.cs",
    "content": "using System;\nusing System.Security.Cryptography;\nusing Libplanet.Common;\nusing Libplanet.Crypto;\nusing Libplanet.Types.Evidence;\n\nnamespace Libplanet.Types.Blocks\n{\n    /// <summary>\n    /// A common interface for blocks that do not have any proofs nor transactions (but only\n    /// <see cref=\"TxHash\"/>).\n    /// </summary>\n    public interface IBlockMetadata\n    {\n        /// <summary>\n        /// The protocol version number.  For the latest protocol version, see\n        /// <see cref=\"BlockMetadata.CurrentProtocolVersion\"/>.  We have the following\n        /// version info:\n        /// <list type=\"bullet\">\n        /// <item><description>\n        /// 0: The initial block protocol version number.  This is not actually recorded in\n        /// storage.  That is, the lack of block protocol version in a stored block means it\n        /// is of version 0.\n        /// </description></item>\n        /// <item><description>\n        /// 1: Introduced to be stored with the block data.  Validation for\n        /// <see cref=\"IPreEvaluationBlockHeader.PreEvaluationHash\"/> was added.\n        /// </description></item>\n        /// <item><description>\n        /// 2: Updated to include <see cref=\"IBlockHeader.Signature\"/> to blocks.  As a result,\n        /// the miner's identity is provided as a <see cref=\"Crypto.PublicKey\"/>\n        /// instead of a <see cref=\"Address\"/>.  Additionally, total difficulty was added.\n        /// </description></item>\n        /// <item><description>\n        /// 3: Updated to fix an issue with the internal execution ordering\n        /// of <see cref=\"Tx.Transaction\"/>s in blocks.\n        /// </description></item>\n        /// <item><description>\n        /// 4: Updated to introduce a PBFT scheme.  <see cref=\"LastCommit\"/> was added and\n        /// total difficulty was removed.\n        /// </description></item>\n        /// <item><description>\n        /// 5: Updated to introduce a world model.  No structural changes were made to blocks.\n        /// This is used as a marker indicating when the data model should be migrated.\n        /// </description></item>\n        /// </list>\n        /// </summary>\n        /// <seealso cref=\"BlockMetadata.CurrentProtocolVersion\"/>\n        int ProtocolVersion { get; }\n\n        /// <summary>\n        /// The height of the block.\n        /// </summary>\n        /// <remarks>Zero means it is a genesis block.  Not allowed to be negative.</remarks>\n        long Index { get; }\n\n        /// <summary>\n        /// The time the block is created.\n        /// </summary>\n        /// <remarks>This is always UTC.</remarks>\n        DateTimeOffset Timestamp { get; }\n\n        /// <summary>\n        /// The address of the miner.\n        /// </summary>\n        Address Miner { get; }\n\n        /// <summary>\n        /// The public key of the <see cref=\"Miner\"/>.  This is used for verifying the signature.\n        /// <para>Although this is nullable type-wise, it is mandatory where\n        /// <see cref=\"ProtocolVersion\"/> is 2 or later.  As blocks had not been signed in\n        /// the previous protocol versions, the type of this is nullable.\n        /// </para>\n        /// </summary>\n        PublicKey? PublicKey { get; }\n\n        /// <summary>\n        /// The previous block's hash.  If it's a genesis block (i.e., its <see cref=\"Index\"/> is 0)\n        /// this must be <see langword=\"null\"/>.\n        /// </summary>\n        BlockHash? PreviousHash { get; }\n\n        /// <summary>\n        /// The hash of all transactions in the block.  This is <see langword=\"null\"/> if the block\n        /// has no transactions.\n        /// </summary>\n        HashDigest<SHA256>? TxHash { get; }\n\n        /// <summary>\n        /// The <see cref=\"BlockCommit\"/> about previous block's vote information.\n        /// </summary>\n        BlockCommit? LastCommit { get; }\n\n        /// <summary>\n        /// Committing <see cref=\"EvidenceId\"/>s of vote infraction\n        /// that has been made on previous blocks.\n        /// </summary>\n        HashDigest<SHA256>? EvidenceHash { get; }\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Types/Blocks/IBlockMetadataExtensions.cs",
    "content": "using System;\n\nnamespace Libplanet.Types.Blocks\n{\n    /// <summary>\n    /// Convenient extension methods for <see cref=\"IBlockMetadata\"/>.\n    /// </summary>\n    public static class IBlockMetadataExtensions\n    {\n        private static readonly TimeSpan TimestampThreshold = TimeSpan.FromSeconds(15);\n\n        /// <summary>\n        /// Checks if the given <paramref name=\"metadata\"/>'s\n        /// <see cref=\"IBlockMetadata.Timestamp\"/> is valid.  No-op if valid.\n        /// </summary>\n        /// <param name=\"metadata\">The block metadata to validate.</param>\n        /// <exception cref=\"InvalidBlockTimestampException\">Thrown when\n        /// <see cref=\"IBlockMetadata.Timestamp\"/> is invalid.  For example,\n        /// if <see cref=\"IBlockMetadata.Timestamp\"/> is too far in the future\n        /// compared to the current time.</exception>\n        public static void ValidateTimestamp(this IBlockMetadata metadata) =>\n            ValidateTimestamp(metadata, DateTimeOffset.UtcNow);\n\n        /// <summary>\n        /// Checks if the given <paramref name=\"metadata\"/>'s\n        /// <see cref=\"IBlockMetadata.Timestamp\"/> is valid.  No-op if valid.\n        /// </summary>\n        /// <param name=\"metadata\">The block metadata to validate.</param>\n        /// <param name=\"currentTime\">Explicitly specify the current time.</param>\n        /// <exception cref=\"InvalidBlockTimestampException\">Thrown when\n        /// <see cref=\"IBlockMetadata.Timestamp\"/> is invalid.  For example,\n        /// if <see cref=\"IBlockMetadata.Timestamp\"/> is too far in the future\n        /// compared to <paramref name=\"currentTime\"/>.</exception>\n        public static void ValidateTimestamp(\n            this IBlockMetadata metadata, DateTimeOffset currentTime)\n        {\n            if (currentTime + TimestampThreshold < metadata.Timestamp)\n            {\n                string hash = metadata is IBlockExcerpt h\n                    ? $\" {h.Hash}\"\n                    : string.Empty;\n                throw new InvalidBlockTimestampException(\n                    $\"The block #{metadata.Index}{hash}'s timestamp \" +\n                    $\"({metadata.Timestamp}) is later than now ({currentTime}, \" +\n                    $\"threshold: {TimestampThreshold}).\");\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Types/Blocks/IPreEvaluationBlock.cs",
    "content": "namespace Libplanet.Types.Blocks\n{\n    /// <summary>\n    /// A common interface for blocks that have their\n    /// <see cref=\"IBlockContent.Transactions\"/>, but are not evaluated yet (i.e., their state\n    /// root hashes are not yet determined).\n    /// </summary>\n    public interface IPreEvaluationBlock : IBlockContent, IPreEvaluationBlockHeader\n    {\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Types/Blocks/IPreEvaluationBlockHeader.cs",
    "content": "using System.Security.Cryptography;\nusing Libplanet.Common;\n\nnamespace Libplanet.Types.Blocks\n{\n    /// <summary>\n    /// A common interface for blocks that are not evaluated yet\n    /// (i.e., state root hash is not yet determined).\n    /// </summary>\n    public interface IPreEvaluationBlockHeader : IBlockMetadata\n    {\n        /// <summary>\n        /// The hash derived from the block <em>except of</em> its state root hash (i.e., without\n        /// action evaluation).\n        /// </summary>\n        HashDigest<SHA256> PreEvaluationHash { get; }\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Types/Blocks/InvalidBlockBytesLengthException.cs",
    "content": "using System;\n\nnamespace Libplanet.Types.Blocks\n{\n    /// <summary>\n    /// An exception thrown when the encoded bytes of <see cref=\"Block.Transactions\"/> exceeds\n    /// <see cref=\"IBlockPolicy.GetMaxTransactionsBytes(long)\"/>.\n    /// </summary>\n    public sealed class InvalidBlockBytesLengthException : BlockPolicyViolationException\n    {\n        /// <summary>\n        /// Initializes a new instance of <see cref=\"InvalidBlockBytesLengthException\"/> class.\n        /// </summary>\n        /// <param name=\"message\">The message that describes the error.</param>\n        /// <param name=\"bytesLength\">The actual encoded length of\n        /// <see cref=\"Block.Transactions\"/> as bytes.</param>\n        public InvalidBlockBytesLengthException(string message, long bytesLength)\n            : base(message)\n        {\n            BytesLength = bytesLength;\n        }\n\n        /// <summary>\n        /// The actual encoded length of <see cref=\"Block.Transactions\"/> as bytes.\n        /// </summary>\n        public long BytesLength { get; private set; }\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Types/Blocks/InvalidBlockCommitException.cs",
    "content": "using System;\n\nnamespace Libplanet.Types.Blocks\n{\n    public class InvalidBlockCommitException : InvalidBlockException\n    {\n        public InvalidBlockCommitException(string message)\n            : base(message)\n        {\n        }\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Types/Blocks/InvalidBlockEvidenceHashException.cs",
    "content": "using System;\nusing System.Security.Cryptography;\nusing Libplanet.Common;\n\nnamespace Libplanet.Types.Blocks\n{\n    public class InvalidBlockEvidenceHashException\n        : InvalidBlockException, IEquatable<InvalidBlockEvidenceHashException>\n    {\n        /// <summary>\n        /// Initializes a new instance of <see cref=\"InvalidBlockEvidenceHashException\"/> class.\n        /// </summary>\n        /// <param name=\"message\">The message that describes the error.</param>\n        /// <param name=\"blockEvidenceHash\">The hash digest of <see cref=\"Block.EvidenceHash\"/>.\n        /// </param>\n        /// <param name=\"calculatedEvidenceHash\">The calculated hash digest from\n        /// <see cref=\"Block.Evidence\"/>.</param>\n        public InvalidBlockEvidenceHashException(\n            string message,\n            HashDigest<SHA256>? blockEvidenceHash,\n            HashDigest<SHA256>? calculatedEvidenceHash)\n            : base(\n                $\"{message}\\n\" +\n                $\"In block header: {blockEvidenceHash}\\n\" +\n                $\"Calculated: {calculatedEvidenceHash}\")\n        {\n            BlockEvidenceHash = blockEvidenceHash;\n            CalculatedEvidenceHash = calculatedEvidenceHash;\n        }\n\n        /// <summary>\n        /// The hash digest from actual block.\n        /// </summary>\n        public HashDigest<SHA256>? BlockEvidenceHash { get; }\n\n        /// <summary>\n        /// The calculated hash digest from evidence in the block.\n        /// </summary>\n        public HashDigest<SHA256>? CalculatedEvidenceHash { get; }\n\n        public static bool operator ==(\n            InvalidBlockEvidenceHashException left,\n            InvalidBlockEvidenceHashException right\n        ) => left.Equals(right);\n\n        public static bool operator !=(\n            InvalidBlockEvidenceHashException left,\n            InvalidBlockEvidenceHashException right\n        ) => !left.Equals(right);\n\n        public bool Equals(InvalidBlockEvidenceHashException? other)\n        {\n            if (other is null)\n            {\n                return false;\n            }\n\n            if (ReferenceEquals(this, other))\n            {\n                return true;\n            }\n\n            return Nullable.Equals(BlockEvidenceHash, other.BlockEvidenceHash) && Nullable.Equals(\n                CalculatedEvidenceHash,\n                other.CalculatedEvidenceHash);\n        }\n\n        public override bool Equals(object? obj) =>\n            obj is InvalidBlockEvidenceHashException other && Equals(other);\n\n        public override int GetHashCode() =>\n            HashCode.Combine(BlockEvidenceHash, CalculatedEvidenceHash);\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Types/Blocks/InvalidBlockEvidencePendingDurationException.cs",
    "content": "using System;\nusing Libplanet.Types.Blocks;\n\nnamespace Libplanet.Blocks\n{\n    /// <summary>\n    /// An exception thrown when the height of <see cref=\"Consensus.Evidence\"/>\n    /// has been expired by the constraint provided by <see cref=\"IBlockPolicy\"/>.\n    /// </summary>\n    public sealed class InvalidBlockEvidencePendingDurationException\n        : BlockPolicyViolationException\n    {\n        /// <summary>\n        /// Initializes a new instance of\n        /// <see cref=\"InvalidBlockEvidencePendingDurationException\"/> class.\n        /// </summary>\n        /// <param name=\"message\">The message that describes the error.</param>\n        public InvalidBlockEvidencePendingDurationException(string message)\n            : base(message)\n        {\n        }\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Types/Blocks/InvalidBlockException.cs",
    "content": "using System;\n\nnamespace Libplanet.Types.Blocks\n{\n    /// <summary>\n    /// Serves as the base class for exceptions related <see cref=\"Block\"/>s' integrity and\n    /// validity.\n    /// </summary>\n    public abstract class InvalidBlockException : Exception\n    {\n        /// <inheritdoc cref=\"Exception(string)\"/>\n        protected InvalidBlockException(string message)\n            : base(message)\n        {\n        }\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Types/Blocks/InvalidBlockHashException.cs",
    "content": "using System;\n\nnamespace Libplanet.Types.Blocks\n{\n    public class InvalidBlockHashException : InvalidBlockException\n    {\n        public InvalidBlockHashException(string message)\n            : base(message)\n        {\n        }\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Types/Blocks/InvalidBlockIndexException.cs",
    "content": "using System;\n\nnamespace Libplanet.Types.Blocks\n{\n    public class InvalidBlockIndexException : InvalidBlockException\n    {\n        public InvalidBlockIndexException(string message)\n            : base(message)\n        {\n        }\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Types/Blocks/InvalidBlockLastCommitException.cs",
    "content": "using System;\n\nnamespace Libplanet.Types.Blocks\n{\n    public class InvalidBlockLastCommitException : InvalidBlockException\n    {\n        public InvalidBlockLastCommitException(string message)\n            : base(message)\n        {\n        }\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Types/Blocks/InvalidBlockPreEvaluationHashException.cs",
    "content": "using System;\nusing System.Collections.Immutable;\nusing System.Diagnostics.Contracts;\nusing System.Linq;\n\nnamespace Libplanet.Types.Blocks\n{\n    /// <summary>\n    /// The exception that is thrown when the a <see cref=\"Block\"/>'s\n    /// <see cref=\"Block.PreEvaluationHash\"/> is invalid.\n    /// </summary>\n    public class InvalidBlockPreEvaluationHashException\n        : InvalidBlockException, IEquatable<InvalidBlockPreEvaluationHashException>\n    {\n        /// <summary>\n        /// Initializes a new instance of the\n        /// <see cref=\"InvalidBlockPreEvaluationHashException\"/> class.\n        /// </summary>\n        /// <param name=\"message\">The message that describes the error.</param>\n        /// <param name=\"actualPreEvaluationHash\">The hash recorded as\n        /// <see cref=\"Block.PreEvaluationHash\"/>.</param>\n        /// <param name=\"expectedPreEvaluationHash\">The hash calculated from the block except\n        /// <see cref=\"Block.StateRootHash\"/>.</param>\n        public InvalidBlockPreEvaluationHashException(\n            string message,\n            ImmutableArray<byte> actualPreEvaluationHash,\n            ImmutableArray<byte> expectedPreEvaluationHash)\n            : base(message)\n        {\n            ActualPreEvaluationHash = actualPreEvaluationHash;\n            ExpectedPreEvaluationHash = expectedPreEvaluationHash;\n        }\n\n        /// <summary>\n        /// The hash calculated from the block except <see cref=\"Block.StateRootHash\"/>.\n        /// </summary>\n        [Pure]\n        public ImmutableArray<byte> ActualPreEvaluationHash { get; }\n\n        /// <summary>\n        /// The hash recorded as <see cref=\"Block.PreEvaluationHash\"/>.\n        /// </summary>\n        [Pure]\n        public ImmutableArray<byte> ExpectedPreEvaluationHash { get; }\n\n        public static bool operator ==(\n            InvalidBlockPreEvaluationHashException left,\n            InvalidBlockPreEvaluationHashException right\n        ) => left.Equals(right);\n\n        public static bool operator !=(\n            InvalidBlockPreEvaluationHashException left,\n            InvalidBlockPreEvaluationHashException right\n        ) => !left.Equals(right);\n\n        public bool Equals(InvalidBlockPreEvaluationHashException? other)\n        {\n            if (other is null)\n            {\n                return false;\n            }\n\n            if (ReferenceEquals(this, other))\n            {\n                return true;\n            }\n\n            return ActualPreEvaluationHash.SequenceEqual(other.ActualPreEvaluationHash) &&\n                   ExpectedPreEvaluationHash.SequenceEqual(other.ExpectedPreEvaluationHash) &&\n                   Message.Equals(other.Message);\n        }\n\n        public override bool Equals(object? obj) =>\n            obj is InvalidBlockPreEvaluationHashException other && Equals(other);\n\n        public override int GetHashCode() =>\n            HashCode.Combine(ActualPreEvaluationHash, ExpectedPreEvaluationHash, Message);\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Types/Blocks/InvalidBlockPreviousHashException.cs",
    "content": "using System;\n\nnamespace Libplanet.Types.Blocks\n{\n    public class InvalidBlockPreviousHashException : InvalidBlockException\n    {\n        public InvalidBlockPreviousHashException(string message)\n            : base(message)\n        {\n        }\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Types/Blocks/InvalidBlockProtocolVersionException.cs",
    "content": "namespace Libplanet.Types.Blocks\n{\n    /// <summary>\n    /// The exception that is thrown when a <see cref=\"Block\"/>'s\n    /// <see cref=\"Block.ProtocolVersion\"/> (or a <see cref=\"BlockHeader\"/>'s\n    /// <see cref=\"BlockHeader.ProtocolVersion\"/>) is invalid.\n    /// </summary>\n    public sealed class InvalidBlockProtocolVersionException : InvalidBlockException\n    {\n        /// <summary>\n        /// Initializes a new instance of <see cref=\"InvalidBlockProtocolVersionException\"/> class.\n        /// </summary>\n        /// <param name=\"message\">The message that describes the error.</param>\n        /// <param name=\"actualProtocolVersion\">The actual block protocol version which is invalid.\n        /// </param>\n        public InvalidBlockProtocolVersionException(string message, int actualProtocolVersion)\n            : base(message)\n        {\n            ActualProtocolVersion = actualProtocolVersion;\n        }\n\n        /// <summary>\n        /// The actual block protocol version which is invalid.\n        /// </summary>\n        public int ActualProtocolVersion { get; set; }\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Types/Blocks/InvalidBlockPublicKeyException.cs",
    "content": "using System.Diagnostics.Contracts;\nusing Libplanet.Crypto;\n\nnamespace Libplanet.Types.Blocks\n{\n    /// <summary>\n    /// An exception thrown when a block's public key is invalid.\n    /// </summary>\n    public class InvalidBlockPublicKeyException : InvalidBlockException\n    {\n        /// <summary>\n        /// Creates a new <see cref=\"InvalidBlockPublicKeyException\"/> instance.\n        /// </summary>\n        /// <param name=\"message\">A message that describes the error.</param>\n        /// <param name=\"invalidPublicKey\">The invalid public key tried to be used\n        /// in the block.</param>\n        public InvalidBlockPublicKeyException(string message, PublicKey? invalidPublicKey)\n            : base(\n                message +\n                (invalidPublicKey is { } pubKey ? $\"\\nInvalid public key: {pubKey}\" : string.Empty)\n            )\n        {\n            InvalidPublicKey = invalidPublicKey;\n        }\n\n        /// <summary>\n        /// The invalid public key tried to be used in the block.\n        /// </summary>\n        [Pure]\n        public PublicKey? InvalidPublicKey { get; }\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Types/Blocks/InvalidBlockSignatureException.cs",
    "content": "using System;\nusing System.Collections.Immutable;\nusing System.Diagnostics.Contracts;\nusing Libplanet.Common;\nusing Libplanet.Crypto;\n\nnamespace Libplanet.Types.Blocks\n{\n    /// <summary>\n    /// An exception thrown when a block's signature is invalid.\n    /// </summary>\n    public class InvalidBlockSignatureException : InvalidBlockException\n    {\n        /// <summary>\n        /// Creates a new <see cref=\"InvalidBlockPublicKeyException\"/> instance.\n        /// </summary>\n        /// <param name=\"message\">A message that describes the error.</param>\n        /// <param name=\"publicKey\">The public key used for signing the block.</param>\n        /// <param name=\"invalidSignature\">The block signature which is invalid.</param>\n        public InvalidBlockSignatureException(\n            string message,\n            PublicKey? publicKey,\n            ImmutableArray<byte>? invalidSignature\n        )\n            : base(\n                message +\n                (publicKey is { } pubKey ? $\"\\nPublic key: {pubKey}\" : string.Empty) +\n                (invalidSignature is { } sig\n                    ? $\"\\nInvalid signature: {ByteUtil.Hex(sig)}\"\n                    : string.Empty)\n            )\n        {\n            PublicKey = publicKey;\n            InvalidSignature = invalidSignature;\n        }\n\n        /// <summary>\n        /// The public key used for signing the block.\n        /// </summary>\n        [Pure]\n        public PublicKey? PublicKey { get; }\n\n        /// <summary>\n        /// The block signature which is invalid.\n        /// </summary>\n        [Pure]\n        public ImmutableArray<byte>? InvalidSignature { get; }\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Types/Blocks/InvalidBlockStateRootHashException.cs",
    "content": "using System;\nusing System.Diagnostics.Contracts;\nusing System.Security.Cryptography;\nusing Libplanet.Common;\n\nnamespace Libplanet.Types.Blocks\n{\n    /// <summary>\n    /// The exception that is thrown when the state root hash in the block has\n    /// mismatches to the state root hash of the trie on the block executed in local.\n    /// </summary>\n    public class InvalidBlockStateRootHashException : InvalidBlockException\n    {\n        /// <summary>\n        /// Initializes a new instance of the\n        /// <see cref=\"InvalidBlockStateRootHashException\"/> class.\n        /// </summary>\n        /// <param name=\"message\">The message that describes the error.</param>\n        /// <param name=\"expectedStateRootHash\">The hash recorded as\n        /// <see cref=\"Block.StateRootHash\"/>>.</param>\n        /// <param name=\"actualStateRootHash\">The hash of state trie on the block executed.</param>\n        public InvalidBlockStateRootHashException(\n            string message,\n            HashDigest<SHA256> expectedStateRootHash,\n            HashDigest<SHA256> actualStateRootHash)\n            : base(message)\n        {\n            ActualStateRootHash = actualStateRootHash;\n            ExpectedStateRootHash = expectedStateRootHash;\n        }\n\n        /// <summary>\n        /// The hash of state trie on the block executed.\n        /// </summary>\n        [Pure]\n        public HashDigest<SHA256> ActualStateRootHash { get; }\n\n        /// <summary>\n        /// The hash recorded as <see cref=\"Block.StateRootHash\"/>>.\n        /// </summary>\n        [Pure]\n        public HashDigest<SHA256> ExpectedStateRootHash { get; }\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Types/Blocks/InvalidBlockTimestampException.cs",
    "content": "using System;\n\nnamespace Libplanet.Types.Blocks\n{\n    public class InvalidBlockTimestampException : InvalidBlockException\n    {\n        public InvalidBlockTimestampException(string message)\n            : base(message)\n        {\n        }\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Types/Blocks/InvalidBlockTxCountException.cs",
    "content": "namespace Libplanet.Types.Blocks\n{\n    /// <summary>\n    /// An exception thrown when the count of <see cref=\"Block.Transactions\"/>\n    /// does not follow the constraint provided by <see cref=\"IBlockPolicy\"/>.\n    /// </summary>\n    public sealed class InvalidBlockTxCountException : BlockPolicyViolationException\n    {\n        /// <summary>\n        /// Initializes a new instance of <see cref=\"InvalidBlockTxCountException\"/> class.\n        /// </summary>\n        /// <param name=\"message\">The message that describes the error.</param>\n        /// <param name=\"txCount\">The invalid count of <see cref=\"Block.Transactions\"/>\n        /// according to <see cref=\"IBlockPolicy\"/>.</param>\n        public InvalidBlockTxCountException(string message, int txCount)\n            : base(message)\n        {\n            TxCount = txCount;\n        }\n\n        public int TxCount { get; private set; }\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Types/Blocks/InvalidBlockTxCountPerSignerException.cs",
    "content": "using Libplanet.Crypto;\nusing Libplanet.Types.Tx;\n\nnamespace Libplanet.Types.Blocks\n{\n    /// <summary>\n    /// An exception thrown when the count of <see cref=\"Block.Transactions\"/>\n    /// does not follow the constraint provided by <see cref=\"IBlockPolicy\"/>.\n    /// </summary>\n    public sealed class InvalidBlockTxCountPerSignerException : BlockPolicyViolationException\n    {\n        /// <summary>\n        /// Initializes a new instance of <see cref=\"InvalidBlockTxCountPerSignerException\"/> class.\n        /// </summary>\n        /// <param name=\"message\">The message that describes the error.</param>\n        /// <param name=\"signer\">An offending <see cref=\"Address\"/> with too many\n        /// <see cref=\"Transaction\"/>'s in a <see cref=\"Block\"/>.</param>\n        /// <param name=\"txCount\">The invalid count of <see cref=\"Block.Transactions\"/>\n        /// by <paramref name=\"signer\"/> according to the <see cref=\"IBlockPolicy\"/>.</param>\n        public InvalidBlockTxCountPerSignerException(string message, Address signer, int txCount)\n            : base(message)\n        {\n            Signer = signer;\n            TxCount = txCount;\n        }\n\n        public Address Signer { get; private set; }\n\n        public int TxCount { get; private set; }\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Types/Blocks/InvalidBlockTxHashException.cs",
    "content": "using System;\nusing System.Security.Cryptography;\nusing Libplanet.Common;\n\nnamespace Libplanet.Types.Blocks\n{\n    public class InvalidBlockTxHashException\n        : InvalidBlockException, IEquatable<InvalidBlockTxHashException>\n    {\n        /// <summary>\n        /// Initializes a new instance of <see cref=\"InvalidBlockTxHashException\"/> class.\n        /// </summary>\n        /// <param name=\"message\">The message that describes the error.</param>\n        /// <param name=\"blockTxHash\">The hash digest of <see cref=\"Block.TxHash\"/>.</param>\n        /// <param name=\"calculatedTxHash\">The calculated hash digest from\n        /// <see cref=\"Block.Transactions\"/>.</param>\n        public InvalidBlockTxHashException(\n            string message,\n            HashDigest<SHA256>? blockTxHash,\n            HashDigest<SHA256>? calculatedTxHash)\n            : base(\n                $\"{message}\\n\" +\n                $\"In block header: {blockTxHash}\\n\" +\n                $\"Calculated: {calculatedTxHash}\")\n        {\n            BlockTxHash = blockTxHash;\n            CalculatedTxHash = calculatedTxHash;\n        }\n\n        /// <summary>\n        /// The hash digest from actual block.\n        /// </summary>\n        public HashDigest<SHA256>? BlockTxHash { get; }\n\n        /// <summary>\n        /// The calculated hash digest from transactions in the block.\n        /// </summary>\n        public HashDigest<SHA256>? CalculatedTxHash { get; }\n\n        public static bool operator ==(\n            InvalidBlockTxHashException left,\n            InvalidBlockTxHashException right\n        ) => left.Equals(right);\n\n        public static bool operator !=(\n            InvalidBlockTxHashException left,\n            InvalidBlockTxHashException right\n        ) => !left.Equals(right);\n\n        public bool Equals(InvalidBlockTxHashException? other)\n        {\n            if (other is null)\n            {\n                return false;\n            }\n\n            if (ReferenceEquals(this, other))\n            {\n                return true;\n            }\n\n            return Nullable.Equals(BlockTxHash, other.BlockTxHash) && Nullable.Equals(\n                CalculatedTxHash,\n                other.CalculatedTxHash);\n        }\n\n        public override bool Equals(object? obj) =>\n            obj is InvalidBlockTxHashException other && Equals(other);\n\n        public override int GetHashCode() => HashCode.Combine(BlockTxHash, CalculatedTxHash);\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Types/Blocks/InvalidGenesisBlockException.cs",
    "content": "using System.Diagnostics.Contracts;\n\nnamespace Libplanet.Types.Blocks\n{\n    /// <summary>\n    /// The exception that is thrown when the genesis block the <see cref=\"IStore\"/> contains\n    /// mismatches to the genesis block the <see cref=\"BlockChain\"/> constructor (i.e., network)\n    /// expects or the first block of <see cref=\"BlockLocator\"/> which the <see cref=\"IStore\"/>\n    /// doesn't contain, because the block which <see cref=\"IStore\"/> doesn't means\n    /// the genesis block in other network.\n    /// </summary>\n    public class InvalidGenesisBlockException : InvalidBlockException\n    {\n        /// <summary>\n        /// Initializes a new instance of the\n        /// <see cref=\"InvalidGenesisBlockException\"/> class.\n        /// </summary>\n        /// <param name=\"message\">The message that describes the error.</param>\n        /// <param name=\"networkExpected\">The genesis block that the network expects.</param>\n        /// <param name=\"stored\">The genesis block that a local <see cref=\"IStore\"/> contains.\n        /// </param>\n        public InvalidGenesisBlockException(\n            string message,\n            BlockHash networkExpected,\n            BlockHash stored\n        )\n            : base(message)\n        {\n            NetworkExpected = networkExpected;\n            Stored = stored;\n        }\n\n        /// <summary>\n        /// The genesis block that the network expects.\n        /// </summary>\n        [Pure]\n        public BlockHash NetworkExpected { get; }\n\n        /// <summary>\n        /// The genesis block that a local <see cref=\"IStore\"/> contains.\n        /// </summary>\n        [Pure]\n        public BlockHash Stored { get; }\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Types/Blocks/PreEvaluationBlock.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Collections.Immutable;\nusing System.Security.Cryptography;\nusing Libplanet.Common;\nusing Libplanet.Crypto;\nusing Libplanet.Types.Evidence;\nusing Libplanet.Types.Tx;\n\nnamespace Libplanet.Types.Blocks\n{\n    /// <summary>\n    /// A block candidate without evaluating actions (in its <see cref=\"Transactions\"/> and\n    /// a possible <see cref=\"Blockchain.Policies.IBlockPolicy.BlockAction\"/>) and state root\n    /// hash.\n    /// </summary>\n    public sealed class PreEvaluationBlock : IPreEvaluationBlock\n    {\n        private BlockContent _content;\n        private PreEvaluationBlockHeader _header;\n\n        public PreEvaluationBlock(\n            IPreEvaluationBlockHeader preEvaluationBlockHeader,\n            IEnumerable<Transaction> transactions,\n            IEnumerable<EvidenceBase> evidence)\n            : this(\n                new BlockContent(preEvaluationBlockHeader, transactions, evidence),\n                preEvaluationBlockHeader.PreEvaluationHash)\n        {\n        }\n\n        /// <summary>\n        /// Creates a <see cref=\"PreEvaluationBlock\"/> instance with its\n        /// <paramref name=\"content\"/> data, a valid <paramref name=\"preEvaluationHash\"/>.\n        /// </summary>\n        /// <param name=\"content\">Block's content data.</param>\n        /// <param name=\"preEvaluationHash\">A valid hash derived from <paramref name=\"content\"/>.\n        /// </param>\n        /// <exception cref=\"InvalidBlockPreEvaluationHashException\">Thrown when\n        /// <paramref name=\"preEvaluationHash\"/> is invalid.</exception>\n        internal PreEvaluationBlock(\n            BlockContent content,\n            in HashDigest<SHA256> preEvaluationHash)\n        {\n            _header = new PreEvaluationBlockHeader(content.Metadata, preEvaluationHash);\n            _content = content;\n        }\n\n        /// <summary>\n        /// Internal <see cref=\"PreEvaluationBlockHeader\"/>.\n        /// </summary>\n        public PreEvaluationBlockHeader Header => _header;\n\n        /// <inheritdoc cref=\"IBlockContent.Transactions\"/>\n        public IReadOnlyList<Transaction> Transactions => _content.Transactions;\n\n        /// <inheritdoc cref=\"IBlockContent.Transactions\" />\n        IReadOnlyList<ITransaction> IBlockContent.Transactions => _content.Transactions;\n\n        public IReadOnlyList<EvidenceBase> Evidence => _content.Evidence;\n\n        /// <inheritdoc cref=\"IBlockMetadata.ProtocolVersion\"/>\n        public int ProtocolVersion => _header.ProtocolVersion;\n\n        /// <inheritdoc cref=\"IBlockMetadata.Index\"/>\n        public long Index => _header.Index;\n\n        /// <inheritdoc cref=\"IBlockMetadata.Timestamp\"/>\n        public DateTimeOffset Timestamp => _header.Timestamp;\n\n        /// <inheritdoc cref=\"IBlockMetadata.Miner\"/>\n        public Address Miner => _header.Miner;\n\n        /// <inheritdoc cref=\"IBlockMetadata.PublicKey\"/>\n        public PublicKey? PublicKey => _header.PublicKey;\n\n        /// <inheritdoc cref=\"IBlockMetadata.PreviousHash\"/>\n        public BlockHash? PreviousHash => _header.PreviousHash;\n\n        /// <inheritdoc cref=\"IBlockMetadata.TxHash\"/>\n        public HashDigest<SHA256>? TxHash => _header.TxHash;\n\n        /// <inheritdoc cref=\"IBlockMetadata.LastCommit\"/>\n        public BlockCommit? LastCommit => _header.LastCommit;\n\n        /// <inheritdoc cref=\"IBlockMetadata.EvidenceHash\"/>\n        public HashDigest<SHA256>? EvidenceHash => _header.EvidenceHash;\n\n        /// <inheritdoc cref=\"IPreEvaluationBlockHeader.PreEvaluationHash\"/>\n        public HashDigest<SHA256> PreEvaluationHash => _header.PreEvaluationHash;\n\n        /// <summary>\n        /// Signs the block content with the given <paramref name=\"stateRootHash\"/>.\n        /// </summary>\n        /// <param name=\"privateKey\">The miner's private key to be used for signing the block.\n        /// This must match to the block's <see cref=\"PreEvaluationBlockHeader.Miner\"/> and\n        /// <see cref=\"PreEvaluationBlockHeader.PublicKey\"/>.</param>\n        /// <param name=\"stateRootHash\">The state root hash to include to the input message to\n        /// sign.</param>\n        /// <returns>The signed block with the <paramref name=\"stateRootHash\"/>.</returns>\n        /// <exception cref=\"InvalidOperationException\">Thrown when the block's\n        /// <see cref=\"PreEvaluationBlockHeader.ProtocolVersion\"/> is less than 2.</exception>\n        /// <exception cref=\"ArgumentException\">Thrown when the given <paramref name=\"privateKey\"/>\n        /// does not match to the block miner's <see cref=\"PublicKey\"/>.</exception>\n        /// <remarks>As blocks have their signatures since the <see\n        /// cref=\"PreEvaluationBlockHeader.ProtocolVersion\"/> 2, it is not usable with blocks of\n        /// the earlier <see cref=\"PreEvaluationBlockHeader.ProtocolVersion\"/>s than 2.\n        /// To create a <see cref=\"Block\"/> instance with <see cref=\"Block.ProtocolVersion\"/>\n        /// less than 2, use <see cref=\"Block\"/>'s constructors with <see langword=\"null\"/>\n        /// signatures.</remarks>\n        public Block Sign(PrivateKey privateKey, HashDigest<SHA256> stateRootHash)\n        {\n            ImmutableArray<byte> sig = Header.MakeSignature(privateKey, stateRootHash);\n            return new Block(\n                this, (stateRootHash, sig, Header.DeriveBlockHash(stateRootHash, sig)));\n        }\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Types/Blocks/PreEvaluationBlockHeader.cs",
    "content": "using System;\nusing System.Collections.Immutable;\nusing System.Security.Cryptography;\nusing Bencodex;\nusing Bencodex.Types;\nusing Libplanet.Common;\nusing Libplanet.Crypto;\n\nnamespace Libplanet.Types.Blocks\n{\n    /// <summary>\n    /// A block candidate without evaluating actions (in its transactions and a possible\n    /// <see cref=\"Blockchain.Policies.IBlockPolicy.BlockAction\"/>) and state root hash.\n    /// </summary>\n    public class PreEvaluationBlockHeader : IPreEvaluationBlockHeader\n    {\n        protected static readonly Codec Codec = new Codec();\n\n        private readonly BlockMetadata _metadata;\n        private readonly HashDigest<SHA256> _preEvaluationHash;\n\n        /// <summary>\n        /// Creates a <see cref=\"PreEvaluationBlockHeader\"/> by copying the fields of another\n        /// pre-evaluation block <paramref name=\"header\"/>.\n        /// </summary>\n        /// <remarks>\n        /// <para>\n        /// As <paramref name=\"header\"/> needn't be an actual <see cref=\"PreEvaluationBlockHeader\"/>\n        /// instance, but simply any object implementing <see cref=\"IPreEvaluationBlockHeader\"/>\n        /// interface, it can't be trusted to satisfy all the constraints for a valid\n        /// <see cref=\"PreEvaluationBlockHeader\"/> instance.  As such, conditions are checked again\n        /// whilst creating a copy.  This is a relatively heavy operation, so must be used\n        /// sparingly.\n        /// </para>\n        /// <para>\n        /// In particular, this creates a new instance of\n        /// <see cref=\"BlockMetadata\"/> with data extracted from <paramref name=\"header\"/>.\n        /// Thus any <see cref=\"Exception\"/>s that can be thrown from a\n        /// <see cref=\"BlockMetadata\"/>'s constructors may also be thrown in addition to the ones\n        /// explicitly listed below.\n        /// </para>\n        /// </remarks>\n        /// <param name=\"header\">The pre-evaluation block header to copy.</param>\n        /// <exception cref=\"InvalidBlockPreEvaluationHashException\">Thrown when the given\n        /// pre-evaluation <paramref name=\"header\"/>'s\n        /// <see cref=\"IPreEvaluationBlockHeader.PreEvaluationHash\"/> is invalid.</exception>\n        /// <seealso cref=\"BlockMetadata\"/>\n        public PreEvaluationBlockHeader(IPreEvaluationBlockHeader header)\n            : this(new BlockMetadata(header), header.PreEvaluationHash)\n        {\n        }\n\n        /// <summary>\n        /// Creates a <see cref=\"PreEvaluationBlockHeader\"/> instance with its\n        /// <paramref name=\"metadata\"/> and a valid <paramref name=\"preEvaluationHash\"/>.\n        /// All other public constructors should be redirected to this one.\n        /// </summary>\n        /// <param name=\"metadata\">Block's metadata.</param>\n        /// <param name=\"preEvaluationHash\">A valid hash derived from <paramref name=\"metadata\"/>.\n        /// </param>\n        /// <exception cref=\"InvalidBlockPreEvaluationHashException\">Thrown when\n        /// <paramref name=\"preEvaluationHash\"/> is invalid.</exception>\n        public PreEvaluationBlockHeader(\n            BlockMetadata metadata,\n            HashDigest<SHA256> preEvaluationHash)\n        {\n            _metadata = metadata;\n            _preEvaluationHash = CheckPreEvaluationHash(metadata, preEvaluationHash);\n        }\n\n        /// <summary>\n        /// Internal <see cref=\"BlockMetadata\"/>.\n        /// </summary>\n        public BlockMetadata Metadata => _metadata;\n\n        /// <inheritdoc cref=\"IBlockMetadata.ProtocolVersion\"/>\n        public int ProtocolVersion => Metadata.ProtocolVersion;\n\n        /// <inheritdoc cref=\"IBlockMetadata.Index\"/>\n        public long Index => Metadata.Index;\n\n        /// <inheritdoc cref=\"IBlockMetadata.Timestamp\"/>\n        public DateTimeOffset Timestamp => Metadata.Timestamp;\n\n        /// <inheritdoc cref=\"IBlockMetadata.Miner\"/>\n        public Address Miner => Metadata.Miner;\n\n        /// <inheritdoc cref=\"IBlockMetadata.PublicKey\"/>\n        public PublicKey? PublicKey => Metadata.PublicKey;\n\n        /// <inheritdoc cref=\"IBlockMetadata.PreviousHash\"/>\n        public BlockHash? PreviousHash => Metadata.PreviousHash;\n\n        /// <inheritdoc cref=\"IBlockMetadata.TxHash\"/>\n        public HashDigest<SHA256>? TxHash => Metadata.TxHash;\n\n        /// <inheritdoc cref=\"IBlockMetadata.LastCommit\"/>\n        public BlockCommit? LastCommit => Metadata.LastCommit;\n\n        /// <inheritdoc cref=\"IBlockMetadata.EvidenceHash\"/>\n        public HashDigest<SHA256>? EvidenceHash => Metadata.EvidenceHash;\n\n        /// <inheritdoc cref=\"IPreEvaluationBlockHeader.PreEvaluationHash\"/>\n        public HashDigest<SHA256> PreEvaluationHash => _preEvaluationHash;\n\n        /// <summary>\n        /// Serializes data of a possible candidate shifted from it into a Bencodex dictionary.\n        /// This data is used as the input to calculate the block <see cref=\"Block.Hash\"/>,\n        /// rather than transmitting the block over the network.\n        /// </summary>\n        /// <param name=\"stateRootHash\">The <see cref=\"Libplanet.Store.Trie.ITrie.Hash\"/> of\n        /// the resulting states after evaluating transactions and\n        /// a <see cref=\"Blockchain.Policies.IBlockPolicy.BlockAction\"/> (if exists).</param>\n        /// <param name=\"signature\">The block signature created using <see cref=\"MakeSignature\"/>\n        /// method with the <paramref name=\"stateRootHash\"/>.  This must be <see langword=\"null\"/>\n        /// for blocks with earlier <seealso cref=\"ProtocolVersion\"/>s than 2.</param>\n        /// <returns>The serialized block header in a Bencodex dictionary.</returns>\n        public Bencodex.Types.Dictionary MakeCandidateData(\n            HashDigest<SHA256> stateRootHash,\n            ImmutableArray<byte>? signature = null)\n        {\n            Dictionary dict = Metadata.MakeCandidateData()\n                .Add(\"state_root_hash\", stateRootHash.ByteArray);\n            if (signature is { } sig)\n            {\n                dict = dict.Add(\"signature\", sig);\n            }\n\n            return dict;\n        }\n\n        /// <summary>\n        /// Makes a signature of the block content with a <paramref name=\"stateRootHash\"/> using\n        /// the given <paramref name=\"privateKey\"/>.\n        /// </summary>\n        /// <param name=\"privateKey\">The miner's private key.  This must match to the block's\n        /// <see cref=\"Miner\"/> and <see cref=\"PublicKey\"/>.</param>\n        /// <param name=\"stateRootHash\">The state root hash to include to the input message to\n        /// sign.</param>\n        /// <returns>The signature of the block content with a <paramref name=\"stateRootHash\"/>\n        /// using the given <paramref name=\"privateKey\"/>.</returns>\n        /// <exception cref=\"InvalidOperationException\">Thrown when the block's\n        /// <see cref=\"ProtocolVersion\"/> is less than 2.</exception>\n        /// <exception cref=\"ArgumentException\">Thrown when the given <paramref name=\"privateKey\"/>\n        /// does not match to the block miner's <see cref=\"PublicKey\"/>.</exception>\n        /// <remarks>As blocks have their signatures since the <see cref=\"ProtocolVersion\"/> 2,\n        /// it is not usable with blocks of the earlier <see cref=\"ProtocolVersion\"/>s than 2.\n        /// </remarks>\n        public ImmutableArray<byte> MakeSignature(\n            PrivateKey privateKey,\n            HashDigest<SHA256> stateRootHash)\n        {\n            if (PublicKey is null)\n            {\n                throw new InvalidOperationException(\n                    \"The block with the protocol version < 2 cannot be signed, because it lacks \" +\n                    \"its miner's public key so that others cannot verify its signature.\"\n                );\n            }\n            else if (!privateKey.PublicKey.Equals(PublicKey))\n            {\n                string m = \"The given private key does not match to the proposer's public key.\" +\n                    $\"Block's public key: {PublicKey}\\n\" +\n                    $\"Derived public key: {privateKey.PublicKey}\\n\";\n                throw new ArgumentException(m, nameof(privateKey));\n            }\n\n            byte[] msg = Codec.Encode(MakeCandidateData(stateRootHash));\n            byte[] sig = privateKey.Sign(msg);\n            return ImmutableArray.Create(sig);\n        }\n\n        /// <summary>\n        /// Verifies if the given block <paramref name=\"signature\"/> is valid with the block\n        /// content and the specified <paramref name=\"stateRootHash\"/>.\n        /// </summary>\n        /// <param name=\"signature\">The block signature created using <see cref=\"MakeSignature\"/>\n        /// method with the <paramref name=\"stateRootHash\"/>.  This must be <see langword=\"null\"/>\n        /// for blocks with earlier <seealso cref=\"ProtocolVersion\"/>s than 2.</param>\n        /// <param name=\"stateRootHash\">The state root hash included in the original message\n        /// of the signature.</param>\n        /// <returns><see langword=\"true\"/> if the signature is valid.  <see langword=\"false\"/>\n        /// otherwise.</returns>\n        public bool VerifySignature(\n            ImmutableArray<byte>? signature,\n            HashDigest<SHA256> stateRootHash)\n        {\n            if (PublicKey is { } pubKey && signature is { } sig)\n            {\n                byte[] msg = Codec.Encode(MakeCandidateData(stateRootHash));\n                return pubKey.Verify(msg, sig);\n            }\n            else if (PublicKey is null)\n            {\n                return signature is null;\n            }\n\n            return false;\n        }\n\n        /// <summary>\n        /// Derives a hash digest from the given pre-evaluation block header and\n        /// <paramref name=\"stateRootHash\"/>.\n        /// </summary>\n        /// <param name=\"stateRootHash\">The state root hash.</param>\n        /// <param name=\"signature\">The block signature created using <see cref=\"MakeSignature\"/>\n        /// method with the <paramref name=\"stateRootHash\"/>.  This must be <see langword=\"null\"/>\n        /// for blocks with earlier <seealso cref=\"ProtocolVersion\"/>s than 2.</param>\n        /// <returns>A block hash.</returns>\n        public BlockHash DeriveBlockHash(\n            in HashDigest<SHA256> stateRootHash,\n            in ImmutableArray<byte>? signature\n        ) =>\n            BlockHash.DeriveFrom(Codec.Encode(MakeCandidateData(stateRootHash, signature)));\n\n        /// <summary>\n        /// Verifies if the <paramref name=\"preEvaluationHash\"/> is the proper hash digest\n        /// derived from the given block <paramref name=\"metadata\"/>.\n        /// If it's incorrect throws an <see cref=\"InvalidBlockPreEvaluationHashException\"/>.\n        /// Throws nothing and returns <paramref name=\"preEvaluationHash\"/> instead.\n        /// </summary>\n        /// <param name=\"metadata\">The block metadata.</param>\n        /// <param name=\"preEvaluationHash\">The pre-evaluation hash digest to verify.</param>\n        /// <returns>A <paramref name=\"preEvaluationHash\"/>\n        /// if the <paramref name=\"preEvaluationHash\"/> is verified to be correct.</returns>\n        /// <exception cref=\"InvalidBlockPreEvaluationHashException\">Thrown when the given\n        /// <paramref name=\"preEvaluationHash\"/> is incorrect.</exception>\n        private static HashDigest<SHA256> CheckPreEvaluationHash(\n            BlockMetadata metadata,\n            in HashDigest<SHA256> preEvaluationHash)\n        {\n            if (metadata.ProtocolVersion < BlockMetadata.PBFTProtocolVersion)\n            {\n                return preEvaluationHash;\n            }\n            else\n            {\n                HashDigest<SHA256> expected = metadata.DerivePreEvaluationHash();\n                return expected.Equals(preEvaluationHash)\n                    ? expected\n                    : throw new InvalidBlockPreEvaluationHashException(\n                        $\"Given {nameof(preEvaluationHash)} {preEvaluationHash} does not match \" +\n                        $\"the expected value {expected}.\",\n                        preEvaluationHash.ByteArray,\n                        expected.ByteArray);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Types/Consensus/IVoteMetadata.cs",
    "content": "using System;\nusing System.Numerics;\nusing Libplanet.Crypto;\nusing Libplanet.Types.Blocks;\n\nnamespace Libplanet.Types.Consensus\n{\n    /// <summary>\n    /// A common <see langword=\"interface\"/> for <see cref=\"Vote\"/>s\n    /// and <see cref=\"VoteMetadata\"/>s.\n    /// </summary>\n    public interface IVoteMetadata\n    {\n        /// <summary>\n        /// Height of the vote target block.\n        /// </summary>\n        long Height { get; }\n\n        /// <summary>\n        /// Round of the vote in given height.\n        /// </summary>\n        int Round { get; }\n\n        /// <summary>\n        /// <see cref=\"BlockHash\"/> of the block in vote. If default, vote nil.\n        /// </summary>\n        BlockHash BlockHash { get; }\n\n        /// <summary>\n        /// The time at which the voting took place.\n        /// </summary>\n        DateTimeOffset Timestamp { get; }\n\n        /// <summary>\n        /// The <see cref=\"PublicKey\"/> of the validator that voted.\n        /// </summary>\n        PublicKey ValidatorPublicKey { get; }\n\n        /// <summary>\n        /// The voting power of the validator that voted.\n        /// </summary>\n        BigInteger? ValidatorPower { get; }\n\n        /// <summary>\n        /// The <see cref=\"VoteFlag\"/> indicating the type of a <see cref=\"Vote\"/>.\n        /// </summary>\n        VoteFlag Flag { get; }\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Types/Consensus/Validator.cs",
    "content": "using System;\nusing System.Numerics;\nusing System.Text.Json.Serialization;\nusing Bencodex;\nusing Bencodex.Types;\nusing Libplanet.Crypto;\n\nnamespace Libplanet.Types.Consensus\n{\n    /// <summary>\n    /// A class designed for a <see langword=\"Validator\"/> of consensus.\n    /// A <see cref=\"Validator\"/> consists of operator's <see cref=\"PublicKey\"/>\n    /// and its corresponding <see langword=\"Power\"/>.\n    /// </summary>\n    public class Validator : IEquatable<Validator>, IBencodable\n    {\n        private static readonly Binary PublicKeyKey = new Binary(new byte[] { 0x50 }); // 'P'\n        private static readonly Binary PowerKey = new Binary(new byte[] { 0x70 });     // 'p'\n\n        /// <summary>\n        /// Creates an instance of <see cref=\"Validator\"/>, with given <paramref name=\"publicKey\"/>\n        /// and <paramref name=\"power\"/>.\n        /// </summary>\n        /// <param name=\"publicKey\">The <see cref=\"Libplanet.Crypto.PublicKey\"/>\n        /// of validator operator.</param>\n        /// <param name=\"power\">The <see langword=\"Power\"/> of validator operator.</param>\n        /// <exception cref=\"ArgumentOutOfRangeException\">Thrown if <paramref name=\"power\"/> is\n        /// negative.</exception>\n        public Validator(\n            PublicKey publicKey,\n            BigInteger power)\n        {\n            if (power < BigInteger.Zero)\n            {\n                throw new ArgumentOutOfRangeException(\n                    nameof(power),\n                    $\"Given {nameof(power)} cannot be negative: {power}\");\n            }\n\n            PublicKey = publicKey;\n            Power = power;\n        }\n\n        public Validator(Bencodex.Types.IValue bencoded)\n            : this(bencoded is Bencodex.Types.Dictionary dict\n                ? dict\n                : throw new ArgumentException(\n                    $\"Given {nameof(bencoded)} must be of type \" +\n                    $\"{typeof(Bencodex.Types.Dictionary)}: {bencoded.GetType()}\",\n                    nameof(bencoded)))\n        {\n        }\n\n        private Validator(Bencodex.Types.Dictionary bencoded)\n            : this(\n                new PublicKey(((Binary)bencoded[PublicKeyKey]).ByteArray),\n                (Integer)bencoded[PowerKey])\n        {\n        }\n\n        /// <summary>\n        /// A <see cref=\"PublicKey\"/> of validator operator.\n        /// </summary>\n        public PublicKey PublicKey { get; }\n\n        /// <summary>\n        /// The <see langword=\"Power\"/> of validator.\n        /// </summary>\n        public BigInteger Power { get; }\n\n        /// <summary>\n        /// An <see cref=\"Address\"/> of the validator operator's <see cref=\"PublicKey\"/>.\n        /// </summary>\n        [JsonIgnore]\n        public Address OperatorAddress => PublicKey.Address;\n\n        /// <inheritdoc/>\n        [JsonIgnore]\n        public Bencodex.Types.IValue Bencoded => Dictionary.Empty\n            .Add(PublicKeyKey, PublicKey.Format(true))\n            .Add(PowerKey, Power);\n\n        public static bool operator ==(Validator obj, Validator other)\n        {\n            return obj.Equals(other);\n        }\n\n        public static bool operator !=(Validator obj, Validator other)\n        {\n            return !(obj == other);\n        }\n\n        /// <inheritdoc/>\n        public override bool Equals(object? obj)\n        {\n            if (obj is Validator other)\n            {\n                return Equals(other);\n            }\n\n            return false;\n        }\n\n        /// <inheritdoc/>\n        public bool Equals(Validator? other)\n        {\n            return PublicKey.Equals(other?.PublicKey) && Power.Equals(other?.Power);\n        }\n\n        /// <inheritdoc/>\n        public override int GetHashCode()\n        {\n            return HashCode.Combine(PublicKey, Power);\n        }\n\n        /// <inheritdoc/>\n        public override string ToString() => $\"{PublicKey}:{Power}\";\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Types/Consensus/ValidatorSet.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Collections.Immutable;\nusing System.Diagnostics.Contracts;\nusing System.Linq;\nusing System.Numerics;\nusing Bencodex;\nusing Libplanet.Crypto;\nusing Libplanet.Types.Blocks;\n\nnamespace Libplanet.Types.Consensus\n{\n    /// <summary>\n    /// A wrapper class for a <see cref=\"List{T}\"/> of <see cref=\"Validator\"/>s.\n    /// This standardizes the ordering of validators by <see cref=\"Address\"/>.\n    /// </summary>\n    public class ValidatorSet : IEquatable<ValidatorSet>, IBencodable\n    {\n        /// <summary>\n        /// Creates an instance of an empty <see cref=\"ValidatorSet\"/>.\n        /// to <see cref=\"Validators\"/>.\n        /// </summary>\n        public ValidatorSet()\n            : this(new List<Validator>())\n        {\n        }\n\n        /// <summary>\n        /// Creates an instance of <see cref=\"ValidatorSet\"/>.  Given <paramref name=\"validators\"/>\n        /// is ordered internally by <see cref=\"Address\"/> before getting assigned\n        /// to <see cref=\"Validators\"/>.\n        /// </summary>\n        /// <param name=\"validators\">The <see cref=\"List{T}\"/> of validators to use.</param>\n        /// <exception cref=\"ArgumentException\">Thrown when one of the following is true:\n        /// <list type=\"bullet\">\n        ///     <item><description>There is a duplicate among <see cref=\"PublicKey\"/>s for\n        ///     <paramref name=\"validators\"/>.\n        ///     </description></item>\n        ///     <item><description>There is a <see cref=\"Validator\"/> with zero power.\n        ///     </description></item>\n        /// </list>\n        /// </exception>\n        public ValidatorSet(List<Validator> validators)\n        {\n            if (validators\n                .Select(validators => validators.PublicKey)\n                .Distinct()\n                .Count() != validators.Count)\n            {\n                throw new ArgumentException(\"All public keys for validators must be unique.\");\n            }\n            else if (validators.Any(validator => validator.Power == BigInteger.Zero))\n            {\n                throw new ArgumentException(\"All validators must have positive power.\");\n            }\n\n            Validators = validators\n                .OrderBy(validator => validator.OperatorAddress)\n                .ToImmutableList();\n        }\n\n        public ValidatorSet(Bencodex.Types.IValue bencoded)\n            : this(bencoded is Bencodex.Types.List list\n                ? list\n                : throw new ArgumentException(\n                    $\"Given {nameof(bencoded)} must be of type \" +\n                    $\"{typeof(Bencodex.Types.List)}: {bencoded.GetType()}\",\n                    nameof(bencoded)))\n        {\n        }\n\n        // FIXME: Order should be checked when deserializing.\n        private ValidatorSet(Bencodex.Types.List bencoded)\n            : this(bencoded.Select(elem => new Validator(elem)).ToList())\n        {\n        }\n\n        /// <summary>\n        /// An <see cref=\"ImmutableList{T}\"/> of validators.  This is guaranteed to be ordered\n        /// by <see cref=\"Address\"/>.\n        /// </summary>\n        public ImmutableList<Validator> Validators { get; }\n\n        /// <summary>\n        /// An <see cref=\"ImmutableList{T}\"/> of public keys of validators.\n        /// This is guaranteed to be ordered by <see cref=\"Address\"/>.\n        /// </summary>\n        public ImmutableList<PublicKey> PublicKeys => Validators.Select(\n            validator => validator.PublicKey).ToImmutableList();\n\n        /// <summary>\n        /// The total number of validators.\n        /// </summary>\n        public int TotalCount => Validators.Count;\n\n        /// <summary>\n        /// The total power of validators.\n        /// </summary>\n        public BigInteger TotalPower => Validators.Aggregate(\n            BigInteger.Zero, (total, next) => total + next.Power);\n\n        /// <summary>\n        /// The two thirds of validator count, rounded down.\n        /// </summary>\n        public int TwoThirdsCount => TotalCount * 2 / 3;\n\n        /// <summary>\n        /// The two thirds of validator total power, rounded down.\n        /// </summary>\n        public BigInteger TwoThirdsPower => TotalPower * 2 / 3;\n\n        /// <summary>\n        /// The one third of validator count, rounded down.\n        /// </summary>\n        public int OneThirdCount => TotalCount / 3;\n\n        /// <summary>\n        /// The one third of validator total power, rounded down.\n        /// </summary>\n        public BigInteger OneThirdPower => TotalPower / 3;\n\n        /// <inheritdoc/>\n        public Bencodex.Types.IValue Bencoded =>\n            new Bencodex.Types.List(Validators.Select(validator => validator.Bencoded));\n\n        /// <summary>\n        /// Gets the validator at given <paramref name=\"index\"/>.\n        /// </summary>\n        /// <param name=\"index\">The index to search.</param>\n        /// <returns>The validator at given <paramref name=\"index\"/>.</returns>\n        public Validator this[int index] => Validators[index];\n\n        /// <summary>\n        /// Gets the index of given <paramref name=\"publicKey\"/>.\n        /// </summary>\n        /// <param name=\"publicKey\">The <see cref=\"PublicKey\"/> to find index.</param>\n        /// <returns>The index of given <paramref name=\"publicKey\"/>.</returns>\n        public int FindIndex(PublicKey publicKey) => Validators.FindIndex(\n            validator => validator.PublicKey.Equals(publicKey));\n\n        public Validator GetValidator(PublicKey publicKey)\n        {\n            if (Validators.Find(validator => validator.PublicKey == publicKey) is { } validator)\n            {\n                return validator;\n            }\n\n            throw new ArgumentException(\n                message: $\"No validator with the given public key: {publicKey}\",\n                paramName: nameof(publicKey));\n        }\n\n        public ImmutableList<Validator> GetValidators(IEnumerable<PublicKey> publicKeys)\n            => (from publicKey in publicKeys select GetValidator(publicKey)).ToImmutableList();\n\n        public BigInteger GetValidatorsPower(List<PublicKey> publicKeys)\n        {\n            return GetValidators(publicKeys).Aggregate(\n                BigInteger.Zero, (total, next) => total + next.Power);\n        }\n\n        /// <summary>\n        /// Checks if given <paramref name=\"validator\"/> is a member of <see cref=\"ValidatorSet\"/>.\n        /// Checks both of <see cref=\"Validator.PublicKey\"/> and <see cref=\"Validator.Power\"/>.\n        /// </summary>\n        /// <param name=\"validator\">The <see cref=\"Validator\"/> to check.</param>\n        /// <returns><see langword=\"true\"/> if given <paramref name=\"validator\"/>\n        /// is in <see cref=\"Validators\"/>, <see langword=\"false\"/> otherwise.</returns>\n        public bool Contains(Validator validator) => Validators.Contains(validator);\n\n        /// <summary>\n        /// Checks if given <paramref name=\"publicKey\"/> is a member of <see cref=\"ValidatorSet\"/>.\n        /// </summary>\n        /// <param name=\"publicKey\">The <see cref=\"PublicKey\"/> of the\n        /// <see cref=\"Validator\"/> to check.</param>\n        /// <returns><see langword=\"true\"/> if given <paramref name=\"publicKey\"/>\n        /// is in <see cref=\"Validators\"/>, <see langword=\"false\"/> otherwise.</returns>\n        public bool ContainsPublicKey(PublicKey publicKey) =>\n            Validators.Any(validator => validator.PublicKey.Equals(publicKey));\n\n        /// <summary>\n        /// Creates a new <see cref=\"ValidatorSet\"/> that has been updated with\n        /// given <paramref name=\"validator\"/> according to the following rule:\n        /// <list type=\"bullet\">\n        ///     <item><description>\n        ///         If <paramref name=\"validator\"/>'s power is zero, the <see cref=\"Validator\"/>\n        ///         with the same <see cref=\"PublicKey\"/> is removed, if it exists.\n        ///         If no matching <see cref=\"Validator\"/> is found, no change is made.\n        ///     </description></item>\n        ///     <item><description>\n        ///         If <paramref name=\"validator\"/>'s power is positive, the <see cref=\"Validator\"/>\n        ///         with the same <see cref=\"PublicKey\"/> is overwritten, if it exists.\n        ///         If no matching <see cref=\"Validator\"/> is found, <paramref name=\"validator\"/>\n        ///         is added to the set.\n        ///     </description></item>\n        /// </list>\n        /// </summary>\n        /// <param name=\"validator\">The <see cref=\"Validator\"/> to update.</param>\n        /// <returns>New <see cref=\"ValidatorSet\"/> updated with\n        /// given <paramref name=\"validator\"/>.</returns>\n        [Pure]\n        public ValidatorSet Update(Validator validator)\n        {\n            var updated = Validators.ToList();\n\n            updated.RemoveAll(v => v.PublicKey.Equals(validator.PublicKey));\n\n            if (validator.Power == BigInteger.Zero)\n            {\n                return new ValidatorSet(updated);\n            }\n            else\n            {\n                updated.Add(validator);\n                return new ValidatorSet(updated);\n            }\n        }\n\n        /// <inheritdoc/>\n        public bool Equals(ValidatorSet? other) =>\n            other is ValidatorSet validators && Validators.SequenceEqual(validators.Validators);\n\n        /// <inheritdoc/>\n        public override bool Equals(object? obj) => obj is ValidatorSet other && Equals(other);\n\n        /// <inheritdoc/>\n        public override int GetHashCode()\n        {\n            int hashCode = 17;\n            foreach (Validator validator in Validators)\n            {\n                hashCode = unchecked(hashCode * (31 + validator.GetHashCode()));\n            }\n\n            return hashCode;\n        }\n\n        /// <summary>\n        /// Gets the proposer for a given context.\n        /// </summary>\n        /// <param name=\"height\">The height of the context under consideration.</param>\n        /// <param name=\"round\">The round of the context under consideration.</param>\n        /// <returns>A <see cref=\"Validator\"/> deterministically chosen from\n        /// <see cref=\"Validators\"/>, <paramref name=\"height\"/>, and <paramref name=\"round\"/>.\n        /// </returns>\n        /// <exception cref=\"InvalidOperationException\">Thrown when\n        /// <see cref=\"Validators\"/> is empty.</exception>\n        public Validator GetProposer(long height, int round)\n        {\n            // FIXME: Empty Validators should not be allowed.  Preventing during construction\n            // would require heavier refactoring of BlockPolicy.\n            return Validators.IsEmpty\n                ? throw new InvalidOperationException(\n                    \"Cannot select a proposer from an empty list of validators.\")\n                : Validators[(int)((height + round) % Validators.Count)];\n        }\n\n        /// <summary>\n        /// Checks whether <see cref=\"BlockCommit.Votes\"/> is ordered\n        /// by <see cref=\"Address\"/> of each <see cref=\"Vote.ValidatorPublicKey\"/>,\n        /// and <see cref=\"Vote.ValidatorPower\"/> equals to the one recorded in the chain states.\n        /// </summary>\n        /// <remarks>\n        /// If <see cref=\"Vote.ValidatorPower\"/> is null, power check is ignored.</remarks>\n        /// <param name=\"blockCommit\">The <see cref=\"BlockCommit\"/> to check.</param>\n        /// <exception cref=\"InvalidBlockCommitException\">Thrown when validators from\n        /// <paramref name=\"blockCommit\"/> is different from validators of this.</exception>\n        /// <exception cref=\"InvalidBlockCommitException\">Thrown when vote's power in the\n        /// <paramref name=\"blockCommit\"/> does not equal to validator power.</exception>\n        public void ValidateBlockCommitValidators(BlockCommit blockCommit)\n        {\n            if (!Validators.Select(validator => validator.PublicKey)\n                    .SequenceEqual(\n                        blockCommit.Votes.Select(vote => vote.ValidatorPublicKey).ToList()))\n            {\n                throw new InvalidBlockCommitException(\n                    $\"BlockCommit of BlockHash {blockCommit.BlockHash} \" +\n                    $\"has different validator set with chain state's validator set: \\n\" +\n                    $\"in states | \\n \" +\n                    Validators.Aggregate(\n                        string.Empty, (s, v) => s + v.PublicKey + \", \\n\") +\n                    $\"in blockCommit | \\n \" +\n                    blockCommit.Votes.Aggregate(\n                        string.Empty, (s, v) => s + v.ValidatorPublicKey + \", \\n\"));\n            }\n\n            if (!blockCommit.Votes.All(\n                v => v.ValidatorPower == GetValidator(v.ValidatorPublicKey).Power))\n            {\n                throw new InvalidBlockCommitException(\n                    $\"BlockCommit of BlockHash {blockCommit.BlockHash} \" +\n                    $\"has different validator power with chain state's validator set: \\n\" +\n                    $\"in states | \\n \" +\n                    Validators.Aggregate(\n                        string.Empty, (s, v) => s + v.Power + \", \\n\") +\n                    $\"in blockCommit | \\n \" +\n                    blockCommit.Votes.Aggregate(\n                        string.Empty, (s, v) => s + v.ValidatorPower + \", \\n\"));\n            }\n        }\n\n        /// <summary>\n        /// Checks whether <see cref=\"BlockCommit.Votes\"/> is ordered\n        /// by <see cref=\"Address\"/> of each <see cref=\"Vote.ValidatorPublicKey\"/>,\n        /// and <see cref=\"Vote.ValidatorPower\"/> equals to the one recorded in the chain states.\n        /// </summary>\n        /// <remarks>\n        /// If <see cref=\"Vote.ValidatorPower\"/> is null, power check is ignored.</remarks>\n        /// <param name=\"blockCommit\">The <see cref=\"BlockCommit\"/> to check.</param>\n        /// <exception cref=\"InvalidBlockCommitException\">Thrown when some votes in the\n        /// <paramref name=\"blockCommit\"/> does not have null power.</exception>\n        /// <exception cref=\"InvalidBlockCommitException\">Thrown when public key of validators from\n        /// <paramref name=\"blockCommit\"/> is different from validator's public keys of this.\n        /// </exception>\n        public void ValidateLegacyBlockCommitValidators(BlockCommit blockCommit)\n        {\n            if (blockCommit.Votes.Any(v => v.ValidatorPower is not null))\n            {\n                throw new InvalidBlockCommitException(\n                    \"All votes in the block commit before block protocol version 10 \" +\n                    \"must have null power.\");\n            }\n\n            if (!Validators.Select(validator => validator.PublicKey).SequenceEqual(\n                blockCommit.Votes.Select(vote => vote.ValidatorPublicKey).ToList()))\n            {\n                throw new InvalidBlockCommitException(\n                    $\"BlockCommit of BlockHash {blockCommit.BlockHash} \" +\n                    $\"has different validator set with chain state's validator set: \\n\" +\n                    $\"in states | \\n \" +\n                    Validators.Aggregate(\n                        string.Empty, (s, key) => s + key + \", \\n\") +\n                    $\"in blockCommit | \\n \" +\n                    blockCommit.Votes.Aggregate(\n                        string.Empty, (s, key) => s + key.ValidatorPublicKey + \", \\n\"));\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Types/Consensus/Vote.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Collections.Immutable;\nusing System.Diagnostics.Contracts;\nusing System.Globalization;\nusing System.Linq;\nusing System.Numerics;\nusing System.Text.Json;\nusing System.Text.Json.Serialization;\nusing Bencodex;\nusing Bencodex.Types;\nusing Libplanet.Common;\nusing Libplanet.Crypto;\nusing Libplanet.Types.Blocks;\n\nnamespace Libplanet.Types.Consensus\n{\n    /// <summary>\n    /// Represents a <see cref=\"Vote\"/> from a validator for consensus.\n    /// </summary>\n    public class Vote : IVoteMetadata, IEquatable<Vote>, IBencodable\n    {\n        private static readonly Binary SignatureKey = new Binary(new byte[] { 0x53 }); // 'S'\n\n        private static readonly Codec _codec = new Codec();\n        private readonly VoteMetadata _metadata;\n\n        public Vote(\n            VoteMetadata metadata,\n            ImmutableArray<byte> signature)\n        {\n            if (signature.IsDefault)\n            {\n                throw new ArgumentException(\n                    $\"Given {nameof(signature)} should not be set to default; use \" +\n                    $\"an empty array to represent a lack of signature for a {nameof(Vote)}.\",\n                    nameof(signature));\n            }\n            else if (!signature.IsEmpty)\n            {\n                if (metadata.Flag != VoteFlag.PreVote && metadata.Flag != VoteFlag.PreCommit)\n                {\n                    throw new ArgumentException(\n                        $\"If {nameof(signature)} is not empty, {metadata.Flag} should be either \" +\n                        $\"{VoteFlag.PreVote} or {VoteFlag.PreCommit}\",\n                        nameof(signature));\n                }\n                else if (!metadata.ValidatorPublicKey.Verify(\n                    _codec.Encode(metadata.Bencoded), signature))\n                {\n                    throw new ArgumentException(\n                        $\"Given {nameof(signature)} is invalid.\",\n                        nameof(signature));\n                }\n            }\n            else if (signature.IsEmpty &&\n                (metadata.Flag != VoteFlag.Null && metadata.Flag != VoteFlag.Unknown))\n            {\n                throw new ArgumentException(\n                    $\"If {nameof(signature)} is empty, {metadata.Flag} should be either \" +\n                    $\"{VoteFlag.Null} or {VoteFlag.Unknown}\",\n                    nameof(signature));\n            }\n\n            _metadata = metadata;\n            Signature = signature;\n        }\n\n        public Vote(Bencodex.Types.IValue bencoded)\n            : this(bencoded is Bencodex.Types.Dictionary dict\n                ? dict\n                : throw new ArgumentException(\n                    $\"Given {nameof(bencoded)} must be of type \" +\n                    $\"{typeof(Bencodex.Types.Dictionary)}: {bencoded.GetType()}\",\n                    nameof(bencoded)))\n        {\n        }\n\n#pragma warning disable SA1118 // The parameter spans multiple lines\n        private Vote(Bencodex.Types.Dictionary encoded)\n            : this(\n                new VoteMetadata((IValue)encoded),\n                encoded.ContainsKey(SignatureKey)\n                    ? ((Binary)encoded[SignatureKey]).ByteArray\n                    : ImmutableArray<byte>.Empty)\n        {\n        }\n#pragma warning restore SA1118\n\n        /// <inheritdoc/>\n        public long Height => _metadata.Height;\n\n        /// <inheritdoc/>\n        public int Round => _metadata.Round;\n\n        /// <inheritdoc/>\n        public BlockHash BlockHash => _metadata.BlockHash;\n\n        /// <inheritdoc/>\n        public DateTimeOffset Timestamp => _metadata.Timestamp;\n\n        /// <inheritdoc/>\n        public PublicKey ValidatorPublicKey => _metadata.ValidatorPublicKey;\n\n        /// <inheritdoc/>\n        public BigInteger? ValidatorPower => _metadata.ValidatorPower;\n\n        /// <inheritdoc/>\n        public VoteFlag Flag => _metadata.Flag;\n\n        /// <summary>\n        /// The signature for the <see cref=\"Vote\"/>.  Lack of signature for a <see cref=\"Vote\"/>\n        /// is represented by an empty array <em>not</em> <see langword=\"default\"/>.\n        /// </summary>\n        public ImmutableArray<byte> Signature { get; }\n\n        /// <inheritdoc/>\n        [JsonIgnore]\n        public Bencodex.Types.IValue Bencoded =>\n            !Signature.IsEmpty\n                ? ((Bencodex.Types.Dictionary)_metadata.Bencoded).Add(SignatureKey, Signature)\n                : _metadata.Bencoded;\n\n        /// <summary>\n        /// Verifies whether the <see cref=\"Vote\"/>'s payload is properly signed by\n        /// <see cref=\"Validator\"/>.\n        /// </summary>\n        /// <returns><see langword=\"true\"/> if the <see cref=\"Signature\"/> is not empty\n        /// and is a valid signature signed by <see cref=\"Validator\"/>,\n        /// <see langword=\"false\"/> otherwise.</returns>\n        [Pure]\n        public bool Verify() =>\n            !Signature.IsEmpty &&\n            ValidatorPublicKey.Verify(\n                _codec.Encode(_metadata.Bencoded).ToImmutableArray(), Signature);\n\n        /// <inheritdoc/>\n        [Pure]\n        public bool Equals(Vote? other)\n        {\n            return other is Vote vote &&\n                _metadata.Equals(vote._metadata) &&\n                Signature.SequenceEqual(vote.Signature);\n        }\n\n        /// <inheritdoc/>\n        [Pure]\n        public override bool Equals(object? obj)\n        {\n            return obj is Vote other && Equals(other);\n        }\n\n        /// <inheritdoc/>\n        [Pure]\n        public override int GetHashCode()\n        {\n            return HashCode.Combine(\n                _metadata.GetHashCode(),\n                ByteUtil.CalculateHashCode(Signature.ToArray()));\n        }\n\n        /// <inheritdoc/>\n        [Pure]\n        public override string ToString()\n        {\n            var dict = new Dictionary<string, object>\n            {\n                { \"validator_public_key\", ValidatorPublicKey.ToString() },\n                { \"validator_power\", $\"{ValidatorPower}\" },\n                { \"vote_flag\", Flag.ToString() },\n                { \"block_hash\", BlockHash.ToString() },\n                { \"height\", Height },\n                { \"round\", Round },\n                { \"timestamp\", Timestamp.ToString(CultureInfo.InvariantCulture) },\n            };\n            return JsonSerializer.Serialize(dict);\n        }\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Types/Consensus/VoteFlag.cs",
    "content": "namespace Libplanet.Types.Consensus\n{\n    /// <summary>\n    /// A State about <see cref=\"Vote\"/>.\n    /// </summary>\n    public enum VoteFlag\n    {\n        /// <summary>\n        /// A flag for a <see cref=\"Vote\"/> indicating that there was no response from a validator.\n        /// </summary>\n        Null = 0,\n\n        /// <summary>\n        /// A flag for a <see cref=\"Vote\"/> that is for a pre-vote phase.\n        /// </summary>\n        PreVote = 1,\n\n        /// <summary>\n        /// A flag for a <see cref=\"Vote\"/> that is for a pre-commit phase.\n        /// </summary>\n        PreCommit = 2,\n\n        /// <summary>\n        /// A flag for a <see cref=\"Vote\"/> that is currently unused.  Reserved only for\n        /// possible future use.\n        /// </summary>\n        Unknown = 3,\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Types/Consensus/VoteMetadata.cs",
    "content": "using System;\nusing System.Collections.Immutable;\nusing System.Globalization;\nusing System.Numerics;\nusing System.Text.Json.Serialization;\nusing Bencodex;\nusing Bencodex.Types;\nusing Libplanet.Crypto;\nusing Libplanet.Types.Blocks;\n\nnamespace Libplanet.Types.Consensus\n{\n    /// <summary>\n    /// Represents a vote metadata from a validator for consensus.\n    /// </summary>\n    public class VoteMetadata : IVoteMetadata, IEquatable<VoteMetadata>, IBencodable\n    {\n        private const string TimestampFormat = \"yyyy-MM-ddTHH:mm:ss.ffffffZ\";\n        private static readonly Binary HeightKey =\n            new Binary(new byte[] { 0x48 }); // 'H'\n\n        private static readonly Binary RoundKey =\n            new Binary(new byte[] { 0x52 }); // 'R'\n\n        private static readonly Binary TimestampKey =\n            new Binary(new byte[] { 0x74 }); // 't'\n\n        private static readonly Binary BlockHashKey =\n            new Binary(new byte[] { 0x68 }); // 'h'\n\n        private static readonly Binary ValidatorPublicKeyKey =\n            new Binary(new byte[] { 0x50 }); // 'P'\n\n        private static readonly Binary ValidatorPowerKey =\n            new Binary(new byte[] { 0x70 }); // 'p'\n\n        private static readonly Binary FlagKey =\n            new Binary(new byte[] { 0x46 }); // 'F'\n\n        private static readonly Codec _codec = new Codec();\n\n        /// <summary>\n        /// Creates a <see cref=\"VoteMetadata\"/> instance.\n        /// </summary>\n        /// <param name=\"height\">Height of the vote target block.</param>\n        /// <param name=\"round\">Round of the vote in given height.</param>\n        /// <param name=\"blockHash\"><see cref=\"BlockHash\"/> of the block in vote.</param>\n        /// <param name=\"timestamp\">The time at which the voting took place.</param>\n        /// <param name=\"validatorPublicKey\">\n        /// <see cref=\"PublicKey\"/> of the validator made the vote.\n        /// </param>\n        /// <param name=\"validatorPower\">The voting power of the validator.</param>\n        /// <param name=\"flag\"><see cref=\"VoteFlag\"/> for the vote's status.</param>\n        /// <exception cref=\"ArgumentException\">Thrown for any of the following reasons:\n        /// <list type=\"bullet\">\n        /// <item><description>\n        ///     Either <paramref name=\"height\"/> or <paramref name=\"round\"/> is negative.\n        /// </description></item>\n        /// <item><description>\n        ///     Given <paramref name=\"blockHash\"/> is <see langword=\"null\"/> when\n        ///     <paramref name=\"flag\"/> is either <see cref=\"VoteFlag.Null\"/>\n        ///     or <see cref=\"VoteFlag.Unknown\"/>.\n        /// </description></item>\n        /// </list>\n        /// </exception>\n        public VoteMetadata(\n            long height,\n            int round,\n            BlockHash blockHash,\n            DateTimeOffset timestamp,\n            PublicKey validatorPublicKey,\n            BigInteger? validatorPower,\n            VoteFlag flag)\n        {\n            if (height < 0)\n            {\n                throw new ArgumentException(\n                    $\"Given {nameof(height)} cannot be negative: {height}\");\n            }\n            else if (round < 0)\n            {\n                throw new ArgumentException(\n                    $\"Given {nameof(round)} cannot be negative: {round}\");\n            }\n            else if (validatorPower is { } power && power <= 0)\n            {\n                var msg = $\"Given {nameof(validatorPower)} cannot be negative \" +\n                          $\"or equal to zero: {validatorPower}\";\n                throw new ArgumentException(msg);\n            }\n            else if (\n                blockHash.Equals(default) && (flag == VoteFlag.Null || flag == VoteFlag.Unknown))\n            {\n                throw new ArgumentException(\n                    $\"Given {nameof(blockHash)} cannot be default if {nameof(flag)} \" +\n                    $\"is {VoteFlag.Null} or {VoteFlag.Unknown}\");\n            }\n\n            Height = height;\n            Round = round;\n            BlockHash = blockHash;\n            Timestamp = timestamp;\n            ValidatorPublicKey = validatorPublicKey;\n            ValidatorPower = validatorPower;\n            Flag = flag;\n        }\n\n        public VoteMetadata(Bencodex.Types.IValue bencoded)\n            : this(bencoded is Bencodex.Types.Dictionary dict\n                ? dict\n                : throw new ArgumentException(\n                    $\"Given {nameof(bencoded)} must be of type \" +\n                    $\"{typeof(Bencodex.Types.Dictionary)}: {bencoded.GetType()}\",\n                    nameof(bencoded)))\n        {\n        }\n\n#pragma warning disable SA1118 // The parameter spans multiple lines\n        private VoteMetadata(Bencodex.Types.Dictionary bencoded)\n            : this(\n                height: (Integer)bencoded[HeightKey],\n                round: (Integer)bencoded[RoundKey],\n                blockHash: new BlockHash(bencoded[BlockHashKey]),\n                timestamp: DateTimeOffset.ParseExact(\n                    (Text)bencoded[TimestampKey],\n                    TimestampFormat,\n                    CultureInfo.InvariantCulture),\n                validatorPublicKey: new PublicKey(\n                    ((Binary)bencoded[ValidatorPublicKeyKey]).ByteArray),\n                validatorPower: bencoded.ContainsKey(ValidatorPowerKey)\n                    ? (Integer)bencoded[ValidatorPowerKey]\n                    : (Integer?)null,\n                flag: (VoteFlag)(int)(Integer)bencoded[FlagKey])\n        {\n        }\n#pragma warning restore SA1118\n\n        /// <inheritdoc/>\n        public long Height { get; }\n\n        /// <inheritdoc/>\n        public int Round { get; }\n\n        /// <inheritdoc/>\n        public BlockHash BlockHash { get; }\n\n        /// <inheritdoc/>\n        public DateTimeOffset Timestamp { get; }\n\n        /// <inheritdoc/>\n        public PublicKey ValidatorPublicKey { get; }\n\n        /// <inheritdoc/>\n        public BigInteger? ValidatorPower { get; }\n\n        /// <inheritdoc/>\n        public VoteFlag Flag { get; }\n\n        /// <inheritdoc/>\n        [JsonIgnore]\n        public Bencodex.Types.IValue Bencoded\n        {\n            get\n            {\n                Dictionary encoded = Bencodex.Types.Dictionary.Empty\n                    .Add(HeightKey, Height)\n                    .Add(RoundKey, Round)\n                    .Add(\n                        TimestampKey,\n                        Timestamp.ToString(TimestampFormat, CultureInfo.InvariantCulture))\n                    .Add(ValidatorPublicKeyKey, ValidatorPublicKey.Format(compress: true))\n                    .Add(FlagKey, (long)Flag);\n\n                if (BlockHash is { } blockHash)\n                {\n                    encoded = encoded.Add(BlockHashKey, blockHash.ByteArray);\n                }\n\n                if (ValidatorPower is { } power)\n                {\n                    encoded = encoded.Add(ValidatorPowerKey, power);\n                }\n\n                return encoded;\n            }\n        }\n\n        /// <summary>\n        /// Signs a <see cref=\"VoteMetadata\"/> to create a <see cref=\"Vote\"/>\n        /// using given <paramref name=\"signer\"/>.\n        /// </summary>\n        /// <param name=\"signer\">The <see cref=\"PrivateKey\"/> to sign the data with.  This can be\n        /// <see langword=\"null\"/> to create an unsigned <see cref=\"Vote\"/> instance.</param>\n        /// <returns>A <see cref=\"Vote\"/> with a (possibly <see langword=\"null\"/>) signature.\n        /// </returns>\n        public Vote Sign(PrivateKey? signer)\n        {\n            return signer is PrivateKey key\n                ? new Vote(this, key.Sign(_codec.Encode(Bencoded)).ToImmutableArray())\n                : new Vote(this, ImmutableArray<byte>.Empty);\n        }\n\n        /// <inheritdoc/>\n        public bool Equals(VoteMetadata? other)\n        {\n            return other is VoteMetadata metadata &&\n                Height == metadata.Height &&\n                Round == metadata.Round &&\n                BlockHash.Equals(metadata.BlockHash) &&\n                Timestamp\n                    .ToString(TimestampFormat, CultureInfo.InvariantCulture).Equals(\n                        metadata.Timestamp.ToString(\n                            TimestampFormat,\n                            CultureInfo.InvariantCulture)) &&\n                ValidatorPublicKey.Equals(metadata.ValidatorPublicKey) &&\n                ValidatorPower == metadata.ValidatorPower &&\n                Flag == metadata.Flag;\n        }\n\n        /// <inheritdoc/>\n        public override bool Equals(object? obj) =>\n            obj is VoteMetadata other && Equals(other);\n\n        /// <inheritdoc/>\n        public override int GetHashCode()\n        {\n            return HashCode.Combine(\n                Height,\n                Round,\n                BlockHash,\n                Timestamp.ToString(TimestampFormat, CultureInfo.InvariantCulture),\n                ValidatorPublicKey,\n                ValidatorPower,\n                Flag);\n        }\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Types/Evidence/DuplicateVoteEvidence.cs",
    "content": "using System;\nusing System.Globalization;\nusing System.Numerics;\nusing Bencodex;\nusing Bencodex.Misc;\nusing Bencodex.Types;\nusing Libplanet.Types.Blocks;\nusing Libplanet.Types.Consensus;\n\nnamespace Libplanet.Types.Evidence\n{\n    /// <summary>\n    /// Represents a evidence of duplicate vote on consensus.\n    /// </summary>\n    public class DuplicateVoteEvidence\n        : EvidenceBase, IEquatable<DuplicateVoteEvidence>\n    {\n        private static readonly byte[] VoteRefKey = { 0x76 };             // 'v'\n        private static readonly byte[] VoteDupKey = { 0x56 };             // 'V'\n        private static readonly byte[] ValidatorPowerKey = { 0x70 };      // 'p'\n        private static readonly byte[] TotalPowerKey = { 0x50 };          // 'P'\n\n        /// <summary>\n        /// Creates a <see cref=\"DuplicateVoteEvidence\"/> instance.\n        /// </summary>\n        /// <param name=\"voteRef\">Reference vote of conflicting <see cref=\"Vote\"/>s.</param>\n        /// <param name=\"voteDup\">Duplicated vote of conflicting <see cref=\"Vote\"/>s.</param>\n        /// <param name=\"validatorSet\"><see cref=\"ValidatorSet\"/>\n        /// from block of conflicting votes has been made.</param>\n        /// <param name=\"timestamp\">The timestamp of evidence.</param>\n        public DuplicateVoteEvidence(\n            Vote voteRef,\n            Vote voteDup,\n            ValidatorSet validatorSet,\n            DateTimeOffset timestamp)\n            : this(\n                  voteRef.Height,\n                  voteRef,\n                  voteDup,\n                  validatorSet.GetValidator(voteRef.ValidatorPublicKey).Power,\n                  validatorSet.TotalPower,\n                  timestamp)\n        {\n        }\n\n        /// <summary>\n        /// Creates a <see cref=\"DuplicateVoteEvidence\"/> instance from\n        /// bencoded <see cref=\"IValue\"/>.\n        /// </summary>\n        /// <param name=\"bencoded\">Bencoded <see cref=\"IValue\"/>.</param>\n        public DuplicateVoteEvidence(IValue bencoded)\n            : base(bencoded)\n        {\n            if (bencoded is Dictionary dictionary)\n            {\n                VoteRef = new Vote(dictionary.GetValue<IValue>(VoteRefKey));\n                VoteDup = new Vote(dictionary.GetValue<IValue>(VoteDupKey));\n                ValidatorPower = dictionary.GetValue<Integer>(ValidatorPowerKey);\n                TotalPower = dictionary.GetValue<Integer>(TotalPowerKey);\n            }\n            else\n            {\n                throw new ArgumentException(\n                    \"Given bencoded must be of type Dictionary.\", nameof(bencoded));\n            }\n        }\n\n        private DuplicateVoteEvidence(\n            long height,\n            Vote voteRef,\n            Vote voteDup,\n            BigInteger validatorPower,\n            BigInteger totalPower,\n            DateTimeOffset timestamp)\n            : base(height, voteRef.ValidatorPublicKey.Address, timestamp)\n        {\n            if (voteRef.Height != height)\n            {\n                throw new ArgumentException(\n                    $\"Height of voteRef is different from height : \" +\n                    $\"Expected {height}, Actual {voteRef.Height}\");\n            }\n\n            if (voteDup.Height != height)\n            {\n                throw new ArgumentException(\n                    $\"Height of voteDup is different from height : \" +\n                    $\"Expected {height}, Actual {voteDup.Height}\");\n            }\n\n            if (voteRef.Round != voteDup.Round)\n            {\n                throw new ArgumentException(\n                    $\"Round of votes are different : \" +\n                    $\"voteRef {voteRef.Round}, voteDup {voteDup.Round}\");\n            }\n\n            if (voteRef.ValidatorPublicKey != voteDup.ValidatorPublicKey)\n            {\n                throw new ArgumentException(\n                    $\"Validator public key of votes are different : \" +\n                    $\"voteRef {voteRef.ValidatorPublicKey},\" +\n                    $\"voteDup {voteDup.ValidatorPublicKey}\");\n            }\n\n            if (voteRef.Flag != voteDup.Flag)\n            {\n                throw new ArgumentException(\n                    $\"Flags of votes are different : \" +\n                    $\"voteRef {voteRef.Flag}, voteDup {voteDup.Flag}\");\n            }\n\n            if (voteRef.BlockHash is { } voteRefHash)\n            {\n            }\n            else\n            {\n                throw new ArgumentException(\n                    $\"voteRef is nill vote\");\n            }\n\n            if (voteDup.BlockHash is { } voteDupHash)\n            {\n            }\n            else\n            {\n                throw new ArgumentException(\n                    $\"voteDup is nill vote\");\n            }\n\n            if (voteRefHash.Equals(voteDupHash))\n            {\n                throw new ArgumentException(\n                    $\"Blockhash of votes are same : \" +\n                    $\"{voteRefHash}\");\n            }\n\n            if (!voteRef.Verify())\n            {\n                throw new ArgumentException(\n                    $\"Signature of voteRef is invalid : \" +\n                    $\"voteRef {voteRef},\" +\n                    $\"signature {voteRef.Signature.Hex()}\");\n            }\n\n            if (!voteDup.Verify())\n            {\n                throw new ArgumentException(\n                    $\"Signature of voteDup is invalid : \" +\n                    $\"voteDup {voteDup},\" +\n                    $\"signature {voteDup.Signature.Hex()}\");\n            }\n\n            if (height < 0L)\n            {\n                throw new ArgumentException(\n                    $\"Height is not positive\");\n            }\n\n            if (validatorPower <= BigInteger.Zero)\n            {\n                throw new ArgumentException(\n                    $\"Validator Power is not positive\");\n            }\n\n            if (totalPower <= BigInteger.Zero)\n            {\n                throw new ArgumentException(\n                    $\"Total power is not positive\");\n            }\n\n            (VoteRef, VoteDup) = OrderDuplicateVotePair(voteRef, voteDup);\n            ValidatorPower = validatorPower;\n            TotalPower = totalPower;\n        }\n\n        /// <summary>\n        /// The reference vote of conflicting votes.\n        /// </summary>\n        public Vote VoteRef { get; }\n\n        /// <summary>\n        /// The duplicated vote of conflicting votes.\n        /// </summary>\n        public Vote VoteDup { get; }\n\n        /// <summary>\n        /// Consensus power of validator that committed infraction at the time\n        /// that infraction has been occurred.\n        /// </summary>\n        public BigInteger ValidatorPower { get; }\n\n        /// <summary>\n        /// Total power of validators at the time that infraction has been occurred.\n        /// </summary>\n        public BigInteger TotalPower { get; }\n\n        public static (Vote, Vote) OrderDuplicateVotePair(Vote voteRef, Vote voteDup)\n        {\n            if (voteRef.BlockHash is { } voteRefHash)\n            {\n            }\n            else\n            {\n                throw new ArgumentException(\n                    $\"voteRef is nill vote\");\n            }\n\n            if (voteDup.BlockHash is { } voteDupHash)\n            {\n            }\n            else\n            {\n                throw new ArgumentException(\n                    $\"voteDup is nill vote\");\n            }\n\n            if (voteRef.Timestamp < voteDup.Timestamp)\n            {\n                return (voteRef, voteDup);\n            }\n            else if (voteRef.Timestamp > voteDup.Timestamp)\n            {\n                return (voteDup, voteRef);\n            }\n            else\n            {\n                if (voteRefHash.CompareTo(voteDupHash) < 0)\n                {\n                    return (voteRef, voteDup);\n                }\n                else\n                {\n                    return (voteDup, voteRef);\n                }\n            }\n        }\n\n        /// <inheritdoc/>\n        public bool Equals(DuplicateVoteEvidence? other)\n        {\n            if (base.Equals(other) == true && other is DuplicateVoteEvidence duplicateVoteEvidence)\n            {\n                return VoteRef.Equals(duplicateVoteEvidence.VoteRef) &&\n                    VoteDup.Equals(duplicateVoteEvidence.VoteDup) &&\n                    ValidatorPower == duplicateVoteEvidence.ValidatorPower &&\n                    TotalPower == duplicateVoteEvidence.TotalPower;\n            }\n\n            return false;\n        }\n\n        /// <inheritdoc/>\n        public override bool Equals(object? obj)\n            => obj is DuplicateVoteEvidence other && Equals(other);\n\n        /// <inheritdoc/>\n        public override int GetHashCode()\n            => HashCode.Combine(\n                Height,\n                VoteRef,\n                VoteDup,\n                ValidatorPower,\n                TotalPower,\n                Timestamp.ToString(TimestampFormat, CultureInfo.InvariantCulture));\n\n        protected override Dictionary OnBencoded(Dictionary dictionary)\n        {\n            return dictionary.Add(VoteRefKey, VoteRef.Bencoded)\n                    .Add(VoteDupKey, VoteDup.Bencoded)\n                    .Add(ValidatorPowerKey, ValidatorPower)\n                    .Add(TotalPowerKey, TotalPower);\n        }\n\n        protected override void OnVerify(IEvidenceContext evidenceContext)\n        {\n            var validatorSet = evidenceContext.ValidatorSet;\n\n            if (!validatorSet.PublicKeys.Contains(VoteRef.ValidatorPublicKey))\n            {\n                throw new InvalidEvidenceException(\n                    $\"Evidence public key is not a validator. \" +\n                    $\"PublicKey: {VoteRef.ValidatorPublicKey}\");\n            }\n\n            BigInteger validatorPower\n                = validatorSet.GetValidator(VoteRef.ValidatorPublicKey).Power;\n            BigInteger totalPower = validatorSet.TotalPower;\n\n            if (ValidatorPower != validatorPower)\n            {\n                throw new InvalidEvidenceException(\n                    $\"Evidence validator power is different from the actual. \" +\n                    $\"Expected: {validatorPower}, \" +\n                    $\"Actual: {ValidatorPower}\");\n            }\n\n            if (TotalPower != validatorSet.TotalPower)\n            {\n                throw new InvalidEvidenceException(\n                    $\"Evidence total power is different from the actual. \" +\n                    $\"Expected: {totalPower}, \" +\n                    $\"Actual: {TotalPower}\");\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Types/Evidence/DuplicateVoteException.cs",
    "content": "using System;\nusing Libplanet.Types.Consensus;\n\nnamespace Libplanet.Types.Evidence\n{\n    /// <summary>\n    /// An exception thrown when a duadskf <see cref=\"Vote\"/> is invalid.  In particular,\n    /// this is thrown pre-emptively before a <see cref=\"Vote\"/> is processed, i.e.\n    /// does not change the state of a <see cref=\"Context\"/> in a meaningful way.\n    /// </summary>\n    public class DuplicateVoteException : EvidenceException\n    {\n        /// <summary>\n        /// Initializes a new instance of <see cref=\"InvalidConsensusMessageException\"/> class.\n        /// </summary>\n        /// <param name=\"message\">The error message that explains the reason for the exception.\n        /// </param>\n        /// <param name=\"voteRef\">The 1<see cref=\"Vote\"/> that caused this exception.\n        /// </param>\n        /// <param name=\"voteDup\">The 2<see cref=\"Vote\"/> that caused this exception.\n        /// </param>\n        /// <param name=\"innerException\">The exception that is the cause of the current exception.\n        /// </param>\n        public DuplicateVoteException(\n            string message,\n            Vote voteRef,\n            Vote voteDup,\n            Exception innerException)\n            : base(message, innerException)\n        {\n            VoteRef = voteRef;\n            VoteDup = voteDup;\n        }\n\n        /// <summary>\n        /// Initializes a new instance of <see cref=\"InvalidConsensusMessageException\"/> class.\n        /// </summary>\n        /// <param name=\"message\">The error message that explains the reason for the exception.\n        /// </param>\n        /// <param name=\"voteRef\">The <see cref=\"Vote\"/> that caused this exception.\n        /// </param>\n        /// <param name=\"voteDup\">The 1<see cref=\"Vote\"/> that caused this exception.\n        /// </param>\n        public DuplicateVoteException(string message, Vote voteRef, Vote voteDup)\n            : base(message)\n        {\n            VoteRef = voteRef;\n            VoteDup = voteDup;\n        }\n\n        public Vote VoteRef { get; }\n\n        public Vote VoteDup { get; }\n\n        public override long Height => VoteRef.Height;\n\n        protected override EvidenceBase OnCreateEvidence(IEvidenceContext evidenceContext)\n        {\n            var voteRef = VoteRef;\n            var voteDup = VoteDup;\n            (_, Vote dup) = DuplicateVoteEvidence.OrderDuplicateVotePair(voteRef, voteDup);\n\n            var validatorSet = evidenceContext.ValidatorSet;\n\n            return new DuplicateVoteEvidence(\n                voteRef: voteRef,\n                voteDup: voteDup,\n                validatorSet: validatorSet,\n                timestamp: dup.Timestamp);\n        }\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Types/Evidence/EvidenceBase.cs",
    "content": "using System;\nusing System.Globalization;\nusing System.Reflection;\nusing System.Security.Cryptography;\nusing System.Text.Json.Serialization;\nusing Bencodex;\nusing Bencodex.Types;\nusing Libplanet.Crypto;\n\nnamespace Libplanet.Types.Evidence\n{\n    /// <summary>\n    /// Base class for evidence that explains how the infraction has been occurred.\n    /// </summary>\n    public abstract class EvidenceBase\n        : IEquatable<EvidenceBase>, IComparable<EvidenceBase>, IComparable, IBencodable\n    {\n        public const string TimestampFormat = \"yyyy-MM-ddTHH:mm:ss.fffffffZ\";\n\n        private const string TypeKey = \"type\";\n        private const string DataKey = \"data\";\n\n        private static readonly Codec Codec = new Codec();\n        private static readonly byte[] HeightKey = { 0x68 };              // 'h'\n        private static readonly byte[] TargetAddressKey = { 0x74, 0x61 }; // 'ta'\n        private static readonly byte[] TimestampKey = { 0x74 };           // 't'\n        private EvidenceId? _id;\n\n        /// <summary>\n        /// Constructor for creating new evidence.\n        /// </summary>\n        /// <param name=\"height\">Indicates the block height that infraction has been\n        /// occurred.</param>\n        /// <param name=\"targetAddress\">Indicates the address of the target that caused\n        /// the infraction.</param>\n        /// <param name=\"timestamp\">Indicates the timestamp the infraction occurred.</param>\n        /// <exception cref=\"ArgumentOutOfRangeException\">\n        /// Thrown if <paramref name=\"height\"/> is less than 0.\n        /// </exception>\n        protected EvidenceBase(long height, Address targetAddress, DateTimeOffset timestamp)\n        {\n            if (height < 0L)\n            {\n                throw new ArgumentOutOfRangeException(\n                    nameof(height),\n                    $\"Parameter {nameof(height)} must be greater than or equal to 0.\");\n            }\n\n            Height = height;\n            TargetAddress = targetAddress;\n            Timestamp = timestamp;\n        }\n\n        /// <summary>\n        /// Constructor for decoding bencoded evidence.\n        /// </summary>\n        /// <param name=\"bencoded\">Bencoded data of evidence.</param>\n        /// <exception cref=\"ArgumentException\">\n        /// Thrown if given bencoded is not of type Dictionary.\n        /// </exception>\n        protected EvidenceBase(IValue bencoded)\n        {\n            if (bencoded is Dictionary dictionary)\n            {\n                Height = dictionary.GetValue<Integer>(HeightKey);\n                TargetAddress = new Address(dictionary.GetValue<IValue>(TargetAddressKey));\n                Timestamp = DateTimeOffset.ParseExact(\n                    dictionary.GetValue<Text>(TimestampKey),\n                    TimestampFormat,\n                    CultureInfo.InvariantCulture);\n            }\n            else\n            {\n                throw new ArgumentException(\n                    \"Given bencoded must be of type Dictionary.\", nameof(bencoded));\n            }\n        }\n\n        /// <summary>\n        /// Indicates the block height that infraction has been occurred.\n        /// </summary>\n        public long Height { get; }\n\n        /// <summary>\n        /// Indicates the address of the target that caused the infraction.\n        /// </summary>\n        public Address TargetAddress { get; }\n\n        /// <summary>\n        /// Indicates the timestamp the infraction occurred.\n        /// </summary>\n        public DateTimeOffset Timestamp { get; }\n\n        /// <summary>\n        /// Indicates identifier of evidence.\n        /// </summary>\n        public EvidenceId Id\n        {\n            get\n            {\n                if (!(_id is { } nonNull))\n                {\n                    using var hasher = SHA256.Create();\n                    byte[] payload = Codec.Encode(Bencoded);\n                    _id = nonNull = new EvidenceId(hasher.ComputeHash(payload));\n                }\n\n                return nonNull;\n            }\n        }\n\n        /// <summary>\n        /// Inner bencoded form of evidence.\n        /// This method won't bencode evidence type, so we can't decode evidence\n        /// without knowing the evidence type.\n        /// For fully bencoded form, use <see cref=\"Bencode(EvidenceBase)\"/>.\n        /// </summary>\n        [JsonIgnore]\n        public IValue Bencoded\n        {\n            get\n            {\n                var timestamp = Timestamp.ToString(TimestampFormat, CultureInfo.InvariantCulture);\n                var bencoded = Dictionary.Empty\n                    .Add(HeightKey, Height)\n                    .Add(TargetAddressKey, TargetAddress.Bencoded)\n                    .Add(TimestampKey, timestamp);\n                bencoded = OnBencoded(bencoded);\n                return bencoded;\n            }\n        }\n\n        /// <summary>\n        /// Bencode <see cref=\"EvidenceBase\"/>.\n        /// This bencodes <paramref name=\"evidence\"/> with its evidence type,\n        /// so its return can be decoded by <see cref=\"Decode(IValue)\"/>\n        /// without concrete evidence type.\n        /// </summary>\n        /// <param name=\"evidence\"><see cref=\"EvidenceBase\"/> to be bencoded.</param>\n        /// <returns>Bencoded <see cref=\"IValue\"/>.</returns>\n        public static IValue Bencode(EvidenceBase evidence)\n        {\n            Dictionary bencoded = Dictionary.Empty\n                .Add(TypeKey, GetTypeName(evidence))\n                .Add(DataKey, evidence.Bencoded);\n            return bencoded;\n        }\n\n        /// <summary>\n        /// Decode <see cref=\"IValue\"/> that bencoded with <see cref=\"Bencode(EvidenceBase)\"/>\n        /// to <see cref=\"EvidenceBase\"/>.\n        /// </summary>\n        /// <param name=\"value\">Bencoded <see cref=\"IValue\"/> to be decoded.</param>\n        /// <returns>Decoded <see cref=\"EvidenceBase\"/>.</returns>\n        /// <exception cref=\"NotSupportedException\">Thrown if evidence type does not have\n        /// a constructor that takes <see cref=\"IValue\"/>.</exception>\n        public static EvidenceBase Decode(IValue value)\n        {\n            var type = (string)((Dictionary)value).GetValue<Text>(TypeKey);\n            var evidenceType = Type.GetType(type) ?? typeof(UnknownEvidence);\n            var data = ((Dictionary)value).GetValue<IValue>(DataKey);\n            if (evidenceType.GetConstructor(new Type[] { typeof(IValue) }) is ConstructorInfo ctor)\n            {\n                var args = new object?[] { data };\n                return (EvidenceBase)ctor.Invoke(args);\n            }\n            else\n            {\n                throw new NotSupportedException(\n                    $\"Evidence type {type} does not have a constructor \" +\n                    $\"that takes {nameof(IValue)}.\");\n            }\n        }\n\n        /// <summary>\n        /// Deserialize <see cref=\"EvidenceBase\"/> from byte array.\n        /// </summary>\n        /// <param name=\"bytes\">\n        /// Byte array to be deserialized.\n        /// </param>\n        /// <returns>\n        /// Deserialized <see cref=\"EvidenceBase\"/>.\n        /// </returns>\n        public static EvidenceBase Deserialize(byte[] bytes) => Decode(Codec.Decode(bytes));\n\n        /// <summary>\n        /// Serialize <see cref=\"EvidenceBase\"/> to byte array.\n        /// </summary>\n        /// <returns>\n        /// Serialized byte array of <see cref=\"EvidenceBase\"/>.\n        /// </returns>\n        public byte[] Serialize() => Codec.Encode(Bencode(this));\n\n        /// <inheritdoc/>\n        public bool Equals(EvidenceBase? other) => Id.Equals(other?.Id);\n\n        /// <inheritdoc/>\n        public override bool Equals(object? obj) => obj is EvidenceBase other && Equals(other);\n\n        /// <inheritdoc/>\n        public override int GetHashCode() => unchecked((17 * 31 + Id.GetHashCode()) * 31);\n\n        /// <inheritdoc cref=\"IComparable{T}.CompareTo(T)\"/>\n        public int CompareTo(EvidenceBase? other) => Id.CompareTo(other?.Id);\n\n        /// <inheritdoc cref=\"IComparable.CompareTo(object)\"/>\n        public int CompareTo(object? obj)\n            => obj is EvidenceBase other ? CompareTo(other: other) : 1;\n\n        public void Verify(IEvidenceContext evidenceContext) => OnVerify(evidenceContext);\n\n        internal static string GetTypeName(Type evidenceType)\n        {\n            if (!typeof(EvidenceBase).IsAssignableFrom(evidenceType))\n            {\n                throw new ArgumentException(\n                    $\"Given type {evidenceType} is not a subclass of {nameof(EvidenceBase)}.\",\n                    nameof(evidenceType));\n            }\n\n            var typeName = evidenceType.FullName;\n            var assemblyName = evidenceType.Assembly.GetName().Name;\n            return $\"{typeName}, {assemblyName}\";\n        }\n\n        internal static string GetTypeName(EvidenceBase evidence)\n            => GetTypeName(evidence.GetType());\n\n        protected abstract Dictionary OnBencoded(Dictionary dictionary);\n\n        protected abstract void OnVerify(IEvidenceContext evidenceContext);\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Types/Evidence/EvidenceContext.cs",
    "content": "using Libplanet.Types.Consensus;\n\nnamespace Libplanet.Types.Evidence\n{\n    /// <summary>\n    /// Indicates the context of evidence for creating and verification.\n    /// </summary>\n    public sealed class EvidenceContext : IEvidenceContext\n    {\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"EvidenceContext\"/> class.\n        /// </summary>\n        /// <param name=\"validatorSet\">\n        /// Indicates the <see cref=\"ValidatorSet\" /> where the infraction occurred at the height.\n        /// </param>\n        public EvidenceContext(ValidatorSet validatorSet)\n        {\n            ValidatorSet = validatorSet;\n        }\n\n        /// <summary>\n        /// Indicates the <see cref=\"ValidatorSet\" /> where the infraction occurred at the height.\n        /// </summary>\n        public ValidatorSet ValidatorSet { get; }\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Types/Evidence/EvidenceException.cs",
    "content": "using System;\n\nnamespace Libplanet.Types.Evidence\n{\n    /// <summary>\n    /// Serves as the base class for exceptions related <see cref=\"EvidenceBase\"/>s'\n    /// integrity and validity.\n    /// </summary>\n    public abstract class EvidenceException : Exception\n    {\n        /// <inheritdoc cref=\"Exception(string)\"/>\n        protected EvidenceException(string message)\n            : base(message)\n        {\n        }\n\n        /// <inheritdoc cref=\"Exception(string, Exception)\"/>\n        protected EvidenceException(string message, Exception innerException)\n            : base(message, innerException)\n        {\n        }\n\n        /// <summary>\n        /// Gets the height of the block that occurred the infraction.\n        /// </summary>\n        public abstract long Height { get; }\n\n        /// <summary>\n        /// Creates an instance of evidence.\n        /// </summary>\n        /// <param name=\"evidenceContext\">\n        /// An instance of <see cref=\"IEvidenceContext\"/> to create the evidence.\n        /// </param>\n        /// <returns>\n        /// An instance of <see cref=\"EvidenceBase\"/> from the <see cref=\"EvidenceException\"/>.\n        /// </returns>\n        public EvidenceBase CreateEvidence(IEvidenceContext evidenceContext)\n        {\n            var evidence = OnCreateEvidence(evidenceContext);\n            if (evidence is null)\n            {\n                var message = $\"{nameof(OnCreateEvidence)} must return a non-null \" +\n                              $\"instance of {nameof(EvidenceBase)}.\";\n                throw new InvalidOperationException(message);\n            }\n\n            return evidence;\n        }\n\n        /// <summary>\n        /// Creates an instance of evidence.\n        /// </summary>\n        /// <param name=\"evidenceContext\">\n        /// An instance of <see cref=\"IEvidenceContext\"/> to create the evidence.\n        /// </param>\n        /// <returns>\n        /// An instance of <see cref=\"EvidenceBase\"/> from the <see cref=\"EvidenceException\"/>.\n        /// </returns>\n        protected abstract EvidenceBase OnCreateEvidence(IEvidenceContext evidenceContext);\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Types/Evidence/EvidenceId.cs",
    "content": "using System;\nusing System.Collections.Immutable;\nusing System.Diagnostics.CodeAnalysis;\nusing System.Diagnostics.Contracts;\nusing System.Linq;\nusing System.Text.Json;\nusing System.Text.Json.Serialization;\nusing Bencodex;\nusing Bencodex.Types;\nusing Libplanet.Common;\n\nnamespace Libplanet.Types.Evidence\n{\n    /// <summary>\n    /// <see cref=\"EvidenceId\"/>, abbreviation of Evidence identifier,\n    /// is a SHA-256 digest derived from a <see cref=\"EvidenceBase\"/>'s\n    /// content.\n    /// <para>As it is a SHA-256 digest, it consists of 32 <see cref=\"byte\"/>s,\n    /// and 64 characters in hexadecimal.\n    /// (See also <see cref=\"Size\"/> constant.)</para>\n    /// </summary>\n    /// <seealso cref=\"EvidenceBase.Id\"/>\n    [JsonConverter(typeof(EvidenceIdJsonConverter))]\n    public readonly struct EvidenceId\n        : IEquatable<EvidenceId>, IComparable<EvidenceId>, IComparable, IBencodable\n    {\n        /// <summary>\n        /// The <see cref=\"byte\"/>s size that each <see cref=\"EvidenceId\"/> takes.\n        /// <para>As a evidenceId is a SHA-256 digest, it is 32 <see cref=\"byte\"/>s.\n        /// </para>\n        /// </summary>\n        public const int Size = 32;\n\n        private static readonly Codec Codec = new Codec();\n\n        private static readonly ImmutableArray<byte> _defaultByteArray =\n            ImmutableArray.Create(new byte[Size]);\n\n        private readonly ImmutableArray<byte> _byteArray;\n\n        /// <summary>\n        /// Converts an immutable <see cref=\"byte\"/> array into a <see cref=\"EvidenceId\"/>.\n        /// </summary>\n        /// <param name=\"evidenceId\">An immutable <see cref=\"byte\"/> array that encodes\n        /// a <see cref=\"EvidenceId\"/>.  It must not be <see langword=\"null\"/>, and its\n        /// <see cref=\"ImmutableArray{T}.Length\"/> must be the same to <see cref=\"Size\"/>.</param>\n        /// <exception cref=\"ArgumentOutOfRangeException\">Thrown when the given\n        /// <paramref name=\"evidenceId\"/>'s <see cref=\"Array.Length\"/>\n        /// is not the same to the required <see cref=\"Size\"/>.</exception>\n        public EvidenceId(in ImmutableArray<byte> evidenceId)\n        {\n            if (evidenceId.Length != Size)\n            {\n                throw new ArgumentOutOfRangeException(\n                    nameof(evidenceId),\n                    $\"Given {nameof(evidenceId)} must be {Size} bytes.\");\n            }\n\n            _byteArray = evidenceId;\n        }\n\n        /// <summary>\n        /// Converts a mutable <see cref=\"byte\"/> array into a <see cref=\"EvidenceId\"/>.\n        /// </summary>\n        /// <param name=\"evidenceId\">A mutable <see cref=\"byte\"/> array that encodes\n        /// a <see cref=\"EvidenceId\"/>.  It must not be <see langword=\"null\"/>,\n        /// and its <see cref=\"Array.Length\"/> must be the same to\n        /// <see cref=\"Size\"/>.</param>\n        /// <exception cref=\"ArgumentOutOfRangeException\">Thrown when the given\n        /// <paramref name=\"evidenceId\"/>'s <see cref=\"Array.Length\"/> is not\n        /// the same to the required <see cref=\"Size\"/>.</exception>\n        public EvidenceId(byte[] evidenceId)\n            : this(evidenceId.ToImmutableArray())\n        {\n        }\n\n        /// <summary>\n        /// Creates a <see cref=\"EvidenceId\"/> instance from given <paramref name=\"bencoded\"/>.\n        /// </summary>\n        /// <param name=\"bencoded\">A Bencodex <see cref=\"Binary\"/> of 32 <see cref=\"byte\"/>s which\n        /// represents an <see cref=\"EvidenceId\"/>.\n        /// </param>\n        /// <exception cref=\"ArgumentException\">Thrown when given <paramref name=\"bencoded\"/>\n        /// is not of type <see cref=\"Binary\"/>.</exception>\n        /// <seealso cref=\"EvidenceId(in ImmutableArray{byte})\"/>\n        public EvidenceId(IValue bencoded)\n            : this(bencoded is Binary binary\n                ? binary\n                : throw new ArgumentException(\n                    $\"Given {nameof(bencoded)} must be of type \" +\n                    $\"{typeof(Binary)}: {bencoded.GetType()}\",\n                    nameof(bencoded)))\n        {\n        }\n\n        private EvidenceId(Binary bencoded)\n            : this(bencoded.ByteArray)\n        {\n        }\n\n        public static ImmutableArray<byte> DefaultByteArray => _defaultByteArray;\n\n        /// <summary>\n        /// A bare immutable <see cref=\"byte\"/> array of\n        /// this <see cref=\"EvidenceId\"/>.\n        /// </summary>\n        /// <remarks>It is immutable.  For a mutable array, use\n        /// <see cref=\"ToByteArray()\"/> method instead.</remarks>\n        /// <seealso cref=\"ToByteArray()\"/>\n        public ImmutableArray<byte> ByteArray => _byteArray.IsDefault\n            ? DefaultByteArray\n            : _byteArray;\n\n        /// <inheritdoc/>\n        public IValue Bencoded => new Binary(ByteArray);\n\n        public static bool operator ==(EvidenceId left, EvidenceId right) => left.Equals(right);\n\n        public static bool operator !=(EvidenceId left, EvidenceId right) => !left.Equals(right);\n\n        /// <summary>\n        /// Creates a <see cref=\"EvidenceId\"/> value from a <paramref name=\"hex\"/> string.\n        /// </summary>\n        /// <param name=\"hex\">A hexadecimal string which encodes a <see cref=\"EvidenceId\"/>.\n        /// This has to contain 64 hexadecimal digits and must not be <see langword=\"null\"/>\n        /// This is usually made by <see cref=\"ToString()\"/> method.</param>\n        /// <returns>A corresponding <see cref=\"EvidenceId\"/> value.</returns>\n        /// <exception cref=\"ArgumentOutOfRangeException\">Thrown when the given\n        /// <paramref name=\"hex\"/> is shorter or longer than 64 characters.</exception>\n        /// <exception cref=\"FormatException\">Thrown when the given <paramref name=\"hex\"/> string is\n        /// not a valid hexadecimal string.</exception>\n        /// <seealso cref=\"ToString()\"/>\n        public static EvidenceId Parse(string hex)\n        {\n            ImmutableArray<byte> bytes = ByteUtil.ParseHexToImmutable(hex);\n            try\n            {\n                return new EvidenceId(bytes);\n            }\n            catch (ArgumentOutOfRangeException)\n            {\n                throw new ArgumentOutOfRangeException(\n                    nameof(hex),\n                    $\"Expected {Size * 2} characters, but {hex.Length} characters given.\");\n            }\n        }\n\n        public static bool TryParse(string hex, out EvidenceId? evidenceId)\n        {\n            try\n            {\n                evidenceId = Parse(hex);\n                return true;\n            }\n            catch (Exception)\n            {\n                evidenceId = null;\n                return false;\n            }\n        }\n\n        public bool Equals(EvidenceId other) => ByteArray.SequenceEqual(other.ByteArray);\n\n        public override bool Equals(object? obj) => obj is EvidenceId other && Equals(other);\n\n        public override int GetHashCode() => ByteUtil.CalculateHashCode(ToByteArray());\n\n        /// <summary>\n        /// Gets a bare mutable <see cref=\"byte\"/> array of\n        /// this <see cref=\"EvidenceId\"/>.\n        /// </summary>\n        /// <returns>A new mutable <see cref=\"byte\"/> array of\n        /// this <see cref=\"EvidenceId\"/>.\n        /// Since a returned array is created every time the method is called,\n        /// any mutations on that array does not affect to\n        /// the <see cref=\"EvidenceId\"/> object.\n        /// </returns>\n        /// <seealso cref=\"ByteArray\"/>\n        [Pure]\n        public byte[] ToByteArray() => ByteArray.ToArray();\n\n        /// <summary>\n        /// Gets a <see cref=\"EvidenceId\"/>'s representative string.\n        /// </summary>\n        /// <returns>A string which represents this <see cref=\"EvidenceId\"/>.\n        /// </returns>\n        [Pure]\n        public override string ToString() => ByteUtil.Hex(ToByteArray());\n\n        /// <inheritdoc cref=\"IComparable{T}.CompareTo(T)\"/>\n        public int CompareTo(EvidenceId other)\n        {\n            for (int i = 0; i < Size; ++i)\n            {\n                int cmp = ByteArray[i].CompareTo(other.ByteArray[i]);\n                if (cmp != 0)\n                {\n                    return cmp;\n                }\n            }\n\n            return 0;\n        }\n\n        /// <inheritdoc cref=\"IComparable.CompareTo(object)\"/>\n        public int CompareTo(object? obj) => obj is EvidenceId other ? CompareTo(other) : 1;\n    }\n\n    [SuppressMessage(\n        \"StyleCop.CSharp.MaintainabilityRules\",\n        \"SA1402:FileMayOnlyContainASingleClass\",\n        Justification = \"It's okay to have non-public classes together in a single file.\"\n    )]\n    internal class EvidenceIdJsonConverter : JsonConverter<EvidenceId>\n    {\n        public override EvidenceId Read(\n            ref Utf8JsonReader reader,\n            Type typeToConvert,\n            JsonSerializerOptions options\n        )\n        {\n            string hex = reader.GetString() ?? throw new JsonException(\"Expected a string.\");\n            try\n            {\n                return EvidenceId.Parse(hex);\n            }\n            catch (ArgumentException e)\n            {\n                throw new JsonException(e.Message);\n            }\n        }\n\n        public override void Write(\n            Utf8JsonWriter writer,\n            EvidenceId value,\n            JsonSerializerOptions options\n        ) =>\n            writer.WriteStringValue(value.ToString());\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Types/Evidence/EvidenceIdComparer.cs",
    "content": "using System;\nusing System.Collections.Generic;\n\nnamespace Libplanet.Types.Evidence\n{\n    public sealed class EvidenceIdComparer : IComparer<EvidenceId>\n    {\n        private readonly Func<EvidenceId, EvidenceId, int> _comparer;\n\n        private EvidenceIdComparer(Func<EvidenceId, EvidenceId, int> comparer)\n        {\n            _comparer = comparer;\n        }\n\n        public static EvidenceIdComparer Ascending { get; }\n            = new EvidenceIdComparer((x, y) => x.CompareTo(y));\n\n        public static EvidenceIdComparer Descending { get; }\n            = new EvidenceIdComparer((x, y) => y.CompareTo(x));\n\n        public int Compare(EvidenceId x, EvidenceId y) => _comparer(x, y);\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Types/Evidence/IEvidenceContext.cs",
    "content": "using Libplanet.Types.Consensus;\n\nnamespace Libplanet.Types.Evidence\n{\n    /// <summary>\n    /// Indicates the context of evidence for creating and verification.\n    /// </summary>\n    public interface IEvidenceContext\n    {\n        /// <summary>\n        /// Indicates the <see cref=\"ValidatorSet\" /> where the infraction occurred at the height.\n        /// </summary>\n        ValidatorSet ValidatorSet { get; }\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Types/Evidence/InvalidEvidenceException.cs",
    "content": "using System;\n\nnamespace Libplanet.Types.Evidence\n{\n    /// <summary>\n    /// Serves as the base class for exceptions related <see cref=\"DuplicateVoteEvidence\"/>s'\n    /// integrity and validity.\n    /// </summary>\n    public class InvalidEvidenceException : Exception\n    {\n        /// <inheritdoc cref=\"Exception(string)\"/>\n        public InvalidEvidenceException(string message)\n            : base(message)\n        {\n        }\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Types/Evidence/UnknownEvidence.cs",
    "content": "using Bencodex.Types;\n\nnamespace Libplanet.Types.Evidence\n{\n    internal sealed class UnknownEvidence : EvidenceBase\n    {\n        private readonly Dictionary _bencoded;\n\n        public UnknownEvidence(IValue bencoded)\n            : base(bencoded)\n        {\n            _bencoded = (Dictionary)bencoded;\n        }\n\n        protected override Dictionary OnBencoded(Dictionary dictionary) => _bencoded;\n\n        protected override void OnVerify(IEvidenceContext evidenceContext)\n        {\n        }\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Types/Libplanet.Types.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <PropertyGroup>\n    <NoWarn>$(NoWarn);SA1012</NoWarn>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <PackageReference Include=\"System.Collections.Immutable\" Version=\"1.*\" />\n    <PackageReference Include=\"System.Text.Json\" Version=\"6.0.*\" />\n    <PackageReference Include=\"Bencodex\" Version=\"0.16.0\" />\n    <PackageReference Include=\"Bencodex.Json\" Version=\"0.16.0\" />\n    <PackageReference Include=\"Microsoft.Bcl.HashCode\" Version=\"1.1.1\" />\n  </ItemGroup>\n\n  <ItemGroup Condition=\"'$(SkipSonar)' != 'true'\">\n    <PackageReference Remove=\"SonarAnalyzer.CSharp\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <ProjectReference Include=\"..\\Libplanet.Common\\Libplanet.Common.csproj\" />\n    <ProjectReference Include=\"..\\Libplanet.Crypto\\Libplanet.Crypto.csproj\" />\n  </ItemGroup>\n\n</Project>\n"
  },
  {
    "path": "src/Libplanet.Types/Tx/AddressSet.cs",
    "content": "using System;\nusing System.Collections;\nusing System.Collections.Generic;\nusing System.Collections.Immutable;\nusing System.Diagnostics.Contracts;\nusing System.Linq;\nusing Libplanet.Crypto;\n\nnamespace Libplanet.Types.Tx\n{\n    /// <summary>\n    /// Order-preserving set of <see cref=\"Address\"/>es.\n    /// </summary>\n    public class AddressSet : IImmutableSet<Address>, IEquatable<AddressSet>\n    {\n        /// <summary>\n        /// An empty <see cref=\"AddressSet\"/>.\n        /// </summary>\n        public static readonly AddressSet Empty = new AddressSet(ImmutableArray<Address>.Empty);\n\n        private readonly ImmutableArray<Address> _addresses;\n\n        /// <summary>\n        /// Creates a new <see cref=\"AddressSet\"/> instance.\n        /// </summary>\n        /// <param name=\"addresses\"><see cref=\"Address\"/>es to include in the set.  Duplicated\n        /// <see cref=\"Address\"/>es are ignored, and only the first occurrence is included.\n        /// The order of <paramref name=\"addresses\"/> is preserved.</param>\n        public AddressSet(IEnumerable<Address> addresses)\n        {\n            var elements = new HashSet<Address>();\n            var builder = ImmutableArray.CreateBuilder<Address>();\n            foreach (Address address in addresses)\n            {\n                if (elements.Add(address))\n                {\n                    builder.Add(address);\n                }\n            }\n\n            builder.Capacity = elements.Count;\n            _addresses = builder.MoveToImmutable();\n        }\n\n        private AddressSet(in ImmutableArray<Address> addresses, bool bypassCheck)\n        {\n            if (!bypassCheck)\n            {\n                throw new ArgumentException(\"Make sure if this call is intended.\");\n            }\n\n            _addresses = addresses;\n        }\n\n        /// <inheritdoc cref=\"IReadOnlyCollection{T}.Count\"/>\n        [Pure]\n        public int Count => _addresses.Length;\n\n        /// <inheritdoc cref=\"IEnumerable{T}.GetEnumerator()\"/>\n        [Pure]\n        public IEnumerator<Address> GetEnumerator() =>\n            ((IEnumerable<Address>)_addresses).GetEnumerator();\n\n        /// <inheritdoc cref=\"IEnumerable.GetEnumerator()\"/>\n        [Pure]\n        IEnumerator IEnumerable.GetEnumerator() =>\n            ((IEnumerable)_addresses).GetEnumerator();\n\n        /// <inheritdoc cref=\"IImmutableSet{T}.Clear()\"/>\n        [Pure]\n        public IImmutableSet<Address> Clear() => Empty;\n\n        /// <inheritdoc cref=\"IImmutableSet{T}.Contains(T)\"/>\n        [Pure]\n        public bool Contains(Address value) =>\n            _addresses.Contains(value);\n\n        /// <inheritdoc cref=\"IImmutableSet{T}.Add(T)\"/>\n        [Pure]\n        public IImmutableSet<Address> Add(Address value) =>\n            new AddressSet(_addresses.Add(value));\n\n        /// <inheritdoc cref=\"IImmutableSet{T}.Remove(T)\"/>\n        [Pure]\n        public IImmutableSet<Address> Remove(Address value) =>\n            new AddressSet(_addresses.Remove(value), bypassCheck: true);\n\n        /// <inheritdoc cref=\"IImmutableSet{T}.TryGetValue(T, out T)\"/>\n        [Pure]\n#if NETSTANDARD2_0_OR_GREATER || NETCOREAPP3_1_OR_GREATER\n        public bool TryGetValue(Address equalValue, out Address actualValue)\n#elif NET6_0_OR_GREATER\n        public bool TryGetValue(\n            Address equalValue,\n            [System.Diagnostics.CodeAnalysis.MaybeNullWhen(false)] out Address actualValue)\n#endif\n        {\n            if (_addresses.Contains(equalValue))\n            {\n                actualValue = equalValue;\n                return true;\n            }\n\n#if NET6_0_OR_GREATER\n            actualValue = default;\n#endif\n            return false;\n        }\n\n        /// <inheritdoc cref=\"IImmutableSet{T}.Intersect(IEnumerable{T})\"/>\n        [Pure]\n        public IImmutableSet<Address> Intersect(IEnumerable<Address> other) =>\n            new AddressSet(_addresses.Intersect(other).ToImmutableArray(), bypassCheck: true);\n\n        /// <inheritdoc cref=\"IImmutableSet{T}.Except(IEnumerable{T})\"/>\n        [Pure]\n        public IImmutableSet<Address> Except(IEnumerable<Address> other) =>\n            new AddressSet(_addresses.Except(other).ToImmutableArray(), bypassCheck: true);\n\n        /// <inheritdoc cref=\"IImmutableSet{T}.SymmetricExcept(IEnumerable{T})\"/>\n        [Pure]\n        public IImmutableSet<Address> SymmetricExcept(IEnumerable<Address> other)\n        {\n            ICollection<Address> operand = other is ICollection<Address> o\n                ? o\n                : other.ToArray();\n            return new AddressSet(_addresses.Union(operand).Except(_addresses.Intersect(operand)));\n        }\n\n        /// <inheritdoc cref=\"IImmutableSet{T}.Union(IEnumerable{T})\"/>\n        [Pure]\n        public IImmutableSet<Address> Union(IEnumerable<Address> other) =>\n            new AddressSet(_addresses.Union(other));\n\n        /// <inheritdoc cref=\"IImmutableSet{T}.SetEquals(IEnumerable{T})\"/>\n        [Pure]\n        public bool SetEquals(IEnumerable<Address> other)\n        {\n            ICollection<Address> operand = other is ICollection<Address> o\n                ? o\n                : other.ToArray();\n            if (_addresses.Length != operand.Count)\n            {\n                return false;\n            }\n\n            return _addresses.All(operand.Contains);\n        }\n\n        /// <inheritdoc cref=\"IImmutableSet{T}.IsProperSubsetOf(IEnumerable{T})\"/>\n        [Pure]\n        public bool IsProperSubsetOf(IEnumerable<Address> other)\n        {\n            ISet<Address> operand = other is ISet<Address> o\n                ? o\n                : other.ToImmutableHashSet();\n            return operand.IsProperSupersetOf(_addresses);\n        }\n\n        /// <inheritdoc cref=\"IImmutableSet{T}.IsProperSupersetOf(IEnumerable{T})\"/>\n        [Pure]\n        public bool IsProperSupersetOf(IEnumerable<Address> other)\n        {\n            ISet<Address> operand = other is ISet<Address> o\n                ? o\n                : other.ToImmutableHashSet();\n            return operand.IsProperSubsetOf(_addresses);\n        }\n\n        /// <inheritdoc cref=\"IImmutableSet{T}.IsSubsetOf(IEnumerable{T})\"/>\n        [Pure]\n        public bool IsSubsetOf(IEnumerable<Address> other)\n        {\n            ISet<Address> operand = other is ISet<Address> o\n                ? o\n                : other.ToImmutableHashSet();\n            return operand.IsSupersetOf(_addresses);\n        }\n\n        /// <inheritdoc cref=\"IImmutableSet{T}.IsSupersetOf(IEnumerable{T})\"/>\n        [Pure]\n        public bool IsSupersetOf(IEnumerable<Address> other)\n        {\n            ISet<Address> operand = other is ISet<Address> o\n                ? o\n                : other.ToImmutableHashSet();\n            return operand.IsSubsetOf(_addresses);\n        }\n\n        /// <inheritdoc cref=\"IImmutableSet{T}.Overlaps(IEnumerable{T})\"/>\n        [Pure]\n        public bool Overlaps(IEnumerable<Address> other)\n        {\n            ICollection<Address> operand = other is ICollection<Address> o\n                ? o\n                : other.ToArray();\n            return _addresses.Any(operand.Contains);\n        }\n\n        /// <inheritdoc cref=\"IEquatable{T}.Equals(T)\"/>\n        [Pure]\n        public bool Equals(AddressSet? other) =>\n            other is { } set && set.SetEquals(this);\n\n        /// <inheritdoc cref=\"object.Equals(object?)\"/>\n        [Pure]\n        public override bool Equals(object? obj) =>\n            obj is AddressSet set && Equals(set);\n\n        /// <inheritdoc cref=\"object.GetHashCode()\"/>\n        [Pure]\n        public override int GetHashCode() =>\n            _addresses.OrderBy(a => a).Aggregate(0, (h, a) => h ^ a.GetHashCode());\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Types/Tx/ITransaction.cs",
    "content": "namespace Libplanet.Types.Tx\n{\n    /// <summary>\n    /// An abstract interface for a transaction.  Unlike <see cref=\"Transaction\"/>, it deals\n    /// with custom actions in a non-generic way.  Instead, they are represented as\n    /// <see cref=\"IAction\"/>.\n    /// </summary>\n    public interface ITransaction : IUnsignedTx\n    {\n        /// <summary>\n        /// The unique identifier derived from this transaction's content including actions and\n        /// signature.\n        /// </summary>\n        /// <seealso cref=\"TxId\"/>\n        TxId Id { get; }\n\n        /// <summary>\n        /// A digital signature of the content of this <see cref=\"ITransaction\"/>.\n        /// </summary>\n        public byte[] Signature { get; }\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Types/Tx/ITxInvoice.cs",
    "content": "using System;\nusing System.Collections.Immutable;\nusing Libplanet.Crypto;\nusing Libplanet.Types.Assets;\nusing Libplanet.Types.Blocks;\n\nnamespace Libplanet.Types.Tx\n{\n    /// <summary>\n    /// Content of a transaction without any information related to author or signature.\n    /// The content is ready to be signed by any account.  It can be made a fully fledged\n    /// <see cref=\"ITransaction\"/> by being combined with an <see cref=\"ITxSigningMetadata\"/>\n    /// and a signature.\n    /// </summary>\n    /// <seealso cref=\"TxInvoice\" />\n    /// <seealso cref=\"ITxSigningMetadata\" />\n    /// <seealso cref=\"IUnsignedTx\" />\n    /// <seealso cref=\"ITransaction\" />\n    public interface ITxInvoice : IEquatable<ITxInvoice>\n    {\n        /// <summary>\n        /// <para>\n        /// A deprecated property which was used as an approximated list of addresses whose states\n        /// would be affected by actions in this transaction.\n        /// </para>\n        /// <para>\n        /// This is no longer officially supported in the sense that a <see cref=\"Transaction\"/>\n        /// cannot be created with a non-empty set of <see cref=\"Address\"/>es through normal means\n        /// (i.e. using intended APIs).\n        /// </para>\n        /// <para>\n        /// It is still possible to create a <see cref=\"Transaction\"/> through other means,\n        /// such as creating a payload directly by assigning appropriate values and signing\n        /// an \"unsigned transaction\".  This is not recommended.\n        /// </para>\n        /// </summary>\n        IImmutableSet<Address> UpdatedAddresses { get; }\n\n        /// <summary>\n        /// The time this transaction is created and signed.\n        /// </summary>\n        DateTimeOffset Timestamp { get; }\n\n        /// <summary>\n        /// A <see cref=\"BlockHash\"/> value of the genesis which this transaction is made\n        /// from.  This can be <see langword=\"null\"/> iff the transaction is contained in\n        /// the genesis block.\n        /// </summary>\n        BlockHash? GenesisHash { get; }\n\n        /// <summary>\n        /// A list of actions in this transaction.\n        /// </summary>\n        TxActionList Actions { get; }\n\n        /// <summary>\n        /// <para>\n        /// The maximum amount of <see cref=\"FungibleAssetValue\"/> that the\n        /// <see cref=\"Transaction\"/>'s author is willing to pay per gas\n        /// for the <see cref=\"Transaction\"/>.\n        /// </para>\n        /// <para>\n        /// If <see langword=\"null\"/>, gas processing is entirely bypassed.\n        /// The parity of <see langword=\"null\"/>-ness is always the same as\n        /// that of <see cref=\"GasLimit\"/>.\n        /// </para>\n        /// <para>\n        /// If not <see langword=\"null\"/>, this value cannot be negative.\n        /// </para>\n        /// </summary>\n        /// <seealso cref=\"IFeeCollector\"/>\n        /// <seealso cref=\"GasLimit\"/>\n        FungibleAssetValue? MaxGasPrice { get; }\n\n        /// <summary>\n        /// <para>\n        /// The limit on the total amount of gas that the <see cref=\"Transaction\"/> can use.\n        /// </para>\n        /// <para>\n        /// If <see langword=\"null\"/>, gas processing is entirely bypassed.\n        /// The parity of <see langword=\"null\"/>-ness is always the same as\n        /// that of <see cref=\"MaxGasPrice\"/>.\n        /// </para>\n        /// <para>\n        /// If not <see langword=\"null\"/>, this value cannot be negative.\n        /// </para>\n        /// </summary>\n        /// <seealso cref=\"IFeeCollector\"/>\n        /// <seealso cref=\"GasLimit\"/>\n        long? GasLimit { get; }\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Types/Tx/ITxSigningMetadata.cs",
    "content": "using System;\nusing Libplanet.Crypto;\n\nnamespace Libplanet.Types.Tx\n{\n    /// <summary>\n    /// Metadata for signing a transaction, except for the actual signature.\n    /// </summary>\n    /// <seealso cref=\"TxSigningMetadata\" />\n    /// <seealso cref=\"ITxInvoice\"/>\n    /// <seealso cref=\"IUnsignedTx\"/>\n    /// <seealso cref=\"ITransaction\"/>\n    public interface ITxSigningMetadata : IEquatable<ITxSigningMetadata>\n    {\n        /// <summary>\n        /// The number of previous <see cref=\"Transaction\"/>s committed by\n        /// the <see cref=\"Signer\"/> of this transaction.  This nonce is used for preventing replay\n        /// attack.\n        /// </summary>\n        long Nonce { get; }\n\n        /// <summary>\n        /// A <see cref=\"PublicKey\"/> of the account who signs this transaction.  This is derived\n        /// from the <see cref=\"PublicKey\"/>.\n        /// </summary>\n        Address Signer { get; }\n\n        /// <summary>\n        /// A <see cref=\"PublicKey\"/> of the account who signs this transaction.\n        /// The <see cref=\"Signer\"/> address is always corresponding to this for each transaction.\n        /// This cannot be <see langword=\"null\"/>.\n        /// </summary>\n        PublicKey PublicKey { get; }\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Types/Tx/IUnsignedTx.cs",
    "content": "using System;\n\nnamespace Libplanet.Types.Tx\n{\n    /// <summary>\n    /// <see cref=\"ITxInvoice\"/> combined with <see cref=\"ITxSigningMetadata\"/>, or\n    /// <see cref=\"ITransaction\"/> minus its <see cref=\"ITransaction.Signature\"/>.\n    /// Ready to be signed by the specified <see cref=\"ITxSigningMetadata.Signer\"/>.\n    /// </summary>\n    /// <seealso cref=\"UnsignedTx\"/>\n    /// <seealso cref=\"ITxInvoice\"/>\n    /// <seealso cref=\"ITxSigningMetadata\"/>\n    /// <seealso cref=\"ITransaction\"/>\n    public interface IUnsignedTx : ITxInvoice, ITxSigningMetadata, IEquatable<IUnsignedTx>\n    {\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Types/Tx/InvalidTxException.cs",
    "content": "using System;\n\nnamespace Libplanet.Types.Tx\n{\n    /// <summary>\n    /// Serves as the base class for exceptions thrown when a transaction is invalid.\n    /// </summary>\n    public abstract class InvalidTxException : Exception\n    {\n        /// <summary>\n        /// Instantiates a new exception object with proper metadata. Use\n        /// <see cref=\"InvalidTxException(string, TxId, Exception)\"/> if innerException\n        /// is required.\n        /// </summary>\n        /// <param name=\"message\">A descriptive error message for programmers.\n        /// </param>\n        /// <param name=\"txid\">The invalid <see cref=\"Transaction\"/>'s\n        /// <see cref=\"Transaction.Id\"/>.  It is automatically included to\n        /// the <see cref=\"Exception.Message\"/> string.</param>\n        protected InvalidTxException(string message, TxId txid)\n            : base($\"{txid.ToHex()}: {message}\")\n        {\n            TxId = txid;\n        }\n\n        /// <inheritdoc cref=\"InvalidTxException(string, TxId)\"/>\n        /// <param name=\"message\">A descriptive error message for programmers.\n        /// </param>\n        /// <param name=\"txid\">The invalid <see cref=\"Transaction\"/>'s\n        /// <see cref=\"Transaction.Id\"/>.  It is automatically included to\n        /// the <see cref=\"Exception.Message\"/> string.</param>\n        /// <param name=\"innerException\">The <see cref=\"Exception\"/> for\n        /// <see cref=\"Exception.InnerException\"/>.</param>\n        protected InvalidTxException(\n            string message,\n            TxId txid,\n            Exception innerException)\n            : base($\"{txid.ToHex()}: {message}\", innerException)\n        {\n            TxId = txid;\n        }\n\n        /// <summary>\n        /// The <see cref=\"TxId\"/> of the invalid <see cref=\"Transaction\"/>.\n        /// </summary>\n        public TxId TxId { get; }\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Types/Tx/InvalidTxGenesisHashException.cs",
    "content": "using System;\nusing System.Diagnostics.CodeAnalysis;\nusing Libplanet.Types.Blocks;\n\nnamespace Libplanet.Types.Tx\n{\n    /// <summary>\n    /// The exception that is thrown when the <see cref=\"Transaction.GenesisHash\"/>\n    /// is different from the <see cref=\"HashDigest{T}\"/> of\n    /// <see cref=\"BlockChain.Genesis\"/>.\n    /// </summary>\n    public sealed class InvalidTxGenesisHashException : InvalidTxException\n    {\n        /// <summary>\n        /// Initializes a new instance of the\n        /// <see cref=\"InvalidTxGenesisHashException\"/> class.\n        /// </summary>\n        /// <param name=\"message\">The message that describes the error.</param>\n        /// <param name=\"txid\">The invalid <see cref=\"Transaction\"/>'s\n        /// <see cref=\"Transaction.Id\"/>.  It is automatically included to\n        /// the <see cref=\"Exception.Message\"/> string.</param>\n        /// <param name=\"expectedGenesisHash\">The <see cref=\"BlockHash\"/>\n        /// value of <see cref=\"BlockChain.Genesis\"/>.</param>\n        /// <param name=\"improperGenesisHash\">The actual\n        /// <see cref=\"Transaction.GenesisHash\"/>.  This can be <see langword=\"null\"/>.</param>\n        [SuppressMessage(\n            \"Microsoft.StyleCop.CSharp.ReadabilityRules\",\n            \"SA1118\",\n            Justification = \"A long error message should be multiline.\")]\n        public InvalidTxGenesisHashException(\n            string message,\n            TxId txid,\n            BlockHash expectedGenesisHash,\n            BlockHash? improperGenesisHash)\n            : base(\n                $\"{message}\\n\" +\n                $\"Expected genesis hash: {expectedGenesisHash}\\n\" +\n                $\"Improper genesis hash: {improperGenesisHash}\",\n                txid)\n        {\n            ExpectedGenesisHash = expectedGenesisHash;\n            ImproperGenesisHash = improperGenesisHash;\n        }\n\n        /// <summary>\n        /// The <see cref=\"HashDigest{SHA256}\"/> value of\n        /// <see cref=\"BlockChain.Genesis\"/>.\n        /// </summary>\n        public BlockHash ExpectedGenesisHash { get; }\n\n        /// <summary>\n        /// The actual <see cref=\"Transaction.GenesisHash\"/>, which is improper.\n        /// </summary>\n        public BlockHash? ImproperGenesisHash { get; }\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Types/Tx/InvalidTxIdException.cs",
    "content": "using System;\n\nnamespace Libplanet.Types.Tx\n{\n    /// <summary>\n    /// The exception that is thrown when a given <see cref=\"TxId\"/> cannot be\n    /// found.\n    /// </summary>\n    /// <remarks>This does <em>not</em> mean a given value is an invalid\n    /// encoding of <see cref=\"TxId\"/>, but there is no corresponding entry to\n    /// a given <see cref=\"TxId\"/>, which is <em>valid</em>.</remarks>\n    public class InvalidTxIdException : InvalidTxException\n    {\n        /// <summary>\n        /// Creates a new <see cref=\"InvalidTxIdException\"/> object.\n        /// </summary>\n        /// <param name=\"message\">Specifies an <see cref=\"Exception.Message\"/>.\n        /// </param>\n        /// <param name=\"txid\">The invalid <see cref=\"TxId\"/>.\n        /// It is automatically included to the <see cref=\"Exception.Message\"/>\n        /// string.</param>\n        public InvalidTxIdException(string message, TxId txid)\n            : base(message, txid)\n        {\n        }\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Types/Tx/InvalidTxNonceException.cs",
    "content": "using System;\nusing Libplanet.Types.Blocks;\n\nnamespace Libplanet.Types.Tx\n{\n    /// <summary>\n    /// An exception that is thrown when the <see cref=\"Transaction.Nonce\"/>\n    /// of a <see cref=\"Transaction\"/> included in a <see cref=\"Block\"/>\n    /// is inconsistent with the expected nonce for the <see cref=\"Transaction.Signer\"/>\n    /// when appending to a <see cref=\"BlockChain\"/>.\n    /// </summary>\n    public sealed class InvalidTxNonceException : InvalidTxException\n    {\n        /// <summary>\n        /// Initializes a new instance of the\n        /// <see cref=\"InvalidTxNonceException\"/> class.\n        /// </summary>\n        /// <param name=\"message\">The message that describes the error.</param>\n        /// <param name=\"txId\">The invalid <see cref=\"Transaction\"/>'s\n        /// <see cref=\"Transaction.Id\"/>.  It is automatically included to\n        /// the <see cref=\"Exception.Message\"/> string.</param>\n        /// <param name=\"expectedNonce\">The expected <see cref=\"Transaction.Nonce\"/> value\n        /// for the <see cref=\"Transaction\"/>.</param>\n        /// <param name=\"improperNonce\">The actual <see cref=\"Transaction.Nonce\"/>.</param>\n        public InvalidTxNonceException(\n            string message,\n            TxId txId,\n            long expectedNonce,\n            long improperNonce)\n            : base(message, txId)\n        {\n            ExpectedNonce = expectedNonce;\n            ImproperNonce = improperNonce;\n        }\n\n        /// <summary>\n        /// The expected <see cref=\"Transaction.Nonce\"/> value\n        /// for the <see cref=\"Transaction\"/> with <see cref=\"TxId\"/>\n        /// as its <see cref=\"Transaction.Id\"/>.\n        /// </summary>\n        public long ExpectedNonce { get; }\n\n        /// <summary>\n        /// The actual <see cref=\"Transaction.Nonce\"/>, which is improper.\n        /// </summary>\n        public long ImproperNonce { get; }\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Types/Tx/InvalidTxSignatureException.cs",
    "content": "using System;\n\nnamespace Libplanet.Types.Tx\n{\n    /// <summary>\n    /// The exception that is thrown when a <see cref=\"Transaction\"/>'s\n    /// <see cref=\"Transaction.Signature\"/> is invalid.\n    /// </summary>\n    public class InvalidTxSignatureException : InvalidTxException\n    {\n        /// <summary>\n        /// Creates a new <see cref=\"InvalidTxSignatureException\"/> object.\n        /// </summary>\n        /// <param name=\"message\">Specifies an <see cref=\"Exception.Message\"/>.</param>\n        /// <param name=\"txid\">The invalid <see cref=\"Transaction\"/>'s\n        /// <see cref=\"Transaction.Id\"/>.  It is automatically included to\n        /// the <see cref=\"Exception.Message\"/> string.</param>\n        public InvalidTxSignatureException(string message, TxId txid)\n            : base(message, txid)\n        {\n        }\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Types/Tx/Transaction.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Collections.Immutable;\nusing System.Diagnostics.Contracts;\nusing System.Linq;\nusing System.Security.Cryptography;\nusing System.Text.Json.Serialization;\nusing Bencodex;\nusing Bencodex.Types;\nusing Libplanet.Crypto;\nusing Libplanet.Types.Assets;\nusing Libplanet.Types.Blocks;\n\nnamespace Libplanet.Types.Tx\n{\n    /// <summary>\n    /// Consists of <see cref=\"IAction\"/> and is signed to be included in\n    /// a <see cref=\"Blocks.Block\"/> and transmitted over the network.\n    /// </summary>\n    /// <seealso cref=\"ITransaction\"/>\n    /// <seealso cref=\"IAction\"/>\n    public sealed class Transaction : IEquatable<Transaction>, ITransaction\n    {\n        private static readonly Codec Codec = new Codec();\n\n        private TxId? _id;\n        private UnsignedTx _unsignedTx;\n        private byte[] _signature;  // FIXME\n\n        /// <summary>\n        /// Creates a new <see cref=\"Transaction\"/> instance by verifying a\n        /// <paramref name=\"signature\"/> of an <paramref name=\"unsignedTx\"/>.\n        /// </summary>\n        /// <param name=\"unsignedTx\">The <see cref=\"IUnsignedTx\"/> instance to combine with\n        /// <paramref name=\"signature\"/>.</param>\n        /// <param name=\"signature\">The signature to combine with <paramref name=\"unsignedTx\"/>.\n        /// </param>\n        /// <exception cref=\"InvalidTxSignatureException\">Thrown when the given\n        /// <paramref name=\"signature\"/> is not valid for <paramref name=\"unsignedTx\"/>.</exception>\n        public Transaction(IUnsignedTx unsignedTx, ImmutableArray<byte> signature)\n        {\n            _unsignedTx = unsignedTx as UnsignedTx ?? new UnsignedTx(unsignedTx);\n            _signature = signature.IsDefaultOrEmpty ? Array.Empty<byte>() : signature.ToArray();\n\n            if (!_unsignedTx.VerifySignature(signature))\n            {\n                throw new InvalidTxSignatureException(\"The given signature is not valid.\", Id);\n            }\n        }\n\n        /// <summary>\n        /// Creates a new <see cref=\"Transaction\"/> instance by signing an\n        /// <paramref name=\"unsignedTx\"/> with a <paramref name=\"privateKey\"/>.\n        /// </summary>\n        /// <param name=\"unsignedTx\">The <see cref=\"IUnsignedTx\"/> instance to sign.</param>\n        /// <param name=\"privateKey\">The private key to sign <paramref name=\"unsignedTx\"/> with.\n        /// </param>\n        /// <exception cref=\"ArgumentException\">Thrown when the given <paramref name=\"privateKey\"/>\n        /// does not match the public key of <paramref name=\"unsignedTx\"/>.</exception>\n        public Transaction(IUnsignedTx unsignedTx, PrivateKey privateKey)\n        {\n            _unsignedTx = unsignedTx as UnsignedTx ?? new UnsignedTx(unsignedTx);\n            _signature = _unsignedTx.CreateSignature(privateKey).ToArray();\n        }\n\n        /// <summary>\n        /// Creates a new <see cref=\"Transaction\"/> instance by combining an\n        /// <paramref name=\"unsignedTx\"/> with a <paramref name=\"alreadyVerifiedSignature\"/>.\n        /// </summary>\n        /// <remarks>As the parameter name suggests, this constructor assumes that the given\n        /// <paramref name=\"alreadyVerifiedSignature\"/> is valid for the given\n        /// <paramref name=\"unsignedTx\"/>, hence it does not verify the signature again.\n        /// That's why this constructor is marked as internal.</remarks>\n        /// <param name=\"unsignedTx\">The <see cref=\"IUnsignedTx\"/> instance to combine with\n        /// <paramref name=\"alreadyVerifiedSignature\"/>.</param>\n        /// <param name=\"alreadyVerifiedSignature\">The signature to combine with\n        /// <paramref name=\"unsignedTx\"/>.</param>\n        private Transaction(UnsignedTx unsignedTx, ImmutableArray<byte> alreadyVerifiedSignature)\n        {\n            _unsignedTx = unsignedTx;\n            _signature = alreadyVerifiedSignature.IsDefaultOrEmpty\n                ? Array.Empty<byte>()\n                : alreadyVerifiedSignature.ToArray();\n        }\n\n        /// <summary>\n        /// A unique identifier derived from this <see cref=\"Transaction\"/>'s\n        /// content.\n        /// <para>For more characteristics, see <see cref=\"TxId\"/> type.</para>\n        /// </summary>\n        /// <seealso cref=\"TxId\"/>\n        public TxId Id\n        {\n            get\n            {\n                if (!(_id is { } nonNull))\n                {\n                    using var hasher = SHA256.Create();\n                    byte[] payload = Serialize();\n                    _id = nonNull = new TxId(hasher.ComputeHash(payload));\n                }\n\n                return nonNull;\n            }\n        }\n\n        /// <inheritdoc cref=\"ITxSigningMetadata.Nonce\"/>\n        public long Nonce => _unsignedTx.Nonce;\n\n        /// <inheritdoc cref=\"ITxSigningMetadata.Signer\"/>\n        public Address Signer => _unsignedTx.Signer;\n\n        /// <inheritdoc cref=\"ITxInvoice.UpdatedAddresses\"/>\n        public IImmutableSet<Address> UpdatedAddresses => _unsignedTx.UpdatedAddresses;\n\n        /// <summary>\n        /// A digital signature of the content of this\n        /// <see cref=\"Transaction\"/>.  This is signed by the account\n        /// who corresponds to <see cref=\"PublicKey\"/>.\n        /// This cannot be <see langword=\"null\"/>.\n        /// </summary>\n        /// <returns>A new <see cref=\"byte\"/> array of this transaction's\n        /// signature.  Changing a returned array does not affect the internal\n        /// state of this <see cref=\"Transaction\"/> object.</returns>\n        /// <remarks>Although this cannot be <see langword=\"null\"/>, it can be an empty\n        /// array if the transaction is not signed yet.</remarks>\n        public byte[] Signature\n        {\n            get\n            {\n                var sig = new byte[_signature.Length];\n                Array.Copy(_signature, sig, _signature.Length);\n                return sig;\n            }\n\n            private set\n            {\n                _signature = new byte[value.Length];\n                Array.Copy(value, _signature, value.Length);\n            }\n        }\n\n        /// <summary>\n        /// A list of <see cref=\"IAction\"/>s.  These are executed in the order.\n        /// This can be empty, but cannot be <see langword=\"null\"/>.\n        /// </summary>\n        [JsonConverter(typeof(TxActionListJsonConverter))]\n        public TxActionList Actions => _unsignedTx.Actions;\n\n        /// <inheritdoc cref=\"ITxInvoice.MaxGasPrice\"/>\n        public FungibleAssetValue? MaxGasPrice => _unsignedTx.MaxGasPrice;\n\n        /// <inheritdoc cref=\"ITxInvoice.GasLimit\"/>\n        public long? GasLimit => _unsignedTx.GasLimit;\n\n        /// <inheritdoc cref=\"ITxInvoice.Timestamp\"/>\n        public DateTimeOffset Timestamp => _unsignedTx.Timestamp;\n\n        /// <inheritdoc cref=\"ITxSigningMetadata.PublicKey\"/>\n        public PublicKey PublicKey => _unsignedTx.PublicKey;\n\n        /// <inheritdoc cref=\"ITxInvoice.GenesisHash\"/>\n        public BlockHash? GenesisHash => _unsignedTx.GenesisHash;\n\n        /// <summary>\n        /// Decodes a <see cref=\"Transaction\"/>'s\n        /// <a href=\"https://bencodex.org/\">Bencodex</a> representation.\n        /// </summary>\n        /// <param name=\"bytes\">A <a href=\"https://bencodex.org/\">Bencodex</a>\n        /// representation of a <see cref=\"Transaction\"/>.</param>\n        /// <returns>A decoded <see cref=\"Transaction\"/> object.</returns>\n        /// <exception cref=\"InvalidTxSignatureException\">Thrown when its\n        /// <see cref=\"Signature\"/> is invalid or not signed by\n        /// the account who corresponds to <see cref=\"PublicKey\"/>.\n        /// </exception>\n        /// <seealso cref=\"Serialize()\"/>\n        public static Transaction Deserialize(byte[] bytes)\n        {\n            // TODO: Move this method to TxMarshaler.\n            IValue value = new Codec().Decode(bytes);\n            if (!(value is Bencodex.Types.Dictionary dict))\n            {\n                throw new DecodingException(\n                    $\"Expected {typeof(Bencodex.Types.Dictionary)} but \" +\n                    $\"{value.GetType()}\");\n            }\n\n            return TxMarshaler.UnmarshalTransaction(dict);\n        }\n\n        /// <summary>\n        /// A fa&#xe7;ade factory to create a new <see cref=\"Transaction\"/>.\n        /// It automatically fills the following values from:\n        /// <list type=\"table\">\n        /// <listheader>\n        /// <term>Property</term>\n        /// <description>Parameter the filled value derived from</description>\n        /// </listheader>\n        /// <item>\n        /// <term><see cref=\"Signer\"/></term>\n        /// <description><paramref name=\"privateKey\"/></description>\n        /// </item>\n        /// <item>\n        /// <term><see cref=\"PublicKey\"/></term>\n        /// <description><paramref name=\"privateKey\"/></description>\n        /// </item>\n        /// <item>\n        /// <term><see cref=\"UpdatedAddresses\"/></term>\n        /// <description><paramref name=\"actions\"/> and\n        /// <paramref name=\"updatedAddresses\"/></description>\n        /// </item>\n        /// </list>\n        /// <para>Note that the <paramref name=\"privateKey\"/> in itself is not\n        /// included in the created <see cref=\"Transaction\"/>.</para>\n        /// </summary>\n        /// <param name=\"nonce\">The number of previous\n        /// <see cref=\"Transaction\"/>s committed by the <see cref=\"Signer\"/>\n        /// of this transaction.  This goes to the\n        /// <see cref=\"Transaction.Nonce\"/> property.</param>\n        /// <param name=\"privateKey\">A <see cref=\"PrivateKey\"/> of the account\n        /// who creates and signs a new transaction.  This key is used to fill\n        /// the <see cref=\"Signer\"/>, <see cref=\"PublicKey\"/>, and\n        /// <see cref=\"Signature\"/> properties, but this in itself is not\n        /// included in the transaction.</param>\n        /// <param name=\"genesisHash\">A <see cref=\"HashDigest{SHA256}\"/> value\n        /// of the genesis which this <see cref=\"Transaction\"/> is made from.\n        /// This can be <see langword=\"null\"/> iff the transaction is contained\n        /// in the genesis block.\n        /// </param>\n        /// <param name=\"actions\">A list of user-defined custom actions to include.  This can\n        /// be empty, but cannot be <see langword=\"null\"/>.  This goes to\n        /// the <see cref=\"Actions\"/> property.</param>\n        /// <param name=\"maxGasPrice\"> The maximum gas price this transaction can pay fee.</param>\n        /// <param name=\"gasLimit\"> The maximum amount of gas this transaction can consume.\n        /// </param>\n        /// <param name=\"timestamp\">The time this <see cref=\"Transaction\"/>\n        /// is created and signed.  This goes to the <see cref=\"Timestamp\"/>\n        /// property.  If <see langword=\"null\"/> (which is default) is passed this will\n        /// be the current time.</param>\n        /// <returns>A created new <see cref=\"Transaction\"/> signed by\n        /// the given <paramref name=\"privateKey\"/>.</returns>\n        /// <exception cref=\"ArgumentNullException\">Thrown when <see langword=\"null\"/>\n        /// is passed to <paramref name=\"privateKey\"/> or <paramref name=\"actions\"/>.\n        /// </exception>\n        public static Transaction Create(\n            long nonce,\n            PrivateKey privateKey,\n            BlockHash? genesisHash,\n            IEnumerable<IValue> actions,\n            FungibleAssetValue? maxGasPrice = null,\n            long? gasLimit = null,\n            DateTimeOffset? timestamp = null) =>\n            Create(\n                nonce,\n                privateKey,\n                genesisHash,\n                new TxActionList(actions),\n                maxGasPrice,\n                gasLimit,\n                timestamp);\n\n        /// <summary>\n        /// Encodes this <see cref=\"Transaction\"/> into a <see cref=\"byte\"/> array.\n        /// </summary>\n        /// <returns>A <a href=\"https://bencodex.org/\">Bencodex</a>\n        /// representation of this <see cref=\"Transaction\"/>.</returns>\n        public byte[] Serialize() =>\n            Codec.Encode(TxMarshaler.MarshalTransaction(this));\n\n        /// <inheritdoc cref=\"IEquatable{T}.Equals(T)\"/>\n        [Pure]\n        bool IEquatable<ITxInvoice>.Equals(ITxInvoice? other) =>\n            other is { } o && o.Equals(_unsignedTx);\n\n        /// <inheritdoc cref=\"IEquatable{T}.Equals(T)\"/>\n        [Pure]\n        bool IEquatable<ITxSigningMetadata>.Equals(ITxSigningMetadata? other) =>\n            other is { } o && o.Equals(_unsignedTx);\n\n        /// <inheritdoc cref=\"IEquatable{T}.Equals(T)\"/>\n        [Pure]\n        bool IEquatable<IUnsignedTx>.Equals(IUnsignedTx? other) =>\n            other is { } o && o.Equals(_unsignedTx);\n\n        /// <inheritdoc />\n        public bool Equals(Transaction? other) => Id.Equals(other?.Id);\n\n        /// <inheritdoc />\n        public override bool Equals(object? obj) => obj is Transaction other && Equals(other);\n\n        /// <inheritdoc />\n        public override int GetHashCode() => Id.GetHashCode();\n\n        /// <inheritdoc cref=\"Transaction(UnsignedTx, ImmutableArray{byte})\"/>\n        /// <returns>A <see cref=\"Transaction\"/> instance.</returns>\n        internal static Transaction CombineWithoutVerification(\n            UnsignedTx unsignedTx,\n            ImmutableArray<byte> alreadyVerifiedSignature\n        ) =>\n            new Transaction(unsignedTx, alreadyVerifiedSignature: alreadyVerifiedSignature);\n\n        private static Transaction Create(\n            long nonce,\n            PrivateKey privateKey,\n            BlockHash? genesisHash,\n            TxActionList actions,\n            FungibleAssetValue? maxGasPrice = null,\n            long? gasLimit = null,\n            DateTimeOffset? timestamp = null)\n        {\n            if (privateKey is null)\n            {\n                throw new ArgumentNullException(nameof(privateKey));\n            }\n\n            var draftInvoice = new TxInvoice(\n                genesisHash,\n                timestamp ?? DateTimeOffset.UtcNow,\n                actions,\n                maxGasPrice,\n                gasLimit);\n            var signMeta = new TxSigningMetadata(privateKey.PublicKey, nonce);\n            var invoice = new TxInvoice(\n                draftInvoice.GenesisHash,\n                draftInvoice.UpdatedAddresses,\n                draftInvoice.Timestamp,\n                draftInvoice.Actions,\n                draftInvoice.MaxGasPrice,\n                draftInvoice.GasLimit);\n            var unsignedTx = new UnsignedTx(invoice, signMeta);\n            return new Transaction(unsignedTx, privateKey);\n        }\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Types/Tx/TransactionExtensions.cs",
    "content": "using System.Collections.Generic;\nusing System.Collections.Immutable;\nusing System.Linq;\nusing Libplanet.Crypto;\nusing Libplanet.Types.Blocks;\n\nnamespace Libplanet.Types.Tx\n{\n    /// <summary>\n    /// Useful extension methods for <see cref=\"ITransaction\"/>.\n    /// </summary>\n    public static class TransactionExtensions\n    {\n        /// <summary>\n        /// Validates if <paramref name=\"transactions\"/> has valid nonces.\n        /// It assumes all given <paramref name=\"transactions\"/> belong to a block together.\n        /// </summary>\n        /// <param name=\"transactions\">A list of transactions.  Their order does not matter.</param>\n        /// <param name=\"blockIndex\">The index of the block that transactions will belong to.\n        /// It's only used for exception messages.</param>\n        /// <exception cref=\"InvalidTxNonceException\">Thrown when the same tx nonce is used by\n        /// a signer twice or more, or a tx nonce is used without its previous nonce by a signer.\n        /// Note that this validates only a block's intrinsic integrity between its transactions,\n        /// but does not guarantee integrity between blocks.  Such validation needs to be conducted\n        /// by <see cref=\"Blockchain.BlockChain\"/>.</exception>\n        /// <exception cref=\"InvalidTxGenesisHashException\">Thrown when transactions to set have\n        /// inconsistent genesis hashes.</exception>\n        // FIXME: Needs a unit tests.  See also BlockContentTest.Transactions* tests.\n        public static void ValidateTxNonces(\n            this IEnumerable<ITransaction> transactions,\n            long blockIndex)\n        {\n            IEnumerable<IGrouping<Address, ITransaction>> signerTxs =\n                transactions.OrderBy(tx => tx.Nonce).GroupBy(tx => tx.Signer);\n            BlockHash? genesisHash = null;\n            foreach (IGrouping<Address, ITransaction> txs in signerTxs)\n            {\n                long lastNonce = -1L;\n                foreach (ITransaction tx in txs)\n                {\n                    long nonce = tx.Nonce;\n                    if (lastNonce >= 0 && lastNonce + 1 != nonce)\n                    {\n                        Address s = tx.Signer;\n                        string msg = nonce <= lastNonce\n                            ? $\"The signer {s}'s nonce {nonce} was already consumed before.\"\n                            : $\"The signer {s}'s nonce {lastNonce} has to be added first.\";\n                        throw new InvalidTxNonceException(msg, tx.Id, lastNonce + 1, tx.Nonce);\n                    }\n\n                    if (genesisHash is { } g && !tx.GenesisHash.Equals(g))\n                    {\n                        throw new InvalidTxGenesisHashException(\n                            $\"Transactions in the block #{blockIndex} are inconsistent.\",\n                            tx.Id,\n                            g,\n                            tx.GenesisHash\n                        );\n                    }\n\n                    lastNonce = nonce;\n                    genesisHash = tx.GenesisHash;\n                }\n            }\n        }\n\n        /// <inheritdoc cref=\"UnsignedTx(ITxInvoice, ITxSigningMetadata)\" />\n        /// <returns>An <see cref=\"UnsignedTx\"/> instance.</returns>\n        public static UnsignedTx Combine(\n            this ITxInvoice invoice,\n            ITxSigningMetadata signingMetadata\n        ) =>\n            new UnsignedTx(invoice, signingMetadata);\n\n        /// <summary>\n        /// Creates a new <see cref=\"Transaction\"/> instance by signing the given\n        /// <paramref name=\"invoice\"/> with the given <paramref name=\"privateKey\"/>.\n        /// </summary>\n        /// <param name=\"invoice\">The <see cref=\"ITxInvoice\"/> to sign.</param>\n        /// <param name=\"privateKey\">The <see cref=\"PrivateKey\"/> to sign the transaction.</param>\n        /// <param name=\"nonce\">The nonce to use for the transaction.</param>\n        /// <returns>A <see cref=\"Transaction\"/> instance.</returns>\n        public static Transaction Sign(\n            this ITxInvoice invoice,\n            PrivateKey privateKey,\n            long nonce)\n        =>\n            invoice.Combine(new TxSigningMetadata(privateKey.PublicKey, nonce)).Sign(privateKey);\n\n        /// <inheritdoc cref=\"Transaction(IUnsignedTx, PrivateKey)\" />\n        /// <returns>A <see cref=\"Transaction\"/> instance.</returns>\n        public static Transaction Sign(this IUnsignedTx unsignedTx, PrivateKey privateKey)\n        =>\n            new Transaction(unsignedTx, privateKey);\n\n        /// <inheritdoc cref=\"Transaction(IUnsignedTx, ImmutableArray{byte})\" />\n        /// <returns>A <see cref=\"Transaction\"/> instance.</returns>\n        public static Transaction Verify(\n            this IUnsignedTx unsignedTx,\n            ImmutableArray<byte> signature) =>\n            new Transaction(unsignedTx, signature: signature);\n\n        /// <inheritdoc cref=\"Transaction.CombineWithoutVerification\"/>\n        internal static Transaction CombineWithoutVerification(\n            this UnsignedTx unsignedTx,\n            ImmutableArray<byte> alreadyVerifiedSignature) =>\n            Transaction.CombineWithoutVerification(unsignedTx, alreadyVerifiedSignature);\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Types/Tx/TxActionList.cs",
    "content": "using System;\nusing System.Collections;\nusing System.Collections.Generic;\nusing System.Collections.Immutable;\nusing System.Diagnostics.CodeAnalysis;\nusing System.Diagnostics.Contracts;\nusing System.Linq;\nusing System.Text.Json;\nusing System.Text.Json.Serialization;\nusing Bencodex;\nusing Bencodex.Json;\nusing Bencodex.Types;\n\nnamespace Libplanet.Types.Tx\n{\n    /// <summary>\n    /// A list of <see cref=\"IAction\"/>s to be executed in a transaction.\n    /// </summary>\n    [JsonConverter(typeof(TxActionListJsonConverter))]\n    public sealed class TxActionList\n        : IReadOnlyList<IValue>, IEquatable<TxActionList>, IBencodable\n    {\n        /// <summary>\n        /// An empty <see cref=\"TxActionList\"/>.\n        /// </summary>\n        public static readonly TxActionList Empty =\n            new TxActionList(List.Empty);\n\n        private IValue _bencoded;\n\n        /// <summary>\n        /// Creates a new <see cref=\"TxActionList\"/> instance with given\n        /// <paramref name=\"actions\"/>.\n        /// </summary>\n        /// <param name=\"actions\">The list of <see cref=\"IAction\"/>s to be executed in a\n        /// transaction.</param>\n        public TxActionList(IEnumerable<IValue> actions)\n            : this(new List(actions.Select(customAction => customAction)))\n        {\n        }\n\n        public TxActionList(IValue bencoded)\n            : this(bencoded is List list\n                ? list\n                : throw new ArgumentException(\n                    $\"Given value must be a {nameof(List)}: {bencoded.GetType()}\",\n                    nameof(bencoded)))\n        {\n        }\n\n        private TxActionList(List list)\n        {\n            _bencoded = list;\n        }\n\n        /// <summary>\n        /// The list of <see cref=\"IAction\"/>s to be executed in a\n        /// transaction.\n        /// </summary>\n        [Pure]\n        public IImmutableList<IValue> Actions => ((List)_bencoded).ToImmutableList();\n\n        /// <inheritdoc cref=\"IReadOnlyCollection{T}.Count\"/>\n        [Pure]\n        public int Count => Actions.Count;\n\n        /// <inheritdoc cref=\"IBencodable.Bencoded\"/>\n        public IValue Bencoded => _bencoded;\n\n        /// <inheritdoc cref=\"IReadOnlyList{T}.this\"/>\n        /// <exception cref=\"ArgumentOutOfRangeException\">Thrown when the given\n        /// <paramref name=\"index\"/> is less than zero.</exception>\n        /// <exception cref=\"IndexOutOfRangeException\">Thrown when the given\n        /// <paramref name=\"index\"/> is greater than or equal to <see cref=\"Count\"/>.</exception>\n        [Pure]\n        public IValue this[int index]\n        {\n            get\n            {\n                if (index < 0)\n                {\n                    throw new ArgumentOutOfRangeException(\n                        nameof(index),\n                        $\"Given {nameof(index)} must be non-negative: {index}\");\n                }\n                else if (index >= Count)\n                {\n                    throw new IndexOutOfRangeException(\n                        $\"The given index {index} is greater than the number of actions \" +\n                        $\"in this {nameof(TxActionList)} instance ({Count}).\");\n                }\n\n                return Actions[index];\n            }\n        }\n\n        /// <inheritdoc cref=\"IEnumerable{T}.GetEnumerator()\"/>\n        [Pure]\n        public IEnumerator<IValue> GetEnumerator() => Actions.GetEnumerator();\n\n        /// <inheritdoc cref=\"IEnumerable.GetEnumerator()\"/>\n        [Pure]\n        IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();\n\n        /// <inheritdoc cref=\"IEquatable{T}.Equals(T)\"/>\n        [Pure]\n        public bool Equals(TxActionList? other) =>\n            other is TxActionList txActionList && Bencoded.Equals(txActionList.Bencoded);\n\n        /// <inheritdoc cref=\"object.Equals(object?)\"/>\n        [Pure]\n        public override bool Equals(object? obj) => obj is TxActionList other && Equals(other);\n\n        /// <inheritdoc cref=\"object.GetHashCode()\"/>\n        [Pure]\n        public override int GetHashCode() => Bencoded.GetHashCode();\n    }\n\n    [SuppressMessage(\n        \"StyleCop.CSharp.MaintainabilityRules\",\n        \"SA1402:FileMayOnlyContainASingleClass\",\n        Justification = \"It's okay to have non-public classes together in a single file.\"\n    )]\n    internal sealed class TxActionListJsonConverter : JsonConverter<TxActionList>\n    {\n        private static readonly BencodexJsonConverter BencodexJsonConverter\n            = new BencodexJsonConverter();\n\n        public override TxActionList? Read(\n            ref Utf8JsonReader reader,\n            Type typeToConvert,\n            JsonSerializerOptions options)\n        {\n            IValue? serialized = BencodexJsonConverter.Read(ref reader, typeToConvert, options);\n            if (serialized is Bencodex.Types.List list)\n            {\n                return new TxActionList((IValue)list);\n            }\n\n            throw new JsonException(\"Serialized actions must be a Bencodex list.\");\n        }\n\n        public override void Write(\n            Utf8JsonWriter writer,\n            TxActionList value,\n            JsonSerializerOptions options)\n        {\n            BencodexJsonConverter.Write(writer, value.Bencoded, options);\n        }\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Types/Tx/TxExecution.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Diagnostics.Contracts;\nusing System.Linq;\nusing System.Security.Cryptography;\nusing Bencodex.Types;\nusing Libplanet.Common;\nusing Libplanet.Types.Blocks;\n\nnamespace Libplanet.Types.Tx\n{\n    /// <summary>\n    /// Summarizes an execution result of a <see cref=\"Transaction\"/>.\n    /// <para>Note that <see cref=\"Transaction\"/>s cannot be executed without belonging to\n    /// a <see cref=\"Block\"/>, and even if it's the same <see cref=\"Transaction\"/> its\n    /// result can vary depending on <see cref=\"Block\"/> that it is executed within.</para>\n    /// </summary>\n    public sealed class TxExecution\n    {\n        internal static readonly Text FailKey = new Text(\"fail\");\n\n        internal static readonly Text InputStateKey = new Text(\"i\");\n\n        internal static readonly Text OutputStateKey = new Text(\"o\");\n\n        internal static readonly Text ExceptionNamesKey = new Text(\"e\");\n\n        public TxExecution(\n            BlockHash blockHash,\n            TxId txId,\n            bool fail,\n            HashDigest<SHA256> inputState,\n            HashDigest<SHA256> outputState,\n            List<Exception?> exceptions)\n            : this(\n                blockHash,\n                txId,\n                fail,\n                inputState,\n                outputState,\n                exceptions\n                    .Select(exception => exception is { } e\n                        ? e.GetType().FullName\n                        : null)\n                    .ToList())\n        {\n        }\n\n        public TxExecution(\n            BlockHash blockHash,\n            TxId txId,\n            bool fail,\n            HashDigest<SHA256> inputState,\n            HashDigest<SHA256> outputState,\n            List<string?> exceptionNames)\n        {\n            BlockHash = blockHash;\n            TxId = txId;\n            Fail = fail;\n            InputState = inputState;\n            OutputState = outputState;\n            ExceptionNames = exceptionNames;\n        }\n\n#pragma warning disable SA1118 // The parameter spans multiple lines.\n        public TxExecution(\n            BlockHash blockHash,\n            TxId txId,\n            IValue bencoded)\n            : this(\n                blockHash,\n                txId,\n                bencoded is Dictionary dict\n                    ? dict\n                    : throw new ArgumentException(\n                        $\"Given {nameof(bencoded)} must be of type \" +\n                        $\"{typeof(Bencodex.Types.Dictionary)}: {bencoded.GetType()}\",\n                        nameof(bencoded)))\n#pragma warning restore SA1118\n        {\n        }\n\n        private TxExecution(\n            BlockHash blockHash,\n            TxId txId,\n            Dictionary bencoded)\n        {\n            BlockHash = blockHash;\n            TxId = txId;\n\n            if (!bencoded.TryGetValue(FailKey, out IValue fail))\n            {\n                throw new ArgumentException(\n                    $\"Given {nameof(bencoded)} is missing fail value\",\n                    nameof(bencoded));\n            }\n            else if (!(fail is Bencodex.Types.Boolean failBoolean))\n            {\n                throw new ArgumentException(\n                    $\"Given {nameof(bencoded)} has an invalid fail value: {fail}\",\n                    nameof(bencoded));\n            }\n            else\n            {\n                Fail = failBoolean.Value;\n            }\n\n            if (bencoded.TryGetValue(InputStateKey, out IValue input) &&\n                input is Binary inputBinary)\n            {\n                InputState = new HashDigest<SHA256>(inputBinary.ByteArray);\n            }\n            else\n            {\n                InputState = null;\n            }\n\n            if (bencoded.TryGetValue(OutputStateKey, out IValue output) &&\n                output is Binary outputBinary)\n            {\n                OutputState = new HashDigest<SHA256>(outputBinary.ByteArray);\n            }\n            else\n            {\n                OutputState = null;\n            }\n\n            if (bencoded.TryGetValue(ExceptionNamesKey, out IValue exceptions) &&\n                exceptions is List exceptionsList)\n            {\n                ExceptionNames = exceptionsList\n                    .Select(value => value is Text t\n                        ? (string?)t.Value\n                        : value is Null\n                            ? (string?)null\n                            : throw new ArgumentException(\n                                $\"Expected either {nameof(Text)} or {nameof(Null)} \" +\n                                $\"but got {value.GetType()}\"))\n                    .ToList();\n            }\n            else\n            {\n                ExceptionNames = null;\n            }\n        }\n\n        /// <summary>\n        /// The <see cref=\"Block.Hash\"/> of the <see cref=\"Block\"/> that\n        /// the <see cref=\"Transaction\"/> is executed within.\n        /// </summary>\n        [Pure]\n        public BlockHash BlockHash { get; }\n\n        /// <summary>\n        /// The executed <see cref=\"Transaction\"/>'s <see cref=\"Transaction.Id\"/>.\n        /// </summary>\n        [Pure]\n        public TxId TxId { get; }\n\n        /// <summary>\n        /// Whether <em>every</em> action in the <see cref=\"Transaction\"/> was\n        /// executed without throwing and <see cref=\"Exception\"/>.\n        /// </summary>\n        public bool Fail { get; }\n\n        /// <summary>\n        /// The state before the execution of the <see cref=\"Transaction\"/>.\n        /// </summary>\n        /// <remarks>\n        /// This is marked <see langword=\"null\"/>-able for backward compatibility.\n        /// </remarks>\n        public HashDigest<SHA256>? InputState { get; }\n\n        /// <summary>\n        /// The state after the execution of the <see cref=\"Transaction\"/>.\n        /// </summary>\n        /// <remarks>\n        /// This is marked <see langword=\"null\"/>-able for backward compatibility.\n        /// </remarks>\n        public HashDigest<SHA256>? OutputState { get; }\n\n        /// <summary>\n        /// The list of <see cref=\"Exception\"/> names thrown by actions\n        /// in the <see cref=\"Transaction\"/>.  A value of <see langword=\"null\"/>\n        /// as an element represents no <see cref=\"Exception\"/> being thrown for\n        /// the action of the same index.\n        /// </summary>\n        /// <remarks>\n        /// This is marked <see langword=\"null\"/>-able for backward compatibility.\n        /// </remarks>\n        public List<string?>? ExceptionNames { get; }\n\n        public IValue ToBencodex()\n        {\n            Dictionary dict = Dictionary.Empty\n                .Add(FailKey, Fail);\n\n            if (InputState is { } inputState)\n            {\n                dict = dict.Add(InputStateKey, inputState.Bencoded);\n            }\n\n            if (OutputState is { } outputState)\n            {\n                dict = dict.Add(OutputStateKey, outputState.Bencoded);\n            }\n\n            if (ExceptionNames is { } exceptionNames)\n            {\n                dict = dict.Add(\n                    ExceptionNamesKey,\n                    new List(exceptionNames\n                        .Select(exceptionName => exceptionName is { } name\n                            ? (IValue)new Text(exceptionName)\n                            : (IValue)Null.Value)));\n            }\n\n            return dict;\n        }\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Types/Tx/TxId.cs",
    "content": "using System;\nusing System.Collections.Immutable;\nusing System.Diagnostics.CodeAnalysis;\nusing System.Diagnostics.Contracts;\nusing System.Linq;\nusing System.Text.Json;\nusing System.Text.Json.Serialization;\nusing Bencodex;\nusing Bencodex.Types;\nusing Libplanet.Common;\n\nnamespace Libplanet.Types.Tx\n{\n    /// <summary>\n    /// <see cref=\"TxId\"/>, abbreviation of transaction identifier,\n    /// is a SHA-256 digest derived from a <see cref=\"Transaction\"/>'s\n    /// content.\n    /// <para>As it is a SHA-256 digest, it consists of 32 <see cref=\"byte\"/>s,\n    /// and 64 characters in hexadecimal.\n    /// (See also <see cref=\"Size\"/> constant.)</para>\n    /// </summary>\n    /// <seealso cref=\"Transaction.Id\"/>\n    [JsonConverter(typeof(TxIdJsonConverter))]\n    public readonly struct TxId\n        : IEquatable<TxId>, IComparable<TxId>, IComparable, IBencodable\n    {\n        /// <summary>\n        /// The <see cref=\"byte\"/>s size that each <see cref=\"TxId\"/> takes.\n        /// <para>As a txid is a SHA-256 digest, it is 32 <see cref=\"byte\"/>s.\n        /// </para>\n        /// </summary>\n        public const int Size = 32;\n\n        private static readonly Codec _codec = new Codec();\n\n        private static readonly ImmutableArray<byte> _defaultByteArray =\n            ImmutableArray.Create<byte>(new byte[Size]);\n\n        private readonly ImmutableArray<byte> _byteArray;\n\n        /// <summary>\n        /// Converts an immutable <see cref=\"byte\"/> array into a <see cref=\"TxId\"/>.\n        /// </summary>\n        /// <param name=\"txid\">An immutable <see cref=\"byte\"/> array that encodes\n        /// a <see cref=\"TxId\"/>.  It must not be <see langword=\"null\"/>, and its\n        /// <see cref=\"ImmutableArray{T}.Length\"/> must be the same to <see cref=\"Size\"/>.</param>\n        /// <exception cref=\"ArgumentOutOfRangeException\">Thrown when the given\n        /// <paramref name=\"txid\"/>'s <see cref=\"Array.Length\"/> is not the same to the required\n        /// <see cref=\"Size\"/>.</exception>\n        public TxId(in ImmutableArray<byte> txid)\n        {\n            if (txid.Length != Size)\n            {\n                throw new ArgumentOutOfRangeException(\n                    nameof(txid), $\"Given {nameof(txid)} must be {Size} bytes.\");\n            }\n\n            _byteArray = txid;\n        }\n\n        /// <summary>\n        /// Converts a mutable <see cref=\"byte\"/> array into a <see cref=\"TxId\"/>.\n        /// </summary>\n        /// <param name=\"txid\">A mutable <see cref=\"byte\"/> array that encodes\n        /// a <see cref=\"TxId\"/>.  It must not be <see langword=\"null\"/>,\n        /// and its <see cref=\"Array.Length\"/> must be the same to\n        /// <see cref=\"Size\"/>.</param>\n        /// <exception cref=\"ArgumentOutOfRangeException\">Thrown when the given\n        /// <paramref name=\"txid\"/>'s <see cref=\"Array.Length\"/> is not\n        /// the same to the required <see cref=\"Size\"/>.</exception>\n        public TxId(byte[] txid)\n            : this(txid.ToImmutableArray())\n        {\n        }\n\n        /// <summary>\n        /// Creates a <see cref=\"TxId\"/> instance from given <paramref name=\"bencoded\"/>.\n        /// </summary>\n        /// <param name=\"bencoded\">A Bencodex <see cref=\"Binary\"/> of 32 <see cref=\"byte\"/>s which\n        /// represents an <see cref=\"TxId\"/>.\n        /// </param>\n        /// <exception cref=\"ArgumentException\">Thrown when given <paramref name=\"bencoded\"/>\n        /// is not of type <see cref=\"Binary\"/>.</exception>\n        /// <seealso cref=\"TxId(in ImmutableArray{byte})\"/>\n        public TxId(IValue bencoded)\n            : this(bencoded is Binary binary\n                ? binary\n                : throw new ArgumentException(\n                    $\"Given {nameof(bencoded)} must be of type \" +\n                    $\"{typeof(Binary)}: {bencoded.GetType()}\",\n                    nameof(bencoded)))\n        {\n        }\n\n        private TxId(Binary bencoded)\n            : this(bencoded.ByteArray)\n        {\n        }\n\n        /// <summary>\n        /// A bare immutable <see cref=\"byte\"/> array of\n        /// this <see cref=\"TxId\"/>.\n        /// </summary>\n        /// <remarks>It is immutable.  For a mutable array, use\n        /// <see cref=\"ToByteArray()\"/> method instead.</remarks>\n        /// <seealso cref=\"ToByteArray()\"/>\n        public ImmutableArray<byte> ByteArray => _byteArray.IsDefault\n            ? _defaultByteArray\n            : _byteArray;\n\n        /// <inheritdoc/>\n        public IValue Bencoded => new Binary(ByteArray);\n\n        public static bool operator ==(TxId left, TxId right) => left.Equals(right);\n\n        public static bool operator !=(TxId left, TxId right) => !left.Equals(right);\n\n        /// <summary>\n        /// Creates a <see cref=\"TxId\"/> value from a <paramref name=\"hex\"/> string.\n        /// </summary>\n        /// <param name=\"hex\">A hexadecimal string which encodes a <see cref=\"TxId\"/>.\n        /// This has to contain 64 hexadecimal digits and must not be <see langword=\"null\"/>\n        /// This is usually made by <see cref=\"ToHex()\"/> method.</param>\n        /// <returns>A corresponding <see cref=\"TxId\"/> value.</returns>\n        /// <exception cref=\"ArgumentOutOfRangeException\">Thrown when the given\n        /// <paramref name=\"hex\"/> is shorter or longer than 64 characters.</exception>\n        /// <exception cref=\"FormatException\">Thrown when the given <paramref name=\"hex\"/> string is\n        /// not a valid hexadecimal string.</exception>\n        /// <seealso cref=\"ToHex()\"/>\n        public static TxId FromHex(string hex)\n        {\n            ImmutableArray<byte> bytes = ByteUtil.ParseHexToImmutable(hex);\n            try\n            {\n                return new TxId(bytes);\n            }\n            catch (ArgumentOutOfRangeException)\n            {\n                throw new ArgumentOutOfRangeException(\n                    nameof(hex),\n                    $\"Expected {Size * 2} characters, but {hex.Length} characters given.\");\n            }\n        }\n\n        public bool Equals(TxId other) => ByteArray.SequenceEqual(other.ByteArray);\n\n        public override bool Equals(object? obj) => obj is TxId other && Equals(other);\n\n        public override int GetHashCode() => ByteUtil.CalculateHashCode(ToByteArray());\n\n        /// <summary>\n        /// Gets a bare mutable <see cref=\"byte\"/> array of\n        /// this <see cref=\"TxId\"/>.\n        /// </summary>\n        /// <returns>A new mutable <see cref=\"byte\"/> array of\n        /// this <see cref=\"TxId\"/>.\n        /// Since a returned array is created every time the method is called,\n        /// any mutations on that array does not affect to\n        /// the <see cref=\"TxId\"/> object.\n        /// </returns>\n        /// <seealso cref=\"ByteArray\"/>\n        [Pure]\n        public byte[] ToByteArray() => ByteArray.ToArray();\n\n        /// <summary>\n        /// Gets a hexadecimal form of a <see cref=\"TxId\"/>.\n        /// </summary>\n        /// <returns>64 hexadecimal characters.</returns>\n        [Pure]\n        public string ToHex() => ByteUtil.Hex(ToByteArray());\n\n        /// <summary>\n        /// Gets a <see cref=\"TxId\"/>'s representative string.\n        /// </summary>\n        /// <returns>A string which represents this <see cref=\"TxId\"/>.\n        /// </returns>\n        [Pure]\n        public override string ToString() => ToHex();\n\n        /// <inheritdoc cref=\"IComparable{T}.CompareTo(T)\"/>\n        public int CompareTo(TxId other)\n        {\n            for (int i = 0; i < Size; ++i)\n            {\n                int cmp = ByteArray[i].CompareTo(other.ByteArray[i]);\n                if (cmp != 0)\n                {\n                    return cmp;\n                }\n            }\n\n            return 0;\n        }\n\n        /// <inheritdoc cref=\"IComparable.CompareTo(object)\"/>\n        public int CompareTo(object? obj) => obj is TxId other\n            ? this.CompareTo(other)\n            : throw new ArgumentException(\n                $\"Argument {nameof(obj)} is not a ${nameof(TxId)}.\", nameof(obj));\n    }\n\n    [SuppressMessage(\n        \"StyleCop.CSharp.MaintainabilityRules\",\n        \"SA1402:FileMayOnlyContainASingleClass\",\n        Justification = \"It's okay to have non-public classes together in a single file.\"\n    )]\n    internal class TxIdJsonConverter : JsonConverter<TxId>\n    {\n        public override TxId Read(\n            ref Utf8JsonReader reader,\n            Type typeToConvert,\n            JsonSerializerOptions options\n        )\n        {\n            string hex = reader.GetString() ?? throw new JsonException(\"Expected a string.\");\n            try\n            {\n                return TxId.FromHex(hex);\n            }\n            catch (ArgumentException e)\n            {\n                throw new JsonException(e.Message);\n            }\n        }\n\n        public override void Write(\n            Utf8JsonWriter writer,\n            TxId value,\n            JsonSerializerOptions options\n        ) =>\n            writer.WriteStringValue(value.ToHex());\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Types/Tx/TxInvoice.cs",
    "content": "using System;\nusing System.Collections.Immutable;\nusing System.Diagnostics.Contracts;\nusing System.Linq;\nusing System.Text.Json.Serialization;\nusing Libplanet.Crypto;\nusing Libplanet.Types.Assets;\nusing Libplanet.Types.Blocks;\n\nnamespace Libplanet.Types.Tx\n{\n    /// <summary>\n    /// A concrete implementation of <see cref=\"ITxInvoice\"/>.\n    /// </summary>\n    /// <seealso cref=\"ITxInvoice\"/>\n    /// <seealso cref=\"TxSigningMetadata\"/>\n    /// <seealso cref=\"UnsignedTx\"/>\n    /// <seealso cref=\"Transaction\"/>\n    public sealed class TxInvoice : ITxInvoice, IEquatable<TxInvoice>\n    {\n        /// <summary>\n        /// Creates a new <see cref=\"TxInvoice\"/> instance by filling data for its fields.\n        /// </summary>\n        /// <param name=\"genesisHash\">The value for <see cref=\"GenesisHash\"/>.</param>\n        /// <param name=\"timestamp\">The value for <see cref=\"Timestamp\"/>.</param>\n        /// <param name=\"actions\">The value of <see cref=\"Actions\"/>.</param>\n        /// <param name=\"maxGasPrice\">The value of <see cref=\"MaxGasPrice\"/>.</param>\n        /// <param name=\"gasLimit\">The value of <see langword=\"Gas\"/> limit.</param>\n        /// <exception cref=\"ArgumentNullException\">Thrown when <paramref name=\"updatedAddresses\"/>\n        /// or <paramref name=\"actions\"/> is <see langword=\"null\"/>.</exception>\n        /// <exception cref=\"ArgumentException\">Thrown when <see langword=\"null\"/>-ness of\n        /// <paramref name=\"maxGasPrice\"/> and <paramref name=\"gasLimit\"/> are not the same.\n        /// </exception>\n        public TxInvoice(\n            BlockHash? genesisHash,\n            DateTimeOffset timestamp,\n            TxActionList actions,\n            FungibleAssetValue? maxGasPrice,\n            long? gasLimit)\n            : this(\n                genesisHash,\n                ImmutableHashSet<Address>.Empty,\n                timestamp,\n                actions,\n                maxGasPrice,\n                gasLimit)\n        {\n        }\n\n        /// <summary>\n        /// Creates a new <see cref=\"TxInvoice\"/> instance by filling data for its fields.  There\n        /// are some default values for some fields.\n        /// </summary>\n        /// <param name=\"genesisHash\">The value for <see cref=\"GenesisHash\"/>.</param>\n        /// <param name=\"timestamp\">The value for <see cref=\"Timestamp\"/>.\n        /// Time of creation by default.</param>\n        /// <param name=\"actions\">The value of <see cref=\"Actions\"/>.\n        /// <see cref=\"TxActionList\"/> by default.</param>\n        /// <param name=\"maxGasPrice\">The value of <see cref=\"MaxGasPrice\"/>.</param>\n        /// <param name=\"gasLimit\">The value of <see langword=\"Gas\"/> limit.</param>\n        public TxInvoice(\n            BlockHash? genesisHash = null,\n            DateTimeOffset? timestamp = null,\n            TxActionList? actions = null,\n            FungibleAssetValue? maxGasPrice = null,\n            long? gasLimit = null)\n            : this(\n                genesisHash,\n                timestamp ?? DateTimeOffset.UtcNow,\n                actions ?? TxActionList.Empty,\n                maxGasPrice,\n                gasLimit)\n        {\n        }\n\n        /// <summary>\n        /// Creates a new <see cref=\"TxInvoice\"/> instance by copying everything from another\n        /// <paramref name=\"invoice\"/>.\n        /// </summary>\n        /// <param name=\"invoice\">Another invoice to copy data from.</param>\n        public TxInvoice(ITxInvoice invoice)\n            : this(\n                  genesisHash: invoice.GenesisHash,\n                  updatedAddresses: invoice.UpdatedAddresses,\n                  timestamp: invoice.Timestamp,\n                  actions: invoice.Actions,\n                  maxGasPrice: invoice.MaxGasPrice,\n                  gasLimit: invoice.GasLimit)\n        {\n        }\n\n        /// <summary>\n        /// Creates a new <see cref=\"TxInvoice\"/> instance by filling data for its fields.\n        /// </summary>\n        /// <param name=\"genesisHash\">The value for <see cref=\"GenesisHash\"/>.</param>\n        /// <param name=\"updatedAddresses\">The value for <see cref=\"UpdatedAddresses\"/>.</param>\n        /// <param name=\"timestamp\">The value for <see cref=\"Timestamp\"/>.</param>\n        /// <param name=\"actions\">The value of <see cref=\"Actions\"/>.</param>\n        /// <param name=\"maxGasPrice\">The value of <see cref=\"MaxGasPrice\"/>.</param>\n        /// <param name=\"gasLimit\">The value of <see langword=\"Gas\"/> limit.</param>\n        /// <exception cref=\"ArgumentNullException\">Thrown when <paramref name=\"updatedAddresses\"/>\n        /// or <paramref name=\"actions\"/> is <see langword=\"null\"/>.</exception>\n        /// <exception cref=\"ArgumentException\">Thrown when <see langword=\"null\"/>-ness of\n        /// <paramref name=\"maxGasPrice\"/> and <paramref name=\"gasLimit\"/> are not the same.\n        /// </exception>\n        internal TxInvoice(\n            BlockHash? genesisHash,\n            IImmutableSet<Address> updatedAddresses,\n            DateTimeOffset timestamp,\n            TxActionList actions,\n            FungibleAssetValue? maxGasPrice,\n            long? gasLimit)\n        {\n            if (updatedAddresses is null)\n            {\n                throw new ArgumentNullException(nameof(updatedAddresses));\n            }\n\n            switch (maxGasPrice, gasLimit)\n            {\n                case (null, null):\n                    break;\n                case (null, { }):\n                case ({ }, null):\n                    throw new ArgumentException(\n                        $\"Either {nameof(maxGasPrice)} (null: {maxGasPrice is null}) and \" +\n                        $\"{nameof(gasLimit)} (null: {gasLimit is null}) must be both null \" +\n                        $\"or both non-null.\");\n                case ({ } mgp, { } gl):\n                    if (mgp.Sign < 0 || gl < 0)\n                    {\n                        throw new ArgumentException(\n                            $\"Both {nameof(maxGasPrice)} ({mgp}) and {nameof(gasLimit)} ({gl}) \" +\n                            $\"must be non-negative.\");\n                    }\n\n                    break;\n            }\n\n            GenesisHash = genesisHash;\n            UpdatedAddresses = updatedAddresses is AddressSet set\n                ? set\n                : new AddressSet(updatedAddresses);\n            Timestamp = timestamp;\n            Actions = actions ?? throw new ArgumentNullException(nameof(actions));\n            MaxGasPrice = maxGasPrice;\n            GasLimit = gasLimit;\n        }\n\n        /// <inheritdoc cref=\"ITxInvoice.GenesisHash\" />\n        public BlockHash? GenesisHash { get; }\n\n        /// <inheritdoc cref=\"ITxInvoice.UpdatedAddresses\" />\n        public IImmutableSet<Address> UpdatedAddresses { get; }\n\n        /// <inheritdoc cref=\"ITxInvoice.Timestamp\" />\n        public DateTimeOffset Timestamp { get; }\n\n        /// <inheritdoc cref=\"ITxInvoice.Actions\" />\n        [JsonConverter(typeof(TxActionListJsonConverter))]\n        public TxActionList Actions { get; }\n\n        /// <inheritdoc cref=\"ITxInvoice.MaxGasPrice\" />\n        public FungibleAssetValue? MaxGasPrice { get; }\n\n        /// <inheritdoc cref=\"ITxInvoice.GasLimit\" />\n        public long? GasLimit { get; }\n\n        /// <inheritdoc cref=\"IEquatable{T}.Equals(T)\"/>\n        [Pure]\n        bool IEquatable<ITxInvoice>.Equals(ITxInvoice? other) =>\n            other is { } o &&\n            (o.GenesisHash is { } otherGenesisHash\n                ? otherGenesisHash.Equals(GenesisHash)\n                : GenesisHash is null) &&\n            o.UpdatedAddresses.SetEquals(UpdatedAddresses) &&\n            o.Timestamp.Equals(Timestamp) &&\n            o.Actions.Equals(Actions) &&\n            o.MaxGasPrice.Equals(MaxGasPrice) &&\n            o.GasLimit.Equals(GasLimit);\n\n        /// <inheritdoc cref=\"IEquatable{T}.Equals(T)\"/>\n        [Pure]\n        public bool Equals(TxInvoice? other) =>\n            other is ITxInvoice otherInvoice && otherInvoice.Equals(this);\n\n        /// <inheritdoc cref=\"object.Equals(object?)\"/>\n        [Pure]\n        public override bool Equals(object? obj) =>\n            obj is ITxInvoice other && ((ITxInvoice)this).Equals(other);\n\n        /// <inheritdoc cref=\"object.GetHashCode()\"/>\n        [Pure]\n        public override int GetHashCode() =>\n            HashCode.Combine(\n                GenesisHash,\n                UpdatedAddresses,\n                Timestamp,\n                Actions,\n                MaxGasPrice,\n                GasLimit\n            );\n\n        /// <inheritdoc cref=\"object.ToString()\"/>\n        [Pure]\n        public override string ToString()\n        {\n            string actions = Actions.ToString() ?? string.Empty;\n            string indentedActions = actions.Replace(\"\\n\", \"\\n  \");\n            return nameof(TxInvoice) + \" {\\n\" +\n                $\"  {nameof(UpdatedAddresses)} = ({UpdatedAddresses.Count})\" +\n                (UpdatedAddresses.Any()\n                    ? $\"\\n    {string.Join(\"\\n    \", UpdatedAddresses)},\\n\"\n                    : \",\\n\") +\n                $\"  {nameof(Timestamp)} = {Timestamp},\\n\" +\n                $\"  {nameof(GenesisHash)} = {GenesisHash?.ToString() ?? \"(null)\"},\\n\" +\n                $\"  {nameof(Actions)} = {indentedActions},\\n\" +\n                \"}\";\n        }\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Types/Tx/TxMarshaler.cs",
    "content": "using System;\nusing System.Collections.Immutable;\nusing System.Diagnostics.Contracts;\nusing System.Globalization;\nusing System.Linq;\nusing System.Runtime.CompilerServices;\nusing Bencodex;\nusing Bencodex.Types;\nusing Libplanet.Crypto;\nusing Libplanet.Types.Assets;\nusing Libplanet.Types.Blocks;\n\nnamespace Libplanet.Types.Tx\n{\n    public static class TxMarshaler\n    {\n        private const string TimestampFormat = \"yyyy-MM-ddTHH:mm:ss.ffffffZ\";\n        private static readonly Binary UpdatedAddressesKey = new Binary(new byte[] { 0x75 }); // 'u'\n        private static readonly Binary TimestampKey = new Binary(new byte[] { 0x74 }); // 't'\n        private static readonly Binary GenesisHashKey = new Binary(new byte[] { 0x67 }); // 'g'\n        private static readonly Binary MaxGasPriceKey = new Binary(new byte[] { 0x6d }); // 'm'\n        private static readonly Binary GasLimitKey = new Binary(new byte[] { 0x6c }); // 'l'\n        private static readonly Binary NonceKey = new Binary(new byte[] { 0x6e }); // 'n'\n        private static readonly Binary SignerKey = new Binary(new byte[] { 0x73 }); // 's'\n        private static readonly Binary PublicKeyKey = new Binary(new byte[] { 0x70 }); // 'p'\n        private static readonly Binary SignatureKey = new Binary(new byte[] { 0x53 }); // 'S'\n        private static readonly Binary ActionsKey = new Binary(new byte[] { 0x61 }); // 'a'\n        private static readonly Codec Codec = new Codec();\n\n        [Pure]\n        public static Bencodex.Types.Dictionary MarshalTxInvoice(this ITxInvoice invoice)\n        {\n            Bencodex.Types.List updatedAddresses = new Bencodex.Types.List(\n                invoice.UpdatedAddresses.Select<Address, IValue>(addr => addr.Bencoded)\n            );\n            string timestamp = invoice.Timestamp\n                .ToUniversalTime()\n                .ToString(TimestampFormat, CultureInfo.InvariantCulture);\n\n            Bencodex.Types.Dictionary dict = Bencodex.Types.Dictionary.Empty;\n            if (invoice.Actions is TxActionList tal)\n            {\n                dict = dict.Add(ActionsKey, tal.Bencoded);\n            }\n\n            dict = dict\n                .Add(UpdatedAddressesKey, updatedAddresses)\n                .Add(TimestampKey, timestamp);\n\n            if (invoice.GenesisHash is { } genesisHash)\n            {\n                dict = dict.Add(GenesisHashKey, genesisHash.ByteArray);\n            }\n\n            if (invoice.MaxGasPrice is { } maxGasPrice)\n            {\n                dict = dict.Add(MaxGasPriceKey, maxGasPrice.Serialize());\n            }\n\n            if (invoice.GasLimit is { } gasLimit)\n            {\n                dict = dict.Add(GasLimitKey, gasLimit);\n            }\n\n            return dict;\n        }\n\n        [Pure]\n        public static Bencodex.Types.Dictionary MarshalTxSigningMetadata(\n            this ITxSigningMetadata metadata\n        ) => Dictionary.Empty\n            .Add(NonceKey, metadata.Nonce)\n            .Add(SignerKey, metadata.Signer.Bencoded)\n            .Add(PublicKeyKey, metadata.PublicKey.ToImmutableArray(compress: false));\n\n        [Pure]\n        public static Bencodex.Types.Dictionary MarshalUnsignedTx(this IUnsignedTx unsignedTx) =>\n            (Bencodex.Types.Dictionary)unsignedTx.MarshalTxInvoice()\n                .AddRange(unsignedTx.MarshalTxSigningMetadata());\n\n        [Pure]\n        public static Bencodex.Types.Dictionary MarshalTransaction(\n            this Transaction transaction) =>\n            transaction.MarshalUnsignedTx().Add(SignatureKey, transaction.Signature);\n\n        [Pure]\n        public static ImmutableArray<byte> SerializeUnsignedTx(this IUnsignedTx unsignedTx)\n        {\n            Bencodex.Types.Dictionary dict = unsignedTx.MarshalUnsignedTx();\n            byte[] encoded = Codec.Encode(dict);\n            ImmutableArray<byte> movedBytes =\n                Unsafe.As<byte[], ImmutableArray<byte>>(ref encoded);\n            return movedBytes;\n        }\n\n        [Pure]\n        public static ITxInvoice UnmarshalTxInvoice(Bencodex.Types.Dictionary dictionary)\n            =>\n#pragma warning disable SA1118 // The parameter spans multiple lines\n                new TxInvoice(\n                    genesisHash: dictionary.TryGetValue(GenesisHashKey, out IValue gv)\n                        ? new BlockHash(gv)\n                        : (BlockHash?)null,\n                    updatedAddresses: new AddressSet(\n                        ((Bencodex.Types.List)dictionary[UpdatedAddressesKey])\n                        .Select(v => new Address(v))),\n                    timestamp: DateTimeOffset.ParseExact(\n                        (Text)dictionary[TimestampKey],\n                        TimestampFormat,\n                        CultureInfo.InvariantCulture).ToUniversalTime(),\n                    actions: dictionary.TryGetValue(ActionsKey, out IValue cav)\n                        ? new TxActionList(dictionary[ActionsKey])\n                        : TxActionList.Empty,\n                    maxGasPrice: dictionary.TryGetValue(MaxGasPriceKey, out IValue mgpv)\n                        ? new FungibleAssetValue(mgpv)\n                        : (FungibleAssetValue?)null,\n                    gasLimit: dictionary.TryGetValue(GasLimitKey, out IValue glv)\n                        ? (long)(Bencodex.Types.Integer)glv\n                        : (long?)null);\n\n#pragma warning restore SA1118\n\n        [Pure]\n        public static ITxSigningMetadata UnmarshalTxSigningMetadata(\n            Bencodex.Types.Dictionary dictionary\n        ) =>\n            new TxSigningMetadata(\n                nonce: (Bencodex.Types.Integer)dictionary[NonceKey],\n                publicKey: new PublicKey(((Binary)dictionary[PublicKeyKey]).ByteArray)\n            );\n\n        [Pure]\n        public static UnsignedTx UnmarshalUnsignedTx(Bencodex.Types.Dictionary dictionary) =>\n            new UnsignedTx(\n                invoice: UnmarshalTxInvoice(dictionary),\n                signingMetadata: UnmarshalTxSigningMetadata(dictionary));\n\n        [Pure]\n        public static ImmutableArray<byte>? UnmarshalTransactionSignature(\n            Bencodex.Types.Dictionary dictionary\n        ) =>\n            dictionary.TryGetValue(SignatureKey, out IValue v) && v is Binary bin\n                ? bin.ToImmutableArray()\n                : (ImmutableArray<byte>?)null;\n\n        [Pure]\n        public static Transaction UnmarshalTransaction(Bencodex.Types.Dictionary dictionary)\n        {\n            ImmutableArray<byte>? sig = UnmarshalTransactionSignature(dictionary);\n            if (!(sig is { } signature))\n            {\n                throw new DecodingException(\"Transaction signature is missing.\");\n            }\n\n            return UnmarshalUnsignedTx(dictionary).Verify(signature);\n        }\n\n        [Pure]\n        public static IUnsignedTx DeserializeUnsignedTx(byte[] bytes)\n        {\n            IValue node = Codec.Decode(bytes);\n            if (node is Bencodex.Types.Dictionary dict)\n            {\n                return UnmarshalUnsignedTx(dict);\n            }\n\n            throw new DecodingException(\n                $\"Expected a {typeof(Bencodex.Types.Dictionary).FullName}, \" +\n                $\"but {node.GetType().Name} given.\");\n        }\n\n        [Pure]\n        public static IUnsignedTx DeserializeUnsignedTx(ImmutableArray<byte> bytes)\n        {\n            byte[] arrayView = Unsafe.As<ImmutableArray<byte>, byte[]>(ref bytes);\n            return DeserializeUnsignedTx(arrayView);\n        }\n\n        [Pure]\n        public static Transaction UnmarshalTransactionWithoutVerification(\n            Bencodex.Types.Dictionary dictionary)\n        {\n            ImmutableArray<byte> sig\n                = dictionary.TryGetValue(SignatureKey, out IValue s) && s is Binary bin\n                ? bin.ToImmutableArray()\n                : ImmutableArray<byte>.Empty;\n            return UnmarshalUnsignedTx(dictionary).CombineWithoutVerification(sig);\n        }\n\n        [Pure]\n        public static Transaction DeserializeTransactionWithoutVerification(byte[] bytes)\n        {\n            IValue node = Codec.Decode(bytes);\n            if (node is Bencodex.Types.Dictionary dict)\n            {\n                return UnmarshalTransactionWithoutVerification(dict);\n            }\n\n            throw new DecodingException(\n                $\"Expected a {typeof(Bencodex.Types.Dictionary).FullName}, \" +\n                $\"but {node.GetType().Name} given.\"\n            );\n        }\n\n        [Pure]\n        internal static Transaction DeserializeTransactionWithoutVerification(\n            ImmutableArray<byte> bytes)\n        {\n            byte[] arrayView = Unsafe.As<ImmutableArray<byte>, byte[]>(ref bytes);\n            return DeserializeTransactionWithoutVerification(arrayView);\n        }\n\n        // TODO: SerializeTransaction, DeserializeTransaction\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Types/Tx/TxMetadata.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Collections.Immutable;\nusing System.Diagnostics.Contracts;\nusing System.Globalization;\nusing System.Linq;\nusing Bencodex.Types;\nusing Libplanet.Crypto;\nusing Libplanet.Types.Blocks;\n\nnamespace Libplanet.Types.Tx\n{\n    /// <summary>\n    /// A <see cref=\"Transaction\"/> without actions and signature.\n    /// </summary>\n    public sealed class TxMetadata\n    {\n        internal static readonly Binary CustomActionsKey = new Binary(new byte[] { 0x61 }); // 'a'\n        internal static readonly Binary SystemActionKey = new Binary(new byte[] { 0x41 }); // 'A'\n        internal static readonly Binary SignatureKey = new Binary(new byte[] { 0x53 }); // 'S'\n        private const string TimestampFormat = \"yyyy-MM-ddTHH:mm:ss.ffffffZ\";\n        private static readonly Binary NonceKey = new Binary(new byte[] { 0x6e }); // 'n'\n        private static readonly Binary SignerKey = new Binary(new byte[] { 0x73 }); // 's'\n        private static readonly Binary GenesisHashKey = new Binary(new byte[] { 0x67 }); // 'g'\n        private static readonly Binary UpdatedAddressesKey = new Binary(new byte[] { 0x75 }); // 'u'\n        private static readonly Binary PublicKeyKey = new Binary(new byte[] { 0x70 }); // 'p'\n        private static readonly Binary TimestampKey = new Binary(new byte[] { 0x74 }); // 't'\n\n        /// <summary>\n        /// Creates a <see cref=\"TxMetadata\"/> instance with a <paramref name=\"publicKey\"/>.\n        /// Other fields can be set using property setters.\n        /// </summary>\n        /// <param name=\"publicKey\">Configures <see cref=\"PublicKey\"/> and <see cref=\"Signer\"/>.\n        /// </param>\n        public TxMetadata(PublicKey publicKey)\n        {\n            PublicKey = publicKey;\n        }\n\n        /// <summary>\n        /// Creates a <see cref=\"TxMetadata\"/> instance by copying fields from the specified\n        /// <paramref name=\"metadata\"/>.\n        /// </summary>\n        /// <param name=\"metadata\">The transaction metadata whose data to copy.</param>\n        /// <remarks><see cref=\"ITxSigningMetadata.Signer\"/> from the specified\n        /// <paramref name=\"metadata\"/> is ignored.  <see cref=\"Signer\"/> field is automatically\n        /// derived from <see cref=\"PublicKey\"/> instead.</remarks>\n        public TxMetadata(ITransaction metadata)\n        {\n            Nonce = metadata.Nonce;\n            GenesisHash = metadata.GenesisHash;\n            UpdatedAddresses = metadata.UpdatedAddresses;\n            PublicKey = metadata.PublicKey;\n            Timestamp = metadata.Timestamp;\n        }\n\n        /// <summary>\n        /// Creates a <see cref=\"TxMetadata\"/> from a Bencodex <paramref name=\"dictionary\"/>.\n        /// </summary>\n        /// <param name=\"dictionary\">A Bencodex dictionary made using\n        /// <see cref=\"ToBencodex()\"/> method.</param>\n        /// <exception cref=\"KeyNotFoundException\">Thrown when the given\n        /// <paramref name=\"dictionary\"/> lacks some fields.</exception>\n        /// <exception cref=\"InvalidCastException\">Thrown when the given\n        /// <paramref name=\"dictionary\"/> has some invalid values.</exception>\n        public TxMetadata(Bencodex.Types.Dictionary dictionary)\n        {\n            Nonce = (Integer)dictionary[NonceKey];\n            GenesisHash = dictionary.TryGetValue(GenesisHashKey, out IValue v)\n                    ? new BlockHash(v)\n                    : (BlockHash?)null;\n            UpdatedAddresses = ((List)dictionary[UpdatedAddressesKey])\n                .Select(v => new Address(v))\n                .ToImmutableHashSet();\n            PublicKey = new PublicKey(((Binary)dictionary[PublicKeyKey]).ByteArray);\n            Timestamp = DateTimeOffset.ParseExact(\n                (Text)dictionary[TimestampKey],\n                TimestampFormat,\n                CultureInfo.InvariantCulture\n            ).ToUniversalTime();\n        }\n\n        /// <summary>\n        /// The number of previous <see cref=\"Transaction\"/>s committed by\n        /// the <see cref=\"Signer\"/> of this transaction.  This nonce is used for preventing\n        /// replay attack.\n        /// </summary>\n        public long Nonce { get; set; }\n\n        /// <summary>\n        /// A <see cref=\"Address\"/> of the account who signs this transaction.\n        /// This is derived from the <see cref=\"PublicKey\"/>.\n        /// </summary>\n        /// <remarks>This is automatically derived from <see cref=\"PublicKey\"/>.</remarks>\n        public Address Signer => new Address(PublicKey);\n\n        /// <summary>\n        /// An approximated list of addresses whose states would be affected by actions in this\n        /// transaction.  However, it could be wrong.\n        /// </summary>\n        /// <remarks>See also https://github.com/planetarium/libplanet/issues/368 .</remarks>\n        public IImmutableSet<Address> UpdatedAddresses { get; set; } =\n            ImmutableHashSet<Address>.Empty;\n\n        /// <summary>\n        /// The time this transaction is created and signed.\n        /// </summary>\n        public DateTimeOffset Timestamp { get; set; } = DateTimeOffset.UtcNow;\n\n        /// <summary>\n        /// A <see cref=\"PublicKey\"/> of the account who signs this transaction.\n        /// The <see cref=\"Signer\"/> address is always corresponding to this\n        /// for each transaction.  This cannot be <see langword=\"null\"/>.\n        /// </summary>\n        public PublicKey PublicKey { get; }\n\n        /// <summary>\n        /// A <see cref=\"BlockHash\"/> value of the genesis which this transaction is made\n        /// from.  This can be <see langword=\"null\"/> iff the transaction is contained in\n        /// the genesis block.\n        /// </summary>\n        public BlockHash? GenesisHash { get; set; }\n\n        [Pure]\n        public Bencodex.Types.Dictionary ToBencodex()\n        {\n            List updatedAddresses = new List(\n                UpdatedAddresses.Select<Address, IValue>(addr => addr.Bencoded));\n            string timestamp = Timestamp\n                .ToUniversalTime()\n                .ToString(TimestampFormat, CultureInfo.InvariantCulture);\n            Bencodex.Types.Dictionary dict = Dictionary.Empty\n                .Add(NonceKey, Nonce)\n                .Add(SignerKey, Signer.Bencoded)\n                .Add(UpdatedAddressesKey, updatedAddresses)\n                .Add(PublicKeyKey, PublicKey.ToImmutableArray(compress: false))\n                .Add(TimestampKey, timestamp);\n\n            if (GenesisHash is { } genesisHash)\n            {\n                dict = dict.Add(GenesisHashKey, genesisHash.ByteArray);\n            }\n\n            return dict;\n        }\n\n        /// <inheritdoc cref=\"object.ToString()\"/>\n        [Pure]\n        public override string ToString()\n        {\n            return nameof(TxMetadata) + \" {\\n\" +\n                $\"  {nameof(Nonce)} = {Nonce},\\n\" +\n                $\"  {nameof(Signer)} = {Signer},\\n\" +\n                $\"  {nameof(UpdatedAddresses)} = ({UpdatedAddresses.Count})\" +\n                (UpdatedAddresses.Any()\n                    ? $\"\\n    {string.Join(\"\\n    \", UpdatedAddresses)};\\n\"\n                    : \";\\n\") +\n                $\"  {nameof(PublicKey)} = {PublicKey},\\n\" +\n                $\"  {nameof(Timestamp)} = {Timestamp},\\n\" +\n                $\"  {nameof(GenesisHash)} = {GenesisHash?.ToString() ?? \"(null)\"},\\n\" +\n                \"}\";\n        }\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Types/Tx/TxPolicyViolationException.cs",
    "content": "using System;\n\nnamespace Libplanet.Types.Tx\n{\n    /// <summary>\n    /// An exception <em>returned</em> when a <see cref=\"Transaction\"/> violates\n    /// a <see cref=\"IBlockPolicy\"/>.\n    /// </summary>\n    public class TxPolicyViolationException : InvalidTxException\n    {\n        /// <summary>\n        /// Creates a new <see cref=\"TxPolicyViolationException\"/> instance. Use\n        /// <see cref=\"TxPolicyViolationException(string, TxId, Exception)\"/> if innerException\n        /// is required.\n        /// </summary>\n        /// <param name=\"message\">A description for the reason of violation\n        /// given by an implementation of <see cref=\"IBlockPolicy\"/>.\n        /// </param>\n        /// <param name=\"txid\">The <see cref=\"Transaction.Id\"/> of the\n        /// <see cref=\"Transaction\"/> violating a <see cref=\"IBlockPolicy\"/>.\n        /// Gets prepended to <paramref name=\"message\"/>.</param>\n        public TxPolicyViolationException(string message, TxId txid)\n            : base(message, txid)\n        {\n        }\n\n        /// <inheritdoc cref=\"TxPolicyViolationException(string, TxId)\"/>\n        /// <param name=\"message\">A description for the reason of violation\n        /// given by an implementation of <see cref=\"IBlockPolicy\"/>. </param>\n        /// <param name=\"txid\">The <see cref=\"Transaction.Id\"/> of the\n        /// <see cref=\"Transaction\"/> violating a <see cref=\"IBlockPolicy\"/>.\n        /// Gets prepended to <paramref name=\"message\"/>.</param>\n        /// <param name=\"innerException\">The <see cref=\"Exception\"/> for\n        /// <see cref=\"Exception.InnerException\"/>.</param>\n        public TxPolicyViolationException(\n            string message,\n            TxId txid,\n            Exception innerException)\n            : base(message, txid, innerException)\n        {\n        }\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Types/Tx/TxSigningMetadata.cs",
    "content": "using System;\nusing System.Diagnostics.Contracts;\nusing Libplanet.Crypto;\n\nnamespace Libplanet.Types.Tx\n{\n    /// <summary>\n    /// A concrete implementation of <see cref=\"ITxSigningMetadata\"/>.\n    /// </summary>\n    /// <seealso cref=\"ITxSigningMetadata\" />\n    /// <seealso cref=\"TxInvoice\"/>\n    /// <seealso cref=\"UnsignedTx\"/>\n    /// <seealso cref=\"Transaction\"/>\n    public sealed class TxSigningMetadata : ITxSigningMetadata, IEquatable<TxSigningMetadata>\n    {\n        /// <summary>\n        /// Creates a new <see cref=\"TxSigningMetadata\"/> instance by filling data for its fields.\n        /// </summary>\n        /// <param name=\"publicKey\">The value for <see cref=\"PublicKey\"/>.</param>\n        /// <param name=\"nonce\">The value for <see cref=\"Nonce\"/>.</param>\n        /// <exception cref=\"ArgumentOutOfRangeException\">Thrown when the given\n        /// <paramref name=\"nonce\"/> is less than 0.</exception>\n        public TxSigningMetadata(PublicKey publicKey, long nonce)\n        {\n            if (nonce < 0)\n            {\n                throw new ArgumentOutOfRangeException(\n                    nameof(nonce),\n                    $\"The nonce must be greater than or equal to 0, but {nonce} was given.\");\n            }\n\n            PublicKey = publicKey;\n            Nonce = nonce;\n        }\n\n        /// <summary>\n        /// Creates a new <see cref=\"TxSigningMetadata\"/> instance by copying the fields from\n        /// the given <paramref name=\"signingMetadata\"/>.\n        /// </summary>\n        /// <param name=\"signingMetadata\">The <see cref=\"ITxSigningMetadata\"/> instance to copy\n        /// fields from.</param>\n        public TxSigningMetadata(ITxSigningMetadata signingMetadata)\n            : this(signingMetadata.PublicKey, signingMetadata.Nonce)\n        {\n        }\n\n        /// <inheritdoc cref=\"ITxSigningMetadata.Signer\" />\n        /// <remarks>This is automatically derived from <see cref=\"PublicKey\"/>.</remarks>\n        public Address Signer => new Address(PublicKey);\n\n        /// <inheritdoc cref=\"ITxSigningMetadata.PublicKey\" />\n        public PublicKey PublicKey { get; }\n\n        /// <inheritdoc cref=\"ITxSigningMetadata.Nonce\" />\n        public long Nonce { get; }\n\n        /// <inheritdoc cref=\"IEquatable{T}.Equals(T)\"/>\n        [Pure]\n        bool IEquatable<ITxSigningMetadata>.Equals(ITxSigningMetadata? other) =>\n            other is { } o && o.PublicKey.Equals(PublicKey) && o.Nonce == Nonce;\n\n        /// <inheritdoc cref=\"IEquatable{T}.Equals(T)\"/>\n        [Pure]\n        public bool Equals(TxSigningMetadata? other) =>\n            other is ITxSigningMetadata otherMetadata && otherMetadata.Equals(this);\n\n        /// <inheritdoc cref=\"object.Equals(object?)\"/>\n        [Pure]\n        public override bool Equals(object? obj) =>\n            obj is ITxSigningMetadata other && ((IEquatable<ITxSigningMetadata>)this).Equals(other);\n\n        /// <inheritdoc cref=\"object.GetHashCode()\"/>\n        [Pure]\n        public override int GetHashCode() => HashCode.Combine(PublicKey, Nonce);\n\n        /// <inheritdoc cref=\"object.ToString()\"/>\n        [Pure]\n        public override string ToString()\n        {\n            return nameof(TxMetadata) + \" {\\n\" +\n                $\"  {nameof(Nonce)} = {Nonce},\\n\" +\n                $\"  {nameof(Signer)} = {Signer},\\n\" +\n                $\"  {nameof(PublicKey)} = {PublicKey},\\n\" +\n                \"}\";\n        }\n    }\n}\n"
  },
  {
    "path": "src/Libplanet.Types/Tx/UnsignedTx.cs",
    "content": "using System;\nusing System.Collections.Immutable;\nusing System.Diagnostics.Contracts;\nusing System.Linq;\nusing System.Runtime.CompilerServices;\nusing System.Text.Json.Serialization;\nusing Bencodex;\nusing Libplanet.Crypto;\nusing Libplanet.Types.Assets;\nusing Libplanet.Types.Blocks;\n\nnamespace Libplanet.Types.Tx\n{\n    /// <summary>\n    /// A concrete implementation of <see cref=\"IUnsignedTx\"/>.\n    /// </summary>\n    /// <seealso cref=\"IUnsignedTx\"/>\n    /// <seealso cref=\"TxInvoice\"/>\n    /// <seealso cref=\"TxSigningMetadata\"/>\n    /// <seealso cref=\"Transaction\"/>\n    public sealed class UnsignedTx : IUnsignedTx, IEquatable<UnsignedTx>\n    {\n        private static readonly Codec _codec = new Codec();\n        private readonly TxInvoice _invoice;\n        private readonly TxSigningMetadata _signingMetadata;\n\n        /// <summary>\n        /// Creates a new <see cref=\"UnsignedTx\"/> instance by combining an <see cref=\"TxInvoice\"/>\n        /// and an <see cref=\"TxSigningMetadata\"/>.\n        /// </summary>\n        /// <param name=\"invoice\">The invoice to combine with <paramref name=\"signingMetadata\"/>.\n        /// </param>\n        /// <param name=\"signingMetadata\">The signing metadata to combine with\n        /// <paramref name=\"invoice\"/>.</param>\n        public UnsignedTx(TxInvoice invoice, TxSigningMetadata signingMetadata)\n        {\n            _invoice = invoice;\n            _signingMetadata = signingMetadata;\n        }\n\n        /// <summary>\n        /// Creates a new <see cref=\"UnsignedTx\"/> instance by copying everything from another\n        /// <paramref name=\"unsignedTx\"/>.\n        /// </summary>\n        /// <param name=\"unsignedTx\">The <see cref=\"IUnsignedTx\"/> instance to copy.</param>\n        public UnsignedTx(IUnsignedTx unsignedTx)\n            : this(unsignedTx, unsignedTx)\n        {\n        }\n\n        /// <summary>\n        /// Creates a new <see cref=\"UnsignedTx\"/> instance by combining an <see cref=\"ITxInvoice\"/>\n        /// and an <see cref=\"ITxSigningMetadata\"/>.  Note that when the arguments are not instances\n        /// of <see cref=\"TxInvoice\"/> or <see cref=\"TxSigningMetadata\"/>, this constructor creates\n        /// new instances of <see cref=\"TxInvoice\"/> and <see cref=\"TxSigningMetadata\"/> by copying.\n        /// </summary>\n        /// <param name=\"invoice\">The invoice to combine with <paramref name=\"signingMetadata\"/>.\n        /// </param>\n        /// <param name=\"signingMetadata\">The signing metadata to combine with\n        /// <paramref name=\"invoice\"/>.</param>\n        public UnsignedTx(ITxInvoice invoice, ITxSigningMetadata signingMetadata)\n            : this(\n                invoice is TxInvoice i ? i : new TxInvoice(invoice),\n                signingMetadata is TxSigningMetadata m ? m : new TxSigningMetadata(signingMetadata))\n        {\n        }\n\n        /// <inheritdoc cref=\"ITxInvoice.UpdatedAddresses\" />\n        public IImmutableSet<Address> UpdatedAddresses => _invoice.UpdatedAddresses;\n\n        /// <inheritdoc cref=\"ITxInvoice.Timestamp\" />\n        public DateTimeOffset Timestamp => _invoice.Timestamp;\n\n        /// <inheritdoc cref=\"ITxInvoice.GenesisHash\" />\n        public BlockHash? GenesisHash => _invoice.GenesisHash;\n\n        /// <inheritdoc cref=\"ITxInvoice.Actions\" />\n        [JsonConverter(typeof(TxActionListJsonConverter))]\n        public TxActionList Actions => _invoice.Actions;\n\n        /// <inheritdoc cref=\"ITxInvoice.MaxGasPrice\" />\n        public FungibleAssetValue? MaxGasPrice => _invoice.MaxGasPrice;\n\n        /// <inheritdoc cref=\"ITxInvoice.GasLimit\" />\n        public long? GasLimit => _invoice.GasLimit;\n\n        /// <inheritdoc cref=\"ITxSigningMetadata.Nonce\" />\n        public long Nonce => _signingMetadata.Nonce;\n\n        /// <inheritdoc cref=\"ITxSigningMetadata.Signer\" />\n        public Address Signer => _signingMetadata.Signer;\n\n        /// <inheritdoc cref=\"ITxSigningMetadata.PublicKey\" />\n        public PublicKey PublicKey => _signingMetadata.PublicKey;\n\n        /// <summary>\n        /// Creates a signature for this transaction with the given <paramref name=\"privateKey\"/>.\n        /// </summary>\n        /// <param name=\"privateKey\">The private key to sign this transaction.</param>\n        /// <returns>A signature for this transaction.</returns>\n        /// <exception cref=\"ArgumentException\">Thrown when the given <paramref name=\"privateKey\"/>\n        /// does not correspond to the <see cref=\"PublicKey\"/> of this transaction.</exception>\n        [Pure]\n        public ImmutableArray<byte> CreateSignature(PrivateKey privateKey)\n        {\n            if (!privateKey.PublicKey.Equals(PublicKey))\n            {\n                throw new ArgumentException(\n                    \"The given private key does not correspond to the public key.\",\n                    paramName: nameof(privateKey)\n                );\n            }\n\n            byte[] sig = privateKey.Sign(CreateMessage());\n            ImmutableArray<byte> movedImmutableArray =\n                Unsafe.As<byte[], ImmutableArray<byte>>(ref sig);\n            return movedImmutableArray;\n        }\n\n        /// <summary>\n        /// Verifies the given <paramref name=\"signature\"/> for this transaction.\n        /// </summary>\n        /// <param name=\"signature\">The signature to verify.</param>\n        /// <returns><see langword=\"true\"/> if the given <paramref name=\"signature\"/> is valid for\n        /// this transaction, otherwise <see langword=\"false\"/>.</returns>\n        [Pure]\n        public bool VerifySignature(ImmutableArray<byte> signature) =>\n            PublicKey.Verify(CreateMessage(), signature);\n\n        /// <inheritdoc cref=\"IEquatable{T}.Equals(T)\"/>\n        [Pure]\n        bool IEquatable<ITxInvoice>.Equals(ITxInvoice? other) =>\n            other is { } o && _invoice.Equals(o);\n\n        /// <inheritdoc cref=\"IEquatable{T}.Equals(T)\"/>\n        [Pure]\n        bool IEquatable<ITxSigningMetadata>.Equals(ITxSigningMetadata? other) =>\n            other is { } o && _signingMetadata.Equals(o);\n\n        /// <inheritdoc cref=\"IEquatable{T}.Equals(T)\"/>\n        [Pure]\n        bool IEquatable<IUnsignedTx>.Equals(IUnsignedTx? other) =>\n            other is { } o &&\n            ((IEquatable<ITxInvoice>)this).Equals(o) &&\n            ((IEquatable<ITxSigningMetadata>)this).Equals(o);\n\n        /// <inheritdoc cref=\"IEquatable{T}.Equals(T)\"/>\n        [Pure]\n        public bool Equals(UnsignedTx? other) =>\n            other is { } o && ((IEquatable<IUnsignedTx>)this).Equals(o);\n\n        /// <inheritdoc cref=\"object.Equals(object?)\"/>\n        [Pure]\n        public override bool Equals(object? obj) =>\n            obj is IUnsignedTx other && ((IUnsignedTx)this).Equals(other);\n\n        /// <inheritdoc cref=\"object.GetHashCode()\"/>\n        [Pure]\n        public override int GetHashCode() =>\n            HashCode.Combine(_invoice, _signingMetadata);\n\n        /// <inheritdoc cref=\"object.ToString()\"/>\n        [Pure]\n        public override string ToString()\n        {\n            string actions = Actions.ToString() ?? string.Empty;\n            string indentedActions = actions.Replace(\"\\n\", \"\\n  \");\n            return nameof(TxInvoice) + \" {\\n\" +\n                $\"  {nameof(UpdatedAddresses)} = ({UpdatedAddresses.Count})\" +\n                (UpdatedAddresses.Any()\n                    ? $\"\\n    {string.Join(\"\\n    \", UpdatedAddresses)};\\n\"\n                    : \";\\n\") +\n                $\"  {nameof(Timestamp)} = {Timestamp},\\n\" +\n                $\"  {nameof(GenesisHash)} = {GenesisHash?.ToString() ?? \"(null)\"},\\n\" +\n                $\"  {nameof(Actions)} = {indentedActions},\\n\" +\n                $\"  {nameof(Nonce)} = {Nonce},\\n\" +\n                $\"  {nameof(Signer)} = {Signer},\\n\" +\n                $\"  {nameof(PublicKey)} = {PublicKey},\\n\" +\n                \"}\";\n        }\n\n        [Pure]\n        private byte[] CreateMessage() =>\n            _codec.Encode(this.MarshalUnsignedTx());\n    }\n}\n"
  },
  {
    "path": "stylecop.json",
    "content": "{\n    \"$schema\": \"https://raw.githubusercontent.com/DotNetAnalyzers/StyleCopAnalyzers/master/StyleCop.Analyzers/StyleCop.Analyzers/Settings/stylecop.schema.json\",\n    \"settings\": {\n        \"orderingRules\": {\n            \"usingDirectivesPlacement\": \"outsideNamespace\"\n        }\n    }\n}\n"
  },
  {
    "path": "test/Directory.Build.props",
    "content": "<Project>\n\n  <Import Project=\"$([MSBuild]::GetPathOfFileAbove('Directory.Build.props', '$(MSBuildThisFileDirectory)../'))\" />\n\n  <PropertyGroup>\n    <IsPackable>false</IsPackable>\n    <IsTestProject>true</IsTestProject>\n    <IsPublishable>false</IsPublishable>\n    <CodeAnalysisRuleSet>$(MSBuildThisFileDirectory)..\\Libplanet.Tests.ruleset</CodeAnalysisRuleSet>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <PackageReference Include=\"JunitXml.TestLogger\" Version=\"3.0.98\" />\n    <PackageReference Include=\"Microsoft.NET.Test.Sdk\" Version=\"17.6.0\"/>\n    <PackageReference Include=\"xunit\" Version=\"2.4.2\"/>\n    <PackageReference Include=\"xunit.runner.visualstudio\" Version=\"2.5.6\">\n      <PrivateAssets>all</PrivateAssets>\n      <IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>\n    </PackageReference>\n    <PackageReference Include=\"xunit.extensibility.execution\" Version=\"2.4.2\" />\n    <PackageReference Include=\"coverlet.collector\" Version=\"6.0.0\">\n      <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>\n      <PrivateAssets>all</PrivateAssets>\n    </PackageReference>\n  </ItemGroup>\n\n</Project>\n"
  },
  {
    "path": "test/Libplanet.Action.Tests/ActionContextTest.cs",
    "content": "using System.Collections.Immutable;\nusing System.Numerics;\nusing Libplanet.Action.State;\nusing Libplanet.Crypto;\nusing Libplanet.Mocks;\nusing Libplanet.Types.Blocks;\nusing Libplanet.Types.Consensus;\nusing Libplanet.Types.Tx;\nusing Xunit;\n\nnamespace Libplanet.Action.Tests\n{\n    public class ActionContextTest\n    {\n        private readonly System.Random _random;\n        private readonly Address _address;\n        private readonly TxId _txid;\n        private readonly BlockCommit _lastCommit;\n\n        public ActionContextTest()\n        {\n            _random = new System.Random();\n            _address = _random.NextAddress();\n            _txid = _random.NextTxId();\n            var key = new PrivateKey();\n            var hash = _random.NextBlockHash();\n            _lastCommit = new BlockCommit(\n                0,\n                0,\n                hash,\n                new[]\n                {\n                    new VoteMetadata(\n                        0,\n                        0,\n                        hash,\n                        DateTimeOffset.UtcNow,\n                        key.PublicKey,\n                        BigInteger.One,\n                        VoteFlag.PreCommit).Sign(key),\n                }.ToImmutableArray());\n        }\n\n        [Fact]\n        public void RandomShouldBeDeterministic()\n        {\n            (int Seed, int Expected)[] testCases =\n            {\n                (0, 1559595546),\n                (1, 534011718),\n            };\n            foreach (var (seed, expected) in testCases)\n            {\n                var context = new ActionContext(\n                    signer: _address,\n                    txid: _txid,\n                    miner: _address,\n                    blockIndex: 1,\n                    blockProtocolVersion: Block.CurrentProtocolVersion,\n                    lastCommit: _lastCommit,\n                    previousState: new World(MockWorldState.CreateModern()),\n                    randomSeed: seed,\n                    isPolicyAction: false,\n                    maxGasPrice: null\n                );\n                IRandom random = context.GetRandom();\n                Assert.Equal(expected, random.Next());\n            }\n        }\n\n        [Fact]\n        public void GuidShouldBeDeterministic()\n        {\n            var context1 = new ActionContext(\n                signer: _address,\n                txid: _txid,\n                miner: _address,\n                blockIndex: 1,\n                blockProtocolVersion: Block.CurrentProtocolVersion,\n                lastCommit: _lastCommit,\n                previousState: new World(MockWorldState.CreateModern()),\n                randomSeed: 0,\n                isPolicyAction: false,\n                maxGasPrice: null\n            );\n\n            var context2 = new ActionContext(\n                signer: _address,\n                txid: _txid,\n                miner: _address,\n                blockIndex: 1,\n                blockProtocolVersion: Block.CurrentProtocolVersion,\n                lastCommit: _lastCommit,\n                previousState: new World(MockWorldState.CreateModern()),\n                randomSeed: 0,\n                isPolicyAction: false,\n                maxGasPrice: null\n            );\n\n            var context3 = new ActionContext(\n                signer: _address,\n                txid: _txid,\n                miner: _address,\n                blockIndex: 1,\n                blockProtocolVersion: Block.CurrentProtocolVersion,\n                lastCommit: _lastCommit,\n                previousState: new World(MockWorldState.CreateModern()),\n                randomSeed: 1,\n                isPolicyAction: false,\n                maxGasPrice: null\n            );\n\n            (Guid Expected, Guid Diff)[] testCases =\n            {\n                (\n                    new Guid(\"6f460c1a-755d-48e4-ad67-65d5f519dbc8\"),\n                    new Guid(\"8286d046-9740-43e4-95cf-ff46699c73c4\")\n                ),\n                (\n                    new Guid(\"3b347c2b-f837-4085-ac5e-64005393b30d\"),\n                    new Guid(\"3410cda1-5b13-434e-af84-a54adf7a0ea0\")\n                ),\n            };\n\n            var rand1 = context1.GetRandom();\n            var rand2 = context2.GetRandom();\n            var rand3 = context3.GetRandom();\n            foreach (var (expected, diff) in testCases)\n            {\n                Assert.Equal(expected, rand1.GenerateRandomGuid());\n                Assert.Equal(expected, rand2.GenerateRandomGuid());\n                Assert.Equal(diff, rand3.GenerateRandomGuid());\n            }\n        }\n\n        [Fact]\n        public void GuidVersionAndVariant()\n        {\n            for (var i = 0; i < 100; i++)\n            {\n                var context = new ActionContext(\n                    signer: _address,\n                    txid: _txid,\n                    miner: _address,\n                    blockIndex: 1,\n                    blockProtocolVersion: Block.CurrentProtocolVersion,\n                    lastCommit: _lastCommit,\n                    previousState: new World(MockWorldState.CreateModern()),\n                    randomSeed: i,\n                    isPolicyAction: false,\n                    maxGasPrice: null\n                );\n                var guid = context.GetRandom().GenerateRandomGuid().ToString();\n\n                Assert.Equal('4', guid[14]);\n                Assert.True(guid[19] >= '8' && guid[19] <= 'b');\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "test/Libplanet.Action.Tests/ActionEvaluationTest.cs",
    "content": "using System.Collections.Immutable;\nusing System.Numerics;\nusing Bencodex.Types;\nusing Libplanet.Action.State;\nusing Libplanet.Action.Tests.Common;\nusing Libplanet.Crypto;\nusing Libplanet.Mocks;\nusing Libplanet.Types.Blocks;\nusing Libplanet.Types.Consensus;\nusing Serilog;\nusing Xunit;\nusing Xunit.Abstractions;\n\nnamespace Libplanet.Action.Tests\n{\n    public class ActionEvaluationTest\n    {\n        private readonly ILogger _logger;\n\n        public ActionEvaluationTest(ITestOutputHelper output)\n        {\n            Log.Logger = _logger = new LoggerConfiguration()\n                .MinimumLevel.Verbose()\n                .Enrich.WithThreadId()\n                .WriteTo.TestOutput(output)\n                .CreateLogger()\n                .ForContext<ActionEvaluationTest>();\n        }\n\n        [Fact]\n        public void Constructor()\n        {\n            var random = new System.Random();\n            var txid = random.NextTxId();\n            Address address = new PrivateKey().Address;\n            var key = new PrivateKey();\n            var hash = random.NextBlockHash();\n            var lastCommit = new BlockCommit(\n                0,\n                0,\n                hash,\n                new[]\n                {\n                    new VoteMetadata(\n                        0,\n                        0,\n                        hash,\n                        DateTimeOffset.UtcNow,\n                        key.PublicKey,\n                        BigInteger.One,\n                        VoteFlag.PreCommit).Sign(key),\n                }.ToImmutableArray());\n            IWorld world = new World(MockWorldState.CreateModern());\n            world = world.SetAccount(\n                ReservedAddresses.LegacyAccount,\n                world.GetAccount(ReservedAddresses.LegacyAccount).SetState(address, (Text)\"item\"));\n            var evaluation = new ActionEvaluation(\n                DumbAction.Create((address, \"item\")),\n                new ActionContext(\n                    address,\n                    txid,\n                    address,\n                    1,\n                    Block.CurrentProtocolVersion,\n                    lastCommit,\n                    new World(MockWorldState.CreateModern()),\n                    123,\n                    false,\n                    maxGasPrice: null),\n                world);\n            var action = (DumbAction)evaluation.Action;\n\n            Assert.Equal(address, action.Append?.At);\n            Assert.Equal(\"item\", action.Append?.Item);\n            Assert.Equal(address, evaluation.InputContext.Signer);\n            Assert.Equal(txid, evaluation.InputContext.TxId);\n            Assert.Equal(address, evaluation.InputContext.Miner);\n            Assert.Equal(1, evaluation.InputContext.BlockIndex);\n            Assert.Null(\n                evaluation.InputContext.PreviousState.GetAccount(\n                    ReservedAddresses.LegacyAccount).GetState(address)\n            );\n            Assert.Equal(\n                (Text)\"item\",\n                evaluation.OutputState.GetAccount(ReservedAddresses.LegacyAccount).GetState(address)\n            );\n            Assert.Equal(lastCommit, evaluation.InputContext.LastCommit);\n        }\n    }\n}\n"
  },
  {
    "path": "test/Libplanet.Action.Tests/ActionTypeAttributeTest.cs",
    "content": "using System.Reflection;\nusing Bencodex.Types;\nusing Xunit;\n\nnamespace Libplanet.Action.Tests\n{\n    public class ActionTypeAttributeTest\n    {\n        [Fact]\n        public void CanExtractValue()\n        {\n            Assert.Equal(\n                new Text(\"test_action\"),\n                typeof(TestAction1).GetCustomAttribute<ActionTypeAttribute>()?.TypeIdentifier);\n            Assert.Null(\n                typeof(TestAction2).GetCustomAttribute<ActionTypeAttribute>()?.TypeIdentifier);\n        }\n    }\n\n#pragma warning disable SA1402 // File may only contain a single class\n    [ActionType(\"test_action\")]\n    internal class TestAction1\n    {\n    }\n\n    internal class TestAction2\n    {\n    }\n#pragma warning restore SA1402 // File may only contain a single class\n}\n"
  },
  {
    "path": "test/Libplanet.Action.Tests/Common/Attack.cs",
    "content": "using System.Collections.Immutable;\nusing Bencodex.Types;\nusing Libplanet.Action.State;\nusing Libplanet.Crypto;\n\nnamespace Libplanet.Action.Tests.Common\n{\n    [ActionType(\"attack\")]\n    public class Attack : BaseAction\n    {\n        public override IValue PlainValue => Dictionary.Empty\n            .Add(\"type_id\", TypeId)\n            .Add(\"values\", Dictionary.Empty\n                .Add(\"weapon\", Weapon)\n                .Add(\"target\", Target)\n                .Add(\"target_address\", TargetAddress.Bencoded));\n\n        public string Weapon { get; set; }\n\n        public string Target { get; set; }\n\n        public Address TargetAddress { get; set; }\n\n        public override void LoadPlainValue(IValue plainValue)\n        {\n            Dictionary values = (Dictionary)GetValues(plainValue);\n            Weapon = (Text)values[\"weapon\"];\n            Target = (Text)values[\"target\"];\n            TargetAddress = new Address(values[\"target_address\"]);\n        }\n\n        public override IWorld Execute(IActionContext context)\n        {\n            IImmutableSet<string> usedWeapons = ImmutableHashSet<string>.Empty;\n            IImmutableSet<string> targets = ImmutableHashSet<string>.Empty;\n            IWorld previousState = context.PreviousState;\n            IAccount legacyAccount = previousState.GetAccount(ReservedAddresses.LegacyAccount);\n\n            object value = legacyAccount.GetState(TargetAddress);\n            if (!ReferenceEquals(value, null))\n            {\n                var previousResult = BattleResult.FromBencodex((Bencodex.Types.Dictionary)value);\n                usedWeapons = previousResult.UsedWeapons;\n                targets = previousResult.Targets;\n            }\n\n            usedWeapons = usedWeapons.Add(Weapon);\n            targets = targets.Add(Target);\n            var result = new BattleResult(usedWeapons, targets);\n            legacyAccount = legacyAccount.SetState(TargetAddress, result.ToBencodex());\n\n            return previousState.SetAccount(ReservedAddresses.LegacyAccount, legacyAccount);\n        }\n    }\n}\n"
  },
  {
    "path": "test/Libplanet.Action.Tests/Common/BaseAction.cs",
    "content": "using System.Reflection;\nusing Bencodex.Types;\nusing Libplanet.Action.State;\n\nnamespace Libplanet.Action.Tests.Common\n{\n    public abstract class BaseAction : IAction\n    {\n        public IValue TypeId => this\n            .GetType()\n            .GetCustomAttribute<ActionTypeAttribute>() is ActionTypeAttribute attribute\n                ? attribute.TypeIdentifier\n                : throw new NullReferenceException(\n                    $\"Given type {this.GetType()} is missing {nameof(ActionTypeAttribute)}.\");\n\n        public abstract IValue PlainValue { get; }\n\n        public abstract IWorld Execute(IActionContext context);\n\n        public abstract void LoadPlainValue(IValue plainValue);\n\n        /// <summary>\n        /// <para>\n        /// Extracts the <c>\"values\"</c> value from <paramref name=\"plainValue\"/>.\n        /// </para>\n        /// <para>\n        /// While extracting, this also does a basic sanity check for <paramref name=\"plainValue\"/>\n        /// for those inheriting this <see langword=\"class\"/>.\n        /// This checks and throws an <see cref=\"ArgumentException\"/> for\n        /// any of the following reasons:\n        /// <list type=\"bullet\">\n        ///     <item><description>\n        ///         <paramref name=\"plainValue\"/> is not a <see cref=\"Dictionary\"/>.\n        ///     </description></item>\n        ///     <item><description>\n        ///         <paramref name=\"plainValue\"/> does not have a <c>\"type_id\"</c> field.\n        ///     </description></item>\n        ///     <item><description>\n        ///         <paramref name=\"plainValue\"/>'s <c>\"type_id\"</c> value does not match\n        ///         the <see cref=\"TypeId\"/>.\n        ///     </description></item>\n        ///     <item><description>\n        ///         <paramref name=\"plainValue\"/> does not have a <c>\"values\"</c> field.\n        ///     </description></item>\n        /// </list>\n        /// </para>\n        /// This does not actually load <see cref=\"plainValue\"/> for the object in question.\n        /// <para>\n        /// </para>\n        /// </summary>\n        /// <param name=\"plainValue\">The <see cref=\"IValue\"/> to check.</param>\n        /// <exception cref=\"ArgumentException\">Thrown for any of the reasons mentioned in\n        /// the method description.\n        /// </exception>\n        /// <returns>\n        /// The <c>\"values\"</c> value from <paramref name=\"plainValue\"/>.\n        /// </returns>\n        protected IValue GetValues(IValue plainValue)\n        {\n            if (!(plainValue is Dictionary dictionary))\n            {\n                throw new ArgumentException(\n                    $\"Given {nameof(plainValue)} must be a dictionary.\");\n            }\n            else if (!dictionary.TryGetValue((Text)\"type_id\", out IValue typeId))\n            {\n                throw new ArgumentException(\n                    $\"Given {nameof(plainValue)} is missing type id.\");\n            }\n            else if (!typeId.Equals(TypeId))\n            {\n                throw new ArgumentException(\n                    $\"Given {nameof(plainValue)}'s expected type id is {TypeId}: {typeId}\");\n            }\n            else if (!dictionary.TryGetValue((Text)\"values\", out IValue values))\n            {\n                throw new ArgumentException(\n                    $\"Given {nameof(plainValue)} is missing values.\");\n            }\n            else\n            {\n                return values;\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "test/Libplanet.Action.Tests/Common/BattleResult.cs",
    "content": "using System.Collections.Immutable;\nusing System.Globalization;\nusing Bencodex.Types;\n\nnamespace Libplanet.Action.Tests.Common\n{\n    public sealed class BattleResult : IEquatable<BattleResult>\n    {\n        public BattleResult(\n            IEnumerable<string> usedWeapons,\n            IEnumerable<string> targets\n        )\n        {\n            IEqualityComparer<string> comparer =\n                StringComparer.Create(CultureInfo.InvariantCulture, false);\n            UsedWeapons = usedWeapons.ToImmutableHashSet(comparer);\n            Targets = targets.ToImmutableHashSet(comparer);\n        }\n\n        public IImmutableSet<string> UsedWeapons { get; }\n\n        public IImmutableSet<string> Targets { get; }\n\n        public static BattleResult FromBencodex(Bencodex.Types.Dictionary dictionary)\n        {\n            return new BattleResult(\n                ((List)dictionary[\"used_weapons\"]).Select(x => ((Text)x).Value),\n                ((List)dictionary[\"targets\"]).Select(x => ((Text)x).Value));\n        }\n\n        public Bencodex.Types.Dictionary ToBencodex() =>\n            new Bencodex.Types.Dictionary(new Dictionary<string, IValue>\n            {\n                [\"used_weapons\"] = new List(UsedWeapons),\n                [\"targets\"] = new List(Targets),\n            });\n\n        public override bool Equals(object other)\n        {\n            return other is IEquatable<BattleResult> o &&\n                   o.Equals(this);\n        }\n\n        public bool Equals(BattleResult other)\n        {\n            return other != null &&\n                UsedWeapons.SetEquals(other.UsedWeapons) &&\n                Targets.SetEquals(other.Targets);\n        }\n\n        public override int GetHashCode()\n        {\n            unchecked\n            {\n                return ((UsedWeapons?.GetHashCode() ?? 0) * 397) ^\n                    (Targets?.GetHashCode() ?? 0);\n            }\n        }\n\n        public override string ToString()\n        {\n            string ListItems(IEnumerable<string> items) =>\n                string.Join(\n                    string.Empty,\n                    items.OrderBy(x => x).Select(a => \"\\n    \" + a)\n                );\n\n            return $@\"{nameof(BattleResult)}\n  {nameof(UsedWeapons)} = {ListItems(UsedWeapons)}\n  {nameof(Targets)} = {ListItems(Targets)}\";\n        }\n    }\n}\n"
  },
  {
    "path": "test/Libplanet.Action.Tests/Common/ContextRecordingAction.cs",
    "content": "using Bencodex.Types;\nusing Libplanet.Action.State;\nusing Libplanet.Crypto;\n\nnamespace Libplanet.Action.Tests.Common\n{\n    /// <summary>\n    /// An <see cref=\"IAction\"/> for testing.  In addition to simply setting\n    /// an <see cref=\"IValue\"/> to a certain <see cref=\"Crypto.Address\"/>,\n    /// records various data that can be accessed from <see cref=\"IActionContext\"/>.\n    /// </summary>\n    public class ContextRecordingAction : IAction\n    {\n        /// <summary>\n        /// The <see cref=\"Crypto.Address\"/> where <see cref=\"IActionContext.Miner\"/>\n        /// will be recorded.\n        /// </summary>\n        public static readonly Address MinerRecordAddress =\n            new Address(\"1000000000000000000000000000000000000001\");\n\n        /// <summary>\n        /// The <see cref=\"Crypto.Address\"/> where <see cref=\"IActionContext.Signer\"/>\n        /// will be recorded.\n        /// </summary>\n        public static readonly Address SignerRecordAddress =\n            new Address(\"1000000000000000000000000000000000000002\");\n\n        /// <summary>\n        /// The <see cref=\"Crypto.Address\"/> where <see cref=\"IActionContext.BlockIndex\"/>\n        /// will be recorded.\n        /// </summary>\n        public static readonly Address BlockIndexRecordAddress =\n            new Address(\"1000000000000000000000000000000000000003\");\n\n        /// <summary>\n        /// The <see cref=\"Crypto.Address\"/> where the next random integer from\n        /// <see cref=\"IActionContext.GetRandom()\"/> will be recorded.\n        /// </summary>\n        public static readonly Address RandomRecordAddress =\n            new Address(\"1000000000000000000000000000000000000004\");\n\n        public ContextRecordingAction()\n        {\n        }\n\n        public ContextRecordingAction(Address address, IValue value)\n        {\n            Address = address;\n            Value = value;\n        }\n\n        public IValue PlainValue => Dictionary.Empty\n            .Add(\"address\", Address.Bencoded)\n            .Add(\"value\", Value);\n\n        private Address Address { get; set; }\n\n        private IValue Value { get; set; }\n\n        public void LoadPlainValue(IValue plainValue)\n        {\n            Address = new Address(((Dictionary)plainValue)[\"address\"]);\n            Value = ((Dictionary)plainValue)[\"value\"];\n        }\n\n        public IWorld Execute(IActionContext context)\n        {\n            IWorld states = context.PreviousState;\n            IAccount account = states.GetAccount(ReservedAddresses.LegacyAccount);\n            account = account\n                .SetState(Address, Value)\n                .SetState(MinerRecordAddress, new Binary(context.Miner.ByteArray))\n                .SetState(SignerRecordAddress, new Binary(context.Signer.ByteArray))\n                .SetState(BlockIndexRecordAddress, new Integer(context.BlockIndex))\n                .SetState(RandomRecordAddress, new Integer(context.GetRandom().Next()));\n            return states.SetAccount(ReservedAddresses.LegacyAccount, account);\n        }\n    }\n}\n"
  },
  {
    "path": "test/Libplanet.Action.Tests/Common/Currencies.cs",
    "content": "using System.Collections.Immutable;\nusing Libplanet.Crypto;\nusing Libplanet.Types.Assets;\n\nnamespace Libplanet.Action.Tests\n{\n    /// <summary>\n    /// A set of variety of <see cref=\"Currency\"><c>Currencies</c></see> used for testing.\n    /// As minter's identities are dynamically generated at runtime, any <see cref=\"Currency\"/>\n    /// with non-<see langword=\"null\"/> <see cref=\"Currency.Minters\"/> specified has variable\n    /// <see cref=\"Currency.Hash\"/>, namely <see cref=\"CurrencyC\"/>, <see cref=\"CurrencyD\"/>,\n    /// <see cref=\"CurrencyE\"/>, and <see cref=\"CurrencyF\"/>.\n    /// </summary>\n    public static class Currencies\n    {\n        /// <summary>\n        /// The <see cref=\"PrivateKey\"/> of a minter for <see cref=\"CurrencyC\"/>,\n        /// <see cref=\"CurrencyD\"/>, <see cref=\"CurrencyE\"/>, and <see cref=\"CurrencyF\"/>.\n        /// </summary>\n        public static readonly PrivateKey MinterAKey = new PrivateKey();\n\n        /// <summary>\n        /// The <see cref=\"PrivateKey\"/> of a minter for <see cref=\"CurrencyD\"/>.\n        /// </summary>\n        public static readonly PrivateKey MinterBKey = new PrivateKey();\n\n        /// <summary>\n        /// The <see cref=\"Address\"/> of a minter for <see cref=\"CurrencyC\"/>,\n        /// <see cref=\"CurrencyD\"/>, <see cref=\"CurrencyE\"/>, and <see cref=\"CurrencyF\"/>.\n        /// </summary>\n        public static readonly Address MinterA = MinterAKey.Address;\n\n        /// <summary>\n        /// The <see cref=\"Address\"/> of a minter for <see cref=\"CurrencyD\"/>.\n        /// </summary>\n        public static readonly Address MinterB = MinterBKey.Address;\n\n#pragma warning disable CS0618\n        /// <summary>\n        /// A simple legacy <see cref=\"Currency\"/> with ticker \"AAA\", no decimal places, and\n        /// no minters.\n        /// </summary>\n        public static readonly Currency CurrencyA =\n            Currency.Legacy(\"AAA\", 0, null);\n\n        /// <summary>\n        /// A simple legacy <see cref=\"Currency\"/> with ticker \"BBB\", two decimal places, and\n        /// no minters.\n        /// </summary>\n        public static readonly Currency CurrencyB =\n            Currency.Legacy(\"BBB\", 2, null);\n\n        /// <summary>\n        /// A simple legacy <see cref=\"Currency\"/> with ticker \"CCC\", no decimal places, and\n        /// <see cref=\"MinterA\"/> as its minter.\n        /// </summary>\n        public static readonly Currency CurrencyC =\n            Currency.Legacy(\"CCC\", 0, new[] { MinterA }.ToImmutableHashSet());\n\n        /// <summary>\n        /// A simple legacy <see cref=\"Currency\"/> with ticker \"DDD\", no decimal places, and\n        /// <see cref=\"MinterA\"/> and <see cref=\"MinterB\"/> as its minters.\n        /// </summary>\n        public static readonly Currency CurrencyD =\n            Currency.Legacy(\"DDD\", 0, new[] { MinterA, MinterB }.ToImmutableHashSet());\n\n        /// <summary>\n        /// A simple uncapped <see cref=\"Currency\"/> with ticker \"EEE\", no decimal places, and\n        /// <see cref=\"MinterA\"/> as its minter.\n        /// </summary>\n        public static readonly Currency CurrencyE =\n            Currency.Uncapped(\"EEE\", 0, new[] { MinterA }.ToImmutableHashSet());\n\n        /// <summary>\n        /// A simple uncapped <see cref=\"Currency\"/> with ticker \"FFF\", no decimal places, and\n        /// <see cref=\"MinterA\"/> as its minter.\n        /// </summary>\n        public static readonly Currency CurrencyF =\n            Currency.Capped(\"FFF\", 0, (100, 0), new[] { MinterA }.ToImmutableHashSet());\n#pragma warning restore CS0618\n    }\n}\n"
  },
  {
    "path": "test/Libplanet.Action.Tests/Common/DelayAction.cs",
    "content": "using Bencodex.Types;\nusing Libplanet.Action.State;\nusing Libplanet.Crypto;\nusing Serilog;\n\nnamespace Libplanet.Action.Tests.Common\n{\n    public sealed class DelayAction : IAction\n    {\n        public static readonly Address TrivialUpdatedAddress =\n            new Address(\"3d94abf05556fdae0755ff4427869f80afd06b58\");\n\n        public DelayAction()\n        {\n        }\n\n        public DelayAction(int milliSecond)\n        {\n            MilliSecond = milliSecond;\n        }\n\n        public int MilliSecond { get; private set; }\n\n        public IValue PlainValue\n        {\n            get\n            {\n                var plainValue = Bencodex.Types.Dictionary.Empty.Add(\n                    \"millisecond\", new Bencodex.Types.Integer(MilliSecond));\n                return plainValue;\n            }\n        }\n\n        public IWorld Execute(IActionContext context)\n        {\n            var state = context.PreviousState;\n            var started = DateTimeOffset.UtcNow;\n            Log.Debug(\n                \"{MethodName} exec started. Delay target: {MilliSecond}\",\n                nameof(DelayAction),\n                MilliSecond);\n            Thread.Sleep(MilliSecond);\n            var ended = DateTimeOffset.UtcNow;\n            var delayAccount = state\n                .GetAccount(ReservedAddresses.LegacyAccount)\n                .SetState(TrivialUpdatedAddress, new Bencodex.Types.Integer(MilliSecond));\n            state = state.SetAccount(ReservedAddresses.LegacyAccount, delayAccount);\n            Log.Debug(\n                \"{MethodName} Total Executed Time: {Elapsed}. Delay target: {MilliSecond}\",\n                nameof(DelayAction),\n                ended - started,\n                MilliSecond);\n            return state;\n        }\n\n        public void LoadPlainValue(IValue plainValue)\n        {\n            var asDict = (Dictionary)plainValue;\n            MilliSecond = (int)((Bencodex.Types.Integer)asDict[\"millisecond\"]);\n        }\n    }\n}\n"
  },
  {
    "path": "test/Libplanet.Action.Tests/Common/DumbAction.cs",
    "content": "#nullable enable\nusing System.Collections.Immutable;\nusing System.Numerics;\nusing Bencodex.Types;\nusing Libplanet.Action.State;\nusing Libplanet.Crypto;\nusing Libplanet.Types.Assets;\nusing Libplanet.Types.Consensus;\n\nnamespace Libplanet.Action.Tests.Common\n{\n    public sealed class DumbAction : IAction\n    {\n        public static readonly DumbAction NoOp = DumbAction.Create();\n\n        public static readonly Text TypeId = new Text(nameof(DumbAction));\n\n        public static readonly Currency DumbCurrency =\n            Currency.Uncapped(\"DUMB\", 0, null);\n\n        public DumbAction()\n        {\n        }\n\n        public (Address At, string Item)? Append { get; private set; }\n\n        public (Address? From, Address? To, BigInteger Amount)? Transfer { get; private set; }\n\n        public ImmutableList<Validator>? Validators { get; private set; }\n\n        public IValue PlainValue\n        {\n            get\n            {\n                var plainValue = Dictionary.Empty\n                    .Add(\"type_id\", TypeId);\n                if (Append is { } set)\n                {\n                    plainValue = plainValue\n                        .Add(\"target_address\", set.At.Bencoded)\n                        .Add(\"item\", set.Item);\n                }\n\n                if (Transfer is { } transfer)\n                {\n                    plainValue = plainValue\n                        .Add(\"transfer_from\", transfer.From?.Bencoded ?? Null.Value)\n                        .Add(\"transfer_to\", transfer.To?.Bencoded ?? Null.Value)\n                        .Add(\"transfer_amount\", transfer.Amount);\n                }\n\n                if (Validators is { } validators)\n                {\n                    plainValue = plainValue\n                        .Add(\"validators\", new List(validators.Select(v => v.Bencoded)));\n                }\n\n                return plainValue;\n            }\n        }\n\n        public static DumbAction Create(\n            (Address At, string Item)? append = null,\n            (Address? From, Address? To, BigInteger Amount)? transfer = null,\n            IEnumerable<Validator>? validators = null,\n            bool recordRandom = false)\n        {\n            if (transfer is { } t && t.From is null && t.To is null)\n            {\n                throw new ArgumentException(\n                    $\"From and To of {nameof(transfer)} cannot both be null when \" +\n                    $\"{nameof(transfer)} is not null: {transfer}\");\n            }\n\n            return new DumbAction()\n            {\n                Append = append,\n                Transfer = transfer,\n                Validators = validators?.ToImmutableList(),\n            };\n        }\n\n        public IWorld Execute(IActionContext context)\n        {\n            IWorld world = context.PreviousState;\n\n            if (Append is { } append)\n            {\n                IAccount account = world.GetAccount(ReservedAddresses.LegacyAccount);\n                string? items = (Text?)account.GetState(append.At);\n                items = items is null ? append.Item : $\"{items},{append.Item}\";\n                account = account.SetState(append.At, (Text)items!);\n                world = world.SetAccount(ReservedAddresses.LegacyAccount, account);\n            }\n\n            if (Transfer is { } transfer)\n            {\n                world = (transfer.From, transfer.To) switch\n                {\n                    (Address from, Address to) => world.TransferAsset(\n                        context,\n                        sender: from,\n                        recipient: to,\n                        value: FungibleAssetValue.FromRawValue(DumbCurrency, transfer.Amount)),\n                    (null, Address to) => world.MintAsset(\n                        context,\n                        recipient: to,\n                        value: FungibleAssetValue.FromRawValue(DumbCurrency, transfer.Amount)),\n                    (Address from, null) => world.BurnAsset(\n                        context,\n                        owner: from,\n                        value: FungibleAssetValue.FromRawValue(DumbCurrency, transfer.Amount)),\n                    _ => throw new ArgumentException(\n                        $\"Both From and To cannot be null for {transfer}\"),\n                };\n            }\n\n            if (Validators is { } validators)\n            {\n                world = world.SetValidatorSet(new ValidatorSet(validators.ToList()));\n            }\n\n            return world;\n        }\n\n        public void LoadPlainValue(IValue plainValue) => LoadPlainValue((Dictionary)plainValue);\n\n        public void LoadPlainValue(Dictionary plainValue)\n        {\n            if (!plainValue[\"type_id\"].Equals(TypeId))\n            {\n                throw new ArgumentException(\n                    $\"An invalid form of {nameof(plainValue)} was given: {plainValue}\");\n            }\n\n            if (plainValue.TryGetValue((Text)\"target_address\", out IValue at) &&\n                plainValue.TryGetValue((Text)\"item\", out IValue item) &&\n                item is Text i)\n            {\n                Append = (new Address(at), i);\n            }\n\n            if (plainValue.TryGetValue((Text)\"transfer_from\", out IValue f) &&\n                plainValue.TryGetValue((Text)\"transfer_to\", out IValue t) &&\n                plainValue.TryGetValue((Text)\"transfer_amount\", out IValue a) &&\n                a is Integer amount)\n            {\n                Address? from = f is Null ? null : new Address(f);\n                Address? to = t is Null ? null : new Address(t);\n                Transfer = (from, to, amount.Value);\n            }\n\n            if (plainValue.ContainsKey((Text)\"validators\"))\n            {\n                Validators = ((List)plainValue[\"validators\"])\n                    .Select(value => new Validator(value))\n                    .ToImmutableList();\n            }\n        }\n\n        public override string ToString()\n        {\n            const string N = \"null\";\n            const string E = \"empty\";\n            string append = Append is { } a\n                ? $\"({a.At}, {a.Item})\"\n                : N;\n            string transfer = Transfer is { } t\n                ? $\"({t.From?.ToString() ?? N}, {t.To?.ToString() ?? N}, {t.Amount})\"\n                : N;\n            string validators = Validators is { } vs && vs.Any()\n                ? string.Join(\",\", vs.Select(v => v.OperatorAddress))\n                : E;\n            return $\"{nameof(DumbAction)} {{ \" +\n                $\"{nameof(Append)} = {append}, \" +\n                $\"{nameof(Transfer)} = {transfer}, \" +\n                $\"{nameof(Validators)} = {validators} \" +\n                $\"}}\";\n        }\n    }\n}\n"
  },
  {
    "path": "test/Libplanet.Action.Tests/Common/DumbModernAction.cs",
    "content": "#nullable enable\nusing System.Collections.Immutable;\nusing System.Numerics;\nusing Bencodex.Types;\nusing Libplanet.Action.State;\nusing Libplanet.Crypto;\nusing Libplanet.Types.Assets;\nusing Libplanet.Types.Consensus;\n\nnamespace Libplanet.Action.Tests.Common\n{\n    public sealed class DumbModernAction : IAction\n    {\n        public static readonly DumbModernAction NoOp = DumbModernAction.Create();\n\n        public static readonly Text TypeId = new Text(nameof(DumbAction));\n\n        public static readonly Address DumbModernAddress =\n            new Address(\"0123456789abcdef0123456789abcdef12345678\");\n\n        public static readonly Currency DumbCurrency =\n            Currency.Uncapped(\"DUMB\", 0, null);\n\n        public DumbModernAction()\n        {\n        }\n\n        public (Address At, string Item)? Append { get; private set; }\n\n        public (Address? From, Address? To, BigInteger Amount)? Transfer { get; private set; }\n\n        public ImmutableList<Validator>? Validators { get; private set; }\n\n        public IValue PlainValue\n        {\n            get\n            {\n                var plainValue = Dictionary.Empty\n                    .Add(\"type_id\", TypeId);\n                if (Append is { } set)\n                {\n                    plainValue = plainValue\n                        .Add(\"target_address\", set.At.Bencoded)\n                        .Add(\"item\", set.Item);\n                }\n\n                if (Transfer is { } transfer)\n                {\n                    plainValue = plainValue\n                        .Add(\"transfer_from\", transfer.From?.Bencoded ?? Null.Value)\n                        .Add(\"transfer_to\", transfer.To?.Bencoded ?? Null.Value)\n                        .Add(\"transfer_amount\", transfer.Amount);\n                }\n\n                if (Validators is { } validators)\n                {\n                    plainValue = plainValue\n                        .Add(\"validators\", new List(validators.Select(v => v.Bencoded)));\n                }\n\n                return plainValue;\n            }\n        }\n\n        public static DumbModernAction Create(\n            (Address At, string Item)? append = null,\n            (Address? From, Address? To, BigInteger Amount)? transfer = null,\n            IEnumerable<Validator>? validators = null,\n            bool recordRandom = false)\n        {\n            if (transfer is { } t && t.From is null && t.To is null)\n            {\n                throw new ArgumentException(\n                    $\"From and To of {nameof(transfer)} cannot both be null when \" +\n                    $\"{nameof(transfer)} is not null: {transfer}\");\n            }\n\n            return new DumbModernAction()\n            {\n                Append = append,\n                Transfer = transfer,\n                Validators = validators?.ToImmutableList(),\n            };\n        }\n\n        public IWorld Execute(IActionContext context)\n        {\n            IWorld world = context.PreviousState;\n\n            if (Append is { } append)\n            {\n                IAccount account = world.GetAccount(DumbModernAddress);\n                string? items = (Text?)account.GetState(append.At);\n                items = items is null ? append.Item : $\"{items},{append.Item}\";\n                account = account.SetState(append.At, (Text)items!);\n                world = world.SetAccount(DumbModernAddress, account);\n            }\n\n            if (Transfer is { } transfer)\n            {\n                world = (transfer.From, transfer.To) switch\n                {\n                    (Address from, Address to) => world.TransferAsset(\n                        context,\n                        sender: from,\n                        recipient: to,\n                        value: FungibleAssetValue.FromRawValue(DumbCurrency, transfer.Amount)),\n                    (null, Address to) => world.MintAsset(\n                        context,\n                        recipient: to,\n                        value: FungibleAssetValue.FromRawValue(DumbCurrency, transfer.Amount)),\n                    (Address from, null) => world.BurnAsset(\n                        context,\n                        owner: from,\n                        value: FungibleAssetValue.FromRawValue(DumbCurrency, transfer.Amount)),\n                    _ => throw new ArgumentException(\n                        $\"Both From and To cannot be null for {transfer}\"),\n                };\n            }\n\n            if (Validators is { } validators)\n            {\n                world = world.SetValidatorSet(new ValidatorSet(validators.ToList()));\n            }\n\n            return world;\n        }\n\n        public void LoadPlainValue(IValue plainValue) => LoadPlainValue((Dictionary)plainValue);\n\n        public void LoadPlainValue(Dictionary plainValue)\n        {\n            if (!plainValue[\"type_id\"].Equals(TypeId))\n            {\n                throw new ArgumentException(\n                    $\"An invalid form of {nameof(plainValue)} was given: {plainValue}\");\n            }\n\n            if (plainValue.TryGetValue((Text)\"target_address\", out IValue at) &&\n                plainValue.TryGetValue((Text)\"item\", out IValue item) &&\n                item is Text i)\n            {\n                Append = (new Address(at), i);\n            }\n\n            if (plainValue.TryGetValue((Text)\"transfer_from\", out IValue f) &&\n                plainValue.TryGetValue((Text)\"transfer_to\", out IValue t) &&\n                plainValue.TryGetValue((Text)\"transfer_amount\", out IValue a) &&\n                a is Integer amount)\n            {\n                Address? from = f is Null ? null : new Address(f);\n                Address? to = t is Null ? null : new Address(t);\n                Transfer = (from, to, amount.Value);\n            }\n\n            if (plainValue.ContainsKey((Text)\"validators\"))\n            {\n                Validators = ((List)plainValue[\"validators\"])\n                    .Select(value => new Validator(value))\n                    .ToImmutableList();\n            }\n        }\n\n        public override string ToString()\n        {\n            const string N = \"null\";\n            const string E = \"empty\";\n            string append = Append is { } a\n                ? $\"({a.At}, {a.Item})\"\n                : N;\n            string transfer = Transfer is { } t\n                ? $\"({t.From?.ToString() ?? N}, {t.To?.ToString() ?? N}, {t.Amount})\"\n                : N;\n            string validators = Validators is { } vs && vs.Any()\n                ? string.Join(\",\", vs.Select(v => v.OperatorAddress))\n                : E;\n            return $\"{nameof(DumbModernAction)} {{ \" +\n                $\"{nameof(Append)} = {append}, \" +\n                $\"{nameof(Transfer)} = {transfer}, \" +\n                $\"{nameof(Validators)} = {validators} \" +\n                $\"}}\";\n        }\n    }\n}\n"
  },
  {
    "path": "test/Libplanet.Action.Tests/Common/MinerReward.cs",
    "content": "using Bencodex.Types;\nusing Libplanet.Action.State;\nusing Libplanet.Crypto;\n\nnamespace Libplanet.Action.Tests.Common\n{\n    public sealed class MinerReward : IAction\n    {\n        public MinerReward()\n        {\n        }\n\n        public MinerReward(int reward)\n        {\n            Reward = reward;\n        }\n\n        public static Address RewardRecordAddress =>\n            new Address(\"0000000000000000000000000000000000000000\");\n\n        public int Reward { get; private set; }\n\n        public IValue PlainValue =>\n            new Bencodex.Types.Dictionary(new Dictionary<string, Integer>\n            {\n                [\"reward\"] = Reward,\n            });\n\n        public void LoadPlainValue(IValue plainValue)\n        {\n            LoadPlainValue((Dictionary)plainValue);\n        }\n\n        public void LoadPlainValue(Dictionary plainValue)\n        {\n            Reward = (Integer)plainValue[\"reward\"];\n        }\n\n        public IWorld Execute(IActionContext ctx)\n        {\n            IWorld states = ctx.PreviousState;\n            IAccount legacyAccount = states.GetAccount(ReservedAddresses.LegacyAccount);\n\n            string rewardRecord = (Text?)legacyAccount.GetState(RewardRecordAddress);\n\n            rewardRecord = rewardRecord is null\n                ? ctx.Miner.ToString()\n                : $\"{rewardRecord},{ctx.Miner}\";\n\n            legacyAccount = legacyAccount.SetState(RewardRecordAddress, (Text)rewardRecord);\n\n            IValue tempQualifier1 = legacyAccount.GetState(ctx.Miner);\n            int previousReward = tempQualifier1 is Integer i ? (int)i.Value : 0;\n            int reward = previousReward + Reward;\n\n            legacyAccount = legacyAccount.SetState(ctx.Miner, (Integer)reward);\n            return states.SetAccount(ReservedAddresses.LegacyAccount, legacyAccount);\n        }\n    }\n}\n"
  },
  {
    "path": "test/Libplanet.Action.Tests/Common/SetStatesAtBlock.cs",
    "content": "using Bencodex.Types;\nusing Libplanet.Action.State;\nusing Libplanet.Crypto;\n\nnamespace Libplanet.Action.Tests.Common\n{\n    public class SetStatesAtBlock : IAction\n    {\n        private Address _address;\n        private IValue _value = Null.Value;\n        private Address _accountAddress;\n        private long _blockIndex;\n\n        public SetStatesAtBlock()\n        {\n        }\n\n        public SetStatesAtBlock(\n            Address address, IValue value, Address accountAddress, long blockIndex)\n        {\n            _address = address;\n            _blockIndex = blockIndex;\n            _accountAddress = accountAddress;\n            _value = value;\n        }\n\n        public IValue PlainValue => Bencodex.Types.Dictionary.Empty\n            .Add(\"address\", _address.Bencoded)\n            .Add(\"value\", _value)\n            .Add(\"account_address\", _accountAddress.ByteArray)\n            .Add(\"block_index\", _blockIndex);\n\n        public void LoadPlainValue(IValue plainValue)\n        {\n            var dict = (Bencodex.Types.Dictionary)plainValue;\n            _address = new Address(dict[\"address\"]);\n            _value = dict[\"value\"];\n            _accountAddress = new Address(dict[\"account_address\"]);\n            _blockIndex = (Integer)dict[\"block_index\"];\n        }\n\n        public IWorld Execute(IActionContext context)\n        {\n            IWorld states = context.PreviousState;\n            IAccount account = states.GetAccount(_accountAddress);\n            if (context.BlockIndex == _blockIndex)\n            {\n                states = states.SetAccount(_accountAddress, account.SetState(_address, _value));\n            }\n\n            return states;\n        }\n    }\n}\n"
  },
  {
    "path": "test/Libplanet.Action.Tests/Common/SetValidator.cs",
    "content": "using Bencodex.Types;\nusing Libplanet.Action.State;\nusing Libplanet.Types.Consensus;\n\nnamespace Libplanet.Action.Tests.Common\n{\n    /// <summary>\n    /// An action that promotes given address to the validator.\n    /// </summary>\n    public sealed class SetValidator : IAction, IEquatable<SetValidator>, IEquatable<IAction>\n    {\n        /// <summary>\n        /// Creates a new instance of <see cref=\"SetValidator\"/> action.\n        /// </summary>\n        /// <param name=\"validator\">The <see cref=\"Validator\"/> to be set.</param>\n        public SetValidator(Validator validator)\n        {\n            Validator = validator;\n        }\n\n        public SetValidator()\n        {\n            Validator = null;\n        }\n\n        public Validator Validator { get; private set; }\n\n        /// <inheritdoc cref=\"IAction.PlainValue\"/>\n        public IValue PlainValue => Bencodex.Types.Dictionary.Empty\n            .Add(\"validator\", Validator.Bencoded);\n\n        /// <inheritdoc cref=\"IAction.LoadPlainValue(IValue)\"/>\n        public void LoadPlainValue(IValue plainValue)\n        {\n            var dict = (Bencodex.Types.Dictionary)plainValue;\n            Validator = new Validator((Dictionary)dict[\"validator\"]);\n        }\n\n        /// <inheritdoc cref=\"IAction.Execute(IActionContext)\"/>\n        public IWorld Execute(IActionContext context)\n        {\n            IWorld world = context.PreviousState;\n            return world.SetValidatorSet(world.GetValidatorSet().Update(Validator));\n        }\n\n        /// <inheritdoc cref=\"IEquatable{T}.Equals(T)\"/>\n        public bool Equals(SetValidator other) =>\n            other is SetValidator o && Validator.Equals(o.Validator);\n\n        /// <inheritdoc cref=\"IEquatable{T}.Equals(T)\"/>\n        public bool Equals(IAction other) => other is SetValidator o && Equals(o);\n\n        /// <inheritdoc cref=\"object.Equals(object?)\"/>\n        public override bool Equals(object obj) => obj is SetValidator o && Equals(o);\n\n        /// <inheritdoc cref=\"object.GetHashCode()\"/>\n        public override int GetHashCode() => Validator.GetHashCode();\n    }\n}\n"
  },
  {
    "path": "test/Libplanet.Action.Tests/Common/Sleep.cs",
    "content": "using Bencodex.Types;\nusing Libplanet.Action.State;\n\nnamespace Libplanet.Action.Tests.Common\n{\n    [ActionType(\"sleep\")]\n    public class Sleep : BaseAction\n    {\n        public int ZoneId { get; set; }\n\n        public override IValue PlainValue => Dictionary.Empty\n            .Add(\"type_id\", TypeId)\n            .Add(\"values\", Dictionary.Empty\n                .Add(\"zone_id\", ZoneId));\n\n        public override IWorld Execute(IActionContext context)\n        {\n            // No-op.\n            return context.PreviousState;\n        }\n\n        public override void LoadPlainValue(IValue plainValue)\n        {\n            Dictionary values = (Dictionary)GetValues(plainValue);\n            ZoneId = (Integer)values[\"zone_id\"];\n        }\n    }\n}\n"
  },
  {
    "path": "test/Libplanet.Action.Tests/Common/ThrowException.cs",
    "content": "using Bencodex.Types;\nusing Libplanet.Action.State;\nusing Boolean = Bencodex.Types.Boolean;\n\nnamespace Libplanet.Action.Tests.Common\n{\n    public class ThrowException : IAction\n    {\n        public ThrowException()\n        {\n        }\n\n        public bool ThrowOnExecution { get; set; }\n\n        public bool Deterministic { get; set; } = true;\n\n        public IValue PlainValue =>\n            new Bencodex.Types.Dictionary(new Dictionary<string, bool>\n            {\n                [\"throw_on_execution\"] = ThrowOnExecution,\n                [\"deterministic\"] = Deterministic,\n            });\n\n        public void LoadPlainValue(IValue plainValue)\n        {\n            LoadPlainValue((Dictionary)plainValue);\n        }\n\n        public void LoadPlainValue(Dictionary plainValue)\n        {\n            ThrowOnExecution = (Boolean)plainValue[\"throw_on_execution\"];\n            Deterministic = (Boolean)plainValue[\"deterministic\"];\n        }\n\n        public IWorld Execute(IActionContext context)\n        {\n            if (ThrowOnExecution)\n            {\n                if (Deterministic)\n                {\n                    throw new SomeException(\"An expected exception\");\n                }\n                else\n                {\n                    throw new OutOfMemoryException();\n                }\n            }\n\n            return context.PreviousState;\n        }\n\n        public class SomeException : Exception\n        {\n            public SomeException(string message)\n                : base(message)\n            {\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "test/Libplanet.Action.Tests/Common/UpdateValueAction.cs",
    "content": "using Bencodex.Types;\nusing Libplanet.Action.State;\nusing Libplanet.Crypto;\n\nnamespace Libplanet.Action.Tests.Common\n{\n    public sealed class UpdateValueAction : IAction\n    {\n        public UpdateValueAction()\n        {\n        }\n\n        public UpdateValueAction(Address address, int increment)\n        {\n            Address = address;\n            Increment = increment;\n        }\n\n        public Address Address { get; set; }\n\n        public Integer Increment { get; set; }\n\n        public IValue PlainValue => Bencodex.Types.Dictionary.Empty\n            .Add(\"address\", Address.Bencoded)\n            .Add(\"value\", Increment);\n\n        public void LoadPlainValue(IValue plainValue)\n        {\n            Address = new Address(((Dictionary)plainValue)[\"address\"]);\n            Increment = (Integer)((Dictionary)plainValue)[\"value\"];\n        }\n\n        public IWorld Execute(IActionContext ctx)\n        {\n            IWorld states = ctx.PreviousState;\n            IAccount account = states.GetAccount(ReservedAddresses.LegacyAccount);\n            Integer value = account.GetState(Address) is Integer integer\n                ? integer + Increment\n                : Increment;\n\n            account = account.SetState(Address, value);\n            return states.SetAccount(ReservedAddresses.LegacyAccount, account);\n        }\n    }\n}\n"
  },
  {
    "path": "test/Libplanet.Action.Tests/DuplicateActionTypeIdentifierExceptionTest.cs",
    "content": "using System.Collections.Immutable;\nusing Libplanet.Action.Tests.Common;\nusing Xunit;\n\nnamespace Libplanet.Action.Tests\n{\n    public class DuplicateActionTypeIdentifierExceptionTest\n    {\n        private readonly DuplicateActionTypeIdentifierException _exception;\n\n        public DuplicateActionTypeIdentifierExceptionTest()\n        {\n            _exception = new DuplicateActionTypeIdentifierException(\n                \"An error message.\",\n                \"type_id\",\n                ImmutableHashSet.Create(typeof(DumbAction), typeof(NullAction))\n            );\n        }\n\n        [Fact]\n        public void Props()\n        {\n            Assert.Equal(\"type_id\", _exception.TypeIdentifier);\n            Assert.Equal(\n                ImmutableHashSet.Create(typeof(DumbAction), typeof(NullAction)),\n                _exception.DuplicateActionTypes\n            );\n        }\n\n        [Fact]\n        public void Message()\n        {\n            const string expected =\n                \"An error message.\\n\\nType ID: type_id\\nAssociated types:\\n\" +\n                \"  Libplanet.Action.NullAction\\n  Libplanet.Action.Tests.Common.DumbAction\";\n            Assert.Equal(expected, _exception.Message);\n        }\n    }\n}\n"
  },
  {
    "path": "test/Libplanet.Action.Tests/Libplanet.Action.Tests.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <PropertyGroup>\n    <Nullable>disable</Nullable>\n    <ImplicitUsings>enable</ImplicitUsings>\n    <NoWarn>$(NoWarn);SA1401;SYSLIB0011</NoWarn>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <PackageReference Include=\"AsyncEnumerator\" Version=\"4.0.2\" />\n    <PackageReference Include=\"DiffPlex\" Version=\"1.7.0\" />\n    <PackageReference Include=\"Microsoft.Bcl.AsyncInterfaces\" Version=\"6.0.0\" />\n    <PackageReference Include=\"Serilog.Enrichers.Thread\" Version=\"3.0.0\" />\n    <PackageReference Include=\"Serilog.Sinks.TestCorrelator\" Version=\"3.2.0\" />\n    <PackageReference Include=\"Serilog.Sinks.XUnit\" Version=\"1.0.7\" />\n    <PackageReference Include=\"System.Collections.Immutable\" Version=\"1.7.*\" />\n    <PackageReference Include=\"SystemTextJson.JsonDiffPatch.Xunit\" Version=\"1.3.0\" />\n    <PackageReference Include=\"xRetry\" Version=\"1.5.0\" />\n    <PackageReference Include=\"Xunit.SkippableFact\" Version=\"1.3.12\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <ProjectReference Include=\"..\\..\\src\\Libplanet.Action\\Libplanet.Action.csproj\" />\n    <ProjectReference Include=\"..\\..\\src\\Libplanet.Store\\Libplanet.Store.csproj\" />\n    <ProjectReference Include=\"..\\Libplanet.Mocks\\Libplanet.Mocks.csproj\" />\n  </ItemGroup>\n\n</Project>\n"
  },
  {
    "path": "test/Libplanet.Action.Tests/Loader/IndexedActionLoaderTest.cs",
    "content": "using Bencodex.Types;\nusing Libplanet.Action.Loader;\nusing Libplanet.Action.Tests.Common;\nusing Libplanet.Crypto;\nusing Xunit;\n\nnamespace Libplanet.Action.Tests.Loader\n{\n    public class IndexedActionLoaderTest\n    {\n        [Fact]\n        public void Create()\n        {\n            var loader1 = new SingleActionLoader(typeof(DumbAction));\n            var loader2 = new SingleActionLoader(typeof(Attack));\n            var loader3 = new SingleActionLoader(typeof(ContextRecordingAction));\n\n            // Works fine with single loader\n            var indexedLoader = new IndexedActionLoader(\n                new List<(long, IActionLoader)> { (0, loader1) });\n\n            // First index does not start with 0\n            Assert.Throws<ArgumentException>(() => new IndexedActionLoader(\n                new List<(long, IActionLoader)> { (1, loader1) }));\n\n            // Indices not strictly increasing\n            Assert.Throws<ArgumentException>(() => new IndexedActionLoader(\n                new List<(long, IActionLoader)>\n                    { (0, loader1), (5, loader2), (5, loader3) }));\n\n            indexedLoader = new IndexedActionLoader(\n                new List<(long, IActionLoader)>\n                    { (0, loader1), (5, loader2), (7, loader3) });\n        }\n\n        [Fact]\n        public void LoadAction()\n        {\n            var loader1 = new SingleActionLoader(typeof(DumbAction));\n            var loader2 = new SingleActionLoader(typeof(Attack));\n            var loader3 = new SingleActionLoader(typeof(ContextRecordingAction));\n            var action1 = DumbAction.Create((new PrivateKey().Address, \"foo\"));\n            var action2 = new Attack();\n            action2.LoadPlainValue(Dictionary.Empty\n                .Add(\"type_id\", \"attack\")\n                .Add(\"values\", Dictionary.Empty\n                    .Add(\"weapon\", \"sword\")\n                    .Add(\"target\", \"dummy\")\n                    .Add(\"target_address\", new PrivateKey().Address.Bencoded)));\n            var action3 = new ContextRecordingAction(new PrivateKey().Address, new Text(\"Foo\"));\n\n            var loader = new IndexedActionLoader(\n                new List<(long, IActionLoader)>\n                    { (0, loader1), (5, loader2), (7, loader3) });\n\n            foreach (var i in new List<int>() { 0, 1, 2, 3, 4 })\n            {\n                var action = loader.LoadAction(i, action1.PlainValue);\n                Assert.Equal(action1.PlainValue, action.PlainValue);\n                Assert.Throws<InvalidActionException>(\n                    () => loader.LoadAction(i, action2.PlainValue));\n                Assert.Throws<InvalidActionException>(\n                    () => loader.LoadAction(i, action3.PlainValue));\n            }\n\n            foreach (var i in new List<int>() { 5, 6 })\n            {\n                Assert.Throws<InvalidActionException>(\n                    () => loader.LoadAction(i, action1.PlainValue));\n                var action = loader.LoadAction(i, action2.PlainValue);\n                Assert.Equal(action2.PlainValue, action.PlainValue);\n                Assert.Throws<InvalidActionException>(\n                    () => loader.LoadAction(i, action3.PlainValue));\n            }\n\n            foreach (var i in new List<int>() { 7, 8, 9 })\n            {\n                Assert.Throws<InvalidActionException>(\n                    () => loader.LoadAction(i, action1.PlainValue));\n                Assert.Throws<InvalidActionException>(\n                    () => loader.LoadAction(i, action2.PlainValue));\n                var action = loader.LoadAction(i, action3.PlainValue);\n                Assert.Equal(action3.PlainValue, action.PlainValue);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "test/Libplanet.Action.Tests/Loader/SingleActionLoaderTest.cs",
    "content": "using Bencodex.Types;\nusing Libplanet.Action.Loader;\nusing Libplanet.Action.Tests.Common;\nusing Libplanet.Crypto;\nusing Xunit;\n\nnamespace Libplanet.Action.Tests.Loader\n{\n    public class SingleActionLoaderTest\n    {\n        [Fact]\n        public void Create()\n        {\n            var loader = new SingleActionLoader(typeof(Attack));\n            Assert.Equal(typeof(Attack), loader.Type);\n            loader = new SingleActionLoader(typeof(BaseAction));\n            Assert.Equal(typeof(BaseAction), loader.Type);\n        }\n\n        [Fact]\n        public void LoadAction()\n        {\n            var actionTypeLoader = new SingleActionLoader(typeof(Attack));\n\n            var plainValue = Dictionary.Empty\n                .Add(\"type_id\", \"attack\")\n                .Add(\"values\", Dictionary.Empty\n                    .Add(\"weapon\", \"foo\")\n                    .Add(\"target\", \"bar\")\n                    .Add(\"target_address\", new Binary(TestUtils.GetRandomBytes(Address.Size))));\n            var action = new Attack();\n            action.LoadPlainValue(plainValue);\n\n            var loadedAction = actionTypeLoader.LoadAction(0, action.PlainValue);\n            Assert.Equal(plainValue, loadedAction.PlainValue);\n            Assert.Throws<InvalidActionException>(\n                () => actionTypeLoader.LoadAction(0, new Text(\"baz\")));\n        }\n    }\n}\n"
  },
  {
    "path": "test/Libplanet.Action.Tests/Loader/TypedActionLoaderTest.cs",
    "content": "using Bencodex.Types;\nusing Libplanet.Action.Loader;\nusing Libplanet.Action.State;\nusing Libplanet.Action.Sys;\nusing Libplanet.Action.Tests.Common;\nusing Libplanet.Crypto;\nusing Libplanet.Types.Assets;\nusing Libplanet.Types.Consensus;\nusing Xunit;\n\nnamespace Libplanet.Action.Tests.Loader\n{\n    public class TypedActionLoaderTest\n    {\n        [Fact]\n        public void Create()\n        {\n            var loader = TypedActionLoader.Create(typeof(Registry).Assembly, null);\n            Assert.Equal(\n                new Dictionary<IValue, Type>\n                {\n                    [new Integer(2)] = typeof(Initialize),\n                },\n                loader.Types);\n\n            loader = TypedActionLoader.Create(null, typeof(Attack));\n            Assert.Equal(\n                new Dictionary<IValue, Type> { [new Text(\"attack\")] = typeof(Attack) },\n                loader.Types);\n\n            // Wrong assembly\n            Assert.Throws<ArgumentException>(\n                () => TypedActionLoader.Create(typeof(Registry).Assembly, typeof(Attack)));\n        }\n\n        [Fact]\n        public void LoadAction()\n        {\n            // We use a system action since BaseAction and its subtypes are incompatible.\n            var loader = TypedActionLoader.Create(typeof(Registry).Assembly, null);\n            Currency currency = Currency.Uncapped(\"FOO\", 0, null);\n\n            Dictionary plainValue = Dictionary.Empty\n                .Add(\"type_id\", 2)\n                .Add(\n                    \"values\",\n                    new List(\n                        new ValidatorSet(\n                            new List<Validator>()\n                                { new Validator(new PrivateKey().PublicKey, 1) }).Bencoded,\n                        Dictionary.Empty.Add(\n                            ReservedAddresses.LegacyAccount.ToByteArray(),\n                            Dictionary.Empty.Add(\n                                default(Address).ToByteArray(), \"initial value\"))));\n            var action = new Initialize();\n            action.LoadPlainValue(plainValue);\n\n            var loadedAction = loader.LoadAction(0, action.PlainValue);\n            Assert.Equal(action.PlainValue, loadedAction.PlainValue);\n            Assert.Throws<InvalidActionException>(\n                () => loader.LoadAction(0, new Text(\"baz\")));\n        }\n    }\n}\n"
  },
  {
    "path": "test/Libplanet.Action.Tests/RandomExtensions.cs",
    "content": "using Libplanet.Crypto;\nusing Libplanet.Types.Blocks;\nusing Libplanet.Types.Tx;\n\nnamespace Libplanet.Action.Tests\n{\n    internal static class RandomExtensions\n    {\n        public static byte[] NextBytes(this System.Random random, int size)\n        {\n            var buffer = new byte[size];\n            random.NextBytes(buffer);\n            return buffer;\n        }\n\n        public static TxId NextTxId(this System.Random random) =>\n            new TxId(random.NextBytes(TxId.Size));\n\n        public static Address NextAddress(this System.Random random) =>\n            new Address(random.NextBytes(Address.Size));\n\n        public static BlockHash NextBlockHash(this System.Random random) =>\n            new BlockHash(random.NextBytes(BlockHash.Size));\n    }\n}\n"
  },
  {
    "path": "test/Libplanet.Action.Tests/State/KeyConvertersTest.cs",
    "content": "using Libplanet.Common;\nusing Libplanet.Crypto;\nusing Libplanet.Store.Trie;\nusing Libplanet.Types.Assets;\nusing Xunit;\n\nnamespace Libplanet.Action.State.Tests\n{\n    public class KeyConvertersTest\n    {\n        public KeyConvertersTest()\n        {\n        }\n\n        [Fact]\n        public void ToKeysSpec()\n        {\n            var address = new PrivateKey().Address;\n            var currency = Currency.Uncapped(\"Foo\", 2, new PrivateKey().Address);\n\n            Assert.Equal(\n                new KeyBytes(ByteUtil.Hex(address.ByteArray)),\n                KeyConverters.ToStateKey(address));\n\n            Assert.Equal(\n                new KeyBytes(\n                    $\"_{ByteUtil.Hex(address.ByteArray)}_{ByteUtil.Hex(currency.Hash.ByteArray)}\"),\n                KeyConverters.ToFungibleAssetKey(address, currency));\n\n            Assert.Equal(\n                new KeyBytes($\"__{ByteUtil.Hex(currency.Hash.ByteArray)}\"),\n                KeyConverters.ToTotalSupplyKey(currency));\n\n            Assert.Equal(\n                new KeyBytes(\"___\"),\n                KeyConverters.ValidatorSetKey);\n        }\n    }\n}\n"
  },
  {
    "path": "test/Libplanet.Action.Tests/State/WorldBaseStateTest.cs",
    "content": "using Bencodex.Types;\nusing Libplanet.Action.State;\nusing Libplanet.Crypto;\nusing Libplanet.Store;\nusing Libplanet.Store.Trie;\nusing Libplanet.Types.Blocks;\nusing Xunit;\nusing static Libplanet.Action.State.KeyConverters;\n\nnamespace Libplanet.Action.Tests.State\n{\n    public class WorldBaseStateTest\n    {\n        private readonly IKeyValueStore _kvStore;\n        private readonly IStateStore _stateStore;\n\n        public WorldBaseStateTest()\n        {\n            _kvStore = new MemoryKeyValueStore();\n            _stateStore = new TrieStateStore(_kvStore);\n        }\n\n        [Fact]\n        public void Constructor()\n        {\n            ITrie trie = new MerkleTrie(_kvStore);\n            var legacyBaseState = new WorldBaseState(trie, _stateStore);\n            Assert.True(legacyBaseState.Legacy);\n            trie = new MerkleTrie(_kvStore);\n            trie = trie.SetMetadata(new TrieMetadata(BlockMetadata.CurrentProtocolVersion));\n            var modernBaseState = new WorldBaseState(trie, _stateStore);\n            Assert.False(modernBaseState.Legacy);\n        }\n\n        [Fact]\n        public void Metadata()\n        {\n            var accountAddress = new Address(TestUtils.GetRandomBytes(20));\n            var address = new Address(TestUtils.GetRandomBytes(20));\n            ITrie accountTrie = new MerkleTrie(_kvStore);\n            accountTrie = accountTrie.Set(ToStateKey(address), (Text)\"foo\");\n            accountTrie =\n                accountTrie.SetMetadata(new TrieMetadata(BlockMetadata.CurrentProtocolVersion));\n            accountTrie = _stateStore.Commit(accountTrie);\n            ITrie worldTrie = new MerkleTrie(_kvStore);\n            worldTrie = worldTrie.Set(\n                ToStateKey(accountAddress),\n                (Binary)accountTrie.Hash.ByteArray);\n            worldTrie =\n                worldTrie.SetMetadata(new TrieMetadata(BlockMetadata.CurrentProtocolVersion));\n            worldTrie = _stateStore.Commit(worldTrie);\n            var stateRoot = worldTrie.Hash;\n            var world = new World(new WorldBaseState(\n                _stateStore.GetStateRoot(stateRoot),\n                _stateStore));\n            Assert.Equal(worldTrie.Hash, world.Trie.Hash);\n            Assert.False(world.Legacy);\n            var account = world.GetAccount(accountAddress);\n            Assert.Equal(accountTrie.Hash, account.Trie.Hash);\n            Assert.Equal(\n                (Text)\"foo\",\n                world.GetAccount(accountAddress).GetState(address));\n        }\n\n        [Fact]\n        public void MetadataLegacy()\n        {\n            var accountAddress = ReservedAddresses.LegacyAccount;\n            var address = new Address(TestUtils.GetRandomBytes(20));\n            ITrie accountTrie = new MerkleTrie(_kvStore);\n            accountTrie = accountTrie.Set(ToStateKey(address), (Text)\"foo\");\n            accountTrie = _stateStore.Commit(accountTrie);\n            ITrie worldTrie = new MerkleTrie(_kvStore);\n            worldTrie = worldTrie.Set(\n                ToStateKey(accountAddress),\n                (Binary)accountTrie.Hash.ByteArray);\n            worldTrie = worldTrie.SetMetadata(new TrieMetadata(\n                BlockMetadata.CurrentProtocolVersion));\n            worldTrie = _stateStore.Commit(worldTrie);\n            var stateRoot = worldTrie.Hash;\n            var world = new World(new WorldBaseState(\n                _stateStore.GetStateRoot(stateRoot),\n                _stateStore));\n            Assert.Equal(worldTrie.Hash, world.Trie.Hash);\n            Assert.False(world.Legacy);\n            var account = world.GetAccount(accountAddress);\n            Assert.Equal(accountTrie.Hash, account.Trie.Hash);\n            Assert.Equal(\n                (Text)\"foo\",\n                world.GetAccount(accountAddress).GetState(address));\n        }\n    }\n}\n"
  },
  {
    "path": "test/Libplanet.Action.Tests/Sys/InitializeTest.cs",
    "content": "using System.Collections.Immutable;\nusing System.Numerics;\nusing Bencodex.Types;\nusing Libplanet.Action.State;\nusing Libplanet.Action.Sys;\nusing Libplanet.Crypto;\nusing Libplanet.Mocks;\nusing Libplanet.Types.Blocks;\nusing Libplanet.Types.Consensus;\nusing Xunit;\n\nnamespace Libplanet.Action.Tests.Sys\n{\n    public class InitializeTest\n    {\n        private static readonly ValidatorSet _validatorSet = new ValidatorSet(\n            new List<Validator>()\n            {\n                new Validator(new PrivateKey().PublicKey, BigInteger.One),\n            }\n        );\n\n        private static readonly IImmutableDictionary<Address, IValue>\n            _states =\n            new Dictionary<Address, IValue>\n            {\n                [default] = (Text)\"initial value\",\n            }.ToImmutableDictionary();\n\n        [Fact]\n        public void Constructor()\n        {\n            var action = new Initialize(\n                validatorSet: _validatorSet,\n                states: _states\n            );\n            Assert.Equal(_validatorSet, action.ValidatorSet);\n            Assert.Equal(_states, action.States);\n        }\n\n        [Fact]\n        public void Execute()\n        {\n            var random = new System.Random();\n            Address signer = random.NextAddress();\n            var prevState = new World(MockWorldState.CreateModern());\n            BlockHash genesisHash = random.NextBlockHash();\n            var context = new ActionContext(\n                signer: signer,\n                txid: random.NextTxId(),\n                miner: random.NextAddress(),\n                blockIndex: 0,\n                blockProtocolVersion: Block.CurrentProtocolVersion,\n                lastCommit: null,\n                previousState: prevState,\n                randomSeed: 123,\n                isPolicyAction: false,\n                maxGasPrice: null);\n            var initialize = new Initialize(\n                states: _states,\n                validatorSet: _validatorSet\n            );\n\n            var nextState = initialize.Execute(context);\n\n            Assert.Equal(_validatorSet, nextState.GetValidatorSet());\n            Assert.Equal(\n                _states[default],\n                nextState.GetAccount(ReservedAddresses.LegacyAccount).GetState(default));\n        }\n\n        [Fact]\n        public void ExecuteInNonGenesis()\n        {\n            var random = new System.Random();\n            Address signer = random.NextAddress();\n            var prevState = new World(MockWorldState.CreateModern());\n            BlockHash genesisHash = random.NextBlockHash();\n            var key = new PrivateKey();\n            var hash = random.NextBlockHash();\n            var lastCommit = new BlockCommit(\n                0,\n                0,\n                hash,\n                new[]\n                {\n                    new VoteMetadata(\n                        0,\n                        0,\n                        hash,\n                        DateTimeOffset.UtcNow,\n                        key.PublicKey,\n                        BigInteger.One,\n                        VoteFlag.PreCommit).Sign(key),\n                }.ToImmutableArray());\n            var context = new ActionContext(\n                signer: signer,\n                txid: random.NextTxId(),\n                miner: random.NextAddress(),\n                blockIndex: 10,\n                blockProtocolVersion: Block.CurrentProtocolVersion,\n                lastCommit: lastCommit,\n                previousState: prevState,\n                randomSeed: 123,\n                isPolicyAction: false,\n                maxGasPrice: null);\n            var initialize = new Initialize(\n                states: _states,\n                validatorSet: _validatorSet\n            );\n\n            Assert.Throws<InvalidOperationException>(\n                () =>\n                {\n                    _ = initialize.Execute(context);\n                }\n            );\n        }\n\n        [Fact]\n        public void Serialize()\n        {\n            var action = new Initialize(_validatorSet, _states);\n            TestUtils.AssertBencodexEqual(\n                Dictionary.Empty\n                    .Add(\"type_id\", 2)\n                    .Add(\n                        \"values\",\n                        new List(\n                            _validatorSet.Bencoded,\n                            Dictionary.Empty.Add(\n                                default(Address).ToByteArray(),\n                                \"initial value\"))),\n                action.PlainValue);\n        }\n\n        [Fact]\n        public void Deserialize()\n        {\n            var encoded = Dictionary.Empty\n                .Add(\"type_id\", 2)\n                .Add(\n                    \"values\",\n                    new List(\n                        _validatorSet.Bencoded,\n                        Dictionary.Empty.Add(\n                            default(Address).ToByteArray(),\n                            \"initial value\")));\n            var action = new Initialize();\n            action.LoadPlainValue(encoded);\n\n            Assert.Equal(_validatorSet, action.ValidatorSet);\n            Assert.Equal(_states, action.States);\n        }\n    }\n}\n"
  },
  {
    "path": "test/Libplanet.Action.Tests/Sys/RegistryTest.cs",
    "content": "using System.Collections.Immutable;\nusing System.Numerics;\nusing Bencodex.Types;\nusing Libplanet.Action.Sys;\nusing Libplanet.Action.Tests.Common;\nusing Libplanet.Crypto;\nusing Libplanet.Types.Assets;\nusing Libplanet.Types.Consensus;\nusing Xunit;\n\nnamespace Libplanet.Action.Tests.Sys\n{\n    public class RegistryTest\n    {\n        private static readonly ValidatorSet _validatorSet = new ValidatorSet(\n            new List<Validator>()\n            {\n                new Validator(new PrivateKey().PublicKey, BigInteger.One),\n            }\n        );\n\n        private static readonly IImmutableDictionary<Address, IValue>\n            _states =\n            new Dictionary<Address, IValue>\n            {\n                [default] = (Text)\"initial value\",\n            }.ToImmutableDictionary();\n\n        private static readonly Currency FooCurrency = Currency.Uncapped(\"FOO\", 2, null);\n\n        [Fact]\n        public void Deserialize()\n        {\n            Dictionary value = Dictionary.Empty\n                .Add(\"type_id\", 2)\n                .Add(\n                    \"values\",\n                    new List(\n                        _validatorSet.Bencoded,\n                        Dictionary.Empty.Add(\n                            default(Address).ToByteArray(),\n                            \"initial value\")));\n            IAction action = Registry.Deserialize(value);\n            var initialize = Assert.IsType<Initialize>(action);\n            Assert.Equal(_validatorSet, initialize.ValidatorSet);\n            Assert.Equal(_states, initialize.States);\n\n            ArgumentException e;\n            e = Assert.Throws<ArgumentException>(\n                () => Registry.Deserialize((Dictionary)value.Remove(new Text(\"type_id\")))\n            );\n            Assert.Equal(\"serialized\", e.ParamName);\n            Assert.Contains(\"type_id\", e.Message);\n\n            e = Assert.Throws<ArgumentException>(\n                () => Registry.Deserialize((Dictionary)value.Remove(new Text(\"values\")))\n            );\n            Assert.Equal(\"serialized\", e.ParamName);\n            Assert.Contains(\"values\", e.Message);\n\n            e = Assert.Throws<ArgumentException>(\n                () => Registry.Deserialize(value.SetItem(\"type_id\", \"non-integer\"))\n            );\n            Assert.Equal(\"serialized\", e.ParamName);\n            Assert.Contains(\"type_id\", e.Message);\n\n            e = Assert.Throws<ArgumentException>(\n                () => Registry.Deserialize(value.SetItem(\"type_id\", short.MaxValue))\n            );\n            Assert.Contains(\n                \"Failed to deserialize\",\n                e.Message,\n                StringComparison.InvariantCultureIgnoreCase);\n        }\n\n        [Fact]\n        public void Serialize()\n        {\n            var random = new System.Random();\n            Address addr = random.NextAddress();\n            IValue actual = new Initialize(_validatorSet, _states).PlainValue;\n            IValue expected = Dictionary.Empty\n                .Add(\"type_id\", 2)\n                .Add(\n                    \"values\",\n                    new List(\n                        _validatorSet.Bencoded,\n                        Dictionary.Empty.Add(\n                            default(Address).ToByteArray(),\n                            \"initial value\")));\n            TestUtils.AssertBencodexEqual(expected, actual);\n        }\n\n        [Fact]\n        public void IsSystemAction()\n        {\n            var random = new System.Random();\n            Address addr = random.NextAddress();\n            Assert.True(Registry.IsSystemAction(new Initialize(_validatorSet, _states)));\n            Assert.False(Registry.IsSystemAction(DumbAction.Create((addr, \"foo\"))));\n\n            Assert.True(Registry.IsSystemAction(Dictionary.Empty\n                .Add(\"type_id\", new Integer(2))));\n            Assert.False(Registry.IsSystemAction(Dictionary.Empty\n                .Add(\"type_id\", new Integer(2308))));\n            Assert.False(Registry.IsSystemAction(Dictionary.Empty\n                .Add(\"type_id\", new Text(\"mint\"))));\n        }\n    }\n}\n"
  },
  {
    "path": "test/Libplanet.Action.Tests/TestUtils.cs",
    "content": "using System.Collections.Immutable;\nusing Bencodex.Types;\nusing DiffPlex.DiffBuilder;\nusing DiffPlex.DiffBuilder.Model;\nusing Libplanet.Action.State;\nusing Xunit;\nusing Xunit.Sdk;\n\nnamespace Libplanet.Action.Tests\n{\n    public static class TestUtils\n    {\n        private static readonly System.Random _random = new System.Random();\n\n        public static void AssertBencodexEqual(IValue expected, IValue actual)\n        {\n            bool equal = (expected is null && actual is null) ||\n                (expected is Null && actual is Null) ||\n                (expected is Bencodex.Types.Boolean && actual is Bencodex.Types.Boolean &&\n                    expected.Equals(actual)) ||\n                (expected is Integer && actual is Integer && expected.Equals(actual)) ||\n                (expected is Binary && actual is Binary && expected.Equals(actual)) ||\n                (expected is Text && actual is Text && expected.Equals(actual)) ||\n                (expected is List && actual is List && expected.Equals(actual)) ||\n                (expected is Dictionary && actual is Dictionary && expected.Equals(actual));\n            if (equal)\n            {\n                return;\n            }\n\n            string expectedInspection = expected?.ToString() ?? \"(null)\";\n            string actualInspection = actual?.ToString() ?? \"(null)\";\n            DiffPaneModel diffModel = InlineDiffBuilder.Diff(expectedInspection, actualInspection);\n            var prefixes = new Dictionary<ChangeType, string>\n            {\n                [ChangeType.Deleted] = \"-\",\n                [ChangeType.Inserted] = \"+\",\n                [ChangeType.Unchanged] = \" \",\n            };\n\n            string diff = string.Join(\n                Environment.NewLine,\n                diffModel.Lines.Select(line =>\n                    (prefixes.TryGetValue(line.Type, out string prefix) ? prefix : \" \") + line.Text\n                )\n            );\n            throw new XunitException(\n                \"Two Bencodex values are not equal.\\n--- Expected\\n+++ Actual\\n\\n\" + diff\n            );\n        }\n\n        public static void AssertAccountEqual(IAccount expected, IAccount actual)\n        {\n            if (expected is null && actual is null)\n            {\n                return;\n            }\n\n            if (expected is null || actual is null ||\n                !(expected is Account ea && actual is Account aa))\n            {\n                throw new XunitException(\"Accounts should be of type Account\");\n            }\n\n            if (!ea.Trie.Hash.Equals(aa.Trie.Hash))\n            {\n                Assert.Equal(expected, actual);\n            }\n        }\n\n        public static bool DictionaryEquals<T1, T2>(\n            IImmutableDictionary<T1, T2> expected,\n            IImmutableDictionary<T1, T2> actual)\n        {\n            if (expected is null && actual is null)\n            {\n                return true;\n            }\n\n            if (expected is null || actual is null)\n            {\n                return false;\n            }\n\n            if (expected.Count != actual.Count)\n            {\n                return false;\n            }\n\n            foreach (KeyValuePair<T1, T2> pair in expected)\n            {\n                if (!actual.TryGetValue(pair.Key, out T2 value) || !pair.Value.Equals(value))\n                {\n                    return false;\n                }\n            }\n\n            return true;\n        }\n\n        public static byte[] GetRandomBytes(int size)\n        {\n            var bytes = new byte[size];\n            _random.NextBytes(bytes);\n\n            return bytes;\n        }\n    }\n}\n"
  },
  {
    "path": "test/Libplanet.Analyzers.Tests/ActionAnalyzerTest.cs",
    "content": "using Libplanet.Analyzers.Tests.Helpers;\nusing Libplanet.Analyzers.Tests.Verifiers;\nusing Microsoft.CodeAnalysis;\nusing Microsoft.CodeAnalysis.Diagnostics;\nusing Xunit;\n\nnamespace Libplanet.Analyzers.Tests\n{\n    public class ActionAnalyzerTest : DiagnosticVerifier\n    {\n        [CSharpAnalysisFact]\n        public void EmptyCode()\n        {\n            VerifyDiagnostic(@\"\n                public class Sample {\n                    public static void Main() {}\n                }\n            \");\n        }\n\n        [CSharpAnalysisFact]\n        public void LA1001_SystemRandomBreaksActionDeterminism()\n        {\n            var test = @\"\n                using System;\n                using Bencodex.Types;\n                using Libplanet.Action;\n                using Libplanet.Action.State;\n                namespace SampleGame {\n                    public class SampleAction : IAction {\n                        public SampleAction() {}\n                        public IValue PlainValue => Null.Value;\n                        public void LoadPlainValue(IValue plainValue) {}\n                        public IWorld Execute(IActionContext context) {\n                            new Random().Next();\n                            return context.PreviousState;\n                        }\n                        public static void Main() {}\n                    }\n                }\n            \";\n            var expected = new DiagnosticResult\n            {\n                Id = \"LAA1001\",\n                Message = \"The System.Random makes an IAction indeterministic; \" +\n                    \"use IActionContext.GetRandom method instead.\",\n                Severity = DiagnosticSeverity.Warning,\n                Locations = new[] { new DiagnosticResultLocation(12, 29) },\n            };\n\n            VerifyDiagnostic(test, expected);\n        }\n\n        [CSharpAnalysisTheory]\n        [InlineData(\n            false,\n            null,\n            \"int\",\n            \"System.Collections.Generic.HashSet<int>\",\n            \"new HashSet<int> { 1, 2, 3 }\"\n        )]\n        [InlineData(\n            false,\n            \"string, int\",\n            \"System.Collections.Generic.KeyValuePair<string, int>\",\n            \"System.Collections.Generic.Dictionary<string, int>\",\n            \"new Dictionary<string, int> { [\\\"foo\\\"] = 1, [\\\"bar\\\"] = 2 }\"\n        )]\n        [InlineData(\n            true,\n            null,\n            \"int\",\n            \"System.Collections.Generic.List<int>\",\n            \"new List<int> { 1, 2, 3 }\"\n        )]\n        [InlineData(true, null, \"char\", \"char[]\", \"new char[] { 'a', 'b', 'c' }\")]\n        [InlineData(\n            true,\n            null,\n            \"int\",\n            \"System.Collections.Generic.SortedSet<int>\",\n            \"new SortedSet<int> { 1, 2, 3 }\"\n        )]\n        [InlineData(\n            true,\n            \"string, int\",\n            \"System.Collections.Generic.KeyValuePair<string, int>\",\n            \"System.Collections.Generic.SortedDictionary<string, int>\",\n            \"new SortedDictionary<string, int> { [\\\"foo\\\"] = 1, [\\\"bar\\\"] = 2 }\"\n        )]\n        [InlineData(\n            true,\n            \"Bencodex.Types.IKey, Bencodex.Types.IValue\",\n            \"System.Collections.Generic.KeyValuePair<Bencodex.Types.IKey, Bencodex.Types.IValue>\",\n            \"Bencodex.Types.Dictionary\",\n            \"Bencodex.Types.Dictionary.Empty.Add(\\\"foo\\\", 1).Add(\\\"bar\\\", 2)\"\n        )]\n        public void LAA1002_DictionariesOrSetsShouldBeOrderedToEnumerate(\n            bool pass,\n            string kvTypes,\n            string elemType,\n            string typeName,\n            string expr\n        )\n        {\n            string dictCode = string.Empty;\n\n            if (!(kvTypes is null))\n            {\n                dictCode = @\"\n                    // should pass:\n                    v.ToDictionary(key => key, val => val);\n                    v.ToImmutableDictionary();\n                    var newDict = new Dict(v);\n\";\n            }\n\n            var test = @\"\n                using System;\n                using System.Collections.Generic;\n                using System.Collections.Immutable;\n                using System.Linq;\n                using System.Security.Cryptography;\n                using Bencodex.Types;\n                using Libplanet;\n                using Libplanet.Action;\n                using Libplanet.Action.State;\n                namespace SampleGame {\n                    public class SampleAction : IAction {\n                        public SampleAction() {}\n                        public IValue PlainValue => Null.Value;\n                        public void LoadPlainValue(IValue plainValue) {}\n                        public IWorld Execute(IActionContext context) {\n                            // Following code should all fail:\n                            var v = \" + expr + @\";\n                            ConsumeEnumerable(v);\n                            var a = v.ToArray();\n                            var randomlySorted = new List<\" + elemType + @\">(v);\n                            foreach (var e in v) Console.WriteLine(e.ToString());\n\n                            // Following code should all pass:\n                            ConsumeEnumerable(v.OrderBy(e => e));\n                            var orderedArray = v.OrderBy(e => e).ToArray();\n                            foreach (var e in v.OrderBy(e => e)) {\n                                Console.WriteLine(e.ToString());\n                            }\n                            v.ToHashSet();\n                            v.ToImmutableHashSet();\n                            var newSet = new HashSet<\" + elemType + @\">(v);\n                            \" + dictCode + @\"\n                            return context.PreviousState;\n                        }\n                        public void ConsumeEnumerable(IEnumerable<\" + elemType + @\"> it) {}\n                        public static void Main() {}\n                    }\n                }\n            \";\n\n            if (!(kvTypes is null))\n            {\n                test += @\"\n                    public class Dict : Dictionary<\" + kvTypes + @\"> {\n                        public Dict(IEnumerable<\" + elemType + @\"> kvs) : base() {\n                            foreach (var kv in kvs) {\n                                Add(kv.Key, kv.Value);\n                            }\n                        }\n                    }\n                \";\n            }\n\n            if (pass)\n            {\n                VerifyDiagnostic(test);\n                return;\n            }\n\n            string message = $\"Enumerating an instance of {typeName} is indeterministic since \" +\n                $\"the order of {typeName} is unspecified; explicitly sort them before\";\n            DiagnosticResult[] expected =\n            {\n                new DiagnosticResult\n                {\n                    Id = \"LAA1002\",\n                    Message =\n                        $\"{message} passing to SampleGame.SampleAction.ConsumeEnumerable(\" +\n                        $\"System.Collections.Generic.IEnumerable<{elemType}>) method.\",\n                    Severity = DiagnosticSeverity.Warning,\n                    Locations = new[] { new DiagnosticResultLocation(19, 47) },\n                },\n                new DiagnosticResult\n                {\n                    Id = \"LAA1002\",\n                    Message = $\"{message} passing to System.Linq.Enumerable.ToArray<{elemType}>(\" +\n                        $\"System.Collections.Generic.IEnumerable<{elemType}>) method.\",\n                    Severity = DiagnosticSeverity.Warning,\n                    Locations = new[] { new DiagnosticResultLocation(20, 37) },\n                },\n                new DiagnosticResult\n                {\n                    Id = \"LAA1002\",\n                    Message =\n                        $\"{message} passing to System.Collections.Generic.List<{elemType}>.\" +\n                        $\"List(System.Collections.Generic.IEnumerable<{elemType}>) constructor.\",\n                    Severity = DiagnosticSeverity.Warning,\n                    Locations = new[] { new DiagnosticResultLocation(21, 61 + elemType.Length) },\n                },\n                new DiagnosticResult\n                {\n                    Id = \"LAA1002\",\n                    Message = $\"{message} iterating via foreach.\",\n                    Severity = DiagnosticSeverity.Warning,\n                    Locations = new[] { new DiagnosticResultLocation(22, 47) },\n                },\n            };\n\n            VerifyDiagnostic(test, expected);\n        }\n\n        protected override DiagnosticAnalyzer GetDiagnosticAnalyzer() =>\n            new ActionAnalyzer();\n    }\n}\n"
  },
  {
    "path": "test/Libplanet.Analyzers.Tests/CSharpAnalysisFactAttribute.cs",
    "content": "using System;\nusing Microsoft.CodeAnalysis;\nusing Xunit;\n\nnamespace Libplanet.Analyzers.Tests\n{\n    public sealed class CSharpAnalysisFactAttribute : FactAttribute\n    {\n        public static readonly bool CSharpSupported = IsCsharpSupported();\n\n        public CSharpAnalysisFactAttribute()\n        {\n            if (!CSharpSupported)\n            {\n                Skip = $\"Code analysis on {LanguageNames.CSharp} is unsupported on this runtime.\";\n            }\n        }\n\n        private static bool IsCsharpSupported()\n        {\n            try\n            {\n                _ = new AdhocWorkspace().CurrentSolution.AddProject(\n                    ProjectId.CreateNewId(\"TestProject\"),\n                    \"TestProject\",\n                    \"TestProject\",\n                    LanguageNames.CSharp\n                );\n            }\n            catch (NotSupportedException e)\n            {\n                if (e.Message.Contains(LanguageNames.CSharp))\n                {\n                    return false;\n                }\n            }\n\n            return true;\n        }\n    }\n}\n"
  },
  {
    "path": "test/Libplanet.Analyzers.Tests/Helpers/DiagnosticResult.cs",
    "content": "using System;\nusing Microsoft.CodeAnalysis;\n\nnamespace Libplanet.Analyzers.Tests.Helpers\n{\n    /// <summary>\n    /// Struct that stores information about a <see cref=\"Diagnostic\"/> appearing in a source.\n    /// </summary>\n    public struct DiagnosticResult\n    {\n        private DiagnosticResultLocation[] locations;\n\n        public DiagnosticResultLocation[] Locations\n        {\n            get\n            {\n                if (this.locations == null)\n                {\n                    this.locations = new DiagnosticResultLocation[] { };\n                }\n\n                return this.locations;\n            }\n\n            set\n            {\n                this.locations = value;\n            }\n        }\n\n        public DiagnosticSeverity Severity { get; set; }\n\n        public string Id { get; set; }\n\n        public string Message { get; set; }\n\n        public string Path => this.Locations.Length > 0 ? this.Locations[0].Path : string.Empty;\n\n        public int Line => this.Locations.Length > 0 ? this.Locations[0].Line : -1;\n\n        public int Column => this.Locations.Length > 0 ? this.Locations[0].Column : -1;\n    }\n}\n"
  },
  {
    "path": "test/Libplanet.Analyzers.Tests/Helpers/DiagnosticResultLocation.cs",
    "content": "using System;\n\nnamespace Libplanet.Analyzers.Tests.Helpers\n{\n    /// <summary>\n    /// Location where the diagnostic appears, as determined by path, line number,\n    /// and column number.\n    /// </summary>\n    public struct DiagnosticResultLocation\n    {\n        public DiagnosticResultLocation(string path, int line, int column)\n        {\n            if (line < -1)\n            {\n                throw new ArgumentOutOfRangeException(nameof(line), \"Line must be >= -1.\");\n            }\n\n            if (column < -1)\n            {\n                throw new ArgumentOutOfRangeException(nameof(column), \"Column must be >= -1.\");\n            }\n\n            this.Path = path;\n            this.Line = line;\n            this.Column = column;\n        }\n\n        public DiagnosticResultLocation(int line, int column)\n            : this(\"Test0.cs\", line, column)\n        {\n        }\n\n        public string Path { get; }\n\n        public int Line { get; }\n\n        public int Column { get; }\n    }\n}\n"
  },
  {
    "path": "test/Libplanet.Analyzers.Tests/Libplanet.Analyzers.Tests.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <PropertyGroup>\n    <Nullable>disable</Nullable>\n    <TreatWarningsAsErrors>true</TreatWarningsAsErrors>\n    <NoWarn>$(NoWarn);SA1401</NoWarn>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <PackageReference Include=\"Microsoft.CodeAnalysis.Analyzers\" Version=\"3.3.0\" />\n    <PackageReference Include=\"Microsoft.CodeAnalysis.CSharp.Workspaces\" Version=\"3.7.0\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <ProjectReference Include=\"..\\..\\tools\\Libplanet.Analyzers\\Libplanet.Analyzers.csproj\" />\n  </ItemGroup>\n\n</Project>\n"
  },
  {
    "path": "test/Libplanet.Analyzers.Tests/Verifiers/CSharpAnalysisTheoryAttribute.cs",
    "content": "using Microsoft.CodeAnalysis;\nusing Xunit;\n\nnamespace Libplanet.Analyzers.Tests.Verifiers\n{\n    public sealed class CSharpAnalysisTheoryAttribute : TheoryAttribute\n    {\n        public CSharpAnalysisTheoryAttribute()\n        {\n            if (!CSharpAnalysisFactAttribute.CSharpSupported)\n            {\n                Skip = $\"Code analysis on {LanguageNames.CSharp} is unsupported on this runtime.\";\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "test/Libplanet.Analyzers.Tests/Verifiers/DiagnosticVerifier.Helper.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Collections.Immutable;\nusing System.IO;\nusing System.Linq;\nusing System.Reflection;\nusing Bencodex.Types;\nusing Libplanet.Action;\nusing Libplanet.Crypto;\nusing Microsoft.CodeAnalysis;\nusing Microsoft.CodeAnalysis.Diagnostics;\nusing Microsoft.CodeAnalysis.Emit;\nusing Microsoft.CodeAnalysis.Text;\n\nnamespace Libplanet.Analyzers.Tests.Verifiers\n{\n    /// <summary>\n    /// Class for turning strings into documents and getting the diagnostics on them.\n    /// All methods are static.\n    /// </summary>\n    public abstract partial class DiagnosticVerifier\n    {\n        internal const string DefaultFilePathPrefix = \"Test\";\n        internal const string CSharpDefaultFileExt = \"cs\";\n        internal const string VisualBasicDefaultExt = \"vb\";\n        internal const string TestProjectName = \"TestProject\";\n\n        /// <summary>\n        /// Given an analyzer and a document to apply it to, run the analyzer and gather an array of\n        /// diagnostics found in it.\n        /// The returned diagnostics are then ordered by location in the source document.\n        /// </summary>\n        /// <param name=\"analyzer\">The analyzer to run on the documents.</param>\n        /// <param name=\"documents\">The documents that the analyzer will be run on.</param>\n        /// <returns>Diagnostics that surfaced in the source code, sorted by their location.\n        /// </returns>\n        protected static Diagnostic[] GetSortedDiagnosticsFromDocuments(\n            DiagnosticAnalyzer analyzer,\n            Document[] documents\n        )\n        {\n            var projects = new HashSet<Project>();\n            foreach (var document in documents)\n            {\n                projects.Add(document.Project);\n            }\n\n            var diagnostics = new List<Diagnostic>();\n            foreach (var project in projects)\n            {\n                Compilation result = project.GetCompilationAsync().Result;\n                EmitResult emitted = result.Emit(new MemoryStream());\n                if (!emitted.Success)\n                {\n                    throw new InvalidOperationException(\n                        \"Failed to compile:\\n\" + string.Join(\n                            \"\\n\",\n                            emitted.Diagnostics.Select(d => $\"\\t{d.ToString()}\")\n                        )\n                    );\n                }\n\n                var compilationWithAnalyzers = result.WithAnalyzers(\n                    ImmutableArray.Create(analyzer));\n                var diags = compilationWithAnalyzers.GetAnalyzerDiagnosticsAsync().Result;\n                foreach (var diag in diags)\n                {\n                    if (diag.Location == Location.None || diag.Location.IsInMetadata)\n                    {\n                        diagnostics.Add(diag);\n                    }\n                    else\n                    {\n                        for (int i = 0; i < documents.Length; i++)\n                        {\n                            var document = documents[i];\n                            var tree = document.GetSyntaxTreeAsync().Result;\n                            if (tree == diag.Location.SourceTree)\n                            {\n                                diagnostics.Add(diag);\n                            }\n                        }\n                    }\n                }\n            }\n\n            var results = SortDiagnostics(diagnostics);\n            diagnostics.Clear();\n            return results;\n        }\n\n        /// <summary>\n        /// Create a document from a string through creating a project that contains it.\n        /// </summary>\n        /// <param name=\"source\">Classes in the form of a string.</param>\n        /// <param name=\"language\">The language the source code is in.</param>\n        /// <returns>A document created from the source string.</returns>\n        protected static Document CreateDocument(\n            string source,\n            string language = LanguageNames.CSharp\n        ) =>\n            CreateProject(new[] { source }, language).Documents.First();\n\n        /// <summary>\n        /// Given classes in the form of strings, their language, and an\n        /// <see cref=\"IDiagnosticAnalyzer\"/> to apply to it, return the diagnostics found\n        /// in the string after converting it to a document.\n        /// </summary>\n        /// <param name=\"sources\">Classes in the form of strings.</param>\n        /// <param name=\"language\">The language the source classes are in.</param>\n        /// <param name=\"analyzer\">The analyzer to be run on the sources.</param>\n        /// <returns>Diagnostics that surfaced in the source code, sorted by their location.\n        /// </returns>\n        private static Diagnostic[] GetSortedDiagnostics(\n            string[] sources,\n            string language,\n            DiagnosticAnalyzer analyzer\n        ) =>\n            GetSortedDiagnosticsFromDocuments(analyzer, GetDocuments(sources, language));\n\n        /// <summary>\n        /// Sorts diagnostics by location in source document.\n        /// </summary>\n        /// <param name=\"diagnostics\">The list of Diagnostics to be sorted.</param>\n        /// <returns>An IEnumerable containing the Diagnostics in order of Location.</returns>\n        private static Diagnostic[] SortDiagnostics(IEnumerable<Diagnostic> diagnostics)\n        {\n            return diagnostics.OrderBy(d => d.Location.SourceSpan.Start).ToArray();\n        }\n\n        /// <summary>\n        /// Given an array of strings as sources and a language, turn them into a project and\n        /// return the documents and spans of it.\n        /// </summary>\n        /// <param name=\"sources\">Classes in the form of strings.</param>\n        /// <param name=\"language\">The language the source code is in.</param>\n        /// <returns>A Tuple containing the Documents produced from the sources and their TextSpans\n        /// if relevant.</returns>\n        private static Document[] GetDocuments(string[] sources, string language)\n        {\n            if (language != LanguageNames.CSharp && language != LanguageNames.VisualBasic)\n            {\n                throw new ArgumentException($\"Unsupported language: {language}.\");\n            }\n\n            var project = CreateProject(sources, language);\n            var documents = project.Documents.ToArray();\n\n            if (sources.Length != documents.Length)\n            {\n                throw new InvalidOperationException(\n                    \"Amount of sources did not match amount of Documents created.\"\n                );\n            }\n\n            return documents;\n        }\n\n        /// <summary>\n        /// Creates a project using the inputted strings as sources.\n        /// </summary>\n        /// <param name=\"sources\">Classes in the form of strings.</param>\n        /// <param name=\"language\">The language the source code is in.</param>\n        /// <returns>A project created out of the documents created from\n        /// the source strings.</returns>\n        private static Project CreateProject(\n            string[] sources,\n            string language = LanguageNames.CSharp\n        )\n        {\n            string fileNamePrefix = DefaultFilePathPrefix;\n            string fileExt = language == LanguageNames.CSharp\n                ? CSharpDefaultFileExt\n                : VisualBasicDefaultExt;\n\n            var projectId = ProjectId.CreateNewId(debugName: TestProjectName);\n\n            var solution = new AdhocWorkspace()\n                .CurrentSolution\n                .AddProject(projectId, TestProjectName, TestProjectName, language);\n            IEnumerable<Assembly> assemblies = GetAssemblies(\n                typeof(object),\n                typeof(Enumerable),\n                typeof(Compilation),\n                typeof(Address),\n                typeof(IAction),\n                typeof(IValue)\n            );\n            foreach (Assembly assembly in assemblies)\n            {\n                if (assembly.IsDynamic)\n                {\n                    continue;\n                }\n\n                solution = solution.AddMetadataReference(\n                    projectId,\n                    MetadataReference.CreateFromFile(assembly.Location)\n                );\n            }\n\n            int count = 0;\n            foreach (var source in sources)\n            {\n                var newFileName = fileNamePrefix + count + \".\" + fileExt;\n                var documentId = DocumentId.CreateNewId(projectId, debugName: newFileName);\n                solution = solution.AddDocument(documentId, newFileName, SourceText.From(source));\n                count++;\n            }\n\n            return solution.GetProject(projectId);\n        }\n\n        private static IEnumerable<Assembly> GetAssemblies(params Type[] rootTypes)\n        {\n            var registry = new Dictionary<string, Assembly>();\n\n            void Register(Assembly assembly)\n            {\n                if (assembly.IsDynamic || registry.ContainsKey(assembly.FullName))\n                {\n                    return;\n                }\n\n                registry.Add(assembly.FullName, assembly);\n                foreach (AssemblyName @ref in assembly.GetReferencedAssemblies())\n                {\n                    if (!registry.ContainsKey(@ref.FullName))\n                    {\n                        Assembly dep;\n                        try\n                        {\n                            dep = Assembly.Load(@ref);\n                        }\n                        catch (FileNotFoundException)\n                        {\n                            continue;\n                        }\n\n                        Register(dep);\n                    }\n                }\n            }\n\n            foreach (Type rootType in rootTypes)\n            {\n                Register(rootType.Assembly);\n            }\n\n            return registry.Values;\n        }\n    }\n}\n"
  },
  {
    "path": "test/Libplanet.Analyzers.Tests/Verifiers/DiagnosticVerifier.cs",
    "content": "using System.Collections.Generic;\nusing System.Linq;\nusing System.Text;\nusing Libplanet.Analyzers.Tests.Helpers;\nusing Microsoft.CodeAnalysis;\nusing Microsoft.CodeAnalysis.Diagnostics;\nusing Xunit;\n\nnamespace Libplanet.Analyzers.Tests.Verifiers\n{\n    /// <summary>\n    /// Superclass of all unit tests for <see cref=\"DiagnosticAnalyzers\"/>.\n    /// </summary>\n    public abstract partial class DiagnosticVerifier\n    {\n        /// <summary>\n        /// Gets the analyzer being tested, to be implemented in non-abstract class.\n        /// </summary>\n        /// <returns>\n        /// The <see cref=\"DiagnosticAnalyzer\"/> to be used for testing.\n        /// </returns>\n        protected abstract DiagnosticAnalyzer GetDiagnosticAnalyzer();\n\n        /// <summary>\n        /// Called to test a <see cref=\"DiagnosticAnalyzer\"/> when applied on the inputted strings\n        /// as a source.\n        /// Note: input a <see cref=\"DiagnosticResult\"/> for each <see cref=\"Diagnostic\"/> expected.\n        /// </summary>\n        /// <param name=\"source\">A class in the form of a string to run the analyzer on.</param>\n        /// <param name=\"expected\">Diagnostic results that should appear after the analyzer is run\n        /// on the source.</param>\n        protected void VerifyDiagnostic(string source, params DiagnosticResult[] expected) =>\n            VerifyDiagnostics(new string[] { source }, GetDiagnosticAnalyzer(), expected);\n\n        /// <summary>\n        /// Called to test a <see cref=\"DiagnosticAnalyzer\"/> when applied on the inputted strings\n        /// as a source.\n        /// Note: input a <see cref=\"DiagnosticResult\"/> for each <see cref=\"Diagnostic\"/> expected.\n        /// </summary>\n        /// <param name=\"sources\">An array of strings to create source documents from to run\n        /// the analyzers on.</param>\n        /// <param name=\"expected\">Diagnostic results that should appear after the analyzer is run\n        /// on the sources.</param>\n        protected void VerifyDiagnostic(string[] sources, params DiagnosticResult[] expected) =>\n            VerifyDiagnostics(sources, GetDiagnosticAnalyzer(), expected);\n\n        /// <summary>\n        /// Checks each of the actual <see cref=\"Diagnostics\"/> found and compares them with\n        /// the corresponding <see cref=\"DiagnosticResult\"/> in the array of expected results.\n        /// <see cref=\"Diagnostic\"/>s are considered equal only if\n        /// the <see cref=\"DiagnosticResultLocation\"/>, <see cref=\"Diagnostic.Id\"/>,\n        /// <see cref=\"Diagnostic.Severity\"/>, and <see cref=\"Diagnostic.Message\"/> of\n        /// the <see cref=\"DiagnosticResult\"/> match the actual diagnostic.\n        /// </summary>\n        /// <param name=\"actualResults\">The diagnostics found by the compiler after running\n        /// the analyzer on the source code.</param>\n        /// <param name=\"analyzer\">The analyzer that was being run on the sources.</param>\n        /// <param name=\"expectedResults\">Diagnostic results that should have appeared in the code.\n        /// </param>\n        private static void VerifyDiagnosticResults(\n            IEnumerable<Diagnostic> actualResults,\n            DiagnosticAnalyzer analyzer,\n            params DiagnosticResult[] expectedResults\n        )\n        {\n            int expectedCount = expectedResults.Count();\n            int actualCount = actualResults.Count();\n\n            string diagnosticsOutput = actualResults.Any()\n                ? FormatDiagnostics(analyzer, actualResults.ToArray())\n                : \"    NONE.\";\n            string msg =\n                $\"Mismatch between number of diagnostics returned, expected \\\"{expectedCount}\\\" \" +\n                $\"actual \\\"{actualCount}\\\"\\r\\n\\r\\nDiagnostics:\\r\\n{diagnosticsOutput}\\r\\n\";\n            Assert.True(expectedCount == actualCount, msg);\n\n            for (int i = 0; i < expectedResults.Length; i++)\n            {\n                Diagnostic actual = actualResults.ElementAt(i);\n                DiagnosticResult expected = expectedResults[i];\n\n                if (expected.Line == -1 && expected.Column == -1)\n                {\n                    msg =\n                        \"Expected:\\nA project diagnostic with no location\\n\" +\n                        $\"Actual:\\n{FormatDiagnostics(analyzer, actual)}\";\n                    Assert.True(actual.Location == Location.None, msg);\n                }\n                else\n                {\n                    VerifyDiagnosticLocation(\n                        analyzer,\n                        actual,\n                        actual.Location,\n                        expected.Locations.First()\n                    );\n                    Location[] additionalLocations = actual.AdditionalLocations.ToArray();\n\n                    msg =\n                        $\"Expected {expected.Locations.Length - 1} additional locations but got \" +\n                        $\"{additionalLocations.Length} for Diagnostic:\" +\n                        $\"\\r\\n    {FormatDiagnostics(analyzer, actual)}\\r\\n\";\n                    Assert.True(\n                        additionalLocations.Length == expected.Locations.Length - 1,\n                        msg\n                    );\n\n                    for (int j = 0; j < additionalLocations.Length; ++j)\n                    {\n                        VerifyDiagnosticLocation(\n                            analyzer,\n                            actual,\n                            additionalLocations[j],\n                            expected.Locations[j + 1]\n                        );\n                    }\n                }\n\n                msg =\n                    $\"Expected diagnostic id to be \\\"{expected.Id}\\\" was \\\"{actual.Id}\\\"\\r\\n\\r\\n\" +\n                    $\"Diagnostic:\\r\\n    {FormatDiagnostics(analyzer, actual)}\\r\\n\";\n                Assert.True(actual.Id == expected.Id);\n\n                msg =\n                    $\"Expected diagnostic severity to be \\\"{expected.Severity}\\\" was \" +\n                    $\"\\\"{actual.Severity}\\\"\\r\\n\\r\\nDiagnostic:\" +\n                    $\"\\r\\n    {FormatDiagnostics(analyzer, actual)}\\r\\n\";\n                Assert.True(actual.Severity == expected.Severity);\n\n                msg =\n                    $\"Expected diagnostic message to be \\\"{expected.Message}\\\" was \" +\n                    $\"\\\"{actual.GetMessage()}\\\"\\r\\n\\r\\nDiagnostic:\" +\n                    $\"\\r\\n    {FormatDiagnostics(analyzer, actual)}\\r\\n\";\n                Assert.True(actual.GetMessage() == expected.Message, msg);\n            }\n        }\n\n        /// <summary>\n        /// Helper method to <see cref=\"VerifyDiagnosticResults\"/> that checks the location of\n        /// a diagnostic and compares it with the location in the expected\n        /// <see cref=\"DiagnosticResult\"/>.\n        /// </summary>\n        /// <param name=\"analyzer\">The analyzer that was being run on the sources.</param>\n        /// <param name=\"diagnostic\">The diagnostic that was found in the code.</param>\n        /// <param name=\"actual\">The location of the diagnostic found in the code.</param>\n        /// <param name=\"expected\">The <see cref=\"DiagnosticResultLocation\"/> that should have been\n        /// found.</param>\n        private static void VerifyDiagnosticLocation(\n            DiagnosticAnalyzer analyzer,\n            Diagnostic diagnostic,\n            Location actual,\n            DiagnosticResultLocation expected\n        )\n        {\n            var actualSpan = actual.GetLineSpan();\n\n            string msg =\n                $\"Expected diagnostic to be in file \\\"{expected.Path}\\\" was actually in file\" +\n                $\" \\\"{actualSpan.Path}\\\"\\r\\n\\r\\nDiagnostic:\" +\n                $\"\\r\\n    {FormatDiagnostics(analyzer, diagnostic)}\\r\\n\";\n            Assert.True(\n                actualSpan.Path == expected.Path || (\n                    actualSpan.Path != null &&\n                    actualSpan.Path.Contains($\"{DefaultFilePathPrefix}0.\") &&\n                    expected.Path.Contains($\"{DefaultFilePathPrefix}.\")\n                ),\n                msg\n            );\n\n            var actualLinePosition = actualSpan.StartLinePosition;\n\n            // Only check line position if there is an actual line in the real diagnostic.\n            if (actualLinePosition.Line > 0)\n            {\n                msg =\n                    $\"Expected diagnostic to be on line \\\"{expected.Line}\\\" was actually on line\" +\n                    $\" \\\"{actualLinePosition.Line + 1}\\\"\\r\\n\\r\\nDiagnostic:\" +\n                    $\"\\r\\n    {FormatDiagnostics(analyzer, diagnostic)}\\r\\n\";\n                Assert.True(actualLinePosition.Line + 1 == expected.Line, msg);\n            }\n\n            // Only check column position if there is an actual column position\n            // in the real diagnostic.\n            if (actualLinePosition.Character > 0)\n            {\n                msg =\n                    $\"Expected diagnostic to start at column \\\"{expected.Column}\\\" was actually \" +\n                    $\"at column \\\"{actualLinePosition.Character + 1}\\\"\\r\\n\\r\\nDiagnostic:\" +\n                    $\"\\r\\n    {FormatDiagnostics(analyzer, diagnostic)}\\r\\n\";\n                Assert.True(expected.Column == actualLinePosition.Character + 1, msg);\n            }\n        }\n\n        /// <summary>\n        /// Helper method to format a <see cref=\"Diagnostic\"/> into an easily readable string.\n        /// </summary>\n        /// <param name=\"analyzer\">The analyzer that this verifier tests.</param>\n        /// <param name=\"diagnostics\">The diagnostics to be formatted.</param>\n        /// <returns>The diagnostics formatted as a string.</returns>\n        private static string FormatDiagnostics(\n            DiagnosticAnalyzer analyzer,\n            params Diagnostic[] diagnostics\n        )\n        {\n            var builder = new StringBuilder();\n            for (int i = 0; i < diagnostics.Length; ++i)\n            {\n                builder.AppendLine(\"// \" + diagnostics[i].ToString());\n\n                var analyzerType = analyzer.GetType();\n                var rules = analyzer.SupportedDiagnostics;\n\n                foreach (var rule in rules)\n                {\n                    if (rule != null && rule.Id == diagnostics[i].Id)\n                    {\n                        var location = diagnostics[i].Location;\n                        if (location == Location.None)\n                        {\n                            builder.AppendFormat(\n                                \"GetGlobalResult({0}.{1})\",\n                                analyzerType.Name,\n                                rule.Id\n                            );\n                        }\n                        else\n                        {\n                            var msg =\n                                \"Test base does not currently handle diagnostics in metadata \" +\n                                $\"locations. Diagnostic in metadata: {diagnostics[i]}\\r\\n\";\n                            Assert.True(location.IsInSource, msg);\n\n                            string resultMethodName =\n                                diagnostics[i].Location.SourceTree.FilePath.EndsWith(\".cs\")\n                                    ? \"GetCSharpResultAt\"\n                                    : \"GetBasicResultAt\";\n                            var linePosition =\n                                diagnostics[i].Location.GetLineSpan().StartLinePosition;\n\n                            builder.AppendFormat(\n                                \"{0}({1}, {2}, {3}.{4})\",\n                                resultMethodName,\n                                linePosition.Line + 1,\n                                linePosition.Character + 1,\n                                analyzerType.Name,\n                                rule.Id\n                            );\n                        }\n\n                        if (i != diagnostics.Length - 1)\n                        {\n                            builder.Append(',');\n                        }\n\n                        builder.AppendLine();\n                        break;\n                    }\n                }\n            }\n\n            return builder.ToString();\n        }\n\n        /// <summary>\n        /// General method that gets a collection of actual diagnostics found in the source after\n        /// the analyzer is run, then verifies each of them.\n        /// </summary>\n        /// <param name=\"sources\">An array of strings to create source documents from to run\n        /// the analyzers on.</param>\n        /// <param name=\"analyzer\">The analyzer to be run on the source code.</param>\n        /// <param name=\"expected\"><see cref=\"DiagnosticResult\"/>s that should appear after\n        /// the analyzer is run on the sources.</param>\n        private void VerifyDiagnostics(\n            string[] sources,\n            DiagnosticAnalyzer analyzer,\n            params DiagnosticResult[] expected\n        )\n        {\n            var diagnostics = GetSortedDiagnostics(sources, LanguageNames.CSharp, analyzer);\n            VerifyDiagnosticResults(diagnostics, analyzer, expected);\n        }\n    }\n}\n"
  },
  {
    "path": "test/Libplanet.Crypto.Secp256k1.Tests/Libplanet.Crypto.Secp256k1.Tests.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <PropertyGroup>\n    <TreatWarningsAsErrors>true</TreatWarningsAsErrors>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <PackageReference Include=\"System.Collections.Immutable\" Version=\"1.7.*\" />\n  </ItemGroup>\n\n  <ItemGroup Condition=\"'$(SkipSonar)' != 'true'\">\n    <PackageReference Remove=\"SonarAnalyzer.CSharp\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <ProjectReference Include=\"..\\..\\src\\Libplanet\\Libplanet.csproj\" />\n    <ProjectReference Include=\"..\\..\\src\\Libplanet.Crypto.Secp256k1\\Libplanet.Crypto.Secp256k1.csproj\" />\n  </ItemGroup>\n\n</Project>\n"
  },
  {
    "path": "test/Libplanet.Crypto.Secp256k1.Tests/Secp256k1CryptoBackendTest.cs",
    "content": "using Libplanet.Common;\nusing Libplanet.Crypto;\n\nnamespace Libplanet.Crypto.Secp256k1.Tests;\n\nusing System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Security.Cryptography;\nusing Libplanet.Crypto;\nusing Libplanet.Crypto.Secp256k1;\nusing Xunit;\n\npublic class Secp256k1CryptoBackendTest\n{\n    public static IEnumerable<object[]> GenerateRandomBytes()\n    {\n        Random random = new ();\n        yield return new object[] { Array.Empty<byte>() };\n        for (int i = 1; i < 100; i++)\n        {\n            byte[] bytes = new byte[i];\n            random.NextBytes(bytes);\n            yield return new object[] { bytes };\n        }\n    }\n\n    [Theory]\n    [MemberData(nameof(GenerateRandomBytes))]\n    public void EnsureIfItBehavesEquivalentToDefaultCryptoBackend(byte[] bytes)\n    {\n        DefaultCryptoBackend<SHA256> defaultBackend = new ();\n        Secp256k1CryptoBackend<SHA256> nativeBackend = new ();\n        PrivateKey key = new ();\n        PublicKey pubKey = key.PublicKey;\n        var msgHash = HashDigest<SHA256>.DeriveFrom(bytes);\n        byte[] wrongHashBytes = new byte[HashDigest<SHA256>.Size];\n        Array.Copy(msgHash.ToByteArray(), 0, wrongHashBytes, 0, wrongHashBytes.Length - 1);\n        wrongHashBytes[wrongHashBytes.Length - 1] =\n            unchecked((byte)(msgHash.ByteArray.Last() + 1));\n        HashDigest<SHA256> wrongHash = new (wrongHashBytes);\n\n        byte[] nativeSig = nativeBackend.Sign(msgHash, key);\n        Assert.True(defaultBackend.Verify(msgHash, nativeSig, pubKey));\n        byte[] wrongNativeSig = nativeBackend.Sign(wrongHash, key);\n        Assert.False(defaultBackend.Verify(msgHash, wrongNativeSig, pubKey));\n\n        byte[] defaultSig = defaultBackend.Sign(msgHash, key);\n        Assert.True(nativeBackend.Verify(msgHash, defaultSig, pubKey));\n        byte[] wrongDefaultSig = defaultBackend.Sign(wrongHash, key);\n        Assert.False(nativeBackend.Verify(msgHash, wrongDefaultSig, pubKey));\n    }\n}\n"
  },
  {
    "path": "test/Libplanet.Explorer.Cocona.Tests/Commands/IndexCommandTest.cs",
    "content": "using System;\nusing System.IO;\nusing Libplanet.Explorer.Cocona.Commands;\nusing Xunit;\n\nnamespace Libplanet.Explorer.Cocona.Tests.Commands\n{\n    public class IndexCommandTest\n    {\n        [Fact]\n        public void LoadIndexFromUri()\n        {\n            var tempFileName = Path.GetTempFileName();\n            File.Delete(tempFileName);\n            Directory.CreateDirectory(tempFileName);\n            IndexCommand.LoadIndexFromUri(\n                $\"rocksdb+file://{Path.Combine(tempFileName, \"success\")}\");\n            Assert.Throws<ArgumentException>(\n                () => IndexCommand.LoadIndexFromUri(\n                    $\"{Path.Combine(tempFileName, \"no-scheme\")}\"));\n            Assert.Throws<ArgumentException>(\n                () => IndexCommand.LoadIndexFromUri(\n                    $\"rocksdb://{Path.Combine(tempFileName, \"no-transport\")}\"));\n            Assert.Throws<ArgumentException>(\n                () => IndexCommand.LoadIndexFromUri(\n                    $\"rocksdb+://{Path.Combine(tempFileName, \"empty-transport\")}\"));\n            Assert.Throws<ArgumentException>(\n                () => IndexCommand.LoadIndexFromUri(\n                    $\"rocksdb+foo://{Path.Combine(tempFileName, \"unknown-transport\")}\"));\n        }\n    }\n}\n"
  },
  {
    "path": "test/Libplanet.Explorer.Cocona.Tests/Libplanet.Explorer.Cocona.Tests.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <PropertyGroup>\n    <TreatWarningsAsErrors>true</TreatWarningsAsErrors>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <ProjectReference Include=\"..\\..\\tools\\Libplanet.Explorer.Cocona\\Libplanet.Explorer.Cocona.csproj\" />\n    <ProjectReference Include=\"..\\Libplanet.Explorer.Tests\\Libplanet.Explorer.Tests.csproj\" />\n  </ItemGroup>\n\n</Project>\n\n"
  },
  {
    "path": "test/Libplanet.Explorer.Tests/Fixtures/BlockChainStatesFixture.cs",
    "content": "using System.Collections.Generic;\nusing System.Numerics;\nusing System.Security.Cryptography;\nusing Bencodex.Types;\nusing Libplanet.Action.State;\nusing Libplanet.Common;\nusing Libplanet.Crypto;\nusing Libplanet.Mocks;\nusing Libplanet.Types.Assets;\nusing Libplanet.Types.Blocks;\nusing Libplanet.Types.Consensus;\n\nnamespace Libplanet.Explorer.Tests.Fixtures\n{\n    public static class BlockChainStatesFixture\n    {\n        /// <summary>\n        /// The <see cref=\"Crypto.Address\"/> to have its state and balance set.\n        /// </summary>\n        public static readonly Address Address =\n            new Address(\"0x5003712B63baAB98094aD678EA2B24BcE445D076\");\n\n        /// <summary>\n        /// The <see cref=\"Types.Assets.Currency\"/> of the balance\n        /// that <see cref=\"Address\"/> is to have.\n        /// </summary>\n#pragma warning disable CS0618  // Obsolete.\n        public static readonly Currency Currency =\n            Currency.Legacy(\"ABC\", 2, null);\n#pragma warning restore CS0618\n\n        /// <summary>\n        /// The amount of <see cref=\"Currency\"/> for <see cref=\"Address\"/> to have.\n        /// </summary>\n        public static readonly FungibleAssetValue Amount =\n            new FungibleAssetValue(Currency, 123);\n\n        /// <summary>\n        /// The amount of <see cref=\"Currency\"/> for a random <see cref=\"Crypto.Address\"/> to have.\n        /// </summary>\n        public static readonly FungibleAssetValue AdditionalSupply =\n            new FungibleAssetValue(Currency, 10000);\n\n        /// <summary>\n        /// The <see cref=\"IValue\"> to be set at <see cref=\"Address\"/> under\n        /// an <see cref=\"IAccount\"/> at <see cref=\"ReservedAddresses.LegacyAccount\"/>\n        /// </summary>\n        public static readonly IValue Value = new Text(\"Foo\");\n\n        public static readonly Validator Validator =\n            new Validator(\n                PublicKey.FromHex(\n                    \"032038e153d344773986c039ba5dbff12ae70cfdf6ea8beb7c5ea9b361a72a9233\"),\n                new BigInteger(1));\n\n        public static readonly ValidatorSet ValidatorSet =\n            new ValidatorSet(new List<Validator>() { Validator });\n\n        public static (IBlockChainStates, BlockHash, HashDigest<SHA256>)\n            CreateMockBlockChainStates(int version)\n        {\n            MockBlockChainStates mockBlockChainStates = new MockBlockChainStates();\n            MockWorldState mock = version >= BlockMetadata.WorldStateProtocolVersion\n                ? MockWorldState.CreateModern(mockBlockChainStates.StateStore, version)\n                : MockWorldState.CreateLegacy(mockBlockChainStates.StateStore);\n            mock = mock\n                .SetBalance(Address, Amount)\n                .SetBalance(new PrivateKey().Address, AdditionalSupply)\n                .SetValidatorSet(ValidatorSet);\n            IAccount account = new Account(mock.GetAccountState(ReservedAddresses.LegacyAccount));\n            account = account.SetState(Address, Value);\n            mock = mock.SetAccount(ReservedAddresses.LegacyAccount, account);\n\n            var blockHash = new BlockHash(TestUtils.GetRandomBytes(BlockHash.Size));\n            var stateRootHash = mock.Trie.Hash;\n            mockBlockChainStates.AttachBlockHashToStateRootHash(blockHash, stateRootHash);\n            return (mockBlockChainStates, blockHash, stateRootHash);\n        }\n    }\n}\n"
  },
  {
    "path": "test/Libplanet.Explorer.Tests/GeneratedBlockChainFixture.cs",
    "content": "using System;\nusing System.Collections.Immutable;\nusing System.Linq;\nusing System.Numerics;\nusing Bencodex.Types;\nusing Libplanet.Action;\nusing Libplanet.Action.Loader;\nusing Libplanet.Action.Sys;\nusing Libplanet.Blockchain;\nusing Libplanet.Blockchain.Policies;\nusing Libplanet.Crypto;\nusing Libplanet.Types.Assets;\nusing Libplanet.Types.Blocks;\nusing Libplanet.Types.Consensus;\nusing Libplanet.Types.Evidence;\nusing Libplanet.Types.Tx;\nusing Libplanet.Store;\nusing Libplanet.Store.Trie;\n\nnamespace Libplanet.Explorer.Tests;\n\npublic class GeneratedBlockChainFixture\n{\n    public static Currency TestCurrency => Currency.Uncapped(\"TEST\", 0, null);\n\n    public BlockChain Chain { get; }\n\n    public ImmutableArray<PrivateKey> PrivateKeys { get; }\n\n    public int MaxTxCount { get; }\n\n    public ImmutableDictionary<Address, ImmutableArray<Block>>\n        MinedBlocks { get; private set; }\n\n    public ImmutableDictionary<Address, ImmutableArray<Transaction>>\n        SignedTxs { get; private set; }\n\n    private System.Random Random { get; }\n\n    public GeneratedBlockChainFixture(\n        int seed,\n        int blockCount = 20,\n        int maxTxCount = 20,\n        int privateKeyCount = 10,\n        ImmutableArray<ImmutableArray<ImmutableArray<SimpleAction>>>?\n            txActionsForSuffixBlocks = null)\n    {\n        txActionsForSuffixBlocks ??=\n            ImmutableArray<ImmutableArray<ImmutableArray<SimpleAction>>>.Empty;\n\n        var store = new MemoryStore();\n        var stateStore = new TrieStateStore(new MemoryKeyValueStore());\n\n        Random = new System.Random(seed);\n        MaxTxCount = maxTxCount;\n        PrivateKeys = Enumerable\n            .Range(0, privateKeyCount)\n            .Select(_ => new PrivateKey())\n            .ToImmutableArray();\n        MinedBlocks = PrivateKeys\n            .ToImmutableDictionary(\n                key => key.Address,\n                key => ImmutableArray<Block>.Empty);\n        SignedTxs = PrivateKeys\n            .ToImmutableDictionary(\n                key => key.Address,\n                key => ImmutableArray<Transaction>.Empty);\n\n        var privateKey = new PrivateKey();\n        var policy = new BlockPolicy(\n            blockInterval: TimeSpan.FromMilliseconds(1),\n            getMaxTransactionsPerBlock: _ => int.MaxValue,\n            getMaxTransactionsBytes: _ => long.MaxValue);\n        var actionEvaluator = new ActionEvaluator(\n            policy.PolicyActionsRegistry,\n            stateStore,\n            TypedActionLoader.Create(typeof(SimpleAction).Assembly, typeof(SimpleAction)));\n        Block genesisBlock = BlockChain.ProposeGenesisBlock(\n            transactions: PrivateKeys\n                .OrderBy(pk => pk.Address.ToHex())\n                .Select(\n                    (pk, i) => Transaction.Create(\n                        nonce: i,\n                        privateKey: privateKey,\n                        genesisHash: null,\n                        actions: new IAction[]\n                            {\n                                new Initialize(\n                                    new ValidatorSet(\n                                        ImmutableList<Validator>.Empty.Add(\n                                            new Validator(pk.PublicKey, 1)).ToList()),\n                                    ImmutableDictionary.Create<Address, IValue>())\n                            }.ToPlainValues()))\n                .ToImmutableList());\n        Chain = BlockChain.Create(\n            policy,\n            new VolatileStagePolicy(),\n            store,\n            stateStore,\n            genesisBlock,\n            actionEvaluator);\n        MinedBlocks = MinedBlocks.SetItem(\n            Chain.Genesis.Miner,\n            ImmutableArray<Block>.Empty.Add(Chain.Genesis));\n\n        while (Chain.Count < blockCount)\n        {\n            AddBlock(GetRandomTransactions());\n        }\n\n        if (txActionsForSuffixBlocks is { } txActionsForSuffixBlocksVal)\n        {\n            foreach (var actionsForTransactions in txActionsForSuffixBlocksVal)\n            {\n                var pk = PrivateKeys[Random.Next(PrivateKeys.Length)];\n                AddBlock(actionsForTransactions\n                    .Select(actions =>\n                        Transaction.Create(\n                            nonce: Chain.GetNextTxNonce(pk.Address),\n                            privateKey: pk,\n                            genesisHash: Chain.Genesis.Hash,\n                            actions: actions.ToPlainValues()))\n                    .ToImmutableArray());\n            }\n        }\n    }\n\n    private ImmutableArray<Transaction> GetRandomTransactions()\n    {\n        var nonces = ImmutableDictionary<PrivateKey, long>.Empty;\n        return Enumerable\n            .Range(0, Random.Next(MaxTxCount))\n            .Select(_ =>\n            {\n                var pk = PrivateKeys[Random.Next(PrivateKeys.Length)];\n                if (!nonces.TryGetValue(pk, out var nonce))\n                {\n                    nonce = Chain.GetNextTxNonce(pk.Address);\n                }\n\n                nonces = nonces.SetItem(pk, nonce + 1);\n\n                return GetRandomTransaction(pk, nonce);\n            })\n            .OrderBy(tx => tx.Id)\n            .ToImmutableArray();\n    }\n\n    private Transaction GetRandomTransaction(PrivateKey pk, long nonce)\n    {\n        return Transaction.Create(\n            nonce: nonce,\n            privateKey: pk,\n            genesisHash: Chain.Genesis.Hash,\n            actions: Random.Next() % 2 == 0\n                ? GetRandomActions().ToPlainValues()\n                : ImmutableHashSet<SimpleAction>.Empty.ToPlainValues(),\n            maxGasPrice: null,\n            gasLimit: null);\n    }\n\n    private ImmutableArray<SimpleAction> GetRandomActions()\n    {\n        return Enumerable\n            .Range(0, Random.Next(10))\n            .Select(_ => SimpleAction.GetAction(Random.Next()))\n            .ToImmutableArray();\n    }\n\n    private void AddBlock(ImmutableArray<Transaction> transactions)\n    {\n        var proposer = PrivateKeys[Random.Next(PrivateKeys.Length)];\n        var block = Chain.EvaluateAndSign(\n            new BlockContent(\n                new BlockMetadata(\n                    Chain.Tip.Index + 1,\n                    DateTimeOffset.UtcNow,\n                    proposer.PublicKey,\n                    Chain.Tip.Hash,\n                    BlockContent.DeriveTxHash(transactions),\n                    Chain.Store.GetChainBlockCommit(Chain.Store.GetCanonicalChainId()!.Value),\n                    evidenceHash: null),\n                transactions,\n                evidence: Array.Empty<EvidenceBase>()).Propose(),\n            proposer);\n        Chain.Append(\n            block,\n            new BlockCommit(\n                Chain.Tip.Index + 1,\n                0,\n                block.Hash,\n                PrivateKeys\n                    .OrderBy(pk => pk.Address.ToHex())\n                    .Select(pk => new VoteMetadata(\n                        Chain.Tip.Index + 1,\n                        0,\n                        block.Hash,\n                        DateTimeOffset.UtcNow,\n                        pk.PublicKey,\n                        BigInteger.One,\n                        VoteFlag.PreCommit).Sign(pk)).ToImmutableArray()));\n        MinedBlocks = MinedBlocks\n            .SetItem(\n                proposer.Address,\n                MinedBlocks[proposer.Address].Add(block));\n        SignedTxs = transactions.Aggregate(\n            SignedTxs,\n            (dict, tx) =>\n                dict.SetItem(\n                    tx.Signer,\n                    dict[tx.Signer]\n                        .Add(tx)\n                        .OrderBy(tx => tx.Nonce)\n                        .ToImmutableArray()));\n    }\n}\n"
  },
  {
    "path": "test/Libplanet.Explorer.Tests/GraphQLTestUtils.cs",
    "content": "using System.Collections.Generic;\nusing System.Threading.Tasks;\nusing GraphQL;\nusing GraphQL.Types;\nusing Libplanet.Explorer.GraphTypes;\nusing Microsoft.Extensions.DependencyInjection;\nusing System;\nusing Libplanet.Action;\nusing Libplanet.Explorer.Interfaces;\nusing Libplanet.Explorer.Tests.Queries;\n\nnamespace Libplanet.Explorer.Tests\n{\n    public static class GraphQLTestUtils\n    {\n        public static Task<ExecutionResult> ExecuteQueryAsync<TObjectGraphType>(\n            string query,\n            IDictionary<string, object> userContext = null,\n            object source = null)\n            where TObjectGraphType : IObjectGraphType, new()\n        {\n            return ExecuteQueryAsync(\n                query,\n                new TObjectGraphType(),\n                userContext,\n                source\n            );\n        }\n\n        public static Task<ExecutionResult> ExecuteQueryAsync(\n            string query,\n            IObjectGraphType queryGraphType,\n            IDictionary<string, object> userContext = null,\n            object source = null\n        )\n        {\n            var documentExecutor = new DocumentExecuter();\n\n            // FIXME these codes are temporary fix and should be replaced with unified provider.\n            // see also: https://github.com/planetarium/libplanet/discussions/2230\n            var services = new ServiceCollection();\n            System.Action addContext = source switch\n            {\n                IBlockChainContext context => () => { services.AddSingleton(context); },\n                _ => () =>\n                {\n                    services.AddSingleton<IBlockChainContext>(\n                        new MockBlockChainContext());\n                }\n            };\n            addContext();\n            services.AddSingleton<BlockType>();\n            services.AddSingleton<TransactionType>();\n            IServiceProvider serviceProvider = services.BuildServiceProvider();\n            var failSafeServiceProvider = new FuncServiceProvider(type =>\n                {\n                    try\n                    {\n                        return serviceProvider.GetRequiredService(type);\n                    }\n                    catch\n                    {\n                        // mimics previous way. (call parameterless constructor)\n                        return Activator.CreateInstance(type);\n                    }\n                }\n            );\n\n            return documentExecutor.ExecuteAsync(\n                new ExecutionOptions\n                {\n                    Query = query,\n                    Schema = new Schema(failSafeServiceProvider)\n                    {\n                        Query = queryGraphType,\n                    },\n                    UserContext = userContext,\n                    Root = source,\n                }\n            );\n        }\n    }\n}\n"
  },
  {
    "path": "test/Libplanet.Explorer.Tests/GraphTypes/AddressTypeTest.cs",
    "content": "using System;\nusing GraphQL.Language.AST;\nusing Libplanet.Common;\nusing Libplanet.Crypto;\nusing Libplanet.Explorer.GraphTypes;\nusing Xunit;\n\nnamespace Libplanet.Explorer.Tests.GraphTypes\n{\n    public class AddressTypeTest : ScalarGraphTypeTestBase<AddressType>\n    {\n        [Fact]\n        public void ParseLiteral()\n        {\n            Assert.Null(_type.ParseLiteral(new NullValue()));\n\n            var bytes = TestUtils.GetRandomBytes(Address.Size);\n            var address = new Address(bytes);\n            var hex = ByteUtil.Hex(bytes);\n            var prefixedHex = address.ToString();\n            Assert.Equal(\n                address,\n                Assert.IsType<Address>(_type.ParseLiteral(new StringValue(prefixedHex))));\n            Assert.Equal(\n                address,\n                Assert.IsType<Address>(_type.ParseLiteral(new StringValue(hex))));\n\n            Assert.Throws<InvalidOperationException>(\n                () => _type.ParseLiteral(new LongValue(1234)));\n            Assert.Throws<InvalidOperationException>(\n                () => _type.ParseValue(new StringValue(\"address\")));\n        }\n\n        [Fact]\n        public void ParseValue()\n        {\n            Assert.Null(_type.ParseValue(null));\n\n            var bytes = TestUtils.GetRandomBytes(Address.Size);\n            var address = new Address(bytes);\n            var hex = ByteUtil.Hex(bytes);\n            var prefixedHex = address.ToString();\n            Assert.Equal(address, _type.ParseValue(prefixedHex));\n            Assert.Equal(address, _type.ParseValue(hex));\n\n            Assert.Throws<InvalidOperationException>(() => _type.ParseValue(0));\n            Assert.Throws<InvalidOperationException>(() => _type.ParseValue(new Address()));\n            Assert.Throws<InvalidOperationException>(() => _type.ParseValue(new object()));\n        }\n\n        [Fact]\n        public void Serialize()\n        {\n            Assert.Null(_type.Serialize(null));\n\n            var bytes = TestUtils.GetRandomBytes(Address.Size);\n            var address = new Address(bytes);\n            var hex = ByteUtil.Hex(bytes);\n            var prefixedHex = address.ToString();\n            Assert.Equal(prefixedHex, _type.Serialize(address));\n            Assert.NotEqual(hex, _type.Serialize(address));\n\n            Assert.Throws<InvalidOperationException>(() => _type.Serialize(0));\n            Assert.Throws<InvalidOperationException>(() => _type.Serialize(\"\"));\n            Assert.Throws<InvalidOperationException>(() => _type.Serialize(new object()));\n        }\n    }\n}\n"
  },
  {
    "path": "test/Libplanet.Explorer.Tests/GraphTypes/BlockCommitTypeTest.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Collections.Immutable;\nusing System.Numerics;\nusing GraphQL;\nusing GraphQL.Types;\nusing GraphQL.Execution;\nusing Libplanet.Common;\nusing Libplanet.Crypto;\nusing Libplanet.Types.Blocks;\nusing Libplanet.Types.Consensus;\nusing Libplanet.Explorer.GraphTypes;\nusing Xunit;\nusing static Libplanet.Explorer.Tests.GraphQLTestUtils;\n\nnamespace Libplanet.Explorer.Tests.GraphTypes\n{\n    public class BlockCommitTypeTest\n    {\n        [Fact]\n        public async void Query()\n        {\n\n            var privateKey = new PrivateKey();\n            var blockHash = new BlockHash(new byte[32]);\n            var vote = new VoteMetadata(\n                1,\n                0,\n                blockHash,\n                DateTimeOffset.Now,\n                privateKey.PublicKey,\n                BigInteger.One,\n                VoteFlag.PreCommit).Sign(privateKey);\n            var blockCommit = new BlockCommit(1, 0, blockHash, ImmutableArray.Create(vote));\n\n            var query =\n                @\"{\n                    height\n                    round\n                    blockHash\n                    votes {\n                        height\n                        round\n                        blockHash\n                        timestamp\n                        validatorPublicKey\n                        flag\n                        signature\n                    }\n                }\";\n\n            var blockCommitType = new BlockCommitType();\n            ExecutionResult result = await ExecuteQueryAsync(\n                query,\n                blockCommitType,\n                source: blockCommit\n            );\n            Dictionary<string, object> resultData =\n                (Dictionary<string, object>)((ExecutionNode)result.Data!)?.ToValue()!;\n            Assert.Null(result.Errors);\n            Assert.Equal(blockCommit.Height, resultData[\"height\"]);\n            Assert.Equal(blockCommit.Round, resultData[\"round\"]);\n            Assert.Equal(blockCommit.BlockHash.ToString(), resultData[\"blockHash\"]);\n            var expectedVotes = new object[] {\n                new Dictionary<string, object>()\n                {\n                    { \"height\", vote.Height },\n                    { \"round\", vote.Round },\n                    { \"blockHash\", vote.BlockHash.ToString() },\n                    { \"timestamp\", new DateTimeOffsetGraphType().Serialize(vote.Timestamp) },\n                    { \"validatorPublicKey\", vote.ValidatorPublicKey.ToString() },\n                    { \"flag\", vote.Flag.ToString() },\n                    { \"signature\", ByteUtil.Hex(vote.Signature) },\n                }\n            };\n            Assert.Equal(expectedVotes, resultData[\"votes\"]);\n        }\n    }\n}\n"
  },
  {
    "path": "test/Libplanet.Explorer.Tests/GraphTypes/BlockHashTypeTest.cs",
    "content": "using System;\nusing GraphQL.Language.AST;\nusing Libplanet.Common;\nusing Libplanet.Explorer.GraphTypes;\nusing Libplanet.Types.Blocks;\nusing Xunit;\n\nnamespace Libplanet.Explorer.Tests.GraphTypes\n{\n    public class BlockHashTypeTest : ScalarGraphTypeTestBase<BlockHashType>\n    {\n        [Fact]\n        public void ParseLiteral()\n        {\n            Assert.Null(_type.ParseLiteral(new NullValue()));\n\n            var bytes = TestUtils.GetRandomBytes(BlockHash.Size);\n            var blockHash = new BlockHash(bytes);\n            var hex = ByteUtil.Hex(bytes);\n            Assert.Equal(\n                blockHash,\n                Assert.IsType<BlockHash>(_type.ParseLiteral(new StringValue(hex))));\n\n            Assert.Throws<InvalidOperationException>(\n                () => _type.ParseLiteral(new LongValue(1234)));\n            Assert.Throws<InvalidOperationException>(\n                () => _type.ParseValue(new StringValue(\"blockHash\")));\n        }\n\n        [Fact]\n        public void ParseValue()\n        {\n            Assert.Null(_type.ParseValue(null));\n\n            var bytes = TestUtils.GetRandomBytes(BlockHash.Size);\n            var blockHash = new BlockHash(bytes);\n            var hex = ByteUtil.Hex(bytes);\n            Assert.Equal(blockHash, _type.ParseValue(hex));\n\n            Assert.Throws<InvalidOperationException>(() => _type.ParseValue(0));\n            Assert.Throws<InvalidOperationException>(() => _type.ParseValue(new BlockHash()));\n            Assert.Throws<InvalidOperationException>(() => _type.ParseValue(new object()));\n        }\n\n        [Fact]\n        public void Serialize()\n        {\n            var bytes = TestUtils.GetRandomBytes(BlockHash.Size);\n            var blockHash = new BlockHash(bytes);\n            var hex = ByteUtil.Hex(bytes);\n            Assert.Equal(hex, _type.Serialize(blockHash));\n\n            Assert.Throws<InvalidOperationException>(() => _type.Serialize(0));\n            Assert.Throws<InvalidOperationException>(() => _type.Serialize(\"\"));\n            Assert.Throws<InvalidOperationException>(() => _type.Serialize(new object()));\n        }\n    }\n}\n"
  },
  {
    "path": "test/Libplanet.Explorer.Tests/GraphTypes/BlockTypeTest.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Collections.Immutable;\nusing System.Numerics;\nusing System.Security.Cryptography;\nusing Bencodex;\nusing Bencodex.Types;\nusing GraphQL;\nusing GraphQL.Execution;\nusing GraphQL.Types;\nusing Libplanet.Common;\nusing Libplanet.Crypto;\nusing Libplanet.Types.Blocks;\nusing Libplanet.Types.Consensus;\nusing Libplanet.Explorer.GraphTypes;\nusing Libplanet.Explorer.Tests.Queries;\nusing Libplanet.Store;\nusing Xunit;\nusing static Libplanet.Explorer.Tests.GraphQLTestUtils;\n\nnamespace Libplanet.Explorer.Tests.GraphTypes\n{\n    public class BlockTypeTest\n    {\n        [Fact]\n        public async void Query()\n        {\n            var privateKey = new PrivateKey();\n            var lastBlockHash = new BlockHash(TestUtils.GetRandomBytes(HashDigest<SHA256>.Size));\n            var lastVotes = ImmutableArray.Create(\n                new VoteMetadata(\n                    1,\n                    0,\n                    lastBlockHash,\n                    DateTimeOffset.Now,\n                    privateKey.PublicKey,\n                    BigInteger.One,\n                    VoteFlag.PreCommit).Sign(privateKey));\n            var lastBlockCommit = new BlockCommit(1, 0, lastBlockHash, lastVotes);\n            var preEval = new BlockContent(\n                new BlockMetadata(\n                    index: 2,\n                    timestamp: DateTimeOffset.UtcNow,\n                    publicKey: privateKey.PublicKey,\n                    previousHash: lastBlockHash,\n                    txHash: null,\n                    lastCommit: lastBlockCommit,\n                    evidenceHash: null)).Propose();\n            var stateRootHash =\n                new HashDigest<SHA256>(TestUtils.GetRandomBytes(HashDigest<SHA256>.Size));\n            var signature = preEval.Header.MakeSignature(privateKey, stateRootHash);\n            var hash = preEval.Header.DeriveBlockHash(stateRootHash, signature);\n            var block = new Block(preEval, (stateRootHash, signature, hash));\n\n            // FIXME We need to test for `previousBlock` field too.\n            var query =\n                @\"{\n                    index\n                    hash\n                    miner\n                    publicKey\n                    timestamp\n                    stateRootHash\n                    signature\n                    preEvaluationHash\n                    lastCommit\n                    {\n                        height\n                        round\n                        blockHash\n                        votes\n                        {\n                            height\n                            round\n                            blockHash\n                            timestamp\n                            validatorPublicKey\n                            validatorPower\n                            flag\n                            signature\n                        }\n                    }\n                    protocolVersion\n                    raw\n                }\";\n\n            var store = new MemoryStore();\n            var blockType = new BlockType(new MockBlockChainContext(store));\n            ExecutionResult result = await ExecuteQueryAsync(\n                query,\n                blockType,\n                source: block\n            );\n            Dictionary<string, object> resultData =\n                (Dictionary<string, object>)((ExecutionNode) result.Data!)?.ToValue()!;\n            Assert.Null(result.Errors);\n            Assert.Equal(block.Index, resultData[\"index\"]);\n            Assert.Equal(\n                ByteUtil.Hex(block.Hash.ToByteArray()),\n                resultData[\"hash\"]);\n            Assert.Equal(\n                block.Miner.ToString(),\n                resultData[\"miner\"]);\n            Assert.Equal(\n                new DateTimeOffsetGraphType().Serialize(block.Timestamp),\n                resultData[\"timestamp\"]);\n            Assert.Equal(\n                ByteUtil.Hex(block.StateRootHash.ToByteArray()),\n                resultData[\"stateRootHash\"]);\n            Assert.Equal(\n                ByteUtil.Hex(block.PreEvaluationHash.ToByteArray()),\n                resultData[\"preEvaluationHash\"]);\n\n            var expectedLastCommit = new Dictionary<string, object>()\n            {\n                { \"height\", lastBlockCommit.Height },\n                { \"round\", lastBlockCommit.Round },\n                { \"blockHash\", lastBlockCommit.BlockHash.ToString() },\n                { \"votes\", new object[]\n                    {\n                        new Dictionary<string, object>()\n                        {\n                            { \"height\", lastVotes[0].Height },\n                            { \"round\", lastVotes[0].Round },\n                            { \"blockHash\", lastVotes[0].BlockHash.ToString() },\n                            { \"timestamp\", new DateTimeOffsetGraphType().Serialize(lastVotes[0].Timestamp) },\n                            { \"validatorPublicKey\", lastVotes[0].ValidatorPublicKey.ToString() },\n                            { \"validatorPower\", lastVotes[0].ValidatorPower?.ToString() },\n                            { \"flag\", lastVotes[0].Flag.ToString() },\n                            { \"signature\", ByteUtil.Hex(lastVotes[0].Signature) },\n                        }\n                    }\n                },\n            };\n\n            Assert.Equal(expectedLastCommit, resultData[\"lastCommit\"]);\n\n            Assert.Equal(\n                block.ProtocolVersion,\n                resultData[\"protocolVersion\"]);\n\n            Assert.Equal(\n                block,\n                BlockMarshaler.UnmarshalBlock(\n                    (Dictionary)new Codec().Decode(ByteUtil.ParseHex((string)resultData[\"raw\"]))));\n        }\n    }\n}\n"
  },
  {
    "path": "test/Libplanet.Explorer.Tests/GraphTypes/ByteStringTypeTest.cs",
    "content": "using GraphQL.Language.AST;\nusing Libplanet.Explorer.GraphTypes;\nusing Xunit;\n\nnamespace Libplanet.Explorer.Tests.GraphTypes\n{\n    public class ByteStringTypeTest : ScalarGraphTypeTestBase<ByteStringType>\n    {\n        [Theory]\n        [InlineData(new byte[0], \"\")]\n        [InlineData(new byte[] { 0xbe, 0xef }, \"beef\")]\n        [InlineData(\"foo\", \"foo\")]\n        [InlineData(1, null)]\n        [InlineData(null, null)]\n        public void Serialize(object value, string expected)\n        {\n            Assert.Equal(expected, _type.Serialize(value));\n        }\n\n        [Theory]\n        [InlineData(null, null)]\n        [InlineData(\"beef\", new byte[] { 0xbe, 0xef })]\n        public void ParseValue(object value, object parsed)\n        {\n            Assert.Equal(parsed, _type.ParseValue(value));\n        }\n\n        [Theory]\n        [InlineData(null, null)]\n        [InlineData(\"beef\", new byte[] { 0xbe, 0xef })]\n        public void ParseLiteral(string stringValue, object parsed)\n        {\n            var actual =\n                stringValue is { } v ? _type.ParseLiteral(new StringValue(v)) : null;\n            Assert.Equal(parsed, actual);\n        }\n\n        [Fact]\n        public void ParseLiteral_NotStringValue_ReturnNull()\n        {\n            Assert.Null(_type.ParseLiteral(new IntValue(0)));\n            Assert.Null(_type.ParseLiteral(new BigIntValue(0)));\n            Assert.Null(_type.ParseLiteral(new EnumValue(\"NAME\")));\n        }\n    }\n}\n"
  },
  {
    "path": "test/Libplanet.Explorer.Tests/GraphTypes/CurrencyInputTypeTest.cs",
    "content": "using System.Collections.Generic;\nusing System.Threading.Tasks;\nusing GraphQL;\nusing GraphQL.Execution;\nusing GraphQL.Types;\nusing Libplanet.Types.Assets;\nusing Libplanet.Explorer.GraphTypes;\nusing Xunit;\nusing static Libplanet.Explorer.Tests.GraphQLTestUtils;\n\nnamespace Libplanet.Explorer.Tests.GraphTypes;\n\npublic class CurrencyInputTypeTest\n{\n    [Theory]\n    [MemberData(nameof(InputTestCases))]\n    public async Task Input(string query, Dictionary<string, object> expected)\n    {\n        var result = await ExecuteQueryAsync<TestQuery>(query);\n        Assert.Null(result.Errors);\n        ExecutionNode resultData = Assert.IsAssignableFrom<ExecutionNode>(result.Data);\n        IDictionary<string, object> resultDict =\n            Assert.IsAssignableFrom<IDictionary<string, object>>(resultData!.ToValue());\n        Assert.Equal(expected, resultDict);\n    }\n\n    [Fact]\n    public async Task OnlyHalfOmitted()\n    {\n        var result = await ExecuteQueryAsync<TestQuery>(\n            @\"query\n            {\n                currency(currency: { ticker: \"\"ABC\"\", decimalPlaces: 5, totalSupplyTrackable: false, minters: null, maximumSupplyMajorUnit: 1 })\n                {\n                    ticker\n                    decimalPlaces\n                    totalSupplyTrackable\n                    minters\n                }\n            }\");\n        var error = Assert.Single(result.Errors);\n        Assert.Contains(\n            \"Both \\\"maximumSupplyMajorUnit\\\" and \\\"maximumSupplyMinorUnit\\\" must be present or omitted\",\n            error.Message);\n    }\n\n    public static IEnumerable<object[]> InputTestCases()\n    {\n        return new object[][] {\n            new object[] {\n                @\"query\n                {\n                    currency(currency: { ticker: \"\"ABC\"\", decimalPlaces: 5, totalSupplyTrackable: false, minters: null })\n                    {\n                        ticker\n                        decimalPlaces\n                        totalSupplyTrackable\n                        minters\n                    }\n                }\",\n                new Dictionary<string, object>\n                {\n                    [\"currency\"] = new Dictionary<string, object>\n                    {\n                        [\"ticker\"] = \"ABC\",\n                        [\"decimalPlaces\"] = (byte)5,\n                        [\"totalSupplyTrackable\"] = false,\n                        [\"minters\"] = null,\n                    },\n                }\n            },\n            new object[] {\n                @\"query\n                {\n                    currency(currency: { ticker: \"\"ABC\"\", decimalPlaces: 5, minters: null })\n                    {\n                        ticker\n                        decimalPlaces\n                        totalSupplyTrackable\n                        minters\n                    }\n                }\",\n                new Dictionary<string, object>\n                {\n                    [\"currency\"] = new Dictionary<string, object>\n                    {\n                        [\"ticker\"] = \"ABC\",\n                        [\"decimalPlaces\"] = (byte)5,\n                        [\"totalSupplyTrackable\"] = false,\n                        [\"minters\"] = null,\n                    },\n                }\n            },\n        };\n    }\n}\n\nclass TestQuery : ObjectGraphType\n{\n    public TestQuery()\n    {\n        Field<CurrencyType>(\"currency\", arguments: new QueryArguments(\n            new QueryArgument<CurrencyInputType>\n            {\n                Name = \"currency\",\n            }\n        ), resolve: context => context.GetArgument<Currency>(\"currency\"));\n    }\n}\n"
  },
  {
    "path": "test/Libplanet.Explorer.Tests/GraphTypes/CurrencyTypeTest.cs",
    "content": "using System.Collections.Generic;\nusing System.Collections.Immutable;\nusing System.Linq;\nusing System.Numerics;\nusing System.Threading.Tasks;\nusing GraphQL;\nusing GraphQL.Execution;\nusing Libplanet.Crypto;\nusing Libplanet.Types.Assets;\nusing Libplanet.Explorer.GraphTypes;\nusing Xunit;\nusing static Libplanet.Explorer.Tests.GraphQLTestUtils;\n\nnamespace Libplanet.Explorer.Tests.GraphTypes;\n\npublic class CurrencyTypeTest\n{\n    [Fact]\n    public async Task Query()\n    {\n        var addrA = new Address(\"D6D639DA5a58A78A564C2cD3DB55FA7CeBE244A9\");\n        var addrB = new Address(\"5003712B63baAB98094aD678EA2B24BcE445D076\");\n        var currency = Currency.Capped(\"ABC\", 2, (12345, 67), ImmutableHashSet.Create(addrA, addrB));\n        ExecutionResult result = await ExecuteQueryAsync<CurrencyType>(@\"\n        {\n            ticker\n            decimalPlaces\n            minters\n            maximumSupply {\n                currency {\n                    ticker\n                    hash\n                }\n                sign\n                majorUnit\n                minorUnit\n                quantity\n                string\n            }\n            totalSupplyTrackable\n            hash\n        }\", source: currency);\n        Assert.Null(result.Errors);\n        ExecutionNode resultData = Assert.IsAssignableFrom<ExecutionNode>(result.Data);\n        IDictionary<string, object> resultDict =\n            Assert.IsAssignableFrom<IDictionary<string, object>>(resultData!.ToValue());\n        Assert.Equal(\"ABC\", resultDict[\"ticker\"]);\n        Assert.Equal((byte)2, resultDict[\"decimalPlaces\"]);\n        IDictionary<string, object> maxSupplyDict =\n            Assert.IsAssignableFrom<IDictionary<string, object>>(resultDict[\"maximumSupply\"]);\n        IDictionary<string, object> currencyDict =\n            Assert.IsAssignableFrom<IDictionary<string, object>>(maxSupplyDict[\"currency\"]);\n        Assert.Equal(\"ABC\", currencyDict[\"ticker\"]);\n        Assert.Equal(\"4bc1a79e2f30892acbff9fc7e5c71e2aea112110\", currencyDict[\"hash\"]);\n        Assert.Equal(1, Assert.IsAssignableFrom<int>(maxSupplyDict[\"sign\"]));\n        Assert.Equal(12345, Assert.IsAssignableFrom<BigInteger>(maxSupplyDict[\"majorUnit\"]));\n        Assert.Equal(67, Assert.IsAssignableFrom<BigInteger>(maxSupplyDict[\"minorUnit\"]));\n        Assert.Equal(\"12345.67\", maxSupplyDict[\"quantity\"]);\n        Assert.Equal(\"12345.67 ABC\", maxSupplyDict[\"string\"]);\n        Assert.True((bool)resultDict[\"totalSupplyTrackable\"]);\n        object[] minters = Assert.IsAssignableFrom<object[]>(resultDict[\"minters\"]);\n        Assert.All(minters, m => Assert.IsType<string>(m));\n        Assert.Equal(minters.Cast<string>().ToArray(), new[]\n        {\n            \"0x5003712B63baAB98094aD678EA2B24BcE445D076\",\n            \"0xD6D639DA5a58A78A564C2cD3DB55FA7CeBE244A9\",\n        });\n        Assert.Equal(\"4bc1a79e2f30892acbff9fc7e5c71e2aea112110\", resultDict[\"hash\"]);\n\n        currency = Currency.Uncapped(\"NOMINTER\", 2, minters: null);\n        result = await ExecuteQueryAsync<CurrencyType>(\n            @\"{\n                minters\n                maximumSupply { quantity }\n                totalSupplyTrackable\n            }\",\n            source: currency\n        );\n        Assert.Null(result.Errors);\n        resultData = Assert.IsAssignableFrom<ExecutionNode>(result.Data);\n        resultDict = Assert.IsAssignableFrom<IDictionary<string, object>>(resultData!.ToValue());\n        Assert.Null(resultDict[\"minters\"]);\n        Assert.Null(resultDict[\"maximumSupply\"]);\n        Assert.True((bool)resultDict[\"totalSupplyTrackable\"]);\n\n#pragma warning disable CS0618\n        currency = Currency.Legacy(\"LEGACY\", 2, minters: null);\n#pragma warning restore CS0618\n        result = await ExecuteQueryAsync<CurrencyType>(\n            @\"{\n                maximumSupply { quantity }\n                totalSupplyTrackable\n            }\",\n            source: currency\n        );\n        Assert.Null(result.Errors);\n        resultData = Assert.IsAssignableFrom<ExecutionNode>(result.Data);\n        resultDict = Assert.IsAssignableFrom<IDictionary<string, object>>(resultData!.ToValue());\n        Assert.Null(resultDict[\"maximumSupply\"]);\n        Assert.False((bool)resultDict[\"totalSupplyTrackable\"]);\n    }\n}\n"
  },
  {
    "path": "test/Libplanet.Explorer.Tests/GraphTypes/FungibleAssetValueTypeTest.cs",
    "content": "using System.Collections.Generic;\nusing System.Linq;\nusing System.Numerics;\nusing System.Threading.Tasks;\nusing GraphQL;\nusing GraphQL.Execution;\nusing Libplanet.Types.Assets;\nusing Libplanet.Explorer.GraphTypes;\nusing Xunit;\nusing static Libplanet.Explorer.Tests.GraphQLTestUtils;\n\nnamespace Libplanet.Explorer.Tests.GraphTypes;\n\npublic class FungibleAssetValueTypeTest\n{\n    [Fact]\n    public async Task Query()\n    {\n        var currency = Currency.Uncapped(\"ABC\", 2, minters: null);\n        var fav = new FungibleAssetValue(currency, -1, 123, 45);\n        ExecutionResult result = await ExecuteQueryAsync<FungibleAssetValueType>(\n            @\"{\n                currency {\n                    ticker\n                    hash\n                }\n                sign\n                majorUnit\n                minorUnit\n                quantity\n                string\n            }\",\n            source: fav\n        );\n        Assert.Null(result.Errors);\n        ExecutionNode resultData = Assert.IsAssignableFrom<ExecutionNode>(result.Data);\n        IDictionary<string, object> resultDict =\n            Assert.IsAssignableFrom<IDictionary<string, object>>(resultData!.ToValue());\n        IDictionary<string, object> currencyDict =\n            Assert.IsAssignableFrom<IDictionary<string, object>>(resultDict[\"currency\"]);\n        Assert.Equal(\"ABC\", currencyDict[\"ticker\"]);\n        Assert.Equal(\"84ba810ca5ac342c122eb7ef455939a8a05d1d40\", currencyDict[\"hash\"]);\n        Assert.Equal(-1, Assert.IsAssignableFrom<int>(resultDict[\"sign\"]));\n        Assert.Equal(123, Assert.IsAssignableFrom<BigInteger>(resultDict[\"majorUnit\"]));\n        Assert.Equal(45, Assert.IsAssignableFrom<BigInteger>(resultDict[\"minorUnit\"]));\n        Assert.Equal(\"-123.45\", resultDict[\"quantity\"]);\n        Assert.Equal(\"-123.45 ABC\", resultDict[\"string\"]);\n    }\n}\n"
  },
  {
    "path": "test/Libplanet.Explorer.Tests/GraphTypes/HashDigestTypeTest.cs",
    "content": "using System;\nusing System.Security.Cryptography;\nusing GraphQL.Language.AST;\nusing Libplanet.Common;\nusing Libplanet.Crypto;\nusing Libplanet.Explorer.GraphTypes;\nusing Xunit;\n\nnamespace Libplanet.Explorer.Tests.GraphTypes\n{\n    public class HashDigestTypeTest : ScalarGraphTypeTestBase<HashDigestType<SHA256>>\n    {\n        [Fact]\n        public void ParseLiteral()\n        {\n            Assert.Null(_type.ParseLiteral(new NullValue()));\n\n            var bytes = TestUtils.GetRandomBytes(HashDigest<SHA256>.Size);\n            var hashDigestSHA256 = new HashDigest<SHA256>(bytes);\n            var hex = ByteUtil.Hex(bytes);\n            Assert.Equal(\n                hashDigestSHA256,\n                Assert.IsType<HashDigest<SHA256>>(_type.ParseLiteral(new StringValue(hex))));\n\n            bytes = TestUtils.GetRandomBytes(HashDigest<SHA1>.Size);\n            hex = ByteUtil.Hex(bytes);\n            Assert.Throws<ArgumentOutOfRangeException>(\n                () => _type.ParseLiteral(new StringValue(hex)));\n            Assert.Throws<InvalidOperationException>(\n                () => _type.ParseLiteral(new LongValue(1234)));\n            Assert.Throws<InvalidOperationException>(\n                () => _type.ParseValue(new StringValue(\"hashDigest\")));\n        }\n\n        [Fact]\n        public void ParseValue()\n        {\n            Assert.Null(_type.ParseValue(null));\n\n            var bytes = TestUtils.GetRandomBytes(HashDigest<SHA256>.Size);\n            var hashDigest = new HashDigest<SHA256>(bytes);\n            var hex = ByteUtil.Hex(bytes);\n            Assert.Equal(hashDigest, _type.ParseValue(hex));\n\n            Assert.Throws<InvalidOperationException>(\n                () => _type.ParseValue(0));\n            Assert.Throws<InvalidOperationException>(\n                () => _type.ParseValue(new HashDigest<SHA256>()));\n            Assert.Throws<InvalidOperationException>(\n                () => _type.ParseValue(new object()));\n        }\n\n        [Fact]\n        public void Serialize()\n        {\n            var bytes = TestUtils.GetRandomBytes(HashDigest<SHA256>.Size);\n            var hashDigest = new HashDigest<SHA256>(bytes);\n            var hex = ByteUtil.Hex(bytes);\n            Assert.Equal(hex, _type.Serialize(hashDigest));\n\n            Assert.Throws<InvalidOperationException>(() => _type.Serialize(0));\n            Assert.Throws<InvalidOperationException>(() => _type.Serialize(\"\"));\n            Assert.Throws<InvalidOperationException>(() => _type.Serialize(new object()));\n        }\n    }\n}\n"
  },
  {
    "path": "test/Libplanet.Explorer.Tests/GraphTypes/PublicKeyTypeTest.cs",
    "content": "using System;\nusing GraphQL.Language.AST;\nusing Libplanet.Crypto;\nusing Libplanet.Explorer.GraphTypes;\nusing Xunit;\n\nnamespace Libplanet.Explorer.Tests.GraphTypes\n{\n    public class PublicKeyTypeTest : ScalarGraphTypeTestBase<PublicKeyType>\n    {\n        [Fact]\n        public void ParseLiteral()\n        {\n            Assert.Null(_type.ParseLiteral(new NullValue()));\n\n            var publicKey = new PrivateKey().PublicKey;\n            var compressed = publicKey.ToHex(true);\n            var uncompressed = publicKey.ToHex(false);\n            Assert.Equal(\n                publicKey,\n                Assert.IsType<PublicKey>(_type.ParseLiteral(new StringValue(compressed))));\n            Assert.Equal(\n                publicKey,\n                Assert.IsType<PublicKey>(_type.ParseLiteral(new StringValue(uncompressed))));\n\n            Assert.Throws<InvalidOperationException>(\n                () => _type.ParseLiteral(new LongValue(1234)));\n            Assert.Throws<InvalidOperationException>(\n                () => _type.ParseValue(new StringValue(\"publicKey\")));\n        }\n\n        [Fact]\n        public void ParseValue()\n        {\n            Assert.Null(_type.ParseValue(null));\n\n            var publicKey = new PrivateKey().PublicKey;\n            var compressed = publicKey.ToHex(true);\n            var uncompressed = publicKey.ToHex(false);\n            Assert.Equal(publicKey, _type.ParseValue(compressed));\n            Assert.Equal(publicKey, _type.ParseValue(uncompressed));\n\n            Assert.Throws<InvalidOperationException>(() => _type.ParseValue(0));\n            Assert.Throws<InvalidOperationException>(\n                () => _type.ParseValue(new PrivateKey().PublicKey));\n            Assert.Throws<InvalidOperationException>(() => _type.ParseValue(new object()));\n        }\n\n        [Fact]\n        public void Serialize()\n        {\n            Assert.Null(_type.Serialize(null));\n\n            var publicKey = new PrivateKey().PublicKey;\n            var compressed = publicKey.ToHex(true);\n            var uncompressed = publicKey.ToHex(false);\n            Assert.Equal(compressed, _type.Serialize(publicKey));\n            Assert.NotEqual(uncompressed, _type.Serialize(publicKey));\n\n            Assert.Throws<InvalidOperationException>(() => _type.Serialize(0));\n            Assert.Throws<InvalidOperationException>(() => _type.Serialize(\"\"));\n            Assert.Throws<InvalidOperationException>(() => _type.Serialize(new object()));\n        }\n    }\n}\n"
  },
  {
    "path": "test/Libplanet.Explorer.Tests/GraphTypes/ScalarGraphTypeTestBase.cs",
    "content": "using GraphQL.Types;\n\nnamespace Libplanet.Explorer.Tests.GraphTypes\n{\n    public class ScalarGraphTypeTestBase<T>\n        where T : ScalarGraphType, new()\n    {\n        protected readonly T _type = new T();\n    }\n}\n"
  },
  {
    "path": "test/Libplanet.Explorer.Tests/GraphTypes/TransactionTypeTest.cs",
    "content": "using System.Collections.Generic;\nusing System.Security.Cryptography;\nusing System.Threading.Tasks;\nusing GraphQL;\nusing GraphQL.Execution;\nusing GraphQL.Types;\nusing Libplanet.Action;\nusing Libplanet.Common;\nusing Libplanet.Crypto;\nusing Libplanet.Types.Blocks;\nusing Libplanet.Types.Tx;\nusing Libplanet.Explorer.GraphTypes;\nusing Libplanet.Explorer.Tests.Queries;\nusing Xunit;\nusing static Libplanet.Explorer.Tests.GraphQLTestUtils;\n\nnamespace Libplanet.Explorer.Tests.GraphTypes\n{\n    // TODO: test `blockRef`.\n    public class TransactionTypeTest\n    {\n        [Fact]\n        public async Task Query()\n        {\n            var privateKey = new PrivateKey();\n            var transaction = Transaction.Create(\n                0,\n                privateKey,\n                new BlockHash(TestUtils.GetRandomBytes(HashDigest<SHA256>.Size)),\n                new[] { new NullAction() }.ToPlainValues());\n            var query =\n                @\"{\n                    id\n                    nonce\n                    signer\n                    publicKey\n                    updatedAddresses\n                    signature\n                    timestamp\n                    actions {\n                      inspection\n                    }\n                }\";\n\n            ExecutionResult result =\n                await ExecuteQueryAsync(\n                    query,\n                    new TransactionType(new MockBlockChainContext()),\n                    source: transaction);\n            Dictionary<string, object> resultData =\n                (Dictionary<string, object>)((ExecutionNode) result.Data!)?.ToValue()!;\n            Assert.Null(result.Errors);\n            Assert.Equal(transaction.Id.ToHex(), resultData[\"id\"]);\n            Assert.Equal(\n                ByteUtil.Hex(transaction.PublicKey.Format(true)),\n                resultData[\"publicKey\"]);\n            Assert.Equal(transaction.Signer.ToString(), resultData[\"signer\"]);\n            Assert.Equal(ByteUtil.Hex(transaction.Signature), resultData[\"signature\"]);\n            Assert.Equal(transaction.Nonce, resultData[\"nonce\"]);\n            Assert.Equal(\n                new DateTimeOffsetGraphType().Serialize(transaction.Timestamp),\n                resultData[\"timestamp\"]);\n            var actions = Assert.IsType<Dictionary<string, object>>(\n                ((object[])resultData[\"actions\"])[0]);\n            Assert.Equal(\n                transaction.Actions[0].Inspect(),\n                actions[\"inspection\"]);\n        }\n    }\n}\n"
  },
  {
    "path": "test/Libplanet.Explorer.Tests/GraphTypes/TxIdTypeTest.cs",
    "content": "using System;\nusing GraphQL.Language.AST;\nusing Libplanet.Common;\nusing Libplanet.Explorer.GraphTypes;\nusing Libplanet.Types.Tx;\nusing Xunit;\n\nnamespace Libplanet.Explorer.Tests.GraphTypes\n{\n    public class TxIdTypeTest : ScalarGraphTypeTestBase<TxIdType>\n    {\n        [Fact]\n        public void ParseLiteral()\n        {\n            Assert.Null(_type.ParseLiteral(new NullValue()));\n\n            var bytes = TestUtils.GetRandomBytes(TxId.Size);\n            var txId = new TxId(bytes);\n            var hex = ByteUtil.Hex(bytes);\n            Assert.Equal(\n                txId,\n                Assert.IsType<TxId>(_type.ParseLiteral(new StringValue(hex))));\n\n            Assert.Throws<InvalidOperationException>(\n                () => _type.ParseLiteral(new LongValue(1234)));\n            Assert.Throws<InvalidOperationException>(\n                () => _type.ParseValue(new StringValue(\"txId\")));\n        }\n\n        [Fact]\n        public void ParseValue()\n        {\n            Assert.Null(_type.ParseValue(null));\n\n            var bytes = TestUtils.GetRandomBytes(TxId.Size);\n            var txId = new TxId(bytes);\n            var hex = ByteUtil.Hex(bytes);\n            Assert.Equal(txId, _type.ParseValue(hex));\n\n            Assert.Throws<InvalidOperationException>(() => _type.ParseValue(0));\n            Assert.Throws<InvalidOperationException>(() => _type.ParseValue(new TxId()));\n            Assert.Throws<InvalidOperationException>(() => _type.ParseValue(new object()));\n        }\n\n        [Fact]\n        public void Serialize()\n        {\n            var bytes = TestUtils.GetRandomBytes(TxId.Size);\n            var txId = new TxId(bytes);\n            var hex = ByteUtil.Hex(bytes);\n            Assert.Equal(hex, _type.Serialize(txId));\n\n            Assert.Throws<InvalidOperationException>(() => _type.Serialize(0));\n            Assert.Throws<InvalidOperationException>(() => _type.Serialize(\"\"));\n            Assert.Throws<InvalidOperationException>(() => _type.Serialize(new object()));\n        }\n    }\n}\n"
  },
  {
    "path": "test/Libplanet.Explorer.Tests/GraphTypes/TxResultTypeTest.cs",
    "content": "using System.Collections.Generic;\nusing System.Security.Cryptography;\nusing GraphQL;\nusing GraphQL.Execution;\nusing Libplanet.Common;\nusing Libplanet.Explorer.GraphTypes;\nusing Xunit;\nusing static Libplanet.Explorer.Tests.GraphQLTestUtils;\n\nnamespace Libplanet.Explorer.Tests.GraphTypes\n{\n    public class TxResultTypeTest\n    {\n        [Theory]\n        [MemberData(nameof(TestCases))]\n        public async void Query(TxResult txResult, IDictionary<string, object> expected)\n        {\n            var query =\n                @\"{\n                    txStatus\n                    blockIndex\n                    blockHash\n                    inputState\n                    outputState\n                    exceptionNames\n                }\";\n\n            var txResultType = new TxResultType();\n            ExecutionResult result = await ExecuteQueryAsync(\n                query,\n                txResultType,\n                source: txResult\n            );\n            Assert.Null(result.Errors);\n            ExecutionNode executionNode = Assert.IsAssignableFrom<ExecutionNode>(result.Data);\n            IDictionary<string, object> dictionary = Assert.IsAssignableFrom<IDictionary<string, object>>(executionNode.ToValue());\n\n            Assert.Equal(expected, dictionary);\n        }\n\n        public static IEnumerable<object[]> TestCases() {\n            return new object[][] {\n                new object[] {\n                    new TxResult(\n                        TxStatus.SUCCESS,\n                        0,\n                        \"45bcaa4c0b00f4f31eb61577e595ea58fb69c7df3ee612aa6eea945bbb0ce39d\",\n                        HashDigest<SHA256>.FromString(\n                            \"7146ddfb3594089795f6992a668a3ce7fde089aacdda68075e1bc37b14ebb06f\"),\n                        HashDigest<SHA256>.FromString(\n                            \"72bb2e17da644cbca9045f5e689fae0323b6af56a0acab9fd828d2243b50df1c\"),\n                        new List<string>() { \"\" }\n                    ),\n                    new Dictionary<string, object> {\n                        [\"txStatus\"] = \"SUCCESS\",\n                        [\"blockIndex\"] = 0L,\n                        [\"blockHash\"] = \"45bcaa4c0b00f4f31eb61577e595ea58fb69c7df3ee612aa6eea945bbb0ce39d\",\n                        [\"inputState\"] =\n                            \"7146ddfb3594089795f6992a668a3ce7fde089aacdda68075e1bc37b14ebb06f\",\n                        [\"outputState\"] =\n                            \"72bb2e17da644cbca9045f5e689fae0323b6af56a0acab9fd828d2243b50df1c\",\n                        [\"exceptionNames\"] = new string[] { \"\" },\n                    }\n                },\n                new object[] {\n                    new TxResult(\n                        TxStatus.FAILURE,\n                        0,\n                        \"45bcaa4c0b00f4f31eb61577e595ea58fb69c7df3ee612aa6eea945bbb0ce39d\",\n                        HashDigest<SHA256>.FromString(\n                            \"7146ddfb3594089795f6992a668a3ce7fde089aacdda68075e1bc37b14ebb06f\"),\n                        HashDigest<SHA256>.FromString(\n                            \"7146ddfb3594089795f6992a668a3ce7fde089aacdda68075e1bc37b14ebb06f\"),\n                        new List<string>() { \"SomeException\" }\n                    ),\n                    new Dictionary<string, object> {\n                        [\"txStatus\"] = \"FAILURE\",\n                        [\"blockIndex\"] = 0L,\n                        [\"inputState\"] =\n                            \"7146ddfb3594089795f6992a668a3ce7fde089aacdda68075e1bc37b14ebb06f\",\n                        [\"outputState\"] =\n                            \"7146ddfb3594089795f6992a668a3ce7fde089aacdda68075e1bc37b14ebb06f\",\n                        [\"blockHash\"] = \"45bcaa4c0b00f4f31eb61577e595ea58fb69c7df3ee612aa6eea945bbb0ce39d\",\n                        [\"exceptionNames\"] = new string[] { \"SomeException\" },\n                    }\n                },\n                new object[] {\n                    new TxResult(\n                        TxStatus.INCLUDED,\n                        0,\n                        \"45bcaa4c0b00f4f31eb61577e595ea58fb69c7df3ee612aa6eea945bbb0ce39d\",\n                        null,\n                        null,\n                        new List<string>() { \"\" }\n                    ),\n                    new Dictionary<string, object> {\n                        [\"txStatus\"] = \"INCLUDED\",\n                        [\"blockIndex\"] = 0L,\n                        [\"blockHash\"] = \"45bcaa4c0b00f4f31eb61577e595ea58fb69c7df3ee612aa6eea945bbb0ce39d\",\n                        [\"inputState\"] = null,\n                        [\"outputState\"] = null,\n                        [\"exceptionNames\"] = new string[] { \"\" },\n                    }\n                },\n                new object[] {\n                    new TxResult(\n                        TxStatus.INVALID,\n                        null,\n                        null,\n                        null,\n                        null,\n                        new List<string>() { \"\" }\n                    ),\n                    new Dictionary<string, object> {\n                        [\"txStatus\"] = \"INVALID\",\n                        [\"blockIndex\"] = null,\n                        [\"blockHash\"] = null,\n                        [\"inputState\"] = null,\n                        [\"outputState\"] = null,\n                        [\"exceptionNames\"] = new string[] { \"\" },\n                    }\n                },\n                new object[] {\n                    new TxResult(\n                        TxStatus.STAGING,\n                        null,\n                        null,\n                        null,\n                        null,\n                        new List<string>() { \"\" }\n                    ),\n                    new Dictionary<string, object> {\n                        [\"txStatus\"] = \"STAGING\",\n                        [\"blockIndex\"] = null,\n                        [\"blockHash\"] = null,\n                        [\"inputState\"] = null,\n                        [\"outputState\"] = null,\n                        [\"exceptionNames\"] = new string[] { \"\" },\n                    }\n                }\n            };\n        }\n    }\n}\n"
  },
  {
    "path": "test/Libplanet.Explorer.Tests/GraphTypes/VoteTypeTest.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Numerics;\nusing GraphQL;\nusing GraphQL.Types;\nusing GraphQL.Execution;\nusing Libplanet.Common;\nusing Libplanet.Crypto;\nusing Libplanet.Types.Blocks;\nusing Libplanet.Types.Consensus;\nusing Libplanet.Explorer.GraphTypes;\nusing Xunit;\nusing static Libplanet.Explorer.Tests.GraphQLTestUtils;\n\nnamespace Libplanet.Explorer.Tests.GraphTypes\n{\n    public class VoteTypeTest\n    {\n        [Fact]\n        public async void Query()\n        {\n\n            var privateKey = new PrivateKey();\n            var blockHash = new BlockHash(new byte[32]);\n            var vote = new VoteMetadata(\n                1,\n                0,\n                blockHash,\n                DateTimeOffset.Now,\n                privateKey.PublicKey,\n                123,\n                VoteFlag.PreCommit).Sign(privateKey);\n\n            var query =\n                @\"{\n                    height\n                    round\n                    blockHash\n                    timestamp\n                    validatorPublicKey\n                    validatorPower\n                    flag\n                    signature\n                }\";\n\n            var voteType = new VoteType();\n            ExecutionResult result = await ExecuteQueryAsync(\n                query,\n                voteType,\n                source: vote\n            );\n            Dictionary<string, object> resultData =\n                (Dictionary<string, object>)((ExecutionNode)result.Data!)?.ToValue()!;\n            Assert.Null(result.Errors);\n            Assert.Equal(vote.Height, resultData[\"height\"]);\n            Assert.Equal(vote.Round, resultData[\"round\"]);\n            Assert.Equal(vote.BlockHash.ToString(), resultData[\"blockHash\"]);\n            Assert.Equal(new DateTimeOffsetGraphType().Serialize(vote.Timestamp), resultData[\"timestamp\"]);\n            Assert.Equal(vote.ValidatorPublicKey.ToString(), resultData[\"validatorPublicKey\"]);\n            Assert.Equal(vote.ValidatorPower?.ToString(), resultData[\"validatorPower\"]);\n            Assert.Equal(vote.Flag.ToString(), resultData[\"flag\"]);\n            Assert.Equal(ByteUtil.Hex(vote.Signature), resultData[\"signature\"]);\n        }\n    }\n}\n"
  },
  {
    "path": "test/Libplanet.Explorer.Tests/Indexing/BlockChainIndexFixture.cs",
    "content": "using System.Threading;\nusing Libplanet.Explorer.Indexing;\nusing Libplanet.Store;\n\nnamespace Libplanet.Explorer.Tests.Indexing;\n\npublic abstract class BlockChainIndexFixture : IBlockChainIndexFixture\n{\n    public IBlockChainIndex Index { get; }\n\n    protected BlockChainIndexFixture(IStore store, IBlockChainIndex index)\n    {\n        Index = index;\n        Index.SynchronizeAsync(store, CancellationToken.None).GetAwaiter().GetResult();\n    }\n\n    public abstract IBlockChainIndex CreateEphemeralIndexInstance();\n}\n"
  },
  {
    "path": "test/Libplanet.Explorer.Tests/Indexing/BlockChainIndexTest.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Collections.Immutable;\nusing System.Linq;\nusing System.Numerics;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing Libplanet.Crypto;\nusing Libplanet.Types.Blocks;\nusing Libplanet.Types.Consensus;\nusing Libplanet.Types.Tx;\nusing Libplanet.Explorer.Indexing;\nusing Xunit;\n\nnamespace Libplanet.Explorer.Tests.Indexing;\n\npublic abstract class BlockChainIndexTest\n{\n    protected const int BlockCount = 20;\n\n    protected const int MaxTxCount = 20;\n\n    protected abstract IBlockChainIndexFixture Fx { get; set; }\n\n    protected GeneratedBlockChainFixture ChainFx { get; set; }\n\n    protected System.Random RandomGenerator { get; }\n\n    protected BlockChainIndexTest()\n    {\n        RandomGenerator = new System.Random();\n        ChainFx = new GeneratedBlockChainFixture(\n            RandomGenerator.Next(), BlockCount, MaxTxCount);\n    }\n\n    [Fact]\n    public async Task Synchronize()\n    {\n        var index = Fx.CreateEphemeralIndexInstance();\n        await index.SynchronizeAsync(ChainFx.Chain.Store, CancellationToken.None);\n\n        var chain = ChainFx.Chain;\n        var block1 = chain.ProposeBlock(\n            ChainFx.PrivateKeys[0],\n            chain.GetBlockCommit(chain.Tip.Hash));\n        var block2 = chain.ProposeBlock(\n            ChainFx.PrivateKeys[0],\n            chain.GetBlockCommit(chain.Tip.Hash));\n        await index.IndexAsync(\n            new Store.BlockDigest(block1.MarshalBlock()),\n            block1.Transactions,\n            CancellationToken.None);\n        await Assert.ThrowsAsync<IndexMismatchException>(\n            async () => await index.IndexAsync(\n            new Store.BlockDigest(block2.MarshalBlock()),\n            block2.Transactions,\n            CancellationToken.None));\n    }\n\n    [Fact]\n    public async Task Tip()\n    {\n        var tip = await Fx.Index.GetTipAsync();\n        Assert.Equal(tip, Fx.Index.Tip);\n        Assert.Equal(ChainFx.Chain.Tip.Hash, tip.Hash);\n        Assert.Equal(ChainFx.Chain.Tip.Index, tip.Index);\n    }\n\n    [Fact]\n    public async Task GetLastNonceByAddress()\n    {\n        foreach (var pk in ChainFx.PrivateKeys)\n        {\n            var address = pk.Address;\n            Assert.Equal(\n                ChainFx.Chain.GetNextTxNonce(address) - 1,\n                // ReSharper disable once MethodHasAsyncOverload\n                Fx.Index.GetLastNonceByAddress(address) ?? -1);\n            Assert.Equal(\n                ChainFx.Chain.GetNextTxNonce(address) - 1,\n                await Fx.Index.GetLastNonceByAddressAsync(address) ?? -1);\n        }\n\n        // ReSharper disable once MethodHasAsyncOverload\n        Assert.Null(Fx.Index.GetLastNonceByAddress(new Address()));\n        Assert.Null(await Fx.Index.GetLastNonceByAddressAsync(new Address()));\n    }\n\n    [Fact]\n    public async Task BlockHashToIndex()\n    {\n        for (var i = 0; i < ChainFx.Chain.Count; i++)\n        {\n            var inChain = ChainFx.Chain[i];\n            // ReSharper disable once MethodHasAsyncOverload\n            Assert.Equal(i, Fx.Index.BlockHashToIndex(inChain.Hash));\n            Assert.Equal(i, await Fx.Index.BlockHashToIndexAsync(inChain.Hash));\n        }\n\n        Assert.Throws<IndexOutOfRangeException>(() => Fx.Index.BlockHashToIndex(new BlockHash()));\n        await Assert.ThrowsAsync<IndexOutOfRangeException>(\n            async () => await Fx.Index.BlockHashToIndexAsync(new BlockHash()));\n    }\n\n    [Fact]\n    public async Task IndexToBlockHash()\n    {\n        for (var i = 0; i < ChainFx.Chain.Count; i++)\n        {\n            var inChain = ChainFx.Chain[i];\n            // ReSharper disable once MethodHasAsyncOverload\n            Assert.Equal(inChain.Hash, Fx.Index.IndexToBlockHash(i));\n            Assert.Equal(inChain.Hash, await Fx.Index.IndexToBlockHashAsync(i));\n        }\n\n        Assert.Throws<IndexOutOfRangeException>(() => Fx.Index.IndexToBlockHash(long.MaxValue));\n        await Assert.ThrowsAsync<IndexOutOfRangeException>(\n            async () => await Fx.Index.IndexToBlockHashAsync(long.MaxValue));\n\n        Assert.Equal(\n            await Fx.Index.IndexToBlockHashAsync(Fx.Index.Tip.Index),\n            await Fx.Index.IndexToBlockHashAsync(-1));\n    }\n\n    [Theory]\n    [MemberData(nameof(BooleanPermutation3))]\n    public async Task GetBlockHashes(bool fromHalfway, bool throughHalfway, bool desc)\n    {\n        var blockCount = (int)ChainFx.Chain.Count;\n        int? fromHeight = fromHalfway ? blockCount / 4 : null;\n        int? maxCount = throughHalfway ? blockCount / 2 : null;\n        int rangeEnd =\n            maxCount is { } limitValue\n                ? (fromHeight ?? 0) + limitValue\n                : blockCount;\n        var blocks = Enumerable.Range(0, (int)ChainFx.Chain.Count)\n            .Select(i => ChainFx.Chain[i])\n            .ToImmutableArray();\n        blocks = desc ? blocks.Reverse().ToImmutableArray() : blocks;\n        var inChain = Enumerable.Range(fromHeight ?? 0, rangeEnd - (fromHeight ?? 0))\n            .Select(i => blocks[i])\n            .ToImmutableArray();\n        var indexed = Fx.Index.GetBlockHashesFromIndex(fromHeight, maxCount, desc).ToArray();\n        Assert.Equal(\n            indexed,\n            await Fx.Index.GetBlockHashesFromIndexAsync(\n                fromHeight, maxCount, desc).ToArrayAsync());\n        Assert.Equal(\n            indexed,\n            Fx.Index.GetBlockHashesByRange((fromHeight ?? 0)..rangeEnd, desc));\n        Assert.Equal(\n            indexed,\n            await Fx.Index.GetBlockHashesByRangeAsync(\n                (fromHeight ?? 0)..rangeEnd, desc).ToArrayAsync());\n        if (!desc)\n        {\n            Assert.Equal(\n                indexed.Select(tuple => tuple.Hash),\n                Fx.Index[(fromHeight ?? 0)..rangeEnd]);\n        }\n\n        Assert.Equal(inChain.Length, indexed.Length);\n        for (var i = 0; i < indexed.Length; i++)\n        {\n            Assert.Equal(inChain[i].Hash, indexed[i].Hash);\n            Assert.Equal(inChain[i].Index, indexed[i].Index);\n        }\n    }\n\n    [Fact]\n    public async Task GetBlockHashesByRangeOutOfRange()\n    {\n        Assert.Throws<ArgumentOutOfRangeException>(() =>\n            Fx.Index.GetBlockHashesByRange(..((int)Fx.Index.Tip.Index + 2)));\n        await Assert.ThrowsAsync<ArgumentOutOfRangeException>(async () =>\n            await Fx.Index.GetBlockHashesByRangeAsync(\n                ..((int)Fx.Index.Tip.Index + 2)).ToArrayAsync());\n    }\n\n    [Theory]\n    [InlineData(SpecialRangeKind.OmitStartEnd, false)]\n    [InlineData(SpecialRangeKind.OmitStartEnd, true)]\n    [InlineData(SpecialRangeKind.OmitEnd, false)]\n    [InlineData(SpecialRangeKind.OmitEnd, true)]\n    [InlineData(SpecialRangeKind.StartFromEnd, false)]\n    [InlineData(SpecialRangeKind.StartFromEnd, true)]\n    [InlineData(SpecialRangeKind.EndFromEnd, false)]\n    [InlineData(SpecialRangeKind.EndFromEnd, true)]\n    public async Task GetBlockHashesByRangeSpecial(SpecialRangeKind kind, bool desc)\n    {\n        var (special, regular) = GetSpecialRange(kind);\n        var byRegular = Fx.Index.GetBlockHashesByRange(regular, desc).ToArray();\n        var byRegularAsync =\n            await Fx.Index.GetBlockHashesByRangeAsync(regular, desc).ToArrayAsync();\n        var bySpecial = Fx.Index.GetBlockHashesByRange(special, desc).ToArray();\n        var bySpecialAsync =\n            await Fx.Index.GetBlockHashesByRangeAsync(special, desc).ToArrayAsync();\n        Assert.Equal(byRegular, bySpecial);\n        Assert.Equal(byRegularAsync, bySpecialAsync);\n        Assert.Equal(byRegular, byRegularAsync);\n        Assert.Equal(bySpecial, bySpecialAsync);\n        if (!desc)\n        {\n            Assert.Equal(\n                Fx.Index[regular],\n                Fx.Index[special]);\n        }\n    }\n\n    public (Range special, Range regular) GetSpecialRange(SpecialRangeKind kind)\n    {\n        var blockCount = (int)ChainFx.Chain.Count;\n        switch (kind)\n        {\n            case SpecialRangeKind.OmitStartEnd:\n                return (.., ..blockCount);\n            case SpecialRangeKind.OmitEnd:\n                return ((blockCount / 4).., (blockCount / 4)..blockCount);\n            case SpecialRangeKind.StartFromEnd:\n                return blockCount < 4\n                    ? (^0.., blockCount..blockCount)\n                    : (\n                    ^(blockCount - blockCount / 4)..,\n                    (blockCount / 4)..blockCount);\n            case SpecialRangeKind.EndFromEnd:\n                return blockCount < 4\n                    ? (..^blockCount, ..0)\n                    : (..^(blockCount / 4), ..(blockCount - blockCount / 4));\n        }\n\n        throw new ArgumentOutOfRangeException();\n    }\n\n    [Theory]\n    [MemberData(nameof(BooleanPermutation3))]\n    public async Task GetBlockHashesByMiner(bool fromHalfway, bool throughHalfway, bool desc)\n    {\n        foreach (var pk in ChainFx.PrivateKeys)\n        {\n            var address = pk.Address;\n            var inChain = ChainFx.MinedBlocks[address].ToArray();\n            inChain = desc ? inChain.Reverse().ToArray() : inChain;\n            int? fromHeight = fromHalfway ? inChain.Length / 4 : null;\n            int? maxCount = throughHalfway ? inChain.Length / 2 : null;\n            inChain = inChain[\n                (fromHeight ?? 0)\n                ..(maxCount is { } limitValue ? (fromHeight ?? 0) + limitValue : inChain.Length)];\n            var indexed =\n                Fx.Index.GetBlockHashesFromIndex(fromHeight, maxCount, desc, address).ToArray();\n            Assert.Equal(\n                indexed,\n                await Fx.Index.GetBlockHashesFromIndexAsync(\n                    fromHeight, maxCount, desc, address)\n                    .ToArrayAsync());\n            Assert.Equal(inChain.Length, indexed.Length);\n            for (var i = 0; i < indexed.Length; i++)\n            {\n                Assert.Equal(inChain[i].Hash, indexed[i].Hash);\n                Assert.Equal(inChain[i].Index, indexed[i].Index);\n            }\n        }\n    }\n\n    [Fact]\n    public async Task GetContainedBlockHashByTxId()\n    {\n        for (var i = 0; i < ChainFx.Chain.Count; i++)\n        {\n            foreach (var txId in ChainFx.Chain[i].Transactions.Select(tx => tx.Id))\n            {\n                // ReSharper disable once MethodHasAsyncOverload\n                var indexed = Fx.Index.GetContainedBlockHashByTxId(txId);\n                Assert.Equal(ChainFx.Chain[i].Hash, indexed);\n                Assert.Equal(indexed, await Fx.Index.GetContainedBlockHashByTxIdAsync(txId));\n                Assert.True(Fx.Index.TryGetContainedBlockHashById(txId, out var indexed2));\n                Assert.Equal(indexed, indexed2);\n            }\n        }\n\n        Assert.Throws<IndexOutOfRangeException>(\n            () => Fx.Index.GetContainedBlockHashByTxId(new TxId()));\n        await Assert.ThrowsAsync<IndexOutOfRangeException>(\n            async () => await Fx.Index.GetContainedBlockHashByTxIdAsync(new TxId()));\n        Assert.False(Fx.Index.TryGetContainedBlockHashById(new TxId(), out _));\n        Assert.Null(await Fx.Index.TryGetContainedBlockHashByIdAsync(new TxId()));\n    }\n\n    [Theory]\n    [MemberData(nameof(BooleanPermutation3))]\n    public async Task GetSignedTxIdsByAddress(bool fromHalfway, bool throughHalfway, bool desc)\n    {\n        foreach (var pk in ChainFx.PrivateKeys)\n        {\n            var address = pk.Address;\n            var inChain = ChainFx.SignedTxs[address].ToArray();\n            inChain = desc ? inChain.Reverse().ToArray() : inChain;\n            int? fromNonce = fromHalfway ? inChain.Length / 4 : null;\n            int? maxCount = throughHalfway ? inChain.Length / 2 : null;\n            inChain = inChain[\n                (fromNonce ?? 0)\n                ..(maxCount is { } limitValue ? (fromNonce ?? 0) + limitValue : inChain.Length)];\n            var indexed =\n                Fx.Index.GetSignedTxIdsByAddress(address, fromNonce, maxCount, desc).ToArray();\n            Assert.Equal(inChain.Length, indexed.Length);\n            Assert.Equal(\n                indexed,\n                await Fx.Index.GetSignedTxIdsByAddressAsync(address, fromNonce, maxCount, desc)\n                    .ToArrayAsync());\n            for (var i = 0; i < indexed.Length; i++)\n            {\n                Assert.Equal(inChain[i].Id, indexed[i]);\n            }\n        }\n    }\n\n    public static IEnumerable<object[]> BooleanPermutation(short count) =>\n        Enumerable.Range(0, 1 << count)\n            .Aggregate(\n                ImmutableArray<object[]>.Empty,\n                (arr, bitString) =>\n                    arr.Add(\n                        Enumerable.Range(0, count)\n                            .Aggregate(\n                                ImmutableArray<object>.Empty,\n                                (arr, item) =>\n                                {\n                                    var newArr = arr.Add(bitString % 2 != 0);\n                                    bitString >>= 1;\n                                    return newArr;\n                                }).ToArray()));\n\n    public static IEnumerable<object[]> BooleanPermutation3() => BooleanPermutation(3);\n\n    public enum SpecialRangeKind\n    {\n        OmitStartEnd,\n        OmitEnd,\n        StartFromEnd,\n        EndFromEnd\n    }\n}\n"
  },
  {
    "path": "test/Libplanet.Explorer.Tests/Indexing/IBlockChainIndexFixture.cs",
    "content": "using Libplanet.Explorer.Indexing;\n\nnamespace Libplanet.Explorer.Tests.Indexing;\n\npublic interface IBlockChainIndexFixture\n{\n    IBlockChainIndex Index { get; }\n\n    IBlockChainIndex CreateEphemeralIndexInstance();\n}\n"
  },
  {
    "path": "test/Libplanet.Explorer.Tests/Indexing/RocksDbBlockChainIndexFixture.cs",
    "content": "using System.IO;\nusing Libplanet.Explorer.Indexing;\nusing Libplanet.Store;\n\nnamespace Libplanet.Explorer.Tests.Indexing;\n\npublic class RocksDbBlockChainIndexFixture: BlockChainIndexFixture\n{\n    public RocksDbBlockChainIndexFixture(IStore store)\n        : base(\n            store,\n            new RocksDbBlockChainIndex(Path.Combine(Path.GetTempPath(), Path.GetRandomFileName())))\n    {\n    }\n\n    public override IBlockChainIndex CreateEphemeralIndexInstance() =>\n        new RocksDbBlockChainIndex(Path.Combine(Path.GetTempPath(), Path.GetRandomFileName()));\n}\n"
  },
  {
    "path": "test/Libplanet.Explorer.Tests/Indexing/RocksDbBlockChainIndexTest.cs",
    "content": "using System.Threading.Tasks;\nusing Libplanet.Action;\nusing Xunit;\n\nnamespace Libplanet.Explorer.Tests.Indexing;\n\npublic class RocksDbBlockChainIndexTest: BlockChainIndexTest\n{\n    public RocksDbBlockChainIndexTest()\n    {\n        Fx = new RocksDbBlockChainIndexFixture(\n            ChainFx.Chain.Store);\n    }\n\n    protected sealed override IBlockChainIndexFixture Fx {\n        get;\n        set;\n    }\n\n    [Theory]\n    [MemberData(nameof(BooleanPermutation3))]\n    public async Task GetBlockHashesMultiByteIndex(bool fromHalfway, bool throughHalfway, bool desc)\n    {\n        ChainFx = new GeneratedBlockChainFixture(\n            RandomGenerator.Next(), byte.MaxValue + 2, 1, 1);\n        Fx = new RocksDbBlockChainIndexFixture(\n            ChainFx.Chain.Store);\n        await GetBlockHashes(fromHalfway, throughHalfway, desc);\n    }\n\n    [Theory]\n    [MemberData(nameof(BooleanPermutation3))]\n    public async Task GetBlockHashesByMinerMultiByteIndex(\n        bool fromHalfway, bool throughHalfway, bool desc)\n    {\n        ChainFx = new GeneratedBlockChainFixture(\n            RandomGenerator.Next(), byte.MaxValue + 2, 1, 1);\n        Fx = new RocksDbBlockChainIndexFixture(\n            ChainFx.Chain.Store);\n        await GetBlockHashesByMiner(fromHalfway, throughHalfway, desc);\n    }\n\n    [Fact]\n    public async Task TipMultiByteIndex()\n    {\n        ChainFx = new GeneratedBlockChainFixture(\n            RandomGenerator.Next(), byte.MaxValue + 2, 1, 1);\n        Fx = new RocksDbBlockChainIndexFixture(\n            ChainFx.Chain.Store);\n        var tip = await Fx.Index.GetTipAsync();\n        Assert.Equal(tip, Fx.Index.Tip);\n        Assert.Equal(ChainFx.Chain.Tip.Hash, tip.Hash);\n        Assert.Equal(ChainFx.Chain.Tip.Index, tip.Index);\n    }\n\n    [Fact]\n    public async Task GetLastNonceByAddressMultiByteIndex()\n    {\n        ChainFx = new GeneratedBlockChainFixture(\n            RandomGenerator.Next(), 2, byte.MaxValue + 2, 1);\n        Fx = new RocksDbBlockChainIndexFixture(\n            ChainFx.Chain.Store);\n        await GetLastNonceByAddress();\n    }\n\n    [Theory]\n    [MemberData(nameof(BooleanPermutation3))]\n    public async Task GetSignedTxIdsByAddressMultiByteIndex(\n        bool fromHalfway, bool throughHalfway, bool desc)\n    {\n        ChainFx = new GeneratedBlockChainFixture(\n            RandomGenerator.Next(), 2, byte.MaxValue + 2, 1);\n        Fx = new RocksDbBlockChainIndexFixture(\n            ChainFx.Chain.Store);\n        await GetSignedTxIdsByAddress(fromHalfway, throughHalfway, desc);\n    }\n}\n"
  },
  {
    "path": "test/Libplanet.Explorer.Tests/Libplanet.Explorer.Tests.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <PropertyGroup>\n    <Nullable>disable</Nullable>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <PackageReference Remove=\"Menees.Analyzers.2017\" />\n    <PackageReference Remove=\"StyleCop.Analyzers\" />\n  </ItemGroup>\n\n  <ItemGroup Condition=\"'$(SkipSonar)' != 'true'\">\n    <PackageReference Remove=\"SonarAnalyzer.CSharp\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <ProjectReference Include=\"..\\..\\tools\\Libplanet.Explorer\\Libplanet.Explorer.csproj\" />\n    <ProjectReference Include=\"..\\Libplanet.Tests\\Libplanet.Tests.csproj\" />\n    <ProjectReference Include=\"..\\Libplanet.Mocks\\Libplanet.Mocks.csproj\" />\n  </ItemGroup>\n\n</Project>\n"
  },
  {
    "path": "test/Libplanet.Explorer.Tests/Queries/HelperQueryTest.cs",
    "content": "using System.Collections.Generic;\nusing System.Threading.Tasks;\nusing GraphQL;\nusing GraphQL.Execution;\nusing Libplanet.Common;\nusing static Libplanet.Explorer.Tests.GraphQLTestUtils;\nusing Libplanet.Explorer.Queries;\nusing Libplanet.Types.Assets;\nusing Xunit;\n\nnamespace Libplanet.Explorer.Tests.Queries;\n\npublic class HelperQueryTest\n{\n    [Fact]\n    public async Task CurrencyHash()\n    {\n        Currency currency = Currency.Uncapped(\"ABC\", 2, minters: null);\n\n        ExecutionResult result = await ExecuteQueryAsync<HelperQuery>(@\"\n        {\n            currencyHash (\n                currency: { ticker: \"\"ABC\"\", decimalPlaces: 2, totalSupplyTrackable: true }\n            )\n        }\n        \");\n\n        Assert.Null(result.Errors);\n        ExecutionNode resultData = Assert.IsAssignableFrom<ExecutionNode>(result.Data);\n        IDictionary<string, object> resultDict =\n            Assert.IsAssignableFrom<IDictionary<string, object>>(resultData!.ToValue());\n        string hash =\n            Assert.IsAssignableFrom<string>(resultDict[\"currencyHash\"]);\n        Assert.Equal(ByteUtil.Hex(currency.Hash.ByteArray), hash);\n    }\n\n    [Fact]\n    public async Task BencodexValue()\n    {\n        ExecutionResult result = await ExecuteQueryAsync<HelperQuery>(@\"\n        {\n            bencodexValue (hex: \"\"7531323a68656c6c6f20776f726c6421\"\") {\n                hex\n                json\n                inspection\n            }\n        }\n        \");\n\n        Assert.Null(result.Errors);\n        ExecutionNode resultData = Assert.IsAssignableFrom<ExecutionNode>(result.Data);\n        IDictionary<string, object> resultDict =\n            Assert.IsAssignableFrom<IDictionary<string, object>>(resultData!.ToValue());\n        IDictionary<string, object> bencodexValue =\n            Assert.IsAssignableFrom<IDictionary<string, object>>(resultDict[\"bencodexValue\"]);\n        string hex = Assert.IsAssignableFrom<string>(bencodexValue[\"hex\"]);\n        string json = Assert.IsAssignableFrom<string>(bencodexValue[\"json\"]);\n        string inspection = Assert.IsAssignableFrom<string>(bencodexValue[\"inspection\"]);\n        Assert.Equal(\"7531323a68656c6c6f20776f726c6421\", hex);\n        Assert.Equal(\"\\\"\\\\uFEFFhello world!\\\"\", json);\n        Assert.Equal(\"\\\"hello world!\\\"\", inspection);\n    }\n\n    [Fact]\n    public async Task KeyHex()\n    {\n        ExecutionResult result = await ExecuteQueryAsync<HelperQuery>(@\"\n        {\n            keyHex (value: \"\"\"\")\n        }\n        \");\n\n        Assert.Null(result.Errors);\n        ExecutionNode resultData = Assert.IsAssignableFrom<ExecutionNode>(result.Data);\n        IDictionary<string, object> resultDict =\n            Assert.IsAssignableFrom<IDictionary<string, object>>(resultData!.ToValue());\n        string hex = Assert.IsAssignableFrom<string>(resultDict[\"keyHex\"]);\n        Assert.Equal(string.Empty, hex);\n\n        result = await ExecuteQueryAsync<HelperQuery>(@\"\n        {\n            keyHex (value: \"\"___\"\")\n        }\n        \");\n\n        Assert.Null(result.Errors);\n        resultData = Assert.IsAssignableFrom<ExecutionNode>(result.Data);\n        resultDict =\n            Assert.IsAssignableFrom<IDictionary<string, object>>(resultData!.ToValue());\n        hex = Assert.IsAssignableFrom<string>(resultDict[\"keyHex\"]);\n        Assert.Equal(\"5f5f5f\", hex);\n\n        result = await ExecuteQueryAsync<HelperQuery>(@\"\n        {\n            keyHex (value: \"\"bc6c73abbe7652f5f73bd48b951437bde868ba65\"\")\n        }\n        \");\n\n        Assert.Null(result.Errors);\n        resultData = Assert.IsAssignableFrom<ExecutionNode>(result.Data);\n        resultDict =\n            Assert.IsAssignableFrom<IDictionary<string, object>>(resultData!.ToValue());\n        hex = Assert.IsAssignableFrom<string>(resultDict[\"keyHex\"]);\n        Assert.Equal(\n            \"62633663373361626265373635326635663733626434386239353134333762646538363862613635\",\n            hex);\n    }\n}\n"
  },
  {
    "path": "test/Libplanet.Explorer.Tests/Queries/MockBlockChainContext.cs",
    "content": "using Libplanet.Action;\nusing Libplanet.Blockchain;\nusing Libplanet.Explorer.Indexing;\nusing Libplanet.Explorer.Interfaces;\nusing Libplanet.Net;\nusing Libplanet.Store;\n\nnamespace Libplanet.Explorer.Tests.Queries;\n\npublic class MockBlockChainContext : IBlockChainContext\n{\n    public bool Preloaded => true;\n\n    public BlockChain BlockChain { get; }\n\n    public IStore Store { get; }\n\n    public Swarm Swarm { get; }\n\n    public IBlockChainIndex Index { get; protected init; }\n\n    public MockBlockChainContext(BlockChain chain)\n    {\n        BlockChain = chain;\n        Store = BlockChain.Store;\n    }\n\n    public MockBlockChainContext(IStore store)\n    {\n        Store = store;\n    }\n\n    public MockBlockChainContext()\n    {\n    }\n}\n"
  },
  {
    "path": "test/Libplanet.Explorer.Tests/Queries/MockBlockChainContextWithIndex.cs",
    "content": "using System.IO;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing Libplanet.Blockchain;\nusing Libplanet.Explorer.Indexing;\n\nnamespace Libplanet.Explorer.Tests.Queries;\n\npublic class MockBlockChainContextWithIndex : MockBlockChainContext\n{\n    public MockBlockChainContextWithIndex(BlockChain chain)\n        : base(chain)\n    {\n        var indexPath = Path.GetTempFileName();\n        File.Delete(indexPath);\n        Directory.CreateDirectory(indexPath);\n        Index = new RocksDbBlockChainIndex(indexPath);\n        Task.Run(\n                async () =>\n                    await Index.SynchronizeAsync(\n                        Store,\n                        CancellationToken.None))\n            .ConfigureAwait(false)\n            .GetAwaiter()\n            .GetResult();\n    }\n}\n"
  },
  {
    "path": "test/Libplanet.Explorer.Tests/Queries/RawStateQueryTest.cs",
    "content": "using System.Collections.Generic;\nusing System.Threading.Tasks;\nusing Bencodex;\nusing GraphQL;\nusing GraphQL.Execution;\nusing Libplanet.Common;\nusing Libplanet.Explorer.Queries;\nusing Xunit;\nusing Fixture = Libplanet.Explorer.Tests.Fixtures.BlockChainStatesFixture;\nusing static Libplanet.Explorer.Tests.GraphQLTestUtils;\n\nnamespace Libplanet.Explorer.Tests.Queries;\n\npublic partial class RawStateQueryTest\n{\n    private static readonly Codec _codec = new Codec();\n\n    [Fact]\n    public async Task StateValue()\n    {\n        // Check value at address path.\n        (var source, _, var stateRootHash) = Fixture.CreateMockBlockChainStates(0);\n        ExecutionResult result = await ExecuteQueryAsync<RawStateQuery>($@\"\n        {{\n            trie(stateRootHash: \"\"{ByteUtil.Hex(stateRootHash.ByteArray)}\"\") {{\n                value(key: \"\"35303033373132623633626161623938303934616436373865613262323462636534343564303736\"\") {{\n                    hex\n                }}\n            }}\n        }}\n        \", source: source);\n        Assert.Null(result.Errors);\n        ExecutionNode resultData = Assert.IsAssignableFrom<ExecutionNode>(result.Data);\n        IDictionary<string, object> resultDict =\n            Assert.IsAssignableFrom<IDictionary<string, object>>(resultData!.ToValue());\n        IDictionary<string, object> trie =\n            Assert.IsAssignableFrom<IDictionary<string, object>>(resultDict[\"trie\"]);\n        IDictionary<string, object> value =\n            Assert.IsAssignableFrom<IDictionary<string, object>>(trie[\"value\"]);\n        Assert.Equal(\n            ByteUtil.Hex(_codec.Encode(Fixture.Value)),\n            Assert.IsAssignableFrom<string>(value[\"hex\"]));\n\n        result = await ExecuteQueryAsync<RawStateQuery>($@\"\n        {{\n            trie(stateRootHash: \"\"{ByteUtil.Hex(stateRootHash.ByteArray)}\"\") {{\n                value(key: \"\"5f5f5f\"\") {{\n                    hex\n                }}\n            }}\n        }}\n        \", source: source);\n        Assert.Null(result.Errors);\n        resultData = Assert.IsAssignableFrom<ExecutionNode>(result.Data);\n        resultDict =\n            Assert.IsAssignableFrom<IDictionary<string, object>>(resultData!.ToValue());\n        trie =\n            Assert.IsAssignableFrom<IDictionary<string, object>>(resultDict[\"trie\"]);\n        value =\n            Assert.IsAssignableFrom<IDictionary<string, object>>(trie[\"value\"]);\n        Assert.Equal(\n            ByteUtil.Hex(_codec.Encode(Fixture.ValidatorSet.Bencoded)),\n            Assert.IsAssignableFrom<string>(value[\"hex\"]));\n    }\n}\n"
  },
  {
    "path": "test/Libplanet.Explorer.Tests/Queries/StateQueryTest.Legacy.cs",
    "content": "using System.Collections.Generic;\nusing System.Numerics;\nusing System.Threading.Tasks;\nusing GraphQL;\nusing GraphQL.Execution;\nusing Libplanet.Common;\nusing Libplanet.Explorer.Queries;\nusing Libplanet.Types.Assets;\nusing Libplanet.Types.Blocks;\nusing Xunit;\nusing Fixture = Libplanet.Explorer.Tests.Fixtures.BlockChainStatesFixture;\nusing static Libplanet.Explorer.Tests.GraphQLTestUtils;\n\nnamespace Libplanet.Explorer.Tests.Queries;\n\npublic partial class StateQueryTest\n{\n    [Theory]\n    [InlineData(0)]\n    [InlineData(BlockMetadata.CurrentProtocolVersion)]\n    public async Task States(int version)\n    {\n        (var source, var blockHash, _) = Fixture.CreateMockBlockChainStates(version);\n        ExecutionResult result = await ExecuteQueryAsync<StateQuery>($@\"\n        {{\n            states(\n                addresses: [\n                   \"\"{ByteUtil.Hex(Fixture.Address.ByteArray)}\"\"\n                   \"\"0x0000000000000000000000000000000000000000\"\"\n                ]\n                offsetBlockHash:\n                    \"\"{ByteUtil.Hex(blockHash.ByteArray)}\"\"\n            )\n        }}\n        \", source: source);\n        Assert.Null(result.Errors);\n        ExecutionNode resultData = Assert.IsAssignableFrom<ExecutionNode>(result.Data);\n        IDictionary<string, object> resultDict =\n            Assert.IsAssignableFrom<IDictionary<string, object>>(resultData!.ToValue());\n        object[] states =\n            Assert.IsAssignableFrom<object[]>(resultDict[\"states\"]);\n        Assert.Equal(2, states.Length);\n        Assert.Equal(new[] { _codec.Encode(Fixture.Value), null }, states);\n    }\n\n    [Theory]\n    [InlineData(0)]\n    [InlineData(BlockMetadata.CurrentProtocolVersion)]\n    public async Task Balance(int version)\n    {\n        (var source, var blockHash, _) = Fixture.CreateMockBlockChainStates(version);\n        ExecutionResult result = await ExecuteQueryAsync<StateQuery>($@\"\n        {{\n            balance(\n                owner: \"\"{ByteUtil.Hex(Fixture.Address.ByteArray)}\"\"\n                currency: {{ ticker: \"\"ABC\"\", decimalPlaces: 2, totalSupplyTrackable: false }}\n                offsetBlockHash: \"\"{ByteUtil.Hex(blockHash.ByteArray)}\"\") {{\n                currency {{ ticker, hash }}\n                sign\n                majorUnit\n                minorUnit\n                quantity\n                string\n            }}\n        }}\n        \", source: source);\n        Assert.Null(result.Errors);\n        ExecutionNode resultData = Assert.IsAssignableFrom<ExecutionNode>(result.Data);\n        IDictionary<string, object> resultDict =\n            Assert.IsAssignableFrom<IDictionary<string, object>>(resultData!.ToValue());\n        IDictionary<string, object> balanceDict =\n            Assert.IsAssignableFrom<IDictionary<string, object>>(resultDict[\"balance\"]);\n        IDictionary<string, object> currencyDict =\n            Assert.IsAssignableFrom<IDictionary<string, object>>(balanceDict[\"currency\"]);\n        Assert.Equal(Fixture.Currency.Ticker, currencyDict[\"ticker\"]);\n        Assert.Equal(ByteUtil.Hex(Fixture.Currency.Hash.ByteArray), currencyDict[\"hash\"]);\n        Assert.Equal(Fixture.Amount.Sign, Assert.IsAssignableFrom<int>(balanceDict[\"sign\"]));\n        Assert.Equal(\n            Fixture.Amount.MajorUnit,\n            Assert.IsAssignableFrom<BigInteger>(balanceDict[\"majorUnit\"]));\n        Assert.Equal(\n            Fixture.Amount.MinorUnit,\n            Assert.IsAssignableFrom<BigInteger>(balanceDict[\"minorUnit\"]));\n        Assert.Equal(Fixture.Amount.GetQuantityString(), balanceDict[\"quantity\"]);\n        Assert.Equal(Fixture.Amount.ToString(), balanceDict[\"string\"]);\n    }\n\n    [Theory]\n    [InlineData(0)]\n    [InlineData(BlockMetadata.CurrentProtocolVersion)]\n    public async Task TotalSupply(int version)\n    {\n#pragma warning disable CS0618  // Legacy, which is obsolete, is the only way to test this:\n         var legacyToken = Currency.Legacy(\"LEG\", 0, null);\n#pragma warning restore CS0618\n        (var source, var blockHash, _) = Fixture.CreateMockBlockChainStates(version);\n        ExecutionResult result = await ExecuteQueryAsync<StateQuery>($@\"\n        {{\n            totalSupply(\n                currency: {{ ticker: \"\"ABC\"\", decimalPlaces: 2, totalSupplyTrackable: false }}\n                offsetBlockHash: \"\"{ByteUtil.Hex(blockHash.ByteArray)}\"\") {{\n                currency {{ ticker, hash }}\n                sign\n                majorUnit\n                minorUnit\n                quantity\n                string\n            }}\n        }}\n        \", source: source);\n        Assert.Null(result.Errors);\n        ExecutionNode resultData = Assert.IsAssignableFrom<ExecutionNode>(result.Data);\n        IDictionary<string, object> resultDict =\n            Assert.IsAssignableFrom<IDictionary<string, object>>(resultData!.ToValue());\n        IDictionary<string, object> totalSupplyDict =\n            Assert.IsAssignableFrom<IDictionary<string, object>>(resultDict[\"totalSupply\"]);\n        IDictionary<string, object> currencyDict =\n            Assert.IsAssignableFrom<IDictionary<string, object>>(totalSupplyDict[\"currency\"]);\n        Assert.Equal(\"ABC\", currencyDict[\"ticker\"]);\n        Assert.Equal(ByteUtil.Hex(Fixture.Currency.Hash.ByteArray), currencyDict[\"hash\"]);\n        FungibleAssetValue expectedTotalSupply = version >= BlockMetadata.CurrencyAccountProtocolVersion\n            ? (Fixture.Amount + Fixture.AdditionalSupply)\n            : (Fixture.Currency * 0);\n        Assert.Equal(\n            expectedTotalSupply.Sign,\n            Assert.IsAssignableFrom<int>(totalSupplyDict[\"sign\"]));\n        Assert.Equal(\n            expectedTotalSupply.MajorUnit,\n            Assert.IsAssignableFrom<BigInteger>(totalSupplyDict[\"majorUnit\"]));\n        Assert.Equal(\n            expectedTotalSupply.MinorUnit,\n            Assert.IsAssignableFrom<BigInteger>(totalSupplyDict[\"minorUnit\"]));\n        Assert.Equal(\n            expectedTotalSupply.GetQuantityString(),\n            totalSupplyDict[\"quantity\"]);\n        Assert.Equal(\n            expectedTotalSupply.ToString(),\n            totalSupplyDict[\"string\"]);\n\n        result = await ExecuteQueryAsync<StateQuery>($@\"\n        {{\n            totalSupply(\n                currency: {{ ticker: \"\"LEG\"\", decimalPlaces: 0, totalSupplyTrackable: false }}\n                offsetBlockHash: \"\"{ByteUtil.Hex(blockHash.ByteArray)}\"\") {{\n                quantity\n            }}\n        }}\n        \", source: source);\n        Assert.Null(result.Errors);\n        resultData = Assert.IsAssignableFrom<ExecutionNode>(result.Data);\n        resultDict =\n            Assert.IsAssignableFrom<IDictionary<string, object>>(resultData!.ToValue());\n        totalSupplyDict =\n            Assert.IsAssignableFrom<IDictionary<string, object>>(resultDict[\"totalSupply\"]);\n        Assert.Equal(\n            (legacyToken * 0).GetQuantityString(),\n            totalSupplyDict[\"quantity\"]);\n    }\n\n    [Theory]\n    [InlineData(0)]\n    [InlineData(BlockMetadata.CurrentProtocolVersion)]\n    public async Task Validators(int version)\n    {\n        (var source, var blockHash, _) = Fixture.CreateMockBlockChainStates(version);\n        ExecutionResult result = await ExecuteQueryAsync<StateQuery>($@\"\n        {{\n            validators(offsetBlockHash: \"\"{ByteUtil.Hex(blockHash.ByteArray)}\"\") {{\n                publicKey\n                power\n            }}\n        }}\n        \", source: source);\n        Assert.Null(result.Errors);\n        ExecutionNode resultData = Assert.IsAssignableFrom<ExecutionNode>(result.Data);\n        IDictionary<string, object> resultDict =\n            Assert.IsAssignableFrom<IDictionary<string, object>>(resultData!.ToValue());\n        object[] validators = Assert.IsAssignableFrom<object[]>(resultDict[\"validators\"]);\n        IDictionary<string, object> validatorDict =\n            Assert.IsAssignableFrom<IDictionary<string, object>>(validators[0]);\n        Assert.Equal(Fixture.Validator.PublicKey.ToHex(true), validatorDict[\"publicKey\"]);\n        Assert.Equal(Fixture.Validator.Power, validatorDict[\"power\"]);\n    }\n\n    [Theory]\n    [InlineData(0)]\n    [InlineData(BlockMetadata.CurrentProtocolVersion)]\n    public async Task ThrowExecutionErrorIfViolateMutualExclusive(int version)\n    {\n        (var source, var blockHash, var stateRootHash) = Fixture.CreateMockBlockChainStates(version);\n        ExecutionResult result = await ExecuteQueryAsync<StateQuery>($@\"\n        {{\n            states(\n                addresses: [\n                    \"\"{ByteUtil.Hex(Fixture.Address.ByteArray)}\"\"\n                    \"\"0x0000000000000000000000000000000000000000\"\"\n                ]\n                offsetBlockHash: \"\"{ByteUtil.Hex(blockHash.ByteArray)}\"\"\n                offsetStateRootHash: \"\"{ByteUtil.Hex(stateRootHash.ByteArray)}\"\")\n        }}\n        \", source: source);\n        Assert.IsType<ExecutionErrors>(result.Errors);\n    }\n\n    [Theory]\n    [InlineData(0)]\n    [InlineData(BlockMetadata.CurrentProtocolVersion)]\n    public async Task StatesBySrh(int version)\n    {\n        (var source, _, var stateRootHash) = Fixture.CreateMockBlockChainStates(version);\n        ExecutionResult result = await ExecuteQueryAsync<StateQuery>($@\"\n        {{\n            states(\n                addresses: [\n                    \"\"{ByteUtil.Hex(Fixture.Address.ByteArray)}\"\"\n                    \"\"0x0000000000000000000000000000000000000000\"\"\n                ]\n                offsetStateRootHash: \"\"{ByteUtil.Hex(stateRootHash.ByteArray)}\"\"\n            )\n        }}\n        \", source: source);\n        Assert.Null(result.Errors);\n        ExecutionNode resultData = Assert.IsAssignableFrom<ExecutionNode>(result.Data);\n        IDictionary<string, object> resultDict =\n            Assert.IsAssignableFrom<IDictionary<string, object>>(resultData!.ToValue());\n        object[] states =\n            Assert.IsAssignableFrom<object[]>(resultDict[\"states\"]);\n        Assert.Equal(new[] { _codec.Encode(Fixture.Value), null }, states);\n    }\n\n    [Theory]\n    [InlineData(0)]\n    [InlineData(BlockMetadata.CurrentProtocolVersion)]\n    public async Task BalanceBySrh(int version)\n    {\n        (var source, _, var stateRootHash) = Fixture.CreateMockBlockChainStates(version);\n        ExecutionResult result = await ExecuteQueryAsync<StateQuery>($@\"\n        {{\n            balance(\n                owner: \"\"{ByteUtil.Hex(Fixture.Address.ByteArray)}\"\"\n                currency: {{ ticker: \"\"ABC\"\", decimalPlaces: 2, totalSupplyTrackable: false }}\n                offsetStateRootHash: \"\"{ByteUtil.Hex(stateRootHash.ByteArray)}\"\"\n            ) {{\n                currency {{ ticker, hash }}\n                sign\n                majorUnit\n                minorUnit\n                quantity\n                string\n            }}\n        }}\n        \", source: source);\n        Assert.Null(result.Errors);\n        ExecutionNode resultData = Assert.IsAssignableFrom<ExecutionNode>(result.Data);\n        IDictionary<string, object> resultDict =\n            Assert.IsAssignableFrom<IDictionary<string, object>>(resultData!.ToValue());\n        IDictionary<string, object> balanceDict =\n            Assert.IsAssignableFrom<IDictionary<string, object>>(resultDict[\"balance\"]);\n        IDictionary<string, object> currencyDict =\n            Assert.IsAssignableFrom<IDictionary<string, object>>(balanceDict[\"currency\"]);\n        Assert.Equal(Fixture.Currency.Ticker, currencyDict[\"ticker\"]);\n        Assert.Equal(ByteUtil.Hex(Fixture.Currency.Hash.ByteArray), currencyDict[\"hash\"]);\n        Assert.Equal(Fixture.Amount.Sign, Assert.IsAssignableFrom<int>(balanceDict[\"sign\"]));\n        Assert.Equal(\n            Fixture.Amount.MajorUnit,\n            Assert.IsAssignableFrom<BigInteger>(balanceDict[\"majorUnit\"]));\n        Assert.Equal(\n            Fixture.Amount.MinorUnit,\n            Assert.IsAssignableFrom<BigInteger>(balanceDict[\"minorUnit\"]));\n        Assert.Equal(Fixture.Amount.GetQuantityString(), balanceDict[\"quantity\"]);\n        Assert.Equal(Fixture.Amount.ToString(), balanceDict[\"string\"]);\n    }\n\n    [Theory]\n    [InlineData(0)]\n    [InlineData(BlockMetadata.CurrentProtocolVersion)]\n    public async Task TotalSupplyBySrh(int version)\n    {\n#pragma warning disable CS0618  // Legacy, which is obsolete, is the only way to test this:\n         var legacyToken = Currency.Legacy(\"LEG\", 0, null);\n#pragma warning restore CS0618\n        (var source, _, var stateRootHash) = Fixture.CreateMockBlockChainStates(version);\n        ExecutionResult result = await ExecuteQueryAsync<StateQuery>($@\"\n        {{\n            totalSupply(\n                currency: {{ ticker: \"\"ABC\"\", decimalPlaces: 2, totalSupplyTrackable: false }}\n                offsetStateRootHash: \"\"{ByteUtil.Hex(stateRootHash.ByteArray)}\"\"\n            ) {{\n                currency {{ ticker, hash }}\n                sign\n                majorUnit\n                minorUnit\n                quantity\n                string\n            }}\n        }}\n        \", source: source);\n        Assert.Null(result.Errors);\n        ExecutionNode resultData = Assert.IsAssignableFrom<ExecutionNode>(result.Data);\n        IDictionary<string, object> resultDict =\n            Assert.IsAssignableFrom<IDictionary<string, object>>(resultData!.ToValue());\n        IDictionary<string, object> totalSupplyDict =\n            Assert.IsAssignableFrom<IDictionary<string, object>>(resultDict[\"totalSupply\"]);\n        IDictionary<string, object> currencyDict =\n            Assert.IsAssignableFrom<IDictionary<string, object>>(totalSupplyDict[\"currency\"]);\n        Assert.Equal(Fixture.Currency.Ticker, currencyDict[\"ticker\"]);\n        Assert.Equal(ByteUtil.Hex(Fixture.Currency.Hash.ByteArray), currencyDict[\"hash\"]);\n        FungibleAssetValue expectedTotalSupply = version >= BlockMetadata.CurrencyAccountProtocolVersion\n            ? (Fixture.Amount + Fixture.AdditionalSupply)\n            : (Fixture.Currency * 0);\n        Assert.Equal(\n            expectedTotalSupply.Sign,\n            Assert.IsAssignableFrom<int>(totalSupplyDict[\"sign\"]));\n        Assert.Equal(\n            expectedTotalSupply.MajorUnit,\n            Assert.IsAssignableFrom<BigInteger>(totalSupplyDict[\"majorUnit\"]));\n        Assert.Equal(\n            expectedTotalSupply.MinorUnit,\n            Assert.IsAssignableFrom<BigInteger>(totalSupplyDict[\"minorUnit\"]));\n        Assert.Equal(\n            expectedTotalSupply.GetQuantityString(),\n            totalSupplyDict[\"quantity\"]);\n        Assert.Equal(\n            expectedTotalSupply.ToString(),\n            totalSupplyDict[\"string\"]);\n\n        result = await ExecuteQueryAsync<StateQuery>($@\"\n        {{\n            totalSupply(\n                currency: {{ ticker: \"\"LEG\"\", decimalPlaces: 0, totalSupplyTrackable: false }}\n                offsetStateRootHash: \"\"{ByteUtil.Hex(stateRootHash.ByteArray)}\"\") {{\n                quantity\n            }}\n        }}\n        \", source: source);\n        Assert.Null(result.Errors);\n        resultData = Assert.IsAssignableFrom<ExecutionNode>(result.Data);\n        resultDict =\n            Assert.IsAssignableFrom<IDictionary<string, object>>(resultData!.ToValue());\n        totalSupplyDict =\n            Assert.IsAssignableFrom<IDictionary<string, object>>(resultDict[\"totalSupply\"]);\n        Assert.Equal(\n            (legacyToken * 0).GetQuantityString(),\n            totalSupplyDict[\"quantity\"]);\n    }\n\n    [Theory]\n    [InlineData(0)]\n    [InlineData(BlockMetadata.CurrentProtocolVersion)]\n    public async Task ValidatorsBySrh(int version)\n    {\n        (var source, _, var stateRootHash) = Fixture.CreateMockBlockChainStates(version);\n        ExecutionResult result = await ExecuteQueryAsync<StateQuery>($@\"\n        {{\n            validators(offsetStateRootHash: \"\"{ByteUtil.Hex(stateRootHash.ByteArray)}\"\") {{\n                publicKey\n                power\n            }}\n        }}\n        \", source: source);\n        Assert.Null(result.Errors);\n        ExecutionNode resultData = Assert.IsAssignableFrom<ExecutionNode>(result.Data);\n        IDictionary<string, object> resultDict =\n            Assert.IsAssignableFrom<IDictionary<string, object>>(resultData!.ToValue());\n        object[] validators = Assert.IsAssignableFrom<object[]>(resultDict[\"validators\"]);\n        IDictionary<string, object> validatorDict =\n            Assert.IsAssignableFrom<IDictionary<string, object>>(validators[0]);\n        Assert.Equal(Fixture.Validator.PublicKey.ToHex(true), validatorDict[\"publicKey\"]);\n        Assert.Equal(Fixture.Validator.Power, validatorDict[\"power\"]);\n    }\n}\n"
  },
  {
    "path": "test/Libplanet.Explorer.Tests/Queries/StateQueryTest.cs",
    "content": "using System.Collections.Generic;\nusing System.Threading.Tasks;\nusing Bencodex;\nusing GraphQL;\nusing GraphQL.Execution;\nusing Libplanet.Common;\nusing Libplanet.Explorer.Queries;\nusing Libplanet.Types.Blocks;\nusing Libplanet.Types.Assets;\nusing Xunit;\nusing Fixture = Libplanet.Explorer.Tests.Fixtures.BlockChainStatesFixture;\nusing static Libplanet.Explorer.Tests.GraphQLTestUtils;\n\nnamespace Libplanet.Explorer.Tests.Queries;\n\npublic partial class StateQueryTest\n{\n    private static readonly Codec _codec = new Codec();\n\n    [Theory]\n    [InlineData(0)]\n    [InlineData(BlockMetadata.CurrentProtocolVersion)]\n    public async Task World(int version)\n    {\n        (var source, var blockHash, _) = Fixture.CreateMockBlockChainStates(version);\n        ExecutionResult result = await ExecuteQueryAsync<StateQuery>($@\"\n        {{\n            world(blockHash: \"\"{ByteUtil.Hex(blockHash.ByteArray)}\"\") {{\n                stateRootHash\n                legacy\n                version\n            }}\n        }}\n        \", source: source);\n        Assert.Null(result.Errors);\n        ExecutionNode resultData = Assert.IsAssignableFrom<ExecutionNode>(result.Data);\n        IDictionary<string, object> resultDict =\n            Assert.IsAssignableFrom<IDictionary<string, object>>(resultData!.ToValue());\n        IDictionary<string, object> states =\n            Assert.IsAssignableFrom<IDictionary<string, object>>(resultDict[\"world\"]);\n        Assert.NotNull(states[\"stateRootHash\"]);\n\n        if (version >= BlockMetadata.WorldStateProtocolVersion)\n        {\n            Assert.False((bool)states[\"legacy\"]);\n        }\n        else\n        {\n            Assert.True((bool)states[\"legacy\"]);\n        }\n\n        Assert.Equal(version, states[\"version\"]);\n    }\n\n    [Theory]\n    [InlineData(0)]\n    [InlineData(BlockMetadata.CurrentProtocolVersion)]\n    public async Task WorldByBlockHashThenAccountThenStateAndStates(int version)\n    {\n        (var source, var blockHash, _) = Fixture.CreateMockBlockChainStates(version);\n        ExecutionResult result = await ExecuteQueryAsync<StateQuery>($@\"\n        {{\n            world (blockHash: \"\"{ByteUtil.Hex(blockHash.ByteArray)}\"\") {{\n                account (address: \"\"0x1000000000000000000000000000000000000000\"\") {{\n                    state (address: \"\"{ByteUtil.Hex(Fixture.Address.ByteArray)}\"\") {{\n                        hex\n                    }}\n                    states (addresses: [\n                        \"\"{ByteUtil.Hex(Fixture.Address.ByteArray)}\"\",\n                        \"\"0x0000000000000000000000000000000000000000\"\"\n                    ]) {{\n                        hex\n                    }}\n                }}\n            }}\n        }}\n        \", source: source);\n\n        Assert.Null(result.Errors);\n        ExecutionNode resultData = Assert.IsAssignableFrom<ExecutionNode>(result.Data);\n        IDictionary<string, object> resultDict =\n            Assert.IsAssignableFrom<IDictionary<string, object>>(resultData!.ToValue());\n        IDictionary<string, object> account =\n            Assert.IsAssignableFrom<IDictionary<string, object>>(\n                Assert.IsAssignableFrom<IDictionary<string, object>>(\n                    resultDict[\"world\"])[\"account\"]);\n\n        IDictionary<string, object> state =\n            Assert.IsAssignableFrom<IDictionary<string, object>>(account[\"state\"]);\n        Assert.Equal(\n            ByteUtil.Hex(_codec.Encode(Fixture.Value)),\n            Assert.IsAssignableFrom<string>(state[\"hex\"]));\n\n        object[] states =\n            Assert.IsAssignableFrom<object[]>(account[\"states\"]);\n        Assert.Equal(2, states.Length);\n        Assert.Equal(\n            ByteUtil.Hex(_codec.Encode(Fixture.Value)),\n            Assert.IsAssignableFrom<string>(\n                Assert.IsAssignableFrom<IDictionary<string, object>>(states[0])[\"hex\"]));\n        Assert.Null(states[1]);\n    }\n\n    [Theory]\n    [InlineData(0)]\n    [InlineData(BlockMetadata.CurrentProtocolVersion)]\n    public async Task WorldByBlockHashThenBalance(int version)\n    {\n        (var source, var blockHash, _) = Fixture.CreateMockBlockChainStates(version);\n        ExecutionResult result = await ExecuteQueryAsync<StateQuery>($@\"\n        {{\n            world (blockHash: \"\"{ByteUtil.Hex(blockHash.ByteArray)}\"\") {{\n                balance (\n                    address: \"\"{ByteUtil.Hex(Fixture.Address.ByteArray)}\"\"\n                    currency: {{\n                        ticker: \"\"ABC\"\"\n                        decimalPlaces: 2\n                        minters: null\n                        totalSupplyTrackable: false }}) {{\n                    string\n                }}\n            }}\n        }}\n        \", source: source);\n\n        Assert.Null(result.Errors);\n        ExecutionNode resultData = Assert.IsAssignableFrom<ExecutionNode>(result.Data);\n        IDictionary<string, object> resultDict =\n            Assert.IsAssignableFrom<IDictionary<string, object>>(resultData!.ToValue());\n        IDictionary<string, object> world =\n            Assert.IsAssignableFrom<IDictionary<string, object>>(resultDict[\"world\"]);\n        IDictionary<string, object> balance =\n            Assert.IsAssignableFrom<IDictionary<string, object>>(world[\"balance\"]);\n        Assert.Equal(\n            Fixture.Amount.ToString(),\n            Assert.IsAssignableFrom<string>(balance[\"string\"]));\n    }\n\n    [Theory]\n    [InlineData(0)]\n    [InlineData(BlockMetadata.CurrentProtocolVersion)]\n    public async Task WorldByBlockHashThenTotalSupply(int version)\n    {\n        (var source, var blockHash, _) = Fixture.CreateMockBlockChainStates(version);\n        ExecutionResult result = await ExecuteQueryAsync<StateQuery>($@\"\n        {{\n            world (blockHash: \"\"{ByteUtil.Hex(blockHash.ByteArray)}\"\") {{\n                totalSupply (currency: {{\n                    ticker: \"\"ABC\"\"\n                    decimalPlaces: 2\n                    minters: null\n                    totalSupplyTrackable: false }}) {{\n                    string\n                }}\n            }}\n        }}\n        \", source: source);\n\n        Assert.Null(result.Errors);\n        ExecutionNode resultData = Assert.IsAssignableFrom<ExecutionNode>(result.Data);\n        IDictionary<string, object> resultDict =\n            Assert.IsAssignableFrom<IDictionary<string, object>>(resultData!.ToValue());\n        IDictionary<string, object> totalSupply =\n            Assert.IsAssignableFrom<IDictionary<string, object>>(\n                Assert.IsAssignableFrom<IDictionary<string, object>>(\n                    resultDict[\"world\"])[\"totalSupply\"]);\n        FungibleAssetValue expectedTotalSupply = version >= BlockMetadata.CurrencyAccountProtocolVersion\n            ? (Fixture.Amount + Fixture.AdditionalSupply)\n            : (Fixture.Currency * 0);\n        Assert.Equal(\n            expectedTotalSupply.ToString(),\n            Assert.IsAssignableFrom<string>(totalSupply[\"string\"]));\n    }\n\n    [Theory]\n    [InlineData(0)]\n    [InlineData(BlockMetadata.CurrentProtocolVersion)]\n    public async Task WorldByBlockHashThenValidatorSet(int version)\n    {\n        (var source, var blockHash, _) = Fixture.CreateMockBlockChainStates(version);\n        ExecutionResult result = await ExecuteQueryAsync<StateQuery>($@\"\n        {{\n            world (blockHash: \"\"{ByteUtil.Hex(blockHash.ByteArray)}\"\") {{\n                validatorSet {{\n                    hex\n                }}\n            }}\n        }}\n        \", source: source);\n\n        Assert.Null(result.Errors);\n        ExecutionNode resultData = Assert.IsAssignableFrom<ExecutionNode>(result.Data);\n        IDictionary<string, object> resultDict =\n            Assert.IsAssignableFrom<IDictionary<string, object>>(resultData!.ToValue());\n        IDictionary<string, object> validatorSet =\n            Assert.IsAssignableFrom<IDictionary<string, object>>(\n                Assert.IsAssignableFrom<IDictionary<string, object>>(\n                    resultDict[\"world\"])[\"validatorSet\"]);\n        Assert.Equal(\n            ByteUtil.Hex(_codec.Encode(Fixture.ValidatorSet.Bencoded)),\n            Assert.IsAssignableFrom<string>(validatorSet[\"hex\"]));\n    }\n\n    [Theory]\n    [InlineData(0)]\n    [InlineData(BlockMetadata.CurrentProtocolVersion)]\n    public async Task WorldByStateRootHashThenAccountThenStateAndStates(int version)\n    {\n        (var source, _, var stateRootHash) = Fixture.CreateMockBlockChainStates(version);\n        ExecutionResult result = await ExecuteQueryAsync<StateQuery>($@\"\n        {{\n            world (stateRootHash: \"\"{ByteUtil.Hex(stateRootHash.ByteArray)}\"\") {{\n                account (address: \"\"0x1000000000000000000000000000000000000000\"\") {{\n                    state (address: \"\"{ByteUtil.Hex(Fixture.Address.ByteArray)}\"\") {{\n                        hex\n                    }}\n                    states (addresses: [\n                        \"\"{ByteUtil.Hex(Fixture.Address.ByteArray)}\"\"\n                        \"\"0x0000000000000000000000000000000000000000\"\"\n                    ]) {{\n                        hex\n                    }}\n                }}\n            }}\n        }}\n        \", source: source);\n\n        Assert.Null(result.Errors);\n        ExecutionNode resultData = Assert.IsAssignableFrom<ExecutionNode>(result.Data);\n        IDictionary<string, object> resultDict =\n            Assert.IsAssignableFrom<IDictionary<string, object>>(resultData!.ToValue());\n        IDictionary<string, object> account =\n            Assert.IsAssignableFrom<IDictionary<string, object>>(\n                Assert.IsAssignableFrom<IDictionary<string, object>>(\n                    resultDict[\"world\"])[\"account\"]);\n\n        IDictionary<string, object> state =\n            Assert.IsAssignableFrom<IDictionary<string, object>>(account[\"state\"]);\n        Assert.Equal(\n            ByteUtil.Hex(_codec.Encode(Fixture.Value)),\n            Assert.IsAssignableFrom<string>(state[\"hex\"]));\n\n        object[] states =\n            Assert.IsAssignableFrom<object[]>(account[\"states\"]);\n        Assert.Equal(2, states.Length);\n        Assert.Equal(\n            ByteUtil.Hex(_codec.Encode(Fixture.Value)),\n            Assert.IsAssignableFrom<string>(\n                Assert.IsAssignableFrom<IDictionary<string, object>>(states[0])[\"hex\"]));\n        Assert.Null(states[1]);\n    }\n\n    [Theory]\n    [InlineData(0)]\n    [InlineData(BlockMetadata.CurrentProtocolVersion)]\n    public async Task WorldByBlockHashThenAccountsThenStateAndStates(int version)\n    {\n        (var source, var blockHash, _) = Fixture.CreateMockBlockChainStates(version);\n        ExecutionResult result = await ExecuteQueryAsync<StateQuery>($@\"\n        {{\n            world (blockHash: \"\"{ByteUtil.Hex(blockHash.ByteArray)}\"\") {{\n                accounts (addresses: [\"\"0x1000000000000000000000000000000000000000\"\"]) {{\n                    state (address: \"\"{ByteUtil.Hex(Fixture.Address.ByteArray)}\"\") {{\n                        hex\n                    }}\n                    states (addresses: [\n                        \"\"{ByteUtil.Hex(Fixture.Address.ByteArray)}\"\"\n                        \"\"0x0000000000000000000000000000000000000000\"\"]) {{\n                        hex\n                    }}\n                }}\n            }}\n        }}\n        \", source: source);\n\n        Assert.Null(result.Errors);\n        ExecutionNode resultData = Assert.IsAssignableFrom<ExecutionNode>(result.Data);\n        IDictionary<string, object> resultDict =\n            Assert.IsAssignableFrom<IDictionary<string, object>>(resultData!.ToValue());\n        object[] accounts =\n            Assert.IsAssignableFrom<object[]>(\n                Assert.IsAssignableFrom<IDictionary<string, object>>(\n                    resultDict[\"world\"])[\"accounts\"]);\n\n        IDictionary<string,object> account =\n            Assert.IsAssignableFrom<IDictionary<string, object>>(Assert.Single(accounts));\n        IDictionary<string, object> state =\n            Assert.IsAssignableFrom<IDictionary<string, object>>(account[\"state\"]);\n        Assert.Equal(\n            ByteUtil.Hex(_codec.Encode(Fixture.Value)),\n            Assert.IsAssignableFrom<string>(state[\"hex\"]));\n\n        object[] states =\n            Assert.IsAssignableFrom<object[]>(account[\"states\"]);\n        Assert.Equal(2, states.Length);\n        Assert.Equal(\n            ByteUtil.Hex(_codec.Encode(Fixture.Value)),\n            Assert.IsAssignableFrom<string>(\n                Assert.IsAssignableFrom<IDictionary<string, object>>(states[0])[\"hex\"]));\n        Assert.Null(states[1]);\n    }\n}\n"
  },
  {
    "path": "test/Libplanet.Explorer.Tests/Queries/TransactionQueryGeneratedTest.cs",
    "content": "#nullable enable\nusing System.Collections.Generic;\nusing System.Collections.Immutable;\nusing System.Globalization;\nusing System.Linq;\nusing System.Threading.Tasks;\nusing GraphQL;\nusing GraphQL.Execution;\nusing Libplanet.Action;\nusing Libplanet.Crypto;\nusing Libplanet.Types.Blocks;\nusing Libplanet.Types.Tx;\nusing Libplanet.Explorer.Queries;\nusing Xunit;\nusing static Libplanet.Explorer.Tests.GraphQLTestUtils;\n\nnamespace Libplanet.Explorer.Tests.Queries;\n\npublic class TransactionQueryGeneratedTest\n{\n    protected readonly GeneratedBlockChainFixture Fx;\n    protected MockBlockChainContext Source;\n    protected TransactionQuery QueryGraph;\n\n    public TransactionQueryGeneratedTest()\n    {\n        Fx = new GeneratedBlockChainFixture(\n            new System.Random().Next(),\n            txActionsForSuffixBlocks:\n            ImmutableArray<ImmutableArray<ImmutableArray<SimpleAction>>>.Empty\n                .Add(ImmutableArray<ImmutableArray<SimpleAction>>.Empty\n                    .Add(ImmutableArray<SimpleAction>.Empty\n                        .Add(new SimpleAction0())\n                        .Add(new SimpleAction0())))     // Successful action transaction\n                .Add(ImmutableArray<ImmutableArray<SimpleAction>>.Empty\n                    .Add(ImmutableArray<SimpleAction>.Empty\n                        .Add(new SimpleAction0())\n                        .Add(new SimpleAction0Fail())\n                        .Add(new SimpleAction0()))) // Failed action transaction\n                .Add(ImmutableArray<ImmutableArray<SimpleAction>>.Empty\n                    .Add(ImmutableArray<SimpleAction>.Empty))); // Empty action transaction\n        Source = new MockBlockChainContext(Fx.Chain);\n        var _ = new ExplorerQuery(Source);\n        QueryGraph = new TransactionQuery(Source);\n    }\n\n    [Fact]\n    public async Task TransactionResult()\n    {\n        var emptyBlock = Fx.Chain.Tip;\n        var emptyTx = emptyBlock.Transactions[0];\n        var failBlock = Fx.Chain.Store.GetBlock(emptyBlock.PreviousHash!.Value)!;\n        var failTx = failBlock.Transactions[0];\n        var successBlock = Fx.Chain.Store.GetBlock(failBlock.PreviousHash!.Value)!;\n        var successTx = successBlock.Transactions[0];\n        var pk = Fx.PrivateKeys[0];\n        var stagingTx = Transaction.Create(\n            Fx.Chain.GetNextTxNonce(pk.Address),\n            pk,\n            Fx.Chain.Genesis.Hash,\n            ImmutableArray<SimpleAction>.Empty.Add(new SimpleAction1()).ToPlainValues());\n        Fx.Chain.StageTransaction(stagingTx);\n\n        var queryResult = await ExecuteTransactionResultQueryAsync(successTx.Id);\n        Assert.Equal(\"SUCCESS\", queryResult.TxStatus);\n        Assert.Equal(successBlock.Index, queryResult.BlockIndex);\n        Assert.Equal(successBlock.Hash.ToString(), queryResult.BlockHash);\n        Assert.Equal(new string?[] { null , null }, queryResult.ExceptionNames);\n        queryResult = await ExecuteTransactionResultQueryAsync(failTx.Id);\n        Assert.Equal(\"FAILURE\", queryResult.TxStatus);\n        Assert.Equal(failBlock.Index, queryResult.BlockIndex);\n        Assert.Equal(failBlock.Hash.ToString(), queryResult.BlockHash);\n        Assert.Equal(\n            new string?[] { null, \"Libplanet.Action.State.CurrencyPermissionException\", null },\n            queryResult.ExceptionNames);\n        queryResult = await ExecuteTransactionResultQueryAsync(emptyTx.Id);\n        Assert.Equal(\"INCLUDED\", queryResult.TxStatus);\n        Assert.Equal(emptyBlock.Index, queryResult.BlockIndex);\n        Assert.Equal(emptyBlock.Hash.ToString(), queryResult.BlockHash);\n        Assert.Null(queryResult.ExceptionNames);\n        queryResult = await ExecuteTransactionResultQueryAsync(new TxId());\n        Assert.Equal(\"INVALID\", queryResult.TxStatus);\n        Assert.Null(queryResult.BlockIndex);\n        Assert.Null(queryResult.BlockHash);\n        Assert.Null(queryResult.ExceptionNames);\n        queryResult = await ExecuteTransactionResultQueryAsync(stagingTx.Id);\n        Assert.Equal(\"STAGING\", queryResult.TxStatus);\n        Assert.Null(queryResult.BlockIndex);\n        Assert.Null(queryResult.BlockHash);\n        Assert.Null(queryResult.ExceptionNames);\n    }\n\n    [Fact]\n    public virtual async Task Transactions()\n    {\n        var allBlocks = Fx.Chain.IterateBlocks().ToImmutableArray();\n        await AssertTransactionsQueryPermutation(allBlocks, null, null);\n        foreach (var signer in Fx.PrivateKeys.Select(pk => pk.Address))\n        {\n            await AssertTransactionsQueryPermutation(allBlocks, signer, null);\n            await AssertTransactionsQueryPermutation(allBlocks, null, signer);\n            foreach (var involved in Fx.PrivateKeys.Select(pk => pk.Address))\n            {\n                await AssertTransactionsQueryPermutation(allBlocks, signer, involved);\n            }\n        }\n    }\n\n    private async Task AssertTransactionsQueryPermutation(\n        ImmutableArray<Block> blocksToTest,\n        Address? signer,\n        Address? involvedAddress)\n    {\n        await AssertAgainstTransactionsQuery(\n            blocksToTest, signer, false, null, null);\n        await AssertAgainstTransactionsQuery(\n            blocksToTest, signer, true, null, null);\n        await AssertAgainstTransactionsQuery(\n            blocksToTest, signer, false, blocksToTest.Length / 4, null);\n        await AssertAgainstTransactionsQuery(\n            blocksToTest,\n            signer,\n            false,\n            blocksToTest.Length / 4 - blocksToTest.Length,\n            null);\n        Assert.Equal<IEnumerable<(string Id, string? BlockHash)>>(\n            await ExecuteTransactionsQueryAsync(\n                signer, false, blocksToTest.Length / 4, null),\n            await ExecuteTransactionsQueryAsync(\n                signer,\n                false,\n                blocksToTest.Length / 4 - blocksToTest.Length,\n                null));\n        await AssertAgainstTransactionsQuery(\n            blocksToTest, signer, true, blocksToTest.Length / 4, null);\n        await AssertAgainstTransactionsQuery(\n            blocksToTest,\n            signer,\n            true,\n            blocksToTest.Length / 4 - blocksToTest.Length,\n            null);\n        Assert.Equal<IEnumerable<(string Id, string? BlockHash)>>(\n            await ExecuteTransactionsQueryAsync(\n                signer, true, blocksToTest.Length / 4, null),\n            await ExecuteTransactionsQueryAsync(\n                signer,\n                true,\n                blocksToTest.Length / 4 - blocksToTest.Length,\n                null));\n        await AssertAgainstTransactionsQuery(\n            blocksToTest, signer, false, null, blocksToTest.Length / 4);\n        await AssertAgainstTransactionsQuery(\n            blocksToTest, signer, true, null, blocksToTest.Length / 4);\n        await AssertAgainstTransactionsQuery(\n            blocksToTest,\n            signer,\n            false,\n            blocksToTest.Length / 3,\n            blocksToTest.Length / 4);\n        await AssertAgainstTransactionsQuery(\n            blocksToTest,\n            signer,\n            false,\n            blocksToTest.Length / 3 - blocksToTest.Length,\n            blocksToTest.Length / 4);\n        Assert.Equal<IEnumerable<(string Id, string? BlockHash)>>(\n            await ExecuteTransactionsQueryAsync(\n                signer,\n                false,\n                blocksToTest.Length / 3,\n                blocksToTest.Length / 4),\n            await ExecuteTransactionsQueryAsync(\n                signer,\n                false,\n                blocksToTest.Length / 3 - blocksToTest.Length,\n                blocksToTest.Length / 4));\n        await AssertAgainstTransactionsQuery(\n            blocksToTest,\n            signer,\n            true,\n            blocksToTest.Length / 3,\n            blocksToTest.Length / 4);\n        await AssertAgainstTransactionsQuery(\n            blocksToTest,\n            signer,\n            true,\n            blocksToTest.Length / 3 - blocksToTest.Length,\n            blocksToTest.Length / 4);\n        Assert.Equal<IEnumerable<(string Id, string? BlockHash)>>(\n            await ExecuteTransactionsQueryAsync(\n                signer,\n                true,\n                blocksToTest.Length / 3,\n                blocksToTest.Length / 4),\n            await ExecuteTransactionsQueryAsync(\n                signer,\n                true,\n                blocksToTest.Length / 3 - blocksToTest.Length,\n                blocksToTest.Length / 4));\n    }\n\n    private async Task AssertAgainstTransactionsQuery(\n        IReadOnlyList<Block> blocksToTest,\n        Address? signer,\n        bool desc,\n        int? offset,\n        int? limit)\n    {\n        IEnumerable<Block> blocks = blocksToTest;\n        if (offset is { } offsetVal)\n        {\n            offsetVal = offsetVal >= 0 ? offsetVal : blocksToTest.Count + offsetVal;\n            blocks = desc ? blocks.SkipLast(offsetVal) : blocks.Skip(offsetVal);\n        }\n        IEnumerable<Transaction> txs =\n            blocks.SelectMany(block => block.Transactions);\n\n        if (desc)\n        {\n            txs = txs.Reverse();\n        }\n\n        if (signer is { } signerVal)\n        {\n            txs = txs.Where(tx => tx.Signer.Equals(signerVal));\n        }\n\n        if (limit is { } limitVal)\n        {\n            txs = txs.Take(limitVal);\n        }\n\n        var expected = txs.ToImmutableArray();\n        var actual =\n            await ExecuteTransactionsQueryAsync(signer, desc, offset, limit);\n\n        foreach (var i in Enumerable.Range(0, actual.Length))\n        {\n            Assert.Equal(expected[i].Id.ToHex(), actual[i].Id);\n            if (Source.Index is not null)\n            {\n                Assert.Equal(\n                    (\n                        await Source.Index.GetContainedBlockHashByTxIdAsync(expected[i].Id)\n                            .ConfigureAwait(false))\n                    .ToString(),\n                    actual[i].BlockHash);\n            }\n        }\n    }\n\n    private async Task<ImmutableArray<(string Id, string? BlockHash)>>\n        ExecuteTransactionsQueryAsync(\n            Address? signer,\n            bool desc,\n            int? offset,\n            int? limit)\n    {\n        ExecutionResult result = await ExecuteQueryAsync(@$\"\n        {{\n            transactions(\n                {(signer is { } signerVal ? @$\"signer: \"\"{signerVal}\"\"\" : \"\")}\n                desc: {(desc ? \"true\" : \"false\")}\n                offset: {offset?.ToString(CultureInfo.InvariantCulture) ?? \"0\"}\n                {(limit is { } limitVal ? $\"limit: {limitVal}\" : \"\")}\n            )\n            {{\n                id\n                {(Source.Index is not null ? \"blockRef { hash }\" : \"\")}\n            }}\n         }}\n        \", QueryGraph, source: Source);\n        Assert.Null(result.Errors);\n        ExecutionNode resultData = Assert.IsAssignableFrom<ExecutionNode>(result.Data);\n        IDictionary<string, object> resultDict =\n            Assert.IsAssignableFrom<IDictionary<string, object>>(resultData.ToValue());\n        return ((IReadOnlyList<object>)resultDict[\"transactions\"])\n            .Select(txData =>\n            (\n                (string)((IDictionary<string, object>)txData)[\"id\"],\n                (string?)(Source.Index is not null\n                    ? ((IDictionary<string, object>)\n                        ((IDictionary<string, object>)txData)[\"blockRef\"]\n                    )[\"hash\"]\n                    : null)))\n            .ToImmutableArray();\n    }\n\n    private async Task<\n            (string TxStatus, long? BlockIndex, string? BlockHash, string?[]? ExceptionNames)>\n        ExecuteTransactionResultQueryAsync(TxId txId)\n    {\n        ExecutionResult result = await ExecuteQueryAsync(@$\"\n        {{\n            transactionResult(txId: \"\"{txId.ToHex()}\"\")\n            {{\n                txStatus\n                blockIndex\n                blockHash\n                exceptionNames\n            }}\n         }}\n        \", QueryGraph, source: Source);\n        Assert.Null(result.Errors);\n        ExecutionNode resultData = Assert.IsAssignableFrom<ExecutionNode>(result.Data);\n        IDictionary<string, object> resultDict =\n            (IDictionary<string, object>)Assert.IsAssignableFrom<IDictionary<string, object>>(\n                resultData.ToValue())[\"transactionResult\"];\n        var exceptionNames = ((object[]?)resultDict[\"exceptionNames\"])?.Select(\n            name => name is { } n ? Assert.IsType<string>(n) : null).ToArray();\n        return (\n            (string)resultDict[\"txStatus\"],\n            (long?)resultDict[\"blockIndex\"],\n            (string?)resultDict[\"blockHash\"],\n            (string?[]?)exceptionNames);\n    }\n}\n"
  },
  {
    "path": "test/Libplanet.Explorer.Tests/Queries/TransactionQueryGeneratedWithIndexTest.cs",
    "content": "using System.Threading.Tasks;\nusing Libplanet.Action;\nusing Libplanet.Explorer.Queries;\nusing Xunit;\n\nnamespace Libplanet.Explorer.Tests.Queries;\n\npublic class TransactionQueryGeneratedWithIndexTest : TransactionQueryGeneratedTest\n{\n    public TransactionQueryGeneratedWithIndexTest()\n    {\n        Source = new MockBlockChainContextWithIndex(Fx.Chain);\n        var _ = new ExplorerQuery(Source);\n        QueryGraph = new TransactionQuery(Source);\n    }\n\n    [SkippableFact(Skip = \"transactionQuery.transactions does not support indexing.\")]\n    public override Task Transactions() => Task.CompletedTask;\n}\n"
  },
  {
    "path": "test/Libplanet.Explorer.Tests/Queries/TransactionQueryTest.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Collections.Immutable;\nusing System.Linq;\nusing System.Threading.Tasks;\nusing Bencodex.Types;\nusing GraphQL;\nusing GraphQL.Execution;\nusing Libplanet.Action;\nusing Libplanet.Action.Sys;\nusing Libplanet.Blockchain;\nusing Libplanet.Blockchain.Policies;\nusing Libplanet.Common;\nusing Libplanet.Crypto;\nusing Libplanet.Types.Assets;\nusing Libplanet.Types.Consensus;\nusing Libplanet.Types.Tx;\nusing Libplanet.Explorer.Queries;\nusing Libplanet.Store;\nusing Libplanet.Store.Trie;\nusing Xunit;\nusing static Libplanet.Explorer.Tests.GraphQLTestUtils;\nusing Libplanet.Action.Loader;\n\nnamespace Libplanet.Explorer.Tests.Queries;\n\npublic class TransactionQueryTest\n{\n    protected readonly BlockChain Chain;\n    protected MockBlockChainContext Source;\n    protected TransactionQuery QueryGraph;\n\n    public TransactionQueryTest()\n    {\n        Chain = Libplanet.Tests.TestUtils.MakeBlockChain(\n            new BlockPolicy(),\n            new MemoryStore(),\n            new TrieStateStore(new MemoryKeyValueStore()),\n            new SingleActionLoader(typeof(NullAction)),\n            privateKey: new PrivateKey(),\n            timestamp: DateTimeOffset.UtcNow\n        );\n        Source = new MockBlockChainContext(Chain);\n        QueryGraph = new TransactionQuery(Source);\n    }\n\n    [Fact]\n    public async Task BindSignatureWithCustomActions()\n    {\n        var tx = Transaction.Create(\n            0L,\n            new PrivateKey(),\n            Source.BlockChain.Genesis.Hash,\n            Enumerable.Empty<NullAction>().ToPlainValues()\n        );\n        tx.MarshalUnsignedTx();\n        ExecutionResult result = await ExecuteQueryAsync(@$\"\n        {{\n            bindSignature(\n                unsignedTransaction: \"\"{ByteUtil.Hex(tx.SerializeUnsignedTx())}\"\",\n                signature: \"\"{ByteUtil.Hex(tx.Signature)}\"\"\n            )\n         }}\n         \", QueryGraph, source: Source);\n        Assert.Null(result.Errors);\n        ExecutionNode resultData = Assert.IsAssignableFrom<ExecutionNode>(result.Data);\n        IDictionary<string, object> resultDict =\n            Assert.IsAssignableFrom<IDictionary<string, object>>(resultData!.ToValue());\n        Assert.Equal(tx.Serialize(), ByteUtil.ParseHex((string)resultDict[\"bindSignature\"]));\n    }\n\n    [Fact]\n    public async Task BindSignatureWithSystemAction()\n    {\n        var foo = Currency.Uncapped(\"FOO\", 2, ImmutableHashSet<Address>.Empty);\n        var action = new Initialize(\n            new ValidatorSet(new List<Validator>()\n                { new Validator(new PrivateKey().PublicKey, 1 )}),\n            new Dictionary<Address, IValue>\n            {\n                [default] = (Text)\"initial value\"\n            }.ToImmutableDictionary());\n        var tx = Transaction.Create(\n            0L,\n            new PrivateKey(),\n            Source.BlockChain.Genesis.Hash,\n            new IAction[] { action }.ToPlainValues()\n        );\n        ExecutionResult result = await ExecuteQueryAsync(@$\"\n        {{\n            bindSignature(\n                unsignedTransaction: \"\"{ByteUtil.Hex(tx.SerializeUnsignedTx())}\"\",\n                signature: \"\"{ByteUtil.Hex(tx.Signature)}\"\"\n            )\n         }}\n         \", QueryGraph, source: Source);\n        Assert.Null(result.Errors);\n        ExecutionNode resultData = Assert.IsAssignableFrom<ExecutionNode>(result.Data);\n        IDictionary<string, object> resultDict =\n            Assert.IsAssignableFrom<IDictionary<string, object>>(resultData!.ToValue());\n        Assert.Equal(tx.Serialize(), ByteUtil.ParseHex((string)resultDict[\"bindSignature\"]));\n    }\n\n    [Fact]\n    public async Task NextNonce()\n    {\n        async Task AssertNextNonce(long expected, Address address) {\n            var result = await ExecuteQueryAsync(@$\"\n            {{\n                nextNonce(\n                    address: \"\"{address}\"\"\n                )\n            }}\n            \", QueryGraph, source: Source);\n\n            Assert.Null(result.Errors);\n            ExecutionNode resultData = Assert.IsAssignableFrom<ExecutionNode>(result.Data);\n            IDictionary<string, object> resultDict =\n                Assert.IsAssignableFrom<IDictionary<string, object>>(resultData!.ToValue());\n            Assert.Equal(Source.BlockChain.GetNextTxNonce(address), (long)resultDict[\"nextNonce\"]);\n            Assert.Equal(expected, (long)resultDict[\"nextNonce\"]);\n        }\n\n        var key1 = new PrivateKey();\n        // account nonce is 0 in the beginning\n        await AssertNextNonce(0, key1.Address);\n\n        // staged txs increase next nonce\n        Source.BlockChain.MakeTransaction(key1, ImmutableList<NullAction>.Empty.Add(new NullAction()));\n        await AssertNextNonce(1, key1.Address);\n        Source.BlockChain.MakeTransaction(key1, ImmutableList<NullAction>.Empty.Add(new NullAction()));\n        await AssertNextNonce(2, key1.Address);\n        var block = Source.BlockChain.ProposeBlock(new PrivateKey());\n        Source.BlockChain.Append(block, Libplanet.Tests.TestUtils.CreateBlockCommit(block));\n        await AssertNextNonce(2, key1.Address);\n\n        var key2 = new PrivateKey();\n        await AssertNextNonce(0, key2.Address);\n\n        // staging txs of key2 does not increase nonce of key1\n        Source.BlockChain.MakeTransaction(key2, ImmutableList<NullAction>.Empty.Add(new NullAction()));\n        block = Source.BlockChain.ProposeBlock(\n            new PrivateKey(),\n            Libplanet.Tests.TestUtils.CreateBlockCommit(block));\n        Source.BlockChain.Append(block, Libplanet.Tests.TestUtils.CreateBlockCommit(block));\n        await AssertNextNonce(1, key2.Address);\n        await AssertNextNonce(2, key1.Address);\n\n        // unstaging txs decrease nonce\n        Source.BlockChain.MakeTransaction(key1, ImmutableList<NullAction>.Empty.Add(new NullAction()));\n        await AssertNextNonce(3, key1.Address);\n        Source.BlockChain.MakeTransaction(key1, ImmutableList<NullAction>.Empty.Add(new NullAction()));\n        await AssertNextNonce(4, key1.Address);\n        Source.BlockChain.GetStagedTransactionIds()\n            .Select(Source.BlockChain.GetTransaction)\n            .Select(Source.BlockChain.UnstageTransaction)\n            .ToImmutableList();\n        await AssertNextNonce(2, key1.Address);\n    }\n}\n"
  },
  {
    "path": "test/Libplanet.Explorer.Tests/Queries/TransactionQueryWithIndexTest.cs",
    "content": "using Libplanet.Explorer.Queries;\n\nnamespace Libplanet.Explorer.Tests.Queries;\n\npublic class TransactionQueryWithIndexTest : TransactionQueryTest\n{\n    public TransactionQueryWithIndexTest()\n    {\n        Source = new MockBlockChainContextWithIndex(Chain);\n        QueryGraph = new TransactionQuery(Source);\n    }\n}\n"
  },
  {
    "path": "test/Libplanet.Explorer.Tests/SimpleAction.cs",
    "content": "using System;\nusing System.Reflection;\nusing Bencodex.Types;\nusing Libplanet.Action;\nusing Libplanet.Action.State;\n\nnamespace Libplanet.Explorer.Tests;\n\npublic abstract class SimpleAction : IAction\n{\n    public IValue TypeId => this\n        .GetType()\n        .GetCustomAttribute<ActionTypeAttribute>() is ActionTypeAttribute attribute\n            ? attribute.TypeIdentifier\n            : throw new NullReferenceException(\n                $\"Given type {this.GetType()} is missing {nameof(ActionTypeAttribute)}.\");\n\n    public IValue PlainValue => Dictionary.Empty\n        .Add(\"type_id\", TypeId)\n        .Add(\"values\", Null.Value);\n\n    public void LoadPlainValue(IValue plainValue)\n    {\n    }\n\n    public virtual IWorld Execute(IActionContext context) => context.PreviousState;\n\n    public static SimpleAction GetAction(int seed) =>\n        (seed % 10) switch\n        {\n            1 => new SimpleAction1(),\n            2 => new SimpleAction2(),\n            3 => new SimpleAction3(),\n            4 => new SimpleAction4(),\n            5 => new SimpleAction5(),\n            6 => new SimpleAction6(),\n            7 => new SimpleAction7(),\n            8 => new SimpleAction8(),\n            9 => new SimpleAction0Fail(),\n            _ => new SimpleAction0(),\n        };\n}\n\n[ActionType(nameof(SimpleAction0))]\npublic class SimpleAction0 : SimpleAction\n{\n}\n\n[ActionType(nameof(SimpleAction1))]\npublic class SimpleAction1 : SimpleAction\n{\n}\n\n[ActionType(nameof(SimpleAction2))]\npublic class SimpleAction2 : SimpleAction\n{\n}\n\n[ActionType(nameof(SimpleAction3))]\npublic class SimpleAction3 : SimpleAction\n{\n}\n\n[ActionType(nameof(SimpleAction4))]\npublic class SimpleAction4 : SimpleAction\n{\n}\n\n[ActionType(nameof(SimpleAction5))]\npublic class SimpleAction5 : SimpleAction\n{\n}\n\n[ActionType(nameof(SimpleAction6))]\npublic class SimpleAction6 : SimpleAction\n{\n}\n\n[ActionType(nameof(SimpleAction7))]\npublic class SimpleAction7 : SimpleAction\n{\n}\n\n[ActionType(nameof(SimpleAction8))]\npublic class SimpleAction8 : SimpleAction\n{\n}\n\n// For overlapping custom action id test and fail test\n[ActionType(nameof(SimpleAction0Fail))]\npublic class SimpleAction0Fail : SimpleAction\n{\n    public override IWorld Execute(IActionContext context) =>\n        throw new CurrencyPermissionException(\"test message\", context.Signer, default);\n}\n"
  },
  {
    "path": "test/Libplanet.Explorer.Tests/TestUtils.cs",
    "content": "using System;\n\nnamespace Libplanet.Explorer.Tests\n{\n    public static class TestUtils\n    {\n        private static readonly Random _random;\n\n        static TestUtils()\n        {\n            _random = new Random();\n        }\n\n        public static byte[] GetRandomBytes(int size)\n        {\n            var bytes = new byte[size];\n            _random.NextBytes(bytes);\n            return bytes;\n        }\n\n        public static int GetRandomNumber() => _random.Next();\n    }\n}\n"
  },
  {
    "path": "test/Libplanet.Extensions.Cocona.Tests/AssemblyInfo.cs",
    "content": "using Xunit;\n\n[assembly: CollectionBehavior(CollectionBehavior.CollectionPerAssembly)]\n"
  },
  {
    "path": "test/Libplanet.Extensions.Cocona.Tests/BlockPolicyParamsTest.cs",
    "content": "namespace Libplanet.Extensions.Cocona.Tests;\n\nusing System;\nusing System.Collections.Immutable;\nusing Libplanet.Action;\nusing Libplanet.Blockchain.Policies;\nusing Xunit;\n\npublic class BlockPolicyParamsTest\n{\n    [Fact]\n    public void DefaultState()\n    {\n        var blockPolicyParams = new BlockPolicyParams();\n        var policyActionsRegistry = blockPolicyParams.GetPolicyActionsRegistry();\n        Assert.Null(blockPolicyParams.GetBlockPolicy());\n        Assert.Empty(policyActionsRegistry.BeginBlockActions);\n        Assert.Empty(policyActionsRegistry.EndBlockActions);\n        Assert.Empty(policyActionsRegistry.BeginBlockActions);\n        Assert.Empty(policyActionsRegistry.EndTxActions);\n    }\n\n    [Fact]\n    public void GetBlockPolicy()\n    {\n        var blockPolicyParams = new BlockPolicyParams\n        {\n            PolicyFactory = $\"{GetType().FullName}.{nameof(BlockPolicyFactory)}\",\n        };\n        BlockPolicy blockPolicy = Assert.IsType<BlockPolicy>(\n            blockPolicyParams.GetBlockPolicy(new[] { GetType().Assembly })\n        );\n        Assert.Single(blockPolicy.PolicyActionsRegistry.BeginBlockActions);\n        Assert.IsType<NullAction>(blockPolicy.PolicyActionsRegistry.BeginBlockActions[0]);\n        Assert.Single(blockPolicy.PolicyActionsRegistry.EndBlockActions);\n        Assert.IsType<NullAction>(blockPolicy.PolicyActionsRegistry.EndBlockActions[0]);\n        Assert.Single(blockPolicy.PolicyActionsRegistry.BeginTxActions);\n        Assert.IsType<NullAction>(blockPolicy.PolicyActionsRegistry.BeginTxActions[0]);\n        Assert.Single(blockPolicy.PolicyActionsRegistry.EndTxActions);\n        Assert.IsType<NullAction>(blockPolicy.PolicyActionsRegistry.EndTxActions[0]);\n    }\n\n    [Fact]\n    public void GetBlockPolicy_NonQualifiedName()\n    {\n        var blockPolicyParams = new BlockPolicyParams\n        {\n            PolicyFactory = nameof(BlockPolicyFactory),\n        };\n        var e = Assert.Throws<TypeLoadException>(() =>\n            blockPolicyParams.GetBlockPolicy(new[] { GetType().Assembly }));\n        Assert.Contains(\"qualified name\", e.Message, StringComparison.InvariantCultureIgnoreCase);\n    }\n\n    [Fact]\n    public void GetBlockPolicy_ReferringNonExistentType()\n    {\n        var blockPolicyParams = new BlockPolicyParams\n        {\n            PolicyFactory = $\"{GetType().FullName}__NonExistent__.{nameof(BlockPolicyFactory)}\",\n        };\n        var e = Assert.Throws<TypeLoadException>(() =>\n            blockPolicyParams.GetBlockPolicy(new[] { GetType().Assembly }));\n        Assert.Contains(\n            \"failed to load policy type\",\n            e.Message,\n            StringComparison.InvariantCultureIgnoreCase);\n    }\n\n    [Fact]\n    public void GetBlockPolicy_ReferringNonExistentMethod()\n    {\n        var blockPolicyParams = new BlockPolicyParams\n        {\n            PolicyFactory = $\"{GetType().FullName}.{nameof(BlockPolicyFactory)}__NonExistent__\",\n        };\n        var e = Assert.Throws<TypeLoadException>(() =>\n            blockPolicyParams.GetBlockPolicy(new[] { GetType().Assembly }));\n        Assert.Contains(\n            \"failed to find a static method\",\n            e.Message,\n            StringComparison.InvariantCultureIgnoreCase);\n    }\n\n    [Fact]\n    public void GetBlockPolicy_ReferringInstanceMethod()\n    {\n        var blockPolicyParams = new BlockPolicyParams\n        {\n            PolicyFactory = $\"{GetType().FullName}.{nameof(BlockPolicyFactoryInstanceMethod)}\",\n        };\n        var e = Assert.Throws<TypeLoadException>(() =>\n            blockPolicyParams.GetBlockPolicy(new[] { GetType().Assembly }));\n        Assert.Contains(\n            \"failed to find a static method\",\n            e.Message,\n            StringComparison.InvariantCultureIgnoreCase);\n    }\n\n    [Fact]\n    public void GetBlockPolicy_NotAcceptingMethodWithParams()\n    {\n        var blockPolicyParams = new BlockPolicyParams\n        {\n            PolicyFactory = $\"{GetType().FullName}.{nameof(BlockPolicyFactoryWithParams)}\",\n        };\n        var e = Assert.Throws<TypeLoadException>(() =>\n            blockPolicyParams.GetBlockPolicy(new[] { GetType().Assembly }));\n        Assert.Contains(\"parameters\", e.Message, StringComparison.InvariantCultureIgnoreCase);\n    }\n\n    [Fact]\n    public void GetBlockPolicy_NotAcceptingMethodWithWrongReturnType()\n    {\n        var blockPolicyParams = new BlockPolicyParams\n        {\n            PolicyFactory = $\"{GetType().FullName}.{nameof(BlockPolicyFactoryWithWrongReturnType)}\",\n        };\n        var e = Assert.Throws<TypeLoadException>(() =>\n            blockPolicyParams.GetBlockPolicy(new[] { GetType().Assembly }));\n        Assert.Contains(\"return type\", e.Message, StringComparison.InvariantCultureIgnoreCase);\n    }\n\n    [Fact]\n    public void GetBlockPolicy_FactoryReturningNull()\n    {\n        var blockPolicyParams = new BlockPolicyParams\n        {\n            PolicyFactory = $\"{GetType().FullName}.{nameof(BlockPolicyFactoryReturningNull)}\",\n        };\n        var e = Assert.Throws<InvalidOperationException>(() =>\n            blockPolicyParams.GetBlockPolicy(new[] { GetType().Assembly }));\n        Assert.Contains(\"returned null\", e.Message, StringComparison.InvariantCultureIgnoreCase);\n    }\n\n    [Fact]\n    public void GetPolicyActionsRegistry()\n    {\n        var blockPolicyParams = new BlockPolicyParams\n        {\n            PolicyFactory = $\"{GetType().FullName}.{nameof(BlockPolicyFactory)}\",\n        };\n        var policyActionsRegistry =\n            blockPolicyParams.GetPolicyActionsRegistry(new[] { GetType().Assembly });\n        Assert.IsType<NullAction>(Assert.Single(policyActionsRegistry.BeginBlockActions));\n        Assert.IsType<NullAction>(Assert.Single(policyActionsRegistry.EndBlockActions));\n        Assert.IsType<NullAction>(Assert.Single(policyActionsRegistry.BeginTxActions));\n        Assert.IsType<NullAction>(Assert.Single(policyActionsRegistry.EndTxActions));\n    }\n\n    internal static BlockPolicy BlockPolicyFactory() =>\n        new BlockPolicy(\n            new PolicyActionsRegistry(\n                ImmutableArray.Create<IAction>(new NullAction()),\n                ImmutableArray.Create<IAction>(new NullAction()),\n                ImmutableArray.Create<IAction>(new NullAction()),\n                ImmutableArray.Create<IAction>(new NullAction())));\n\n    internal static BlockPolicy BlockPolicyFactoryWithParams(bool param) =>\n        new BlockPolicy();\n\n    internal static int BlockPolicyFactoryWithWrongReturnType() => 0;\n\n    internal static BlockPolicy BlockPolicyFactoryReturningNull() => null!;\n\n    internal BlockPolicy BlockPolicyFactoryInstanceMethod() => new BlockPolicy();\n}\n"
  },
  {
    "path": "test/Libplanet.Extensions.Cocona.Tests/Commands/MptCommandTest.cs",
    "content": "#nullable disable\nusing System;\nusing System.Collections.Generic;\nusing System.IO;\nusing Bencodex.Types;\nusing Libplanet.Common;\nusing Libplanet.Extensions.Cocona.Commands;\nusing Libplanet.Extensions.Cocona.Configuration;\nusing Libplanet.Store;\nusing Libplanet.Store.Trie;\nusing Libplanet.Tools.Tests.Services;\nusing Xunit;\n\nnamespace Libplanet.Extensions.Cocona.Tests.Commands;\n\npublic class MptCommandTest : IDisposable\n{\n    private readonly MptCommand _command;\n    private readonly string _pathA;\n    private readonly string _pathB;\n    private readonly ITrie _trieA;\n    private readonly ITrie _trieB;\n\n    public MptCommandTest()\n    {\n        _command = new MptCommand();\n\n        _pathA = NewTempPath();\n        _pathB = NewTempPath();\n        using var stateKeyValueStoreA = new DefaultKeyValueStore(_pathA);\n        using var stateKeyValueStoreB = new DefaultKeyValueStore(_pathB);\n        using var stateStoreA = new TrieStateStore(new DefaultKeyValueStore(_pathA));\n        using var stateStoreB = new TrieStateStore(new DefaultKeyValueStore(_pathB));\n        _trieA = stateStoreA.Commit(\n            stateStoreA.GetStateRoot(null)\n                .Set(new KeyBytes(\"deleted\"), Null.Value)\n                .Set(new KeyBytes(\"common\"), (Text)\"before\"));\n        _trieB = stateStoreB.Commit(\n            stateStoreB.GetStateRoot(null)\n                .Set(new KeyBytes(\"created\"), Null.Value)\n                .Set(new KeyBytes(\"common\"), (Text)\"after\"));\n    }\n\n    [Fact]\n    public void Diff_PrintsAsJson()\n    {\n        using StringWriter stringWriter = new StringWriter { NewLine = \"\\n\" };\n        var originalOutWriter = Console.Out;\n        try\n        {\n            Console.SetOut(stringWriter);\n            var kvStoreUri = $\"default://{_pathA}\";\n            var otherKvStoreUri = $\"default://{_pathB}\";\n            var configuration =\n                new ToolConfiguration(new MptConfiguration(new Dictionary<string, string>()));\n            string stateRootHashHex = ByteUtil.Hex(_trieA.Hash.ByteArray);\n            string otherStateRootHashHex = ByteUtil.Hex(_trieB.Hash.ByteArray);\n\n            _command.Diff(\n                kvStoreUri,\n                stateRootHashHex,\n                otherKvStoreUri,\n                otherStateRootHashHex,\n                new TestToolConfigurationService(configuration));\n\n            string expected = string.Format(\n                @\"{{\"\"Key\"\":\"\"636f6d6d6f6e\"\",\"\"StateRootHashToValue\"\":\" +\n                @\"{{\"\"{0}\"\":\"\"75353a6166746572\"\",\"\"{1}\"\":\"\"75363a6265666f7265\"\"}}}}\" + \"\\n\" +\n                @\"{{\"\"Key\"\":\"\"64656c65746564\"\",\" +\n                @\"\"\"StateRootHashToValue\"\":{{\"\"{0}\"\":\"\"null\"\",\"\"{1}\"\":\"\"6e\"\"}}}}\" + \"\\n\",\n                otherStateRootHashHex,\n                stateRootHashHex);\n            Assert.Equal(\n                expected,\n                stringWriter.ToString());\n        }\n        finally\n        {\n            Console.SetOut(originalOutWriter);\n        }\n    }\n\n    public void Dispose()\n    {\n        if (Directory.Exists(_pathA))\n        {\n            Directory.Delete(_pathA, true);\n        }\n\n        if (Directory.Exists(_pathB))\n        {\n            Directory.Delete(_pathB, true);\n        }\n    }\n\n    private static string NewTempPath() =>\n        Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString())\n            .Replace(\"\\\\\", \"/\")\n            .Replace(\"C:\", string.Empty);\n}\n"
  },
  {
    "path": "test/Libplanet.Extensions.Cocona.Tests/Commands/StatsCommandTest.cs",
    "content": "namespace Libplanet.Extensions.Cocona.Tests.Commands;\n\nusing System;\nusing System.Collections.Immutable;\nusing System.IO;\nusing Libplanet.Extensions.Cocona.Commands;\nusing Libplanet.RocksDBStore.Tests;\nusing Libplanet.Tests.Store;\nusing Xunit;\n\npublic class StatsCommandTest : IDisposable\n{\n    private readonly ImmutableArray<StoreFixture> _storeFixtures;\n    private readonly StatsCommand _command;\n    private readonly TextWriter _originalWriter;\n\n    public StatsCommandTest()\n    {\n        _command = new StatsCommand();\n        _originalWriter = Console.Out;\n        try\n        {\n            _storeFixtures = ImmutableArray.Create<StoreFixture>(\n                new DefaultStoreFixture(false),\n                new RocksDBStoreFixture()\n            );\n        }\n        catch (TypeInitializationException)\n        {\n            throw new SkipException(\"RocksDB is not available.\");\n        }\n\n        foreach (var storeFixture in _storeFixtures)\n        {\n            var guid = Guid.NewGuid();\n            storeFixture.Store.SetCanonicalChainId(guid);\n            storeFixture.Store.PutBlock(storeFixture.Block1);\n            storeFixture.Store.AppendIndex(guid, storeFixture.Block1.Hash);\n            storeFixture.Store.PutTransaction(storeFixture.Transaction1);\n        }\n    }\n\n    ~StatsCommandTest()\n    {\n        Dispose();\n    }\n\n    [SkippableFact]\n    [Trait(\"CircleCI\", \"Skip\")]\n    public void SummaryInvalidArguments()\n    {\n        string badPathFormat = \"rocksdb+foo+bar://\" + \"/bar\";\n        string badPathScheme = \"foo://\" + \"/bar\";\n        long badOffset = long.MaxValue;\n        long badLimit = 0;\n\n        foreach (var storeFixture in _storeFixtures)\n        {\n            _command.Summary(\n                store: storeFixture.Store,\n                header: true,\n                offset: 0,\n                limit: 1);\n\n            Assert.Throws<ArgumentException>(() =>\n                _command.Summary(\n                    path: badPathFormat,\n                    header: true,\n                    offset: 0,\n                    limit: 1));\n            Assert.Throws<ArgumentException>(() =>\n                _command.Summary(\n                    path: badPathScheme,\n                    header: true,\n                    offset: 0,\n                    limit: 1));\n            Assert.Throws<ArgumentException>(() =>\n                _command.Summary(\n                    store: storeFixture.Store,\n                    header: true,\n                    offset: badOffset,\n                    limit: 1));\n            Assert.Throws<ArgumentException>(() =>\n                _command.Summary(\n                    store: storeFixture.Store,\n                    header: true,\n                    offset: 0,\n                    limit: badLimit));\n        }\n    }\n\n    public void Dispose()\n    {\n        foreach (var storeFixture in _storeFixtures)\n        {\n            storeFixture.Store?.Dispose();\n            storeFixture.StateStore?.Dispose();\n        }\n\n        Console.SetOut(_originalWriter);\n        _originalWriter.Dispose();\n    }\n}\n"
  },
  {
    "path": "test/Libplanet.Extensions.Cocona.Tests/Commands/StoreCommandTest.cs",
    "content": "#nullable disable\nusing System;\nusing System.Collections.Immutable;\nusing System.IO;\nusing global::Cocona;\nusing Libplanet.Action;\nusing Libplanet.Crypto;\nusing Libplanet.Extensions.Cocona.Commands;\nusing Libplanet.RocksDBStore.Tests;\nusing Libplanet.Tests;\nusing Libplanet.Tests.Store;\nusing Libplanet.Types.Blocks;\nusing Libplanet.Types.Tx;\nusing Xunit;\nusing Xunit.Abstractions;\n\nnamespace Libplanet.Extensions.Cocona.Tests.Commands;\n\n[Trait(\"CircleCI\", \"Skip\")]\npublic class StoreCommandTest : IDisposable\n{\n    private readonly ImmutableArray<StoreFixture> _storeFixtures;\n    private readonly ITestOutputHelper _testOutput;\n    private readonly TextWriter _originalOut;\n    private readonly TextWriter _originalError;\n    private readonly Block _genesisBlock;\n    private readonly Block _block1;\n    private readonly Block _block2;\n    private readonly Block _block3;\n    private readonly Block _block4;\n    private readonly Block _block5;\n    private readonly Transaction _transaction1;\n    private readonly Transaction _transaction2;\n    private readonly Transaction _transaction3;\n    private readonly Transaction _transaction4;\n\n    public StoreCommandTest(ITestOutputHelper testOutput)\n    {\n        _testOutput = testOutput;\n        _originalOut = Console.Out;\n        _originalError = Console.Error;\n\n        try\n        {\n            _storeFixtures = ImmutableArray.Create<StoreFixture>(\n                new DefaultStoreFixture(false),\n                new RocksDBStoreFixture()\n            );\n        }\n        catch (TypeInitializationException)\n        {\n            throw new SkipException(\"RocksDB is not available.\");\n        }\n\n        _genesisBlock =\n                TestUtils.ProposeGenesisBlock(TestUtils.GenesisProposer);\n        _transaction1 = DummyTransaction();\n        _transaction2 = DummyTransaction();\n        _transaction3 = DummyTransaction();\n        _transaction4 = DummyTransaction();\n\n        _block1 = TestUtils.ProposeNextBlock(\n                _genesisBlock,\n                TestUtils.GenesisProposer,\n                new[] { _transaction1 },\n                lastCommit: null);\n        _block2 = TestUtils.ProposeNextBlock(\n                _block1,\n                TestUtils.GenesisProposer,\n                new[] { _transaction2 },\n                lastCommit: TestUtils.CreateBlockCommit(_block1));\n        _block3 = TestUtils.ProposeNextBlock(\n                _block2,\n                TestUtils.GenesisProposer,\n                new[] { _transaction3 },\n                lastCommit: TestUtils.CreateBlockCommit(_block2));\n        _block4 = TestUtils.ProposeNextBlock(\n                _block3,\n                TestUtils.GenesisProposer,\n                new[] { _transaction3 },\n                lastCommit: TestUtils.CreateBlockCommit(_block3));\n        _block5 = TestUtils.ProposeNextBlock(\n                _block4,\n                TestUtils.GenesisProposer,\n                lastCommit: TestUtils.CreateBlockCommit(_block4));\n\n        var guid = Guid.NewGuid();\n        foreach (var v in _storeFixtures)\n        {\n            v.Store.SetCanonicalChainId(guid);\n            v.Store.PutBlock(_genesisBlock);\n            v.Store.AppendIndex(guid, _genesisBlock.Hash);\n\n            v.Store.PutBlock(_block1);\n            v.Store.AppendIndex(guid, _block1.Hash);\n            v.Store.PutTransaction(_transaction1);\n\n            v.Store.PutBlock(_block2);\n            v.Store.AppendIndex(guid, _block2.Hash);\n            v.Store.PutTransaction(_transaction2);\n\n            v.Store.PutBlock(_block3);\n            v.Store.AppendIndex(guid, _block3.Hash);\n            v.Store.PutTransaction(_transaction3);\n\n            v.Store.PutBlock(_block4);\n            v.Store.AppendIndex(guid, _block4.Hash);\n\n            v.Store?.Dispose();\n            v.StateStore?.Dispose();\n        }\n    }\n\n    ~StoreCommandTest()\n    {\n        Dispose();\n    }\n\n    [SkippableFact]\n    public void TestInvalidArguments()\n    {\n        Assert.Throws<ArgumentException>(() =>\n            new StoreCommand().BlockByHash(\n                \"rocksdb+file+file://\" + \"/blah\",\n                \"dummy\"\n            ));\n        Assert.Throws<ArgumentException>(() =>\n            new StoreCommand().BlockByHash(\n                \"rocksdb+memory://\" + \"/blah\",\n                \"dummy\"\n            ));\n        Assert.Throws<ArgumentException>(() =>\n            new StoreCommand().BlockByHash(\n                \"leveldb://\" + \"/blah\",\n                \"dummy\"\n            ));\n    }\n\n    [SkippableFact]\n    public void TestBlockByTxIdNotExist()\n    {\n        foreach (var fx in _storeFixtures)\n        {\n            new StoreCommand().BuildIndexTxBlock(\n                fx.Scheme + fx.Path,\n                0,\n                10);\n        }\n\n        foreach (var fx in _storeFixtures)\n        {\n            Assert.Throws<CommandExitedException>(() =>\n                new StoreCommand().BlocksByTxId(\n                    fx.Scheme + fx.Path,\n                    _transaction4.Id.ToString()\n                ));\n        }\n    }\n\n    [SkippableFact]\n    public void TestBlockByTxIdTwo()\n    {\n        foreach (var fx in _storeFixtures)\n        {\n            new StoreCommand().BuildIndexTxBlock(\n                fx.Scheme + fx.Path,\n                0,\n                10);\n        }\n\n        foreach (var fx in _storeFixtures)\n        {\n            using var stdout = new StringWriter();\n            using var stderr = new StringWriter();\n            Console.SetOut(stdout);\n            Console.SetError(stderr);\n            new StoreCommand().BlocksByTxId(\n                fx.Scheme + fx.Path,\n                _transaction3.Id.ToString()\n            );\n            var actual = stdout.ToString();\n            _testOutput.WriteLine($\"stdout:\\n  {actual.Replace(\"\\n\", \"\\n  \")}\\n\");\n            _testOutput.WriteLine($\"stderr:\\n  {stderr.ToString().Replace(\"\\n\", \"\\n  \")}\\n\");\n            var expected = Utils.SerializeHumanReadable(new[] { _block3, _block4 });\n            if (expected.TrimEnd() != actual.TrimEnd())\n            {\n                expected = Utils.SerializeHumanReadable(new[] { _block4, _block3 });\n            }\n\n            _testOutput.WriteLine($\"expected:\\n  {expected.Replace(\"\\n\", \"\\n  \")}\\n\");\n            Assert.Equal(\n                expected.TrimEnd(),\n                actual.TrimEnd(),\n                ignoreLineEndingDifferences: true,\n                ignoreWhiteSpaceDifferences: true\n            );\n        }\n    }\n\n    [SkippableFact]\n    public void TestBlockHashesByTxId()\n    {\n        foreach (var fx in _storeFixtures)\n        {\n            new StoreCommand().BuildIndexTxBlock(\n                fx.Scheme + fx.Path,\n                0,\n                10);\n        }\n\n        foreach (var fx in _storeFixtures)\n        {\n            using var sw = new StringWriter();\n            Console.SetOut(sw);\n            new StoreCommand().BlockHashesByTxId(\n                fx.Scheme + fx.Path,\n                _transaction3.Id.ToString()\n            );\n            var actual = sw.ToString();\n            var expected = Utils.SerializeHumanReadable(new[] { _block3.Hash, _block4.Hash });\n            if (expected.TrimEnd() != actual.TrimEnd())\n            {\n                expected = Utils.SerializeHumanReadable(new[] { _block4.Hash, _block3.Hash });\n            }\n\n            Assert.Equal(expected.TrimEnd(), actual.TrimEnd());\n        }\n    }\n\n    [SkippableFact]\n    public void TestBuildIndexTxBlockBlockByTxId()\n    {\n        foreach (var fx in _storeFixtures)\n        {\n            new StoreCommand().BuildIndexTxBlock(\n                fx.Scheme + fx.Path,\n                0,\n                10);\n        }\n\n        foreach (var fx in _storeFixtures)\n        {\n            void AssertTxBlockIndex(\n                Transaction tx,\n                Block block\n            )\n            {\n                using var sw = new StringWriter();\n                Console.SetOut(sw);\n                new StoreCommand().BlocksByTxId(\n                    fx.Scheme + fx.Path,\n                    tx.Id.ToString()\n                );\n                var actual = sw.ToString();\n                var expected = Utils.SerializeHumanReadable(new[] { block });\n                Assert.Equal(expected.TrimEnd(), actual.TrimEnd());\n            }\n\n            AssertTxBlockIndex(_transaction1, _block1);\n            AssertTxBlockIndex(_transaction2, _block2);\n        }\n    }\n\n    [SkippableFact]\n    public void TestBlockByHashNotExists()\n    {\n        foreach (var fx in _storeFixtures)\n        {\n            Assert.Throws<CommandExitedException>(() =>\n                new StoreCommand().BlockByHash(\n                    fx.Scheme + fx.Path,\n                    _block5.Hash.ToString())\n            );\n        }\n    }\n\n    [SkippableFact]\n    public void TestBlockByHash()\n    {\n        foreach (var fx in _storeFixtures)\n        {\n            using var sw = new StringWriter();\n            Console.SetOut(sw);\n            new StoreCommand().BlockByHash(\n                fx.Scheme + fx.Path,\n                _block1.Hash.ToString());\n            var actual = sw.ToString();\n            var expected = Utils.SerializeHumanReadable(_block1);\n            Assert.Equal(expected.TrimEnd(), actual.TrimEnd());\n        }\n    }\n\n    [SkippableFact]\n    public void TestBlockByIndexNotExists()\n    {\n        foreach (var fx in _storeFixtures)\n        {\n            Assert.Throws<CommandExitedException>(() =>\n                new StoreCommand().BlockByIndex(\n                    fx.Scheme + fx.Path,\n                    9999999 * 100\n                )\n            );\n        }\n    }\n\n    [SkippableFact]\n    public void TestBlockByIndex()\n    {\n        foreach (var fx in _storeFixtures)\n        {\n            using var sw = new StringWriter();\n            Console.SetOut(sw);\n            new StoreCommand().BlockByIndex(fx.Scheme + fx.Path, 0);\n            var actual = sw.ToString();\n            var expected = Utils.SerializeHumanReadable(_genesisBlock);\n            Assert.Equal(expected.TrimEnd(), actual.TrimEnd());\n        }\n    }\n\n    [SkippableFact]\n    public void TestTxByIdNotExists()\n    {\n        foreach (var fx in _storeFixtures)\n        {\n            Assert.Throws<CommandExitedException>(() =>\n                new StoreCommand().TxById(\n                    fx.Scheme + fx.Path,\n                    fx.Transaction2.Id.ToString())\n            );\n        }\n    }\n\n    [SkippableFact]\n    public void TestTxById()\n    {\n        foreach (var fx in _storeFixtures)\n        {\n            using var sw = new StringWriter();\n            Console.SetOut(sw);\n            new StoreCommand().TxById(\n                fx.Scheme + fx.Path,\n                _transaction1.Id.ToString());\n            var actual = sw.ToString();\n            var expected = Utils.SerializeHumanReadable(_transaction1);\n            Assert.Equal(expected.TrimEnd(), actual.TrimEnd());\n        }\n    }\n\n    public void Dispose()\n    {\n        foreach (var storeFixture in _storeFixtures)\n        {\n            storeFixture.Store?.Dispose();\n            storeFixture.StateStore?.Dispose();\n        }\n\n        Console.SetOut(_originalOut);\n        Console.SetError(_originalError);\n        _originalOut.Dispose();\n        _originalError.Dispose();\n    }\n\n    private Transaction DummyTransaction()\n    {\n        return Transaction.Create(\n            0,\n            new PrivateKey(),\n            _genesisBlock.Hash,\n            new[] { new Utils.DummyAction() }.ToPlainValues(),\n            null,\n            null,\n            DateTimeOffset.UtcNow);\n    }\n}\n"
  },
  {
    "path": "test/Libplanet.Extensions.Cocona.Tests/Commands/TxCommandTest.cs",
    "content": "using System.IO;\nusing System.Reflection;\nusing Libplanet.Extensions.Cocona.Commands;\nusing Xunit;\n\nnamespace Libplanet.Extensions.Cocona.Tests.Commands;\n\npublic class TxCommandTest\n{\n    public static readonly string FixturesPath = Path.Combine(\n        Path.GetDirectoryName(Assembly.GetAssembly(typeof(TxCommandTest))!.Location)!,\n        \"Fixtures\");\n\n    [Fact]\n    public void Analyze()\n    {\n        TxCommand cmd = new ();\n        int exitCode = cmd.Analyze(\n            Path.Combine(FixturesPath, \"tx.bin\"),\n            unsigned: false,\n            ignoreSignature: false);\n        Assert.Equal(0, exitCode);\n\n        exitCode = cmd.Analyze(\n            Path.Combine(FixturesPath, \"invalid-tx.bin\"),\n            unsigned: false,\n            ignoreSignature: false);\n        Assert.Equal(-1, exitCode);\n    }\n}\n"
  },
  {
    "path": "test/Libplanet.Extensions.Cocona.Tests/Libplanet.Extensions.Cocona.Tests.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <PropertyGroup>\n    <TreatWarningsAsErrors>true</TreatWarningsAsErrors>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <PackageReference Include=\"System.Collections.Immutable\" Version=\"1.7.*\" />\n  </ItemGroup>\n\n  <ItemGroup Condition=\"'$(SkipSonar)' != 'true'\">\n    <PackageReference Remove=\"SonarAnalyzer.CSharp\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <ProjectReference Include=\"..\\..\\tools\\Libplanet.Extensions.Cocona\\Libplanet.Extensions.Cocona.csproj\" />\n    <ProjectReference Include=\"..\\..\\test\\Libplanet.RocksDBStore.Tests\\Libplanet.RocksDBStore.Tests.csproj\" />\n    <ProjectReference Include=\"..\\Libplanet.Tests\\Libplanet.Tests.csproj\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <None Include=\"Fixtures\\**\" CopyToOutputDirectory=\"PreserveNewest\" CopyToPublishDirectory=\"PreserveNewest\" LinkBase=\"Fixtures\" />\n  </ItemGroup>\n\n</Project>\n"
  },
  {
    "path": "test/Libplanet.Extensions.Cocona.Tests/Services/TestToolConfigurationService.cs",
    "content": "namespace Libplanet.Tools.Tests.Services;\n\nusing Libplanet.Extensions.Cocona.Configuration;\nusing Libplanet.Extensions.Cocona.Services;\n\npublic class TestToolConfigurationService : IConfigurationService<ToolConfiguration>\n{\n    public TestToolConfigurationService(ToolConfiguration configuration)\n    {\n        Configuration = configuration;\n    }\n\n    private ToolConfiguration Configuration { get; set; }\n\n    public ToolConfiguration Load()\n    {\n        return Configuration;\n    }\n\n    public void Store(ToolConfiguration configuration)\n    {\n        Configuration = configuration;\n    }\n}\n"
  },
  {
    "path": "test/Libplanet.Extensions.Cocona.Tests/UtilsTest.cs",
    "content": "namespace Libplanet.Extensions.Cocona.Tests;\n\nusing System;\nusing System.Collections.Immutable;\nusing System.Globalization;\nusing System.Linq;\nusing Xunit;\n\npublic class UtilsTest\n{\n    [Fact]\n    public void TestHumanReadable()\n    {\n        var byteArray = ImmutableArray.Create<byte>(\n            0x45, 0xa2, 0x21, 0x87, 0xe2, 0xd8, 0x85, 0x0b, 0xb3, 0x57\n        );\n        var dateTimeOffset = DateTimeOffset.ParseExact(\n            DateTimeOffset.UtcNow.ToString(\n                Utils.DateTimeOffsetFormat,\n                CultureInfo.InvariantCulture\n            ), Utils.DateTimeOffsetFormat,\n            CultureInfo.InvariantCulture);\n        var dummyClass = new DummyClass(byteArray, dateTimeOffset);\n\n        var serialized = Utils.SerializeHumanReadable(dummyClass);\n        var dummyClass2 = Utils.DeserializeHumanReadable<DummyClass>(serialized);\n        Assert.NotNull(dummyClass2);\n        Assert.True(dummyClass.SampleByteArray.SequenceEqual(dummyClass2!.SampleByteArray));\n        Assert.Equal(dummyClass.SampleDateTimeOffset, dummyClass2.SampleDateTimeOffset);\n    }\n\n    private class DummyClass\n    {\n        public DummyClass()\n        {\n        }\n\n        public DummyClass(\n            ImmutableArray<byte> sampleByteArray,\n            DateTimeOffset sampleDateTimeOffset)\n        {\n            SampleByteArray = sampleByteArray;\n            SampleDateTimeOffset = sampleDateTimeOffset;\n        }\n\n        public ImmutableArray<byte> SampleByteArray { get; set; }\n\n        public DateTimeOffset SampleDateTimeOffset { get; set; }\n    }\n}\n"
  },
  {
    "path": "test/Libplanet.Mocks/Libplanet.Mocks.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <PropertyGroup>\n    <TargetFrameworks Condition=\"'$(_IsPacking)'=='true'\">$(TargetFrameworks);netstandard2.0;netstandard2.1</TargetFrameworks>\n    <IsPackable>true</IsPackable>\n    <IsTestProject>false</IsTestProject>\n    <IsPublishable>true</IsPublishable>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <PackageReference Include=\"System.Collections.Immutable\" Version=\"1.*\" />\n    <PackageReference Include=\"System.Text.Json\" Version=\"6.0.*\" />\n    <PackageReference Include=\"Bencodex\" Version=\"0.16.0\" />\n  </ItemGroup>\n\n  <ItemGroup Condition=\"'$(SkipSonar)' != 'true'\">\n    <PackageReference Remove=\"SonarAnalyzer.CSharp\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <PackageReference Remove=\"JunitXml.TestLogger\" />\n    <PackageReference Remove=\"Microsoft.NET.Test.Sdk\" />\n    <PackageReference Remove=\"xunit\" />\n    <PackageReference Remove=\"xunit.runner.visualstudio\" />\n    <PackageReference Remove=\"xunit.extensibility.execution\" />\n    <PackageReference Remove=\"coverlet.collector\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <ProjectReference Include=\"..\\..\\src\\Libplanet.Action\\Libplanet.Action.csproj\" />\n    <ProjectReference Include=\"..\\..\\src\\Libplanet.Common\\Libplanet.Common.csproj\" />\n    <ProjectReference Include=\"..\\..\\src\\Libplanet.Crypto\\Libplanet.Crypto.csproj\" />\n    <ProjectReference Include=\"..\\..\\src\\Libplanet.Store\\Libplanet.Store.csproj\" />\n    <ProjectReference Include=\"..\\..\\src\\Libplanet.Types\\Libplanet.Types.csproj\" />\n  </ItemGroup>\n\n</Project>\n"
  },
  {
    "path": "test/Libplanet.Mocks/MockBlockChainStates.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Security.Cryptography;\nusing Libplanet.Action.State;\nusing Libplanet.Common;\nusing Libplanet.Store;\nusing Libplanet.Store.Trie;\nusing Libplanet.Types.Blocks;\n\nnamespace Libplanet.Mocks\n{\n    public class MockBlockChainStates : IBlockChainStates\n    {\n        private IStateStore _stateStore;\n\n        private Dictionary<BlockHash, HashDigest<SHA256>> _map;\n\n        public MockBlockChainStates()\n        {\n            _stateStore = new TrieStateStore(new MemoryKeyValueStore());\n            _map = new Dictionary<BlockHash, HashDigest<SHA256>>();\n        }\n\n        public IStateStore StateStore => _stateStore;\n\n        public void AttachBlockHashToStateRootHash(\n            BlockHash blockHash,\n            HashDigest<SHA256> stateRootHash)\n        {\n            if (_map.ContainsKey(blockHash))\n            {\n                throw new ArgumentException(\n                    $\"Already contains block hash {blockHash} associated to \" +\n                    $\"state root hash {_map[blockHash]}.\",\n                    nameof(blockHash));\n            }\n            else if (!_stateStore.GetStateRoot(stateRootHash).Recorded)\n            {\n                throw new ArgumentException(\n                    $\"No state root for given state root hash {stateRootHash} found.\",\n                    nameof(stateRootHash));\n            }\n\n            _map[blockHash] = stateRootHash;\n        }\n\n        /// <inheritdoc cref=\"IBlockChainStates.GetWorldState(BlockHash?)\"/>\n        public IWorldState GetWorldState(BlockHash offset)\n        {\n            if (_map.ContainsKey(offset))\n            {\n                return GetWorldState(_map[offset]);\n            }\n            else\n            {\n                throw new ArgumentException(\n                    $\"No state root associated with given block hash {offset} found.\",\n                    nameof(offset));\n            }\n        }\n\n        /// <inheritdoc cref=\"IBlockChainStates.GetWorldState(HashDigest{SHA256}?)\"/>\n        public IWorldState GetWorldState(HashDigest<SHA256>? stateRootHash)\n        {\n            ITrie trie = _stateStore.GetStateRoot(stateRootHash);\n            return trie.Recorded\n                ? new WorldBaseState(trie, _stateStore)\n                : throw new ArgumentException(\n                    $\"Could not find state root {stateRootHash} in {nameof(IStateStore)}.\",\n                    nameof(stateRootHash));\n        }\n    }\n}\n"
  },
  {
    "path": "test/Libplanet.Mocks/MockUtil.cs",
    "content": "using Libplanet.Action.State;\nusing Libplanet.Store;\nusing Libplanet.Store.Trie;\n\nnamespace Libplanet.Mocks\n{\n    public static class MockUtil\n    {\n        private static readonly IStateStore _stateStore =\n            new TrieStateStore(new MemoryKeyValueStore());\n\n        /// <summary>\n        /// A disposable empty <see cref=\"ITrie\"/>.\n        /// </summary>\n        public static ITrie MockTrie => _stateStore.GetStateRoot(null);\n\n        /// <summary>\n        /// A disposable empty <see cref=\"IAccountState\"/>.\n        /// </summary>\n        public static IAccountState MockAccountState => new AccountState(MockTrie);\n\n        /// <summary>\n        /// A disposable empty legacy <see cref=\"IWorldState\"/>.\n        /// </summary>\n        public static IWorldState MockLegacyWorldState => MockWorldState.CreateLegacy(_stateStore);\n\n        /// <summary>\n        /// A disposable empty modern <see cref=\"IWorldState\"/>.\n        /// </summary>\n        public static IWorldState MockModernWorldState => MockWorldState.CreateModern(_stateStore);\n    }\n}\n"
  },
  {
    "path": "test/Libplanet.Mocks/MockWorldState.cs",
    "content": "using System;\nusing System.Security.Cryptography;\nusing Bencodex.Types;\nusing Libplanet.Action.State;\nusing Libplanet.Common;\nusing Libplanet.Crypto;\nusing Libplanet.Store;\nusing Libplanet.Store.Trie;\nusing Libplanet.Types.Assets;\nusing Libplanet.Types.Blocks;\nusing Libplanet.Types.Consensus;\nusing static Libplanet.Action.State.KeyConverters;\n\nnamespace Libplanet.Mocks\n{\n    /// <summary>\n    /// <para>\n    /// A mock implementation of <see cref=\"IWorldState\"/> with various methods for\n    /// setting up a semi-valid <see cref=\"IWorldState\"/> for testing.\n    /// </para>\n    /// <para>\n    /// For ease of use, any mutating method automatically commits the resulting\n    /// <see cref=\"MockWorldState\"/> to the <see cref=\"IStateStore\"/> that the instance is tied to.\n    /// </para>\n    /// <para>\n    /// If simply an empty disposable <see cref=\"IWorldState\"/> is needed, use\n    /// <see cref=\"MockUtil.MockLegacyWorldState\"/> or <see cref=\"MockUtil.MockModernWorldState\"/>\n    /// instead.\n    /// </para>\n    /// </summary>\n    public class MockWorldState : IWorldState\n    {\n        private readonly IStateStore _stateStore;\n\n        /// <summary>\n        /// Creates an instance of <see cref=\"MockWorldState\"/>.  Unless using explicitly for\n        /// setting up an ephemeral <see cref=\"IWorldState\"/>, a use of this constructor\n        /// is not recommended.  Use <see cref=\"MockBlockChainStates.GetMockWorldState\"/> instead.\n        /// </summary>\n        /// <param name=\"trie\">An <see cref=\"ITrie\"/> representing the current state of\n        /// an <see cref=\"IWorldState\"/>.</param>\n        /// <param name=\"stateStore\">The <see cref=\"IStateStore\"/> from which\n        /// <paramref name=\"trie\"/> was created.</param>\n        /// <seealso cref=\"MockBlockChainStates.GetMockWorldState\"/>\n        internal MockWorldState(\n            ITrie trie,\n            IStateStore stateStore)\n        {\n            Trie = trie;\n            _stateStore = stateStore;\n            Version = trie.GetMetadata() is { } value\n                ? value.Version\n                : 0;\n        }\n\n        /// <inheritdoc cref=\"IWorldState.Trie\"/>\n        public ITrie Trie { get; }\n\n        /// <inheritdoc cref=\"IWorldState.Legacy\"/>\n        public bool Legacy => Version < BlockMetadata.WorldStateProtocolVersion;\n\n        /// <inheritdoc cref=\"IWorldState.Version\"/>\n        public int Version { get; }\n\n        /// <summary>\n        /// Creates a new manipulable empty legacy <see cref=\"IWorldState\"/>\n        /// that is tied to <paramref name=\"stateStore\"/>.\n        /// </summary>\n        /// <param name=\"stateStore\">The <see cref=\"IStateStore\"/> to use\n        /// as the new instance's backend storage.  If <see langword=\"null\"/>,\n        /// uses an ephemeral on-memory <see cref=\"IStateStore\"/>.</param>\n        /// <returns>A new empty legacy <see cref=\"IWorldState\"/>.</returns>\n        public static MockWorldState CreateLegacy(IStateStore? stateStore = null)\n        {\n            stateStore ??= new TrieStateStore(new MemoryKeyValueStore());\n            return new MockWorldState(stateStore.GetStateRoot(null), stateStore);\n        }\n\n        /// <summary>\n        /// Creates a new manipulable empty modern <see cref=\"IWorldState\"/>\n        /// that is tied to <paramref name=\"stateStore\"/>.\n        /// </summary>\n        /// <param name=\"stateStore\">The <see cref=\"IStateStore\"/> to use\n        /// as the new instance's backend storage.  If <see langword=\"null\"/>,\n        /// uses an ephemeral on-memory <see cref=\"IStateStore\"/>.</param>\n        /// <param name=\"version\">The version of the backing <see cref=\"ITrie\"/>\n        /// to use.  If not specified, defaults to\n        /// <see cref=\"BlockMetadata.CurrentProtocolVersion\"/>.</param>\n        /// <returns>A new empty modern <see cref=\"IWorldState\"/>.</returns>\n        public static MockWorldState CreateModern(\n            IStateStore? stateStore = null,\n            int version = BlockMetadata.CurrentProtocolVersion)\n        {\n            stateStore ??= new TrieStateStore(new MemoryKeyValueStore());\n            ITrie trie = stateStore.GetStateRoot(null);\n            trie = trie.SetMetadata(new TrieMetadata(version));\n            trie = stateStore.Commit(trie);\n            return new MockWorldState(trie, stateStore);\n        }\n\n        /// <inheritdoc cref=\"IWorldState.GetAccountState\"/>\n        public IAccountState GetAccountState(Address address) =>\n            Legacy && address.Equals(ReservedAddresses.LegacyAccount)\n                ? new AccountState(Trie)\n                : new AccountState(\n                    Trie.Get(ToStateKey(address)) is { } stateRootNotNull\n                        ? _stateStore.GetStateRoot(new HashDigest<SHA256>(stateRootNotNull))\n                        : _stateStore.GetStateRoot(null));\n\n        /// <summary>\n        /// Sets given <paramref name=\"accountState\"/> to <paramref name=\"address\"/>.\n        /// </summary>\n        /// <param name=\"address\">The <see cref=\"Address\"/> location to set\n        /// <paramref name=\"accountState\"/>.</param>\n        /// <param name=\"accountState\">The <see cref=\"IAccountState\"/> to set.</param>\n        /// <returns>A new <see cref=\"MockWorldState\"/> with a committed <see cref=\"ITrie\"/>.\n        /// </returns>\n        /// <exception>Thrown when trying to set an <see cref=\"IAccountState\"/> to a\n        /// non-legacy <see cref=\"Address\"/> for a legacy <see cref=\"IWorld\"/>.</exception>\n        /// <remarks>Unlike <see cref=\"IWorld.SetAccount\"/>, a result returned always\n        /// has a committed <see cref=\"ITrie\"/>.</remarks>\n        public MockWorldState SetAccount(Address address, IAccountState accountState)\n        {\n            if (Legacy)\n            {\n                if (!address.Equals(ReservedAddresses.LegacyAccount))\n                {\n                    throw new ArgumentException(\n                        $\"Cannot set an account to a non legacy address {address} for \" +\n                        $\"a legacy world\");\n                }\n\n                ITrie trie = _stateStore.Commit(accountState.Trie);\n                return new MockWorldState(trie, _stateStore);\n            }\n            else\n            {\n                ITrie trie = _stateStore.Commit(accountState.Trie);\n                trie = Trie.Set(ToStateKey(address), new Binary(trie.Hash.ByteArray));\n                trie = _stateStore.Commit(trie);\n                return new MockWorldState(trie, _stateStore);\n            }\n        }\n\n        /// <summary>\n        /// Sets given <paramref name=\"value\"/> to <paramref name=\"address\"/>.\n        /// This bypasses all checks (minter authority, total supply, etc.).\n        /// </summary>\n        /// <param name=\"address\">The <see cref=\"Address\"/> location to set\n        /// <paramref name=\"value\"/>.</param>\n        /// <param name=\"value\">The <see cref=\"FungibleAssetValue\"/> to set.</param>\n        /// <returns>A new <see cref=\"MockWorldState\"/> with a committed <see cref=\"ITrie\"/>.\n        /// </returns>\n        public MockWorldState SetBalance(Address address, FungibleAssetValue value) =>\n            SetBalance(address, value.Currency, new Integer(value.RawValue));\n\n        /// <summary>\n        /// Sets given <see cref=\"FungibleAssetValue\"/> derived from <paramref name=\"currency\"/>\n        /// and <paramref name=\"rawValue\"/> to <paramref name=\"address\"/>.\n        /// This bypasses all checks (minter authority, maximum supply, etc.) and adjusts\n        /// the total supply accordingly, if applicable.\n        /// </summary>\n        /// <param name=\"address\">The <see cref=\"Address\"/> of the <paramref name=\"value\"/>\n        /// to set.</param>\n        /// <param name=\"currency\">The <see cref=\"Currency\"/> of the\n        /// <see cref=\"FungibleAssetValue\"/> to set.</param>\n        /// <param name=\"rawValue\">The raw amount of <see cref=\"FungibleAssetValue\"/> to set.\n        /// </param>\n        /// <returns>A new <see cref=\"MockWorldState\"/> with a committed <see cref=\"ITrie\"/>.\n        /// </returns>\n        public MockWorldState SetBalance(Address address, Currency currency, Integer rawValue)\n        {\n            if (Version >= BlockMetadata.CurrencyAccountProtocolVersion)\n            {\n                Address accountAddress = new Address(currency.Hash.ByteArray);\n                KeyBytes balanceKey = ToStateKey(address);\n                KeyBytes totalSupplyKey = ToStateKey(CurrencyAccount.TotalSupplyAddress);\n\n                ITrie trie = GetAccountState(accountAddress).Trie;\n                Integer balance = trie.Get(balanceKey) is Integer b\n                    ? b\n                    : new Integer(0);\n                Integer totalSupply = trie.Get(totalSupplyKey) is Integer t\n                    ? t\n                    : new Integer(0);\n\n                trie = trie.Set(\n                    totalSupplyKey,\n                    new Integer(totalSupply.Value - balance.Value + rawValue.Value));\n                trie = trie.Set(balanceKey, rawValue);\n                return SetAccount(accountAddress, new Account(new AccountState(trie)));\n            }\n            else\n            {\n                Address accountAddress = ReservedAddresses.LegacyAccount;\n                KeyBytes balanceKey = ToFungibleAssetKey(address, currency);\n                KeyBytes totalSupplyKey = ToTotalSupplyKey(currency);\n\n                ITrie trie = GetAccountState(accountAddress).Trie;\n                if (currency.TotalSupplyTrackable)\n                {\n                    Integer balance = trie.Get(balanceKey) is Integer b\n                        ? b\n                        : new Integer(0);\n                    Integer totalSupply = trie.Get(totalSupplyKey) is Integer t\n                        ? t\n                        : new Integer(0);\n                    trie = trie.Set(\n                        totalSupplyKey,\n                        new Integer(totalSupply.Value - balance.Value + rawValue.Value));\n                }\n\n                trie = trie.Set(balanceKey, rawValue);\n                return SetAccount(accountAddress, new AccountState(trie));\n            }\n        }\n\n        public MockWorldState SetValidatorSet(ValidatorSet validatorSet)\n        {\n            var validatorSetAccount = this.GetValidatorSetAccount();\n            validatorSetAccount = validatorSetAccount.SetValidatorSet(validatorSet);\n            return Version >= BlockMetadata.ValidatorSetAccountProtocolVersion\n                ? SetAccount(ReservedAddresses.ValidatorSetAccount, validatorSetAccount.AsAccount())\n                : SetAccount(ReservedAddresses.LegacyAccount, validatorSetAccount.AsAccount());\n        }\n    }\n}\n"
  },
  {
    "path": "test/Libplanet.Net.Tests/AppProtocolVersionTest.cs",
    "content": "#nullable disable\nusing System;\nusing System.Collections.Immutable;\nusing System.Linq;\nusing Bencodex;\nusing Libplanet.Crypto;\nusing Xunit;\n\nnamespace Libplanet.Net.Tests\n{\n    public class AppProtocolVersionTest\n    {\n        public static readonly PrivateKey SignerFixture = new PrivateKey(new byte[]\n        {\n            0x45, 0x7a, 0xfa, 0x94, 0x17, 0x78, 0x6e, 0x0c, 0xff, 0x4b, 0xa2,\n            0x5b, 0x35, 0x95, 0xe1, 0xfb, 0x2a, 0x54, 0x39, 0xf9, 0x0e, 0xd2,\n            0x9d, 0x39, 0xdf, 0x54, 0x57, 0x9b, 0x13, 0xea, 0x7c, 0x0f,\n        });\n\n        private static readonly AppProtocolVersion ValidClaimFixture = new AppProtocolVersion(\n            version: 1,\n            extra: null,\n            signer: SignerFixture.Address,\n            signature: new byte[]\n            {\n                0x30, 0x45, 0x02, 0x21, 0x00, 0x89, 0x95, 0x9c, 0x59, 0x25, 0x83, 0x4e,\n                0xbc, 0x45, 0x59, 0xd7, 0x9b, 0xca, 0x82, 0x4a, 0x69, 0x20, 0xe5, 0x18,\n                0xf0, 0xc5, 0xad, 0xe2, 0xb9, 0xa3, 0xa3, 0xb3, 0x29, 0xbb, 0xa3, 0x3d,\n                0xd8, 0x02, 0x20, 0x1d, 0xcb, 0x88, 0xa1, 0x3a, 0x3c, 0x19, 0x2d, 0xe1,\n                0x9e, 0x39, 0xf6, 0x58, 0x05, 0xd4, 0x06, 0xbf, 0xb2, 0x93, 0xd1, 0x64,\n                0x85, 0x75, 0xa8, 0xa2, 0xcb, 0x9f, 0x95, 0xd9, 0x90, 0xb9, 0x51,\n            }.ToImmutableArray()\n        );\n\n        private static readonly AppProtocolVersion ValidClaimWExtraFixture = new AppProtocolVersion(\n            version: 123,\n            extra: (Bencodex.Types.Text)\"foo\",\n            signer: SignerFixture.Address,\n            signature: new byte[]\n            {\n                0x30, 0x44, 0x02, 0x20, 0x08, 0x5d, 0xd4, 0x4d, 0x2f, 0xa1, 0x57, 0xe0,\n                0x01, 0xca, 0x6f, 0xca, 0x98, 0x8d, 0x7a, 0x1d, 0x13, 0x74, 0xcb, 0xc9,\n                0x26, 0xca, 0x3b, 0xc3, 0xdf, 0x14, 0x3d, 0x37, 0xe2, 0xad, 0x04, 0x88,\n                0x02, 0x20, 0x16, 0xd4, 0xae, 0x72, 0x42, 0x31, 0x63, 0xe9, 0x73, 0x99,\n                0x50, 0x0b, 0xb9, 0x19, 0x49, 0xa1, 0xf2, 0xbb, 0x63, 0x20, 0x99, 0x5a,\n                0x77, 0xd2, 0x15, 0xfd, 0xbd, 0x59, 0x99, 0xec, 0x5c, 0x51,\n            }.ToImmutableArray()\n        );\n\n        [Fact]\n        public void Sign()\n        {\n            var signer = new PrivateKey();\n            PublicKey otherParty = new PrivateKey().PublicKey;\n            AppProtocolVersion claim = AppProtocolVersion.Sign(signer, 1, null);\n            Assert.Equal(1, claim.Version);\n            Assert.Null(claim.Extra);\n            Assert.True(claim.Verify(signer.PublicKey));\n            Assert.False(claim.Verify(otherParty));\n\n            AppProtocolVersion claimWithExtra =\n                AppProtocolVersion.Sign(signer, 2, (Bencodex.Types.Text)\"extra\");\n            Assert.Equal(2, claimWithExtra.Version);\n            Assert.Equal((Bencodex.Types.Text)\"extra\", claimWithExtra.Extra);\n            Assert.True(claimWithExtra.Verify(signer.PublicKey));\n            Assert.False(claimWithExtra.Verify(otherParty));\n\n            ArgumentNullException exception =\n                Assert.Throws<ArgumentNullException>(() => AppProtocolVersion.Sign(null, 1));\n            Assert.Equal(\"signer\", exception.ParamName);\n        }\n\n        [Fact]\n        public void Verify()\n        {\n            PublicKey signerPublicKey = SignerFixture.PublicKey;\n            var otherParty = new PrivateKey();\n            PublicKey otherPartyPublicKey = otherParty.PublicKey;\n\n            Assert.True(ValidClaimFixture.Verify(signerPublicKey));\n            Assert.False(ValidClaimFixture.Verify(otherPartyPublicKey));\n\n            // A signature is no more valid for a different version.\n            var invalidVersionClaim = new AppProtocolVersion(\n                version: ValidClaimFixture.Version + 1,\n                extra: ValidClaimFixture.Extra,\n                signer: ValidClaimFixture.Signer,\n                signature: ValidClaimFixture.Signature\n            );\n            Assert.False(invalidVersionClaim.Verify(signerPublicKey));\n            Assert.False(invalidVersionClaim.Verify(otherPartyPublicKey));\n\n            // A signature is no more valid for a different extra data.\n            var invalidExtraClaim = new AppProtocolVersion(\n                version: ValidClaimFixture.Version,\n                extra: (Bencodex.Types.Text)\"invalid extra\",\n                signer: ValidClaimFixture.Signer,\n                signature: ValidClaimFixture.Signature\n            );\n            Assert.False(invalidExtraClaim.Verify(signerPublicKey));\n            Assert.False(invalidExtraClaim.Verify(otherPartyPublicKey));\n\n            // If a signer field does not correspond to an actual private key which signed\n            // a signature a claim is invalid even if a signature in itself is valid.\n            var invalidSigner = new AppProtocolVersion(\n                version: ValidClaimFixture.Version,\n                extra: ValidClaimFixture.Extra,\n                signer: otherPartyPublicKey.Address,\n                signature: ValidClaimFixture.Signature\n            );\n            Assert.False(invalidSigner.Verify(signerPublicKey));\n            Assert.False(invalidSigner.Verify(otherPartyPublicKey));\n        }\n\n        [Fact]\n        public void Equality()\n        {\n            Codec codec = new Codec();\n            var signer = new PrivateKey();\n            AppProtocolVersion claim =\n                AppProtocolVersion.Sign(signer, 123, (Bencodex.Types.Text)\"foo\");\n\n            // Copy to make sure not to use the same reference\n            var address = new Address(claim.Signer.ByteArray);\n            var version = claim.Version;\n            var extra = codec.Decode(codec.Encode(claim.Extra));\n            var signature = claim.Signature.ToArray().ToImmutableArray();\n\n            // Different version\n            var claim2 = new AppProtocolVersion(version + 1, extra, signature, address);\n            Assert.False(((IEquatable<AppProtocolVersion>)claim).Equals(claim2));\n            Assert.False(((object)claim).Equals(claim2));\n            Assert.NotEqual(claim.GetHashCode(), claim2.GetHashCode());\n            Assert.False(claim == claim2);\n            Assert.True(claim != claim2);\n\n            // Different extra\n            var claim3 = new AppProtocolVersion(\n                version,\n                Bencodex.Types.Null.Value,\n                signature,\n                address);\n            Assert.False(((IEquatable<AppProtocolVersion>)claim).Equals(claim3));\n            Assert.False(((object)claim).Equals(claim3));\n            Assert.NotEqual(claim.GetHashCode(), claim3.GetHashCode());\n            Assert.False(claim == claim3);\n            Assert.True(claim != claim3);\n\n            // Empty signature\n            var claim4 = new AppProtocolVersion(\n                version,\n                extra,\n                ImmutableArray<byte>.Empty,\n                address);\n            Assert.False(((IEquatable<AppProtocolVersion>)claim).Equals(claim4));\n            Assert.False(((object)claim).Equals(claim4));\n            Assert.NotEqual(claim.GetHashCode(), claim4.GetHashCode());\n            Assert.False(claim == claim4);\n            Assert.True(claim != claim4);\n\n            // Different address\n            var claim5 = new AppProtocolVersion(\n                version,\n                extra,\n                signature,\n                new PrivateKey().Address);\n            Assert.False(((IEquatable<AppProtocolVersion>)claim).Equals(claim5));\n            Assert.False(((object)claim).Equals(claim5));\n            Assert.NotEqual(claim.GetHashCode(), claim5.GetHashCode());\n            Assert.False(claim == claim5);\n            Assert.True(claim != claim5);\n\n            var sameClaim = new AppProtocolVersion(\n                version,\n                extra,\n                signature,\n                address);\n            Assert.True(((IEquatable<AppProtocolVersion>)claim).Equals(sameClaim));\n            Assert.True(((object)claim).Equals(sameClaim));\n            Assert.Equal(claim.GetHashCode(), sameClaim.GetHashCode());\n            Assert.True(claim == sameClaim);\n            Assert.False(claim != sameClaim);\n\n            AppProtocolVersion claimWithoutExtra = AppProtocolVersion.Sign(signer, 1);\n            var sameClaimWithoutExtra = new AppProtocolVersion(\n                claimWithoutExtra.Version,\n                claimWithoutExtra.Extra,\n                ImmutableArray.Create(\n                    claimWithoutExtra.Signature,\n                    0,\n                    claimWithoutExtra.Signature.Length\n                ),\n                new Address(claimWithoutExtra.Signer.ByteArray)\n            );\n            Assert.True(\n                ((IEquatable<AppProtocolVersion>)claimWithoutExtra).Equals(sameClaimWithoutExtra)\n            );\n            Assert.True(((object)claimWithoutExtra).Equals(sameClaimWithoutExtra));\n            Assert.Equal(claimWithoutExtra.GetHashCode(), sameClaimWithoutExtra.GetHashCode());\n            Assert.True(claimWithoutExtra == sameClaimWithoutExtra);\n            Assert.False(claimWithoutExtra != sameClaimWithoutExtra);\n        }\n\n        [Fact]\n        public void String()\n        {\n            var signer = new PrivateKey();\n            AppProtocolVersion claim = AppProtocolVersion.Sign(signer, 123);\n            Assert.Equal(\"123\", claim.ToString());\n\n            AppProtocolVersion claimWithExtra =\n                AppProtocolVersion.Sign(signer, 456, (Bencodex.Types.Text)\"extra\");\n            Assert.Equal(\"456 (Bencodex.Types.Text \\\"extra\\\")\", claimWithExtra.ToString());\n        }\n\n        [Fact]\n        public void Token()\n        {\n            var expected =\n                \"1/271e00B29aeB93B2F4e30ECbebA4f72ac02f72b4/\" +\n                \"MEUCIQCJlZxZJYNOvEVZ15vKgkppIOUY8MWt4rmjo7Mpu6M92AIgHcuIoTo8GS3hnjn2WAXUBr+yk9Fk\" +\n                \"hXWoosufldmQuVE=\";\n            Assert.Equal(expected, ValidClaimFixture.Token);\n\n            expected =\n                \"123/271e00B29aeB93B2F4e30ECbebA4f72ac02f72b4/\" +\n                \"MEQCIAhd1E0voVfgAcpvypiNeh0TdMvJJso7w98UPTfirQSIAiAW1K5yQjFj6XOZUAu5GUmh8rtjIJla\" +\n                \"d9IV.b1ZmexcUQ==/\" +\n                \"dTM6Zm9v\";\n            Assert.Equal(expected, ValidClaimWExtraFixture.Token);\n        }\n\n        [Fact]\n        public void FromToken()\n        {\n            Assert.Equal(\n                ValidClaimFixture,\n                AppProtocolVersion.FromToken(\n                    \"1/271e00B29aeB93B2F4e30ECbebA4f72ac02f72b4/\" +\n                    \"MEUCIQCJlZxZJYNOvEVZ15vKgkppIOUY8MWt4rmjo7Mpu6M92AIgHcuIoTo8GS3hnjn2WAXUBr+y\" +\n                    \"k9FkhXWoosufldmQuVE=\"\n                )\n            );\n            Assert.Equal(\n                ValidClaimWExtraFixture,\n                AppProtocolVersion.FromToken(\n                    \"123/271e00B29aeB93B2F4e30ECbebA4f72ac02f72b4/\" +\n                    \"MEQCIAhd1E0voVfgAcpvypiNeh0TdMvJJso7w98UPTfirQSIAiAW1K5yQjFj6XOZUAu5GUmh8rtj\" +\n                    \"IJlad9IV.b1ZmexcUQ==/\" +\n                    \"dTM6Zm9v\"\n                )\n            );\n\n            Assert.Throws<ArgumentNullException>(() => AppProtocolVersion.FromToken(null));\n\n            // No first delimiter\n            Assert.Throws<FormatException>(() => AppProtocolVersion.FromToken(\"123\"));\n\n            // No second delimiter\n            Assert.Throws<FormatException>(() =>\n                AppProtocolVersion.FromToken(\"123/271e00B29aeB93B2F4e30ECbebA4f72ac02f72b4\")\n            );\n\n            // A version is not an integer\n            Assert.Throws<FormatException>(() =>\n                AppProtocolVersion.FromToken(\n                    \"INCORRECT/271e00B29aeB93B2F4e30ECbebA4f72ac02f72b4/\" +\n                    \"MEUCIQCJlZxZJYNOvEVZ15vKgkppIOUY8MWt4rmjo7Mpu6M92AIgHcuIoTo8GS3hnjn2WAXUBr+y\" +\n                    \"k9FkhXWoosufldmQuVE=\"\n                )\n            );\n\n            // A signer address is incorrect\n            Assert.Throws<FormatException>(() =>\n                AppProtocolVersion.FromToken(\n                    \"123/INCORRECT/\" +\n                    \"MEUCIQCJlZxZJYNOvEVZ15vKgkppIOUY8MWt4rmjo7Mpu6M92AIgHcuIoTo8GS3hnjn2WAXUBr+y\" +\n                    \"k9FkhXWoosufldmQuVE=\"\n                )\n            );\n\n            // A signature is not a valid base64 string\n            Assert.Throws<FormatException>(() =>\n                AppProtocolVersion.FromToken(\n                    \"123/271e00B29aeB93B2F4e30ECbebA4f72ac02f72b4/_INCORRECT_\"\n                )\n            );\n\n            // An extra data is not a valid base64 string\n            Assert.Throws<FormatException>(() =>\n                AppProtocolVersion.FromToken(\n                    \"123/271e00B29aeB93B2F4e30ECbebA4f72ac02f72b4/\" +\n                    \"MEQCIAhd1E0voVfgAcpvypiNeh0TdMvJJso7w98UPTfirQSIAiAW1K5yQjFj6XOZUAu5GUmh8rtj\" +\n                    \"IJlad9IV.b1ZmexcUQ==/\" +\n                    \"_INCORRECT_\"\n                )\n            );\n        }\n\n        [Fact]\n        public void DefaultConstructor()\n        {\n            AppProtocolVersion defaultValue = default(AppProtocolVersion);\n            ImmutableArray<byte> defaultSig = defaultValue.Signature;\n            Assert.False(defaultSig.IsDefault);\n            Assert.True(defaultSig.IsEmpty);\n            Assert.Equal(\"0/0000000000000000000000000000000000000000/\", defaultValue.Token);\n        }\n    }\n}\n"
  },
  {
    "path": "test/Libplanet.Net.Tests/BlockCandidateTableTest.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing Libplanet.Blockchain;\nusing Libplanet.Tests.Store;\nusing Libplanet.Types.Blocks;\nusing Xunit;\n\nnamespace Libplanet.Net.Tests\n{\n    public class BlockCandidateTableTest\n    {\n        private StoreFixture _fx;\n\n        public BlockCandidateTableTest()\n        {\n            _fx = new MemoryStoreFixture();\n        }\n\n        [Fact]\n        public void Add()\n        {\n            var table = new BlockCandidateTable();\n            var header = _fx.GenesisBlock.Header;\n\n            // Ignore existing key\n            var firstBranch = new Branch(\n                new List<(Block, BlockCommit?)>\n                {\n                    (_fx.Block2, TestUtils.CreateBlockCommit(_fx.Block2)),\n                    (_fx.Block3, TestUtils.CreateBlockCommit(_fx.Block3)),\n                    (_fx.Block4, TestUtils.CreateBlockCommit(_fx.Block4)),\n                });\n            var secondBranch = new Branch(\n                new List<(Block, BlockCommit?)>\n                {\n                    (_fx.Block3, TestUtils.CreateBlockCommit(_fx.Block3)),\n                    (_fx.Block4, TestUtils.CreateBlockCommit(_fx.Block4)),\n                });\n            table.Add(header, firstBranch);\n            Assert.Equal(1, table.Count);\n            table.Add(header, secondBranch);\n            Assert.Equal(1, table.Count);\n            var branch = table.GetCurrentRoundCandidate(header)\n                ?? throw new NullReferenceException();\n            Assert.Equal(branch.Blocks, firstBranch.Blocks);\n        }\n    }\n}\n"
  },
  {
    "path": "test/Libplanet.Net.Tests/BoundPeerTest.cs",
    "content": "using System;\nusing System.Net;\nusing Libplanet.Crypto;\nusing Xunit;\n\nnamespace Libplanet.Net.Tests\n{\n    public class BoundPeerTest\n    {\n        [Fact]\n        public void Bencoded()\n        {\n            var expected = new BoundPeer(\n                new PrivateKey().PublicKey, new DnsEndPoint(\"0.0.0.0\", 1234));\n            var deserialized = new BoundPeer(expected.Bencoded);\n            Assert.Equal(expected, deserialized);\n        }\n\n        [Fact]\n        public void ParsePeer()\n        {\n#pragma warning disable MEN002 // Line is too long\n            var peerInfo = \"032038e153d344773986c039ba5dbff12ae70cfdf6ea8beb7c5ea9b361a72a9233,192.168.0.1,3333\";\n            var expected = new BoundPeer(\n                PublicKey.FromHex(\"032038e153d344773986c039ba5dbff12ae70cfdf6ea8beb7c5ea9b361a72a9233\"),\n                new DnsEndPoint(\"192.168.0.1\", 3333)\n            );\n#pragma warning restore MEN002 // Line is too long\n            Assert.Equal(expected, BoundPeer.ParsePeer(peerInfo));\n        }\n\n        [Fact]\n        public void PeerString()\n        {\n#pragma warning disable MEN002 // Line is too long\n            var expected = \"032038e153d344773986c039ba5dbff12ae70cfdf6ea8beb7c5ea9b361a72a9233,192.168.0.1,3333\";\n            var boundPeer = new BoundPeer(\n                PublicKey.FromHex(\"032038e153d344773986c039ba5dbff12ae70cfdf6ea8beb7c5ea9b361a72a9233\"),\n                new DnsEndPoint(\"192.168.0.1\", 3333)\n            );\n#pragma warning restore MEN002 // Line is too long\n            Assert.Equal(expected, boundPeer.PeerString);\n        }\n\n        [Fact]\n        public void ParsePeerException()\n        {\n            Assert.Throws<ArgumentException>(() => BoundPeer.ParsePeer(string.Empty));\n#pragma warning disable MEN002 // Line is too long\n            Assert.Throws<ArgumentException>(() => BoundPeer.ParsePeer(\"032038e153d344773986c039ba5dbff12ae70cfdf6ea8beb7c5ea9b361a72a9233\"));\n            Assert.Throws<ArgumentException>(() => BoundPeer.ParsePeer(\"032038e153d344773986c039ba5dbff12ae70cfdf6ea8beb7c5ea9b361a72a9233,192.168.0.1\"));\n            Assert.Throws<ArgumentException>(() => BoundPeer.ParsePeer(\"032038e153d344773986c039ba5dbff12ae70cfdf6ea8beb7c5ea9b361a72a9233,192.168.0.1,999999\"));\n            Assert.Throws<ArgumentException>(() => BoundPeer.ParsePeer(\"032038e153d344773986c039ba5dbff12ae70cfdf6ea8beb7c5ea9b361a72a9233,.ninodes.com,31234\"));\n#pragma warning restore MEN002 // Line is too long\n        }\n\n        [Fact]\n        public void InvalidHostname()\n        {\n            Assert.Throws<ArgumentException>(() =>\n                new BoundPeer(new PrivateKey().PublicKey, new DnsEndPoint(\".ninodes.com\", 31234)));\n        }\n    }\n}\n"
  },
  {
    "path": "test/Libplanet.Net.Tests/Consensus/ConsensusContextNonProposerTest.cs",
    "content": "using System;\nusing System.Collections.Immutable;\nusing System.Linq;\nusing System.Numerics;\nusing Bencodex;\nusing Bencodex.Types;\nusing Libplanet.Crypto;\nusing Libplanet.Net.Consensus;\nusing Libplanet.Net.Messages;\nusing Libplanet.Types.Blocks;\nusing Libplanet.Types.Consensus;\nusing Nito.AsyncEx;\nusing Serilog;\nusing xRetry;\nusing Xunit;\nusing Xunit.Abstractions;\n\nnamespace Libplanet.Net.Tests.Consensus\n{\n    public class ConsensusContextNonProposerTest\n    {\n        private const int Timeout = 30000;\n        private readonly ILogger _logger;\n\n        public ConsensusContextNonProposerTest(ITestOutputHelper output)\n        {\n            const string outputTemplate =\n                \"{Timestamp:HH:mm:ss:ffffffZ} - {Message} {Exception}\";\n            Log.Logger = new LoggerConfiguration()\n                .MinimumLevel.Verbose()\n                .WriteTo.TestOutput(output, outputTemplate: outputTemplate)\n                .CreateLogger()\n                .ForContext<ConsensusContextNonProposerTest>();\n\n            _logger = Log.ForContext<ConsensusContextNonProposerTest>();\n        }\n\n        [Fact(Timeout = Timeout)]\n        public async void NewHeightWithLastCommit()\n        {\n            var codec = new Codec();\n            var tipChanged = new AsyncAutoResetEvent();\n            ConsensusProposalMsg? proposal = null;\n            var heightTwoProposalSent = new AsyncAutoResetEvent();\n            var (blockChain, consensusContext) = TestUtils.CreateDummyConsensusContext(\n                TimeSpan.FromSeconds(1),\n                TestUtils.Policy,\n                TestUtils.ActionLoader,\n                TestUtils.PrivateKeys[2]);\n            blockChain.TipChanged += (_, __) => tipChanged.Set();\n            consensusContext.MessagePublished += (_, eventArgs) =>\n            {\n                if (eventArgs.Height == 2 && eventArgs.Message is ConsensusProposalMsg proposalMsg)\n                {\n                    proposal = proposalMsg;\n                    heightTwoProposalSent.Set();\n                }\n            };\n\n            consensusContext.Start();\n            var block1 = blockChain.ProposeBlock(TestUtils.PrivateKeys[1]);\n            consensusContext.HandleMessage(\n                TestUtils.CreateConsensusPropose(block1, TestUtils.PrivateKeys[1]));\n            var expectedVotes = new Vote[4];\n\n            // Peer2 sends a ConsensusVote via background process.\n            // Enough votes are present to proceed even without Peer3's vote.\n            for (int i = 0; i < 2; i++)\n            {\n                expectedVotes[i] = new VoteMetadata(\n                    1,\n                    0,\n                    block1.Hash,\n                    DateTimeOffset.UtcNow,\n                    TestUtils.ValidatorSet[i].PublicKey,\n                    TestUtils.ValidatorSet[i].Power,\n                    VoteFlag.PreVote).Sign(TestUtils.PrivateKeys[i]);\n                consensusContext.HandleMessage(new ConsensusPreVoteMsg(expectedVotes[i]));\n            }\n\n            // Peer2 sends a ConsensusCommit via background process.\n            // Enough votes are present to proceed even without Peer3's vote.\n            for (int i = 0; i < 2; i++)\n            {\n                expectedVotes[i] = new VoteMetadata(\n                    1,\n                    0,\n                    block1.Hash,\n                    DateTimeOffset.UtcNow,\n                    TestUtils.ValidatorSet[i].PublicKey,\n                    TestUtils.ValidatorSet[i].Power,\n                    VoteFlag.PreCommit).Sign(TestUtils.PrivateKeys[i]);\n                consensusContext.HandleMessage(new ConsensusPreCommitMsg(expectedVotes[i]));\n            }\n\n            await heightTwoProposalSent.WaitAsync();\n            Assert.NotNull(proposal);\n\n            Block proposedBlock = BlockMarshaler.UnmarshalBlock(\n                (Dictionary)codec.Decode(proposal!.Proposal.MarshaledBlock));\n            ImmutableArray<Vote> votes = proposedBlock.LastCommit?.Votes is { } vs\n                ? vs\n                : throw new NullReferenceException();\n            Assert.Equal(VoteFlag.PreCommit, votes[0].Flag);\n            Assert.Equal(VoteFlag.PreCommit, votes[1].Flag);\n            Assert.Equal(VoteFlag.PreCommit, votes[2].Flag);\n            Assert.Equal(VoteFlag.Null, votes[3].Flag);\n        }\n\n        [Fact(Timeout = Timeout)]\n        public async void HandleMessageFromHigherHeight()\n        {\n            var codec = new Codec();\n            ConsensusProposalMsg? proposal = null;\n            var heightTwoStepChangedToPreVote = new AsyncAutoResetEvent();\n            var heightTwoStepChangedToPreCommit = new AsyncAutoResetEvent();\n            var heightTwoStepChangedToEndCommit = new AsyncAutoResetEvent();\n            var heightThreeStepChangedToPropose = new AsyncAutoResetEvent();\n            var heightThreeStepChangedToPreVote = new AsyncAutoResetEvent();\n            var proposalSent = new AsyncAutoResetEvent();\n            var newHeightDelay = TimeSpan.FromSeconds(1);\n\n            var (blockChain, consensusContext) = TestUtils.CreateDummyConsensusContext(\n                newHeightDelay,\n                TestUtils.Policy,\n                TestUtils.ActionLoader,\n                TestUtils.PrivateKeys[2]);\n            consensusContext.Start();\n\n            consensusContext.StateChanged += (_, eventArgs) =>\n            {\n                if (eventArgs.Height == 2)\n                {\n                    if (eventArgs.Step == ConsensusStep.PreVote)\n                    {\n                        heightTwoStepChangedToPreVote.Set();\n                    }\n                    else if (eventArgs.Step == ConsensusStep.PreCommit)\n                    {\n                        heightTwoStepChangedToPreCommit.Set();\n                    }\n                    else if (eventArgs.Step == ConsensusStep.EndCommit)\n                    {\n                        heightTwoStepChangedToEndCommit.Set();\n                    }\n                }\n                else if (eventArgs.Height == 3)\n                {\n                    if (eventArgs.Step == ConsensusStep.Propose)\n                    {\n                        heightThreeStepChangedToPropose.Set();\n                    }\n                    else if (eventArgs.Step == ConsensusStep.PreVote)\n                    {\n                        heightThreeStepChangedToPreVote.Set();\n                    }\n                }\n            };\n            consensusContext.MessagePublished += (_, eventArgs) =>\n            {\n                if (eventArgs.Message is ConsensusProposalMsg proposalMsg)\n                {\n                    proposal = proposalMsg;\n                    proposalSent.Set();\n                }\n            };\n\n            Block block = blockChain.ProposeBlock(TestUtils.PrivateKeys[1]);\n            blockChain.Append(block, TestUtils.CreateBlockCommit(block));\n\n            blockChain.Store.PutBlockCommit(TestUtils.CreateBlockCommit(blockChain[1]));\n            await proposalSent.WaitAsync();\n\n            Assert.Equal(2, consensusContext.Height);\n\n            if (proposal is null)\n            {\n                throw new Exception(\"Proposal is null.\");\n            }\n\n            foreach ((PrivateKey privateKey, BigInteger power)\n                     in TestUtils.PrivateKeys.Zip(\n                         TestUtils.ValidatorSet.Validators.Select(v => v.Power),\n                         (first, second) => (first, second)))\n            {\n                if (privateKey == TestUtils.PrivateKeys[2])\n                {\n                    // Peer2 will send a ConsensusVote by handling the ConsensusPropose message.\n                    continue;\n                }\n\n                consensusContext.HandleMessage(\n                    new ConsensusPreVoteMsg(\n                        new VoteMetadata(\n                            2,\n                            0,\n                            proposal!.BlockHash,\n                            DateTimeOffset.UtcNow,\n                            privateKey.PublicKey,\n                            power,\n                            VoteFlag.PreVote).Sign(privateKey)));\n            }\n\n            foreach ((PrivateKey privateKey, BigInteger power)\n                     in TestUtils.PrivateKeys.Zip(\n                         TestUtils.ValidatorSet.Validators.Select(v => v.Power),\n                         (first, second) => (first, second)))\n            {\n                if (privateKey == TestUtils.PrivateKeys[2])\n                {\n                    // Peer2 will send a ConsensusCommit by handling the ConsensusVote message.\n                    continue;\n                }\n\n                consensusContext.HandleMessage(\n                    new ConsensusPreCommitMsg(\n                        new VoteMetadata(\n                            2,\n                            0,\n                            proposal!.BlockHash,\n                            DateTimeOffset.UtcNow,\n                            privateKey.PublicKey,\n                            power,\n                            VoteFlag.PreCommit).Sign(privateKey)));\n            }\n\n            await heightTwoStepChangedToEndCommit.WaitAsync();\n\n            var blockHeightTwo =\n                BlockMarshaler.UnmarshalBlock(\n                    (Dictionary)codec.Decode(proposal.Proposal.MarshaledBlock));\n            var blockHeightThree = blockChain.ProposeBlock(\n                TestUtils.PrivateKeys[3],\n                TestUtils.CreateBlockCommit(blockHeightTwo));\n\n            // Message from higher height\n            consensusContext.HandleMessage(\n                TestUtils.CreateConsensusPropose(blockHeightThree, TestUtils.PrivateKeys[3], 3));\n\n            // New height started.\n            await heightThreeStepChangedToPropose.WaitAsync();\n            // Propose -> PreVote (message consumed)\n            await heightThreeStepChangedToPreVote.WaitAsync();\n            Assert.Equal(3, consensusContext.Height);\n            Assert.Equal(ConsensusStep.PreVote, consensusContext.Step);\n        }\n\n        [Fact(Timeout = Timeout)]\n        public async void UseLastCommitCacheIfHeightContextIsEmpty()\n        {\n            var codec = new Codec();\n            var heightTwoProposalSent = new AsyncAutoResetEvent();\n            Block? proposedBlock = null;\n\n            var (blockChain, consensusContext) = TestUtils.CreateDummyConsensusContext(\n                TimeSpan.FromSeconds(1),\n                TestUtils.Policy,\n                TestUtils.ActionLoader,\n                TestUtils.PrivateKeys[2]);\n            consensusContext.MessageConsumed += (_, eventArgs) =>\n            {\n                if (eventArgs.Height == 2 &&\n                    eventArgs.Message is ConsensusProposalMsg propose)\n                {\n                    proposedBlock = BlockMarshaler.UnmarshalBlock(\n                        (Dictionary)codec.Decode(propose!.Proposal.MarshaledBlock));\n                    heightTwoProposalSent.Set();\n                }\n            };\n\n            consensusContext.Start();\n            Block block = blockChain.ProposeBlock(TestUtils.PrivateKeys[1]);\n            var createdLastCommit = TestUtils.CreateBlockCommit(block);\n            blockChain.Append(block, createdLastCommit);\n\n            // Context for height #2 where node #2 is the proposer is automatically started\n            // by watching blockchain's Tip.\n            await heightTwoProposalSent.WaitAsync();\n            Assert.NotNull(proposedBlock);\n            Assert.Equal(2, proposedBlock!.Index);\n            Assert.Equal(createdLastCommit, proposedBlock!.LastCommit);\n        }\n\n        // Retry: This calculates delta time.\n        [RetryFact(10, Timeout = Timeout)]\n        public async void NewHeightDelay()\n        {\n            var newHeightDelay = TimeSpan.FromSeconds(1);\n            // The maximum error margin. (macos-netcore-test)\n            var timeError = 500;\n            var heightOneEndCommit = new AsyncAutoResetEvent();\n            var heightTwoProposalSent = new AsyncAutoResetEvent();\n            var (blockChain, consensusContext) = TestUtils.CreateDummyConsensusContext(\n                newHeightDelay,\n                TestUtils.Policy,\n                TestUtils.ActionLoader,\n                TestUtils.PrivateKeys[2]);\n            consensusContext.StateChanged += (_, eventArgs) =>\n            {\n                if (eventArgs.Height == 1 && eventArgs.Step == ConsensusStep.EndCommit)\n                {\n                    heightOneEndCommit.Set();\n                }\n            };\n            consensusContext.MessagePublished += (_, eventArgs) =>\n            {\n                if (eventArgs.Height == 2 && eventArgs.Message is ConsensusProposalMsg)\n                {\n                    heightTwoProposalSent.Set();\n                }\n            };\n\n            consensusContext.Start();\n            var block = blockChain.ProposeBlock(TestUtils.PrivateKeys[1]);\n            consensusContext.HandleMessage(\n                TestUtils.CreateConsensusPropose(block, TestUtils.PrivateKeys[1]));\n\n            TestUtils.HandleFourPeersPreCommitMessages(\n                 consensusContext, TestUtils.PrivateKeys[2], block.Hash);\n\n            await heightOneEndCommit.WaitAsync();\n            var endCommitTime = DateTimeOffset.UtcNow;\n\n            await heightTwoProposalSent.WaitAsync();\n            var proposeTime = DateTimeOffset.UtcNow;\n            var difference = proposeTime - endCommitTime;\n\n            _logger.Debug(\"Difference: {Difference}\", difference);\n            // Check new height delay; slight margin of error is allowed as delay task\n            // is run asynchronously from context events.\n            Assert.True(\n                ((proposeTime - endCommitTime) - newHeightDelay).Duration() <\n                    TimeSpan.FromMilliseconds(timeError));\n        }\n    }\n}\n"
  },
  {
    "path": "test/Libplanet.Net.Tests/Consensus/ConsensusContextProposerTest.cs",
    "content": "using System;\nusing Libplanet.Net.Messages;\nusing Libplanet.Types.Consensus;\nusing Nito.AsyncEx;\nusing Serilog;\nusing Xunit;\nusing Xunit.Abstractions;\n\nnamespace Libplanet.Net.Tests.Consensus\n{\n    public class ConsensusContextProposerTest\n    {\n        private const int Timeout = 30000;\n        private readonly ILogger _logger;\n\n        public ConsensusContextProposerTest(ITestOutputHelper output)\n        {\n            const string outputTemplate =\n                \"{Timestamp:HH:mm:ss:ffffffZ} - {Message} {Exception}\";\n            Log.Logger = new LoggerConfiguration()\n                .MinimumLevel.Verbose()\n                .WriteTo.TestOutput(output, outputTemplate: outputTemplate)\n                .CreateLogger()\n                .ForContext<ConsensusContextProposerTest>();\n\n            _logger = Log.ForContext<ConsensusContextProposerTest>();\n        }\n\n        [Fact(Timeout = Timeout)]\n        public async void IncreaseRoundWhenTimeout()\n        {\n            var (blockChain, consensusContext) = TestUtils.CreateDummyConsensusContext(\n                TimeSpan.FromSeconds(1),\n                TestUtils.Policy,\n                TestUtils.ActionLoader,\n                TestUtils.PrivateKeys[1]);\n            var timeoutProcessed = new AsyncAutoResetEvent();\n            consensusContext.TimeoutProcessed += (_, eventArgs) =>\n            {\n                if (eventArgs.Height == 1)\n                {\n                    timeoutProcessed.Set();\n                }\n            };\n\n            consensusContext.Start();\n\n            // Wait for block to be proposed.\n            Assert.Equal(1, consensusContext.Height);\n            Assert.Equal(0, consensusContext.Round);\n\n            // Triggers timeout +2/3 with NIL and Block\n            consensusContext.HandleMessage(\n                new ConsensusPreVoteMsg(\n                    TestUtils.CreateVote(\n                        TestUtils.PrivateKeys[2],\n                        TestUtils.ValidatorSet[2].Power,\n                        1,\n                        0,\n                        hash: default,\n                        flag: VoteFlag.PreVote)));\n\n            consensusContext.HandleMessage(\n                new ConsensusPreVoteMsg(\n                    vote: TestUtils.CreateVote(\n                        TestUtils.PrivateKeys[3],\n                        TestUtils.ValidatorSet[3].Power,\n                        1,\n                        0,\n                        hash: default,\n                        flag: VoteFlag.PreVote)));\n\n            await timeoutProcessed.WaitAsync();\n\n            consensusContext.HandleMessage(\n                new ConsensusPreCommitMsg(\n                    TestUtils.CreateVote(\n                        TestUtils.PrivateKeys[2],\n                        TestUtils.ValidatorSet[2].Power,\n                        1,\n                        0,\n                        hash: default,\n                        flag: VoteFlag.PreCommit)));\n\n            consensusContext.HandleMessage(\n                new ConsensusPreCommitMsg(\n                    vote: TestUtils.CreateVote(\n                        TestUtils.PrivateKeys[3],\n                        TestUtils.ValidatorSet[3].Power,\n                        1,\n                        0,\n                        hash: default,\n                        flag: VoteFlag.PreCommit)));\n\n            await timeoutProcessed.WaitAsync();\n            Assert.Equal(1, consensusContext.Height);\n            Assert.Equal(1, consensusContext.Round);\n        }\n    }\n}\n"
  },
  {
    "path": "test/Libplanet.Net.Tests/Consensus/ConsensusContextTest.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Numerics;\nusing System.Threading.Tasks;\nusing Bencodex;\nusing Libplanet.Consensus;\nusing Libplanet.Crypto;\nusing Libplanet.Net.Consensus;\nusing Libplanet.Net.Messages;\nusing Libplanet.Tests;\nusing Libplanet.Types.Blocks;\nusing Libplanet.Types.Consensus;\nusing Nito.AsyncEx;\nusing Serilog;\nusing Xunit;\nusing Xunit.Abstractions;\n\nnamespace Libplanet.Net.Tests.Consensus\n{\n    public class ConsensusContextTest\n    {\n        private const int Timeout = 30000;\n        private readonly ILogger _logger;\n\n        public ConsensusContextTest(ITestOutputHelper output)\n        {\n            const string outputTemplate =\n                \"{Timestamp:HH:mm:ss:ffffffZ} - {Message} {Exception}\";\n            Log.Logger = new LoggerConfiguration()\n                .MinimumLevel.Verbose()\n                .WriteTo.TestOutput(output, outputTemplate: outputTemplate)\n                .CreateLogger()\n                .ForContext<ConsensusContextTest>();\n\n            _logger = Log.ForContext<ConsensusContextTest>();\n        }\n\n        [Fact(Timeout = Timeout)]\n        public async void NewHeightIncreasing()\n        {\n            ConsensusProposalMsg? proposal = null;\n            var proposalMessageSent = new AsyncAutoResetEvent();\n            var (blockChain, consensusContext) = TestUtils.CreateDummyConsensusContext(\n                TimeSpan.FromSeconds(1),\n                TestUtils.Policy,\n                TestUtils.ActionLoader,\n                TestUtils.PrivateKeys[3]);\n            consensusContext.Start();\n\n            AsyncAutoResetEvent heightThreeStepChangedToPropose = new AsyncAutoResetEvent();\n            AsyncAutoResetEvent heightThreeStepChangedToEndCommit = new AsyncAutoResetEvent();\n            AsyncAutoResetEvent heightFourStepChangedToPropose = new AsyncAutoResetEvent();\n            AsyncAutoResetEvent onTipChangedToThree = new AsyncAutoResetEvent();\n            consensusContext.StateChanged += (_, eventArgs) =>\n            {\n                if (eventArgs.Height == 3 && eventArgs.Step == ConsensusStep.Propose)\n                {\n                    heightThreeStepChangedToPropose.Set();\n                }\n                else if (eventArgs.Height == 3 && eventArgs.Step == ConsensusStep.EndCommit)\n                {\n                    heightThreeStepChangedToEndCommit.Set();\n                }\n                else if (eventArgs.Height == 4 && eventArgs.Step == ConsensusStep.Propose)\n                {\n                    heightFourStepChangedToPropose.Set();\n                }\n            };\n            consensusContext.MessagePublished += (_, eventArgs) =>\n            {\n                if (eventArgs.Message is ConsensusProposalMsg proposalMsg)\n                {\n                    proposal = proposalMsg;\n                    proposalMessageSent.Set();\n                }\n            };\n            blockChain.TipChanged += (_, eventArgs) =>\n            {\n                if (eventArgs.NewTip.Index == 3L)\n                {\n                    onTipChangedToThree.Set();\n                }\n            };\n\n            var block = blockChain.ProposeBlock(TestUtils.PrivateKeys[1]);\n            var blockCommit = TestUtils.CreateBlockCommit(block);\n            blockChain.Append(block, blockCommit);\n            block = blockChain.ProposeBlock(TestUtils.PrivateKeys[2], blockCommit);\n            blockChain.Append(block, TestUtils.CreateBlockCommit(block));\n            Assert.Equal(2, blockChain.Tip.Index);\n\n            // Wait for context of height 3 to start.\n            await heightThreeStepChangedToPropose.WaitAsync();\n            Assert.Equal(3, consensusContext.Height);\n\n            // Cannot call NewHeight() with invalid heights.\n            Assert.Throws<InvalidHeightIncreasingException>(() => consensusContext.NewHeight(2));\n            Assert.Throws<InvalidHeightIncreasingException>(() => consensusContext.NewHeight(3));\n\n            await proposalMessageSent.WaitAsync();\n            BlockHash proposedblockHash = Assert.IsType<BlockHash>(proposal?.BlockHash);\n\n            consensusContext.HandleMessage(\n                new ConsensusPreCommitMsg(\n                    TestUtils.CreateVote(\n                        TestUtils.PrivateKeys[0],\n                        TestUtils.ValidatorSet[0].Power,\n                        3,\n                        0,\n                        hash: proposedblockHash,\n                        flag: VoteFlag.PreCommit)));\n            consensusContext.HandleMessage(\n                new ConsensusPreCommitMsg(\n                    TestUtils.CreateVote(\n                        TestUtils.PrivateKeys[1],\n                        TestUtils.ValidatorSet[1].Power,\n                        3,\n                        0,\n                        hash: proposedblockHash,\n                        flag: VoteFlag.PreCommit)));\n            consensusContext.HandleMessage(\n                new ConsensusPreCommitMsg(\n                    TestUtils.CreateVote(\n                        TestUtils.PrivateKeys[2],\n                        TestUtils.ValidatorSet[2].Power,\n                        3,\n                        0,\n                        hash: proposedblockHash,\n                        flag: VoteFlag.PreCommit)));\n\n            // Waiting for commit.\n            await heightThreeStepChangedToEndCommit.WaitAsync();\n            await onTipChangedToThree.WaitAsync();\n            Assert.Equal(3, blockChain.Tip.Index);\n\n            // Next height starts normally.\n            await heightFourStepChangedToPropose.WaitAsync();\n            Assert.Equal(4, consensusContext.Height);\n            Assert.Equal(0, consensusContext.Round);\n        }\n\n        [Fact(Timeout = Timeout)]\n        public void Ctor()\n        {\n            var (_, consensusContext) = TestUtils.CreateDummyConsensusContext(\n                TimeSpan.FromSeconds(1),\n                TestUtils.Policy,\n                TestUtils.ActionLoader,\n                TestUtils.PrivateKeys[1]);\n\n            Assert.Equal(ConsensusStep.Default, consensusContext.Step);\n            Assert.Equal(1, consensusContext.Height);\n            Assert.Equal(-1, consensusContext.Round);\n        }\n\n        [Fact]\n        public void CannotStartTwice()\n        {\n            var (_, consensusContext) = TestUtils.CreateDummyConsensusContext(\n                TimeSpan.FromSeconds(1),\n                TestUtils.Policy,\n                TestUtils.ActionLoader,\n                TestUtils.PrivateKeys[1]);\n            consensusContext.Start();\n            Assert.Throws<InvalidOperationException>(() => consensusContext.Start());\n        }\n\n        [Fact(Timeout = Timeout)]\n        public async void NewHeightWhenTipChanged()\n        {\n            var newHeightDelay = TimeSpan.FromSeconds(1);\n            var (blockChain, consensusContext) = TestUtils.CreateDummyConsensusContext(\n                newHeightDelay,\n                TestUtils.Policy,\n                TestUtils.ActionLoader,\n                TestUtils.PrivateKeys[1]);\n            consensusContext.Start();\n\n            Assert.Equal(1, consensusContext.Height);\n            Block block = blockChain.ProposeBlock(new PrivateKey());\n            blockChain.Append(block, TestUtils.CreateBlockCommit(block));\n            Assert.Equal(1, consensusContext.Height);\n            await Task.Delay(newHeightDelay + TimeSpan.FromSeconds(1));\n            Assert.Equal(2, consensusContext.Height);\n        }\n\n        [Fact(Timeout = Timeout)]\n        public void IgnoreMessagesFromLowerHeight()\n        {\n            var (blockChain, consensusContext) = TestUtils.CreateDummyConsensusContext(\n                TimeSpan.FromSeconds(1),\n                TestUtils.Policy,\n                TestUtils.ActionLoader,\n                TestUtils.PrivateKeys[1]);\n            consensusContext.Start();\n            Assert.True(consensusContext.Height == 1);\n            Assert.False(consensusContext.HandleMessage(\n                TestUtils.CreateConsensusPropose(\n                    blockChain.ProposeBlock(TestUtils.PrivateKeys[0]),\n                    TestUtils.PrivateKeys[0],\n                    0)));\n        }\n\n        [Fact(Timeout = Timeout)]\n        public async void VoteSetGetOnlyProposeCommitHash()\n        {\n            ConsensusProposalMsg? proposal = null;\n            var heightOneProposalSent = new AsyncAutoResetEvent();\n            var heightOneEndCommit = new AsyncAutoResetEvent();\n            var votes = new List<Vote>();\n\n            var (blockChain, consensusContext) = TestUtils.CreateDummyConsensusContext(\n                TimeSpan.FromSeconds(1),\n                TestUtils.Policy,\n                TestUtils.ActionLoader,\n                TestUtils.PrivateKeys[1]);\n            consensusContext.StateChanged += (sender, tuple) =>\n            {\n                if (tuple.Height == 1 && tuple.Step == ConsensusStep.EndCommit)\n                {\n                    heightOneEndCommit.Set();\n                }\n            };\n            consensusContext.MessagePublished += (_, eventArgs) =>\n            {\n                if (eventArgs.Height == 1 && eventArgs.Message is ConsensusProposalMsg proposalMsg)\n                {\n                    proposal = proposalMsg;\n                    heightOneProposalSent.Set();\n                }\n            };\n\n            consensusContext.Start();\n            await heightOneProposalSent.WaitAsync();\n            BlockHash proposedblockHash = Assert.IsType<BlockHash>(proposal?.BlockHash);\n\n            votes.Add(TestUtils.CreateVote(\n                TestUtils.PrivateKeys[0],\n                TestUtils.ValidatorSet[0].Power,\n                1,\n                0,\n                new BlockHash(TestUtils.GetRandomBytes(BlockHash.Size)),\n                VoteFlag.PreCommit));\n            votes.AddRange(Enumerable.Range(1, 3).Select(x => TestUtils.CreateVote(\n                TestUtils.PrivateKeys[x],\n                TestUtils.ValidatorSet[x].Power,\n                1,\n                0,\n                proposedblockHash,\n                VoteFlag.PreCommit)));\n\n            foreach (var vote in votes)\n            {\n                consensusContext.HandleMessage(new ConsensusPreCommitMsg(vote));\n            }\n\n            await heightOneEndCommit.WaitAsync();\n\n            var blockCommit = consensusContext.CurrentContext.GetBlockCommit();\n            Assert.NotNull(blockCommit);\n            Assert.NotEqual(votes[0], blockCommit!.Votes.First(x =>\n                x.ValidatorPublicKey.Equals(TestUtils.PrivateKeys[0].PublicKey)));\n\n            var actualVotesWithoutInvalid =\n                HashSetExtensions.ToHashSet(blockCommit.Votes.Where(x =>\n                    !x.ValidatorPublicKey.Equals(TestUtils.PrivateKeys[0].PublicKey)));\n\n            var expectedVotes = HashSetExtensions.ToHashSet(votes.Where(x =>\n                !x.ValidatorPublicKey.Equals(TestUtils.PrivateKeys[0].PublicKey)));\n\n            Assert.Equal(expectedVotes, actualVotesWithoutInvalid);\n        }\n\n        [Fact(Timeout = Timeout)]\n        public async Task GetVoteSetBits()\n        {\n            PrivateKey proposer = TestUtils.PrivateKeys[1];\n            BigInteger proposerPower = TestUtils.ValidatorSet[1].Power;\n            AsyncAutoResetEvent stepChanged = new AsyncAutoResetEvent();\n            AsyncAutoResetEvent committed = new AsyncAutoResetEvent();\n            var (blockChain, consensusContext) = TestUtils.CreateDummyConsensusContext(\n                TimeSpan.FromSeconds(1),\n                TestUtils.Policy,\n                TestUtils.ActionLoader,\n                TestUtils.PrivateKeys[0]);\n            consensusContext.Start();\n            var block = blockChain.ProposeBlock(proposer);\n            var proposal = new ProposalMetadata(\n                1,\n                0,\n                DateTimeOffset.UtcNow,\n                proposer.PublicKey,\n                new Codec().Encode(block.MarshalBlock()),\n                -1).Sign(proposer);\n            var preVote1 = new VoteMetadata(\n                1,\n                0,\n                block.Hash,\n                DateTimeOffset.UtcNow,\n                proposer.PublicKey,\n                proposerPower,\n                VoteFlag.PreVote).Sign(proposer);\n            var preVote2 = new VoteMetadata(\n                1,\n                0,\n                block.Hash,\n                DateTimeOffset.UtcNow,\n                TestUtils.PrivateKeys[2].PublicKey,\n                TestUtils.ValidatorSet[2].Power,\n                VoteFlag.PreVote).Sign(TestUtils.PrivateKeys[2]);\n            var preVote3 = new VoteMetadata(\n                1,\n                0,\n                block.Hash,\n                DateTimeOffset.UtcNow,\n                TestUtils.PrivateKeys[3].PublicKey,\n                TestUtils.ValidatorSet[3].Power,\n                VoteFlag.PreVote).Sign(TestUtils.PrivateKeys[3]);\n            consensusContext.StateChanged += (_, eventArgs) =>\n            {\n                if (eventArgs is { Height: 1, Step: ConsensusStep.PreCommit })\n                {\n                    stepChanged.Set();\n                }\n            };\n            consensusContext.CurrentContext.VoteSetModified += (_, eventArgs) =>\n            {\n                if (eventArgs.Flag == VoteFlag.PreCommit)\n                {\n                    committed.Set();\n                }\n            };\n\n            consensusContext.HandleMessage(new ConsensusProposalMsg(proposal));\n            consensusContext.HandleMessage(new ConsensusPreVoteMsg(preVote1));\n            consensusContext.HandleMessage(new ConsensusPreVoteMsg(preVote3));\n            await stepChanged.WaitAsync();\n            await committed.WaitAsync();\n\n            // VoteSetBits expects missing votes\n            VoteSetBits voteSetBits = consensusContext.CurrentContext\n                .GetVoteSetBits(0, block.Hash, VoteFlag.PreVote);\n            Assert.True(\n                voteSetBits.VoteBits.SequenceEqual(new[] { true, true, false, true }));\n            voteSetBits = consensusContext.CurrentContext\n                .GetVoteSetBits(0, block.Hash, VoteFlag.PreCommit);\n            Assert.True(\n                voteSetBits.VoteBits.SequenceEqual(new[] { true, false, false, false }));\n        }\n\n        [Fact(Timeout = Timeout)]\n        public async Task HandleVoteSetBits()\n        {\n            PrivateKey proposer = TestUtils.PrivateKeys[1];\n            BigInteger proposerPower = TestUtils.ValidatorSet[1].Power;\n            ConsensusStep step = ConsensusStep.Default;\n            var stepChanged = new AsyncAutoResetEvent();\n            var (blockChain, consensusContext) = TestUtils.CreateDummyConsensusContext(\n                TimeSpan.FromSeconds(1),\n                TestUtils.Policy,\n                TestUtils.ActionLoader,\n                TestUtils.PrivateKeys[0]);\n            consensusContext.StateChanged += (_, eventArgs) =>\n            {\n                if (eventArgs.Step != step)\n                {\n                    step = eventArgs.Step;\n                    stepChanged.Set();\n                }\n            };\n\n            consensusContext.Start();\n            var block = blockChain.ProposeBlock(proposer);\n            var proposal = new ProposalMetadata(\n                1,\n                0,\n                DateTimeOffset.UtcNow,\n                proposer.PublicKey,\n                new Codec().Encode(block.MarshalBlock()),\n                -1).Sign(proposer);\n            var preVote1 = new VoteMetadata(\n                1,\n                0,\n                block.Hash,\n                DateTimeOffset.UtcNow,\n                proposer.PublicKey,\n                proposerPower,\n                VoteFlag.PreVote).Sign(proposer);\n            var preVote2 = new VoteMetadata(\n                1,\n                0,\n                block.Hash,\n                DateTimeOffset.UtcNow,\n                TestUtils.PrivateKeys[2].PublicKey,\n                TestUtils.ValidatorSet[2].Power,\n                VoteFlag.PreVote).Sign(TestUtils.PrivateKeys[2]);\n            consensusContext.HandleMessage(new ConsensusProposalMsg(proposal));\n            consensusContext.HandleMessage(new ConsensusPreVoteMsg(preVote1));\n            consensusContext.HandleMessage(new ConsensusPreVoteMsg(preVote2));\n            do\n            {\n                await stepChanged.WaitAsync();\n            }\n            while (step != ConsensusStep.PreCommit);\n\n            // VoteSetBits expects missing votes\n            var voteSetBits =\n                new VoteSetBitsMetadata(\n                        1,\n                        0,\n                        block.Hash,\n                        DateTimeOffset.UtcNow,\n                        TestUtils.PrivateKeys[1].PublicKey,\n                        VoteFlag.PreVote,\n                        new[] { false, false, true, false })\n                    .Sign(TestUtils.PrivateKeys[1]);\n            ConsensusMsg[] votes =\n                consensusContext.HandleVoteSetBits(voteSetBits).ToArray();\n            Assert.True(votes.All(vote => vote is ConsensusPreVoteMsg));\n            Assert.Equal(2, votes.Length);\n            Assert.Equal(TestUtils.PrivateKeys[0].PublicKey, votes[0].ValidatorPublicKey);\n            Assert.Equal(TestUtils.PrivateKeys[1].PublicKey, votes[1].ValidatorPublicKey);\n        }\n\n        [Fact(Timeout = Timeout)]\n        public async Task HandleProposalClaim()\n        {\n            PrivateKey proposer = TestUtils.PrivateKeys[1];\n            ConsensusStep step = ConsensusStep.Default;\n            var stepChanged = new AsyncAutoResetEvent();\n            var (blockChain, consensusContext) = TestUtils.CreateDummyConsensusContext(\n                TimeSpan.FromSeconds(1),\n                TestUtils.Policy,\n                TestUtils.ActionLoader,\n                TestUtils.PrivateKeys[0]);\n            consensusContext.StateChanged += (_, eventArgs) =>\n            {\n                if (eventArgs.Step != step)\n                {\n                    step = eventArgs.Step;\n                    stepChanged.Set();\n                }\n            };\n            consensusContext.Start();\n            var block = blockChain.ProposeBlock(proposer);\n            var proposal = new ProposalMetadata(\n                1,\n                0,\n                DateTimeOffset.UtcNow,\n                proposer.PublicKey,\n                new Codec().Encode(block.MarshalBlock()),\n                -1).Sign(proposer);\n            consensusContext.HandleMessage(new ConsensusProposalMsg(proposal));\n            await stepChanged.WaitAsync();\n\n            // ProposalClaim expects corresponding proposal if exists\n            var proposalClaim =\n                new ProposalClaimMetadata(\n                        1,\n                        0,\n                        block.Hash,\n                        DateTimeOffset.UtcNow,\n                        TestUtils.PrivateKeys[1].PublicKey)\n                    .Sign(TestUtils.PrivateKeys[1]);\n            Proposal? reply =\n                consensusContext.HandleProposalClaim(proposalClaim);\n            Assert.NotNull(reply);\n            Assert.Equal(proposal, reply);\n        }\n    }\n}\n"
  },
  {
    "path": "test/Libplanet.Net.Tests/Consensus/ConsensusContextUtils.cs",
    "content": "using System;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing Libplanet.Net.Consensus;\nusing Libplanet.Net.Messages;\nusing Nito.AsyncEx;\n\nnamespace Libplanet.Net.Tests.Consensus\n{\n    public static class ConsensusContextUtils\n    {\n        public static async Task WaitUntilHeightAsync(\n            ConsensusContext consensusContext,\n            long height,\n            CancellationToken cancellationToken)\n        {\n            if (consensusContext.Height > height)\n            {\n                throw new InvalidOperationException($\"Height {height} is already passed.\");\n            }\n\n            while (true)\n            {\n                if (consensusContext.Height == height)\n                {\n                    return;\n                }\n\n                await Task.Delay(100, cancellationToken);\n            }\n        }\n\n        public static async Task WaitUntilStateAsync(\n            ConsensusContext consensusContext,\n            long height,\n            ConsensusStep consensusStep,\n            CancellationToken cancellationToken)\n        {\n            var asyncAutoResetEvent = new AsyncAutoResetEvent();\n            consensusContext.StateChanged += ConsensusContext_StateChanged;\n            try\n            {\n                if (consensusContext.Step != consensusStep || consensusContext.Height != height)\n                {\n                    await asyncAutoResetEvent.WaitAsync(cancellationToken);\n                }\n            }\n            finally\n            {\n                consensusContext.StateChanged -= ConsensusContext_StateChanged;\n            }\n\n            void ConsensusContext_StateChanged(object? sender, Context.ContextState e)\n            {\n                if (e.Step == consensusStep && e.Height == height)\n                {\n                    asyncAutoResetEvent.Set();\n                }\n            }\n        }\n\n        public static async Task<T> WaitUntilPublishedAsync<T>(\n            ConsensusContext consensusContext,\n            long height,\n            CancellationToken cancellationToken)\n            where T : ConsensusMsg\n        {\n            T? consensusMessage = null;\n            var asyncAutoResetEvent = new AsyncAutoResetEvent();\n            consensusContext.MessagePublished += ConsensusContext_MessagePublished;\n            try\n            {\n                await asyncAutoResetEvent.WaitAsync(cancellationToken);\n                return consensusMessage!;\n            }\n            finally\n            {\n                consensusContext.MessagePublished -= ConsensusContext_MessagePublished;\n            }\n\n            void ConsensusContext_MessagePublished(\n                object? sender, (long Height, ConsensusMsg Message) e)\n            {\n                if (e.Message is T { } message && e.Height == height)\n                {\n                    consensusMessage = message;\n                    asyncAutoResetEvent.Set();\n                }\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "test/Libplanet.Net.Tests/Consensus/ConsensusReactorTest.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Net;\nusing System.Text.Json;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing Libplanet.Action;\nusing Libplanet.Action.Loader;\nusing Libplanet.Action.Tests.Common;\nusing Libplanet.Blockchain;\nusing Libplanet.Blockchain.Policies;\nusing Libplanet.Net.Consensus;\nusing Libplanet.Store;\nusing Libplanet.Store.Trie;\nusing Libplanet.Tests.Store;\nusing NetMQ;\nusing Serilog;\nusing Xunit;\nusing Xunit.Abstractions;\n\nnamespace Libplanet.Net.Tests.Consensus\n{\n    [Collection(\"NetMQConfiguration\")]\n    public class ConsensusReactorTest : IDisposable\n    {\n        private const int PropagationDelay = 25_000;\n        private const int Timeout = 60 * 1000;\n        private ILogger _logger;\n\n        public ConsensusReactorTest(ITestOutputHelper output)\n        {\n            const string outputTemplate =\n                \"{Timestamp:HH:mm:ss:ffffffZ} - {Message}\";\n            Log.Logger = new LoggerConfiguration()\n                .MinimumLevel.Verbose()\n                .WriteTo.TestOutput(output, outputTemplate: outputTemplate)\n                .CreateLogger()\n                .ForContext<ConsensusReactorTest>();\n\n            _logger = Log.ForContext<ConsensusReactorTest>();\n        }\n\n        [Fact(Timeout = Timeout)]\n        public async void StartAsync()\n        {\n            var consensusReactors = new ConsensusReactor[4];\n            var stores = new IStore[4];\n            var blockChains = new BlockChain[4];\n            var fx = new MemoryStoreFixture(TestUtils.Policy.PolicyActionsRegistry);\n            var validatorPeers = new List<BoundPeer>();\n            var cancellationTokenSource = new CancellationTokenSource();\n\n            for (var i = 0; i < 4; i++)\n            {\n                validatorPeers.Add(\n                    new BoundPeer(\n                        TestUtils.PrivateKeys[i].PublicKey,\n                        new DnsEndPoint(\"127.0.0.1\", 6000 + i)));\n                stores[i] = new MemoryStore();\n                var stateStore = new TrieStateStore(new MemoryKeyValueStore());\n                blockChains[i] = BlockChain.Create(\n                    TestUtils.Policy,\n                    new VolatileStagePolicy(),\n                    stores[i],\n                    stateStore,\n                    fx.GenesisBlock,\n                    new ActionEvaluator(\n                        policyActionsRegistry: TestUtils.Policy.PolicyActionsRegistry,\n                        stateStore: stateStore,\n                        actionTypeLoader: new SingleActionLoader(typeof(DumbAction))));\n            }\n\n            for (var i = 0; i < 4; i++)\n            {\n                consensusReactors[i] = TestUtils.CreateDummyConsensusReactor(\n                    blockChain: blockChains[i],\n                    key: TestUtils.PrivateKeys[i],\n                    consensusPort: 6000 + i,\n                    validatorPeers: validatorPeers,\n                    newHeightDelayMilliseconds: PropagationDelay * 2);\n            }\n\n            try\n            {\n                consensusReactors.AsParallel().ForAll(\n                    reactor => _ = reactor.StartAsync(cancellationTokenSource.Token));\n\n                Dictionary<string, JsonElement> json;\n\n                await Task.Delay(PropagationDelay, cancellationTokenSource.Token);\n                foreach (var reactor in consensusReactors)\n                {\n                    await reactor.StopAsync(cancellationTokenSource.Token);\n                }\n\n                var isPolka = new bool[4];\n\n                for (var node = 0; node < 4; ++node)\n                {\n                    json = JsonSerializer.Deserialize<Dictionary<string, JsonElement>>(\n                               consensusReactors[node].ToString())\n                           ?? throw new NullReferenceException(\n                               $\"Failed to deserialize consensus reactor\");\n\n                    // Genesis block exists, add 1 to the height.\n                    if (json[\"step\"].GetString() == \"EndCommit\")\n                    {\n                        isPolka[node] = true;\n                    }\n                    else\n                    {\n                        Log.Error(\n                            \"[Failed]: {0} {1}\",\n                            json[\"step\"].GetString(),\n                            blockChains[node].Count);\n                        isPolka[node] = false;\n                    }\n                }\n\n                Assert.Equal(4, isPolka.Sum(x => x ? 1 : 0));\n\n                for (var node = 0; node < 4; ++node)\n                {\n                    json = JsonSerializer.Deserialize<Dictionary<string, JsonElement>>(\n                               consensusReactors[node].ToString())\n                           ?? throw new NullReferenceException(\n                               $\"Failed to deserialize consensus reactor\");\n\n                    Assert.Equal(\n                        validatorPeers[node].Address.ToString(),\n                        json[\"node_id\"].GetString());\n                    Assert.Equal(1, json[\"height\"].GetInt32());\n                    Assert.Equal(2, blockChains[node].Count);\n                    Assert.Equal(0L, json[\"round\"].GetInt32());\n                    Assert.Equal(\"EndCommit\", json[\"step\"].GetString());\n                }\n            }\n            finally\n            {\n                cancellationTokenSource.Cancel();\n                for (int i = 0; i < 4; ++i)\n                {\n                    await consensusReactors[i].StopAsync(cancellationTokenSource.Token);\n                    consensusReactors[i].Dispose();\n                }\n            }\n        }\n\n        public void Dispose()\n        {\n            NetMQConfig.Cleanup(false);\n        }\n    }\n}\n"
  },
  {
    "path": "test/Libplanet.Net.Tests/Consensus/ContextNonProposerTest.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Collections.Immutable;\nusing System.Security.Cryptography;\nusing System.Text.Json;\nusing System.Threading.Tasks;\nusing Bencodex.Types;\nusing Libplanet.Action;\nusing Libplanet.Action.Loader;\nusing Libplanet.Action.Tests.Common;\nusing Libplanet.Blockchain;\nusing Libplanet.Blockchain.Policies;\nusing Libplanet.Common;\nusing Libplanet.Crypto;\nusing Libplanet.Net.Consensus;\nusing Libplanet.Net.Messages;\nusing Libplanet.Tests.Store;\nusing Libplanet.Types.Blocks;\nusing Libplanet.Types.Consensus;\nusing Libplanet.Types.Evidence;\nusing Libplanet.Types.Tx;\nusing Nito.AsyncEx;\nusing Serilog;\nusing Xunit;\nusing Xunit.Abstractions;\n\nnamespace Libplanet.Net.Tests.Consensus\n{\n    public class ContextNonProposerTest\n    {\n        private const int Timeout = 30000;\n        private readonly ILogger _logger;\n\n        public ContextNonProposerTest(ITestOutputHelper output)\n        {\n            const string outputTemplate =\n                \"{Timestamp:HH:mm:ss:ffffffZ} - {Message} {Exception}\";\n            Log.Logger = new LoggerConfiguration()\n                .MinimumLevel.Verbose()\n                .WriteTo.TestOutput(output, outputTemplate: outputTemplate)\n                .CreateLogger()\n                .ForContext<ContextNonProposerTest>();\n\n            _logger = Log.ForContext<ContextNonProposerTest>();\n        }\n\n        [Fact(Timeout = Timeout)]\n        public async Task EnterPreVoteBlockOneThird()\n        {\n            var (blockChain, context) = TestUtils.CreateDummyContext(\n                privateKey: TestUtils.PrivateKeys[0]);\n\n            var block = blockChain.ProposeBlock(TestUtils.PrivateKeys[1]);\n            var stateChangedToRoundOnePreVote = new AsyncAutoResetEvent();\n            context.StateChanged += (_, eventArgs) =>\n            {\n                if (eventArgs.Round == 1 && eventArgs.Step == ConsensusStep.PreVote)\n                {\n                    stateChangedToRoundOnePreVote.Set();\n                }\n            };\n\n            context.Start();\n            context.ProduceMessage(\n                new ConsensusPreVoteMsg(\n                    TestUtils.CreateVote(\n                        TestUtils.PrivateKeys[2],\n                        TestUtils.ValidatorSet[2].Power,\n                        1,\n                        1,\n                        hash: block.Hash,\n                        flag: VoteFlag.PreVote)));\n            context.ProduceMessage(\n                new ConsensusPreVoteMsg(\n                    TestUtils.CreateVote(\n                        TestUtils.PrivateKeys[3],\n                        TestUtils.ValidatorSet[3].Power,\n                        1,\n                        1,\n                        hash: block.Hash,\n                        flag: VoteFlag.PreVote)));\n\n            // Wait for round 1 prevote step.\n            await stateChangedToRoundOnePreVote.WaitAsync();\n            Assert.Equal(ConsensusStep.PreVote, context.Step);\n            Assert.Equal(1, context.Height);\n            Assert.Equal(1, context.Round);\n        }\n\n        [Fact(Timeout = Timeout)]\n        public async Task EnterPreCommitBlockTwoThird()\n        {\n            var stepChangedToPreCommit = new AsyncAutoResetEvent();\n            ConsensusPreCommitMsg? preCommit = null;\n            var preCommitSent = new AsyncAutoResetEvent();\n            var (blockChain, context) = TestUtils.CreateDummyContext(\n                privateKey: TestUtils.PrivateKeys[0]);\n\n            var block = blockChain.ProposeBlock(TestUtils.PrivateKeys[1]);\n\n            context.StateChanged += (_, eventArgs) =>\n            {\n                if (eventArgs.Step == ConsensusStep.PreCommit)\n                {\n                    stepChangedToPreCommit.Set();\n                }\n            };\n            context.MessageToPublish += (_, message) =>\n            {\n                if (message is ConsensusPreCommitMsg preCommitMsg)\n                {\n                    preCommit = preCommitMsg;\n                    preCommitSent.Set();\n                }\n            };\n\n            context.Start();\n            context.ProduceMessage(\n                TestUtils.CreateConsensusPropose(block, TestUtils.PrivateKeys[1]));\n\n            context.ProduceMessage(\n                new ConsensusPreVoteMsg(\n                    TestUtils.CreateVote(\n                        TestUtils.PrivateKeys[1],\n                        TestUtils.ValidatorSet[1].Power,\n                        1,\n                        0,\n                        hash: block.Hash,\n                        VoteFlag.PreVote)));\n            context.ProduceMessage(\n                new ConsensusPreVoteMsg(\n                    TestUtils.CreateVote(\n                        TestUtils.PrivateKeys[2],\n                        TestUtils.ValidatorSet[2].Power,\n                        1,\n                        0,\n                        hash: block.Hash,\n                        VoteFlag.PreVote)));\n            context.ProduceMessage(\n                new ConsensusPreVoteMsg(\n                    TestUtils.CreateVote(\n                        TestUtils.PrivateKeys[3],\n                        TestUtils.ValidatorSet[3].Power,\n                        1,\n                        0,\n                        hash: block.Hash,\n                        VoteFlag.PreVote)));\n\n            await Task.WhenAll(preCommitSent.WaitAsync(), stepChangedToPreCommit.WaitAsync());\n            Assert.Equal(block.Hash, preCommit?.BlockHash);\n            Assert.Equal(ConsensusStep.PreCommit, context.Step);\n            Assert.Equal(1, context.Height);\n            Assert.Equal(0, context.Round);\n\n            var json =\n                JsonSerializer.Deserialize<Dictionary<string, JsonElement>>(context.ToString())\n                    ?? throw new NullReferenceException(\"Failed to deserialize context\");\n\n            Assert.Equal(0, json[\"locked_round\"].GetInt64());\n            Assert.Equal(0, json[\"valid_round\"].GetInt64());\n            Assert.Equal(block.Hash.ToString(), json[\"locked_value\"].GetString());\n            Assert.Equal(block.Hash.ToString(), json[\"valid_value\"].GetString());\n        }\n\n        [Fact(Timeout = Timeout)]\n        public async void EnterPreCommitNilTwoThird()\n        {\n            var stepChangedToPreCommit = new AsyncAutoResetEvent();\n            var preCommitSent = new AsyncAutoResetEvent();\n\n            var (blockChain, context) = TestUtils.CreateDummyContext(\n                privateKey: TestUtils.PrivateKeys[0]);\n\n            var key = new PrivateKey();\n            var invalidBlock = blockChain.EvaluateAndSign(\n                new BlockContent(\n                    new BlockMetadata(\n                        index: blockChain.Tip.Index + 1,\n                        timestamp: DateTimeOffset.UtcNow,\n                        publicKey: key.PublicKey,\n                        previousHash: blockChain.Tip.Hash,\n                        txHash: null,\n                        lastCommit: null,\n                        evidenceHash: null)).Propose(),\n                key);\n\n            context.StateChanged += (_, eventArgs) =>\n            {\n                if (eventArgs.Step == ConsensusStep.PreCommit)\n                {\n                    stepChangedToPreCommit.Set();\n                }\n            };\n            context.MessageToPublish += (_, message) =>\n            {\n                if (message is ConsensusPreCommitMsg preCommitMsg &&\n                    preCommitMsg.BlockHash.Equals(default))\n                {\n                    preCommitSent.Set();\n                }\n            };\n\n            context.Start();\n            context.ProduceMessage(\n                TestUtils.CreateConsensusPropose(invalidBlock, TestUtils.PrivateKeys[1]));\n            context.ProduceMessage(\n                new ConsensusPreVoteMsg(\n                    TestUtils.CreateVote(\n                        TestUtils.PrivateKeys[1],\n                        TestUtils.ValidatorSet[1].Power,\n                        1,\n                        0,\n                        hash: default,\n                        VoteFlag.PreVote)));\n            context.ProduceMessage(\n                new ConsensusPreVoteMsg(\n                    TestUtils.CreateVote(\n                        TestUtils.PrivateKeys[2],\n                        TestUtils.ValidatorSet[2].Power,\n                        1,\n                        0,\n                        hash: default,\n                        VoteFlag.PreVote)));\n            context.ProduceMessage(\n                new ConsensusPreVoteMsg(\n                    TestUtils.CreateVote(\n                        TestUtils.PrivateKeys[3],\n                        TestUtils.ValidatorSet[3].Power,\n                        1,\n                        0,\n                        hash: default,\n                        VoteFlag.PreVote)));\n\n            await Task.WhenAll(preCommitSent.WaitAsync(), stepChangedToPreCommit.WaitAsync());\n            Assert.Equal(ConsensusStep.PreCommit, context.Step);\n            Assert.Equal(1, context.Height);\n            Assert.Equal(0, context.Round);\n        }\n\n        [Fact(Timeout = Timeout)]\n        public async Task EnterPreVoteNilOnInvalidBlockHeader()\n        {\n            var stepChangedToPreVote = new AsyncAutoResetEvent();\n            var timeoutProcessed = false;\n            var nilPreVoteSent = new AsyncAutoResetEvent();\n\n            var (blockChain, context) = TestUtils.CreateDummyContext(\n                privateKey: TestUtils.PrivateKeys[0]);\n            context.StateChanged += (_, eventArgs) =>\n            {\n                if (eventArgs.Step == ConsensusStep.PreVote)\n                {\n                    stepChangedToPreVote.Set();\n                }\n            };\n            context.TimeoutProcessed += (_, __) =>\n            {\n                timeoutProcessed = true;\n            };\n            context.MessageToPublish += (_, message) =>\n            {\n                if (message is ConsensusPreVoteMsg vote && vote.PreVote.BlockHash.Equals(default))\n                {\n                    nilPreVoteSent.Set();\n                }\n            };\n\n            // 1. ProtocolVersion should be matched.\n            // 2. Index should be increased monotonically.\n            // 3. Timestamp should be increased monotonically.\n            // 4. PreviousHash should be matched with Tip hash.\n            var invalidBlock = blockChain.EvaluateAndSign(\n                new BlockContent(\n                    new BlockMetadata(\n                        protocolVersion: BlockMetadata.CurrentProtocolVersion,\n                        index: blockChain.Tip.Index + 2,\n                        timestamp: blockChain.Tip.Timestamp.Subtract(TimeSpan.FromSeconds(1)),\n                        miner: TestUtils.PrivateKeys[1].Address,\n                        publicKey: TestUtils.PrivateKeys[1].PublicKey,\n                        previousHash: blockChain.Tip.Hash,\n                        txHash: null,\n                        lastCommit: null,\n                        evidenceHash: null)).Propose(),\n                TestUtils.PrivateKeys[1]);\n\n            context.Start();\n            context.ProduceMessage(\n                TestUtils.CreateConsensusPropose(\n                    invalidBlock, TestUtils.PrivateKeys[1]));\n\n            await Task.WhenAll(nilPreVoteSent.WaitAsync(), stepChangedToPreVote.WaitAsync());\n            Assert.False(timeoutProcessed); // Check step transition isn't by timeout.\n            Assert.Equal(ConsensusStep.PreVote, context.Step);\n            Assert.Equal(1, context.Height);\n            Assert.Equal(0, context.Round);\n        }\n\n        [Fact(Timeout = Timeout)]\n        public async Task EnterPreVoteNilOnInvalidBlockContent()\n        {\n            // NOTE: This test does not check tx nonces, different state root hash.\n            var stepChangedToPreVote = new AsyncAutoResetEvent();\n            var timeoutProcessed = false;\n            var nilPreVoteSent = new AsyncAutoResetEvent();\n            var invalidKey = new PrivateKey();\n            var policy = new BlockPolicy(\n                new PolicyActionsRegistry(\n                    endBlockActions: ImmutableArray.Create<IAction>(new MinerReward(1))),\n                getMaxTransactionsBytes: _ => 50 * 1024,\n                validateNextBlockTx: IsSignerValid);\n\n            TxPolicyViolationException? IsSignerValid(\n                BlockChain chain, Transaction tx)\n            {\n                var validAddress = TestUtils.PrivateKeys[1].Address;\n                return tx.Signer.Equals(validAddress)\n                    ? null\n                    : new TxPolicyViolationException(\"invalid signer\", tx.Id);\n            }\n\n            var (blockChain, context) = TestUtils.CreateDummyContext(\n                policy: policy,\n                privateKey: TestUtils.PrivateKeys[0]);\n            context.StateChanged += (_, eventArgs) =>\n            {\n                if (eventArgs.Step == ConsensusStep.PreVote)\n                {\n                    stepChangedToPreVote.Set();\n                }\n            };\n            context.TimeoutProcessed += (_, __) =>\n            {\n                timeoutProcessed = true;\n            };\n            context.MessageToPublish += (_, message) =>\n            {\n                if (message is ConsensusPreVoteMsg vote && vote.PreVote.BlockHash.Equals(default))\n                {\n                    nilPreVoteSent.Set();\n                }\n            };\n\n            var diffPolicyBlockChain =\n                TestUtils.CreateDummyBlockChain(\n                    policy, new SingleActionLoader(typeof(DumbAction)), blockChain.Genesis);\n\n            var invalidTx = diffPolicyBlockChain.MakeTransaction(invalidKey, new DumbAction[] { });\n\n            Block invalidBlock = diffPolicyBlockChain.EvaluateAndSign(\n                Libplanet.Tests.TestUtils.ProposeNext(\n                    blockChain.Genesis,\n                    new[] { invalidTx },\n                    miner: TestUtils.PrivateKeys[1].PublicKey,\n                    blockInterval: TimeSpan.FromSeconds(10)),\n                TestUtils.PrivateKeys[1]);\n\n            context.Start();\n            context.ProduceMessage(\n                TestUtils.CreateConsensusPropose(\n                    invalidBlock,\n                    TestUtils.PrivateKeys[1]));\n\n            await Task.WhenAll(nilPreVoteSent.WaitAsync(), stepChangedToPreVote.WaitAsync());\n            Assert.False(timeoutProcessed); // Check step transition isn't by timeout.\n            Assert.Equal(ConsensusStep.PreVote, context.Step);\n            Assert.Equal(1, context.Height);\n            Assert.Equal(0, context.Round);\n        }\n\n        [Fact(Timeout = Timeout)]\n        public async Task EnterPreVoteNilOnInvalidAction()\n        {\n            // NOTE: This test does not check tx nonces, different state root hash.\n            var stepChangedToPreVote = new AsyncAutoResetEvent();\n            var timeoutProcessed = false;\n            var nilPreVoteSent = new AsyncAutoResetEvent();\n            var nilPreCommitSent = new AsyncAutoResetEvent();\n            var txSigner = new PrivateKey();\n            var policy = new BlockPolicy(\n                new PolicyActionsRegistry(\n                    endBlockActions: ImmutableArray.Create<IAction>(new MinerReward(1))),\n                getMaxTransactionsBytes: _ => 50 * 1024);\n\n            var (blockChain, context) = TestUtils.CreateDummyContext(\n                policy: policy,\n                privateKey: TestUtils.PrivateKeys[0]);\n            context.StateChanged += (_, eventArgs) =>\n            {\n                if (eventArgs.Step == ConsensusStep.PreVote)\n                {\n                    stepChangedToPreVote.Set();\n                }\n            };\n            context.TimeoutProcessed += (_, __) =>\n            {\n                timeoutProcessed = true;\n            };\n            context.MessageToPublish += (_, message) =>\n            {\n                if (message is ConsensusPreVoteMsg vote && vote.PreVote.BlockHash.Equals(default))\n                {\n                    nilPreVoteSent.Set();\n                }\n                else if (\n                    message is ConsensusPreCommitMsg commit &&\n                    commit.PreCommit.BlockHash.Equals(default))\n                {\n                    nilPreCommitSent.Set();\n                }\n            };\n\n            using var fx = new MemoryStoreFixture(policy.PolicyActionsRegistry);\n\n            var unsignedInvalidTx = new UnsignedTx(\n                new TxInvoice(\n                    blockChain.Genesis.Hash,\n                    DateTimeOffset.UtcNow,\n                    new TxActionList((IValue)List.Empty.Add(new Text(\"Foo\")))), // Invalid action\n                new TxSigningMetadata(txSigner.PublicKey, 0));\n            var invalidTx = new Transaction(\n                unsignedInvalidTx, unsignedInvalidTx.CreateSignature(txSigner));\n            var txs = new[] { invalidTx };\n            var evs = Array.Empty<EvidenceBase>();\n\n            var metadata = new BlockMetadata(\n                index: 1L,\n                timestamp: DateTimeOffset.UtcNow,\n                publicKey: TestUtils.PrivateKeys[1].PublicKey,\n                previousHash: blockChain.Genesis.Hash,\n                txHash: BlockContent.DeriveTxHash(txs),\n                lastCommit: null,\n                evidenceHash: null);\n            var preEval = new PreEvaluationBlock(\n                preEvaluationBlockHeader: new PreEvaluationBlockHeader(\n                    metadata, metadata.DerivePreEvaluationHash()),\n                transactions: txs,\n                evidence: evs);\n            var invalidBlock = preEval.Sign(\n                TestUtils.PrivateKeys[1],\n                HashDigest<SHA256>.DeriveFrom(TestUtils.GetRandomBytes(1024)));\n\n            context.Start();\n            context.ProduceMessage(\n                TestUtils.CreateConsensusPropose(\n                    invalidBlock,\n                    TestUtils.PrivateKeys[1]));\n            await Task.WhenAll(nilPreVoteSent.WaitAsync(), stepChangedToPreVote.WaitAsync());\n            Assert.False(timeoutProcessed); // Check step transition isn't by timeout.\n            Assert.Equal(ConsensusStep.PreVote, context.Step);\n            Assert.Equal(1, context.Height);\n            Assert.Equal(0, context.Round);\n\n            context.ProduceMessage(\n                new ConsensusPreVoteMsg(\n                    TestUtils.CreateVote(\n                        TestUtils.PrivateKeys[1],\n                        TestUtils.ValidatorSet[1].Power,\n                        1,\n                        0,\n                        invalidBlock.Hash,\n                        VoteFlag.PreVote)));\n            context.ProduceMessage(\n                new ConsensusPreVoteMsg(\n                    TestUtils.CreateVote(\n                        TestUtils.PrivateKeys[2],\n                        TestUtils.ValidatorSet[2].Power,\n                        1,\n                        0,\n                        default,\n                        VoteFlag.PreVote)));\n            context.ProduceMessage(\n                new ConsensusPreVoteMsg(\n                    TestUtils.CreateVote(\n                        TestUtils.PrivateKeys[3],\n                        TestUtils.ValidatorSet[3].Power,\n                        1,\n                        0,\n                        default,\n                        VoteFlag.PreVote)));\n            await nilPreCommitSent.WaitAsync();\n            Assert.Equal(ConsensusStep.PreCommit, context.Step);\n        }\n\n        [Fact(Timeout = Timeout)]\n        public async Task EnterPreVoteNilOneThird()\n        {\n            var (blockChain, context) = TestUtils.CreateDummyContext(\n                privateKey: TestUtils.PrivateKeys[0]);\n\n            var block = blockChain.ProposeBlock(TestUtils.PrivateKeys[1]);\n            var stepChangedToRoundOnePreVote = new AsyncAutoResetEvent();\n            context.StateChanged += (_, eventArgs) =>\n            {\n                if (eventArgs.Round == 1 && eventArgs.Step == ConsensusStep.PreVote)\n                {\n                    stepChangedToRoundOnePreVote.Set();\n                }\n            };\n            context.Start();\n\n            context.ProduceMessage(\n                new ConsensusPreVoteMsg(\n                    TestUtils.CreateVote(\n                        TestUtils.PrivateKeys[2],\n                        TestUtils.ValidatorSet[2].Power,\n                        1,\n                        1,\n                        hash: default,\n                        flag: VoteFlag.PreVote)));\n            context.ProduceMessage(\n                new ConsensusPreVoteMsg(\n                    TestUtils.CreateVote(\n                        TestUtils.PrivateKeys[3],\n                        TestUtils.ValidatorSet[3].Power,\n                        1,\n                        1,\n                        hash: default,\n                        flag: VoteFlag.PreVote)));\n\n            await stepChangedToRoundOnePreVote.WaitAsync();\n            Assert.Equal(ConsensusStep.PreVote, context.Step);\n            Assert.Equal(1, context.Height);\n            Assert.Equal(1, context.Round);\n        }\n\n        [Fact(Timeout = Timeout)]\n        public async void TimeoutPropose()\n        {\n            var stepChangedToPreVote = new AsyncAutoResetEvent();\n            var preVoteSent = new AsyncAutoResetEvent();\n\n            var (_, context) = TestUtils.CreateDummyContext(\n                privateKey: TestUtils.PrivateKeys[0],\n                contextOption: new ContextOption(proposeTimeoutBase: 1_000));\n\n            context.StateChanged += (_, eventArgs) =>\n            {\n                if (eventArgs.Step == ConsensusStep.PreVote)\n                {\n                    stepChangedToPreVote.Set();\n                }\n            };\n            context.MessageToPublish += (_, message) =>\n            {\n                if (message is ConsensusPreVoteMsg)\n                {\n                    preVoteSent.Set();\n                }\n            };\n\n            context.Start();\n            await Task.WhenAll(preVoteSent.WaitAsync(), stepChangedToPreVote.WaitAsync());\n            Assert.Equal(ConsensusStep.PreVote, context.Step);\n            Assert.Equal(1, context.Height);\n            Assert.Equal(0, context.Round);\n        }\n\n        [Fact(Timeout = Timeout)]\n        public async Task UponRulesCheckAfterTimeout()\n        {\n            var (blockChain, context) = TestUtils.CreateDummyContext(\n                privateKey: TestUtils.PrivateKeys[0],\n                contextOption: new ContextOption(\n                    preVoteTimeoutBase: 1_000,\n                    preCommitTimeoutBase: 1_000));\n\n            var block1 = blockChain.ProposeBlock(TestUtils.PrivateKeys[1]);\n            var block2 = blockChain.ProposeBlock(TestUtils.PrivateKeys[2]);\n            var roundOneStepChangedToPreVote = new AsyncAutoResetEvent();\n            context.StateChanged += (_, eventArgs) =>\n            {\n                if (eventArgs.Round == 1 && eventArgs.Step == ConsensusStep.PreVote)\n                {\n                    roundOneStepChangedToPreVote.Set();\n                }\n            };\n\n            // Push round 0 and round 1 proposes.\n            context.ProduceMessage(\n                TestUtils.CreateConsensusPropose(\n                    block1, TestUtils.PrivateKeys[1], round: 0));\n            context.ProduceMessage(\n                TestUtils.CreateConsensusPropose(\n                    block2, TestUtils.PrivateKeys[2], round: 1));\n\n            // Two additional votes should be enough to trigger prevote timeout timer.\n            context.ProduceMessage(\n                new ConsensusPreVoteMsg(\n                    TestUtils.CreateVote(\n                        TestUtils.PrivateKeys[2],\n                        TestUtils.ValidatorSet[2].Power,\n                        1,\n                        0,\n                        hash: default,\n                        flag: VoteFlag.PreVote)));\n            context.ProduceMessage(\n                new ConsensusPreVoteMsg(\n                    TestUtils.CreateVote(\n                        TestUtils.PrivateKeys[3],\n                        TestUtils.ValidatorSet[3].Power,\n                        1,\n                        0,\n                        hash: default,\n                        flag: VoteFlag.PreVote)));\n\n            // Two additional votes should be enough to trigger precommit timeout timer.\n            context.ProduceMessage(\n                new ConsensusPreCommitMsg(\n                    TestUtils.CreateVote(\n                        TestUtils.PrivateKeys[2],\n                        TestUtils.ValidatorSet[2].Power,\n                        1,\n                        0,\n                        hash: default,\n                        flag: VoteFlag.PreCommit)));\n            context.ProduceMessage(\n                new ConsensusPreCommitMsg(\n                    TestUtils.CreateVote(\n                        TestUtils.PrivateKeys[3],\n                        TestUtils.ValidatorSet[3].Power,\n                        1,\n                        0,\n                        hash: default,\n                        flag: VoteFlag.PreCommit)));\n\n            context.Start();\n\n            // Round 0 Propose -> Round 0 PreVote (due to Round 0 Propose message) ->\n            // PreVote timeout start (due to PreVote messages) ->\n            // PreVote timeout end -> Round 0 PreCommit ->\n            // PreCommit timeout start (due to state mutation check and PreCommit messages) ->\n            // PreCommit timeout end -> Round 1 Propose ->\n            // Round 1 PreVote (due to state mutation check and Round 1 Propose message)\n            await roundOneStepChangedToPreVote.WaitAsync();\n            Assert.Equal(1, context.Height);\n            Assert.Equal(1, context.Round);\n            Assert.Equal(ConsensusStep.PreVote, context.Step);\n        }\n\n        [Fact(Timeout = Timeout)]\n        public async Task TimeoutPreVote()\n        {\n            var (blockChain, context) = TestUtils.CreateDummyContext(\n                privateKey: TestUtils.PrivateKeys[0],\n                contextOption: new ContextOption(preVoteTimeoutBase: 1_000));\n\n            var block = blockChain.ProposeBlock(TestUtils.PrivateKeys[1]);\n            var timeoutProcessed = new AsyncAutoResetEvent();\n            context.TimeoutProcessed += (_, __) => timeoutProcessed.Set();\n            context.Start();\n\n            context.ProduceMessage(\n                TestUtils.CreateConsensusPropose(\n                    block, TestUtils.PrivateKeys[1], round: 0));\n\n            context.ProduceMessage(\n                new ConsensusPreVoteMsg(\n                    TestUtils.CreateVote(\n                        TestUtils.PrivateKeys[1],\n                        TestUtils.ValidatorSet[1].Power,\n                        1,\n                        0,\n                        hash: block.Hash,\n                        flag: VoteFlag.PreVote)));\n            context.ProduceMessage(\n                new ConsensusPreVoteMsg(\n                    TestUtils.CreateVote(\n                        TestUtils.PrivateKeys[2],\n                        TestUtils.ValidatorSet[2].Power,\n                        1,\n                        0,\n                        hash: default,\n                        flag: VoteFlag.PreVote)));\n            context.ProduceMessage(\n                new ConsensusPreVoteMsg(\n                    TestUtils.CreateVote(\n                        TestUtils.PrivateKeys[3],\n                        TestUtils.ValidatorSet[3].Power,\n                        1,\n                        0,\n                        hash: default,\n                        flag: VoteFlag.PreVote)));\n\n            // Wait for timeout.\n            await timeoutProcessed.WaitAsync();\n            Assert.Equal(ConsensusStep.PreCommit, context.Step);\n            Assert.Equal(1, context.Height);\n            Assert.Equal(0, context.Round);\n        }\n\n        [Fact(Timeout = Timeout)]\n        public async Task TimeoutPreCommit()\n        {\n            var (blockChain, context) = TestUtils.CreateDummyContext(\n                privateKey: TestUtils.PrivateKeys[0],\n                contextOption: new ContextOption(preCommitTimeoutBase: 1_000));\n\n            var block = blockChain.ProposeBlock(TestUtils.PrivateKeys[1]);\n            var timeoutProcessed = new AsyncAutoResetEvent();\n            context.TimeoutProcessed += (_, __) => timeoutProcessed.Set();\n            context.Start();\n\n            context.ProduceMessage(\n                TestUtils.CreateConsensusPropose(\n                    block, TestUtils.PrivateKeys[1], round: 0));\n\n            context.ProduceMessage(\n                new ConsensusPreCommitMsg(\n                    TestUtils.CreateVote(\n                        TestUtils.PrivateKeys[1],\n                        TestUtils.ValidatorSet[1].Power,\n                        1,\n                        0,\n                        hash: block.Hash,\n                        flag: VoteFlag.PreCommit)));\n            context.ProduceMessage(\n                new ConsensusPreCommitMsg(\n                    TestUtils.CreateVote(\n                        TestUtils.PrivateKeys[2],\n                        TestUtils.ValidatorSet[2].Power,\n                        1,\n                        0,\n                        hash: default,\n                        flag: VoteFlag.PreCommit)));\n            context.ProduceMessage(\n                new ConsensusPreCommitMsg(\n                    TestUtils.CreateVote(\n                        TestUtils.PrivateKeys[3],\n                        TestUtils.ValidatorSet[3].Power,\n                        1,\n                        0,\n                        hash: default,\n                        flag: VoteFlag.PreCommit)));\n\n            // Wait for timeout.\n            await timeoutProcessed.WaitAsync();\n            Assert.Equal(ConsensusStep.Propose, context.Step);\n            Assert.Equal(1, context.Height);\n            Assert.Equal(1, context.Round);\n        }\n    }\n}\n"
  },
  {
    "path": "test/Libplanet.Net.Tests/Consensus/ContextProposerTest.cs",
    "content": "using System.Threading.Tasks;\nusing Libplanet.Crypto;\nusing Libplanet.Net.Consensus;\nusing Libplanet.Net.Messages;\nusing Libplanet.Types.Blocks;\nusing Libplanet.Types.Consensus;\nusing Nito.AsyncEx;\nusing Serilog;\nusing Xunit;\nusing Xunit.Abstractions;\n\nnamespace Libplanet.Net.Tests.Consensus\n{\n    public class ContextProposerTest\n    {\n        private const int Timeout = 30000;\n        private readonly ILogger _logger;\n\n        public ContextProposerTest(ITestOutputHelper output)\n        {\n            const string outputTemplate =\n                \"{Timestamp:HH:mm:ss:ffffffZ} - {Message} {Exception}\";\n            Log.Logger = new LoggerConfiguration()\n                .MinimumLevel.Verbose()\n                .WriteTo.TestOutput(output, outputTemplate: outputTemplate)\n                .CreateLogger()\n                .ForContext<ContextProposerTest>();\n\n            _logger = Log.ForContext<ContextProposerTest>();\n        }\n\n        [Fact(Timeout = Timeout)]\n        public async Task EnterPreCommitNil()\n        {\n            var stepChangedToPreCommit = new AsyncAutoResetEvent();\n            ConsensusPreCommitMsg? preCommit = null;\n            var preCommitSent = new AsyncAutoResetEvent();\n\n            var (_, context) = TestUtils.CreateDummyContext();\n            context.StateChanged += (_, eventArgs) =>\n            {\n                if (eventArgs.Step == ConsensusStep.PreCommit)\n                {\n                    stepChangedToPreCommit.Set();\n                }\n            };\n            context.MessageToPublish += (_, message) =>\n            {\n                if (message is ConsensusPreCommitMsg preCommitMsg)\n                {\n                    preCommit = preCommitMsg;\n                    preCommitSent.Set();\n                }\n            };\n\n            context.Start();\n            context.ProduceMessage(\n                new ConsensusPreVoteMsg(\n                    TestUtils.CreateVote(\n                        TestUtils.PrivateKeys[0],\n                        TestUtils.ValidatorSet[0].Power,\n                        1,\n                        0,\n                        hash: default,\n                        flag: VoteFlag.PreVote)));\n            context.ProduceMessage(\n                new ConsensusPreVoteMsg(\n                    TestUtils.CreateVote(\n                        TestUtils.PrivateKeys[2],\n                        TestUtils.ValidatorSet[2].Power,\n                        1,\n                        0,\n                        hash: default,\n                        flag: VoteFlag.PreVote)));\n            context.ProduceMessage(\n                new ConsensusPreVoteMsg(\n                    TestUtils.CreateVote(\n                        TestUtils.PrivateKeys[3],\n                        TestUtils.ValidatorSet[3].Power,\n                        1,\n                        0,\n                        hash: default,\n                        flag: VoteFlag.PreVote)));\n\n            await Task.WhenAll(preCommitSent.WaitAsync(), stepChangedToPreCommit.WaitAsync());\n            Assert.Equal(default(BlockHash), preCommit?.BlockHash);\n            Assert.Equal(1, context.Height);\n            Assert.Equal(0, context.Round);\n            Assert.Equal(ConsensusStep.PreCommit, context.Step);\n        }\n\n        [Fact(Timeout = Timeout)]\n        public async void EnterPreCommitBlock()\n        {\n            var stepChangedToPreCommit = new AsyncAutoResetEvent();\n            ConsensusProposalMsg? proposal = null;\n            var proposalSent = new AsyncAutoResetEvent();\n            ConsensusPreCommitMsg? preCommit = null;\n            var preCommitSent = new AsyncAutoResetEvent();\n\n            var (_, context) = TestUtils.CreateDummyContext();\n            context.StateChanged += (_, eventArgs) =>\n            {\n                if (eventArgs.Step == ConsensusStep.PreCommit)\n                {\n                    stepChangedToPreCommit.Set();\n                }\n            };\n            context.MessageToPublish += (_, message) =>\n            {\n                if (message is ConsensusProposalMsg proposalMsg)\n                {\n                    proposal = proposalMsg;\n                    proposalSent.Set();\n                }\n                else if (message is ConsensusPreCommitMsg preCommitMsg)\n                {\n                    preCommit = preCommitMsg;\n                    preCommitSent.Set();\n                }\n            };\n\n            context.Start();\n\n            // Wait for propose to process.\n            await proposalSent.WaitAsync();\n            BlockHash proposedblockHash = Assert.IsType<BlockHash>(proposal?.BlockHash);\n\n            context.ProduceMessage(\n                new ConsensusPreVoteMsg(TestUtils.CreateVote(\n                    TestUtils.PrivateKeys[0],\n                    TestUtils.ValidatorSet[0].Power,\n                    1,\n                    0,\n                    hash: proposedblockHash,\n                    flag: VoteFlag.PreVote)));\n            context.ProduceMessage(\n                new ConsensusPreVoteMsg(TestUtils.CreateVote(\n                    TestUtils.PrivateKeys[2],\n                    TestUtils.ValidatorSet[2].Power,\n                    1,\n                    0,\n                    hash: proposedblockHash,\n                    flag: VoteFlag.PreVote)));\n            context.ProduceMessage(\n                new ConsensusPreVoteMsg(TestUtils.CreateVote(\n                    TestUtils.PrivateKeys[3],\n                    TestUtils.ValidatorSet[3].Power,\n                    1,\n                    0,\n                    hash: proposedblockHash,\n                    flag: VoteFlag.PreVote)));\n\n            await Task.WhenAll(preCommitSent.WaitAsync(), stepChangedToPreCommit.WaitAsync());\n            Assert.Equal(proposedblockHash, preCommit?.BlockHash);\n            Assert.Equal(1, context.Height);\n            Assert.Equal(0, context.Round);\n            Assert.Equal(ConsensusStep.PreCommit, context.Step);\n        }\n\n        [Fact(Timeout = Timeout)]\n        public async void EnterNewRoundNil()\n        {\n            var roundChangedToOne = new AsyncAutoResetEvent();\n\n            var (_, context) = TestUtils.CreateDummyContext();\n            context.StateChanged += (_, eventArgs) =>\n            {\n                if (eventArgs.Round == 1)\n                {\n                    roundChangedToOne.Set();\n                }\n            };\n\n            context.Start();\n            context.ProduceMessage(\n                new ConsensusPreCommitMsg(\n                    TestUtils.CreateVote(\n                        TestUtils.PrivateKeys[0],\n                        TestUtils.ValidatorSet[0].Power,\n                        1,\n                        0,\n                        hash: default,\n                        flag: VoteFlag.PreCommit)));\n            context.ProduceMessage(\n                new ConsensusPreCommitMsg(\n                    TestUtils.CreateVote(\n                        TestUtils.PrivateKeys[2],\n                        TestUtils.ValidatorSet[2].Power,\n                        1,\n                        0,\n                        hash: default,\n                        flag: VoteFlag.PreCommit)));\n            context.ProduceMessage(\n                new ConsensusPreCommitMsg(\n                    TestUtils.CreateVote(\n                        TestUtils.PrivateKeys[3],\n                        TestUtils.ValidatorSet[3].Power,\n                        1,\n                        0,\n                        hash: default,\n                        flag: VoteFlag.PreCommit)));\n\n            await roundChangedToOne.WaitAsync();\n            Assert.Equal(1, context.Height);\n            Assert.Equal(1, context.Round);\n            Assert.Equal(ConsensusStep.Propose, context.Step);\n        }\n\n        [Fact(Timeout = Timeout)]\n        public async Task EndCommitBlock()\n        {\n            var stepChangedToEndCommit = new AsyncAutoResetEvent();\n            var stepChangedToPreCommit = new AsyncAutoResetEvent();\n            ConsensusProposalMsg? proposal = null;\n            var proposalSent = new AsyncAutoResetEvent();\n\n            var (_, context) = TestUtils.CreateDummyContext();\n            context.StateChanged += (_, eventArgs) =>\n            {\n                if (eventArgs.Step == ConsensusStep.PreCommit)\n                {\n                    stepChangedToPreCommit.Set();\n                }\n\n                if (eventArgs.Step == ConsensusStep.EndCommit)\n                {\n                    stepChangedToEndCommit.Set();\n                }\n            };\n            context.MessageToPublish += (_, message) =>\n            {\n                if (message is ConsensusProposalMsg proposalMsg)\n                {\n                    proposal = proposalMsg;\n                    proposalSent.Set();\n                }\n            };\n\n            context.Start();\n\n            // Wait for propose to process.\n            await proposalSent.WaitAsync();\n            Assert.NotNull(proposal?.BlockHash);\n\n            TestUtils.HandleFourPeersPreVoteMessages(\n                context,\n                TestUtils.PrivateKeys[1],\n                proposal!.Proposal.BlockHash);\n\n            await stepChangedToPreCommit.WaitAsync();\n\n            TestUtils.HandleFourPeersPreCommitMessages(\n                context,\n                TestUtils.PrivateKeys[1],\n                proposal!.Proposal.BlockHash);\n\n            await stepChangedToEndCommit.WaitAsync();\n            Assert.Equal(proposal?.BlockHash, context.GetBlockCommit()?.BlockHash);\n            Assert.Equal(1, context.Height);\n            Assert.Equal(0, context.Round);\n            Assert.Equal(ConsensusStep.EndCommit, context.Step);\n        }\n\n        [Fact(Timeout = Timeout)]\n        public async void EnterPreVoteNil()\n        {\n            var stepChangedToPreVote = new AsyncAutoResetEvent();\n            var nilPreVoteSent = new AsyncAutoResetEvent();\n            var (_, context) = TestUtils.CreateDummyContext(\n                height: 5,\n                validatorSet: Libplanet.Tests.TestUtils.ValidatorSet); // Peer1 should be a proposer\n\n            context.StateChanged += (_, eventArgs) =>\n            {\n                if (eventArgs.Step == ConsensusStep.PreVote)\n                {\n                    stepChangedToPreVote.Set();\n                }\n            };\n            context.MessageToPublish += (_, message) =>\n            {\n                if (message is ConsensusPreVoteMsg vote && vote.PreVote.BlockHash.Equals(default))\n                {\n                    nilPreVoteSent.Set();\n                }\n            };\n\n            context.Start();\n            await Task.WhenAll(nilPreVoteSent.WaitAsync(), stepChangedToPreVote.WaitAsync());\n            Assert.Equal(ConsensusStep.PreVote, context.Step);\n            Assert.Equal(5, context.Height);\n        }\n\n        [Fact(Timeout = Timeout)]\n        public async void EnterPreVoteBlock()\n        {\n            var stepChangedToPreVote = new AsyncAutoResetEvent();\n            ConsensusProposalMsg? proposal = null;\n            var proposalSent = new AsyncAutoResetEvent();\n            ConsensusPreVoteMsg? preVote = null;\n            var preVoteSent = new AsyncAutoResetEvent();\n\n            var (_, context) = TestUtils.CreateDummyContext();\n\n            context.StateChanged += (_, eventArgs) =>\n            {\n                if (eventArgs.Step == ConsensusStep.PreVote)\n                {\n                    stepChangedToPreVote.Set();\n                }\n            };\n            context.MessageToPublish += (_, message) =>\n            {\n                if (message is ConsensusProposalMsg proposalMsg)\n                {\n                    proposal = proposalMsg;\n                    proposalSent.Set();\n                }\n                else if (message is ConsensusPreVoteMsg preVoteMsg)\n                {\n                    preVote = preVoteMsg;\n                    preVoteSent.Set();\n                }\n            };\n\n            context.Start();\n            await proposalSent.WaitAsync();\n            Assert.NotNull(proposal?.BlockHash);\n\n            await Task.WhenAll(preVoteSent.WaitAsync(), stepChangedToPreVote.WaitAsync());\n            Assert.Equal(proposal?.BlockHash, preVote?.BlockHash);\n            Assert.Equal(1, context.Height);\n            Assert.Equal(0, context.Round);\n            Assert.Equal(ConsensusStep.PreVote, context.Step);\n        }\n\n        [Fact(Timeout = Timeout)]\n        public async void VoteNilOnSelfProposedInvalidBlock()\n        {\n            var privateKey = new PrivateKey();\n            ConsensusProposalMsg? proposal = null;\n            var proposalSent = new AsyncAutoResetEvent();\n            ConsensusPreVoteMsg? preVote = null;\n            var preVoteSent = new AsyncAutoResetEvent();\n\n            var blockChain = TestUtils.CreateDummyBlockChain();\n            var block1 = blockChain.ProposeBlock(new PrivateKey());\n            var block1Commit = TestUtils.CreateBlockCommit(block1);\n            blockChain.Append(block1, block1Commit);\n            var block2 = blockChain.ProposeBlock(new PrivateKey(), block1Commit);\n            var block2Commit = TestUtils.CreateBlockCommit(block2);\n            blockChain.Append(block2, block2Commit);\n\n            var context = TestUtils.CreateDummyContext(\n                blockChain,\n                privateKey: TestUtils.PrivateKeys[2],\n                height: 2,\n                lastCommit: block2Commit,\n                validatorSet: TestUtils.ValidatorSet);\n            context.MessageToPublish += (_, message) =>\n            {\n                if (message is ConsensusProposalMsg proposalMsg)\n                {\n                    proposal = proposalMsg;\n                    proposalSent.Set();\n                }\n                else if (message is ConsensusPreVoteMsg preVoteMsg)\n                {\n                    preVote = preVoteMsg;\n                    preVoteSent.Set();\n                }\n            };\n\n            Assert.Equal(\n                TestUtils.PrivateKeys[2].PublicKey,\n                TestUtils.ValidatorSet.GetProposer(2, 0).PublicKey);\n\n            context.Start();\n            await proposalSent.WaitAsync();\n            Bencodex.Codec codec = new Bencodex.Codec();\n            var proposedBlock = BlockMarshaler.UnmarshalBlock(\n                (Bencodex.Types.Dictionary)codec.Decode(proposal?.Proposal.MarshaledBlock!));\n            Assert.Equal(context.Height + 1, proposedBlock.Index);\n            await preVoteSent.WaitAsync();\n            Assert.Equal(default(BlockHash), preVote?.BlockHash);\n            Assert.Equal(default(BlockHash), preVote?.PreVote.BlockHash);\n        }\n    }\n}\n"
  },
  {
    "path": "test/Libplanet.Net.Tests/Consensus/ContextProposerValidRoundTest.cs",
    "content": "using System;\nusing System.Threading.Tasks;\nusing Libplanet.Crypto;\nusing Libplanet.Net.Consensus;\nusing Libplanet.Net.Messages;\nusing Libplanet.Types.Blocks;\nusing Libplanet.Types.Consensus;\nusing Nito.AsyncEx;\nusing Serilog;\nusing Xunit;\nusing Xunit.Abstractions;\n\nnamespace Libplanet.Net.Tests.Consensus\n{\n    public class ContextProposerValidRoundTest\n    {\n        private const int Timeout = 30000;\n        private static Bencodex.Codec _codec = new Bencodex.Codec();\n        private readonly ILogger _logger;\n\n        public ContextProposerValidRoundTest(ITestOutputHelper output)\n        {\n            const string outputTemplate =\n                \"{Timestamp:HH:mm:ss:ffffffZ} - {Message} {Exception}\";\n            Log.Logger = new LoggerConfiguration()\n                .MinimumLevel.Verbose()\n                .WriteTo.TestOutput(output, outputTemplate: outputTemplate)\n                .CreateLogger()\n                .ForContext<ContextProposerValidRoundTest>();\n\n            _logger = Log.ForContext<ContextProposerValidRoundTest>();\n        }\n\n        [Fact(Timeout = Timeout)]\n        public async Task EnterValidRoundPreVoteBlock()\n        {\n            ConsensusProposalMsg? proposal = null;\n            var proposalSent = new AsyncAutoResetEvent();\n            var roundTwoVoteSent = new AsyncAutoResetEvent();\n            var stateChangedToRoundTwoPropose = new AsyncAutoResetEvent();\n            bool timeoutProcessed = false;\n\n            var (_, context) = TestUtils.CreateDummyContext();\n            context.StateChanged += (_, eventArgs) =>\n            {\n                if (eventArgs.Round == 2 && eventArgs.Step == ConsensusStep.Propose)\n                {\n                    stateChangedToRoundTwoPropose.Set();\n                }\n            };\n            context.TimeoutProcessed += (_, __) => timeoutProcessed = true;\n            context.MessageToPublish += (_, message) =>\n            {\n                if (message is ConsensusProposalMsg proposalMsg)\n                {\n                    proposal = proposalMsg;\n                    proposalSent.Set();\n                }\n                else if (message is ConsensusPreVoteMsg prevote &&\n                    prevote.BlockHash is { } hash &&\n                    hash.Equals(proposal?.BlockHash) &&\n                    prevote.Round == 2)\n                {\n                    roundTwoVoteSent.Set();\n                }\n            };\n\n            context.Start();\n            await proposalSent.WaitAsync();\n            Assert.NotNull(proposal);\n            Block proposedBlock = BlockMarshaler.UnmarshalBlock(\n                (Bencodex.Types.Dictionary)_codec.Decode(proposal!.Proposal.MarshaledBlock));\n\n            // Force round change.\n            context.ProduceMessage(\n                new ConsensusPreVoteMsg(TestUtils.CreateVote(\n                    TestUtils.PrivateKeys[0],\n                    TestUtils.ValidatorSet[0].Power,\n                    1,\n                    round: 2,\n                    hash: proposedBlock.Hash,\n                    flag: VoteFlag.PreVote)));\n            context.ProduceMessage(\n                new ConsensusPreVoteMsg(TestUtils.CreateVote(\n                    TestUtils.PrivateKeys[2],\n                    TestUtils.ValidatorSet[2].Power,\n                    height: 1,\n                    round: 2,\n                    hash: proposedBlock.Hash,\n                    flag: VoteFlag.PreVote)));\n            await stateChangedToRoundTwoPropose.WaitAsync();\n            Assert.Equal(2, context.Round);\n\n            context.ProduceMessage(TestUtils.CreateConsensusPropose(\n                proposedBlock, TestUtils.PrivateKeys[3], round: 2, validRound: 1));\n            context.ProduceMessage(\n                new ConsensusPreVoteMsg(TestUtils.CreateVote(\n                    TestUtils.PrivateKeys[0],\n                    TestUtils.ValidatorSet[0].Power,\n                    height: 1,\n                    round: 1,\n                    hash: proposedBlock.Hash,\n                    flag: VoteFlag.PreVote)));\n            context.ProduceMessage(\n                new ConsensusPreVoteMsg(TestUtils.CreateVote(\n                    TestUtils.PrivateKeys[2],\n                    TestUtils.ValidatorSet[2].Power,\n                    height: 1,\n                    round: 1,\n                    hash: proposedBlock.Hash,\n                    flag: VoteFlag.PreVote)));\n            context.ProduceMessage(\n                new ConsensusPreVoteMsg(TestUtils.CreateVote(\n                    TestUtils.PrivateKeys[3],\n                    TestUtils.ValidatorSet[3].Power,\n                    1,\n                    round: 1,\n                    hash: proposedBlock.Hash,\n                    flag: VoteFlag.PreVote)));\n\n            await roundTwoVoteSent.WaitAsync();\n            Assert.False(timeoutProcessed); // Assert no transition is due to timeout.\n            Assert.Equal(ConsensusStep.PreVote, context.Step);\n        }\n\n        [Fact(Timeout = Timeout)]\n        public async void EnterValidRoundPreVoteNil()\n        {\n            ConsensusProposalMsg? proposal = null;\n            var proposalSent = new AsyncAutoResetEvent();\n            var stateChangedToRoundTwoPropose = new AsyncAutoResetEvent();\n            var stateChangedToRoundTwoPreVote = new AsyncAutoResetEvent();\n            var stateChangedToRoundTwoPreCommit = new AsyncAutoResetEvent();\n            var stateChangedToRoundThreePropose = new AsyncAutoResetEvent();\n            var roundThreeNilPreVoteSent = new AsyncAutoResetEvent();\n            bool timeoutProcessed = false;\n            var (blockChain, context) = TestUtils.CreateDummyContext();\n            context.StateChanged += (_, eventArgs) =>\n            {\n                if (eventArgs.Round == 2 && eventArgs.Step == ConsensusStep.Propose)\n                {\n                    stateChangedToRoundTwoPropose.Set();\n                }\n                else if (eventArgs.Round == 2 && eventArgs.Step == ConsensusStep.PreVote)\n                {\n                    stateChangedToRoundTwoPreVote.Set();\n                }\n                else if (eventArgs.Round == 2 && eventArgs.Step == ConsensusStep.PreCommit)\n                {\n                    stateChangedToRoundTwoPreCommit.Set();\n                }\n                else if (eventArgs.Round == 3 && eventArgs.Step == ConsensusStep.Propose)\n                {\n                    stateChangedToRoundThreePropose.Set();\n                }\n            };\n            context.TimeoutProcessed += (_, __) => timeoutProcessed = true;\n            context.MessageToPublish += (_, message) =>\n            {\n                if (message is ConsensusProposalMsg proposalMsg)\n                {\n                    proposal = proposalMsg;\n                    proposalSent.Set();\n                }\n                else if (message is ConsensusPreVoteMsg prevote &&\n                    prevote.Round == 3 &&\n                    prevote.BlockHash.Equals(default))\n                {\n                    roundThreeNilPreVoteSent.Set();\n                }\n            };\n\n            var key = new PrivateKey();\n            var differentBlock = blockChain.EvaluateAndSign(\n                new BlockContent(\n                    new BlockMetadata(\n                        protocolVersion: BlockMetadata.CurrentProtocolVersion,\n                        index: blockChain.Tip.Index + 1,\n                        timestamp: blockChain.Tip.Timestamp.Add(TimeSpan.FromSeconds(1)),\n                        miner: key.Address,\n                        publicKey: key.PublicKey,\n                        previousHash: blockChain.Tip.Hash,\n                        txHash: null,\n                        lastCommit: null,\n                        evidenceHash: null)).Propose(),\n                key);\n\n            context.Start();\n            await proposalSent.WaitAsync();\n            Assert.NotNull(proposal);\n            Block proposedBlock = BlockMarshaler.UnmarshalBlock(\n                (Bencodex.Types.Dictionary)_codec.Decode(proposal!.Proposal.MarshaledBlock));\n\n            // Force round change to 2.\n            context.ProduceMessage(\n                new ConsensusPreVoteMsg(TestUtils.CreateVote(\n                    TestUtils.PrivateKeys[0],\n                    TestUtils.ValidatorSet[0].Power,\n                    height: 1,\n                    round: 2,\n                    hash: proposedBlock.Hash,\n                    flag: VoteFlag.PreVote)));\n            context.ProduceMessage(\n                new ConsensusPreVoteMsg(TestUtils.CreateVote(\n                    TestUtils.PrivateKeys[2],\n                    TestUtils.ValidatorSet[2].Power,\n                    height: 1,\n                    round: 2,\n                    hash: proposedBlock.Hash,\n                    flag: VoteFlag.PreVote)));\n            await stateChangedToRoundTwoPropose.WaitAsync();\n            Assert.Equal(2, context.Round);\n            Assert.False(timeoutProcessed); // Assert no transition is due to timeout.\n\n            // Updated locked round and valid round to 2.\n            context.ProduceMessage(\n                TestUtils.CreateConsensusPropose(\n                    proposedBlock,\n                    TestUtils.PrivateKeys[3],\n                    height: 1,\n                    round: 2,\n                    validRound: -1));\n            context.ProduceMessage(\n                new ConsensusPreVoteMsg(TestUtils.CreateVote(\n                    TestUtils.PrivateKeys[3],\n                    TestUtils.ValidatorSet[3].Power,\n                    height: 1,\n                    round: 2,\n                    hash: proposedBlock.Hash,\n                    flag: VoteFlag.PreVote)));\n            await stateChangedToRoundTwoPreCommit.WaitAsync();\n\n            // Force round change to 3.\n            context.ProduceMessage(\n                new ConsensusPreVoteMsg(TestUtils.CreateVote(\n                    TestUtils.PrivateKeys[0],\n                    TestUtils.ValidatorSet[0].Power,\n                    height: 1,\n                    round: 3,\n                    hash: differentBlock.Hash,\n                    flag: VoteFlag.PreVote)));\n            context.ProduceMessage(\n                new ConsensusPreVoteMsg(TestUtils.CreateVote(\n                    TestUtils.PrivateKeys[2],\n                    TestUtils.ValidatorSet[2].Power,\n                    height: 1,\n                    round: 3,\n                    hash: differentBlock.Hash,\n                    flag: VoteFlag.PreVote)));\n            await stateChangedToRoundThreePropose.WaitAsync();\n            Assert.Equal(3, context.Round);\n\n            context.ProduceMessage(TestUtils.CreateConsensusPropose(\n                differentBlock, TestUtils.PrivateKeys[0], round: 3, validRound: 0));\n            context.ProduceMessage(\n                new ConsensusPreVoteMsg(TestUtils.CreateVote(\n                    TestUtils.PrivateKeys[3],\n                    TestUtils.ValidatorSet[3].Power,\n                    height: 1,\n                    round: 3,\n                    hash: differentBlock.Hash,\n                    flag: VoteFlag.PreVote)));\n\n            await roundThreeNilPreVoteSent.WaitAsync();\n            Assert.False(timeoutProcessed);\n        }\n    }\n}\n"
  },
  {
    "path": "test/Libplanet.Net.Tests/Consensus/ContextTest.cs",
    "content": "using System;\nusing System.Collections.Immutable;\nusing System.Diagnostics;\nusing System.Linq;\nusing System.Numerics;\nusing System.Text.Json;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing Bencodex;\nusing Bencodex.Types;\nusing Libplanet.Action;\nusing Libplanet.Action.Loader;\nusing Libplanet.Action.State;\nusing Libplanet.Action.Tests.Common;\nusing Libplanet.Blockchain.Policies;\nusing Libplanet.Consensus;\nusing Libplanet.Crypto;\nusing Libplanet.Net.Consensus;\nusing Libplanet.Net.Messages;\nusing Libplanet.Store;\nusing Libplanet.Store.Trie;\nusing Libplanet.Tests;\nusing Libplanet.Tests.Store;\nusing Libplanet.Types.Blocks;\nusing Libplanet.Types.Consensus;\nusing Libplanet.Types.Tx;\nusing Nito.AsyncEx;\nusing Serilog;\nusing Xunit;\nusing Xunit.Abstractions;\nusing Xunit.Sdk;\n\nnamespace Libplanet.Net.Tests.Consensus\n{\n    public class ContextTest\n    {\n        private const int Timeout = 30000;\n        private readonly ILogger _logger;\n\n        public ContextTest(ITestOutputHelper output)\n        {\n            const string outputTemplate =\n                \"{Timestamp:HH:mm:ss:ffffffZ} - {Message}\";\n            Log.Logger = new LoggerConfiguration()\n                .MinimumLevel.Verbose()\n                .WriteTo.TestOutput(output, outputTemplate: outputTemplate)\n                .CreateLogger()\n                .ForContext<ContextTest>();\n\n            _logger = Log.ForContext<ContextTest>();\n        }\n\n        [Fact(Timeout = Timeout)]\n        public async Task StartAsProposer()\n        {\n            var proposalSent = new AsyncAutoResetEvent();\n            var stepChangedToPreVote = new AsyncAutoResetEvent();\n            var (_, context) = TestUtils.CreateDummyContext();\n            context.StateChanged += (_, eventArgs) =>\n            {\n                if (eventArgs.Step == ConsensusStep.PreVote)\n                {\n                    stepChangedToPreVote.Set();\n                }\n            };\n            context.MessageToPublish += (_, message) =>\n            {\n                if (message is ConsensusProposalMsg)\n                {\n                    proposalSent.Set();\n                }\n            };\n\n            context.Start();\n            await Task.WhenAll(proposalSent.WaitAsync(), stepChangedToPreVote.WaitAsync());\n\n            Assert.Equal(ConsensusStep.PreVote, context.Step);\n            Assert.Equal(1, context.Height);\n            Assert.Equal(0, context.Round);\n        }\n\n        [Fact(Timeout = Timeout)]\n        public async Task StartAsProposerWithLastCommit()\n        {\n            var stepChangedToPreVote = new AsyncAutoResetEvent();\n            ConsensusProposalMsg? proposal = null;\n            var proposalSent = new AsyncAutoResetEvent();\n\n            // Assumed that height 1 is already committed.  It will catch a propose to check\n            // whether the lastCommit of height 1 is used for propose.  Note that Peer2\n            // is the proposer for height 2.\n            var blockChain = TestUtils.CreateDummyBlockChain();\n            Block heightOneBlock = blockChain.ProposeBlock(TestUtils.PrivateKeys[1]);\n            var lastCommit = TestUtils.CreateBlockCommit(heightOneBlock);\n            blockChain.Append(heightOneBlock, lastCommit);\n\n            var context = TestUtils.CreateDummyContext(\n                blockChain,\n                height: 2,\n                lastCommit: lastCommit,\n                privateKey: TestUtils.PrivateKeys[2],\n                validatorSet: Libplanet.Tests.TestUtils.ValidatorSet);\n\n            context.StateChanged += (_, eventArgs) =>\n            {\n                if (eventArgs.Step == ConsensusStep.PreVote)\n                {\n                    stepChangedToPreVote.Set();\n                }\n            };\n            context.MessageToPublish += (_, message) =>\n            {\n                if (message is ConsensusProposalMsg proposalMsg)\n                {\n                    proposal = proposalMsg;\n                    proposalSent.Set();\n                }\n            };\n\n            context.Start();\n            await Task.WhenAll(stepChangedToPreVote.WaitAsync(), proposalSent.WaitAsync());\n\n            Assert.Equal(ConsensusStep.PreVote, context.Step);\n            Assert.NotNull(proposal);\n            Block proposed = BlockMarshaler.UnmarshalBlock(\n                (Dictionary)new Codec().Decode(proposal!.Proposal.MarshaledBlock));\n            Assert.NotNull(proposed.LastCommit);\n            Assert.Equal(lastCommit, proposed.LastCommit);\n        }\n\n        [Fact(Timeout = Timeout)]\n        public async Task CannotStartTwice()\n        {\n            var stepChanged = new AsyncAutoResetEvent();\n            var (_, context) = TestUtils.CreateDummyContext();\n            context.StateChanged += (_, eventArgs) =>\n            {\n                if (eventArgs.Step == ConsensusStep.Propose)\n                {\n                    stepChanged.Set();\n                }\n            };\n            context.Start();\n\n            await stepChanged.WaitAsync();\n            Assert.Throws<InvalidOperationException>(() => context.Start());\n        }\n\n        [Fact(Timeout = Timeout)]\n        public async Task CanAcceptMessagesAfterCommitFailure()\n        {\n            Codec codec = new Codec();\n            var stepChangedToPreVote = new AsyncAutoResetEvent();\n            ConsensusProposalMsg? proposal = null;\n            var proposalSent = new AsyncAutoResetEvent();\n            Block? proposedBlock = null;\n            var stepChangedToEndCommit = new AsyncAutoResetEvent();\n            var exceptionOccurred = new AsyncAutoResetEvent();\n            Exception? exceptionThrown = null;\n\n            // Add block #1 so we can start with a last commit for height 2.\n            var blockChain = TestUtils.CreateDummyBlockChain();\n            Block heightOneBlock = blockChain.ProposeBlock(TestUtils.PrivateKeys[1]);\n            var lastCommit = TestUtils.CreateBlockCommit(heightOneBlock);\n            blockChain.Append(heightOneBlock, lastCommit);\n\n            var context = TestUtils.CreateDummyContext(\n                blockChain,\n                height: 2,\n                lastCommit: lastCommit,\n                privateKey: TestUtils.PrivateKeys[2],\n                validatorSet: TestUtils.ValidatorSet);\n\n            context.StateChanged += (_, eventArgs) =>\n            {\n                if (eventArgs.Step == ConsensusStep.PreVote)\n                {\n                    stepChangedToPreVote.Set();\n                }\n                else if (eventArgs.Step == ConsensusStep.EndCommit)\n                {\n                    stepChangedToEndCommit.Set();\n                }\n            };\n            context.MessageToPublish += (_, message) =>\n            {\n                if (message is ConsensusProposalMsg proposalMsg)\n                {\n                    proposal = proposalMsg;\n                    proposedBlock = BlockMarshaler.UnmarshalBlock(\n                        (Dictionary)codec.Decode(proposalMsg!.Proposal.MarshaledBlock));\n                    proposalSent.Set();\n                }\n            };\n            context.ExceptionOccurred += (_, exception) =>\n            {\n                exceptionThrown = exception;\n                exceptionOccurred.Set();\n            };\n\n            context.Start();\n\n            await Task.WhenAll(stepChangedToPreVote.WaitAsync(), proposalSent.WaitAsync());\n\n            // Simulate bypass of context and block sync by swarm by\n            // directly appending to the blockchain.\n            Assert.NotNull(proposedBlock);\n            blockChain.Append(proposedBlock!, TestUtils.CreateBlockCommit(proposedBlock!));\n            Assert.Equal(2, blockChain.Tip.Index);\n\n            // Make PreVotes to normally move to PreCommit step.\n            foreach (int i in new int[] { 0, 1, 3 })\n            {\n                context.ProduceMessage(new ConsensusPreVoteMsg(new VoteMetadata(\n                    2,\n                    0,\n                    proposedBlock!.Hash,\n                    DateTimeOffset.UtcNow,\n                    TestUtils.PrivateKeys[i].PublicKey,\n                    TestUtils.ValidatorSet[i].Power,\n                    VoteFlag.PreVote).Sign(TestUtils.PrivateKeys[i])));\n            }\n\n            // Validator 2 will automatically vote its PreCommit.\n            foreach (int i in new int[] { 0, 1 })\n            {\n                context.ProduceMessage(new ConsensusPreCommitMsg(new VoteMetadata(\n                    2,\n                    0,\n                    proposedBlock!.Hash,\n                    DateTimeOffset.UtcNow,\n                    TestUtils.PrivateKeys[i].PublicKey,\n                    TestUtils.ValidatorSet[i].Power,\n                    VoteFlag.PreCommit).Sign(TestUtils.PrivateKeys[i])));\n            }\n\n            await stepChangedToEndCommit.WaitAsync();\n\n            // Check context has only three votes.\n            BlockCommit? commit = context.GetBlockCommit();\n            Assert.Equal(3, commit?.Votes.Where(vote => vote.Flag == VoteFlag.PreCommit).Count());\n\n            // Context should still accept new votes.\n            context.ProduceMessage(new ConsensusPreCommitMsg(new VoteMetadata(\n                2,\n                0,\n                proposedBlock!.Hash,\n                DateTimeOffset.UtcNow,\n                TestUtils.PrivateKeys[3].PublicKey,\n                TestUtils.ValidatorSet[3].Power,\n                VoteFlag.PreCommit).Sign(TestUtils.PrivateKeys[3])));\n\n            await Task.Delay(100);  // Wait for the new message to be added to the message log.\n            commit = context.GetBlockCommit();\n            Assert.Equal(4, commit?.Votes.Where(vote => vote.Flag == VoteFlag.PreCommit).Count());\n        }\n\n        [Fact(Timeout = Timeout)]\n        public async Task ThrowOnInvalidProposerMessage()\n        {\n            Exception? exceptionThrown = null;\n            var exceptionOccurred = new AsyncAutoResetEvent();\n\n            var (blockChain, context) = TestUtils.CreateDummyContext();\n            context.ExceptionOccurred += (_, e) =>\n            {\n                exceptionThrown = e;\n                exceptionOccurred.Set();\n            };\n            var block = blockChain.ProposeBlock(TestUtils.PrivateKeys[1]);\n\n            context.Start();\n            context.ProduceMessage(\n                TestUtils.CreateConsensusPropose(block, TestUtils.PrivateKeys[0]));\n            await exceptionOccurred.WaitAsync();\n            Assert.IsType<InvalidConsensusMessageException>(exceptionThrown);\n        }\n\n        [Fact(Timeout = Timeout)]\n        public async Task ThrowOnDifferentHeightMessage()\n        {\n            Exception? exceptionThrown = null;\n            var exceptionOccurred = new AsyncAutoResetEvent();\n\n            var (blockChain, context) = TestUtils.CreateDummyContext();\n            context.ExceptionOccurred += (_, e) =>\n            {\n                exceptionThrown = e;\n                exceptionOccurred.Set();\n            };\n            var block = blockChain.ProposeBlock(TestUtils.PrivateKeys[2]);\n\n            context.Start();\n            context.ProduceMessage(\n                TestUtils.CreateConsensusPropose(block, TestUtils.PrivateKeys[2], 2, 2));\n            await exceptionOccurred.WaitAsync();\n            Assert.IsType<InvalidConsensusMessageException>(exceptionThrown);\n\n            // Reset exception thrown.\n            exceptionThrown = null;\n            context.ProduceMessage(\n                new ConsensusPreVoteMsg(\n                    TestUtils.CreateVote(\n                        TestUtils.PrivateKeys[2],\n                        TestUtils.ValidatorSet[2].Power,\n                        2,\n                        0,\n                        block.Hash,\n                        VoteFlag.PreVote)));\n            await exceptionOccurred.WaitAsync();\n            Assert.IsType<InvalidConsensusMessageException>(exceptionThrown);\n        }\n\n        [Fact(Timeout = Timeout)]\n        public async Task CanPreCommitOnEndCommit()\n        {\n            var enteredPreVote = new AsyncAutoResetEvent();\n            var enteredPreCommit = new AsyncAutoResetEvent();\n            var enteredEndCommit = new AsyncAutoResetEvent();\n            var blockHeightOneAppended = new AsyncAutoResetEvent();\n            var enteredHeightTwo = new AsyncAutoResetEvent();\n\n            TimeSpan newHeightDelay = TimeSpan.FromSeconds(1);\n\n            var policy = new BlockPolicy(\n                new PolicyActionsRegistry(\n                    endBlockActions: ImmutableArray.Create<IAction>(new MinerReward(1))),\n                getMaxTransactionsBytes: _ => 50 * 1024);\n            var fx = new MemoryStoreFixture(policy.PolicyActionsRegistry);\n            var blockChain = Libplanet.Tests.TestUtils.MakeBlockChain(\n                policy,\n                fx.Store,\n                new TrieStateStore(new MemoryKeyValueStore()),\n                new SingleActionLoader(typeof(DelayAction)));\n\n            Context context = new Context(\n                blockChain,\n                1L,\n                null,\n                TestUtils.PrivateKeys[0],\n                blockChain\n                    .GetNextWorldState(0L)\n                    .GetValidatorSet(),\n                contextOption: new ContextOption());\n            context.MessageToPublish += (sender, message) => context.ProduceMessage(message);\n\n            context.StateChanged += (_, eventArgs) =>\n            {\n                if (eventArgs.Step == ConsensusStep.PreVote)\n                {\n                    enteredPreVote.Set();\n                }\n\n                if (eventArgs.Step == ConsensusStep.PreCommit)\n                {\n                    enteredPreCommit.Set();\n                }\n\n                if (eventArgs.Step == ConsensusStep.EndCommit)\n                {\n                    enteredEndCommit.Set();\n                }\n            };\n\n            blockChain.TipChanged += (_, eventArgs) =>\n            {\n                if (eventArgs.NewTip.Index == 1L)\n                {\n                    blockHeightOneAppended.Set();\n                }\n            };\n\n            var action = new DelayAction(100);\n            var tx = Transaction.Create(\n                nonce: 0,\n                privateKey: TestUtils.PrivateKeys[1],\n                genesisHash: blockChain.Genesis.Hash,\n                actions: new[] { action }.ToPlainValues());\n            blockChain.StageTransaction(tx);\n            var block = blockChain.ProposeBlock(TestUtils.PrivateKeys[1]);\n\n            context.Start();\n            context.ProduceMessage(\n                TestUtils.CreateConsensusPropose(block, TestUtils.PrivateKeys[1]));\n\n            foreach (int i in new int[] { 1, 2, 3 })\n            {\n                context.ProduceMessage(\n                    new ConsensusPreVoteMsg(\n                        new VoteMetadata(\n                            1,\n                            0,\n                            block.Hash,\n                            DateTimeOffset.UtcNow,\n                            TestUtils.PrivateKeys[i].PublicKey,\n                            TestUtils.ValidatorSet[i].Power,\n                            VoteFlag.PreVote).Sign(TestUtils.PrivateKeys[i])));\n            }\n\n            // Two additional votes should be enough to reach a consensus.\n            foreach (int i in new int[] { 1, 2 })\n            {\n                context.ProduceMessage(\n                    new ConsensusPreCommitMsg(\n                        new VoteMetadata(\n                            1,\n                            0,\n                            block.Hash,\n                            DateTimeOffset.UtcNow,\n                            TestUtils.PrivateKeys[i].PublicKey,\n                            TestUtils.ValidatorSet[i].Power,\n                            VoteFlag.PreCommit).Sign(TestUtils.PrivateKeys[i])));\n            }\n\n            await blockHeightOneAppended.WaitAsync();\n            Assert.Equal(\n                3,\n                context.GetBlockCommit()!.Votes.Count(vote => vote.Flag == VoteFlag.PreCommit));\n\n            Assert.True(enteredPreVote.IsSet);\n            Assert.True(enteredPreCommit.IsSet);\n            Assert.True(enteredEndCommit.IsSet);\n\n            // Add the last vote and wait for it to be consumed.\n            context.ProduceMessage(\n                new ConsensusPreCommitMsg(\n                    new VoteMetadata(\n                        1,\n                        0,\n                        block.Hash,\n                        DateTimeOffset.UtcNow,\n                        TestUtils.PrivateKeys[3].PublicKey,\n                        BigInteger.One,\n                        VoteFlag.PreCommit).Sign(TestUtils.PrivateKeys[3])));\n            Thread.Sleep(10);\n            Assert.Equal(\n                4,\n                context.GetBlockCommit()!.Votes.Count(vote => vote.Flag == VoteFlag.PreCommit));\n        }\n\n        /// <summary>\n        /// <para>\n        /// This test tests whether a validator can discard received proposal\n        /// when another proposal has +2/3 votes and maj23 information.\n        /// This Can be happen in following scenario.\n        /// </para>\n        /// <para>\n        /// There exists 4 validators A B C and D, where D is attacker.\n        /// <list type=\"bullet\">\n        /// <item><description>\n        ///     Validator D sends the block X's proposal to validator A, and block Y's proposal to\n        ///     validator B and C, both blocks are valid.\n        /// </description></item>\n        /// <item><description>\n        ///     The validator A will broadcast block X's pre-vote and the validator C and D\n        ///     will broadcast block Y's pre-vote.\n        /// </description></item>\n        /// <item><description>\n        ///     The validator D sends block X's pre-vote to the validator A and B,\n        ///     and sends block Y's pre-vote to the validator C.\n        /// </description></item>\n        /// <item><description>\n        ///     The validator C will lock block Y and change its state to pre-commit state\n        ///     since 2/3+ pre-vote messages are collected.\n        /// </description></item>\n        ///     Round is increased and other validator proposes valid block, but there are no\n        ///     2/3+ validator to vote to the new valid block since 1/3 of them are locked in\n        ///     block Y.\n        /// <item><description>\n        /// </description></item>\n        /// </list>\n        /// </para>\n        /// <para>\n        /// So this test make one single candidate which is validator A in scenario above,\n        /// to check the validator A can replace its proposal from block X to block Y when\n        /// receiving <see cref=\"ConsensusMaj23Msg\"/> message from peer C or D.\n        /// </para>\n        /// </summary>\n        [Fact(Timeout = Timeout)]\n        public async Task CanReplaceProposal()\n        {\n            var codec = new Codec();\n            var privateKeys = Enumerable.Range(0, 4).Select(_ => new PrivateKey()).ToArray();\n            // Order keys as validator set's order to run test as intended.\n            privateKeys = privateKeys.OrderBy(key => key.Address).ToArray();\n            var proposer = privateKeys[1];\n            var key1 = privateKeys[2];\n            var key2 = privateKeys[3];\n            BigInteger proposerPower = TestUtils.ValidatorSet[1].Power;\n            BigInteger power1 = TestUtils.ValidatorSet[2].Power;\n            BigInteger power2 = TestUtils.ValidatorSet[3].Power;\n            var stepChanged = new AsyncAutoResetEvent();\n            var proposalModified = new AsyncAutoResetEvent();\n            var prevStep = ConsensusStep.Default;\n            BlockHash? prevProposal = null;\n            var validatorSet = new ValidatorSet(\n                new[]\n                {\n                    new Validator(privateKeys[0].PublicKey, 1),\n                    new Validator(proposer.PublicKey, 1),\n                    new Validator(key1.PublicKey, 1),\n                    new Validator(key2.PublicKey, 1),\n                }.ToList());\n\n            var (blockChain, context) = TestUtils.CreateDummyContext(\n                privateKey: privateKeys[0],\n                validatorSet: validatorSet);\n            var blockA = blockChain.ProposeBlock(\n                proposer,\n                lastCommit: blockChain.GetBlockCommit(blockChain.Tip.Hash));\n            var blockB = blockChain.ProposeBlock(\n                proposer,\n                lastCommit: blockChain.GetBlockCommit(blockChain.Tip.Hash));\n            context.StateChanged += (sender, state) =>\n            {\n                if (state.Step != prevStep)\n                {\n                    prevStep = state.Step;\n                    stepChanged.Set();\n                }\n\n                if (!state.Proposal.Equals(prevProposal))\n                {\n                    prevProposal = state.Proposal;\n                    proposalModified.Set();\n                }\n            };\n            context.Start();\n            await stepChanged.WaitAsync();\n            Assert.Equal(ConsensusStep.Propose, context.Step);\n\n            var proposalA = new ProposalMetadata(\n                1,\n                0,\n                DateTimeOffset.UtcNow,\n                proposer.PublicKey,\n                codec.Encode(blockA.MarshalBlock()),\n                -1).Sign(proposer);\n            var preVoteA2 = new ConsensusPreVoteMsg(\n                new VoteMetadata(\n                    1,\n                    0,\n                    blockA.Hash,\n                    DateTimeOffset.UtcNow,\n                    key2.PublicKey,\n                    power2,\n                    VoteFlag.PreVote).Sign(key2));\n            var proposalB = new ProposalMetadata(\n                1,\n                0,\n                DateTimeOffset.UtcNow,\n                proposer.PublicKey,\n                codec.Encode(blockB.MarshalBlock()),\n                -1).Sign(proposer);\n            var proposalAMsg = new ConsensusProposalMsg(proposalA);\n            var proposalBMsg = new ConsensusProposalMsg(proposalB);\n            context.ProduceMessage(proposalAMsg);\n            await proposalModified.WaitAsync();\n            Assert.Equal(proposalA, context.Proposal);\n\n            // Proposal B is ignored because proposal A is received first.\n            context.ProduceMessage(proposalBMsg);\n            Assert.Equal(proposalA, context.Proposal);\n            context.ProduceMessage(preVoteA2);\n\n            // Validator 1 (key1) collected +2/3 pre-vote messages,\n            // sends maj23 message to context.\n            var maj23 = new Maj23Metadata(\n                1,\n                0,\n                blockB.Hash,\n                DateTimeOffset.UtcNow,\n                key1.PublicKey,\n                VoteFlag.PreVote).Sign(key1);\n            context.AddMaj23(maj23);\n\n            var preVoteB0 = new ConsensusPreVoteMsg(\n                new VoteMetadata(\n                    1,\n                    0,\n                    blockB.Hash,\n                    DateTimeOffset.UtcNow,\n                    proposer.PublicKey,\n                    proposerPower,\n                    VoteFlag.PreVote).Sign(proposer));\n            var preVoteB1 = new ConsensusPreVoteMsg(\n                new VoteMetadata(\n                    1,\n                    0,\n                    blockB.Hash,\n                    DateTimeOffset.UtcNow,\n                    key1.PublicKey,\n                    power1,\n                    VoteFlag.PreVote).Sign(key1));\n            var preVoteB2 = new ConsensusPreVoteMsg(\n                new VoteMetadata(\n                    1,\n                    0,\n                    blockB.Hash,\n                    DateTimeOffset.UtcNow,\n                    key2.PublicKey,\n                    power2,\n                    VoteFlag.PreVote).Sign(key2));\n            context.ProduceMessage(preVoteB0);\n            context.ProduceMessage(preVoteB1);\n            context.ProduceMessage(preVoteB2);\n            await proposalModified.WaitAsync();\n            Assert.Null(context.Proposal);\n            context.ProduceMessage(proposalBMsg);\n            await proposalModified.WaitAsync();\n            Assert.Equal(\n                context.Proposal,\n                proposalBMsg.Proposal);\n            await stepChanged.WaitAsync();\n            await stepChanged.WaitAsync();\n            Assert.Equal(ConsensusStep.PreCommit, context.Step);\n            Assert.Equal(\n                blockB.Hash.ToString(),\n                JsonSerializer.Deserialize<ContextJson>(context.ToString()).valid_value);\n        }\n\n        [Fact(Timeout = Timeout)]\n        public async Task CanCreateContextWithLastingEvaluation()\n        {\n            var onTipChanged = new AsyncAutoResetEvent();\n            var enteredHeightTwo = new AsyncAutoResetEvent();\n\n            TimeSpan newHeightDelay = TimeSpan.FromMilliseconds(100);\n            int actionDelay = 2000;\n\n            var fx = new MemoryStoreFixture();\n            var blockChain = Libplanet.Tests.TestUtils.MakeBlockChain(\n                new BlockPolicy(),\n                fx.Store,\n                fx.StateStore,\n                new SingleActionLoader(typeof(DelayAction)));\n\n            var consensusContext = new ConsensusContext(\n                new TestUtils.DummyConsensusMessageHandler(message => { }),\n                blockChain,\n                TestUtils.PrivateKeys[0],\n                newHeightDelay,\n                new ContextOption());\n            Context context = consensusContext.CurrentContext;\n            context.MessageToPublish += (sender, message) => context.ProduceMessage(message);\n\n            blockChain.TipChanged += (_, eventArgs) =>\n            {\n                if (eventArgs.NewTip.Index == 1L)\n                {\n                    onTipChanged.Set();\n                }\n            };\n\n            consensusContext.StateChanged += (_, eventArgs) =>\n            {\n                if (consensusContext.Height == 2L)\n                {\n                    enteredHeightTwo.Set();\n                }\n            };\n\n            var action = new DelayAction(actionDelay);\n            var tx = Transaction.Create(\n                nonce: 0,\n                privateKey: TestUtils.PrivateKeys[1],\n                genesisHash: blockChain.Genesis.Hash,\n                actions: new[] { action }.ToPlainValues());\n            blockChain.StageTransaction(tx);\n            var block = blockChain.ProposeBlock(TestUtils.PrivateKeys[1]);\n\n            consensusContext.Start();\n            context.ProduceMessage(\n                TestUtils.CreateConsensusPropose(block, TestUtils.PrivateKeys[1]));\n\n            foreach (int i in new int[] { 1, 2, 3 })\n            {\n                context.ProduceMessage(\n                    new ConsensusPreVoteMsg(\n                        new VoteMetadata(\n                            1,\n                            0,\n                            block.Hash,\n                            DateTimeOffset.UtcNow,\n                            TestUtils.PrivateKeys[i].PublicKey,\n                            TestUtils.ValidatorSet[i].Power,\n                            VoteFlag.PreVote).Sign(TestUtils.PrivateKeys[i])));\n            }\n\n            foreach (int i in new int[] { 1, 2, 3 })\n            {\n                context.ProduceMessage(\n                    new ConsensusPreCommitMsg(\n                        new VoteMetadata(\n                            1,\n                            0,\n                            block.Hash,\n                            DateTimeOffset.UtcNow,\n                            TestUtils.PrivateKeys[i].PublicKey,\n                            TestUtils.ValidatorSet[i].Power,\n                            VoteFlag.PreCommit).Sign(TestUtils.PrivateKeys[i])));\n            }\n\n            Assert.Equal(1, consensusContext.Height);\n            var watch = Stopwatch.StartNew();\n            await onTipChanged.WaitAsync();\n            Assert.True(watch.ElapsedMilliseconds < (actionDelay * 0.5));\n            watch.Restart();\n\n            await enteredHeightTwo.WaitAsync();\n            Assert.Equal(\n                4,\n                context.GetBlockCommit()!.Votes.Count(\n                    vote => vote.Flag.Equals(VoteFlag.PreCommit)));\n            Assert.True(watch.ElapsedMilliseconds > (actionDelay * 0.5));\n            Assert.Equal(2, consensusContext.Height);\n        }\n\n        [Theory(Timeout = Timeout)]\n        [InlineData(0)]\n        [InlineData(100)]\n        [InlineData(500)]\n        public async Task CanCollectPreVoteAfterMajority(int delay)\n        {\n            var stepChangedToPreVote = new AsyncAutoResetEvent();\n            var stepChangedToPreCommit = new AsyncAutoResetEvent();\n            Block? proposedBlock = null;\n            int numPreVotes = 0;\n            var (_, context) = TestUtils.CreateDummyContext(\n                contextOption: new ContextOption(\n                    enterPreCommitDelay: delay));\n            context.StateChanged += (_, eventArgs) =>\n            {\n                if (eventArgs.Step == ConsensusStep.PreVote)\n                {\n                    stepChangedToPreVote.Set();\n                }\n                else if (eventArgs.Step == ConsensusStep.PreCommit)\n                {\n                    stepChangedToPreCommit.Set();\n                }\n            };\n            context.MessageToPublish += (_, message) =>\n            {\n                if (message is ConsensusProposalMsg proposalMsg)\n                {\n                    proposedBlock = BlockMarshaler.UnmarshalBlock(\n                        (Dictionary)new Codec().Decode(proposalMsg!.Proposal.MarshaledBlock));\n                }\n            };\n            context.VoteSetModified += (_, tuple) =>\n            {\n                if (tuple.Flag == VoteFlag.PreVote)\n                {\n                    numPreVotes = tuple.Votes.Count();\n                }\n            };\n            context.Start();\n            await stepChangedToPreVote.WaitAsync();\n            Assert.Equal(ConsensusStep.PreVote, context.Step);\n            if (proposedBlock is not { } block)\n            {\n                throw new XunitException(\"No proposal is made\");\n            }\n\n            for (int i = 0; i < 3; i++)\n            {\n                context.ProduceMessage(\n                    new ConsensusPreVoteMsg(\n                        new VoteMetadata(\n                            block.Index,\n                            0,\n                            block.Hash,\n                            DateTimeOffset.UtcNow,\n                            TestUtils.PrivateKeys[i].PublicKey,\n                            TestUtils.ValidatorSet[i].Power,\n                            VoteFlag.PreVote).Sign(TestUtils.PrivateKeys[i])));\n            }\n\n            // Send delayed PreVote message after sending preCommit message\n            var cts = new CancellationTokenSource();\n            const int preVoteDelay = 300;\n            _ = Task.Run(\n                async () =>\n                {\n                    await Task.Delay(preVoteDelay, cts.Token);\n                    context.ProduceMessage(\n                        new ConsensusPreVoteMsg(\n                            new VoteMetadata(\n                                block.Index,\n                                0,\n                                block.Hash,\n                                DateTimeOffset.UtcNow,\n                                TestUtils.PrivateKeys[3].PublicKey,\n                                TestUtils.ValidatorSet[3].Power,\n                                VoteFlag.PreVote).Sign(TestUtils.PrivateKeys[3])));\n                }, cts.Token);\n\n            await stepChangedToPreCommit.WaitAsync();\n            cts.Cancel();\n            Assert.Equal(delay < preVoteDelay ? 3 : 4, numPreVotes);\n        }\n\n        public struct ContextJson\n        {\n#pragma warning disable SA1300\n#pragma warning disable IDE1006\n            public string locked_value { get; set; }\n\n            public int locked_round { get; set; }\n\n            public string valid_value { get; set; }\n\n            public int valid_round { get; set; }\n#pragma warning restore IDE1006\n#pragma warning restore SA1300\n        }\n    }\n}\n"
  },
  {
    "path": "test/Libplanet.Net.Tests/Consensus/DuplicateVoteEvidenceTest.cs",
    "content": "#pragma warning disable S125\nusing System;\nusing System.Numerics;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing Bencodex;\nusing Bencodex.Types;\nusing Libplanet.Net.Consensus;\nusing Libplanet.Net.Messages;\nusing Libplanet.Types.Blocks;\nusing Libplanet.Types.Consensus;\nusing Serilog;\nusing Xunit;\nusing Xunit.Abstractions;\nusing static Libplanet.Net.Tests.Consensus.ConsensusContextUtils;\n\nnamespace Libplanet.Net.Tests.Consensus\n{\n    public class DuplicateVoteEvidenceTest\n    {\n        private const int Timeout = 30000;\n        private static readonly Codec _codec = new Codec();\n        private readonly ILogger _logger;\n\n        public DuplicateVoteEvidenceTest(ITestOutputHelper output)\n        {\n            const string outputTemplate =\n                \"{Timestamp:HH:mm:ss:ffffffZ} - {Message} {Exception}\";\n            Log.Logger = new LoggerConfiguration()\n                .MinimumLevel.Verbose()\n                .WriteTo.TestOutput(output, outputTemplate: outputTemplate)\n                .CreateLogger()\n                .ForContext<ConsensusContextTest>();\n\n            _logger = Log.ForContext<ConsensusContextTest>();\n        }\n\n        [Fact(Timeout = Timeout)]\n        public async Task Evidence_WithDuplicateVotes_Test()\n        {\n            var privateKeys = TestUtils.PrivateKeys;\n            var (blockChain, consensusContext) = TestUtils.CreateDummyConsensusContext(\n                TimeSpan.FromSeconds(1),\n                TestUtils.Policy,\n                null,\n                privateKeys[3]);\n\n            var consensusProposalMsgAt3Task = WaitUntilPublishedAsync<ConsensusProposalMsg>(\n                consensusContext: consensusContext,\n                height: 3,\n                cancellationToken: new CancellationTokenSource(Timeout).Token);\n            var consensusProposalMsgAt7Task = WaitUntilPublishedAsync<ConsensusProposalMsg>(\n                consensusContext: consensusContext,\n                height: 7,\n                cancellationToken: new CancellationTokenSource(Timeout).Token);\n            var block = blockChain.ProposeBlock(privateKeys[1]);\n            var blockCommit = TestUtils.CreateBlockCommit(block);\n            consensusContext.Start();\n            blockChain.Append(block, blockCommit);\n            block = blockChain.ProposeBlock(privateKeys[2], blockCommit);\n            blockChain.Append(block, TestUtils.CreateBlockCommit(block));\n\n            await consensusProposalMsgAt3Task;\n            var consensusProposalMsgAt3 = consensusProposalMsgAt3Task.Result;\n            var blockHash = consensusProposalMsgAt3.BlockHash;\n\n            consensusContext.HandleMessage(new ConsensusPreCommitMsg(TestUtils.CreateVote(\n                privateKey: privateKeys[0],\n                power: BigInteger.One,\n                height: 3,\n                round: 0,\n                hash: blockHash,\n                flag: VoteFlag.PreCommit)));\n            consensusContext.HandleMessage(new ConsensusPreCommitMsg(TestUtils.CreateVote(\n                privateKey: privateKeys[0],\n                power: BigInteger.One,\n                height: 3,\n                round: 0,\n                hash: new BlockHash(TestUtils.GetRandomBytes(BlockHash.Size)),\n                flag: VoteFlag.PreCommit)));\n            consensusContext.HandleMessage(new ConsensusPreCommitMsg(TestUtils.CreateVote(\n                privateKey: privateKeys[1],\n                power: BigInteger.One,\n                height: 3,\n                round: 0,\n                hash: blockHash,\n                flag: VoteFlag.PreCommit)));\n            consensusContext.HandleMessage(new ConsensusPreCommitMsg(TestUtils.CreateVote(\n                privateKey: privateKeys[2],\n                power: BigInteger.One,\n                height: 3,\n                round: 0,\n                hash: blockHash,\n                flag: VoteFlag.PreCommit)));\n\n            await WaitUntilHeightAsync(\n                consensusContext: consensusContext,\n                height: 4,\n                cancellationToken: new CancellationTokenSource(Timeout).Token);\n\n            Assert.Single(blockChain.GetPendingEvidence());\n            Assert.Equal(4, consensusContext.Height);\n            Assert.Equal(0, consensusContext.Round);\n\n            blockCommit = blockChain.GetBlockCommit(blockChain.Tip.Hash);\n            block = blockChain.ProposeBlock(privateKeys[0], blockCommit);\n            blockCommit = TestUtils.CreateBlockCommit(block);\n            blockChain.Append(block, blockCommit);\n\n            block = blockChain.ProposeBlock(privateKeys[1], blockCommit);\n            blockCommit = TestUtils.CreateBlockCommit(block);\n            blockChain.Append(block, blockCommit);\n\n            block = blockChain.ProposeBlock(privateKeys[2], blockCommit);\n            blockCommit = TestUtils.CreateBlockCommit(block);\n            blockChain.Append(block, blockCommit);\n\n            await consensusProposalMsgAt7Task;\n            var consensusProposalMsgAt7 = consensusProposalMsgAt7Task.Result;\n            Assert.NotNull(consensusProposalMsgAt3?.BlockHash);\n            var actualBlock = BlockMarshaler.UnmarshalBlock(\n                (Dictionary)_codec.Decode(consensusProposalMsgAt7.Proposal.MarshaledBlock));\n            Assert.Single(actualBlock.Evidence);\n        }\n\n        [Fact(Timeout = Timeout)]\n        public async Task IgnoreDifferentHeightVote()\n        {\n            var privateKeys = TestUtils.PrivateKeys;\n            var (blockChain, consensusContext) = TestUtils.CreateDummyConsensusContext(\n                TimeSpan.FromSeconds(1),\n                TestUtils.Policy,\n                actionLoader: null,\n                privateKeys[3]);\n\n            var consensusProposalMsgAt3Task = WaitUntilPublishedAsync<ConsensusProposalMsg>(\n                consensusContext: consensusContext,\n                height: 3,\n                cancellationToken: new CancellationTokenSource(Timeout).Token);\n            var block = blockChain.ProposeBlock(privateKeys[1]);\n            var blockCommit = TestUtils.CreateBlockCommit(block);\n            consensusContext.Start();\n            blockChain.Append(block, blockCommit);\n            block = blockChain.ProposeBlock(privateKeys[2], blockCommit);\n            blockChain.Append(block, TestUtils.CreateBlockCommit(block));\n\n            await consensusProposalMsgAt3Task;\n            var consensusProposalMsgAt3 = consensusProposalMsgAt3Task.Result;\n            var blockHash = consensusProposalMsgAt3.BlockHash;\n\n            consensusContext.HandleMessage(new ConsensusPreCommitMsg(TestUtils.CreateVote(\n                privateKey: privateKeys[0],\n                power: BigInteger.One,\n                height: 3,\n                round: 0,\n                hash: blockHash,\n                flag: VoteFlag.PreCommit)));\n            consensusContext.HandleMessage(new ConsensusPreCommitMsg(TestUtils.CreateVote(\n                privateKey: privateKeys[0],\n                power: BigInteger.One,\n                height: 4,\n                round: 0,\n                hash: new BlockHash(TestUtils.GetRandomBytes(BlockHash.Size)),\n                flag: VoteFlag.PreCommit)));\n            consensusContext.HandleMessage(new ConsensusPreCommitMsg(TestUtils.CreateVote(\n                privateKey: privateKeys[1],\n                power: BigInteger.One,\n                height: 3,\n                round: 0,\n                hash: blockHash,\n                flag: VoteFlag.PreCommit)));\n            consensusContext.HandleMessage(new ConsensusPreCommitMsg(TestUtils.CreateVote(\n                privateKey: privateKeys[2],\n                power: BigInteger.One,\n                height: 3,\n                round: 0,\n                hash: blockHash,\n                flag: VoteFlag.PreCommit)));\n\n            await WaitUntilHeightAsync(\n                consensusContext: consensusContext,\n                height: 4,\n                cancellationToken: new CancellationTokenSource(Timeout).Token);\n\n            Assert.Empty(blockChain[3].Evidence);\n        }\n\n        [Fact(Timeout = Timeout)]\n        public async Task IgnoreDifferentRoundVote()\n        {\n            var privateKeys = TestUtils.PrivateKeys;\n            var (blockChain, consensusContext) = TestUtils.CreateDummyConsensusContext(\n                TimeSpan.FromSeconds(1),\n                TestUtils.Policy,\n                actionLoader: null,\n                TestUtils.PrivateKeys[3]);\n\n            var consensusProposalMsgAt3Task = WaitUntilPublishedAsync<ConsensusProposalMsg>(\n                consensusContext: consensusContext,\n                height: 3,\n                cancellationToken: new CancellationTokenSource(Timeout).Token);\n            var block = blockChain.ProposeBlock(privateKeys[1]);\n            var blockCommit = TestUtils.CreateBlockCommit(block);\n            consensusContext.Start();\n            blockChain.Append(block, blockCommit);\n            block = blockChain.ProposeBlock(privateKeys[2], blockCommit);\n            blockChain.Append(block, TestUtils.CreateBlockCommit(block));\n\n            await consensusProposalMsgAt3Task;\n            var consensusProposalMsgAt3 = consensusProposalMsgAt3Task.Result;\n            var blockHash = consensusProposalMsgAt3.BlockHash;\n\n            consensusContext.HandleMessage(new ConsensusPreCommitMsg(TestUtils.CreateVote(\n                privateKey: privateKeys[0],\n                power: BigInteger.One,\n                height: 3,\n                round: 0,\n                hash: blockHash,\n                flag: VoteFlag.PreCommit)));\n            consensusContext.HandleMessage(new ConsensusPreCommitMsg(TestUtils.CreateVote(\n                privateKey: privateKeys[0],\n                power: BigInteger.One,\n                height: 3,\n                round: 1,\n                hash: new BlockHash(TestUtils.GetRandomBytes(BlockHash.Size)),\n                flag: VoteFlag.PreCommit)));\n            consensusContext.HandleMessage(new ConsensusPreCommitMsg(TestUtils.CreateVote(\n                privateKey: privateKeys[1],\n                power: BigInteger.One,\n                height: 3,\n                round: 0,\n                hash: blockHash,\n                flag: VoteFlag.PreCommit)));\n            consensusContext.HandleMessage(new ConsensusPreCommitMsg(TestUtils.CreateVote(\n                privateKey: privateKeys[2],\n                power: BigInteger.One,\n                height: 3,\n                round: 0,\n                hash: blockHash,\n                flag: VoteFlag.PreCommit)));\n\n            await WaitUntilHeightAsync(\n                consensusContext: consensusContext,\n                height: 4,\n                cancellationToken: new CancellationTokenSource(Timeout).Token);\n\n            Assert.Empty(blockChain[3].Evidence);\n        }\n\n        [Fact(Timeout = Timeout)]\n        public async Task IgnoreDifferentFlagVote()\n        {\n            var privateKeys = TestUtils.PrivateKeys;\n            var (blockChain, consensusContext) = TestUtils.CreateDummyConsensusContext(\n                TimeSpan.FromSeconds(1),\n                TestUtils.Policy,\n                actionLoader: null,\n                privateKeys[3]);\n\n            var consensusProposalMsgAt3Task = WaitUntilPublishedAsync<ConsensusProposalMsg>(\n                consensusContext: consensusContext,\n                height: 3,\n                cancellationToken: new CancellationTokenSource(Timeout).Token);\n            var block = blockChain.ProposeBlock(privateKeys[1]);\n            var blockCommit = TestUtils.CreateBlockCommit(block);\n            consensusContext.Start();\n            blockChain.Append(block, blockCommit);\n            block = blockChain.ProposeBlock(privateKeys[2], blockCommit);\n            blockChain.Append(block, TestUtils.CreateBlockCommit(block));\n\n            await consensusProposalMsgAt3Task;\n            var consensusProposalMsgAt3 = consensusProposalMsgAt3Task.Result;\n            var blockHash = consensusProposalMsgAt3.BlockHash;\n\n            consensusContext.HandleMessage(new ConsensusPreCommitMsg(TestUtils.CreateVote(\n                privateKey: privateKeys[0],\n                power: BigInteger.One,\n                height: 3,\n                round: 0,\n                hash: blockHash,\n                flag: VoteFlag.PreCommit)));\n            consensusContext.HandleMessage(new ConsensusPreVoteMsg(TestUtils.CreateVote(\n                privateKey: privateKeys[0],\n                power: BigInteger.One,\n                height: 3,\n                round: 0,\n                hash: new BlockHash(TestUtils.GetRandomBytes(BlockHash.Size)),\n                flag: VoteFlag.PreVote)));\n            consensusContext.HandleMessage(new ConsensusPreCommitMsg(TestUtils.CreateVote(\n                privateKey: privateKeys[1],\n                power: BigInteger.One,\n                height: 3,\n                round: 0,\n                hash: blockHash,\n                flag: VoteFlag.PreCommit)));\n            consensusContext.HandleMessage(new ConsensusPreCommitMsg(TestUtils.CreateVote(\n                privateKey: privateKeys[2],\n                power: BigInteger.One,\n                height: 3,\n                round: 0,\n                hash: blockHash,\n                flag: VoteFlag.PreCommit)));\n\n            await WaitUntilHeightAsync(\n                consensusContext: consensusContext,\n                height: 4,\n                cancellationToken: new CancellationTokenSource(Timeout).Token);\n\n            Assert.Empty(blockChain[3].Evidence);\n        }\n\n        [Fact(Timeout = Timeout)]\n        public async Task IgnoreSameBlockHashVote()\n        {\n            var privateKeys = TestUtils.PrivateKeys;\n            var (blockChain, consensusContext) = TestUtils.CreateDummyConsensusContext(\n                TimeSpan.FromSeconds(1),\n                TestUtils.Policy,\n                actionLoader: null,\n                TestUtils.PrivateKeys[3]);\n\n            var consensusProposalMsgAt3Task = WaitUntilPublishedAsync<ConsensusProposalMsg>(\n                consensusContext: consensusContext,\n                height: 3,\n                cancellationToken: new CancellationTokenSource(Timeout).Token);\n            var block = blockChain.ProposeBlock(privateKeys[1]);\n            var blockCommit = TestUtils.CreateBlockCommit(block);\n            consensusContext.Start();\n            blockChain.Append(block, blockCommit);\n            block = blockChain.ProposeBlock(privateKeys[2], blockCommit);\n            blockChain.Append(block, TestUtils.CreateBlockCommit(block));\n\n            await consensusProposalMsgAt3Task;\n            var consensusProposalMsgAt3 = consensusProposalMsgAt3Task.Result;\n            var blockHash = consensusProposalMsgAt3.BlockHash;\n\n            consensusContext.HandleMessage(new ConsensusPreCommitMsg(TestUtils.CreateVote(\n                privateKey: privateKeys[0],\n                power: BigInteger.One,\n                height: 3,\n                round: 0,\n                hash: blockHash,\n                flag: VoteFlag.PreCommit)));\n            consensusContext.HandleMessage(new ConsensusPreCommitMsg(TestUtils.CreateVote(\n                privateKey: privateKeys[0],\n                power: BigInteger.One,\n                height: 3,\n                round: 0,\n                hash: blockHash,\n                flag: VoteFlag.PreCommit)));\n            consensusContext.HandleMessage(new ConsensusPreCommitMsg(TestUtils.CreateVote(\n                privateKey: privateKeys[1],\n                power: BigInteger.One,\n                height: 3,\n                round: 0,\n                hash: blockHash,\n                flag: VoteFlag.PreCommit)));\n            consensusContext.HandleMessage(new ConsensusPreCommitMsg(TestUtils.CreateVote(\n                privateKey: privateKeys[2],\n                power: BigInteger.One,\n                height: 3,\n                round: 0,\n                hash: blockHash,\n                flag: VoteFlag.PreCommit)));\n\n            await WaitUntilHeightAsync(\n                consensusContext: consensusContext,\n                height: 4,\n                cancellationToken: new CancellationTokenSource(Timeout).Token);\n\n            Assert.Empty(blockChain[3].Evidence);\n        }\n\n        [Fact(Timeout = Timeout)]\n        public async Task IgnoreNillVote()\n        {\n            var privateKeys = TestUtils.PrivateKeys;\n            var (blockChain, consensusContext) = TestUtils.CreateDummyConsensusContext(\n                TimeSpan.FromSeconds(1),\n                TestUtils.Policy,\n                actionLoader: null,\n                privateKeys[3]);\n\n            var consensusProposalMsgAt3Task = WaitUntilPublishedAsync<ConsensusProposalMsg>(\n                consensusContext: consensusContext,\n                height: 3,\n                cancellationToken: new CancellationTokenSource(Timeout).Token);\n            var block = blockChain.ProposeBlock(privateKeys[1]);\n            var blockCommit = TestUtils.CreateBlockCommit(block);\n            consensusContext.Start();\n            blockChain.Append(block, blockCommit);\n            block = blockChain.ProposeBlock(privateKeys[2], blockCommit);\n            blockChain.Append(block, TestUtils.CreateBlockCommit(block));\n\n            await consensusProposalMsgAt3Task;\n            var consensusProposalMsgAt3 = consensusProposalMsgAt3Task.Result;\n            var blockHash = consensusProposalMsgAt3.BlockHash;\n\n            consensusContext.HandleMessage(new ConsensusPreCommitMsg(TestUtils.CreateVote(\n                privateKey: privateKeys[0],\n                power: BigInteger.One,\n                height: 3,\n                round: 0,\n                hash: blockHash,\n                flag: VoteFlag.PreCommit)));\n            consensusContext.HandleMessage(new ConsensusPreCommitMsg(TestUtils.CreateVote(\n                privateKey: privateKeys[0],\n                power: BigInteger.One,\n                height: 3,\n                round: 0,\n                hash: default,\n                flag: VoteFlag.PreCommit)));\n            consensusContext.HandleMessage(new ConsensusPreCommitMsg(TestUtils.CreateVote(\n                privateKey: privateKeys[1],\n                power: BigInteger.One,\n                height: 3,\n                round: 0,\n                hash: blockHash,\n                flag: VoteFlag.PreCommit)));\n            consensusContext.HandleMessage(new ConsensusPreCommitMsg(TestUtils.CreateVote(\n                privateKey: privateKeys[2],\n                power: BigInteger.One,\n                height: 3,\n                round: 0,\n                hash: blockHash,\n                flag: VoteFlag.PreCommit)));\n\n            await WaitUntilHeightAsync(\n                consensusContext: consensusContext,\n                height: 4,\n                cancellationToken: new CancellationTokenSource(Timeout).Token);\n\n            Assert.Empty(blockChain[3].Evidence);\n        }\n    }\n}\n"
  },
  {
    "path": "test/Libplanet.Net.Tests/Consensus/GossipConsensusMessageCommunicatorTest.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Collections.Immutable;\nusing System.Linq;\nusing System.Net;\nusing System.Numerics;\nusing System.Threading.Tasks;\nusing Libplanet.Crypto;\nusing Libplanet.Net.Consensus;\nusing Libplanet.Net.Messages;\nusing Libplanet.Net.Options;\nusing Libplanet.Net.Transports;\nusing Libplanet.Tests.Store;\nusing Libplanet.Types.Consensus;\nusing NetMQ;\nusing Nito.AsyncEx;\nusing Serilog;\nusing Xunit;\nusing Xunit.Abstractions;\n\nnamespace Libplanet.Net.Tests.Consensus\n{\n    [Collection(\"NetMQConfiguration\")]\n    public class GossipConsensusMessageCommunicatorTest : IDisposable\n    {\n        private const int Timeout = 60 * 1000;\n        private readonly ILogger _logger;\n\n        public GossipConsensusMessageCommunicatorTest(ITestOutputHelper output)\n        {\n            const string outputTemplate =\n                \"{Timestamp:HH:mm:ss:ffffffZ} - {Message}\";\n            Log.Logger = new LoggerConfiguration()\n                .MinimumLevel.Verbose()\n                .WriteTo.TestOutput(output, outputTemplate: outputTemplate)\n                .CreateLogger()\n                .ForContext<GossipConsensusMessageCommunicatorTest>();\n\n            _logger = Log.ForContext<GossipConsensusMessageCommunicatorTest>();\n        }\n\n        public void Dispose()\n        {\n            NetMQConfig.Cleanup();\n        }\n\n        [Fact(Timeout = Timeout)]\n        public async void SendHigherMessage()\n        {\n            MemoryStoreFixture fx = new MemoryStoreFixture();\n            int nPreVoteReceived = 0;\n            var key1 = new PrivateKey();\n            var key2 = new PrivateKey();\n            var receivedPreVotes = new AsyncAutoResetEvent();\n            var receivedPreCommitFrom3 = new AsyncAutoResetEvent();\n            var communicator1 = CreateGossipConesnsusMessageCommunicator(\n                content => { },\n                key1,\n                6001,\n                new[] { new BoundPeer(key2.PublicKey, new DnsEndPoint(\"127.0.0.1\", 6002)) });\n            var communicator2 = CreateGossipConesnsusMessageCommunicator(\n                content =>\n                {\n                    if (content is ConsensusPreVoteMsg preVote)\n                    {\n                        nPreVoteReceived++;\n                        receivedPreVotes.Set();\n                    }\n                },\n                key2,\n                6002,\n                new[] { new BoundPeer(key1.PublicKey, new DnsEndPoint(\"127.0.0.1\", 6001)) });\n\n            try\n            {\n                _ = communicator1.Gossip.StartAsync(default);\n                _ = communicator2.Gossip.StartAsync(default);\n                await communicator1.Gossip.WaitForRunningAsync();\n                await communicator2.Gossip.WaitForRunningAsync();\n\n                communicator1.OnStartHeight(1);\n                communicator2.OnStartHeight(1);\n                communicator1.OnStartRound(2);\n                communicator2.OnStartRound(4);\n\n                // Add message of higher round to communicator1\n                communicator1.Gossip.AddMessage(\n                    new ConsensusPreVoteMsg(\n                        TestUtils.CreateVote(\n                            new PrivateKey(),\n                            BigInteger.One,\n                            1,\n                            3,\n                            fx.Hash1,\n                            VoteFlag.PreVote)));\n\n                // Add message of same round to communicator1\n                communicator1.Gossip.AddMessage(\n                    new ConsensusPreVoteMsg(\n                        TestUtils.CreateVote(\n                            new PrivateKey(),\n                            BigInteger.One,\n                            1,\n                            2,\n                            fx.Hash1,\n                            VoteFlag.PreVote)));\n\n                await receivedPreVotes.WaitAsync();\n                await Task.Delay(1500);\n\n                // Only message of same round has been transmitted,\n                // message of higher round has been rejected to be sent.\n                Assert.Equal(1, nPreVoteReceived);\n            }\n            finally\n            {\n                await communicator1.Gossip.StopAsync(TimeSpan.FromMilliseconds(100), default);\n                await communicator2.Gossip.StopAsync(TimeSpan.FromMilliseconds(100), default);\n                communicator1.Gossip.Dispose();\n                communicator2.Gossip.Dispose();\n            }\n        }\n\n        [Fact(Timeout = Timeout)]\n        public async void ReceiveHigherMessage()\n        {\n            MemoryStoreFixture fx = new MemoryStoreFixture();\n            int nHigherPreVoteReceived = 0;\n            int nValidPreVoteReceived = 0;\n            int nPreCommitReceived = 0;\n            var key1 = new PrivateKey();\n            var key2 = new PrivateKey();\n            var key3 = new PrivateKey();\n            var receivedTwoHigherPreVotes = new AsyncAutoResetEvent();\n            var receivedPreCommitFrom3 = new AsyncAutoResetEvent();\n\n            var communicator1 = CreateGossipConesnsusMessageCommunicator(\n                content =>\n                {\n                    if (content is ConsensusPreVoteMsg preVote)\n                    {\n                        if (preVote.Round > 2)\n                        {\n                            // If received message of higher round, counts.\n                            nHigherPreVoteReceived++;\n                            _logger.Debug($\"PreVote round({preVote.Round}) > 2 received, \" +\n                                $\" total: {nHigherPreVoteReceived}\");\n                        }\n                        else\n                        {\n                            // If received message of same or lower round, counts,\n                            nValidPreVoteReceived++;\n                        }\n\n                        if (nHigherPreVoteReceived >= 2)\n                        {\n                            // If received two higher round messages,\n                            // Spam filter logic will be activated on third\n                            // higher round message encounter.\n                            receivedTwoHigherPreVotes.Set();\n                        }\n                    }\n\n                    if (content is ConsensusPreCommitMsg preCommit)\n                    {\n                        nPreCommitReceived++;\n\n                        if (preCommit.Round == 2)\n                        {\n                            // Check if received message from communicator3.\n                            receivedPreCommitFrom3.Set();\n                        }\n                    }\n                },\n                key1,\n                6001);\n\n            var transport2 = CreateTransport(key2, 6002);\n            var transport3 = CreateTransport(key3, 6003);\n\n            async Task CheckDeniedAsync()\n            {\n                bool isPeer1Denied = false;\n                while (!isPeer1Denied)\n                {\n                    isPeer1Denied = communicator1.Gossip.DeniedPeers.Contains(transport2.AsPeer);\n                    await Task.Delay(200);\n                }\n            }\n\n            try\n            {\n                _ = communicator1.Gossip.StartAsync(default);\n                _ = transport2.StartAsync();\n                _ = transport3.StartAsync();\n                await communicator1.Gossip.WaitForRunningAsync();\n\n                communicator1.OnStartHeight(1);\n                communicator1.OnStartRound(2);\n\n                var peer1 = new BoundPeer[] { communicator1.Gossip.AsPeer };\n\n                // This message will be accepted, since its round is valid.\n                transport2.BroadcastMessage(\n                    peer1,\n                    new ConsensusPreVoteMsg(\n                        TestUtils.CreateVote(\n                            new PrivateKey(),\n                            BigInteger.One,\n                            1,\n                            2,\n                            fx.Hash1,\n                            VoteFlag.PreVote)));\n\n                // Higher round messages. These will trigger spam filter,\n                // and only two will be received.\n                transport2.BroadcastMessage(\n                    peer1,\n                    new ConsensusPreVoteMsg(\n                        TestUtils.CreateVote(\n                            new PrivateKey(),\n                            BigInteger.One,\n                            1,\n                            3,\n                            fx.Hash1,\n                            VoteFlag.PreVote)));\n                transport2.BroadcastMessage(\n                    peer1,\n                    new ConsensusPreVoteMsg(\n                        TestUtils.CreateVote(\n                            new PrivateKey(),\n                            BigInteger.One,\n                            1,\n                            4,\n                            fx.Hash1,\n                            VoteFlag.PreVote)));\n                // Higher round message. This will trigger spam filter, if encounter three times.\n                transport2.BroadcastMessage(\n                    peer1,\n                    new ConsensusPreVoteMsg(\n                        TestUtils.CreateVote(\n                            new PrivateKey(),\n                            BigInteger.One,\n                            1,\n                            5,\n                            fx.Hash1,\n                            VoteFlag.PreVote)));\n\n                // Wait for third higher round message encounter.\n                await receivedTwoHigherPreVotes.WaitAsync();\n                await CheckDeniedAsync();\n\n                // These messages will be rejected, since spam filter logic has been activated\n                // to communicator1, and gossip denies messages from it.\n                transport2.BroadcastMessage(\n                    peer1,\n                    new ConsensusPreVoteMsg(\n                        TestUtils.CreateVote(\n                            new PrivateKey(),\n                            BigInteger.One,\n                            1,\n                            1,\n                            fx.Hash1,\n                            VoteFlag.PreVote)));\n                transport2.BroadcastMessage(\n                    peer1,\n                    new ConsensusPreCommitMsg(\n                        TestUtils.CreateVote(\n                            new PrivateKey(),\n                            BigInteger.One,\n                            1,\n                            1,\n                            fx.Hash1,\n                            VoteFlag.PreCommit)));\n\n                // Since communicator3 wasn't denied, this message will be received without block.\n                transport3.BroadcastMessage(\n                    peer1,\n                    new ConsensusPreCommitMsg(\n                        TestUtils.CreateVote(\n                            new PrivateKey(),\n                            BigInteger.One,\n                            1,\n                            2,\n                            fx.Hash1,\n                            VoteFlag.PreCommit)));\n\n                // Wait for message from communicator1's precommit encounter,\n                // but this message will be rejected by spam filter logic.\n                await receivedPreCommitFrom3.WaitAsync();\n                await Task.Delay(1500);\n\n                // Accepted 1, Rejected 1\n                Assert.Equal(1, nValidPreVoteReceived);\n\n                // Accepted 2, Rejected 1\n                Assert.Equal(2, nHigherPreVoteReceived);\n\n                // Accepted 1, Rejected 1\n                Assert.Equal(1, nPreCommitReceived);\n            }\n            finally\n            {\n                await communicator1.Gossip.StopAsync(TimeSpan.FromMilliseconds(100), default);\n                await transport2.StopAsync(TimeSpan.FromMilliseconds(100), default);\n                await transport3.StopAsync(TimeSpan.FromMilliseconds(100), default);\n                communicator1.Gossip.Dispose();\n                transport2.Dispose();\n                transport3.Dispose();\n            }\n        }\n\n        private NetMQTransport CreateTransport(\n            PrivateKey? privateKey = null,\n            int? port = null)\n        {\n            var apvOptions = new AppProtocolVersionOptions\n            { AppProtocolVersion = TestUtils.AppProtocolVersion };\n            HostOptions hostOptions;\n            if (port is { } p)\n            {\n                hostOptions = new HostOptions(\"127.0.0.1\", Array.Empty<IceServer>(), p);\n            }\n            else\n            {\n                hostOptions = new HostOptions(\"127.0.0.1\", Array.Empty<IceServer>());\n            }\n\n            return NetMQTransport.Create(\n                privateKey ?? new PrivateKey(),\n                apvOptions,\n                hostOptions).ConfigureAwait(false).GetAwaiter().GetResult();\n        }\n\n        private GossipConsensusMessageCommunicator CreateGossipConesnsusMessageCommunicator(\n            Action<MessageContent> processMessage,\n            PrivateKey? privateKey = null,\n            int? port = null,\n            IEnumerable<BoundPeer>? peers = null,\n            IEnumerable<BoundPeer>? seeds = null)\n        {\n            var transport = CreateTransport(privateKey, port);\n\n            return new GossipConsensusMessageCommunicator(\n                transport,\n                peers?.ToImmutableArray() ?? ImmutableArray<BoundPeer>.Empty,\n                seeds?.ToImmutableArray() ?? ImmutableArray<BoundPeer>.Empty,\n                processMessage);\n        }\n    }\n}\n"
  },
  {
    "path": "test/Libplanet.Net.Tests/Consensus/GossipTest.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Collections.Immutable;\nusing System.Net;\nusing System.Threading.Tasks;\nusing Libplanet.Crypto;\nusing Libplanet.Net.Consensus;\nusing Libplanet.Net.Messages;\nusing Libplanet.Net.Options;\nusing Libplanet.Net.Transports;\nusing Libplanet.Tests.Store;\nusing NetMQ;\nusing Nito.AsyncEx;\nusing Serilog;\nusing Xunit;\nusing Xunit.Abstractions;\n\nnamespace Libplanet.Net.Tests.Consensus\n{\n    [Collection(\"NetMQConfiguration\")]\n    public class GossipTest : IDisposable\n    {\n        private const int Timeout = 60 * 1000;\n        private readonly ILogger _logger;\n\n        public GossipTest(ITestOutputHelper output)\n        {\n            const string outputTemplate =\n                \"{Timestamp:HH:mm:ss:ffffffZ} - {Message}\";\n            Log.Logger = new LoggerConfiguration()\n                .MinimumLevel.Verbose()\n                .WriteTo.TestOutput(output, outputTemplate: outputTemplate)\n                .CreateLogger()\n                .ForContext<GossipTest>();\n\n            _logger = Log.ForContext<GossipTest>();\n        }\n\n        public void Dispose()\n        {\n            NetMQConfig.Cleanup();\n        }\n\n        [Fact(Timeout = Timeout)]\n        public async void PublishMessage()\n        {\n            MemoryStoreFixture fx = new MemoryStoreFixture();\n            bool received1 = false;\n            bool received2 = false;\n            var key1 = new PrivateKey();\n            var key2 = new PrivateKey();\n            var receivedEvent = new AsyncAutoResetEvent();\n            var gossip1 = CreateGossip(\n                content =>\n                {\n                    if (content is ConsensusProposalMsg)\n                    {\n                        received1 = true;\n                    }\n                },\n                key1,\n                6001,\n                new[] { new BoundPeer(key2.PublicKey, new DnsEndPoint(\"127.0.0.1\", 6002)) });\n            var gossip2 = CreateGossip(\n                content =>\n                {\n                    if (content is ConsensusProposalMsg)\n                    {\n                        received2 = true;\n                        receivedEvent.Set();\n                    }\n                },\n                key2,\n                6002,\n                new[] { new BoundPeer(key1.PublicKey, new DnsEndPoint(\"127.0.0.1\", 6001)) });\n            try\n            {\n                _ = gossip1.StartAsync(default);\n                _ = gossip2.StartAsync(default);\n                await gossip1.WaitForRunningAsync();\n                await gossip2.WaitForRunningAsync();\n                gossip1.PublishMessage(\n                    TestUtils.CreateConsensusPropose(fx.Block1, new PrivateKey(), 0));\n                await receivedEvent.WaitAsync();\n                Assert.True(received1);\n                Assert.True(received2);\n            }\n            finally\n            {\n                await gossip1.StopAsync(TimeSpan.FromMilliseconds(100), default);\n                await gossip2.StopAsync(TimeSpan.FromMilliseconds(100), default);\n                gossip1.Dispose();\n                gossip2.Dispose();\n            }\n        }\n\n        [Fact(Timeout = Timeout)]\n        public async void AddMessage()\n        {\n            // It has no difference with PublishMessage() test,\n            // since two methods only has timing difference.\n            MemoryStoreFixture fx = new MemoryStoreFixture();\n            bool received1 = false;\n            bool received2 = false;\n            var key1 = new PrivateKey();\n            var key2 = new PrivateKey();\n            var receivedEvent = new AsyncAutoResetEvent();\n            var gossip1 = CreateGossip(\n                content =>\n                {\n                    if (content is ConsensusProposalMsg)\n                    {\n                        received1 = true;\n                    }\n                },\n                key1,\n                6001,\n                new[] { new BoundPeer(key2.PublicKey, new DnsEndPoint(\"127.0.0.1\", 6002)) });\n            var gossip2 = CreateGossip(\n                content =>\n                {\n                    if (content is ConsensusProposalMsg)\n                    {\n                        received2 = true;\n                        receivedEvent.Set();\n                    }\n                },\n                key2,\n                6002,\n                new[] { new BoundPeer(key1.PublicKey, new DnsEndPoint(\"127.0.0.1\", 6001)) });\n            try\n            {\n                _ = gossip1.StartAsync(default);\n                _ = gossip2.StartAsync(default);\n                await gossip1.WaitForRunningAsync();\n                await gossip2.WaitForRunningAsync();\n                gossip1.AddMessage(\n                    TestUtils.CreateConsensusPropose(fx.Block1, new PrivateKey(), 0));\n                await receivedEvent.WaitAsync();\n                Assert.True(received1);\n                Assert.True(received2);\n            }\n            finally\n            {\n                await gossip1.StopAsync(TimeSpan.FromMilliseconds(100), default);\n                await gossip2.StopAsync(TimeSpan.FromMilliseconds(100), default);\n                gossip1.Dispose();\n                gossip2.Dispose();\n            }\n        }\n\n        [Fact(Timeout = Timeout)]\n        public async void AddMessages()\n        {\n            MemoryStoreFixture fx = new MemoryStoreFixture();\n            int received1 = 0;\n            int received2 = 0;\n            var key1 = new PrivateKey();\n            var key2 = new PrivateKey();\n            var receivedEvent = new AsyncAutoResetEvent();\n            var gossip1 = CreateGossip(\n                content =>\n                {\n                    if (content is ConsensusProposalMsg)\n                    {\n                        received1++;\n                    }\n                },\n                key1,\n                6001,\n                new[] { new BoundPeer(key2.PublicKey, new DnsEndPoint(\"127.0.0.1\", 6002)) });\n            var gossip2 = CreateGossip(\n                content =>\n                {\n                    if (content is ConsensusProposalMsg)\n                    {\n                        received2++;\n                    }\n\n                    if (received2 == 4)\n                    {\n                        receivedEvent.Set();\n                    }\n                },\n                key2,\n                6002,\n                new[] { new BoundPeer(key1.PublicKey, new DnsEndPoint(\"127.0.0.1\", 6001)) });\n            try\n            {\n                _ = gossip1.StartAsync(default);\n                _ = gossip2.StartAsync(default);\n                await gossip1.WaitForRunningAsync();\n                await gossip2.WaitForRunningAsync();\n                PrivateKey key = new PrivateKey();\n                gossip1.AddMessages(\n                    new[]\n                    {\n                        TestUtils.CreateConsensusPropose(fx.Block1, key, 0),\n                        TestUtils.CreateConsensusPropose(fx.Block1, key, 1),\n                        TestUtils.CreateConsensusPropose(fx.Block1, key, 2),\n                        TestUtils.CreateConsensusPropose(fx.Block1, key, 3),\n                    });\n\n                await receivedEvent.WaitAsync();\n                Assert.Equal(4, received1);\n                Assert.Equal(4, received2);\n            }\n            finally\n            {\n                await gossip1.StopAsync(TimeSpan.FromMilliseconds(100), default);\n                await gossip2.StopAsync(TimeSpan.FromMilliseconds(100), default);\n                gossip1.Dispose();\n                gossip2.Dispose();\n            }\n        }\n\n        [Fact(Timeout = Timeout)]\n        public async void AddPeerWithHaveMessage()\n        {\n            var key1 = new PrivateKey();\n            var key2 = new PrivateKey();\n            var received = false;\n            var receivedEvent = new AsyncAutoResetEvent();\n            var transport1 = CreateTransport(key1, 6001);\n\n            async Task HandleMessage(Message message)\n            {\n                received = true;\n                receivedEvent.Set();\n                await Task.Yield();\n            }\n\n            transport1.ProcessMessageHandler.Register(HandleMessage);\n            var gossip = new Gossip(\n                transport1,\n                ImmutableArray<BoundPeer>.Empty,\n                ImmutableArray<BoundPeer>.Empty,\n                _ => { },\n                _ => { },\n                _ => { });\n            var transport2 = CreateTransport(key2, 6002);\n            try\n            {\n                _ = gossip.StartAsync(default);\n                _ = transport2.StartAsync(default);\n                await gossip.WaitForRunningAsync();\n                await transport2.WaitForRunningAsync();\n\n                await transport2.SendMessageAsync(\n                    gossip.AsPeer,\n                    new HaveMessage(Array.Empty<MessageId>()),\n                    TimeSpan.FromSeconds(1),\n                    default);\n\n                await receivedEvent.WaitAsync();\n                Assert.True(received);\n                Assert.Contains(transport2.AsPeer, gossip.Peers);\n            }\n            finally\n            {\n                await gossip.StopAsync(TimeSpan.FromMilliseconds(100), default);\n                await transport2.StopAsync(TimeSpan.FromMilliseconds(100), default);\n                gossip.Dispose();\n                transport2.Dispose();\n            }\n        }\n\n        [Fact(Timeout = Timeout)]\n        public async void DoNotBroadcastToSeedPeers()\n        {\n            bool received = false;\n            async Task ProcessMessage(Message msg)\n            {\n                if (msg.Content is HaveMessage)\n                {\n                    received = true;\n                }\n\n                await Task.CompletedTask;\n            }\n\n            ITransport seed = CreateTransport();\n            seed.ProcessMessageHandler.Register(ProcessMessage);\n            Gossip gossip = CreateGossip(_ => { }, seeds: new[] { seed.AsPeer });\n\n            try\n            {\n                _ = seed.StartAsync();\n                _ = gossip.StartAsync(default);\n                await seed.WaitForRunningAsync();\n                await gossip.WaitForRunningAsync();\n                gossip.AddMessage(new PingMsg());\n\n                // Wait heartbeat interval * 2.\n                await Task.Delay(2 * 1000);\n                Assert.False(received);\n            }\n            finally\n            {\n                await seed.StopAsync(TimeSpan.FromMilliseconds(100), default);\n                await gossip.StopAsync(TimeSpan.FromMilliseconds(100), default);\n                seed.Dispose();\n                gossip.Dispose();\n            }\n        }\n\n        [Fact(Timeout = Timeout)]\n        public async void DoNotSendDuplicateMessageRequest()\n        {\n            int received = 0;\n            async Task ProcessMessage(Message msg)\n            {\n                if (msg.Content is WantMessage)\n                {\n                    received++;\n                }\n\n                await Task.CompletedTask;\n            }\n\n            Gossip receiver = CreateGossip(_ => { });\n            ITransport sender1 = CreateTransport();\n            sender1.ProcessMessageHandler.Register(ProcessMessage);\n            ITransport sender2 = CreateTransport();\n            sender2.ProcessMessageHandler.Register(ProcessMessage);\n\n            try\n            {\n                _ = receiver.StartAsync(default);\n                _ = sender1.StartAsync(default);\n                _ = sender2.StartAsync(default);\n                await receiver.WaitForRunningAsync();\n                await sender1.WaitForRunningAsync();\n                await sender2.WaitForRunningAsync();\n                var msg1 = new PingMsg();\n                var msg2 = new PongMsg();\n                await sender1.SendMessageAsync(\n                    receiver.AsPeer,\n                    new HaveMessage(new[] { msg1.Id, msg2.Id }),\n                    null,\n                    default);\n                await sender2.SendMessageAsync(\n                    receiver.AsPeer,\n                    new HaveMessage(new[] { msg1.Id, msg2.Id }),\n                    null,\n                    default);\n\n                // Wait heartbeat interval * 2.\n                await Task.Delay(2 * 1000);\n                Assert.Equal(1, received);\n            }\n            finally\n            {\n                await receiver.StopAsync(TimeSpan.FromMilliseconds(100), default);\n                await sender1.StopAsync(TimeSpan.FromMilliseconds(100), default);\n                await sender2.StopAsync(TimeSpan.FromMilliseconds(100), default);\n                receiver.Dispose();\n                sender1.Dispose();\n                sender2.Dispose();\n            }\n        }\n\n        private Gossip CreateGossip(\n            Action<MessageContent> processMessage,\n            PrivateKey? privateKey = null,\n            int? port = null,\n            IEnumerable<BoundPeer>? peers = null,\n            IEnumerable<BoundPeer>? seeds = null)\n        {\n            var transport = CreateTransport(privateKey, port);\n            return new Gossip(\n                transport,\n                peers?.ToImmutableArray() ?? ImmutableArray<BoundPeer>.Empty,\n                seeds?.ToImmutableArray() ?? ImmutableArray<BoundPeer>.Empty,\n                _ => { },\n                _ => { },\n                processMessage);\n        }\n\n        private NetMQTransport CreateTransport(\n            PrivateKey? privateKey = null,\n            int? port = null)\n        {\n            var apvOptions = new AppProtocolVersionOptions\n                { AppProtocolVersion = TestUtils.AppProtocolVersion };\n            HostOptions hostOptions;\n            if (port is { } p)\n            {\n                hostOptions = new HostOptions(\"127.0.0.1\", Array.Empty<IceServer>(), p);\n            }\n            else\n            {\n                hostOptions = new HostOptions(\"127.0.0.1\", Array.Empty<IceServer>());\n            }\n\n            return NetMQTransport.Create(\n                privateKey ?? new PrivateKey(),\n                apvOptions,\n                hostOptions).ConfigureAwait(false).GetAwaiter().GetResult();\n        }\n    }\n}\n"
  },
  {
    "path": "test/Libplanet.Net.Tests/Consensus/HeightVoteSetTest.cs",
    "content": "using System;\nusing System.Linq;\nusing System.Numerics;\nusing Libplanet.Blockchain;\nusing Libplanet.Crypto;\nusing Libplanet.Net.Consensus;\nusing Libplanet.Types.Blocks;\nusing Libplanet.Types.Consensus;\nusing Libplanet.Types.Evidence;\nusing Xunit;\n\nnamespace Libplanet.Net.Tests.Consensus\n{\n    public class HeightVoteSetTest\n    {\n        private static Bencodex.Codec _codec = new Bencodex.Codec();\n        private BlockChain _blockChain;\n        private BlockCommit _lastCommit;\n        private HeightVoteSet _heightVoteSet;\n\n        /// <summary>\n        /// Sets up a <see cref=\"BlockChain\"/> with tip index of 1, i.e. two blocks.\n        /// </summary>\n        public HeightVoteSetTest()\n        {\n            _blockChain = TestUtils.CreateDummyBlockChain();\n            var block = _blockChain.ProposeBlock(TestUtils.PrivateKeys[1]);\n            _lastCommit = TestUtils.CreateBlockCommit(block);\n            _heightVoteSet = new HeightVoteSet(2, TestUtils.ValidatorSet);\n            _blockChain.Append(block, TestUtils.CreateBlockCommit(block));\n        }\n\n        [Fact]\n        public void CannotAddDifferentHeight()\n        {\n            var preVote = new VoteMetadata(\n                3,\n                0,\n                default,\n                DateTimeOffset.UtcNow,\n                TestUtils.PrivateKeys[0].PublicKey,\n                TestUtils.ValidatorSet[0].Power,\n                VoteFlag.PreVote).Sign(TestUtils.PrivateKeys[0]);\n\n            Assert.Throws<InvalidVoteException>(() => _heightVoteSet.AddVote(preVote));\n        }\n\n        [Fact]\n        public void CannotAddUnknownValidator()\n        {\n            var key = new PrivateKey();\n            var preVote = new VoteMetadata(\n                2,\n                0,\n                default,\n                DateTimeOffset.UtcNow,\n                key.PublicKey,\n                BigInteger.One,\n                VoteFlag.PreVote).Sign(key);\n\n            Assert.Throws<InvalidVoteException>(() => _heightVoteSet.AddVote(preVote));\n        }\n\n        [Fact]\n        public void CannotAddValidatorWithInvalidPower()\n        {\n            var preVote = new VoteMetadata(\n                2,\n                0,\n                default,\n                DateTimeOffset.UtcNow,\n                TestUtils.ValidatorSet[0].PublicKey,\n                TestUtils.ValidatorSet[0].Power + 1,\n                VoteFlag.PreVote).Sign(TestUtils.PrivateKeys[0]);\n\n            Assert.Throws<InvalidVoteException>(() => _heightVoteSet.AddVote(preVote));\n        }\n\n        [Fact]\n        public void CannotAddMultipleVotesPerRoundPerValidator()\n        {\n            Random random = new Random();\n            var preVote0 = new VoteMetadata(\n                2,\n                0,\n                default,\n                DateTimeOffset.UtcNow,\n                TestUtils.PrivateKeys[0].PublicKey,\n                TestUtils.ValidatorSet[0].Power,\n                VoteFlag.PreVote).Sign(TestUtils.PrivateKeys[0]);\n            var preVote1 = new VoteMetadata(\n                2,\n                0,\n                new BlockHash(TestUtils.GetRandomBytes(BlockHash.Size)),\n                DateTimeOffset.UtcNow,\n                TestUtils.PrivateKeys[0].PublicKey,\n                TestUtils.ValidatorSet[0].Power,\n                VoteFlag.PreVote).Sign(TestUtils.PrivateKeys[0]);\n            var preCommit0 = new VoteMetadata(\n                2,\n                0,\n                default,\n                DateTimeOffset.UtcNow,\n                TestUtils.PrivateKeys[0].PublicKey,\n                TestUtils.ValidatorSet[0].Power,\n                VoteFlag.PreCommit).Sign(TestUtils.PrivateKeys[0]);\n            var preCommit1 = new VoteMetadata(\n                2,\n                0,\n                new BlockHash(TestUtils.GetRandomBytes(BlockHash.Size)),\n                DateTimeOffset.UtcNow,\n                TestUtils.PrivateKeys[0].PublicKey,\n                TestUtils.ValidatorSet[0].Power,\n                VoteFlag.PreCommit).Sign(TestUtils.PrivateKeys[0]);\n\n            _heightVoteSet.AddVote(preVote0);\n            Assert.Throws<DuplicateVoteException>(() => _heightVoteSet.AddVote(preVote1));\n            _heightVoteSet.AddVote(preCommit0);\n            Assert.Throws<DuplicateVoteException>(\n                () => _heightVoteSet.AddVote(preCommit1));\n        }\n\n        [Fact]\n        public void CannotAddVoteWithoutValidatorPower()\n        {\n            var preVote = new VoteMetadata(\n                2,\n                0,\n                default,\n                DateTimeOffset.UtcNow,\n                TestUtils.PrivateKeys[0].PublicKey,\n                null,\n                VoteFlag.PreVote).Sign(TestUtils.PrivateKeys[0]);\n\n            var exception = Assert.Throws<InvalidVoteException>(\n                () => _heightVoteSet.AddVote(preVote));\n            Assert.Equal(\"ValidatorPower of the vote cannot be null\", exception.Message);\n        }\n\n        [Fact]\n        public void GetCount()\n        {\n            var preVotes = Enumerable.Range(0, TestUtils.PrivateKeys.Count)\n                .Select(\n                    index => new VoteMetadata(\n                            2,\n                            0,\n                            default,\n                            DateTimeOffset.UtcNow,\n                            TestUtils.PrivateKeys[index].PublicKey,\n                            TestUtils.ValidatorSet[index].Power,\n                            VoteFlag.PreVote)\n                        .Sign(TestUtils.PrivateKeys[index]))\n                .ToList();\n            var preCommit = new VoteMetadata(\n                    2,\n                    0,\n                    default,\n                    DateTimeOffset.UtcNow,\n                    TestUtils.PrivateKeys[0].PublicKey,\n                    TestUtils.ValidatorSet[0].Power,\n                    VoteFlag.PreCommit)\n                .Sign(TestUtils.PrivateKeys[0]);\n\n            foreach (var preVote in preVotes)\n            {\n                _heightVoteSet.AddVote(preVote);\n            }\n\n            _heightVoteSet.AddVote(preCommit);\n\n            Assert.Equal(5, _heightVoteSet.Count);\n        }\n    }\n}\n"
  },
  {
    "path": "test/Libplanet.Net.Tests/Consensus/MessageCacheTest.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing Libplanet.Net.Consensus;\nusing Libplanet.Net.Messages;\nusing Xunit;\n\nnamespace Libplanet.Net.Tests.Consensus\n{\n    public class MessageCacheTest\n    {\n        [Fact]\n        public void Put()\n        {\n            var cache = new MessageCache();\n            var msg = new PingMsg();\n            cache.Put(msg);\n            Assert.Throws<ArgumentException>(\"message\", () => cache.Put(msg));\n        }\n\n        [Fact]\n        public void Get()\n        {\n            var cache = new MessageCache();\n            var messageId = TestUtils.GetRandomBytes(MessageId.Size);\n            // Had to use HaveMessage for testing the persistent dataFrame.\n            var msg = new HaveMessage(new[] { messageId });\n            Assert.Throws<KeyNotFoundException>(() => cache.Get(msg.Id));\n            cache.Put(msg);\n            var ret = cache.Get(msg.Id);\n            Assert.NotEqual(ret, msg);\n\n            // Message data is persistent\n            Assert.Equal(msg.Type, ret.Type);\n            Assert.Equal(msg.Ids, ((HaveMessage)ret).Ids);\n        }\n    }\n}\n"
  },
  {
    "path": "test/Libplanet.Net.Tests/Consensus/VoteSetTest.cs",
    "content": "using System;\nusing Libplanet.Net.Consensus;\nusing Libplanet.Types.Blocks;\nusing Libplanet.Types.Consensus;\nusing Xunit;\n\nnamespace Libplanet.Net.Tests.Consensus\n{\n    public class VoteSetTest\n    {\n        [Fact]\n        public void Majority()\n        {\n            var voteSet = new VoteSet(0, 0, VoteFlag.PreCommit, TestUtils.ValidatorSet);\n            Assert.False(voteSet.HasOneThirdsAny());\n            Assert.False(voteSet.HasTwoThirdsAny());\n            Assert.False(voteSet.HasTwoThirdsMajority());\n            Assert.False(voteSet.TwoThirdsMajority(out var hash0));\n            Assert.Equal(default, hash0);\n\n            var blockHash = new BlockHash(TestUtils.GetRandomBytes(BlockHash.Size));\n            voteSet.AddVote(new VoteMetadata(\n                0,\n                0,\n                blockHash,\n                DateTimeOffset.UtcNow,\n                TestUtils.ValidatorSet[0].PublicKey,\n                TestUtils.ValidatorSet[0].Power,\n                VoteFlag.PreCommit).Sign(TestUtils.PrivateKeys[0]));\n            Assert.False(voteSet.HasOneThirdsAny());\n            Assert.False(voteSet.HasTwoThirdsAny());\n            Assert.False(voteSet.HasTwoThirdsMajority());\n            Assert.False(voteSet.TwoThirdsMajority(out var hash1));\n            Assert.Equal(default, hash1);\n\n            voteSet.AddVote(new VoteMetadata(\n                0,\n                0,\n                blockHash,\n                DateTimeOffset.UtcNow,\n                TestUtils.ValidatorSet[1].PublicKey,\n                TestUtils.ValidatorSet[1].Power,\n                VoteFlag.PreCommit).Sign(TestUtils.PrivateKeys[1]));\n            Assert.True(voteSet.HasOneThirdsAny());\n            Assert.False(voteSet.HasTwoThirdsAny());\n            Assert.False(voteSet.HasTwoThirdsMajority());\n            Assert.False(voteSet.TwoThirdsMajority(out var hash2));\n            Assert.Equal(default, hash2);\n\n            voteSet.AddVote(new VoteMetadata(\n                0,\n                0,\n                new BlockHash(TestUtils.GetRandomBytes(BlockHash.Size)),\n                DateTimeOffset.UtcNow,\n                TestUtils.ValidatorSet[2].PublicKey,\n                TestUtils.ValidatorSet[2].Power,\n                VoteFlag.PreCommit).Sign(TestUtils.PrivateKeys[2]));\n            Assert.True(voteSet.HasOneThirdsAny());\n            Assert.True(voteSet.HasTwoThirdsAny());\n            Assert.False(voteSet.HasTwoThirdsMajority());\n            Assert.False(voteSet.TwoThirdsMajority(out var hash3));\n            Assert.Equal(default, hash3);\n\n            voteSet.AddVote(new VoteMetadata(\n                0,\n                0,\n                blockHash,\n                DateTimeOffset.UtcNow,\n                TestUtils.ValidatorSet[3].PublicKey,\n                TestUtils.ValidatorSet[3].Power,\n                VoteFlag.PreCommit).Sign(TestUtils.PrivateKeys[3]));\n            Assert.True(voteSet.HasOneThirdsAny());\n            Assert.True(voteSet.HasTwoThirdsAny());\n            Assert.True(voteSet.HasTwoThirdsMajority());\n            Assert.True(voteSet.TwoThirdsMajority(out var hash4));\n            Assert.Equal(blockHash, hash4);\n        }\n    }\n}\n"
  },
  {
    "path": "test/Libplanet.Net.Tests/FactOnlyTurnAvailableAttribute.cs",
    "content": "#nullable disable\nusing System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing xRetry;\n\nnamespace Libplanet.Net.Tests\n{\n    public sealed class FactOnlyTurnAvailableAttribute : RetryFactAttribute\n    {\n        public const string TurnUrlsVarName = \"TURN_SERVER_URLS\";\n\n        public static readonly IReadOnlyList<Uri> TurnUris =\n            (Environment.GetEnvironmentVariable(TurnUrlsVarName) ?? string.Empty)\n                .Split(' ', '\\t', '\\r', '\\n')\n                .Where(s => s.Trim().Any()).Select(s => new Uri(s)).ToArray();\n\n        private static readonly Random _random = new Random();\n\n        private static readonly IceServer[] _iceServers = TurnUris\n            .Select(turnUri =>\n            {\n                try\n                {\n                    return new IceServer(url: turnUri);\n                }\n                catch (ArgumentNullException)\n                {\n                    return null;\n                }\n            })\n            .Where(s => !(s is null))\n            .ToArray();\n\n        public FactOnlyTurnAvailableAttribute(int maxRetries = 1, int delayBetweenRetriesMs = 0)\n            : base(maxRetries, delayBetweenRetriesMs)\n        {\n            if (!TurnUris.Any())\n            {\n                Skip =\n                    $\"Skipped as TURN/ICE servers are not configured; \" +\n                    $\"set the environment variable {TurnUrlsVarName} with \" +\n                    $\"space-separated TURN/ICE server URLs.\";\n            }\n            else if (!GetIceServers().Any())\n            {\n                Skip = \"Available only when any TURN/ICE server is running.\";\n            }\n        }\n\n        public static Uri GetTurnUri() =>\n            TurnUris[_random.Next(TurnUris.Count)];\n\n        public static IReadOnlyList<IceServer> GetIceServers()\n        {\n            var list = new IceServer[_iceServers.Length];\n            Array.Copy(_iceServers, list, list.Length);\n\n            // Fisher–Yates shuffle\n            int n = list.Length;\n            while (n > 1)\n            {\n                n--;\n                int k = _random.Next(n + 1);\n                IceServer value = list[k];\n                list[k] = list[n];\n                list[n] = value;\n            }\n\n            return list;\n        }\n    }\n}\n"
  },
  {
    "path": "test/Libplanet.Net.Tests/IceServerTest.cs",
    "content": "#nullable disable\nusing System;\nusing System.Collections.Generic;\nusing System.Threading.Tasks;\nusing Libplanet.Stun;\nusing Xunit;\n\nnamespace Libplanet.Net.Tests\n{\n    public class IceServerTest\n    {\n        private const int Timeout = 60 * 1000;\n\n        [Fact]\n        public void ParseUrl()\n        {\n            string urlString;\n            IceServer iceServer;\n\n            urlString = \"turn://only.path.component\";\n            iceServer = new IceServer(urlString);\n            Assert.Empty(iceServer.Username);\n            Assert.Empty(iceServer.Credential);\n\n            urlString = \"turn://@path.with.at.symbol\";\n            iceServer = new IceServer(urlString);\n            Assert.Empty(iceServer.Username);\n            Assert.Empty(iceServer.Credential);\n\n            urlString = \"turn://path@with.username\";\n            iceServer = new IceServer(urlString);\n            Assert.Equal(\"path\", iceServer.Username);\n            Assert.Empty(iceServer.Credential);\n\n            urlString = \"turn://username:@with.empty.credential\";\n            iceServer = new IceServer(urlString);\n            Assert.Equal(\"username\", iceServer.Username);\n            Assert.Empty(iceServer.Credential);\n\n            urlString = \"turn://:empty@username.with.credential\";\n            iceServer = new IceServer(urlString);\n            Assert.Empty(iceServer.Username);\n            Assert.Equal(\"empty\", iceServer.Credential);\n\n            urlString = \"turn://:@only.userinfo.separator\";\n            iceServer = new IceServer(urlString);\n            Assert.Empty(iceServer.Username);\n            Assert.Empty(iceServer.Credential);\n\n            urlString = \"turn://user:info@some.path\";\n            iceServer = new IceServer(urlString);\n            Assert.Equal(\"user\", iceServer.Username);\n            Assert.Equal(\"info\", iceServer.Credential);\n\n            urlString = \"turn://user:info:invalid@some.path\";\n            Assert.Throws<ArgumentException>(() => new IceServer(urlString));\n        }\n\n        [FactOnlyTurnAvailable(Timeout = Timeout)]\n        public async Task CreateTurnClient()\n        {\n            var turnUri = FactOnlyTurnAvailableAttribute.GetTurnUri();\n            var userInfo = turnUri.UserInfo.Split(':');\n            await Assert.ThrowsAsync<ArgumentException>(\n                async () => await TurnClient.Create(\n                    new[] { new IceServer(\"stun://stun.l.google.com:19302\") }));\n            var servers = new List<IceServer>()\n            {\n                new IceServer(\"turn://turn.does-not-exists.org\"),\n            };\n\n            await Assert.ThrowsAsync<IceServerException>(\n                async () => await TurnClient.Create(servers));\n\n            servers.Add(new IceServer(turnUri));\n            for (int i = 3; i > 0; i--)\n            {\n                TurnClient turnClient;\n                try\n                {\n                    turnClient = await TurnClient.Create(servers);\n                }\n                catch (IceServerException)\n                {\n                    // Try up to 3 times, as the servers are not well operational.\n                    if (i > 1)\n                    {\n                        await Task.Delay(1000);\n                        continue;\n                    }\n\n                    throw;\n                }\n\n                Assert.Equal(userInfo[0], turnClient.Username);\n                Assert.Equal(userInfo[1], turnClient.Password);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "test/Libplanet.Net.Tests/Libplanet.Net.Tests.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <PropertyGroup>\n    <TreatWarningsAsErrors>true</TreatWarningsAsErrors>\n    <NoWarn>$(NoWarn);SA1401;SYSLIB0011</NoWarn>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <PackageReference Include=\"Xunit.SkippableFact\" Version=\"1.3.12\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <ProjectReference Include=\"..\\..\\src\\Libplanet\\Libplanet.csproj\" />\n    <ProjectReference Include=\"..\\..\\src\\Libplanet.Net\\Libplanet.Net.csproj\" />\n    <ProjectReference Include=\"..\\..\\src\\Libplanet.Stun\\Libplanet.Stun.csproj\" />\n    <ProjectReference Include=\"..\\Libplanet.Tests\\Libplanet.Tests.csproj\" />\n  </ItemGroup>\n\n</Project>\n"
  },
  {
    "path": "test/Libplanet.Net.Tests/Messages/BlockHashesTest.cs",
    "content": "#nullable disable\nusing System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Net;\nusing Libplanet.Crypto;\nusing Libplanet.Net.Messages;\nusing Libplanet.Types.Blocks;\nusing NetMQ;\nusing Xunit;\n\nnamespace Libplanet.Net.Tests.Messages\n{\n    [Collection(\"NetMQConfiguration\")]\n    public class BlockHashesTest : IDisposable\n    {\n        public void Dispose()\n        {\n            NetMQConfig.Cleanup(false);\n        }\n\n        [Fact]\n        public void Decode()\n        {\n            BlockHash[] blockHashes = GenerateRandomBlockHashes(100L).ToArray();\n            var messageContent = new BlockHashesMsg(blockHashes);\n            Assert.Equal(blockHashes, messageContent.Hashes);\n            var privateKey = new PrivateKey();\n            AppProtocolVersion apv = AppProtocolVersion.Sign(privateKey, 3);\n            var peer = new BoundPeer(privateKey.PublicKey, new DnsEndPoint(\"0.0.0.0\", 1234));\n            var messageCodec = new NetMQMessageCodec();\n            NetMQMessage encoded = messageCodec.Encode(\n                new Message(\n                    messageContent,\n                    apv,\n                    peer,\n                    DateTimeOffset.UtcNow,\n                    null),\n                privateKey);\n            BlockHashesMsg restored = (BlockHashesMsg)messageCodec.Decode(encoded, true).Content;\n            Assert.Equal(messageContent.Hashes, restored.Hashes);\n        }\n\n        private static IEnumerable<BlockHash> GenerateRandomBlockHashes(long count)\n        {\n            var random = new Random();\n            var buffer = new byte[32];\n            for (long i = 0; i < count; i++)\n            {\n                random.NextBytes(buffer);\n                yield return new BlockHash(buffer);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "test/Libplanet.Net.Tests/Messages/MessageIdTest.cs",
    "content": "using System;\nusing System.Linq;\nusing Libplanet.Net.Messages;\nusing Xunit;\n\nnamespace Libplanet.Net.Tests.Messages\n{\n    public class MessageIdTest\n    {\n        [Fact]\n        public void MessageIdMustBe32Bytes()\n        {\n            for (int size = 0; size < 36; size++)\n            {\n                if (size == 32)\n                {\n                    continue;\n                }\n\n                byte[] bytes = GetRandomBytes(size);\n                Assert.Throws<ArgumentOutOfRangeException>(\n                    \"messageId\",\n                    () => new MessageId(bytes)\n                );\n            }\n        }\n\n        [Fact]\n        public void FromHex()\n        {\n            MessageId actual = MessageId.FromHex(\n                \"45a22187e2d8850bb357886958bc3e8560929ccc886958bc3e8560929ccc9ccc\");\n            var expected = new MessageId(\n                new byte[]\n                {\n                    0x45, 0xa2, 0x21, 0x87, 0xe2, 0xd8, 0x85, 0x0b, 0xb3, 0x57,\n                    0x88, 0x69, 0x58, 0xbc, 0x3e, 0x85, 0x60, 0x92, 0x9c, 0xcc,\n                    0x88, 0x69, 0x58, 0xbc, 0x3e, 0x85, 0x60, 0x92, 0x9c, 0xcc,\n                    0x9c, 0xcc,\n                }\n            );\n            Assert.Equal(expected, actual);\n\n            Assert.Throws<FormatException>(() => MessageId.FromHex(\"0g\"));\n            Assert.Throws<ArgumentOutOfRangeException>(\"hex\", () => MessageId.FromHex(\"1\"));\n            Assert.Throws<ArgumentOutOfRangeException>(\n                \"hex\",\n                () => MessageId.FromHex(\n                    \"45a22187e2d8850bb357886958bc3e8560929ccc886958bc3e8560929ccc9c\")\n            );\n            Assert.Throws<ArgumentOutOfRangeException>(\n                \"hex\",\n                () =>\n                    MessageId.FromHex(\n                        \"45a22187e2d8850bb357886958bc3e8560929ccc886958bc3e8560929ccc9ccc0\")\n            );\n            Assert.Throws<ArgumentOutOfRangeException>(\n                \"hex\",\n                () =>\n                    MessageId.FromHex(\n                        \"45a22187e2d8850bb357886958bc3e8560929ccc886958bc3e8560929ccc9ccc00\")\n            );\n        }\n\n        [Fact]\n        public void ToByteArray()\n        {\n            var bytes = GetRandomBytes(MessageId.Size);\n            var messageId = new MessageId(bytes);\n\n            Assert.Equal(bytes, messageId.ToByteArray());\n        }\n\n        [Fact]\n        public void ToByteArrayShouldNotExposeContents()\n        {\n            var id = new MessageId(\n                new byte[]\n                {\n                    0x45, 0xa2, 0x21, 0x87, 0xe2, 0xd8, 0x85, 0x0b, 0xb3, 0x57,\n                    0x88, 0x69, 0x58, 0xbc, 0x3e, 0x85, 0x60, 0x92, 0x9c, 0xcc,\n                    0x88, 0x69, 0x58, 0xbc, 0x3e, 0x85, 0x60, 0x92, 0x9c, 0xcc,\n                    0x9c, 0xcc,\n                }\n            );\n            id.ToByteArray()[0] = 0x00;\n            Assert.Equal(0x45, id.ToByteArray()[0]);\n        }\n\n        [Fact]\n        public void ToHex()\n        {\n            var id = new MessageId(\n                new byte[]\n                {\n                    0x45, 0xa2, 0x21, 0x87, 0xe2, 0xd8, 0x85, 0x0b, 0xb3, 0x57,\n                    0x88, 0x69, 0x58, 0xbc, 0x3e, 0x85, 0x60, 0x92, 0x9c, 0xcc,\n                    0x88, 0x69, 0x58, 0xbc, 0x3e, 0x85, 0x60, 0x92, 0x9c, 0xcc,\n                    0x9c, 0xcc,\n                }\n            );\n            Assert.Equal(\n                \"45a22187e2d8850bb357886958bc3e8560929ccc886958bc3e8560929ccc9ccc\",\n                id.ToHex()\n            );\n        }\n\n        [Fact]\n        public void ToString_()\n        {\n            var id = new MessageId(\n                new byte[]\n                {\n                    0x45, 0xa2, 0x21, 0x87, 0xe2, 0xd8, 0x85, 0x0b, 0xb3, 0x57,\n                    0x88, 0x69, 0x58, 0xbc, 0x3e, 0x85, 0x60, 0x92, 0x9c, 0xcc,\n                    0x88, 0x69, 0x58, 0xbc, 0x3e, 0x85, 0x60, 0x92, 0x9c, 0xcc,\n                    0x9c, 0xcc,\n                }\n            );\n            Assert.Equal(\n                \"45a22187e2d8850bb357886958bc3e8560929ccc886958bc3e8560929ccc9ccc\",\n                id.ToString()\n            );\n        }\n\n        [Fact]\n        public void Equals_()\n        {\n            var sameId1 = new MessageId(\n                new byte[]\n                {\n                    0x45, 0xa2, 0x21, 0x87, 0xe2, 0xd8, 0x85, 0x0b, 0xb3, 0x57,\n                    0x88, 0x69, 0x58, 0xbc, 0x3e, 0x85, 0x60, 0x92, 0x9c, 0xcc,\n                    0x88, 0x69, 0x58, 0xbc, 0x3e, 0x85, 0x60, 0x92, 0x9c, 0xcc,\n                    0x9c, 0xcc,\n                }\n            );\n            var sameId2 = new MessageId(\n                new byte[]\n                {\n                    0x45, 0xa2, 0x21, 0x87, 0xe2, 0xd8, 0x85, 0x0b, 0xb3, 0x57,\n                    0x88, 0x69, 0x58, 0xbc, 0x3e, 0x85, 0x60, 0x92, 0x9c, 0xcc,\n                    0x88, 0x69, 0x58, 0xbc, 0x3e, 0x85, 0x60, 0x92, 0x9c, 0xcc,\n                    0x9c, 0xcc,\n                }\n            );\n            var differentId = new MessageId(\n                new byte[]\n                {\n                    0x45, 0xa2, 0x21, 0x87, 0xe2, 0xd8, 0x85, 0x0b, 0xb3, 0x57,\n                    0x88, 0x69, 0x58, 0xbc, 0x3e, 0x85, 0x60, 0x92, 0x9c, 0x00,\n                    0x88, 0x69, 0x58, 0xbc, 0x3e, 0x85, 0x60, 0x92, 0x9c, 0x00,\n                    0x9c, 0x00,\n                }\n            );\n\n            Assert.Equal(sameId1, sameId2);\n            Assert.NotEqual(sameId2, differentId);\n\n            Assert.True(sameId1 == sameId2);\n            Assert.False(sameId2 == differentId);\n\n            Assert.False(sameId1 != sameId2);\n            Assert.True(sameId2 != differentId);\n        }\n\n        [Fact]\n        public void Compare()\n        {\n            var random = new Random();\n            var buffer = new byte[32];\n            MessageId[] ids = Enumerable.Repeat(0, 50).Select(_ =>\n            {\n                random.NextBytes(buffer);\n                return new MessageId(buffer);\n            }).ToArray();\n            for (int i = 1; i < ids.Length; i++)\n            {\n                MessageId left = ids[i - 1], right = ids[i];\n                string leftString = left.ToHex().ToLower(),\n                    rightString = right.ToHex().ToLower();\n                Assert.Equal(\n                    Math.Min(Math.Max(left.CompareTo(right), 1), -1),\n                    Math.Min(Math.Max(leftString.CompareTo(rightString), 1), -1)\n                );\n                Assert.Equal(\n                    left.CompareTo(right),\n                    (left as IComparable).CompareTo(right)\n                );\n            }\n\n            Assert.Throws<ArgumentNullException>(() =>\n                ids[0].CompareTo(null)\n            );\n            Assert.Throws<ArgumentException>(() =>\n                ids[0].CompareTo(\"invalid\")\n            );\n        }\n\n        private byte[] GetRandomBytes(int size)\n        {\n            var random = new Random();\n            var bytes = new byte[size];\n            random.NextBytes(bytes);\n            return bytes;\n        }\n    }\n}\n"
  },
  {
    "path": "test/Libplanet.Net.Tests/Messages/MessageTest.cs",
    "content": "using System;\nusing System.Collections.Immutable;\nusing System.Linq;\nusing System.Net;\nusing Libplanet.Common;\nusing Libplanet.Crypto;\nusing Libplanet.Net.Messages;\nusing Libplanet.Net.Transports;\nusing Libplanet.Types.Blocks;\nusing Libplanet.Types.Consensus;\nusing NetMQ;\nusing Xunit;\nusing static Libplanet.Tests.TestUtils;\n\nnamespace Libplanet.Net.Tests.Messages\n{\n    public class MessageTest\n    {\n        [Fact]\n        public void BlockHeaderMsg()\n        {\n            var privateKey = new PrivateKey();\n            var peer = new BoundPeer(privateKey.PublicKey, new DnsEndPoint(\"0.0.0.0\", 0));\n            var apv = new AppProtocolVersion(\n                1,\n                new Bencodex.Types.Integer(0),\n                ImmutableArray<byte>.Empty,\n                default(Address));\n            var dateTimeOffset = DateTimeOffset.UtcNow;\n            Block genesis = ProposeGenesisBlock(GenesisProposer);\n            var messageContent = new BlockHeaderMsg(genesis.Hash, genesis.Header);\n            var codec = new NetMQMessageCodec();\n            NetMQMessage raw = codec.Encode(\n                new Message(messageContent, apv, peer, dateTimeOffset, null), privateKey);\n            var parsed = codec.Decode(raw, true);\n            Assert.Equal(peer, parsed.Remote);\n        }\n\n        [Fact]\n        public void InvalidCredential()\n        {\n            var ping = new PingMsg();\n            var privateKey = new PrivateKey();\n            var apv = new AppProtocolVersion(\n                1,\n                new Bencodex.Types.Integer(0),\n                ImmutableArray<byte>.Empty,\n                default(Address));\n            var peer = new BoundPeer(privateKey.PublicKey, new DnsEndPoint(\"0.0.0.0\", 0));\n            var timestamp = DateTimeOffset.UtcNow;\n            var badPrivateKey = new PrivateKey();\n            var codec = new NetMQMessageCodec();\n            Assert.Throws<InvalidCredentialException>(() =>\n                codec.Encode(\n                    new Message(ping, apv, peer, timestamp, null), badPrivateKey));\n        }\n\n        [Fact]\n        public void UseInvalidSignature()\n        {\n            // Victim\n            var privateKey = new PrivateKey();\n            var peer = new BoundPeer(privateKey.PublicKey, new DnsEndPoint(\"0.0.0.0\", 0));\n            var timestamp = DateTimeOffset.UtcNow;\n            var apv = new AppProtocolVersion(\n                1,\n                new Bencodex.Types.Integer(0),\n                ImmutableArray<byte>.Empty,\n                default(Address));\n            var ping = new PingMsg();\n            var codec = new NetMQMessageCodec();\n            var netMqMessage = codec.Encode(\n                new Message(ping, apv, peer, timestamp, null), privateKey).ToArray();\n\n            // Attacker\n            var fakePeer = new BoundPeer(privateKey.PublicKey, new DnsEndPoint(\"1.2.3.4\", 0));\n            var fakeMessage = codec.Encode(\n                new Message(ping, apv, fakePeer, timestamp, null), privateKey).ToArray();\n\n            var frames = new NetMQMessage();\n            frames.Push(netMqMessage[4]);\n            frames.Push(netMqMessage[3]);\n            frames.Push(fakeMessage[2]);\n            frames.Push(netMqMessage[1]);\n            frames.Push(netMqMessage[0]);\n\n            Assert.Throws<InvalidMessageSignatureException>(() =>\n                codec.Decode(frames, true));\n        }\n\n        [Fact]\n        public void InvalidArguments()\n        {\n            var codec = new NetMQMessageCodec();\n            var message = new PingMsg();\n            var privateKey = new PrivateKey();\n            var apv = new AppProtocolVersion(\n                1,\n                new Bencodex.Types.Integer(0),\n                ImmutableArray<byte>.Empty,\n                default(Address));\n            Assert.Throws<ArgumentException>(\n                () => codec.Decode(new NetMQMessage(), true));\n        }\n\n        [Fact]\n        public void GetId()\n        {\n            var privateKey = new PrivateKey();\n            var peer = new BoundPeer(privateKey.PublicKey, new DnsEndPoint(\"1.2.3.4\", 1234));\n            var apv = new AppProtocolVersion(\n                1,\n                new Bencodex.Types.Integer(0),\n                ImmutableArray<byte>.Empty,\n                default(Address));\n            var dateTimeOffset = DateTimeOffset.MinValue + TimeSpan.FromHours(6.1234);\n            Block genesis = ProposeGenesisBlock(GenesisProposer);\n            var message = new BlockHeaderMsg(genesis.Hash, genesis.Header);\n            Assert.Equal(\n                new MessageId(ByteUtil.ParseHex(\n                    \"70b510a01be2ac0fbe87f69000e2d2b07cbd4dacf45b644c09f16f1490aafba4\")),\n                message.Id);\n        }\n\n        [Fact]\n        public void InvalidVoteFlagConsensus()\n        {\n            var blockHash = new BlockHash(TestUtils.GetRandomBytes(BlockHash.Size));\n\n            var preVote = TestUtils.CreateVote(\n                TestUtils.PrivateKeys[0],\n                TestUtils.ValidatorSet[0].Power,\n                1,\n                0,\n                blockHash,\n                VoteFlag.PreVote);\n\n            var preCommit = TestUtils.CreateVote(\n                TestUtils.PrivateKeys[0],\n                TestUtils.ValidatorSet[0].Power,\n                1,\n                0,\n                blockHash,\n                VoteFlag.PreCommit);\n\n            // Valid message cases\n            _ = new ConsensusPreVoteMsg(preVote);\n            _ = new ConsensusPreCommitMsg(preCommit);\n\n            // Invalid message cases\n            Assert.Throws<ArgumentException>(() => new ConsensusPreVoteMsg(preCommit));\n            Assert.Throws<ArgumentException>(() => new ConsensusPreCommitMsg(preVote));\n        }\n    }\n}\n"
  },
  {
    "path": "test/Libplanet.Net.Tests/Messages/MessageValidatorTest.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Collections.Immutable;\nusing System.Net;\nusing Libplanet.Crypto;\nusing Libplanet.Net.Messages;\nusing Libplanet.Net.Options;\nusing Libplanet.Net.Transports;\nusing Xunit;\n\nnamespace Libplanet.Net.Tests.Messages\n{\n    public class MessageValidatorTest\n    {\n        [Fact]\n        public void ValidateTimestamp()\n        {\n            var peer = new BoundPeer(new PrivateKey().PublicKey, new DnsEndPoint(\"0.0.0.0\", 0));\n            var buffer = TimeSpan.FromSeconds(1);\n            var apvOption = new AppProtocolVersionOptions();\n            var messageValidator = new MessageValidator(apvOption, buffer);\n\n            // Within buffer window is okay.\n            messageValidator.ValidateTimestamp(\n                new Message(\n                    new PingMsg(),\n                    apvOption.AppProtocolVersion,\n                    peer,\n                    DateTimeOffset.UtcNow + buffer.Divide(2),\n                    null));\n            messageValidator.ValidateTimestamp(\n                new Message(\n                    new PingMsg(),\n                    apvOption.AppProtocolVersion,\n                    peer,\n                    DateTimeOffset.UtcNow - buffer.Divide(2),\n                    null));\n\n            // Outside buffer throws an exception.\n            Assert.Throws<InvalidMessageTimestampException>(() =>\n                messageValidator.ValidateTimestamp(\n                    new Message(\n                        new PingMsg(),\n                        apvOption.AppProtocolVersion,\n                        peer,\n                        DateTimeOffset.UtcNow + buffer.Multiply(2),\n                        null)));\n            Assert.Throws<InvalidMessageTimestampException>(() =>\n                messageValidator.ValidateTimestamp(\n                    new Message(\n                        new PingMsg(),\n                        apvOption.AppProtocolVersion,\n                        peer,\n                        DateTimeOffset.UtcNow - buffer.Multiply(2),\n                        null)));\n\n            // If buffer is null, no exception gets thrown.\n            messageValidator = new MessageValidator(apvOption, null);\n            messageValidator.ValidateTimestamp(\n                new Message(\n                    new PingMsg(),\n                    apvOption.AppProtocolVersion,\n                    peer,\n                    DateTimeOffset.MaxValue,\n                    null));\n            messageValidator.ValidateTimestamp(\n                new Message(\n                    new PingMsg(),\n                    apvOption.AppProtocolVersion,\n                    peer,\n                    DateTimeOffset.MinValue,\n                    null));\n        }\n\n        [Fact]\n        public void ValidateAppProtocolVersion()\n        {\n            var random = new Random();\n            var identity = new byte[16];\n            random.NextBytes(identity);\n            var called = false;\n            var trustedSigner = new PrivateKey();\n            var unknownSigner = new PrivateKey();\n            var version1 = 1;\n            var version2 = 2;\n            var extra1 = new Bencodex.Types.Integer(13);\n            var extra2 = new Bencodex.Types.Integer(17);\n\n            DifferentAppProtocolVersionEncountered callback = (p, pv, lv) => { called = true; };\n            var peer = new BoundPeer(trustedSigner.PublicKey, new DnsEndPoint(\"0.0.0.0\", 0));\n\n            // Apv\n            var trustedApv = AppProtocolVersion.Sign(trustedSigner, version1, extra1);\n            var trustedDifferentVersionApv = AppProtocolVersion.Sign(\n                trustedSigner, version2, extra1);\n            var trustedDifferentExtraApv = AppProtocolVersion.Sign(trustedSigner, version1, extra2);\n            var unknownApv = AppProtocolVersion.Sign(unknownSigner, version1, extra1);\n            var unknownDifferentVersionApv = AppProtocolVersion.Sign(\n                unknownSigner, version2, extra1);\n            var unknownDifferentExtraApv = AppProtocolVersion.Sign(unknownSigner, version1, extra2);\n\n            // Signer\n            ImmutableHashSet<PublicKey>? trustedApvSigners =\n                new HashSet<PublicKey>() { trustedSigner.PublicKey }.ToImmutableHashSet();\n            ImmutableHashSet<PublicKey>? emptyApvSigners =\n                new HashSet<PublicKey>() { }.ToImmutableHashSet();\n\n            // Ping\n            var trustedPing = new Message(\n                new PingMsg(),\n                trustedApv,\n                peer,\n                DateTimeOffset.UtcNow,\n                null);\n            var trustedDifferentVersionPing = new Message(\n                new PingMsg(),\n                trustedDifferentVersionApv,\n                peer,\n                DateTimeOffset.UtcNow,\n                null);\n            var trustedDifferentExtraPing = new Message(\n                new PingMsg(),\n                trustedDifferentExtraApv,\n                peer,\n                DateTimeOffset.UtcNow,\n                null);\n            var unknownPing = new Message(\n                new PingMsg(),\n                unknownApv,\n                peer,\n                DateTimeOffset.UtcNow,\n                null);\n            var unknownDifferentVersionPing = new Message(\n                new PingMsg(),\n                unknownDifferentVersionApv,\n                peer,\n                DateTimeOffset.UtcNow,\n                null);\n            var unknownDifferentExtraPing = new Message(\n                new PingMsg(),\n                unknownDifferentExtraApv,\n                peer,\n                DateTimeOffset.UtcNow,\n                null);\n\n            DifferentAppProtocolVersionException exception;\n            AppProtocolVersionOptions appProtocolVersionOptions;\n            MessageValidator messageValidator;\n\n            // Trust specific signers.\n            appProtocolVersionOptions = new AppProtocolVersionOptions()\n            {\n                AppProtocolVersion = trustedApv,\n                TrustedAppProtocolVersionSigners = trustedApvSigners,\n                DifferentAppProtocolVersionEncountered = callback,\n            };\n\n            messageValidator = new MessageValidator(appProtocolVersionOptions, null);\n\n            // Check trust pings\n            messageValidator.ValidateAppProtocolVersion(trustedPing);\n            Assert.False(called);\n            exception = Assert.Throws<DifferentAppProtocolVersionException>(\n                () => messageValidator.ValidateAppProtocolVersion(trustedDifferentVersionPing));\n            Assert.True(exception.Trusted);\n            Assert.True(called);\n            called = false;\n            messageValidator.ValidateAppProtocolVersion(trustedDifferentExtraPing);\n            Assert.True(called);\n            called = false;\n\n            // Check unknown pings\n            exception = Assert.Throws<DifferentAppProtocolVersionException>(\n                () => messageValidator.ValidateAppProtocolVersion(unknownPing));\n            Assert.False(exception.Trusted);\n            Assert.False(called);\n            exception = Assert.Throws<DifferentAppProtocolVersionException>(\n                () => messageValidator.ValidateAppProtocolVersion(unknownDifferentVersionPing));\n            Assert.False(exception.Trusted);\n            Assert.False(called);\n            exception = Assert.Throws<DifferentAppProtocolVersionException>(\n                () => messageValidator.ValidateAppProtocolVersion(unknownDifferentExtraPing));\n            Assert.False(exception.Trusted);\n            Assert.False(called);\n\n            // Trust no one.\n            appProtocolVersionOptions = new AppProtocolVersionOptions()\n            {\n                AppProtocolVersion = trustedApv,\n                TrustedAppProtocolVersionSigners = emptyApvSigners,\n                DifferentAppProtocolVersionEncountered = callback,\n            };\n\n            messageValidator = new MessageValidator(appProtocolVersionOptions, null);\n\n            // Check trust pings\n            messageValidator.ValidateAppProtocolVersion(trustedPing);\n            Assert.False(called);\n            exception = Assert.Throws<DifferentAppProtocolVersionException>(\n                () => messageValidator.ValidateAppProtocolVersion(trustedDifferentVersionPing));\n            Assert.False(exception.Trusted);\n            Assert.False(called);\n            exception = Assert.Throws<DifferentAppProtocolVersionException>(\n                () => messageValidator.ValidateAppProtocolVersion(trustedDifferentExtraPing));\n            Assert.False(exception.Trusted);\n            Assert.False(called);\n\n            // Check unknown pings\n            exception = Assert.Throws<DifferentAppProtocolVersionException>(\n                () => messageValidator.ValidateAppProtocolVersion(unknownPing));\n            Assert.False(exception.Trusted);\n            Assert.False(called);\n            exception = Assert.Throws<DifferentAppProtocolVersionException>(\n                () => messageValidator.ValidateAppProtocolVersion(unknownDifferentVersionPing));\n            Assert.False(exception.Trusted);\n            Assert.False(called);\n            exception = Assert.Throws<DifferentAppProtocolVersionException>(\n                () => messageValidator.ValidateAppProtocolVersion(unknownDifferentExtraPing));\n            Assert.False(exception.Trusted);\n            Assert.False(called);\n        }\n    }\n}\n"
  },
  {
    "path": "test/Libplanet.Net.Tests/Messages/NetMQMessageCodecTest.cs",
    "content": "#nullable disable\nusing System;\nusing System.Collections.Immutable;\nusing System.Net;\nusing System.Numerics;\nusing Bencodex;\nusing Libplanet.Action.Loader;\nusing Libplanet.Action.Tests.Common;\nusing Libplanet.Blockchain;\nusing Libplanet.Blockchain.Policies;\nusing Libplanet.Consensus;\nusing Libplanet.Crypto;\nusing Libplanet.Net.Messages;\nusing Libplanet.Store;\nusing Libplanet.Store.Trie;\nusing Libplanet.Types.Blocks;\nusing Libplanet.Types.Consensus;\nusing NetMQ;\nusing Xunit;\nusing static Libplanet.Tests.TestUtils;\n\nnamespace Libplanet.Net.Tests.Messages\n{\n    [Collection(\"NetMQConfiguration\")]\n    public class NetMQMessageCodecTest : IDisposable\n    {\n        public void Dispose()\n        {\n            NetMQConfig.Cleanup(false);\n        }\n\n        [Theory]\n        [InlineData(MessageContent.MessageType.Ping)]\n        [InlineData(MessageContent.MessageType.Pong)]\n        [InlineData(MessageContent.MessageType.GetBlockHashes)]\n        [InlineData(MessageContent.MessageType.TxIds)]\n        [InlineData(MessageContent.MessageType.GetBlocks)]\n        [InlineData(MessageContent.MessageType.GetTxs)]\n        [InlineData(MessageContent.MessageType.Blocks)]\n        [InlineData(MessageContent.MessageType.Tx)]\n        [InlineData(MessageContent.MessageType.FindNeighbors)]\n        [InlineData(MessageContent.MessageType.Neighbors)]\n        [InlineData(MessageContent.MessageType.BlockHeaderMessage)]\n        [InlineData(MessageContent.MessageType.BlockHashes)]\n        [InlineData(MessageContent.MessageType.GetChainStatus)]\n        [InlineData(MessageContent.MessageType.ChainStatus)]\n        [InlineData(MessageContent.MessageType.DifferentVersion)]\n        [InlineData(MessageContent.MessageType.HaveMessage)]\n        [InlineData(MessageContent.MessageType.WantMessage)]\n        [InlineData(MessageContent.MessageType.ConsensusProposal)]\n        [InlineData(MessageContent.MessageType.ConsensusVote)]\n        [InlineData(MessageContent.MessageType.ConsensusCommit)]\n        [InlineData(MessageContent.MessageType.ConsensusMaj23Msg)]\n        [InlineData(MessageContent.MessageType.ConsensusVoteSetBitsMsg)]\n        [InlineData(MessageContent.MessageType.ConsensusProposalClaimMsg)]\n        public void CheckMessages(MessageContent.MessageType type)\n        {\n            var privateKey = new PrivateKey();\n            var peer = new BoundPeer(privateKey.PublicKey, new DnsEndPoint(\"0.0.0.0\", 0));\n            var dateTimeOffset = DateTimeOffset.UtcNow;\n            var apv = new AppProtocolVersion(\n                1,\n                new Bencodex.Types.Integer(0),\n                ImmutableArray<byte>.Empty,\n                default(Address));\n            var messageContent = CreateMessage(type);\n            var codec = new NetMQMessageCodec();\n            NetMQMessage raw =\n                codec.Encode(\n                    new Message(messageContent, apv, peer, dateTimeOffset, null),\n                    privateKey);\n            var parsed = codec.Decode(raw, true);\n            Assert.Equal(apv, parsed.Version);\n            Assert.Equal(peer, parsed.Remote);\n            Assert.Equal(dateTimeOffset, parsed.Timestamp);\n            Assert.IsType(messageContent.GetType(), parsed.Content);\n            Assert.Equal(messageContent.DataFrames, parsed.Content.DataFrames);\n        }\n\n        private MessageContent CreateMessage(MessageContent.MessageType type)\n        {\n            var privateKey = new PrivateKey();\n            var boundPeer = new BoundPeer(privateKey.PublicKey, new DnsEndPoint(\"127.0.0.1\", 1000));\n            IBlockPolicy policy = new BlockPolicy();\n            BlockChain chain = MakeBlockChain(\n                policy,\n                new MemoryStore(),\n                new TrieStateStore(new MemoryKeyValueStore()),\n                new SingleActionLoader(typeof(DumbAction))\n            );\n            var codec = new Codec();\n            Block genesis = chain.Genesis;\n            var transaction = chain.MakeTransaction(privateKey, new DumbAction[] { });\n            switch (type)\n            {\n                case MessageContent.MessageType.Ping:\n                    return new PingMsg();\n                case MessageContent.MessageType.Pong:\n                    return new PongMsg();\n                case MessageContent.MessageType.GetBlockHashes:\n                    return new GetBlockHashesMsg(chain.GetBlockLocator());\n                case MessageContent.MessageType.TxIds:\n                    return new TxIdsMsg(new[] { transaction.Id });\n                case MessageContent.MessageType.GetBlocks:\n                    return new GetBlocksMsg(new[] { genesis.Hash }, 10);\n                case MessageContent.MessageType.GetTxs:\n                    return new GetTxsMsg(new[] { transaction.Id });\n                case MessageContent.MessageType.Blocks:\n                    return new Libplanet.Net.Messages.BlocksMsg(new[]\n                    {\n                        BitConverter.GetBytes(2),\n                        codec.Encode(genesis.MarshalBlock()),\n                        Array.Empty<byte>(),\n                    });\n                case MessageContent.MessageType.Tx:\n                    return new Libplanet.Net.Messages.TxMsg(transaction.Serialize());\n                case MessageContent.MessageType.FindNeighbors:\n                    return new FindNeighborsMsg(privateKey.Address);\n                case MessageContent.MessageType.Neighbors:\n                    return new NeighborsMsg(new[] { boundPeer });\n                case MessageContent.MessageType.BlockHeaderMessage:\n                    return new BlockHeaderMsg(genesis.Hash, genesis.Header);\n                case MessageContent.MessageType.BlockHashes:\n                    return new BlockHashesMsg(new[] { genesis.Hash });\n                case MessageContent.MessageType.GetChainStatus:\n                    return new GetChainStatusMsg();\n                case MessageContent.MessageType.ChainStatus:\n                    return new ChainStatusMsg(\n                        0,\n                        genesis.Hash,\n                        chain.Tip.Index,\n                        chain.Tip.Hash);\n                case MessageContent.MessageType.DifferentVersion:\n                    return new DifferentVersionMsg();\n                case MessageContent.MessageType.HaveMessage:\n                    return new HaveMessage(\n                        new[] { new MessageId(TestUtils.GetRandomBytes(MessageId.Size)) });\n                case MessageContent.MessageType.WantMessage:\n                    return new WantMessage(\n                        new[] { new MessageId(TestUtils.GetRandomBytes(MessageId.Size)) });\n                case MessageContent.MessageType.ConsensusProposal:\n                    return new ConsensusProposalMsg(\n                        new ProposalMetadata(\n                            0,\n                            0,\n                            DateTimeOffset.UtcNow,\n                            privateKey.PublicKey,\n                            codec.Encode(genesis.MarshalBlock()),\n                            -1).Sign(privateKey));\n                case MessageContent.MessageType.ConsensusVote:\n                    return new ConsensusPreVoteMsg(\n                            new VoteMetadata(\n                            0,\n                            0,\n                            genesis.Hash,\n                            DateTimeOffset.UtcNow,\n                            privateKey.PublicKey,\n                            BigInteger.One,\n                            VoteFlag.PreVote).Sign(privateKey));\n                case MessageContent.MessageType.ConsensusCommit:\n                    return new ConsensusPreCommitMsg(\n                        new VoteMetadata(\n                            0,\n                            0,\n                            genesis.Hash,\n                            DateTimeOffset.UtcNow,\n                            privateKey.PublicKey,\n                            BigInteger.One,\n                            VoteFlag.PreCommit).Sign(privateKey));\n                case MessageContent.MessageType.ConsensusMaj23Msg:\n                    return new ConsensusMaj23Msg(\n                        new Maj23Metadata(\n                            0,\n                            0,\n                            genesis.Hash,\n                            DateTimeOffset.UtcNow,\n                            privateKey.PublicKey,\n                            VoteFlag.PreVote).Sign(privateKey));\n                case MessageContent.MessageType.ConsensusVoteSetBitsMsg:\n                    return new ConsensusVoteSetBitsMsg(\n                        new VoteSetBitsMetadata(\n                            0,\n                            0,\n                            genesis.Hash,\n                            DateTimeOffset.UtcNow,\n                            privateKey.PublicKey,\n                            VoteFlag.PreVote,\n                            new[] { true, true, false, false }).Sign(privateKey));\n                case MessageContent.MessageType.ConsensusProposalClaimMsg:\n                    return new ConsensusProposalClaimMsg(\n                        new ProposalClaimMetadata(\n                            0,\n                            0,\n                            genesis.Hash,\n                            DateTimeOffset.UtcNow,\n                            privateKey.PublicKey).Sign(privateKey));\n                default:\n                    throw new Exception($\"Cannot create a message of invalid type {type}\");\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "test/Libplanet.Net.Tests/NullableSemaphoreTest.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing Xunit;\n\nnamespace Libplanet.Net.Tests\n{\n    public class NullableSemaphoreTest\n    {\n        [Fact]\n        public async void WaitAsync()\n        {\n            var semaphore = new NullableSemaphore(3);\n            int count = 0;\n            async Task SampleTask(NullableSemaphore sema)\n            {\n                if (await sema.WaitAsync(TimeSpan.Zero, default))\n                {\n                    await Task.Delay(1000);\n                    Interlocked.Increment(ref count);\n                }\n            }\n\n            var tasks = new List<Task>\n            {\n                SampleTask(semaphore),\n                SampleTask(semaphore),\n                SampleTask(semaphore),\n                SampleTask(semaphore),\n            };\n            await Task.WhenAll(tasks);\n\n            Assert.Equal(3, count);\n        }\n\n        [Fact]\n        public async void WaitAsyncZero()\n        {\n            var semaphore = new NullableSemaphore(0);\n            int count = 0;\n            async Task SampleTask(NullableSemaphore sema)\n            {\n                if (await sema.WaitAsync(TimeSpan.Zero, default))\n                {\n                    await Task.Delay(1000);\n                    Interlocked.Increment(ref count);\n                }\n            }\n\n            var tasks = new List<Task>\n            {\n                SampleTask(semaphore),\n                SampleTask(semaphore),\n                SampleTask(semaphore),\n            };\n            await Task.WhenAll(tasks);\n\n            Assert.Equal(3, count);\n        }\n\n        [Fact]\n        public async void Release()\n        {\n            var semaphore = new NullableSemaphore(3);\n            int count = 0;\n            async Task SampleTask(NullableSemaphore sema)\n            {\n                if (await sema.WaitAsync(TimeSpan.Zero, default))\n                {\n                    await Task.Delay(1000);\n                    Interlocked.Increment(ref count);\n                    sema.Release();\n                }\n            }\n\n            var tasks = new List<Task>\n            {\n                SampleTask(semaphore),\n                SampleTask(semaphore),\n                SampleTask(semaphore),\n            };\n            await Task.WhenAll(tasks);\n            await SampleTask(semaphore);\n\n            Assert.Equal(4, count);\n        }\n    }\n}\n"
  },
  {
    "path": "test/Libplanet.Net.Tests/Options/HostOptionsTest.cs",
    "content": "using System;\nusing Libplanet.Net.Options;\nusing Xunit;\n\nnamespace Libplanet.Net.Tests.Options\n{\n    public class HostOptionsTest\n    {\n        [Fact]\n        public void Constructor()\n        {\n            Assert.Throws<ArgumentException>(\n                () => new HostOptions(null, new IceServer[] { }));\n            Assert.Throws<ArgumentException>(\n                () => new HostOptions(\n                    \"127.0.0.1\", new IceServer[] { new IceServer(\"turn://user:info@some.path\") }));\n        }\n    }\n}\n"
  },
  {
    "path": "test/Libplanet.Net.Tests/Protocols/KBucketDictionaryTest.cs",
    "content": "using System;\nusing System.Net;\nusing Libplanet.Crypto;\nusing Libplanet.Net.Protocols;\nusing Serilog.Core;\nusing Xunit;\n\nnamespace Libplanet.Net.Tests.Protocols\n{\n    public class KBucketDictionaryTest\n    {\n        [Fact]\n        public void KBucketDictionary()\n        {\n            Assert.Throws<ArgumentOutOfRangeException>(() =>\n                new KBucketDictionary(size: 0, replace: false, logger: Logger.None));\n        }\n\n        [Fact]\n        public void MutateWithoutReplacement()\n        {\n            var kBucketDictionary = new KBucketDictionary(\n                size: 4, replace: false, logger: Logger.None);\n            var peer1 = new BoundPeer(\n                new PrivateKey().PublicKey,\n                new DnsEndPoint(\"0.0.0.0\", 1234));\n            var peer2 = new BoundPeer(\n                new PrivateKey().PublicKey,\n                new DnsEndPoint(\"0.0.0.0\", 1234));\n            var peer3 = new BoundPeer(\n                new PrivateKey().PublicKey,\n                new DnsEndPoint(\"0.0.0.0\", 1234));\n            var peer4 = new BoundPeer(\n                new PrivateKey().PublicKey,\n                new DnsEndPoint(\"0.0.0.0\", 1234));\n            var peer5 = new BoundPeer(\n                new PrivateKey().PublicKey,\n                new DnsEndPoint(\"0.0.0.0\", 1234));\n\n            // Initial state\n            Assert.Equal(0, kBucketDictionary.Count);\n            Assert.Null(kBucketDictionary.Head);\n            Assert.Null(kBucketDictionary.Tail);\n\n            // Add more peers than allowed\n            Assert.True(kBucketDictionary.AddOrUpdate(peer1));\n            Assert.True(kBucketDictionary.AddOrUpdate(peer2));\n            Assert.True(kBucketDictionary.AddOrUpdate(peer3));\n            Assert.True(kBucketDictionary.AddOrUpdate(peer4));\n            Assert.False(kBucketDictionary.AddOrUpdate(peer5));\n            Assert.Equal(4, kBucketDictionary.Count);\n            Assert.Equal(peer1.Address, kBucketDictionary.Tail!.Peer.Address);\n            Assert.Equal(peer4.Address, kBucketDictionary.Head!.Peer.Address);\n            Assert.True(kBucketDictionary.Contains(peer1));\n            Assert.False(kBucketDictionary.Contains(peer5));\n\n            // Replace one of the peers\n            Assert.True(kBucketDictionary.AddOrUpdate(peer2));\n            Assert.Equal(peer1.Address, kBucketDictionary.Tail!.Peer.Address);\n            Assert.Equal(peer2.Address, kBucketDictionary.Head!.Peer.Address);\n\n            // Remove\n            Assert.True(kBucketDictionary.Remove(peer3));\n            Assert.False(kBucketDictionary.Remove(peer5));\n\n            // Clear\n            kBucketDictionary.Clear();\n            Assert.Equal(0, kBucketDictionary.Count);\n            Assert.Null(kBucketDictionary.Head);\n            Assert.Null(kBucketDictionary.Tail);\n        }\n\n        [Fact]\n        public void MutateWithReplacement()\n        {\n            var kBucketDictionary = new KBucketDictionary(\n                size: 4, replace: true, logger: Logger.None);\n            var peer1 = new BoundPeer(\n                new PrivateKey().PublicKey,\n                new DnsEndPoint(\"0.0.0.0\", 1234));\n            var peer2 = new BoundPeer(\n                new PrivateKey().PublicKey,\n                new DnsEndPoint(\"0.0.0.0\", 1234));\n            var peer3 = new BoundPeer(\n                new PrivateKey().PublicKey,\n                new DnsEndPoint(\"0.0.0.0\", 1234));\n            var peer4 = new BoundPeer(\n                new PrivateKey().PublicKey,\n                new DnsEndPoint(\"0.0.0.0\", 1234));\n            var peer5 = new BoundPeer(\n                new PrivateKey().PublicKey,\n                new DnsEndPoint(\"0.0.0.0\", 1234));\n\n            // Initial state\n            Assert.Equal(0, kBucketDictionary.Count);\n            Assert.Null(kBucketDictionary.Head);\n            Assert.Null(kBucketDictionary.Tail);\n\n            // Add more peers than allowed\n            Assert.True(kBucketDictionary.AddOrUpdate(peer1));\n            Assert.True(kBucketDictionary.AddOrUpdate(peer2));\n            Assert.True(kBucketDictionary.AddOrUpdate(peer3));\n            Assert.True(kBucketDictionary.AddOrUpdate(peer4));\n            Assert.True(kBucketDictionary.AddOrUpdate(peer5));\n            Assert.Equal(4, kBucketDictionary.Count);\n            Assert.Equal(peer2.Address, kBucketDictionary.Tail!.Peer.Address);\n            Assert.Equal(peer5.Address, kBucketDictionary.Head!.Peer.Address);\n            Assert.False(kBucketDictionary.Contains(peer1));\n            Assert.True(kBucketDictionary.Contains(peer5));\n\n            // Replace one of the peers\n            Assert.True(kBucketDictionary.AddOrUpdate(peer2));\n            Assert.Equal(peer3.Address, kBucketDictionary.Tail!.Peer.Address);\n            Assert.Equal(peer2.Address, kBucketDictionary.Head!.Peer.Address);\n\n            // Remove\n            Assert.True(kBucketDictionary.Remove(peer2));\n            Assert.False(kBucketDictionary.Remove(peer1));\n        }\n    }\n}\n"
  },
  {
    "path": "test/Libplanet.Net.Tests/Protocols/KBucketTest.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Net;\nusing System.Threading;\nusing Libplanet.Crypto;\nusing Libplanet.Net.Protocols;\nusing Serilog.Core;\nusing Xunit;\n#if NETFRAMEWORK && (NET47 || NET471)\nusing static Libplanet.Tests.HashSetExtensions;\n#endif\n\nnamespace Libplanet.Net.Tests.Protocols\n{\n    public class KBucketTest\n    {\n        [Fact]\n        public void BucketTest()\n        {\n            var bucket = new KBucket(4, new System.Random(), Logger.None);\n            var peer1 = new BoundPeer(\n                new PrivateKey().PublicKey,\n                new DnsEndPoint(\"0.0.0.0\", 1234));\n            var peer2 = new BoundPeer(\n                new PrivateKey().PublicKey,\n                new DnsEndPoint(\"0.0.0.0\", 1234));\n            var peer3 = new BoundPeer(\n                new PrivateKey().PublicKey,\n                new DnsEndPoint(\"0.0.0.0\", 1234));\n            var peer4 = new BoundPeer(\n                new PrivateKey().PublicKey,\n                new DnsEndPoint(\"0.0.0.0\", 1234));\n            var peer5 = new BoundPeer(\n                new PrivateKey().PublicKey,\n                new DnsEndPoint(\"0.0.0.0\", 1234));\n\n            // Checks for an empty bucket.\n            Assert.True(bucket.IsEmpty);\n            Assert.False(bucket.IsFull);\n            Assert.Empty(bucket.Peers);\n            Assert.Empty(bucket.PeerStates);\n            Assert.Null(bucket.GetRandomPeer());\n            Assert.Null(bucket.Head);\n            Assert.Null(bucket.Tail);\n\n            // Checks for a partially filled bucket.\n            bucket.AddPeer(peer1, DateTimeOffset.UtcNow);\n            Assert.False(bucket.IsEmpty);\n            Assert.False(bucket.IsFull);\n            Assert.True(bucket.Contains(peer1));\n            Assert.False(bucket.Contains(peer2));\n            Assert.NotNull(bucket.GetRandomPeer());\n            Assert.Null(bucket.GetRandomPeer(peer1.Address));\n            Assert.NotNull(bucket.GetRandomPeer(peer2.Address));\n            Assert.Equal(peer1, bucket.Head?.Peer);\n            Assert.Equal(peer1, bucket.Tail?.Peer);\n\n            // Sleep statement is used to distinguish updated times.\n            Thread.Sleep(100);\n            bucket.AddPeer(peer2, DateTimeOffset.UtcNow);\n            Assert.Contains(\n                bucket.GetRandomPeer(),\n                new[] { peer1, peer2 }\n            );\n            Assert.Contains(\n                bucket.GetRandomPeer(peer1.Address),\n                new[] { peer2 }\n            );\n\n            // Checks for a full bucket.\n            Thread.Sleep(100);\n            bucket.AddPeer(peer3, DateTimeOffset.UtcNow);\n            Thread.Sleep(100);\n            bucket.AddPeer(peer4, DateTimeOffset.UtcNow);\n            Assert.True(bucket.IsFull);\n            Assert.Equal(\n                bucket.Peers.ToHashSet(),\n                new HashSet<BoundPeer> { peer1, peer2, peer3, peer4 }\n            );\n            Assert.Contains(\n                bucket.GetRandomPeer(),\n                new[] { peer1, peer2, peer3, peer4 }\n            );\n            Thread.Sleep(100);\n            bucket.AddPeer(peer5, DateTimeOffset.UtcNow);\n            Assert.Equal(\n                bucket.Peers.ToHashSet(),\n                new HashSet<BoundPeer> { peer1, peer2, peer3, peer4 }\n            );\n            Assert.False(bucket.Contains(peer5));\n            Assert.Equal(peer4, bucket.Head?.Peer);\n            Assert.Equal(peer1, bucket.Tail?.Peer);\n\n            // Check order has changed.\n            Thread.Sleep(100);\n            bucket.AddPeer(peer1, DateTimeOffset.UtcNow);\n            Assert.Equal(peer1, bucket.Head?.Peer);\n            Assert.Equal(peer2, bucket.Tail?.Peer);\n\n            Assert.False(bucket.RemovePeer(peer5));\n            Assert.True(bucket.RemovePeer(peer1));\n            Assert.DoesNotContain(peer1, bucket.Peers);\n            Assert.Equal(3, bucket.Peers.Count());\n\n            // Clear the bucket.\n            bucket.Clear();\n            Assert.True(bucket.IsEmpty);\n            Assert.Empty(bucket.Peers);\n            Assert.Null(bucket.Head);\n            Assert.Null(bucket.Tail);\n            Assert.Null(bucket.GetRandomPeer());\n        }\n    }\n}\n"
  },
  {
    "path": "test/Libplanet.Net.Tests/Protocols/ProtocolTest.cs",
    "content": "#nullable disable\nusing System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing Libplanet.Crypto;\nusing Libplanet.Net.Protocols;\nusing Libplanet.Net.Transports;\nusing Serilog;\nusing Xunit;\nusing Xunit.Abstractions;\n#if NETFRAMEWORK && (NET47 || NET471)\nusing static Libplanet.Tests.HashSetExtensions;\n#endif\nusing static Libplanet.Net.Tests.TestUtils;\n\nnamespace Libplanet.Net.Tests.Protocols\n{\n    [Trait(\"CircleCI\", \"Skip\")]\n    public class ProtocolTest\n    {\n        private const int Timeout = 60 * 1000;\n        private readonly Dictionary<Address, TestTransport> _transports;\n\n        public ProtocolTest(ITestOutputHelper output)\n        {\n            const string outputTemplate =\n                \"{Timestamp:HH:mm:ss}[@{Address}][{ThreadId}] - {Message}\";\n            Log.Logger = new LoggerConfiguration()\n                .MinimumLevel.Verbose()\n                .Enrich.WithThreadId()\n                .WriteTo.TestOutput(output, outputTemplate: outputTemplate)\n                .CreateLogger()\n                .ForContext<ProtocolTest>();\n\n            _transports = new Dictionary<Address, TestTransport>();\n        }\n\n        [Fact]\n        public void KademliaTest()\n        {\n            var addr1 = new Address(\"0000000000000000000000000000000000000000\");\n            var addr2 = new Address(\"0000000000000000000000000000000000000001\");\n            var addr3 = new Address(\"000000000000000000000000000000000000000c\");\n            var addr4 = new Address(\"0000000001000001111110001000011001000001\");\n            var addr5 = new Address(\"ffffffffffffffffffffffffffffffffffffffff\");\n\n            Assert.Equal(\n                new Address(\"000000000100000111111000100001100100000d\"),\n                Kademlia.CalculateDifference(addr3, addr4));\n            Assert.Equal(\n                Kademlia.CalculateDifference(addr2, addr4),\n                Kademlia.CalculateDifference(addr4, addr2));\n\n            Assert.Equal(159, Kademlia.CommonPrefixLength(addr1, addr2));\n            Assert.Equal(156, Kademlia.CommonPrefixLength(addr1, addr3));\n            Assert.Equal(39, Kademlia.CommonPrefixLength(addr1, addr4));\n\n            Assert.Equal(0, Kademlia.CalculateDistance(addr4, addr4));\n            Assert.Equal(Address.Size * 8, Kademlia.CalculateDistance(addr1, addr5));\n\n            Assert.True(string.CompareOrdinal(addr1.ToHex(), addr2.ToHex()) < 1);\n            Assert.True(string.CompareOrdinal(addr2.ToHex(), addr3.ToHex()) < 1);\n            Assert.True(string.CompareOrdinal(addr3.ToHex(), addr4.ToHex()) < 1);\n            Assert.True(string.CompareOrdinal(addr4.ToHex(), addr4.ToHex()) == 0);\n        }\n\n        [Fact(Timeout = Timeout)]\n        public async Task Start()\n        {\n            var transportA = CreateTestTransport();\n            var transportB = CreateTestTransport();\n\n            Assert.Throws<TransportException>(() => transportA.SendPing(transportB.AsPeer));\n            await StartTestTransportAsync(transportA);\n            await Assert.ThrowsAsync<TimeoutException>(() =>\n                transportA.AddPeersAsync(\n                    new[] { transportB.AsPeer },\n                    TimeSpan.FromMilliseconds(500))\n            );\n            Assert.Empty(transportA.ReceivedMessages);\n        }\n\n        [Fact(Timeout = Timeout)]\n        public async Task Ping()\n        {\n            var transportA = CreateTestTransport();\n            var transportB = CreateTestTransport();\n\n            try\n            {\n                await StartTestTransportAsync(transportA);\n                await StartTestTransportAsync(transportB);\n                transportA.SendPing(transportB.AsPeer);\n                await transportA.MessageReceived.WaitAsync();\n                await Task.Delay(100);\n\n                Assert.Single(transportA.ReceivedMessages);\n                Assert.Single(transportB.ReceivedMessages);\n                Assert.Contains(transportA.AsPeer, transportB.Peers);\n            }\n            finally\n            {\n                await transportA.StopAsync(TimeSpan.Zero);\n                await transportB.StopAsync(TimeSpan.Zero);\n            }\n        }\n\n        [Fact(Timeout = Timeout)]\n        public async Task PingTwice()\n        {\n            var transportA = CreateTestTransport();\n            var transportB = CreateTestTransport();\n\n            try\n            {\n                await StartTestTransportAsync(transportA);\n                await StartTestTransportAsync(transportB);\n\n                transportA.SendPing(transportB.AsPeer);\n                await transportA.MessageReceived.WaitAsync();\n                await transportB.MessageReceived.WaitAsync();\n                transportB.SendPing(transportA.AsPeer);\n                await transportA.MessageReceived.WaitAsync();\n                await transportB.MessageReceived.WaitAsync();\n\n                Assert.Equal(2, transportA.ReceivedMessages.Count);\n                Assert.Equal(2, transportB.ReceivedMessages.Count);\n                Assert.Contains(transportA.AsPeer, transportB.Peers);\n                Assert.Contains(transportB.AsPeer, transportA.Peers);\n            }\n            finally\n            {\n                await transportA.StopAsync(TimeSpan.Zero);\n                await transportB.StopAsync(TimeSpan.Zero);\n            }\n        }\n\n        [Fact(Timeout = Timeout)]\n        public async Task PingToClosedPeer()\n        {\n            var transportA = CreateTestTransport();\n            var transportB = CreateTestTransport();\n            var transportC = CreateTestTransport();\n\n            await StartTestTransportAsync(transportA);\n            await StartTestTransportAsync(transportB);\n            await StartTestTransportAsync(transportC);\n\n            await transportA.AddPeersAsync(new[] { transportB.AsPeer, transportC.AsPeer }, null);\n\n            Assert.Contains(transportB.AsPeer, transportA.Peers);\n            Assert.Contains(transportC.AsPeer, transportA.Peers);\n\n            await transportC.StopAsync(TimeSpan.Zero);\n            await Assert.ThrowsAsync<TimeoutException>(\n                () => transportA.AddPeersAsync(\n                    new[] { transportC.AsPeer },\n                    TimeSpan.FromSeconds(3)));\n            await transportA.AddPeersAsync(new[] { transportB.AsPeer }, null);\n\n            Assert.Contains(transportB.AsPeer, transportA.Peers);\n\n            transportA.Dispose();\n            transportB.Dispose();\n            transportC.Dispose();\n        }\n\n        [Fact(Timeout = Timeout)]\n        public async Task BootstrapException()\n        {\n            var transportA = CreateTestTransport();\n            var transportB = CreateTestTransport();\n\n            await Assert.ThrowsAsync<TransportException>(\n                () => transportB.BootstrapAsync(\n                    new[] { transportA.AsPeer },\n                    TimeSpan.FromSeconds(3))\n            );\n\n            transportA.Dispose();\n            transportB.Dispose();\n        }\n\n        [Fact(Timeout = Timeout)]\n        public async Task BootstrapAsyncTest()\n        {\n            var transportA = CreateTestTransport();\n            var transportB = CreateTestTransport();\n            var transportC = CreateTestTransport();\n\n            try\n            {\n                await StartTestTransportAsync(transportA);\n                await StartTestTransportAsync(transportB);\n                await StartTestTransportAsync(transportC);\n\n                await transportB.BootstrapAsync(new[] { transportA.AsPeer });\n                await transportC.BootstrapAsync(new[] { transportA.AsPeer });\n\n                Assert.Contains(transportB.AsPeer, transportC.Peers);\n                Assert.Contains(transportC.AsPeer, transportB.Peers);\n\n                transportA.Table.Clear();\n                transportB.Table.Clear();\n                transportC.Table.Clear();\n\n                await transportB.AddPeersAsync(new[] { transportC.AsPeer }, null);\n                await transportC.StopAsync(TimeSpan.Zero);\n                await transportA.BootstrapAsync(new[] { transportB.AsPeer });\n                Assert.Contains(transportB.AsPeer, transportA.Peers);\n                Assert.DoesNotContain(transportC.AsPeer, transportA.Peers);\n            }\n            finally\n            {\n                transportA.Dispose();\n                transportB.Dispose();\n                transportC.Dispose();\n            }\n        }\n\n        [Fact(Timeout = Timeout)]\n        public async Task RemoveStalePeers()\n        {\n            var transportA = CreateTestTransport();\n            var transportB = CreateTestTransport();\n\n            await StartTestTransportAsync(transportA);\n            await StartTestTransportAsync(transportB);\n\n            await transportA.AddPeersAsync(new[] { transportB.AsPeer }, null);\n            Assert.Single(transportA.Peers);\n\n            await transportB.StopAsync(TimeSpan.Zero);\n            await Task.Delay(100);\n            await transportA.Protocol.RefreshTableAsync(TimeSpan.Zero, default);\n            Assert.Empty(transportA.Peers);\n\n            transportA.Dispose();\n            transportB.Dispose();\n        }\n\n        [Fact(Timeout = Timeout)]\n        public async Task RoutingTableFull()\n        {\n            var transport = CreateTestTransport(tableSize: 1, bucketSize: 1);\n            var transportA = CreateTestTransport();\n            var transportB = CreateTestTransport();\n            var transportC = CreateTestTransport();\n\n            await StartTestTransportAsync(transport);\n            await StartTestTransportAsync(transportA);\n            await StartTestTransportAsync(transportB);\n            await StartTestTransportAsync(transportC);\n\n            await transportA.AddPeersAsync(new[] { transport.AsPeer }, null);\n            await transportB.AddPeersAsync(new[] { transport.AsPeer }, null);\n            await transportC.AddPeersAsync(new[] { transport.AsPeer }, null);\n\n            Assert.Single(transportA.Peers);\n            Assert.Contains(transportA.AsPeer, transport.Peers);\n            Assert.DoesNotContain(transportB.AsPeer, transport.Peers);\n            Assert.DoesNotContain(transportC.AsPeer, transport.Peers);\n\n            transport.Dispose();\n            transportA.Dispose();\n            transportB.Dispose();\n            transportC.Dispose();\n        }\n\n        [Fact(Timeout = Timeout)]\n        public async Task ReplacementCache()\n        {\n            var transport = CreateTestTransport(tableSize: 1, bucketSize: 1);\n            var transportA = CreateTestTransport();\n            var transportB = CreateTestTransport();\n            var transportC = CreateTestTransport();\n\n            await StartTestTransportAsync(transport);\n            await StartTestTransportAsync(transportA);\n            await StartTestTransportAsync(transportB);\n            await StartTestTransportAsync(transportC);\n\n            await transportA.AddPeersAsync(new[] { transport.AsPeer }, null);\n            await transportB.AddPeersAsync(new[] { transport.AsPeer }, null);\n            await Task.Delay(100);\n            await transportC.AddPeersAsync(new[] { transport.AsPeer }, null);\n\n            Assert.Single(transportA.Peers);\n            Assert.Contains(transportA.AsPeer, transport.Peers);\n            Assert.DoesNotContain(transportB.AsPeer, transport.Peers);\n            Assert.DoesNotContain(transportC.AsPeer, transport.Peers);\n\n            await transportA.StopAsync(TimeSpan.Zero);\n            await transport.Protocol.RefreshTableAsync(TimeSpan.Zero, default);\n            await transport.Protocol.CheckReplacementCacheAsync(default);\n\n            Assert.Single(transport.Peers);\n            Assert.DoesNotContain(transportA.AsPeer, transport.Peers);\n            Assert.DoesNotContain(transportB.AsPeer, transport.Peers);\n            Assert.Contains(transportC.AsPeer, transport.Peers);\n\n            transport.Dispose();\n            transportA.Dispose();\n            transportB.Dispose();\n            transportC.Dispose();\n        }\n\n        [Fact(Timeout = Timeout)]\n        public async Task RemoveDeadReplacementCache()\n        {\n            var transport = CreateTestTransport(tableSize: 1, bucketSize: 1);\n            var transportA = CreateTestTransport();\n            var transportB = CreateTestTransport();\n            var transportC = CreateTestTransport();\n\n            await StartTestTransportAsync(transport);\n            await StartTestTransportAsync(transportA);\n            await StartTestTransportAsync(transportB);\n            await StartTestTransportAsync(transportC);\n\n            await transportA.AddPeersAsync(new[] { transport.AsPeer }, null);\n            await transportB.AddPeersAsync(new[] { transport.AsPeer }, null);\n\n            Assert.Single(transport.Peers);\n            Assert.Contains(transportA.AsPeer, transport.Peers);\n            Assert.DoesNotContain(transportB.AsPeer, transport.Peers);\n\n            await transportA.StopAsync(TimeSpan.Zero);\n            await transportB.StopAsync(TimeSpan.Zero);\n\n            await transportC.AddPeersAsync(new[] { transport.AsPeer }, null);\n            await transport.Protocol.RefreshTableAsync(TimeSpan.Zero, default);\n            await transport.Protocol.CheckReplacementCacheAsync(default);\n\n            Assert.Single(transport.Peers);\n            Assert.DoesNotContain(transportA.AsPeer, transport.Peers);\n            Assert.DoesNotContain(transportB.AsPeer, transport.Peers);\n            Assert.Contains(transportC.AsPeer, transport.Peers);\n\n            transport.Dispose();\n            transportA.Dispose();\n            transportB.Dispose();\n            transportC.Dispose();\n        }\n\n        [Theory(Timeout = 2 * Timeout)]\n        [InlineData(1)]\n        [InlineData(5)]\n        [InlineData(20)]\n        [InlineData(50)]\n        public async Task BroadcastMessage(int count)\n        {\n            var seed = CreateTestTransport();\n            await StartTestTransportAsync(seed);\n            var transports = new TestTransport[count];\n            for (var i = 0; i < count; i++)\n            {\n                transports[i] = CreateTestTransport();\n                await StartTestTransportAsync(transports[i]);\n            }\n\n            try\n            {\n                foreach (var transport in transports)\n                {\n                    await transport.BootstrapAsync(new[] { seed.AsPeer });\n                }\n\n                Log.Debug(\"Bootstrap completed\");\n\n                var tasks =\n                    transports.Select(transport => transport.WaitForTestMessageWithData(\"foo\"));\n\n                seed.BroadcastTestMessage(null, \"foo\");\n                Log.Debug(\"Broadcast completed\");\n\n                await Task.WhenAll(tasks);\n            }\n            finally\n            {\n                seed.Dispose();\n                foreach (var transport in transports)\n                {\n                    Assert.True(transport.ReceivedTestMessageOfData(\"foo\"));\n                    transport.Dispose();\n                }\n            }\n        }\n\n        [Fact(Timeout = Timeout)]\n        public async Task BroadcastGuarantee()\n        {\n            // Make sure t1 and t2 is in same bucket of seed's routing table.\n            var privateKey0 = new PrivateKey(new byte[]\n            {\n                0x1a, 0x55, 0x30, 0x84, 0xe8, 0x9e, 0xee, 0x1e, 0x9f, 0xe2, 0xd1, 0x49, 0xe7, 0xa9,\n                0x53, 0xa9, 0xb4, 0xe4, 0xfe, 0x5a, 0xc1, 0x6c, 0x61, 0x9f, 0x54, 0x8f, 0x5e, 0xd9,\n                0x7f, 0xa3, 0xa0, 0x79,\n            });\n            var privateKey1 = new PrivateKey(new byte[]\n            {\n                0x8e, 0x26, 0x31, 0x4a, 0xee, 0x84, 0xd, 0x8a, 0xea, 0x7b, 0x6, 0xf8, 0x81, 0x5f,\n                0x69, 0xb3, 0x44, 0x46, 0xe0, 0x27, 0x65, 0x17, 0x1, 0x16, 0x58, 0x26, 0x69, 0x93,\n                0x48, 0xbb, 0xf, 0xb4,\n            });\n            var privateKey2 = new PrivateKey(new byte[]\n            {\n                0xd4, 0x6b, 0x4b, 0x38, 0xde, 0x39, 0x25, 0x3b, 0xd8, 0x1, 0x9d, 0x2, 0x2, 0x7a,\n                0x90, 0x9, 0x46, 0x2f, 0xc1, 0xd3, 0xd9, 0xa, 0xa6, 0xf4, 0xfa, 0x9a, 0x6, 0xa3,\n                0x60, 0xed, 0xf3, 0xd7,\n            });\n\n            var seed = CreateTestTransport(privateKey0);\n            var t1 = CreateTestTransport(privateKey1, true);\n            var t2 = CreateTestTransport(privateKey2);\n            await StartTestTransportAsync(seed);\n            await StartTestTransportAsync(t1);\n            await StartTestTransportAsync(t2);\n\n            try\n            {\n                await t1.BootstrapAsync(new[] { seed.AsPeer });\n                await t2.BootstrapAsync(new[] { seed.AsPeer });\n\n                Log.Debug(\"Bootstrap completed\");\n\n                var tcs = new CancellationTokenSource();\n                var task = t2.WaitForTestMessageWithData(\"foo\", tcs.Token);\n\n                seed.BroadcastTestMessage(null, \"foo\");\n                Log.Debug(\"Broadcast \\\"foo\\\" completed\");\n\n                tcs.CancelAfter(TimeSpan.FromSeconds(5));\n                await task;\n\n                Assert.True(t2.ReceivedTestMessageOfData(\"foo\"));\n\n                tcs = new CancellationTokenSource();\n                task = t2.WaitForTestMessageWithData(\"bar\", tcs.Token);\n\n                seed.BroadcastTestMessage(null, \"bar\");\n                Log.Debug(\"Broadcast \\\"bar\\\" completed\");\n\n                tcs.CancelAfter(TimeSpan.FromSeconds(5));\n                await task;\n\n                Assert.True(t2.ReceivedTestMessageOfData(\"bar\"));\n\n                tcs = new CancellationTokenSource();\n                task = t2.WaitForTestMessageWithData(\"baz\", tcs.Token);\n\n                seed.BroadcastTestMessage(null, \"baz\");\n                Log.Debug(\"Broadcast \\\"baz\\\" completed\");\n\n                tcs.CancelAfter(TimeSpan.FromSeconds(5));\n                await task;\n\n                Assert.True(t2.ReceivedTestMessageOfData(\"baz\"));\n\n                tcs = new CancellationTokenSource();\n                task = t2.WaitForTestMessageWithData(\"qux\", tcs.Token);\n\n                seed.BroadcastTestMessage(null, \"qux\");\n                Log.Debug(\"Broadcast \\\"qux\\\" completed\");\n\n                tcs.CancelAfter(TimeSpan.FromSeconds(5));\n                await task;\n\n                Assert.True(t2.ReceivedTestMessageOfData(\"qux\"));\n            }\n            finally\n            {\n                seed.Dispose();\n                t1.Dispose();\n                t2.Dispose();\n            }\n        }\n\n        [Fact(Timeout = Timeout)]\n        public async Task DoNotBroadcastToSourcePeer()\n        {\n            TestTransport transportA = CreateTestTransport(new PrivateKey());\n            TestTransport transportB = CreateTestTransport(new PrivateKey());\n            TestTransport transportC = CreateTestTransport(new PrivateKey());\n\n            await StartTestTransportAsync(transportA);\n            await StartTestTransportAsync(transportB);\n            await StartTestTransportAsync(transportC);\n\n            try\n            {\n                await transportA.AddPeersAsync(new[] { transportB.AsPeer }, null);\n                await transportB.AddPeersAsync(new[] { transportC.AsPeer }, null);\n\n                transportA.BroadcastTestMessage(null, \"foo\");\n                await transportC.WaitForTestMessageWithData(\"foo\");\n                await Task.Delay(100);\n\n                Assert.True(transportC.ReceivedTestMessageOfData(\"foo\"));\n                Assert.False(transportA.ReceivedTestMessageOfData(\"foo\"));\n            }\n            finally\n            {\n                transportA.Dispose();\n                transportB.Dispose();\n                transportC.Dispose();\n            }\n        }\n\n        [Fact(Timeout = Timeout)]\n        public async Task RefreshTable()\n        {\n            const int peersCount = 10;\n            var privateKey = new PrivateKey();\n            var privateKeys = Enumerable.Range(0, peersCount).Select(\n                i => GeneratePrivateKeyOfBucketIndex(privateKey.Address, i / 2));\n            TestTransport transport = CreateTestTransport(privateKey);\n            TestTransport[] transports =\n                privateKeys.Select(key => CreateTestTransport(key)).ToArray();\n\n            await StartTestTransportAsync(transport);\n            foreach (var t in transports)\n            {\n                await StartTestTransportAsync(t);\n            }\n\n            try\n            {\n                foreach (var t in transports)\n                {\n                    transport.Table.AddPeer(\n                        t.AsPeer,\n                        DateTimeOffset.UtcNow - TimeSpan.FromMinutes(2));\n                }\n\n                IReadOnlyList<BoundPeer> refreshCandidates =\n                    transport.Table.PeersToRefresh(TimeSpan.FromMinutes(1));\n                Assert.Equal(peersCount, transport.Peers.Count());\n                Assert.Equal(peersCount / 2, refreshCandidates.Count);\n                Assert.Equal(peersCount / 2, transport.Table.NonEmptyBuckets.Count());\n\n                await transport.Protocol.RefreshTableAsync(TimeSpan.FromMinutes(1), default);\n                Assert.NotEqual(\n                    refreshCandidates.ToHashSet(),\n                    transport.Table.PeersToRefresh(TimeSpan.FromMinutes(1)).ToHashSet());\n                Assert.Equal(\n                    peersCount / 2,\n                    transport.Table.PeersToRefresh(TimeSpan.FromMinutes(1)).Count());\n                Assert.Equal(peersCount / 2, transport.Table.NonEmptyBuckets.Count());\n\n                await transport.Protocol.RefreshTableAsync(TimeSpan.FromMinutes(1), default);\n                Assert.Empty(transport.Table.PeersToRefresh(TimeSpan.FromMinutes(1)));\n            }\n            finally\n            {\n                transport.Dispose();\n                foreach (var t in transports)\n                {\n                    t.Dispose();\n                }\n            }\n        }\n\n        private TestTransport CreateTestTransport(\n            PrivateKey privateKey = null,\n            bool blockBroadcast = false,\n            int tableSize = Kademlia.TableSize,\n            int bucketSize = Kademlia.BucketSize,\n            TimeSpan? networkDelay = null)\n        {\n            return new TestTransport(\n                _transports,\n                privateKey ?? new PrivateKey(),\n                blockBroadcast,\n                tableSize,\n                bucketSize,\n                networkDelay);\n        }\n\n        private async Task StartTestTransportAsync(\n            TestTransport transport,\n            CancellationToken cancellationToken = default)\n        {\n            _ = transport.StartAsync(cancellationToken);\n            await transport.WaitForRunningAsync();\n        }\n    }\n}\n"
  },
  {
    "path": "test/Libplanet.Net.Tests/Protocols/RoutingTableTest.cs",
    "content": "#nullable disable\nusing System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Net;\nusing Libplanet.Common;\nusing Libplanet.Crypto;\nusing Libplanet.Net.Protocols;\nusing Serilog;\nusing Xunit;\nusing Xunit.Abstractions;\n#if NETFRAMEWORK && (NET47 || NET471)\nusing static Libplanet.Tests.HashSetExtensions;\n#endif\n\nnamespace Libplanet.Net.Tests.Protocols\n{\n    public class RoutingTableTest\n    {\n        private const int BucketSize = 16;\n        private const int TableSize = Address.Size * sizeof(byte) * 8;\n\n        private static readonly PrivateKey VersionSigner = new PrivateKey();\n        private static readonly AppProtocolVersion AppProtocolVer =\n            AppProtocolVersion.Sign(VersionSigner, 1);\n\n        public RoutingTableTest(ITestOutputHelper output)\n        {\n            const string outputTemplate =\n                \"{Timestamp:HH:mm:ss:ffffff} - {Message}\";\n            Log.Logger = new LoggerConfiguration()\n                .MinimumLevel.Verbose()\n                .WriteTo.TestOutput(output, outputTemplate: outputTemplate)\n                .CreateLogger()\n                .ForContext<RoutingTableTest>();\n        }\n\n        [Fact]\n        public void AddSelf()\n        {\n            var pubKey = new PrivateKey().PublicKey;\n            var table = new RoutingTable(pubKey.Address);\n            var peer = new BoundPeer(pubKey, new DnsEndPoint(\"0.0.0.0\", 1234));\n            Assert.Throws<ArgumentException>(() => table.AddPeer(peer));\n        }\n\n        [Fact]\n        public void AddPeer()\n        {\n            var pubKey0 = new PrivateKey().PublicKey;\n            var pubKey1 = new PrivateKey().PublicKey;\n            var pubKey2 = new PrivateKey().PublicKey;\n            var pubKey3 = new PrivateKey().PublicKey;\n            var table = new RoutingTable(pubKey0.Address, 1, 2);\n            var peer1 = new BoundPeer(pubKey1, new DnsEndPoint(\"0.0.0.0\", 1234));\n            var peer2 = new BoundPeer(pubKey2, new DnsEndPoint(\"0.0.0.0\", 1234));\n            var peer3 = new BoundPeer(pubKey3, new DnsEndPoint(\"0.0.0.0\", 1234));\n            table.AddPeer(peer1);\n            table.AddPeer(peer2);\n            table.AddPeer(peer3);\n            table.AddPeer(peer1);\n            table.AddPeer(peer3);\n            Assert.Equal(\n                new HashSet<BoundPeer> { peer1, peer2 },\n                table.Peers.ToHashSet()\n            );\n        }\n\n        [Fact]\n        public void RemovePeer()\n        {\n            var pubKey1 = new PrivateKey().PublicKey;\n            var pubKey2 = new PrivateKey().PublicKey;\n            var table = new RoutingTable(pubKey1.Address, 1, 2);\n            var peer1 = new BoundPeer(pubKey1, new DnsEndPoint(\"0.0.0.0\", 1234));\n            var peer2 = new BoundPeer(pubKey2, new DnsEndPoint(\"0.0.0.0\", 1234));\n\n            Assert.Throws<ArgumentException>(() => table.RemovePeer(peer1));\n\n            bool ret = table.RemovePeer(peer2);\n            Assert.False(ret);\n            table.AddPeer(peer2);\n            ret = table.RemovePeer(peer2);\n            Assert.True(ret);\n        }\n\n        [Fact]\n        public void Generate()\n        {\n            var table = new RoutingTable(\n                new Address(\n                    new byte[]\n                    {\n                        0xaa, 0xba, 0xf4, 0x9a, 0x08, 0x49, 0xaf, 0xa2, 0x43, 0x0b, 0x8e, 0x2b,\n                        0xf7, 0xaf, 0x9c, 0x48, 0x05, 0xb7, 0x63, 0xb9,\n                    }));\n            const int targetBucket = 5;\n            int count = 0;\n            PublicKey publicKey;\n            do\n            {\n                count++;\n                publicKey = new PrivateKey().PublicKey;\n            }\n            while (table.GetBucketIndexOf(publicKey.Address) != targetBucket);\n\n            Log.Debug(\n                \"Found public key of bucket index {Index} in {Count} tries: {Key}\",\n                table.GetBucketIndexOf(publicKey.Address),\n                count,\n                ByteArrayToString(publicKey.Format(true)));\n            Assert.Equal(targetBucket, table.GetBucketIndexOf(publicKey.Address));\n        }\n\n        [Fact]\n        public void PeersToBroadcast()\n        {\n            var (publicKey, publicKeys) = GeneratePeersDifferentBuckets();\n\n            var table = new RoutingTable(publicKey.Address);\n            var peers = publicKeys\n                .Select(pk => new BoundPeer(pk, new DnsEndPoint(\"0.0.0.0\", 1234)))\n                .ToArray();\n            Assert.Equal(10, peers.Length);\n            for (var i = 0; i < peers.Length; i++)\n            {\n                var peer = peers[i];\n                table.AddPeer(peer);\n                Assert.Equal(i / 2, table.GetBucketIndexOf(peer.Address));\n            }\n\n            var broadcastCandidate = table.PeersToBroadcast(null, 0);\n            Assert.Equal(5, broadcastCandidate.Count);\n            Assert.Equal(\n                new HashSet<int> { 0, 1, 2, 3, 4 },\n                broadcastCandidate.Select(peer => table.GetBucketIndexOf(peer.Address))\n                    .ToHashSet());\n\n            broadcastCandidate = table.PeersToBroadcast(null, 10);\n            Assert.Equal(10, broadcastCandidate.Count);\n            Assert.Equal(peers.ToHashSet(), broadcastCandidate.ToHashSet());\n        }\n\n        [Fact]\n        public void PeersToRefresh()\n        {\n            var (publicKey, publicKeys) = GeneratePeersDifferentBuckets();\n            var table = new RoutingTable(publicKey.Address);\n            int peerCount = publicKeys.Length;\n            BoundPeer[] peers = publicKeys\n                .Select(\n                    key => new BoundPeer(\n                        key,\n                        new DnsEndPoint(\"0.0.0.0\", 1234)))\n                .ToArray();\n            for (var i = 0; i < peerCount; i++)\n            {\n                table.AddPeer(\n                    peers[i],\n                    DateTimeOffset.UtcNow - (i % 2 == 0 ? TimeSpan.Zero : TimeSpan.FromMinutes(2)));\n            }\n\n            Assert.Equal(peerCount, table.Peers.Count);\n            Assert.Equal(\n                Enumerable\n                    .Range(0, peerCount / 2)\n                    .Select(i => peers[i * 2 + 1]).ToHashSet(),\n                table.PeersToRefresh(TimeSpan.FromMinutes(1)).ToHashSet());\n        }\n\n        [Fact]\n        public void PeersToRefreshInSingleBucket()\n        {\n            var publicKey = new PrivateKey().PublicKey;\n            var table = new RoutingTable(publicKey.Address, 1);\n            const int peerCount = 10;\n            BoundPeer[] peers = Enumerable.Range(0, peerCount)\n                .Select(\n                    i => new BoundPeer(\n                        new PrivateKey().PublicKey,\n                        new DnsEndPoint(\"0.0.0.0\", 1000 + i)))\n                .ToArray();\n            for (int i = 0; i < peerCount; i++)\n            {\n                table.AddPeer(\n                    peers[i],\n                    DateTimeOffset.UtcNow - TimeSpan.FromMinutes(2) + TimeSpan.FromSeconds(i));\n            }\n\n            Assert.Equal(peerCount, table.Peers.Count);\n            for (int i = 0; i < peerCount; i++)\n            {\n                Assert.Equal(peers[i], table.PeersToRefresh(TimeSpan.FromMinutes(1)).First());\n                table.AddPeer(peers[i]);\n            }\n\n            Assert.Empty(table.PeersToRefresh(TimeSpan.FromMinutes(1)));\n        }\n\n        private (PublicKey, PublicKey[]) GeneratePeersDifferentBuckets()\n        {\n            var publicKey = new PublicKey(ByteUtil.ParseHex(\n                \"031df3534d8dee5d35d26cf41c52629326fc20bf96d49bdd6c4596db491896daf7\"));\n            var publicKeys = new[]\n            {\n                // Peer 0 is in bucket 0\n                new PublicKey(ByteUtil.ParseHex(\n                    \"02ac9d719f8dd7fb8d32a61f95b341e232edf7cae330c76bbfc3b988ef664d36b7\")),\n                // Peer 1 is in bucket 0\n                new PublicKey(ByteUtil.ParseHex(\n                    \"03a6a0eabb9a025e20b0890a0d5bfdf2168d3af96ac8e19d83265f75ce98a2dade\")),\n                // Peer 2 is in bucket 1\n                new PublicKey(ByteUtil.ParseHex(\n                    \"0224973583a36a2b80fdb7aea7e37fc5d3cd97aacc6a83f50eff3f499d6edc0b45\")),\n                // Peer 3 is in bucket 1\n                new PublicKey(ByteUtil.ParseHex(\n                    \"02bda770f7a0608135b47e1f07de2802d2a2ec61ae1e93f9416bb065a622b687a6\")),\n                // Peer 4 is in bucket 2\n                new PublicKey(ByteUtil.ParseHex(\n                    \"0273472fb28a73fe14a3ec598e7390340bacf5d83c7f4b22165a395d0b2fd9c721\")),\n                // Peer 5 is in bucket 2\n                new PublicKey(ByteUtil.ParseHex(\n                    \"035f735b3ea526d6af53d1102a5fe2b3cc95c7caae41dd58e1a35f1b8459ff8ada\")),\n                // Peer 6 is in bucket 3\n                new PublicKey(ByteUtil.ParseHex(\n                    \"0365bd28ceeb8b4a1e5636260f36ddd19f140e8e1e48201cdd57de7152266ea95b\")),\n                // Peer 7 is in bucket 3\n                new PublicKey(ByteUtil.ParseHex(\n                    \"0241049ccd1ecb8ac2be2c98db628e9ff29b9c3d2d8a3d63f2d1b7a6c3d30c7d8f\")),\n                // Peer 8 is in bucket 4\n                new PublicKey(ByteUtil.ParseHex(\n                    \"03384eeffb76caf5e95fccf154b4af1685d648a7c87d4474fffcf15d92a6e9796e\")),\n                // Peer 9 is in bucket 4\n                new PublicKey(ByteUtil.ParseHex(\n                    \"024c11057c7e18d604d45b01dbba6c03f06c9545a99850bc8e9b7c65be4197ce5c\")),\n            };\n\n            return (publicKey, publicKeys);\n        }\n\n        private string ByteArrayToString(byte[] bytes)\n        {\n            var str = BitConverter.ToString(bytes);\n            str = \"0x\" + str.Replace(\"-\", \", 0x\").ToLower();\n\n            return str + \",\";\n        }\n    }\n}\n"
  },
  {
    "path": "test/Libplanet.Net.Tests/Protocols/TestMessage.cs",
    "content": "#nullable disable\nusing System.Collections.Generic;\nusing System.Text;\nusing Libplanet.Net.Messages;\n\nnamespace Libplanet.Net.Tests.Protocols\n{\n    internal class TestMessage : MessageContent\n    {\n        public TestMessage(string data)\n        {\n            Data = data;\n        }\n\n        public TestMessage(byte[][] dataFrames)\n        {\n            Data = Encoding.UTF8.GetString(dataFrames[0]);\n        }\n\n        public string Data { get; }\n\n        public override MessageType Type => MessageType.Ping;\n\n        public override IEnumerable<byte[]> DataFrames => new[] { Encoding.UTF8.GetBytes(Data), };\n    }\n}\n"
  },
  {
    "path": "test/Libplanet.Net.Tests/Protocols/TestTransport.cs",
    "content": "#nullable disable\nusing System;\nusing System.Collections.Concurrent;\nusing System.Collections.Generic;\nusing System.Collections.Immutable;\nusing System.Linq;\nusing System.Net;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing Libplanet.Common;\nusing Libplanet.Crypto;\nusing Libplanet.Net.Messages;\nusing Libplanet.Net.Protocols;\nusing Libplanet.Net.Transports;\nusing Nito.AsyncEx;\nusing Serilog;\n\nnamespace Libplanet.Net.Tests.Protocols\n{\n    internal class TestTransport : ITransport\n    {\n        private static readonly AppProtocolVersion _appProtocolVersion =\n            AppProtocolVersion.Sign(new PrivateKey(), 1);\n\n        private readonly Dictionary<Address, TestTransport> _transports;\n        private readonly ILogger _logger;\n        private readonly ConcurrentDictionary<byte[], Address> _peersToReply;\n        private readonly ConcurrentDictionary<byte[], Message> _replyToReceive;\n        private readonly AsyncCollection<Request> _requests;\n        private readonly List<string> _ignoreTestMessageWithData;\n        private readonly PrivateKey _privateKey;\n        private readonly Random _random;\n        private readonly bool _blockBroadcast;\n\n        private TaskCompletionSource<object> _runningEvent;\n        private CancellationTokenSource _swarmCancellationTokenSource;\n        private TimeSpan _networkDelay;\n        private bool _disposed;\n\n        public TestTransport(\n            Dictionary<Address, TestTransport> transports,\n            PrivateKey privateKey,\n            bool blockBroadcast,\n            int tableSize,\n            int bucketSize,\n            TimeSpan? networkDelay)\n        {\n            _runningEvent = new TaskCompletionSource<object>();\n            _privateKey = privateKey;\n            _blockBroadcast = blockBroadcast;\n            var loggerId = _privateKey.Address.ToHex();\n            _logger = Log.ForContext<TestTransport>()\n                .ForContext(\"Address\", loggerId);\n\n            _peersToReply = new ConcurrentDictionary<byte[], Address>();\n            _replyToReceive = new ConcurrentDictionary<byte[], Message>();\n            ReceivedMessages = new ConcurrentBag<Message>();\n            MessageReceived = new AsyncAutoResetEvent();\n            _transports = transports;\n            _transports[privateKey.Address] = this;\n            _networkDelay = networkDelay ?? TimeSpan.Zero;\n            _requests = new AsyncCollection<Request>();\n            _ignoreTestMessageWithData = new List<string>();\n            _random = new Random();\n            Table = new RoutingTable(Address, tableSize, bucketSize);\n            ProcessMessageHandler = new AsyncDelegate<Message>();\n            Protocol = new KademliaProtocol(Table, this, Address);\n            MessageHistory = new FixedSizedQueue<Message>(30);\n        }\n\n        public AsyncDelegate<Message> ProcessMessageHandler { get; }\n\n        public AsyncAutoResetEvent MessageReceived { get; }\n\n        public Address Address => _privateKey.Address;\n\n        public BoundPeer AsPeer => new BoundPeer(\n            _privateKey.PublicKey,\n            new DnsEndPoint(\"127.0.0.1\", 1234));\n\n        public IReadOnlyList<BoundPeer> Peers => Table.Peers;\n\n        public DateTimeOffset? LastMessageTimestamp { get; private set; }\n\n        public bool Running\n        {\n            get => _runningEvent.Task.Status == TaskStatus.RanToCompletion;\n\n            private set\n            {\n                if (value)\n                {\n                    _runningEvent.TrySetResult(null);\n                }\n                else\n                {\n                    _runningEvent = new TaskCompletionSource<object>();\n                }\n            }\n        }\n\n        public ConcurrentQueue<Message> MessageHistory { get; }\n\n        public AppProtocolVersion AppProtocolVersion => _appProtocolVersion;\n\n        public IImmutableSet<PublicKey> TrustedAppProtocolVersionSigners =>\n            ImmutableHashSet<PublicKey>.Empty;\n\n        public DifferentAppProtocolVersionEncountered DifferentAppProtocolVersionEncountered =>\n            (peer, peerVersion, localVersion) => { };\n\n        internal ConcurrentBag<Message> ReceivedMessages { get; }\n\n        internal RoutingTable Table { get; }\n\n        internal IProtocol Protocol { get; }\n\n        public void Dispose()\n        {\n            if (!_disposed)\n            {\n                _swarmCancellationTokenSource?.Cancel();\n                Running = false;\n                _disposed = true;\n            }\n        }\n\n        public async Task StartAsync(\n            CancellationToken cancellationToken = default)\n        {\n            if (_disposed)\n            {\n                throw new ObjectDisposedException(nameof(TestTransport));\n            }\n\n            _logger.Debug(\"Starting transport of {Peer}\", AsPeer);\n            _swarmCancellationTokenSource = new CancellationTokenSource();\n            CancellationToken token = cancellationToken.Equals(CancellationToken.None)\n                ? _swarmCancellationTokenSource.Token\n                : CancellationTokenSource\n                    .CreateLinkedTokenSource(\n                        _swarmCancellationTokenSource.Token, cancellationToken)\n                    .Token;\n            Running = true;\n            await ProcessRuntime(token);\n        }\n\n        public async Task StopAsync(\n            TimeSpan waitFor,\n            CancellationToken cancellationToken = default)\n        {\n            if (_disposed)\n            {\n                throw new ObjectDisposedException(nameof(TestTransport));\n            }\n\n            if (Running)\n            {\n                _logger.Debug(\"Stopping transport of {Peer}\", AsPeer);\n                _swarmCancellationTokenSource.Cancel();\n                Running = false;\n            }\n\n            await Task.Delay(waitFor, cancellationToken);\n        }\n\n        /// <inheritdoc cref=\"ITransport.WaitForRunningAsync\"/>\n        public Task WaitForRunningAsync() => _runningEvent.Task;\n\n#pragma warning disable S4457 // Cannot split the method since method is in interface\n        public async Task BootstrapAsync(\n            IEnumerable<BoundPeer> bootstrapPeers,\n            TimeSpan? pingSeedTimeout = null,\n            int depth = 3,\n            CancellationToken cancellationToken = default)\n        {\n            if (_disposed)\n            {\n                throw new ObjectDisposedException(nameof(TestTransport));\n            }\n\n            if (!Running)\n            {\n                throw new TransportException(\"Start transport before use.\");\n            }\n\n            if (bootstrapPeers is null)\n            {\n                throw new ArgumentNullException(nameof(bootstrapPeers));\n            }\n\n            await Protocol.BootstrapAsync(\n                bootstrapPeers.ToImmutableList(),\n                pingSeedTimeout,\n                Kademlia.MaxDepth,\n                cancellationToken);\n        }\n\n        public Task SendMessageAsync(\n            BoundPeer peer,\n            MessageContent content,\n            CancellationToken cancellationToken)\n            => SendMessageAsync(\n                peer,\n                content,\n                TimeSpan.FromSeconds(3),\n                cancellationToken);\n\n        public Task AddPeersAsync(\n            IEnumerable<BoundPeer> peers,\n            TimeSpan? timeout,\n            CancellationToken cancellationToken = default)\n        {\n            if (_disposed)\n            {\n                throw new ObjectDisposedException(nameof(TestTransport));\n            }\n\n            if (!Running)\n            {\n                throw new TransportException(\"Start transport before use.\");\n            }\n\n            if (peers is null)\n            {\n                throw new ArgumentNullException(nameof(peers));\n            }\n\n            async Task DoAddPeersAsync()\n            {\n                try\n                {\n                    KademliaProtocol kp = (KademliaProtocol)Protocol;\n\n                    var tasks = new List<Task>();\n                    foreach (var peer in peers)\n                    {\n                        if (peer is BoundPeer boundPeer)\n                        {\n                            tasks.Add(\n                                kp.PingAsync(\n                                    boundPeer,\n                                    timeout: timeout,\n                                    cancellationToken: cancellationToken));\n                        }\n                    }\n\n                    _logger.Verbose(\"Trying to ping all {PeersNumber} peers\", tasks.Count);\n                    await Task.WhenAll(tasks);\n                    _logger.Verbose(\"Update complete\");\n                }\n                catch (DifferentAppProtocolVersionException)\n                {\n                    _logger.Debug(\n                        \"Different version encountered during {MethodName}()\",\n                        nameof(AddPeersAsync));\n                }\n                catch (PingTimeoutException)\n                {\n                    var msg =\n                        $\"Timeout occurred during {nameof(AddPeersAsync)}() after {timeout}\";\n                    _logger.Debug(msg);\n                    throw new TimeoutException(msg);\n                }\n                catch (TaskCanceledException)\n                {\n                    _logger.Debug(\n                        \"Task was cancelled during {MethodName}()\",\n                        nameof(AddPeersAsync));\n                }\n                catch (Exception e)\n                {\n                    _logger.Error(\n                        e,\n                        \"Unexpected exception occurred during {MethodName}()\",\n                        nameof(AddPeersAsync));\n                    throw;\n                }\n            }\n\n            return DoAddPeersAsync();\n        }\n\n        public void SendPing(BoundPeer peer, TimeSpan? timeSpan = null)\n        {\n            if (_disposed)\n            {\n                throw new ObjectDisposedException(nameof(TestTransport));\n            }\n\n            if (!Running)\n            {\n                throw new TransportException(\"Start transport before use.\");\n            }\n\n            Task.Run(() =>\n            {\n                _ = (Protocol as KademliaProtocol).PingAsync(\n                    peer,\n                    timeSpan,\n                    default);\n            });\n        }\n\n        public void BroadcastTestMessage(Address? except, string data)\n        {\n            if (_disposed)\n            {\n                throw new ObjectDisposedException(nameof(TestTransport));\n            }\n\n            if (!Running)\n            {\n                throw new TransportException(\"Start transport before use.\");\n            }\n\n            var message = new TestMessage(data);\n            _ignoreTestMessageWithData.Add(data);\n            BroadcastMessage(Table.PeersToBroadcast(except), message);\n        }\n\n        public void BroadcastMessage(IEnumerable<BoundPeer> peers, MessageContent content)\n        {\n            if (_disposed)\n            {\n                throw new ObjectDisposedException(nameof(TestTransport));\n            }\n\n            var peersList = peers.ToList();\n            var peersString = string.Join(\", \", peersList.Select(peer => peer.Address));\n            _logger.Debug(\n                \"Broadcasting test message {Data} to {Count} peers which are: {Peers}\",\n                ((TestMessage)content).Data,\n                peersList.Count,\n                peersString);\n            foreach (var peer in peersList)\n            {\n                _ = SendMessageAsync(peer, content, null, _swarmCancellationTokenSource.Token);\n            }\n        }\n\n#pragma warning disable S4457 // Cannot split the method since method is in interface\n        public async Task<Message> SendMessageAsync(\n            BoundPeer peer,\n            MessageContent content,\n            TimeSpan? timeout,\n            CancellationToken cancellationToken)\n        {\n            if (_disposed)\n            {\n                throw new ObjectDisposedException(nameof(TestTransport));\n            }\n\n            if (!Running)\n            {\n                throw new TransportException(\"Start transport before use.\");\n            }\n\n            var bytes = new byte[10];\n            _random.NextBytes(bytes);\n            var sendTime = DateTimeOffset.UtcNow;\n            var identity = _privateKey.Address.ByteArray.Concat(bytes).ToArray();\n            _logger.Debug(\"Adding request of {Content} of {Identity}\", content, identity);\n            await _requests.AddAsync(\n                new Request\n                {\n                    Message = new Message(\n                        content,\n                        AppProtocolVersion,\n                        AsPeer,\n                        sendTime,\n                        identity),\n                    Target = peer,\n                },\n                cancellationToken);\n\n            while (!cancellationToken.IsCancellationRequested &&\n                   !_replyToReceive.ContainsKey(identity))\n            {\n                if (DateTimeOffset.UtcNow - sendTime > (timeout ?? TimeSpan.MaxValue))\n                {\n                    _logger.Error(\n                        \"Reply of {Content} of {identity} did not received in \" +\n                        \"expected timespan {TimeSpan}\",\n                        content,\n                        identity,\n                        timeout ?? TimeSpan.MaxValue);\n                    throw new CommunicationFailException(\n                        $\"Timeout occurred during {nameof(SendMessageAsync)}().\",\n                        content.Type,\n                        peer);\n                }\n\n                await Task.Delay(10, cancellationToken);\n            }\n\n            if (cancellationToken.IsCancellationRequested)\n            {\n                throw new OperationCanceledException(\n                    $\"Operation is canceled during {nameof(SendMessageAsync)}().\");\n            }\n\n            if (_replyToReceive.TryRemove(identity, out Message reply))\n            {\n                _logger.Debug(\n                    \"Received reply {Content} of message with identity {identity}\",\n                    reply.Content,\n                    identity);\n                LastMessageTimestamp = DateTimeOffset.UtcNow;\n                ReceivedMessages.Add(reply);\n                MessageHistory.Enqueue(reply);\n                MessageReceived.Set();\n                return reply;\n            }\n            else\n            {\n                _logger.Error(\n                    \"Unexpected error occurred during \" +\n                    $\"{nameof(SendMessageAsync)}()\");\n                throw new SwarmException();\n            }\n        }\n#pragma warning restore S4457 // Cannot split the method since method is in interface\n\n        public async Task<IEnumerable<Message>> SendMessageAsync(\n            BoundPeer peer,\n            MessageContent content,\n            TimeSpan? timeout,\n            int expectedResponses,\n            bool returnWhenTimeout,\n            CancellationToken cancellationToken = default)\n        {\n            return new[]\n            {\n                await SendMessageAsync(peer, content, timeout, cancellationToken),\n            };\n        }\n\n        public async Task ReplyMessageAsync(\n            MessageContent content,\n            byte[] identity,\n            CancellationToken cancellationToken)\n        {\n            if (_disposed)\n            {\n                throw new ObjectDisposedException(nameof(TestTransport));\n            }\n\n            if (!Running)\n            {\n                throw new TransportException(\"Start transport before use.\");\n            }\n\n            _logger.Debug(\"Replying {Content}...\", content);\n            var message = new Message(\n                content,\n                AppProtocolVersion,\n                AsPeer,\n                DateTimeOffset.UtcNow,\n                identity);\n            await Task.Delay(_networkDelay, cancellationToken);\n            _transports[_peersToReply[identity]].ReceiveReply(message);\n            _peersToReply.TryRemove(identity, out Address addr);\n        }\n\n        public async Task WaitForTestMessageWithData(\n            string data,\n            CancellationToken token = default)\n        {\n            if (_disposed)\n            {\n                throw new ObjectDisposedException(nameof(TestTransport));\n            }\n\n            if (!Running)\n            {\n                throw new TransportException(\"Start transport before use.\");\n            }\n\n            while (!token.IsCancellationRequested && !ReceivedTestMessageOfData(data))\n            {\n                await Task.Delay(10, token);\n            }\n        }\n\n        public bool ReceivedTestMessageOfData(string data)\n        {\n            if (_disposed)\n            {\n                throw new ObjectDisposedException(nameof(TestTransport));\n            }\n\n            return ReceivedMessages.Select(m => m.Content)\n                .OfType<TestMessage>()\n                .Any(c => c.Data == data);\n        }\n\n        private void ReceiveMessage(Message message)\n        {\n            if (_swarmCancellationTokenSource.IsCancellationRequested)\n            {\n                return;\n            }\n\n            MessageHistory.Enqueue(message);\n            if (message.Content is TestMessage testMessage)\n            {\n                if (_ignoreTestMessageWithData.Contains(testMessage.Data))\n                {\n                    _logger.Debug(\"Ignore received test message {Data}\", testMessage.Data);\n                }\n                else\n                {\n                    _logger.Debug(\"Received test message with {Data}\", testMessage.Data);\n                    _ignoreTestMessageWithData.Add(testMessage.Data);\n                    // If this transport is blocked for testing, do not broadcast.\n                    if (!_blockBroadcast)\n                    {\n                        BroadcastTestMessage(message.Remote.Address, testMessage.Data);\n                    }\n                }\n            }\n            else\n            {\n                if (message.Identity is null)\n                {\n                    throw new ArgumentNullException(\"message.Identity\");\n                }\n\n                _peersToReply[message.Identity] = message.Remote.Address;\n            }\n\n            LastMessageTimestamp = DateTimeOffset.UtcNow;\n            ReceivedMessages.Add(message);\n            _ = ProcessMessageHandler.InvokeAsync(message);\n            MessageReceived.Set();\n        }\n\n        private void ReceiveReply(Message message)\n        {\n            if (message.Identity is null)\n            {\n                throw new ArgumentNullException(\"message.Identity\");\n            }\n\n            _replyToReceive[message.Identity] = message;\n        }\n\n        private async Task ProcessRuntime(CancellationToken cancellationToken)\n        {\n            while (!cancellationToken.IsCancellationRequested)\n            {\n                Request req = await _requests.TakeAsync(cancellationToken);\n\n                if (req.Message.Timestamp + _networkDelay <= DateTimeOffset.UtcNow)\n                {\n                    _logger.Debug(\n                        \"Send {Content} with identity {Identity} to {Peer}\",\n                        req.Message.Content,\n                        req.Message.Identity,\n                        req.Target);\n                    _transports[req.Target.Address].ReceiveMessage(req.Message);\n                }\n                else\n                {\n                    await _requests.AddAsync(req, cancellationToken);\n                    await Task.Delay(10, cancellationToken);\n                }\n            }\n        }\n\n        private struct Request\n        {\n            public BoundPeer Target;\n\n            public Message Message;\n        }\n    }\n}\n"
  },
  {
    "path": "test/Libplanet.Net.Tests/SwarmTest.AppProtocolVersion.cs",
    "content": "using System;\nusing System.Collections.Concurrent;\nusing System.Collections.Generic;\nusing System.Collections.Immutable;\nusing System.Linq;\nusing System.Threading.Tasks;\nusing Libplanet.Crypto;\nusing Libplanet.Net.Options;\nusing Libplanet.Net.Protocols;\nusing Xunit;\n\nnamespace Libplanet.Net.Tests\n{\n    public partial class SwarmTest\n    {\n        [Fact(Timeout = Timeout)]\n        public async Task DetectAppProtocolVersion()\n        {\n            var signer = new PrivateKey();\n            AppProtocolVersionOptions v2 = new AppProtocolVersionOptions()\n                { AppProtocolVersion = AppProtocolVersion.Sign(signer, 2) };\n            AppProtocolVersionOptions v3 = new AppProtocolVersionOptions()\n                { AppProtocolVersion = AppProtocolVersion.Sign(signer, 3) };\n            var a = await CreateSwarm(appProtocolVersionOptions: v2).ConfigureAwait(false);\n            var b = await CreateSwarm(appProtocolVersionOptions: v3).ConfigureAwait(false);\n            var c = await CreateSwarm(appProtocolVersionOptions: v2).ConfigureAwait(false);\n            var d = await CreateSwarm(appProtocolVersionOptions: v3).ConfigureAwait(false);\n\n            try\n            {\n                await StartAsync(c);\n                await StartAsync(d);\n\n                var peers = new[] { c.AsPeer, d.AsPeer };\n\n                foreach (var peer in peers)\n                {\n                    await a.AddPeersAsync(new[] { peer }, null);\n                    await b.AddPeersAsync(new[] { peer }, null);\n                }\n\n                Assert.Equal(new[] { c.AsPeer }, a.Peers.ToArray());\n                Assert.Equal(new[] { d.AsPeer }, b.Peers.ToArray());\n            }\n            finally\n            {\n                await StopAsync(c);\n                await StopAsync(d);\n\n                a.Dispose();\n                b.Dispose();\n                c.Dispose();\n                d.Dispose();\n            }\n        }\n\n        [Fact(Timeout = Timeout)]\n        public async Task HandleDifferentAppProtocolVersion()\n        {\n            var isCalled = false;\n\n            var signer = new PrivateKey();\n            AppProtocolVersionOptions v1 = new AppProtocolVersionOptions()\n            {\n                AppProtocolVersion = AppProtocolVersion.Sign(signer, 1),\n                TrustedAppProtocolVersionSigners =\n                    new HashSet<PublicKey>() { signer.PublicKey }.ToImmutableHashSet(),\n                DifferentAppProtocolVersionEncountered = (_, ver, __) => { isCalled = true; },\n            };\n            AppProtocolVersionOptions v2 = new AppProtocolVersionOptions()\n                { AppProtocolVersion = AppProtocolVersion.Sign(signer, 2) };\n            var a = await CreateSwarm(appProtocolVersionOptions: v1).ConfigureAwait(false);\n            var b = await CreateSwarm(appProtocolVersionOptions: v2).ConfigureAwait(false);\n\n            try\n            {\n                await StartAsync(b);\n\n                await Assert.ThrowsAsync<PeerDiscoveryException>(() => BootstrapAsync(a, b.AsPeer));\n\n                Assert.True(isCalled);\n            }\n            finally\n            {\n                await StopAsync(a);\n                await StopAsync(b);\n\n                a.Dispose();\n                b.Dispose();\n            }\n        }\n\n        [Fact(Timeout = Timeout)]\n        public async Task IgnoreUntrustedAppProtocolVersion()\n        {\n            var signer = new PrivateKey();\n            AppProtocolVersion older = AppProtocolVersion.Sign(signer, 2);\n            AppProtocolVersion newer = AppProtocolVersion.Sign(signer, 3);\n\n            var untrustedSigner = new PrivateKey();\n            AppProtocolVersion untrustedOlder = AppProtocolVersion.Sign(untrustedSigner, 2);\n            AppProtocolVersion untrustedNewer = AppProtocolVersion.Sign(untrustedSigner, 3);\n\n            _output.WriteLine(\"Trusted version signer: {0}\", signer.Address);\n            _output.WriteLine(\"Untrusted version signer: {0}\", untrustedSigner.Address);\n\n            var logs = new ConcurrentDictionary<BoundPeer, AppProtocolVersion>();\n\n            void DifferentAppProtocolVersionEncountered(\n                BoundPeer peer,\n                AppProtocolVersion peerVersion,\n                AppProtocolVersion localVersion\n            )\n            {\n                logs[peer] = peerVersion;\n            }\n\n            var trustedSigners = new[] { signer.PublicKey }.ToImmutableHashSet();\n            var untrustedSigners = new[] { untrustedSigner.PublicKey }.ToImmutableHashSet();\n            var optionsA = new AppProtocolVersionOptions()\n            {\n                AppProtocolVersion = older,\n                TrustedAppProtocolVersionSigners = trustedSigners,\n                DifferentAppProtocolVersionEncountered = DifferentAppProtocolVersionEncountered,\n            };\n            var a = await CreateSwarm(appProtocolVersionOptions: optionsA).ConfigureAwait(false);\n            var optionsB = new AppProtocolVersionOptions()\n            {\n                AppProtocolVersion = newer,\n                TrustedAppProtocolVersionSigners = trustedSigners,\n            };\n            var b = await CreateSwarm(appProtocolVersionOptions: optionsB).ConfigureAwait(false);\n            var optionsC = new AppProtocolVersionOptions()\n            {\n                AppProtocolVersion = older,\n                TrustedAppProtocolVersionSigners = trustedSigners,\n            };\n            var c = await CreateSwarm(appProtocolVersionOptions: optionsC).ConfigureAwait(false);\n            var optionsD = new AppProtocolVersionOptions()\n            {\n                AppProtocolVersion = newer,\n                TrustedAppProtocolVersionSigners = trustedSigners,\n            };\n            var d = await CreateSwarm(appProtocolVersionOptions: optionsD).ConfigureAwait(false);\n            var optionsE = new AppProtocolVersionOptions()\n            {\n                AppProtocolVersion = untrustedOlder,\n                TrustedAppProtocolVersionSigners = untrustedSigners,\n            };\n            var e = await CreateSwarm(appProtocolVersionOptions: optionsE).ConfigureAwait(false);\n            var optionsF = new AppProtocolVersionOptions()\n            {\n                AppProtocolVersion = untrustedNewer,\n                TrustedAppProtocolVersionSigners = untrustedSigners,\n            };\n            var f = await CreateSwarm(appProtocolVersionOptions: optionsF).ConfigureAwait(false);\n\n            try\n            {\n                await StartAsync(c);\n                await StartAsync(d);\n                await StartAsync(e);\n                await StartAsync(f);\n\n                await a.AddPeersAsync(new[] { c.AsPeer }, TimeSpan.FromSeconds(1));\n                await a.AddPeersAsync(new[] { d.AsPeer }, TimeSpan.FromSeconds(1));\n                await a.AddPeersAsync(new[] { e.AsPeer }, TimeSpan.FromSeconds(1));\n                await a.AddPeersAsync(new[] { f.AsPeer }, TimeSpan.FromSeconds(1));\n\n                await b.AddPeersAsync(new[] { c.AsPeer }, TimeSpan.FromSeconds(1));\n                await b.AddPeersAsync(new[] { d.AsPeer }, TimeSpan.FromSeconds(1));\n                await b.AddPeersAsync(new[] { e.AsPeer }, TimeSpan.FromSeconds(1));\n                await b.AddPeersAsync(new[] { f.AsPeer }, TimeSpan.FromSeconds(1));\n\n                Assert.Equal(new[] { c.AsPeer }, a.Peers.ToArray());\n                Assert.Equal(new[] { d.AsPeer }, b.Peers.ToArray());\n\n                _output.WriteLine(\"Logged encountered peers:\");\n                foreach (KeyValuePair<BoundPeer, AppProtocolVersion> kv in logs)\n                {\n                    _output.WriteLine(\n                        \"{0}; {1}; {2} -> {3}\",\n                        kv.Key,\n                        kv.Value.Version,\n                        kv.Value.Signer,\n                        kv.Value.Verify(signer.PublicKey) ? \"verified\" : \"not verified\"\n                    );\n                }\n            }\n            finally\n            {\n                await StopAsync(c);\n                await StopAsync(d);\n                await StopAsync(e);\n                await StopAsync(f);\n\n                a.Dispose();\n                b.Dispose();\n                c.Dispose();\n                d.Dispose();\n                e.Dispose();\n                f.Dispose();\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "test/Libplanet.Net.Tests/SwarmTest.Broadcast.cs",
    "content": "#nullable disable\nusing System;\nusing System.Collections.Generic;\nusing System.Collections.Immutable;\nusing System.Linq;\nusing System.Net;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing Libplanet.Action;\nusing Libplanet.Action.Loader;\nusing Libplanet.Action.Tests.Common;\nusing Libplanet.Blockchain;\nusing Libplanet.Blockchain.Policies;\nusing Libplanet.Blockchain.Renderers;\nusing Libplanet.Blockchain.Renderers.Debug;\nusing Libplanet.Crypto;\nusing Libplanet.Net.Messages;\nusing Libplanet.Net.Options;\nusing Libplanet.Net.Transports;\nusing Libplanet.Store;\nusing Libplanet.Store.Trie;\nusing Libplanet.Tests.Blockchain.Evidence;\nusing Libplanet.Tests.Store;\nusing Libplanet.Types.Blocks;\nusing Libplanet.Types.Evidence;\nusing Libplanet.Types.Tx;\nusing Serilog;\nusing Serilog.Events;\nusing xRetry;\nusing Xunit;\n#if NETFRAMEWORK && (NET47 || NET471)\nusing static Libplanet.Tests.HashSetExtensions;\n#endif\nusing static Libplanet.Tests.LoggerExtensions;\nusing static Libplanet.Tests.TestUtils;\n\nnamespace Libplanet.Net.Tests\n{\n    public partial class SwarmTest\n    {\n        [Fact(Timeout = Timeout)]\n        public async Task BroadcastBlock()\n        {\n            const int numBlocks = 5;\n            var policy = new NullBlockPolicy();\n            var genesis = new MemoryStoreFixture(policy.PolicyActionsRegistry).GenesisBlock;\n\n            var swarmA = await CreateSwarm(\n                privateKey: new PrivateKey(),\n                policy: policy,\n                genesis: genesis).ConfigureAwait(false);\n            var swarmB = await CreateSwarm(\n                privateKey: new PrivateKey(),\n                policy: policy,\n                genesis: genesis).ConfigureAwait(false);\n            var chainA = swarmA.BlockChain;\n            var chainB = swarmB.BlockChain;\n\n            foreach (int i in Enumerable.Range(0, numBlocks))\n            {\n                var block = chainA.ProposeBlock(\n                    new PrivateKey(), TestUtils.CreateBlockCommit(chainA.Tip));\n                chainA.Append(block, TestUtils.CreateBlockCommit(block));\n            }\n\n            Assert.Equal(numBlocks, chainA.Tip.Index);\n            Assert.NotEqual(chainA.Tip, chainB.Tip);\n            Assert.NotNull(chainA.GetBlockCommit(chainA.Tip.Hash));\n\n            try\n            {\n                await StartAsync(swarmA);\n                await StartAsync(swarmB);\n\n                await swarmA.AddPeersAsync(new[] { swarmB.AsPeer }, null);\n                await swarmB.AddPeersAsync(new[] { swarmA.AsPeer }, null);\n\n                swarmA.BroadcastBlock(chainA.Tip);\n                await swarmB.BlockAppended.WaitAsync();\n\n                Assert.Equal(chainA.Tip, chainB.Tip);\n                Assert.Equal(\n                    chainA.GetBlockCommit(chainA.Tip.Hash),\n                    chainB.GetBlockCommit(chainB.Tip.Hash));\n            }\n            finally\n            {\n                CleaningSwarm(swarmA);\n                CleaningSwarm(swarmB);\n            }\n        }\n\n        [Fact(Timeout = Timeout)]\n        public async Task BroadcastBlockToReconnectedPeer()\n        {\n            var miner = new PrivateKey();\n            var policy = new NullBlockPolicy();\n            var fx = new MemoryStoreFixture(policy.PolicyActionsRegistry);\n            var minerChain = MakeBlockChain(\n                policy, fx.Store, fx.StateStore, new SingleActionLoader(typeof(DumbAction)));\n            foreach (int i in Enumerable.Range(0, 10))\n            {\n                Block block = minerChain.ProposeBlock(\n                    miner, CreateBlockCommit(minerChain.Tip));\n                minerChain.Append(block, TestUtils.CreateBlockCommit(block));\n            }\n\n            Swarm seed = await CreateSwarm(\n                miner,\n                policy: policy,\n                genesis: minerChain.Genesis\n            ).ConfigureAwait(false);\n            BlockChain seedChain = seed.BlockChain;\n\n            var privateKey = new PrivateKey();\n            Swarm swarmA = await CreateSwarm(\n                privateKey: privateKey,\n                policy: policy,\n                genesis: minerChain.Genesis\n            ).ConfigureAwait(false);\n            Swarm swarmB = await CreateSwarm(\n                privateKey: privateKey,\n                policy: policy,\n                genesis: minerChain.Genesis\n            ).ConfigureAwait(false);\n\n            foreach (BlockHash blockHash in minerChain.BlockHashes.Skip(1).Take(4))\n            {\n                seedChain.Append(\n                    minerChain[blockHash],\n                    TestUtils.CreateBlockCommit(minerChain[blockHash]));\n            }\n\n            try\n            {\n                await StartAsync(seed);\n                await StartAsync(swarmA);\n                await StartAsync(swarmB);\n\n                Assert.Equal(swarmA.AsPeer.Address, swarmB.AsPeer.Address);\n                Assert.Equal(swarmA.AsPeer.PublicIPAddress, swarmB.AsPeer.PublicIPAddress);\n\n                await swarmA.AddPeersAsync(new[] { seed.AsPeer }, null);\n                await StopAsync(swarmA);\n                await seed.PeerDiscovery.RefreshTableAsync(\n                    TimeSpan.Zero,\n                    default);\n\n                Assert.DoesNotContain(swarmA.AsPeer, seed.Peers);\n\n                foreach (BlockHash blockHash in minerChain.BlockHashes.Skip(5))\n                {\n                    seedChain.Append(\n                        minerChain[blockHash],\n                        TestUtils.CreateBlockCommit(minerChain[blockHash]));\n                }\n\n                await swarmB.AddPeersAsync(new[] { seed.AsPeer }, null);\n\n                // This is added for context switching.\n                await Task.Delay(100);\n\n                Assert.Contains(swarmB.AsPeer, seed.Peers);\n                Assert.Contains(seed.AsPeer, swarmB.Peers);\n\n                seed.BroadcastBlock(seedChain.Tip);\n\n                await swarmB.BlockAppended.WaitAsync();\n\n                Assert.NotEqual(seedChain.BlockHashes, swarmA.BlockChain.BlockHashes);\n                Assert.Equal(seedChain.BlockHashes, swarmB.BlockChain.BlockHashes);\n            }\n            finally\n            {\n                CleaningSwarm(seed);\n                CleaningSwarm(swarmA);\n                CleaningSwarm(swarmB);\n            }\n        }\n\n        [Fact(Timeout = Timeout)]\n        public async Task BroadcastIgnoreFromDifferentGenesisHash()\n        {\n            var receiverKey = new PrivateKey();\n            Swarm receiverSwarm = await CreateSwarm(receiverKey).ConfigureAwait(false);\n            BlockChain receiverChain = receiverSwarm.BlockChain;\n            var seedStateStore = new TrieStateStore(new MemoryKeyValueStore());\n            IBlockPolicy policy = receiverChain.Policy;\n            BlockChain seedChain = MakeBlockChain(\n                policy,\n                new MemoryStore(),\n                seedStateStore,\n                new SingleActionLoader(typeof(DumbAction)),\n                privateKey: receiverKey);\n            var seedMiner = new PrivateKey();\n            Swarm seedSwarm =\n                await CreateSwarm(seedChain, seedMiner).ConfigureAwait(false);\n            try\n            {\n                await StartAsync(receiverSwarm);\n                await StartAsync(seedSwarm);\n\n                await receiverSwarm.AddPeersAsync(new[] { seedSwarm.AsPeer }, null);\n                Block block = seedChain.ProposeBlock(seedMiner);\n                seedChain.Append(block, TestUtils.CreateBlockCommit(block));\n                seedSwarm.BroadcastBlock(block);\n                Assert.NotEqual(seedChain.Tip, receiverChain.Tip);\n            }\n            finally\n            {\n                CleaningSwarm(seedSwarm);\n                CleaningSwarm(receiverSwarm);\n            }\n        }\n\n        [RetryFact(10, Timeout = Timeout)]\n        public async Task BroadcastWhileMining()\n        {\n            var minerA = new PrivateKey();\n            var minerB = new PrivateKey();\n            Swarm a = await CreateSwarm(minerA).ConfigureAwait(false);\n            Swarm b = await CreateSwarm(minerB).ConfigureAwait(false);\n\n            BlockChain chainA = a.BlockChain;\n            BlockChain chainB = b.BlockChain;\n\n            Task CreateMiner(\n                PrivateKey miner,\n                Swarm swarm,\n                BlockChain chain,\n                int delay,\n                CancellationToken cancellationToken\n            )\n            {\n                return Task.Run(async () =>\n                {\n                    while (!cancellationToken.IsCancellationRequested)\n                    {\n                        try\n                        {\n                            var block = chain.ProposeBlock(\n                                miner, CreateBlockCommit(chain.Tip));\n                            chain.Append(block, TestUtils.CreateBlockCommit(block));\n\n                            Log.Debug(\n                                \"Block mined. [Node: {0}, Block: {1}]\",\n                                swarm.Address,\n                                block.Hash);\n                            swarm.BroadcastBlock(block);\n                        }\n                        catch (OperationCanceledException)\n                        {\n                            continue;\n                        }\n                        finally\n                        {\n                            await Task.Delay(delay);\n                        }\n                    }\n\n                    swarm.BroadcastBlock(chain[-1]);\n                    Log.Debug(\"Mining complete\");\n                });\n            }\n\n            try\n            {\n                await StartAsync(a);\n                await StartAsync(b);\n\n                await a.AddPeersAsync(new[] { b.AsPeer }, null);\n\n                var minerCanceller = new CancellationTokenSource();\n                Task miningA = CreateMiner(minerA, a, chainA, 4000, minerCanceller.Token);\n\n                await Task.Delay(10000);\n                minerCanceller.Cancel();\n\n                await miningA;\n                await Task.Delay(5000);\n            }\n            finally\n            {\n                CleaningSwarm(a);\n                CleaningSwarm(b);\n            }\n\n            _logger.CompareBothChains(LogEventLevel.Debug, \"A\", chainA, \"B\", chainB);\n            Assert.Equal(chainA.BlockHashes, chainB.BlockHashes);\n        }\n\n        [Fact(Timeout = Timeout)]\n        public async Task BroadcastTx()\n        {\n            var minerA = new PrivateKey();\n            Swarm swarmA = await CreateSwarm(minerA).ConfigureAwait(false);\n            Swarm swarmB = await CreateSwarm().ConfigureAwait(false);\n            Swarm swarmC = await CreateSwarm().ConfigureAwait(false);\n\n            BlockChain chainA = swarmA.BlockChain;\n            BlockChain chainB = swarmB.BlockChain;\n            BlockChain chainC = swarmC.BlockChain;\n\n            Transaction tx = Transaction.Create(\n                0,\n                new PrivateKey(),\n                chainA.Genesis.Hash,\n                new DumbAction[] { }.ToPlainValues()\n            );\n\n            chainA.StageTransaction(tx);\n            Block block = chainA.ProposeBlock(minerA);\n            chainA.Append(block, TestUtils.CreateBlockCommit(block));\n\n            try\n            {\n                await StartAsync(swarmA);\n                await StartAsync(swarmB);\n                await StartAsync(swarmC);\n\n                await swarmA.AddPeersAsync(new[] { swarmB.AsPeer }, null);\n                await swarmB.AddPeersAsync(new[] { swarmC.AsPeer }, null);\n                await swarmC.AddPeersAsync(new[] { swarmA.AsPeer }, null);\n\n                swarmA.BroadcastTxs(new[] { tx });\n\n                await swarmC.TxReceived.WaitAsync();\n                await swarmB.TxReceived.WaitAsync();\n\n                Assert.Equal(tx, chainB.GetTransaction(tx.Id));\n                Assert.Equal(tx, chainC.GetTransaction(tx.Id));\n            }\n            finally\n            {\n                CleaningSwarm(swarmA);\n                CleaningSwarm(swarmB);\n                CleaningSwarm(swarmC);\n            }\n        }\n\n        [Fact(Timeout = Timeout)]\n        public async Task BroadcastTxWhileMining()\n        {\n            Swarm swarmA = await CreateSwarm().ConfigureAwait(false);\n            var minerC = new PrivateKey();\n            Swarm swarmC = await CreateSwarm(minerC).ConfigureAwait(false);\n\n            BlockChain chainA = swarmA.BlockChain;\n            BlockChain chainC = swarmC.BlockChain;\n\n            var privateKey = new PrivateKey();\n            var address = privateKey.Address;\n            var txCount = 10;\n\n            var txs = Enumerable.Range(0, txCount).Select(_ =>\n                    chainA.MakeTransaction(\n                        new PrivateKey(),\n                        new[] { DumbAction.Create((address, \"foo\")) }))\n                .ToArray();\n\n            try\n            {\n                await StartAsync(swarmA);\n                await StartAsync(swarmC);\n\n                await swarmC.AddPeersAsync(new[] { swarmA.AsPeer }, null);\n                Assert.Contains(swarmC.AsPeer, swarmA.Peers);\n                Assert.Contains(swarmA.AsPeer, swarmC.Peers);\n\n                Task miningTask = Task.Run(() =>\n                {\n                    for (var i = 0; i < 10; i++)\n                    {\n                        Block block = chainC.ProposeBlock(\n                            minerC, CreateBlockCommit(chainC.Tip));\n                        chainC.Append(block, TestUtils.CreateBlockCommit(block));\n                    }\n                });\n\n                Task txReceivedTask = swarmC.TxReceived.WaitAsync();\n\n                for (var i = 0; i < 100; i++)\n                {\n                    swarmA.BroadcastTxs(txs);\n                }\n\n                await txReceivedTask;\n                await miningTask;\n\n                for (var i = 0; i < txCount; i++)\n                {\n                    Assert.NotNull(chainC.GetTransaction(txs[i].Id));\n                }\n            }\n            finally\n            {\n                CleaningSwarm(swarmA);\n                CleaningSwarm(swarmC);\n            }\n        }\n\n        [Fact(Timeout = Timeout)]\n        public async Task BroadcastTxAsync()\n        {\n            Swarm swarmA = await CreateSwarm().ConfigureAwait(false);\n            Swarm swarmB = await CreateSwarm().ConfigureAwait(false);\n            Swarm swarmC = await CreateSwarm().ConfigureAwait(false);\n\n            BlockChain chainA = swarmA.BlockChain;\n            BlockChain chainB = swarmB.BlockChain;\n            BlockChain chainC = swarmC.BlockChain;\n\n            Transaction tx = Transaction.Create(\n                0,\n                new PrivateKey(),\n                chainA.Genesis.Hash,\n                new DumbAction[] { }.ToPlainValues()\n            );\n\n            chainA.StageTransaction(tx);\n\n            try\n            {\n                await StartAsync(swarmA);\n                await StartAsync(swarmB);\n                await StartAsync(swarmC);\n\n                // Broadcast tx swarmA to swarmB\n                await swarmA.AddPeersAsync(new[] { swarmB.AsPeer }, null);\n\n                await swarmB.TxReceived.WaitAsync();\n                Assert.Equal(tx, chainB.GetTransaction(tx.Id));\n\n                CleaningSwarm(swarmA);\n\n                // Re-Broadcast received tx swarmB to swarmC\n                await swarmB.AddPeersAsync(new[] { swarmC.AsPeer }, null);\n\n                await swarmC.TxReceived.WaitAsync();\n                Assert.Equal(tx, chainC.GetTransaction(tx.Id));\n            }\n            finally\n            {\n                CleaningSwarm(swarmB);\n                CleaningSwarm(swarmC);\n            }\n        }\n\n        [RetryFact(Timeout = Timeout)]\n        public async Task BroadcastTxAsyncMany()\n        {\n            int size = 5;\n\n            var policy = new BlockPolicy();\n            StoreFixture[] fxs = new StoreFixture[size];\n            BlockChain[] blockChains = new BlockChain[size];\n            Swarm[] swarms = new Swarm[size];\n\n            for (int i = 0; i < size; i++)\n            {\n                fxs[i] = new MemoryStoreFixture();\n                blockChains[i] = BlockChain.Create(\n                    policy,\n                    new VolatileStagePolicy(),\n                    fxs[i].Store,\n                    fxs[i].StateStore,\n                    fxs[i].GenesisBlock,\n                    new ActionEvaluator(\n                        policyActionsRegistry: policy.PolicyActionsRegistry,\n                        stateStore: fxs[i].StateStore,\n                        actionTypeLoader: new SingleActionLoader(typeof(DumbAction))));\n                swarms[i] = await CreateSwarm(blockChains[i]).ConfigureAwait(false);\n            }\n\n            Transaction tx = Transaction.Create(\n                0,\n                new PrivateKey(),\n                blockChains[size - 1].Genesis.Hash,\n                new DumbAction[] { }.ToPlainValues()\n            );\n\n            blockChains[size - 1].StageTransaction(tx);\n\n            try\n            {\n                for (int i = 0; i < size; i++)\n                {\n                    await StartAsync(swarms[i]);\n                }\n\n                List<Task> tasks = new List<Task>();\n                for (int i = 1; i < size; i++)\n                {\n                    await BootstrapAsync(swarms[i], swarms[0].AsPeer);\n                }\n\n                for (int i = 0; i < size - 1; i++)\n                {\n                    tasks.Add(swarms[i].TxReceived.WaitAsync());\n                }\n\n                await Task.WhenAll(tasks);\n\n                for (int i = 0; i < size; i++)\n                {\n                    Assert.Equal(tx, blockChains[i].GetTransaction(tx.Id));\n                }\n            }\n            finally\n            {\n                for (int i = 0; i < size; i++)\n                {\n                    CleaningSwarm(swarms[i]);\n                    fxs[i].Dispose();\n                }\n            }\n        }\n\n        [Fact(Timeout = Timeout)]\n        public async Task DoNotRebroadcastTxsWithLowerNonce()\n        {\n            // If the bucket stored peers are the same, the block may not propagate,\n            // so specify private keys to make the buckets different.\n            PrivateKey keyA = PrivateKey.FromString(\n                \"8568eb6f287afedece2c7b918471183db0451e1a61535bb0381cfdf95b85df20\");\n            PrivateKey keyB = PrivateKey.FromString(\n                \"c34f7498befcc39a14f03b37833f6c7bb78310f1243616524eda70e078b8313c\");\n            PrivateKey keyC = PrivateKey.FromString(\n                \"941bc2edfab840d79914d80fe3b30840628ac37a5d812d7f922b5d2405a223d3\");\n\n            var autoBroadcastDisabled = new SwarmOptions\n            {\n                BlockBroadcastInterval = TimeSpan.FromSeconds(Timeout),\n                TxBroadcastInterval = TimeSpan.FromSeconds(Timeout),\n            };\n\n            var swarmA =\n                await CreateSwarm(keyA, options: autoBroadcastDisabled).ConfigureAwait(false);\n            var swarmB =\n                await CreateSwarm(keyB, options: autoBroadcastDisabled).ConfigureAwait(false);\n            var swarmC =\n                await CreateSwarm(keyC, options: autoBroadcastDisabled).ConfigureAwait(false);\n\n            BlockChain chainA = swarmA.BlockChain;\n            BlockChain chainB = swarmB.BlockChain;\n            BlockChain chainC = swarmC.BlockChain;\n\n            var privateKey = new PrivateKey();\n\n            try\n            {\n                var tx1 = swarmA.BlockChain.MakeTransaction(\n                    privateKey: privateKey,\n                    actions: new DumbAction[] { });\n                var tx2 = swarmA.BlockChain.MakeTransaction(\n                    privateKey: privateKey,\n                    actions: new DumbAction[] { });\n                Assert.Equal(0, tx1.Nonce);\n                Assert.Equal(1, tx2.Nonce);\n\n                await StartAsync(swarmA);\n                await StartAsync(swarmB);\n                await swarmA.AddPeersAsync(new[] { swarmB.AsPeer }, null);\n                swarmA.BroadcastTxs(new[] { tx1, tx2 });\n                await swarmB.TxReceived.WaitAsync();\n                Assert.Equal(\n                    new HashSet<TxId> { tx1.Id, tx2.Id },\n                    chainB.GetStagedTransactionIds().ToHashSet());\n                swarmA.RoutingTable.RemovePeer(swarmB.AsPeer);\n                swarmB.RoutingTable.RemovePeer(swarmA.AsPeer);\n\n                chainA.UnstageTransaction(tx2);\n                Assert.Equal(1, chainA.GetNextTxNonce(privateKey.Address));\n\n                await StopAsync(swarmA);\n                await StopAsync(swarmB);\n\n                swarmA.RoutingTable.RemovePeer(swarmB.AsPeer);\n                swarmB.RoutingTable.RemovePeer(swarmA.AsPeer);\n                Assert.Empty(swarmA.Peers);\n                Assert.Empty(swarmB.Peers);\n\n                await StartAsync(swarmA);\n                await StartAsync(swarmB);\n\n                Block block = chainB.ProposeBlock(keyB);\n                chainB.Append(block, TestUtils.CreateBlockCommit(block));\n\n                var tx3 = chainA.MakeTransaction(\n                    privateKey: privateKey,\n                    actions: new DumbAction[] { });\n                var tx4 = chainA.MakeTransaction(\n                    privateKey: privateKey,\n                    actions: new DumbAction[] { });\n                Assert.Equal(1, tx3.Nonce);\n                Assert.Equal(2, tx4.Nonce);\n\n                await StartAsync(swarmC);\n                await swarmA.AddPeersAsync(new[] { swarmB.AsPeer }, null);\n                await swarmB.AddPeersAsync(new[] { swarmC.AsPeer }, null);\n\n                swarmA.BroadcastTxs(new[] { tx3, tx4 });\n                await swarmB.TxReceived.WaitAsync();\n\n                // SwarmB receives tx3 and is staged, but policy filters it.\n                Assert.DoesNotContain(tx3.Id, chainB.GetStagedTransactionIds());\n                Assert.Contains(\n                    tx3.Id,\n                    chainB.StagePolicy.Iterate(chainB, filtered: false).Select(tx => tx.Id));\n                Assert.Contains(tx4.Id, chainB.GetStagedTransactionIds());\n\n                await swarmC.TxReceived.WaitAsync();\n                // SwarmC can not receive tx3 because SwarmB does not rebroadcast it.\n                Assert.DoesNotContain(tx3.Id, chainC.GetStagedTransactionIds());\n                Assert.DoesNotContain(\n                    tx3.Id,\n                    chainC.StagePolicy.Iterate(chainC, filtered: false).Select(tx => tx.Id));\n                Assert.Contains(tx4.Id, chainC.GetStagedTransactionIds());\n            }\n            finally\n            {\n                CleaningSwarm(swarmA);\n                CleaningSwarm(swarmB);\n                CleaningSwarm(swarmC);\n            }\n        }\n\n        [Fact(Timeout = Timeout)]\n        public async Task CanBroadcastBlock()\n        {\n            // If the bucket stored peers are the same, the block may not propagate,\n            // so specify private keys to make the buckets different.\n            PrivateKey keyA = PrivateKey.FromString(\n                \"8568eb6f287afedece2c7b918471183db0451e1a61535bb0381cfdf95b85df20\");\n            PrivateKey keyB = PrivateKey.FromString(\n                \"c34f7498befcc39a14f03b37833f6c7bb78310f1243616524eda70e078b8313c\");\n            PrivateKey keyC = PrivateKey.FromString(\n                \"941bc2edfab840d79914d80fe3b30840628ac37a5d812d7f922b5d2405a223d3\");\n\n            var swarmA = await CreateSwarm(keyA).ConfigureAwait(false);\n            var swarmB = await CreateSwarm(keyB).ConfigureAwait(false);\n            var swarmC = await CreateSwarm(keyC).ConfigureAwait(false);\n\n            BlockChain chainA = swarmA.BlockChain;\n            BlockChain chainB = swarmB.BlockChain;\n            BlockChain chainC = swarmC.BlockChain;\n\n            foreach (int i in Enumerable.Range(0, 10))\n            {\n                Block block = chainA.ProposeBlock(\n                    keyA, CreateBlockCommit(chainA.Tip));\n                chainA.Append(block, TestUtils.CreateBlockCommit(block));\n                if (i < 5)\n                {\n                    chainB.Append(block, TestUtils.CreateBlockCommit(block));\n                }\n            }\n\n            try\n            {\n                await StartAsync(swarmA);\n                await StartAsync(swarmB);\n                await StartAsync(swarmC);\n\n                await BootstrapAsync(swarmB, swarmA.AsPeer);\n                await BootstrapAsync(swarmC, swarmA.AsPeer);\n\n                swarmB.BroadcastBlock(chainB.Tip);\n\n                // chainA ignores block header received because its index is shorter.\n                await swarmA.BlockHeaderReceived.WaitAsync();\n                await swarmC.BlockAppended.WaitAsync();\n                Assert.False(swarmA.BlockAppended.IsSet);\n\n                // chainB doesn't applied to chainA since chainB is shorter\n                // than chainA\n                Assert.NotEqual(chainB, chainA);\n\n                swarmA.BroadcastBlock(chainA.Tip);\n\n                await swarmB.BlockAppended.WaitAsync();\n                await swarmC.BlockAppended.WaitAsync();\n\n                Log.Debug(\"Compare chainA and chainB\");\n                Assert.Equal(chainA.BlockHashes, chainB.BlockHashes);\n                Log.Debug(\"Compare chainA and chainC\");\n                Assert.Equal(chainA.BlockHashes, chainC.BlockHashes);\n            }\n            finally\n            {\n                CleaningSwarm(swarmA);\n                CleaningSwarm(swarmB);\n                CleaningSwarm(swarmC);\n            }\n        }\n\n        [Fact(Timeout = Timeout)]\n        public async Task BroadcastBlockWithSkip()\n        {\n            var policy = new BlockPolicy(\n                new PolicyActionsRegistry(\n                    endBlockActions: ImmutableArray.Create<IAction>(new MinerReward(1))));\n            var fx1 = new MemoryStoreFixture();\n            var blockChain = MakeBlockChain(\n                policy, fx1.Store, fx1.StateStore, new SingleActionLoader(typeof(DumbAction)));\n            var privateKey = new PrivateKey();\n            var minerSwarm = await CreateSwarm(blockChain, privateKey).ConfigureAwait(false);\n            var fx2 = new MemoryStoreFixture();\n            var receiverRenderer = new RecordingActionRenderer();\n            var loggedRenderer = new LoggedActionRenderer(\n                receiverRenderer,\n                _logger);\n            var receiverChain = MakeBlockChain(\n                policy,\n                fx2.Store,\n                fx2.StateStore,\n                new SingleActionLoader(typeof(DumbAction)),\n                renderers: new[] { loggedRenderer });\n            Swarm receiverSwarm =\n                await CreateSwarm(receiverChain).ConfigureAwait(false);\n\n            int renderCount = 0;\n\n            receiverRenderer.RenderEventHandler += (_, a) => renderCount += IsDumbAction(a) ? 1 : 0;\n\n            Transaction[] transactions =\n            {\n                fx1.MakeTransaction(\n                    new[]\n                    {\n                        DumbAction.Create((fx1.Address2, \"foo\")),\n                        DumbAction.Create((fx1.Address2, \"bar\")),\n                    },\n                    timestamp: DateTimeOffset.MinValue,\n                    nonce: 0,\n                    privateKey: privateKey),\n                fx1.MakeTransaction(\n                    new[]\n                    {\n                        DumbAction.Create((fx1.Address2, \"baz\")),\n                        DumbAction.Create((fx1.Address2, \"qux\")),\n                    },\n                    timestamp: DateTimeOffset.MinValue.AddSeconds(5),\n                    nonce: 1,\n                    privateKey: privateKey),\n            };\n\n            Block block1 = blockChain.ProposeBlock(\n                GenesisProposer,\n                new[] { transactions[0] }.ToImmutableList(),\n                TestUtils.CreateBlockCommit(blockChain.Tip),\n                ImmutableArray<EvidenceBase>.Empty);\n            blockChain.Append(block1, TestUtils.CreateBlockCommit(block1), true);\n            Block block2 = blockChain.ProposeBlock(\n                GenesisProposer,\n                new[] { transactions[1] }.ToImmutableList(),\n                CreateBlockCommit(blockChain.Tip),\n                ImmutableArray<EvidenceBase>.Empty);\n            blockChain.Append(block2, TestUtils.CreateBlockCommit(block2), true);\n\n            try\n            {\n                await StartAsync(minerSwarm);\n                await StartAsync(receiverSwarm);\n\n                await BootstrapAsync(receiverSwarm, minerSwarm.AsPeer);\n\n                minerSwarm.BroadcastBlock(block2);\n\n                await AssertThatEventually(\n                    () => receiverChain.Tip.Equals(block2),\n                    5_000,\n                    1_000\n                );\n                Assert.Equal(3, receiverChain.Count);\n                Assert.Equal(4, renderCount);\n            }\n            finally\n            {\n                CleaningSwarm(minerSwarm);\n                CleaningSwarm(receiverSwarm);\n                fx1.Dispose();\n            }\n        }\n\n        [Fact(Timeout = Timeout)]\n        public async Task BroadcastBlockWithoutGenesis()\n        {\n            var keyA = new PrivateKey();\n            var keyB = new PrivateKey();\n\n            Swarm swarmA = await CreateSwarm(keyA).ConfigureAwait(false);\n            Swarm swarmB = await CreateSwarm(keyB).ConfigureAwait(false);\n\n            BlockChain chainA = swarmA.BlockChain;\n            BlockChain chainB = swarmB.BlockChain;\n\n            try\n            {\n                await StartAsync(swarmA);\n                await StartAsync(swarmB);\n\n                await BootstrapAsync(swarmB, swarmA.AsPeer);\n                var block = chainA.ProposeBlock(\n                    keyA, CreateBlockCommit(chainA.Tip));\n                chainA.Append(block, TestUtils.CreateBlockCommit(block));\n                swarmA.BroadcastBlock(chainA[-1]);\n\n                await swarmB.BlockAppended.WaitAsync();\n\n                Assert.Equal(chainB.BlockHashes, chainA.BlockHashes);\n\n                block = chainA.ProposeBlock(\n                    keyB, CreateBlockCommit(chainA.Tip));\n                chainA.Append(block, TestUtils.CreateBlockCommit(block));\n                swarmA.BroadcastBlock(chainA[-1]);\n\n                await swarmB.BlockAppended.WaitAsync();\n\n                Assert.Equal(chainB.BlockHashes, chainA.BlockHashes);\n            }\n            finally\n            {\n                CleaningSwarm(swarmA);\n                CleaningSwarm(swarmB);\n            }\n        }\n\n        [Fact(Timeout = Timeout)]\n        public async Task IgnoreExistingBlocks()\n        {\n            var keyA = new PrivateKey();\n            var keyB = new PrivateKey();\n\n            Swarm swarmA = await CreateSwarm(keyA).ConfigureAwait(false);\n            Swarm swarmB =\n                await CreateSwarm(keyB, genesis: swarmA.BlockChain.Genesis).ConfigureAwait(false);\n\n            BlockChain chainA = swarmA.BlockChain;\n            BlockChain chainB = swarmB.BlockChain;\n\n            var block = chainA.ProposeBlock(\n                keyA, CreateBlockCommit(chainA.Tip));\n            BlockCommit blockCommit = TestUtils.CreateBlockCommit(block);\n            chainA.Append(block, blockCommit);\n            chainB.Append(block, blockCommit);\n\n            foreach (int i in Enumerable.Range(0, 3))\n            {\n                block = chainA.ProposeBlock(\n                    keyA, CreateBlockCommit(chainA.Tip));\n                chainA.Append(block, TestUtils.CreateBlockCommit(block));\n            }\n\n            try\n            {\n                await StartAsync(swarmA);\n                await StartAsync(swarmB);\n\n                await BootstrapAsync(swarmB, swarmA.AsPeer);\n                swarmA.BroadcastBlock(chainA[-1]);\n                await swarmB.BlockAppended.WaitAsync();\n\n                Assert.Equal(chainA.BlockHashes, chainB.BlockHashes);\n\n                CancellationTokenSource cts = new CancellationTokenSource();\n                swarmA.BroadcastBlock(chainA[-1]);\n                Task t = swarmB.BlockAppended.WaitAsync(cts.Token);\n\n                // Actually, previous code may pass this test if message is\n                // delayed over 5 seconds.\n                await Task.Delay(5000);\n                Assert.False(t.IsCompleted);\n\n                cts.Cancel();\n            }\n            finally\n            {\n                CleaningSwarm(swarmA);\n                CleaningSwarm(swarmB);\n            }\n        }\n\n        [Fact(Timeout = Timeout)]\n        public async Task PullBlocks()\n        {\n            var keyA = new PrivateKey();\n            var keyB = new PrivateKey();\n            var keyC = new PrivateKey();\n\n            var swarmA = await CreateSwarm(keyA).ConfigureAwait(false);\n            var swarmB = await CreateSwarm(keyB).ConfigureAwait(false);\n            var swarmC = await CreateSwarm(keyC).ConfigureAwait(false);\n\n            BlockChain chainA = swarmA.BlockChain;\n            BlockChain chainB = swarmB.BlockChain;\n            BlockChain chainC = swarmC.BlockChain;\n\n            foreach (int i in Enumerable.Range(0, 5))\n            {\n                Block block = chainA.ProposeBlock(keyA, CreateBlockCommit(chainA.Tip));\n                chainA.Append(block, TestUtils.CreateBlockCommit(block));\n                if (i < 3)\n                {\n                    chainC.Append(block, TestUtils.CreateBlockCommit(block));\n                }\n            }\n\n            Block chainATip = chainA.Tip;\n\n            foreach (int i in Enumerable.Range(0, 10))\n            {\n                Block block = chainB.ProposeBlock(keyB, CreateBlockCommit(chainB.Tip));\n                chainB.Append(block, TestUtils.CreateBlockCommit(block));\n            }\n\n            try\n            {\n                await StartAsync(swarmA);\n                await StartAsync(swarmB);\n                await StartAsync(swarmC);\n\n                await BootstrapAsync(swarmB, swarmA.AsPeer);\n                await BootstrapAsync(swarmC, swarmA.AsPeer);\n\n                await swarmC.PullBlocksAsync(TimeSpan.FromSeconds(5), int.MaxValue, default);\n                await swarmC.BlockAppended.WaitAsync();\n                Assert.Equal(chainC.Tip, chainATip);\n            }\n            finally\n            {\n                CleaningSwarm(swarmA);\n                CleaningSwarm(swarmB);\n                CleaningSwarm(swarmC);\n            }\n        }\n\n        [Fact(Timeout = Timeout)]\n        public async Task CanFillWithInvalidTransaction()\n        {\n            var privateKey = new PrivateKey();\n            var address = privateKey.Address;\n            var swarm1 = await CreateSwarm().ConfigureAwait(false);\n            var swarm2 = await CreateSwarm().ConfigureAwait(false);\n\n            var tx1 = swarm2.BlockChain.MakeTransaction(\n                privateKey,\n                new[] { DumbAction.Create((address, \"foo\")) });\n\n            var tx2 = swarm2.BlockChain.MakeTransaction(\n                privateKey,\n                new[] { DumbAction.Create((address, \"bar\")) });\n\n            var tx3 = swarm2.BlockChain.MakeTransaction(\n                privateKey,\n                new[] { DumbAction.Create((address, \"quz\")) });\n\n            var tx4 = Transaction.Create(\n                4,\n                privateKey,\n                swarm1.BlockChain.Genesis.Hash,\n                new[] { DumbAction.Create((address, \"qux\")) }.ToPlainValues());\n\n            try\n            {\n                await StartAsync(swarm1);\n                await StartAsync(swarm2);\n                await swarm1.AddPeersAsync(new[] { swarm2.AsPeer }, null);\n\n                var transport = swarm1.Transport;\n                var msg = new GetTxsMsg(new[] { tx1.Id, tx2.Id, tx3.Id, tx4.Id });\n                var replies = (await transport.SendMessageAsync(\n                    swarm2.AsPeer,\n                    msg,\n                    TimeSpan.FromSeconds(1),\n                    4,\n                    true,\n                    default)).ToList();\n\n                Assert.Equal(3, replies.Count);\n                Assert.Equal(\n                    new[] { tx1, tx2, tx3 }.ToHashSet(),\n                    replies.Select(\n                        m => Transaction.Deserialize(\n                            ((TxMsg)m.Content).Payload)).ToHashSet());\n            }\n            finally\n            {\n                CleaningSwarm(swarm1);\n                CleaningSwarm(swarm2);\n            }\n        }\n\n        [Fact(Timeout = Timeout)]\n        public async Task DoNotSpawnMultipleTaskForSinglePeer()\n        {\n            var key = new PrivateKey();\n            var apv = new AppProtocolVersionOptions();\n            Swarm receiver =\n                await CreateSwarm(appProtocolVersionOptions: apv).ConfigureAwait(false);\n            ITransport mockTransport = await NetMQTransport.Create(\n                new PrivateKey(),\n                apv,\n                new HostOptions(\n                    IPAddress.Loopback.ToString(),\n                    Array.Empty<IceServer>()));\n            int requestCount = 0;\n\n            async Task MessageHandler(Message message)\n            {\n                _logger.Debug(\"Received message: {Content}\", message);\n                switch (message.Content)\n                {\n                    case PingMsg ping:\n                        await mockTransport.ReplyMessageAsync(\n                            new PongMsg(),\n                            message.Identity,\n                            default);\n                        break;\n\n                    case GetBlockHashesMsg gbhm:\n                        requestCount++;\n                        break;\n                }\n            }\n\n            mockTransport.ProcessMessageHandler.Register(MessageHandler);\n\n            Block block1 = ProposeNextBlock(\n                receiver.BlockChain.Genesis,\n                key,\n                new Transaction[] { });\n            Block block2 = ProposeNextBlock(\n                block1,\n                key,\n                new Transaction[] { });\n\n            try\n            {\n                await StartAsync(receiver);\n                _ = mockTransport.StartAsync();\n                await mockTransport.WaitForRunningAsync();\n\n                // Send block header for block 1.\n                var blockHeaderMsg1 = new BlockHeaderMsg(\n                    receiver.BlockChain.Genesis.Hash,\n                    block1.Header);\n                await mockTransport.SendMessageAsync(\n                    receiver.AsPeer,\n                    blockHeaderMsg1,\n                    TimeSpan.FromSeconds(5),\n                    default);\n                await receiver.BlockHeaderReceived.WaitAsync();\n\n                // Wait until FillBlockAsync task has spawned block demand task.\n                await Task.Delay(1000);\n\n                // Re-send block header for block 1, make sure it does not spawn new task.\n                await mockTransport.SendMessageAsync(\n                    receiver.AsPeer,\n                    blockHeaderMsg1,\n                    TimeSpan.FromSeconds(5),\n                    default);\n                await receiver.BlockHeaderReceived.WaitAsync();\n                await Task.Delay(1000);\n\n                // Send block header for block 2, make sure it does not spawn new task.\n                var blockHeaderMsg2 = new BlockHeaderMsg(\n                    receiver.BlockChain.Genesis.Hash,\n                    block2.Header);\n                await mockTransport.SendMessageAsync(\n                    receiver.AsPeer,\n                    blockHeaderMsg2,\n                    TimeSpan.FromSeconds(5),\n                    default);\n                await receiver.BlockHeaderReceived.WaitAsync();\n                await Task.Delay(1000);\n\n                Assert.Equal(1, requestCount);\n            }\n            finally\n            {\n                CleaningSwarm(receiver);\n                await mockTransport.StopAsync(TimeSpan.FromMilliseconds(10));\n                mockTransport.Dispose();\n            }\n        }\n\n        [Fact(Timeout = Timeout)]\n        public async Task BroadcastEvidence()\n        {\n            var cancellationTokenSource = new CancellationTokenSource(Timeout);\n            var minerA = new PrivateKey();\n            var validatorAddress = new PrivateKey().Address;\n            var swarmA = await CreateSwarm(minerA).ConfigureAwait(false);\n            var swarmB = await CreateSwarm().ConfigureAwait(false);\n            var swarmC = await CreateSwarm().ConfigureAwait(false);\n\n            var chainA = swarmA.BlockChain;\n            var chainB = swarmB.BlockChain;\n            var chainC = swarmC.BlockChain;\n\n            var evidence = new TestEvidence(0, validatorAddress, DateTimeOffset.UtcNow);\n            chainA.AddEvidence(evidence);\n\n            try\n            {\n                await StartAsync(swarmA);\n                await StartAsync(swarmB);\n                await StartAsync(swarmC);\n\n                await swarmA.AddPeersAsync(new[] { swarmB.AsPeer }, null);\n                await swarmB.AddPeersAsync(new[] { swarmC.AsPeer }, null);\n                await swarmC.AddPeersAsync(new[] { swarmA.AsPeer }, null);\n\n                swarmA.BroadcastEvidence(new[] { evidence });\n\n                await swarmC.EvidenceReceived.WaitAsync(cancellationTokenSource.Token);\n                await swarmB.EvidenceReceived.WaitAsync(cancellationTokenSource.Token);\n\n                Assert.Equal(evidence, chainB.GetPendingEvidence(evidence.Id));\n                Assert.Equal(evidence, chainC.GetPendingEvidence(evidence.Id));\n            }\n            finally\n            {\n                CleaningSwarm(swarmA);\n                CleaningSwarm(swarmB);\n                CleaningSwarm(swarmC);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "test/Libplanet.Net.Tests/SwarmTest.Consensus.cs",
    "content": ""
  },
  {
    "path": "test/Libplanet.Net.Tests/SwarmTest.Evidence.cs",
    "content": "using System;\nusing System.Collections.Immutable;\nusing System.Linq;\nusing System.Net;\nusing System.Numerics;\nusing System.Reflection;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing Libplanet.Blockchain;\nusing Libplanet.Blockchain.Policies;\nusing Libplanet.Crypto;\nusing Libplanet.Net.Consensus;\nusing Libplanet.Net.Messages;\nusing Libplanet.Tests.Store;\nusing Libplanet.Types.Blocks;\nusing Libplanet.Types.Consensus;\nusing Nito.AsyncEx;\nusing Xunit;\n\nnamespace Libplanet.Net.Tests\n{\n    public partial class SwarmTest\n    {\n        [Fact(Timeout = Timeout)]\n        public async Task DuplicateVote_Test()\n        {\n            var policy = new NullBlockPolicy();\n            var genesisBlock = new MemoryStoreFixture(policy.PolicyActionsRegistry).GenesisBlock;\n            var genesisProposer = Libplanet.Tests.TestUtils.GenesisProposer;\n            var privateKeys = Libplanet.Tests.TestUtils.ValidatorPrivateKeys.ToArray();\n            var count = privateKeys.Length;\n            var consensusPeers = Enumerable.Range(0, count).Select(i =>\n                new BoundPeer(\n                    privateKeys[i].PublicKey,\n                    new DnsEndPoint(\"127.0.0.1\", 6000 + i))).ToImmutableList();\n            var reactorOptions = Enumerable.Range(0, count).Select(i =>\n                new ConsensusReactorOption\n                {\n                    ConsensusPeers = consensusPeers,\n                    ConsensusPort = 6000 + i,\n                    ConsensusPrivateKey = privateKeys[i],\n                    ConsensusWorkers = 100,\n                    TargetBlockInterval = TimeSpan.FromSeconds(4),\n                    ContextOption = new ContextOption(),\n                }).ToList();\n\n            var swarmTasks = privateKeys.Select(\n                (item, index) => CreateSwarm(\n                    privateKey: item,\n                    policy: policy,\n                    genesis: genesisBlock,\n                    consensusReactorOption: reactorOptions[index]));\n            var swarms = await Task.WhenAll(swarmTasks);\n            var blockChains = swarms.Select(item => item.BlockChain).ToArray();\n\n            try\n            {\n                var startTasks = swarms.Select(item => StartAsync(item));\n                await Task.WhenAll(startTasks);\n                var addPeerTasks = swarms.Select(\n                    (swarm, index) => swarm.AddPeersAsync(\n                        swarms.Where((_, i) => i != index).Select(item => item.AsPeer),\n                        null));\n                await Task.WhenAll(addPeerTasks);\n\n                var consensusContext = swarms[0].ConsensusReactor.ConsensusContext;\n                var round = 0;\n                var height = 1L;\n                var context = consensusContext.CurrentContext;\n                var bindingFlags = BindingFlags.Instance | BindingFlags.NonPublic;\n                var methodName = \"PublishMessage\";\n                var methodInfo = context.GetType().GetMethod(methodName, bindingFlags);\n\n                Assert.NotNull(methodInfo);\n\n                var vote = MakeRandomVote(privateKeys[0], height, round, VoteFlag.PreVote);\n                var args = new object[] { new ConsensusPreVoteMsg(vote) };\n\n                await WaitUntilStepAsync(consensusContext, ConsensusStep.PreVote, default);\n                methodInfo.Invoke(context, args);\n\n                var i = 2;\n                for (; i < 10; i++)\n                {\n                    var waitTasks1 = blockChains.Select(item => WaitUntilBlockIndexAsync(item, i));\n                    await Task.WhenAll(waitTasks1);\n                    Array.ForEach(blockChains, item => Assert.Equal(i + 1, item.Count));\n                    if (blockChains.Any(item => item[i].Evidence.Count > 0))\n                    {\n                        break;\n                    }\n                }\n\n                Assert.NotEqual(10, i);\n\n                var waitTasks2 = blockChains.Select(item => WaitUntilBlockIndexAsync(item, i));\n                await Task.WhenAll(waitTasks2);\n                foreach (BlockChain blockChain in blockChains)\n                {\n                    Assert.Equal(i + 1, blockChain.Count);\n                }\n            }\n            finally\n            {\n                var cleanTasks = swarms.Select(StopAsync);\n                await Task.WhenAll(cleanTasks);\n            }\n        }\n\n        private static Vote MakeRandomVote(\n            PrivateKey privateKey, long height, int round, VoteFlag flag)\n        {\n            if (flag == VoteFlag.Null || flag == VoteFlag.Unknown)\n            {\n                throw new ArgumentException(\n                    $\"{nameof(flag)} must be either {VoteFlag.PreVote} or {VoteFlag.PreCommit}\" +\n                    $\"to create a valid signed vote.\");\n            }\n\n            var hash = new BlockHash(GetRandomBytes(BlockHash.Size));\n            var voteMetadata = new VoteMetadata(\n                height,\n                round,\n                hash,\n                DateTimeOffset.UtcNow,\n                privateKey.PublicKey,\n                validatorPower: BigInteger.One,\n                flag);\n\n            return voteMetadata.Sign(privateKey);\n\n            static byte[] GetRandomBytes(int size)\n            {\n                var bytes = new byte[size];\n                var random = new System.Random();\n                random.NextBytes(bytes);\n\n                return bytes;\n            }\n        }\n\n        private static async Task WaitUntilBlockIndexAsync(\n            BlockChain blockChain,\n            long index)\n        {\n            if (blockChain.Tip.Index < index)\n            {\n                var manualResetEvent = new ManualResetEvent(false);\n                var cancellationTokenSource = new CancellationTokenSource(Timeout);\n                blockChain.TipChanged += BlockChain_TipChanged;\n                try\n                {\n                    await Task.Run(WaitAction, cancellationTokenSource.Token);\n                }\n                finally\n                {\n                    blockChain.TipChanged -= BlockChain_TipChanged;\n                }\n\n                void WaitAction()\n                {\n                    manualResetEvent.WaitOne(Timeout);\n                }\n\n                void BlockChain_TipChanged(object? sender, (Block OldTip, Block NewTip) e)\n                {\n                    if (e.NewTip.Index >= index)\n                    {\n                        manualResetEvent.Set();\n                    }\n                }\n            }\n        }\n\n        private static async Task WaitUntilStepAsync(\n            ConsensusContext consensusContext,\n            ConsensusStep consensusStep,\n            CancellationToken cancellationToken)\n        {\n            var asyncAutoResetEvent = new AsyncAutoResetEvent();\n            consensusContext.StateChanged += ConsensusContext_StateChanged;\n            try\n            {\n                if (consensusContext.Step != consensusStep)\n                {\n                    await asyncAutoResetEvent.WaitAsync(cancellationToken);\n                }\n            }\n            finally\n            {\n                consensusContext.StateChanged -= ConsensusContext_StateChanged;\n            }\n\n            void ConsensusContext_StateChanged(object? sender, Context.ContextState e)\n            {\n                if (e.Step == consensusStep)\n                {\n                    asyncAutoResetEvent.Set();\n                }\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "test/Libplanet.Net.Tests/SwarmTest.Fixtures.cs",
    "content": "#nullable disable\nusing System;\nusing System.Collections.Generic;\nusing System.Collections.Immutable;\nusing System.Linq;\nusing System.Net;\nusing System.Threading.Tasks;\nusing Libplanet.Action;\nusing Libplanet.Action.Loader;\nusing Libplanet.Action.Tests.Common;\nusing Libplanet.Blockchain;\nusing Libplanet.Blockchain.Policies;\nusing Libplanet.Crypto;\nusing Libplanet.Net.Consensus;\nusing Libplanet.Net.Options;\nusing Libplanet.Net.Transports;\nusing Libplanet.Tests.Store;\nusing Libplanet.Types.Blocks;\nusing Serilog;\nusing static Libplanet.Tests.TestUtils;\n\nnamespace Libplanet.Net.Tests\n{\n    public partial class SwarmTest\n    {\n        private static Block[] _fixtureBlocksForPreloadAsyncCancellationTest;\n\n        private readonly List<Func<Task>> _finalizers;\n\n        private static (Address, Block[])\n            MakeFixtureBlocksForPreloadAsyncCancellationTest()\n        {\n            Block[] blocks = _fixtureBlocksForPreloadAsyncCancellationTest;\n\n            if (blocks is null)\n            {\n                var policy = new BlockPolicy(new PolicyActionsRegistry(\n                    endBlockActions: ImmutableArray.Create<IAction>(new MinerReward(1))));\n                using (var storeFx = new MemoryStoreFixture())\n                {\n                    var chain =\n                        MakeBlockChain(\n                            policy,\n                            storeFx.Store,\n                            storeFx.StateStore,\n                            new SingleActionLoader(typeof(DumbAction)));\n                    var miner = new PrivateKey();\n                    var signer = new PrivateKey();\n                    Address address = signer.Address;\n                    Log.Logger.Information(\"Fixture blocks:\");\n                    for (int i = 0; i < 20; i++)\n                    {\n                        for (int j = 0; j < 5; j++)\n                        {\n                            chain.MakeTransaction(\n                                signer,\n                                new[] { DumbAction.Create((address, $\"Item{i}.{j}\")) }\n                            );\n                        }\n\n                        Block block = chain.ProposeBlock(\n                            miner, CreateBlockCommit(chain.Tip));\n                        Log.Logger.Information(\"  #{0,2} {1}\", block.Index, block.Hash);\n                        chain.Append(block, CreateBlockCommit(block));\n                    }\n\n                    var blockList = new List<Block>();\n                    for (var i = 1; i < chain.Count; i++)\n                    {\n                        Block block = chain[i];\n                        blockList.Add(block);\n                    }\n\n                    blocks = blockList.ToArray();\n\n                    _fixtureBlocksForPreloadAsyncCancellationTest = blocks;\n                }\n            }\n\n            var action = new DumbAction();\n            action.LoadPlainValue(blocks[1].Transactions.First().Actions.First());\n            return (action.Append is { } s ? s.At : throw new NullReferenceException(), blocks);\n        }\n\n        private Task<Swarm> CreateConsensusSwarm(\n            PrivateKey privateKey = null,\n            AppProtocolVersionOptions appProtocolVersionOptions = null,\n            HostOptions hostOptions = null,\n            SwarmOptions options = null,\n            IBlockPolicy policy = null,\n            Block genesis = null,\n            ConsensusReactorOption? consensusReactorOption = null)\n        {\n            return CreateSwarm(\n                privateKey,\n                appProtocolVersionOptions,\n                hostOptions,\n                options,\n                policy,\n                genesis,\n                consensusReactorOption ?? new ConsensusReactorOption\n            {\n                SeedPeers = ImmutableList<BoundPeer>.Empty,\n                ConsensusPeers = ImmutableList<BoundPeer>.Empty,\n                ConsensusPort = 0,\n                ConsensusPrivateKey = new PrivateKey(),\n                ConsensusWorkers = 100,\n                TargetBlockInterval = TimeSpan.FromSeconds(10),\n            });\n        }\n\n        private async Task<Swarm> CreateSwarm(\n            PrivateKey privateKey = null,\n            AppProtocolVersionOptions appProtocolVersionOptions = null,\n            HostOptions hostOptions = null,\n            SwarmOptions options = null,\n            IBlockPolicy policy = null,\n            Block genesis = null,\n            ConsensusReactorOption? consensusReactorOption = null)\n        {\n            policy = policy ?? new BlockPolicy(\n                new PolicyActionsRegistry(\n                    endBlockActions: ImmutableArray.Create<IAction>(new MinerReward(1))));\n            var fx = new MemoryStoreFixture(policy.PolicyActionsRegistry);\n            var blockchain = MakeBlockChain(\n                policy,\n                fx.Store,\n                fx.StateStore,\n                new SingleActionLoader(typeof(DumbAction)),\n                genesisBlock: genesis\n            );\n            appProtocolVersionOptions ??= new AppProtocolVersionOptions();\n            hostOptions ??= new HostOptions(IPAddress.Loopback.ToString(), new IceServer[] { });\n\n            return await CreateSwarm(\n                blockchain,\n                privateKey,\n                appProtocolVersionOptions,\n                hostOptions,\n                options,\n                consensusReactorOption: consensusReactorOption);\n        }\n\n        private async Task<Swarm> CreateSwarm(\n            BlockChain blockChain,\n            PrivateKey privateKey = null,\n            AppProtocolVersionOptions appProtocolVersionOptions = null,\n            HostOptions hostOptions = null,\n            SwarmOptions options = null,\n            ConsensusReactorOption? consensusReactorOption = null\n        )\n        {\n            appProtocolVersionOptions ??= new AppProtocolVersionOptions();\n            hostOptions ??= new HostOptions(IPAddress.Loopback.ToString(), new IceServer[] { });\n            options ??= new SwarmOptions();\n            privateKey ??= new PrivateKey();\n            var transport = await NetMQTransport.Create(\n                privateKey,\n                appProtocolVersionOptions,\n                hostOptions,\n                options.MessageTimestampBuffer);\n            ITransport consensusTransport = null;\n            if (consensusReactorOption is { } option)\n            {\n                var consensusHostOptions = new HostOptions(\n                    hostOptions.Host,\n                    hostOptions.IceServers,\n                    option.ConsensusPort);\n                consensusTransport = await NetMQTransport.Create(\n                    privateKey,\n                    appProtocolVersionOptions,\n                    consensusHostOptions,\n                    options.MessageTimestampBuffer);\n            }\n\n            var swarm = new Swarm(\n                blockChain,\n                privateKey,\n                transport,\n                options,\n                consensusTransport: consensusTransport,\n                consensusOption: consensusReactorOption);\n            _finalizers.Add(async () =>\n            {\n                try\n                {\n                    await StopAsync(swarm);\n                    swarm.Dispose();\n                }\n                catch (ObjectDisposedException)\n                {\n                    _logger.Debug(\"Swarm {Swarm} is already disposed\", swarm);\n                }\n            });\n            return swarm;\n        }\n    }\n}\n"
  },
  {
    "path": "test/Libplanet.Net.Tests/SwarmTest.Preload.cs",
    "content": "#nullable disable\nusing System;\nusing System.Collections.Generic;\nusing System.Collections.Immutable;\nusing System.Linq;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing Bencodex.Types;\nusing Libplanet.Action;\nusing Libplanet.Action.Loader;\nusing Libplanet.Action.State;\nusing Libplanet.Action.Tests.Common;\nusing Libplanet.Blockchain;\nusing Libplanet.Blockchain.Policies;\nusing Libplanet.Blockchain.Renderers.Debug;\nusing Libplanet.Crypto;\nusing Libplanet.Store;\nusing Libplanet.Store.Trie;\nusing Libplanet.Tests;\nusing Libplanet.Tests.Store;\nusing Libplanet.Types.Blocks;\nusing Libplanet.Types.Consensus;\nusing Libplanet.Types.Evidence;\nusing Libplanet.Types.Tx;\nusing Serilog;\nusing Serilog.Events;\nusing xRetry;\nusing Xunit;\nusing static Libplanet.Tests.TestUtils;\n\nnamespace Libplanet.Net.Tests\n{\n    public partial class SwarmTest\n    {\n        [Fact(Timeout = Timeout)]\n        public async Task InitialBlockDownload()\n        {\n            var minerKey = new PrivateKey();\n\n            Swarm minerSwarm = await CreateSwarm(minerKey).ConfigureAwait(false);\n            Swarm receiverSwarm = await CreateSwarm().ConfigureAwait(false);\n\n            BlockChain minerChain = minerSwarm.BlockChain;\n            BlockChain receiverChain = receiverSwarm.BlockChain;\n\n            foreach (int i in Enumerable.Range(0, 10))\n            {\n                Block block = minerChain.ProposeBlock(\n                    minerKey, CreateBlockCommit(minerChain.Tip));\n                minerChain.Append(block, TestUtils.CreateBlockCommit(block));\n            }\n\n            try\n            {\n                await StartAsync(minerSwarm);\n                await receiverSwarm.AddPeersAsync(new[] { minerSwarm.AsPeer }, null);\n\n                await receiverSwarm.PreloadAsync();\n\n                Assert.Equal(minerChain.BlockHashes, receiverChain.BlockHashes);\n            }\n            finally\n            {\n                CleaningSwarm(minerSwarm);\n                CleaningSwarm(receiverSwarm);\n            }\n        }\n\n        [Fact(Timeout = Timeout)]\n        public async Task InitialBlockDownloadStates()\n        {\n            var minerKey = new PrivateKey();\n\n            Swarm minerSwarm = await CreateSwarm(minerKey).ConfigureAwait(false);\n            Swarm receiverSwarm = await CreateSwarm().ConfigureAwait(false);\n\n            BlockChain minerChain = minerSwarm.BlockChain;\n            BlockChain receiverChain = receiverSwarm.BlockChain;\n\n            var key = new PrivateKey();\n            var address1 = key.Address;\n            var address2 = new PrivateKey().Address;\n\n            var action = DumbAction.Create(\n                (address1, \"foo\"),\n                transfer: (null, address2, 10));\n\n            minerChain.MakeTransaction(key, new[] { action });\n            var block = minerChain.ProposeBlock(\n                minerKey, CreateBlockCommit(minerChain.Tip));\n            minerChain.Append(block, TestUtils.CreateBlockCommit(block));\n\n            minerChain.MakeTransaction(key, new[] { DumbAction.Create((address1, \"bar\")) });\n            block = minerChain.ProposeBlock(\n                minerKey, CreateBlockCommit(minerChain.Tip));\n            minerChain.Append(block, TestUtils.CreateBlockCommit(block));\n\n            minerChain.MakeTransaction(key, new[] { DumbAction.Create((address1, \"baz\")) });\n            block = minerChain.ProposeBlock(\n                minerKey, CreateBlockCommit(minerChain.Tip));\n            minerChain.Append(block, TestUtils.CreateBlockCommit(block));\n\n            try\n            {\n                await StartAsync(minerSwarm);\n                await receiverSwarm.AddPeersAsync(new[] { minerSwarm.AsPeer }, null);\n\n                await receiverSwarm.PreloadAsync();\n                var state = receiverChain\n                    .GetNextWorldState()\n                    .GetAccountState(ReservedAddresses.LegacyAccount)\n                    .GetState(address1);\n\n                Assert.Equal((Text)\"foo,bar,baz\", state);\n                Assert.Equal(minerChain.BlockHashes, receiverChain.BlockHashes);\n            }\n            finally\n            {\n                CleaningSwarm(minerSwarm);\n                CleaningSwarm(receiverSwarm);\n            }\n        }\n\n        [Fact(Timeout = Timeout)]\n        public async Task Preload()\n        {\n            Swarm minerSwarm = await CreateSwarm().ConfigureAwait(false);\n            Swarm receiverSwarm = await CreateSwarm().ConfigureAwait(false);\n\n            BlockChain minerChain = minerSwarm.BlockChain;\n            BlockChain receiverChain = receiverSwarm.BlockChain;\n\n            var blocks = new List<Block>();\n            foreach (int i in Enumerable.Range(0, 12))\n            {\n                Block block = minerChain.EvaluateAndSign(\n                    ProposeNext(\n                        previousBlock: i == 0 ? minerChain.Genesis : blocks[i - 1],\n                        miner: GenesisProposer.PublicKey,\n                        lastCommit: CreateBlockCommit(minerChain.Tip)),\n                    GenesisProposer);\n                blocks.Add(block);\n                if (i != 11)\n                {\n                    minerChain.Append(blocks[i], TestUtils.CreateBlockCommit(blocks[i]));\n                }\n            }\n\n            var actualStates = new List<BlockSyncState>();\n            var progress = new ActionProgress<BlockSyncState>(state =>\n            {\n                _logger.Information(\"Received a progress event: {@State}\", state);\n                lock (actualStates)\n                {\n                    actualStates.Add(state);\n\n                    if (actualStates.Count == 10)\n                    {\n                        minerChain.Append(blocks[11], CreateBlockCommit(blocks[11]));\n                    }\n                }\n            });\n\n            try\n            {\n                await StartAsync(minerSwarm);\n\n                await receiverSwarm.AddPeersAsync(new[] { minerSwarm.AsPeer }, null);\n\n                _logger.Verbose(\"Both chains before synchronization:\");\n                _logger.CompareBothChains(\n                    LogEventLevel.Verbose,\n                    \"Miner chain\",\n                    minerChain,\n                    \"Receiver chain\",\n                    receiverChain\n                );\n\n                minerSwarm.FindNextHashesChunkSize = 3;\n                await receiverSwarm.PreloadAsync(\n                    TimeSpan.FromSeconds(1),\n                    0,\n                    progress);\n\n                // Await 1 second to make sure all progresses is reported.\n                await Task.Delay(1000);\n\n                _logger.Verbose(\n                    $\"Both chains after synchronization ({nameof(receiverSwarm.PreloadAsync)}):\"\n                );\n                _logger.CompareBothChains(\n                    LogEventLevel.Verbose,\n                    \"Miner chain\",\n                    minerChain,\n                    \"Receiver chain\",\n                    receiverChain\n                );\n\n                Assert.Equal(minerChain.Tip.Hash, receiverChain.Tip.Hash);\n            }\n            finally\n            {\n                CleaningSwarm(minerSwarm);\n                CleaningSwarm(receiverSwarm);\n            }\n        }\n\n        [Fact(\n            Skip = \"Scenario is no more possible since validator set has moved to state.\",\n            Timeout = Timeout)]\n        public async Task PreloadWithMaliciousPeer()\n        {\n            const int initialSharedTipHeight = 3;\n            const int maliciousTipHeight = 5;\n            const int honestTipHeight = 7;\n            var policy = new NullBlockPolicy();\n            var policyB = new NullBlockPolicy();\n            var genesis = new MemoryStoreFixture(policy.PolicyActionsRegistry).GenesisBlock;\n\n            var swarmA = await CreateSwarm(\n                privateKey: new PrivateKey(),\n                policy: policy,\n                genesis: genesis).ConfigureAwait(false);\n            var swarmB = await CreateSwarm(\n                privateKey: new PrivateKey(),\n                policy: policyB,\n                genesis: genesis).ConfigureAwait(false);\n            var swarmC = await CreateSwarm(\n                privateKey: new PrivateKey(),\n                policy: policy,\n                genesis: genesis).ConfigureAwait(false);\n            var chainA = swarmA.BlockChain;\n            var chainB = swarmB.BlockChain;\n            var chainC = swarmC.BlockChain;\n\n            // Setup initial state where all chains share the same blockchain state.\n            for (int i = 1; i <= initialSharedTipHeight; i++)\n            {\n                var block = chainA.ProposeBlock(\n                    new PrivateKey(), TestUtils.CreateBlockCommit(chainA.Tip));\n                chainA.Append(block, TestUtils.CreateBlockCommit(block));\n                chainB.Append(block, TestUtils.CreateBlockCommit(block));\n                chainC.Append(block, TestUtils.CreateBlockCommit(block));\n            }\n\n            // Setup malicious node to broadcast.\n            for (int i = initialSharedTipHeight + 1; i < maliciousTipHeight; i++)\n            {\n                var block = chainB.ProposeBlock(\n                    new PrivateKey(), TestUtils.CreateBlockCommit(chainB.Tip));\n                chainB.Append(block, TestUtils.CreateBlockCommit(block));\n                chainC.Append(block, TestUtils.CreateBlockCommit(block));\n            }\n\n            var specialBlock = chainB.ProposeBlock(\n                new PrivateKey(), TestUtils.CreateBlockCommit(chainB.Tip));\n            var invalidBlockCommit = new BlockCommit(\n                maliciousTipHeight,\n                0,\n                specialBlock.Hash,\n                ImmutableArray<Vote>.Empty\n                    .Add(new VoteMetadata(\n                        maliciousTipHeight,\n                        0,\n                        specialBlock.Hash,\n                        DateTimeOffset.UtcNow,\n                        TestUtils.PrivateKeys[0].PublicKey,\n                        TestUtils.ValidatorSet[0].Power,\n                        VoteFlag.PreCommit).Sign(TestUtils.PrivateKeys[0])));\n            var validBlockCommit = TestUtils.CreateBlockCommit(specialBlock);\n            chainB.Append(specialBlock, invalidBlockCommit);\n            chainC.Append(specialBlock, validBlockCommit);\n\n            // Setup honest node with higher tip\n            for (int i = maliciousTipHeight + 1; i <= honestTipHeight; i++)\n            {\n                var block = chainC.ProposeBlock(\n                    new PrivateKey(), TestUtils.CreateBlockCommit(chainC.Tip));\n                chainC.Append(block, TestUtils.CreateBlockCommit(block));\n            }\n\n            Assert.Equal(initialSharedTipHeight, chainA.Tip.Index);\n            Assert.Equal(maliciousTipHeight, chainB.Tip.Index);\n            Assert.Equal(honestTipHeight, chainC.Tip.Index);\n\n            try\n            {\n                await StartAsync(swarmA, millisecondsBroadcastBlockInterval: int.MaxValue);\n                await StartAsync(swarmB, millisecondsBroadcastBlockInterval: int.MaxValue);\n                await StartAsync(swarmC, millisecondsBroadcastBlockInterval: int.MaxValue);\n\n                // Checks swarmB cannot make swarmA append a block with invalid block commit.\n                await swarmA.AddPeersAsync(new[] { swarmB.AsPeer }, null);\n                await swarmB.AddPeersAsync(new[] { swarmA.AsPeer }, null);\n\n                try\n                {\n                    await swarmA.PreloadAsync();\n                }\n                catch (InvalidBlockCommitException)\n                {\n                }\n\n                // Makes sure preload failed.\n                Assert.Equal(initialSharedTipHeight, chainA.Tip.Index);\n\n                // Checks swarmA can sync with an honest node with higher tip afterwards.\n                await swarmA.AddPeersAsync(new[] { swarmC.AsPeer }, null);\n                await swarmC.AddPeersAsync(new[] { swarmA.AsPeer }, null);\n\n                await swarmA.PreloadAsync();\n\n                Assert.Equal(chainC.Tip, chainA.Tip);\n                Assert.Equal(\n                    chainC.GetBlockCommit(chainC.Tip.Hash),\n                    chainA.GetBlockCommit(chainA.Tip.Hash));\n            }\n            finally\n            {\n                CleaningSwarm(swarmA);\n                CleaningSwarm(swarmB);\n                CleaningSwarm(swarmC);\n            }\n        }\n\n        [RetryFact(Timeout = Timeout)]\n        public async Task NoRenderInPreload()\n        {\n            var policy = new BlockPolicy(\n                new PolicyActionsRegistry(\n                    endBlockActions: ImmutableArray.Create<IAction>(new MinerReward(1))));\n            var renderer = new RecordingActionRenderer();\n            var chain = MakeBlockChain(\n                policy,\n                new MemoryStore(),\n                new TrieStateStore(new MemoryKeyValueStore()),\n                new SingleActionLoader(typeof(DumbAction)),\n                renderers: new[] { renderer });\n\n            var senderKey = new PrivateKey();\n\n            var receiver = await CreateSwarm(chain).ConfigureAwait(false);\n            var sender = await CreateSwarm(\n                MakeBlockChain(\n                    policy,\n                    new MemoryStore(),\n                    new TrieStateStore(new MemoryKeyValueStore()),\n                    new SingleActionLoader(typeof(DumbAction))\n                ),\n                senderKey\n            ).ConfigureAwait(false);\n\n            int renderCount = 0;\n\n            var privKey = new PrivateKey();\n            var addr = sender.Address;\n            var item = \"foo\";\n\n            const int iteration = 3;\n            for (var i = 0; i < iteration; i++)\n            {\n                sender.BlockChain.MakeTransaction(\n                    privKey, new[] { DumbAction.Create((addr, item)) });\n                Block block = sender.BlockChain.ProposeBlock(\n                    senderKey, CreateBlockCommit(sender.BlockChain.Tip));\n                sender.BlockChain.Append(block, TestUtils.CreateBlockCommit(block));\n            }\n\n            renderer.RenderEventHandler += (_, a) =>\n                renderCount += IsDumbAction(a) ? 1 : 0;\n\n            await StartAsync(receiver);\n            await StartAsync(sender);\n\n            await BootstrapAsync(receiver, sender.AsPeer);\n            await receiver.PreloadAsync();\n\n            Assert.Equal(sender.BlockChain.Tip, receiver.BlockChain.Tip);\n            Assert.Equal(sender.BlockChain.Count, receiver.BlockChain.Count);\n            Assert.Equal(0, renderCount);\n\n            CleaningSwarm(receiver);\n            CleaningSwarm(sender);\n        }\n\n        [Fact(Timeout = Timeout)]\n        public async Task PreloadWithFailedActions()\n        {\n            var policy = new BlockPolicy();\n            var fx1 = new MemoryStoreFixture();\n            var fx2 = new MemoryStoreFixture();\n            var minerChain = MakeBlockChain(\n                policy, fx1.Store, fx1.StateStore, new SingleActionLoader(typeof(ThrowException)));\n            var receiverChain = MakeBlockChain(\n                policy, fx2.Store, fx2.StateStore, new SingleActionLoader(typeof(ThrowException)));\n\n            var minerKey = new PrivateKey();\n\n            Swarm minerSwarm =\n                await CreateSwarm(minerChain, minerKey).ConfigureAwait(false);\n            Swarm receiverSwarm =\n                await CreateSwarm(receiverChain).ConfigureAwait(false);\n\n            foreach (var unused in Enumerable.Range(0, 10))\n            {\n                Block block = minerSwarm.BlockChain.ProposeBlock(\n                    minerKey, CreateBlockCommit(minerSwarm.BlockChain.Tip));\n                minerSwarm.BlockChain.Append(block, TestUtils.CreateBlockCommit(block));\n            }\n\n            try\n            {\n                await StartAsync(minerSwarm);\n\n                await receiverSwarm.AddPeersAsync(new[] { minerSwarm.AsPeer }, null);\n                await receiverSwarm.PreloadAsync();\n\n                var action = new ThrowException { ThrowOnExecution = true };\n\n                var chainId = receiverChain.Id;\n                Transaction tx = Transaction.Create(\n                    0,\n                    new PrivateKey(),\n                    minerSwarm.BlockChain.Genesis.Hash,\n                    new[] { action }.ToPlainValues(),\n                    null,\n                    null,\n                    DateTimeOffset.UtcNow);\n\n                Block block = minerChain.ProposeBlock(\n                    GenesisProposer,\n                    new[] { tx }.ToImmutableList(),\n                    CreateBlockCommit(minerChain.Tip),\n                    ImmutableArray<EvidenceBase>.Empty);\n                minerSwarm.BlockChain.Append(block, CreateBlockCommit(block), true);\n\n                await receiverSwarm.PreloadAsync();\n\n                // Preloading should succeed even if action throws exception.\n                Assert.Equal(minerChain.Tip, receiverChain.Tip);\n            }\n            finally\n            {\n                CleaningSwarm(minerSwarm);\n                CleaningSwarm(receiverSwarm);\n            }\n        }\n\n        [Fact(Timeout = Timeout)]\n        public async Task PreloadFromNominer()\n        {\n            var minerKey = new PrivateKey();\n            Swarm minerSwarm = await CreateSwarm(minerKey).ConfigureAwait(false);\n            Swarm receiverSwarm = await CreateSwarm().ConfigureAwait(false);\n            var fxForNominers = new StoreFixture[2];\n            var policy = new BlockPolicy(\n                new PolicyActionsRegistry(\n                    endBlockActions: ImmutableArray.Create<IAction>(new MinerReward(1))));\n            fxForNominers[0] = new MemoryStoreFixture(policy.PolicyActionsRegistry);\n            fxForNominers[1] = new MemoryStoreFixture(policy.PolicyActionsRegistry);\n            var blockChainsForNominers = new[]\n            {\n                MakeBlockChain(\n                    policy,\n                    fxForNominers[0].Store,\n                    fxForNominers[0].StateStore,\n                    new SingleActionLoader(typeof(DumbAction))),\n                MakeBlockChain(\n                    policy,\n                    fxForNominers[1].Store,\n                    fxForNominers[1].StateStore,\n                    new SingleActionLoader(typeof(DumbAction))),\n            };\n            var nominerSwarm0 =\n                await CreateSwarm(blockChainsForNominers[0]).ConfigureAwait(false);\n            var nominerSwarm1 =\n                await CreateSwarm(blockChainsForNominers[1]).ConfigureAwait(false);\n\n            BlockChain minerChain = minerSwarm.BlockChain;\n            BlockChain receiverChain = receiverSwarm.BlockChain;\n\n            foreach (int i in Enumerable.Range(0, 10))\n            {\n                Block block = minerChain.ProposeBlock(\n                    minerKey, CreateBlockCommit(minerChain.Tip));\n                minerChain.Append(block, CreateBlockCommit(block));\n            }\n\n            var actualStates = new List<BlockSyncState>();\n            var progress = new ActionProgress<BlockSyncState>(state =>\n            {\n                lock (actualStates)\n                {\n                    actualStates.Add(state);\n                }\n            });\n\n            try\n            {\n                await StartAsync(minerSwarm);\n                await StartAsync(nominerSwarm0);\n                await StartAsync(nominerSwarm1);\n                minerSwarm.FindNextHashesChunkSize = 2;\n                nominerSwarm0.FindNextHashesChunkSize = 2;\n                nominerSwarm1.FindNextHashesChunkSize = 2;\n\n                await nominerSwarm0.AddPeersAsync(new[] { minerSwarm.AsPeer }, null);\n                await nominerSwarm0.PreloadAsync(TimeSpan.FromSeconds(1), 0);\n                await nominerSwarm1.AddPeersAsync(new[] { nominerSwarm0.AsPeer }, null);\n                await nominerSwarm1.PreloadAsync(TimeSpan.FromSeconds(1), 0);\n                await receiverSwarm.AddPeersAsync(new[] { nominerSwarm1.AsPeer }, null);\n                await receiverSwarm.PreloadAsync(TimeSpan.FromSeconds(1), 0, progress);\n\n                // Await 1 second to make sure all progresses is reported.\n                await Task.Delay(1000);\n\n                Assert.Equal(minerChain.BlockHashes, receiverChain.BlockHashes);\n            }\n            finally\n            {\n                CleaningSwarm(minerSwarm);\n                CleaningSwarm(nominerSwarm0);\n                CleaningSwarm(nominerSwarm1);\n                CleaningSwarm(receiverSwarm);\n\n                fxForNominers[0].Dispose();\n                fxForNominers[1].Dispose();\n            }\n        }\n\n        [Theory(Timeout = Timeout)]\n        [InlineData(4)]\n        [InlineData(8)]\n        [InlineData(16)]\n        [InlineData(32)]\n        public async Task PreloadRetryWithNextPeers(int blockCount)\n        {\n            var key0 = new PrivateKey();\n\n            Swarm swarm0 = await CreateSwarm(key0).ConfigureAwait(false);\n            Swarm swarm1 = await CreateSwarm().ConfigureAwait(false);\n            Swarm receiverSwarm = await CreateSwarm().ConfigureAwait(false);\n\n            receiverSwarm.Options.TimeoutOptions.GetBlockHashesTimeout\n                = TimeSpan.FromMilliseconds(1000);\n\n            swarm0.FindNextHashesChunkSize = blockCount / 2;\n            swarm1.FindNextHashesChunkSize = blockCount / 2;\n\n            for (int i = 0; i < blockCount; ++i)\n            {\n                var block = swarm0.BlockChain.ProposeBlock(\n                    key0, CreateBlockCommit(swarm0.BlockChain.Tip));\n                swarm0.BlockChain.Append(block, TestUtils.CreateBlockCommit(block));\n                swarm1.BlockChain.Append(block, TestUtils.CreateBlockCommit(block));\n            }\n\n            await StartAsync(swarm0);\n            await StartAsync(swarm1);\n\n            Assert.Equal(swarm0.BlockChain.BlockHashes, swarm1.BlockChain.BlockHashes);\n\n            await receiverSwarm.AddPeersAsync(new[] { swarm0.AsPeer, swarm1.AsPeer }, null);\n            Assert.Equal(\n                new[] { swarm0.AsPeer, swarm1.AsPeer }.ToImmutableHashSet(),\n                receiverSwarm.Peers.ToImmutableHashSet());\n\n            var startedStop = false;\n            var shouldStopSwarm =\n                swarm0.AsPeer.Equals(receiverSwarm.Peers.First()) ? swarm0 : swarm1;\n\n            // FIXME: This relies on progress report to artificially stop preloading.\n            async void Action(BlockSyncState state)\n            {\n                if (!startedStop)\n                {\n                    startedStop = true;\n                    await shouldStopSwarm.StopAsync(TimeSpan.Zero);\n                }\n            }\n\n            await receiverSwarm.PreloadAsync(\n                TimeSpan.FromSeconds(1),\n                0,\n                progress: new ActionProgress<BlockSyncState>(Action));\n\n            Assert.Equal(swarm1.BlockChain.BlockHashes, receiverSwarm.BlockChain.BlockHashes);\n            Assert.Equal(swarm0.BlockChain.BlockHashes, receiverSwarm.BlockChain.BlockHashes);\n\n            CleaningSwarm(swarm0);\n            CleaningSwarm(swarm1);\n            CleaningSwarm(receiverSwarm);\n        }\n\n        [RetryTheory(10, Timeout = Timeout)]\n        [InlineData(0)]\n        [InlineData(50)]\n        [InlineData(100)]\n        [InlineData(500)]\n        [InlineData(1000)]\n        [InlineData(2500)]\n        [InlineData(5000)]\n        public async Task PreloadAsyncCancellation(int cancelAfter)\n        {\n            Swarm minerSwarm = await CreateSwarm().ConfigureAwait(false);\n            Swarm receiverSwarm = await CreateSwarm().ConfigureAwait(false);\n            Log.Logger.Information(\"Miner:    {0}\", minerSwarm.Address);\n            Log.Logger.Information(\"Receiver: {0}\", receiverSwarm.Address);\n\n            BlockChain minerChain = minerSwarm.BlockChain;\n            BlockChain receiverChain = receiverSwarm.BlockChain;\n\n            Guid receiverChainId = receiverChain.Id;\n\n            (Address address, IEnumerable<Block> blocks) =\n                MakeFixtureBlocksForPreloadAsyncCancellationTest();\n\n            var blockArray = blocks.ToArray();\n            foreach (Block block in blockArray)\n            {\n                minerChain.Append(block, CreateBlockCommit(block));\n            }\n\n            receiverChain.Append(blockArray[0], CreateBlockCommit(blockArray[0]));\n\n            Assert.NotNull(minerChain.Tip);\n\n            minerSwarm.FindNextHashesChunkSize = 2;\n            await StartAsync(minerSwarm);\n            await receiverSwarm.AddPeersAsync(new[] { minerSwarm.AsPeer }, null);\n\n            CancellationTokenSource cts = new CancellationTokenSource();\n            cts.CancelAfter(cancelAfter);\n            bool canceled = true;\n            try\n            {\n                await receiverSwarm.PreloadAsync(\n                    TimeSpan.FromSeconds(1),\n                    0,\n                    cancellationToken: cts.Token);\n                canceled = false;\n                Log.Logger.Debug(\n                    \"{MethodName}() normally finished\", nameof(receiverSwarm.PreloadAsync));\n            }\n            catch (OperationCanceledException)\n            {\n                Log.Logger.Debug(\"{MethodName}() aborted\", nameof(receiverSwarm.PreloadAsync));\n            }\n            catch (AggregateException ae) when (ae.InnerException is TaskCanceledException)\n            {\n                Log.Logger.Debug(\"{MethodName}() aborted\", nameof(receiverSwarm.PreloadAsync));\n            }\n\n            cts.Dispose();\n\n            Assert.InRange(receiverChain.Store.ListChainIds().Count(), 0, 1);\n\n            if (canceled)\n            {\n                Assert.Equal(receiverChainId, receiverChain.Id);\n                Assert.Contains(receiverChain.Tip, blockArray);\n                Assert.NotEqual(blockArray.Last(), receiverChain.Tip);\n                Assert.Equal(\n                    (Text)string.Join(\n                        \",\",\n                        Enumerable.Range(0, (int)receiverChain.Tip.Index).Select(i =>\n                            string.Join(\",\", Enumerable.Range(0, 5).Select(j => $\"Item{i}.{j}\")))),\n                    receiverChain\n                        .GetNextWorldState()\n                        .GetAccountState(ReservedAddresses.LegacyAccount)\n                        .GetState(address));\n            }\n            else\n            {\n                Assert.Equal(minerChain.Tip, receiverChain.Tip);\n                Assert.Equal(\n                    (Text)string.Join(\n                        \",\",\n                        Enumerable.Range(0, 20).Select(i =>\n                            string.Join(\",\", Enumerable.Range(0, 5).Select(j => $\"Item{i}.{j}\")))),\n                    receiverChain\n                        .GetNextWorldState()\n                        .GetAccountState(ReservedAddresses.LegacyAccount)\n                        .GetState(address)\n                );\n            }\n\n            CleaningSwarm(minerSwarm);\n            CleaningSwarm(receiverSwarm);\n        }\n\n        [Fact(Timeout = Timeout)]\n        public async Task GetDemandBlockHashes()\n        {\n            Swarm minerSwarm = await CreateSwarm().ConfigureAwait(false);\n            Swarm receiverSwarm = await CreateSwarm().ConfigureAwait(false);\n            Log.Logger.Information(\"Miner:    {0}\", minerSwarm.Address);\n            Log.Logger.Information(\"Receiver: {0}\", receiverSwarm.Address);\n\n            BlockChain minerChain = minerSwarm.BlockChain;\n            BlockChain receiverChain = receiverSwarm.BlockChain;\n\n            (_, IEnumerable<Block> blocks) =\n                MakeFixtureBlocksForPreloadAsyncCancellationTest();\n\n            foreach (Block block in blocks)\n            {\n                minerChain.Append(block, CreateBlockCommit(block));\n            }\n\n            const int FindNextHashesChunkSize = 3;\n            minerSwarm.FindNextHashesChunkSize = FindNextHashesChunkSize;\n            await StartAsync(minerSwarm);\n\n            (BoundPeer, IBlockExcerpt)[] peersWithExcerpt =\n            {\n                (minerSwarm.AsPeer, minerChain.Tip.Header),\n            };\n\n            (var _, List<BlockHash> demands) = await receiverSwarm.GetDemandBlockHashes(\n                receiverChain,\n                peersWithExcerpt,\n                cancellationToken: CancellationToken.None);\n\n            IEnumerable<BlockHash> expectedBlocks = minerChain\n                .IterateBlocks()\n                .Where(b => b.Index >= receiverChain.Tip.Index)\n                .Take(FindNextHashesChunkSize)\n                .Select(b => b.Hash);\n            Assert.Equal(expectedBlocks, demands);\n\n            CleaningSwarm(minerSwarm);\n            CleaningSwarm(receiverSwarm);\n        }\n\n        [Fact(Timeout = Timeout)]\n        public async Task PreloadToTheHighestTipIndexChain()\n        {\n            var minerKey1 = new PrivateKey();\n            Swarm minerSwarm1 = await CreateSwarm(minerKey1).ConfigureAwait(false);\n            Swarm minerSwarm2 = await CreateSwarm().ConfigureAwait(false);\n            Swarm receiverSwarm = await CreateSwarm().ConfigureAwait(false);\n            BlockChain minerChain1 = minerSwarm1.BlockChain;\n            BlockChain minerChain2 = minerSwarm2.BlockChain;\n            BlockChain receiverChain = receiverSwarm.BlockChain;\n\n            Block block1 = minerChain1.ProposeBlock(\n                minerKey1, CreateBlockCommit(minerChain1.Tip));\n            minerChain1.Append(block1, CreateBlockCommit(block1));\n            minerChain2.Append(block1, CreateBlockCommit(block1));\n            Block block2 = minerChain1.ProposeBlock(\n                minerKey1, CreateBlockCommit(minerChain1.Tip));\n            minerChain1.Append(block2, CreateBlockCommit(block2));\n\n            Assert.True(minerChain1.Count > minerChain2.Count);\n\n            try\n            {\n                await StartAsync(minerSwarm1);\n                await StartAsync(minerSwarm2);\n                await receiverSwarm.AddPeersAsync(\n                    new[] { minerSwarm1.AsPeer, minerSwarm2.AsPeer },\n                    null);\n                await receiverSwarm.PreloadAsync(TimeSpan.FromSeconds(1), 0);\n            }\n            finally\n            {\n                CleaningSwarm(minerSwarm1);\n                CleaningSwarm(minerSwarm2);\n                CleaningSwarm(receiverSwarm);\n            }\n\n            Assert.Equal(minerChain1.Count, receiverChain.Count);\n            Assert.Equal(minerChain1.Tip, receiverChain.Tip);\n        }\n\n        [Fact(Timeout = Timeout)]\n        public async Task PreloadIgnorePeerWithDifferentGenesisBlock()\n        {\n            var key1 = new PrivateKey();\n            var key2 = new PrivateKey();\n            var policy = new BlockPolicy();\n\n            BlockChain receiverChain = MakeBlockChain(\n                policy,\n                new MemoryStore(),\n                new TrieStateStore(new MemoryKeyValueStore()),\n                new SingleActionLoader(typeof(DumbAction)),\n                privateKey: key1);\n            BlockChain validSeedChain = MakeBlockChain(\n                policy,\n                new MemoryStore(),\n                new TrieStateStore(new MemoryKeyValueStore()),\n                new SingleActionLoader(typeof(DumbAction)),\n                privateKey: key1,\n                genesisBlock: receiverChain.Genesis);\n            BlockChain invalidSeedChain = MakeBlockChain(\n                policy,\n                new MemoryStore(),\n                new TrieStateStore(new MemoryKeyValueStore()),\n                new SingleActionLoader(typeof(DumbAction)),\n                privateKey: key2);\n            Swarm receiverSwarm =\n                await CreateSwarm(receiverChain).ConfigureAwait(false);\n            Swarm validSeedSwarm =\n                await CreateSwarm(validSeedChain).ConfigureAwait(false);\n            Swarm invalidSeedSwarm =\n                await CreateSwarm(invalidSeedChain).ConfigureAwait(false);\n\n            Assert.Equal(receiverSwarm.BlockChain.Genesis, validSeedSwarm.BlockChain.Genesis);\n            Assert.NotEqual(receiverSwarm.BlockChain.Genesis, invalidSeedSwarm.BlockChain.Genesis);\n\n            for (int i = 0; i < 10; i++)\n            {\n                Block block = validSeedChain.ProposeBlock(\n                    key1, CreateBlockCommit(validSeedChain.Tip));\n                validSeedChain.Append(block, CreateBlockCommit(block));\n            }\n\n            for (int i = 0; i < 20; i++)\n            {\n                Block block = invalidSeedChain.ProposeBlock(\n                    key1, CreateBlockCommit(invalidSeedChain.Tip));\n                invalidSeedChain.Append(block, CreateBlockCommit(block));\n            }\n\n            try\n            {\n                await StartAsync(receiverSwarm);\n                await StartAsync(validSeedSwarm);\n                await StartAsync(invalidSeedSwarm);\n\n                await receiverSwarm.AddPeersAsync(\n                    new[] { validSeedSwarm.AsPeer, invalidSeedSwarm.AsPeer }, null);\n                await receiverSwarm.PreloadAsync();\n\n                Assert.Equal(receiverChain.Tip, validSeedChain.Tip);\n            }\n            finally\n            {\n                CleaningSwarm(receiverSwarm);\n                CleaningSwarm(validSeedSwarm);\n                CleaningSwarm(invalidSeedSwarm);\n            }\n        }\n\n        [Fact(Timeout = Timeout)]\n        public async Task UpdateTxExecution()\n        {\n            PrivateKey seedKey = new PrivateKey();\n            var policy = new BlockPolicy(\n                new PolicyActionsRegistry(\n                    endBlockActions: ImmutableArray.Create<IAction>(new MinerReward(1))));\n            var fx1 = new MemoryStoreFixture(policy.PolicyActionsRegistry);\n            var fx2 = new MemoryStoreFixture(policy.PolicyActionsRegistry);\n            var seedChain = MakeBlockChain(\n                policy, fx1.Store, fx1.StateStore, new SingleActionLoader(typeof(DumbAction)));\n            var receiverChain = MakeBlockChain(\n                policy, fx2.Store, fx2.StateStore, new SingleActionLoader(typeof(DumbAction)));\n\n            Swarm seed =\n                await CreateSwarm(seedChain).ConfigureAwait(false);\n            Swarm receiver =\n                await CreateSwarm(receiverChain).ConfigureAwait(false);\n\n            List<Transaction> transactions = new List<Transaction>();\n            for (int i = 0; i < 10; i++)\n            {\n                var transaction = seedChain.MakeTransaction(\n                    new PrivateKey(),\n                    new[]\n                    {\n                        DumbAction.Create((default, $\"Item{i}\")),\n                    });\n                Block block = seedChain.ProposeBlock(\n                    seedKey, CreateBlockCommit(seedChain.Tip));\n                seedChain.Append(block, TestUtils.CreateBlockCommit(block));\n                transactions.Add(transaction);\n            }\n\n            Assert.Equal(10, seedChain.Tip.Index);\n\n            try\n            {\n                await StartAsync(seed);\n                await StartAsync(receiver);\n\n                await receiver.AddPeersAsync(\n                    new[] { seed.AsPeer }, null);\n                await receiver.PreloadAsync();\n\n                Assert.Equal(receiverChain.Tip, seedChain.Tip);\n\n                for (int i = 1; i < receiverChain.Count; i++)\n                {\n                    Assert.NotNull(fx2.Store.GetTxExecution(\n                        receiverChain[i].Hash,\n                        transactions[i - 1].Id));\n                }\n            }\n            finally\n            {\n                CleaningSwarm(seed);\n                CleaningSwarm(receiver);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "test/Libplanet.Net.Tests/SwarmTest.cs",
    "content": "#nullable disable\nusing System;\nusing System.Collections.Generic;\nusing System.Collections.Immutable;\nusing System.Linq;\nusing System.Net;\nusing System.Net.Sockets;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing Bencodex.Types;\nusing Libplanet.Action;\nusing Libplanet.Action.Loader;\nusing Libplanet.Action.State;\nusing Libplanet.Action.Tests.Common;\nusing Libplanet.Blockchain;\nusing Libplanet.Blockchain.Policies;\nusing Libplanet.Common;\nusing Libplanet.Crypto;\nusing Libplanet.Net.Consensus;\nusing Libplanet.Net.Messages;\nusing Libplanet.Net.Options;\nusing Libplanet.Net.Protocols;\nusing Libplanet.Net.Transports;\nusing Libplanet.Store;\nusing Libplanet.Store.Trie;\nusing Libplanet.Stun;\nusing Libplanet.Tests.Store;\nusing Libplanet.Types.Blocks;\nusing Libplanet.Types.Tx;\nusing NetMQ;\nusing Nito.AsyncEx;\nusing Nito.AsyncEx.Synchronous;\nusing Serilog;\nusing xRetry;\nusing Xunit;\nusing Xunit.Abstractions;\n#if NETFRAMEWORK && (NET47 || NET471)\nusing static Libplanet.Tests.HashSetExtensions;\n#endif\nusing static Libplanet.Tests.TestUtils;\n\nnamespace Libplanet.Net.Tests\n{\n    [Collection(\"NetMQConfiguration\")]\n    public partial class SwarmTest : IDisposable\n    {\n        private const int Timeout = 60 * 1000;\n        private const int DisposeTimeout = 5 * 1000;\n\n        private readonly ITestOutputHelper _output;\n        private readonly ILogger _logger;\n\n        private bool _disposed = false;\n\n        public SwarmTest(ITestOutputHelper output)\n        {\n            const string outputTemplate =\n                \"{Timestamp:HH:mm:ss:ffffffZ}[@{SwarmId}][{ThreadId}] - {Message}\";\n            Log.Logger = new LoggerConfiguration()\n                .MinimumLevel.Verbose()\n                .Enrich.WithThreadId()\n                .WriteTo.TestOutput(output, outputTemplate: outputTemplate)\n                .CreateLogger()\n                .ForContext<SwarmTest>();\n\n            _logger = Log.ForContext<SwarmTest>();\n            _output = output;\n\n            _finalizers = new List<Func<Task>>();\n        }\n\n        ~SwarmTest()\n        {\n            Dispose(false);\n        }\n\n        public void Dispose()\n        {\n            Dispose(true);\n            GC.SuppressFinalize(this);\n        }\n\n        [Fact(Timeout = Timeout)]\n        public async Task CanNotStartTwice()\n        {\n            Swarm swarm = await CreateSwarm().ConfigureAwait(false);\n\n            Task t = await Task.WhenAny(\n                swarm.StartAsync(),\n                swarm.StartAsync());\n\n            Assert.True(swarm.Running);\n            Assert.True(t.IsFaulted);\n            Assert.True(\n                t.Exception.InnerException is SwarmException,\n                $\"Expected SwarmException, but actual exception was: {t.Exception.InnerException}\"\n            );\n\n            CleaningSwarm(swarm);\n        }\n\n        [Fact(Timeout = Timeout)]\n        public async Task HandleReconnection()\n        {\n            Swarm seed = await CreateSwarm().ConfigureAwait(false);\n\n            var privateKey = new PrivateKey();\n            Swarm swarmA =\n                await CreateSwarm(privateKey: privateKey).ConfigureAwait(false);\n            Swarm swarmB =\n                await CreateSwarm(privateKey: privateKey).ConfigureAwait(false);\n\n            try\n            {\n                await StartAsync(seed);\n                await StartAsync(swarmA);\n                await StartAsync(swarmB);\n                await swarmA.AddPeersAsync(new[] { seed.AsPeer }, null);\n                await StopAsync(swarmA);\n                await swarmB.AddPeersAsync(new[] { seed.AsPeer }, null);\n\n                Assert.Contains(swarmB.AsPeer, seed.Peers);\n                Assert.Contains(seed.AsPeer, swarmB.Peers);\n            }\n            finally\n            {\n                CleaningSwarm(seed);\n                CleaningSwarm(swarmA);\n                CleaningSwarm(swarmB);\n            }\n        }\n\n        [Fact(Timeout = Timeout)]\n        public async Task RunConsensusReactorIfOptionGiven()\n        {\n            Swarm swarmA = await CreateSwarm().ConfigureAwait(false);\n            Swarm swarmB = await CreateConsensusSwarm().ConfigureAwait(false);\n\n            await StartAsync(swarmA);\n            await StartAsync(swarmB);\n            await Task.Delay(1000);\n\n            Assert.True(swarmA.Running);\n            Assert.True(swarmB.Running);\n            Assert.False(swarmA.ConsensusRunning);\n            Assert.True(swarmB.ConsensusRunning);\n\n            CleaningSwarm(swarmA);\n            CleaningSwarm(swarmB);\n        }\n\n        [Fact(Timeout = Timeout)]\n        public async Task StopAsyncTest()\n        {\n            Swarm swarm = await CreateSwarm().ConfigureAwait(false);\n\n            await swarm.StopAsync();\n            var task = await StartAsync(swarm);\n\n            Assert.True(swarm.Running);\n            await swarm.StopAsync();\n\n            Assert.False(swarm.Running);\n\n            Assert.False(\n                task.IsFaulted,\n                $\"A task was faulted due to an exception: {task.Exception}\"\n            );\n        }\n\n        [Fact(Timeout = Timeout)]\n        public async Task CanWaitForRunning()\n        {\n            Swarm swarm = await CreateSwarm().ConfigureAwait(false);\n\n            Assert.False(swarm.Running);\n\n            Task consumerTask = Task.Run(\n                async () =>\n                {\n                    await swarm.WaitForRunningAsync();\n                    Assert.True(swarm.Running);\n                }\n            );\n\n            Task producerTask = Task.Run(async () => { await swarm.StartAsync(); });\n\n            await consumerTask;\n            Assert.True(swarm.Running);\n\n            CleaningSwarm(swarm);\n            Assert.False(swarm.Running);\n        }\n\n        [Fact(Timeout = Timeout)]\n        public async Task AddPeersWithoutStart()\n        {\n            Swarm a = await CreateSwarm().ConfigureAwait(false);\n            Swarm b = await CreateSwarm().ConfigureAwait(false);\n\n            try\n            {\n                await StartAsync(b);\n\n                await a.AddPeersAsync(new BoundPeer[] { b.AsPeer }, null);\n\n                Assert.Contains(b.AsPeer, a.Peers);\n                Assert.Contains(a.AsPeer, b.Peers);\n            }\n            finally\n            {\n                CleaningSwarm(a);\n                CleaningSwarm(b);\n            }\n        }\n\n        [Fact(Timeout = Timeout)]\n        public async Task AddPeersAsync()\n        {\n            Swarm a = await CreateSwarm().ConfigureAwait(false);\n            Swarm b = await CreateSwarm().ConfigureAwait(false);\n\n            try\n            {\n                await StartAsync(a);\n                await StartAsync(b);\n\n                await a.AddPeersAsync(new BoundPeer[] { b.AsPeer }, null);\n\n                Assert.Contains(a.AsPeer, b.Peers);\n                Assert.Contains(b.AsPeer, a.Peers);\n            }\n            finally\n            {\n                CleaningSwarm(a);\n                CleaningSwarm(b);\n            }\n        }\n\n        [Fact(Timeout = Timeout)]\n        public async Task BootstrapException()\n        {\n            Swarm swarmA = await CreateSwarm().ConfigureAwait(false);\n            Swarm swarmB = await CreateSwarm().ConfigureAwait(false);\n\n            try\n            {\n                await Assert.ThrowsAsync<PeerDiscoveryException>(\n                    () => swarmB.BootstrapAsync(\n                        new[] { swarmA.AsPeer },\n                        TimeSpan.FromMilliseconds(3000),\n                        Kademlia.MaxDepth));\n\n                await StartAsync(swarmA);\n            }\n            finally\n            {\n                CleaningSwarm(swarmA);\n                CleaningSwarm(swarmB);\n            }\n        }\n\n        [Fact(Timeout = Timeout)]\n        public async Task BootstrapAsyncWithoutStart()\n        {\n            Swarm swarmA = await CreateSwarm().ConfigureAwait(false);\n            Swarm swarmB = await CreateSwarm().ConfigureAwait(false);\n            Swarm swarmC = await CreateSwarm().ConfigureAwait(false);\n            Swarm swarmD = await CreateSwarm().ConfigureAwait(false);\n\n            try\n            {\n                await StartAsync(swarmA);\n                await StartAsync(swarmB);\n                await StartAsync(swarmD);\n\n                var bootstrappedAt = DateTimeOffset.UtcNow;\n                swarmC.RoutingTable.AddPeer(swarmD.AsPeer);\n                await BootstrapAsync(swarmB, swarmA.AsPeer);\n                await BootstrapAsync(swarmC, swarmA.AsPeer);\n\n                Assert.Contains(swarmB.AsPeer, swarmC.Peers);\n                Assert.Contains(swarmC.AsPeer, swarmB.Peers);\n                foreach (PeerState state in swarmB.RoutingTable.PeerStates)\n                {\n                    Assert.InRange(state.LastUpdated, bootstrappedAt, DateTimeOffset.UtcNow);\n                }\n\n                foreach (PeerState state in swarmC.RoutingTable.PeerStates)\n                {\n                    if (state.Peer.Address == swarmD.AsPeer.Address)\n                    {\n                        // Peers added before bootstrap should not be marked as stale.\n                        Assert.InRange(state.LastUpdated, bootstrappedAt, DateTimeOffset.UtcNow);\n                    }\n                    else\n                    {\n                        Assert.Equal(DateTimeOffset.MinValue, state.LastUpdated);\n                    }\n                }\n            }\n            finally\n            {\n                CleaningSwarm(swarmA);\n                CleaningSwarm(swarmB);\n                CleaningSwarm(swarmC);\n            }\n        }\n\n        [Fact(Timeout = Timeout)]\n        public async Task MaintainStaticPeers()\n        {\n            var keyA = new PrivateKey();\n            var hostOptionsA = new HostOptions(\n                IPAddress.Loopback.ToString(), new IceServer[] { }, 20_000);\n            var hostOptionsB = new HostOptions(\n                IPAddress.Loopback.ToString(), new IceServer[] { }, 20_001);\n\n            Swarm swarmA =\n                await CreateSwarm(keyA, hostOptions: hostOptionsA).ConfigureAwait(false);\n            Swarm swarmB =\n                await CreateSwarm(hostOptions: hostOptionsB).ConfigureAwait(false);\n            await StartAsync(swarmA);\n            await StartAsync(swarmB);\n\n            Swarm swarm = await CreateSwarm(\n                options: new SwarmOptions\n                {\n                    StaticPeers = new[]\n                    {\n                        swarmA.AsPeer,\n                        swarmB.AsPeer,\n                        // Unreachable peer:\n                        new BoundPeer(\n                            new PrivateKey().PublicKey,\n                            new DnsEndPoint(\"127.0.0.1\", 65535)\n                        ),\n                    }.ToImmutableHashSet(),\n                    StaticPeersMaintainPeriod = TimeSpan.FromMilliseconds(100),\n                }).ConfigureAwait(false);\n\n            await StartAsync(swarm);\n            await AssertThatEventually(() => swarm.Peers.Contains(swarmA.AsPeer), 5_000);\n            await AssertThatEventually(() => swarm.Peers.Contains(swarmB.AsPeer), 5_000);\n\n            _logger.Debug(\"Address of swarmA: {Address}\", swarmA.Address);\n            CleaningSwarm(swarmA);\n            swarmA.Dispose();\n            await Task.Delay(100);\n            await swarm.PeerDiscovery.RefreshTableAsync(\n                TimeSpan.Zero,\n                default);\n            // Invoke once more in case of swarmA and swarmB is in the same bucket,\n            // and swarmA is last updated.\n            await swarm.PeerDiscovery.RefreshTableAsync(\n                TimeSpan.Zero,\n                default);\n            Assert.DoesNotContain(swarmA.AsPeer, swarm.Peers);\n            Assert.Contains(swarmB.AsPeer, swarm.Peers);\n\n            Swarm swarmC =\n                await CreateSwarm(keyA, hostOptions: hostOptionsA).ConfigureAwait(false);\n            await StartAsync(swarmC);\n            await AssertThatEventually(() => swarm.Peers.Contains(swarmB.AsPeer), 5_000);\n            await AssertThatEventually(() => swarm.Peers.Contains(swarmC.AsPeer), 5_000);\n\n            CleaningSwarm(swarm);\n            CleaningSwarm(swarmB);\n            CleaningSwarm(swarmC);\n        }\n\n        [Fact(Timeout = Timeout)]\n        public async Task Cancel()\n        {\n            Swarm swarm = await CreateSwarm().ConfigureAwait(false);\n            var cts = new CancellationTokenSource();\n\n            Task task = await StartAsync(\n                swarm,\n                cancellationToken: cts.Token\n            );\n\n            await Task.Delay(100);\n            cts.Cancel();\n            await Assert.ThrowsAsync<TaskCanceledException>(async () => await task);\n            CleaningSwarm(swarm);\n        }\n\n        [Fact(Timeout = Timeout)]\n        public async Task BootstrapContext()\n        {\n            var collectedTwoMessages = Enumerable.Range(0, 4).Select(i =>\n                new AsyncAutoResetEvent()).ToList();\n            var stepChangedToPreCommits = Enumerable.Range(0, 4).Select(i =>\n                new AsyncAutoResetEvent()).ToList();\n            var roundChangedToOnes = Enumerable.Range(0, 4).Select(i =>\n                new AsyncAutoResetEvent()).ToList();\n            var roundOneProposed = new AsyncAutoResetEvent();\n            var policy = new NullBlockPolicy();\n            var genesis = new MemoryStoreFixture(policy.PolicyActionsRegistry).GenesisBlock;\n\n            var consensusPeers = Enumerable.Range(0, 4).Select(i =>\n                new BoundPeer(\n                    TestUtils.PrivateKeys[i].PublicKey,\n                    new DnsEndPoint(\"127.0.0.1\", 6000 + i))).ToImmutableList();\n            var reactorOpts = Enumerable.Range(0, 4).Select(i =>\n                new ConsensusReactorOption\n                {\n                    ConsensusPeers = consensusPeers,\n                    ConsensusPort = 6000 + i,\n                    ConsensusPrivateKey = TestUtils.PrivateKeys[i],\n                    ConsensusWorkers = 100,\n                    TargetBlockInterval = TimeSpan.FromSeconds(10),\n                    ContextOption = new ContextOption(),\n                }).ToList();\n            var swarms = new List<Swarm>();\n            for (int i = 0; i < 4; i++)\n            {\n                swarms.Add(await CreateSwarm(\n                    privateKey: TestUtils.PrivateKeys[i],\n                    hostOptions: new HostOptions(\n                        \"127.0.0.1\",\n                        Array.Empty<IceServer>(),\n                        9000 + i),\n                    policy: policy,\n                    genesis: genesis,\n                    consensusReactorOption: reactorOpts[i]).ConfigureAwait(false));\n            }\n\n            try\n            {\n                // swarms[1] is the round 0 proposer for height 1.\n                // swarms[2] is the round 1 proposer for height 2.\n                _ = swarms[0].StartAsync();\n                _ = swarms[3].StartAsync();\n\n                swarms[0].ConsensusReactor.ConsensusContext.StateChanged += (_, eventArgs) =>\n                {\n                    if (eventArgs.VoteCount == 2)\n                    {\n                        collectedTwoMessages[0].Set();\n                    }\n                };\n\n                // Make sure both swarms time out and swarm[0] collects two PreVotes.\n                await collectedTwoMessages[0].WaitAsync();\n\n                // Dispose swarm[3] to simulate shutdown during bootstrap.\n                swarms[3].Dispose();\n\n                // Bring swarm[2] online.\n                _ = swarms[2].StartAsync();\n                swarms[0].ConsensusReactor.ConsensusContext.StateChanged += (_, eventArgs) =>\n                {\n                    if (eventArgs.Step == ConsensusStep.PreCommit)\n                    {\n                        stepChangedToPreCommits[0].Set();\n                    }\n                };\n                swarms[2].ConsensusReactor.ConsensusContext.StateChanged += (_, eventArgs) =>\n                {\n                    if (eventArgs.Step == ConsensusStep.PreCommit)\n                    {\n                        stepChangedToPreCommits[2].Set();\n                    }\n                };\n\n                // Since we already have swarm[3]'s PreVote, when swarm[2] times out,\n                // swarm[2] adds additional PreVote, making it possible to reach PreCommit.\n                // Current network's context state should be:\n                // Proposal: null\n                // PreVote: swarm[0], swarm[2], swarm[3],\n                // PreCommit: swarm[0], swarm[2]\n                await Task.WhenAll(\n                    stepChangedToPreCommits[0].WaitAsync(), stepChangedToPreCommits[2].WaitAsync());\n\n                // After swarm[1] comes online, eventually it'll catch up to vote PreCommit,\n                // at which point the round will move to 1 where swarm[2] is the proposer.\n                _ = swarms[1].StartAsync();\n                swarms[2].ConsensusReactor.ConsensusContext.MessagePublished += (_, eventArgs) =>\n                {\n                    if (eventArgs.Message is ConsensusProposalMsg proposalMsg &&\n                        proposalMsg.Round == 1 &&\n                        proposalMsg.ValidatorPublicKey.Equals(TestUtils.PrivateKeys[2].PublicKey))\n                    {\n                        roundOneProposed.Set();\n                    }\n                };\n\n                await roundOneProposed.WaitAsync();\n\n                await AssertThatEventually(() => swarms[0].BlockChain.Tip.Index == 1, int.MaxValue);\n                Assert.Equal(1, swarms[0].BlockChain.GetBlockCommit(1).Round);\n            }\n            finally\n            {\n                CleaningSwarm(swarms[0]);\n                CleaningSwarm(swarms[1]);\n                CleaningSwarm(swarms[2]);\n            }\n        }\n\n        [Fact(Timeout = Timeout)]\n        public async Task GetBlocks()\n        {\n            var keyA = new PrivateKey();\n\n            Swarm swarmA =\n                await CreateSwarm(keyA).ConfigureAwait(false);\n            Block genesis = swarmA.BlockChain.Genesis;\n            Swarm swarmB =\n                await CreateSwarm(genesis: genesis).ConfigureAwait(false);\n\n            BlockChain chainA = swarmA.BlockChain;\n\n            Block block1 = chainA.ProposeBlock(keyA);\n            chainA.Append(block1, TestUtils.CreateBlockCommit(block1));\n            Block block2 = chainA.ProposeBlock(keyA, CreateBlockCommit(block1));\n            chainA.Append(block2, TestUtils.CreateBlockCommit(block2));\n\n            try\n            {\n                await StartAsync(swarmA);\n                await StartAsync(swarmB);\n\n                await swarmA.AddPeersAsync(new[] { swarmB.AsPeer }, null);\n\n                List<BlockHash> inventories = await swarmB.GetBlockHashes(\n                    swarmA.AsPeer,\n                    new BlockLocator(genesis.Hash));\n                Assert.Equal(\n                    new[] { genesis.Hash, block1.Hash, block2.Hash },\n                    inventories);\n\n                (Block, BlockCommit)[] receivedBlocks =\n                    await swarmB.GetBlocksAsync(\n                        swarmA.AsPeer,\n                        inventories,\n                        cancellationToken: default\n                    ).ToArrayAsync();\n                Assert.Equal(\n                    new[] { genesis, block1, block2 }, receivedBlocks.Select(pair => pair.Item1));\n            }\n            finally\n            {\n                CleaningSwarm(swarmA);\n                CleaningSwarm(swarmB);\n            }\n        }\n\n        [Fact(Timeout = Timeout)]\n        public async Task GetMultipleBlocksAtOnce()\n        {\n            var keyA = new PrivateKey();\n            var keyB = new PrivateKey();\n\n            Swarm swarmA = await CreateSwarm(keyA).ConfigureAwait(false);\n            Block genesis = swarmA.BlockChain.Genesis;\n            Swarm swarmB =\n                await CreateSwarm(keyB, genesis: genesis).ConfigureAwait(false);\n\n            BlockChain chainA = swarmA.BlockChain;\n            BlockChain chainB = swarmB.BlockChain;\n\n            Block block1 = chainA.ProposeBlock(\n                keyA, CreateBlockCommit(chainA.Tip));\n            chainA.Append(block1, TestUtils.CreateBlockCommit(block1));\n            Block block2 = chainA.ProposeBlock(\n                keyA, CreateBlockCommit(chainA.Tip));\n            chainA.Append(block2, TestUtils.CreateBlockCommit(block2));\n\n            try\n            {\n                await StartAsync(swarmA);\n                await StartAsync(swarmB);\n\n                var peer = swarmA.AsPeer;\n\n                await swarmB.AddPeersAsync(new[] { peer }, null);\n\n                List<BlockHash> hashes = await swarmB.GetBlockHashes(\n                    peer,\n                    new BlockLocator(genesis.Hash));\n\n                ITransport transport = swarmB.Transport;\n\n                var request = new GetBlocksMsg(hashes, 2);\n                Message[] responses = (await transport.SendMessageAsync(\n                    swarmA.AsPeer,\n                    request,\n                    null,\n                    2,\n                    false,\n                    default)).ToArray();\n                var blockMessage = (BlocksMsg)responses[0].Content;\n\n                Assert.Equal(2, responses.Length);\n                Assert.Equal(4, blockMessage.Payloads.Count);\n\n                blockMessage = (BlocksMsg)responses[1].Content;\n\n                Assert.Equal(2, blockMessage.Payloads.Count);\n            }\n            finally\n            {\n                CleaningSwarm(swarmA);\n                CleaningSwarm(swarmB);\n            }\n        }\n\n        [Fact(Timeout = Timeout)]\n        public async Task GetTx()\n        {\n            var keyB = new PrivateKey();\n\n            Swarm swarmA = await CreateSwarm().ConfigureAwait(false);\n            Block genesis = swarmA.BlockChain.Genesis;\n            Swarm swarmB =\n                await CreateSwarm(keyB, genesis: genesis).ConfigureAwait(false);\n            BlockChain chainB = swarmB.BlockChain;\n\n            Transaction tx = Transaction.Create(\n                0,\n                new PrivateKey(),\n                chainB.Genesis.Hash,\n                Array.Empty<DumbAction>().ToPlainValues()\n            );\n            chainB.StageTransaction(tx);\n            Block block = chainB.ProposeBlock(keyB);\n            chainB.Append(block, TestUtils.CreateBlockCommit(block));\n\n            try\n            {\n                await StartAsync(swarmA);\n                await StartAsync(swarmB);\n\n                await swarmA.AddPeersAsync(new[] { swarmB.AsPeer }, null);\n\n                List<Transaction> txs =\n                    await swarmA.GetTxsAsync(\n                        swarmB.AsPeer,\n                        new[] { tx.Id },\n                        cancellationToken: default\n                    ).ToListAsync();\n\n                Assert.Equal(new[] { tx }, txs);\n            }\n            finally\n            {\n                CleaningSwarm(swarmA);\n                CleaningSwarm(swarmB);\n            }\n        }\n\n        [Fact(Timeout = Timeout)]\n        public async Task ThrowArgumentExceptionInConstructor()\n        {\n            var fx = new MemoryStoreFixture();\n            var policy = new BlockPolicy();\n            var blockchain = MakeBlockChain(\n                policy, fx.Store, fx.StateStore, new SingleActionLoader(typeof(DumbAction)));\n            var key = new PrivateKey();\n            var apv = AppProtocolVersion.Sign(key, 1);\n            var apvOptions = new AppProtocolVersionOptions() { AppProtocolVersion = apv };\n            var hostOptions = new HostOptions(\n                IPAddress.Loopback.ToString(), new IceServer[] { });\n            var transport = await NetMQTransport.Create(\n                key,\n                apvOptions,\n                hostOptions);\n\n            // TODO: Check Consensus Parameters.\n            Assert.Throws<ArgumentNullException>(() =>\n                new Swarm(null, key, transport));\n            Assert.Throws<ArgumentNullException>(() =>\n                new Swarm(blockchain, null, transport));\n        }\n\n        [Fact(Timeout = Timeout)]\n        public async void CanResolveEndPoint()\n        {\n            var expected = new DnsEndPoint(\"1.2.3.4\", 5678);\n            var hostOptions = new HostOptions(\"1.2.3.4\", new IceServer[] { }, 5678);\n            Swarm s = await CreateSwarm(hostOptions: hostOptions).ConfigureAwait(false);\n            Assert.Equal(expected, s.EndPoint);\n            Assert.Equal(expected, s.AsPeer?.EndPoint);\n            CleaningSwarm(s);\n        }\n\n        [Fact(Timeout = Timeout)]\n        public async Task StopGracefullyWhileStarting()\n        {\n            Swarm a = await CreateSwarm().ConfigureAwait(false);\n\n            Task t = await StartAsync(a);\n            bool canceled = false;\n            try\n            {\n                await Task.WhenAll(a.StopAsync(), t);\n            }\n            catch (OperationCanceledException)\n            {\n                canceled = true;\n            }\n\n            Assert.True(canceled || t.IsCompleted);\n            CleaningSwarm(a);\n        }\n\n        [Fact(Timeout = Timeout)]\n        public async Task AsPeer()\n        {\n            Swarm swarm = await CreateSwarm().ConfigureAwait(false);\n            Assert.IsType<BoundPeer>(swarm.AsPeer);\n\n            await StartAsync(swarm);\n            Assert.IsType<BoundPeer>(swarm.AsPeer);\n            CleaningSwarm(swarm);\n        }\n\n        [FactOnlyTurnAvailable(Timeout = Timeout)]\n        public async Task ExchangeWithIceServer()\n        {\n            var iceServers = FactOnlyTurnAvailableAttribute.GetIceServers();\n            var seedHostOptions = new HostOptions(\"127.0.0.1\", ImmutableList<IceServer>.Empty, 0);\n            var swarmHostOptions = new HostOptions(null, iceServers);\n            var seed = await CreateSwarm(hostOptions: seedHostOptions).ConfigureAwait(false);\n            var swarmA = await CreateSwarm(hostOptions: swarmHostOptions).ConfigureAwait(false);\n            var swarmB = await CreateSwarm(hostOptions: swarmHostOptions).ConfigureAwait(false);\n\n            try\n            {\n                await StartAsync(seed);\n                await StartAsync(swarmA);\n                await StartAsync(swarmB);\n\n                await swarmA.AddPeersAsync(new[] { seed.AsPeer }, null);\n                await swarmB.AddPeersAsync(new[] { seed.AsPeer }, null);\n                await swarmA.AddPeersAsync(new[] { swarmB.AsPeer }, null);\n\n                Assert.Equal(\n                    new HashSet<BoundPeer>\n                    {\n                        swarmA.AsPeer,\n                        swarmB.AsPeer,\n                    },\n                    seed.Peers.ToHashSet());\n                Assert.Equal(\n                    new HashSet<BoundPeer> { seed.AsPeer, swarmB.AsPeer },\n                    swarmA.Peers.ToHashSet());\n                Assert.Equal(\n                    new HashSet<BoundPeer> { seed.AsPeer, swarmA.AsPeer },\n                    swarmB.Peers.ToHashSet());\n            }\n            finally\n            {\n                CleaningSwarm(seed);\n                CleaningSwarm(swarmA);\n                CleaningSwarm(swarmB);\n            }\n        }\n\n        [FactOnlyTurnAvailable(10, 5000, Timeout = Timeout)]\n        public async Task ReconnectToTurn()\n        {\n            int port;\n            using (var socket = new Socket(SocketType.Stream, ProtocolType.Tcp))\n            {\n                socket.Bind(new IPEndPoint(IPAddress.Loopback, 0));\n                port = ((IPEndPoint)socket.LocalEndPoint).Port;\n            }\n\n            Uri turnUrl = FactOnlyTurnAvailableAttribute.GetTurnUri();\n            string[] userInfo = turnUrl.UserInfo.Split(':');\n            string username = userInfo[0];\n            string password = userInfo[1];\n            var proxyUri = new Uri($\"turn://{username}:{password}@127.0.0.1:{port}/\");\n            IEnumerable<IceServer> iceServers = new[] { new IceServer(url: proxyUri) };\n\n            var cts = new CancellationTokenSource();\n            var proxyTask = TurnProxy(port, turnUrl, cts.Token);\n\n            var seedKey = new PrivateKey();\n            var seedHostOptions = new HostOptions(\"127.0.0.1\", ImmutableList<IceServer>.Empty, 0);\n            var swarmHostOptions = new HostOptions(null, iceServers, 0);\n            var seed =\n                await CreateSwarm(seedKey, hostOptions: seedHostOptions).ConfigureAwait(false);\n            var swarmA =\n                await CreateSwarm(hostOptions: swarmHostOptions).ConfigureAwait(false);\n\n            async Task RefreshTableAsync(CancellationToken cancellationToken)\n            {\n                while (!cancellationToken.IsCancellationRequested)\n                {\n                    await Task.Delay(1000, cancellationToken);\n                    try\n                    {\n                        await swarmA.PeerDiscovery.RefreshTableAsync(\n                            TimeSpan.FromSeconds(1), cancellationToken);\n                    }\n                    catch (InvalidOperationException)\n                    {\n                    }\n                    catch (TurnClientException)\n                    {\n                    }\n                }\n            }\n\n            async Task MineAndBroadcast(CancellationToken cancellationToken)\n            {\n                while (!cancellationToken.IsCancellationRequested)\n                {\n                    var block = seed.BlockChain.ProposeBlock(seedKey);\n                    seed.BlockChain.Append(block, TestUtils.CreateBlockCommit(block));\n                    seed.BroadcastBlock(block);\n                    await Task.Delay(1000, cancellationToken);\n                }\n            }\n\n            try\n            {\n                await StartAsync(seed);\n                await StartAsync(swarmA, cancellationToken: cts.Token);\n\n                await swarmA.AddPeersAsync(new[] { seed.AsPeer }, null);\n\n                cts.Cancel();\n                await proxyTask;\n                cts = new CancellationTokenSource();\n\n                proxyTask = TurnProxy(port, turnUrl, cts.Token);\n                _ = RefreshTableAsync(cts.Token);\n                _ = MineAndBroadcast(cts.Token);\n\n                cts.CancelAfter(1500);\n                await swarmA.BlockReceived.WaitAsync(cts.Token);\n                cts.Cancel();\n                await Task.Delay(1000);\n\n                Assert.NotEqual(swarmA.BlockChain.Genesis, swarmA.BlockChain.Tip);\n                Assert.Contains(\n                    swarmA.BlockChain.Tip.Hash,\n                    seed.BlockChain.BlockHashes\n                );\n            }\n            finally\n            {\n                CleaningSwarm(seed);\n                CleaningSwarm(swarmA);\n            }\n        }\n\n        [Fact(Timeout = Timeout)]\n        public async Task CannotBlockSyncWithForkedChain()\n        {\n            var policy = new NullBlockPolicy();\n            var chain1 = MakeBlockChain(\n                policy,\n                new MemoryStore(),\n                new TrieStateStore(new MemoryKeyValueStore()),\n                new SingleActionLoader(typeof(DumbAction)));\n            var chain2 = MakeBlockChain(\n                policy,\n                new MemoryStore(),\n                new TrieStateStore(new MemoryKeyValueStore()),\n                new SingleActionLoader(typeof(DumbAction)));\n\n            var key1 = new PrivateKey();\n            var key2 = new PrivateKey();\n\n            var miner1 = await CreateSwarm(chain1, key1).ConfigureAwait(false);\n            var miner2 = await CreateSwarm(chain2, key2).ConfigureAwait(false);\n\n            var privKey = new PrivateKey();\n            var addr = miner1.Address;\n            var item = \"foo\";\n\n            miner1.BlockChain.MakeTransaction(privKey, new[] { DumbAction.Create((addr, item)) });\n            Block block1 = miner1.BlockChain.ProposeBlock(\n                key1, CreateBlockCommit(miner1.BlockChain.Tip));\n            miner1.BlockChain.Append(block1, TestUtils.CreateBlockCommit(block1));\n            var miner1TipHash = miner1.BlockChain.Tip.Hash;\n\n            miner2.BlockChain.MakeTransaction(privKey, new[] { DumbAction.Create((addr, item)) });\n            Block block2 = miner2.BlockChain.ProposeBlock(\n                key2, CreateBlockCommit(miner2.BlockChain.Tip));\n            miner2.BlockChain.Append(block2, TestUtils.CreateBlockCommit(block2));\n\n            miner2.BlockChain.MakeTransaction(privKey, new[] { DumbAction.Create((addr, item)) });\n            var latest = miner2.BlockChain.ProposeBlock(\n                key2, CreateBlockCommit(miner2.BlockChain.Tip));\n            miner2.BlockChain.Append(latest, TestUtils.CreateBlockCommit(latest));\n\n            await StartAsync(miner1);\n            await StartAsync(miner2);\n\n            await BootstrapAsync(miner2, miner1.AsPeer);\n\n            miner2.BroadcastBlock(latest);\n\n            await Task.Delay(5_000);\n            Assert.Equal(miner1TipHash, miner1.BlockChain.Tip.Hash);\n\n            CleaningSwarm(miner1);\n            CleaningSwarm(miner2);\n        }\n\n        [Fact(Timeout = Timeout)]\n        public async Task UnstageInvalidTransaction()\n        {\n            var validKey = new PrivateKey();\n\n            TxPolicyViolationException IsSignerValid(\n                BlockChain chain, Transaction tx)\n            {\n                var validAddress = validKey.Address;\n                return tx.Signer.Equals(validAddress) ||\n                       tx.Signer.Equals(GenesisProposer.Address)\n                    ? null\n                    : new TxPolicyViolationException(\"invalid signer\", tx.Id);\n            }\n\n            var policy = new BlockPolicy(validateNextBlockTx: IsSignerValid);\n            var fx1 = new MemoryStoreFixture();\n            var fx2 = new MemoryStoreFixture();\n\n            var swarmA = await CreateSwarm(\n                MakeBlockChain(\n                    policy,\n                    fx1.Store,\n                    fx1.StateStore,\n                    new SingleActionLoader(typeof(DumbAction)),\n                    privateKey: validKey))\n                .ConfigureAwait(false);\n            var swarmB = await CreateSwarm(\n                MakeBlockChain(\n                    policy,\n                    fx2.Store,\n                    fx2.StateStore,\n                    new SingleActionLoader(typeof(DumbAction)),\n                    privateKey: validKey))\n                .ConfigureAwait(false);\n\n            var invalidKey = new PrivateKey();\n\n            try\n            {\n                var validTx = swarmA.BlockChain.MakeTransaction(validKey, new DumbAction[] { });\n                var invalidTx = swarmA.BlockChain.MakeTransaction(invalidKey, new DumbAction[] { });\n\n                await StartAsync(swarmA);\n                await StartAsync(swarmB);\n\n                await BootstrapAsync(swarmA, swarmB.AsPeer);\n\n                swarmA.BroadcastTxs(new[] { validTx, invalidTx });\n                await swarmB.TxReceived.WaitAsync();\n\n                Assert.Equal(swarmB.BlockChain.GetTransaction(validTx.Id), validTx);\n                Assert.Throws<KeyNotFoundException>(\n                    () => swarmB.BlockChain.GetTransaction(invalidTx.Id)\n                );\n\n                Assert.Contains(validTx.Id, swarmB.BlockChain.GetStagedTransactionIds());\n                Assert.DoesNotContain(invalidTx.Id, swarmB.BlockChain.GetStagedTransactionIds());\n            }\n            finally\n            {\n                CleaningSwarm(swarmA);\n                CleaningSwarm(swarmB);\n\n                fx1.Dispose();\n                fx2.Dispose();\n            }\n        }\n\n        [RetryFact(Timeout = Timeout)]\n        public async Task IgnoreTransactionFromDifferentGenesis()\n        {\n            var validKey = new PrivateKey();\n\n            TxPolicyViolationException IsSignerValid(\n                BlockChain chain, Transaction tx)\n            {\n                var validAddress = validKey.Address;\n                return tx.Signer.Equals(validAddress) ||\n                       tx.Signer.Equals(GenesisProposer.Address)\n                    ? null\n                    : new TxPolicyViolationException(\"invalid signer\", tx.Id);\n            }\n\n            var policy = new BlockPolicy(validateNextBlockTx: IsSignerValid);\n            var fx1 = new MemoryStoreFixture();\n            var fx2 = new MemoryStoreFixture();\n\n            var swarmA = await CreateSwarm(\n                MakeBlockChain(\n                    policy,\n                    fx1.Store,\n                    fx1.StateStore,\n                    new SingleActionLoader(typeof(DumbAction)),\n                    privateKey: validKey,\n                    timestamp: DateTimeOffset.MinValue)).ConfigureAwait(false);\n            var swarmB = await CreateSwarm(\n                MakeBlockChain(\n                    policy,\n                    fx2.Store,\n                    fx2.StateStore,\n                    new SingleActionLoader(typeof(DumbAction)),\n                    privateKey: validKey,\n                    timestamp: DateTimeOffset.MinValue.AddSeconds(1))).ConfigureAwait(false);\n\n            try\n            {\n                var tx = swarmA.BlockChain.MakeTransaction(validKey, new DumbAction[] { });\n\n                await StartAsync(swarmA);\n                await StartAsync(swarmB);\n\n                await BootstrapAsync(swarmA, swarmB.AsPeer);\n\n                swarmA.BroadcastTxs(new[] { tx });\n                await swarmB.TxReceived.WaitAsync();\n\n                Assert.Throws<KeyNotFoundException>(() => swarmB.BlockChain.GetTransaction(tx.Id));\n                Assert.DoesNotContain(tx.Id, swarmB.BlockChain.GetStagedTransactionIds());\n            }\n            finally\n            {\n                CleaningSwarm(swarmA);\n                CleaningSwarm(swarmB);\n\n                fx1.Dispose();\n                fx2.Dispose();\n            }\n        }\n\n        [Fact(Timeout = Timeout)]\n        public async Task DoNotReceiveBlockFromNodeHavingDifferentGenesisBlock()\n        {\n            var keyA = ByteUtil.ParseHex(\n                \"8568eb6f287afedece2c7b918471183db0451e1a61535bb0381cfdf95b85df20\");\n            var keyB = ByteUtil.ParseHex(\n                \"c34f7498befcc39a14f03b37833f6c7bb78310f1243616524eda70e078b8313c\");\n            var keyC = ByteUtil.ParseHex(\n                \"941bc2edfab840d79914d80fe3b30840628ac37a5d812d7f922b5d2405a223d3\");\n\n            var privateKeyA = new PrivateKey(keyA);\n            var privateKeyB = new PrivateKey(keyB);\n            var privateKeyC = new PrivateKey(keyC);\n\n            var signerAddress = new PrivateKey().Address;\n\n            var actionsA = new[] { DumbAction.Create((signerAddress, \"1\")) };\n            var actionsB = new[] { DumbAction.Create((signerAddress, \"2\")) };\n\n            var genesisChainA = MakeBlockChain(\n                new BlockPolicy(),\n                new MemoryStore(),\n                new TrieStateStore(new MemoryKeyValueStore()),\n                new SingleActionLoader(typeof(DumbAction)),\n                actionsA,\n                null,\n                privateKeyA);\n            var genesisBlockA = genesisChainA.Genesis;\n            var genesisChainB = MakeBlockChain(\n                new BlockPolicy(),\n                new MemoryStore(),\n                new TrieStateStore(new MemoryKeyValueStore()),\n                new SingleActionLoader(typeof(DumbAction)),\n                actionsB,\n                null,\n                privateKeyB);\n            var genesisChainC = MakeBlockChain(\n                new BlockPolicy(),\n                new MemoryStore(),\n                new TrieStateStore(new MemoryKeyValueStore()),\n                new SingleActionLoader(typeof(DumbAction)),\n                genesisBlock: genesisBlockA);\n\n            var swarmA =\n                await CreateSwarm(genesisChainA, privateKeyA).ConfigureAwait(false);\n            var swarmB =\n                await CreateSwarm(genesisChainB, privateKeyB).ConfigureAwait(false);\n            var swarmC =\n                await CreateSwarm(genesisChainC, privateKeyC).ConfigureAwait(false);\n            try\n            {\n                await StartAsync(swarmA);\n                await StartAsync(swarmB);\n                await StartAsync(swarmC);\n\n                await swarmB.AddPeersAsync(new[] { swarmA.AsPeer }, null);\n                await swarmC.AddPeersAsync(new[] { swarmA.AsPeer }, null);\n\n                var block = swarmA.BlockChain.ProposeBlock(privateKeyA);\n                swarmA.BlockChain.Append(block, TestUtils.CreateBlockCommit(block));\n\n                Task.WaitAll(new[]\n                {\n                    Task.Run(() => swarmC.BlockAppended.Wait()),\n                    Task.Run(() => swarmA.BroadcastBlock(block)),\n                });\n\n                Assert.NotEqual(genesisChainA.Genesis, genesisChainB.Genesis);\n                Assert.Equal(genesisChainA.BlockHashes, genesisChainC.BlockHashes);\n                Assert.Equal(2, genesisChainA.Count);\n                Assert.Equal(1, genesisChainB.Count);\n                Assert.Equal(2, genesisChainC.Count);\n\n                Assert.Equal(\n                    \"1\",\n                    (Text)genesisChainA\n                        .GetNextWorldState()\n                        .GetAccountState(ReservedAddresses.LegacyAccount)\n                        .GetState(signerAddress));\n                Assert.Equal(\n                    \"2\",\n                    (Text)genesisChainB\n                        .GetNextWorldState()\n                        .GetAccountState(ReservedAddresses.LegacyAccount)\n                        .GetState(signerAddress));\n                Assert.Equal(\n                    \"1\",\n                    (Text)genesisChainC\n                        .GetNextWorldState()\n                        .GetAccountState(ReservedAddresses.LegacyAccount)\n                        .GetState(signerAddress));\n            }\n            finally\n            {\n                CleaningSwarm(swarmA);\n                CleaningSwarm(swarmB);\n                CleaningSwarm(swarmC);\n            }\n        }\n\n        [Fact(Timeout = Timeout)]\n        public async Task FindSpecificPeerAsync()\n        {\n            Swarm swarmA = await CreateSwarm().ConfigureAwait(false);\n            Swarm swarmB = await CreateSwarm().ConfigureAwait(false);\n            Swarm swarmC = await CreateSwarm().ConfigureAwait(false);\n            Swarm swarmD = await CreateSwarm().ConfigureAwait(false);\n            try\n            {\n                await StartAsync(swarmA);\n                await StartAsync(swarmB);\n                await StartAsync(swarmC);\n                await StartAsync(swarmD);\n\n                await swarmA.AddPeersAsync(new BoundPeer[] { swarmB.AsPeer }, null);\n                await swarmB.AddPeersAsync(new BoundPeer[] { swarmC.AsPeer }, null);\n                await swarmC.AddPeersAsync(new BoundPeer[] { swarmD.AsPeer }, null);\n\n                BoundPeer foundPeer = await swarmA.FindSpecificPeerAsync(\n                    swarmB.AsPeer.Address,\n                    -1,\n                    TimeSpan.FromMilliseconds(3000));\n\n                Assert.Equal(swarmB.AsPeer.Address, foundPeer.Address);\n                Assert.DoesNotContain(swarmC.AsPeer, swarmA.Peers);\n\n                foundPeer = await swarmA.FindSpecificPeerAsync(\n                    swarmD.AsPeer.Address,\n                    -1,\n                    TimeSpan.FromMilliseconds(3000));\n\n                Assert.Equal(swarmD.AsPeer.Address, foundPeer.Address);\n                Assert.Contains(swarmC.AsPeer, swarmA.Peers);\n                Assert.Contains(swarmD.AsPeer, swarmA.Peers);\n            }\n            finally\n            {\n                CleaningSwarm(swarmA);\n                CleaningSwarm(swarmB);\n                CleaningSwarm(swarmC);\n                CleaningSwarm(swarmD);\n            }\n        }\n\n        [Fact(Timeout = Timeout)]\n        public async Task FindSpecificPeerAsyncFail()\n        {\n            Swarm swarmA = await CreateSwarm().ConfigureAwait(false);\n            Swarm swarmB = await CreateSwarm().ConfigureAwait(false);\n            Swarm swarmC = await CreateSwarm().ConfigureAwait(false);\n            try\n            {\n                await StartAsync(swarmA);\n                await StartAsync(swarmB);\n                await StartAsync(swarmC);\n\n                await swarmA.AddPeersAsync(new BoundPeer[] { swarmB.AsPeer }, null);\n                await swarmB.AddPeersAsync(new BoundPeer[] { swarmC.AsPeer }, null);\n\n                CleaningSwarm(swarmB);\n\n                BoundPeer foundPeer = await swarmA.FindSpecificPeerAsync(\n                    swarmB.AsPeer.Address,\n                    -1,\n                    TimeSpan.FromMilliseconds(3000));\n\n                Assert.Null(foundPeer);\n\n                foundPeer = await swarmA.FindSpecificPeerAsync(\n                    swarmC.AsPeer.Address,\n                    -1,\n                    TimeSpan.FromMilliseconds(3000));\n\n                Assert.Null(foundPeer);\n                Assert.DoesNotContain(swarmC.AsPeer, swarmA.Peers);\n            }\n            finally\n            {\n                CleaningSwarm(swarmA);\n                CleaningSwarm(swarmC);\n            }\n        }\n\n        [Fact(Timeout = Timeout)]\n        public async Task FindSpecificPeerAsyncDepthFail()\n        {\n            Swarm swarmA = await CreateSwarm().ConfigureAwait(false);\n            Swarm swarmB = await CreateSwarm().ConfigureAwait(false);\n            Swarm swarmC = await CreateSwarm().ConfigureAwait(false);\n            Swarm swarmD = await CreateSwarm().ConfigureAwait(false);\n\n            _output.WriteLine(\"{0}: {1}\", nameof(swarmA), swarmA.AsPeer);\n            _output.WriteLine(\"{0}: {1}\", nameof(swarmB), swarmB.AsPeer);\n            _output.WriteLine(\"{0}: {1}\", nameof(swarmC), swarmC.AsPeer);\n            _output.WriteLine(\"{0}: {1}\", nameof(swarmD), swarmD.AsPeer);\n\n            try\n            {\n                await StartAsync(swarmA);\n                await StartAsync(swarmB);\n                await StartAsync(swarmC);\n                await StartAsync(swarmD);\n\n                await swarmA.AddPeersAsync(new BoundPeer[] { swarmB.AsPeer }, null);\n                await swarmB.AddPeersAsync(new BoundPeer[] { swarmC.AsPeer }, null);\n                await swarmC.AddPeersAsync(new BoundPeer[] { swarmD.AsPeer }, null);\n\n                BoundPeer foundPeer = await swarmA.FindSpecificPeerAsync(\n                    swarmC.AsPeer.Address,\n                    1,\n                    TimeSpan.FromMilliseconds(3000));\n\n                Assert.Equal(swarmC.AsPeer.Address, foundPeer.Address);\n                swarmA.RoutingTable.Clear();\n                Assert.Empty(swarmA.Peers);\n                await swarmA.AddPeersAsync(new BoundPeer[] { swarmB.AsPeer }, null);\n\n                foundPeer = await swarmA.FindSpecificPeerAsync(\n                    swarmD.AsPeer.Address,\n                    1,\n                    TimeSpan.FromMilliseconds(3000));\n\n                Assert.Null(foundPeer);\n            }\n            finally\n            {\n                CleaningSwarm(swarmA);\n                CleaningSwarm(swarmB);\n                CleaningSwarm(swarmC);\n                CleaningSwarm(swarmD);\n            }\n        }\n\n        [Fact(Timeout = Timeout)]\n        public async Task DoNotFillWhenGetAllBlockAtFirstTimeFromSender()\n        {\n            Swarm receiver = await CreateSwarm().ConfigureAwait(false);\n            Swarm sender = await CreateSwarm().ConfigureAwait(false);\n            await StartAsync(receiver);\n            await StartAsync(sender);\n\n            receiver.FindNextHashesChunkSize = 8;\n            sender.FindNextHashesChunkSize = 8;\n            BlockChain chain = sender.BlockChain;\n\n            for (int i = 0; i < 6; i++)\n            {\n                Block block = chain.ProposeBlock(\n                    GenesisProposer, TestUtils.CreateBlockCommit(chain.Tip));\n                chain.Append(block, TestUtils.CreateBlockCommit(block));\n            }\n\n            Log.Debug(\"Sender's BlockChain Tip index: #{index}\", sender.BlockChain.Tip.Index);\n\n            try\n            {\n                await BootstrapAsync(sender, receiver.AsPeer);\n\n                sender.BroadcastBlock(sender.BlockChain.Tip);\n\n                await receiver.BlockReceived.WaitAsync();\n                await receiver.BlockAppended.WaitAsync();\n                Assert.Equal(\n                    7,\n                    receiver.BlockChain.Count);\n            }\n            finally\n            {\n                CleaningSwarm(receiver);\n                CleaningSwarm(sender);\n            }\n        }\n\n        [Fact(Timeout = Timeout)]\n        public async Task FillWhenGetAChunkOfBlocksFromSender()\n        {\n            Swarm receiver = await CreateSwarm().ConfigureAwait(false);\n            Swarm sender = await CreateSwarm().ConfigureAwait(false);\n            await StartAsync(receiver);\n            await StartAsync(sender);\n\n            receiver.FindNextHashesChunkSize = 2;\n            sender.FindNextHashesChunkSize = 2;\n            BlockChain chain = sender.BlockChain;\n\n            for (int i = 0; i < 6; i++)\n            {\n                Block block = chain.ProposeBlock(\n                    GenesisProposer, TestUtils.CreateBlockCommit(chain.Tip));\n                chain.Append(block, TestUtils.CreateBlockCommit(block));\n            }\n\n            Log.Debug(\"Sender's BlockChain Tip index: #{index}\", sender.BlockChain.Tip.Index);\n\n            try\n            {\n                await BootstrapAsync(sender, receiver.AsPeer);\n\n                sender.BroadcastBlock(sender.BlockChain.Tip);\n\n                await receiver.BlockReceived.WaitAsync();\n                await receiver.BlockAppended.WaitAsync();\n                Log.Debug(\"Count: {Count}\", receiver.BlockChain.Count);\n                Assert.Equal(\n                    2,\n                    receiver.BlockChain.Count);\n            }\n            finally\n            {\n                CleaningSwarm(receiver);\n                CleaningSwarm(sender);\n            }\n        }\n\n        [Fact(Timeout = Timeout)]\n        public async Task FillWhenGetAllBlocksFromSender()\n        {\n            Swarm receiver = await CreateSwarm().ConfigureAwait(false);\n            Swarm sender = await CreateSwarm().ConfigureAwait(false);\n            await StartAsync(receiver);\n            await StartAsync(sender);\n\n            receiver.FindNextHashesChunkSize = 3;\n            sender.FindNextHashesChunkSize = 3;\n            BlockChain chain = sender.BlockChain;\n\n            for (int i = 0; i < 6; i++)\n            {\n                Block block = chain.ProposeBlock(\n                    GenesisProposer, CreateBlockCommit(chain.Tip));\n                chain.Append(block, TestUtils.CreateBlockCommit(block));\n            }\n\n            Log.Debug(\"Sender's BlockChain Tip index: #{index}\", sender.BlockChain.Tip.Index);\n\n            try\n            {\n                await BootstrapAsync(sender, receiver.AsPeer);\n\n                sender.BroadcastBlock(sender.BlockChain.Tip);\n\n                await receiver.BlockReceived.WaitAsync();\n                await receiver.BlockAppended.WaitAsync();\n                Log.Debug(\"Count: {Count}\", receiver.BlockChain.Count);\n                sender.BroadcastBlock(sender.BlockChain.Tip);\n                Assert.Equal(\n                    3,\n                    receiver.BlockChain.Count);\n\n                sender.BroadcastBlock(sender.BlockChain.Tip);\n\n                await receiver.BlockReceived.WaitAsync();\n                await receiver.BlockAppended.WaitAsync();\n                Log.Debug(\"Count: {Count}\", receiver.BlockChain.Count);\n                sender.BroadcastBlock(sender.BlockChain.Tip);\n                Assert.Equal(\n                    5,\n                    receiver.BlockChain.Count);\n\n                sender.BroadcastBlock(sender.BlockChain.Tip);\n\n                await receiver.BlockReceived.WaitAsync();\n                await receiver.BlockAppended.WaitAsync();\n                Log.Debug(\"Count: {Count}\", receiver.BlockChain.Count);\n                sender.BroadcastBlock(sender.BlockChain.Tip);\n                Assert.Equal(\n                    7,\n                    receiver.BlockChain.Count);\n            }\n            finally\n            {\n                CleaningSwarm(receiver);\n                CleaningSwarm(sender);\n            }\n        }\n\n        [RetryFact(10, Timeout = Timeout)]\n        public async Task GetPeerChainStateAsync()\n        {\n            var key2 = new PrivateKey();\n\n            Swarm swarm1 = await CreateSwarm().ConfigureAwait(false);\n            Swarm swarm2 = await CreateSwarm(key2).ConfigureAwait(false);\n            Swarm swarm3 = await CreateSwarm().ConfigureAwait(false);\n\n            var peerChainState = await swarm1.GetPeerChainStateAsync(\n                TimeSpan.FromSeconds(1), default);\n            Assert.Empty(peerChainState);\n\n            try\n            {\n                await StartAsync(swarm2);\n                await StartAsync(swarm3);\n\n                await BootstrapAsync(swarm1, swarm2.AsPeer);\n\n                peerChainState = await swarm1.GetPeerChainStateAsync(\n                    TimeSpan.FromSeconds(1), default);\n                Assert.Equal(\n                    new PeerChainState(swarm2.AsPeer, 0),\n                    peerChainState.First()\n                );\n\n                Block block = swarm2.BlockChain.ProposeBlock(key2);\n                swarm2.BlockChain.Append(block, TestUtils.CreateBlockCommit(block));\n                peerChainState = await swarm1.GetPeerChainStateAsync(\n                    TimeSpan.FromSeconds(1), default);\n                Assert.Equal(\n                    new PeerChainState(swarm2.AsPeer, 1),\n                    peerChainState.First()\n                );\n\n                await BootstrapAsync(swarm1, swarm3.AsPeer);\n                peerChainState = await swarm1.GetPeerChainStateAsync(\n                    TimeSpan.FromSeconds(1), default);\n                Assert.Equal(\n                    new[]\n                    {\n                        new PeerChainState(swarm2.AsPeer, 1),\n                        new PeerChainState(swarm3.AsPeer, 0),\n                    }.ToHashSet(),\n                    peerChainState.ToHashSet()\n                );\n            }\n            finally\n            {\n                CleaningSwarm(swarm2);\n                CleaningSwarm(swarm3);\n            }\n        }\n\n        [Fact(Timeout = Timeout)]\n        public async Task LastMessageTimestamp()\n        {\n            Swarm swarm1 = await CreateSwarm().ConfigureAwait(false);\n            Swarm swarm2 = await CreateSwarm().ConfigureAwait(false);\n\n            Assert.Null(swarm1.LastMessageTimestamp);\n\n            try\n            {\n                await StartAsync(swarm1);\n                Assert.Null(swarm1.LastMessageTimestamp);\n                DateTimeOffset bootstrappedAt = DateTimeOffset.UtcNow;\n                await BootstrapAsync(swarm2, swarm1.AsPeer);\n                await StartAsync(swarm2);\n\n                Assert.NotNull(swarm1.LastMessageTimestamp);\n                Assert.InRange(\n                    swarm1.LastMessageTimestamp.Value,\n                    bootstrappedAt,\n                    DateTimeOffset.UtcNow\n                );\n            }\n            finally\n            {\n                CleaningSwarm(swarm1);\n                CleaningSwarm(swarm2);\n            }\n        }\n\n        [RetryFact(10, Timeout = Timeout)]\n        public async Task RegulateGetBlocksMsg()\n        {\n            var options = new SwarmOptions\n            {\n                TaskRegulationOptions =\n                {\n                    MaxTransferBlocksTaskCount = 3,\n                },\n            };\n            var apvOptions = new AppProtocolVersionOptions();\n\n            var key = new PrivateKey();\n            Swarm swarm = await CreateSwarm(\n                    options: options,\n                    appProtocolVersionOptions: apvOptions)\n                .ConfigureAwait(false);\n            NetMQTransport transport = await NetMQTransport.Create(\n                key,\n                apvOptions,\n                new HostOptions(\"localhost\", Enumerable.Empty<IceServer>()));\n\n            try\n            {\n                await StartAsync(swarm);\n                _ = transport.StartAsync();\n                await transport.WaitForRunningAsync();\n                var tasks = new List<Task>();\n                var content = new GetBlocksMsg(new[] { swarm.BlockChain.Genesis.Hash });\n                for (int i = 0; i < 5; i++)\n                {\n                    tasks.Add(\n                        Task.Run(async () => await transport.SendMessageAsync(\n                            swarm.AsPeer,\n                            content,\n                            TimeSpan.FromMilliseconds(1000),\n                            1,\n                            false,\n                            default)));\n                }\n\n                try\n                {\n                    await Task.WhenAll(tasks);\n                }\n                catch (Exception)\n                {\n                    // ignored\n                }\n\n                Assert.Equal(\n                    options.TaskRegulationOptions.MaxTransferBlocksTaskCount,\n                    tasks.Count(t => t.IsCompletedSuccessfully));\n            }\n            finally\n            {\n                CleaningSwarm(swarm);\n                await transport.StopAsync(TimeSpan.Zero);\n            }\n        }\n\n        [RetryFact(10, Timeout = Timeout)]\n        public async Task RegulateGetTxsMsg()\n        {\n            var options = new SwarmOptions\n            {\n                TaskRegulationOptions =\n                {\n                    MaxTransferTxsTaskCount = 3,\n                },\n            };\n            var apvOptions = new AppProtocolVersionOptions();\n\n            var key = new PrivateKey();\n            Swarm swarm = await CreateSwarm(\n                    options: options,\n                    appProtocolVersionOptions: apvOptions)\n                .ConfigureAwait(false);\n            NetMQTransport transport = await NetMQTransport.Create(\n                key,\n                apvOptions,\n                new HostOptions(\"localhost\", Enumerable.Empty<IceServer>()));\n\n            try\n            {\n                await StartAsync(swarm);\n                var fx = new MemoryStoreFixture();\n                _ = transport.StartAsync();\n                await transport.WaitForRunningAsync();\n                var tasks = new List<Task>();\n                var content = new GetTxsMsg(new[] { fx.TxId1 });\n                for (int i = 0; i < 5; i++)\n                {\n                    tasks.Add(\n                        transport.SendMessageAsync(\n                            swarm.AsPeer,\n                            content,\n                            TimeSpan.FromMilliseconds(1000),\n                            1,\n                            false,\n                            default));\n                }\n\n                try\n                {\n                    await Task.WhenAll(tasks);\n                }\n                catch (Exception)\n                {\n                    // ignored\n                }\n\n                Assert.Equal(\n                    options.TaskRegulationOptions.MaxTransferBlocksTaskCount,\n                    tasks.Count(t => t.IsCompletedSuccessfully));\n            }\n            finally\n            {\n                CleaningSwarm(swarm);\n                await transport.StopAsync(TimeSpan.Zero);\n            }\n        }\n\n        protected void Dispose(bool disposing)\n        {\n            if (!_disposed)\n            {\n                if (disposing)\n                {\n                    _logger.Debug(\"Starts to finalize {Resources} resources...\", _finalizers.Count);\n                    int i = 1;\n                    foreach (Func<Task> finalize in _finalizers)\n                    {\n                        _logger.Debug(\"Tries to finalize the resource #{Resource}...\", i++);\n                        finalize().WaitAndUnwrapException();\n                    }\n\n                    _logger.Debug(\"Finished to finalize {Resources} resources\", _finalizers.Count);\n                    NetMQConfig.Cleanup(false);\n                }\n\n                _disposed = true;\n            }\n        }\n\n        private async Task<Task> StartAsync(\n            Swarm swarm,\n            int millisecondsBroadcastBlockInterval = 15 * 1000,\n            CancellationToken cancellationToken = default)\n        {\n            Task task = swarm.StartAsync(\n                dialTimeout: TimeSpan.FromMilliseconds(200),\n                broadcastBlockInterval:\n                    TimeSpan.FromMilliseconds(millisecondsBroadcastBlockInterval),\n                broadcastTxInterval: TimeSpan.FromMilliseconds(200),\n                cancellationToken: cancellationToken\n            );\n            await swarm.WaitForRunningAsync();\n            return task;\n        }\n\n        private Task StopAsync(Swarm swarm)\n        {\n            return swarm.StopAsync(TimeSpan.FromMilliseconds(10));\n        }\n\n        private void CleaningSwarm(Swarm swarm)\n        {\n            swarm.StopAsync(TimeSpan.FromMilliseconds(10)).WaitAndUnwrapException();\n            swarm.Dispose();\n        }\n\n        private Task BootstrapAsync(\n            Swarm swarm,\n            BoundPeer seed,\n            CancellationToken cancellationToken = default\n        ) =>\n            BootstrapAsync(swarm, new[] { seed }, cancellationToken);\n\n        private async Task BootstrapAsync(\n            Swarm swarm,\n            IEnumerable<BoundPeer> seeds,\n            CancellationToken cancellationToken = default)\n        {\n            await swarm.BootstrapAsync(\n                seeds,\n                dialTimeout: TimeSpan.FromSeconds(3),\n                searchDepth: Kademlia.MaxDepth,\n                cancellationToken: cancellationToken);\n        }\n\n        private async Task TurnProxy(\n            int port,\n            Uri turnUri,\n            CancellationToken cancellationToken)\n        {\n            var server = new TcpListener(IPAddress.Loopback, port);\n            server.Start();\n            var tasks = new List<Task>();\n            var clients = new List<TcpClient>();\n\n            cancellationToken.Register(() => server.Stop());\n            while (!cancellationToken.IsCancellationRequested)\n            {\n                TcpClient client;\n                try\n                {\n                    client = await server.AcceptTcpClientAsync();\n                }\n                catch (ObjectDisposedException)\n                {\n                    break;\n                }\n\n                clients.Add(client);\n\n                tasks.Add(Task.Run(\n                    async () =>\n                    {\n                        const int bufferSize = 8192;\n                        NetworkStream stream = client.GetStream();\n\n                        using (TcpClient remoteClient = new TcpClient(turnUri.Host, turnUri.Port))\n                        {\n                            var remoteStream = remoteClient.GetStream();\n                            await await Task.WhenAny(\n                                remoteStream.CopyToAsync(stream, bufferSize, cancellationToken),\n                                stream.CopyToAsync(remoteStream, bufferSize, cancellationToken));\n                        }\n\n                        client.Dispose();\n                    },\n                    cancellationToken));\n            }\n\n            foreach (var client in clients)\n            {\n                client?.Dispose();\n            }\n\n            Log.Debug(\"TurnProxy is canceled\");\n\n            await Task.WhenAny(tasks);\n        }\n\n        private class Sleep : IAction\n        {\n            public IValue PlainValue => Null.Value;\n\n            public IWorld Execute(IActionContext context)\n            {\n                Thread.Sleep(10);\n                return context.PreviousState;\n            }\n\n            public void LoadPlainValue(IValue plainValue)\n            {\n            }\n        }\n\n        private class EmulatingUnstableGetBlockStore : ProxyStore\n        {\n            public EmulatingUnstableGetBlockStore(IStore store)\n                : base(store)\n            {\n            }\n\n            public bool BlockGettable { get; set; } = true;\n\n            public override Block GetBlock(BlockHash blockHash) =>\n                BlockGettable ? base.GetBlock(blockHash) : null;\n        }\n    }\n}\n"
  },
  {
    "path": "test/Libplanet.Net.Tests/TestUtils.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Collections.Immutable;\nusing System.Linq;\nusing System.Net;\nusing System.Numerics;\nusing System.Threading.Tasks;\nusing Bencodex;\nusing Libplanet.Action;\nusing Libplanet.Action.Loader;\nusing Libplanet.Action.State;\nusing Libplanet.Action.Tests.Common;\nusing Libplanet.Blockchain;\nusing Libplanet.Blockchain.Policies;\nusing Libplanet.Consensus;\nusing Libplanet.Crypto;\nusing Libplanet.Net.Consensus;\nusing Libplanet.Net.Messages;\nusing Libplanet.Net.Options;\nusing Libplanet.Net.Protocols;\nusing Libplanet.Net.Transports;\nusing Libplanet.Store;\nusing Libplanet.Store.Trie;\nusing Libplanet.Tests;\nusing Libplanet.Tests.Store;\nusing Libplanet.Types.Blocks;\nusing Libplanet.Types.Consensus;\nusing Random = System.Random;\n\nnamespace Libplanet.Net.Tests\n{\n    public static class TestUtils\n    {\n        public static readonly BlockHash BlockHash0 =\n            BlockHash.FromString(\n                \"042b81bef7d4bca6e01f5975ce9ac7ed9f75248903d08836bed6566488c8089d\");\n\n        public static readonly ImmutableList<PrivateKey> PrivateKeys =\n            Libplanet.Tests.TestUtils.ValidatorPrivateKeys;\n\n        public static readonly List<BoundPeer> Peers = new List<BoundPeer>()\n        {\n            new BoundPeer(PrivateKeys[0].PublicKey, new DnsEndPoint(\"1.0.0.0\", 1000)),\n            new BoundPeer(PrivateKeys[1].PublicKey, new DnsEndPoint(\"1.0.0.1\", 1001)),\n            new BoundPeer(PrivateKeys[2].PublicKey, new DnsEndPoint(\"1.0.0.2\", 1002)),\n            new BoundPeer(PrivateKeys[3].PublicKey, new DnsEndPoint(\"1.0.0.3\", 1003)),\n        };\n\n        public static readonly ValidatorSet ValidatorSet = Libplanet.Tests.TestUtils.ValidatorSet;\n\n        public static readonly IBlockPolicy Policy = new BlockPolicy(\n            new PolicyActionsRegistry(\n                endBlockActions: ImmutableArray.Create<IAction>(new MinerReward(1))),\n            getMaxTransactionsBytes: _ => 50 * 1024);\n\n        public static readonly IActionLoader ActionLoader = new SingleActionLoader(\n            typeof(DumbAction));\n\n        public static AppProtocolVersion AppProtocolVersion = AppProtocolVersion.FromToken(\n            \"1/54684Ac4ee5B933e72144C4968BEa26056880d71/MEQCICGonYW\" +\n            \".X8y4JpPIyccPYWGrsCXWA95sBfextucz3lOyAiBUoY5t8aYNPT0lwYwC0MSkK3HT7T\" +\n            \".lGJJW13dJi+06nw==\");\n\n        private static readonly Random Random = new Random();\n\n        public static Vote CreateVote(\n            PrivateKey privateKey,\n            BigInteger power,\n            long height,\n            int round,\n            BlockHash hash,\n            VoteFlag flag) =>\n            new VoteMetadata(\n                height,\n                round,\n                hash,\n                DateTimeOffset.Now,\n                privateKey.PublicKey,\n                power,\n                flag).Sign(privateKey);\n\n        public static PrivateKey GeneratePrivateKeyOfBucketIndex(Address tableAddress, int target)\n        {\n            var table = new RoutingTable(tableAddress);\n            PrivateKey privateKey;\n            do\n            {\n                privateKey = new PrivateKey();\n            }\n            while (table.GetBucketIndexOf(privateKey.Address) != target);\n\n            return privateKey;\n        }\n\n        public static BlockChain CreateDummyBlockChain(\n            IBlockPolicy? policy = null,\n            IActionLoader? actionLoader = null,\n            Block? genesisBlock = null)\n        {\n            policy ??= Policy;\n            actionLoader ??= ActionLoader;\n            var fx = new MemoryStoreFixture(policy.PolicyActionsRegistry);\n            var blockChain = Libplanet.Tests.TestUtils.MakeBlockChain(\n                policy,\n                fx.Store,\n                new TrieStateStore(new MemoryKeyValueStore()),\n                actionLoader,\n                genesisBlock: genesisBlock);\n\n            return blockChain;\n        }\n\n        public static ConsensusProposalMsg CreateConsensusPropose(\n            Block block,\n            PrivateKey privateKey,\n            long height = 1,\n            int round = 0,\n            int validRound = -1)\n        {\n            var codec = new Codec();\n            return new ConsensusProposalMsg(\n                new ProposalMetadata(\n                    height,\n                    round,\n                    DateTimeOffset.UtcNow,\n                    privateKey.PublicKey,\n                    codec.Encode(block.MarshalBlock()),\n                    validRound).Sign(privateKey));\n        }\n\n        public static BlockCommit CreateBlockCommit(Block block) =>\n            Libplanet.Tests.TestUtils.CreateBlockCommit(block);\n\n        public static BlockCommit CreateBlockCommit(BlockHash blockHash, long height, int round) =>\n            Libplanet.Tests.TestUtils.CreateBlockCommit(blockHash, height, round);\n\n        public static void HandleFourPeersPreCommitMessages(\n            ConsensusContext consensusContext,\n            PrivateKey nodePrivateKey,\n            BlockHash roundBlockHash)\n        {\n            foreach ((PrivateKey privateKey, BigInteger power)\n                     in PrivateKeys.Zip(\n                         ValidatorSet.Validators.Select(v => v.Power),\n                         (first, second) => (first, second)))\n            {\n                if (privateKey == nodePrivateKey)\n                {\n                    continue;\n                }\n\n                consensusContext.HandleMessage(\n                    new ConsensusPreCommitMsg(\n                        new VoteMetadata(\n                            consensusContext.Height,\n                            (int)consensusContext.Round,\n                            roundBlockHash,\n                            DateTimeOffset.UtcNow,\n                            privateKey.PublicKey,\n                            power,\n                            VoteFlag.PreCommit).Sign(privateKey)));\n            }\n        }\n\n        public static void HandleFourPeersPreCommitMessages(\n            Context context,\n            PrivateKey nodePrivateKey,\n            BlockHash roundBlockHash)\n        {\n            foreach ((PrivateKey privateKey, BigInteger power)\n                     in PrivateKeys.Zip(\n                         ValidatorSet.Validators.Select(v => v.Power),\n                         (first, second) => (first, second)))\n            {\n                if (privateKey == nodePrivateKey)\n                {\n                    continue;\n                }\n\n                context.ProduceMessage(\n                    new ConsensusPreCommitMsg(\n                        new VoteMetadata(\n                            context.Height,\n                            context.Round,\n                            roundBlockHash,\n                            DateTimeOffset.UtcNow,\n                            privateKey.PublicKey,\n                            power,\n                            VoteFlag.PreCommit).Sign(privateKey)));\n            }\n        }\n\n        public static void HandleFourPeersPreVoteMessages(\n            Context context,\n            PrivateKey nodePrivateKey,\n            BlockHash roundBlockHash)\n        {\n            foreach ((PrivateKey privateKey, BigInteger power)\n                     in PrivateKeys.Zip(\n                         ValidatorSet.Validators.Select(v => v.Power),\n                         (first, second) => (first, second)))\n            {\n                if (privateKey == nodePrivateKey)\n                {\n                    continue;\n                }\n\n                context.ProduceMessage(\n                    new ConsensusPreVoteMsg(\n                        new VoteMetadata(\n                            context.Height,\n                            context.Round,\n                            roundBlockHash,\n                            DateTimeOffset.UtcNow,\n                            privateKey.PublicKey,\n                            power,\n                            VoteFlag.PreVote).Sign(privateKey)));\n            }\n        }\n\n        public static void HandleFourPeersPreVoteMessages(\n            ConsensusContext consensusContext,\n            PrivateKey nodePrivateKey,\n            BlockHash roundBlockHash)\n        {\n            foreach ((PrivateKey privateKey, BigInteger power)\n                     in PrivateKeys.Zip(\n                         ValidatorSet.Validators.Select(v => v.Power),\n                         (first, second) => (first, second)))\n            {\n                if (privateKey == nodePrivateKey)\n                {\n                    continue;\n                }\n\n                consensusContext.HandleMessage(\n                    new ConsensusPreVoteMsg(\n                        new VoteMetadata(\n                            consensusContext.Height,\n                            (int)consensusContext.Round,\n                            roundBlockHash,\n                            DateTimeOffset.UtcNow,\n                            privateKey.PublicKey,\n                            power,\n                            VoteFlag.PreVote).Sign(privateKey)));\n            }\n        }\n\n        public static (BlockChain BlockChain, ConsensusContext ConsensusContext)\n            CreateDummyConsensusContext(\n                TimeSpan newHeightDelay,\n                IBlockPolicy? policy = null,\n                IActionLoader? actionLoader = null,\n                PrivateKey? privateKey = null,\n                ContextOption? contextOption = null)\n        {\n            policy ??= Policy;\n            var blockChain = CreateDummyBlockChain(policy, actionLoader);\n            ConsensusContext? consensusContext = null;\n\n            privateKey ??= PrivateKeys[1];\n\n            void BroadcastMessage(ConsensusMsg message) =>\n                Task.Run(() =>\n                {\n                    // ReSharper disable once AccessToModifiedClosure\n                    consensusContext!.HandleMessage(message);\n                });\n\n            consensusContext = new ConsensusContext(\n                new DummyConsensusMessageHandler(BroadcastMessage),\n                blockChain,\n                privateKey,\n                newHeightDelay,\n                contextOption ?? new ContextOption());\n\n            return (blockChain, consensusContext);\n        }\n\n        public static Context CreateDummyContext(\n            BlockChain blockChain,\n            long height = 1,\n            BlockCommit? lastCommit = null,\n            PrivateKey? privateKey = null,\n            ContextOption? contextOption = null,\n            ValidatorSet? validatorSet = null)\n        {\n            Context? context = null;\n            privateKey ??= PrivateKeys[0];\n            context = new Context(\n                blockChain,\n                height,\n                lastCommit,\n                privateKey,\n                validatorSet ?? blockChain\n                    .GetNextWorldState(height - 1)\n                    .GetValidatorSet(),\n                contextOption: contextOption ?? new ContextOption());\n            context.MessageToPublish += (sender, message) => context.ProduceMessage(message);\n            return context;\n        }\n\n        public static (BlockChain BlockChain, Context Context)\n            CreateDummyContext(\n                long height = 1,\n                BlockCommit? lastCommit = null,\n                IBlockPolicy? policy = null,\n                IActionLoader? actionLoader = null,\n                PrivateKey? privateKey = null,\n                ContextOption? contextOption = null,\n                ValidatorSet? validatorSet = null)\n        {\n            Context? context = null;\n            privateKey ??= PrivateKeys[1];\n            policy ??= Policy;\n\n            var blockChain = CreateDummyBlockChain(policy, actionLoader);\n            context = new Context(\n                blockChain,\n                height,\n                lastCommit,\n                privateKey,\n                validatorSet ?? blockChain\n                    .GetNextWorldState(height - 1)\n                    .GetValidatorSet(),\n                contextOption: contextOption ?? new ContextOption());\n            context.MessageToPublish += (sender, message) => context.ProduceMessage(message);\n\n            return (blockChain, context);\n        }\n\n        public static ConsensusReactor CreateDummyConsensusReactor(\n            BlockChain blockChain,\n            PrivateKey? key = null,\n            string host = \"127.0.0.1\",\n            int consensusPort = 5101,\n            List<BoundPeer>? validatorPeers = null,\n            int newHeightDelayMilliseconds = 10_000,\n            ContextOption? contextOption = null)\n        {\n            key ??= PrivateKeys[1];\n            validatorPeers ??= Peers;\n\n            var apvOption = new AppProtocolVersionOptions\n            { AppProtocolVersion = AppProtocolVersion };\n            var hostOption = new HostOptions(host, Array.Empty<IceServer>(), consensusPort);\n            var consensusTransport = NetMQTransport.Create(\n                key,\n                apvOption,\n                hostOption).ConfigureAwait(false).GetAwaiter().GetResult();\n\n            return new ConsensusReactor(\n                consensusTransport,\n                blockChain,\n                key,\n                validatorPeers.ToImmutableList(),\n                new List<BoundPeer>().ToImmutableList(),\n                TimeSpan.FromMilliseconds(newHeightDelayMilliseconds),\n                contextOption: contextOption ?? new ContextOption());\n        }\n\n        public static byte[] GetRandomBytes(int size)\n        {\n            var bytes = new byte[size];\n            Random.NextBytes(bytes);\n\n            return bytes;\n        }\n\n        public class DummyConsensusMessageHandler : IConsensusMessageCommunicator\n        {\n            private Action<ConsensusMsg> _publishMessage;\n\n            public DummyConsensusMessageHandler(Action<ConsensusMsg> publishMessage)\n            {\n                _publishMessage = publishMessage;\n            }\n\n            public void PublishMessage(ConsensusMsg message)\n                => _publishMessage(message);\n\n            public void OnStartHeight(long height)\n            {\n            }\n\n            public void OnStartRound(int round)\n            {\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "test/Libplanet.Net.Tests/Transports/BoundPeerExtensionsTest.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Net;\nusing System.Net.Sockets;\nusing System.Threading.Tasks;\nusing Libplanet.Action.Loader;\nusing Libplanet.Action.Tests.Common;\nusing Libplanet.Blockchain.Policies;\nusing Libplanet.Crypto;\nusing Libplanet.Net.Options;\nusing Libplanet.Net.Transports;\nusing Libplanet.Tests.Store;\nusing NetMQ;\nusing Xunit;\nusing Xunit.Sdk;\nusing static Libplanet.Tests.TestUtils;\n\nnamespace Libplanet.Net.Tests.Transports\n{\n    [Collection(\"NetMQConfiguration\")]\n    public class BoundPeerExtensionsTest : IDisposable\n    {\n        public void Dispose()\n        {\n            NetMQConfig.Cleanup(false);\n        }\n\n        [Fact(Timeout = 60 * 1000)]\n        public async Task QueryAppProtocolVersion()\n        {\n            var fx = new MemoryStoreFixture();\n            var policy = new BlockPolicy();\n            var blockchain = MakeBlockChain(\n                policy, fx.Store, fx.StateStore, new SingleActionLoader(typeof(DumbAction)));\n            var swarmKey = new PrivateKey();\n            var consensusKey = new PrivateKey();\n            var validators = new List<PublicKey>()\n            {\n                swarmKey.PublicKey,\n            };\n            var apv = AppProtocolVersion.Sign(new PrivateKey(), 1);\n            var apvOptions = new AppProtocolVersionOptions() { AppProtocolVersion = apv };\n            string host = IPAddress.Loopback.ToString();\n            int port = FreeTcpPort();\n            var hostOptions = new HostOptions(\n                IPAddress.Loopback.ToString(), new IceServer[] { }, port);\n            var option = new SwarmOptions();\n            var transport = await NetMQTransport.Create(\n                swarmKey,\n                apvOptions,\n                hostOptions);\n            using (var swarm = new Swarm(\n                blockchain,\n                swarmKey,\n                transport,\n                options: option))\n            {\n                var peer = new BoundPeer(swarmKey.PublicKey, new DnsEndPoint(host, port));\n                // Before swarm starting...\n                Assert.Throws<TimeoutException>(() =>\n                {\n                    if (swarm.Transport is NetMQTransport)\n                    {\n                        peer.QueryAppProtocolVersionNetMQ(timeout: TimeSpan.FromSeconds(1));\n                    }\n                    else\n                    {\n                        throw new XunitException(\n                            \"Each type of transport must have corresponding test case.\");\n                    }\n                });\n                _ = swarm.StartAsync();\n                try\n                {\n                    AppProtocolVersion receivedAPV = default;\n                    if (swarm.Transport is NetMQTransport)\n                    {\n                        receivedAPV = peer.QueryAppProtocolVersionNetMQ(\n                            timeout: TimeSpan.FromSeconds(1));\n                    }\n                    else\n                    {\n                        throw new XunitException(\n                            \"Each type of transport must have corresponding test case.\");\n                    }\n\n                    Assert.Equal(apv, receivedAPV);\n                }\n                finally\n                {\n                    await swarm.StopAsync();\n                }\n            }\n\n            NetMQConfig.Cleanup(false);\n        }\n\n        [Theory]\n        [InlineData(\"127.0.0.1\", 3000, new[] { \"tcp://127.0.0.1:3000\" })]\n        [InlineData(\"127.0.0.1\", 3000, new[] { \"tcp://127.0.0.1:3000\", \"tcp://::1:3000\" })]\n        public async Task ResolveNetMQAddressAsync(string host, int port, string[] expected)\n        {\n            var bp = new BoundPeer(\n                new PrivateKey().PublicKey,\n                new DnsEndPoint(host, port)\n            );\n            var addr = await bp.ResolveNetMQAddressAsync();\n\n            Assert.Contains(addr, expected);\n        }\n\n        [Fact]\n        public async Task ResolveNetMQAddressAsyncFails()\n        {\n            string hostDoesNotExist = $\"{Guid.NewGuid()}.com\";\n            var bp = new BoundPeer(\n                new PrivateKey().PublicKey,\n                new DnsEndPoint(hostDoesNotExist, 3000)\n            );\n            await Assert.ThrowsAnyAsync<SocketException>(async () =>\n            {\n                await bp.ResolveNetMQAddressAsync();\n            });\n        }\n\n        private static int FreeTcpPort()\n        {\n            var l = new TcpListener(IPAddress.Loopback, 0);\n            l.Start();\n            int port = ((IPEndPoint)l.LocalEndpoint).Port;\n            l.Stop();\n            return port;\n        }\n    }\n}\n"
  },
  {
    "path": "test/Libplanet.Net.Tests/Transports/NetMQTransportTest.cs",
    "content": "#nullable disable\nusing System;\nusing System.Net;\nusing System.Net.Sockets;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing Libplanet.Crypto;\nusing Libplanet.Net.Messages;\nusing Libplanet.Net.Options;\nusing Libplanet.Net.Transports;\nusing NetMQ;\nusing Serilog;\nusing Xunit;\nusing Xunit.Abstractions;\n\nnamespace Libplanet.Net.Tests.Transports\n{\n    [Collection(\"NetMQConfiguration\")]\n    public class NetMQTransportTest : TransportTest, IDisposable\n    {\n        private bool _disposed;\n\n        public NetMQTransportTest(ITestOutputHelper testOutputHelper)\n        {\n            TransportConstructor = async (\n                    privateKey,\n                    appProtocolVersionOptions,\n                    hostOptions,\n                    messageTimestampBuffer) =>\n                await CreateNetMQTransport(\n                    privateKey,\n                    appProtocolVersionOptions,\n                    hostOptions,\n                    messageTimestampBuffer);\n\n            const string outputTemplate =\n                \"{Timestamp:HH:mm:ss:ffffff}[{ThreadId}] - {Message}\";\n            Log.Logger = new LoggerConfiguration()\n                .MinimumLevel.Verbose()\n                .Enrich.WithThreadId()\n                .WriteTo.TestOutput(testOutputHelper, outputTemplate: outputTemplate)\n                .CreateLogger()\n                .ForContext<NetMQTransportTest>();\n            Logger = Log.ForContext<NetMQTransportTest>();\n        }\n\n        ~NetMQTransportTest()\n        {\n            Dispose(false);\n        }\n\n        [Fact]\n        public async Task SendMessageAsyncNetMQSocketLeak()\n        {\n            int previousMaxSocket = NetMQConfig.MaxSockets;\n\n            try\n            {\n                // An arbitrary number to fit one transport testing.\n                NetMQConfig.MaxSockets = 12;\n                NetMQTransport transport = await NetMQTransport.Create(\n                    new PrivateKey(),\n                    new AppProtocolVersionOptions(),\n                    new HostOptions(IPAddress.Loopback.ToString(), new IceServer[] { }, 0)\n                ).ConfigureAwait(false);\n                transport.ProcessMessageHandler.Register(\n                    async m =>\n                    {\n                        await transport.ReplyMessageAsync(\n                            new PongMsg(),\n                            m.Identity,\n                            CancellationToken.None\n                        );\n                    }\n                );\n                await InitializeAsync(transport);\n\n                string invalidHost = Guid.NewGuid().ToString();\n\n                // it isn't assertion for Libplanet codes, but to make sure that `invalidHost`\n                // really fails lookup before moving to the next step.\n                Assert.ThrowsAny<SocketException>(() =>\n                {\n                    Dns.GetHostEntry(invalidHost);\n                });\n                var invalidPeer = new BoundPeer(\n                    new PrivateKey().PublicKey,\n                    new DnsEndPoint(invalidHost, 0)\n                );\n\n                CommunicationFailException exc =\n                    await Assert.ThrowsAsync<CommunicationFailException>(\n                        () => transport.SendMessageAsync(\n                            invalidPeer,\n                            new PingMsg(),\n                            TimeSpan.FromSeconds(5),\n                            default\n                        )\n                    );\n\n                // Expecting SocketException about host resolving since `invalidPeer` has an\n                // invalid hostname\n                Assert.IsAssignableFrom<SocketException>(exc.InnerException);\n\n                // Check sending/receiving after exceptions exceeding NetMQConifg.MaxSockets.\n                Message reply = await transport.SendMessageAsync(\n                    transport.AsPeer,\n                    new PingMsg(),\n                    TimeSpan.FromSeconds(1),\n                    default\n                );\n                Assert.IsType<PongMsg>(reply.Content);\n\n                await transport.StopAsync(TimeSpan.Zero, CancellationToken.None);\n            }\n            finally\n            {\n                NetMQConfig.MaxSockets = previousMaxSocket;\n            }\n        }\n\n        public void Dispose()\n        {\n            Dispose(true);\n            GC.SuppressFinalize(this);\n        }\n\n        protected void Dispose(bool disposing)\n        {\n            if (!_disposed)\n            {\n                if (disposing)\n                {\n                    NetMQConfig.Cleanup(false);\n                }\n\n                _disposed = true;\n            }\n        }\n\n        private Task<NetMQTransport> CreateNetMQTransport(\n            PrivateKey privateKey,\n            AppProtocolVersionOptions appProtocolVersionOptions,\n            HostOptions hostOptions,\n            TimeSpan? messageTimestampBuffer)\n        {\n            privateKey = privateKey ?? new PrivateKey();\n            return NetMQTransport.Create(\n                privateKey,\n                appProtocolVersionOptions,\n                hostOptions,\n                messageTimestampBuffer\n            );\n        }\n    }\n}\n"
  },
  {
    "path": "test/Libplanet.Net.Tests/Transports/TransportTest.cs",
    "content": "#nullable disable\nusing System;\nusing System.Collections;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Net;\nusing System.Net.Sockets;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing Libplanet.Crypto;\nusing Libplanet.Net.Messages;\nusing Libplanet.Net.Options;\nusing Libplanet.Net.Protocols;\nusing Libplanet.Net.Transports;\nusing NetMQ;\nusing Serilog;\nusing Xunit;\nusing Xunit.Sdk;\nusing static Libplanet.Net.Tests.TestUtils;\n\nnamespace Libplanet.Net.Tests.Transports\n{\n    public abstract class TransportTest\n    {\n        protected const int Timeout = 60 * 1000;\n\n        protected ILogger Logger { get; set; }\n\n        #pragma warning disable MEN002\n        protected Func<PrivateKey, AppProtocolVersionOptions, HostOptions, TimeSpan?, Task<ITransport>> TransportConstructor { get; set; }\n        #pragma warning restore MEN002\n\n        [SkippableFact(Timeout = Timeout)]\n        public async Task StartAsync()\n        {\n            ITransport transport = await CreateTransportAsync().ConfigureAwait(false);\n\n            try\n            {\n                _ = transport.StartAsync();\n                await transport.WaitForRunningAsync();\n                Assert.True(transport.Running);\n            }\n            finally\n            {\n                await transport.StopAsync(TimeSpan.FromMilliseconds(100));\n                transport.Dispose();\n            }\n        }\n\n        [SkippableFact(Timeout = Timeout)]\n        public async Task RestartAsync()\n        {\n            ITransport transport = await CreateTransportAsync().ConfigureAwait(false);\n\n            try\n            {\n                await InitializeAsync(transport);\n                Assert.True(transport.Running);\n                await transport.StopAsync(TimeSpan.Zero);\n                Assert.False(transport.Running);\n\n                await InitializeAsync(transport);\n                Assert.True(transport.Running);\n            }\n            finally\n            {\n                await transport.StopAsync(TimeSpan.FromMilliseconds(100));\n                transport.Dispose();\n                if (transport is NetMQTransport)\n                {\n                    NetMQConfig.Cleanup(false);\n                }\n            }\n        }\n\n        [SkippableFact(Timeout = Timeout)]\n        public async Task DisposeTest()\n        {\n            ITransport transport = await CreateTransportAsync().ConfigureAwait(false);\n\n            try\n            {\n                await InitializeAsync(transport);\n                Assert.True(transport.Running);\n                await transport.StopAsync(TimeSpan.FromMilliseconds(100));\n                transport.Dispose();\n                var boundPeer = new BoundPeer(\n                    new PrivateKey().PublicKey,\n                    new DnsEndPoint(\"127.0.0.1\", 1234));\n                var message = new PingMsg();\n                await Assert.ThrowsAsync<ObjectDisposedException>(\n                    async () => await transport.StartAsync());\n                await Assert.ThrowsAsync<ObjectDisposedException>(\n                    async () => await transport.StopAsync(TimeSpan.Zero));\n                await Assert.ThrowsAsync<ObjectDisposedException>(\n                    async () => await transport.SendMessageAsync(\n                        boundPeer,\n                        message,\n                        null,\n                        default));\n                await Assert.ThrowsAsync<ObjectDisposedException>(\n                    async () => await transport.SendMessageAsync(\n                        boundPeer,\n                        message,\n                        null,\n                        3,\n                        false,\n                        default));\n                Assert.Throws<ObjectDisposedException>(\n                    () => transport.BroadcastMessage(null, message));\n                await Assert.ThrowsAsync<ObjectDisposedException>(\n                    async () => await transport.ReplyMessageAsync(\n                        message,\n                        Array.Empty<byte>(),\n                        default));\n\n                // To check multiple Dispose() throws error or not.\n                transport.Dispose();\n            }\n            finally\n            {\n                transport.Dispose();\n            }\n        }\n\n        [SkippableFact(Timeout = Timeout)]\n        public async Task AsPeer()\n        {\n            var privateKey = new PrivateKey();\n            string host = IPAddress.Loopback.ToString();\n            ITransport transport =\n                await CreateTransportAsync(privateKey: privateKey).ConfigureAwait(false);\n\n            try\n            {\n                var peer = transport.AsPeer;\n                Assert.Equal(privateKey.Address, peer.Address);\n                Assert.Equal(host, peer.EndPoint.Host);\n            }\n            finally\n            {\n                await transport.StopAsync(TimeSpan.FromMilliseconds(100));\n                transport.Dispose();\n            }\n        }\n\n        // This also tests ITransport.ReplyMessageAsync at the same time.\n        [SkippableFact(Timeout = Timeout)]\n        public async Task SendMessageAsync()\n        {\n            ITransport transportA = await CreateTransportAsync().ConfigureAwait(false);\n            ITransport transportB = await CreateTransportAsync().ConfigureAwait(false);\n\n            transportB.ProcessMessageHandler.Register(async message =>\n            {\n                if (message.Content is PingMsg)\n                {\n                    await transportB.ReplyMessageAsync(\n                        new PongMsg(),\n                        message.Identity,\n                        CancellationToken.None);\n                }\n            });\n\n            try\n            {\n                await InitializeAsync(transportA);\n                await InitializeAsync(transportB);\n\n                Message reply = await transportA.SendMessageAsync(\n                    transportB.AsPeer,\n                    new PingMsg(),\n                    TimeSpan.FromSeconds(3),\n                    CancellationToken.None);\n\n                Assert.IsType<PongMsg>(reply.Content);\n            }\n            finally\n            {\n                await transportA.StopAsync(TimeSpan.FromMilliseconds(100));\n                await transportB.StopAsync(TimeSpan.FromMilliseconds(100));\n                transportA.Dispose();\n                transportB.Dispose();\n            }\n        }\n\n        [SkippableFact(Timeout = Timeout)]\n        public async Task SendMessageCancelAsync()\n        {\n            ITransport transportA = await CreateTransportAsync().ConfigureAwait(false);\n            ITransport transportB = await CreateTransportAsync().ConfigureAwait(false);\n            var cts = new CancellationTokenSource();\n\n            try\n            {\n                await InitializeAsync(transportA, default);\n                await InitializeAsync(transportB, default);\n\n                cts.CancelAfter(TimeSpan.FromSeconds(1));\n                await Assert.ThrowsAsync<TaskCanceledException>(\n                    async () => await transportA.SendMessageAsync(\n                        transportB.AsPeer,\n                        new PingMsg(),\n                        null,\n                        cts.Token));\n            }\n            finally\n            {\n                await transportA.StopAsync(TimeSpan.FromMilliseconds(100));\n                await transportB.StopAsync(TimeSpan.FromMilliseconds(100));\n                transportA.Dispose();\n                transportB.Dispose();\n                cts.Dispose();\n            }\n        }\n\n        [SkippableFact(Timeout = Timeout)]\n        public async Task SendMessageMultipleRepliesAsync()\n        {\n            ITransport transportA = await CreateTransportAsync().ConfigureAwait(false);\n            ITransport transportB = await CreateTransportAsync().ConfigureAwait(false);\n\n            transportB.ProcessMessageHandler.Register(async message =>\n            {\n                if (message.Content is PingMsg)\n                {\n                    await transportB.ReplyMessageAsync(\n                        new PingMsg(),\n                        message.Identity,\n                        default);\n                    await transportB.ReplyMessageAsync(\n                        new PongMsg(),\n                        message.Identity,\n                        default);\n                }\n            });\n\n            try\n            {\n                await InitializeAsync(transportA);\n                await InitializeAsync(transportB);\n\n                var replies = (await transportA.SendMessageAsync(\n                    transportB.AsPeer,\n                    new PingMsg(),\n                    TimeSpan.FromSeconds(3),\n                    2,\n                    false,\n                    CancellationToken.None)).ToArray();\n\n                Assert.Contains(replies, message => message.Content is PingMsg);\n                Assert.Contains(replies, message => message.Content is PongMsg);\n            }\n            finally\n            {\n                await transportA.StopAsync(TimeSpan.FromMilliseconds(100));\n                await transportB.StopAsync(TimeSpan.FromMilliseconds(100));\n                transportA.Dispose();\n                transportB.Dispose();\n            }\n        }\n\n        // This also tests ITransport.ReplyMessage at the same time.\n        [SkippableFact(Timeout = Timeout)]\n        public async Task SendMessageAsyncTimeout()\n        {\n            ITransport transportA = await CreateTransportAsync().ConfigureAwait(false);\n            ITransport transportB = await CreateTransportAsync().ConfigureAwait(false);\n\n            try\n            {\n                await InitializeAsync(transportA);\n                await InitializeAsync(transportB);\n\n                var e = await Assert.ThrowsAsync<CommunicationFailException>(\n                    async () => await transportA.SendMessageAsync(\n                        transportB.AsPeer,\n                        new PingMsg(),\n                        TimeSpan.FromSeconds(3),\n                        CancellationToken.None));\n                Assert.True(e.InnerException is TimeoutException ie);\n            }\n            finally\n            {\n                await transportA.StopAsync(TimeSpan.FromMilliseconds(100));\n                await transportB.StopAsync(TimeSpan.FromMilliseconds(100));\n                transportA.Dispose();\n                transportB.Dispose();\n            }\n        }\n\n        [SkippableTheory(Timeout = Timeout)]\n        [ClassData(typeof(TransportTestInvalidPeers))]\n        public async Task SendMessageToInvalidPeerAsync(BoundPeer invalidPeer)\n        {\n            ITransport transport = await CreateTransportAsync().ConfigureAwait(false);\n\n            try\n            {\n                await InitializeAsync(transport);\n                Task task = transport.SendMessageAsync(\n                    invalidPeer,\n                    new PingMsg(),\n                    TimeSpan.FromSeconds(5),\n                    default);\n\n                // TcpTransport and NetMQTransport fail for different reasons, i.e.\n                // a thrown exception for each case has a different inner exception.\n                await Assert.ThrowsAsync<CommunicationFailException>(async () => await task);\n            }\n            finally\n            {\n                await transport.StopAsync(TimeSpan.FromMilliseconds(100));\n                transport.Dispose();\n            }\n        }\n\n        [SkippableFact(Timeout = Timeout)]\n        public async Task SendMessageAsyncCancelWhenTransportStop()\n        {\n            ITransport transportA = await CreateTransportAsync().ConfigureAwait(false);\n            ITransport transportB = await CreateTransportAsync().ConfigureAwait(false);\n\n            try\n            {\n                await InitializeAsync(transportA);\n                await InitializeAsync(transportB);\n\n                Task t = transportA.SendMessageAsync(\n                        transportB.AsPeer,\n                        new PingMsg(),\n                        null,\n                        CancellationToken.None);\n\n                // For context change\n                await Task.Delay(100);\n\n                await transportA.StopAsync(TimeSpan.Zero);\n                Assert.False(transportA.Running);\n                await Assert.ThrowsAsync<TaskCanceledException>(async () => await t);\n                Assert.True(t.IsCanceled);\n            }\n            finally\n            {\n                await transportA.StopAsync(TimeSpan.FromMilliseconds(100));\n                await transportB.StopAsync(TimeSpan.FromMilliseconds(100));\n                transportA.Dispose();\n                transportB.Dispose();\n            }\n        }\n\n        [SkippableFact(Timeout = Timeout)]\n        public async Task BroadcastMessage()\n        {\n            var address = new PrivateKey().Address;\n            ITransport transportA = null;\n            ITransport transportB = await CreateTransportAsync(\n                privateKey: GeneratePrivateKeyOfBucketIndex(address, 0));\n            ITransport transportC = await CreateTransportAsync(\n                privateKey: GeneratePrivateKeyOfBucketIndex(address, 1));\n            ITransport transportD = await CreateTransportAsync(\n                privateKey: GeneratePrivateKeyOfBucketIndex(address, 2));\n\n            var tcsB = new TaskCompletionSource<Message>();\n            var tcsC = new TaskCompletionSource<Message>();\n            var tcsD = new TaskCompletionSource<Message>();\n\n            transportB.ProcessMessageHandler.Register(MessageHandler(tcsB));\n            transportC.ProcessMessageHandler.Register(MessageHandler(tcsC));\n            transportD.ProcessMessageHandler.Register(MessageHandler(tcsD));\n\n            Func<Message, Task> MessageHandler(TaskCompletionSource<Message> tcs)\n            {\n                return async message =>\n                {\n                    if (message.Content is PingMsg)\n                    {\n                        tcs.SetResult(message);\n                    }\n\n                    await Task.Yield();\n                };\n            }\n\n            try\n            {\n                await InitializeAsync(transportB);\n                await InitializeAsync(transportC);\n                await InitializeAsync(transportD);\n\n                var table = new RoutingTable(address, bucketSize: 1);\n                table.AddPeer(transportB.AsPeer);\n                table.AddPeer(transportC.AsPeer);\n                table.AddPeer(transportD.AsPeer);\n\n                transportA = await CreateTransportAsync().ConfigureAwait(false);\n                await InitializeAsync(transportA);\n\n                transportA.BroadcastMessage(\n                    table.PeersToBroadcast(transportD.AsPeer.Address),\n                    new PingMsg());\n\n                await Task.WhenAll(tcsB.Task, tcsC.Task);\n\n                Assert.IsType<PingMsg>(tcsB.Task.Result.Content);\n                Assert.IsType<PingMsg>(tcsC.Task.Result.Content);\n                Assert.False(tcsD.Task.IsCompleted);\n\n                tcsD.SetCanceled();\n            }\n            finally\n            {\n                await transportA?.StopAsync(TimeSpan.FromMilliseconds(100));\n                transportA?.Dispose();\n                await transportB.StopAsync(TimeSpan.FromMilliseconds(100));\n                transportB.Dispose();\n                await transportC.StopAsync(TimeSpan.FromMilliseconds(100));\n                transportC.Dispose();\n                await transportD.StopAsync(TimeSpan.FromMilliseconds(100));\n                transportD.Dispose();\n            }\n        }\n\n        protected async Task InitializeAsync(\n            ITransport transport,\n            CancellationToken cts = default)\n        {\n            _ = transport.StartAsync(cts);\n            await transport.WaitForRunningAsync();\n        }\n\n        private Task<ITransport> CreateTransportAsync(\n            PrivateKey privateKey = null,\n            AppProtocolVersionOptions appProtocolVersionOptions = null,\n            HostOptions hostOptions = null,\n            TimeSpan? messageTimestampBuffer = null\n        )\n        {\n            if (TransportConstructor is null)\n            {\n                throw new XunitException(\"Transport constructor is not defined.\");\n            }\n\n            privateKey = privateKey ?? new PrivateKey();\n            return TransportConstructor(\n                privateKey,\n                appProtocolVersionOptions ?? new AppProtocolVersionOptions(),\n                hostOptions ?? new HostOptions(\n                    IPAddress.Loopback.ToString(), new IceServer[] { }, 0),\n                messageTimestampBuffer);\n        }\n\n        private class TransportTestInvalidPeers : IEnumerable<object[]>\n        {\n            public IEnumerator<object[]> GetEnumerator()\n            {\n                // Make sure the tcp port is invalid.\n                var l = new TcpListener(IPAddress.Loopback, 0);\n                l.Start();\n                int port = ((IPEndPoint)l.LocalEndpoint).Port;\n                l.Stop();\n\n                yield return new[]\n                {\n                    new BoundPeer(\n                        new PrivateKey().PublicKey,\n                        new DnsEndPoint(\"0.0.0.0\", port)),\n                };\n            }\n\n            IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();\n        }\n    }\n}\n"
  },
  {
    "path": "test/Libplanet.Net.Tests/xunit.runner.mono.json",
    "content": "{\n  \"$schema\": \"https://xunit.github.io/schema/current/xunit.runner.schema.json\",\n  \"appDomain\": \"denied\",\n  \"parallelizeAssembly\": false,\n  \"parallelizeTestCollections\": false\n}\n"
  },
  {
    "path": "test/Libplanet.RocksDBStore.Tests/Libplanet.RocksDBStore.Tests.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <PropertyGroup>\n    <Nullable>disable</Nullable>\n    <TreatWarningsAsErrors>true</TreatWarningsAsErrors>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <PackageReference Include=\"Serilog.Enrichers.Thread\" Version=\"3.0.0\" />\n    <PackageReference Include=\"Serilog.Sinks.XUnit\" Version=\"1.0.7\" />\n    <PackageReference Include=\"System.Collections.Immutable\" Version=\"1.7.*\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <ProjectReference Include=\"..\\..\\src\\Libplanet.RocksDBStore\\Libplanet.RocksDBStore.csproj\" />\n    <ProjectReference Include=\"..\\Libplanet.Tests\\Libplanet.Tests.csproj\" />\n  </ItemGroup>\n\n</Project>\n"
  },
  {
    "path": "test/Libplanet.RocksDBStore.Tests/RocksDBKeyValueStoreTest.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.IO;\nusing Libplanet.Store.Trie;\nusing Libplanet.Tests.Store.Trie;\nusing RocksDbSharp;\nusing Xunit;\n\nnamespace Libplanet.RocksDBStore.Tests\n{\n    public class RocksDBKeyValueStoreTest : KeyValueStoreTest, IDisposable\n    {\n        private readonly RocksDBKeyValueStore _rocksDbKeyValueStore;\n\n        public RocksDBKeyValueStoreTest()\n        {\n            try\n            {\n                KeyValueStore = _rocksDbKeyValueStore = new RocksDBKeyValueStore(Path.Combine(\n                        Path.GetTempPath(),\n                        $\"rocksdb_key_value_test_{Guid.NewGuid()}\"));\n                InitializePreStoredData();\n            }\n            catch (TypeInitializationException)\n            {\n                throw new SkipException(\"RocksDB is not available.\");\n            }\n        }\n\n        [Fact]\n        public void ReadOnlyRocksDb()\n        {\n            var basePath = Path.Combine(\n                Path.GetTempPath(),\n                $\"rocksdb_key_value_test_{Guid.NewGuid()}\");\n            var primaryRocksDb = new RocksDBKeyValueStore(basePath);\n            var readonlyRocksDb = new RocksDBKeyValueStore(basePath, RocksDBInstanceType.ReadOnly);\n\n            var key = new KeyBytes(\"new\");\n            var value = new byte[] { 1, 2, 3 };\n            primaryRocksDb.Set(key, value);\n            Assert.Equal(value, primaryRocksDb.Get(key));\n            Assert.Throws<KeyNotFoundException>(() => readonlyRocksDb.Get(key));\n            Assert.Throws<RocksDbException>(() => readonlyRocksDb.TryCatchUpWithPrimary());\n        }\n\n        [Fact]\n        public void SecondaryRocksDb()\n        {\n            var basePath = Path.Combine(\n                Path.GetTempPath(),\n                $\"rocksdb_key_value_test_{Guid.NewGuid()}\");\n            var primaryRocksDb = new RocksDBKeyValueStore(basePath);\n            var secondaryRocksDb = new RocksDBKeyValueStore(\n                basePath,\n                RocksDBInstanceType.Secondary);\n\n            var key = new KeyBytes(\"new\");\n            var value = new byte[] { 1, 2, 3 };\n            primaryRocksDb.Set(key, value);\n            Assert.Equal(value, primaryRocksDb.Get(key));\n            Assert.Throws<KeyNotFoundException>(() => secondaryRocksDb.Get(key));\n\n            secondaryRocksDb.TryCatchUpWithPrimary();\n            Assert.Equal(value, secondaryRocksDb.Get(key));\n        }\n\n        public void Dispose()\n        {\n            _rocksDbKeyValueStore.Dispose();\n        }\n    }\n}\n"
  },
  {
    "path": "test/Libplanet.RocksDBStore.Tests/RocksDBStoreBlockChainTest.cs",
    "content": "using System;\nusing Libplanet.Action;\nusing Libplanet.Tests.Blockchain;\nusing Libplanet.Tests.Store;\nusing Xunit;\nusing Xunit.Abstractions;\n\nnamespace Libplanet.RocksDBStore.Tests\n{\n    public class RocksDBStoreBlockChainTest : BlockChainTest\n    {\n        public RocksDBStoreBlockChainTest(ITestOutputHelper output)\n            : base(output)\n        {\n        }\n\n        protected override StoreFixture GetStoreFixture(\n            IPolicyActionsRegistry policyActionsRegistry = null)\n        {\n            try\n            {\n                return new RocksDBStoreFixture(\n                    policyActionsRegistry);\n            }\n            catch (TypeInitializationException)\n            {\n                throw new SkipException(\"RocksDB is not available.\");\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "test/Libplanet.RocksDBStore.Tests/RocksDBStoreFixture.cs",
    "content": "using System;\nusing System.IO;\nusing Libplanet.Action;\nusing Libplanet.Store;\nusing Libplanet.Store.Trie;\nusing Libplanet.Tests.Store;\n\nnamespace Libplanet.RocksDBStore.Tests\n{\n    public class RocksDBStoreFixture : StoreFixture\n    {\n        public RocksDBStoreFixture(\n            IPolicyActionsRegistry policyActionsRegistry = null)\n            : base(policyActionsRegistry)\n        {\n            Path = System.IO.Path.Combine(\n                System.IO.Path.GetTempPath(),\n                $\"rocksdb_test_{Guid.NewGuid()}\"\n            );\n\n            Scheme = \"rocksdb+file://\";\n\n            var store = new RocksDBStore(Path, blockCacheSize: 2, txCacheSize: 2);\n            Store = store;\n            StateStore = LoadTrieStateStore(Path);\n        }\n\n        public IStateStore LoadTrieStateStore(string path)\n        {\n            IKeyValueStore stateKeyValueStore =\n                new RocksDBKeyValueStore(System.IO.Path.Combine(path, \"states\"));\n            return new TrieStateStore(stateKeyValueStore);\n        }\n\n        public override void Dispose()\n        {\n            Store?.Dispose();\n            StateStore?.Dispose();\n\n            if (!(Path is null))\n            {\n                Directory.Delete(Path, true);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "test/Libplanet.RocksDBStore.Tests/RocksDBStoreTest.cs",
    "content": "using System;\nusing System.IO;\nusing System.Linq;\nusing System.Reflection;\nusing Libplanet.Action;\nusing Libplanet.Action.Loader;\nusing Libplanet.Action.Tests.Common;\nusing Libplanet.Blockchain;\nusing Libplanet.Blockchain.Policies;\nusing Libplanet.Common;\nusing Libplanet.Store;\nusing Libplanet.Store.Trie;\nusing Libplanet.Tests.Store;\nusing Libplanet.Types.Tx;\nusing RocksDbSharp;\nusing Xunit;\nusing Xunit.Abstractions;\n\nnamespace Libplanet.RocksDBStore.Tests\n{\n    public class RocksDBStoreTest : StoreTest, IDisposable\n    {\n        private readonly RocksDBStoreFixture _fx;\n\n        public RocksDBStoreTest(ITestOutputHelper testOutputHelper)\n        {\n            try\n            {\n                TestOutputHelper = testOutputHelper;\n                Fx = _fx = new RocksDBStoreFixture();\n                FxConstructor = () => new RocksDBStoreFixture();\n            }\n            catch (TypeInitializationException)\n            {\n                throw new SkipException(\"RocksDB is not available.\");\n            }\n        }\n\n        protected override ITestOutputHelper TestOutputHelper { get; }\n\n        protected override StoreFixture Fx { get; }\n\n        protected override Func<StoreFixture> FxConstructor { get; }\n\n        public void Dispose()\n        {\n            _fx?.Dispose();\n        }\n\n        [SkippableFact]\n        public void Loader()\n        {\n            // TODO: Test query parameters as well.\n            string tempDirPath = Path.GetTempFileName();\n            File.Delete(tempDirPath);\n            var uri = new Uri(tempDirPath, UriKind.Absolute);\n            Assert.StartsWith(\"file://\", uri.ToString());\n            uri = new Uri(\"rocksdb+\" + uri);\n            (IStore Store, IStateStore StateStore)? pair = StoreLoaderAttribute.LoadStore(uri);\n            Assert.NotNull(pair);\n            IStore store = pair.Value.Store;\n            Assert.IsAssignableFrom<RocksDBStore>(store);\n            var stateStore = (TrieStateStore)pair.Value.StateStore;\n            var kvStore = typeof(TrieStateStore)\n                .GetProperty(\n                    \"StateKeyValueStore\",\n                    BindingFlags.Public | BindingFlags.GetProperty | BindingFlags.Instance)\n                ?.GetMethod\n                ?.Invoke(stateStore, Array.Empty<object>());\n            Assert.IsAssignableFrom<RocksDBKeyValueStore>(kvStore);\n        }\n\n        [SkippableFact]\n        public void ReopenStoreAfterDispose()\n        {\n            var path = Path.Combine(Path.GetTempPath(), $\"rocksdb_test_{Guid.NewGuid()}\");\n\n            try\n            {\n                var store = new RocksDBStore(path);\n                var stateStore = new TrieStateStore(new MemoryKeyValueStore());\n                var blocks = BlockChain.Create(\n                    new NullBlockPolicy(),\n                    new VolatileStagePolicy(),\n                    store,\n                    stateStore,\n                    Fx.GenesisBlock,\n                    new ActionEvaluator(\n                        policyActionsRegistry: new PolicyActionsRegistry(),\n                        stateStore: stateStore,\n                        actionTypeLoader: new SingleActionLoader(typeof(DumbAction))));\n                store.Dispose();\n\n                store = new RocksDBStore(path);\n                store.Dispose();\n            }\n            finally\n            {\n                Directory.Delete(path, true);\n            }\n        }\n\n        [SkippableFact]\n        public void ParallelGetBlock()\n        {\n            var path = Path.Combine(Path.GetTempPath(), $\"rocksdb_test_{Guid.NewGuid()}\");\n            var store = new RocksDBStore(path);\n            try\n            {\n                Guid cid = Guid.NewGuid();\n                store.AppendIndex(cid, Fx.Block1.Hash);\n                store.AppendIndex(cid, Fx.Block2.Hash);\n                store.AppendIndex(cid, Fx.Block3.Hash);\n\n                store.PutBlock(Fx.Block1);\n                store.PutBlock(Fx.Block2);\n                store.PutBlock(Fx.Block3);\n\n                store.Dispose();\n                store = new RocksDBStore(path);\n\n                Enumerable.Range(0, 3).AsParallel().ForAll(i =>\n                {\n                    var bHash = store.IndexBlockHash(cid, i).Value;\n                    var block = store.GetBlock(bHash);\n                    Assert.NotNull(block);\n                });\n            }\n            finally\n            {\n                store.Dispose();\n                Directory.Delete(path, true);\n            }\n        }\n\n        [SkippableFact]\n        public void ListChainIds()\n        {\n            var path = Path.Combine(Path.GetTempPath(), $\"rocksdb_test_{Guid.NewGuid()}\");\n            var store = new RocksDBStore(path);\n            try\n            {\n                Guid cid = Guid.NewGuid();\n                store.AppendIndex(cid, Fx.Block1.Hash);\n                store.AppendIndex(cid, Fx.Block2.Hash);\n                store.AppendIndex(cid, Fx.Block3.Hash);\n\n                store.PutBlock(Fx.Block1);\n                store.PutBlock(Fx.Block2);\n                store.PutBlock(Fx.Block3);\n\n                Assert.Single(store.ListChainIds());\n\n                store.ForkBlockIndexes(cid, Guid.NewGuid(), Fx.Block3.Hash);\n                Assert.Equal(2, store.ListChainIds().Count());\n            }\n            finally\n            {\n                store.Dispose();\n                Directory.Delete(path, true);\n            }\n        }\n\n        [SkippableFact]\n        public void ParallelGetTransaction()\n        {\n            var path = Path.Combine(Path.GetTempPath(), $\"rocksdb_test_{Guid.NewGuid()}\");\n            var store = new RocksDBStore(path);\n            Transaction[] txs = new[]\n            {\n                Fx.Transaction1,\n                Fx.Transaction2,\n                Fx.Transaction3,\n            };\n            try\n            {\n                store.PutTransaction(Fx.Transaction1);\n                store.PutTransaction(Fx.Transaction2);\n                store.PutTransaction(Fx.Transaction3);\n                store.Dispose();\n                store = new RocksDBStore(path);\n\n                Enumerable.Range(0, 3).AsParallel().ForAll(i =>\n                {\n                    Assert.NotNull(store.GetTransaction(txs[i].Id));\n                });\n            }\n            finally\n            {\n                store.Dispose();\n                Directory.Delete(path, true);\n            }\n        }\n\n        [SkippableFact]\n        public void PruneOutdatedChainsRocksDb()\n        {\n            var path = Path.Combine(Path.GetTempPath(), $\"rocksdb_test_{Guid.NewGuid()}\");\n            var store = new RocksDBStore(path);\n            RocksDb chainDb = null;\n\n            int KeysWithChainId(RocksDb db, Guid cid)\n            {\n                using (Iterator it = db.NewIterator())\n                {\n                    byte[] key = cid.ToByteArray();\n                    int count = 0;\n                    for (it.SeekToFirst(); it.Valid(); it.Next())\n                    {\n                        if (!it.Key().Skip(1).ToArray().StartsWith(key))\n                        {\n                            continue;\n                        }\n\n                        count++;\n                    }\n\n                    return count;\n                }\n            }\n\n            try\n            {\n                store.PutBlock(Fx.GenesisBlock);\n                store.PutBlock(Fx.Block1);\n                store.PutBlock(Fx.Block2);\n                store.PutBlock(Fx.Block3);\n\n                Guid cid1 = Guid.NewGuid();\n                int guidLength = cid1.ToByteArray().Length;\n                store.AppendIndex(cid1, Fx.GenesisBlock.Hash);\n                store.AppendIndex(cid1, Fx.Block1.Hash);\n                store.AppendIndex(cid1, Fx.Block2.Hash);\n                Assert.Single(store.ListChainIds());\n                Assert.Equal(\n                    new[] { Fx.GenesisBlock.Hash, Fx.Block1.Hash, Fx.Block2.Hash },\n                    store.IterateIndexes(cid1, 0, null));\n\n                Guid cid2 = Guid.NewGuid();\n                store.ForkBlockIndexes(cid1, cid2, Fx.Block1.Hash);\n                store.AppendIndex(cid2, Fx.Block2.Hash);\n                store.AppendIndex(cid2, Fx.Block3.Hash);\n                Assert.Equal(2, store.ListChainIds().Count());\n                Assert.Equal(\n                    new[] { Fx.GenesisBlock.Hash, Fx.Block1.Hash, Fx.Block2.Hash, Fx.Block3.Hash },\n                    store.IterateIndexes(cid2, 0, null));\n\n                Guid cid3 = Guid.NewGuid();\n                store.ForkBlockIndexes(cid1, cid3, Fx.Block2.Hash);\n                Assert.Equal(3, store.ListChainIds().Count());\n                Assert.Equal(\n                    new[] { Fx.GenesisBlock.Hash, Fx.Block1.Hash, Fx.Block2.Hash },\n                    store.IterateIndexes(cid3, 0, null));\n\n                Assert.Throws<InvalidOperationException>(() => store.PruneOutdatedChains());\n                store.PruneOutdatedChains(true);\n                store.SetCanonicalChainId(cid3);\n                store.PruneOutdatedChains();\n                Assert.Single(store.ListChainIds());\n                Assert.Equal(\n                    new[] { Fx.GenesisBlock.Hash, Fx.Block1.Hash, Fx.Block2.Hash },\n                    store.IterateIndexes(cid3, 0, null));\n                Assert.Equal(3, store.CountIndex(cid3));\n\n                store.Dispose();\n                store = null;\n\n                chainDb = RocksDb.Open(new DbOptions(), Path.Combine(path, \"chain\"));\n\n                Assert.Equal(0, KeysWithChainId(chainDb, cid1));\n                Assert.Equal(0, KeysWithChainId(chainDb, cid2));\n                Assert.NotEqual(0, KeysWithChainId(chainDb, cid3));\n            }\n            finally\n            {\n                store?.Dispose();\n                chainDb?.Dispose();\n                Directory.Delete(path, true);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "test/Libplanet.Store.Remote.Tests/Helpers/LoggerHelper.cs",
    "content": "using Microsoft.Extensions.Logging;\nusing Microsoft.Extensions.Logging.Abstractions;\n\nnamespace Libplanet.Store.Remote.Tests.Helpers\n{\n    public static class LoggerHelper\n    {\n        public static ILogger<T> CreateLogger<T>(LoggerOutputType outputType = LoggerOutputType.Null) => \n            outputType switch\n            {\n                LoggerOutputType.Console => new LoggerFactory().CreateLogger<T>(),\n                LoggerOutputType.Null => new NullLogger<T>(),\n                _ => new NullLogger<T>()\n            };\n    }\n    \n    public enum LoggerOutputType\n    {\n        Console,\n        Null\n    }\n}\n"
  },
  {
    "path": "test/Libplanet.Store.Remote.Tests/Helpers/RemoteKeyValueServiceExtensions.cs",
    "content": "using Google.Protobuf.WellKnownTypes;\nusing Libplanet.Store.Remote.Server;\n\nnamespace Libplanet.Store.Remote.Tests.Helpers\n{\n    public static class RemoteKeyValueServiceExtensions\n    {\n        public static async Task<KeyValueStoreValue> GetValue(this RemoteKeyValueService service, GetValueRequest request) =>\n            await service.GetValue(request, TestServerCallContextHelper.Create());\n\n        public static async Task<KeyValueStoreValue> SetValue(this RemoteKeyValueService service, SetValueRequest request) =>\n            await service.SetValue(request, TestServerCallContextHelper.Create());\n\n        public static async Task<SetValuesResponse> SetValues(this RemoteKeyValueService service, SetValuesRequest request) =>\n            await service.SetValues(request, TestServerCallContextHelper.Create());\n\n        public static async Task<Empty> DeleteValue(this RemoteKeyValueService service, DeleteValueRequest request) =>\n            await service.DeleteValue(request, TestServerCallContextHelper.Create());\n\n        public static async Task<Empty> DeleteValues(this RemoteKeyValueService service, DeleteValuesRequest request) =>\n            await service.DeleteValues(request, TestServerCallContextHelper.Create());\n\n        public static async Task<ExistsKeyResponse> ExistsKey(this RemoteKeyValueService service, ExistsKeyRequest request) =>\n            await service.ExistsKey(request, TestServerCallContextHelper.Create());\n\n        public static async Task<ListKeysResponse> ListKeys(this RemoteKeyValueService service, ListKeysRequest request) =>\n            await service.ListKeys(request, TestServerCallContextHelper.Create());\n    }\n}\n"
  },
  {
    "path": "test/Libplanet.Store.Remote.Tests/Helpers/TestServerCallContextHelper.cs",
    "content": "using Grpc.Core;\nusing Grpc.Core.Testing;\n\nnamespace Libplanet.Store.Remote.Tests.Helpers\n{\n    public static class TestServerCallContextHelper\n    {\n        public static ServerCallContext Create()\n        {\n            return TestServerCallContext.Create(\n                \"test\",\n                null,\n                DateTime.UtcNow,\n                new Metadata(),\n                CancellationToken.None,\n                \"peer\",\n                null,\n                null,\n                null,\n                null,\n                null);\n        }\n    }\n}\n"
  },
  {
    "path": "test/Libplanet.Store.Remote.Tests/Integrations/ServiceIntegration.cs",
    "content": "using Google.Protobuf;\nusing Grpc.Core;\nusing Libplanet.Store.Remote.Extensions;\nusing Libplanet.Store.Remote.Server;\nusing Libplanet.Store.Remote.Tests.Helpers;\nusing Libplanet.Store.Trie;\nusing Serilog;\nusing Xunit.Abstractions;\nusing ILogger = Serilog.ILogger;\n\nnamespace Libplanet.Store.Remote.Tests.Integrations\n{\n    public class ServiceIntegration\n    {\n        private readonly ILogger _logger;\n\n        public ServiceIntegration(ITestOutputHelper output)\n        {\n            _logger = new LoggerConfiguration()\n                .WriteTo.TestOutput(output)\n                .CreateLogger();\n        }\n\n        [Fact]\n        public async Task Get_Set()\n        {\n            // Arrange\n            var store = (IKeyValueStore)new MemoryKeyValueStore();\n            var key = new KeyBytes(0x01);\n            byte[] value = { 0x02 };\n            var service = new RemoteKeyValueService(_logger, store);\n\n            // Act\n            await Assert.ThrowsAsync<RpcException>(() =>\n                service.GetValue(new GetValueRequest\n                {\n                    Key = key.ToKeyValueStoreKey(),\n                }));\n\n            KeyValueStoreValue setResponse = await service.SetValue(new SetValueRequest\n            {\n                Item = new KeyValueStorePair\n                {\n                    Key = key.ToKeyValueStoreKey(),\n                    Value = ByteString.CopyFrom(value).ToKeyValueStoreValue(),\n                },\n            });\n\n            // Assert\n            Assert.Equal(value, store.Get(key));\n            Assert.Equal(value, setResponse.Data);\n        }\n\n        [Fact]\n        public async Task Get_Delete()\n        {\n            // Arrange\n            var store = (IKeyValueStore)new MemoryKeyValueStore();\n            var key = new KeyBytes(0x01);\n            byte[] value = { 0x02 };\n            store.Set(key, value);\n            var service = new RemoteKeyValueService(_logger, store);\n\n            // Act\n            KeyValueStoreValue getResponse = await service.GetValue(new GetValueRequest\n            {\n                Key = key.ToKeyValueStoreKey(),\n            });\n\n            _ = await service.DeleteValue(new DeleteValueRequest\n            {\n                Key = key.ToKeyValueStoreKey(),\n            });\n\n            // Assert\n            Assert.Equal(value, getResponse.Data.ToByteArray());\n            Assert.Throws<KeyNotFoundException>(() => store.Get(key));\n        }\n\n        [Fact]\n        public async Task Get_Delete_Get()\n        {\n            // Arrange\n            var store = (IKeyValueStore)new MemoryKeyValueStore();\n            var key = new KeyBytes(0x01);\n            byte[] value = { 0x02 };\n            store.Set(key, value);\n            var service = new RemoteKeyValueService(_logger, store);\n\n            // Act\n            KeyValueStoreValue first = await service.GetValue(new GetValueRequest\n            {\n                Key = key.ToKeyValueStoreKey(),\n            });\n\n            _ = await service.DeleteValue(new DeleteValueRequest\n            {\n                Key = key.ToKeyValueStoreKey(),\n            });\n\n            // Assert\n            Assert.Equal(value, first.Data.ToByteArray());\n\n            await Assert.ThrowsAsync<RpcException>(async () =>\n            {\n                _ = await service.GetValue(new GetValueRequest\n                {\n                    Key = key.ToKeyValueStoreKey(),\n                });\n            });\n        }\n\n        [Fact]\n        public async Task Set_Get()\n        {\n            // Arrange\n            var store = (IKeyValueStore)new MemoryKeyValueStore();\n            var key = new KeyBytes(0x01);\n            byte[] value = { 0x02 };\n            var service = new RemoteKeyValueService(_logger, store);\n\n            // Act\n            _ = await service.SetValue(new SetValueRequest\n            {\n                Item = new KeyValueStorePair\n                {\n                    Key = key.ToKeyValueStoreKey(),\n                    Value = ByteString.CopyFrom(value).ToKeyValueStoreValue(),\n                },\n            });\n\n            KeyValueStoreValue response = await service.GetValue(new GetValueRequest\n            {\n                Key = key.ToKeyValueStoreKey(),\n            });\n\n            // Assert\n            Assert.Equal(value, response.Data);\n            Assert.Equal(value, store.Get(key));\n        }\n\n        [Fact]\n        public async Task Set_Delete()\n        {\n            // Arrange\n            var store = (IKeyValueStore)new MemoryKeyValueStore();\n            var key = new KeyBytes(0x01);\n            byte[] value = { 0x02 };\n            var service = new RemoteKeyValueService(_logger, store);\n\n            // Act\n            _ = await service.SetValue(new SetValueRequest\n            {\n                Item = new KeyValueStorePair\n                {\n                    Key = key.ToKeyValueStoreKey(),\n                    Value = ByteString.CopyFrom(value).ToKeyValueStoreValue(),\n                },\n            });\n\n            _ = await service.DeleteValue(new DeleteValueRequest\n            {\n                Key = key.ToKeyValueStoreKey(),\n            });\n\n            // Assert\n            await Assert.ThrowsAsync<RpcException>(async () =>\n                await service.GetValue(new GetValueRequest\n                {\n                    Key = key.ToKeyValueStoreKey(),\n                }));\n        }\n\n        [Fact]\n        public async Task Set_Set()\n        {\n            // Arrange\n            var store = (IKeyValueStore)new MemoryKeyValueStore();\n            var key = new KeyBytes(0x01);\n            byte[] value = { 0x02 };\n            var service = new RemoteKeyValueService(_logger, store);\n\n            // Act\n            await service.SetValue(new SetValueRequest\n            {\n                Item = new KeyValueStorePair\n                {\n                    Key = key.ToKeyValueStoreKey(),\n                    Value = ByteString.CopyFrom(value).ToKeyValueStoreValue(),\n                },\n            });\n            await service.SetValue(new SetValueRequest\n            {\n                Item = new KeyValueStorePair\n                {\n                    Key = key.ToKeyValueStoreKey(),\n                    Value = ByteString.CopyFrom(value).ToKeyValueStoreValue(),\n                },\n            });\n            KeyValueStoreValue response = await service.GetValue(new GetValueRequest\n            {\n                Key = key.ToKeyValueStoreKey(),\n            });\n\n            // Assert\n            Assert.Equal(value, response.Data);\n            Assert.Equal(value, store.Get(key));\n        }\n\n        [Fact]\n        public async Task Set_SetDifferentValue()\n        {\n            // Arrange\n            var store = (IKeyValueStore)new MemoryKeyValueStore();\n            var key = new KeyBytes(0x01);\n            byte[] value = { 0x02 };\n            byte[] differentValue = { 0x03 };\n            var service = new RemoteKeyValueService(_logger, store);\n\n            // Act\n            await service.SetValue(new SetValueRequest\n            {\n                Item = new KeyValueStorePair\n                {\n                    Key = key.ToKeyValueStoreKey(),\n                    Value = ByteString.CopyFrom(value).ToKeyValueStoreValue(),\n                },\n            });\n            await service.SetValue(new SetValueRequest\n            {\n                Item = new KeyValueStorePair\n                {\n                    Key = key.ToKeyValueStoreKey(),\n                    Value = ByteString.CopyFrom(differentValue).ToKeyValueStoreValue(),\n                },\n            });\n            KeyValueStoreValue response = await service.GetValue(new GetValueRequest\n            {\n                Key = key.ToKeyValueStoreKey(),\n            });\n\n            // Assert\n            Assert.Equal(differentValue, response.Data);\n            Assert.Equal(differentValue, store.Get(key));\n        }\n\n        [Fact]\n        public async Task Set_Delete_Set()\n        {\n            // Arrange\n            var store = (IKeyValueStore)new MemoryKeyValueStore();\n            var key = new KeyBytes(0x01);\n            byte[] value = { 0x02 };\n            byte[] differentValue = { 0x03 };\n            var service = new RemoteKeyValueService(_logger, store);\n\n            // Act\n            _ = await service.SetValue(new SetValueRequest\n            {\n                Item = new KeyValueStorePair\n                {\n                    Key = key.ToKeyValueStoreKey(),\n                    Value = ByteString.CopyFrom(value).ToKeyValueStoreValue(),\n                },\n            });\n            _ = await service.DeleteValue(new DeleteValueRequest { Key = key.ToKeyValueStoreKey() });\n            _ = await service.SetValue(new SetValueRequest\n            {\n                Item = new KeyValueStorePair\n                {\n                    Key = key.ToKeyValueStoreKey(),\n                    Value = ByteString.CopyFrom(differentValue).ToKeyValueStoreValue(),\n                },\n            });\n            KeyValueStoreValue response = await service.GetValue(new GetValueRequest\n            {\n                Key = key.ToKeyValueStoreKey(),\n            });\n\n            // Assert\n            Assert.Equal(differentValue, response.Data);\n            Assert.Equal(differentValue, store.Get(key));\n        }\n    }\n}\n"
  },
  {
    "path": "test/Libplanet.Store.Remote.Tests/Libplanet.Store.Remote.Tests.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <PropertyGroup>\n    <ImplicitUsings>enable</ImplicitUsings>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <PackageReference Include=\"Grpc.Core.Testing\" Version=\"2.46.6\" />\n    <PackageReference Include=\"Microsoft.AspNetCore.Mvc.Testing\" Version=\"6.0.27\" />\n    <PackageReference Include=\"Moq\" Version=\"4.20.70\" />\n    <PackageReference Include=\"Moq.AutoMock\" Version=\"3.5.0\" />\n    <PackageReference Include=\"Serilog.Sinks.XUnit\" Version=\"3.0.5\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <PackageReference Remove=\"Menees.Analyzers.2017\" />\n    <PackageReference Remove=\"StyleCop.Analyzers\" />\n  </ItemGroup>\n\n  <ItemGroup Condition=\"'$(SkipSonar)' != 'true'\">\n    <PackageReference Remove=\"SonarAnalyzer.CSharp\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <ProjectReference Include=\"..\\..\\src\\Libplanet.Store.Remote\\Libplanet.Store.Remote.csproj\" />\n  </ItemGroup>\n\n</Project>\n"
  },
  {
    "path": "test/Libplanet.Store.Remote.Tests/Units/ServiceUnit.cs",
    "content": "using Google.Protobuf;\nusing Grpc.Core;\nusing Libplanet.Store.Remote.Extensions;\nusing Libplanet.Store.Remote.Server;\nusing Libplanet.Store.Remote.Tests.Helpers;\nusing Libplanet.Store.Trie;\nusing Moq;\nusing Moq.AutoMock;\n\nnamespace Libplanet.Store.Remote.Tests.Units;\n\npublic class ServiceUnit\n{\n    [Fact]\n    public async Task GetUnaryTest()\n    {\n        // Arrange\n        var mocker = new AutoMocker();\n        var key = new KeyBytes(1, 2, 3);\n        byte[] value = new byte[] { 4, 5, 6 };\n        mocker.Use<IKeyValueStore>(kvStore => kvStore.Get(key) == value);\n        RemoteKeyValueService service = mocker.CreateInstance<RemoteKeyValueService>();\n\n        // Act\n        KeyValueStoreValue response = await service.GetValue(new GetValueRequest\n        {\n            Key = key.ToKeyValueStoreKey(),\n        });\n\n        // Assert\n        mocker.VerifyAll();\n        Assert.Equal(value, response.Data);\n    }\n\n    [Fact]\n    public async Task GetUnary_NotFoundTest()\n    {\n        // Arrange\n        var mocker = new AutoMocker();\n        var key = new KeyBytes(1, 2, 3);\n        mocker.Setup<IKeyValueStore>(store => store.Get(key))\n            .Throws<KeyNotFoundException>()\n            .Verifiable();\n        RemoteKeyValueService service = mocker.CreateInstance<RemoteKeyValueService>();\n\n        // Act\n        await Assert.ThrowsAsync<RpcException>(async () =>\n        {\n            await service.GetValue(new GetValueRequest\n            {\n                Key = key.ToKeyValueStoreKey(),\n            });\n        });\n\n        // Assert\n        mocker.VerifyAll();\n    }\n\n    [Fact]\n    public async Task GetUnary_EmptyValueTest()\n    {\n        // Arrange\n        var mocker = new AutoMocker();\n        var key = new KeyBytes(1, 2, 3);\n        mocker.Use<IKeyValueStore>(kvStore => kvStore.Get(key) == Array.Empty<byte>());\n        RemoteKeyValueService service = mocker.CreateInstance<RemoteKeyValueService>();\n\n        // Act\n        KeyValueStoreValue response = await service.GetValue(new GetValueRequest\n        {\n            Key = key.ToKeyValueStoreKey(),\n        });\n\n        // Assert\n        mocker.VerifyAll();\n        Assert.Empty(response.Data);\n    }\n\n    [Fact]\n    public async Task SetUnaryTest()\n    {\n        // Arrange\n        var mocker = new AutoMocker();\n        var key = new KeyBytes(1, 2, 3);\n        var value = new byte[] { 4, 5, 6 };\n        mocker\n            .Setup<IKeyValueStore>(store => store.Set(key, value))\n            .Verifiable();\n        var service = mocker.CreateInstance<RemoteKeyValueService>();\n\n        // Act\n        await service.SetValue(new SetValueRequest\n        {\n                Item = new KeyValueStorePair\n                {\n                        Key = key.ToKeyValueStoreKey(),\n                        Value = ByteString.CopyFrom(value).ToKeyValueStoreValue(),\n                },\n        });\n\n        // Assert\n        mocker.VerifyAll();\n    }\n\n    [Fact]\n    public async Task SetValuesUnaryTest()\n    {\n        // Arrange\n        var mocker = new AutoMocker();\n        var setValuesRequest = new SetValuesRequest\n        {\n            Items =\n            {\n                new KeyValueStorePair\n                {\n                    Key = new KeyBytes(1, 2, 3).ToKeyValueStoreKey(),\n                    Value = ByteString.CopyFrom(4, 5, 6).ToKeyValueStoreValue(),\n                },\n                new KeyValueStorePair\n                {\n                    Key = new KeyBytes(2, 3, 4).ToKeyValueStoreKey(),\n                    Value = ByteString.CopyFrom(5, 6, 7).ToKeyValueStoreValue(),\n                },\n            },\n        };\n\n        mocker\n            .Setup<IKeyValueStore>(store => store.Set(It.IsAny<IDictionary<KeyBytes, byte[]>>()))\n            .Verifiable();\n        RemoteKeyValueService service = mocker.CreateInstance<RemoteKeyValueService>();\n\n        // Act\n        await service.SetValues(setValuesRequest);\n\n        // Assert\n        mocker.VerifyAll();\n    }\n\n    [Fact]\n    public async Task DeleteUnaryTest()\n    {\n        // Arrange\n        var mocker = new AutoMocker();\n        var key = new KeyBytes(1, 2, 3);\n        mocker\n            .Setup<IKeyValueStore>(store => store.Delete(key))\n            .Verifiable();\n        var service = mocker.CreateInstance<RemoteKeyValueService>();\n\n        // Act\n        await service.DeleteValue(new DeleteValueRequest\n        {\n            Key = key.ToKeyValueStoreKey(),\n        });\n\n        // Assert\n        mocker.VerifyAll();\n    }\n\n    [Fact]\n    public async Task DeleteCollectionUnaryTest()\n    {\n        // Arrange\n        var mocker = new AutoMocker();\n        var deleteValuesRequest = new DeleteValuesRequest\n        {\n            Keys =\n            {\n                new KeyBytes(1, 2, 3).ToKeyValueStoreKey(),\n                new KeyBytes(2, 3, 4).ToKeyValueStoreKey(),\n            },\n        };\n\n        mocker\n            .Setup<IKeyValueStore>(store => store.Delete(It.IsAny<IEnumerable<KeyBytes>>()))\n            .Verifiable();\n        var service = mocker.CreateInstance<RemoteKeyValueService>();\n\n        // Act\n        await service.DeleteValues(deleteValuesRequest);\n\n        // Assert\n        mocker.VerifyAll();\n    }\n\n    [Fact]\n    public async Task ExistsUnaryTest()\n    {\n        // Arrange\n        var mocker = new AutoMocker();\n        var key = new KeyBytes(1, 2, 3);\n        mocker.Use<IKeyValueStore>(store => store.Exists(key) == true);\n        var service = mocker.CreateInstance<RemoteKeyValueService>();\n\n        // Act\n        var response = await service.ExistsKey(new ExistsKeyRequest\n        {\n            Key = key.ToKeyValueStoreKey(),\n        });\n\n        // Assert\n        mocker.VerifyAll();\n        Assert.True(response.Exists);\n    }\n\n    [Fact]\n    public async Task ListKeysUnaryTest()\n    {\n        // Arrange\n        var mocker = new AutoMocker();\n        var keys = new List<KeyBytes>\n        {\n            new KeyBytes(1, 2, 3),\n            new KeyBytes(2, 3, 4),\n        };\n        mocker.Use<IKeyValueStore>(store => store.ListKeys() == keys);\n\n        var service = mocker.CreateInstance<RemoteKeyValueService>();\n\n        // Act\n        var response = await service.ListKeys(new ListKeysRequest());\n\n        // Assert\n        mocker.VerifyAll();\n        Assert.Equal(keys.Select(bytes => bytes.ToKeyValueStoreKey()), response.Keys);\n    }\n}\n"
  },
  {
    "path": "test/Libplanet.Store.Remote.Tests/Units/StoreUnit.cs",
    "content": "using Google.Protobuf;\nusing Google.Protobuf.WellKnownTypes;\nusing Grpc.Core;\nusing Libplanet.Store.Remote.Client;\nusing Libplanet.Store.Remote.Extensions;\nusing Libplanet.Store.Trie;\nusing Moq;\nusing Moq.AutoMock;\n\nnamespace Libplanet.Store.Remote.Tests.Units;\n\npublic class StoreUnit\n{\n    [Fact]\n    public void GetUnaryTest()\n    {\n        // Arrange\n        var mocker = new AutoMocker();\n        var key = new KeyBytes(0x01);\n        byte[] value = { 0x02 };\n        var request = new GetValueRequest { Key = key.ToKeyValueStoreKey() };\n        var response = new KeyValueStoreValue { Data = ByteString.CopyFrom(value) };\n        mocker.Use<KeyValueStore.KeyValueStoreClient>(\n            client => client.GetValue(request, null, null, CancellationToken.None) == response);\n        RemoteKeyValueStore store = mocker.CreateInstance<RemoteKeyValueStore>();\n\n        // Act\n        byte[] result = store.Get(key);\n\n        // Assert\n        mocker.VerifyAll();\n        Assert.Equal(value, result);\n    }\n\n    [Fact]\n    public void GetUnary_NotFoundTest()\n    {\n        // Arrange\n        var key = new KeyBytes(0x01);\n        // Cannot use `AutoMocker` in here. (dunno why)\n        var mockClient = new Mock<KeyValueStore.KeyValueStoreClient>();\n        mockClient\n            .Setup(client => client.GetValue(It.IsAny<GetValueRequest>(), null, null,\n                CancellationToken.None))\n            .Throws(new RpcException(new Status(StatusCode.NotFound, \"Not found\")));\n        var store = new RemoteKeyValueStore(mockClient.Object);\n\n        // Act & Assert\n        Assert.Throws<KeyNotFoundException>(() => store.Get(key));\n        mockClient.VerifyAll();\n    }\n\n    [Fact]\n    public void GetUnary_EmptyValueTest()\n    {\n        // Arrange\n        var mocker = new AutoMocker();\n        var key = new KeyBytes(0x01);\n        var request = new GetValueRequest { Key = key.ToKeyValueStoreKey() };\n        var response = new KeyValueStoreValue { Data = ByteString.Empty };\n        mocker.Use<KeyValueStore.KeyValueStoreClient>(\n            client => client.GetValue(request, null, null, CancellationToken.None) == response);\n        RemoteKeyValueStore store = mocker.CreateInstance<RemoteKeyValueStore>();\n\n        // Act\n        byte[] result = store.Get(key);\n\n        // Assert\n        mocker.VerifyAll();\n        Assert.Empty(result);\n    }\n\n    [Fact]\n    public void SetUnaryTest()\n    {\n        // Arrange\n        var mocker = new AutoMocker();\n        var key = new KeyBytes(0x01);\n        var value = new byte[] { 0x02 };\n        var request = new SetValueRequest\n        {\n            Item = new KeyValueStorePair\n            {\n                Key = key.ToKeyValueStoreKey(),\n                Value = ByteString.CopyFrom(value).ToKeyValueStoreValue(),\n            },\n        };\n        var response = new KeyValueStoreValue();\n        mocker.Use<KeyValueStore.KeyValueStoreClient>(\n            client => client.SetValue(request, null, null, CancellationToken.None) == response);\n        RemoteKeyValueStore store = mocker.CreateInstance<RemoteKeyValueStore>();\n\n        // Act\n        store.Set(key, value);\n\n        // Assert\n        mocker.VerifyAll();\n    }\n\n    [Fact]\n    public void MapSetUnaryTest()\n    {\n        // Arrange\n        var mocker = new AutoMocker();\n        var key1 = new KeyBytes(0x01);\n        var key2 = new KeyBytes(0x02);\n\n        var request = new SetValuesRequest\n        {\n            Items =\n            {\n                new KeyValueStorePair\n                {\n                    Key = key1.ToKeyValueStoreKey(),\n                    Value = ByteString.CopyFrom(0x01, 0x02).ToKeyValueStoreValue(),\n                },\n                new KeyValueStorePair\n                {\n                    Key = key2.ToKeyValueStoreKey(),\n                    Value = ByteString.CopyFrom(0x03, 0x04).ToKeyValueStoreValue(),\n                },\n            },\n        };\n\n        var response = new SetValuesResponse();\n        mocker.Use<KeyValueStore.KeyValueStoreClient>(\n            client => client.SetValues(request, null, null, CancellationToken.None) == response);\n        RemoteKeyValueStore store = mocker.CreateInstance<RemoteKeyValueStore>();\n\n        // Act\n        store.Set(new Dictionary<KeyBytes, byte[]>\n        {\n            { key1, new byte[] { 0x01, 0x02 }},\n            { key2, new byte[] { 0x03, 0x04 } },\n        });\n\n        // Assert\n        mocker.VerifyAll();\n    }\n\n    [Fact]\n    public void DeleteUnaryTest()\n    {\n        // Arrange\n        var mocker = new AutoMocker();\n        var key = new KeyBytes(0x01);\n        var request = new DeleteValueRequest\n        {\n            Key = key.ToKeyValueStoreKey(),\n        };\n\n        var response = new Empty();\n        mocker.Use<KeyValueStore.KeyValueStoreClient>(\n            client => client.DeleteValue(request, null, null, CancellationToken.None) == response);\n        RemoteKeyValueStore store = mocker.CreateInstance<RemoteKeyValueStore>();\n\n        // Act\n        store.Delete(key);\n\n        // Assert\n        mocker.VerifyAll();\n    }\n\n    [Fact]\n    public void CollectionDeleteUnaryTest()\n    {\n        // Arrange\n        var mocker = new AutoMocker();\n        var key1 = new KeyBytes(0x01);\n        var key2 = new KeyBytes(0x02);\n        var request = new DeleteValuesRequest\n        {\n            Keys =\n            {\n                key1.ToKeyValueStoreKey(),\n                key2.ToKeyValueStoreKey(),\n            },\n        };\n\n        var response = new Empty();\n        mocker.Use<KeyValueStore.KeyValueStoreClient>(\n            client => client.DeleteValues(request, null, null, CancellationToken.None) == response);\n        RemoteKeyValueStore store = mocker.CreateInstance<RemoteKeyValueStore>();\n\n        // Act\n        store.Delete(new List<KeyBytes> { key1, key2 });\n\n        // Assert\n        mocker.VerifyAll();\n    }\n\n    [Fact]\n    public void ExistsUnaryTest()\n    {\n        // Arrange\n        var mocker = new AutoMocker();\n        var key = new KeyBytes(0x01);\n        var request = new ExistsKeyRequest\n        {\n            Key = key.ToKeyValueStoreKey(),\n        };\n\n        var response = new ExistsKeyResponse { Exists = true };\n        mocker.Use<KeyValueStore.KeyValueStoreClient>(\n            client => client.ExistsKey(request, null, null, CancellationToken.None) == response);\n        RemoteKeyValueStore store = mocker.CreateInstance<RemoteKeyValueStore>();\n\n        // Act\n        bool result = store.Exists(key);\n\n        // Assert\n        mocker.VerifyAll();\n        Assert.True(result);\n    }\n\n    [Fact]\n    public void ListKeysUnaryTest()\n    {\n        // Arrange\n        var mocker = new AutoMocker();\n        var response = new ListKeysResponse();\n        mocker.Use<KeyValueStore.KeyValueStoreClient>(\n            client => client.ListKeys(new ListKeysRequest(), null, null, CancellationToken.None) == response);\n        RemoteKeyValueStore store = mocker.CreateInstance<RemoteKeyValueStore>();\n\n        // Act\n        IEnumerable<KeyBytes> result = store.ListKeys();\n\n        // Assert\n        mocker.VerifyAll();\n        Assert.Empty(result);\n    }\n\n    [Fact]\n    public void ListKeysUnary_SomeValuesTest()\n    {\n        // Arrange\n        var mocker = new AutoMocker();\n        var key1 = new KeyBytes(0x01);\n        var key2 = new KeyBytes(0x02);\n        var response = new ListKeysResponse\n        {\n            Keys =\n            {\n                key1.ToKeyValueStoreKey(),\n                key2.ToKeyValueStoreKey(),\n            },\n        };\n\n        mocker.Use<KeyValueStore.KeyValueStoreClient>(\n            client => client.ListKeys(new ListKeysRequest(), null, null, CancellationToken.None) == response);\n        RemoteKeyValueStore store = mocker.CreateInstance<RemoteKeyValueStore>();\n\n        // Act\n        IEnumerable<KeyBytes> result = store.ListKeys();\n\n        // Assert\n        mocker.VerifyAll();\n        Assert.Equal(new[] { key1, key2 }, result);\n    }\n}\n"
  },
  {
    "path": "test/Libplanet.Store.Remote.Tests/Usings.cs",
    "content": "global using Xunit;\n"
  },
  {
    "path": "test/Libplanet.Stun.Tests/Libplanet.Stun.Tests.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <PropertyGroup>\n    <Nullable>disable</Nullable>\n    <TreatWarningsAsErrors>true</TreatWarningsAsErrors>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <ProjectReference Include=\"..\\..\\src\\Libplanet.Stun\\Libplanet.Stun.csproj\" />\n  </ItemGroup>\n\n</Project>\n"
  },
  {
    "path": "test/Libplanet.Stun.Tests/Stun/Attributes/ErrorCodeTest.cs",
    "content": "using Libplanet.Stun.Attributes;\nusing Xunit;\n\nnamespace Libplanet.Stun.Tests.Attributes\n{\n    public class ErrorCodeTest\n    {\n        [Fact]\n        public void EncodeToBytes()\n        {\n            var attr = new ErrorCode(401, \"Unauthorized\");\n            Assert.Equal(\n                new byte[]\n                {\n                    0x00, 0x09, 0x00, 0x10, 0x00, 0x00, 0x04, 0x01, 0x55, 0x6e,\n                    0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x65, 0x64,\n                },\n                attr.ToByteArray());\n        }\n\n        [Fact]\n        public void ParseFromBytes()\n        {\n            ErrorCode attr = ErrorCode.Parse(\n                new byte[]\n                {\n                    0x00, 0x00, 0x04, 0x01, 0x55, 0x6e, 0x61, 0x75, 0x74, 0x68,\n                    0x6f, 0x72, 0x69, 0x7a, 0x65, 0x64,\n                });\n            Assert.Equal(401, attr.Code);\n            Assert.Equal(\"Unauthorized\", attr.Reason);\n        }\n    }\n}\n"
  },
  {
    "path": "test/Libplanet.Stun.Tests/Stun/Attributes/LifetimeTest.cs",
    "content": "using Libplanet.Stun.Attributes;\nusing Xunit;\n\nnamespace Libplanet.Stun.Tests.Attributes\n{\n    public class LifetimeTest\n    {\n        [Fact]\n        public void EncodeToBytes()\n        {\n            var attr = new Lifetime(777);\n            Assert.Equal(\n                new byte[]\n                {\n                    0x00, 0x0d, 0x00, 0x04, 0x00, 0x00, 0x03, 0x09,\n                },\n                attr.ToByteArray());\n        }\n    }\n}\n"
  },
  {
    "path": "test/Libplanet.Stun.Tests/Stun/Attributes/MessageIntegrityTest.cs",
    "content": "using Libplanet.Stun.Attributes;\nusing Xunit;\n\nnamespace Libplanet.Stun.Tests.Attributes\n{\n    public class MessageIntegrityTest\n    {\n        [Fact]\n        public void EncodeToBytes()\n        {\n            byte[] digest = new byte[]\n            {\n                0xfd, 0x49, 0x5a, 0x92, 0xb5, 0x9f, 0x59, 0x67, 0x33, 0xce,\n                0xcf, 0xf4, 0x45, 0xb7, 0xa5, 0x88, 0x04, 0x8a, 0x39, 0x05,\n            };\n            var attr = new MessageIntegrity(digest);\n\n            Assert.Equal(\n                new byte[]\n                {\n                    0x00, 0x08, 0x00, 0x14,\n                    0xfd, 0x49, 0x5a, 0x92, 0xb5, 0x9f, 0x59, 0x67, 0x33, 0xce,\n                    0xcf, 0xf4, 0x45, 0xb7, 0xa5, 0x88, 0x04, 0x8a, 0x39, 0x05,\n                },\n                attr.ToByteArray());\n        }\n\n        [Fact]\n        public void CalculateProperly()\n        {\n            var username = \"ae0633cd58ba097a1167c6d2cc4e236db52256a40d565f11edf76c02d13db93c\";\n            var password = \"U/X7qP2MosBElz8/T2CESYkvqyUIOoGTlOJoSsHvZkQ=\";\n            var realm = \"twilio.com\";\n            var message = new byte[]\n            {\n                0x00, 0x03, 0x00, 0x90, 0x21, 0x12, 0xa4, 0x42, 0xf5, 0xdb,\n                0xe7, 0xc1, 0x2a, 0x74, 0xbe, 0xf9, 0x8b, 0x16, 0x56, 0x3e,\n                0x00, 0x19, 0x00, 0x04, 0x06, 0x00, 0x00, 0x00, 0x00, 0x0d,\n                0x00, 0x04, 0x00, 0x00, 0x03, 0x09, 0x00, 0x06, 0x00, 0x40,\n                0x61, 0x65, 0x30, 0x36, 0x33, 0x33, 0x63, 0x64, 0x35, 0x38,\n                0x62, 0x61, 0x30, 0x39, 0x37, 0x61, 0x31, 0x31, 0x36, 0x37,\n                0x63, 0x36, 0x64, 0x32, 0x63, 0x63, 0x34, 0x65, 0x32, 0x33,\n                0x36, 0x64, 0x62, 0x35, 0x32, 0x32, 0x35, 0x36, 0x61, 0x34,\n                0x30, 0x64, 0x35, 0x36, 0x35, 0x66, 0x31, 0x31, 0x65, 0x64,\n                0x66, 0x37, 0x36, 0x63, 0x30, 0x32, 0x64, 0x31, 0x33, 0x64,\n                0x62, 0x39, 0x33, 0x63, 0x00, 0x15, 0x00, 0x10, 0x37, 0x35,\n                0x64, 0x34, 0x35, 0x34, 0x31, 0x39, 0x63, 0x33, 0x39, 0x33,\n                0x34, 0x33, 0x66, 0x65, 0x00, 0x14, 0x00, 0x0a, 0x74, 0x77,\n                0x69, 0x6c, 0x69, 0x6f, 0x2e, 0x63, 0x6f, 0x6d, 0x00, 0x00,\n            };\n\n            MessageIntegrity attr =\n                MessageIntegrity.Calculate(username, password, realm, message);\n\n            Assert.Equal(\n                new byte[]\n                {\n                    0x77, 0xe8, 0xcf, 0x30, 0x9e, 0x85, 0x6c, 0x22, 0x72, 0x53,\n                    0xa3, 0xb7, 0xe0, 0x35, 0x7c, 0xc2, 0x30, 0xfc, 0xbc, 0xf4,\n                },\n                attr.Value\n            );\n        }\n    }\n}\n"
  },
  {
    "path": "test/Libplanet.Stun.Tests/Stun/Attributes/NonceTest.cs",
    "content": "using Xunit;\n\nnamespace Libplanet.Stun.Tests.Attributes\n{\n    public class NonceTest\n    {\n        [Fact]\n        public void ConvertToBytesProperly()\n        {\n            var attr = new Libplanet.Stun.Attributes.Nonce(\n                new byte[]\n                {\n                    0x37, 0x35, 0x64, 0x34, 0x35, 0x34, 0x31, 0x39, 0x63, 0x33,\n                    0x39, 0x33, 0x34, 0x33, 0x66, 0x65,\n                });\n            Assert.Equal(\n                new byte[]\n                {\n                    0x00, 0x15, 0x00, 0x10, 0x37, 0x35, 0x64, 0x34, 0x35, 0x34,\n                    0x31, 0x39, 0x63, 0x33, 0x39, 0x33, 0x34, 0x33, 0x66, 0x65,\n                },\n                attr.ToByteArray());\n        }\n\n        [Fact]\n        public void ParseFromBytes()\n        {\n            Libplanet.Stun.Attributes.Nonce attr =\n                Libplanet.Stun.Attributes.Nonce.Parse(\n                    new byte[]\n                    {\n                        0x37, 0x35, 0x64, 0x34, 0x35, 0x34,\n                        0x31, 0x39, 0x63, 0x33, 0x39, 0x33,\n                        0x34, 0x33, 0x66, 0x65,\n                    });\n            Assert.Equal(\n                new byte[]\n                {\n                    0x37, 0x35, 0x64, 0x34, 0x35, 0x34,\n                    0x31, 0x39, 0x63, 0x33, 0x39, 0x33,\n                    0x34, 0x33, 0x66, 0x65,\n                },\n                attr.Value);\n        }\n    }\n}\n"
  },
  {
    "path": "test/Libplanet.Stun.Tests/Stun/Attributes/RealmTest.cs",
    "content": "using Libplanet.Stun.Attributes;\nusing Xunit;\n\nnamespace Libplanet.Stun.Tests.Attributes\n{\n    public class RealmTest\n    {\n        [Fact]\n        public void EncodeToBytes()\n        {\n            var attr = new Realm(\"twilio.com\");\n            Assert.Equal(\n                new byte[]\n                {\n                    0x00, 0x14, 0x00, 0x0a, 0x74, 0x77, 0x69, 0x6c, 0x69, 0x6f,\n                    0x2e, 0x63, 0x6f, 0x6d, 0x00, 0x00,\n                },\n                attr.ToByteArray());\n        }\n\n        [Fact]\n        public void ParseFromBytes()\n        {\n            Realm attr = Realm.Parse(\n                new byte[]\n                {\n                    0x74, 0x77, 0x69, 0x6c, 0x69, 0x6f, 0x2e, 0x63, 0x6f, 0x6d,\n                });\n            Assert.Equal(\"twilio.com\", attr.Value);\n        }\n    }\n}\n"
  },
  {
    "path": "test/Libplanet.Stun.Tests/Stun/Attributes/RequestedTransportTest.cs",
    "content": "using Libplanet.Stun.Attributes;\nusing Xunit;\n\nnamespace Libplanet.Stun.Tests.Attributes\n{\n    public class RequestedTransportTest\n    {\n        [Fact]\n        public void EncodeToBytes()\n        {\n            var attr = new RequestedTransport(\n                RequestedTransport.TransportType.TCP);\n            Assert.Equal(\n                new byte[]\n                {\n                    0x00, 0x19, 0x00, 0x04, 0x06, 0x00, 0x00, 0x00,\n                },\n                attr.ToByteArray());\n        }\n    }\n}\n"
  },
  {
    "path": "test/Libplanet.Stun.Tests/Stun/Attributes/StunAddressExtensionsTest.cs",
    "content": "using System.Collections.Generic;\nusing System.Net;\nusing Libplanet.Stun.Attributes;\nusing Xunit;\n\nnamespace Libplanet.Stun.Tests.Attributes\n{\n    public class StunAddressExtensionsTest\n    {\n        public static IEnumerable<object[]> Testcases => new List<object[]>\n        {\n            new object[]\n            {\n                new IPEndPoint(IPAddress.Parse(\"2002:d3b0:815a:0:0:0:0:0\"), 35206),\n                new byte[]\n                {\n                    0x00, 0x02, 0xa8, 0x94, 0x01, 0x10, 0x77, 0xf2, 0xa5, 0xe3,\n                    0xce, 0x0f, 0x6f, 0x49, 0xcb, 0x29, 0x64, 0x11, 0x0f, 0x3e,\n                },\n            },\n            new object[]\n            {\n                new IPEndPoint(IPAddress.Parse(\"211.176.129.90\"), 35206),\n                new byte[]\n                {\n                    0x00, 0x01, 0xa8, 0x94, 0xf2, 0xa2, 0x25, 0x18,\n                },\n            },\n        };\n\n        [Theory]\n        [MemberData(nameof(Testcases))]\n        public void EncodeToBytes(IPEndPoint endpoint, byte[] expected)\n        {\n            var transactionId = new byte[]\n            {\n                0x24, 0xb9, 0xce, 0x0f, 0x6f, 0x49, 0xcb, 0x29, 0x64, 0x11,\n                0x0f, 0x3e,\n            };\n\n            Assert.Equal(\n                expected,\n                endpoint.EncodeStunAddress(transactionId));\n        }\n\n        [Theory]\n        [MemberData(nameof(Testcases))]\n        public void DecodeFromBytes(IPEndPoint endpoint, byte[] encoded)\n        {\n            var transactionId = new byte[]\n            {\n                0x24, 0xb9, 0xce, 0x0f, 0x6f, 0x49, 0xcb, 0x29, 0x64, 0x11,\n                0x0f, 0x3e,\n            };\n\n            Assert.Equal(\n                endpoint,\n                encoded.DecodeStunAddress(transactionId));\n        }\n    }\n}\n"
  },
  {
    "path": "test/Libplanet.Stun.Tests/Stun/Attributes/UserNameTest.cs",
    "content": "using Libplanet.Stun.Attributes;\nusing Xunit;\n\nnamespace Libplanet.Stun.Tests.Attributes\n{\n    public class UserNameTest\n    {\n        [Fact]\n        public void EncodeToBytes()\n        {\n            var attr = new Username(\n                \"ae0633cd58ba097a1167c6d2cc4e236db52256a40d565f11edf76c02d13db93c\"\n            );\n            Assert.Equal(\n                new byte[]\n                {\n                    0x00, 0x06, 0x00, 0x40, 0x61, 0x65, 0x30, 0x36, 0x33, 0x33,\n                    0x63, 0x64, 0x35, 0x38, 0x62, 0x61, 0x30, 0x39, 0x37, 0x61,\n                    0x31, 0x31, 0x36, 0x37, 0x63, 0x36, 0x64, 0x32, 0x63, 0x63,\n                    0x34, 0x65, 0x32, 0x33, 0x36, 0x64, 0x62, 0x35, 0x32, 0x32,\n                    0x35, 0x36, 0x61, 0x34, 0x30, 0x64, 0x35, 0x36, 0x35, 0x66,\n                    0x31, 0x31, 0x65, 0x64, 0x66, 0x37, 0x36, 0x63, 0x30, 0x32,\n                    0x64, 0x31, 0x33, 0x64, 0x62, 0x39, 0x33, 0x63,\n                },\n                attr.ToByteArray());\n        }\n    }\n}\n"
  },
  {
    "path": "test/Libplanet.Stun.Tests/Stun/Crc32Test.cs",
    "content": "using System;\nusing System.Text;\nusing Xunit;\n\nnamespace Libplanet.Stun.Tests\n{\n    public class Crc32Test\n    {\n        [Fact]\n        public void Calculate()\n        {\n            byte[] bytes = Encoding.ASCII.GetBytes(\n                \"The quick brown fox jumps over the lazy dog\");\n            uint expected = BitConverter.ToUInt32(\n                new byte[]\n                {\n                    0x39, 0xa3, 0x4f, 0x41,\n                }, 0);\n            Assert.Equal(expected, Crc32.Calculate(bytes));\n        }\n    }\n}\n"
  },
  {
    "path": "test/Libplanet.Stun.Tests/Stun/Messages/AllocateErrorResponseTest.cs",
    "content": "using System.IO;\nusing System.Threading.Tasks;\nusing Libplanet.Stun.Messages;\nusing Xunit;\n\nnamespace Libplanet.Stun.Tests.Messages\n{\n    public class AllocateErrorResponseTest\n    {\n        [Fact]\n        public async Task ParseBytes()\n        {\n            var bytes = new byte[]\n            {\n                0x01, 0x13, 0x00, 0x48, 0x21, 0x12, 0xa4, 0x42, 0xee, 0x29,\n                0xdd, 0x2d, 0x7a, 0xe9, 0x9c, 0xf4, 0x00, 0x82, 0xf2, 0x5e,\n                0x00, 0x09, 0x00, 0x10, 0x00, 0x00, 0x04, 0x01, 0x55, 0x6e,\n                0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x65, 0x64,\n                0x00, 0x15, 0x00, 0x10, 0x37, 0x35, 0x64, 0x34, 0x35, 0x34,\n                0x31, 0x39, 0x63, 0x33, 0x39, 0x33, 0x34, 0x33, 0x66, 0x65,\n                0x00, 0x14, 0x00, 0x0a, 0x74, 0x77, 0x69, 0x6c, 0x69, 0x6f,\n                0x2e, 0x63, 0x6f, 0x6d, 0x03, 0x6d, 0x80, 0x22, 0x00, 0x04,\n                0x4e, 0x6f, 0x6e, 0x65, 0x80, 0x28, 0x00, 0x04, 0x6e, 0x1e,\n                0x55, 0x49,\n            };\n\n            using (var stream = new MemoryStream(bytes))\n            {\n                var response =\n                    (AllocateErrorResponse)await StunMessage.ParseAsync(stream);\n                Assert.Equal(\n                    new byte[]\n                    {\n                        0xee, 0x29, 0xdd, 0x2d, 0x7a, 0xe9, 0x9c, 0xf4, 0x00, 0x82,\n                        0xf2, 0x5e,\n                    },\n                    response.TransactionId);\n                Assert.Equal(401, response.ErrorCode);\n                Assert.Equal(\"twilio.com\", response.Realm);\n                Assert.Equal(\n                    new byte[]\n                    {\n                    0x37, 0x35, 0x64, 0x34, 0x35, 0x34,\n                    0x31, 0x39, 0x63, 0x33, 0x39, 0x33,\n                    0x34, 0x33, 0x66, 0x65,\n                    },\n                    response.Nonce\n                );\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "test/Libplanet.Stun.Tests/Stun/Messages/AllocateRequestTest.cs",
    "content": "using Libplanet.Stun.Messages;\nusing Xunit;\n\nnamespace Libplanet.Stun.Tests.Messages\n{\n    public class AllocateRequestTest\n    {\n        [Fact]\n        public void EncodeToBytes()\n        {\n            var request = new AllocateRequest(777)\n            {\n                TransactionId = new byte[]\n                {\n                    0xee, 0x29, 0xdd, 0x2d, 0x7a, 0xe9, 0x9c, 0xf4, 0x00, 0x82,\n                    0xf2, 0x5e,\n                },\n            };\n            Assert.Equal(\n                new byte[]\n                {\n                    0x00, 0x03, 0x00, 0x18, 0x21, 0x12, 0xa4, 0x42, 0xee, 0x29,\n                    0xdd, 0x2d, 0x7a, 0xe9, 0x9c, 0xf4, 0x00, 0x82, 0xf2, 0x5e,\n                    0x00, 0x19, 0x00, 0x04, 0x06, 0x00, 0x00, 0x00, 0x00, 0x0d,\n                    0x00, 0x04, 0x00, 0x00, 0x03, 0x09, 0x80, 0x28, 0x00, 0x04,\n                    0x3d, 0xbe, 0x42, 0x75,\n                },\n                request.Encode(new TestStunContext())\n            );\n        }\n\n        [Fact]\n        public void EncodeToBytesWithCredential()\n        {\n            var request = new AllocateRequest(777)\n            {\n                TransactionId = new byte[]\n                {\n                    0xf5, 0xdb, 0xe7, 0xc1, 0x2a, 0x74, 0xbe, 0xf9, 0x8b, 0x16,\n                    0x56, 0x3e,\n                },\n            };\n            var ctx = new TestStunContext()\n            {\n                Username = \"ae0633cd58ba097a1167c6d2cc4e236db52256a40d565f11edf76c02d13db93c\",\n                Password = \"U/X7qP2MosBElz8/T2CESYkvqyUIOoGTlOJoSsHvZkQ=\",\n                Realm = \"twilio.com\",\n                Nonce = new byte[]\n                {\n                    0x37, 0x35, 0x64, 0x34, 0x35, 0x34, 0x31, 0x39, 0x63, 0x33,\n                    0x39, 0x33, 0x34, 0x33, 0x66, 0x65,\n                },\n            };\n\n            Assert.Equal(\n                new byte[]\n                {\n                    0x00, 0x03, 0x00, 0x98, 0x21, 0x12, 0xa4, 0x42, 0xf5, 0xdb,\n                    0xe7, 0xc1, 0x2a, 0x74, 0xbe, 0xf9, 0x8b, 0x16, 0x56, 0x3e,\n                    0x00, 0x19, 0x00, 0x04, 0x06, 0x00, 0x00, 0x00, 0x00, 0x0d,\n                    0x00, 0x04, 0x00, 0x00, 0x03, 0x09, 0x00, 0x06, 0x00, 0x40,\n                    0x61, 0x65, 0x30, 0x36, 0x33, 0x33, 0x63, 0x64, 0x35, 0x38,\n                    0x62, 0x61, 0x30, 0x39, 0x37, 0x61, 0x31, 0x31, 0x36, 0x37,\n                    0x63, 0x36, 0x64, 0x32, 0x63, 0x63, 0x34, 0x65, 0x32, 0x33,\n                    0x36, 0x64, 0x62, 0x35, 0x32, 0x32, 0x35, 0x36, 0x61, 0x34,\n                    0x30, 0x64, 0x35, 0x36, 0x35, 0x66, 0x31, 0x31, 0x65, 0x64,\n                    0x66, 0x37, 0x36, 0x63, 0x30, 0x32, 0x64, 0x31, 0x33, 0x64,\n                    0x62, 0x39, 0x33, 0x63, 0x00, 0x15, 0x00, 0x10, 0x37, 0x35,\n                    0x64, 0x34, 0x35, 0x34, 0x31, 0x39, 0x63, 0x33, 0x39, 0x33,\n                    0x34, 0x33, 0x66, 0x65, 0x00, 0x14, 0x00, 0x0a, 0x74, 0x77,\n                    0x69, 0x6c, 0x69, 0x6f, 0x2e, 0x63, 0x6f, 0x6d, 0x00, 0x00,\n                    0x00, 0x08, 0x00, 0x14, 0x77, 0xe8, 0xcf, 0x30, 0x9e, 0x85,\n                    0x6c, 0x22, 0x72, 0x53, 0xa3, 0xb7, 0xe0, 0x35, 0x7c, 0xc2,\n                    0x30, 0xfc, 0xbc, 0xf4, 0x80, 0x28, 0x00, 0x04, 0x98, 0x46,\n                    0x9c, 0x07,\n                },\n                request.Encode(ctx));\n        }\n    }\n}\n"
  },
  {
    "path": "test/Libplanet.Stun.Tests/Stun/Messages/AllocateSuccessResponseTest.cs",
    "content": "using System.IO;\nusing System.Net;\nusing System.Threading.Tasks;\nusing Libplanet.Stun.Messages;\nusing Xunit;\n\nnamespace Libplanet.Stun.Tests.Messages\n{\n    public class AllocateSuccessResponseTest\n    {\n        [Fact]\n        public async Task ParseBytes()\n        {\n            var bytes = new byte[]\n            {\n                0x01, 0x03, 0x00, 0x48, 0x21, 0x12, 0xa4, 0x42, 0xf5, 0xdb,\n                0xe7, 0xc1, 0x2a, 0x74, 0xbe, 0xf9, 0x8b, 0x16, 0x56, 0x3e,\n                0x00, 0x16, 0x00, 0x08, 0x00, 0x01, 0xc1, 0x9e, 0x17, 0x53,\n                0x9b, 0x96, 0x00, 0x20, 0x00, 0x08, 0x00, 0x01, 0xaa, 0xaa,\n                0xf2, 0xa2, 0x25, 0x18, 0x00, 0x0d, 0x00, 0x04, 0x00, 0x00,\n                0x03, 0x09, 0x80, 0x22, 0x00, 0x04, 0x4e, 0x6f, 0x6e, 0x65,\n                0x00, 0x08, 0x00, 0x14, 0x2b, 0x24, 0xd2, 0x75, 0xb9, 0x91,\n                0x34, 0xd6, 0x48, 0x51, 0xc2, 0x15, 0x17, 0xf5, 0x65, 0x90,\n                0x98, 0xfa, 0x9f, 0x7d, 0x80, 0x28, 0x00, 0x04, 0x6c, 0xcc,\n                0x0c, 0x46,\n            };\n\n            using (var stream = new MemoryStream(bytes))\n            {\n                var response =\n                    (AllocateSuccessResponse)await StunMessage.ParseAsync(stream);\n                Assert.Equal(\n                    new byte[]\n                    {\n                        0xf5, 0xdb, 0xe7, 0xc1, 0x2a, 0x74, 0xbe, 0xf9, 0x8b, 0x16,\n                        0x56, 0x3e,\n                    },\n                    response.TransactionId);\n                Assert.Equal(\n                    new IPEndPoint(IPAddress.Parse(\"54.65.63.212\"), 57484),\n                    response.RelayedEndPoint);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "test/Libplanet.Stun.Tests/Stun/Messages/BindingRequestSuccessTest.cs",
    "content": "using System.IO;\nusing System.Net;\nusing System.Threading.Tasks;\nusing Libplanet.Stun.Messages;\nusing Xunit;\n\nnamespace Libplanet.Stun.Tests.Messages\n{\n    public class BindingRequestSuccessTest\n    {\n        [Fact]\n        public async Task ParseBytes()\n        {\n            var bytes = new byte[]\n            {\n                0x01, 0x01, 0x00, 0x0c, 0x21, 0x12, 0xa4, 0x42, 0xb9, 0x5e,\n                0x6c, 0xcd, 0xa3, 0x84, 0x74, 0xfb, 0x43, 0xe9, 0xae, 0xb1,\n                0x00, 0x20, 0x00, 0x08, 0x00, 0x01, 0xf2, 0x6f, 0xf2, 0xa2,\n                0x25, 0x18,\n            };\n\n            using (var stream = new MemoryStream(bytes))\n            {\n                var response =\n                    (BindingSuccessResponse)await StunMessage.ParseAsync(stream);\n                Assert.Equal(\n                    new IPEndPoint(IPAddress.Parse(\"211.176.129.90\"), 54141),\n                    response.MappedAddress);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "test/Libplanet.Stun.Tests/Stun/Messages/BindingRequestTest.cs",
    "content": "using Libplanet.Stun.Messages;\nusing Xunit;\n\nnamespace Libplanet.Stun.Tests.Messages\n{\n    public class BindingRequestTest\n    {\n        [Fact]\n        public void EncodeToBytes()\n        {\n            var request = new BindingRequest()\n            {\n                TransactionId = new byte[]\n                {\n                    0xb9, 0x5e, 0x6c, 0xcd, 0xa3, 0x84, 0x74, 0xfb, 0x43, 0xe9,\n                    0xae, 0xb1,\n                },\n            };\n            Assert.Equal(\n                new byte[]\n                {\n                    0x00, 0x01, 0x00, 0x08, 0x21, 0x12, 0xa4, 0x42, 0xb9, 0x5e,\n                    0x6c, 0xcd, 0xa3, 0x84, 0x74, 0xfb, 0x43, 0xe9, 0xae, 0xb1,\n                    0x80, 0x28, 0x00, 0x04, 0xa7, 0xca, 0x62, 0xd4,\n                },\n                request.Encode(new TestStunContext()));\n        }\n    }\n}\n"
  },
  {
    "path": "test/Libplanet.Stun.Tests/Stun/Messages/ConnectionAttemptTest.cs",
    "content": "using System.IO;\nusing System.Threading.Tasks;\nusing Libplanet.Stun.Messages;\nusing Xunit;\n\nnamespace Libplanet.Stun.Tests.Messages\n{\n    public class ConnectionAttemptTest\n    {\n        [Fact]\n        public async Task ParseBytes()\n        {\n            var bytes = new byte[]\n            {\n                0x00, 0x1c, 0x00, 0x24, 0x21, 0x12, 0xa4, 0x42, 0x8e, 0x3b,\n                0x82, 0x73, 0xda, 0x6f, 0xc3, 0xa9, 0x1e, 0x88, 0x8f, 0x0b,\n                0x00, 0x2a, 0x00, 0x04, 0x21, 0x5a, 0x86, 0x01, 0x00, 0x12,\n                0x00, 0x08, 0x00, 0x01, 0x60, 0xc6, 0x17, 0x53, 0x9b, 0x96,\n                0x80, 0x22, 0x00, 0x04, 0x4e, 0x6f, 0x6e, 0x65, 0x80, 0x28,\n                0x00, 0x04, 0x58, 0x07, 0xfb, 0x8e,\n            };\n\n            using (var stream = new MemoryStream(bytes))\n            {\n                var response =\n                    (ConnectionAttempt)await StunMessage.ParseAsync(stream);\n                Assert.Equal(\n                    new byte[] { 0x21, 0x5a, 0x86, 0x01 },\n                    response.ConnectionId);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "test/Libplanet.Stun.Tests/Stun/Messages/ConnectionBindRequestTest.cs",
    "content": "using Libplanet.Stun.Messages;\nusing Xunit;\n\nnamespace Libplanet.Stun.Tests.Messages\n{\n    public class ConnectionBindRequestTest\n    {\n        [Fact]\n        public void EncodeToBytes()\n        {\n            var connectionId = new byte[] { 0x1e, 0xe2, 0x38, 0x02 };\n            var request = new ConnectionBindRequest(connectionId)\n            {\n                TransactionId = new byte[]\n                {\n                    0x3d, 0x29, 0x0c, 0x81, 0x83, 0x69, 0xa5, 0x48, 0x36, 0xfa,\n                    0x52, 0x6c,\n                },\n            };\n            var ctx = new TestStunContext()\n            {\n                Username = \"ae0633cd58ba097a1167c6d2cc4e236db52256a40d565f11edf76c02d13db93c\",\n                Password = \"U/X7qP2MosBElz8/T2CESYkvqyUIOoGTlOJoSsHvZkQ=\",\n                Realm = \"twilio.com\",\n                Nonce = new byte[]\n                {\n                    0x64, 0x32, 0x34, 0x35, 0x39, 0x35, 0x35, 0x39, 0x61, 0x33,\n                    0x38, 0x37, 0x34, 0x63, 0x39, 0x61,\n                },\n            };\n\n            Assert.Equal(\n                new byte[]\n                {\n                    0x00, 0x0b, 0x00, 0x90, 0x21, 0x12, 0xa4, 0x42, 0x3d, 0x29,\n                    0x0c, 0x81, 0x83, 0x69, 0xa5, 0x48, 0x36, 0xfa, 0x52, 0x6c,\n                    0x00, 0x2a, 0x00, 0x04, 0x1e, 0xe2, 0x38, 0x02, 0x00, 0x06,\n                    0x00, 0x40, 0x61, 0x65, 0x30, 0x36, 0x33, 0x33, 0x63, 0x64,\n                    0x35, 0x38, 0x62, 0x61, 0x30, 0x39, 0x37, 0x61, 0x31, 0x31,\n                    0x36, 0x37, 0x63, 0x36, 0x64, 0x32, 0x63, 0x63, 0x34, 0x65,\n                    0x32, 0x33, 0x36, 0x64, 0x62, 0x35, 0x32, 0x32, 0x35, 0x36,\n                    0x61, 0x34, 0x30, 0x64, 0x35, 0x36, 0x35, 0x66, 0x31, 0x31,\n                    0x65, 0x64, 0x66, 0x37, 0x36, 0x63, 0x30, 0x32, 0x64, 0x31,\n                    0x33, 0x64, 0x62, 0x39, 0x33, 0x63, 0x00, 0x15, 0x00, 0x10,\n                    0x64, 0x32, 0x34, 0x35, 0x39, 0x35, 0x35, 0x39, 0x61, 0x33,\n                    0x38, 0x37, 0x34, 0x63, 0x39, 0x61, 0x00, 0x14, 0x00, 0x0a,\n                    0x74, 0x77, 0x69, 0x6c, 0x69, 0x6f, 0x2e, 0x63, 0x6f, 0x6d,\n                    0x00, 0x00, 0x00, 0x08, 0x00, 0x14, 0x5e, 0xc8, 0x5b, 0xaa,\n                    0x0c, 0x7e, 0x44, 0x0d, 0xca, 0x22, 0xa6, 0xaa, 0x3a, 0xf7,\n                    0x0f, 0x4b, 0x5f, 0xe3, 0x09, 0x63, 0x80, 0x28, 0x00, 0x04,\n                    0x22, 0x0e, 0x0e, 0x02,\n                },\n                request.Encode(ctx));\n        }\n    }\n}\n"
  },
  {
    "path": "test/Libplanet.Stun.Tests/Stun/Messages/ConnectionBindSuccessResponseTest.cs",
    "content": "using System.IO;\nusing System.Threading.Tasks;\nusing Libplanet.Stun.Messages;\nusing Xunit;\n\nnamespace Libplanet.Stun.Tests.Messages\n{\n    public class ConnectionBindSuccessResponseTest\n    {\n        [Fact]\n        public async Task ParseBytes()\n        {\n            var bytes = new byte[]\n            {\n                0x01, 0x0b, 0x00, 0x28, 0x21, 0x12, 0xa4, 0x42, 0x3d, 0x29,\n                0x0c, 0x81, 0x83, 0x69, 0xa5, 0x48, 0x36, 0xfa, 0x52, 0x6c,\n                0x80, 0x22, 0x00, 0x04, 0x4e, 0x6f, 0x6e, 0x65, 0x00, 0x08,\n                0x00, 0x14, 0xf9, 0xa4, 0x0f, 0x85, 0x74, 0xa1, 0x45, 0x91,\n                0xb9, 0x71, 0x12, 0x09, 0x53, 0x15, 0x61, 0xc6, 0x4e, 0xec,\n                0x82, 0x07, 0x80, 0x28, 0x00, 0x04, 0xd1, 0xf8, 0x6c, 0xd8,\n            };\n\n            using (var stream = new MemoryStream(bytes))\n            {\n                var response = await StunMessage.ParseAsync(stream);\n                Assert.Equal(\n                    new byte[]\n                    {\n                        0x3d, 0x29, 0x0c, 0x81, 0x83, 0x69, 0xa5, 0x48, 0x36, 0xfa,\n                        0x52, 0x6c,\n                    },\n                    response.TransactionId);\n                Assert.IsType<ConnectionBindSuccessResponse>(response);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "test/Libplanet.Stun.Tests/Stun/Messages/CreatePermissionRequestTest.cs",
    "content": "using System.Net;\nusing Libplanet.Stun.Messages;\nusing Xunit;\n\nnamespace Libplanet.Stun.Tests.Messages\n{\n    public class CreatePermissionRequestTest\n    {\n        [Fact]\n        public void EncodeToBytes()\n        {\n            var request = new CreatePermissionRequest(\n                new IPEndPoint(IPAddress.Parse(\"54.65.63.212\"), 37005)\n            )\n            {\n                TransactionId = new byte[]\n                {\n                    0xf8, 0x57, 0xe3, 0x50, 0x4c, 0x8f, 0xd3, 0x9d, 0xb8, 0xca,\n                    0x69, 0x83,\n                },\n            };\n            var ctx = new TestStunContext()\n            {\n                Username = \"ae0633cd58ba097a1167c6d2cc4e236db52256a40d565f11edf76c02d13db93c\",\n                Password = \"U/X7qP2MosBElz8/T2CESYkvqyUIOoGTlOJoSsHvZkQ=\",\n                Realm = \"twilio.com\",\n                Nonce = new byte[]\n                {\n                    0x64, 0x32, 0x34, 0x35, 0x39, 0x35, 0x35, 0x39, 0x61, 0x33,\n                    0x38, 0x37, 0x34, 0x63, 0x39, 0x61,\n                },\n            };\n\n            Assert.Equal(\n                new byte[]\n                {\n                    0x00, 0x08, 0x00, 0x94, 0x21, 0x12, 0xa4, 0x42, 0xf8, 0x57,\n                    0xe3, 0x50, 0x4c, 0x8f, 0xd3, 0x9d, 0xb8, 0xca, 0x69, 0x83,\n                    0x00, 0x12, 0x00, 0x08, 0x00, 0x01, 0xb1, 0x9f, 0x17, 0x53,\n                    0x9b, 0x96, 0x00, 0x06, 0x00, 0x40, 0x61, 0x65, 0x30, 0x36,\n                    0x33, 0x33, 0x63, 0x64, 0x35, 0x38, 0x62, 0x61, 0x30, 0x39,\n                    0x37, 0x61, 0x31, 0x31, 0x36, 0x37, 0x63, 0x36, 0x64, 0x32,\n                    0x63, 0x63, 0x34, 0x65, 0x32, 0x33, 0x36, 0x64, 0x62, 0x35,\n                    0x32, 0x32, 0x35, 0x36, 0x61, 0x34, 0x30, 0x64, 0x35, 0x36,\n                    0x35, 0x66, 0x31, 0x31, 0x65, 0x64, 0x66, 0x37, 0x36, 0x63,\n                    0x30, 0x32, 0x64, 0x31, 0x33, 0x64, 0x62, 0x39, 0x33, 0x63,\n                    0x00, 0x15, 0x00, 0x10, 0x64, 0x32, 0x34, 0x35, 0x39, 0x35,\n                    0x35, 0x39, 0x61, 0x33, 0x38, 0x37, 0x34, 0x63, 0x39, 0x61,\n                    0x00, 0x14, 0x00, 0x0a, 0x74, 0x77, 0x69, 0x6c, 0x69, 0x6f,\n                    0x2e, 0x63, 0x6f, 0x6d, 0x00, 0x00, 0x00, 0x08, 0x00, 0x14,\n                    0xe9, 0x4a, 0x95, 0x2a, 0x53, 0xb0, 0xdc, 0x8c, 0x3a, 0x42,\n                    0xd7, 0xfd, 0x21, 0xeb, 0x0c, 0xd4, 0x2f, 0x6c, 0x8d, 0x40,\n                    0x80, 0x28, 0x00, 0x04, 0x31, 0x5b, 0x2f, 0x0e,\n                },\n                request.Encode(ctx));\n        }\n    }\n}\n"
  },
  {
    "path": "test/Libplanet.Stun.Tests/Stun/Messages/CreatePermissionSuccessResponseTest.cs",
    "content": "using System.IO;\nusing System.Threading.Tasks;\nusing Libplanet.Stun.Messages;\nusing Xunit;\n\nnamespace Libplanet.Stun.Tests.Messages\n{\n    public class CreatePermissionSuccessResponseTest\n    {\n        [Fact]\n        public async Task ParseBytes()\n        {\n            var bytes = new byte[]\n            {\n                0x01, 0x08, 0x00, 0x28, 0x21, 0x12, 0xa4, 0x42, 0xf8, 0x57,\n                0xe3, 0x50, 0x4c, 0x8f, 0xd3, 0x9d, 0xb8, 0xca, 0x69, 0x83,\n                0x80, 0x22, 0x00, 0x04, 0x4e, 0x6f, 0x6e, 0x65, 0x00, 0x08,\n                0x00, 0x14, 0xee, 0x56, 0x3a, 0x74, 0x03, 0x16, 0x80, 0xc4,\n                0xe5, 0x2f, 0xfa, 0x37, 0x1e, 0x30, 0x42, 0xa6, 0x45, 0x15,\n                0x8e, 0x84, 0x80, 0x28, 0x00, 0x04, 0xa0, 0x39, 0xc6, 0x25,\n            };\n\n            using (var stream = new MemoryStream(bytes))\n            {\n                var response = await StunMessage.ParseAsync(stream);\n                Assert.Equal(\n                    new byte[]\n                    {\n                        0xf8, 0x57, 0xe3, 0x50, 0x4c, 0x8f, 0xd3, 0x9d, 0xb8, 0xca,\n                        0x69, 0x83,\n                    },\n                    response.TransactionId);\n                Assert.IsType<CreatePermissionSuccessResponse>(response);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "test/Libplanet.Stun.Tests/Stun/Messages/RefreshErrorResponseTest.cs",
    "content": "using System.IO;\nusing System.Threading.Tasks;\nusing Libplanet.Stun.Messages;\nusing Xunit;\n\nnamespace Libplanet.Stun.Tests.Messages\n{\n    public class RefreshErrorResponseTest\n    {\n        [Fact]\n        public async Task ParseBytes()\n        {\n            var bytes = new byte[]\n            {\n                0x01, 0x14, 0x00, 0x2c, 0x21, 0x12, 0xa4, 0x42, 0x0c, 0x85,\n                0x2c, 0x24, 0x1a, 0x87, 0x02, 0xc9, 0xa8, 0x2c, 0x0b, 0xad,\n                0x00, 0x09, 0x00, 0x18, 0x00, 0x00, 0x04, 0x25, 0x49, 0x6e,\n                0x76, 0x61, 0x6c, 0x69, 0x64, 0x20, 0x61, 0x6c, 0x6c, 0x6f,\n                0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x00, 0x00, 0x80, 0x22,\n                0x00, 0x04, 0x4e, 0x6f, 0x6e, 0x65, 0x80, 0x28, 0x00, 0x04,\n                0x88, 0x34, 0xf9, 0x1e,\n            };\n\n            using (var stream = new MemoryStream(bytes))\n            {\n                var response = (RefreshErrorResponse)await StunMessage.ParseAsync(stream);\n                Assert.Equal(\n                    new byte[]\n                    {\n                        0x0c, 0x85, 0x2c, 0x24, 0x1a, 0x87, 0x02, 0xc9, 0xa8, 0x2c,\n                        0x0b, 0xad,\n                    },\n                    response.TransactionId);\n                Assert.Equal(437, response.ErrorCode);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "test/Libplanet.Stun.Tests/Stun/Messages/RefreshRequestTest.cs",
    "content": "using Libplanet.Stun.Messages;\nusing Xunit;\n\nnamespace Libplanet.Stun.Tests.Messages\n{\n    public class RefreshRequestTest\n    {\n        [Fact]\n        public void EncodeToBytes()\n        {\n            var request = new RefreshRequest(777)\n            {\n                TransactionId = new byte[]\n                {\n                    0xaf, 0x9d, 0x6b, 0xa5, 0x71, 0x17, 0xd7, 0xf2, 0x0a, 0x3a,\n                    0x94, 0x7b,\n                },\n            };\n            Assert.Equal(\n                new byte[]\n                {\n                    0x00, 0x04, 0x00, 0x10, 0x21, 0x12, 0xa4, 0x42, 0xaf, 0x9d, 0x6b,\n                    0xa5, 0x71, 0x17, 0xd7, 0xf2, 0x0a, 0x3a, 0x94, 0x7b, 0x00, 0x0d,\n                    0x00, 0x04, 0x00, 0x00, 0x03, 0x09, 0x80, 0x28, 0x00, 0x04, 0x72,\n                    0x1c, 0x63, 0x88,\n                },\n                request.Encode(new TestStunContext()));\n        }\n    }\n}\n"
  },
  {
    "path": "test/Libplanet.Stun.Tests/Stun/Messages/RefreshSuccessResponseTest.cs",
    "content": "using System.IO;\nusing System.Threading.Tasks;\nusing Libplanet.Stun.Messages;\nusing Xunit;\n\nnamespace Libplanet.Stun.Tests.Messages\n{\n    public class RefreshSuccessResponseTest\n    {\n        [Fact]\n        public async Task ParseBytes()\n        {\n            var bytes = new byte[]\n            {\n                0x01, 0x04, 0x00, 0x30, 0x21, 0x12, 0xa4, 0x42, 0xaf, 0x9d,\n                0x6b, 0xa5, 0x71, 0x17, 0xd7, 0xf2, 0x0a, 0x3a, 0x94, 0x7b,\n                0x00, 0x0d, 0x00, 0x04, 0x00, 0x00, 0x03, 0x09, 0x80, 0x22,\n                0x00, 0x1a, 0x43, 0x6f, 0x74, 0x75, 0x72, 0x6e, 0x2d, 0x34,\n                0x2e, 0x35, 0x2e, 0x30, 0x2e, 0x38, 0x20, 0x27, 0x64, 0x61,\n                0x6e, 0x20, 0x45, 0x69, 0x64, 0x65, 0x72, 0x27, 0x74, 0x75,\n                0x80, 0x28, 0x00, 0x04, 0xa9, 0x72, 0xb1, 0xa3,\n            };\n\n            using (var stream = new MemoryStream(bytes))\n            {\n                var response =\n                    (RefreshSuccessResponse)await StunMessage.ParseAsync(stream);\n                Assert.Equal(\n                    new byte[]\n                    {\n                        0xaf, 0x9d, 0x6b, 0xa5, 0x71, 0x17, 0xd7, 0xf2, 0x0a, 0x3a,\n                        0x94, 0x7b,\n                    },\n                    response.TransactionId);\n                Assert.Equal(777, response.Lifetime);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "test/Libplanet.Stun.Tests/Stun/Messages/StunMessageTest.cs",
    "content": "using System.Collections.Generic;\nusing System.Linq;\nusing Libplanet.Stun.Attributes;\nusing Libplanet.Stun.Messages;\nusing Xunit;\n\nnamespace Libplanet.Stun.Tests.Messages\n{\n    public class StunMessageTest\n    {\n        [Fact]\n        public void ParseClass()\n        {\n            Assert.Equal(\n                StunMessage.MessageClass.Request,\n                StunMessage.ParseClass(0x00, 0x03)\n            );\n            Assert.Equal(\n                StunMessage.MessageClass.Request,\n                StunMessage.ParseClass(0x00, 0x04)\n            );\n            Assert.Equal(\n                StunMessage.MessageClass.Request,\n                StunMessage.ParseClass(0x00, 0x08)\n            );\n\n            Assert.Equal(\n                StunMessage.MessageClass.ErrorResponse,\n                StunMessage.ParseClass(0x01, 0x13)\n            );\n            Assert.Equal(\n                StunMessage.MessageClass.SuccessResponse,\n                StunMessage.ParseClass(0x01, 0x03)\n            );\n\n            Assert.Equal(\n                StunMessage.MessageClass.Indication,\n                StunMessage.ParseClass(0x00, 0x1c)\n            );\n        }\n\n        [Fact]\n        public void ParseMethod()\n        {\n            Assert.Equal(\n                StunMessage.MessageMethod.Allocate,\n                StunMessage.ParseMethod(0x00, 0x03)\n            );\n\n            Assert.Equal(\n                StunMessage.MessageMethod.Refresh,\n                StunMessage.ParseMethod(0x00, 0x04)\n            );\n\n            Assert.Equal(\n                StunMessage.MessageMethod.CreatePermission,\n                StunMessage.ParseMethod(0x00, 0x08)\n            );\n\n            Assert.Equal(\n                StunMessage.MessageMethod.ConnectionBind,\n                StunMessage.ParseMethod(0x00, 0x0b)\n            );\n        }\n\n        [Fact]\n        public void ParseAttributes()\n        {\n            var payload = new byte[]\n            {\n                0x00, 0x09, 0x00, 0x10, 0x00, 0x00, 0x04, 0x01, 0x55, 0x6e,\n                0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x65, 0x64,\n                0x00, 0x15, 0x00, 0x10, 0x37, 0x35, 0x64, 0x34, 0x35, 0x34,\n                0x31, 0x39, 0x63, 0x33, 0x39, 0x33, 0x34, 0x33, 0x66, 0x65,\n                0x00, 0x14, 0x00, 0x0a, 0x74, 0x77, 0x69, 0x6c, 0x69, 0x6f,\n                0x2e, 0x63, 0x6f, 0x6d, 0x03, 0x6d, 0x80, 0x22, 0x00, 0x04,\n                0x4e, 0x6f, 0x6e, 0x65, 0x80, 0x28, 0x00, 0x04, 0x6e, 0x1e,\n                0x55, 0x49,\n            };\n\n            Assert.Equal(\n                new Attribute[]\n                {\n                    new ErrorCode(401, \"Unauthorized\"),\n                    new Libplanet.Stun.Attributes.Nonce(\n                        new byte[]\n                        {\n                            0x37, 0x35, 0x64, 0x34, 0x35, 0x34,\n                            0x31, 0x39, 0x63, 0x33, 0x39, 0x33,\n                            0x34, 0x33, 0x66, 0x65,\n                        }\n                    ),\n                    new Realm(\"twilio.com\"),\n                    new Software(\"None\"),\n                    new Fingerprint(1847481673),\n                },\n                StunMessage.ParseAttributes(payload),\n                new AttributeComparer()\n            );\n        }\n\n        private class AttributeComparer : IEqualityComparer<Attribute>\n        {\n            public bool Equals(Attribute x, Attribute y)\n            {\n                return x.ToByteArray().SequenceEqual(y.ToByteArray());\n            }\n\n            public int GetHashCode(Attribute obj)\n            {\n                return obj.ToByteArray().GetHashCode();\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "test/Libplanet.Stun.Tests/Stun/Messages/TestStunContext.cs",
    "content": "namespace Libplanet.Stun.Tests.Messages\n{\n    internal class TestStunContext : IStunContext\n    {\n        public string Username { get; set; }\n\n        public string Password { get; set; }\n\n        public string Realm { get; set; }\n\n        public byte[] Nonce { get; set; }\n    }\n}\n"
  },
  {
    "path": "test/Libplanet.Stun.Tests/xunit.runner.mono.json",
    "content": "{\n  \"$schema\": \"https://xunit.github.io/schema/current/xunit.runner.schema.json\",\n  \"appDomain\": \"denied\"\n}\n"
  },
  {
    "path": "test/Libplanet.Tests/Action/AccountDiffTest.cs",
    "content": "using Bencodex.Types;\nusing Libplanet.Action;\nusing Libplanet.Action.State;\nusing Libplanet.Crypto;\nusing Libplanet.Store;\nusing Libplanet.Store.Trie;\nusing Libplanet.Types.Blocks;\nusing Xunit;\n\nnamespace Libplanet.Tests.Action\n{\n    public class AccountDiffTest\n    {\n        [Fact]\n        public void EmptyAccountStateSource()\n        {\n            IStateStore stateStore = new TrieStateStore(new MemoryKeyValueStore());\n            ITrie targetTrie = stateStore.GetStateRoot(null);\n            ITrie sourceTrie = stateStore.GetStateRoot(null);\n\n            AccountDiff diff = AccountDiff.Create(targetTrie, sourceTrie);\n            Assert.Empty(diff.StateDiffs);\n\n            IAccount targetAccount = new Account(new AccountState(targetTrie));\n            PrivateKey signer = new PrivateKey();\n            targetAccount = targetAccount.SetState(signer.Address, new Text(\"Foo\"));\n\n            targetTrie = stateStore.Commit(targetAccount.Trie);\n\n            diff = AccountDiff.Create(targetTrie, sourceTrie);\n            Assert.Empty(diff.StateDiffs);\n        }\n\n        [Fact]\n        public void Diff()\n        {\n            IStateStore stateStore = new TrieStateStore(new MemoryKeyValueStore());\n            ITrie targetTrie = stateStore.GetStateRoot(null);\n            ITrie sourceTrie = stateStore.GetStateRoot(null);\n\n            Address addr1 = new Address(TestUtils.GetRandomBytes(Address.Size));\n            Address addr2 = new Address(TestUtils.GetRandomBytes(Address.Size));\n            Address addr3 = new Address(TestUtils.GetRandomBytes(Address.Size));\n\n            AccountDiff diff = AccountDiff.Create(targetTrie, sourceTrie);\n            Assert.Empty(diff.StateDiffs);\n\n            IAccount targetAccount = new Account(new AccountState(targetTrie));\n            PrivateKey signer = new PrivateKey();\n            targetAccount = targetAccount.SetState(addr1, new Text(\"One\"));\n            targetAccount = targetAccount.SetState(addr2, new Text(\"Two\"));\n            targetTrie = stateStore.Commit(targetAccount.Trie);\n\n            sourceTrie = targetTrie;\n\n            IAccount sourceAccount = new Account(new AccountState(sourceTrie));\n            sourceAccount = sourceAccount.SetState(addr2, new Text(\"Two_\"));\n            sourceAccount = sourceAccount.SetState(addr3, new Text(\"Three\"));\n\n            sourceTrie = stateStore.Commit(sourceAccount.Trie);\n\n            diff = AccountDiff.Create(targetTrie, sourceTrie);\n            Assert.Equal(2, diff.StateDiffs.Count);\n            Assert.Equal((new Text(\"Two\"), new Text(\"Two_\")), diff.StateDiffs[addr2]);\n            Assert.Equal((null, new Text(\"Three\")), diff.StateDiffs[addr3]);\n\n            diff = AccountDiff.Create(sourceTrie, targetTrie);\n            Assert.Single(diff.StateDiffs);                 // Note addr3 is not tracked\n            Assert.Equal((new Text(\"Two_\"), new Text(\"Two\")), diff.StateDiffs[addr2]);\n        }\n\n        public IActionContext CreateActionContext(Address signer, ITrie trie) =>\n            new ActionContext(\n                signer,\n                null,\n                signer,\n                0,\n                Block.CurrentProtocolVersion,\n                null,\n                new World(\n                    new WorldBaseState(\n                        trie,\n                        new TrieStateStore(new MemoryKeyValueStore()))),\n                0,\n                true,\n                null);\n    }\n}\n"
  },
  {
    "path": "test/Libplanet.Tests/Action/AccountTest.cs",
    "content": "using System.Linq;\nusing Bencodex.Types;\nusing Libplanet.Action.State;\nusing Libplanet.Crypto;\nusing Libplanet.Mocks;\nusing Xunit;\nusing Xunit.Abstractions;\n\nnamespace Libplanet.Tests.Action\n{\n    public class AccountTest\n    {\n        private readonly PrivateKey[] _keys;\n        private readonly Address[] _addr;\n        private readonly IAccount _initAccount;\n\n        public AccountTest(ITestOutputHelper output)\n        {\n            _keys = new[]\n            {\n                new PrivateKey(),\n                new PrivateKey(),\n                new PrivateKey(),\n            };\n\n            _addr = _keys.Select(key => key.Address).ToArray();\n            _initAccount = new Account(MockUtil.MockAccountState)\n                .SetState(_addr[0], (Text)\"a\")\n                .SetState(_addr[1], (Text)\"b\");\n\n            output.WriteLine(\"Fixtures  {0,-42}  State\", \"Address\");\n            int i = 0;\n            foreach (Address a in _addr)\n            {\n                output.WriteLine(\n                    \"_addr[{0}]  {1}  {2}\",\n                    i++,\n                    a,\n                    _initAccount.GetStates(new[] { a })[0]);\n            }\n        }\n\n        [Fact]\n        public virtual void NullDelta()\n        {\n            Assert.Equal(\"a\", (Text)_initAccount.GetState(_addr[0]));\n            Assert.Equal(\"b\", (Text)_initAccount.GetState(_addr[1]));\n            Assert.Null(_initAccount.GetState(_addr[2]));\n        }\n\n        [Fact]\n        public virtual void States()\n        {\n            IAccount a = _initAccount.SetState(_addr[0], (Text)\"A\");\n            AccountDiff diffa = AccountDiff.Create(_initAccount.Trie, a.Trie);\n            Assert.Equal(\"A\", (Text)a.GetState(_addr[0]));\n            Assert.Equal(\"a\", (Text)_initAccount.GetState(_addr[0]));\n            Assert.Equal(\"b\", (Text)a.GetState(_addr[1]));\n            Assert.Equal(\"b\", (Text)_initAccount.GetState(_addr[1]));\n            Assert.Null(a.GetState(_addr[2]));\n            Assert.Null(_initAccount.GetState(_addr[2]));\n            Assert.Equal(\n                _addr[0],\n                Assert.Single(diffa.StateDiffs).Key);\n\n            IAccount b = a.SetState(_addr[0], (Text)\"z\");\n            AccountDiff diffb = AccountDiff.Create(a.Trie, b.Trie);\n            Assert.Equal(\"z\", (Text)b.GetState(_addr[0]));\n            Assert.Equal(\"A\", (Text)a.GetState(_addr[0]));\n            Assert.Equal(\"a\", (Text)_initAccount.GetState(_addr[0]));\n            Assert.Equal(\"b\", (Text)b.GetState(_addr[1]));\n            Assert.Equal(\"b\", (Text)a.GetState(_addr[1]));\n            Assert.Null(b.GetState(_addr[2]));\n            Assert.Null(a.GetState(_addr[2]));\n            Assert.Equal(\n                _addr[0],\n                Assert.Single(diffb.StateDiffs).Key);\n\n            IAccount c = b.SetState(_addr[0], (Text)\"a\");\n            Assert.Equal(\"a\", (Text)c.GetState(_addr[0]));\n            Assert.Equal(\"z\", (Text)b.GetState(_addr[0]));\n        }\n\n        [Fact]\n        public void RemoveState()\n        {\n            IAccount a = _initAccount.SetState(_addr[0], (Text)\"A\");\n            a = a.SetState(_addr[1], (Text)\"B\");\n            Assert.Equal((Text)\"A\", a.GetState(_addr[0]));\n            Assert.Equal((Text)\"B\", a.GetState(_addr[1]));\n\n            a = a.RemoveState(_addr[0]);\n            Assert.Null(a.GetState(_addr[0]));\n            Assert.Equal((Text)\"B\", a.GetState(_addr[1]));\n\n            a = a.RemoveState(_addr[1]);\n            Assert.Null(a.GetState(_addr[0]));\n            Assert.Null(a.GetState(_addr[1]));\n        }\n    }\n}\n"
  },
  {
    "path": "test/Libplanet.Tests/Action/ActionEvaluatorTest.GasTracer.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Collections.Immutable;\nusing Bencodex.Types;\nusing Libplanet.Action;\nusing Libplanet.Action.Loader;\nusing Libplanet.Action.State;\nusing Libplanet.Blockchain;\nusing Libplanet.Blockchain.Policies;\nusing Libplanet.Crypto;\nusing Libplanet.Store;\nusing Libplanet.Store.Trie;\nusing Libplanet.Types.Assets;\nusing Libplanet.Types.Blocks;\nusing Libplanet.Types.Tx;\nusing Xunit;\nusing static Libplanet.Action.State.KeyConverters;\nusing static Libplanet.Tests.TestUtils;\n\nnamespace Libplanet.Tests.Action\n{\n    public partial class ActionEvaluatorTest\n    {\n        [Theory]\n        [InlineData(false, 1, 1)]\n        [InlineData(true, 1, 0)]\n        public void Evaluate_WithGasTracer(\n            bool cancelTrace, long goldAmount, long expectedGoldAmount)\n        {\n            var gold = Currency.Uncapped(\"FOO\", 18, null);\n            var gas = Currency.Uncapped(\"GAS\", 18, null);\n            var privateKey = new PrivateKey();\n            var policy = new BlockPolicy(\n                new PolicyActionsRegistry(\n                    beginBlockActions: ImmutableArray<IAction>.Empty,\n                    endBlockActions: ImmutableArray<IAction>.Empty,\n                    beginTxActions: ImmutableArray.Create<IAction>(\n                        new GasTraceAction() { CancelTrace = cancelTrace }),\n                    endTxActions: ImmutableArray<IAction>.Empty),\n                getMaxTransactionsBytes: _ => 50 * 1024);\n\n            var store = new MemoryStore();\n            var stateStore = new TrieStateStore(new MemoryKeyValueStore());\n            var chain = TestUtils.MakeBlockChain(\n                policy: policy,\n                store: store,\n                stateStore: stateStore,\n                actionLoader: new SingleActionLoader(typeof(UseGasAction)));\n            var action = new UseGasAction\n            {\n                GasUsage = 10,\n                MintValue = gold * goldAmount,\n                Receiver = privateKey.Address,\n                Memo = string.Empty,\n            };\n\n            var tx = Transaction.Create(\n                nonce: 0,\n                privateKey: privateKey,\n                genesisHash: chain.Genesis.Hash,\n                actions: new[] { action }.ToPlainValues(),\n                maxGasPrice: gas * 10,\n                gasLimit: 10);\n            var expectedGold = gold * expectedGoldAmount;\n\n            chain.StageTransaction(tx);\n            var miner = new PrivateKey();\n            Block block = chain.ProposeBlock(miner);\n            chain.Append(block, CreateBlockCommit(block));\n            var evaluations = chain.ActionEvaluator.Evaluate(\n                block, chain.GetNextStateRootHash((BlockHash)block.PreviousHash));\n\n            var actualGold = chain.GetNextWorldState().GetBalance(privateKey.Address, gold);\n\n            Assert.Equal(expectedGold, actualGold);\n        }\n\n        [Fact]\n        public void Evaluate_CancelTrace_BeginBlockAction_Throw()\n        {\n            var policy = new BlockPolicy(\n                new PolicyActionsRegistry(\n                    beginBlockActions: ImmutableArray.Create<IAction>(\n                        new GasTraceAction() { CancelTrace = true }),\n                    endBlockActions: ImmutableArray<IAction>.Empty,\n                    beginTxActions: ImmutableArray<IAction>.Empty,\n                    endTxActions: ImmutableArray<IAction>.Empty),\n                getMaxTransactionsBytes: _ => 50 * 1024);\n            var evaluations = Evaluate_CancelTrace(policy);\n            var exception = (UnexpectedlyTerminatedActionException)evaluations[0].Exception;\n\n            Assert.IsType<GasTraceAction>(exception.Action);\n            Assert.IsType<InvalidOperationException>(exception.InnerException);\n            Assert.Equal(\n                \"CancelTrace can only be called in TxAction.\", exception.InnerException.Message);\n        }\n\n        [Fact]\n        public void Evaluate_CancelTrace_EndBlockAction_Throw()\n        {\n            var policy = new BlockPolicy(\n                new PolicyActionsRegistry(\n                    beginBlockActions: ImmutableArray<IAction>.Empty,\n                    endBlockActions: ImmutableArray.Create<IAction>(\n                        new GasTraceAction() { CancelTrace = true }),\n                    beginTxActions: ImmutableArray<IAction>.Empty,\n                    endTxActions: ImmutableArray<IAction>.Empty),\n                getMaxTransactionsBytes: _ => 50 * 1024);\n            var evaluations = Evaluate_CancelTrace(policy);\n            var exception = (UnexpectedlyTerminatedActionException)evaluations[1].Exception;\n\n            Assert.IsType<GasTraceAction>(exception.Action);\n            Assert.IsType<InvalidOperationException>(exception.InnerException);\n            Assert.Equal(\n                \"CancelTrace can only be called in TxAction.\", exception.InnerException.Message);\n        }\n\n        [Fact]\n        public void Evaluate_CancelTrace_EndTxAction_Throw()\n        {\n            var policy = new BlockPolicy(\n                new PolicyActionsRegistry(\n                    beginBlockActions: ImmutableArray<IAction>.Empty,\n                    endBlockActions: ImmutableArray<IAction>.Empty,\n                    beginTxActions: ImmutableArray<IAction>.Empty,\n                    endTxActions: ImmutableArray.Create<IAction>(\n                        new GasTraceAction() { CancelTrace = true })),\n                getMaxTransactionsBytes: _ => 50 * 1024);\n            var evaluations = Evaluate_CancelTrace(policy);\n            var exception = (UnexpectedlyTerminatedActionException)evaluations[1].Exception;\n\n            Assert.IsType<GasTraceAction>(exception.Action);\n            Assert.IsType<InvalidOperationException>(exception.InnerException);\n            Assert.Equal(\n                \"CancelTrace can only be called in TxAction.\", exception.InnerException.Message);\n        }\n\n        [Fact]\n        public void Evaluate_CancelTrace_Action_Throw()\n        {\n            var policy = new BlockPolicy(\n                new PolicyActionsRegistry(\n                    beginBlockActions: ImmutableArray<IAction>.Empty,\n                    endBlockActions: ImmutableArray<IAction>.Empty,\n                    beginTxActions: ImmutableArray<IAction>.Empty,\n                    endTxActions: ImmutableArray<IAction>.Empty),\n                getMaxTransactionsBytes: _ => 50 * 1024);\n            var gold = Currency.Uncapped(\"FOO\", 18, null);\n            var gas = Currency.Uncapped(\"GAS\", 18, null);\n            var privateKey = new PrivateKey();\n\n            var store = new MemoryStore();\n            var stateStore = new TrieStateStore(new MemoryKeyValueStore());\n            var chain = TestUtils.MakeBlockChain(\n                policy: policy,\n                store: store,\n                stateStore: stateStore,\n                actionLoader: new SingleActionLoader(typeof(GasTraceAction)));\n            var action = new GasTraceAction\n            {\n                CancelTrace = true,\n            };\n\n            var tx = Transaction.Create(\n                nonce: 0,\n                privateKey: privateKey,\n                genesisHash: chain.Genesis.Hash,\n                actions: new[] { action }.ToPlainValues(),\n                maxGasPrice: gas * 10,\n                gasLimit: 10);\n\n            chain.StageTransaction(tx);\n            var miner = new PrivateKey();\n            Block block = chain.ProposeBlock(miner);\n            chain.Append(block, CreateBlockCommit(block));\n            var evaluations = chain.ActionEvaluator.Evaluate(\n                block, chain.GetNextStateRootHash((BlockHash)block.PreviousHash));\n            var exception = (UnexpectedlyTerminatedActionException)evaluations[0].Exception;\n\n            Assert.IsType<GasTraceAction>(exception.Action);\n            Assert.IsType<InvalidOperationException>(exception.InnerException);\n            Assert.Equal(\n                \"CancelTrace can only be called in TxAction.\", exception.InnerException.Message);\n        }\n\n        private IReadOnlyList<ICommittedActionEvaluation> Evaluate_CancelTrace(BlockPolicy policy)\n        {\n            var gold = Currency.Uncapped(\"FOO\", 18, null);\n            var gas = Currency.Uncapped(\"GAS\", 18, null);\n            var privateKey = new PrivateKey();\n\n            var store = new MemoryStore();\n            var stateStore = new TrieStateStore(new MemoryKeyValueStore());\n            var chain = TestUtils.MakeBlockChain(\n                policy: policy,\n                store: store,\n                stateStore: stateStore,\n                actionLoader: new SingleActionLoader(typeof(UseGasAction)));\n            var action = new UseGasAction\n            {\n                GasUsage = 10,\n                MintValue = gold * 10,\n                Receiver = privateKey.Address,\n                Memo = string.Empty,\n            };\n\n            var tx = Transaction.Create(\n                nonce: 0,\n                privateKey: privateKey,\n                genesisHash: chain.Genesis.Hash,\n                actions: new[] { action }.ToPlainValues(),\n                maxGasPrice: gas * 10,\n                gasLimit: 10);\n\n            chain.StageTransaction(tx);\n            var miner = new PrivateKey();\n            Block block = chain.ProposeBlock(miner);\n            chain.Append(block, CreateBlockCommit(block));\n            return chain.ActionEvaluator.Evaluate(\n                block, chain.GetNextStateRootHash((BlockHash)block.PreviousHash));\n        }\n\n        private sealed class GasTraceAction : IAction\n        {\n            public bool CancelTrace { get; set; }\n\n            public IValue PlainValue => new List(\n                (Bencodex.Types.Boolean)CancelTrace);\n\n            public void LoadPlainValue(IValue plainValue)\n            {\n                var list = (List)plainValue;\n                CancelTrace = (Bencodex.Types.Boolean)list[0];\n            }\n\n            public IWorld Execute(IActionContext context)\n            {\n                if (CancelTrace)\n                {\n                    GasTracer.CancelTrace();\n                }\n\n                return context.PreviousState;\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "test/Libplanet.Tests/Action/ActionEvaluatorTest.Migration.cs",
    "content": "using System.Linq;\nusing System.Security.Cryptography;\nusing Bencodex.Types;\nusing Libplanet.Action;\nusing Libplanet.Action.Loader;\nusing Libplanet.Action.State;\nusing Libplanet.Action.Tests.Common;\nusing Libplanet.Blockchain.Policies;\nusing Libplanet.Common;\nusing Libplanet.Crypto;\nusing Libplanet.Mocks;\nusing Libplanet.Store;\nusing Libplanet.Store.Trie;\nusing Libplanet.Types.Assets;\nusing Libplanet.Types.Blocks;\nusing Libplanet.Types.Consensus;\nusing Libplanet.Types.Tx;\nusing Serilog;\nusing Xunit;\nusing static Libplanet.Tests.TestUtils;\n\nnamespace Libplanet.Tests.Action\n{\n    public partial class ActionEvaluatorTest\n    {\n        [Fact]\n        public void MigrateWorld()\n        {\n            var stateStore = new TrieStateStore(new MemoryKeyValueStore());\n            var actionEvaluator = new ActionEvaluator(\n                new PolicyActionsRegistry(),\n                stateStore,\n                new SingleActionLoader(typeof(DumbAction)));\n#pragma warning disable CS0618\n            var legacyCurrency = Currency.Legacy(\"LEG\", 2, null);\n#pragma warning restore CS0618\n            var modernCurrency = Currency.Uncapped(\"MOD\", 4, null);\n\n            var address = new PrivateKey().Address;\n            var value = new Text(\"Foo\");\n            var validatorSet = new ValidatorSet(\n                Enumerable\n                    .Range(0, 4)\n                    .Select(_ => new Validator(new PrivateKey().PublicKey, 1))\n                    .ToList());\n\n            // Throwaway addresses are used to differentiate balance and total supply.\n            var world0 = new World(MockWorldState.CreateLegacy(stateStore)\n                .SetBalance(address, legacyCurrency, 123)\n                .SetBalance(address, modernCurrency, 456)\n                .SetBalance(new PrivateKey().Address, legacyCurrency, 1000)\n                .SetBalance(new PrivateKey().Address, modernCurrency, 2000)\n                .SetValidatorSet(validatorSet));\n            var trie0 = world0.Trie;\n            trie0 = trie0.Set(KeyConverters.ToStateKey(address), value);\n            trie0 = stateStore.Commit(trie0);\n            world0 = new World(new WorldBaseState(trie0, stateStore));\n\n            var world4 = stateStore.MigrateWorld(\n                world0, BlockMetadata.PBFTProtocolVersion);\n            Assert.True(world4.Trie.Recorded);\n            Assert.Equal(0, world4.Version);\n            Assert.Equal(world0.Trie.Hash, world4.Trie.Hash);\n            Assert.Equal(value, world4.Trie.Get(KeyConverters.ToStateKey(address)));\n            Assert.Equal(\n                value,\n                world4.GetAccount(ReservedAddresses.LegacyAccount).GetState(address));\n            Assert.Equal(\n                validatorSet.Bencoded,\n                world4.Trie.Get(KeyConverters.ValidatorSetKey));\n            Assert.Equal(\n                validatorSet,\n                world4.GetValidatorSet());\n            Assert.Equal(\n                new Integer(123),\n                world4.Trie.Get(KeyConverters.ToFungibleAssetKey(address, legacyCurrency)));\n            Assert.Equal(\n                new Integer(456),\n                world4.Trie.Get(KeyConverters.ToFungibleAssetKey(address, modernCurrency)));\n            Assert.Equal(\n                FungibleAssetValue.FromRawValue(legacyCurrency, 123),\n                world4.GetBalance(address, legacyCurrency));\n            Assert.Equal(\n                FungibleAssetValue.FromRawValue(modernCurrency, 456),\n                world4.GetBalance(address, modernCurrency));\n            Assert.Null(world4.Trie.Get(KeyConverters.ToTotalSupplyKey(legacyCurrency)));\n            Assert.Equal(\n                new Integer(2456),\n                world4.Trie.Get(KeyConverters.ToTotalSupplyKey(modernCurrency)));\n            Assert.Equal(\n                FungibleAssetValue.FromRawValue(legacyCurrency, 0),\n                world4.GetTotalSupply(legacyCurrency));\n            Assert.Equal(\n                FungibleAssetValue.FromRawValue(modernCurrency, 2456),\n                world4.GetTotalSupply(modernCurrency));\n\n            var world5 = stateStore.MigrateWorld(\n                world0, BlockMetadata.WorldStateProtocolVersion);\n            Assert.True(world5.Trie.Recorded);\n            Assert.Equal(5, world5.Version);\n            Assert.NotEqual(world0.Trie.Hash, world5.Trie.Hash);\n            Assert.Null(world5.Trie.Get(KeyConverters.ToStateKey(address)));\n            Assert.Equal(\n                value,\n                world5.GetAccount(ReservedAddresses.LegacyAccount).GetState(address));\n            Assert.Null(world5.Trie.Get(KeyConverters.ValidatorSetKey));\n            Assert.Equal(\n                validatorSet.Bencoded,\n                world5\n                    .GetAccount(ReservedAddresses.LegacyAccount)\n                    .Trie\n                    .Get(KeyConverters.ValidatorSetKey));\n            Assert.Equal(validatorSet, world5.GetValidatorSet());\n            Assert.Equal(\n                new Integer(123),\n                world5\n                    .GetAccount(ReservedAddresses.LegacyAccount)\n                    .Trie\n                    .Get(KeyConverters.ToFungibleAssetKey(address, legacyCurrency)));\n            Assert.Equal(\n                new Integer(456),\n                world5\n                    .GetAccount(ReservedAddresses.LegacyAccount)\n                    .Trie\n                    .Get(KeyConverters.ToFungibleAssetKey(address, modernCurrency)));\n            Assert.Equal(\n                FungibleAssetValue.FromRawValue(legacyCurrency, 123),\n                world5.GetBalance(address, legacyCurrency));\n            Assert.Equal(\n                FungibleAssetValue.FromRawValue(modernCurrency, 456),\n                world5.GetBalance(address, modernCurrency));\n            Assert.Null(\n                world5\n                    .GetAccount(ReservedAddresses.LegacyAccount)\n                    .Trie\n                    .Get(KeyConverters.ToTotalSupplyKey(legacyCurrency)));\n            Assert.Equal(\n                new Integer(2456),\n                world5\n                    .GetAccount(ReservedAddresses.LegacyAccount)\n                    .Trie\n                    .Get(KeyConverters.ToTotalSupplyKey(modernCurrency)));\n            Assert.Equal(\n                FungibleAssetValue.FromRawValue(legacyCurrency, 0),\n                world5.GetTotalSupply(legacyCurrency));\n            Assert.Equal(\n                FungibleAssetValue.FromRawValue(modernCurrency, 2456),\n                world5.GetTotalSupply(modernCurrency));\n\n            var world6 = stateStore.MigrateWorld(\n                world0, BlockMetadata.ValidatorSetAccountProtocolVersion);\n            Assert.True(world6.Trie.Recorded);\n            Assert.Equal(6, world6.Version);\n            Assert.NotEqual(world0.Trie.Hash, world6.Trie.Hash);\n            Assert.NotEqual(world5.Trie.Hash, world6.Trie.Hash);\n            Assert.Null(world6.Trie.Get(KeyConverters.ToStateKey(address)));\n            Assert.Equal(\n                value,\n                world6.GetAccount(ReservedAddresses.LegacyAccount).GetState(address));\n            Assert.Null(world6.Trie.Get(KeyConverters.ValidatorSetKey));\n            Assert.Null(\n                world6\n                    .GetAccount(ReservedAddresses.LegacyAccount)\n                    .Trie\n                    .Get(KeyConverters.ValidatorSetKey));\n            Assert.Equal(\n                validatorSet.Bencoded,\n                world6\n                    .GetAccount(ReservedAddresses.ValidatorSetAccount)\n                    .Trie\n                    .Get(KeyConverters.ToStateKey(ValidatorSetAccount.ValidatorSetAddress)));\n            Assert.Equal(validatorSet, world6.GetValidatorSet());\n            Assert.Equal(\n                new Integer(123),\n                world6\n                    .GetAccount(ReservedAddresses.LegacyAccount)\n                    .Trie\n                    .Get(KeyConverters.ToFungibleAssetKey(address, legacyCurrency)));\n            Assert.Equal(\n                new Integer(456),\n                world6\n                    .GetAccount(ReservedAddresses.LegacyAccount)\n                    .Trie\n                    .Get(KeyConverters.ToFungibleAssetKey(address, modernCurrency)));\n            Assert.Equal(\n                FungibleAssetValue.FromRawValue(legacyCurrency, 123),\n                world6.GetBalance(address, legacyCurrency));\n            Assert.Equal(\n                FungibleAssetValue.FromRawValue(modernCurrency, 456),\n                world6.GetBalance(address, modernCurrency));\n            Assert.Null(\n                world6\n                    .GetAccount(ReservedAddresses.LegacyAccount)\n                    .Trie\n                    .Get(KeyConverters.ToTotalSupplyKey(legacyCurrency)));\n            Assert.Equal(\n                new Integer(2456),\n                world6\n                    .GetAccount(ReservedAddresses.LegacyAccount)\n                    .Trie\n                    .Get(KeyConverters.ToTotalSupplyKey(modernCurrency)));\n            Assert.Equal(\n                FungibleAssetValue.FromRawValue(legacyCurrency, 0),\n                world6.GetTotalSupply(legacyCurrency));\n            Assert.Equal(\n                FungibleAssetValue.FromRawValue(modernCurrency, 2456),\n                world6.GetTotalSupply(modernCurrency));\n\n            var world7 = stateStore.MigrateWorld(\n                world0, BlockMetadata.CurrencyAccountProtocolVersion);\n            Assert.True(world7.Trie.Recorded);\n            Assert.Equal(7, world7.Version);\n            Assert.NotEqual(world0.Trie.Hash, world7.Trie.Hash);\n            Assert.NotEqual(world6.Trie.Hash, world7.Trie.Hash);\n            Assert.Null(world7.Trie.Get(KeyConverters.ToStateKey(address)));\n            Assert.Equal(\n                value,\n                world7.GetAccount(ReservedAddresses.LegacyAccount).GetState(address));\n            Assert.Null(world7.Trie.Get(KeyConverters.ValidatorSetKey));\n            Assert.Null(\n                world7\n                    .GetAccount(ReservedAddresses.LegacyAccount)\n                    .Trie\n                    .Get(KeyConverters.ValidatorSetKey));\n            Assert.Equal(\n                validatorSet.Bencoded,\n                world7\n                    .GetAccount(ReservedAddresses.ValidatorSetAccount)\n                    .Trie\n                    .Get(KeyConverters.ToStateKey(ValidatorSetAccount.ValidatorSetAddress)));\n            Assert.Equal(validatorSet, world7.GetValidatorSet());\n            Assert.Null(\n                world7\n                    .GetAccount(ReservedAddresses.LegacyAccount)\n                    .Trie\n                    .Get(KeyConverters.ToFungibleAssetKey(address, legacyCurrency)));\n            Assert.Equal(\n                new Integer(123),\n                world7\n                    .GetAccount(new Address(legacyCurrency.Hash.ByteArray))\n                    .Trie\n                    .Get(KeyConverters.ToStateKey(address)));\n            Assert.Null(\n                world7\n                    .GetAccount(ReservedAddresses.LegacyAccount)\n                    .Trie\n                    .Get(KeyConverters.ToFungibleAssetKey(address, modernCurrency)));\n            Assert.Equal(\n                new Integer(456),\n                world7\n                    .GetAccount(new Address(modernCurrency.Hash.ByteArray))\n                    .Trie\n                    .Get(KeyConverters.ToStateKey(address)));\n            Assert.Equal(\n                FungibleAssetValue.FromRawValue(legacyCurrency, 123),\n                world7.GetBalance(address, legacyCurrency));\n            Assert.Equal(\n                FungibleAssetValue.FromRawValue(modernCurrency, 456),\n                world7.GetBalance(address, modernCurrency));\n            Assert.Null(\n                world7\n                    .GetAccount(ReservedAddresses.LegacyAccount)\n                    .Trie\n                    .Get(KeyConverters.ToTotalSupplyKey(legacyCurrency)));\n            Assert.Equal(\n                new Integer(1123),\n                world7\n                    .GetAccount(new Address(legacyCurrency.Hash.ByteArray))\n                    .Trie\n                    .Get(KeyConverters.ToStateKey(CurrencyAccount.TotalSupplyAddress)));\n            Assert.Null(\n                world7\n                    .GetAccount(ReservedAddresses.LegacyAccount)\n                    .Trie\n                    .Get(KeyConverters.ToTotalSupplyKey(modernCurrency)));\n            Assert.Equal(\n                new Integer(2456),\n                world7\n                    .GetAccount(new Address(modernCurrency.Hash.ByteArray))\n                    .Trie\n                    .Get(KeyConverters.ToStateKey(CurrencyAccount.TotalSupplyAddress)));\n            Assert.Equal(\n                FungibleAssetValue.FromRawValue(legacyCurrency, 1123),\n                world7.GetTotalSupply(legacyCurrency));\n            Assert.Equal(\n                FungibleAssetValue.FromRawValue(modernCurrency, 2456),\n                world7.GetTotalSupply(modernCurrency));\n        }\n\n        [Fact]\n        public void MigrateThroughBlockWorldState()\n        {\n            var store = new MemoryStore();\n            var stateStore = new TrieStateStore(new MemoryKeyValueStore());\n            Log.Debug(\"Test Start.\");\n            var chain = MakeBlockChain(\n                policy: new BlockPolicy(),\n                store: store,\n                stateStore: stateStore,\n                actionLoader: new SingleActionLoader(typeof(ModernAction)),\n                protocolVersion: BlockMetadata.WorldStateProtocolVersion - 1);\n            Assert.Equal(0, chain.GetWorldState().Version);\n            var miner = new PrivateKey();\n            var preEval1 = TestUtils.ProposeNext(\n                chain.Tip,\n                miner: miner.PublicKey,\n                protocolVersion: BlockMetadata.WorldStateProtocolVersion - 1);\n            var block1 = chain.EvaluateAndSign(preEval1, miner);\n            var blockCommit = CreateBlockCommit(block1);\n            chain.Append(block1, blockCommit);\n            Assert.Equal(0, chain.GetWorldState().Version);\n\n            // A block that doesn't touch any state does not migrate its state.\n            var block2 = chain.ProposeBlock(miner, blockCommit);\n            blockCommit = CreateBlockCommit(block2);\n            chain.Append(block2, blockCommit);\n            Assert.Equal(0, chain.GetWorldState().Version);\n\n            // Check if after migration, accounts can be created correctly.\n            var action = new ModernAction()\n            {\n                Memo = \"foo\",\n            };\n\n            var tx = Transaction.Create(\n                nonce: 0,\n                privateKey: miner,\n                genesisHash: chain.Genesis.Hash,\n                actions: new[] { action }.ToPlainValues());\n\n            chain.StageTransaction(tx);\n            var block3 = chain.ProposeBlock(miner, blockCommit);\n            chain.Append(block3, CreateBlockCommit(block3));\n            Assert.Equal(BlockMetadata.CurrentProtocolVersion, chain.GetNextWorldState().Version);\n            var accountStateRoot = stateStore.GetStateRoot(chain.GetNextStateRootHash(block3.Hash))\n                .Get(KeyConverters.ToStateKey(ModernAction.AccountAddress));\n            Assert.NotNull(accountStateRoot);\n            var accountTrie = stateStore.GetStateRoot(new HashDigest<SHA256>(accountStateRoot));\n            Assert.Equal(\n                (Text)\"foo\",\n                accountTrie.Get(KeyConverters.ToStateKey(ModernAction.Address)));\n        }\n\n        [Fact]\n        public void MigrateThroughBlockCurrencyAccount()\n        {\n            var store = new MemoryStore();\n            var stateStore = new TrieStateStore(new MemoryKeyValueStore());\n            Log.Debug(\"Test Start.\");\n            var chain = MakeBlockChain(\n                policy: new BlockPolicy(),\n                store: store,\n                stateStore: stateStore,\n                actionLoader: new SingleActionLoader(typeof(DumbAction)),\n                protocolVersion: BlockMetadata.WorldStateProtocolVersion - 1);\n            Assert.Equal(0, chain.GetWorldState().Version);\n            var miner = new PrivateKey();\n            var preEval1 = TestUtils.ProposeNext(\n                chain.Tip,\n                miner: miner.PublicKey,\n                protocolVersion: BlockMetadata.WorldStateProtocolVersion - 1);\n            var block1 = chain.EvaluateAndSign(preEval1, miner);\n            var blockCommit = CreateBlockCommit(block1);\n            chain.Append(block1, blockCommit);\n            Assert.Equal(0, chain.GetWorldState().Version);\n\n            // A block that doesn't touch any state does not migrate its state.\n            var block2 = chain.ProposeBlock(miner, blockCommit);\n            blockCommit = CreateBlockCommit(block2);\n            chain.Append(block2, blockCommit);\n            Assert.Equal(0, chain.GetWorldState().Version);\n\n            // Check if after migration, accounts can be created correctly.\n            var action = DumbAction.Create(\n                null,\n                (null, miner.Address, 10));\n\n            var tx = Transaction.Create(\n                nonce: 0,\n                privateKey: miner,\n                genesisHash: chain.Genesis.Hash,\n                actions: new[] { action }.ToPlainValues());\n\n            chain.StageTransaction(tx);\n            var block3 = chain.ProposeBlock(miner, blockCommit);\n            chain.Append(block3, CreateBlockCommit(block3));\n            Assert.Equal(BlockMetadata.CurrentProtocolVersion, chain.GetNextWorldState().Version);\n\n            var nextStateRootHash = chain.GetNextStateRootHash(block3.Hash);\n            var currencyAccountStateRoot = stateStore\n                    .GetStateRoot(nextStateRootHash)\n                    .Get(KeyConverters.ToStateKey(\n                        new Address(DumbAction.DumbCurrency.Hash.ByteArray)));\n            Assert.NotNull(currencyAccountStateRoot);\n            var currencyAccountTrie = stateStore.GetStateRoot(\n                new HashDigest<SHA256>(currencyAccountStateRoot));\n            Assert.Equal(\n                new Integer(10),\n                currencyAccountTrie.Get(KeyConverters.ToStateKey(miner.Address)));\n            Assert.Equal(\n                new Integer(10),\n                currencyAccountTrie.Get(\n                    KeyConverters.ToStateKey(CurrencyAccount.TotalSupplyAddress)));\n        }\n    }\n}\n"
  },
  {
    "path": "test/Libplanet.Tests/Action/ActionEvaluatorTest.cs",
    "content": "#pragma warning disable MEN003 // Method is too long\nusing System;\nusing System.Collections;\nusing System.Collections.Generic;\nusing System.Collections.Immutable;\nusing System.Linq;\nusing System.Numerics;\nusing Bencodex.Types;\nusing Libplanet.Action;\nusing Libplanet.Action.Loader;\nusing Libplanet.Action.State;\nusing Libplanet.Action.Tests.Common;\nusing Libplanet.Blockchain.Policies;\nusing Libplanet.Crypto;\nusing Libplanet.Mocks;\nusing Libplanet.Store;\nusing Libplanet.Store.Trie;\nusing Libplanet.Tests.Blocks;\nusing Libplanet.Tests.Fixtures;\nusing Libplanet.Tests.Store;\nusing Libplanet.Tests.Tx;\nusing Libplanet.Types.Assets;\nusing Libplanet.Types.Blocks;\nusing Libplanet.Types.Evidence;\nusing Libplanet.Types.Tx;\nusing Serilog;\nusing Xunit;\nusing Xunit.Abstractions;\nusing static Libplanet.Action.State.KeyConverters;\nusing static Libplanet.Tests.TestUtils;\n\nnamespace Libplanet.Tests.Action\n{\n    public partial class ActionEvaluatorTest\n    {\n        private readonly ILogger _logger;\n        private readonly ITestOutputHelper _output;\n        private readonly BlockPolicy _policy;\n        private readonly StoreFixture _storeFx;\n        private readonly TxFixture _txFx;\n\n        private readonly Address _beginBlockValueAddress =\n            new Address(\"0000000000000000000000000000000000000120\");\n\n        private readonly Address _endBlockValueAddress =\n            new Address(\"0000000000000000000000000000000000000121\");\n\n        private readonly Address _beginTxValueAddress =\n            new Address(\"0000000000000000000000000000000000000122\");\n\n        private readonly Address _endTxValueAddress =\n            new Address(\"0000000000000000000000000000000000000123\");\n\n        public ActionEvaluatorTest(ITestOutputHelper output)\n        {\n            Log.Logger = _logger = new LoggerConfiguration()\n                .MinimumLevel.Verbose()\n                .Enrich.WithThreadId()\n                .WriteTo.TestOutput(output)\n                .CreateLogger()\n                .ForContext<ActionEvaluatorTest>();\n\n            _output = output;\n            _policy = new BlockPolicy(\n                new PolicyActionsRegistry(\n                    beginBlockActions: ImmutableArray.Create<IAction>(\n                        new UpdateValueAction(_beginBlockValueAddress, 1)),\n                    endBlockActions: ImmutableArray.Create<IAction>(\n                        new UpdateValueAction(_endBlockValueAddress, 1)),\n                    beginTxActions: ImmutableArray.Create<IAction>(\n                        new UpdateValueAction(_beginTxValueAddress, 1)),\n                    endTxActions: ImmutableArray.Create<IAction>(\n                        new UpdateValueAction(_endTxValueAddress, 1))),\n                getMaxTransactionsBytes: _ => 50 * 1024);\n            _storeFx = new MemoryStoreFixture(_policy.PolicyActionsRegistry);\n            _txFx = new TxFixture(null);\n        }\n\n        [Fact]\n        public void Idempotent()\n        {\n            // NOTE: This test checks that blocks can be evaluated idempotently. Also it checks\n            // the action results in pre-evaluation step and in evaluation step are equal.\n            const int repeatCount = 2;\n            var signer = new PrivateKey();\n            var timestamp = DateTimeOffset.UtcNow;\n            var txAddress = signer.Address;\n            var txs = new[]\n            {\n                Transaction.Create(\n                    nonce: 0,\n                    privateKey: signer,\n                    genesisHash: null,\n                    actions: new[] { new ContextRecordingAction(txAddress, new Text(\"Foo\")), }\n                        .ToPlainValues()),\n            };\n            var evs = Array.Empty<EvidenceBase>();\n            var stateStore = new TrieStateStore(new MemoryKeyValueStore());\n            var noStateRootBlock = new BlockContent(\n                new BlockMetadata(\n                    protocolVersion: Block.CurrentProtocolVersion,\n                    index: 0,\n                    timestamp: timestamp,\n                    miner: GenesisProposer.Address,\n                    publicKey: GenesisProposer.PublicKey,\n                    previousHash: null,\n                    txHash: BlockContent.DeriveTxHash(txs),\n                    lastCommit: null,\n                    evidenceHash: null),\n                transactions: txs,\n                evidence: evs).Propose();\n            var actionEvaluator = new ActionEvaluator(\n                new PolicyActionsRegistry(),\n                stateStore,\n                new SingleActionLoader(typeof(ContextRecordingAction)));\n            Block stateRootBlock = noStateRootBlock.Sign(\n                GenesisProposer,\n                MerkleTrie.EmptyRootHash);\n            var generatedRandomNumbers = new List<int>();\n\n            AssertPreEvaluationBlocksEqual(stateRootBlock, noStateRootBlock);\n\n            for (int i = 0; i < repeatCount; ++i)\n            {\n                var actionEvaluations = actionEvaluator.Evaluate(noStateRootBlock, null);\n                generatedRandomNumbers.Add(\n                    (Integer)new WorldBaseState(\n                        stateStore.GetStateRoot(actionEvaluations[0].OutputState), stateStore)\n                            .GetAccountState(ReservedAddresses.LegacyAccount)\n                            .GetState(ContextRecordingAction.RandomRecordAddress));\n                actionEvaluations = actionEvaluator.Evaluate(stateRootBlock, null);\n                generatedRandomNumbers.Add(\n                    (Integer)new WorldBaseState(\n                        stateStore.GetStateRoot(actionEvaluations[0].OutputState), stateStore)\n                            .GetAccountState(ReservedAddresses.LegacyAccount)\n                            .GetState(ContextRecordingAction.RandomRecordAddress));\n            }\n\n            for (int i = 1; i < generatedRandomNumbers.Count; ++i)\n            {\n                Assert.Equal(generatedRandomNumbers[0], generatedRandomNumbers[i]);\n            }\n        }\n\n        [Fact]\n        public void Evaluate()\n        {\n            var privateKey = new PrivateKey();\n            var address = privateKey.Address;\n            var value = new Text(\"Foo\");\n\n            var store = new MemoryStore();\n            var stateStore = new TrieStateStore(new MemoryKeyValueStore());\n            var chain = TestUtils.MakeBlockChain(\n                policy: new BlockPolicy(),\n                store: store,\n                stateStore: stateStore,\n                actionLoader: new SingleActionLoader(typeof(ContextRecordingAction)));\n            var action = new ContextRecordingAction(address, value);\n            var tx = Transaction.Create(\n                nonce: 0,\n                privateKey: privateKey,\n                genesisHash: chain.Genesis.Hash,\n                actions: new[] { action }.ToPlainValues());\n\n            chain.StageTransaction(tx);\n            var miner = new PrivateKey();\n            Block block = chain.ProposeBlock(miner);\n            chain.Append(block, CreateBlockCommit(block));\n\n            var evaluations = chain.ActionEvaluator.Evaluate(\n                chain.Tip, chain.Store.GetStateRootHash(chain.Tip.PreviousHash));\n\n            Assert.False(evaluations[0].InputContext.IsPolicyAction);\n            Assert.Single(evaluations);\n            Assert.Null(evaluations.Single().Exception);\n            Assert.Equal(\n                chain\n                    .GetNextWorldState()\n                    .GetAccountState(ReservedAddresses.LegacyAccount)\n                    .GetState(address),\n                value);\n            Assert.Equal(\n                chain\n                    .GetNextWorldState()\n                    .GetAccountState(ReservedAddresses.LegacyAccount)\n                    .GetState(ContextRecordingAction.MinerRecordAddress),\n                block.Miner.Bencoded);\n            Assert.Equal(\n                chain\n                    .GetNextWorldState()\n                    .GetAccountState(ReservedAddresses.LegacyAccount)\n                    .GetState(ContextRecordingAction.SignerRecordAddress),\n                tx.Signer.Bencoded);\n            Assert.Equal(\n                chain\n                    .GetNextWorldState()\n                    .GetAccountState(ReservedAddresses.LegacyAccount)\n                    .GetState(ContextRecordingAction.BlockIndexRecordAddress),\n                new Integer(block.Index));\n            Assert.Equal(\n                chain\n                    .GetNextWorldState()\n                    .GetAccountState(ReservedAddresses.LegacyAccount)\n                    .GetState(ContextRecordingAction.RandomRecordAddress),\n                new Integer(evaluations.Single().InputContext.GetRandom().Next()));\n        }\n\n        [Fact]\n        public void EvaluateWithPolicyActions()\n        {\n            var store = new MemoryStore();\n            var stateStore = new TrieStateStore(new MemoryKeyValueStore());\n            var (chain, actionEvaluator) =\n                TestUtils.MakeBlockChainAndActionEvaluator(\n                    policy: _policy,\n                    store: store,\n                    stateStore: stateStore,\n                    actionLoader: new SingleActionLoader(typeof(DumbAction)));\n\n            Assert.Equal(\n                (Integer)1,\n                chain\n                    .GetNextWorldState()\n                    .GetAccountState(ReservedAddresses.LegacyAccount)\n                    .GetState(_beginBlockValueAddress));\n            Assert.Equal(\n                (Integer)1,\n                chain\n                    .GetNextWorldState()\n                    .GetAccountState(ReservedAddresses.LegacyAccount)\n                    .GetState(_endBlockValueAddress));\n            Assert.Equal(\n                (Integer)chain.Genesis.Transactions.Count,\n                chain\n                    .GetNextWorldState()\n                    .GetAccountState(ReservedAddresses.LegacyAccount)\n                    .GetState(_beginTxValueAddress));\n            Assert.Equal(\n                (Integer)chain.Genesis.Transactions.Count,\n                chain\n                    .GetNextWorldState()\n                    .GetAccountState(ReservedAddresses.LegacyAccount)\n                    .GetState(_endTxValueAddress));\n\n            (_, Transaction[] txs) = MakeFixturesForAppendTests();\n            var block = chain.ProposeBlock(\n                proposer: GenesisProposer,\n                transactions: txs.ToImmutableList(),\n                lastCommit: CreateBlockCommit(chain.Tip),\n                evidence: ImmutableArray<EvidenceBase>.Empty);\n            var evaluations = actionEvaluator.Evaluate(\n                block, chain.Store.GetStateRootHash(chain.Tip.Hash)).ToArray();\n\n            // BeginBlockAction + (BeginTxAction + #Action + EndTxAction) * #Tx + EndBlockAction\n            Assert.Equal(\n                2 + txs.Length * 2 + txs.Aggregate(0, (sum, tx) => sum + tx.Actions.Count),\n                evaluations.Length);\n\n            chain.Append(block, CreateBlockCommit(block));\n            Assert.Equal(\n                (Integer)2,\n                chain\n                    .GetNextWorldState()\n                    .GetAccountState(ReservedAddresses.LegacyAccount)\n                    .GetState(_beginBlockValueAddress));\n            Assert.Equal(\n                (Integer)2,\n                chain\n                    .GetNextWorldState()\n                    .GetAccountState(ReservedAddresses.LegacyAccount)\n                    .GetState(_endBlockValueAddress));\n            Assert.Equal(\n                (Integer)(chain.Genesis.Transactions.Count + txs.Length),\n                chain\n                    .GetNextWorldState()\n                    .GetAccountState(ReservedAddresses.LegacyAccount)\n                    .GetState(_beginTxValueAddress));\n            Assert.Equal(\n                (Integer)(chain.Genesis.Transactions.Count + txs.Length),\n                chain\n                    .GetNextWorldState()\n                    .GetAccountState(ReservedAddresses.LegacyAccount)\n                    .GetState(_endTxValueAddress));\n        }\n\n        [Fact]\n        public void EvaluateWithPolicyActionsWithException()\n        {\n            var store = new MemoryStore();\n            var stateStore = new TrieStateStore(new MemoryKeyValueStore());\n            var policyWithExceptions = new BlockPolicy(\n                new PolicyActionsRegistry(\n                    beginBlockActions: new IAction[]\n                    {\n                        new UpdateValueAction(_beginBlockValueAddress, 1),\n                        new ThrowException { ThrowOnExecution = true },\n                    }.ToImmutableArray(),\n                    endBlockActions: new IAction[]\n                    {\n                        new UpdateValueAction(_endBlockValueAddress, 1),\n                        new ThrowException { ThrowOnExecution = true },\n                    }.ToImmutableArray(),\n                    beginTxActions: new IAction[]\n                    {\n                        new UpdateValueAction(_beginTxValueAddress, 1),\n                        new ThrowException { ThrowOnExecution = true },\n                    }.ToImmutableArray(),\n                    endTxActions: new IAction[]\n                    {\n                        new UpdateValueAction(_endTxValueAddress, 1),\n                        new ThrowException { ThrowOnExecution = true },\n                    }.ToImmutableArray()));\n\n            var (chain, actionEvaluator) =\n                TestUtils.MakeBlockChainAndActionEvaluator(\n                    policy: policyWithExceptions,\n                    store: store,\n                    stateStore: stateStore,\n                    actionLoader: new SingleActionLoader(typeof(DumbAction)));\n\n            (_, Transaction[] txs) = MakeFixturesForAppendTests();\n            var block = chain.ProposeBlock(\n                GenesisProposer,\n                txs.ToImmutableList(),\n                CreateBlockCommit(chain.Tip),\n                ImmutableArray<EvidenceBase>.Empty);\n            var evaluations = actionEvaluator.Evaluate(\n                block, chain.Store.GetStateRootHash(chain.Tip.Hash)).ToArray();\n\n            // BeginBlockAction + (BeginTxAction + #Action + EndTxAction) * #Tx + EndBlockAction\n            Assert.Equal(\n                4 + txs.Length * 4 + txs.Sum(tx => tx.Actions.Count),\n                evaluations.Length);\n            Assert.Equal(\n                2 + txs.Length * 2,\n                evaluations.Count(e => e.Exception != null));\n        }\n\n        [Fact]\n        public void EvaluateWithException()\n        {\n            var privateKey = new PrivateKey();\n            var address = privateKey.Address;\n\n            var action = new ThrowException { ThrowOnExecution = true };\n\n            var store = new MemoryStore();\n            var stateStore = new TrieStateStore(new MemoryKeyValueStore());\n            var chain = TestUtils.MakeBlockChain(\n                policy: new BlockPolicy(),\n                store: store,\n                stateStore: stateStore,\n                actionLoader: new SingleActionLoader(typeof(ThrowException)));\n            var tx = Transaction.Create(\n                nonce: 0,\n                privateKey: privateKey,\n                genesisHash: chain.Genesis.Hash,\n                actions: new[] { action }.ToPlainValues());\n\n            chain.StageTransaction(tx);\n            Block block = chain.ProposeBlock(new PrivateKey());\n            chain.Append(block, CreateBlockCommit(block));\n            var evaluations = chain.ActionEvaluator.Evaluate(\n                chain.Tip, chain.Store.GetStateRootHash(chain.Tip.PreviousHash));\n\n            Assert.False(evaluations[0].InputContext.IsPolicyAction);\n            Assert.Single(evaluations);\n            Assert.NotNull(evaluations.Single().Exception);\n            Assert.IsType<UnexpectedlyTerminatedActionException>(\n                evaluations.Single().Exception);\n            Assert.IsType<ThrowException.SomeException>(\n                evaluations.Single().Exception.InnerException);\n        }\n\n        [Fact]\n        public void EvaluateWithCriticalException()\n        {\n            var privateKey = new PrivateKey();\n            var address = privateKey.Address;\n\n            var action = new ThrowException\n            {\n                ThrowOnExecution = true,\n                Deterministic = false,\n            };\n\n            var store = new MemoryStore();\n            var stateStore =\n                new TrieStateStore(new MemoryKeyValueStore());\n            var (chain, actionEvaluator) =\n                TestUtils.MakeBlockChainAndActionEvaluator(\n                    policy: new BlockPolicy(),\n                    store: store,\n                    stateStore: stateStore,\n                    actionLoader: new SingleActionLoader(typeof(ThrowException)));\n            var genesis = chain.Genesis;\n            // Evaluation is run with rehearsal true to get updated addresses on tx creation.\n            var tx = Transaction.Create(\n                nonce: 0,\n                privateKey: privateKey,\n                genesisHash: genesis.Hash,\n                actions: new[] { action }.ToPlainValues());\n            var txs = new Transaction[] { tx };\n            var evs = Array.Empty<EvidenceBase>();\n            PreEvaluationBlock block = new BlockContent(\n                new BlockMetadata(\n                    index: 1L,\n                    timestamp: DateTimeOffset.UtcNow,\n                    publicKey: new PrivateKey().PublicKey,\n                    previousHash: genesis.Hash,\n                    txHash: BlockContent.DeriveTxHash(txs),\n                    lastCommit: null,\n                    evidenceHash: null),\n                transactions: txs,\n                evidence: evs).Propose();\n            IWorld previousState = stateStore.GetWorld(genesis.StateRootHash);\n\n            Assert.Throws<OutOfMemoryException>(\n                () => actionEvaluator.EvaluateTx(\n                    block: block,\n                    tx: tx,\n                    previousState: previousState).ToList());\n            Assert.Throws<OutOfMemoryException>(\n                () => chain.ActionEvaluator.Evaluate(\n                    block, chain.Store.GetStateRootHash(block.PreviousHash)).ToList());\n        }\n\n        [Fact]\n        public void EvaluateTxs()\n        {\n            DumbAction MakeAction(Address address, char identifier, Address? transferTo = null)\n            {\n                return DumbAction.Create(\n                    append: (address, identifier.ToString()),\n                    transfer: transferTo is Address to\n                        ? (address, to, 5)\n                        : ((Address, Address, BigInteger)?)null);\n            }\n\n            Address[] addresses =\n            {\n                _txFx.Address1,\n                _txFx.Address2,\n                _txFx.Address3,\n                _txFx.Address4,\n                _txFx.Address5,\n            };\n\n            IStateStore stateStore = new TrieStateStore(new MemoryKeyValueStore());\n            IWorld world = new World(MockWorldState.CreateLegacy(stateStore)\n                .SetBalance(addresses[0], DumbAction.DumbCurrency * 100)\n                .SetBalance(addresses[1], DumbAction.DumbCurrency * 100)\n                .SetBalance(addresses[2], DumbAction.DumbCurrency * 100)\n                .SetBalance(addresses[3], DumbAction.DumbCurrency * 100)\n                .SetBalance(addresses[4], DumbAction.DumbCurrency * 100));\n            ITrie trie = stateStore.Commit(world.Trie);\n\n            Block genesis = ProposeGenesisBlock(\n                TestUtils.GenesisProposer,\n                stateRootHash: trie.Hash);\n            var actionEvaluator = new ActionEvaluator(\n                new PolicyActionsRegistry(),\n                stateStore: stateStore,\n                actionTypeLoader: new SingleActionLoader(typeof(DumbAction)));\n\n            Transaction[] block1Txs =\n            {\n                new Transaction(\n                    new UnsignedTx(\n                        new TxInvoice(\n                            genesisHash: genesis.Hash,\n                            updatedAddresses: new[]\n                            {\n                                addresses[0],\n                                addresses[1],\n                            }.ToImmutableHashSet(),\n                            timestamp: DateTimeOffset.MinValue.AddSeconds(2),\n                            actions: new TxActionList(new[]\n                            {\n                                MakeAction(addresses[0], 'A', addresses[1]),\n                                MakeAction(addresses[1], 'B', addresses[2]),\n                            }.ToPlainValues()),\n                            maxGasPrice: null,\n                            gasLimit: null),\n                        new TxSigningMetadata(_txFx.PrivateKey1.PublicKey, 0)),\n                    _txFx.PrivateKey1),\n                new Transaction(\n                    new UnsignedTx(\n                        new TxInvoice(\n                            genesisHash: genesis.Hash,\n                            updatedAddresses: ImmutableHashSet<Address>.Empty,\n                            timestamp: DateTimeOffset.MinValue.AddSeconds(4),\n                            actions: new TxActionList(new[]\n                            {\n                                MakeAction(addresses[2], 'C', addresses[3]),\n                            }.ToPlainValues()),\n                            maxGasPrice: null,\n                            gasLimit: null),\n                        new TxSigningMetadata(_txFx.PrivateKey2.PublicKey, 0)),\n                    _txFx.PrivateKey2),\n                new Transaction(\n                    new UnsignedTx(\n                        new TxInvoice(\n                            genesisHash: genesis.Hash,\n                            updatedAddresses: ImmutableHashSet<Address>.Empty,\n                            timestamp: DateTimeOffset.MinValue.AddSeconds(7),\n                            actions: TxActionList.Empty,\n                            maxGasPrice: null,\n                            gasLimit: null),\n                        new TxSigningMetadata(_txFx.PrivateKey3.PublicKey, 0)),\n                    _txFx.PrivateKey3),\n            };\n            foreach ((var tx, var i) in block1Txs.Zip(\n                Enumerable.Range(0, block1Txs.Length), (x, y) => (x, y)))\n            {\n                _logger.Debug(\"{0}[{1}] = {2}\", nameof(block1Txs), i, tx.Id);\n            }\n\n            Block block1 = ProposeNextBlock(\n                genesis,\n                GenesisProposer,\n                block1Txs);\n            IWorld previousState = stateStore.GetWorld(genesis.StateRootHash);\n            var evals = actionEvaluator.EvaluateBlock(\n                block1,\n                previousState).ToImmutableArray();\n            // Once the BlockMetadata.CurrentProtocolVersion gets bumped, expectations may also\n            // have to be updated, since the order may change due to different PreEvaluationHash.\n            (int TxIdx, int ActionIdx, string[] UpdatedStates, Address Signer)[] expectations =\n            {\n                (1, 0, new[] { null, null, \"C\", null, null }, _txFx.Address2),  // Adds \"A\"\n                (0, 0, new[] { \"A\", null, \"C\", null, null }, _txFx.Address1),   // Adds \"B\"\n                (0, 1, new[] { \"A\", \"B\", \"C\", null, null }, _txFx.Address1),    // Adds \"C\"\n            };\n\n#if DEBUG\n            // This code was created by ilgyu.\n            // You can preview the result of the test in the debug console.\n            // If this test fails, you can copy the result from the debug console\n            // and paste it to the upper part of the test code.\n            System.Diagnostics.Trace.WriteLine(\"------- 1\");\n            foreach (var eval in evals)\n            {\n                int txIdx = block1Txs.Select(\n                    (e, idx) => new { e, idx }).First(\n                    x => x.e.Id.Equals(eval.InputContext.TxId)).idx;\n                int actionIdx = block1Txs[txIdx].Actions.Select(\n                    (e, idx) => new { e, idx }).First(\n                    x => x.e.Equals(eval.Action.PlainValue)).idx;\n                string updatedStates = \"new[] { \" + string.Join(\", \", addresses.Select(\n                    eval.OutputState.GetAccount(ReservedAddresses.LegacyAccount).GetState)\n                    .Select(x => x is Text t ? '\"' + t.Value + '\"' : \"null\")) + \" }\";\n                string signerIdx = \"_txFx.Address\" + (addresses.Select(\n                    (e, idx) => new { e, idx }).First(\n                    x => x.e.Equals(eval.InputContext.Signer)).idx + 1);\n                System.Diagnostics.Trace.WriteLine(\n                    $\"({txIdx}, {actionIdx}, {updatedStates}, {signerIdx}),\");\n            }\n\n            System.Diagnostics.Trace.WriteLine(\"---------\");\n#endif // DEBUG\n\n            Assert.Equal(expectations.Length, evals.Length);\n            foreach (var (expect, eval) in expectations.Zip(evals, (x, y) => (x, y)))\n            {\n                Assert.Equal(\n                    expect.UpdatedStates,\n                    addresses.Select(\n                        eval.OutputState.GetAccount(ReservedAddresses.LegacyAccount).GetState)\n                        .Select(x => x is Text t ? t.Value : null));\n                Assert.Equal(block1Txs[expect.TxIdx].Id, eval.InputContext.TxId);\n                Assert.Equal(\n                    block1Txs[expect.TxIdx].Actions[expect.ActionIdx],\n                    eval.Action.PlainValue);\n                Assert.Equal(expect.Signer, eval.InputContext.Signer);\n                Assert.Equal(GenesisProposer.Address, eval.InputContext.Miner);\n                Assert.Equal(block1.Index, eval.InputContext.BlockIndex);\n            }\n\n            previousState = stateStore.GetWorld(genesis.StateRootHash);\n            ActionEvaluation[] evals1 =\n                actionEvaluator.EvaluateBlock(block1, previousState).ToArray();\n            var output1 = new WorldBaseState(evals1.Last().OutputState.Trie, stateStore);\n            Assert.Equal(\n                (Text)\"A\",\n                output1.GetAccountState(ReservedAddresses.LegacyAccount).GetState(addresses[0]));\n            Assert.Equal(\n                (Text)\"B\",\n                output1.GetAccountState(ReservedAddresses.LegacyAccount).GetState(addresses[1]));\n            Assert.Equal(\n                (Text)\"C\",\n                output1.GetAccountState(ReservedAddresses.LegacyAccount).GetState(addresses[2]));\n            Assert.Equal(\n                new FungibleAssetValue(DumbAction.DumbCurrency, 95, 0),\n                output1.GetBalance(addresses[0], DumbAction.DumbCurrency));\n            Assert.Equal(\n                new FungibleAssetValue(DumbAction.DumbCurrency, 100, 0),\n                output1.GetBalance(addresses[1], DumbAction.DumbCurrency));\n            Assert.Equal(\n                new FungibleAssetValue(DumbAction.DumbCurrency, 100, 0),\n                output1.GetBalance(addresses[2], DumbAction.DumbCurrency));\n            Assert.Equal(\n                new FungibleAssetValue(DumbAction.DumbCurrency, 105, 0),\n                output1.GetBalance(addresses[3], DumbAction.DumbCurrency));\n\n            Transaction[] block2Txs =\n            {\n                // Note that these timestamps in themselves does not have any meanings but are\n                // only arbitrary.  These purpose to make their evaluation order in a block\n                // equal to the order we (the test) intend:\n                new Transaction(\n                    new UnsignedTx(\n                        new TxInvoice(\n                            genesisHash: genesis.Hash,\n                            updatedAddresses: new[] { addresses[0] }.ToImmutableHashSet(),\n                            timestamp: DateTimeOffset.MinValue.AddSeconds(3),\n                            actions: new TxActionList(new[]\n                            {\n                                MakeAction(addresses[0], 'D'),\n                            }.ToPlainValues()),\n                            maxGasPrice: null,\n                            gasLimit: null),\n                        new TxSigningMetadata(_txFx.PrivateKey1.PublicKey, 0)),\n                    _txFx.PrivateKey1),\n                new Transaction(\n                    new UnsignedTx(\n                        new TxInvoice(\n                            genesisHash: genesis.Hash,\n                            updatedAddresses: new[] { addresses[3] }.ToImmutableHashSet(),\n                            timestamp: DateTimeOffset.MinValue.AddSeconds(2),\n                            actions: new TxActionList(new[]\n                            {\n                                MakeAction(addresses[3], 'E'),\n                            }.ToPlainValues()),\n                            maxGasPrice: null,\n                            gasLimit: null),\n                        new TxSigningMetadata(_txFx.PrivateKey2.PublicKey, 0)),\n                    _txFx.PrivateKey2),\n                new Transaction(\n                    new UnsignedTx(\n                        new TxInvoice(\n                            genesisHash: genesis.Hash,\n                            updatedAddresses: new[] { addresses[4] }.ToImmutableHashSet(),\n                            timestamp: DateTimeOffset.MinValue.AddSeconds(5),\n                            actions: new TxActionList(new[]\n                            {\n                                DumbAction.Create(\n                                    (addresses[4], \"F\"),\n                                    transfer: (addresses[0], addresses[4], 8)),\n                            }.ToPlainValues()),\n                            maxGasPrice: null,\n                            gasLimit: null),\n                        new TxSigningMetadata(_txFx.PrivateKey3.PublicKey, 0)),\n                    _txFx.PrivateKey3),\n            };\n            foreach ((var tx, var i) in block2Txs.Zip(\n                Enumerable.Range(0, block2Txs.Length), (x, y) => (x, y)))\n            {\n                _logger.Debug(\"{0}[{1}] = {2}\", nameof(block2Txs), i, tx.Id);\n            }\n\n            // Same as above, use the same timestamp of last commit for each to get a deterministic\n            // test result.\n            Block block2 = ProposeNextBlock(\n                block1,\n                GenesisProposer,\n                block2Txs,\n                lastCommit: CreateBlockCommit(block1, true));\n\n            // Forcefully reset to null delta\n            previousState = evals1.Last().OutputState;\n            evals = actionEvaluator.EvaluateBlock(\n                block2,\n                previousState).ToImmutableArray();\n\n            // Once the BlockMetadata.CurrentProtocolVersion gets bumped, expectations may also\n            // have to be updated, since the order may change due to different PreEvaluationHash.\n            expectations = new (int TxIdx, int ActionIdx, string[] UpdatedStates, Address Signer)[]\n            {\n                (0, 0, new[] { \"A,D\", \"B\", \"C\", null, null }, _txFx.Address1),\n                (2, 0, new[] { \"A,D\", \"B\", \"C\", null, \"F\" }, _txFx.Address3),\n                (1, 0, new[] { \"A,D\", \"B\", \"C\", \"E\", \"F\" }, _txFx.Address2),\n            };\n\n#if DEBUG\n            // This code was created by ilgyu.\n            // You can preview the result of the test in the debug console.\n            // If this test fails, you can copy the result from the debug console\n            // and paste it to the upper part of the test code.\n            System.Diagnostics.Trace.WriteLine(\"------- 2\");\n            foreach (var eval in evals)\n            {\n                int txIdx = block2Txs.Select(\n                    (e, idx) => new { e, idx }).First(\n                    x => x.e.Id.Equals(eval.InputContext.TxId)).idx;\n                int actionIdx = block2Txs[txIdx].Actions.Select(\n                    (e, idx) => new { e, idx }).First(\n                    x => x.e.Equals(eval.Action.PlainValue)).idx;\n                string updatedStates = \"new[] { \" + string.Join(\", \", addresses.Select(\n                    eval.OutputState.GetAccount(ReservedAddresses.LegacyAccount).GetState)\n                    .Select(x => x is Text t ? '\"' + t.Value + '\"' : \"null\")) + \" }\";\n                string signerIdx = \"_txFx.Address\" + (addresses.Select(\n                    (e, idx) => new { e, idx }).First(\n                    x => x.e.Equals(eval.InputContext.Signer)).idx + 1);\n                System.Diagnostics.Trace.WriteLine(\n                    $\"({txIdx}, {actionIdx}, {updatedStates}, {signerIdx}),\");\n            }\n\n            System.Diagnostics.Trace.WriteLine(\"---------\");\n#endif // DEBUG\n\n            Assert.Equal(expectations.Length, evals.Length);\n            foreach (var (expect, eval) in expectations.Zip(evals, (x, y) => (x, y)))\n            {\n                List<string> updatedStates = addresses\n                    .Select(eval.OutputState.GetAccount(ReservedAddresses.LegacyAccount).GetState)\n                    .Select(x => x is Text t ? t.Value : null)\n                    .ToList();\n                Assert.Equal(expect.UpdatedStates, updatedStates);\n                Assert.Equal(block2Txs[expect.TxIdx].Id, eval.InputContext.TxId);\n                Assert.Equal(\n                    block2Txs[expect.TxIdx].Actions[expect.ActionIdx],\n                    eval.Action.PlainValue);\n                Assert.Equal(expect.Signer, eval.InputContext.Signer);\n                Assert.Equal(GenesisProposer.Address, eval.InputContext.Miner);\n                Assert.Equal(block2.Index, eval.InputContext.BlockIndex);\n                Assert.Null(eval.Exception);\n            }\n\n            previousState = evals1.Last().OutputState;\n            var evals2 = actionEvaluator.EvaluateBlock(block2, previousState).ToArray();\n            var output2 = new WorldBaseState(evals2.Last().OutputState.Trie, stateStore);\n            Assert.Equal(\n                (Text)\"A,D\",\n                output2.GetAccountState(ReservedAddresses.LegacyAccount).GetState(addresses[0]));\n            Assert.Equal(\n                (Text)\"E\",\n                output2.GetAccountState(ReservedAddresses.LegacyAccount).GetState(addresses[3]));\n            Assert.Equal(\n                (Text)\"F\",\n                output2.GetAccountState(ReservedAddresses.LegacyAccount).GetState(addresses[4]));\n        }\n\n        [Fact]\n        public void EvaluateTx()\n        {\n            PrivateKey[] keys = { new PrivateKey(), new PrivateKey(), new PrivateKey() };\n            Address[] addresses = keys.Select(key => key.Address).ToArray();\n            DumbAction[] actions =\n            {\n                DumbAction.Create(\n                    append: (addresses[0], \"0\"),\n                    transfer: (addresses[0], addresses[1], 5)),\n                DumbAction.Create(\n                    append: (addresses[1], \"1\"),\n                    transfer: (addresses[2], addresses[1], 10)),\n                DumbAction.Create(\n                    append: (addresses[0], \"2\"),\n                    transfer: (addresses[1], addresses[0], 10)),\n                DumbAction.Create((addresses[2], \"R\")),\n            };\n            var tx =\n                Transaction.Create(0, _txFx.PrivateKey1, null, actions.ToPlainValues());\n            var txs = new Transaction[] { tx };\n            var evs = Array.Empty<EvidenceBase>();\n            var block = new BlockContent(\n                new BlockMetadata(\n                    index: 1L,\n                    timestamp: DateTimeOffset.UtcNow,\n                    publicKey: keys[0].PublicKey,\n                    previousHash: default(BlockHash),\n                    txHash: BlockContent.DeriveTxHash(txs),\n                    lastCommit: null,\n                    evidenceHash: null),\n                transactions: txs,\n                evidence: evs).Propose();\n            IStateStore stateStore = new TrieStateStore(new MemoryKeyValueStore());\n            IWorld world = new World(MockWorldState.CreateLegacy(stateStore)\n                .SetBalance(addresses[0], DumbAction.DumbCurrency * 100)\n                .SetBalance(addresses[1], DumbAction.DumbCurrency * 100)\n                .SetBalance(addresses[2], DumbAction.DumbCurrency * 100));\n            ITrie initTrie = stateStore.Commit(world.Trie);\n            var actionEvaluator = new ActionEvaluator(\n                new PolicyActionsRegistry(),\n                stateStore: stateStore,\n                actionTypeLoader: new SingleActionLoader(typeof(DumbAction)));\n\n            IWorld previousState = stateStore.GetWorld(initTrie.Hash);\n            var evaluations = actionEvaluator.EvaluateTx(\n                block: block,\n                tx: tx,\n                previousState: previousState).ToImmutableArray();\n\n            Assert.Equal(actions.Length, evaluations.Length);\n            string[][] expectedStates =\n            {\n                new[] { \"0\", null, null },\n                new[] { \"0\", \"1\", null },\n                new[] { \"0,2\", \"1\", null },\n                new[] { \"0,2\", \"1\", \"R\" },\n            };\n            BigInteger[][] expectedBalances =\n            {\n                new BigInteger[] { 95, 105, 100 },\n                new BigInteger[] { 95, 115, 90 },\n                new BigInteger[] { 105, 105, 90 },\n                new BigInteger[] { 105, 105, 90 },\n            };\n\n            Currency currency = DumbAction.DumbCurrency;\n            IValue[] initStates = new IValue[3];\n            BigInteger[] initBalances = new BigInteger[] { 100, 100, 100 };\n            for (int i = 0; i < evaluations.Length; i++)\n            {\n                IActionEvaluation eval = evaluations[i];\n                Assert.Equal(actions[i].PlainValue, eval.Action);\n                Assert.Equal(_txFx.Address1, eval.InputContext.Signer);\n                Assert.Equal(tx.Id, eval.InputContext.TxId);\n                Assert.Equal(addresses[0], eval.InputContext.Miner);\n                Assert.Equal(1, eval.InputContext.BlockIndex);\n                IActionEvaluation prevEval = i > 0 ? evaluations[i - 1] : null;\n                Assert.Equal(\n                    prevEval is null\n                        ? initStates\n                        : addresses.Select(\n                            prevEval.OutputState\n                                .GetAccount(ReservedAddresses.LegacyAccount)\n                                .GetState),\n                    addresses.Select(\n                        eval.InputContext.PreviousState\n                            .GetAccount(ReservedAddresses.LegacyAccount)\n                            .GetState));\n                Assert.Equal(\n                    expectedStates[i],\n                    addresses.Select(eval.OutputState\n                        .GetAccount(ReservedAddresses.LegacyAccount)\n                        .GetState)\n                        .Select(x => x is Text t ? t.Value : null));\n                Assert.Equal(\n                    prevEval is null\n                        ? initBalances\n                        : addresses.Select(a =>\n                            prevEval.OutputState\n                                .GetBalance(a, currency).RawValue),\n                    addresses.Select(\n                        a => eval.InputContext.PreviousState\n                                .GetBalance(a, currency).RawValue));\n                Assert.Equal(\n                    expectedBalances[i],\n                    addresses.Select(a => eval.OutputState\n                        .GetBalance(a, currency).RawValue));\n            }\n\n            previousState = stateStore.GetWorld(initTrie.Hash);\n            IWorld delta = actionEvaluator.EvaluateTx(\n                block: block,\n                tx: tx,\n                previousState: previousState).Last().OutputState;\n            Assert.Empty(evaluations[3].OutputState.Trie.Diff(delta.Trie));\n        }\n\n        [Fact]\n        public void EvaluateTxResultThrowingException()\n        {\n            var action = new ThrowException { ThrowOnExecution = true };\n            var tx = Transaction.Create(\n                0,\n                _txFx.PrivateKey1,\n                null,\n                new[] { action }.ToPlainValues(),\n                null,\n                null,\n                DateTimeOffset.UtcNow);\n            var txs = new Transaction[] { tx };\n            var evs = Array.Empty<EvidenceBase>();\n            var hash = new BlockHash(GetRandomBytes(BlockHash.Size));\n            IStateStore stateStore = new TrieStateStore(new MemoryKeyValueStore());\n            var actionEvaluator = new ActionEvaluator(\n                new PolicyActionsRegistry(),\n                stateStore: stateStore,\n                actionTypeLoader: new SingleActionLoader(typeof(ThrowException))\n            );\n            var block = new BlockContent(\n                new BlockMetadata(\n                    index: 123,\n                    timestamp: DateTimeOffset.UtcNow,\n                    publicKey: GenesisProposer.PublicKey,\n                    previousHash: hash,\n                    txHash: BlockContent.DeriveTxHash(txs),\n                    lastCommit: CreateBlockCommit(hash, 122, 0),\n                    evidenceHash: null),\n                transactions: txs,\n                evidence: evs).Propose();\n            IWorld previousState = stateStore.GetWorld(null);\n            var nextState = actionEvaluator.EvaluateTx(\n                block: block,\n                tx: tx,\n                previousState: previousState).Last().OutputState;\n\n            Assert.Empty(nextState.Trie.Diff(previousState.Trie));\n        }\n\n        [Fact]\n        public void EvaluateActions()\n        {\n            IntegerSet fx = new IntegerSet(new[] { 5, 10 });\n\n            // txA: ((5 + 1) * 2) + 3 = 15\n            (Transaction txA, var deltaA) = fx.Sign(\n                0,\n                Arithmetic.Add(1),\n                Arithmetic.Mul(2),\n                Arithmetic.Add(3));\n\n            Block blockA = fx.Propose();\n            fx.Append(blockA);\n            ActionEvaluation[] evalsA = ActionEvaluator.EvaluateActions(\n                block: blockA,\n                tx: txA,\n                previousState: fx.StateStore.GetWorld(blockA.StateRootHash),\n                actions: txA.Actions\n                    .Select(action => (IAction)ToAction<Arithmetic>(action))\n                    .ToImmutableArray(),\n                stateStore: fx.StateStore,\n                isPolicyAction: false).ToArray();\n\n            Assert.Equal(evalsA.Length, deltaA.Count - 1);\n            Assert.Equal(\n                new Integer(15),\n                evalsA.Last().OutputState\n                    .GetAccount(ReservedAddresses.LegacyAccount).GetState(txA.Signer));\n            Assert.All(evalsA, eval => Assert.Empty(eval.InputContext.Txs));\n\n            for (int i = 0; i < evalsA.Length; i++)\n            {\n                IActionEvaluation eval = evalsA[i];\n                IActionContext context = eval.InputContext;\n                IWorld prevState = context.PreviousState;\n                IWorld outputState = eval.OutputState;\n                _logger.Debug(\"evalsA[{0}] = {1}\", i, eval);\n                _logger.Debug(\"txA.Actions[{0}] = {1}\", i, txA.Actions[i]);\n\n                Assert.Equal(txA.Actions[i], eval.Action);\n                Assert.Equal(txA.Id, context.TxId);\n                Assert.Equal(blockA.Miner, context.Miner);\n                Assert.Equal(blockA.Index, context.BlockIndex);\n                Assert.Equal(txA.Signer, context.Signer);\n                Assert.False(context.IsPolicyAction);\n                Assert.Equal(\n                    (Integer)deltaA[i].Value,\n                    prevState.GetAccount(ReservedAddresses.LegacyAccount).GetState(txA.Signer));\n                Assert.Equal(\n                    ToStateKey(txA.Signer),\n                    Assert.Single(\n                        outputState.GetAccount(ReservedAddresses.LegacyAccount).Trie.Diff(\n                            prevState.GetAccount(ReservedAddresses.LegacyAccount).Trie))\n                    .Path);\n                Assert.Equal(\n                    (Integer)deltaA[i + 1].Value,\n                    outputState.GetAccount(ReservedAddresses.LegacyAccount).GetState(txA.Signer));\n                Assert.Null(eval.Exception);\n            }\n\n            // txB: error(10 - 3) + -1 =\n            //           (10 - 3) + -1 = 6  (error() does nothing)\n            (Transaction txB, var deltaB) = fx.Sign(\n                1,\n                Arithmetic.Sub(3),\n                new Arithmetic(),\n                Arithmetic.Add(-1));\n\n            Block blockB = fx.Propose();\n            fx.Append(blockB);\n            ActionEvaluation[] evalsB = ActionEvaluator.EvaluateActions(\n                block: blockB,\n                tx: txB,\n                previousState: fx.StateStore.GetWorld(blockB.StateRootHash),\n                actions: txB.Actions\n                    .Select(action => (IAction)ToAction<Arithmetic>(action))\n                    .ToImmutableArray(),\n                stateStore: fx.StateStore,\n                isPolicyAction: false).ToArray();\n\n            Assert.Equal(evalsB.Length, deltaB.Count - 1);\n            Assert.Equal(\n                new Integer(6),\n                evalsB.Last().OutputState\n                    .GetAccount(ReservedAddresses.LegacyAccount).GetState(txB.Signer));\n            Assert.All(evalsB, eval => Assert.Empty(eval.InputContext.Txs));\n\n            for (int i = 0; i < evalsB.Length; i++)\n            {\n                IActionEvaluation eval = evalsB[i];\n                IActionContext context = eval.InputContext;\n                IWorld prevState = context.PreviousState;\n                IWorld outputState = eval.OutputState;\n\n                _logger.Debug(\"evalsB[{0}] = {@1}\", i, eval);\n                _logger.Debug(\"txB.Actions[{0}] = {@1}\", i, txB.Actions[i]);\n\n                Assert.Equal(txB.Actions[i], eval.Action);\n                Assert.Equal(txB.Id, context.TxId);\n                Assert.Equal(blockB.Miner, context.Miner);\n                Assert.Equal(blockB.Index, context.BlockIndex);\n                Assert.Equal(txB.Signer, context.Signer);\n                Assert.False(context.IsPolicyAction);\n                Assert.Equal(\n                    (Integer)deltaB[i].Value,\n                    prevState.GetAccount(ReservedAddresses.LegacyAccount).GetState(txB.Signer));\n                Assert.Equal(\n                    (Integer)deltaB[i + 1].Value,\n                    outputState.GetAccount(ReservedAddresses.LegacyAccount).GetState(txB.Signer));\n                if (i == 1)\n                {\n                    Assert.Empty(outputState.Trie.Diff(prevState.Trie));\n                    Assert.IsType<UnexpectedlyTerminatedActionException>(eval.Exception);\n                    Assert.IsType<InvalidOperationException>(eval.Exception.InnerException);\n                }\n                else\n                {\n                    Assert.Equal(\n                        ToStateKey(txB.Signer),\n                        Assert.Single(\n                            outputState.GetAccount(ReservedAddresses.LegacyAccount).Trie.Diff(\n                                prevState.GetAccount(ReservedAddresses.LegacyAccount).Trie))\n                        .Path);\n                    Assert.Null(eval.Exception);\n                }\n            }\n        }\n\n        [Fact]\n        public void EvaluatePolicyBeginBlockActions()\n        {\n            var (chain, actionEvaluator) = MakeBlockChainAndActionEvaluator(\n                policy: _policy,\n                store: _storeFx.Store,\n                stateStore: _storeFx.StateStore,\n                actionLoader: new SingleActionLoader(typeof(DumbAction)),\n                genesisBlock: _storeFx.GenesisBlock,\n                privateKey: GenesisProposer);\n            (_, Transaction[] txs) = MakeFixturesForAppendTests();\n            var genesis = chain.Genesis;\n            var block = chain.ProposeBlock(\n                proposer: GenesisProposer,\n                transactions: txs.ToImmutableList(),\n                lastCommit: CreateBlockCommit(chain.Tip),\n                evidence: ImmutableArray<EvidenceBase>.Empty);\n\n            IWorld previousState = _storeFx.StateStore.GetWorld(null);\n            var evaluations = actionEvaluator.EvaluatePolicyBeginBlockActions(\n                genesis,\n                previousState);\n\n            Assert.Equal<IAction>(\n                chain.Policy.PolicyActionsRegistry.BeginBlockActions,\n                evaluations.Select(item => item.Action).ToImmutableArray());\n            Assert.Single(evaluations);\n            Assert.Equal(\n                (Integer)1,\n                (Integer)evaluations[0].OutputState\n                    .GetAccount(ReservedAddresses.LegacyAccount)\n                    .GetState(_beginBlockValueAddress));\n            Assert.True(evaluations[0].InputContext.IsPolicyAction);\n\n            previousState = evaluations[0].OutputState;\n            evaluations = actionEvaluator.EvaluatePolicyBeginBlockActions(\n                block,\n                previousState);\n\n            Assert.Equal<IAction>(\n                chain.Policy.PolicyActionsRegistry.BeginBlockActions,\n                evaluations.Select(item => item.Action).ToImmutableArray());\n            Assert.Single(evaluations);\n            Assert.Equal(\n                (Integer)2,\n                (Integer)evaluations[0].OutputState\n                    .GetAccount(ReservedAddresses.LegacyAccount)\n                    .GetState(_beginBlockValueAddress));\n            Assert.True(evaluations[0].InputContext.IsPolicyAction);\n        }\n\n        [Fact]\n        public void EvaluatePolicyEndBlockActions()\n        {\n            var (chain, actionEvaluator) = MakeBlockChainAndActionEvaluator(\n                policy: _policy,\n                store: _storeFx.Store,\n                stateStore: _storeFx.StateStore,\n                actionLoader: new SingleActionLoader(typeof(DumbAction)),\n                genesisBlock: _storeFx.GenesisBlock,\n                privateKey: GenesisProposer);\n            (_, Transaction[] txs) = MakeFixturesForAppendTests();\n            var genesis = chain.Genesis;\n            var block = chain.ProposeBlock(\n                GenesisProposer,\n                txs.ToImmutableList(),\n                CreateBlockCommit(chain.Tip),\n                ImmutableArray<EvidenceBase>.Empty);\n\n            IWorld previousState = _storeFx.StateStore.GetWorld(null);\n            var evaluations = actionEvaluator.EvaluatePolicyEndBlockActions(\n                genesis,\n                previousState);\n\n            Assert.Equal<IAction>(\n                chain.Policy.PolicyActionsRegistry.EndBlockActions,\n                evaluations.Select(item => item.Action).ToImmutableArray());\n            Assert.Single(evaluations);\n            Assert.Equal(\n                (Integer)1,\n                (Integer)evaluations[0].OutputState\n                    .GetAccount(ReservedAddresses.LegacyAccount)\n                    .GetState(_endBlockValueAddress));\n            Assert.True(evaluations[0].InputContext.IsPolicyAction);\n            Assert.Equal(genesis.Transactions, evaluations[0].InputContext.Txs);\n\n            previousState = evaluations[0].OutputState;\n            evaluations = actionEvaluator.EvaluatePolicyEndBlockActions(\n                block,\n                previousState);\n\n            Assert.Equal<IAction>(\n                chain.Policy.PolicyActionsRegistry.EndBlockActions,\n                evaluations.Select(item => item.Action).ToImmutableArray());\n            Assert.Single(evaluations);\n            Assert.Equal(\n                (Integer)2,\n                (Integer)evaluations[0].OutputState\n                    .GetAccount(ReservedAddresses.LegacyAccount)\n                    .GetState(_endBlockValueAddress));\n            Assert.True(evaluations[0].InputContext.IsPolicyAction);\n        }\n\n        [Fact]\n        public void EvaluatePolicyBeginTxActions()\n        {\n            var (chain, actionEvaluator) = MakeBlockChainAndActionEvaluator(\n                policy: _policy,\n                store: _storeFx.Store,\n                stateStore: _storeFx.StateStore,\n                actionLoader: new SingleActionLoader(typeof(DumbAction)),\n                genesisBlock: _storeFx.GenesisBlock,\n                privateKey: GenesisProposer);\n            (_, Transaction[] txs) = MakeFixturesForAppendTests();\n            var genesis = chain.Genesis;\n            var block = chain.ProposeBlock(\n                proposer: GenesisProposer,\n                transactions: txs.ToImmutableList(),\n                lastCommit: CreateBlockCommit(chain.Tip),\n                evidence: ImmutableArray<EvidenceBase>.Empty);\n\n            IWorld previousState = _storeFx.StateStore.GetWorld(null);\n            var evaluations = actionEvaluator.EvaluatePolicyBeginTxActions(\n                genesis,\n                txs[0],\n                previousState);\n\n            Assert.Equal<IAction>(\n                chain.Policy.PolicyActionsRegistry.BeginTxActions,\n                evaluations.Select(item => item.Action).ToImmutableArray());\n            Assert.Single(evaluations);\n            Assert.Equal(\n                (Integer)1,\n                (Integer)evaluations[0].OutputState\n                    .GetAccount(ReservedAddresses.LegacyAccount)\n                    .GetState(_beginTxValueAddress));\n            Assert.Equal(txs[0].Signer, evaluations[0].InputContext.Signer);\n            Assert.True(evaluations[0].InputContext.IsPolicyAction);\n\n            previousState = evaluations[0].OutputState;\n            evaluations = actionEvaluator.EvaluatePolicyBeginTxActions(\n                block,\n                txs[1],\n                previousState);\n\n            Assert.Equal<IAction>(\n                chain.Policy.PolicyActionsRegistry.BeginTxActions,\n                evaluations.Select(item => item.Action).ToImmutableArray());\n            Assert.Single(evaluations);\n            Assert.Equal(\n                (Integer)2,\n                (Integer)evaluations[0].OutputState\n                    .GetAccount(ReservedAddresses.LegacyAccount)\n                    .GetState(_beginTxValueAddress));\n            Assert.Equal(txs[1].Signer, evaluations[0].InputContext.Signer);\n            Assert.True(evaluations[0].InputContext.IsPolicyAction);\n        }\n\n        [Fact]\n        public void EvaluatePolicyEndTxActions()\n        {\n            var (chain, actionEvaluator) = MakeBlockChainAndActionEvaluator(\n                policy: _policy,\n                store: _storeFx.Store,\n                stateStore: _storeFx.StateStore,\n                actionLoader: new SingleActionLoader(typeof(DumbAction)),\n                genesisBlock: _storeFx.GenesisBlock,\n                privateKey: GenesisProposer);\n            (_, Transaction[] txs) = MakeFixturesForAppendTests();\n            var genesis = chain.Genesis;\n            var block = chain.ProposeBlock(\n                proposer: GenesisProposer,\n                transactions: txs.ToImmutableList(),\n                lastCommit: CreateBlockCommit(chain.Tip),\n                evidence: ImmutableArray<EvidenceBase>.Empty);\n\n            IWorld previousState = _storeFx.StateStore.GetWorld(null);\n            var evaluations = actionEvaluator.EvaluatePolicyEndTxActions(\n                genesis,\n                txs[0],\n                previousState);\n\n            Assert.Equal<IAction>(\n                chain.Policy.PolicyActionsRegistry.EndTxActions,\n                evaluations.Select(item => item.Action).ToImmutableArray());\n            Assert.Single(evaluations);\n            Assert.Equal(\n                (Integer)1,\n                (Integer)evaluations[0].OutputState\n                    .GetAccount(ReservedAddresses.LegacyAccount)\n                    .GetState(_endTxValueAddress));\n            Assert.Equal(txs[0].Signer, evaluations[0].InputContext.Signer);\n            Assert.True(evaluations[0].InputContext.IsPolicyAction);\n\n            previousState = evaluations[0].OutputState;\n            evaluations = actionEvaluator.EvaluatePolicyEndTxActions(\n                block,\n                txs[1],\n                previousState);\n\n            Assert.Equal<IAction>(\n                chain.Policy.PolicyActionsRegistry.EndTxActions,\n                evaluations.Select(item => item.Action).ToImmutableArray());\n            Assert.Single(evaluations);\n            Assert.Equal(\n                (Integer)2,\n                (Integer)evaluations[0].OutputState\n                    .GetAccount(ReservedAddresses.LegacyAccount)\n                    .GetState(_endTxValueAddress));\n            Assert.Equal(txs[1].Signer, evaluations[0].InputContext.Signer);\n            Assert.True(evaluations[0].InputContext.IsPolicyAction);\n            Assert.Equal(block.Transactions, evaluations[0].InputContext.Txs);\n        }\n\n        [Theory]\n        [ClassData(typeof(OrderTxsForEvaluationData))]\n        public void OrderTxsForEvaluation(\n            int protocolVersion,\n            List<string> originalAddresses,\n            List<string> orderedAddresses)\n        {\n            const int numSigners = 5;\n            const int numTxsPerSigner = 3;\n            var epoch = DateTimeOffset.FromUnixTimeSeconds(0);\n\n            TxFixture txFx = new BlockFixture().TxFixture;\n            ImmutableArray<PrivateKey> signers = ImmutableArray.Create(\n                txFx.PrivateKey1,\n                txFx.PrivateKey2,\n                txFx.PrivateKey3,\n                txFx.PrivateKey4,\n                txFx.PrivateKey5\n            );\n            ImmutableArray<ImmutableArray<int>> noncesPerSigner = ImmutableArray.Create(\n                ImmutableArray.Create(0, 2, 1),\n                ImmutableArray.Create(1, 0, 2),\n                ImmutableArray.Create(1, 2, 0),\n                ImmutableArray.Create(2, 0, 1),\n                ImmutableArray.Create(2, 1, 0)\n            );\n            // Unix Epoch used for hard coded timestamp.\n            ImmutableArray<Transaction> txs =\n                signers.Zip(noncesPerSigner, (signer, nonces) => (signer, nonces))\n                    .SelectMany(\n                        signerNoncesPair => signerNoncesPair.nonces,\n                        (signerNoncesPair, nonce) => (signerNoncesPair.signer, nonce))\n                    .Select(signerNoncePair =>\n                    {\n                        Address targetAddress = signerNoncePair.signer.Address;\n                        return new Transaction(\n                            new UnsignedTx(\n                                new TxInvoice(\n                                    genesisHash: null,\n                                    updatedAddresses: ImmutableHashSet.Create(targetAddress),\n                                    timestamp: epoch,\n                                    actions: new TxActionList(new[]\n                                    {\n                                        new ContextRecordingAction(\n                                            signerNoncePair.signer.Address,\n                                            new Integer(signerNoncePair.nonce)),\n                                    }.ToPlainValues()),\n                                    maxGasPrice: null,\n                                    gasLimit: null),\n                                new TxSigningMetadata(\n                                    signerNoncePair.signer.PublicKey,\n                                    signerNoncePair.nonce)),\n                            signerNoncePair.signer);\n                    }).ToImmutableArray();\n\n            // Rearrange transactions so that transactions are not grouped by signers\n            // while keeping the hard coded mixed order nonces above.\n            txs = txs\n                .Where((tx, i) => i % numTxsPerSigner == 0)\n                .Concat(txs.Where((tx, i) => i % numTxsPerSigner != 0)).ToImmutableArray();\n\n            // FIXME: Invalid length for PreEvaluationHash.\n            byte[] preEvaluationHashBytes =\n            {\n                0x45, 0xa2, 0x21, 0x87, 0xe2, 0xd8, 0x85, 0x0b, 0xb3, 0x57,\n                0x88, 0x69, 0x58, 0xbc, 0x3e, 0x85, 0x60, 0x92, 0x9c, 0xcc,\n            };\n\n            // Sanity check.\n            Assert.True(originalAddresses.SequenceEqual(\n                signers.Select(signer => signer.Address.ToString())));\n\n            var orderedTxs = ActionEvaluator.OrderTxsForEvaluation(\n                protocolVersion: protocolVersion,\n                txs: txs,\n                preEvaluationHashBytes: preEvaluationHashBytes.ToImmutableArray()\n            ).ToImmutableArray();\n\n            // Check signers are grouped together.\n            for (int i = 0; i < numSigners; i++)\n            {\n                var signerTxs = orderedTxs.Skip(i * numTxsPerSigner).Take(numTxsPerSigner);\n                Assert.True(signerTxs.Select(tx => tx.Signer).Distinct().Count() == 1);\n            }\n\n            // Check nonces are ordered.\n            foreach (var signer in signers)\n            {\n                var signerTxs = orderedTxs.Where(tx => tx.Signer == signer.Address);\n                Assert.Equal(signerTxs.OrderBy(tx => tx.Nonce).ToArray(), signerTxs.ToArray());\n            }\n\n            // Check according to spec.\n            Assert.True(orderedAddresses.SequenceEqual(\n                orderedTxs\n                    .Where((tx, i) => i % numTxsPerSigner == 0)\n                    .Select(tx => tx.Signer.ToString())));\n        }\n\n        [Fact]\n        public void EvaluateActionAndCollectFee()\n        {\n            var privateKey = new PrivateKey();\n            var address = privateKey.Address;\n            Currency foo = Currency.Uncapped(\n                \"FOO\",\n                18,\n                null\n            );\n\n            var freeGasAction = new UseGasAction()\n            {\n                GasUsage = 0,\n                Memo = \"FREE\",\n                MintValue = FungibleAssetValue.FromRawValue(foo, 10),\n                Receiver = address,\n            };\n\n            var payGasAction = new UseGasAction()\n            {\n                GasUsage = 1,\n                Memo = \"CHARGE\",\n            };\n\n            var store = new MemoryStore();\n            var stateStore = new TrieStateStore(new MemoryKeyValueStore());\n            var chain = TestUtils.MakeBlockChain(\n                policy: new BlockPolicy(),\n                actions: new[] { freeGasAction, },\n                store: store,\n                stateStore: stateStore,\n                actionLoader: new SingleActionLoader(typeof(UseGasAction)));\n            var tx = Transaction.Create(\n                nonce: 0,\n                privateKey: privateKey,\n                genesisHash: chain.Genesis.Hash,\n                maxGasPrice: FungibleAssetValue.FromRawValue(foo, 1),\n                gasLimit: 3,\n                actions: new[]\n                {\n                    payGasAction,\n                }.ToPlainValues());\n\n            chain.StageTransaction(tx);\n            var miner = new PrivateKey();\n            Block block = chain.ProposeBlock(miner);\n\n            var evaluations = chain.ActionEvaluator.Evaluate(\n                block, chain.GetNextStateRootHash((BlockHash)block.PreviousHash));\n\n            Assert.False(evaluations[0].InputContext.IsPolicyAction);\n            Assert.Single(evaluations);\n            Assert.Null(evaluations.Single().Exception);\n            Assert.Equal(2, GasTracer.GasAvailable);\n            Assert.Equal(1, GasTracer.GasUsed);\n        }\n\n        [Fact]\n        public void EvaluateThrowingExceedGasLimit()\n        {\n            var privateKey = new PrivateKey();\n            var address = privateKey.Address;\n            Currency foo = Currency.Uncapped(\n                \"FOO\",\n                18,\n                null\n            );\n\n            var freeGasAction = new UseGasAction()\n            {\n                GasUsage = 0,\n                Memo = \"FREE\",\n                MintValue = FungibleAssetValue.FromRawValue(foo, 10),\n                Receiver = address,\n            };\n\n            var payGasAction = new UseGasAction()\n            {\n                GasUsage = 10,\n                Memo = \"CHARGE\",\n            };\n\n            var store = new MemoryStore();\n            var stateStore = new TrieStateStore(new MemoryKeyValueStore());\n            var chain = TestUtils.MakeBlockChain(\n                policy: new BlockPolicy(),\n                actions: new[]\n                {\n                    freeGasAction,\n                },\n                store: store,\n                stateStore: stateStore,\n                actionLoader: new SingleActionLoader(typeof(UseGasAction)));\n            var tx = Transaction.Create(\n                nonce: 0,\n                privateKey: privateKey,\n                genesisHash: chain.Genesis.Hash,\n                maxGasPrice: FungibleAssetValue.FromRawValue(foo, 1),\n                gasLimit: 5,\n                actions: new[]\n                {\n                    payGasAction,\n                }.ToPlainValues());\n\n            chain.StageTransaction(tx);\n            var miner = new PrivateKey();\n            Block block = chain.ProposeBlock(miner);\n\n            var evaluations = chain.ActionEvaluator.Evaluate(\n                block,\n                chain.GetNextStateRootHash((BlockHash)block.PreviousHash));\n\n            Assert.False(evaluations[0].InputContext.IsPolicyAction);\n            Assert.Single(evaluations);\n            Assert.NotNull(evaluations.Single().Exception);\n            Assert.NotNull(evaluations.Single().Exception?.InnerException);\n            Assert.Equal(\n                typeof(GasLimitExceededException),\n                evaluations.Single().Exception?.InnerException?.GetType());\n            Assert.Equal(0, GasTracer.GasAvailable);\n            Assert.Equal(5, GasTracer.GasUsed);\n        }\n\n        [Fact]\n        public void GenerateRandomSeed()\n        {\n            byte[] preEvaluationHashBytes =\n            {\n                0x45, 0xa2, 0x21, 0x87, 0xe2, 0xd8, 0x85, 0x0b, 0xb3, 0x57,\n                0x88, 0x69, 0x58, 0xbc, 0x3e, 0x85, 0x60, 0x92, 0x9c, 0xcc,\n            };\n            byte[] signature =\n            {\n                0x30, 0x44, 0x02, 0x20, 0x2f, 0x2d, 0xbe, 0x5a, 0x91, 0x65, 0x59, 0xde, 0xdb,\n                0xe8, 0xd8, 0x4f, 0xa9, 0x20, 0xe2, 0x01, 0x29, 0x4d, 0x4f, 0x40, 0xea, 0x1e,\n                0x97, 0x44, 0x1f, 0xbf, 0xa2, 0x5c, 0x8b, 0xd0, 0x0e, 0x23, 0x02, 0x20, 0x3c,\n                0x06, 0x02, 0x1f, 0xb8, 0x3f, 0x67, 0x49, 0x92, 0x3c, 0x07, 0x59, 0x67, 0x96,\n                0xa8, 0x63, 0x04, 0xb0, 0xc3, 0xfe, 0xbb, 0x6c, 0x7a, 0x7b, 0x58, 0x58, 0xe9,\n                0x7d, 0x37, 0x67, 0xe1, 0xe9,\n            };\n\n            int seed = ActionEvaluator.GenerateRandomSeed(preEvaluationHashBytes, signature, 0);\n            Assert.Equal(353767086, seed);\n            seed = ActionEvaluator.GenerateRandomSeed(preEvaluationHashBytes, signature, 1);\n            Assert.Equal(353767087, seed);\n        }\n\n        [Fact]\n        public void CheckRandomSeedInAction()\n        {\n            IntegerSet fx = new IntegerSet(new[] { 5, 10 });\n\n            // txA: ((5 + 1) * 2) + 3 = 15\n            (Transaction txA, var deltaA) = fx.Sign(\n                0,\n                Arithmetic.Add(1),\n                Arithmetic.Mul(2),\n                Arithmetic.Add(3));\n\n            Block blockA = fx.Propose();\n            ActionEvaluation[] evalsA = ActionEvaluator.EvaluateActions(\n                block: blockA,\n                tx: txA,\n                previousState: fx.StateStore.GetWorld(blockA.StateRootHash),\n                actions: txA.Actions\n                    .Select(action => (IAction)ToAction<Arithmetic>(action))\n                    .ToImmutableArray(),\n                stateStore: fx.StateStore,\n                isPolicyAction: false).ToArray();\n\n            byte[] preEvaluationHashBytes = blockA.PreEvaluationHash.ToByteArray();\n            int[] randomSeeds = Enumerable\n                .Range(0, txA.Actions.Count)\n                .Select(offset => ActionEvaluator.GenerateRandomSeed(\n                    preEvaluationHashBytes,\n                    txA.Signature,\n                    offset))\n                .ToArray();\n\n            for (int i = 0; i < evalsA.Length; i++)\n            {\n                IActionEvaluation eval = evalsA[i];\n                IActionContext context = eval.InputContext;\n                Assert.Equal(randomSeeds[i], context.RandomSeed);\n            }\n        }\n\n        [Fact]\n        public void BlockProtocolVersionNotSupported()\n        {\n            Block block = BlockMarshaler.UnmarshalBlock(LegacyBlocks.BencodedV1Block);\n            var actionEvaluator = new ActionEvaluator(\n                new PolicyActionsRegistry(),\n                new TrieStateStore(new MemoryKeyValueStore()),\n                new SingleActionLoader(typeof(DumbAction)));\n            Assert.Throws<BlockProtocolVersionNotSupportedException>(\n                () => actionEvaluator.Evaluate(block, null));\n        }\n\n        private (Address[], Transaction[]) MakeFixturesForAppendTests(\n            PrivateKey privateKey = null,\n            DateTimeOffset epoch = default)\n        {\n            Address[] addresses =\n            {\n                _storeFx.Address1,\n                _storeFx.Address2,\n                _storeFx.Address3,\n                _storeFx.Address4,\n                _storeFx.Address5,\n            };\n\n            privateKey = privateKey ?? new PrivateKey(new byte[]\n            {\n                0xa8, 0x21, 0xc7, 0xc2, 0x08, 0xa9, 0x1e, 0x53, 0xbb, 0xb2,\n                0x71, 0x15, 0xf4, 0x23, 0x5d, 0x82, 0x33, 0x44, 0xd1, 0x16,\n                0x82, 0x04, 0x13, 0xb6, 0x30, 0xe7, 0x96, 0x4f, 0x22, 0xe0,\n                0xec, 0xe0,\n            });\n\n            Transaction[] txs =\n            {\n                _storeFx.MakeTransaction(\n                    new[]\n                    {\n                        DumbAction.Create((addresses[0], \"foo\")),\n                        DumbAction.Create((addresses[1], \"bar\")),\n                    },\n                    timestamp: epoch,\n                    nonce: 0,\n                    privateKey: privateKey),\n                _storeFx.MakeTransaction(\n                    new[]\n                    {\n                        DumbAction.Create((addresses[2], \"baz\")),\n                        DumbAction.Create((addresses[3], \"qux\")),\n                    },\n                    timestamp: epoch.AddSeconds(5),\n                    nonce: 1,\n                    privateKey: privateKey),\n            };\n\n            return (addresses, txs);\n        }\n\n        private sealed class ModernAction : IAction\n        {\n            public static readonly Address AccountAddress\n                = new Address(\"1230000000000000000000000000000000000000\");\n\n            public static readonly Address Address\n                = new Address(\"1234000000000000000000000000000000000000\");\n\n            public string Memo { get; set; }\n\n            public IValue PlainValue => new List((Text)Memo);\n\n            public void LoadPlainValue(IValue plainValue)\n            {\n                var asList = (List)plainValue;\n                Memo = ((Text)asList[0]).Value;\n            }\n\n            public IWorld Execute(IActionContext context)\n            {\n                return context.PreviousState\n                    .SetAccount(\n                        AccountAddress,\n                        context.PreviousState.GetAccount(AccountAddress)\n                            .SetState(Address, (Text)Memo));\n            }\n        }\n\n        private sealed class UseGasAction : IAction\n        {\n            public long GasUsage { get; set; }\n\n            public string Memo { get; set; }\n\n            public FungibleAssetValue? MintValue { get; set; }\n\n            public Address? Receiver { get; set; }\n\n            public IValue PlainValue => new List(\n                (Integer)GasUsage,\n                (Text)Memo,\n                MintValue is null ? (IValue)default(Null) : MintValue.Value.Serialize(),\n                Receiver is null ? (IValue)default(Null) : (IValue)(Binary)Receiver.Value.ByteArray\n                );\n\n            public void LoadPlainValue(IValue plainValue)\n            {\n                var asList = (List)plainValue;\n                GasUsage = (Bencodex.Types.Integer)asList[0];\n                Memo = (Text)asList[1];\n                if (!(asList[2] is Bencodex.Types.Null))\n                {\n                    MintValue = new FungibleAssetValue(asList[2]);\n                }\n\n                if (!(asList[3] is Bencodex.Types.Null))\n                {\n                    Receiver = new Address(asList[3]);\n                }\n            }\n\n            public IWorld Execute(IActionContext context)\n            {\n                GasTracer.UseGas(GasUsage);\n                var state = context.PreviousState\n                    .SetAccount(\n                        ReservedAddresses.LegacyAccount,\n                        context.PreviousState.GetAccount(ReservedAddresses.LegacyAccount)\n                            .SetState(context.Signer, (Text)Memo));\n                if (!(Receiver is null) && !(MintValue is null))\n                {\n                    state = state.MintAsset(context, Receiver.Value, MintValue.Value);\n                }\n\n                return state;\n            }\n        }\n    }\n\n#pragma warning disable SA1402 // File may only contain a single type\n    internal class OrderTxsForEvaluationData : IEnumerable<object[]>\n    {\n        // For fixture sanity.\n        public List<string> OriginalAddresses = new List<string>\n        {\n            \"0xc2A86014073D662a4a9bFCF9CB54263dfa4F5cBc\",\n            \"0x921Ba81C0be280C8A2faed79E14aD2a098874759\",\n            \"0x1d2B31bF9A2CA71051f8c66E1C783Ae70EF32798\",\n            \"0xfcbfa4977B2Fc7A608E4Bd2F6F0D6b27C0a4cd13\",\n            \"0xB0ea0018Ab647418FA81c384194C9167e6A3C925\",\n        };\n\n        // Spec for protocol version < 3.\n        public List<string> OrderedAddressesV0 = new List<string>\n        {\n            \"0xB0ea0018Ab647418FA81c384194C9167e6A3C925\",\n            \"0x1d2B31bF9A2CA71051f8c66E1C783Ae70EF32798\",\n            \"0xfcbfa4977B2Fc7A608E4Bd2F6F0D6b27C0a4cd13\",\n            \"0xc2A86014073D662a4a9bFCF9CB54263dfa4F5cBc\",\n            \"0x921Ba81C0be280C8A2faed79E14aD2a098874759\",\n        };\n\n        // Spec for protocol version >= 3.\n        public List<string> OrderedAddressesV3 = new List<string>\n        {\n            \"0x921Ba81C0be280C8A2faed79E14aD2a098874759\",\n            \"0xB0ea0018Ab647418FA81c384194C9167e6A3C925\",\n            \"0xc2A86014073D662a4a9bFCF9CB54263dfa4F5cBc\",\n            \"0xfcbfa4977B2Fc7A608E4Bd2F6F0D6b27C0a4cd13\",\n            \"0x1d2B31bF9A2CA71051f8c66E1C783Ae70EF32798\",\n        };\n\n        public IEnumerator<object[]> GetEnumerator()\n        {\n            yield return new object[]\n            {\n                0,\n                OriginalAddresses,\n                OrderedAddressesV0,\n            };\n            yield return new object[]\n            {\n                3,\n                OriginalAddresses,\n                OrderedAddressesV3,\n            };\n            yield return new object[]\n            {\n                BlockMetadata.CurrentProtocolVersion,\n                OriginalAddresses,\n                OrderedAddressesV3,\n            };\n        }\n\n        IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();\n    }\n#pragma warning restore SA1402\n}\n"
  },
  {
    "path": "test/Libplanet.Tests/Action/WorldTest.cs",
    "content": "using System;\nusing System.Linq;\nusing System.Numerics;\nusing Libplanet.Action;\nusing Libplanet.Action.Loader;\nusing Libplanet.Action.State;\nusing Libplanet.Action.Tests;\nusing Libplanet.Action.Tests.Common;\nusing Libplanet.Blockchain;\nusing Libplanet.Blockchain.Policies;\nusing Libplanet.Crypto;\nusing Libplanet.Mocks;\nusing Libplanet.Store;\nusing Libplanet.Store.Trie;\nusing Libplanet.Types.Assets;\nusing Libplanet.Types.Blocks;\nusing Libplanet.Types.Consensus;\nusing Libplanet.Types.Tx;\nusing Xunit;\nusing Xunit.Abstractions;\n\nnamespace Libplanet.Tests.Action\n{\n    public abstract class WorldTest\n    {\n        protected readonly PrivateKey[] _keys;\n\n        /// <summary>\n        /// A list of <see cref=\"Address\"/>es used for testing derived from <c>_keys</c>.\n        /// </summary>\n        protected readonly Address[] _addr;\n\n        /// <summary>\n        /// A list of <see cref=\"Currency\"><c>Currencies</c></see> used for testing:\n        /// <list type=\"bullet\">\n        ///     <item><description>\n        ///         <c>_currencies[0]</c>: Legacy AAA with no minters.\n        ///     </description></item>\n        ///     <item><description>\n        ///         <c>_currencies[1]</c>: Legacy BBB with two decimal places and no minters.\n        ///     </description></item>\n        ///     <item><description>\n        ///         <c>_currencies[2]</c>: Legacy CCC with <c>_addresses[0]</c> as its minter.\n        ///     </description></item>\n        ///     <item><description>\n        ///         <c>_currencies[3]</c>: Legacy DDD with <c>_addresses[0]</c>\n        ///         and <c>_addresses[1]</c> as its minters.\n        ///     </description></item>\n        ///     <item><description>\n        ///         <c>_currencies[3]</c>: Uncapped EEE with <c>_addresses[0]</c> as its minter.\n        ///     </description></item>\n        ///     <item><description>\n        ///         <c>_currencies[4]</c>: Capped FFF with <c>_addresses[0]</c> as its minter.\n        ///     </description></item>\n        /// </list>\n        /// Unless explicitly specified, each <see cref=\"Currency\"/> has zero decimal places.\n        /// </summary>\n        protected readonly Currency[] _currencies;\n\n        /// <summary>\n        /// An initial <see cref=\"IWorld\"/> state set up for testing:\n        /// <list type=\"bullet\">\n        ///     <item><description>\n        ///         <c>_addresses[0]</c>: Has 5 AAA, 10 CCC, 5 EEE.\n        ///     </description></item>\n        ///     <item><description>\n        ///         <c>_addresses[1]</c>: Has 15 CCC, 20 DDD.\n        ///     </description></item>\n        ///     <item><description>\n        ///         Validators: Each address is a validator of power 1.\n        ///     </description></item>\n        /// </list>\n        /// </summary>\n        protected readonly IWorld _initWorld;\n        protected readonly IActionContext _initContext;\n\n        protected WorldTest(ITestOutputHelper output)\n        {\n            _keys = new[]\n            {\n                Currencies.MinterAKey,\n                Currencies.MinterBKey,\n                new PrivateKey(),\n                new PrivateKey(),\n            };\n\n            _addr = _keys.Select(key => key.Address).ToArray();\n\n            _currencies = new[]\n            {\n                Currencies.CurrencyA,\n                Currencies.CurrencyB,\n                Currencies.CurrencyC,\n                Currencies.CurrencyD,\n                Currencies.CurrencyE,\n                Currencies.CurrencyF,\n            };\n\n            MockWorldState initMockWorldState =\n                ProtocolVersion >= BlockMetadata.WorldStateProtocolVersion\n                    ? MockWorldState.CreateModern(version: ProtocolVersion)\n                    : MockWorldState.CreateLegacy();\n            _initWorld = new World(initMockWorldState\n                .SetBalance(_addr[0], _currencies[0], 5)\n                .SetBalance(_addr[0], _currencies[2], 10)\n                .SetBalance(_addr[0], _currencies[4], 5)\n                .SetBalance(_addr[1], _currencies[2], 15)\n                .SetBalance(_addr[1], _currencies[3], 20)\n                .SetValidatorSet(new ValidatorSet(_keys\n                    .Select(key => new Validator(key.PublicKey, 1))\n                    .ToList())));\n\n            output.WriteLine(\"Fixtures  Address\");\n            int i = 0;\n            foreach (Address address in _addr)\n            {\n                output.WriteLine(\n                    \"_addr[{0}]  {1}  {2,6}  {3,6}  {4,6}  {5,6}  {6,6}  {7,6}\",\n                    i++,\n                    address,\n                    _initWorld.GetBalance(address, _currencies[0]),\n                    _initWorld.GetBalance(address, _currencies[1]),\n                    _initWorld.GetBalance(address, _currencies[2]),\n                    _initWorld.GetBalance(address, _currencies[3]),\n                    _initWorld.GetBalance(address, _currencies[4]),\n                    _initWorld.GetBalance(address, _currencies[5]));\n            }\n\n            output.WriteLine(\"Validators: {0}\", _initWorld.GetValidatorSet());\n\n            _initContext = CreateContext(_initWorld, _addr[0]);\n        }\n\n        public abstract int ProtocolVersion { get; }\n\n        public IActionContext CreateContext(IWorld world, Address signer)\n        {\n            return new ActionContext(\n                signer,\n                null,\n                signer,\n                0,\n                ProtocolVersion,\n                null,\n                world,\n                0,\n                false,\n                null);\n        }\n\n        [Fact]\n        public void InitialSetup()\n        {\n            // All non-zero balances.\n            Assert.Equal(Value(0, 5), _initWorld.GetBalance(_addr[0], _currencies[0]));\n            Assert.Equal(Value(2, 10), _initWorld.GetBalance(_addr[0], _currencies[2]));\n            Assert.Equal(Value(4, 5), _initWorld.GetBalance(_addr[0], _currencies[4]));\n            Assert.Equal(Value(2, 15), _initWorld.GetBalance(_addr[1], _currencies[2]));\n            Assert.Equal(Value(3, 20), _initWorld.GetBalance(_addr[1], _currencies[3]));\n\n            // Exhaustive check for the rest.\n            Assert.Equal(Value(1, 0), _initWorld.GetBalance(_addr[0], _currencies[1]));\n            Assert.Equal(Value(3, 0), _initWorld.GetBalance(_addr[0], _currencies[3]));\n            Assert.Equal(Value(5, 0), _initWorld.GetBalance(_addr[0], _currencies[5]));\n\n            Assert.Equal(Value(0, 0), _initWorld.GetBalance(_addr[1], _currencies[0]));\n            Assert.Equal(Value(1, 0), _initWorld.GetBalance(_addr[1], _currencies[1]));\n            Assert.Equal(Value(4, 0), _initWorld.GetBalance(_addr[1], _currencies[4]));\n            Assert.Equal(Value(5, 0), _initWorld.GetBalance(_addr[1], _currencies[5]));\n\n            Assert.Equal(Value(0, 0), _initWorld.GetBalance(_addr[2], _currencies[0]));\n            Assert.Equal(Value(1, 0), _initWorld.GetBalance(_addr[2], _currencies[1]));\n            Assert.Equal(Value(2, 0), _initWorld.GetBalance(_addr[2], _currencies[2]));\n            Assert.Equal(Value(3, 0), _initWorld.GetBalance(_addr[2], _currencies[3]));\n            Assert.Equal(Value(4, 0), _initWorld.GetBalance(_addr[2], _currencies[4]));\n            Assert.Equal(Value(5, 0), _initWorld.GetBalance(_addr[2], _currencies[5]));\n\n            Assert.Equal(Value(0, 0), _initWorld.GetBalance(_addr[3], _currencies[0]));\n            Assert.Equal(Value(1, 0), _initWorld.GetBalance(_addr[3], _currencies[1]));\n            Assert.Equal(Value(2, 0), _initWorld.GetBalance(_addr[3], _currencies[2]));\n            Assert.Equal(Value(3, 0), _initWorld.GetBalance(_addr[3], _currencies[3]));\n            Assert.Equal(Value(4, 0), _initWorld.GetBalance(_addr[3], _currencies[4]));\n            Assert.Equal(Value(5, 0), _initWorld.GetBalance(_addr[3], _currencies[5]));\n        }\n\n        [Fact]\n        public virtual void FungibleAssets()\n        {\n            IWorld world = _initWorld.TransferAsset(\n                _initContext, _addr[1], _addr[2], Value(3, 5));\n            Assert.Equal(Value(0, 5), world.GetBalance(_addr[0], _currencies[0]));\n            Assert.Equal(Value(2, 10), world.GetBalance(_addr[0], _currencies[2]));\n            Assert.Equal(Value(4, 5), world.GetBalance(_addr[0], _currencies[4]));\n            Assert.Equal(Value(2, 15), world.GetBalance(_addr[1], _currencies[2]));\n            Assert.Equal(Value(3, 15), world.GetBalance(_addr[1], _currencies[3]));\n            Assert.Equal(Value(3, 5), world.GetBalance(_addr[2], _currencies[3]));\n\n            var accountDiff = AccountDiff.Create(\n                _initContext.PreviousState.GetAccount(ReservedAddresses.LegacyAccount).Trie,\n                world.GetAccount(ReservedAddresses.LegacyAccount).Trie);\n            Assert.Empty(accountDiff.StateDiffs);\n        }\n\n        [Fact]\n        public void TransferAsset()\n        {\n            Assert.Throws<ArgumentOutOfRangeException>(() =>\n                _initWorld.TransferAsset(_initContext, _addr[0], _addr[1], Value(0, 0)));\n            Assert.Throws<ArgumentOutOfRangeException>(() =>\n                _initWorld.TransferAsset(_initContext, _addr[0], _addr[1], Value(0, -1)));\n            Assert.Throws<InsufficientBalanceException>(() =>\n                _initWorld.TransferAsset(_initContext, _addr[0], _addr[1], Value(0, 6)));\n\n            IWorld world = _initWorld.TransferAsset(_initContext, _addr[0], _addr[1], Value(0, 4));\n            Assert.Equal(Value(0, 1), world.GetBalance(_addr[0], _currencies[0]));\n            Assert.Equal(Value(0, 4), world.GetBalance(_addr[1], _currencies[0]));\n\n            world = _initWorld.TransferAsset(_initContext, _addr[0], _addr[0], Value(0, 2));\n            if (ProtocolVersion >= BlockMetadata.TransferFixProtocolVersion)\n            {\n                Assert.Equal(Value(0, 5), world.GetBalance(_addr[0], _currencies[0]));\n            }\n            else\n            {\n                Assert.Equal(Value(0, 7), world.GetBalance(_addr[0], _currencies[0]));\n            }\n        }\n\n        [Fact]\n        public virtual void TransferAssetInBlock()\n        {\n            var store = new MemoryStore();\n            var stateStore = new TrieStateStore(new MemoryKeyValueStore());\n            var privateKey = new PrivateKey();\n            BlockChain chain = TestUtils.MakeBlockChain(\n                new NullBlockPolicy(),\n                store,\n                stateStore,\n                new SingleActionLoader(typeof(DumbAction)),\n                protocolVersion: ProtocolVersion,\n                privateKey: privateKey\n            );\n\n            // Mint\n            DumbAction action = DumbAction.Create(null, (null, _addr[1], 20));\n            Transaction tx = Transaction.Create(\n                0,\n                _keys[0],\n                chain.Genesis.Hash,\n                new[] { action }.ToPlainValues());\n            var block1PreEval = TestUtils.ProposeNext(\n                chain.Tip,\n                new[] { tx },\n                miner: privateKey.PublicKey,\n                protocolVersion: ProtocolVersion);\n            var stateRootHash =\n                chain.DetermineBlockPrecededStateRootHash(block1PreEval, out _);\n            var hash = block1PreEval.Header.DeriveBlockHash(stateRootHash, null);\n            Block block1 = ProtocolVersion >= BlockMetadata.SignatureProtocolVersion\n                ? chain.EvaluateAndSign(block1PreEval, privateKey)\n                : new Block(block1PreEval, (stateRootHash, null, hash));\n            chain.Append(block1, TestUtils.CreateBlockCommit(block1));\n            Assert.Equal(\n                DumbAction.DumbCurrency * 0,\n                chain\n                    .GetNextWorldState()\n                    .GetBalance(_addr[0], DumbAction.DumbCurrency));\n            Assert.Equal(\n                DumbAction.DumbCurrency * 20,\n                chain\n                    .GetNextWorldState()\n                    .GetBalance(_addr[1], DumbAction.DumbCurrency));\n\n            // Transfer\n            action = DumbAction.Create(null, (_addr[1], _addr[0], 5));\n            tx = Transaction.Create(\n                1,\n                _keys[0],\n                chain.Genesis.Hash,\n                new[] { action }.ToPlainValues());\n            var block2PreEval = TestUtils.ProposeNext(\n                chain.Tip,\n                new[] { tx },\n                miner: privateKey.PublicKey,\n                protocolVersion: ProtocolVersion,\n                lastCommit: chain.GetBlockCommit(chain.Tip.Index));\n            stateRootHash = chain.DetermineBlockPrecededStateRootHash(block2PreEval, out _);\n            hash = block2PreEval.Header.DeriveBlockHash(stateRootHash, null);\n            Block block2 = ProtocolVersion >= BlockMetadata.SignatureProtocolVersion\n                ? chain.EvaluateAndSign(block2PreEval, privateKey)\n                : new Block(block2PreEval, (stateRootHash, null, hash));\n            chain.Append(block2, TestUtils.CreateBlockCommit(block2));\n            Assert.Equal(\n                DumbAction.DumbCurrency * 5,\n                chain\n                    .GetNextWorldState()\n                    .GetBalance(_addr[0], DumbAction.DumbCurrency));\n            Assert.Equal(\n                DumbAction.DumbCurrency * 15,\n                chain\n                    .GetNextWorldState()\n                    .GetBalance(_addr[1], DumbAction.DumbCurrency));\n\n            // Transfer bugged\n            action = DumbAction.Create((_addr[0], \"a\"), (_addr[0], _addr[0], 1));\n            tx = Transaction.Create(\n                chain.GetNextTxNonce(_addr[0]),\n                _keys[0],\n                chain.Genesis.Hash,\n                new[] { action }.ToPlainValues());\n            var block3PreEval = TestUtils.ProposeNext(\n                chain.Tip,\n                new[] { tx },\n                miner: _keys[1].PublicKey,\n                protocolVersion: ProtocolVersion,\n                lastCommit: chain.GetBlockCommit(chain.Tip.Index));\n            stateRootHash = chain.DetermineBlockPrecededStateRootHash(block3PreEval, out _);\n            hash = block3PreEval.Header.DeriveBlockHash(stateRootHash, null);\n            Block block3 = ProtocolVersion >= BlockMetadata.SignatureProtocolVersion\n                ? chain.EvaluateAndSign(block3PreEval, _keys[1])\n                : new Block(block3PreEval, (stateRootHash, null, hash));\n            chain.Append(block3, TestUtils.CreateBlockCommit(block3));\n            Assert.Equal(\n                DumbAction.DumbCurrency * 5,\n                chain.GetWorldState().GetBalance(_addr[0], DumbAction.DumbCurrency));\n        }\n\n        [Fact]\n        public void MintAsset()\n        {\n            Assert.Throws<ArgumentOutOfRangeException>(() =>\n                _initWorld.MintAsset(_initContext, _addr[0], Value(0, 0)));\n            Assert.Throws<ArgumentOutOfRangeException>(() =>\n                _initWorld.MintAsset(_initContext, _addr[0], Value(0, -1)));\n\n            IWorld delta0 = _initWorld;\n            IActionContext context0 = _initContext;\n            // currencies[0] (AAA) allows everyone to mint\n            delta0 = delta0.MintAsset(context0, _addr[2], Value(0, 10));\n            Assert.Equal(Value(0, 10), delta0.GetBalance(_addr[2], _currencies[0]));\n\n            // currencies[2] (CCC) allows only _addr[0] to mint\n            delta0 = delta0.MintAsset(context0, _addr[0], Value(2, 10));\n            Assert.Equal(Value(2, 20), delta0.GetBalance(_addr[0], _currencies[2]));\n\n            // currencies[3] (DDD) allows _addr[0] & _addr[1] to mint\n            delta0 = delta0.MintAsset(context0, _addr[1], Value(3, 10));\n            Assert.Equal(Value(3, 30), delta0.GetBalance(_addr[1], _currencies[3]));\n\n            // currencies[5] (FFF) has a cap of 100\n            Assert.Throws<SupplyOverflowException>(\n                () => _initWorld.MintAsset(_initContext, _addr[0], Value(5, 200)));\n\n            IWorld delta1 = _initWorld;\n            IActionContext context1 = CreateContext(delta1, _addr[1]);\n            // currencies[0] (DDD) allows everyone to mint\n            delta1 = delta1.MintAsset(context1, _addr[2], Value(0, 10));\n            Assert.Equal(Value(0, 10), delta1.GetBalance(_addr[2], _currencies[0]));\n\n            // currencies[2] (CCC) disallows _addr[1] to mint\n            Assert.Throws<CurrencyPermissionException>(() =>\n                delta1.MintAsset(context1, _addr[1], Value(2, 10)));\n\n            // currencies[3] (DDD) allows _addr[0] & _addr[1] to mint\n            delta1 = delta1.MintAsset(context1, _addr[0], Value(3, 20));\n            Assert.Equal(Value(3, 20), delta1.GetBalance(_addr[0], _currencies[3]));\n        }\n\n        [Fact]\n        public virtual void BurnAsset()\n        {\n            Assert.Throws<ArgumentOutOfRangeException>(() =>\n                _initWorld.BurnAsset(_initContext, _addr[0], Value(0, 0)));\n            Assert.Throws<ArgumentOutOfRangeException>(() =>\n                _initWorld.BurnAsset(_initContext, _addr[0], Value(0, -1)));\n            Assert.Throws<InsufficientBalanceException>(() =>\n                _initWorld.BurnAsset(_initContext, _addr[0], Value(0, 6)));\n\n            IWorld delta0 = _initWorld;\n            IActionContext context0 = _initContext;\n            // currencies[0] (AAA) allows everyone to burn\n            delta0 = delta0.BurnAsset(context0, _addr[0], Value(0, 2));\n            Assert.Equal(Value(0, 3), delta0.GetBalance(_addr[0], _currencies[0]));\n\n            // currencies[2] (CCC) allows only _addr[0] to burn\n            delta0 = delta0.BurnAsset(context0, _addr[0], Value(2, 4));\n            Assert.Equal(Value(2, 6), delta0.GetBalance(_addr[0], _currencies[2]));\n\n            // currencies[3] (DDD) allows _addr[0] & _addr[1] to burn\n            delta0 = delta0.BurnAsset(context0, _addr[1], Value(3, 8));\n            Assert.Equal(Value(3, 12), delta0.GetBalance(_addr[1], _currencies[3]));\n\n            IWorld delta1 = _initWorld;\n            IActionContext context1 = CreateContext(delta1, _addr[1]);\n            // currencies[0] (AAA) allows everyone to burn\n            delta1 = delta1.BurnAsset(context1, _addr[0], Value(0, 2));\n            Assert.Equal(Value(0, 3), delta1.GetBalance(_addr[0], _currencies[0]));\n\n            // currencies[2] (CCC) disallows _addr[1] to burn\n            Assert.Throws<CurrencyPermissionException>(() =>\n                delta1.BurnAsset(context1, _addr[0], Value(2, 4)));\n\n            // currencies[3] (DDD) allows _addr[0] & _addr[1] to burn\n            delta1 = delta1.BurnAsset(context1, _addr[1], Value(3, 8));\n            Assert.Equal(Value(3, 12), delta1.GetBalance(_addr[1], _currencies[3]));\n        }\n\n        [Fact]\n        public virtual void SetValidatorSet()\n        {\n            const int newValidatorCount = 6;\n            var world = _initWorld;\n            var keys = Enumerable\n                .Range(0, newValidatorCount)\n                .Select(i => new PrivateKey())\n                .ToList();\n\n            var validatorSet = new ValidatorSet(\n                keys.Select(key => new Validator(key.PublicKey, 1)).ToList());\n            world = world.SetValidatorSet(validatorSet);\n            Assert.Equal(newValidatorCount, world.GetValidatorSet().TotalCount);\n            Assert.NotEqual(_initWorld.GetValidatorSet(), world.GetValidatorSet());\n            var oldValidatorSetRawValue = world\n                .GetAccountState(ReservedAddresses.LegacyAccount)\n                .Trie\n                .Get(KeyConverters.ValidatorSetKey);\n            var newValidatorSetRawValue = world\n                .GetAccountState(ReservedAddresses.ValidatorSetAccount)\n                .Trie\n                .Get(KeyConverters.ToStateKey(ValidatorSetAccount.ValidatorSetAddress));\n            if (ProtocolVersion >= BlockMetadata.ValidatorSetAccountProtocolVersion)\n            {\n                Assert.Null(oldValidatorSetRawValue);\n                Assert.NotNull(newValidatorSetRawValue);\n            }\n            else\n            {\n                Assert.NotNull(oldValidatorSetRawValue);\n                Assert.Null(newValidatorSetRawValue);\n            }\n\n            world = world.SetValidatorSet(new ValidatorSet());\n            Assert.Equal(0, world.GetValidatorSet().TotalCount);\n            oldValidatorSetRawValue =\n                world.GetAccountState(ReservedAddresses.LegacyAccount).Trie.Get(\n                    KeyConverters.ValidatorSetKey);\n            newValidatorSetRawValue =\n                world.GetAccountState(ReservedAddresses.ValidatorSetAccount).Trie.Get(\n                    KeyConverters.ToStateKey(ValidatorSetAccount.ValidatorSetAddress));\n            if (ProtocolVersion >= BlockMetadata.ValidatorSetAccountProtocolVersion)\n            {\n                Assert.Null(oldValidatorSetRawValue);\n                Assert.NotNull(newValidatorSetRawValue);\n            }\n            else\n            {\n                Assert.NotNull(oldValidatorSetRawValue);\n                Assert.Null(newValidatorSetRawValue);\n            }\n        }\n\n        [Fact]\n        public virtual void TotalSupplyTracking()\n        {\n            IWorld world = _initWorld;\n            IActionContext context = _initContext;\n\n            if (ProtocolVersion >= BlockMetadata.CurrencyAccountProtocolVersion)\n            {\n                Assert.Equal(\n                    Value(0, 5),\n                    world.GetTotalSupply(_currencies[0]));\n            }\n            else\n            {\n                Assert.Equal(\n                    Value(0, 0),\n                    world.GetTotalSupply(_currencies[0]));\n            }\n\n            Assert.Equal(\n                Value(4, 5),\n                _initWorld.GetTotalSupply(_currencies[4]));\n\n            world = world.MintAsset(context, _addr[0], Value(0, 10));\n            if (ProtocolVersion >= BlockMetadata.CurrencyAccountProtocolVersion)\n            {\n                Assert.Equal(\n                    Value(0, 15),\n                    world.GetTotalSupply(_currencies[0]));\n            }\n            else\n            {\n                Assert.Equal(\n                    Value(0, 0),\n                    world.GetTotalSupply(_currencies[0]));\n            }\n\n            world = world.MintAsset(context, _addr[0], Value(4, 10));\n            Assert.Equal(\n                Value(4, 15),\n                world.GetTotalSupply(_currencies[4]));\n\n            Assert.Throws<InsufficientBalanceException>(() =>\n                world.BurnAsset(context, _addr[0], Value(4, 100)));\n\n            world = world.BurnAsset(context, _addr[0], Value(4, 5));\n            Assert.Equal(\n                Value(4, 10),\n                world.GetTotalSupply(_currencies[4]));\n        }\n\n        protected FungibleAssetValue Value(int currencyIndex, BigInteger quantity) =>\n            new FungibleAssetValue(_currencies[currencyIndex], quantity, 0);\n    }\n}\n"
  },
  {
    "path": "test/Libplanet.Tests/Action/WorldV0Test.cs",
    "content": "using Xunit.Abstractions;\n\nnamespace Libplanet.Tests.Action\n{\n    public class WorldV0Test : WorldTest\n    {\n        public WorldV0Test(ITestOutputHelper output)\n            : base(output)\n        {\n        }\n\n        public override int ProtocolVersion { get; } = 0;\n\n        public override void TransferAssetInBlock()\n        {\n            return;\n        }\n\n        public override void SetValidatorSet()\n        {\n            return;\n        }\n\n        public override void TotalSupplyTracking()\n        {\n            return;\n        }\n    }\n}\n"
  },
  {
    "path": "test/Libplanet.Tests/Action/WorldV1Test.cs",
    "content": "using Libplanet.Types.Blocks;\nusing Xunit.Abstractions;\n\nnamespace Libplanet.Tests.Action\n{\n    public class WorldV1Test : WorldTest\n    {\n        public WorldV1Test(ITestOutputHelper output)\n            : base(output)\n        {\n        }\n\n        public override int ProtocolVersion { get; } = BlockMetadata.TransferFixProtocolVersion;\n\n        public override void TransferAssetInBlock()\n        {\n            return;\n        }\n\n        public override void SetValidatorSet()\n        {\n            return;\n        }\n\n        public override void TotalSupplyTracking()\n        {\n            return;\n        }\n    }\n}\n"
  },
  {
    "path": "test/Libplanet.Tests/Action/WorldV5Test.cs",
    "content": "using Libplanet.Types.Blocks;\nusing Xunit.Abstractions;\n\nnamespace Libplanet.Tests.Action\n{\n    public class WorldV5Test : WorldTest\n    {\n        public WorldV5Test(ITestOutputHelper output)\n            : base(output)\n        {\n        }\n\n        public override int ProtocolVersion { get; } = BlockMetadata.WorldStateProtocolVersion;\n    }\n}\n"
  },
  {
    "path": "test/Libplanet.Tests/Action/WorldV6Test.cs",
    "content": "using Libplanet.Types.Blocks;\nusing Xunit.Abstractions;\n\nnamespace Libplanet.Tests.Action\n{\n    public class WorldV6Test : WorldTest\n    {\n        public WorldV6Test(ITestOutputHelper output)\n            : base(output)\n        {\n        }\n\n        public override int ProtocolVersion { get; } =\n            BlockMetadata.ValidatorSetAccountProtocolVersion;\n    }\n}\n"
  },
  {
    "path": "test/Libplanet.Tests/Action/WorldV7Test.cs",
    "content": "using Libplanet.Types.Blocks;\nusing Xunit.Abstractions;\n\nnamespace Libplanet.Tests.Action\n{\n    public class WorldV7Test : WorldTest\n    {\n        public WorldV7Test(ITestOutputHelper output)\n            : base(output)\n        {\n        }\n\n        public override int ProtocolVersion { get; } =\n            BlockMetadata.CurrencyAccountProtocolVersion;\n    }\n}\n"
  },
  {
    "path": "test/Libplanet.Tests/ActionProgress.cs",
    "content": "using System;\n\nnamespace Libplanet.Tests\n{\n    public sealed class ActionProgress<T> : IProgress<T>\n    {\n        private Action<T> _action;\n\n        public ActionProgress(Action<T> action) =>\n            _action = action ?? throw new ArgumentNullException(nameof(action));\n\n        public void Report(T value) =>\n            _action(value);\n    }\n}\n"
  },
  {
    "path": "test/Libplanet.Tests/AddressTest.cs",
    "content": "using System;\nusing System.Collections.Immutable;\nusing System.ComponentModel;\nusing System.Linq;\nusing Bencodex.Types;\nusing Libplanet.Crypto;\nusing Xunit;\nusing static Libplanet.Tests.TestUtils;\n\nnamespace Libplanet.Tests\n{\n    public class AddressTest\n    {\n        [Fact]\n        public void ConstructWithImmutableArray()\n        {\n            byte[] addr = new byte[20]\n            {\n                0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, 0xab,\n                0xcd, 0xef, 0xab, 0xcd, 0xef, 0xab, 0xcd, 0xef, 0xab,\n                0xcd, 0xef,\n            };\n\n            Assert.Equal(\n                new Address(\"0123456789ABcdefABcdEfABcdEFabcDEFabCDEF\"),\n                new Address(addr.ToImmutableArray())\n            );\n        }\n\n        [Fact]\n        public void DefaultConstructor()\n        {\n            Address defaultValue = default;\n            Assert.Equal(new Address(new byte[20]), defaultValue);\n        }\n\n        [Fact]\n        public void DerivingConstructor()\n        {\n            var key = new PublicKey(\n                new byte[]\n                {\n                    0x03, 0x43, 0x8b, 0x93, 0x53, 0x89, 0xa7, 0xeb, 0xf8,\n                    0x38, 0xb3, 0xae, 0x41, 0x25, 0xbd, 0x28, 0x50, 0x6a,\n                    0xa2, 0xdd, 0x45, 0x7f, 0x20, 0xaf, 0xc8, 0x43, 0x72,\n                    0x9d, 0x3e, 0x7d, 0x60, 0xd7, 0x28,\n                }\n            );\n            Assert.Equal(\n                new Address(\n                    new byte[]\n                    {\n                        0xd4, 0x1f, 0xad, 0xf6, 0x1b, 0xad, 0xf5, 0xbe,\n                        0x2d, 0xe6, 0x0e, 0x9f, 0xc3, 0x23, 0x0c, 0x0a,\n                        0x8a, 0x43, 0x90, 0xf0,\n                    }\n                ),\n                new Address(key)\n            );\n        }\n\n        [Fact]\n        public void HexAddressConstructor()\n        {\n            Assert.Equal(\n                new Address(\n                    new byte[20]\n                    {\n                        0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, 0xab,\n                        0xcd, 0xef, 0xab, 0xcd, 0xef, 0xab, 0xcd, 0xef, 0xab,\n                        0xcd, 0xef,\n                    }\n                ),\n                new Address(\n                    \"0123456789ABcdefABcdEfABcdEFabcDEFabCDEF\"\n                )\n            );\n\n            var address = new Address(\n                \"45a22187e2d8850bb357886958bc3e8560929ccc\"\n            );\n            Assert.Equal(\n                \"45a22187e2D8850bb357886958bC3E8560929ccc\",\n                address.ToHex()\n            );\n        }\n\n        [Fact]\n        public void DeriveFromHex()\n        {\n            Assert.Throws<ArgumentException>(\n                () => new Address(\"0123456789ABcdefABcdEfABcdEFabcDEFabCDE\"));      // 39 chars\n            Assert.Throws<ArgumentException>(\n                () => new Address(\"0123456789ABcdefABcdEfABcdEFabcDEFabCDEFF\"));    // 41 chars\n            Assert.Throws<ArgumentException>(\n                () => new Address(\"1x0123456789ABcdefABcdEfABcdEFabcDEFabCDEF\"));   // bad prefix\n            Assert.Throws<ArgumentException>(\n                () => new Address(\"0x0123456789ABcdefABcdEfABcdEFabcDEFabCDE\"));    // 41 chars\n            Assert.Throws<ArgumentException>(\n                () => new Address(\"0x0123456789ABcdefABcdEfABcdEFabcDEFabCDEFF\"));  // 43 chars\n        }\n\n        [Fact]\n        public void HexAddressConstructorOnlyTakesHexadecimalCharacters()\n        {\n            Assert.Throws<ArgumentException>(\n                () => new Address(\"45a22187e2d8850bb357886958BC3E8560929ghi\")\n            );\n            Assert.Throws<ArgumentException>(\n                () => new Address(\"45a22187e2d8850bb357886958BC3E8560929£한글\")\n            );\n        }\n\n        [Fact]\n        public void CanDetectInvalidMixedCaseChecksum()\n        {\n            Assert.Throws<ArgumentException>(() =>\n                new Address(\"45A22187E2D8850BB357886958BC3E8560929CCC\")\n            );\n        }\n\n        [Fact]\n        public void AddressMustBe20Bytes()\n        {\n            for (int size = 0; size < 25; size++)\n            {\n                if (size == 20)\n                {\n                    continue;\n                }\n\n                byte[] addressBytes = GetRandomBytes(size);\n                Assert.Throws<ArgumentException>(() =>\n                    new Address(addressBytes)\n                );\n            }\n        }\n\n        [Fact]\n        public void ConstructWithBinary()\n        {\n            byte[] addr =\n            {\n                0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, 0xab,\n                0xcd, 0xef, 0xab, 0xcd, 0xef, 0xab, 0xcd, 0xef, 0xab,\n                0xcd, 0xef,\n            };\n\n            Assert.Equal(\n                new Address(\"0123456789ABcdefABcdEfABcdEFabcDEFabCDEF\"),\n                new Address((IValue)new Binary(addr))\n            );\n\n            var invalidAddr = new byte[19];\n            Assert.Throws<ArgumentException>(() => new Address((IValue)new Binary(invalidAddr)));\n        }\n\n        [Fact]\n        public void ToByteArray()\n        {\n            byte[] addressBytes = GetRandomBytes(20);\n            var address = new Address(addressBytes);\n            Assert.Equal(addressBytes, address.ToByteArray());\n        }\n\n        [Fact]\n        public void ToByteArrayShouldNotExposeContents()\n        {\n            var address = new Address(\n                new byte[20]\n                {\n                    0x45, 0xa2, 0x21, 0x87, 0xe2, 0xd8, 0x85, 0x0b, 0xb3, 0x57,\n                    0x88, 0x69, 0x58, 0xbc, 0x3e, 0x85, 0x60, 0x92, 0x9c, 0xcc,\n                }\n            );\n            address.ToByteArray()[0] = 0x00;\n\n            Assert.Equal(0x45, address.ToByteArray()[0]);\n        }\n\n        [Fact]\n        public void ToHex()\n        {\n            var address = new Address(\n                new byte[20]\n                {\n                    0x45, 0xa2, 0x21, 0x87, 0xe2, 0xd8, 0x85, 0x0b, 0xb3, 0x57,\n                    0x88, 0x69, 0x58, 0xbc, 0x3e, 0x85, 0x60, 0x92, 0x9c, 0xcc,\n                }\n            );\n            Assert.Equal(\n                \"45a22187e2D8850bb357886958bC3E8560929ccc\",\n                address.ToHex()\n            );\n            Assert.Equal(\n                \"0x45a22187e2D8850bb357886958bC3E8560929ccc\",\n                address.ToString()\n            );\n        }\n\n        [Fact]\n        public void Equals_()\n        {\n            var sameAddress1 = new Address(\n                new byte[20]\n                {\n                    0x45, 0xa2, 0x21, 0x87, 0xe2, 0xd8, 0x85, 0x0b, 0xb3, 0x57,\n                    0x88, 0x69, 0x58, 0xbc, 0x3e, 0x85, 0x60, 0x92, 0x9c, 0xcc,\n                }\n            );\n            var sameAddress2 = new Address(\n                new byte[20]\n                {\n                    0x45, 0xa2, 0x21, 0x87, 0xe2, 0xd8, 0x85, 0x0b, 0xb3, 0x57,\n                    0x88, 0x69, 0x58, 0xbc, 0x3e, 0x85, 0x60, 0x92, 0x9c, 0xcc,\n                }\n            );\n            var differentAddress = new Address(\n                new byte[20]\n                {\n                    0x45, 0xa2, 0x21, 0x87, 0xe2, 0xd8, 0x85, 0x0b, 0xb3, 0x57,\n                    0x88, 0x69, 0x58, 0xbc, 0x3e, 0x85, 0x60, 0x92, 0x9c, 0x00,\n                }\n            );\n\n            Assert.Equal(sameAddress1, sameAddress2);\n            Assert.NotEqual(sameAddress2, differentAddress);\n\n            Assert.True(sameAddress1 == sameAddress2);\n            Assert.False(sameAddress2 == differentAddress);\n\n            Assert.False(sameAddress1 != sameAddress2);\n            Assert.True(sameAddress2 != differentAddress);\n        }\n\n        [Fact]\n        public void SerializeAndDeserializeWithDefault()\n        {\n            var defaultAddress = default(Address);\n            Address deserializedAddress = new Address(defaultAddress.Bencoded);\n            Assert.Equal(default, deserializedAddress);\n        }\n\n        [Fact]\n        public void Compare()\n        {\n            var random = new System.Random();\n            var buffer = new byte[20];\n            Address[] addresses = Enumerable.Repeat(0, 50).Select(_ =>\n            {\n                random.NextBytes(buffer);\n                return new Address(buffer);\n            }).ToArray();\n            for (int i = 1; i < addresses.Length; i++)\n            {\n                Address left = addresses[i - 1];\n                Address right = addresses[i];\n                string leftString = addresses[i - 1].ToHex().ToLower(),\n                       rightString = right.ToHex().ToLower();\n                Assert.Equal(\n                    Math.Min(Math.Max(left.CompareTo(right), 1), -1),\n                    Math.Min(Math.Max(leftString.CompareTo(rightString), 1), -1)\n                );\n                Assert.Equal(\n                    left.CompareTo(right),\n                    left.CompareTo(right as object)\n                );\n            }\n\n            Assert.Throws<ArgumentException>(() => addresses[0].CompareTo(null));\n            Assert.Throws<ArgumentException>(() => addresses[0].CompareTo(\"invalid\"));\n        }\n\n        [Fact]\n        public void ReplaceHexPrefixString()\n        {\n            var address = new Address(\"0x0123456789ABcdefABcdEfABcdEFabcDEFabCDEF\");\n\n            Assert.Equal(\n                \"0x0123456789ABcdefABcdEfABcdEFabcDEFabCDEF\",\n                address.ToString()\n            );\n        }\n\n        [Fact]\n        public void ReplaceHexUpperCasePrefixString()\n        {\n            Assert.Throws<ArgumentException>(() =>\n                 new Address(\"0X0123456789ABcdefABcdEfABcdEFabcDEFabCDEF\")\n            );\n        }\n\n        [Fact]\n        public void Bencoded()\n        {\n            var expected = new Address(TestUtils.GetRandomBytes(Address.Size));\n            var deserialized = new Address(expected.Bencoded);\n            Assert.Equal(expected, deserialized);\n            expected = default(Address);\n            deserialized = new Address(expected.Bencoded);\n            Assert.Equal(expected, deserialized);\n        }\n\n        [Fact]\n        public void TypeConverter()\n        {\n            TypeConverter converter = TypeDescriptor.GetConverter(typeof(Address));\n            var address = new Address(\"0123456789ABcdefABcdEfABcdEFabcDEFabCDEF\");\n            Assert.True(converter.CanConvertFrom(typeof(string)));\n            Assert.Equal(\n                address,\n                converter.ConvertFrom(\"0x0123456789ABcdefABcdEfABcdEFabcDEFabCDEF\"));\n            Assert.Equal(\n                address,\n                converter.ConvertFrom(\"0123456789ABcdefABcdEfABcdEFabcDEFabCDEF\"));\n            Assert.Throws<ArgumentException>(() => converter.ConvertFrom(\"INVALID\"));\n\n            Assert.True(converter.CanConvertTo(typeof(string)));\n            Assert.Equal(\n                \"0123456789ABcdefABcdEfABcdEFabcDEFabCDEF\",\n                converter.ConvertTo(address, typeof(string)));\n        }\n\n        [SkippableFact]\n        public void JsonSerialization()\n        {\n            var address = new Address(\"0123456789ABcdefABcdEfABcdEFabcDEFabCDEF\");\n            AssertJsonSerializable(\n                address,\n                \"\\\"0123456789ABcdefABcdEfABcdEFabcDEFabCDEF\\\"\"\n            );\n        }\n    }\n}\n"
  },
  {
    "path": "test/Libplanet.Tests/AnonymousComparer.cs",
    "content": "using System;\nusing System.Collections.Generic;\n\nnamespace Libplanet.Tests\n{\n    public class AnonymousComparer<T> : IComparer<T>\n    {\n        private Func<T, T, int> _comparer;\n\n        public AnonymousComparer(Func<T, T, int> comparer)\n        {\n            _comparer = comparer;\n        }\n\n        public int Compare(T x, T y) => _comparer(x, y);\n    }\n}\n"
  },
  {
    "path": "test/Libplanet.Tests/ArrayEqualityComparerTest.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing Libplanet.Common;\nusing Xunit;\n\nnamespace Libplanet.Tests\n{\n    public class ArrayEqualityComparerTest\n    {\n        private static readonly int[] ThreeInts = { 1, 2, 3 };\n        private static readonly int[] ThreeInts2 = { 1, 2, 3 };\n        private static readonly int[] DifferentInts = { 1, 2, 4 };\n        private static readonly int[] FourInts = { 1, 2, 3, 4 };\n        private static readonly int[] SignedInts = { -1, 2, -3 };\n        private readonly ArrayEqualityComparer<int> _comparer = new ArrayEqualityComparer<int>();\n        private readonly ArrayEqualityComparer<int> _absComparer =\n            new ArrayEqualityComparer<int>(new AbsIntComparer());\n\n        [Fact]\n        public void Nulls()\n        {\n            Assert.True(_comparer.Equals(null, null));\n            Assert.False(_comparer.Equals(null, ThreeInts));\n            Assert.False(_comparer.Equals(ThreeInts, null));\n            Assert.True(_absComparer.Equals(null, null));\n            Assert.False(_absComparer.Equals(null, ThreeInts));\n            Assert.False(_absComparer.Equals(ThreeInts, null));\n\n            Assert.Equal(0, _comparer.GetHashCode(null));\n            Assert.Equal(0, _absComparer.GetHashCode(null));\n        }\n\n        [Fact]\n        public void Equal()\n        {\n            Assert.True(_comparer.Equals(ThreeInts, ThreeInts2));\n            Assert.Equal(_comparer.GetHashCode(ThreeInts), _comparer.GetHashCode(ThreeInts2));\n            Assert.True(_absComparer.Equals(ThreeInts, ThreeInts2));\n            Assert.True(_absComparer.Equals(ThreeInts, SignedInts));\n            Assert.Equal(\n                _absComparer.GetHashCode(ThreeInts),\n                _absComparer.GetHashCode(ThreeInts2));\n            Assert.Equal(\n                _absComparer.GetHashCode(ThreeInts),\n                _absComparer.GetHashCode(SignedInts)\n            );\n        }\n\n        [Fact]\n        public void DifferentElements()\n        {\n            Assert.False(_comparer.Equals(ThreeInts, DifferentInts));\n            Assert.False(_comparer.Equals(ThreeInts, SignedInts));\n            Assert.False(_absComparer.Equals(ThreeInts, DifferentInts));\n\n            Assert.NotEqual(\n                _comparer.GetHashCode(ThreeInts),\n                _comparer.GetHashCode(DifferentInts)\n            );\n            Assert.NotEqual(\n                _comparer.GetHashCode(ThreeInts),\n                _comparer.GetHashCode(SignedInts)\n            );\n            Assert.NotEqual(\n                _absComparer.GetHashCode(ThreeInts),\n                _absComparer.GetHashCode(DifferentInts)\n            );\n        }\n\n        [Fact]\n        public void DifferentLengths()\n        {\n            Assert.False(_comparer.Equals(ThreeInts, FourInts));\n            Assert.NotEqual(_comparer.GetHashCode(ThreeInts), _comparer.GetHashCode(FourInts));\n\n            Assert.False(_absComparer.Equals(ThreeInts, FourInts));\n            Assert.NotEqual(\n                _absComparer.GetHashCode(ThreeInts),\n                _absComparer.GetHashCode(FourInts)\n            );\n        }\n\n        private class AbsIntComparer : EqualityComparer<int>\n        {\n            public override bool Equals(int x, int y) => Math.Abs(x) == Math.Abs(y);\n\n            public override int GetHashCode(int obj) => Math.Abs(obj);\n        }\n    }\n}\n"
  },
  {
    "path": "test/Libplanet.Tests/Assets/CurrencyTest.cs",
    "content": "using System;\nusing System.Collections.Immutable;\nusing System.Security.Cryptography;\nusing Bencodex.Types;\nusing Libplanet.Common;\nusing Libplanet.Crypto;\nusing Libplanet.Types.Assets;\nusing Xunit;\nusing static Libplanet.Tests.TestUtils;\n\nnamespace Libplanet.Tests.Assets\n{\n    public class CurrencyTest\n    {\n        public static readonly Address AddressA =\n            new Address(\"D6D639DA5a58A78A564C2cD3DB55FA7CeBE244A9\");\n\n        public static readonly Address AddressB =\n            new Address(\"5003712B63baAB98094aD678EA2B24BcE445D076\");\n\n        [Fact]\n        public void Constructor()\n        {\n#pragma warning disable CS0618  // must test obsoleted Currency.Legacy() for backwards compatibility\n            var foo = Currency.Legacy(\"FOO\", 2, ImmutableHashSet<Address>.Empty);\n#pragma warning restore CS0618  // must test obsoleted Currency.Legacy() for backwards compatibility\n            Assert.Equal(\"FOO\", foo.Ticker);\n            Assert.Equal(2, foo.DecimalPlaces);\n            Assert.Null(foo.MaximumSupply);\n            Assert.Empty(foo.Minters);\n            Assert.False(foo.TotalSupplyTrackable);\n\n            var bar = Currency.Capped(\n                \"\\t BAR \\n\",\n                0,\n                (100, 0),\n                ImmutableHashSet.Create(AddressA, AddressB));\n            Assert.Equal(\"BAR\", bar.Ticker);\n            Assert.Equal(0, bar.DecimalPlaces);\n            Assert.Equal(new FungibleAssetValue(bar, 100, 0), bar.MaximumSupply);\n            Assert.True(bar.Minters.SetEquals(new[] { AddressA, AddressB }));\n            Assert.True(bar.TotalSupplyTrackable);\n\n            var baz = Currency.Uncapped(\"baz\", 1, AddressA);\n            Assert.Equal(\"baz\", baz.Ticker);\n            Assert.Equal(1, baz.DecimalPlaces);\n            Assert.Null(baz.MaximumSupply);\n            Assert.True(baz.Minters.SetEquals(new[] { AddressA }));\n            Assert.True(baz.TotalSupplyTrackable);\n\n            var qux = Currency.Uncapped(\"QUX\", 0, null);\n            Assert.Equal(\"QUX\", qux.Ticker);\n            Assert.Null(qux.MaximumSupply);\n            Assert.Equal(0, qux.DecimalPlaces);\n            Assert.Null(qux.Minters);\n            Assert.True(qux.TotalSupplyTrackable);\n\n            var quux = Currency.Capped(\"QUUX\", 3, (100, 0), null);\n            Assert.Equal(\"QUUX\", quux.Ticker);\n            Assert.Equal(3, quux.DecimalPlaces);\n            Assert.Equal(new FungibleAssetValue(quux, 100, 0), quux.MaximumSupply);\n            Assert.Null(quux.Minters);\n            Assert.True(qux.TotalSupplyTrackable);\n\n            Assert.Throws<ArgumentException>(() =>\n                Currency.Uncapped(string.Empty, 0, ImmutableHashSet<Address>.Empty)\n            );\n            Assert.Throws<ArgumentException>(() =>\n                Currency.Uncapped(\"   \\n\", 1, ImmutableHashSet<Address>.Empty)\n            );\n            Assert.Throws<ArgumentException>(() =>\n                Currency.Capped(\"TEST\", 0, (100, 1), ImmutableHashSet<Address>.Empty)\n            );\n            Assert.Throws<ArgumentException>(() =>\n                Currency.Capped(\"TEST\", 1, (-100, 1), ImmutableHashSet<Address>.Empty)\n            );\n            Assert.Throws<ArgumentException>(() =>\n                Currency.Capped(\"TEST\", 1, (100, -1), ImmutableHashSet<Address>.Empty)\n            );\n            Assert.Throws<ArgumentException>(() =>\n                Currency.Capped(\"TEST\", 1, (-100, -1), ImmutableHashSet<Address>.Empty)\n            );\n        }\n\n        [Fact]\n        public void Hash()\n        {\n#pragma warning disable CS0618  // must test obsoleted Currency.Legacy() for backwards compatibility\n            Currency currency = Currency.Legacy(\"GOLD\", 2, AddressA);\n#pragma warning restore CS0618  // must test obsoleted Currency.Legacy() for backwards compatibility\n            HashDigest<SHA1> expected =\n                HashDigest<SHA1>.FromString(\"81446cd346c1be9e686835742bfd3772194dea21\");\n            AssertBytesEqual(expected, currency.Hash);\n\n#pragma warning disable CS0618  // must test obsoleted Currency.Legacy() for backwards compatibility\n            currency = Currency.Legacy(\"NCG\", 8, ImmutableHashSet.Create(AddressA, AddressB));\n#pragma warning restore CS0618  // must test obsoleted Currency.Legacy() for backwards compatibility\n            expected = HashDigest<SHA1>.FromString(\"42ce3a098fe14084e89d3d4449f56126693aeed1\");\n            AssertBytesEqual(expected, currency.Hash);\n\n#pragma warning disable CS0618  // must test obsoleted Currency.Legacy() for backwards compatibility\n            currency = Currency.Legacy(\"FOO\", 0, ImmutableHashSet<Address>.Empty);\n#pragma warning restore CS0618  // must test obsoleted Currency.Legacy() for backwards compatibility\n            expected = HashDigest<SHA1>.FromString(\"801990ea2885bd51eebca0e826cc0e27f0917a9b\");\n            AssertBytesEqual(expected, currency.Hash);\n\n#pragma warning disable CS0618  // must test obsoleted Currency.Legacy() for backwards compatibility\n            currency = Currency.Legacy(\"BAR\", 1, null);\n#pragma warning restore CS0618  // must test obsoleted Currency.Legacy() for backwards compatibility\n            expected = HashDigest<SHA1>.FromString(\"da42781871890f1e1b7d6f49c7f2733d3ba7b8bd\");\n            AssertBytesEqual(expected, currency.Hash);\n\n            currency = Currency.Uncapped(\"BAZ\", 1, null);\n            expected = HashDigest<SHA1>.FromString(\"d7fe111cae5b2503939c9bce864ca3b64d575e8d\");\n            AssertBytesEqual(expected, currency.Hash);\n\n            currency = Currency.Capped(\"BAZ\", 1, (100, 0), null);\n            expected = HashDigest<SHA1>.FromString(\"38bd85ea71c09ca7ed82b61fe91bc205101db191\");\n            AssertBytesEqual(expected, currency.Hash);\n        }\n\n        [Fact]\n        public void AllowsToMint()\n        {\n            Address addressC = new PrivateKey().Address;\n            Currency currency = Currency.Uncapped(\"FOO\", 0, AddressA);\n            Assert.True(currency.AllowsToMint(AddressA));\n            Assert.False(currency.AllowsToMint(AddressB));\n            Assert.False(currency.AllowsToMint(addressC));\n\n            currency = Currency.Uncapped(\"BAR\", 2, ImmutableHashSet.Create(AddressA, AddressB));\n            Assert.True(currency.AllowsToMint(AddressA));\n            Assert.True(currency.AllowsToMint(AddressB));\n            Assert.False(currency.AllowsToMint(addressC));\n\n            currency = Currency.Uncapped(\"BAZ\", 0, ImmutableHashSet<Address>.Empty);\n            Assert.False(currency.AllowsToMint(AddressA));\n            Assert.False(currency.AllowsToMint(AddressB));\n            Assert.False(currency.AllowsToMint(addressC));\n\n            currency = Currency.Uncapped(\"QUX\", 3, null);\n            Assert.True(currency.AllowsToMint(AddressA));\n            Assert.True(currency.AllowsToMint(AddressB));\n            Assert.True(currency.AllowsToMint(addressC));\n        }\n\n        [Fact]\n        public void String()\n        {\n#pragma warning disable CS0618  // must test obsoleted Currency.Legacy() for backwards compatibility\n            Currency currency = Currency.Legacy(\"GOLD\", 0, AddressA);\n#pragma warning restore CS0618  // must test obsoleted Currency.Legacy() for backwards compatibility\n            Assert.Equal(\"GOLD (688ded7b7ae6e551e14e58ec23fef3540d442a35)\", currency.ToString());\n\n            currency = Currency.Uncapped(\"GOLD\", 0, AddressA);\n            Assert.Equal(\"GOLD (a418b63455695d932ed154d5ce59575ea7cbb1f0)\", currency.ToString());\n\n            currency = Currency.Capped(\"GOLD\", 0, (100, 0), AddressA);\n            Assert.Equal(\"GOLD (f0fd50b87b39d9f24c0922551e59914dbbeb3544)\", currency.ToString());\n        }\n\n        [Fact]\n        public void Equal()\n        {\n            var currencyA = Currency.Uncapped(\"GOLD\", 0, AddressA);\n            var currencyB = Currency.Uncapped(\"GOLD\", 0, AddressA);\n            var currencyC = Currency.Uncapped(\"GOLD\", 1, AddressA);\n            var currencyD = Currency.Uncapped(\"GOLD\", 0, AddressB);\n            var currencyE = Currency.Uncapped(\"SILVER\", 2, AddressA);\n#pragma warning disable CS0618  // must test obsoleted Currency.Legacy() for backwards compatibility\n            var currencyF = Currency.Legacy(\"GOLD\", 0, AddressA);\n#pragma warning restore CS0618  // must test obsoleted Currency.Legacy() for backwards compatibility\n            var currencyG = Currency.Capped(\"GOLD\", 0, (100, 0), AddressA);\n            var currencyH = Currency.Capped(\"GOLD\", 0, (200, 0), AddressA);\n            var currencyI = Currency.Capped(\"SILVER\", 0, (200, 0), AddressA);\n\n            Assert.Equal(currencyA, currencyA);\n            Assert.Equal(currencyA, currencyB);\n            Assert.NotEqual(currencyA, currencyC);\n            Assert.NotEqual(currencyA, currencyD);\n            Assert.NotEqual(currencyA, currencyE);\n            Assert.NotEqual(currencyA, currencyF);\n            Assert.NotEqual(currencyA, currencyG);\n            Assert.NotEqual(currencyG, currencyH);\n            Assert.NotEqual(currencyH, currencyI);\n        }\n\n        [Fact]\n        public void GetFungibleAssetValue()\n        {\n            var foo = Currency.Uncapped(\"FOO\", 0, null);\n            Assert.Equal(new FungibleAssetValue(foo, 123, 0), 123 * foo);\n            Assert.Equal(new FungibleAssetValue(foo, -123, 0), foo * -123);\n        }\n\n        [Fact]\n        public void Serialize()\n        {\n#pragma warning disable CS0618  // must test obsoleted Currency.Legacy() for backwards compatibility\n            var foo = Currency.Legacy(\"FOO\", 2,  null);\n#pragma warning restore CS0618  // must test obsoleted Currency.Legacy() for backwards compatibility\n\n            Assert.Equal(\n                Dictionary.Empty\n                    .Add(\"ticker\", \"FOO\")\n                    .Add(\"decimalPlaces\", new byte[] { 2 })\n                    .Add(\"minters\", Null.Value),\n                foo.Serialize());\n\n            Assert.Equal(foo, new Currency(foo.Serialize()));\n\n            var bar =\n                Currency.Capped(\"BAR\", 0, (100, 0), ImmutableHashSet.Create(AddressA, AddressB));\n\n            Assert.Equal(\n                Dictionary.Empty\n                    .Add(\"ticker\", \"BAR\")\n                    .Add(\"decimalPlaces\", new byte[] { 0 })\n                    .Add(\"maximumSupplyMajor\", 100)\n                    .Add(\"maximumSupplyMinor\", 0)\n                    .Add(\n                        \"minters\",\n                        List.Empty.Add(AddressB.ToByteArray()).Add(AddressA.ToByteArray()))\n                    .Add(\"totalSupplyTrackable\", true),\n                bar.Serialize());\n\n            Assert.Equal(bar, new Currency(bar.Serialize()));\n        }\n\n        [SkippableFact]\n        public void JsonSerialization()\n        {\n#pragma warning disable CS0618  // must test obsoleted Currency.Legacy() for backwards compatibility\n            var foo = Currency.Legacy(\"FOO\", 2, null);\n#pragma warning restore CS0618  // must test obsoleted Currency.Legacy() for backwards compatibility\n            AssertJsonSerializable(foo, @\"\n                {\n                    \"\"hash\"\": \"\"8db87f973776e2218113202e00e09e185fff8971\"\",\n                    \"\"ticker\"\": \"\"FOO\"\",\n                    \"\"decimalPlaces\"\": 2,\n                    \"\"minters\"\": null,\n                    \"\"maximumSupply\"\": null,\n                    \"\"totalSupplyTrackable\"\": false,\n                }\n            \");\n\n            var bar =\n                Currency.Capped(\"BAR\", 0, (100, 0), ImmutableHashSet.Create(AddressA, AddressB));\n            AssertJsonSerializable(bar, @\"\n                {\n                    \"\"hash\"\": \"\"e4ee30562819a9e74be40098c76f84209d05da5e\"\",\n                    \"\"ticker\"\": \"\"BAR\"\",\n                    \"\"decimalPlaces\"\": 0,\n                    \"\"minters\"\": [\n                        \"\"5003712B63baAB98094aD678EA2B24BcE445D076\"\",\n                        \"\"D6D639DA5a58A78A564C2cD3DB55FA7CeBE244A9\"\",\n                    ],\n                    \"\"maximumSupply\"\": \"\"100.0\"\",\n                    \"\"totalSupplyTrackable\"\": true,\n                }\n            \");\n        }\n    }\n}\n"
  },
  {
    "path": "test/Libplanet.Tests/Assets/FungibleAssetValueTest.cs",
    "content": "#pragma warning disable S1764\nusing System;\nusing Libplanet.Types.Assets;\nusing Xunit;\nusing static Libplanet.Tests.TestUtils;\n\nnamespace Libplanet.Tests.Assets\n{\n    public class FungibleAssetValueTest\n    {\n        private static readonly Currency FOO = Currency.Uncapped(\"FOO\", 2, null);\n        private static readonly Currency BAR = Currency.Uncapped(\"BAR\", 0, null);\n        private static readonly Currency BARMAX = Currency.Capped(\"BAR\", 0, (100000, 0), null);\n#pragma warning disable CS0618  // must test obsoleted Currency.Legacy() for backwards compatibility\n        private static readonly Currency BARNOTRACK = Currency.Legacy(\"BAR\", 0, null);\n#pragma warning restore CS0618  // must test obsoleted Currency.Legacy() for backwards compatibility\n\n        [Fact]\n        public void Constructor()\n        {\n            FungibleAssetValue v;\n            v = new FungibleAssetValue(FOO, 123, 45);\n            Assert.Equal(new FungibleAssetValue(FOO, 1, 123, 45), v);\n            Assert.Equal(12345, v.RawValue);\n            Assert.Equal(123, v.MajorUnit);\n            Assert.Equal(45, v.MinorUnit);\n            Assert.Equal(1, v.Sign);\n\n            v = new FungibleAssetValue(FOO, 456, 9);\n            Assert.Equal(new FungibleAssetValue(FOO, 1, 456, 9), v);\n            Assert.Equal(45609, v.RawValue);\n            Assert.Equal(456, v.MajorUnit);\n            Assert.Equal(9, v.MinorUnit);\n            Assert.Equal(1, v.Sign);\n\n            v = new FungibleAssetValue(FOO, 0, 10);\n            Assert.Equal(new FungibleAssetValue(FOO, 1, 0, 10), v);\n            Assert.Equal(10, v.RawValue);\n            Assert.Equal(0, v.MajorUnit);\n            Assert.Equal(10, v.MinorUnit);\n            Assert.Equal(1, v.Sign);\n\n            v = new FungibleAssetValue(FOO, 0, 9);\n            Assert.Equal(new FungibleAssetValue(FOO, 1, 0, 9), v);\n            Assert.Equal(9, v.RawValue);\n            Assert.Equal(0, v.MajorUnit);\n            Assert.Equal(9, v.MinorUnit);\n            Assert.Equal(1, v.Sign);\n\n            v = new FungibleAssetValue(FOO, -789, 1);\n            Assert.Equal(new FungibleAssetValue(FOO, -1, 789, 1), v);\n            Assert.Equal(-78901, v.RawValue);\n            Assert.Equal(789, v.MajorUnit);\n            Assert.Equal(1, v.MinorUnit);\n            Assert.Equal(-1, v.Sign);\n\n            v = new FungibleAssetValue(FOO, 0, -2);\n            Assert.Equal(new FungibleAssetValue(FOO, -1, 0, 2), v);\n            Assert.Equal(-2, v.RawValue);\n            Assert.Equal(0, v.MajorUnit);\n            Assert.Equal(2, v.MinorUnit);\n            Assert.Equal(-1, v.Sign);\n\n            v = new FungibleAssetValue(FOO, 123, 0);\n            Assert.Equal(new FungibleAssetValue(FOO, 1, 123, 0), v);\n            Assert.Equal(12300, v.RawValue);\n            Assert.Equal(123, v.MajorUnit);\n            Assert.Equal(0, v.MinorUnit);\n            Assert.Equal(1, v.Sign);\n\n            v = new FungibleAssetValue(BAR, 1, 0);\n            Assert.Equal(new FungibleAssetValue(BAR, 1, 1, 0), v);\n            Assert.Equal(FungibleAssetValue.FromRawValue(BAR, 1), v);\n            Assert.Equal(1, v.RawValue);\n            Assert.Equal(1, v.MajorUnit);\n            Assert.Equal(0, v.MinorUnit);\n            Assert.Equal(1, v.Sign);\n\n            v = new FungibleAssetValue(FOO, 0, 0);\n            Assert.Equal(new FungibleAssetValue(FOO, 0, 0, 0), v);\n            Assert.Equal(new FungibleAssetValue(FOO), v);\n            Assert.Equal(0, v.RawValue);\n            Assert.Equal(0, v.MajorUnit);\n            Assert.Equal(0, v.MinorUnit);\n            Assert.Equal(0, v.Sign);\n\n            Assert.Throws<ArgumentException>(() => new FungibleAssetValue(FOO, -2, 1, 0));\n            Assert.Throws<ArgumentException>(() => new FungibleAssetValue(FOO, 2, 1, 0));\n            Assert.Throws<ArgumentException>(() => new FungibleAssetValue(FOO, 0, 1, 0));\n            Assert.Throws<ArgumentException>(() => new FungibleAssetValue(FOO, 0, 0, 1));\n            Assert.Throws<ArgumentException>(() => new FungibleAssetValue(FOO, 1, -1, 0));\n            Assert.Throws<ArgumentException>(() => new FungibleAssetValue(FOO, 1, 1, -1));\n            Assert.Throws<ArgumentException>(() => new FungibleAssetValue(FOO, 1, 1, 100));\n            Assert.Throws<ArgumentException>(() => new FungibleAssetValue(FOO, 10, -10));\n            Assert.Throws<ArgumentException>(() => new FungibleAssetValue(FOO, -10, -10));\n            Assert.Throws<ArgumentException>(() => new FungibleAssetValue(FOO, 1, 100));\n            Assert.Throws<ArgumentException>(() => new FungibleAssetValue(BAR, 1, 2));\n        }\n\n        [Fact]\n        public void Equality()\n        {\n            FungibleAssetValue foo100a = FungibleAssetValue.FromRawValue(FOO, 100);\n            FungibleAssetValue foo100b = FungibleAssetValue.FromRawValue(FOO, 100);\n            FungibleAssetValue foo200a = FungibleAssetValue.FromRawValue(FOO, 200);\n            FungibleAssetValue foo200b = FungibleAssetValue.FromRawValue(FOO, 200);\n            FungibleAssetValue bar100a = FungibleAssetValue.FromRawValue(BAR, 100);\n            FungibleAssetValue bar100b = FungibleAssetValue.FromRawValue(BAR, 100);\n            FungibleAssetValue bar200a = FungibleAssetValue.FromRawValue(BAR, 200);\n            FungibleAssetValue bar200b = FungibleAssetValue.FromRawValue(BAR, 200);\n            FungibleAssetValue barmax100 = FungibleAssetValue.FromRawValue(BARMAX, 100);\n            FungibleAssetValue barnotrack100 = FungibleAssetValue.FromRawValue(BARNOTRACK, 100);\n\n            Assert.Equal(foo100b, foo100a);\n            Assert.Equal(foo100b.GetHashCode(), foo100a.GetHashCode());\n            Assert.True(foo100b.Equals((object)foo100a));\n            Assert.True(foo100b == foo100a);\n            Assert.False(foo100b != foo100a);\n            Assert.Equal(foo200b, foo200a);\n            Assert.Equal(foo200b.GetHashCode(), foo200a.GetHashCode());\n            Assert.True(foo200b.Equals((object)foo200a));\n            Assert.True(foo200b == foo200a);\n            Assert.False(foo200b != foo200a);\n            Assert.Equal(bar100b, bar100a);\n            Assert.Equal(bar100b.GetHashCode(), bar100a.GetHashCode());\n            Assert.True(bar100b.Equals((object)bar100a));\n            Assert.True(bar100b == bar100a);\n            Assert.False(bar100b != bar100a);\n            Assert.Equal(bar200b, bar200a);\n            Assert.Equal(bar200b.GetHashCode(), bar200a.GetHashCode());\n            Assert.True(bar200b.Equals((object)bar200a));\n            Assert.True(bar200b == bar200a);\n            Assert.False(bar200b != bar200a);\n\n            Assert.NotEqual(foo100a, foo200a);\n            Assert.False(foo100a.Equals((object)foo200a));\n            Assert.False(foo100a == foo200a);\n            Assert.True(foo100a != foo200a);\n            Assert.NotEqual(foo100a, bar100a);\n            Assert.False(foo100a.Equals((object)bar100a));\n            Assert.False(foo100a == bar100a);\n            Assert.True(foo100a != bar100a);\n            Assert.NotEqual(foo100a, bar200a);\n            Assert.False(foo100a.Equals((object)bar200a));\n            Assert.False(foo100a == bar200a);\n            Assert.True(foo100a != bar200a);\n            Assert.NotEqual(bar100a, foo200a);\n            Assert.False(bar100a.Equals((object)foo200a));\n            Assert.False(bar100a == foo200a);\n            Assert.True(bar100a != foo200a);\n            Assert.NotEqual(foo100a, bar100a);\n            Assert.False(foo100a.Equals((object)bar100a));\n            Assert.False(foo100a == bar100a);\n            Assert.True(foo100a != bar100a);\n            Assert.NotEqual(foo100a, bar200a);\n            Assert.False(foo100a.Equals((object)bar200a));\n            Assert.False(foo100a == bar200a);\n            Assert.True(foo100a != bar200a);\n            Assert.NotEqual(bar100a, barmax100);\n            Assert.False(bar100a.Equals((object)barmax100));\n            Assert.False(bar100a == barmax100);\n            Assert.True(bar100a != barmax100);\n            Assert.NotEqual(bar100a, barnotrack100);\n            Assert.False(bar100a.Equals((object)barnotrack100));\n            Assert.False(bar100a == barnotrack100);\n            Assert.True(bar100a != barnotrack100);\n\n            Assert.False(foo100a.Equals(100));\n            Assert.False(foo200a.Equals(200));\n        }\n\n        [Fact]\n        public void Compare()\n        {\n            FungibleAssetValue foo100a = FungibleAssetValue.FromRawValue(FOO, 100);\n            FungibleAssetValue foo100b = FungibleAssetValue.FromRawValue(FOO, 100);\n            FungibleAssetValue foo200 = FungibleAssetValue.FromRawValue(FOO, 200);\n            FungibleAssetValue bar100 = FungibleAssetValue.FromRawValue(BAR, 100);\n            FungibleAssetValue barmax100 = FungibleAssetValue.FromRawValue(BARMAX, 100);\n            FungibleAssetValue barnotrack100 = FungibleAssetValue.FromRawValue(BARNOTRACK, 100);\n\n            Assert.Equal(0, foo100a.CompareTo(foo100b));\n            Assert.Equal(0, foo100a.CompareTo((object)foo100b));\n            Assert.False(foo100a < foo100b);\n            Assert.True(foo100a <= foo100b);\n            Assert.False(foo100a > foo100b);\n            Assert.True(foo100a >= foo100b);\n\n            Assert.True(foo100a.CompareTo(foo200) < 0);\n            Assert.True(foo100a.CompareTo((object)foo200) < 0);\n            Assert.True(foo100a < foo200);\n            Assert.True(foo100a <= foo200);\n            Assert.False(foo100a > foo200);\n            Assert.False(foo100a >= foo200);\n\n            Assert.True(foo200.CompareTo(foo100b) > 0);\n            Assert.True(foo200.CompareTo((object)foo100b) > 0);\n            Assert.False(foo200 < foo100b);\n            Assert.False(foo200 <= foo100b);\n            Assert.True(foo200 > foo100b);\n            Assert.True(foo200 >= foo100b);\n\n            Assert.Throws<ArgumentException>(() => foo100a.CompareTo(bar100));\n            Assert.Throws<ArgumentException>(() => foo100a.CompareTo((object)bar100));\n            Assert.Throws<ArgumentException>(() => foo100a < bar100);\n            Assert.Throws<ArgumentException>(() => foo100a <= bar100);\n            Assert.Throws<ArgumentException>(() => foo100a > bar100);\n            Assert.Throws<ArgumentException>(() => foo100a >= bar100);\n\n            Assert.Throws<ArgumentException>(() => bar100.CompareTo(barmax100));\n            Assert.Throws<ArgumentException>(() => bar100.CompareTo((object)barmax100));\n            Assert.Throws<ArgumentException>(() => bar100 < barmax100);\n            Assert.Throws<ArgumentException>(() => bar100 <= barmax100);\n            Assert.Throws<ArgumentException>(() => bar100 > barmax100);\n            Assert.Throws<ArgumentException>(() => bar100 >= barmax100);\n\n            Assert.Throws<ArgumentException>(() => bar100.CompareTo(barnotrack100));\n            Assert.Throws<ArgumentException>(() => bar100.CompareTo((object)barnotrack100));\n            Assert.Throws<ArgumentException>(() => bar100 < barnotrack100);\n            Assert.Throws<ArgumentException>(() => bar100 <= barnotrack100);\n            Assert.Throws<ArgumentException>(() => bar100 > barnotrack100);\n            Assert.Throws<ArgumentException>(() => bar100 >= barnotrack100);\n\n            Assert.Throws<ArgumentException>(() => foo100a.CompareTo(100));\n        }\n\n        [Fact]\n        public void Negate()\n        {\n            FungibleAssetValue foo_3 = FungibleAssetValue.FromRawValue(FOO, -3);\n            FungibleAssetValue foo0 = new FungibleAssetValue(FOO);\n            FungibleAssetValue foo3 = FungibleAssetValue.FromRawValue(FOO, 3);\n\n            Assert.Equal(foo_3, -foo3);\n            Assert.Equal(foo3, -foo_3);\n            Assert.Equal(foo0, -foo0);\n        }\n\n        [Fact]\n        public void Add()\n        {\n            FungibleAssetValue foo_1 = FungibleAssetValue.FromRawValue(FOO, -1);\n            FungibleAssetValue foo0 = new FungibleAssetValue(FOO);\n            FungibleAssetValue foo1 = FungibleAssetValue.FromRawValue(FOO, 1);\n            FungibleAssetValue foo2 = FungibleAssetValue.FromRawValue(FOO, 2);\n            FungibleAssetValue foo3 = FungibleAssetValue.FromRawValue(FOO, 3);\n            FungibleAssetValue bar3 = FungibleAssetValue.FromRawValue(BAR, 3);\n            FungibleAssetValue barmax3 = FungibleAssetValue.FromRawValue(BARMAX, 3);\n            FungibleAssetValue barnotrack3 = FungibleAssetValue.FromRawValue(BARNOTRACK, 3);\n\n            Assert.Equal(foo1, foo1 + foo0);\n            Assert.Equal(foo1, foo0 + foo1);\n            Assert.Equal(foo2, foo1 + foo1);\n            Assert.Equal(foo3, foo1 + foo2);\n            Assert.Equal(foo3, foo2 + foo1);\n            Assert.Equal(foo1, foo2 + foo_1);\n            Assert.Equal(foo1, foo_1 + foo2);\n            Assert.Equal(foo_1, foo_1 + foo0);\n            Assert.Equal(foo_1, foo0 + foo_1);\n\n            Assert.Throws<ArgumentException>(() => foo1 + bar3);\n            Assert.Throws<ArgumentException>(() => bar3 + barmax3);\n            Assert.Throws<ArgumentException>(() => bar3 + barnotrack3);\n        }\n\n        [Fact]\n        public void Subtract()\n        {\n            FungibleAssetValue foo_1 = FungibleAssetValue.FromRawValue(FOO, -1);\n            FungibleAssetValue foo0 = new FungibleAssetValue(FOO);\n            FungibleAssetValue foo1 = FungibleAssetValue.FromRawValue(FOO, 1);\n            FungibleAssetValue foo2 = FungibleAssetValue.FromRawValue(FOO, 2);\n            FungibleAssetValue bar3 = FungibleAssetValue.FromRawValue(BAR, 3);\n            FungibleAssetValue barmax3 = FungibleAssetValue.FromRawValue(BARMAX, 3);\n            FungibleAssetValue barnotrack3 = FungibleAssetValue.FromRawValue(BARNOTRACK, 3);\n\n            Assert.Equal(foo0, foo1 - foo1);\n            Assert.Equal(foo_1, foo1 - foo2);\n            Assert.Equal(foo2, foo1 - foo_1);\n            Assert.Equal(foo0, foo_1 - foo_1);\n\n            Assert.Throws<ArgumentException>(() => bar3 - foo1);\n            Assert.Throws<ArgumentException>(() => bar3 - barmax3);\n            Assert.Throws<ArgumentException>(() => bar3 - barnotrack3);\n        }\n\n        [Fact]\n        public void Multiply()\n        {\n            FungibleAssetValue foo_2 = FungibleAssetValue.FromRawValue(FOO, -2);\n            FungibleAssetValue foo_1 = FungibleAssetValue.FromRawValue(FOO, -1);\n            FungibleAssetValue foo0 = new FungibleAssetValue(FOO);\n            FungibleAssetValue foo1 = FungibleAssetValue.FromRawValue(FOO, 1);\n            FungibleAssetValue foo2 = FungibleAssetValue.FromRawValue(FOO, 2);\n            FungibleAssetValue foo4 = FungibleAssetValue.FromRawValue(FOO, 4);\n\n            Assert.Equal(foo2, foo1 * 2);\n            Assert.Equal(foo2, 2 * foo1);\n            Assert.Equal(foo2, foo2 * 1);\n            Assert.Equal(foo2, 1 * foo2);\n            Assert.Equal(foo_2, foo2 * -1);\n            Assert.Equal(foo_2, -1 * foo2);\n            Assert.Equal(foo_2, foo_1 * 2);\n            Assert.Equal(foo_2, 2 * foo_1);\n            Assert.Equal(foo_1, foo_1 * 1);\n            Assert.Equal(foo_1, 1 * foo_1);\n            Assert.Equal(foo4, foo2 * 2);\n            Assert.Equal(foo4, 2 * foo2);\n            Assert.Equal(foo0, foo2 * 0);\n            Assert.Equal(foo0, 0 * foo2);\n            Assert.Equal(foo0, foo_1 * 0);\n            Assert.Equal(foo0, 0 * foo_1);\n        }\n\n        [Fact]\n        public void DivRem()\n        {\n            FungibleAssetValue foo7 = FungibleAssetValue.FromRawValue(FOO, 7);\n            FungibleAssetValue foo6 = FungibleAssetValue.FromRawValue(FOO, 6);\n            FungibleAssetValue foo3 = FungibleAssetValue.FromRawValue(FOO, 3);\n            FungibleAssetValue foo2 = FungibleAssetValue.FromRawValue(FOO, 2);\n            FungibleAssetValue foo1 = FungibleAssetValue.FromRawValue(FOO, 1);\n            FungibleAssetValue foo0 = new FungibleAssetValue(FOO);\n            FungibleAssetValue rem;\n\n            Assert.Equal((foo6, foo0), foo6.DivRem(1));\n            Assert.Equal(foo6, foo6.DivRem(1, out rem));\n            Assert.Equal(foo0, rem);\n            Assert.Equal(foo0, foo6 % 1);\n\n            Assert.Equal((foo2, foo0), foo6.DivRem(3));\n            Assert.Equal(foo2, foo6.DivRem(3, out rem));\n            Assert.Equal(foo0, rem);\n            Assert.Equal(foo0, foo6 % 3);\n\n            Assert.Equal((foo2, foo1), foo7.DivRem(3));\n            Assert.Equal(foo2, foo7.DivRem(3, out rem));\n            Assert.Equal(foo1, rem);\n            Assert.Equal(foo1, foo7 % 3);\n\n            Assert.Equal((foo0, foo6), foo6.DivRem(7));\n            Assert.Equal(foo0, foo6.DivRem(7, out rem));\n            Assert.Equal(foo6, rem);\n            Assert.Equal(foo6, foo6 % 7);\n\n            Assert.Equal((foo0, foo0), foo0.DivRem(2));\n            Assert.Equal(foo0, foo0.DivRem(2, out rem));\n            Assert.Equal(foo0, rem);\n            Assert.Equal(foo0, foo0 % 2);\n\n            Assert.Equal((6, foo0), foo6.DivRem(foo1));\n            Assert.Equal(6, foo6.DivRem(foo1, out rem));\n            Assert.Equal(foo0, rem);\n            Assert.Equal(foo0, foo6 % foo1);\n\n            Assert.Equal((2, foo0), foo6.DivRem(foo3));\n            Assert.Equal(2, foo6.DivRem(foo3, out rem));\n            Assert.Equal(foo0, rem);\n            Assert.Equal(foo0, foo6 % foo3);\n\n            Assert.Equal((2, foo1), foo7.DivRem(foo3));\n            Assert.Equal(2, foo7.DivRem(foo3, out rem));\n            Assert.Equal(foo1, rem);\n            Assert.Equal(foo1, foo7 % foo3);\n\n            Assert.Equal((0, foo6), foo6.DivRem(foo7));\n            Assert.Equal(0, foo6.DivRem(foo7, out rem));\n            Assert.Equal(foo6, rem);\n            Assert.Equal(foo6, foo6 % foo7);\n\n            Assert.Equal((0, foo0), foo0.DivRem(foo2));\n            Assert.Equal(0, foo0.DivRem(foo2, out rem));\n            Assert.Equal(foo0, rem);\n            Assert.Equal(foo0, foo0 % foo2);\n\n            Assert.Throws<DivideByZeroException>(() => foo1.DivRem(0));\n            Assert.Throws<DivideByZeroException>(() => foo1.DivRem(0, out rem));\n            Assert.Throws<DivideByZeroException>(() => foo1 % 0);\n            Assert.Throws<DivideByZeroException>(() => foo1.DivRem(foo0));\n            Assert.Throws<DivideByZeroException>(() => foo1.DivRem(foo0, out rem));\n            Assert.Throws<DivideByZeroException>(() => foo1 % foo0);\n\n            FungibleAssetValue bar1 = FungibleAssetValue.FromRawValue(BAR, 1);\n            Assert.Throws<ArgumentException>(() => bar1.DivRem(foo1));\n            Assert.Throws<ArgumentException>(() => bar1.DivRem(foo1, out rem));\n            Assert.Throws<ArgumentException>(() => bar1 % foo1);\n        }\n\n        [Fact]\n        public void Abs()\n        {\n            FungibleAssetValue foo_3 = FungibleAssetValue.FromRawValue(FOO, -3);\n            FungibleAssetValue foo0 = new FungibleAssetValue(FOO);\n            FungibleAssetValue foo3 = FungibleAssetValue.FromRawValue(FOO, 3);\n\n            Assert.Equal(foo3, foo3.Abs());\n            Assert.Equal(foo3, foo_3.Abs());\n            Assert.Equal(foo0, foo0.Abs());\n        }\n\n        [Fact]\n        public void GetQuantityString()\n        {\n            FungibleAssetValue v;\n            v = new FungibleAssetValue(FOO, 123, 45);\n            Assert.Equal(\"123.45\", v.GetQuantityString());\n            Assert.Equal(\"123.45\", v.GetQuantityString(true));\n\n            v = new FungibleAssetValue(FOO, 456, 9);\n            Assert.Equal(\"456.09\", v.GetQuantityString());\n            Assert.Equal(\"456.09\", v.GetQuantityString(true));\n\n            v = new FungibleAssetValue(FOO, 0, 10);\n            Assert.Equal(\"0.1\", v.GetQuantityString());\n            Assert.Equal(\"0.10\", v.GetQuantityString(true));\n\n            v = new FungibleAssetValue(FOO, 0, 9);\n            Assert.Equal(\"0.09\", v.GetQuantityString());\n            Assert.Equal(\"0.09\", v.GetQuantityString(true));\n\n            v = new FungibleAssetValue(FOO, -789, 1);\n            Assert.Equal(\"-789.01\", v.GetQuantityString());\n            Assert.Equal(\"-789.01\", v.GetQuantityString(true));\n\n            v = new FungibleAssetValue(FOO, 0, -2);\n            Assert.Equal(\"-0.02\", v.GetQuantityString());\n            Assert.Equal(\"-0.02\", v.GetQuantityString(true));\n\n            v = new FungibleAssetValue(FOO, 123, 0);\n            Assert.Equal(\"123\", v.GetQuantityString());\n            Assert.Equal(\"123.00\", v.GetQuantityString(true));\n\n            v = new FungibleAssetValue(FOO, 0, 0);\n            Assert.Equal(\"0\", v.GetQuantityString());\n            Assert.Equal(\"0.00\", v.GetQuantityString(true));\n        }\n\n        [Fact]\n        public void String()\n        {\n            FungibleAssetValue foo100 = FungibleAssetValue.FromRawValue(FOO, 100);\n            FungibleAssetValue bar90000000 = FungibleAssetValue.FromRawValue(BAR, 90000000);\n            Assert.Equal(\"1 FOO\", foo100.ToString());\n            Assert.Equal(\"90000000 BAR\", bar90000000.ToString());\n        }\n\n        [Fact]\n        public void Parse()\n        {\n            var baz = Currency.Uncapped(\"BAZ\", 1, null);\n            FormatException e;\n\n            e = Assert.Throws<FormatException>(() => FungibleAssetValue.Parse(FOO, \"abc\"));\n            Assert.StartsWith(\"The value string must consist of digits\", e.Message);\n\n            const string signError = \"Plus (+) or minus (-) sign can be appeared only at\";\n            e = Assert.Throws<FormatException>(() => FungibleAssetValue.Parse(FOO, \"++123\"));\n            Assert.StartsWith(signError, e.Message);\n            e = Assert.Throws<FormatException>(() => FungibleAssetValue.Parse(FOO, \"--123\"));\n            Assert.StartsWith(signError, e.Message);\n            e = Assert.Throws<FormatException>(() => FungibleAssetValue.Parse(FOO, \"++123.45\"));\n            Assert.StartsWith(signError, e.Message);\n            e = Assert.Throws<FormatException>(() => FungibleAssetValue.Parse(FOO, \"--123.45\"));\n            Assert.StartsWith(signError, e.Message);\n            e = Assert.Throws<FormatException>(() => FungibleAssetValue.Parse(FOO, \"23.4-5\"));\n            Assert.StartsWith(signError, e.Message);\n            e = Assert.Throws<FormatException>(() => FungibleAssetValue.Parse(FOO, \"45.6+7\"));\n            Assert.StartsWith(signError, e.Message);\n            e = Assert.Throws<FormatException>(() => FungibleAssetValue.Parse(FOO, \"2-3\"));\n            Assert.StartsWith(signError, e.Message);\n            e = Assert.Throws<FormatException>(() => FungibleAssetValue.Parse(FOO, \"45+6\"));\n            Assert.StartsWith(signError, e.Message);\n            e = Assert.Throws<FormatException>(() => FungibleAssetValue.Parse(FOO, \"+12-3\"));\n            Assert.StartsWith(signError, e.Message);\n            e = Assert.Throws<FormatException>(() => FungibleAssetValue.Parse(FOO, \"-45+6\"));\n            Assert.StartsWith(signError, e.Message);\n\n            const string decimalSeparatorError = \"The decimal separator (.) cannot be appeared\";\n            e = Assert.Throws<FormatException>(() => FungibleAssetValue.Parse(FOO, \"123..4\"));\n            Assert.Contains(decimalSeparatorError, e.Message);\n            e = Assert.Throws<FormatException>(() => FungibleAssetValue.Parse(FOO, \"123.4.5\"));\n            Assert.Contains(decimalSeparatorError, e.Message);\n\n            const string decimalsError = \"does not allow more than\";\n            e = Assert.Throws<FormatException>(() => FungibleAssetValue.Parse(FOO, \"123.456\"));\n            Assert.Contains(decimalsError, e.Message);\n            e = Assert.Throws<FormatException>(() => FungibleAssetValue.Parse(BAR, \"123.0\"));\n            Assert.Contains(decimalsError, e.Message);\n            e = Assert.Throws<FormatException>(() => FungibleAssetValue.Parse(baz, \"123.12\"));\n            Assert.Contains(decimalsError, e.Message);\n\n            Assert.Equal(\n                new FungibleAssetValue(FOO, 123, 45),\n                FungibleAssetValue.Parse(FOO, \"123.45\")\n            );\n            Assert.Equal(\n                new FungibleAssetValue(FOO, 123, 45),\n                FungibleAssetValue.Parse(FOO, \"+123.45\")\n            );\n            Assert.Equal(\n                new FungibleAssetValue(FOO, -123, 45),\n                FungibleAssetValue.Parse(FOO, \"-123.45\")\n            );\n            Assert.Equal(\n                new FungibleAssetValue(FOO, 123, 40),\n                FungibleAssetValue.Parse(FOO, \"123.4\")\n            );\n            Assert.Equal(\n                new FungibleAssetValue(FOO, 123, 40),\n                FungibleAssetValue.Parse(FOO, \"+123.4\")\n            );\n            Assert.Equal(\n                new FungibleAssetValue(FOO, -123, 40),\n                FungibleAssetValue.Parse(FOO, \"-123.4\")\n            );\n            Assert.Equal(new FungibleAssetValue(FOO, 123, 0), FungibleAssetValue.Parse(FOO, \"123\"));\n            Assert.Equal(new FungibleAssetValue(FOO, 12, 0), FungibleAssetValue.Parse(FOO, \"+12\"));\n            Assert.Equal(new FungibleAssetValue(FOO, -12, 0), FungibleAssetValue.Parse(FOO, \"-12\"));\n        }\n\n        [SkippableFact]\n        public void JsonSerialization()\n        {\n            var v = new FungibleAssetValue(FOO, 123, 45);\n            AssertJsonSerializable(v, @\"\n                {\n                    \"\"quantity\"\": \"\"123.45\"\",\n                    \"\"currency\"\": {\n                        \"\"hash\"\": \"\"946ea39b6f49926c0ed3df2a3aa0d2aba0f0fc25\"\",\n                        \"\"ticker\"\": \"\"FOO\"\",\n                        \"\"decimalPlaces\"\": 2,\n                        \"\"minters\"\": null,\n                        \"\"maximumSupply\"\": null,\n                        \"\"totalSupplyTrackable\"\": true,\n                    }\n                }\n            \");\n\n            v = new FungibleAssetValue(FOO, -456, 0);\n            AssertJsonSerializable(v, @\"\n                {\n                    \"\"quantity\"\": \"\"-456\"\",\n                    \"\"currency\"\": {\n                        \"\"hash\"\": \"\"946ea39b6f49926c0ed3df2a3aa0d2aba0f0fc25\"\",\n                        \"\"ticker\"\": \"\"FOO\"\",\n                        \"\"decimalPlaces\"\": 2,\n                        \"\"minters\"\": null,\n                        \"\"maximumSupply\"\": null,\n                        \"\"totalSupplyTrackable\"\": true,\n                    }\n                }\n            \");\n        }\n    }\n}\n\n#pragma warning restore S1764\n"
  },
  {
    "path": "test/Libplanet.Tests/BlockChainExtensions.cs",
    "content": "using System.Security.Cryptography;\nusing Libplanet.Action.State;\nusing Libplanet.Blockchain;\nusing Libplanet.Common;\nusing Libplanet.Types.Blocks;\n\nnamespace Libplanet.Tests\n{\n    public static class BlockChainExtensions\n    {\n        /// <summary>\n        /// Returns an <see cref=\"IWorldState\"/> resulting from the execution of\n        /// the tip of <paramref name=\"blockChain\"/>.\n        /// </summary>\n        /// <param name=\"blockChain\">The <see cref=\"BlockChain\"/> to search.</param>\n        /// <returns>An <see cref=\"IWorldState\"/> resulting from the execution of\n        /// the tip of <paramref name=\"blockChain\"/>.</returns>\n        public static IWorldState GetNextWorldState(this BlockChain blockChain) =>\n            blockChain.GetNextStateRootHash() is HashDigest<SHA256> stateRootHash\n                ? blockChain.GetWorldState(stateRootHash)\n                : null;\n\n        /// <summary>\n        /// Returns an <see cref=\"IWorldState\"/> resulting from the execution of\n        /// a <see cref=\"Block\"/> associated with given <paramref name=\"index\"/>\n        /// from <paramref name=\"blockChain\"/>.\n        /// </summary>\n        /// <param name=\"blockChain\">The <see cref=\"BlockChain\"/> to search.</param>\n        /// <param name=\"index\">The index of a <see cref=\"Block\"/> to search.</param>\n        /// <returns>An <see cref=\"IWorldState\"/> resulting from the execution of\n        /// a <see cref=\"Block\"/> associated with given <paramref name=\"index\"/>.</returns>\n        public static IWorldState GetNextWorldState(this BlockChain blockChain, long index) =>\n            blockChain.GetNextStateRootHash(index) is HashDigest<SHA256> stateRootHash\n                ? blockChain.GetWorldState(stateRootHash)\n                : null;\n\n        /// <summary>\n        /// Returns an <see cref=\"IWorldState\"/> resulting from the execution of\n        /// a <see cref=\"Block\"/> associated with given <paramref name=\"blockHash\"/>\n        /// from <paramref name=\"blockChain\"/>.\n        /// </summary>\n        /// <param name=\"blockChain\">The <see cref=\"BlockChain\"/> to search.</param>\n        /// <param name=\"blockHash\">The <see cref=\"BlockHash\"/> to search.</param>\n        /// <returns>An <see cref=\"IWorldState\"/> resulting from the execution of\n        /// a <see cref=\"Block\"/> associated with given <paramref name=\"blockHash\"/>.</returns>\n        public static IWorldState GetNextWorldState(\n            this BlockChain blockChain,\n            BlockHash blockHash) =>\n            blockChain.GetNextStateRootHash(blockHash) is HashDigest<SHA256> stateRootHash\n                ? blockChain.GetWorldState(stateRootHash)\n                : null;\n    }\n}\n"
  },
  {
    "path": "test/Libplanet.Tests/Blockchain/BlockChainTest.Append.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Collections.Immutable;\nusing System.Linq;\nusing System.Security.Cryptography;\nusing Bencodex.Types;\nusing Libplanet.Action;\nusing Libplanet.Action.Loader;\nusing Libplanet.Action.State;\nusing Libplanet.Action.Sys;\nusing Libplanet.Action.Tests.Common;\nusing Libplanet.Blockchain;\nusing Libplanet.Blockchain.Policies;\nusing Libplanet.Blockchain.Renderers;\nusing Libplanet.Blockchain.Renderers.Debug;\nusing Libplanet.Common;\nusing Libplanet.Crypto;\nusing Libplanet.Store;\nusing Libplanet.Store.Trie;\nusing Libplanet.Tests.Store;\nusing Libplanet.Types.Blocks;\nusing Libplanet.Types.Evidence;\nusing Libplanet.Types.Tx;\nusing Serilog;\nusing Xunit;\n\nnamespace Libplanet.Tests.Blockchain\n{\n    public partial class BlockChainTest\n    {\n        [SkippableTheory]\n        [InlineData(true)]\n        [InlineData(false)]\n        public void Append(bool getTxExecutionViaStore)\n        {\n            Func<BlockHash, TxId, TxExecution> getTxExecution\n                = getTxExecutionViaStore\n                ? (Func<BlockHash, TxId, TxExecution>)_blockChain.Store.GetTxExecution\n                : _blockChain.GetTxExecution;\n\n            PrivateKey[] keys = Enumerable.Repeat(0, 5).Select(_ => new PrivateKey()).ToArray();\n            (Address[] addresses, Transaction[] txs) =\n                MakeFixturesForAppendTests(keys: keys);\n            var genesis = _blockChain.Genesis;\n\n            Assert.Equal(1, _blockChain.Count);\n            Assert.Empty(_renderer.ActionRecords);\n            Assert.Empty(_renderer.BlockRecords);\n            var block1 = _blockChain.ProposeBlock(\n                keys[4], TestUtils.CreateBlockCommit(_blockChain.Tip));\n            _blockChain.Append(block1, TestUtils.CreateBlockCommit(block1));\n            Assert.NotNull(_blockChain.GetBlockCommit(block1.Hash));\n            Block block2 = _blockChain.ProposeBlock(\n                keys[4],\n                txs.ToImmutableList(),\n                lastCommit: TestUtils.CreateBlockCommit(block1),\n                evidence: ImmutableArray<EvidenceBase>.Empty);\n            foreach (Transaction tx in txs)\n            {\n                Assert.Null(getTxExecution(genesis.Hash, tx.Id));\n                Assert.Null(getTxExecution(block1.Hash, tx.Id));\n                Assert.Null(getTxExecution(block2.Hash, tx.Id));\n            }\n\n            foreach (var tx in txs)\n            {\n                Assert.Null(_fx.Store.GetFirstTxIdBlockHashIndex(tx.Id));\n            }\n\n            _blockChain.Append(block2, TestUtils.CreateBlockCommit(block2));\n\n            foreach (var tx in txs)\n            {\n                Assert.True(_fx.Store.GetFirstTxIdBlockHashIndex(tx.Id)?.Equals(block2.Hash));\n            }\n\n            Assert.True(_blockChain.ContainsBlock(block2.Hash));\n\n            RenderRecord.ActionSuccess[] renders = _renderer.ActionSuccessRecords\n                .Where(r => TestUtils.IsDumbAction(r.Action))\n                .ToArray();\n            DumbAction[] actions = renders.Select(r => TestUtils.ToDumbAction(r.Action)).ToArray();\n            Assert.Equal(4, renders.Length);\n            Assert.True(renders.All(r => r.Render));\n            Assert.Equal(\"foo\", actions[0].Append?.Item);\n            Assert.Equal(2, renders[0].Context.BlockIndex);\n            Assert.Equal(\n                new IValue[] { null, null, null, null, (Integer)1 },\n                addresses.Select(_blockChain\n                    .GetWorldState(renders[0].Context.PreviousState)\n                    .GetAccountState(ReservedAddresses.LegacyAccount)\n                    .GetState)\n            );\n            Assert.Equal(\n                new IValue[] { (Text)\"foo\", null, null, null, (Integer)1 },\n                addresses.Select(_blockChain\n                    .GetWorldState(renders[0].NextState)\n                    .GetAccountState(ReservedAddresses.LegacyAccount)\n                    .GetState)\n            );\n            Assert.Equal(\"bar\", actions[1].Append?.Item);\n            Assert.Equal(2, renders[1].Context.BlockIndex);\n            Assert.Equal(\n                addresses.Select(_blockChain\n                    .GetWorldState(renders[0].NextState)\n                    .GetAccountState(ReservedAddresses.LegacyAccount)\n                    .GetState),\n                addresses.Select(_blockChain\n                    .GetWorldState(renders[1].Context.PreviousState)\n                    .GetAccountState(ReservedAddresses.LegacyAccount)\n                    .GetState)\n            );\n            Assert.Equal(\n                new IValue[] { (Text)\"foo\", (Text)\"bar\", null, null, (Integer)1 },\n                addresses.Select(\n                    _blockChain.GetWorldState(renders[1].NextState)\n                        .GetAccountState(ReservedAddresses.LegacyAccount).GetState)\n            );\n            Assert.Equal(\"baz\", actions[2].Append?.Item);\n            Assert.Equal(2, renders[2].Context.BlockIndex);\n            Assert.Equal(\n                addresses.Select(\n                    _blockChain.GetWorldState(renders[1].NextState)\n                        .GetAccountState(ReservedAddresses.LegacyAccount).GetState),\n                addresses.Select(\n                    _blockChain.GetWorldState(renders[2].Context.PreviousState)\n                        .GetAccountState(ReservedAddresses.LegacyAccount).GetState)\n            );\n            Assert.Equal(\n                new IValue[] { (Text)\"foo\", (Text)\"bar\", (Text)\"baz\", null, (Integer)1 },\n                addresses.Select(\n                    _blockChain\n                        .GetWorldState(renders[2].NextState)\n                        .GetAccountState(ReservedAddresses.LegacyAccount)\n                        .GetState)\n            );\n            Assert.Equal(\"qux\", actions[3].Append?.Item);\n            Assert.Equal(2, renders[3].Context.BlockIndex);\n            Assert.Equal(\n                addresses.Select(\n                    _blockChain\n                        .GetWorldState(renders[2].NextState)\n                        .GetAccountState(ReservedAddresses.LegacyAccount)\n                        .GetState),\n                addresses.Select(\n                    _blockChain\n                        .GetWorldState(renders[3].Context.PreviousState)\n                        .GetAccountState(ReservedAddresses.LegacyAccount)\n                        .GetState)\n            );\n            Assert.Equal(\n                new IValue[]\n                {\n                    (Text)\"foo\", (Text)\"bar\", (Text)\"baz\", (Text)\"qux\", (Integer)1,\n                },\n                _blockChain\n                    .GetWorldState(renders[3].NextState)\n                    .GetAccountState(ReservedAddresses.LegacyAccount)\n                    .GetStates(addresses)\n            );\n\n            Address minerAddress = addresses[4];\n            RenderRecord.ActionSuccess[] blockRenders = _renderer.ActionSuccessRecords\n                .Where(r => TestUtils.IsMinerReward(r.Action))\n                .ToArray();\n\n            Assert.Equal(\n                (Integer)2,\n                (Integer)_blockChain\n                    .GetNextWorldState()\n                    .GetAccountState(ReservedAddresses.LegacyAccount)\n                    .GetState(minerAddress));\n            Assert.Equal(2, blockRenders.Length);\n            Assert.True(blockRenders.All(r => r.Render));\n            Assert.Equal(1, blockRenders[0].Context.BlockIndex);\n            Assert.Equal(2, blockRenders[1].Context.BlockIndex);\n\n            Assert.Equal(\n                (Integer)1,\n                (Integer)_blockChain\n                    .GetWorldState(blockRenders[0].NextState)\n                    .GetAccountState(ReservedAddresses.LegacyAccount)\n                    .GetState(minerAddress)\n            );\n            Assert.Equal(\n                (Integer)1,\n                (Integer)_blockChain\n                    .GetWorldState(blockRenders[1].Context.PreviousState)\n                    .GetAccountState(ReservedAddresses.LegacyAccount)\n                    .GetState(minerAddress)\n            );\n            Assert.Equal(\n                (Integer)2,\n                (Integer)_blockChain\n                    .GetWorldState(blockRenders[1].NextState)\n                    .GetAccountState(ReservedAddresses.LegacyAccount)\n                    .GetState(minerAddress)\n            );\n\n            foreach (Transaction tx in txs)\n            {\n                Assert.Null(getTxExecution(genesis.Hash, tx.Id));\n                Assert.Null(getTxExecution(block1.Hash, tx.Id));\n\n                TxExecution e = getTxExecution(block2.Hash, tx.Id);\n                Assert.False(e.Fail);\n                Assert.Equal(block2.Hash, e.BlockHash);\n                Assert.Equal(tx.Id, e.TxId);\n            }\n\n            TxExecution txe = getTxExecution(block2.Hash, txs[0].Id);\n            var outputWorld = _blockChain\n                .GetWorldState(Assert.IsType<HashDigest<SHA256>>(txe.OutputState));\n            Assert.Equal(\n                DumbAction.DumbCurrency * 100,\n                outputWorld.GetBalance(addresses[0], DumbAction.DumbCurrency));\n            Assert.Equal(\n                DumbAction.DumbCurrency * 100,\n                outputWorld.GetBalance(addresses[1], DumbAction.DumbCurrency));\n            Assert.Equal(\n                DumbAction.DumbCurrency * 200,\n                outputWorld.GetTotalSupply(DumbAction.DumbCurrency));\n            txe = getTxExecution(block2.Hash, txs[1].Id);\n            outputWorld = _blockChain\n                .GetWorldState(Assert.IsType<HashDigest<SHA256>>(txe.OutputState));\n            Assert.Equal(\n                DumbAction.DumbCurrency * 100,\n                outputWorld.GetBalance(addresses[2], DumbAction.DumbCurrency));\n            Assert.Equal(\n                DumbAction.DumbCurrency * 100,\n                outputWorld.GetBalance(addresses[3], DumbAction.DumbCurrency));\n            Assert.Equal(\n                DumbAction.DumbCurrency * 400,\n                outputWorld.GetTotalSupply(DumbAction.DumbCurrency));\n\n            var pk = new PrivateKey();\n            Transaction tx1Transfer = _fx.MakeTransaction(\n                new[]\n                {\n                    DumbAction.Create((pk.Address, \"foo\"), (addresses[0], addresses[1], 10)),\n                    DumbAction.Create((addresses[0], \"bar\"), (addresses[0], addresses[2], 20)),\n                },\n                nonce: 0,\n                privateKey: pk\n            );\n            Transaction tx2Error = _fx.MakeTransaction(\n                new[]\n                {\n                    // As it tries to transfer a negative value, it throws\n                    // ArgumentOutOfRangeException:\n                    DumbAction.Create((pk.Address, \"foo\"), (addresses[0], addresses[1], -5)),\n                },\n                nonce: 1,\n                privateKey: pk\n            );\n            Transaction tx3Transfer = _fx.MakeTransaction(\n                new[]\n                {\n                    DumbAction.Create((pk.Address, \"foo\"), (addresses[0], addresses[1], 5)),\n                },\n                nonce: 2,\n                privateKey: pk\n            );\n            Block block3 = _blockChain.ProposeBlock(\n                keys[4],\n                new[] { tx1Transfer, tx2Error, tx3Transfer }.ToImmutableList(),\n                TestUtils.CreateBlockCommit(_blockChain.Tip),\n                ImmutableArray<EvidenceBase>.Empty);\n            _blockChain.Append(block3, TestUtils.CreateBlockCommit(block3));\n            var txExecution1 = getTxExecution(block3.Hash, tx1Transfer.Id);\n            _logger.Verbose(nameof(txExecution1) + \" = {@TxExecution}\", txExecution1);\n            Assert.False(txExecution1.Fail);\n            var inputAccount1 = _blockChain.GetWorldState(\n                Assert.IsType<HashDigest<SHA256>>(txExecution1.InputState))\n                    .GetAccountState(ReservedAddresses.LegacyAccount);\n            var outputWorld1 = _blockChain.GetWorldState(\n                Assert.IsType<HashDigest<SHA256>>(txExecution1.OutputState));\n            var outputAccount1 = outputWorld1\n                    .GetAccountState(ReservedAddresses.LegacyAccount);\n            var accountDiff1 = AccountDiff.Create(inputAccount1, outputAccount1);\n\n            Assert.Equal(\n                (new Address[] { addresses[0], pk.Address }).ToImmutableHashSet(),\n                accountDiff1.StateDiffs.Select(kv => kv.Key).ToImmutableHashSet());\n            Assert.Equal(\n                new Text(\"foo\"),\n                outputAccount1.GetState(pk.Address));\n            Assert.Equal(\n                new Text(\"foo,bar\"),\n                outputAccount1.GetState(addresses[0]));\n            Assert.Equal(\n                DumbAction.DumbCurrency * 0,\n                outputWorld1.GetBalance(pk.Address, DumbAction.DumbCurrency));\n            Assert.Equal(\n                DumbAction.DumbCurrency * 70,\n                outputWorld1.GetBalance(addresses[0], DumbAction.DumbCurrency));\n            Assert.Equal(\n                DumbAction.DumbCurrency * 110,\n                outputWorld1.GetBalance(addresses[1], DumbAction.DumbCurrency));\n            Assert.Equal(\n                DumbAction.DumbCurrency * 120,\n                outputWorld1.GetBalance(addresses[2], DumbAction.DumbCurrency));\n\n            var txExecution2 = getTxExecution(block3.Hash, tx2Error.Id);\n            _logger.Verbose(nameof(txExecution2) + \" = {@TxExecution}\", txExecution2);\n            Assert.True(txExecution2.Fail);\n            Assert.Equal(block3.Hash, txExecution2.BlockHash);\n            Assert.Equal(tx2Error.Id, txExecution2.TxId);\n            Assert.Contains(\n                $\"{nameof(System)}.{nameof(ArgumentOutOfRangeException)}\",\n                txExecution2.ExceptionNames);\n\n            var txExecution3 = getTxExecution(block3.Hash, tx3Transfer.Id);\n            _logger.Verbose(nameof(txExecution3) + \" = {@TxExecution}\", txExecution3);\n            Assert.False(txExecution3.Fail);\n            var outputWorld3 = _blockChain.GetWorldState(\n                Assert.IsType<HashDigest<SHA256>>(txExecution3.OutputState));\n            Assert.Equal(\n                DumbAction.DumbCurrency * 0,\n                outputWorld3.GetBalance(pk.Address, DumbAction.DumbCurrency));\n            Assert.Equal(\n                DumbAction.DumbCurrency * 65,\n                outputWorld3.GetBalance(addresses[0], DumbAction.DumbCurrency));\n            Assert.Equal(\n                DumbAction.DumbCurrency * 115,\n                outputWorld3.GetBalance(addresses[1], DumbAction.DumbCurrency));\n        }\n\n        [SkippableFact]\n        public void AppendModern()\n        {\n            _blockChain = TestUtils.MakeBlockChain(\n                new NullBlockPolicy(),\n                new MemoryStore(),\n                new TrieStateStore(new MemoryKeyValueStore()),\n                new SingleActionLoader(typeof(DumbModernAction)));\n            var genesis = _blockChain.Genesis;\n            var address1 = new Address(TestUtils.GetRandomBytes(20));\n            var address2 = new Address(TestUtils.GetRandomBytes(20));\n            var miner = new PrivateKey();\n            var action1 = DumbModernAction.Create((address1, \"foo\"));\n            var action2 = DumbModernAction.Create((address2, \"bar\"));\n            var tx1 = Transaction.Create(0, miner, genesis.Hash, new[] { action1 }.ToPlainValues());\n            var tx2 = Transaction.Create(1, miner, genesis.Hash, new[] { action2 }.ToPlainValues());\n            var block1 = _blockChain.ProposeBlock(\n                miner,\n                new[] { tx1 }.ToImmutableList(),\n                TestUtils.CreateBlockCommit(_blockChain.Tip),\n                ImmutableArray<EvidenceBase>.Empty);\n            var commit1 = TestUtils.CreateBlockCommit(block1);\n            _blockChain.Append(block1, commit1);\n            var world1 = _blockChain.GetNextWorldState();\n            Assert.False(world1.Legacy);\n            Assert.Equal(\n                (Text)\"foo\",\n                world1.GetAccountState(DumbModernAction.DumbModernAddress).GetState(address1));\n            var block2 = _blockChain.ProposeBlock(\n                miner,\n                new[] { tx2 }.ToImmutableList(),\n                commit1,\n                ImmutableArray<EvidenceBase>.Empty);\n            _blockChain.Append(block2, TestUtils.CreateBlockCommit(block2));\n            var world2 = _blockChain.GetNextWorldState();\n            Assert.False(world2.Legacy);\n            Assert.Equal(\n                (Text)\"bar\",\n                world2.GetAccountState(DumbModernAction.DumbModernAddress).GetState(address2));\n        }\n\n        [SkippableFact]\n        public void AppendFailDueToInvalidBytesLength()\n        {\n            DumbAction[] manyActions =\n                Enumerable.Repeat(DumbAction.Create((default, \"_\")), 200).ToArray();\n            PrivateKey signer = null;\n            int nonce = 0;\n            var heavyTxs = new List<Transaction>();\n            for (int i = 0; i < 100; i++)\n            {\n                if (i % 25 == 0)\n                {\n                    nonce = 0;\n                    signer = new PrivateKey();\n                }\n\n                Transaction heavyTx = _fx.MakeTransaction(\n                    manyActions,\n                    nonce: nonce,\n                    privateKey: signer);\n                heavyTxs.Add(heavyTx);\n                nonce += 1;\n            }\n\n            var miner = new PrivateKey();\n            var block = _blockChain.ProposeBlock(\n                miner,\n                heavyTxs.ToImmutableList(),\n                TestUtils.CreateBlockCommit(_blockChain.Tip),\n                ImmutableArray<EvidenceBase>.Empty);\n            long maxBytes = _blockChain.Policy.GetMaxTransactionsBytes(block.Index);\n            Assert.True(block.MarshalBlock().EncodingLength > maxBytes);\n\n            var e = Assert.Throws<InvalidBlockBytesLengthException>(() =>\n                _blockChain.Append(block, TestUtils.CreateBlockCommit(block))\n            );\n        }\n\n        [SkippableFact]\n        public void AppendFailDueToInvalidTxCount()\n        {\n            int nonce = 0;\n            int maxTxs = _blockChain.Policy.GetMaxTransactionsPerBlock(1);\n            var manyTxs = new List<Transaction>();\n            for (int i = 0; i <= maxTxs; i++)\n            {\n                Transaction heavyTx = _fx.MakeTransaction(\n                    nonce: nonce,\n                    privateKey: null);\n                manyTxs.Add(heavyTx);\n            }\n\n            Assert.True(manyTxs.Count > maxTxs);\n\n            var miner = new PrivateKey();\n            Block block = _blockChain.ProposeBlock(\n                miner,\n                manyTxs.ToImmutableList(),\n                TestUtils.CreateBlockCommit(_blockChain.Tip),\n                ImmutableArray<EvidenceBase>.Empty);\n            Assert.Equal(manyTxs.Count, block.Transactions.Count);\n\n            var e = Assert.Throws<InvalidBlockTxCountException>(() =>\n                _blockChain.Append(block, TestUtils.CreateBlockCommit(block))\n            );\n        }\n\n        [SkippableFact]\n        public void AppendWhenActionEvaluationFailed()\n        {\n            var policy = new NullBlockPolicy();\n            var store = new MemoryStore();\n            var stateStore =\n                new TrieStateStore(new MemoryKeyValueStore());\n            var actionLoader = new SingleActionLoader(typeof(ThrowException));\n            var renderer = new RecordingActionRenderer();\n            BlockChain blockChain =\n                TestUtils.MakeBlockChain(\n                    policy, store, stateStore, actionLoader, renderers: new[] { renderer });\n            var privateKey = new PrivateKey();\n\n            var action = new ThrowException { ThrowOnExecution = true };\n            blockChain.MakeTransaction(privateKey, new[] { action });\n\n            renderer.ResetRecords();\n            Block block = blockChain.ProposeBlock(new PrivateKey());\n            blockChain.Append(block, TestUtils.CreateBlockCommit(block));\n\n            Assert.Equal(2, blockChain.Count);\n            Assert.Empty(renderer.ActionSuccessRecords);\n            Assert.Single(renderer.ActionErrorRecords);\n            RenderRecord.ActionError errorRecord = renderer.ActionErrorRecords[0];\n            Assert.Equal(action.PlainValue, errorRecord.Action);\n            Assert.IsType<UnexpectedlyTerminatedActionException>(errorRecord.Exception);\n            Assert.IsType<ThrowException.SomeException>(errorRecord.Exception.InnerException);\n        }\n\n        [SkippableFact]\n        public void AppendBlockWithPolicyViolationTx()\n        {\n            var validKey = new PrivateKey();\n            var invalidKey = new PrivateKey();\n\n            TxPolicyViolationException IsSignerValid(\n                BlockChain chain, Transaction tx)\n            {\n                var validAddress = validKey.Address;\n                return tx.Signer.Equals(validAddress) || tx.Signer.Equals(_fx.Proposer.Address)\n                    ? null\n                    : new TxPolicyViolationException(\"invalid signer\", tx.Id);\n            }\n\n            var policy = new BlockPolicy(validateNextBlockTx: IsSignerValid);\n            using (var fx = new MemoryStoreFixture())\n            {\n                var blockChain = BlockChain.Create(\n                    policy,\n                    new VolatileStagePolicy(),\n                    fx.Store,\n                    fx.StateStore,\n                    fx.GenesisBlock,\n                    new ActionEvaluator(\n                        policy.PolicyActionsRegistry,\n                        stateStore: fx.StateStore,\n                        actionTypeLoader: new SingleActionLoader(typeof(DumbAction))));\n\n                var validTx = blockChain.MakeTransaction(validKey, Array.Empty<DumbAction>());\n                var invalidTx = blockChain.MakeTransaction(invalidKey, Array.Empty<DumbAction>());\n\n                var miner = new PrivateKey();\n\n                Block block1 = blockChain.ProposeBlock(\n                    miner,\n                    new[] { validTx }.ToImmutableList(),\n                    TestUtils.CreateBlockCommit(blockChain.Tip),\n                    ImmutableArray<EvidenceBase>.Empty);\n                blockChain.Append(block1, TestUtils.CreateBlockCommit(block1));\n\n                Block block2 = blockChain.ProposeBlock(\n                    miner,\n                    new[] { invalidTx }.ToImmutableList(),\n                    TestUtils.CreateBlockCommit(blockChain.Tip),\n                    ImmutableArray<EvidenceBase>.Empty);\n                Assert.Throws<TxPolicyViolationException>(() => blockChain.Append(\n                    block2, TestUtils.CreateBlockCommit(block2)));\n            }\n        }\n\n        [SkippableFact]\n        public void UnstageAfterAppendComplete()\n        {\n            PrivateKey privateKey = new PrivateKey();\n            (Address[] addresses, Transaction[] txs) =\n                MakeFixturesForAppendTests(privateKey, epoch: DateTimeOffset.UtcNow);\n            Assert.Empty(_blockChain.GetStagedTransactionIds());\n\n            // Mining with empty staged.\n            Block block1 = _blockChain.ProposeBlock(\n                privateKey,\n                TestUtils.CreateBlockCommit(_blockChain.Tip));\n            _blockChain.Append(block1, TestUtils.CreateBlockCommit(block1));\n            Assert.Empty(_blockChain.GetStagedTransactionIds());\n\n            StageTransactions(txs);\n            Assert.Equal(2, _blockChain.GetStagedTransactionIds().Count);\n\n            // Tx with nonce 0 is mined.\n            Block block2 = _blockChain.ProposeBlock(\n                privateKey,\n                ImmutableList<Transaction>.Empty.Add(txs[0]),\n                TestUtils.CreateBlockCommit(_blockChain.Tip),\n                ImmutableArray<EvidenceBase>.Empty);\n            _blockChain.Append(block2, TestUtils.CreateBlockCommit(block2));\n            Assert.Equal(1, _blockChain.GetStagedTransactionIds().Count);\n\n            // Two txs with nonce 1 are staged.\n            var actions = new[] { DumbAction.Create((addresses[0], \"foobar\")) };\n            Transaction[] txs2 =\n            {\n                _fx.MakeTransaction(actions, privateKey: privateKey, nonce: 1),\n            };\n            StageTransactions(txs2);\n            Assert.Equal(2, _blockChain.GetStagedTransactionIds().Count);\n\n            // Unmined tx is left intact in the stage.\n            Block block3 = _blockChain.ProposeBlock(\n                privateKey,\n                ImmutableList<Transaction>.Empty.Add(txs[1]),\n                TestUtils.CreateBlockCommit(_blockChain.Tip),\n                ImmutableArray<EvidenceBase>.Empty);\n            _blockChain.Append(block3, TestUtils.CreateBlockCommit(block3));\n            Assert.Empty(_blockChain.GetStagedTransactionIds());\n            Assert.Empty(_blockChain.StagePolicy.Iterate(_blockChain, filtered: true));\n            Assert.Single(_blockChain.StagePolicy.Iterate(_blockChain, filtered: false));\n        }\n\n        [SkippableFact]\n        public void AppendValidatesBlock()\n        {\n            var policy = new NullBlockPolicy(\n                    new BlockPolicyViolationException(string.Empty));\n            var blockChainStates = new BlockChainStates(_fx.Store, _fx.StateStore);\n            var blockChain = new BlockChain(\n                policy,\n                new VolatileStagePolicy(),\n                _fx.Store,\n                _fx.StateStore,\n                _fx.GenesisBlock,\n                blockChainStates,\n                new ActionEvaluator(\n                    policy.PolicyActionsRegistry,\n                    _fx.StateStore,\n                    new SingleActionLoader(typeof(DumbAction))));\n            Assert.Throws<BlockPolicyViolationException>(\n                () => blockChain.Append(_fx.Block1, TestUtils.CreateBlockCommit(_fx.Block1)));\n        }\n\n        [SkippableFact]\n        public void AppendWithdrawTxsWithExpiredNoncesFromStage()\n        {\n            void AssertTxIdSetEqual(\n                IEnumerable<TxId> setOne,\n                IEnumerable<TxId> setTwo)\n            {\n                Assert.Equal(\n                    setOne.OrderBy(id => id), setTwo.OrderBy(id => id));\n            }\n\n            var signerA = new PrivateKey();\n            var signerB = new PrivateKey();\n            BlockHash genesis = _blockChain.Genesis.Hash;\n            var emptyActions = Array.Empty<IValue>();\n            Transaction\n                txA0 = Transaction.Create(0, signerA, genesis, emptyActions),\n                txA1 = Transaction.Create(1, signerA, genesis, emptyActions);\n            _blockChain.StageTransaction(txA0);\n            _blockChain.StageTransaction(txA1);\n            Block block = _blockChain.ProposeBlock(signerA);\n\n            Transaction\n                txA2 = Transaction.Create(2, signerA, genesis, emptyActions),\n                txA0_ = Transaction.Create(0, signerA, genesis, emptyActions),\n                txA1_ = Transaction.Create(1, signerA, genesis, emptyActions),\n                txB0 = Transaction.Create(1, signerB, genesis, emptyActions),\n                txB1 = Transaction.Create(1, signerB, genesis, emptyActions),\n                txB2 = Transaction.Create(2, signerB, genesis, emptyActions),\n                txB0_ = Transaction.Create(1, signerB, genesis, emptyActions),\n                txB1_ = Transaction.Create(1, signerB, genesis, emptyActions);\n            _blockChain.StageTransaction(txA2);\n            _blockChain.StageTransaction(txA0_);\n            _blockChain.StageTransaction(txA1_);\n            _blockChain.StageTransaction(txB0);\n            _blockChain.StageTransaction(txB1);\n            _blockChain.StageTransaction(txB2);\n            _blockChain.StageTransaction(txB0_);\n            _blockChain.StageTransaction(txB1_);\n            AssertTxIdSetEqual(\n                new Transaction[]\n                {\n                    txA0, txA1, txA2, txA0_, txA1_, txB0, txB1, txB2, txB0_, txB1_,\n                }.Select(tx => tx.Id).ToImmutableHashSet(),\n                _blockChain.GetStagedTransactionIds());\n\n            _blockChain.Append(block, TestUtils.CreateBlockCommit(block));\n            AssertTxIdSetEqual(\n                new Transaction[]\n                {\n                    txA2, txB0, txB1, txB2, txB0_, txB1_,\n                }.Select(tx => tx.Id).ToImmutableHashSet(),\n                _blockChain.GetStagedTransactionIds());\n            AssertTxIdSetEqual(\n                new Transaction[]\n                {\n                    txA2, txB0, txB1, txB2, txB0_, txB1_,\n                }.Select(tx => tx.Id).ToImmutableHashSet(),\n                _blockChain.StagePolicy.Iterate(_blockChain, filtered: true).Select(tx => tx.Id));\n            AssertTxIdSetEqual(\n                new Transaction[]\n                {\n                    txA2, txA0_, txA1_, txB0, txB1, txB2, txB0_, txB1_,\n                }.Select(tx => tx.Id).ToImmutableHashSet(),\n                _blockChain.StagePolicy.Iterate(_blockChain, filtered: false).Select(tx => tx.Id));\n        }\n\n        [SkippableFact]\n        public void DoesNotMigrateStateWithoutAction()\n        {\n            var policy = new BlockPolicy(\n                new PolicyActionsRegistry(),\n                getMaxTransactionsBytes: _ => 50 * 1024);\n            var stagePolicy = new VolatileStagePolicy();\n            var fx = GetStoreFixture(policy.PolicyActionsRegistry);\n            var renderer = new ValidatingActionRenderer();\n            var actionEvaluator = new ActionEvaluator(\n                policy.PolicyActionsRegistry,\n                stateStore: fx.StateStore,\n                actionTypeLoader: new SingleActionLoader(typeof(DumbAction)));\n\n            var txs = new[]\n            {\n                Transaction.Create(\n                    0,\n                    fx.Proposer,\n                    null,\n                    actions: new IAction[]\n                    {\n                        new Initialize(\n                            validatorSet: TestUtils.ValidatorSet,\n                            states: ImmutableDictionary.Create<Address, IValue>()),\n                    }.ToPlainValues(),\n                    timestamp: DateTimeOffset.UtcNow),\n            };\n            var evs = Array.Empty<EvidenceBase>();\n            PreEvaluationBlock preEvalGenesis = new BlockContent(\n                new BlockMetadata(\n                    protocolVersion: BlockMetadata.WorldStateProtocolVersion - 1,\n                    index: 0L,\n                    timestamp: DateTimeOffset.UtcNow,\n                    miner: fx.Proposer.Address,\n                    publicKey: fx.Proposer.PublicKey,\n                    previousHash: null,\n                    txHash: BlockContent.DeriveTxHash(txs),\n                    lastCommit: null,\n                    evidenceHash: null),\n                transactions: txs,\n                evidence: evs).Propose();\n            var genesis = preEvalGenesis.Sign(\n                fx.Proposer,\n                actionEvaluator.Evaluate(preEvalGenesis, null).Last().OutputState);\n            var blockChain = BlockChain.Create(\n                policy,\n                stagePolicy,\n                fx.Store,\n                fx.StateStore,\n                genesis,\n                actionEvaluator,\n                renderers: new[] { new LoggedActionRenderer(renderer, Log.Logger) });\n            Assert.True(blockChain.GetWorldState().Legacy);\n            var emptyBlock = blockChain.ProposeBlock(\n                fx.Proposer,\n                ImmutableList<Transaction>.Empty,\n                TestUtils.CreateBlockCommit(blockChain.Tip),\n                ImmutableArray<EvidenceBase>.Empty);\n            blockChain.Append(emptyBlock, TestUtils.CreateBlockCommit(emptyBlock));\n            Assert.True(blockChain.GetNextWorldState(emptyBlock.Hash).Legacy);\n            Assert.Equal<byte>(\n                blockChain.GetWorldState(genesis.StateRootHash).Trie.Hash.ByteArray,\n                blockChain.GetNextWorldState(emptyBlock.Hash).Trie.Hash.ByteArray);\n        }\n\n        [Fact]\n        public void AppendSRHPostponeBPVBump()\n        {\n            var beforePostponeBPV = BlockMetadata.SlothProtocolVersion - 1;\n            var policy = new NullBlockPolicy();\n            var store = new MemoryStore();\n            var stateStore = new TrieStateStore(new MemoryKeyValueStore());\n            var actionLoader = new SingleActionLoader(typeof(DumbAction));\n            var actionEvaluator = new ActionEvaluator(\n                policy.PolicyActionsRegistry,\n                stateStore,\n                actionLoader);\n\n            var preGenesis = TestUtils.ProposeGenesis(\n                proposer: TestUtils.GenesisProposer.PublicKey,\n                protocolVersion: beforePostponeBPV);\n            var genesis = preGenesis.Sign(\n                TestUtils.GenesisProposer,\n                actionEvaluator.Evaluate(preGenesis, MerkleTrie.EmptyRootHash).Last().OutputState);\n            Assert.Equal(beforePostponeBPV, genesis.ProtocolVersion);\n\n            var blockChain = TestUtils.MakeBlockChain(\n                policy,\n                store,\n                stateStore,\n                actionLoader,\n                genesisBlock: genesis);\n\n            // Append block before state root hash postpone\n            var miner = new PrivateKey();\n            var action = DumbAction.Create((new Address(TestUtils.GetRandomBytes(20)), \"foo\"));\n            var tx = Transaction.Create(0, miner, genesis.Hash, new[] { action }.ToPlainValues());\n            var preBlockBeforeBump = TestUtils.ProposeNext(\n                genesis,\n                new[] { tx }.ToImmutableList(),\n                miner.PublicKey,\n                protocolVersion: beforePostponeBPV);\n            var blockBeforeBump = preBlockBeforeBump.Sign(\n                miner,\n                actionEvaluator.Evaluate(\n                    preBlockBeforeBump, genesis.StateRootHash).Last().OutputState);\n            Assert.Equal(beforePostponeBPV, blockBeforeBump.ProtocolVersion);\n            var commitBeforeBump = TestUtils.CreateBlockCommit(blockBeforeBump);\n            blockChain.Append(blockBeforeBump, commitBeforeBump);\n\n            // Append block after state root hash postpone - previous block is not bumped\n            action = DumbAction.Create((new Address(TestUtils.GetRandomBytes(20)), \"bar\"));\n            tx = Transaction.Create(1, miner, genesis.Hash, new[] { action }.ToPlainValues());\n            var blockAfterBump1 = blockChain.ProposeBlock(\n                miner,\n                new[] { tx }.ToImmutableList(),\n                commitBeforeBump,\n                evidence: ImmutableArray<EvidenceBase>.Empty);\n            Assert.Equal(\n                BlockMetadata.CurrentProtocolVersion,\n                blockAfterBump1.ProtocolVersion);\n            var commitAfterBump1 = TestUtils.CreateBlockCommit(blockAfterBump1);\n            blockChain.Append(blockAfterBump1, commitAfterBump1);\n            Assert.Equal(blockBeforeBump.StateRootHash, blockAfterBump1.StateRootHash);\n\n            // Append block after state root hash postpone - previous block is bumped\n            action = DumbAction.Create((new Address(TestUtils.GetRandomBytes(20)), \"baz\"));\n            tx = Transaction.Create(2, miner, genesis.Hash, new[] { action }.ToPlainValues());\n            var blockAfterBump2 = blockChain.ProposeBlock(\n                miner,\n                new[] { tx }.ToImmutableList(),\n                commitAfterBump1,\n                evidence: ImmutableArray<EvidenceBase>.Empty);\n            Assert.Equal(\n                BlockMetadata.CurrentProtocolVersion,\n                blockAfterBump2.ProtocolVersion);\n            var commitAfterBump2 = TestUtils.CreateBlockCommit(blockAfterBump2);\n            blockChain.Append(blockAfterBump2, commitAfterBump2);\n            Assert.Equal(\n                actionEvaluator.Evaluate(\n                    blockAfterBump1, blockAfterBump1.StateRootHash).Last().OutputState,\n                blockAfterBump2.StateRootHash);\n        }\n    }\n}\n"
  },
  {
    "path": "test/Libplanet.Tests/Blockchain/BlockChainTest.Evidence.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Collections.Immutable;\nusing System.Linq;\nusing System.Numerics;\nusing Libplanet.Blockchain;\nusing Libplanet.Blocks;\nusing Libplanet.Crypto;\nusing Libplanet.Tests.Blockchain.Evidence;\nusing Libplanet.Types.Blocks;\nusing Libplanet.Types.Consensus;\nusing Libplanet.Types.Evidence;\nusing Xunit;\n\nnamespace Libplanet.Tests.Blockchain\n{\n    public partial class BlockChainTest\n    {\n        [Fact]\n        public void GetPendingEvidence_Test()\n        {\n            Assert.Empty(_blockChain.GetPendingEvidence());\n        }\n\n        [Fact]\n        public void GetPendingEvidence_AfterAddingEvidence_Test()\n        {\n            // Given\n            var blockChain = _blockChain;\n            var height = blockChain.Tip.Index;\n            var address = new PrivateKey().Address;\n            var testEvidence = new TestEvidence(height, address, DateTimeOffset.UtcNow);\n\n            // When\n            blockChain.AddEvidence(testEvidence);\n\n            // Then\n            Assert.Single(blockChain.GetPendingEvidence());\n        }\n\n        [Fact]\n        public void GetPendingEvidence_Throw_Test()\n        {\n            var blockChain = _blockChain;\n            var height = blockChain.Tip.Index;\n            var address = new PrivateKey().Address;\n            var testEvidence = new TestEvidence(height, address, DateTimeOffset.UtcNow);\n            Assert.Throws<KeyNotFoundException>(\n                () => _blockChain.GetPendingEvidence(testEvidence.Id));\n        }\n\n        [Fact]\n        public void GetPendingEvidence_AfterAppendingBlock_Throw_Test()\n        {\n            // Given\n            var blockChain = _blockChain;\n            var key = TestUtils.ValidatorPrivateKeys.First();\n            var proposer = key;\n            var address = new PrivateKey().Address;\n            var expectedEvidence = new TestEvidence(0, address, DateTimeOffset.UtcNow);\n\n            // When\n            NextBlock(blockChain, proposer, ImmutableArray.Create<EvidenceBase>(expectedEvidence));\n\n            // Then\n            Assert.Throws<KeyNotFoundException>(\n                () => blockChain.GetPendingEvidence(expectedEvidence.Id));\n        }\n\n        [Fact]\n        public void GetPendingEvidence_Add_Test()\n        {\n            // Given\n            var blockChain = _blockChain;\n            var address = new PrivateKey().Address;\n            var expectedEvidence = new TestEvidence(0, address, DateTimeOffset.UtcNow);\n            blockChain.AddEvidence(expectedEvidence);\n\n            // Then\n            var actualEvidence = blockChain.GetPendingEvidence(expectedEvidence.Id);\n            Assert.Equal(expectedEvidence, actualEvidence);\n        }\n\n        [Fact]\n        public void GetCommittedEvidence_Throw_Test()\n        {\n            var blockChain = _blockChain;\n            var height = blockChain.Tip.Index;\n            var address = new PrivateKey().Address;\n            var testEvidence = new TestEvidence(height, address, DateTimeOffset.UtcNow);\n            Assert.Throws<KeyNotFoundException>(\n                () => _blockChain.GetCommittedEvidence(testEvidence.Id));\n        }\n\n        [Fact]\n        public void GetCommittedEvidence_Test()\n        {\n            // Given\n            var blockChain = _blockChain;\n            var key = TestUtils.ValidatorPrivateKeys.First();\n            var proposer = key;\n            var address = new PrivateKey().Address;\n            var expectedEvidence = new TestEvidence(0, address, DateTimeOffset.UtcNow);\n\n            // When\n            NextBlock(blockChain, proposer, ImmutableArray.Create<EvidenceBase>(expectedEvidence));\n\n            // Then\n            var actualEvidence = blockChain.GetCommittedEvidence(expectedEvidence.Id);\n            Assert.Equal(expectedEvidence, actualEvidence);\n        }\n\n        [Fact]\n        public void AddEvidence_CommittedEvidence_ThrowTest()\n        {\n            // Given\n            var key = TestUtils.ValidatorPrivateKeys.First();\n            var proposer = key;\n            var blockChain = _blockChain;\n            var address = new PrivateKey().Address;\n            var testEvidence = new TestEvidence(0, address, DateTimeOffset.UtcNow);\n\n            // When\n            NextBlock(blockChain, proposer, ImmutableArray.Create<EvidenceBase>(testEvidence));\n\n            // Then\n            Assert.Throws<ArgumentException>(\n                () => blockChain.AddEvidence(testEvidence));\n        }\n\n        [Fact]\n        public void AddEvidence_PendingEvidence_ThrowTest()\n        {\n            // Given\n            var key = TestUtils.ValidatorPrivateKeys.First();\n            var proposer = key;\n            var blockChain = _blockChain;\n            var address = new PrivateKey().Address;\n            var testEvidence = new TestEvidence(0, address, DateTimeOffset.UtcNow);\n            blockChain.AddEvidence(testEvidence);\n\n            // Then\n            Assert.Throws<ArgumentException>(\n                () => blockChain.AddEvidence(testEvidence));\n        }\n\n        [Fact]\n        public void AddEvidence_HeightGreaterThanTip_ThrowTest()\n        {\n            // Given\n            var key = TestUtils.ValidatorPrivateKeys.First();\n            var proposer = key;\n            var blockChain = _blockChain;\n            var address = new PrivateKey().Address;\n            var height = blockChain.Tip.Index + 1;\n            var testEvidence = new TestEvidence(height, address, DateTimeOffset.UtcNow);\n\n            // Then\n            Assert.Throws<ArgumentException>(\n                () => blockChain.AddEvidence(testEvidence));\n        }\n\n        [Fact]\n        public void AddEvidence_ExpiredEvidence_ThrowTest()\n        {\n            // Given\n            var key = TestUtils.ValidatorPrivateKeys.First();\n            var proposer = key;\n            var blockChain = _blockChain;\n            var address = new PrivateKey().Address;\n            var testEvidence = new TestEvidence(0, address, DateTimeOffset.UtcNow);\n            var index = blockChain.Tip.Index;\n            var pendingDuration = blockChain.Policy.GetMaxEvidencePendingDuration(\n                index: index);\n            var emptyEvidence = ImmutableArray<EvidenceBase>.Empty;\n\n            // When\n            for (var i = index; i < pendingDuration + 1; i++)\n            {\n                NextBlock(blockChain, proposer, emptyEvidence);\n            }\n\n            // Then\n            Assert.Throws<ArgumentException>(\n                () => blockChain.AddEvidence(testEvidence));\n        }\n\n        [Fact]\n        public void AddEvidence_Test()\n        {\n            // Given\n            var address = new PrivateKey().Address;\n            var blockChain = _blockChain;\n            var testEvidence = new TestEvidence(0, address, DateTimeOffset.UtcNow);\n\n            // When\n            blockChain.AddEvidence(testEvidence);\n\n            // Then\n            Assert.Single(blockChain.GetPendingEvidence());\n        }\n\n        [Fact]\n        public void CommitEvidence_AddingCommittedEvidence_ThrowTest()\n        {\n            // Given\n            var key = TestUtils.ValidatorPrivateKeys.First();\n            var proposer = key;\n            var blockChain = _blockChain;\n            var address = new PrivateKey().Address;\n            var testEvidence = new TestEvidence(0, address, DateTimeOffset.UtcNow);\n\n            // When\n            NextBlock(blockChain, proposer, ImmutableArray.Create<EvidenceBase>(testEvidence));\n\n            // Then\n            Assert.Throws<ArgumentException>(\n                () => blockChain.CommitEvidence(testEvidence));\n        }\n\n        [Fact]\n        public void CommitEvidence_AddingExpiredEvidence_ThrowTest()\n        {\n            // Given\n            var key = TestUtils.ValidatorPrivateKeys.First();\n            var proposer = key;\n            var blockChain = _blockChain;\n            var address = new PrivateKey().Address;\n            var testEvidence = new TestEvidence(0, address, DateTimeOffset.UtcNow);\n            var index = blockChain.Tip.Index;\n            var pendingDuration = blockChain.Policy.GetMaxEvidencePendingDuration(\n                index: index);\n            var emptyEvidence = ImmutableArray<EvidenceBase>.Empty;\n\n            // When\n            for (var i = index; i < pendingDuration + 1; i++)\n            {\n                NextBlock(blockChain, proposer, emptyEvidence);\n            }\n\n            // Then\n            Assert.Throws<ArgumentException>(\n                () => blockChain.CommitEvidence(testEvidence));\n        }\n\n        [Fact]\n        public void CommitEvidence_WithoutPendingEvidence_Test()\n        {\n            // Given\n            var key = TestUtils.ValidatorPrivateKeys.First();\n            var proposer = key;\n            var blockChain = _blockChain;\n            var address = new PrivateKey().Address;\n            var testEvidence = new TestEvidence(0, address, DateTimeOffset.UtcNow);\n\n            // When\n            blockChain.CommitEvidence(testEvidence);\n\n            // Then\n            Assert.True(blockChain.IsEvidenceCommitted(testEvidence.Id));\n        }\n\n        [Fact]\n        public void CommitEvidence_Test()\n        {\n            // Given\n            var address = new PrivateKey().Address;\n            var blockChain = _blockChain;\n            var testEvidence = new TestEvidence(0, address, DateTimeOffset.UtcNow);\n            blockChain.AddEvidence(testEvidence);\n\n            // When\n            blockChain.CommitEvidence(testEvidence);\n\n            // Then\n            Assert.Empty(blockChain.GetPendingEvidence());\n            Assert.True(blockChain.IsEvidenceCommitted(testEvidence.Id));\n        }\n\n        [Fact]\n        public void IsEvidencePending_True_Test()\n        {\n            // Given\n            var address = new PrivateKey().Address;\n            var testEvidence = new TestEvidence(0, address, DateTimeOffset.UtcNow);\n            _blockChain.AddEvidence(testEvidence);\n\n            // Then\n            Assert.True(_blockChain.IsEvidencePending(testEvidence.Id));\n        }\n\n        [Fact]\n        public void IsEvidencePending_False_Test()\n        {\n            // Given\n            var address = new PrivateKey().Address;\n            var testEvidence = new TestEvidence(0, address, DateTimeOffset.UtcNow);\n\n            // Then\n            Assert.False(_blockChain.IsEvidencePending(testEvidence.Id));\n        }\n\n        [Fact]\n        public void IsEvidenceCommitted_True_Test()\n        {\n            // Given\n            var address = new PrivateKey().Address;\n            var testEvidence = new TestEvidence(0, address, DateTimeOffset.UtcNow);\n            _blockChain.AddEvidence(testEvidence);\n            _blockChain.CommitEvidence(testEvidence);\n\n            // Then\n            Assert.True(_blockChain.IsEvidenceCommitted(testEvidence.Id));\n        }\n\n        [Fact]\n        public void IsEvidenceCommitted_False_Test()\n        {\n            // Given\n            var address = new PrivateKey().Address;\n            var testEvidence = new TestEvidence(0, address, DateTimeOffset.UtcNow);\n            _blockChain.AddEvidence(testEvidence);\n\n            // Then\n            Assert.False(_blockChain.IsEvidenceCommitted(testEvidence.Id));\n        }\n\n        [Fact]\n        public void IsEvidenceExpired_True_Test()\n        {\n            // Given\n            var address = new PrivateKey().Address;\n            var height = Random.Shared.Next(1, 6);\n            var testEvidence = new TestEvidence(height, address, DateTimeOffset.UtcNow);\n            var index = _blockChain.Tip.Index;\n            var pendingDuration = _blockChain.Policy.GetMaxEvidencePendingDuration(\n                index: index);\n            var emptyEvidence = ImmutableArray<EvidenceBase>.Empty;\n\n            // When\n            for (var i = index; i < testEvidence.Height + pendingDuration + 1; i++)\n            {\n                NextBlock(_blockChain, TestUtils.ValidatorPrivateKeys.First(), emptyEvidence);\n            }\n\n            // Then\n            Assert.True(_blockChain.IsEvidenceExpired(testEvidence));\n        }\n\n        [Fact]\n        public void IsEvidenceExpired_False_Test()\n        {\n            // Given\n            var address = new PrivateKey().Address;\n            var height = Random.Shared.Next(1, 6);\n            var testEvidence = new TestEvidence(height, address, DateTimeOffset.UtcNow);\n            var index = _blockChain.Tip.Index;\n            var emptyEvidence = ImmutableArray<EvidenceBase>.Empty;\n\n            // When\n            for (var i = index; i < testEvidence.Height; i++)\n            {\n                NextBlock(_blockChain, TestUtils.ValidatorPrivateKeys.First(), emptyEvidence);\n            }\n\n            // Then\n            Assert.False(_blockChain.IsEvidenceExpired(testEvidence));\n        }\n\n        [Fact]\n        public void DeletePendingEvidence_True_Test()\n        {\n            // Given\n            var address = new PrivateKey().Address;\n            var testEvidence = new TestEvidence(0, address, DateTimeOffset.UtcNow);\n            _blockChain.AddEvidence(testEvidence);\n\n            // Then\n            Assert.True(_blockChain.DeletePendingEvidence(testEvidence.Id));\n        }\n\n        [Fact]\n        public void DeletePendingEvidence_False_Test()\n        {\n            // Given\n            var address = new PrivateKey().Address;\n            var testEvidence = new TestEvidence(0, address, DateTimeOffset.UtcNow);\n\n            // Then\n            Assert.False(_blockChain.DeletePendingEvidence(testEvidence.Id));\n            Assert.False(_blockChain.IsEvidencePending(testEvidence.Id));\n            Assert.False(_blockChain.IsEvidenceCommitted(testEvidence.Id));\n        }\n\n        [Fact]\n        public void AddEvidence_CommitEvidence_DuplicatedVoteEvidence_Test()\n        {\n            var key = TestUtils.ValidatorPrivateKeys.First();\n            var proposer = key;\n            var blockChain = _blockChain;\n            var voteRef = new VoteMetadata(\n                height: blockChain.Tip.Index,\n                round: 2,\n                blockHash: new BlockHash(TestUtils.GetRandomBytes(BlockHash.Size)),\n                timestamp: DateTimeOffset.UtcNow,\n                validatorPublicKey: key.PublicKey,\n                validatorPower: BigInteger.One,\n                flag: VoteFlag.PreCommit).Sign(key);\n            var voteDup = new VoteMetadata(\n                height: blockChain.Tip.Index,\n                round: 2,\n                blockHash: new BlockHash(TestUtils.GetRandomBytes(BlockHash.Size)),\n                timestamp: DateTimeOffset.UtcNow,\n                validatorPublicKey: key.PublicKey,\n                validatorPower: BigInteger.One,\n                flag: VoteFlag.PreCommit).Sign(key);\n            var evidence = new DuplicateVoteEvidence(\n                voteRef,\n                voteDup,\n                TestUtils.ValidatorSet,\n                voteDup.Timestamp);\n\n            Assert.Empty(blockChain.GetPendingEvidence());\n            Assert.False(blockChain.IsEvidencePending(evidence.Id));\n            Assert.False(blockChain.IsEvidenceCommitted(evidence.Id));\n\n            blockChain.AddEvidence(evidence);\n            NextBlock(blockChain, proposer, ImmutableArray<EvidenceBase>.Empty);\n\n            Assert.Single(blockChain.GetPendingEvidence());\n            Assert.Equal(evidence, blockChain.GetPendingEvidence().First());\n            Assert.True(blockChain.IsEvidencePending(evidence.Id));\n            Assert.False(blockChain.IsEvidenceCommitted(evidence.Id));\n\n            blockChain.CommitEvidence(evidence);\n\n            Assert.Empty(blockChain.GetPendingEvidence());\n            Assert.False(blockChain.IsEvidencePending(evidence.Id));\n            Assert.True(blockChain.IsEvidenceCommitted(evidence.Id));\n        }\n\n        [Fact]\n        public void CommitEvidence_DuplicateVoteEvidence_Test()\n        {\n            var key = TestUtils.ValidatorPrivateKeys.First();\n            var blockChain = _blockChain;\n            var voteRef = new VoteMetadata(\n                height: blockChain.Tip.Index,\n                round: 2,\n                blockHash: new BlockHash(TestUtils.GetRandomBytes(BlockHash.Size)),\n                timestamp: DateTimeOffset.UtcNow,\n                validatorPublicKey: key.PublicKey,\n                validatorPower: BigInteger.One,\n                flag: VoteFlag.PreCommit).Sign(key);\n            var voteDup = new VoteMetadata(\n                height: blockChain.Tip.Index,\n                round: 2,\n                blockHash: new BlockHash(TestUtils.GetRandomBytes(BlockHash.Size)),\n                timestamp: DateTimeOffset.UtcNow,\n                validatorPublicKey: key.PublicKey,\n                validatorPower: BigInteger.One,\n                flag: VoteFlag.PreCommit).Sign(key);\n            var evidence = new DuplicateVoteEvidence(\n                voteRef,\n                voteDup,\n                TestUtils.ValidatorSet,\n                voteDup.Timestamp);\n\n            Assert.Empty(blockChain.GetPendingEvidence());\n            Assert.False(blockChain.IsEvidencePending(evidence.Id));\n            Assert.False(blockChain.IsEvidenceCommitted(evidence.Id));\n\n            blockChain.CommitEvidence(evidence);\n\n            Assert.Empty(blockChain.GetPendingEvidence());\n            Assert.False(blockChain.IsEvidencePending(evidence.Id));\n            Assert.True(blockChain.IsEvidenceCommitted(evidence.Id));\n        }\n\n        [Fact]\n        public void AddEvidence_DuplicateVoteEvidence_FromNonValidator_ThrowTest()\n        {\n            var key = new PrivateKey();\n            var voteRef = new VoteMetadata(\n                height: _blockChain.Tip.Index,\n                round: 2,\n                blockHash: new BlockHash(TestUtils.GetRandomBytes(BlockHash.Size)),\n                timestamp: DateTimeOffset.UtcNow,\n                validatorPublicKey: key.PublicKey,\n                validatorPower: BigInteger.One,\n                flag: VoteFlag.PreCommit).Sign(key);\n            var voteDup = new VoteMetadata(\n                height: _blockChain.Tip.Index,\n                round: 2,\n                blockHash: new BlockHash(TestUtils.GetRandomBytes(BlockHash.Size)),\n                timestamp: DateTimeOffset.UtcNow,\n                validatorPublicKey: key.PublicKey,\n                validatorPower: BigInteger.One,\n                flag: VoteFlag.PreCommit).Sign(key);\n            var evidence = new DuplicateVoteEvidence(\n                voteRef,\n                voteDup,\n                new ValidatorSet(\n                    new List<Validator> { new Validator(key.PublicKey, BigInteger.One) }),\n                voteDup.Timestamp);\n\n            Assert.Empty(_blockChain.GetPendingEvidence());\n            Assert.False(_blockChain.IsEvidencePending(evidence.Id));\n            Assert.False(_blockChain.IsEvidenceCommitted(evidence.Id));\n\n            Assert.Throws<InvalidEvidenceException>(\n                () => _blockChain.AddEvidence(evidence));\n\n            Assert.Empty(_blockChain.GetPendingEvidence());\n            Assert.False(_blockChain.IsEvidencePending(evidence.Id));\n            Assert.False(_blockChain.IsEvidenceCommitted(evidence.Id));\n        }\n\n        [Fact]\n        public void EvidenceExpired_ThrowTest()\n        {\n            var key = TestUtils.ValidatorPrivateKeys.First();\n            var proposer = key;\n            var blockChain = _blockChain;\n            var voteRef = new VoteMetadata(\n                height: blockChain.Tip.Index,\n                round: 2,\n                blockHash: new BlockHash(TestUtils.GetRandomBytes(BlockHash.Size)),\n                timestamp: DateTimeOffset.UtcNow,\n                validatorPublicKey: key.PublicKey,\n                validatorPower: BigInteger.One,\n                flag: VoteFlag.PreCommit).Sign(key);\n            var voteDup = new VoteMetadata(\n                height: blockChain.Tip.Index,\n                round: 2,\n                blockHash: new BlockHash(TestUtils.GetRandomBytes(BlockHash.Size)),\n                timestamp: DateTimeOffset.UtcNow,\n                validatorPublicKey: key.PublicKey,\n                validatorPower: BigInteger.One,\n                flag: VoteFlag.PreCommit).Sign(key);\n            var evidence = new DuplicateVoteEvidence(\n                voteRef,\n                voteDup,\n                TestUtils.ValidatorSet,\n                voteDup.Timestamp);\n\n            Assert.Empty(blockChain.GetPendingEvidence());\n            Assert.False(blockChain.IsEvidencePending(evidence.Id));\n            Assert.False(blockChain.IsEvidenceCommitted(evidence.Id));\n\n            blockChain.AddEvidence(evidence);\n\n            Assert.Single(blockChain.GetPendingEvidence());\n            Assert.Equal(evidence, blockChain.GetPendingEvidence().First());\n            Assert.True(blockChain.IsEvidencePending(evidence.Id));\n            Assert.False(blockChain.IsEvidenceCommitted(evidence.Id));\n\n            var pendingDuration = blockChain.Policy.GetMaxEvidencePendingDuration(\n                index: blockChain.Tip.Index);\n            var emptyEvidence = ImmutableArray<EvidenceBase>.Empty;\n\n            for (var i = 0; i < pendingDuration; i++)\n            {\n                NextBlock(blockChain, proposer, emptyEvidence);\n            }\n\n            Assert.Throws<InvalidBlockEvidencePendingDurationException>(\n                () => NextBlock(blockChain, proposer, blockChain.GetPendingEvidence()));\n\n            Assert.Single(blockChain.GetPendingEvidence());\n\n            NextBlock(blockChain, proposer, emptyEvidence);\n\n            Assert.Empty(blockChain.GetPendingEvidence());\n        }\n\n        private static Block NextBlock(\n            BlockChain blockChain, PrivateKey proposer, ImmutableArray<EvidenceBase> evidence)\n        {\n            var tip = blockChain.Tip;\n            var block = blockChain.ProposeBlock(\n                proposer: proposer,\n                lastCommit: TestUtils.CreateBlockCommit(tip, true),\n                evidence: evidence);\n            blockChain.Append(block, TestUtils.CreateBlockCommit(block, true));\n            return block;\n        }\n    }\n}\n"
  },
  {
    "path": "test/Libplanet.Tests/Blockchain/BlockChainTest.Internals.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Collections.Immutable;\nusing System.Linq;\nusing System.Security.Cryptography;\nusing Bencodex.Types;\nusing Libplanet.Action;\nusing Libplanet.Action.State;\nusing Libplanet.Action.Tests.Common;\nusing Libplanet.Common;\nusing Libplanet.Crypto;\nusing Libplanet.Types.Blocks;\nusing Libplanet.Types.Evidence;\nusing Libplanet.Types.Tx;\nusing Xunit;\nusing static Libplanet.Action.State.KeyConverters;\nusing static Libplanet.Tests.TestUtils;\n\nnamespace Libplanet.Tests.Blockchain\n{\n    public partial class BlockChainTest\n    {\n        [SkippableFact]\n        public void ListStagedTransactions()\n        {\n            Skip.IfNot(\n                Environment.GetEnvironmentVariable(\"XUNIT_UNITY_RUNNER\") is null,\n                \"This test causes timeout\"\n            );\n\n            Transaction MkTx(PrivateKey key, long nonce, DateTimeOffset? ts = null) =>\n                Transaction.Create(\n                    nonce,\n                    key,\n                    _blockChain.Genesis.Hash,\n                    Array.Empty<DumbAction>().ToPlainValues(),\n                    null,\n                    null,\n                    ts ?? DateTimeOffset.UtcNow);\n\n            PrivateKey a = new PrivateKey();\n            PrivateKey b = new PrivateKey();\n            PrivateKey c = new PrivateKey();\n            PrivateKey d = new PrivateKey();\n            PrivateKey e = new PrivateKey();\n            List<Address> signers = new List<Address>()\n            {\n                a.Address, b.Address, c.Address, d.Address, e.Address,\n            };\n\n            // A normal case and corner cases:\n            // A. Normal case (3 txs: 0, 1, 2)\n            // B. Nonces are out of order (2 txs: 1, 0)\n            // C. Smaller nonces have later timestamps (2 txs: 0 (later), 1)\n            // D. Some nonce numbers are missed out (3 txs: 0, 1, 3)\n            // E. Reused nonces (4 txs: 0, 1, 1, 2)\n            _blockChain.MakeTransaction(a, new DumbAction[0]);\n            DateTimeOffset currentTime = DateTimeOffset.UtcNow;\n            _blockChain.StageTransaction(MkTx(b, 1, currentTime + TimeSpan.FromHours(1)));\n            _blockChain.StageTransaction(MkTx(c, 0, DateTimeOffset.UtcNow + TimeSpan.FromHours(1)));\n            _blockChain.StageTransaction(MkTx(d, 0, DateTimeOffset.UtcNow));\n            _blockChain.StageTransaction(MkTx(e, 0, DateTimeOffset.UtcNow));\n            _blockChain.MakeTransaction(a, new DumbAction[0]);\n            _blockChain.StageTransaction(MkTx(b, 0, currentTime));\n            _blockChain.StageTransaction(MkTx(c, 1, DateTimeOffset.UtcNow));\n            _blockChain.StageTransaction(MkTx(d, 1, DateTimeOffset.UtcNow));\n            _blockChain.StageTransaction(MkTx(e, 1, DateTimeOffset.UtcNow));\n            _blockChain.StageTransaction(MkTx(d, 3, DateTimeOffset.UtcNow));\n            _blockChain.StageTransaction(MkTx(e, 1, DateTimeOffset.UtcNow));\n            _blockChain.StageTransaction(MkTx(e, 2, DateTimeOffset.UtcNow));\n            _blockChain.MakeTransaction(a, new DumbAction[0]);\n\n            ImmutableList<Transaction> stagedTransactions =\n                _blockChain.ListStagedTransactions();\n\n            // List is ordered by nonce.\n            foreach (var signer in signers)\n            {\n                var signerTxs = stagedTransactions\n                    .Where(tx => tx.Signer.Equals(signer))\n                    .ToImmutableList();\n                Assert.Equal(signerTxs, signerTxs.OrderBy(tx => tx.Nonce));\n            }\n\n            // A is prioritized over B, C, D, E:\n            IComparer<Transaction> priority = Comparer<Transaction>.Create(\n                (tx1, tx2) => tx1.Signer.Equals(a.Address) ? -1 : 1\n            );\n            stagedTransactions = _blockChain.ListStagedTransactions(priority);\n\n            foreach (var tx in stagedTransactions.Take(3))\n            {\n                Assert.True(tx.Signer.Equals(a.Address));\n            }\n\n            // List is ordered by nonce.\n            foreach (var signer in signers)\n            {\n                var signerTxs = stagedTransactions\n                    .Where(tx => tx.Signer.Equals(signer))\n                    .ToImmutableList();\n                Assert.Equal(signerTxs, signerTxs.OrderBy(tx => tx.Nonce));\n            }\n        }\n\n        [SkippableFact]\n        public void ExecuteActions()\n        {\n            (var addresses, Transaction[] txs) = MakeFixturesForAppendTests();\n            var genesis = _blockChain.Genesis;\n\n            Block block1 = _blockChain.ProposeBlock(\n                _fx.Proposer,\n                txs.ToImmutableList(),\n                CreateBlockCommit(_blockChain.Tip),\n                ImmutableArray<EvidenceBase>.Empty);\n            _blockChain.Append(block1, CreateBlockCommit(block1), render: true);\n\n            var minerAddress = genesis.Miner;\n\n            var expectedStates = new Dictionary<Address, IValue>\n            {\n                { addresses[0], (Text)\"foo\" },\n                { addresses[1], (Text)\"bar\" },\n                { addresses[2], (Text)\"baz\" },\n                { addresses[3], (Text)\"qux\" },\n                { minerAddress, (Integer)2 },\n                { MinerReward.RewardRecordAddress, (Text)$\"{minerAddress},{minerAddress}\" },\n            };\n\n            IValue legacyStateRootRaw =\n                _fx.StateStore.GetStateRoot(_blockChain.GetNextStateRootHash())\n                .Get(ToStateKey(ReservedAddresses.LegacyAccount));\n            Assert.NotNull(legacyStateRootRaw);\n            var legacyStateRoot =\n                new HashDigest<SHA256>(((Binary)legacyStateRootRaw).ByteArray);\n            foreach (KeyValuePair<Address, IValue> pair in expectedStates)\n            {\n                AssertBencodexEqual(\n                    pair.Value,\n                    _fx.StateStore\n                        .GetStateRoot(legacyStateRoot)\n                        .Get(new[] { ToStateKey(pair.Key) })[0]\n                );\n            }\n        }\n\n        [SkippableTheory]\n        [InlineData(true)]\n        [InlineData(false)]\n        public void UpdateTxExecutions(bool getTxExecutionViaStore)\n        {\n            void AssertTxExecutionEqual(TxExecution expected, TxExecution actual)\n            {\n                Assert.Equal(expected.Fail, actual.Fail);\n                Assert.Equal(expected.TxId, actual.TxId);\n                Assert.Equal(expected.BlockHash, actual.BlockHash);\n                Assert.Equal(expected.InputState, actual.InputState);\n                Assert.Equal(expected.OutputState, actual.OutputState);\n                Assert.Equal(expected.ExceptionNames, actual.ExceptionNames);\n            }\n\n            Func<BlockHash, TxId, TxExecution> getTxExecution\n                = getTxExecutionViaStore\n                ? (Func<BlockHash, TxId, TxExecution>)_blockChain.Store.GetTxExecution\n                : _blockChain.GetTxExecution;\n\n            Assert.Null(getTxExecution(_fx.Hash1, _fx.TxId1));\n            Assert.Null(getTxExecution(_fx.Hash1, _fx.TxId2));\n            Assert.Null(getTxExecution(_fx.Hash2, _fx.TxId1));\n            Assert.Null(getTxExecution(_fx.Hash2, _fx.TxId2));\n\n            var random = new System.Random();\n            var inputA = new TxExecution(\n                _fx.Hash1,\n                _fx.TxId1,\n                false,\n                new HashDigest<SHA256>(TestUtils.GetRandomBytes(HashDigest<SHA256>.Size)),\n                new HashDigest<SHA256>(TestUtils.GetRandomBytes(HashDigest<SHA256>.Size)),\n                new List<string>() { string.Empty });\n            var inputB = new TxExecution(\n                _fx.Hash1,\n                _fx.TxId2,\n                true,\n                new HashDigest<SHA256>(TestUtils.GetRandomBytes(HashDigest<SHA256>.Size)),\n                new HashDigest<SHA256>(TestUtils.GetRandomBytes(HashDigest<SHA256>.Size)),\n                new List<string>() { \"AnExceptionName\" });\n            var inputC = new TxExecution(\n                _fx.Hash2,\n                _fx.TxId1,\n                true,\n                new HashDigest<SHA256>(TestUtils.GetRandomBytes(HashDigest<SHA256>.Size)),\n                new HashDigest<SHA256>(TestUtils.GetRandomBytes(HashDigest<SHA256>.Size)),\n                new List<string>() { \"AnotherExceptionName\", \"YetAnotherExceptionName\" });\n            _blockChain.UpdateTxExecutions(new TxExecution[] { inputA, inputB, inputC });\n\n            AssertTxExecutionEqual(inputA, getTxExecution(_fx.Hash1, _fx.TxId1));\n            AssertTxExecutionEqual(inputB, getTxExecution(_fx.Hash1, _fx.TxId2));\n            AssertTxExecutionEqual(inputC, getTxExecution(_fx.Hash2, _fx.TxId1));\n            Assert.Null(getTxExecution(_fx.Hash2, _fx.TxId2));\n        }\n    }\n}\n"
  },
  {
    "path": "test/Libplanet.Tests/Blockchain/BlockChainTest.ProposeBlock.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Collections.Immutable;\nusing System.Linq;\nusing System.Numerics;\nusing Bencodex.Types;\nusing Libplanet.Action;\nusing Libplanet.Action.Loader;\nusing Libplanet.Action.State;\nusing Libplanet.Action.Tests.Common;\nusing Libplanet.Blockchain;\nusing Libplanet.Blockchain.Policies;\nusing Libplanet.Crypto;\nusing Libplanet.Tests.Store;\nusing Libplanet.Types.Blocks;\nusing Libplanet.Types.Consensus;\nusing Libplanet.Types.Evidence;\nusing Libplanet.Types.Tx;\nusing Xunit;\nusing static Libplanet.Tests.TestUtils;\nusing Random = System.Random;\n\nnamespace Libplanet.Tests.Blockchain\n{\n    public partial class BlockChainTest\n    {\n        [SkippableFact]\n        public void ProposeBlock()\n        {\n            Func<long, long> getMaxTransactionsBytes = _blockChain.Policy.GetMaxTransactionsBytes;\n            Assert.Equal(1, _blockChain.Count);\n            AssertBencodexEqual(\n                (Text)$\"{GenesisProposer.Address}\",\n                _blockChain\n                    .GetNextWorldState()\n                    .GetAccountState(ReservedAddresses.LegacyAccount)\n                    .GetState(default));\n\n            var proposerA = new PrivateKey();\n            Block block = _blockChain.ProposeBlock(proposerA);\n            _blockChain.Append(block, CreateBlockCommit(block));\n            Assert.True(_blockChain.ContainsBlock(block.Hash));\n            Assert.Equal(2, _blockChain.Count);\n            Assert.True(\n                block.MarshalBlock().EncodingLength <= getMaxTransactionsBytes(block.Index));\n            AssertBencodexEqual(\n                (Text)$\"{GenesisProposer.Address},{proposerA.Address}\",\n                _blockChain\n                    .GetNextWorldState()\n                    .GetAccountState(ReservedAddresses.LegacyAccount)\n                    .GetState(default)\n            );\n\n            var proposerB = new PrivateKey();\n            Block anotherBlock = _blockChain.ProposeBlock(\n                proposerB,\n                CreateBlockCommit(_blockChain.Tip.Hash, _blockChain.Tip.Index, 0),\n                _blockChain.GetPendingEvidence());\n            _blockChain.Append(anotherBlock, CreateBlockCommit(anotherBlock));\n            Assert.True(_blockChain.ContainsBlock(anotherBlock.Hash));\n            Assert.Equal(3, _blockChain.Count);\n            Assert.True(\n                anotherBlock.MarshalBlock().EncodingLength <=\n                    getMaxTransactionsBytes(anotherBlock.Index));\n            Text expected = new Text(\n                $\"{GenesisProposer.Address},{proposerA.Address},{proposerB.Address}\");\n            AssertBencodexEqual(\n                expected,\n                _blockChain\n                    .GetNextWorldState()\n                    .GetAccountState(ReservedAddresses.LegacyAccount)\n                    .GetState(default)\n            );\n\n            Block block3 = _blockChain.ProposeBlock(\n                new PrivateKey(),\n                CreateBlockCommit(_blockChain.Tip.Hash, _blockChain.Tip.Index, 0),\n                _blockChain.GetPendingEvidence());\n            Assert.False(_blockChain.ContainsBlock(block3.Hash));\n            Assert.Equal(3, _blockChain.Count);\n            Assert.True(\n                block3.MarshalBlock().EncodingLength <= getMaxTransactionsBytes(block3.Index));\n            expected = new Text(\n                $\"{GenesisProposer.Address},{proposerA.Address},{proposerB.Address}\");\n            AssertBencodexEqual(\n                expected,\n                _blockChain\n                    .GetNextWorldState()\n                    .GetAccountState(ReservedAddresses.LegacyAccount)\n                    .GetState(default)\n            );\n\n            // Tests if ProposeBlock() method automatically fits the number of transactions\n            // according to the right size.\n            DumbAction[] manyActions =\n                Enumerable.Repeat(DumbAction.Create((default, \"_\")), 200).ToArray();\n            PrivateKey signer = null;\n            int nonce = 0;\n            for (int i = 0; i < 100; i++)\n            {\n                if (i % 25 == 0)\n                {\n                    nonce = 0;\n                    signer = new PrivateKey();\n                }\n\n                Transaction heavyTx = _fx.MakeTransaction(\n                    manyActions,\n                    nonce: nonce,\n                    privateKey: signer);\n                _blockChain.StageTransaction(heavyTx);\n            }\n\n            Block block4 = _blockChain.ProposeBlock(\n                new PrivateKey(),\n                CreateBlockCommit(_blockChain.Tip.Hash, _blockChain.Tip.Index, 0),\n                _blockChain.GetPendingEvidence());\n            Assert.False(_blockChain.ContainsBlock(block4.Hash));\n            _logger.Debug(\n                $\"{nameof(block4)}: {0} bytes\",\n                block4.MarshalBlock().EncodingLength\n            );\n            _logger.Debug(\n                $\"{nameof(getMaxTransactionsBytes)}({nameof(block4)}.{nameof(block4.Index)}) = {0}\",\n                getMaxTransactionsBytes(block4.Index)\n            );\n            Assert.True(\n                block4.MarshalBlock().EncodingLength <= getMaxTransactionsBytes(block4.Index));\n            Assert.Equal(3, block4.Transactions.Count());\n            expected = new Text(\n                $\"{GenesisProposer.Address},{proposerA.Address},{proposerB.Address}\");\n            AssertBencodexEqual(\n                expected,\n                _blockChain\n                    .GetNextWorldState()\n                    .GetAccountState(ReservedAddresses.LegacyAccount)\n                    .GetState(default)\n            );\n        }\n\n        [SkippableFact]\n        public void CanProposeInvalidGenesisBlock()\n        {\n            using (var fx = new MemoryStoreFixture())\n            {\n                var policy = new BlockPolicy();\n                var actionEvaluator = new ActionEvaluator(\n                    policy.PolicyActionsRegistry,\n                    fx.StateStore,\n                    new SingleActionLoader(typeof(DumbAction)));\n                var genesis = BlockChain.ProposeGenesisBlock(\n                    new PrivateKey(),\n                    null,\n                    new[]\n                    {\n                        Transaction.Create(\n                            5,  // Invalid nonce,\n                            new PrivateKey(),\n                            null,\n                            actions: new[]\n                            {\n                                DumbAction.Create((new PrivateKey().Address, \"foo\")),\n                            }.ToPlainValues()),\n                    }.ToImmutableList());\n                Assert.Throws<InvalidTxNonceException>(() => BlockChain.Create(\n                    policy,\n                    new VolatileStagePolicy(),\n                    fx.Store,\n                    fx.StateStore,\n                    genesis,\n                    actionEvaluator));\n            }\n        }\n\n        [SkippableFact]\n        public void CanProposeInvalidBlock()\n        {\n            using (var fx = new MemoryStoreFixture())\n            {\n                var policy = new BlockPolicy();\n                var blockChain = BlockChain.Create(\n                    policy,\n                    new VolatileStagePolicy(),\n                    fx.Store,\n                    fx.StateStore,\n                    fx.GenesisBlock,\n                    new ActionEvaluator(\n                        policy.PolicyActionsRegistry,\n                        stateStore: fx.StateStore,\n                        actionTypeLoader: new SingleActionLoader(typeof(DumbAction))));\n                var txs = new[]\n                {\n                    Transaction.Create(\n                        5,  // Invalid nonce\n                        new PrivateKey(),\n                        _blockChain.Genesis.Hash,\n                        new[]\n                        {\n                            DumbAction.Create((new PrivateKey().Address, \"foo\")),\n                        }.ToPlainValues()),\n                }.ToImmutableList();\n\n                var block = blockChain.ProposeBlock(\n                    new PrivateKey(), txs, null, ImmutableArray<EvidenceBase>.Empty);\n                Assert.Throws<InvalidTxNonceException>(\n                    () => blockChain.Append(block, CreateBlockCommit(block)));\n            }\n        }\n\n        [SkippableFact]\n        public void ProposeBlockWithPendingTxs()\n        {\n            var keys = new[] { new PrivateKey(), new PrivateKey(), new PrivateKey() };\n            var keyA = new PrivateKey();\n            var keyB = new PrivateKey();\n            var keyC = new PrivateKey();\n            var keyD = new PrivateKey();\n            var keyE = new PrivateKey();\n            var addrA = keyA.Address;\n            var addrB = keyB.Address;\n            var addrC = keyC.Address;\n            var addrD = keyD.Address;\n            var addrE = keyE.Address;\n\n            var txs = new[]\n            {\n                Transaction.Create(\n                    0,\n                    keys[0],\n                    _blockChain.Genesis.Hash,\n                    new[]\n                    {\n                        DumbAction.Create((addrA, \"1a\")),\n                        DumbAction.Create((addrB, \"1b\")),\n                    }.ToPlainValues()\n                ),\n                Transaction.Create(\n                    1,\n                    keys[0],\n                    _blockChain.Genesis.Hash,\n                    new[]\n                    {\n                        DumbAction.Create((addrC, \"2a\")),\n                        DumbAction.Create((addrD, \"2b\")),\n                    }.ToPlainValues()\n                ),\n\n                // pending txs1\n                Transaction.Create(\n                    1,\n                    keys[1],\n                    _blockChain.Genesis.Hash,\n                    new[]\n                    {\n                        DumbAction.Create((addrE, \"3a\")),\n                        DumbAction.Create((addrA, \"3b\")),\n                    }.ToPlainValues()\n                ),\n                Transaction.Create(\n                    2,\n                    keys[1],\n                    _blockChain.Genesis.Hash,\n                    new[]\n                    {\n                        DumbAction.Create((addrB, \"4a\")),\n                        DumbAction.Create((addrC, \"4b\")),\n                    }.ToPlainValues()\n                ),\n\n                // pending txs2\n                Transaction.Create(\n                    0,\n                    keys[2],\n                    _blockChain.Genesis.Hash,\n                    new[]\n                    {\n                        DumbAction.Create((addrD, \"5a\")),\n                        DumbAction.Create((addrE, \"5b\")),\n                    }.ToPlainValues()\n                ),\n                Transaction.Create(\n                    2,\n                    keys[2],\n                    _blockChain.Genesis.Hash,\n                    new[]\n                    {\n                        DumbAction.Create((addrA, \"6a\")),\n                        DumbAction.Create((addrB, \"6b\")),\n                    }.ToPlainValues()\n                ),\n            };\n\n            StageTransactions(txs);\n\n            Assert.Null(_blockChain\n                .GetNextWorldState()\n                .GetAccountState(ReservedAddresses.LegacyAccount)\n                .GetState(addrA));\n            Assert.Null(_blockChain\n                .GetNextWorldState()\n                .GetAccountState(ReservedAddresses.LegacyAccount)\n                .GetState(addrB));\n            Assert.Null(_blockChain\n                .GetNextWorldState()\n                .GetAccountState(ReservedAddresses.LegacyAccount)\n                .GetState(addrC));\n            Assert.Null(_blockChain\n                .GetNextWorldState()\n                .GetAccountState(ReservedAddresses.LegacyAccount)\n                .GetState(addrD));\n            Assert.Null(_blockChain\n                .GetNextWorldState()\n                .GetAccountState(ReservedAddresses.LegacyAccount)\n                .GetState(addrE));\n\n            foreach (Transaction tx in txs)\n            {\n                Assert.Null(_blockChain.GetTxExecution(_blockChain.Genesis.Hash, tx.Id));\n            }\n\n            Block block = _blockChain.ProposeBlock(keyA);\n            _blockChain.Append(block, CreateBlockCommit(block));\n\n            Assert.True(_blockChain.ContainsBlock(block.Hash));\n            Assert.Contains(txs[0], block.Transactions);\n            Assert.Contains(txs[1], block.Transactions);\n            Assert.DoesNotContain(txs[2], block.Transactions);\n            Assert.DoesNotContain(txs[3], block.Transactions);\n            Assert.Contains(txs[4], block.Transactions);\n            Assert.DoesNotContain(txs[5], block.Transactions);\n            IImmutableSet<TxId> txIds = _blockChain.GetStagedTransactionIds();\n            Assert.Contains(txs[2].Id, txIds);\n            Assert.Contains(txs[3].Id, txIds);\n\n            Assert.Equal(\n                new Integer(1),\n                _blockChain\n                    .GetNextWorldState()\n                    .GetAccountState(ReservedAddresses.LegacyAccount)\n                    .GetState(addrA));\n            Assert.Equal(\n                new Text(\"1b\"),\n                _blockChain\n                    .GetNextWorldState()\n                    .GetAccountState(ReservedAddresses.LegacyAccount)\n                    .GetState(addrB));\n            Assert.Equal(\n                new Text(\"2a\"),\n                _blockChain\n                    .GetNextWorldState()\n                    .GetAccountState(ReservedAddresses.LegacyAccount)\n                    .GetState(addrC));\n            Assert.IsType<Text>(\n                _blockChain\n                    .GetNextWorldState()\n                    .GetAccountState(ReservedAddresses.LegacyAccount)\n                    .GetState(addrD));\n            Assert.Equal(\n                new HashSet<string> { \"2b\", \"5a\" },\n                ((string)(Text)_blockChain\n                    .GetNextWorldState()\n                    .GetAccountState(ReservedAddresses.LegacyAccount)\n                    .GetState(addrD)).Split(new[] { ',' }).ToHashSet()\n            );\n            Assert.Equal(\n                new Text(\"5b\"),\n                _blockChain\n                    .GetNextWorldState()\n                    .GetAccountState(ReservedAddresses.LegacyAccount)\n                    .GetState(addrE));\n\n            foreach (Transaction tx in new[] { txs[0], txs[1], txs[4] })\n            {\n                TxExecution txx = _blockChain.GetTxExecution(block.Hash, tx.Id);\n                _logger.Debug(\n                    nameof(_blockChain.GetTxExecution) + \"({Hash}, {Id}) = {TxExecution}\",\n                    block.Hash,\n                    tx.Id,\n                    txx\n                );\n                Assert.False(txx.Fail);\n                Assert.Equal(block.Hash, txx.BlockHash);\n                Assert.Equal(tx.Id, txx.TxId);\n                Assert.Null(_blockChain.GetTxExecution(_blockChain.Genesis.Hash, tx.Id));\n            }\n        }\n\n        [SkippableFact]\n        public void ProposeBlockWithPolicyViolationTx()\n        {\n            var validKey = new PrivateKey();\n            var invalidKey = new PrivateKey();\n\n            TxPolicyViolationException IsSignerValid(\n                BlockChain chain, Transaction tx)\n            {\n                var validAddress = validKey.Address;\n                return tx.Signer.Equals(validAddress) || tx.Signer.Equals(_fx.Proposer.Address)\n                    ? null\n                    : new TxPolicyViolationException(\"invalid signer\", tx.Id);\n            }\n\n            var policy = new BlockPolicy(validateNextBlockTx: IsSignerValid);\n            using (var fx = new MemoryStoreFixture())\n            {\n                var blockChain = BlockChain.Create(\n                    policy,\n                    new VolatileStagePolicy(),\n                    fx.Store,\n                    fx.StateStore,\n                    fx.GenesisBlock,\n                    new ActionEvaluator(\n                        policy.PolicyActionsRegistry,\n                        stateStore: fx.StateStore,\n                        actionTypeLoader: new SingleActionLoader(typeof(DumbAction))));\n\n                var validTx = blockChain.MakeTransaction(validKey, new DumbAction[] { });\n                var invalidTx = blockChain.MakeTransaction(invalidKey, new DumbAction[] { });\n\n                var proposer = new PrivateKey();\n                var block = blockChain.ProposeBlock(proposer);\n                blockChain.Append(block, CreateBlockCommit(block));\n\n                var txs = block.Transactions.ToHashSet();\n\n                Assert.Contains(validTx, txs);\n                Assert.DoesNotContain(invalidTx, txs);\n\n                Assert.Empty(blockChain.GetStagedTransactionIds());\n            }\n        }\n\n        [SkippableFact]\n        public void ProposeBlockWithReverseNonces()\n        {\n            var key = new PrivateKey();\n            var txs = new[]\n            {\n                Transaction.Create(\n                    2,\n                    key,\n                    _blockChain.Genesis.Hash,\n                    Array.Empty<DumbAction>().ToPlainValues()\n                ),\n                Transaction.Create(\n                    1,\n                    key,\n                    _blockChain.Genesis.Hash,\n                    Array.Empty<DumbAction>().ToPlainValues()\n                ),\n                Transaction.Create(\n                    0,\n                    key,\n                    _blockChain.Genesis.Hash,\n                    Array.Empty<DumbAction>().ToPlainValues()\n                ),\n            };\n            StageTransactions(txs);\n            Block block = _blockChain.ProposeBlock(new PrivateKey());\n            Assert.Equal(txs.Length, block.Transactions.Count());\n        }\n\n        [SkippableFact]\n        public void ProposeBlockWithLowerNonces()\n        {\n            var key = new PrivateKey();\n            StageTransactions(\n                new[]\n                {\n                    Transaction.Create(\n                        0,\n                        key,\n                        _blockChain.Genesis.Hash,\n                        Array.Empty<DumbAction>().ToPlainValues()\n                    ),\n                }\n            );\n            Block block1 = _blockChain.ProposeBlock(new PrivateKey());\n            _blockChain.Append(block1, CreateBlockCommit(block1));\n\n            // Trying to propose with lower nonce (0) than expected.\n            StageTransactions(\n                new[]\n                {\n                    Transaction.Create(\n                        0,\n                        key,\n                        _blockChain.Genesis.Hash,\n                        Array.Empty<DumbAction>().ToPlainValues()\n                    ),\n                }\n            );\n            Block block2 = _blockChain.ProposeBlock(\n                new PrivateKey(),\n                CreateBlockCommit(\n                    _blockChain.Tip.Hash,\n                    _blockChain.Tip.Index,\n                    0),\n                _blockChain.GetPendingEvidence());\n            _blockChain.Append(block2, CreateBlockCommit(block2));\n\n            Assert.Empty(block2.Transactions);\n            Assert.Empty(_blockChain.ListStagedTransactions());\n            Assert.Empty(_blockChain.StagePolicy.Iterate(_blockChain, filtered: true));\n            Assert.Single(_blockChain.StagePolicy.Iterate(_blockChain, filtered: false));\n        }\n\n        [SkippableFact]\n        public void ProposeBlockWithBlockAction()\n        {\n            var privateKey1 = new PrivateKey();\n            var address1 = privateKey1.Address;\n\n            var privateKey2 = new PrivateKey();\n            var address2 = privateKey2.Address;\n\n            var policy = new BlockPolicy(\n                new PolicyActionsRegistry(\n                    beginBlockActions: ImmutableArray<IAction>.Empty,\n                    endBlockActions: ImmutableArray.Create<IAction>(\n                        DumbAction.Create((address1, \"foo\")))));\n            var blockChainStates = new BlockChainStates(_fx.Store, _fx.StateStore);\n\n            var blockChain = new BlockChain(\n                policy,\n                new VolatileStagePolicy(),\n                _fx.Store,\n                _fx.StateStore,\n                _fx.GenesisBlock,\n                blockChainStates,\n                new ActionEvaluator(\n                    policy.PolicyActionsRegistry,\n                    _fx.StateStore,\n                    new SingleActionLoader(typeof(DumbAction))));\n\n            blockChain.MakeTransaction(privateKey2, new[] { DumbAction.Create((address2, \"baz\")) });\n            var block = blockChain.ProposeBlock(\n                privateKey1,\n                CreateBlockCommit(_blockChain.Tip),\n                _blockChain.GetPendingEvidence());\n            blockChain.Append(block, CreateBlockCommit(block));\n\n            var state1 = blockChain\n                .GetNextWorldState()\n                .GetAccountState(ReservedAddresses.LegacyAccount)\n                .GetState(address1);\n            var state2 = blockChain\n                .GetNextWorldState()\n                .GetAccountState(ReservedAddresses.LegacyAccount)\n                .GetState(address2);\n\n            Assert.Equal(0, blockChain.GetNextTxNonce(address1));\n            Assert.Equal(1, blockChain.GetNextTxNonce(address2));\n            Assert.Equal((Text)\"foo,foo\", state1);\n            Assert.Equal((Text)\"baz\", state2);\n\n            blockChain.MakeTransaction(privateKey1, new[] { DumbAction.Create((address1, \"bar\")) });\n            block = blockChain.ProposeBlock(\n                privateKey1,\n                CreateBlockCommit(_blockChain.Tip),\n                _blockChain.GetPendingEvidence());\n            blockChain.Append(block, CreateBlockCommit(block));\n\n            state1 = blockChain\n                .GetNextWorldState()\n                .GetAccountState(ReservedAddresses.LegacyAccount)\n                .GetState(address1);\n            state2 = blockChain\n                .GetNextWorldState()\n                .GetAccountState(ReservedAddresses.LegacyAccount)\n                .GetState(address2);\n\n            Assert.Equal(1, blockChain.GetNextTxNonce(address1));\n            Assert.Equal(1, blockChain.GetNextTxNonce(address2));\n            Assert.Equal((Text)\"foo,foo,bar,foo\", state1);\n            Assert.Equal((Text)\"baz\", state2);\n        }\n\n        [SkippableFact]\n        public void ProposeBlockWithTxPriority()\n        {\n            var keyA = new PrivateKey();\n            var keyB = new PrivateKey();\n            var keyC = new PrivateKey();\n            Address a = keyA.Address; // Rank 0\n            Address b = keyB.Address; // Rank 1\n            Address c = keyC.Address; // Rank 2\n            int Rank(Address address) => address.Equals(a) ? 0 : address.Equals(b) ? 1 : 2;\n            Transaction[] txsA = Enumerable.Range(0, 50)\n                .Select(nonce => _fx.MakeTransaction(nonce: nonce, privateKey: keyA))\n                .ToArray();\n            Transaction[] txsB = Enumerable.Range(0, 60)\n                .Select(nonce => _fx.MakeTransaction(nonce: nonce, privateKey: keyB))\n                .ToArray();\n            Transaction[] txsC = Enumerable.Range(0, 40)\n                .Select(nonce => _fx.MakeTransaction(nonce: nonce, privateKey: keyC))\n                .ToArray();\n\n            var random = new Random();\n            Transaction[] txs =\n                txsA.Concat(txsB).Concat(txsC).Shuffle(random).ToArray();\n            StageTransactions(txs);\n            Assert.Equal(txs.Length, _blockChain.ListStagedTransactions().Count);\n\n            IComparer<Transaction> txPriority =\n                Comparer<Transaction>.Create((tx1, tx2) =>\n                    Rank(tx1.Signer).CompareTo(Rank(tx2.Signer)));\n            Block block = _blockChain.ProposeBlock(\n                new PrivateKey(),\n                txPriority: txPriority);\n            Assert.Equal(100, block.Transactions.Count);\n            Assert.Equal(\n                txsA.Concat(txsB.Take(50)).Select(tx => tx.Id).ToHashSet(),\n                block.Transactions.Select(tx => tx.Id).ToHashSet());\n        }\n\n        [SkippableFact]\n        public void ProposeBlockWithLastCommit()\n        {\n            var keys = Enumerable.Range(0, 3).Select(_ => new PrivateKey()).ToList();\n            var votes = keys.Select(key => new VoteMetadata(\n                _blockChain.Tip.Index,\n                0,\n                _blockChain.Tip.Hash,\n                DateTimeOffset.UtcNow,\n                key.PublicKey,\n                BigInteger.One,\n                VoteFlag.PreCommit).Sign(key)).ToImmutableArray();\n            var blockCommit = new BlockCommit(\n                _blockChain.Tip.Index, 0, _blockChain.Tip.Hash, votes);\n            Block block = _blockChain.ProposeBlock(\n                new PrivateKey(),\n                blockCommit,\n                _blockChain.GetPendingEvidence());\n\n            Assert.NotNull(block.LastCommit);\n            Assert.Equal(block.LastCommit, blockCommit);\n        }\n\n        [SkippableFact]\n        public void IgnoreLowerNonceTxsAndPropose()\n        {\n            var privateKey = new PrivateKey();\n            var address = privateKey.Address;\n            var txsA = Enumerable.Range(0, 3)\n                .Select(nonce => _fx.MakeTransaction(\n                    nonce: nonce, privateKey: privateKey, timestamp: DateTimeOffset.Now))\n                .ToArray();\n            StageTransactions(txsA);\n            Block b1 = _blockChain.ProposeBlock(new PrivateKey());\n            _blockChain.Append(b1, CreateBlockCommit(b1));\n            Assert.Equal(\n                txsA,\n                ActionEvaluator.OrderTxsForEvaluation(\n                    b1.ProtocolVersion,\n                    b1.Transactions,\n                    b1.PreEvaluationHash.ByteArray\n                )\n            );\n\n            var txsB = Enumerable.Range(0, 4)\n                .Select(nonce => _fx.MakeTransaction(\n                    nonce: nonce, privateKey: privateKey, timestamp: DateTimeOffset.Now))\n                .ToArray();\n            StageTransactions(txsB);\n\n            // Propose only txs having higher or equal with nonce than expected nonce.\n            Block b2 = _blockChain.ProposeBlock(\n                new PrivateKey(),\n                CreateBlockCommit(b1),\n                _blockChain.GetPendingEvidence());\n            Assert.Single(b2.Transactions);\n            Assert.Contains(txsB[3], b2.Transactions);\n        }\n\n        [SkippableFact]\n        public void IgnoreDuplicatedNonceTxs()\n        {\n            var privateKey = new PrivateKey();\n            var txs = Enumerable.Range(0, 3)\n                .Select(_ => _fx.MakeTransaction(\n                    nonce: 0,\n                    privateKey: privateKey,\n                    timestamp: DateTimeOffset.Now))\n                .ToArray();\n            StageTransactions(txs);\n            Block b = _blockChain.ProposeBlock(privateKey);\n            _blockChain.Append(b, CreateBlockCommit(b));\n\n            Assert.Single(b.Transactions);\n            Assert.Contains(b.Transactions.Single(), txs);\n        }\n\n        [SkippableFact]\n        public void GatherTransactionsToPropose()\n        {\n            // TODO: We test more properties of GatherTransactionsToPropose() method:\n            //       - if transactions are cut off if they exceed GetMaxTransactionsBytes()\n            //       - if transactions with already consumed nonces are excluded\n            //       - if transactions with greater nonces than unconsumed nonces are excluded\n            //       - if transactions are cut off if the process exceeds the timeout (4 sec)\n            var keyA = new PrivateKey();\n            var keyB = new PrivateKey();\n            var keyC = new PrivateKey();\n            Address a = keyA.Address;\n            Address b = keyB.Address;\n            Address c = keyC.Address;\n            _logger.Verbose(\"Address {Name}: {Address}\", nameof(a), a);\n            _logger.Verbose(\"Address {Name}: {Address}\", nameof(b), b);\n            _logger.Verbose(\"Address {Name}: {Address}\", nameof(c), c);\n\n            Transaction[] txsA = Enumerable.Range(0, 3)\n                .Select(nonce => _fx.MakeTransaction(nonce: nonce, privateKey: keyA))\n                .ToArray();\n            Transaction[] txsB = Enumerable.Range(0, 4)\n                .Select(nonce => _fx.MakeTransaction(nonce: nonce, privateKey: keyB))\n                .ToArray();\n            Transaction[] txsC = Enumerable.Range(0, 2)\n                .Select(nonce => _fx.MakeTransaction(nonce: nonce, privateKey: keyC))\n                .ToArray();\n            var random = new Random();\n            Transaction[] txs =\n                txsA.Concat(txsB).Concat(txsC).Shuffle(random).ToArray();\n            Assert.Empty(_blockChain.ListStagedTransactions());\n            StageTransactions(txs);\n\n            // Test if minTransactions and minTransactionsPerSigner work:\n            ImmutableList<Transaction> gathered =\n                _blockChain.GatherTransactionsToPropose(1024 * 1024, 5, 3, 0);\n            Assert.Equal(5, gathered.Count);\n            var expectedNonces = new Dictionary<Address, long> { [a] = 0, [b] = 0, [c] = 0 };\n            foreach (Transaction tx in gathered)\n            {\n                long expectedNonce = expectedNonces[tx.Signer];\n                Assert.True(expectedNonce < 3);\n                Assert.Equal(expectedNonce, tx.Nonce);\n                expectedNonces[tx.Signer] = expectedNonce + 1;\n            }\n\n            // Test if txPriority works:\n            IComparer<Transaction> txPriority =\n                Comparer<Transaction>.Create((tx1, tx2) =>\n                {\n                    int rank1 = tx1.Signer.Equals(a) ? 0 : (tx1.Signer.Equals(b) ? 1 : 2);\n                    int rank2 = tx2.Signer.Equals(a) ? 0 : (tx2.Signer.Equals(b) ? 1 : 2);\n                    return rank1.CompareTo(rank2);\n                });\n            gathered = _blockChain.GatherTransactionsToPropose(1024 * 1024, 8, 3, 0, txPriority);\n            Assert.Equal(\n                txsA.Concat(txsB.Take(3)).Concat(txsC).Select(tx => tx.Id).ToArray(),\n                gathered.Select(tx => tx.Id).ToArray()\n            );\n        }\n\n        [SkippableFact]\n        public void MarkTransactionsToIgnoreWhileProposing()\n        {\n            var keyA = new PrivateKey();\n            var keyB = new PrivateKey();\n            var unsignedInvalidTx = new UnsignedTx(\n                new TxInvoice(\n                    _blockChain.Genesis.Hash,\n                    DateTimeOffset.UtcNow,\n                    new TxActionList((IValue)List.Empty.Add(new Text(\"Foo\")))), // Invalid action\n                new TxSigningMetadata(keyB.PublicKey, 1));\n            var txWithInvalidAction = new Transaction(\n                unsignedInvalidTx, unsignedInvalidTx.CreateSignature(keyB)\n            );\n            Transaction txWithInvalidNonce = Transaction.Create(\n                2, keyB, _blockChain.Genesis.Hash, Array.Empty<DumbAction>().ToPlainValues()\n            );\n            var txs = new[]\n            {\n                Transaction.Create(\n                    0,\n                    keyA,\n                    _blockChain.Genesis.Hash,\n                    Array.Empty<DumbAction>().ToPlainValues()),\n                Transaction.Create(\n                    1,\n                    keyA,\n                    _blockChain.Genesis.Hash,\n                    Array.Empty<DumbAction>().ToPlainValues()),\n                Transaction.Create(\n                    2,\n                    keyA,\n                    _blockChain.Genesis.Hash,\n                    Array.Empty<DumbAction>().ToPlainValues()),\n                Transaction.Create(\n                    0,\n                    keyB,\n                    _blockChain.Genesis.Hash,\n                    Array.Empty<DumbAction>().ToPlainValues()),\n                txWithInvalidAction,\n                txWithInvalidNonce,\n            };\n\n            // Invalid txs can be staged.\n            StageTransactions(txs);\n            Assert.Equal(txs.Length, _blockChain.ListStagedTransactions().Count);\n\n            var block = _blockChain.ProposeBlock(\n                new PrivateKey(),\n                CreateBlockCommit(_blockChain.Tip),\n                _blockChain.GetPendingEvidence());\n\n            Assert.DoesNotContain(txWithInvalidNonce, block.Transactions);\n            Assert.DoesNotContain(txWithInvalidAction, block.Transactions);\n\n            // txWithInvalidAction is marked ignored and removed\n            Assert.Equal(txs.Length - 1, _blockChain.ListStagedTransactions().Count);\n            Assert.True(_blockChain.StagePolicy.Ignores(_blockChain, txWithInvalidAction.Id));\n        }\n    }\n}\n"
  },
  {
    "path": "test/Libplanet.Tests/Blockchain/BlockChainTest.Stage.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing Libplanet.Action;\nusing Libplanet.Action.Tests.Common;\nusing Libplanet.Crypto;\nusing Libplanet.Types.Blocks;\nusing Libplanet.Types.Tx;\nusing Xunit;\n\nnamespace Libplanet.Tests.Blockchain\n{\n    public partial class BlockChainTest\n    {\n        [SkippableFact]\n        public void StageTransaction()\n        {\n            var txs = new HashSet<Transaction>()\n            {\n                _fx.Transaction1,\n                _fx.Transaction2,\n            };\n            Assert.Empty(_blockChain.StagePolicy.Iterate(_blockChain));\n\n            StageTransactions(txs);\n            Assert.Equal(txs, _blockChain.StagePolicy.Iterate(_blockChain).ToHashSet());\n        }\n\n        [SkippableFact]\n        public void StageTransactionWithDifferentGenesis()\n        {\n            Transaction tx1 = Transaction.Create(\n                0,\n                new PrivateKey(),\n                _blockChain.Genesis.Hash,\n                new List<DumbAction>().ToPlainValues());\n            Transaction tx2 = Transaction.Create(\n                0,\n                new PrivateKey(),\n                null,\n                new List<DumbAction>().ToPlainValues());\n            Transaction tx3 = Transaction.Create(\n                0,\n                new PrivateKey(),\n                default(BlockHash),\n                new List<DumbAction>().ToPlainValues());\n\n            Assert.True(_blockChain.StageTransaction(tx1));\n            Assert.Equal(1, _blockChain.GetStagedTransactionIds().Count);\n            Assert.Throws<InvalidTxGenesisHashException>(() => _blockChain.StageTransaction(tx2));\n            Assert.Equal(1, _blockChain.GetStagedTransactionIds().Count);\n            Assert.Throws<InvalidTxGenesisHashException>(() => _blockChain.StageTransaction(tx3));\n            Assert.Equal(1, _blockChain.GetStagedTransactionIds().Count);\n        }\n\n        [SkippableFact]\n        public void TransactionsWithDuplicatedNonce()\n        {\n            var key = new PrivateKey();\n\n            Transaction tx_0_0 = _fx.MakeTransaction(\n                Array.Empty<DumbAction>(),\n                nonce: 0,\n                privateKey: key\n            );\n            Transaction tx_0_1 = _fx.MakeTransaction(\n                Array.Empty<DumbAction>(),\n                nonce: 0,\n                privateKey: key\n            );\n            Transaction tx_1_0 = _fx.MakeTransaction(\n                Array.Empty<DumbAction>(),\n                nonce: 1,\n                privateKey: key\n            );\n            Transaction tx_1_1 = _fx.MakeTransaction(\n                Array.Empty<DumbAction>(),\n                nonce: 1,\n                privateKey: key\n            );\n\n            // stage tx_0_0 -> mine tx_0_0 -> stage tx_0_1\n            Assert.True(_blockChain.StageTransaction(tx_0_0));\n            var block = _blockChain.ProposeBlock(key);\n            _blockChain.Append(block, TestUtils.CreateBlockCommit(block));\n            Assert.Empty(_blockChain.GetStagedTransactionIds());\n            Assert.Empty(_blockChain.StagePolicy.Iterate(_blockChain, filtered: true));\n            Assert.Empty(_blockChain.StagePolicy.Iterate(_blockChain, filtered: false));\n            // should still able to stage a low nonce tx\n            Assert.True(_blockChain.StageTransaction(tx_0_1));\n            // tx_0_1 is still staged, just filtered.\n            Assert.Empty(_blockChain.GetStagedTransactionIds());\n            Assert.Empty(_blockChain.StagePolicy.Iterate(_blockChain, filtered: true));\n            Assert.NotEmpty(_blockChain.StagePolicy.Iterate(_blockChain, filtered: false));\n\n            // stage tx_1_0 -> stage tx_1_1 -> mine tx_1_0 or tx_1_1\n            Assert.True(_blockChain.StageTransaction(tx_1_0));\n            Assert.True(_blockChain.StageTransaction(tx_1_1));\n            var txIds = new List<TxId>() { tx_1_0.Id, tx_1_1.Id };\n            Assert.Equal(2, _blockChain.GetStagedTransactionIds().Count);\n            Assert.Equal(\n                txIds.OrderBy(id => id),\n                _blockChain.GetStagedTransactionIds().OrderBy(id => id)\n            );\n            block = _blockChain.ProposeBlock(key, TestUtils.CreateBlockCommit(_blockChain.Tip));\n            _blockChain.Append(block, TestUtils.CreateBlockCommit(block));\n            // tx_0_1 and tx_1_x should be still staged, just filtered\n            Assert.Empty(_blockChain.GetStagedTransactionIds());\n            Assert.Empty(_blockChain.StagePolicy.Iterate(_blockChain, filtered: true));\n            Assert.Equal(2, _blockChain.StagePolicy.Iterate(_blockChain, filtered: false).Count());\n        }\n\n        [SkippableFact]\n        public void UnstageTransaction()\n        {\n            Transaction[] txs = { _fx.Transaction1, _fx.Transaction2 };\n            Assert.Empty(_blockChain.GetStagedTransactionIds());\n\n            StageTransactions(txs);\n\n            HashSet<TxId> txIds = txs.Select(tx => tx.Id).ToHashSet();\n            HashSet<TxId> stagedTxIds = _blockChain.GetStagedTransactionIds().ToHashSet();\n\n            Assert.Equal(txIds, stagedTxIds);\n\n            Assert.True(_blockChain.UnstageTransaction(_fx.Transaction1));\n            Assert.True(_blockChain.UnstageTransaction(_fx.Transaction2));\n\n            Assert.Empty(_blockChain.GetStagedTransactionIds());\n        }\n\n        private void StageTransactions(IEnumerable<Transaction> txs)\n        {\n            foreach (Transaction tx in txs)\n            {\n                _blockChain.StageTransaction(tx);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "test/Libplanet.Tests/Blockchain/BlockChainTest.ValidateNextBlock.cs",
    "content": "using System;\nusing System.Collections.Immutable;\nusing System.Linq;\nusing System.Numerics;\nusing Bencodex.Types;\nusing Libplanet.Action;\nusing Libplanet.Action.Loader;\nusing Libplanet.Action.Tests.Common;\nusing Libplanet.Blockchain;\nusing Libplanet.Blockchain.Policies;\nusing Libplanet.Crypto;\nusing Libplanet.Store;\nusing Libplanet.Store.Trie;\nusing Libplanet.Types.Blocks;\nusing Libplanet.Types.Consensus;\nusing Xunit;\n\nnamespace Libplanet.Tests.Blockchain\n{\n    public partial class BlockChainTest\n    {\n        [SkippableFact]\n        public void ValidateNextBlock()\n        {\n            Block validNextBlock = _blockChain.EvaluateAndSign(\n                new BlockContent(\n                    new BlockMetadata(\n                        index: 1L,\n                        timestamp: _fx.GenesisBlock.Timestamp.AddDays(1),\n                        publicKey: _fx.Proposer.PublicKey,\n                        previousHash: _fx.GenesisBlock.Hash,\n                        txHash: null,\n                        lastCommit: null,\n                        evidenceHash: null)).Propose(),\n                _fx.Proposer);\n            _blockChain.Append(validNextBlock, TestUtils.CreateBlockCommit(validNextBlock));\n            Assert.Equal(_blockChain.Tip, validNextBlock);\n        }\n\n        [SkippableFact]\n        public void ValidateNextBlockProtocolVersion()\n        {\n            var protocolVersion = _blockChain.Tip.ProtocolVersion;\n            Block block1 = _blockChain.EvaluateAndSign(\n                new BlockContent(\n                    new BlockMetadata(\n                        protocolVersion: protocolVersion,\n                        index: 1L,\n                        timestamp: _fx.GenesisBlock.Timestamp.AddDays(1),\n                        miner: _fx.Proposer.Address,\n                        publicKey: protocolVersion >= 2 ? _fx.Proposer.PublicKey : null,\n                        previousHash: _fx.GenesisBlock.Hash,\n                        txHash: null,\n                        lastCommit: null,\n                        evidenceHash: null)).Propose(),\n                _fx.Proposer);\n            _blockChain.Append(block1, TestUtils.CreateBlockCommit(block1));\n\n            Assert.Throws<ApplicationException>(() => _blockChain.EvaluateAndSign(\n                new BlockContent(\n                    new BlockMetadata(\n                        protocolVersion: BlockMetadata.WorldStateProtocolVersion - 1,\n                        index: 2L,\n                        timestamp: _fx.GenesisBlock.Timestamp.AddDays(2),\n                        miner: _fx.Proposer.Address,\n                        publicKey: protocolVersion - 1 >= 2 ? _fx.Proposer.PublicKey : null,\n                        previousHash: block1.Hash,\n                        txHash: null,\n                        lastCommit: null,\n                        evidenceHash: null)).Propose(),\n                _fx.Proposer));\n\n            Assert.Throws<InvalidBlockProtocolVersionException>(() =>\n            {\n                Block block3 = _blockChain.EvaluateAndSign(\n                    new BlockContent(\n                        new BlockMetadata(\n                            protocolVersion: BlockMetadata.CurrentProtocolVersion + 1,\n                            index: 2L,\n                            timestamp: _fx.GenesisBlock.Timestamp.AddDays(2),\n                            miner: _fx.Proposer.Address,\n                            publicKey: _fx.Proposer.PublicKey,\n                            previousHash: block1.Hash,\n                            txHash: null,\n                            lastCommit: null,\n                            evidenceHash: null)).Propose(),\n                    _fx.Proposer);\n                _blockChain.Append(block3, TestUtils.CreateBlockCommit(block3));\n            });\n        }\n\n        [SkippableFact]\n        public void ValidateNextBlockInvalidIndex()\n        {\n            _blockChain.Append(_validNext, TestUtils.CreateBlockCommit(_validNext));\n\n            Block prev = _blockChain.Tip;\n            Block blockWithAlreadyUsedIndex = _blockChain.EvaluateAndSign(\n                new BlockContent(\n                    new BlockMetadata(\n                        index: prev.Index,\n                        timestamp: DateTimeOffset.UtcNow,\n                        publicKey: _fx.Proposer.PublicKey,\n                        previousHash: prev.Hash,\n                        txHash: null,\n                        lastCommit: null,\n                        evidenceHash: null)).Propose(),\n                _fx.Proposer);\n            Assert.Throws<InvalidBlockIndexException>(\n                () => _blockChain.Append(\n                    blockWithAlreadyUsedIndex,\n                    TestUtils.CreateBlockCommit(blockWithAlreadyUsedIndex))\n            );\n\n            Block blockWithIndexAfterNonexistentIndex = _blockChain.EvaluateAndSign(\n                new BlockContent(\n                    new BlockMetadata(\n                        index: prev.Index + 2,\n                        timestamp: DateTimeOffset.UtcNow,\n                        publicKey: _fx.Proposer.PublicKey,\n                        previousHash: prev.Hash,\n                        txHash: null,\n                        lastCommit: TestUtils.CreateBlockCommit(prev.Hash, prev.Index + 1, 0),\n                        evidenceHash: null))\n                        .Propose(),\n                _fx.Proposer);\n            Assert.Throws<InvalidBlockIndexException>(\n                () => _blockChain.Append(\n                    blockWithIndexAfterNonexistentIndex,\n                    TestUtils.CreateBlockCommit(blockWithIndexAfterNonexistentIndex))\n            );\n        }\n\n        [SkippableFact]\n        public void ValidateNextBlockInvalidPreviousHash()\n        {\n            _blockChain.Append(_validNext, TestUtils.CreateBlockCommit(_validNext));\n\n            Block invalidPreviousHashBlock = _blockChain.EvaluateAndSign(\n                new BlockContent(\n                    new BlockMetadata(\n                        index: 2,\n                        timestamp: DateTimeOffset.UtcNow,\n                        publicKey: _fx.Proposer.PublicKey,\n                        // Should be _validNext.Hash instead\n                        previousHash: _validNext.PreviousHash,\n                        txHash: null,\n                        // ReSharper disable once PossibleInvalidOperationException\n                        lastCommit: TestUtils.CreateBlockCommit(\n                            _validNext.PreviousHash.Value, 1, 0),\n                        evidenceHash: null)).Propose(),\n                _fx.Proposer);\n            Assert.Throws<InvalidBlockPreviousHashException>(() =>\n                    _blockChain.Append(\n                        invalidPreviousHashBlock,\n                        TestUtils.CreateBlockCommit(invalidPreviousHashBlock)));\n        }\n\n        [SkippableFact]\n        public void ValidateNextBlockInvalidTimestamp()\n        {\n            _blockChain.Append(_validNext, TestUtils.CreateBlockCommit(_validNext));\n\n            Block invalidPreviousTimestamp = _blockChain.EvaluateAndSign(\n                new BlockContent(\n                    new BlockMetadata(\n                        index: 2,\n                        timestamp: _validNext.Timestamp.AddSeconds(-1),\n                        publicKey: _fx.Proposer.PublicKey,\n                        previousHash: _validNext.Hash,\n                        txHash: null,\n                        lastCommit: TestUtils.CreateBlockCommit(_validNext),\n                        evidenceHash: null)).Propose(),\n                _fx.Proposer);\n            Assert.Throws<InvalidBlockTimestampException>(() =>\n                    _blockChain.Append(\n                        invalidPreviousTimestamp,\n                        TestUtils.CreateBlockCommit(invalidPreviousTimestamp)));\n        }\n\n        [SkippableFact]\n        public void ValidateNextBlockInvalidStateRootHash()\n        {\n            var policy = new BlockPolicy(\n                blockInterval: TimeSpan.FromMilliseconds(3 * 60 * 60 * 1000)\n            );\n            var stateStore1 = new TrieStateStore(new MemoryKeyValueStore());\n            IStore store1 = new MemoryStore();\n            var actionEvaluator1 = new ActionEvaluator(\n                policy.PolicyActionsRegistry,\n                stateStore1,\n                new SingleActionLoader(typeof(DumbAction)));\n            var genesisBlock = TestUtils.ProposeGenesisBlock(\n                TestUtils.ProposeGenesis(TestUtils.GenesisProposer.PublicKey),\n                TestUtils.GenesisProposer);\n            var chain1 = BlockChain.Create(\n                policy,\n                new VolatileStagePolicy(),\n                store1,\n                stateStore1,\n                genesisBlock,\n                actionEvaluator1);\n\n            var endBlockActions = new IAction[]\n            {\n                new SetStatesAtBlock(default, (Text)\"foo\", default, 0),\n            }.ToImmutableArray();\n            var policyWithBlockAction = new BlockPolicy(\n                new PolicyActionsRegistry(\n                    endBlockActions: ImmutableArray.Create<IAction>(\n                        new SetStatesAtBlock(default, (Text)\"foo\", default, 0))),\n                blockInterval: policy.BlockInterval);\n            var stateStore2 = new TrieStateStore(new MemoryKeyValueStore());\n            IStore store2 = new MemoryStore();\n            var actionEvaluator2 = new ActionEvaluator(\n                policyWithBlockAction.PolicyActionsRegistry,\n                stateStore2,\n                new SingleActionLoader(typeof(DumbAction)));\n            var chain2 = BlockChain.Create(\n                policyWithBlockAction,\n                new VolatileStagePolicy(),\n                store2,\n                stateStore2,\n                genesisBlock,\n                actionEvaluator2);\n\n            Block block1 = chain1.EvaluateAndSign(\n                new BlockContent(\n                    new BlockMetadata(\n                        protocolVersion: BlockMetadata.CurrentProtocolVersion,\n                        index: 1,\n                        timestamp: genesisBlock.Timestamp.AddSeconds(1),\n                        miner: TestUtils.GenesisProposer.Address,\n                        publicKey: TestUtils.GenesisProposer.PublicKey,\n                        previousHash: genesisBlock.Hash,\n                        txHash: null,\n                        lastCommit: null,\n                        evidenceHash: null)).Propose(),\n                TestUtils.GenesisProposer);\n\n            Assert.Throws<InvalidBlockStateRootHashException>(() =>\n                chain2.Append(block1, TestUtils.CreateBlockCommit(block1)));\n\n            chain1.Append(block1, TestUtils.CreateBlockCommit(block1));\n        }\n\n        [Fact]\n        public void ValidateNextBlockInvalidStateRootHashBeforePostpone()\n        {\n            var beforePostponeBPV = BlockMetadata.SlothProtocolVersion - 1;\n            var policy = new BlockPolicy(\n                blockInterval: TimeSpan.FromMilliseconds(3 * 60 * 60 * 1000)\n            );\n            var stateStore = new TrieStateStore(new MemoryKeyValueStore());\n            IStore store = new MemoryStore();\n            var actionEvaluator = new ActionEvaluator(\n                policy.PolicyActionsRegistry,\n                stateStore,\n                new SingleActionLoader(typeof(DumbAction)));\n            var preGenesis = TestUtils.ProposeGenesis(\n                proposer: TestUtils.GenesisProposer.PublicKey,\n                protocolVersion: beforePostponeBPV);\n            var genesisBlock = preGenesis.Sign(\n                TestUtils.GenesisProposer,\n                actionEvaluator.Evaluate(preGenesis, MerkleTrie.EmptyRootHash).Last().OutputState);\n            var chain1 = BlockChain.Create(\n                policy,\n                new VolatileStagePolicy(),\n                store,\n                stateStore,\n                genesisBlock,\n                actionEvaluator);\n\n            Block block1 = chain1.EvaluateAndSign(\n                new BlockContent(\n                    new BlockMetadata(\n                        protocolVersion: beforePostponeBPV,\n                        index: 1,\n                        timestamp: genesisBlock.Timestamp.AddSeconds(1),\n                        miner: TestUtils.GenesisProposer.Address,\n                        publicKey: TestUtils.GenesisProposer.PublicKey,\n                        previousHash: genesisBlock.Hash,\n                        txHash: null,\n                        lastCommit: null,\n                        evidenceHash: null)).Propose(),\n                TestUtils.GenesisProposer);\n\n            var policyWithBlockAction = new BlockPolicy(\n                new PolicyActionsRegistry(\n                    beginBlockActions: ImmutableArray<IAction>.Empty,\n                    endBlockActions: ImmutableArray.Create<IAction>(\n                        new SetStatesAtBlock(default, (Text)\"foo\", default, 1))),\n                blockInterval: policy.BlockInterval);\n            var blockChainStates = new BlockChainStates(store, stateStore);\n            var chain2 = new BlockChain(\n                policyWithBlockAction,\n                new VolatileStagePolicy(),\n                store,\n                stateStore,\n                genesisBlock,\n                blockChainStates,\n                new ActionEvaluator(\n                    policyWithBlockAction.PolicyActionsRegistry,\n                    stateStore,\n                    new SingleActionLoader(typeof(DumbAction))));\n\n            Assert.Throws<InvalidBlockStateRootHashException>(() =>\n                chain2.Append(block1, TestUtils.CreateBlockCommit(block1)));\n\n            chain1.Append(block1, TestUtils.CreateBlockCommit(block1));\n        }\n\n        [Fact]\n        public void ValidateNextBlockInvalidStateRootHashOnPostpone()\n        {\n            var beforePostponeBPV = BlockMetadata.SlothProtocolVersion - 1;\n            var policy = new BlockPolicy(\n                new PolicyActionsRegistry(\n                    beginBlockActions: ImmutableArray.Create<IAction>(\n                        new SetStatesAtBlock(default, (Text)\"foo\", default, 1))),\n                blockInterval: TimeSpan.FromMilliseconds(3 * 60 * 60 * 1000));\n            var stateStore = new TrieStateStore(new MemoryKeyValueStore());\n            IStore store = new MemoryStore();\n            var actionEvaluator = new ActionEvaluator(\n                policy.PolicyActionsRegistry,\n                stateStore,\n                new SingleActionLoader(typeof(DumbAction)));\n            var preGenesis = TestUtils.ProposeGenesis(\n                proposer: TestUtils.GenesisProposer.PublicKey,\n                protocolVersion: beforePostponeBPV);\n            var genesisBlock = preGenesis.Sign(\n                TestUtils.GenesisProposer,\n                actionEvaluator.Evaluate(preGenesis, MerkleTrie.EmptyRootHash).Last().OutputState);\n            var chain = BlockChain.Create(\n                policy,\n                new VolatileStagePolicy(),\n                store,\n                stateStore,\n                genesisBlock,\n                actionEvaluator);\n\n            PreEvaluationBlock preBlock1 = new BlockContent(\n                new BlockMetadata(\n                    protocolVersion: BlockMetadata.SlothProtocolVersion,\n                    index: 1,\n                    timestamp: genesisBlock.Timestamp.AddSeconds(1),\n                    miner: TestUtils.GenesisProposer.Address,\n                    publicKey: TestUtils.GenesisProposer.PublicKey,\n                    previousHash: genesisBlock.Hash,\n                    txHash: null,\n                    lastCommit: null,\n                    evidenceHash: null)).Propose();\n            Block block1 = chain.EvaluateAndSign(\n                preBlock1,\n                TestUtils.GenesisProposer);\n            Assert.Equal(genesisBlock.StateRootHash, block1.StateRootHash);\n\n            Block block2 = preBlock1.Sign(\n                TestUtils.GenesisProposer,\n                actionEvaluator.Evaluate(preBlock1, genesisBlock.StateRootHash).Last().OutputState);\n\n            Assert.Throws<InvalidBlockStateRootHashException>(() =>\n                chain.Append(block2, TestUtils.CreateBlockCommit(block2)));\n\n            chain.Append(block1, TestUtils.CreateBlockCommit(block1));\n        }\n\n        [SkippableFact]\n        public void ValidateNextBlockLastCommitNullAtIndexOne()\n        {\n            Block validNextBlock = _blockChain.EvaluateAndSign(\n                new BlockContent(\n                    new BlockMetadata(\n                        index: 1L,\n                        timestamp: DateTimeOffset.UtcNow,\n                        publicKey: _fx.Proposer.PublicKey,\n                        previousHash: _fx.GenesisBlock.Hash,\n                        txHash: null,\n                        lastCommit: null,\n                        evidenceHash: null)).Propose(),\n                _fx.Proposer);\n            _blockChain.Append(validNextBlock, TestUtils.CreateBlockCommit(validNextBlock));\n            Assert.Equal(_blockChain.Tip, validNextBlock);\n        }\n\n        [SkippableFact]\n        public void ValidateNextBlockLastCommitUpperIndexOne()\n        {\n            Block block1 = _blockChain.EvaluateAndSign(\n                new BlockContent(\n                    new BlockMetadata(\n                        index: 1L,\n                        timestamp: DateTimeOffset.UtcNow,\n                        publicKey: _fx.Proposer.PublicKey,\n                        previousHash: _fx.GenesisBlock.Hash,\n                        txHash: null,\n                        lastCommit: null,\n                        evidenceHash: null)).Propose(),\n                _fx.Proposer);\n            _blockChain.Append(block1, TestUtils.CreateBlockCommit(block1));\n\n            var blockCommit = TestUtils.CreateBlockCommit(block1);\n            Block block2 = _blockChain.EvaluateAndSign(\n                new BlockContent(\n                    new BlockMetadata(\n                        index: 2L,\n                        timestamp: DateTimeOffset.UtcNow,\n                        publicKey: _fx.Proposer.PublicKey,\n                        previousHash: block1.Hash,\n                        txHash: null,\n                        lastCommit: blockCommit,\n                        evidenceHash: null)).Propose(),\n                _fx.Proposer);\n            _blockChain.Append(block2, TestUtils.CreateBlockCommit(block2));\n            Assert.Equal(_blockChain.Tip, block2);\n        }\n\n        [SkippableFact]\n        public void ValidateNextBlockLastCommitFailsUnexpectedValidator()\n        {\n            Block block1 = _blockChain.EvaluateAndSign(\n                new BlockContent(\n                    new BlockMetadata(\n                        index: 1L,\n                        timestamp: DateTimeOffset.UtcNow,\n                        publicKey: _fx.Proposer.PublicKey,\n                        previousHash: _fx.GenesisBlock.Hash,\n                        txHash: null,\n                        lastCommit: null,\n                        evidenceHash: null)).Propose(),\n                _fx.Proposer);\n            _blockChain.Append(block1, TestUtils.CreateBlockCommit(block1));\n\n            var invalidValidator = new PrivateKey();\n            var validators = TestUtils.ValidatorPrivateKeys.Append(invalidValidator).ToList();\n            var validatorPowers = TestUtils.ValidatorSet.Validators.Select(v => v.Power)\n                .Append(BigInteger.One)\n                .ToList();\n            var votes = Enumerable.Range(0, validators.Count).Select(index => new VoteMetadata(\n                1,\n                0,\n                block1.Hash,\n                DateTimeOffset.UtcNow,\n                validators[index].PublicKey,\n                validatorPowers[index],\n                VoteFlag.PreCommit).Sign(validators[index])).ToImmutableArray();\n            var blockCommit = new BlockCommit(1, 0, block1.Hash, votes);\n\n            Block block2 = _blockChain.EvaluateAndSign(\n                new BlockContent(\n                    new BlockMetadata(\n                        index: 2L,\n                        timestamp: DateTimeOffset.UtcNow,\n                        publicKey: _fx.Proposer.PublicKey,\n                        previousHash: block1.Hash,\n                        txHash: null,\n                        lastCommit: blockCommit,\n                        evidenceHash: null)).Propose(),\n                _fx.Proposer);\n            Assert.Throws<InvalidBlockLastCommitException>(() =>\n                _blockChain.Append(block2, TestUtils.CreateBlockCommit(block2)));\n        }\n\n        [SkippableFact]\n        public void ValidateNextBlockLastCommitFailsDropExpectedValidator()\n        {\n            Block block1 = _blockChain.EvaluateAndSign(\n                new BlockContent(\n                    new BlockMetadata(\n                        index: 1L,\n                        timestamp: DateTimeOffset.UtcNow,\n                        publicKey: _fx.Proposer.PublicKey,\n                        previousHash: _fx.GenesisBlock.Hash,\n                        txHash: null,\n                        lastCommit: null,\n                        evidenceHash: null)).Propose(),\n                _fx.Proposer);\n            _blockChain.Append(block1, TestUtils.CreateBlockCommit(block1));\n\n            var keysExceptPeer0 = TestUtils.ValidatorPrivateKeys.Where(\n                key => key != TestUtils.ValidatorPrivateKeys[0]).ToList();\n            var votes = keysExceptPeer0.Select(key => new VoteMetadata(\n                1,\n                0,\n                block1.Hash,\n                DateTimeOffset.UtcNow,\n                key.PublicKey,\n                TestUtils.ValidatorSet.GetValidator(key.PublicKey).Power,\n                VoteFlag.PreCommit).Sign(key)).ToImmutableArray();\n            var blockCommit = new BlockCommit(1, 0, block1.Hash, votes);\n            Block block2 = _blockChain.EvaluateAndSign(\n                new BlockContent(\n                    new BlockMetadata(\n                        index: 2,\n                        timestamp: DateTimeOffset.UtcNow,\n                        publicKey: _fx.Proposer.PublicKey,\n                        previousHash: block1.Hash,\n                        txHash: null,\n                        lastCommit: blockCommit,\n                        evidenceHash: null)).Propose(),\n                _fx.Proposer);\n            Assert.Throws<InvalidBlockLastCommitException>(() =>\n                _blockChain.Append(block2, TestUtils.CreateBlockCommit(block2)));\n        }\n\n        [SkippableFact]\n        public void ValidateBlockCommitGenesis()\n        {\n            // Works fine.\n            _blockChain.ValidateBlockCommit(_fx.GenesisBlock, null);\n\n            // Should be null for genesis.\n            Assert.Throws<InvalidBlockCommitException>(() => _blockChain.ValidateBlockCommit(\n                _fx.GenesisBlock,\n                new BlockCommit(\n                    0,\n                    0,\n                    _fx.GenesisBlock.Hash,\n                    TestUtils.ValidatorPrivateKeys.Select(x => new VoteMetadata(\n                        0,\n                        0,\n                        _fx.GenesisBlock.Hash,\n                        DateTimeOffset.UtcNow,\n                        x.PublicKey,\n                        TestUtils.ValidatorSet.GetValidator(x.PublicKey).Power,\n                        VoteFlag.PreCommit).Sign(x)).ToImmutableArray())));\n        }\n\n        [SkippableFact]\n        public void ValidateBlockCommitFailsDifferentBlockHash()\n        {\n            Block validNextBlock = _blockChain.EvaluateAndSign(\n                new BlockContent(\n                    new BlockMetadata(\n                        index: 1L,\n                        timestamp: _fx.GenesisBlock.Timestamp.AddDays(1),\n                        publicKey: _fx.Proposer.PublicKey,\n                        previousHash: _fx.GenesisBlock.Hash,\n                        txHash: null,\n                        lastCommit: null,\n                        evidenceHash: null)).Propose(),\n                _fx.Proposer);\n\n            Assert.Throws<InvalidBlockCommitException>(() =>\n                _blockChain.Append(\n                    validNextBlock,\n                    TestUtils.CreateBlockCommit(\n                        new BlockHash(TestUtils.GetRandomBytes(BlockHash.Size)),\n                        1,\n                        0)));\n        }\n\n        [SkippableFact]\n        public void ValidateBlockCommitFailsDifferentHeight()\n        {\n            Block validNextBlock = _blockChain.EvaluateAndSign(\n                new BlockContent(\n                    new BlockMetadata(\n                        index: 1L,\n                        timestamp: _fx.GenesisBlock.Timestamp.AddDays(1),\n                        publicKey: _fx.Proposer.PublicKey,\n                        previousHash: _fx.GenesisBlock.Hash,\n                        txHash: null,\n                        lastCommit: null,\n                        evidenceHash: null)).Propose(),\n                _fx.Proposer);\n\n            Assert.Throws<InvalidBlockCommitException>(() =>\n                _blockChain.Append(\n                    validNextBlock,\n                    TestUtils.CreateBlockCommit(\n                        validNextBlock.Hash,\n                        2,\n                        0)));\n        }\n\n        [SkippableFact]\n        public void ValidateBlockCommitFailsDifferentValidatorSet()\n        {\n            Block validNextBlock = _blockChain.EvaluateAndSign(\n                new BlockContent(\n                    new BlockMetadata(\n                        index: 1L,\n                        timestamp: _fx.GenesisBlock.Timestamp.AddDays(1),\n                        publicKey: _fx.Proposer.PublicKey,\n                        previousHash: _fx.GenesisBlock.Hash,\n                        txHash: null,\n                        lastCommit: null,\n                        evidenceHash: null)).Propose(),\n                _fx.Proposer);\n\n            Assert.Throws<InvalidBlockCommitException>(() =>\n                _blockChain.Append(\n                    validNextBlock,\n                    new BlockCommit(\n                        1,\n                        0,\n                        validNextBlock.Hash,\n                        Enumerable.Range(0, TestUtils.ValidatorSet.TotalCount)\n                            .Select(x => new PrivateKey())\n                            .Select(x => new VoteMetadata(\n                            1,\n                            0,\n                            validNextBlock.Hash,\n                            DateTimeOffset.UtcNow,\n                            x.PublicKey,\n                            BigInteger.One,\n                            VoteFlag.PreCommit).Sign(x)).ToImmutableArray())));\n        }\n\n        [SkippableFact]\n        public void ValidateBlockCommitFailsNullBlockCommit()\n        {\n            Block validNextBlock = _blockChain.EvaluateAndSign(\n                new BlockContent(\n                    new BlockMetadata(\n                        index: 1L,\n                        timestamp: _fx.GenesisBlock.Timestamp.AddDays(1),\n                        publicKey: _fx.Proposer.PublicKey,\n                        previousHash: _fx.GenesisBlock.Hash,\n                        txHash: null,\n                        lastCommit: null,\n                        evidenceHash: null)).Propose(),\n                _fx.Proposer);\n\n            Assert.Throws<InvalidBlockCommitException>(() =>\n                _blockChain.Append(validNextBlock, null));\n        }\n\n        [SkippableFact]\n        public void ValidateBlockCommitFailsInsufficientPower()\n        {\n            var privateKey1 = new PrivateKey();\n            var privateKey2 = new PrivateKey();\n            var privateKey3 = new PrivateKey();\n            var privateKey4 = new PrivateKey();\n            var validator1 = new Validator(privateKey1.PublicKey, 10);\n            var validator2 = new Validator(privateKey2.PublicKey, 1);\n            var validator3 = new Validator(privateKey3.PublicKey, 1);\n            var validator4 = new Validator(privateKey4.PublicKey, 1);\n            var validatorSet = new ValidatorSet(\n                new[] { validator1, validator2, validator3, validator4 }.ToList());\n            BlockChain blockChain = TestUtils.MakeBlockChain(\n                new NullBlockPolicy(),\n                new MemoryStore(),\n                new TrieStateStore(new MemoryKeyValueStore()),\n                new SingleActionLoader(typeof(DumbAction)),\n                validatorSet: validatorSet);\n            Block validNextBlock = blockChain.EvaluateAndSign(\n                new BlockContent(\n                    new BlockMetadata(\n                        index: 1L,\n                        timestamp: blockChain.Genesis.Timestamp.AddDays(1),\n                        publicKey: _fx.Proposer.PublicKey,\n                        previousHash: blockChain.Genesis.Hash,\n                        txHash: null,\n                        lastCommit: null,\n                        evidenceHash: null)).Propose(),\n                _fx.Proposer);\n\n            Vote GenerateVote(PrivateKey key, BigInteger power, VoteFlag flag)\n            {\n                var metadata = new VoteMetadata(\n                    1,\n                    0,\n                    validNextBlock.Hash,\n                    DateTimeOffset.UtcNow,\n                    key.PublicKey,\n                    power,\n                    flag);\n                return metadata.Sign(flag == VoteFlag.Null ? null : key);\n            }\n\n            ImmutableArray<Vote> GenerateVotes(\n                VoteFlag flag1,\n                VoteFlag flag2,\n                VoteFlag flag3,\n                VoteFlag flag4)\n            {\n                return new[]\n                {\n                    GenerateVote(privateKey1, validator1.Power, flag1),\n                    GenerateVote(privateKey2, validator2.Power, flag2),\n                    GenerateVote(privateKey3, validator3.Power, flag3),\n                    GenerateVote(privateKey4, validator4.Power, flag4),\n                }.OrderBy(vote => vote.ValidatorPublicKey.Address).ToImmutableArray();\n            }\n\n            var fullBlockCommit = new BlockCommit(\n                1,\n                0,\n                validNextBlock.Hash,\n                GenerateVotes(\n                    VoteFlag.PreCommit,\n                    VoteFlag.PreCommit,\n                    VoteFlag.PreCommit,\n                    VoteFlag.PreCommit)\n            );\n            blockChain.ValidateBlockCommit(validNextBlock, fullBlockCommit);\n\n            // Can propose if power is big enough even count condition is not met.\n            var validBlockCommit = new BlockCommit(\n                1,\n                0,\n                validNextBlock.Hash,\n                GenerateVotes(\n                    VoteFlag.PreCommit,\n                    VoteFlag.Null,\n                    VoteFlag.Null,\n                    VoteFlag.Null)\n            );\n            blockChain.ValidateBlockCommit(validNextBlock, validBlockCommit);\n\n            // Can not propose if power isn't big enough even count condition is met.\n            var invalidBlockCommit = new BlockCommit(\n                1,\n                0,\n                validNextBlock.Hash,\n                GenerateVotes(\n                    VoteFlag.Null,\n                    VoteFlag.PreCommit,\n                    VoteFlag.PreCommit,\n                    VoteFlag.PreCommit)\n            );\n            Assert.Throws<InvalidBlockCommitException>(() =>\n                blockChain.ValidateBlockCommit(validNextBlock, invalidBlockCommit));\n        }\n\n        [Fact]\n        public void ValidateNextBlockOnChainRestart()\n        {\n            var newChain = new BlockChain(\n                _blockChain.Policy,\n                _blockChain.StagePolicy,\n                _blockChain.Store,\n                _blockChain.StateStore,\n                _blockChain.Genesis,\n                new BlockChainStates(_blockChain.Store, _blockChain.StateStore),\n                _blockChain.ActionEvaluator);\n\n            newChain.Append(_validNext, TestUtils.CreateBlockCommit(_validNext));\n            Assert.Equal(newChain.Tip, _validNext);\n        }\n\n        [Fact]\n        public void ValidateNextBlockAEVChangedOnChainRestart()\n        {\n            var endBlockActions =\n                new IAction[] { new SetStatesAtBlock(default, (Text)\"foo\", default, 0), }\n                    .ToImmutableArray();\n            var policyWithBlockAction = new BlockPolicy(\n                new PolicyActionsRegistry(endBlockActions: endBlockActions));\n\n            var actionEvaluator = new ActionEvaluator(\n                policyWithBlockAction.PolicyActionsRegistry,\n                _blockChain.StateStore,\n                new SingleActionLoader(typeof(DumbAction)));\n\n            var newChain = new BlockChain(\n                policyWithBlockAction,\n                _blockChain.StagePolicy,\n                _blockChain.Store,\n                _blockChain.StateStore,\n                _blockChain.Genesis,\n                new BlockChainStates(_blockChain.Store, _blockChain.StateStore),\n                actionEvaluator);\n\n            Block newValidNext = newChain.EvaluateAndSign(\n                new BlockContent(\n                    new BlockMetadata(\n                        protocolVersion: BlockMetadata.CurrentProtocolVersion,\n                        index: newChain.Tip.Index + 1,\n                        timestamp: newChain.Tip.Timestamp.AddSeconds(1),\n                        miner: TestUtils.GenesisProposer.Address,\n                        publicKey: TestUtils.GenesisProposer.PublicKey,\n                        previousHash: newChain.Tip.Hash,\n                        txHash: null,\n                        lastCommit: null,\n                        evidenceHash: null)).Propose(),\n                TestUtils.GenesisProposer);\n\n            Assert.NotEqual(_validNext, newValidNext);\n\n            Assert.Throws<InvalidBlockStateRootHashException>(() =>\n                newChain.Append(_validNext, TestUtils.CreateBlockCommit(_validNext)));\n\n            newChain.Append(newValidNext, TestUtils.CreateBlockCommit(newValidNext));\n        }\n    }\n}\n"
  },
  {
    "path": "test/Libplanet.Tests/Blockchain/BlockChainTest.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Collections.Immutable;\nusing System.Linq;\nusing System.Numerics;\nusing System.Security.Cryptography;\nusing System.Threading.Tasks;\nusing Bencodex.Types;\nusing Libplanet.Action;\nusing Libplanet.Action.Loader;\nusing Libplanet.Action.State;\nusing Libplanet.Action.Sys;\nusing Libplanet.Action.Tests.Common;\nusing Libplanet.Blockchain;\nusing Libplanet.Blockchain.Policies;\nusing Libplanet.Blockchain.Renderers;\nusing Libplanet.Blockchain.Renderers.Debug;\nusing Libplanet.Common;\nusing Libplanet.Crypto;\nusing Libplanet.Store;\nusing Libplanet.Store.Trie;\nusing Libplanet.Tests.Store;\nusing Libplanet.Types.Blocks;\nusing Libplanet.Types.Consensus;\nusing Libplanet.Types.Evidence;\nusing Libplanet.Types.Tx;\nusing Serilog;\nusing Xunit;\nusing Xunit.Abstractions;\nusing static Libplanet.Tests.TestUtils;\n\nnamespace Libplanet.Tests.Blockchain\n{\n    public partial class BlockChainTest : IDisposable\n    {\n        private readonly ILogger _logger;\n        private StoreFixture _fx;\n        private BlockPolicy _policy;\n        private BlockChain _blockChain;\n        private ValidatingActionRenderer _renderer;\n        private Block _validNext;\n        private IStagePolicy _stagePolicy;\n\n        public BlockChainTest(ITestOutputHelper output)\n        {\n            Log.Logger = _logger = new LoggerConfiguration()\n                .MinimumLevel.Verbose()\n                .Enrich.WithThreadId()\n                .WriteTo.TestOutput(output)\n                .CreateLogger()\n                .ForContext<BlockChainTest>();\n\n            _policy = new BlockPolicy(\n                new PolicyActionsRegistry(\n                    endBlockActions: ImmutableArray.Create<IAction>(new MinerReward(1))),\n                getMaxTransactionsBytes: _ => 50 * 1024);\n            _stagePolicy = new VolatileStagePolicy();\n            _fx = GetStoreFixture(_policy.PolicyActionsRegistry);\n            _renderer = new ValidatingActionRenderer();\n            _blockChain = BlockChain.Create(\n                _policy,\n                _stagePolicy,\n                _fx.Store,\n                _fx.StateStore,\n                _fx.GenesisBlock,\n                new ActionEvaluator(\n                    _policy.PolicyActionsRegistry,\n                    stateStore: _fx.StateStore,\n                    actionTypeLoader: new SingleActionLoader(typeof(DumbAction))),\n                renderers: new[] { new LoggedActionRenderer(_renderer, Log.Logger) }\n            );\n            _renderer.ResetRecords();\n\n            _validNext = _blockChain.EvaluateAndSign(\n                new BlockContent(\n                    new BlockMetadata(\n                        protocolVersion: BlockMetadata.CurrentProtocolVersion,\n                        index: 1,\n                        timestamp: _fx.GenesisBlock.Timestamp.AddSeconds(1),\n                        miner: _fx.Proposer.Address,\n                        publicKey: _fx.Proposer.PublicKey,\n                        previousHash: _fx.GenesisBlock.Hash,\n                        txHash: null,\n                        lastCommit: null,\n                        evidenceHash: null)).Propose(),\n                _fx.Proposer);\n        }\n\n        public void Dispose()\n        {\n            _fx.Dispose();\n        }\n\n        [SkippableFact]\n        public void CanonicalId()\n        {\n            var chain1 = _blockChain;\n            var key = new PrivateKey();\n            Block block1 = chain1.ProposeBlock(key);\n            chain1.Append(block1, CreateBlockCommit(block1));\n            Block block2 = chain1.ProposeBlock(key, CreateBlockCommit(chain1.Tip));\n            chain1.Append(block2, CreateBlockCommit(block2));\n            Assert.Equal(chain1.Id, _fx.Store.GetCanonicalChainId());\n            Assert.Equal(chain1.Id, _fx.Store.GetCanonicalChainId());\n\n            var beginActions = ImmutableArray.Create<IAction>(\n            );\n            var endActions = ImmutableArray.Create<IAction>(\n                new MinerReward(1)\n            );\n\n            var policy = new BlockPolicy(\n                new PolicyActionsRegistry(\n                    beginBlockActions: beginActions,\n                    endBlockActions: endActions));\n            var blockChainStates = new BlockChainStates(_fx.Store, _fx.StateStore);\n            var z = new BlockChain(\n                policy,\n                new VolatileStagePolicy(),\n                _fx.Store,\n                _fx.StateStore,\n                _fx.GenesisBlock,\n                blockChainStates,\n                new ActionEvaluator(\n                    policy.PolicyActionsRegistry,\n                    _fx.StateStore,\n                    new SingleActionLoader(typeof(DumbAction))));\n\n            Assert.Equal(chain1.Id, z.Id);\n        }\n\n        [SkippableFact]\n        public void ValidatorSet()\n        {\n            var validatorSet = _blockChain\n                .GetNextWorldState()\n                .GetValidatorSet();\n            _logger.Debug(\n                \"GenesisBlock is {Hash}, Transactions: {Txs}\",\n                _blockChain.Genesis,\n                _blockChain.Genesis.Transactions);\n            Assert.Equal(TestUtils.ValidatorSet.TotalCount, validatorSet.TotalCount);\n        }\n\n        [SkippableFact]\n        public void CanFindBlockByIndex()\n        {\n            var genesis = _blockChain.Genesis;\n            Assert.Equal(genesis, _blockChain[0]);\n\n            Block block = _blockChain.ProposeBlock(new PrivateKey());\n            _blockChain.Append(block, TestUtils.CreateBlockCommit(block));\n            Assert.Equal(block, _blockChain[1]);\n        }\n\n        [SkippableFact]\n        public void BlockHashes()\n        {\n            var key = new PrivateKey();\n            var genesis = _blockChain.Genesis;\n\n            Assert.Single(_blockChain.BlockHashes);\n\n            Block b1 = _blockChain.ProposeBlock(key);\n            _blockChain.Append(b1, CreateBlockCommit(b1));\n            Assert.Equal(new[] { genesis.Hash, b1.Hash }, _blockChain.BlockHashes);\n\n            Block b2 = _blockChain.ProposeBlock(\n                key, CreateBlockCommit(_blockChain.Tip));\n            _blockChain.Append(b2, CreateBlockCommit(b2));\n            Assert.Equal(\n                new[] { genesis.Hash, b1.Hash, b2.Hash },\n                _blockChain.BlockHashes\n            );\n\n            Block b3 = _blockChain.ProposeBlock(\n                key, CreateBlockCommit(_blockChain.Tip));\n            _blockChain.Append(b3, CreateBlockCommit(b3));\n            Assert.Equal(\n                new[] { genesis.Hash, b1.Hash, b2.Hash, b3.Hash },\n                _blockChain.BlockHashes\n            );\n        }\n\n        [SkippableFact]\n        public void ProcessActions()\n        {\n            var store = new MemoryStore();\n            var stateStore = new TrieStateStore(new MemoryKeyValueStore());\n            var blockChainStates = new BlockChainStates(store, stateStore);\n            var policy = new BlockPolicy();\n            var actionLoader = TypedActionLoader.Create(\n                typeof(BaseAction).Assembly, typeof(BaseAction));\n            var actionEvaluator = new ActionEvaluator(\n                policy.PolicyActionsRegistry,\n                stateStore,\n                actionLoader);\n            var nonce = 0;\n            var txs = TestUtils.ValidatorSet.Validators\n                .Select(validator => Transaction.Create(\n                    nonce++,\n                    GenesisProposer,\n                    null,\n                    actions: new IAction[]\n                        {\n                            new Initialize(\n                                validatorSet: TestUtils.ValidatorSet,\n                                states: ImmutableDictionary.Create<Address, IValue>()),\n                        }.ToPlainValues(),\n                    timestamp: DateTimeOffset.UtcNow))\n                .OrderBy(tx => tx.Id)\n                .ToImmutableList();\n            var genesis = BlockChain.ProposeGenesisBlock(transactions: txs);\n            var chain = BlockChain.Create(\n                policy,\n                new VolatileStagePolicy(),\n                store,\n                stateStore,\n                genesis,\n                actionEvaluator);\n            Block genesisBlock = chain.Genesis;\n\n            var actions1 = new List<BaseAction>\n            {\n                new Attack\n                {\n                    Weapon = \"sword\",\n                    Target = \"goblin\",\n                    TargetAddress = _fx.Address1,\n                },\n                new Attack\n                {\n                    Weapon = \"sword\",\n                    Target = \"orc\",\n                    TargetAddress = _fx.Address1,\n                },\n                new Attack\n                {\n                    Weapon = \"staff\",\n                    Target = \"goblin\",\n                    TargetAddress = _fx.Address1,\n                },\n            };\n            var tx1 = Transaction.Create(\n                0,\n                new PrivateKey(),\n                genesisBlock.Hash,\n                actions1.ToPlainValues()\n            );\n\n            chain.StageTransaction(tx1);\n            Block block1 = chain.ProposeBlock(new PrivateKey());\n            chain.Append(block1, CreateBlockCommit(block1));\n            IValue state = chain\n                .GetNextWorldState()\n                .GetAccountState(ReservedAddresses.LegacyAccount)\n                .GetState(_fx.Address1);\n            Assert.NotNull(state);\n\n            var result = BattleResult.FromBencodex((Bencodex.Types.Dictionary)state);\n            Assert.Contains(\"sword\", result.UsedWeapons);\n            Assert.Contains(\"staff\", result.UsedWeapons);\n            Assert.Contains(\"orc\", result.Targets);\n            Assert.Contains(\"goblin\", result.Targets);\n\n            BaseAction[] actions2 =\n            {\n                new Attack\n                {\n                    Weapon = \"bow\",\n                    Target = \"goblin\",\n                    TargetAddress = _fx.Address1,\n                },\n            };\n            var tx2 = Transaction.Create(\n                0,\n                new PrivateKey(),\n                genesisBlock.Hash,\n                actions2.ToPlainValues()\n            );\n\n            chain.StageTransaction(tx2);\n            Block block2 = chain.ProposeBlock(\n                new PrivateKey(), CreateBlockCommit(chain.Tip));\n            chain.Append(block2, CreateBlockCommit(block2));\n\n            state = chain\n                .GetNextWorldState()\n                .GetAccountState(ReservedAddresses.LegacyAccount)\n                .GetState(_fx.Address1);\n            result = BattleResult.FromBencodex((Bencodex.Types.Dictionary)state);\n            Assert.Contains(\"bow\", result.UsedWeapons);\n\n            var tx3 = Transaction.Create(\n                0,\n                new PrivateKey(),\n                genesisBlock.Hash,\n                new List<BaseAction>\n                {\n                    new Attack\n                    {\n                        Weapon = \"sword\",\n                        Target = \"orc\",\n                        TargetAddress = _fx.Address1,\n                    },\n                }.ToPlainValues()\n            );\n            Block block3 = chain.ProposeBlock(\n                new PrivateKey(), CreateBlockCommit(chain.Tip));\n            chain.StageTransaction(tx3);\n            chain.Append(block3, CreateBlockCommit(block3));\n            state = chain\n                .GetNextWorldState()\n                .GetAccountState(ReservedAddresses.LegacyAccount)\n                .GetState(_fx.Address1);\n\n            Assert.NotNull(state);\n        }\n\n        [SkippableFact]\n        public void ActionRenderersHaveDistinctContexts()\n        {\n            var policy = new NullBlockPolicy();\n            var store = new MemoryStore();\n            var stateStore = new TrieStateStore(new MemoryKeyValueStore());\n            var actionLoader = new SingleActionLoader(typeof(DumbAction));\n            var generatedRandomValueLogs = new List<int>();\n            IActionRenderer[] renderers = Enumerable.Range(0, 2).Select(i =>\n                new LoggedActionRenderer(\n                    new AnonymousActionRenderer\n                    {\n                        ActionRenderer = (act, context, nextState) =>\n                            // Consuming the random state through IRandom.Next() should not\n                            // affect contexts passed to other action renderers.\n                            generatedRandomValueLogs.Add(context.GetRandom().Next()),\n                    },\n                    Log.Logger.ForContext(\"RendererIndex\", i)\n                )\n            ).ToArray();\n            BlockChain blockChain = MakeBlockChain(\n                policy,\n                store,\n                stateStore,\n                actionLoader,\n                renderers: renderers\n            );\n            var privateKey = new PrivateKey();\n            var action = DumbAction.Create((default, string.Empty));\n            var actions = new[] { action };\n            blockChain.MakeTransaction(privateKey, actions);\n            Block block = blockChain.ProposeBlock(new PrivateKey());\n\n            generatedRandomValueLogs.Clear();\n            Assert.Empty(generatedRandomValueLogs);\n            blockChain.Append(block, CreateBlockCommit(block));\n            Assert.Equal(2, generatedRandomValueLogs.Count);\n            Assert.Equal(generatedRandomValueLogs[0], generatedRandomValueLogs[1]);\n        }\n\n        [SkippableFact]\n        public void RenderActionsAfterBlockIsRendered()\n        {\n            var policy = new NullBlockPolicy();\n            var store = new MemoryStore();\n            var stateStore = new TrieStateStore(new MemoryKeyValueStore());\n            var actionLoader = new SingleActionLoader(typeof(DumbAction));\n            var recordingRenderer = new RecordingActionRenderer();\n            var renderer = new LoggedActionRenderer(recordingRenderer, Log.Logger);\n            BlockChain blockChain = MakeBlockChain(\n                policy, store, stateStore, actionLoader, renderers: new[] { renderer });\n            var privateKey = new PrivateKey();\n\n            var action = DumbAction.Create((default, string.Empty));\n            var actions = new[] { action };\n            blockChain.MakeTransaction(privateKey, actions);\n            recordingRenderer.ResetRecords();\n            Block prevBlock = blockChain.Tip;\n            Block block = blockChain.ProposeBlock(new PrivateKey());\n            blockChain.Append(block, CreateBlockCommit(block));\n\n            Assert.Equal(2, blockChain.Count);\n            IReadOnlyList<RenderRecord.BlockEvent> blockLogs = recordingRenderer.BlockRecords;\n            Assert.Equal(2, blockLogs.Count);\n            IReadOnlyList<RenderRecord.ActionBase> actionLogs = recordingRenderer.ActionRecords;\n            Assert.Single(actions);\n            Assert.Equal(prevBlock, blockLogs[0].OldTip);\n            Assert.Equal(block, blockLogs[0].NewTip);\n            Assert.Equal(0, blockLogs[0].Index);\n            Assert.Equal(1, actionLogs[0].Index);\n            Assert.Equal(action.PlainValue, actionLogs[0].Action);\n            Assert.Equal(prevBlock, blockLogs[1].OldTip);\n            Assert.Equal(block, blockLogs[1].NewTip);\n            Assert.Equal(2, blockLogs[1].Index);\n        }\n\n        [SkippableFact]\n        public void RenderActionsAfterAppendComplete()\n        {\n            var policy = new NullBlockPolicy();\n            var store = new MemoryStore();\n            var stateStore = new TrieStateStore(new MemoryKeyValueStore());\n            var actionLoader = new SingleActionLoader(typeof(DumbAction));\n\n            IActionRenderer renderer = new AnonymousActionRenderer\n            {\n                ActionRenderer = (a, __, nextState) =>\n                {\n                    if (!(a is Dictionary dictionary &&\n                          dictionary.TryGetValue((Text)\"type_id\", out IValue typeId) &&\n                          typeId.Equals((Integer)2)))\n                    {\n                        throw new ThrowException.SomeException(\"thrown by renderer\");\n                    }\n                },\n            };\n            renderer = new LoggedActionRenderer(renderer, Log.Logger);\n            BlockChain blockChain = MakeBlockChain(\n                policy, store, stateStore, actionLoader, renderers: new[] { renderer });\n            var privateKey = new PrivateKey();\n\n            var action = DumbAction.Create((default, string.Empty));\n            var actions = new[] { action };\n            blockChain.MakeTransaction(privateKey, actions);\n            Block block = blockChain.ProposeBlock(new PrivateKey());\n\n            ThrowException.SomeException e = Assert.Throws<ThrowException.SomeException>(\n                () => blockChain.Append(block, CreateBlockCommit(block)));\n            Assert.Equal(\"thrown by renderer\", e.Message);\n            Assert.Equal(2, blockChain.Count);\n        }\n\n        [SkippableFact]\n        public void FindNextHashes()\n        {\n            var key = new PrivateKey();\n            IReadOnlyList<BlockHash> hashes;\n\n            hashes = _blockChain.FindNextHashes(new BlockLocator(_blockChain.Genesis.Hash));\n            Assert.Single(hashes);\n            Assert.Equal(_blockChain.Genesis.Hash, hashes.First());\n            var block0 = _blockChain.Genesis;\n            var block1 = _blockChain.ProposeBlock(key);\n            _blockChain.Append(block1, CreateBlockCommit(block1));\n            var block2 = _blockChain.ProposeBlock(\n                key, lastCommit: CreateBlockCommit(_blockChain.Tip));\n            _blockChain.Append(block2, CreateBlockCommit(block2));\n            var block3 = _blockChain.ProposeBlock(\n                key, lastCommit: CreateBlockCommit(_blockChain.Tip));\n            _blockChain.Append(block3, CreateBlockCommit(block3));\n\n            hashes = _blockChain.FindNextHashes(new BlockLocator(block0.Hash));\n            Assert.Equal(new[] { block0.Hash, block1.Hash, block2.Hash, block3.Hash }, hashes);\n\n            hashes = _blockChain.FindNextHashes(new BlockLocator(block1.Hash));\n            Assert.Equal(new[] { block1.Hash, block2.Hash, block3.Hash }, hashes);\n\n            hashes = _blockChain.FindNextHashes(new BlockLocator(block0.Hash), count: 2);\n            Assert.Equal(new[] { block0.Hash, block1.Hash }, hashes);\n        }\n\n        [SkippableFact]\n        public void DetectInvalidTxNonce()\n        {\n            var privateKey = new PrivateKey();\n            var actions = new[] { DumbAction.Create((_fx.Address1, \"foo\")) };\n\n            var genesis = _blockChain.Genesis;\n\n            Transaction[] txsA =\n            {\n                _fx.MakeTransaction(actions, privateKey: privateKey),\n            };\n\n            Block b1 = _blockChain.ProposeBlock(\n                _fx.Proposer,\n                txsA.ToImmutableList(),\n                CreateBlockCommit(_blockChain.Tip),\n                ImmutableArray<EvidenceBase>.Empty);\n            _blockChain.Append(b1, TestUtils.CreateBlockCommit(b1));\n\n            Block b2 = _blockChain.ProposeBlock(\n                _fx.Proposer,\n                txsA.ToImmutableList(),\n                CreateBlockCommit(_blockChain.Tip),\n                ImmutableArray<EvidenceBase>.Empty);\n            Assert.Throws<InvalidTxNonceException>(() =>\n                _blockChain.Append(b2, CreateBlockCommit(b2)));\n\n            Transaction[] txsB =\n            {\n                _fx.MakeTransaction(\n                    actions,\n                    nonce: 1,\n                    privateKey: privateKey),\n            };\n            b2 = _blockChain.ProposeBlock(\n                _fx.Proposer,\n                txsB.ToImmutableList(),\n                CreateBlockCommit(_blockChain.Tip),\n                ImmutableArray<EvidenceBase>.Empty);\n            _blockChain.Append(b2, CreateBlockCommit(b2));\n        }\n\n        [SkippableFact]\n        public void GetBlockLocator()\n        {\n            var key = new PrivateKey();\n            List<Block> blocks = new List<Block>();\n            foreach (var i in Enumerable.Range(0, 10))\n            {\n                var block = _blockChain.ProposeBlock(\n                    key,\n                    lastCommit: CreateBlockCommit(_blockChain.Tip));\n                _blockChain.Append(block, CreateBlockCommit(block));\n                blocks.Add(block);\n            }\n\n            BlockLocator actual = _blockChain.GetBlockLocator();\n            BlockLocator expected = new BlockLocator(blocks[9].Hash);\n\n            Assert.Equal(expected, actual);\n        }\n\n        [SkippableFact]\n        public void GetBlockCommit()\n        {\n            // Note: Getting BlockCommit from PoW block test is not present.\n            // Requesting blockCommit of genesis block returns null.\n            Assert.Null(_blockChain.GetBlockCommit(0));\n            Assert.Null(_blockChain.GetBlockCommit(_blockChain.Genesis.Hash));\n\n            // BlockCommit is put to store when block is appended.\n            Block block1 = _blockChain.ProposeBlock(new PrivateKey());\n            BlockCommit blockCommit1 = CreateBlockCommit(block1);\n            _blockChain.Append(block1, blockCommit1);\n            Assert.Equal(blockCommit1, _blockChain.GetBlockCommit(block1.Index));\n            Assert.Equal(blockCommit1, _blockChain.GetBlockCommit(block1.Hash));\n\n            // BlockCommit is retrieved from lastCommit.\n            Block block2 = _blockChain.ProposeBlock(\n                new PrivateKey(),\n                lastCommit: CreateBlockCommit(_blockChain.Tip));\n            BlockCommit blockCommit2 = CreateBlockCommit(block2);\n            _blockChain.Append(block2, blockCommit2);\n\n            // These are different due to timestamps on votes.\n            Assert.NotEqual(blockCommit1, _blockChain.GetBlockCommit(block1.Index));\n            Assert.Equal(block2.LastCommit, _blockChain.GetBlockCommit(block1.Index));\n            Assert.Equal(block2.LastCommit, _blockChain.GetBlockCommit(block1.Hash));\n        }\n\n        [SkippableFact]\n        public void CleanupBlockCommitStore()\n        {\n            BlockCommit blockCommit1 = CreateBlockCommit(\n                new BlockHash(GetRandomBytes(BlockHash.Size)), 1, 0);\n            BlockCommit blockCommit2 = CreateBlockCommit(\n                new BlockHash(GetRandomBytes(BlockHash.Size)), 2, 0);\n            BlockCommit blockCommit3 = CreateBlockCommit(\n                new BlockHash(GetRandomBytes(BlockHash.Size)), 3, 0);\n\n            _blockChain.Store.PutBlockCommit(blockCommit1);\n            _blockChain.Store.PutBlockCommit(blockCommit2);\n            _blockChain.Store.PutBlockCommit(blockCommit3);\n            _blockChain.CleanupBlockCommitStore(blockCommit3.Height);\n\n            Assert.Null(_blockChain.Store.GetBlockCommit(blockCommit1.BlockHash));\n            Assert.Null(_blockChain.Store.GetBlockCommit(blockCommit2.BlockHash));\n            Assert.Equal(blockCommit3, _blockChain.Store.GetBlockCommit(blockCommit3.BlockHash));\n        }\n\n        [SkippableFact]\n        public void GetStatesOnCreatingBlockChain()\n        {\n            bool invoked = false;\n            var policy = new NullPolicyForGetStatesOnCreatingBlockChain(\n                c =>\n                {\n                    // ReSharper disable AccessToModifiedClosure\n                    // The following method calls should not throw any exceptions:\n                    invoked = true;\n                    // ReSharper restore AccessToModifiedClosure\n                });\n            IStore store = new MemoryStore();\n            var stateStore = new TrieStateStore(new MemoryKeyValueStore());\n            var actionEvaluator = new ActionEvaluator(\n                policy.PolicyActionsRegistry,\n                stateStore,\n                new SingleActionLoader(typeof(DumbAction)));\n            Block genesisWithTx = ProposeGenesisBlock(\n                ProposeGenesis(\n                    GenesisProposer.PublicKey,\n                    new[]\n                    {\n                        Transaction.Create(\n                            0,\n                            new PrivateKey(),\n                            null,\n                            Array.Empty<DumbAction>().ToPlainValues()\n                        ),\n                    }),\n                GenesisProposer);\n            var chain = BlockChain.Create(\n                policy,\n                new VolatileStagePolicy(),\n                store,\n                stateStore,\n                genesisWithTx,\n                actionEvaluator);\n            Assert.False(invoked);\n        }\n\n        // This is a regression test for:\n        // https://github.com/planetarium/libplanet/issues/189#issuecomment-482443607.\n        [SkippableFact]\n        public void GetStateOnlyDrillsDownUntilRequestedAddressesAreFound()\n        {\n            var policy = new NullBlockPolicy();\n            var tracker = new StoreTracker(_fx.Store);\n            var blockChainStates = new BlockChainStates(tracker, _fx.StateStore);\n            var chain = new BlockChain(\n                policy,\n                new VolatileStagePolicy(),\n                tracker,\n                _fx.StateStore,\n                _fx.GenesisBlock,\n                blockChainStates,\n                new ActionEvaluator(\n                    policy.PolicyActionsRegistry,\n                    _fx.StateStore,\n                    new SingleActionLoader(typeof(DumbAction))));\n\n            Block b = chain.Genesis;\n            Address[] addresses = new Address[30];\n            for (int i = 0; i < addresses.Length; ++i)\n            {\n                var privateKey = new PrivateKey();\n                Address address = privateKey.Address;\n                addresses[i] = address;\n                DumbAction[] actions =\n                {\n                    DumbAction.Create((address, \"foo\")),\n                    DumbAction.Create((i < 1 ? address : addresses[i - 1], \"bar\")),\n                };\n                Transaction[] txs =\n                {\n                    Transaction.Create(0, privateKey, chain.Genesis.Hash, actions.ToPlainValues()),\n                };\n                b = chain.ProposeBlock(\n                    _fx.Proposer,\n                    txs.ToImmutableList(),\n                    CreateBlockCommit(chain.Tip),\n                    ImmutableArray<EvidenceBase>.Empty);\n                chain.Append(b, CreateBlockCommit(b));\n            }\n\n            tracker.ClearLogs();\n            int testingDepth = addresses.Length / 2;\n            Address[] targetAddresses = Enumerable.Range(\n                testingDepth,\n                Math.Min(10, addresses.Length - testingDepth - 1)\n            ).Select(i => addresses[i]).ToArray();\n\n            Assert.All(\n                chain\n                    .GetNextWorldState()\n                    .GetAccountState(ReservedAddresses.LegacyAccount)\n                    .GetStates(targetAddresses),\n                Assert.NotNull);\n\n            var callCount = tracker.Logs.Where(\n                trackLog => trackLog.Method == \"GetBlockStates\"\n            ).Select(trackLog => trackLog.Params).Count();\n            Assert.True(testingDepth >= callCount);\n        }\n\n        [SkippableFact]\n        public void GetStateReturnsEarlyForNonexistentAccount()\n        {\n            var policy = new NullBlockPolicy();\n            var tracker = new StoreTracker(_fx.Store);\n            var blockChainStates = new BlockChainStates(tracker, _fx.StateStore);\n            var chain = new BlockChain(\n                policy,\n                new VolatileStagePolicy(),\n                tracker,\n                _fx.StateStore,\n                _fx.GenesisBlock,\n                blockChainStates,\n                new ActionEvaluator(\n                    policy.PolicyActionsRegistry,\n                    _fx.StateStore,\n                    new SingleActionLoader(typeof(DumbAction))));\n\n            Block b = chain.Genesis;\n            for (int i = 0; i < 20; ++i)\n            {\n                b = chain.ProposeBlock(_fx.Proposer, CreateBlockCommit(chain.Tip));\n                chain.Append(b, CreateBlockCommit(b));\n            }\n\n            tracker.ClearLogs();\n            Address nonexistent = new PrivateKey().Address;\n            IValue result = chain\n                .GetNextWorldState()\n                .GetAccountState(ReservedAddresses.LegacyAccount)\n                .GetState(nonexistent);\n            Assert.Null(result);\n            var callCount = tracker.Logs.Where(\n                trackLog => trackLog.Method == \"GetBlockStates\"\n            ).Select(trackLog => trackLog.Params).Count();\n            Assert.True(\n                callCount <= 1,\n                $\"GetBlocksStates() was called {callCount} times\"\n            );\n        }\n\n        [SkippableFact]\n        public void GetStateReturnsLatestStatesWhenMultipleAddresses()\n        {\n            var privateKeys = Enumerable.Range(1, 10).Select(_ => new PrivateKey()).ToList();\n            var addresses = privateKeys.Select(key => key.Address).ToList();\n            var policy = new NullBlockPolicy();\n            var blockChainStates = new BlockChainStates(_fx.Store, _fx.StateStore);\n            var chain = new BlockChain(\n                policy,\n                new VolatileStagePolicy(),\n                _fx.Store,\n                _fx.StateStore,\n                _fx.GenesisBlock,\n                blockChainStates,\n                new ActionEvaluator(\n                    policy.PolicyActionsRegistry,\n                    _fx.StateStore,\n                    new SingleActionLoader(typeof(DumbAction))));\n\n            Assert.All(\n                chain\n                    .GetNextWorldState()\n                    .GetAccountState(ReservedAddresses.LegacyAccount)\n                    .GetStates(addresses),\n                Assert.Null);\n            foreach (var address in addresses)\n            {\n                Assert.Null(chain\n                    .GetNextWorldState()\n                    .GetAccountState(ReservedAddresses.LegacyAccount)\n                    .GetState(address));\n            }\n\n            var privateKeysAndAddresses10 = privateKeys.Zip(addresses, (k, a) => (k, a));\n            foreach (var (key, address) in privateKeysAndAddresses10)\n            {\n                chain.MakeTransaction(key, new[] { DumbAction.Create((address, \"1\")) });\n            }\n\n            Block block1 = chain.ProposeBlock(\n                privateKeys[0], lastCommit: CreateBlockCommit(chain.Tip));\n\n            chain.Append(block1, CreateBlockCommit(block1));\n\n            Assert.All(\n                chain\n                    .GetNextWorldState()\n                    .GetAccountState(ReservedAddresses.LegacyAccount)\n                    .GetStates(addresses),\n                v => Assert.Equal((Text)\"1\", v));\n            foreach (var address in addresses)\n            {\n                Assert.Equal(\n                    (Text)\"1\",\n                    chain\n                        .GetNextWorldState()\n                        .GetAccountState(ReservedAddresses.LegacyAccount)\n                        .GetState(address));\n            }\n\n            chain.MakeTransaction(privateKeys[0], new[] { DumbAction.Create((addresses[0], \"2\")) });\n            Block block2 = chain.ProposeBlock(\n                privateKeys[0], lastCommit: CreateBlockCommit(chain.Tip));\n            chain.Append(block2, CreateBlockCommit(block2));\n            Assert.Equal(\n                (Text)\"1,2\",\n                chain\n                    .GetNextWorldState()\n                    .GetAccountState(ReservedAddresses.LegacyAccount)\n                    .GetState(addresses[0]));\n            Assert.All(\n                chain\n                    .GetNextWorldState()\n                    .GetAccountState(ReservedAddresses.LegacyAccount)\n                    .GetStates(addresses.Skip(1).ToArray()),\n                v => Assert.Equal((Text)\"1\", v)\n            );\n        }\n\n        [SkippableFact]\n        public void FindBranchPoint()\n        {\n            var key = new PrivateKey();\n            Block b1 = _blockChain.ProposeBlock(key);\n            _blockChain.Append(b1, CreateBlockCommit(b1));\n            Block b2 = _blockChain.ProposeBlock(\n                key, lastCommit: CreateBlockCommit(_blockChain.Tip));\n            _blockChain.Append(b2, CreateBlockCommit(b2));\n            Block b3 = _blockChain.ProposeBlock(\n                key, lastCommit: CreateBlockCommit(_blockChain.Tip));\n            _blockChain.Append(b3, CreateBlockCommit(b3));\n            Block b4 = _blockChain.ProposeBlock(\n                key, lastCommit: CreateBlockCommit(_blockChain.Tip));\n            _blockChain.Append(b4, CreateBlockCommit(b4));\n\n            Assert.Equal(b1.PreviousHash, _blockChain.Genesis.Hash);\n\n            var emptyLocator = new BlockLocator(_blockChain.Genesis.Hash);\n            var invalidLocator = new BlockLocator(\n                new BlockHash(TestUtils.GetRandomBytes(BlockHash.Size)));\n            var locator = new BlockLocator(b4.Hash);\n\n            using (var emptyFx = new MemoryStoreFixture(_policy.PolicyActionsRegistry))\n            using (var forkFx = new MemoryStoreFixture(_policy.PolicyActionsRegistry))\n            {\n                var emptyChain = BlockChain.Create(\n                    _blockChain.Policy,\n                    new VolatileStagePolicy(),\n                    emptyFx.Store,\n                    emptyFx.StateStore,\n                    emptyFx.GenesisBlock,\n                    new ActionEvaluator(\n                        _blockChain.Policy.PolicyActionsRegistry,\n                        stateStore: emptyFx.StateStore,\n                        actionTypeLoader: new SingleActionLoader(typeof(DumbAction))));\n                var fork = BlockChain.Create(\n                    _blockChain.Policy,\n                    new VolatileStagePolicy(),\n                    forkFx.Store,\n                    forkFx.StateStore,\n                    forkFx.GenesisBlock,\n                    new ActionEvaluator(\n                        _blockChain.Policy.PolicyActionsRegistry,\n                        stateStore: forkFx.StateStore,\n                        actionTypeLoader: new SingleActionLoader(typeof(DumbAction))));\n                fork.Append(b1, CreateBlockCommit(b1));\n                fork.Append(b2, CreateBlockCommit(b2));\n                Block b5 = fork.ProposeBlock(\n                    key, lastCommit: CreateBlockCommit(fork.Tip));\n                fork.Append(b5, CreateBlockCommit(b5));\n\n                // Testing emptyChain\n                Assert.Equal(_blockChain.Genesis.Hash, emptyChain.FindBranchpoint(emptyLocator));\n                Assert.Null(emptyChain.FindBranchpoint(invalidLocator));\n                Assert.Null(emptyChain.FindBranchpoint(locator));\n\n                // Testing _blockChain\n                Assert.Equal(_blockChain.Genesis.Hash, _blockChain.FindBranchpoint(emptyLocator));\n                Assert.Null(_blockChain.FindBranchpoint(invalidLocator));\n                Assert.Equal(b4.Hash, _blockChain.FindBranchpoint(locator));\n\n                // Testing fork\n                Assert.Equal(_blockChain.Genesis.Hash, fork.FindBranchpoint(emptyLocator));\n                Assert.Null(fork.FindBranchpoint(invalidLocator));\n                Assert.Null(fork.FindBranchpoint(locator));\n            }\n        }\n\n        [SkippableFact]\n        public void GetNextTxNonce()\n        {\n            var privateKey = new PrivateKey();\n            Address address = privateKey.Address;\n            var actions = new[] { DumbAction.Create((_fx.Address1, \"foo\")) };\n            var genesis = _blockChain.Genesis;\n\n            Assert.Equal(0, _blockChain.GetNextTxNonce(address));\n\n            Transaction[] txsA =\n            {\n                _fx.MakeTransaction(actions, privateKey: privateKey, nonce: 0),\n            };\n\n            Block b1 = _blockChain.ProposeBlock(\n                _fx.Proposer,\n                txsA.ToImmutableList(),\n                CreateBlockCommit(_blockChain.Tip),\n                ImmutableArray<EvidenceBase>.Empty);\n            _blockChain.Append(b1, CreateBlockCommit(b1));\n\n            Assert.Equal(1, _blockChain.GetNextTxNonce(address));\n\n            Transaction[] txsB =\n            {\n                _fx.MakeTransaction(actions, privateKey: privateKey, nonce: 1),\n                _fx.MakeTransaction(actions, privateKey: privateKey, nonce: 2),\n            };\n\n            StageTransactions(txsB);\n\n            Assert.Equal(3, _blockChain.GetNextTxNonce(address));\n\n            Transaction[] txsC =\n            {\n                _fx.MakeTransaction(actions, privateKey: privateKey, nonce: 3),\n                _fx.MakeTransaction(actions, privateKey: privateKey, nonce: 3),\n            };\n            StageTransactions(txsC);\n\n            Assert.Equal(4, _blockChain.GetNextTxNonce(address));\n\n            Transaction[] txsD =\n            {\n                _fx.MakeTransaction(actions, privateKey: privateKey, nonce: 5),\n            };\n            StageTransactions(txsD);\n\n            Assert.Equal(4, _blockChain.GetNextTxNonce(address));\n\n            Transaction[] txsE =\n            {\n                _fx.MakeTransaction(actions, privateKey: privateKey, nonce: 4),\n                _fx.MakeTransaction(actions, privateKey: privateKey, nonce: 5),\n                _fx.MakeTransaction(actions, privateKey: privateKey, nonce: 7),\n            };\n            StageTransactions(txsE);\n\n            foreach (var tx in _blockChain.StagePolicy.Iterate(_blockChain))\n            {\n                _logger.Fatal(\n                    \"{Id}; {Signer}; {Nonce}; {Timestamp}\",\n                    tx.Id,\n                    tx.Signer,\n                    tx.Nonce,\n                    tx.Timestamp);\n            }\n\n            Assert.Equal(6, _blockChain.GetNextTxNonce(address));\n        }\n\n        [SkippableFact]\n        public void GetNextTxNonceWithStaleTx()\n        {\n            var privateKey = new PrivateKey();\n            var address = privateKey.Address;\n            var actions = new[] { DumbAction.Create((address, \"foo\")) };\n\n            Transaction[] txs =\n            {\n                _fx.MakeTransaction(actions, privateKey: privateKey),\n                _fx.MakeTransaction(actions, privateKey: privateKey, nonce: 1),\n            };\n\n            StageTransactions(txs);\n            Block block = _blockChain.ProposeBlock(privateKey);\n            _blockChain.Append(block, CreateBlockCommit(block));\n\n            Transaction[] staleTxs =\n            {\n                _fx.MakeTransaction(actions, privateKey: privateKey, nonce: 0),\n                _fx.MakeTransaction(actions, privateKey: privateKey, nonce: 1),\n            };\n            StageTransactions(staleTxs);\n\n            Assert.Equal(2, _blockChain.GetNextTxNonce(address));\n\n            _blockChain.MakeTransaction(privateKey, actions);\n            Assert.Equal(3, _blockChain.GetNextTxNonce(address));\n\n            _blockChain.MakeTransaction(privateKey, actions);\n            Assert.Equal(4, _blockChain.GetNextTxNonce(address));\n        }\n\n        [SkippableFact]\n        public void ValidateTxNonces()\n        {\n            var privateKey = new PrivateKey();\n            var actions = new[] { DumbAction.Create((_fx.Address1, string.Empty)) };\n\n            var genesis = _blockChain.Genesis;\n\n            Block ProposeNext(\n                Block block,\n                IReadOnlyList<Transaction> txs\n            ) =>\n                _blockChain.EvaluateAndSign(\n                    TestUtils.ProposeNext(\n                        block,\n                        txs,\n                        blockInterval: TimeSpan.FromSeconds(10),\n                        miner: _fx.Proposer.PublicKey,\n                        lastCommit: CreateBlockCommit(block)),\n                    _fx.Proposer);\n\n            Transaction[] txsA =\n            {\n                _fx.MakeTransaction(actions, privateKey: privateKey, nonce: 1),\n                _fx.MakeTransaction(actions, privateKey: privateKey, nonce: 0),\n            };\n            Block b1 = ProposeNext(genesis, txsA);\n            _blockChain.Append(b1, CreateBlockCommit(b1));\n\n            Transaction[] txsB =\n            {\n                _fx.MakeTransaction(actions, privateKey: privateKey, nonce: 2),\n            };\n            Block b2 = ProposeNext(b1, txsB);\n            _blockChain.Append(b2, CreateBlockCommit(b2));\n\n            // Invalid if nonce is too low\n            Transaction[] txsC =\n            {\n                _fx.MakeTransaction(actions, privateKey: privateKey, nonce: 1),\n            };\n            Block b3a = ProposeNext(b2, txsC);\n            Assert.Throws<InvalidTxNonceException>(() =>\n                _blockChain.Append(b3a, CreateBlockCommit(b3a)));\n\n            // Invalid if nonce is too high\n            Transaction[] txsD =\n            {\n                _fx.MakeTransaction(actions, privateKey: privateKey, nonce: 4),\n            };\n            Block b3b = ProposeNext(b2, txsD);\n            Assert.Throws<InvalidTxNonceException>(() =>\n                _blockChain.Append(b3b, CreateBlockCommit(b3b)));\n        }\n\n        [SkippableFact]\n        public void MakeTransactionWithSystemAction()\n        {\n            var privateKey = new PrivateKey();\n            Address address = privateKey.Address;\n            var action = new Initialize(\n                new ValidatorSet(\n                    new List<Validator>() { new Validator(new PrivateKey().PublicKey, 1) }),\n                new Dictionary<Address, IValue>\n                {\n                    [default] = (Text)\"initial value\",\n                }.ToImmutableDictionary());\n\n            _blockChain.MakeTransaction(privateKey, actions: new IAction[] { action });\n            _blockChain.MakeTransaction(privateKey, actions: new IAction[] { action });\n\n            List<Transaction> txs = _stagePolicy\n                .Iterate(_blockChain)\n                .OrderBy(tx => tx.Nonce)\n                .ToList();\n\n            Assert.Equal(2, txs.Count);\n\n            var transaction = txs[0];\n            Assert.Equal(0, transaction.Nonce);\n            Assert.Equal(address, transaction.Signer);\n            Assert.Equal(action.PlainValue, transaction.Actions[0]);\n\n            transaction = txs[1];\n            Assert.Equal(1, transaction.Nonce);\n            Assert.Equal(address, transaction.Signer);\n            Assert.Equal(action.PlainValue, transaction.Actions[0]);\n        }\n\n        [SkippableFact]\n        public void MakeTransactionWithCustomActions()\n        {\n            var privateKey = new PrivateKey();\n            Address address = privateKey.Address;\n            var actions = new[] { DumbAction.Create((address, \"foo\")) };\n\n            _blockChain.MakeTransaction(privateKey, actions);\n            _blockChain.MakeTransaction(privateKey, actions);\n\n            List<Transaction> txs = _stagePolicy\n                .Iterate(_blockChain)\n                .OrderBy(tx => tx.Nonce)\n                .ToList();\n\n            Assert.Equal(2, txs.Count);\n\n            var transaction = txs[0];\n            Assert.Equal(0, transaction.Nonce);\n            Assert.Equal(address, transaction.Signer);\n            Assert.Equal(actions.Select(action => action.PlainValue), transaction.Actions);\n\n            transaction = txs[1];\n            Assert.Equal(1, transaction.Nonce);\n            Assert.Equal(address, transaction.Signer);\n            Assert.Equal(actions.Select(action => action.PlainValue), transaction.Actions);\n        }\n\n        [SkippableFact]\n        public async Task MakeTransactionConcurrency()\n        {\n            var privateKey = new PrivateKey();\n            Address address = privateKey.Address;\n            var actions = new[] { DumbAction.Create((address, \"foo\")) };\n\n            var tasks = Enumerable.Range(0, 10)\n                .Select(_ => Task.Run(() => _blockChain.MakeTransaction(privateKey, actions)));\n\n            await Task.WhenAll(tasks);\n\n            var txIds = _blockChain.GetStagedTransactionIds();\n\n            var nonces = txIds\n                .Select(id => _stagePolicy.Get(_blockChain, id)\n                    ?? _blockChain.GetTransaction(id))\n                .Select(tx => tx.Nonce)\n                .OrderBy(nonce => nonce)\n                .ToArray();\n\n            Assert.Equal(\n                nonces,\n                new long[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }\n            );\n        }\n\n        [SkippableFact]\n        public void BlockActionWithMultipleAddress()\n        {\n            var miner0 = _blockChain.Genesis.Miner;\n            var miner1 = new PrivateKey();\n            var miner2 = new PrivateKey();\n            var rewardRecordAddress = MinerReward.RewardRecordAddress;\n\n            Block block1 = _blockChain.ProposeBlock(\n                miner1, lastCommit: CreateBlockCommit(_blockChain.Tip));\n            _blockChain.Append(block1, CreateBlockCommit(block1));\n            Block block2 = _blockChain.ProposeBlock(\n                miner1, lastCommit: CreateBlockCommit(_blockChain.Tip));\n            _blockChain.Append(block2, CreateBlockCommit(block2));\n            Block block3 = _blockChain.ProposeBlock(\n                miner2, lastCommit: CreateBlockCommit(_blockChain.Tip));\n            _blockChain.Append(block3, CreateBlockCommit(block3));\n\n            IValue miner1state = _blockChain\n                .GetNextWorldState()\n                .GetAccountState(ReservedAddresses.LegacyAccount)\n                .GetState(miner1.Address);\n            IValue miner2state = _blockChain\n                .GetNextWorldState()\n                .GetAccountState(ReservedAddresses.LegacyAccount)\n                .GetState(miner2.Address);\n            IValue rewardState = _blockChain\n                .GetNextWorldState()\n                .GetAccountState(ReservedAddresses.LegacyAccount)\n                .GetState(rewardRecordAddress);\n\n            AssertBencodexEqual((Integer)2, miner1state);\n            AssertBencodexEqual((Integer)1, miner2state);\n\n            AssertBencodexEqual(\n                (Text)$\"{miner0},{miner1.Address},{miner1.Address},{miner2.Address}\",\n                rewardState\n            );\n        }\n\n        /// <summary>\n        /// Builds a fixture that has incomplete states for blocks other\n        /// than the tip, to test <c>GetState()</c> method's\n        /// <c>completeStates: true</c> option.\n        ///\n        /// <para>The fixture this makes has total 5 addresses (i.e., accounts;\n        /// these go to the second item of the returned triple) and 11 blocks\n        /// (these go to the third item of the returned triple). Every block\n        /// contains a transaction with an action that mutates one account\n        /// state except for the genesis block.  All transactions in the fixture\n        /// are signed by one private key (its address goes to the first item\n        /// of the returned triple).  The most important thing is that\n        /// overall blocks in the fixture look like:</para>\n        ///\n        /// <code>\n        ///  Index   UpdatedAddresses   States in Store\n        /// ------- ------------------ -----------------\n        ///      0                      Absent\n        ///      1   addresses[0]       Absent\n        ///      2   addresses[1]       Absent\n        ///      3   addresses[2]       Absent\n        ///      4   addresses[3]       Present\n        ///      5   addresses[4]       Absent\n        ///      6   addresses[0]       Absent\n        ///      7   addresses[1]       Present\n        ///      8   addresses[2]       Absent\n        ///      9   addresses[3]       Absent\n        ///     10   addresses[4]       Absent\n        /// </code>\n        /// </summary>\n        /// <param name=\"store\">store.</param>\n        /// <param name=\"stateStore\">State Store.</param>\n        /// <returns>Tuple of addresses and chain.</returns>\n        internal static (Address, Address[] Addresses, BlockChain Chain)\n            MakeIncompleteBlockStates(IStore store, IStateStore stateStore)\n        {\n            List<int> presentIndices = new List<int>() { 4, 7 };\n            List<Block> presentBlocks = new List<Block>();\n\n            IBlockPolicy blockPolicy = new NullBlockPolicy();\n            store = new StoreTracker(store);\n            Guid chainId = Guid.NewGuid();\n            var chainStates = new BlockChainStates(store, stateStore);\n            var actionEvaluator = new ActionEvaluator(\n                blockPolicy.PolicyActionsRegistry,\n                stateStore: stateStore,\n                actionTypeLoader: new SingleActionLoader(typeof(DumbAction)));\n            Block genesisBlock = ProposeGenesisBlock(\n                ProposeGenesis(GenesisProposer.PublicKey),\n                GenesisProposer);\n            var chain = BlockChain.Create(\n                blockPolicy,\n                new VolatileStagePolicy(),\n                store,\n                stateStore,\n                genesisBlock,\n                renderers: null,\n                blockChainStates: chainStates,\n                actionEvaluator: actionEvaluator);\n            var privateKey = new PrivateKey();\n            Address signer = privateKey.Address;\n\n            void BuildIndex(Guid id, Block block)\n            {\n                foreach (Transaction tx in block.Transactions)\n                {\n                    store.IncreaseTxNonce(id, tx.Signer);\n                }\n\n                store.AppendIndex(id, block.Hash);\n            }\n\n            // Build a store with incomplete states\n            Block b = chain.Genesis;\n            IWorld previousState = stateStore.GetWorld(null);\n            const int accountsCount = 5;\n            Address[] addresses = Enumerable.Repeat<object>(null, accountsCount)\n                .Select(_ => new PrivateKey().Address)\n                .ToArray();\n            for (int i = 0; i < 2; ++i)\n            {\n                for (int j = 0; j < accountsCount; ++j)\n                {\n                    int index = i * accountsCount + j;\n                    Transaction tx = Transaction.Create(\n                        store.GetTxNonce(chain.Id, signer),\n                        privateKey,\n                        chain.Genesis.Hash,\n                        new[] { DumbAction.Create((addresses[j], index.ToString())) }\n                            .ToPlainValues()\n                    );\n                    b = chain.EvaluateAndSign(\n                        ProposeNext(\n                            b,\n                            new[] { tx },\n                            blockInterval: TimeSpan.FromSeconds(10),\n                            miner: GenesisProposer.PublicKey,\n                            lastCommit: CreateBlockCommit(b)),\n                        GenesisProposer);\n\n                    var evals = actionEvaluator.EvaluateBlock(b, previousState);\n                    var dirty = evals.Last().OutputState.Trie\n                        .Diff(evals.First().InputContext.PreviousState.Trie)\n                        .ToList();\n                    Assert.NotEmpty(dirty);\n                    store.PutBlock(b);\n                    BuildIndex(chain.Id, b);\n                    Assert.Equal(b, chain[b.Hash]);\n                    if (presentIndices.Contains((int)b.Index))\n                    {\n                        presentBlocks.Add(b);\n                    }\n                }\n            }\n\n            IStateStore incompleteStateStore = new TrieStateStore(new MemoryKeyValueStore());\n            ((TrieStateStore)stateStore).CopyStates(\n                ImmutableHashSet<HashDigest<SHA256>>.Empty\n                    .Add(presentBlocks[0].StateRootHash)\n                    .Add(presentBlocks[1].StateRootHash),\n                (TrieStateStore)incompleteStateStore);\n\n            chain = new BlockChain(\n                blockPolicy,\n                new VolatileStagePolicy(),\n                store,\n                incompleteStateStore,\n                genesisBlock,\n                renderers: null,\n                blockChainStates: chainStates,\n                actionEvaluator: actionEvaluator);\n\n            return (signer, addresses, chain);\n        }\n\n        /// <summary>\n        /// Configures the store fixture that every test in this class depends on.\n        /// Subclasses should override this.\n        /// </summary>\n        /// <param name=\"policyActionsRegistry\">The policy block actions to use.</param>\n        /// <returns>The store fixture that every test in this class depends on.</returns>\n        protected virtual StoreFixture GetStoreFixture(\n            IPolicyActionsRegistry policyActionsRegistry = null)\n            => new MemoryStoreFixture(policyActionsRegistry);\n\n        private (Address[], Transaction[]) MakeFixturesForAppendTests(\n            PrivateKey privateKey = null,\n            DateTimeOffset epoch = default,\n            PrivateKey[] keys = null\n        )\n        {\n            Address[] addresses = keys is PrivateKey[] ks\n                ? ks.Select(k => k.Address).ToArray()\n                : new[]\n                {\n                    _fx.Address1,\n                    _fx.Address2,\n                    _fx.Address3,\n                    _fx.Address4,\n                    _fx.Address5,\n                };\n\n            if (addresses.Length != 5)\n            {\n                throw new ArgumentException(\"The number of keys must 5.\", nameof(keys));\n            }\n\n            privateKey = privateKey ?? new PrivateKey(new byte[]\n            {\n                0xa8, 0x21, 0xc7, 0xc2, 0x08, 0xa9, 0x1e, 0x53, 0xbb, 0xb2,\n                0x71, 0x15, 0xf4, 0x23, 0x5d, 0x82, 0x33, 0x44, 0xd1, 0x16,\n                0x82, 0x04, 0x13, 0xb6, 0x30, 0xe7, 0x96, 0x4f, 0x22, 0xe0,\n                0xec, 0xe0,\n            });\n\n            Transaction[] txs =\n            {\n                _fx.MakeTransaction(\n                    new[]\n                    {\n                        DumbAction.Create((addresses[0], \"foo\"), (null, addresses[0], 100)),\n                        DumbAction.Create((addresses[1], \"bar\"), (null, addresses[1], 100)),\n                    },\n                    timestamp: epoch,\n                    nonce: 0,\n                    privateKey: privateKey),\n                _fx.MakeTransaction(\n                    new[]\n                    {\n                        DumbAction.Create((addresses[2], \"baz\"), (null, addresses[2], 100)),\n                        DumbAction.Create((addresses[3], \"qux\"), (null, addresses[3], 100)),\n                    },\n                    timestamp: epoch.AddSeconds(5),\n                    nonce: 1,\n                    privateKey: privateKey),\n            };\n\n            return (addresses, txs);\n        }\n\n        [SkippableFact]\n        private void TipChanged()\n        {\n            var genesis = _blockChain.Genesis;\n\n            _renderer.ResetRecords();\n\n            Assert.Empty(_renderer.BlockRecords);\n            Block block = _blockChain.ProposeBlock(new PrivateKey());\n            _blockChain.Append(block, CreateBlockCommit(block));\n            IReadOnlyList<RenderRecord.BlockEvent> records = _renderer.BlockRecords;\n            Assert.Equal(2, records.Count);\n            foreach (RenderRecord.BlockEvent record in records)\n            {\n                Assert.Equal(genesis, record.OldTip);\n                Assert.Equal(block, record.NewTip);\n                Assert.Equal(1, record.NewTip.Index);\n            }\n\n            _renderer.ResetRecords();\n            Assert.Throws<InvalidBlockIndexException>(\n                () => _blockChain.Append(block, CreateBlockCommit(block)));\n            Assert.Empty(_renderer.BlockRecords);\n        }\n\n        [SkippableFact]\n        private void CreateWithGenesisBlock()\n        {\n            var storeFixture = new MemoryStoreFixture();\n            var policy = new NullBlockPolicy();\n\n            var addresses = ImmutableList<Address>.Empty\n                .Add(storeFixture.Address1)\n                .Add(storeFixture.Address2)\n                .Add(storeFixture.Address3);\n\n            var validatorPrivKey = new PrivateKey();\n\n            var privateKey = new PrivateKey();\n            var systemActions = new IAction[]\n            {\n                new Initialize(\n                    states: ImmutableDictionary.Create<Address, IValue>(),\n                    validatorSet: new ValidatorSet(\n                        new List<Validator>\n                        {\n                            new Validator(validatorPrivKey.PublicKey, BigInteger.One),\n                        }\n                    )\n                ),\n            };\n\n            var customActions =\n                addresses\n                    .Select((address, index) => DumbAction.Create((address, index.ToString())))\n                    .ToArray();\n\n            var systemTxs = systemActions\n                .Select((systemAction, i) => Transaction.Create(\n                    nonce: i,\n                    privateKey: privateKey,\n                    genesisHash: null,\n                    actions: new IAction[] { systemAction }.ToPlainValues()))\n                .ToArray();\n            var customTxs = new[]\n            {\n                new Transaction(\n                    new UnsignedTx(\n                        new TxInvoice(\n                            genesisHash: null,\n                            updatedAddresses: addresses.ToImmutableHashSet(),\n                            timestamp: DateTimeOffset.UtcNow,\n                            actions: new TxActionList(customActions.ToPlainValues()),\n                            maxGasPrice: null,\n                            gasLimit: null),\n                        new TxSigningMetadata(privateKey.PublicKey, systemTxs.Length)),\n                    privateKey),\n            };\n            var txs = systemTxs.Concat(customTxs).ToImmutableList();\n            var blockChainStates = new BlockChainStates(\n                storeFixture.Store, storeFixture.StateStore);\n            var actionEvaluator = new ActionEvaluator(\n                policy.PolicyActionsRegistry,\n                storeFixture.StateStore,\n                new SingleActionLoader(typeof(DumbAction)));\n            BlockChain blockChain = BlockChain.Create(\n                policy,\n                new VolatileStagePolicy(),\n                storeFixture.Store,\n                storeFixture.StateStore,\n                BlockChain.ProposeGenesisBlock(\n                    privateKey: privateKey,\n                    transactions: txs),\n                actionEvaluator);\n\n            var validator = blockChain\n                .GetNextWorldState()\n                .GetValidatorSet()[0];\n            Assert.Equal(validatorPrivKey.PublicKey, validator.PublicKey);\n            Assert.Equal(BigInteger.One, validator.Power);\n            Assert.Equal(\n                addresses,\n                blockChain.Genesis.Transactions.Single(\n                    tx => !(tx.Actions is null) &&\n                        tx.Actions.All(a => !Registry.IsSystemAction(a))).UpdatedAddresses);\n\n            var states = addresses\n                .Select(address => blockChain\n                    .GetNextWorldState()\n                    .GetAccountState(ReservedAddresses.LegacyAccount)\n                    .GetState(address))\n                .ToArray();\n            for (int i = 0; i < states.Length; ++i)\n            {\n                Assert.Equal((Text)states[i], i.ToString());\n            }\n        }\n\n        [SkippableFact]\n        private void ConstructWithUnexpectedGenesisBlock()\n        {\n            var policy = new NullBlockPolicy();\n            var stagePolicy = new VolatileStagePolicy();\n            IStore store = new MemoryStore();\n            var stateStore = new TrieStateStore(new MemoryKeyValueStore());\n            var blockChainStates = new BlockChainStates(store, stateStore);\n            var actionEvaluator = new ActionEvaluator(\n                policy.PolicyActionsRegistry,\n                stateStore,\n                new SingleActionLoader(typeof(DumbAction)));\n            var genesisBlockA = BlockChain.ProposeGenesisBlock();\n            var genesisBlockB = BlockChain.ProposeGenesisBlock();\n\n            var blockChain = BlockChain.Create(\n                policy,\n                stagePolicy,\n                store,\n                stateStore,\n                genesisBlockA,\n                actionEvaluator);\n\n            Assert.Throws<InvalidGenesisBlockException>(() =>\n            {\n                var blockchain = new BlockChain(\n                    policy,\n                    stagePolicy,\n                    store,\n                    stateStore,\n                    genesisBlockB,\n                    blockChainStates,\n                    actionEvaluator);\n            });\n        }\n\n        [SkippableFact]\n        private void FilterLowerNonceTxAfterStaging()\n        {\n            var privateKey = new PrivateKey();\n            var txsA = Enumerable.Range(0, 3)\n                .Select(nonce => _fx.MakeTransaction(\n                    nonce: nonce, privateKey: privateKey, timestamp: DateTimeOffset.Now))\n                .ToArray();\n            StageTransactions(txsA);\n            Block b1 = _blockChain.ProposeBlock(privateKey);\n            _blockChain.Append(b1, CreateBlockCommit(b1));\n            Assert.Equal(\n                txsA,\n                ActionEvaluator.OrderTxsForEvaluation(\n                    b1.ProtocolVersion,\n                    b1.Transactions,\n                    b1.PreEvaluationHash.ByteArray\n                )\n            );\n\n            var txsB = Enumerable.Range(0, 4)\n                .Select(nonce => _fx.MakeTransaction(\n                    nonce: nonce, privateKey: privateKey, timestamp: DateTimeOffset.Now))\n                .ToArray();\n            StageTransactions(txsB);\n\n            // Stage only txs having higher or equal with nonce than expected nonce.\n            Assert.Single(_blockChain.GetStagedTransactionIds());\n            Assert.Single(_blockChain.StagePolicy.Iterate(_blockChain, filtered: true));\n            Assert.Equal(4, _blockChain.StagePolicy.Iterate(_blockChain, filtered: false).Count());\n        }\n\n        [SkippableFact]\n        private void CheckIfTxPolicyExceptionHasInnerException()\n        {\n            var policy = new NullPolicyButTxPolicyAlwaysThrows(\n                x =>\n                {\n                    // ReSharper disable AccessToModifiedClosure\n                    // The following method calls should not throw any exceptions:\n                    x?.GetNextWorldState()\n                        .GetAccountState(ReservedAddresses.LegacyAccount)\n                        .GetStates(new[] { default(Address) });\n                    x?.GetNextWorldState()\n                        .GetAccountState(ReservedAddresses.LegacyAccount)\n                        .GetState(default);\n                    // ReSharper restore AccessToModifiedClosure\n                });\n            IStore store = new MemoryStore();\n            var stateStore = new TrieStateStore(new MemoryKeyValueStore());\n            var genesisTx = Transaction.Create(\n                0,\n                new PrivateKey(),\n                null,\n                List.Empty);\n            var actionEvaluator = new ActionEvaluator(\n                policy.PolicyActionsRegistry,\n                stateStore,\n                new SingleActionLoader(typeof(DumbAction)));\n            var genesisWithTx = ProposeGenesisBlock(\n                ProposeGenesis(GenesisProposer.PublicKey, new[] { genesisTx }),\n                privateKey: GenesisProposer);\n\n            var chain = BlockChain.Create(\n                policy,\n                new VolatileStagePolicy(),\n                store,\n                stateStore,\n                genesisWithTx,\n                actionEvaluator);\n\n            var blockTx = Transaction.Create(\n                0,\n                new PrivateKey(),\n                null,\n                Array.Empty<DumbAction>().ToPlainValues());\n            var nextStateRootHash = chain.GetNextStateRootHash(genesisWithTx.Hash);\n            var block = ProposeNextBlock(\n                previousBlock: chain.Genesis,\n                miner: GenesisProposer,\n                txs: new[] { blockTx },\n                stateRootHash: (HashDigest<SHA256>)nextStateRootHash);\n\n            var e = Assert.Throws<TxPolicyViolationException>(\n                () => chain.Append(block, CreateBlockCommit(block)));\n            Assert.NotNull(e.InnerException);\n        }\n\n        [SkippableFact]\n        private void ValidateNextBlockCommitOnValidatorSetChange()\n        {\n            var storeFixture = new MemoryStoreFixture();\n            var policy = new NullBlockPolicy();\n\n            var addresses = ImmutableList<Address>.Empty\n                .Add(storeFixture.Address1)\n                .Add(storeFixture.Address2)\n                .Add(storeFixture.Address3);\n\n            var newValidatorPrivateKey = new PrivateKey();\n            var newValidators = ValidatorPrivateKeys.Append(newValidatorPrivateKey).ToArray();\n            var newValidatorPowers = TestUtils.ValidatorSet.Validators.Select(v => v.Power)\n                .Append(BigInteger.One).ToArray();\n            var initialValidatorSet = new ValidatorSet(\n                ValidatorPrivateKeys.Select(\n                    pk => new Validator(pk.PublicKey, BigInteger.One)\n                ).ToList()\n            );\n            var systemActions = new[]\n            {\n                new Initialize(\n                    validatorSet: initialValidatorSet,\n                    states: ImmutableDictionary.Create<Address, IValue>()\n                ),\n            };\n            var privateKey = new PrivateKey();\n            var txs = systemActions\n                .Select((systemAction, i) => Transaction.Create(\n                    nonce: i,\n                    privateKey: privateKey,\n                    genesisHash: null,\n                    actions: new IAction[] { systemAction }.ToPlainValues()))\n                .ToImmutableList();\n\n            var actionEvaluator = new ActionEvaluator(\n                policy.PolicyActionsRegistry,\n                storeFixture.StateStore,\n                new SingleActionLoader(typeof(SetValidator)));\n            Block genesis = BlockChain.ProposeGenesisBlock(\n                privateKey: privateKey,\n                transactions: txs);\n            BlockChain blockChain = BlockChain.Create(\n                policy,\n                new VolatileStagePolicy(),\n                storeFixture.Store,\n                storeFixture.StateStore,\n                genesis,\n                actionEvaluator);\n\n            blockChain.MakeTransaction(\n                new PrivateKey(),\n                new[]\n                {\n                    new SetValidator(\n                        new Validator(newValidatorPrivateKey.PublicKey, BigInteger.One)),\n                }\n            );\n            var newBlock = blockChain.ProposeBlock(new PrivateKey());\n            var newBlockCommit = new BlockCommit(\n                newBlock.Index, 0, newBlock.Hash, ValidatorPrivateKeys.Select(\n                    pk => new VoteMetadata(\n                        newBlock.Index,\n                        0,\n                        newBlock.Hash,\n                        DateTimeOffset.UtcNow,\n                        pk.PublicKey,\n                        TestUtils.ValidatorSet.GetValidator(pk.PublicKey).Power,\n                        VoteFlag.PreCommit).Sign(pk))\n                .OrderBy(vote => vote.ValidatorPublicKey.Address)\n                .ToImmutableArray());\n            blockChain.Append(newBlock, newBlockCommit);\n\n            blockChain.MakeTransaction(\n                new PrivateKey(),\n                new[]\n                {\n                    new SetValidator(new Validator(new PrivateKey().PublicKey, BigInteger.One)),\n                }\n            );\n            var nextBlock = blockChain.ProposeBlock(\n                new PrivateKey(), lastCommit: newBlockCommit);\n            var nextBlockCommit = new BlockCommit(\n                nextBlock.Index,\n                0,\n                nextBlock.Hash,\n                Enumerable.Range(0, newValidators.Length)\n                    .Select(\n                        index => new VoteMetadata(\n                            nextBlock.Index,\n                            0,\n                            nextBlock.Hash,\n                            DateTimeOffset.UtcNow,\n                            newValidators[index].PublicKey,\n                            newValidatorPowers[index],\n                            VoteFlag.PreCommit).Sign(newValidators[index]))\n                    .OrderBy(vote => vote.ValidatorPublicKey.Address)\n                    .ToImmutableArray());\n            blockChain.Append(nextBlock, nextBlockCommit);\n\n            blockChain.MakeTransaction(\n                new PrivateKey(),\n                new[]\n                {\n                    new SetValidator(new Validator(new PrivateKey().PublicKey, BigInteger.One)),\n                }\n            );\n            var invalidCommitBlock = blockChain.ProposeBlock(\n                new PrivateKey(), lastCommit: nextBlockCommit);\n\n            Assert.Throws<InvalidBlockCommitException>(\n                () => blockChain.Append(\n                    invalidCommitBlock,\n                    new BlockCommit(\n                        invalidCommitBlock.Index,\n                        0,\n                        invalidCommitBlock.Hash,\n                        Enumerable.Range(0, newValidators.Length)\n                            .Select(\n                                index => new VoteMetadata(\n                                    invalidCommitBlock.Index,\n                                    0,\n                                    invalidCommitBlock.Hash,\n                                    DateTimeOffset.UtcNow,\n                                    newValidators[index].PublicKey,\n                                    newValidatorPowers[index],\n                                    VoteFlag.PreCommit).Sign(newValidators[index]))\n                            .ToImmutableArray())));\n\n            Assert.Equal(\n                blockChain\n                    .GetNextWorldState(0L)\n                    .GetValidatorSet(),\n                new ValidatorSet(\n                    ValidatorPrivateKeys.Select(\n                        pk => new Validator(pk.PublicKey, BigInteger.One)).ToList()));\n\n            Assert.Equal(\n                blockChain\n                    .GetNextWorldState(1L)\n                    .GetValidatorSet(),\n                new ValidatorSet(\n                    newValidators.Select(\n                        pk => new Validator(pk.PublicKey, BigInteger.One)).ToList()));\n        }\n\n        private class\n            NullPolicyButTxPolicyAlwaysThrows : NullPolicyForGetStatesOnCreatingBlockChain\n        {\n            public NullPolicyButTxPolicyAlwaysThrows(\n                Action<BlockChain> hook)\n                : base(hook)\n            {\n            }\n\n            public override TxPolicyViolationException ValidateNextBlockTx(\n                BlockChain blockChain,\n                Transaction transaction\n            )\n            {\n                _hook(blockChain);\n                return new TxPolicyViolationException(\"Test Message\", transaction.Id);\n            }\n        }\n\n        private class NullPolicyForGetStatesOnCreatingBlockChain : NullBlockPolicy\n        {\n            protected readonly Action<BlockChain> _hook;\n\n            public NullPolicyForGetStatesOnCreatingBlockChain(\n                Action<BlockChain> hook\n            )\n            {\n                _hook = hook;\n            }\n\n            public override TxPolicyViolationException ValidateNextBlockTx(\n                BlockChain blockChain,\n                Transaction transaction\n            )\n            {\n                _hook(blockChain);\n                return base.ValidateNextBlockTx(blockChain, transaction);\n            }\n\n            public override BlockPolicyViolationException ValidateNextBlock(\n                BlockChain blocks,\n                Block nextBlock\n            )\n            {\n                _hook(blocks);\n                return base.ValidateNextBlock(blocks, nextBlock);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "test/Libplanet.Tests/Blockchain/BranchTest.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing Libplanet.Blockchain;\nusing Libplanet.Tests.Store;\nusing Libplanet.Types.Blocks;\nusing Xunit;\nusing static Libplanet.Tests.TestUtils;\n\nnamespace Libplanet.Tests.Blockchain\n{\n    public class BranchTest\n    {\n        private StoreFixture _fx;\n\n        public BranchTest()\n        {\n            _fx = new MemoryStoreFixture();\n        }\n\n        [Fact]\n        public void Constructor()\n        {\n            // Cannot create empty\n            var emptySet = new List<(Block, BlockCommit)>();\n            Assert.Throws<ArgumentException>(() => new Branch(emptySet));\n\n            // Cannot create with duplicates\n            var duplicateSet = new List<(Block, BlockCommit)>\n            {\n                (_fx.Block1, CreateBlockCommit(_fx.Block1)),\n                (_fx.Block1, CreateBlockCommit(_fx.Block1)),\n                (_fx.Block2, CreateBlockCommit(_fx.Block2)),\n            };\n            Assert.Throws<ArgumentException>(() => new Branch(duplicateSet));\n\n            // Cannot create with non-consecutive indices\n            var nonConsecutiveIndexSet = new List<(Block, BlockCommit)>\n            {\n                (_fx.Block1, CreateBlockCommit(_fx.Block1)),\n                (_fx.Block2, CreateBlockCommit(_fx.Block2)),\n                (_fx.Block4, CreateBlockCommit(_fx.Block4)),\n            };\n            Assert.Throws<ArgumentException>(() => new Branch(nonConsecutiveIndexSet));\n\n            // Cannot create with non-consecutive blocks\n            var nonConsecutiveHashSet = new List<(Block, BlockCommit)>\n            {\n                (_fx.Block2, CreateBlockCommit(_fx.Block2)),\n                (_fx.Block3Alt, CreateBlockCommit(_fx.Block3Alt)),\n                (_fx.Block4, CreateBlockCommit(_fx.Block4)),\n            };\n            Assert.Throws<ArgumentException>(() => new Branch(nonConsecutiveHashSet));\n\n            var shuffledSet = new List<(Block, BlockCommit)>\n            {\n                (_fx.Block4, CreateBlockCommit(_fx.Block4)),\n                (_fx.Block2, CreateBlockCommit(_fx.Block2)),\n                (_fx.Block3, CreateBlockCommit(_fx.Block3)),\n                (_fx.Block1, CreateBlockCommit(_fx.Block1)),\n            };\n            var branch = new Branch(shuffledSet);\n            AssertSorted(branch.Blocks.Select(block => block.Item1.Index));\n        }\n    }\n}\n"
  },
  {
    "path": "test/Libplanet.Tests/Blockchain/DefaultStoreBlockChainTest.cs",
    "content": "using Libplanet.Action;\nusing Libplanet.Tests.Store;\nusing Xunit.Abstractions;\n\nnamespace Libplanet.Tests.Blockchain\n{\n    public class DefaultStoreBlockChainTest : BlockChainTest\n    {\n        public DefaultStoreBlockChainTest(ITestOutputHelper output)\n            : base(output)\n        {\n        }\n\n        protected override StoreFixture GetStoreFixture(\n            IPolicyActionsRegistry policyActionsRegistry = null) =>\n                new DefaultStoreFixture(policyActionsRegistry: policyActionsRegistry);\n    }\n}\n"
  },
  {
    "path": "test/Libplanet.Tests/Blockchain/Evidence/DuplicateVoteEvidenceTest.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Numerics;\nusing Libplanet.Crypto;\nusing Libplanet.Types.Blocks;\nusing Libplanet.Types.Consensus;\nusing Libplanet.Types.Evidence;\nusing Xunit;\n\nnamespace Libplanet.Tests.Blockchain.Evidence\n{\n    public class DuplicateVoteEvidenceTest\n    {\n        [Fact]\n        public void Create_WithDifferentHeight_FailTest()\n        {\n            // Given\n            var privateKey = new PrivateKey();\n            var validatorPublicKey = privateKey.PublicKey;\n            var validatorList = new List<Validator>\n            {\n                new Validator(validatorPublicKey, BigInteger.One),\n            };\n\n            var voteRef = new VoteMetadata(\n                height: 1,\n                round: 2,\n                blockHash: new BlockHash(TestUtils.GetRandomBytes(BlockHash.Size)),\n                timestamp: DateTimeOffset.UtcNow,\n                validatorPublicKey: validatorPublicKey,\n                validatorPower: BigInteger.One,\n                flag: VoteFlag.PreCommit).Sign(privateKey);\n            var voteDup = new VoteMetadata(\n                height: 2,\n                round: 2,\n                blockHash: new BlockHash(TestUtils.GetRandomBytes(BlockHash.Size)),\n                timestamp: DateTimeOffset.UtcNow,\n                validatorPublicKey: validatorPublicKey,\n                validatorPower: BigInteger.One,\n                flag: VoteFlag.PreCommit).Sign(privateKey);\n\n            // When, Then\n            Assert.Throws<ArgumentException>(() =>\n            {\n                new DuplicateVoteEvidence(\n                    voteRef,\n                    voteDup,\n                    new ValidatorSet(validatorList),\n                    DateTimeOffset.UtcNow);\n            });\n        }\n\n        [Fact]\n        public void Create_WithDifferentRound_FailTest()\n        {\n            // Given\n            var privateKey = new PrivateKey();\n            var validatorPublicKey = privateKey.PublicKey;\n            var validatorList = new List<Validator>\n            {\n                new Validator(validatorPublicKey, BigInteger.One),\n            };\n\n            var voteRef = new VoteMetadata(\n                height: 1,\n                round: 2,\n                blockHash: new BlockHash(TestUtils.GetRandomBytes(BlockHash.Size)),\n                timestamp: DateTimeOffset.UtcNow,\n                validatorPublicKey: validatorPublicKey,\n                validatorPower: BigInteger.One,\n                flag: VoteFlag.PreCommit).Sign(privateKey);\n            var voteDup = new VoteMetadata(\n                height: 1,\n                round: 3,\n                blockHash: new BlockHash(TestUtils.GetRandomBytes(BlockHash.Size)),\n                timestamp: DateTimeOffset.UtcNow,\n                validatorPublicKey: validatorPublicKey,\n                validatorPower: BigInteger.One,\n                flag: VoteFlag.PreCommit).Sign(privateKey);\n\n            // When, Then\n            Assert.Throws<ArgumentException>(() =>\n            {\n                new DuplicateVoteEvidence(\n                    voteRef,\n                    voteDup,\n                    new ValidatorSet(validatorList),\n                    DateTimeOffset.UtcNow);\n            });\n        }\n\n        [Fact]\n        public void Create_WithDifferentPublicKey_FailTest()\n        {\n            // Given\n            var privateKeys = new PrivateKey[]\n            {\n                new PrivateKey(),\n                new PrivateKey(),\n            };\n            var validatorPublicKeys = privateKeys.Select(item => item.PublicKey).ToArray();\n            var validatorList\n                = validatorPublicKeys.Select(item => new Validator(item, BigInteger.One)).ToList();\n\n            var voteRef = new VoteMetadata(\n                height: 1,\n                round: 2,\n                blockHash: new BlockHash(TestUtils.GetRandomBytes(BlockHash.Size)),\n                timestamp: DateTimeOffset.UtcNow,\n                validatorPublicKey: validatorPublicKeys[0],\n                validatorPower: BigInteger.One,\n                flag: VoteFlag.PreCommit).Sign(privateKeys[0]);\n            var voteDup = new VoteMetadata(\n                height: 1,\n                round: 2,\n                blockHash: new BlockHash(TestUtils.GetRandomBytes(BlockHash.Size)),\n                timestamp: DateTimeOffset.UtcNow,\n                validatorPublicKey: validatorPublicKeys[1],\n                validatorPower: BigInteger.One,\n                flag: VoteFlag.PreCommit).Sign(privateKeys[1]);\n\n            // When, Then\n            Assert.Throws<ArgumentException>(() =>\n            {\n                new DuplicateVoteEvidence(\n                    voteRef: voteRef,\n                    voteDup: voteDup,\n                    validatorSet: new ValidatorSet(validatorList),\n                    timestamp: DateTimeOffset.UtcNow);\n            });\n        }\n\n        [Fact]\n        public void Create_WithDifferentFlag_FailTest()\n        {\n            // Given\n            var privateKey = new PrivateKey();\n            var validatorPublicKey = privateKey.PublicKey;\n            var validatorList = new List<Validator>\n            {\n                new Validator(validatorPublicKey, BigInteger.One),\n            };\n\n            var voteRef = new VoteMetadata(\n                height: 1,\n                round: 2,\n                blockHash: new BlockHash(TestUtils.GetRandomBytes(BlockHash.Size)),\n                timestamp: DateTimeOffset.UtcNow,\n                validatorPublicKey: validatorPublicKey,\n                validatorPower: BigInteger.One,\n                flag: VoteFlag.PreCommit).Sign(privateKey);\n            var voteDup = new VoteMetadata(\n                height: 1,\n                round: 2,\n                blockHash: new BlockHash(TestUtils.GetRandomBytes(BlockHash.Size)),\n                timestamp: DateTimeOffset.UtcNow,\n                validatorPublicKey: validatorPublicKey,\n                validatorPower: BigInteger.One,\n                flag: VoteFlag.PreVote).Sign(privateKey);\n\n            // When, Then\n            Assert.Throws<ArgumentException>(() =>\n            {\n                new DuplicateVoteEvidence(\n                    voteRef: voteRef,\n                    voteDup: voteDup,\n                    validatorSet: new ValidatorSet(validatorList),\n                    timestamp: DateTimeOffset.UtcNow);\n            });\n        }\n\n        [Fact]\n        public void Create_WithSameBlock_FailTest()\n        {\n            // Given\n            var privateKey = new PrivateKey();\n            var validatorPublicKey = privateKey.PublicKey;\n            var blockHash = new BlockHash(TestUtils.GetRandomBytes(BlockHash.Size));\n            var validatorList = new List<Validator>\n            {\n                new Validator(validatorPublicKey, BigInteger.One),\n            };\n\n            var voteRef = new VoteMetadata(\n                height: 1,\n                round: 2,\n                blockHash: blockHash,\n                timestamp: DateTimeOffset.UtcNow,\n                validatorPublicKey: validatorPublicKey,\n                validatorPower: BigInteger.One,\n                flag: VoteFlag.PreCommit).Sign(privateKey);\n            var voteDup = new VoteMetadata(\n                height: 1,\n                round: 2,\n                blockHash: blockHash,\n                timestamp: DateTimeOffset.UtcNow,\n                validatorPublicKey: validatorPublicKey,\n                validatorPower: BigInteger.One,\n                flag: VoteFlag.PreCommit).Sign(privateKey);\n\n            // When, Then\n            Assert.Throws<ArgumentException>(() =>\n            {\n                new DuplicateVoteEvidence(\n                    voteRef: voteRef,\n                    voteDup: voteDup,\n                    validatorSet: new ValidatorSet(validatorList),\n                    timestamp: DateTimeOffset.UtcNow);\n            });\n        }\n\n        [Fact]\n        public void Bencoded()\n        {\n            // Given\n            var privateKey = new PrivateKey();\n            var validatorPublicKey = privateKey.PublicKey;\n            var validatorList = new List<Validator>\n            {\n                new Validator(validatorPublicKey, BigInteger.One),\n            };\n\n            var voteRef = new VoteMetadata(\n                height: 1,\n                round: 2,\n                blockHash: new BlockHash(TestUtils.GetRandomBytes(BlockHash.Size)),\n                timestamp: DateTimeOffset.UtcNow,\n                validatorPublicKey: validatorPublicKey,\n                validatorPower: BigInteger.One,\n                flag: VoteFlag.PreCommit).Sign(privateKey);\n            var voteDup = new VoteMetadata(\n                height: 1,\n                round: 2,\n                blockHash: new BlockHash(TestUtils.GetRandomBytes(BlockHash.Size)),\n                timestamp: DateTimeOffset.UtcNow,\n                validatorPublicKey: validatorPublicKey,\n                validatorPower: BigInteger.One,\n                flag: VoteFlag.PreCommit).Sign(privateKey);\n\n            // When\n            var expectedEvidence = new DuplicateVoteEvidence(\n                voteRef: voteRef,\n                voteDup: voteDup,\n                validatorSet: new ValidatorSet(validatorList),\n                timestamp: voteDup.Timestamp);\n\n            // Then\n            var actualEvidence = new DuplicateVoteEvidence(expectedEvidence.Bencoded);\n\n            Assert.Equal(expectedEvidence.Bencoded, actualEvidence.Bencoded);\n            Assert.Equal(expectedEvidence, actualEvidence);\n        }\n\n        [Fact]\n        public void Serialize_and_Deserialize_Test()\n        {\n            // Given\n            var privateKey = new PrivateKey();\n            var validatorPublicKey = privateKey.PublicKey;\n            var validatorList = new List<Validator>\n            {\n                new Validator(validatorPublicKey, BigInteger.One),\n            };\n\n            var voteRef = new VoteMetadata(\n                height: 1,\n                round: 2,\n                blockHash: new BlockHash(TestUtils.GetRandomBytes(BlockHash.Size)),\n                timestamp: DateTimeOffset.UtcNow,\n                validatorPublicKey: validatorPublicKey,\n                validatorPower: BigInteger.One,\n                flag: VoteFlag.PreCommit).Sign(privateKey);\n            var voteDup = new VoteMetadata(\n                height: 1,\n                round: 2,\n                blockHash: new BlockHash(TestUtils.GetRandomBytes(BlockHash.Size)),\n                timestamp: DateTimeOffset.UtcNow,\n                validatorPublicKey: validatorPublicKey,\n                validatorPower: BigInteger.One,\n                flag: VoteFlag.PreCommit).Sign(privateKey);\n\n            // When\n            var expectedEvidence = new DuplicateVoteEvidence(\n                voteRef: voteRef,\n                voteDup: voteDup,\n                validatorSet: new ValidatorSet(validatorList),\n                timestamp: voteDup.Timestamp);\n\n            // Then\n            var bencoded = expectedEvidence.Serialize();\n            var actualEvidence = EvidenceBase.Deserialize(bencoded);\n\n            Assert.Equal(expectedEvidence.Bencoded, actualEvidence.Bencoded);\n            Assert.Equal(expectedEvidence, actualEvidence);\n        }\n    }\n}\n"
  },
  {
    "path": "test/Libplanet.Tests/Blockchain/Evidence/EvidenceIdTest.cs",
    "content": "using System;\nusing System.Collections.Immutable;\nusing System.Linq;\nusing Libplanet.Types.Evidence;\nusing Xunit;\nusing static Libplanet.Tests.TestUtils;\n\nnamespace Libplanet.Tests.Blockchain.Evidence\n{\n    public class EvidenceIdTest\n    {\n        public static readonly object[][] RandomBytes = new[]\n        {\n            new object[] { GetRandomBytes(0) },\n            new object[] { GetRandomBytes(31) },\n            new object[] { GetRandomBytes(33) },\n        };\n\n        [Theory]\n        [MemberData(nameof(RandomBytes))]\n        public void Create_WithBytesLengthNot32_FailTest(byte[] evidenceId)\n        {\n            Assert.Throws<ArgumentOutOfRangeException>(\n                paramName: nameof(evidenceId),\n                testCode: () => new EvidenceId(evidenceId));\n        }\n\n        [Theory]\n        [MemberData(nameof(RandomBytes))]\n        public void Create_WithImmutableBytesLengthNot32_FailTest(byte[] evidenceId)\n        {\n            Assert.Throws<ArgumentOutOfRangeException>(\n                paramName: nameof(evidenceId),\n                testCode: () => new EvidenceId(evidenceId.ToImmutableArray()));\n        }\n\n        [Fact]\n        public void FromHex_Test()\n        {\n            // Given\n            var expectedEvidenceId = new EvidenceId(\n                new byte[]\n                {\n                    0x45, 0xa2, 0x21, 0x87, 0xe2, 0xd8, 0x85, 0x0b, 0xb3, 0x57,\n                    0x88, 0x69, 0x58, 0xbc, 0x3e, 0x85, 0x60, 0x92, 0x9c, 0xcc,\n                    0x88, 0x69, 0x58, 0xbc, 0x3e, 0x85, 0x60, 0x92, 0x9c, 0xcc,\n                    0x9c, 0xcc,\n                }\n            );\n\n            // Then\n            var actualEvidenceId = EvidenceId.Parse(\n                \"45a22187e2d8850bb357886958bc3e8560929ccc886958bc3e8560929ccc9ccc\");\n            Assert.Equal(expectedEvidenceId, actualEvidenceId);\n        }\n\n        [Theory]\n        [InlineData(\"0g\")]\n        public void FromHex_WithInvalidFormat_FailTest(string hex)\n        {\n            Assert.Throws<FormatException>(() => EvidenceId.Parse(hex));\n        }\n\n        [Theory]\n        [InlineData(\"1\")]\n        [InlineData(\"45a22187e2d8850bb357886958bc3e8560929ccc886958bc3e8560929ccc9c\")]\n        [InlineData(\"45a22187e2d8850bb357886958bc3e8560929ccc886958bc3e8560929ccc9ccc0\")]\n        [InlineData(\"45a22187e2d8850bb357886958bc3e8560929ccc886958bc3e8560929ccc9ccc00\")]\n        public void FromHex_WithInvalidLength_FailTest(string hex)\n        {\n            Assert.Throws<ArgumentOutOfRangeException>(\n                paramName: nameof(hex),\n                testCode: () => EvidenceId.Parse(hex));\n        }\n\n        [Fact]\n        public void ToByteArray_Test()\n        {\n            // Given\n            var expectedBytes = GetRandomBytes(EvidenceId.Size);\n\n            // When\n            var evidenceId = new EvidenceId(expectedBytes);\n\n            // Then\n            var actualBytes = evidenceId.ToByteArray();\n\n            Assert.Equal(expectedBytes, actualBytes);\n        }\n\n        [Fact]\n        public void ToByteArray_ShouldNotExposeContents_Test()\n        {\n            // Given\n            var bytes = new byte[]\n            {\n                0x45, 0xa2, 0x21, 0x87, 0xe2, 0xd8, 0x85, 0x0b, 0xb3, 0x57,\n                0x88, 0x69, 0x58, 0xbc, 0x3e, 0x85, 0x60, 0x92, 0x9c, 0xcc,\n                0x88, 0x69, 0x58, 0xbc, 0x3e, 0x85, 0x60, 0x92, 0x9c, 0xcc,\n                0x9c, 0xcc,\n            };\n            var evidenceId = new EvidenceId(bytes);\n            var index = Random.Shared.Next(bytes.Length);\n            var expectedByte = bytes[index];\n\n            // When\n            evidenceId.ToByteArray()[index] = 0x00;\n\n            // Then\n            var actualByte = evidenceId.ToByteArray()[index];\n            Assert.Equal(expectedByte, actualByte);\n        }\n\n        [Fact]\n        public void ToHex_Test()\n        {\n            // Given\n            var evidenceId = new EvidenceId(\n                new byte[]\n                {\n                    0x45, 0xa2, 0x21, 0x87, 0xe2, 0xd8, 0x85, 0x0b, 0xb3, 0x57,\n                    0x88, 0x69, 0x58, 0xbc, 0x3e, 0x85, 0x60, 0x92, 0x9c, 0xcc,\n                    0x88, 0x69, 0x58, 0xbc, 0x3e, 0x85, 0x60, 0x92, 0x9c, 0xcc,\n                    0x9c, 0xcc,\n                }\n            );\n\n            // Then\n            var expectedHex = \"45a22187e2d8850bb357886958bc3e8560929ccc886958bc3e8560929ccc9ccc\";\n            var actualHex = evidenceId.ToString();\n            Assert.Equal(expectedHex, actualHex);\n        }\n\n        [Fact]\n        public void ToString_Test()\n        {\n            // Given\n            var evidenceId = new EvidenceId(\n                new byte[]\n                {\n                    0x45, 0xa2, 0x21, 0x87, 0xe2, 0xd8, 0x85, 0x0b, 0xb3, 0x57,\n                    0x88, 0x69, 0x58, 0xbc, 0x3e, 0x85, 0x60, 0x92, 0x9c, 0xcc,\n                    0x88, 0x69, 0x58, 0xbc, 0x3e, 0x85, 0x60, 0x92, 0x9c, 0xcc,\n                    0x9c, 0xcc,\n                }\n            );\n\n            // Then\n            var expectedString = \"45a22187e2d8850bb357886958bc3e8560929ccc886958bc3e8560929ccc9ccc\";\n            var actualString = evidenceId.ToString();\n            Assert.Equal(expectedString, actualString);\n        }\n\n        [Fact]\n        public void Equals_Test()\n        {\n            // Given\n            var sameEvidenceId1 = new EvidenceId(\n                new byte[]\n                {\n                    0x45, 0xa2, 0x21, 0x87, 0xe2, 0xd8, 0x85, 0x0b, 0xb3, 0x57,\n                    0x88, 0x69, 0x58, 0xbc, 0x3e, 0x85, 0x60, 0x92, 0x9c, 0xcc,\n                    0x88, 0x69, 0x58, 0xbc, 0x3e, 0x85, 0x60, 0x92, 0x9c, 0xcc,\n                    0x9c, 0xcc,\n                }\n            );\n            var sameEvidenceId2 = new EvidenceId(\n                new byte[]\n                {\n                    0x45, 0xa2, 0x21, 0x87, 0xe2, 0xd8, 0x85, 0x0b, 0xb3, 0x57,\n                    0x88, 0x69, 0x58, 0xbc, 0x3e, 0x85, 0x60, 0x92, 0x9c, 0xcc,\n                    0x88, 0x69, 0x58, 0xbc, 0x3e, 0x85, 0x60, 0x92, 0x9c, 0xcc,\n                    0x9c, 0xcc,\n                }\n            );\n            var differentEvidenceId = new EvidenceId(\n                new byte[]\n                {\n                    0x45, 0xa2, 0x21, 0x87, 0xe2, 0xd8, 0x85, 0x0b, 0xb3, 0x57,\n                    0x88, 0x69, 0x58, 0xbc, 0x3e, 0x85, 0x60, 0x92, 0x9c, 0x00,\n                    0x88, 0x69, 0x58, 0xbc, 0x3e, 0x85, 0x60, 0x92, 0x9c, 0x00,\n                    0x9c, 0x00,\n                }\n            );\n\n            // Then\n            Assert.Equal(sameEvidenceId1, sameEvidenceId2);\n            Assert.NotEqual(sameEvidenceId2, differentEvidenceId);\n\n            Assert.True(sameEvidenceId1 == sameEvidenceId2);\n            Assert.False(sameEvidenceId2 == differentEvidenceId);\n\n            Assert.False(sameEvidenceId1 != sameEvidenceId2);\n            Assert.True(sameEvidenceId2 != differentEvidenceId);\n        }\n\n        [Fact]\n        public void Compare_Test()\n        {\n            const int length = 50;\n            var evidenceIds\n                = Enumerable.Repeat(0, length)\n                            .Select(_ => new EvidenceId(GetRandomBytes(EvidenceId.Size)))\n                            .ToArray();\n\n            for (int i = 1; i < evidenceIds.Length; i++)\n            {\n                var left = evidenceIds[i - 1];\n                var right = evidenceIds[i];\n                var leftString = left.ToString().ToLower();\n                var rightString = right.ToString().ToLower();\n                Assert.Equal(\n                    Math.Min(Math.Max(left.CompareTo(right), 1), -1),\n                    Math.Min(Math.Max(leftString.CompareTo(rightString), 1), -1)\n                );\n                Assert.Equal(\n                    left.CompareTo(right),\n                    (left as IComparable).CompareTo(right)\n                );\n            }\n        }\n\n        [Theory]\n        [InlineData(null)]\n        [InlineData(\"invalid\")]\n        public void Compare_WithInvalidValue_FailTest(object value)\n        {\n            // Given\n            var evidenceId = new EvidenceId(GetRandomBytes(EvidenceId.Size));\n\n            // Then\n            Assert.Equal(1, evidenceId.CompareTo(value));\n        }\n\n        [Fact]\n        public void Bencoded_Test()\n        {\n            var expectedEvidenceId = new EvidenceId(GetRandomBytes(EvidenceId.Size));\n            var actualEvidenceId = new EvidenceId(expectedEvidenceId.Bencoded);\n            Assert.Equal(expectedEvidenceId, actualEvidenceId);\n        }\n\n        [Fact]\n        public void Bencoded_WithDefaultInstance_Test()\n        {\n            var expectedEvidenceId = default(EvidenceId);\n            var actualEvidenceId = new EvidenceId(expectedEvidenceId.Bencoded);\n            Assert.Equal(expectedEvidenceId, actualEvidenceId);\n        }\n\n        [SkippableFact]\n        public void JsonSerialization()\n        {\n            EvidenceId evidenceId = EvidenceId.Parse(\n                \"45a22187e2d8850bb357886958bc3e8560929ccc886958bc3e8560929ccc9ccc\");\n            AssertJsonSerializable(\n                evidenceId,\n                \"\\\"45a22187e2d8850bb357886958bc3e8560929ccc886958bc3e8560929ccc9ccc\\\"\"\n            );\n        }\n    }\n}\n"
  },
  {
    "path": "test/Libplanet.Tests/Blockchain/Evidence/EvidenceTest.cs",
    "content": "using System;\nusing Bencodex.Types;\nusing Libplanet.Crypto;\nusing Libplanet.Types.Evidence;\nusing Xunit;\n\nnamespace Libplanet.Tests.Blockchain.Evidence\n{\n    public class EvidenceTest\n    {\n        [Fact]\n        public void Create_WithNegativeHeight_FailTest()\n        {\n            Assert.Throws<ArgumentOutOfRangeException>(\n                paramName: \"height\",\n                testCode: () => new TestEvidence(-1, default, DateTimeOffset.UtcNow));\n        }\n\n        [Fact]\n        public void Create_WithNotDictionary_FailTest()\n        {\n            Assert.Throws<ArgumentException>(\n                paramName: \"bencoded\",\n                testCode: () => new TestEvidence(new Bencodex.Types.Integer(0)));\n        }\n\n        [Fact]\n        public void Decode_WithInvalidEvidenceWithoutConstructor_FailTest()\n        {\n            var height = 0L;\n            var address = new PrivateKey().Address;\n            var timestamp = DateTimeOffset.UtcNow;\n            var evidence = new TestEvidence(height, address, timestamp);\n\n            var bencoded = EvidenceBase.Bencode(evidence);\n            if (bencoded is Dictionary dictionary)\n            {\n                var typeName = EvidenceBase.GetTypeName(typeof(InvalidEvidence));\n                bencoded = dictionary.SetItem(\"type\", new Text(typeName));\n            }\n\n            Assert.Throws<NotSupportedException>(\n                testCode: () => EvidenceBase.Decode(bencoded));\n        }\n\n        [Fact]\n        public void GetTypeName_Test()\n        {\n            var evidenceType = typeof(InvalidEvidence);\n            var actualTypeName = EvidenceBase.GetTypeName(evidenceType);\n            var expectedTypeName\n                = $\"{evidenceType.FullName}, {evidenceType.Assembly.GetName().Name}\";\n            Assert.Equal(expectedTypeName, actualTypeName);\n        }\n\n        private sealed class InvalidEvidence : EvidenceBase\n        {\n            public InvalidEvidence(long height, Address targetAddress, DateTimeOffset timestamp)\n                : base(height, targetAddress, timestamp)\n            {\n            }\n\n            protected override Dictionary OnBencoded(Dictionary dictionary)\n            {\n                return dictionary;\n            }\n\n            protected override void OnVerify(IEvidenceContext evidenceContext)\n            {\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "test/Libplanet.Tests/Blockchain/Evidence/TestEvidence.cs",
    "content": "using System;\nusing Bencodex.Types;\nusing Libplanet.Crypto;\nusing Libplanet.Types.Evidence;\n\nnamespace Libplanet.Tests.Blockchain.Evidence\n{\n    public sealed class TestEvidence : EvidenceBase, IEquatable<TestEvidence>\n    {\n        public TestEvidence(\n            long height,\n            Address validatorAddress,\n            DateTimeOffset timestamp)\n            : base(height, validatorAddress, timestamp)\n        {\n        }\n\n        public TestEvidence(IValue bencoded)\n            : base(bencoded)\n        {\n        }\n\n        public Address ValidatorAddress => TargetAddress;\n\n        /// <inheritdoc/>\n        public bool Equals(TestEvidence other) => base.Equals(other);\n\n        /// <inheritdoc/>\n        public override bool Equals(object obj)\n            => obj is TestEvidence other && Equals(other);\n\n        /// <inheritdoc/>\n        public override int GetHashCode() => base.GetHashCode();\n\n        protected override Dictionary OnBencoded(Dictionary dictionary)\n            => dictionary;\n\n        protected override void OnVerify(IEvidenceContext evidenceContext)\n        {\n        }\n    }\n}\n"
  },
  {
    "path": "test/Libplanet.Tests/Blockchain/Evidence/UnknownEvidenceTest.cs",
    "content": "using System;\nusing Bencodex.Types;\nusing Libplanet.Crypto;\nusing Libplanet.Types.Evidence;\nusing Xunit;\n\nnamespace Libplanet.Tests.Blockchain.Evidence\n{\n    public class UnknownEvidenceTest\n    {\n        [Fact]\n        public void Decode_Test()\n        {\n            var height = 0L;\n            var address = new PrivateKey().Address;\n            var timestamp = DateTimeOffset.UtcNow;\n            var expectedEvidence = new TestEvidence(height, address, timestamp);\n\n            var bencoded = EvidenceBase.Bencode(expectedEvidence);\n            if (bencoded is Dictionary dictionary)\n            {\n                bencoded = dictionary.SetItem(\"type\", new Text(\"invalid type\"));\n            }\n\n            var actualEvidence = EvidenceBase.Decode(bencoded);\n\n            Assert.Equal(expectedEvidence.Height, actualEvidence.Height);\n            Assert.Equal(expectedEvidence.TargetAddress, actualEvidence.TargetAddress);\n            Assert.Equal(expectedEvidence.Timestamp, actualEvidence.Timestamp);\n            Assert.Equal(expectedEvidence, actualEvidence);\n        }\n    }\n}\n"
  },
  {
    "path": "test/Libplanet.Tests/Blockchain/Policies/BlockPolicyTest.cs",
    "content": "using System;\nusing System.Collections.Immutable;\nusing System.Linq;\nusing Libplanet.Action;\nusing Libplanet.Action.Loader;\nusing Libplanet.Action.Tests.Common;\nusing Libplanet.Blockchain;\nusing Libplanet.Blockchain.Policies;\nusing Libplanet.Crypto;\nusing Libplanet.Store;\nusing Libplanet.Store.Trie;\nusing Libplanet.Tests.Store;\nusing Libplanet.Types.Tx;\nusing Xunit;\nusing Xunit.Abstractions;\n\nnamespace Libplanet.Tests.Blockchain.Policies\n{\n    public class BlockPolicyTest : IDisposable\n    {\n        private static readonly DateTimeOffset FixtureEpoch =\n            new DateTimeOffset(2018, 1, 1, 0, 0, 0, TimeSpan.Zero);\n\n        private readonly ITestOutputHelper _output;\n\n        private StoreFixture _fx;\n        private BlockChain _chain;\n        private IBlockPolicy _policy;\n        private IStagePolicy _stagePolicy;\n\n        public BlockPolicyTest(ITestOutputHelper output)\n        {\n            _fx = new MemoryStoreFixture();\n            _output = output;\n            _policy = new BlockPolicy(\n                new PolicyActionsRegistry(),\n                blockInterval: TimeSpan.FromMilliseconds(3 * 60 * 60 * 1000));\n            _stagePolicy = new VolatileStagePolicy();\n            _chain = BlockChain.Create(\n                _policy,\n                _stagePolicy,\n                _fx.Store,\n                _fx.StateStore,\n                _fx.GenesisBlock,\n                new ActionEvaluator(\n                    _policy.PolicyActionsRegistry,\n                    stateStore: _fx.StateStore,\n                    actionTypeLoader: new SingleActionLoader(typeof(DumbAction))));\n        }\n\n        public void Dispose()\n        {\n            _fx.Dispose();\n        }\n\n        [Fact]\n        public void Constructors()\n        {\n            var tenSec = new TimeSpan(0, 0, 10);\n            var a = new BlockPolicy(\n                new PolicyActionsRegistry(),\n                blockInterval: tenSec);\n            Assert.Equal(tenSec, a.BlockInterval);\n\n            var b = new BlockPolicy(\n                blockInterval: TimeSpan.FromMilliseconds(65000));\n            Assert.Equal(\n                new TimeSpan(0, 1, 5),\n                b.BlockInterval);\n\n            var c = new BlockPolicy();\n            Assert.Equal(\n                new TimeSpan(0, 0, 5),\n                c.BlockInterval);\n        }\n\n        [Fact]\n        public void ValidateNextBlockTx()\n        {\n            var validKey = new PrivateKey();\n\n            TxPolicyViolationException IsSignerValid(\n                BlockChain chain, Transaction tx)\n            {\n                var validAddress = validKey.Address;\n                return tx.Signer.Equals(validAddress)\n                    ? null\n                    : new TxPolicyViolationException(\"invalid signer\", tx.Id);\n            }\n\n            var policy = new BlockPolicy(validateNextBlockTx: IsSignerValid);\n\n            // Valid Transaction\n            var validTx = _chain.MakeTransaction(validKey, new DumbAction[] { });\n            var expected = policy.ValidateNextBlockTx(_chain, validTx);\n            Assert.Null(expected);\n\n            // Invalid Transaction\n            var invalidKey = new PrivateKey();\n            var invalidTx = _chain.MakeTransaction(invalidKey, new DumbAction[] { });\n            expected = policy.ValidateNextBlockTx(_chain, invalidTx);\n            Assert.NotNull(expected);\n        }\n\n        [Fact]\n        public void ValidateNextBlockTxWithInnerException()\n        {\n            var validKey = new PrivateKey();\n            var invalidKey = new PrivateKey();\n\n            TxPolicyViolationException IsSignerValid(\n                BlockChain chain, Transaction tx)\n            {\n                var validAddress = validKey.Address;\n                return tx.Signer.Equals(validAddress)\n                    ? null\n                    : new TxPolicyViolationException(\"invalid signer\", tx.Id);\n            }\n\n            //Invalid Transaction with inner-exception\n            TxPolicyViolationException IsSignerValidWithInnerException(\n                BlockChain chain, Transaction tx)\n            {\n                var validAddress = validKey.Address;\n                return tx.Signer.Equals(validAddress)\n                    ? null\n                    : new TxPolicyViolationException(\n                        \"invalid signer\",\n                        tx.Id,\n                        new InvalidTxSignatureException(\"Invalid Signature\", tx.Id));\n            }\n\n            // Invalid Transaction without Inner-exception\n            var policy = new BlockPolicy(\n                validateNextBlockTx: IsSignerValid);\n\n            var invalidTx = _chain.MakeTransaction(invalidKey, new DumbAction[] { });\n            var expected = policy.ValidateNextBlockTx(_chain, invalidTx);\n            Assert.NotNull(expected);\n            Assert.Null(expected.InnerException);\n\n            // Invalid Transaction with Inner-exception.\n            policy = new BlockPolicy(\n                validateNextBlockTx: IsSignerValidWithInnerException);\n\n            invalidTx = _chain.MakeTransaction(invalidKey, new DumbAction[] { });\n            expected = policy.ValidateNextBlockTx(_chain, invalidTx);\n            Assert.NotNull(expected);\n            Assert.NotNull(expected.InnerException);\n        }\n\n        [Fact]\n        public void GetMinTransactionsPerBlock()\n        {\n            const int policyLimit = 2;\n\n            var store = new MemoryStore();\n            var stateStore = new TrieStateStore(new MemoryKeyValueStore());\n            var actionLoader = new SingleActionLoader(typeof(DumbAction));\n            var policy = new BlockPolicy(\n                new PolicyActionsRegistry(\n                    endBlockActions: ImmutableArray.Create<IAction>(new MinerReward(1))),\n                getMinTransactionsPerBlock: index => index == 0 ? 0 : policyLimit);\n            var privateKey = new PrivateKey();\n            var chain = TestUtils.MakeBlockChain(policy, store, stateStore, actionLoader);\n\n            _ = chain.MakeTransaction(privateKey, new DumbAction[] { });\n            Assert.Single(chain.ListStagedTransactions());\n\n            // Tests if MineBlock() method will throw an exception if less than the minimum\n            // transactions are present\n            Assert.Throws<OperationCanceledException>(\n                () => chain.ProposeBlock(new PrivateKey()));\n        }\n\n        [Fact]\n        public void GetMaxTransactionsPerBlock()\n        {\n            const int generatedTxCount = 10;\n            const int policyLimit = 5;\n\n            var store = new MemoryStore();\n            var stateStore = new TrieStateStore(new MemoryKeyValueStore());\n            var actionLoader = new SingleActionLoader(typeof(DumbAction));\n            var policy = new BlockPolicy(\n                getMaxTransactionsPerBlock: _ => policyLimit);\n            var privateKey = new PrivateKey();\n            var chain = TestUtils.MakeBlockChain(policy, store, stateStore, actionLoader);\n\n            _ = Enumerable\n                    .Range(0, generatedTxCount)\n                    .Select(_ => chain.MakeTransaction(privateKey, new DumbAction[] { }))\n                    .ToList();\n            Assert.Equal(generatedTxCount, chain.ListStagedTransactions().Count);\n\n            var block = chain.ProposeBlock(privateKey);\n            Assert.Equal(policyLimit, block.Transactions.Count);\n        }\n\n        [Fact]\n        public void GetMaxTransactionsPerSignerPerBlock()\n        {\n            const int keyCount = 2;\n            const int generatedTxCount = 10;\n            const int policyLimit = 4;\n\n            var store = new MemoryStore();\n            var stateStore = new TrieStateStore(new MemoryKeyValueStore());\n            var actionLoader = new SingleActionLoader(typeof(DumbAction));\n            var policy = new BlockPolicy(\n                getMaxTransactionsPerSignerPerBlock: _ => policyLimit);\n            var privateKeys = Enumerable.Range(0, keyCount).Select(_ => new PrivateKey()).ToList();\n            var minerKey = privateKeys.First();\n            var chain = TestUtils.MakeBlockChain(policy, store, stateStore, actionLoader);\n\n            privateKeys.ForEach(\n                key => _ = Enumerable\n                    .Range(0, generatedTxCount)\n                    .Select(_ => chain.MakeTransaction(key, new DumbAction[] { }))\n                    .ToList());\n            Assert.Equal(generatedTxCount * keyCount, chain.ListStagedTransactions().Count);\n\n            var block = chain.ProposeBlock(minerKey);\n            Assert.Equal(policyLimit * keyCount, block.Transactions.Count);\n            privateKeys.ForEach(\n                key => Assert.Equal(\n                    policyLimit,\n                    block.Transactions.Count(tx => tx.Signer.Equals(key.Address))));\n        }\n    }\n}\n"
  },
  {
    "path": "test/Libplanet.Tests/Blockchain/Policies/StagePolicyTest.cs",
    "content": "using System.Collections.Generic;\nusing System.Linq;\nusing Libplanet.Action;\nusing Libplanet.Action.Loader;\nusing Libplanet.Action.Tests.Common;\nusing Libplanet.Blockchain;\nusing Libplanet.Blockchain.Policies;\nusing Libplanet.Crypto;\nusing Libplanet.Tests.Store;\nusing Libplanet.Types.Tx;\nusing Xunit;\n\nnamespace Libplanet.Tests.Blockchain.Policies\n{\n    public abstract class StagePolicyTest\n    {\n        protected readonly BlockPolicy _policy;\n        protected readonly MemoryStoreFixture _fx;\n        protected readonly BlockChain _chain;\n        protected readonly PrivateKey _key;\n        protected readonly Transaction[] _txs;\n\n        protected StagePolicyTest()\n        {\n            _policy = new BlockPolicy();\n            _fx = new MemoryStoreFixture();\n            _chain = BlockChain.Create(\n                _policy,\n                StagePolicy,\n                _fx.Store,\n                _fx.StateStore,\n                _fx.GenesisBlock,\n                new ActionEvaluator(\n                    _policy.PolicyActionsRegistry,\n                    stateStore: _fx.StateStore,\n                    actionTypeLoader: new SingleActionLoader(typeof(DumbAction))));\n            _key = new PrivateKey();\n            _txs = Enumerable.Range(0, 5).Select(i =>\n                Transaction.Create(\n                    i,\n                    _key,\n                    _fx.GenesisBlock.Hash,\n                    Enumerable.Empty<DumbAction>().ToPlainValues()\n                )\n            ).ToArray();\n        }\n\n        protected abstract IStagePolicy StagePolicy { get; }\n\n        [Fact]\n        public void Stage()\n        {\n            void AssertTxSetEqual(\n                IEnumerable<Transaction> setOne,\n                IEnumerable<Transaction> setTwo)\n            {\n                Assert.Equal(setOne.OrderBy(tx => tx.Id), setTwo.OrderBy(tx => tx.Id));\n            }\n\n            var duplicateNonceTx = Transaction.Create(\n                2,\n                _key,\n                _fx.GenesisBlock.Hash,\n                Enumerable.Empty<DumbAction>().ToPlainValues()\n            );\n\n            Assert.Empty(StagePolicy.Iterate(_chain));\n\n            Assert.True(StagePolicy.Stage(_chain, _txs[0]));\n            AssertTxSetEqual(_txs.Take(1), StagePolicy.Iterate(_chain));\n\n            Assert.True(StagePolicy.Stage(_chain, _txs[1]));\n            AssertTxSetEqual(_txs.Take(2), StagePolicy.Iterate(_chain));\n\n            // If already staged, no exception is thrown.\n            Assert.False(StagePolicy.Stage(_chain, _txs[0]));\n            AssertTxSetEqual(_txs.Take(2), StagePolicy.Iterate(_chain));\n\n            // Duplicate nonces can be staged.\n            Assert.True(StagePolicy.Stage(_chain, _txs[2]));\n            AssertTxSetEqual(_txs.Take(3), StagePolicy.Iterate(_chain));\n            Assert.True(StagePolicy.Stage(_chain, duplicateNonceTx));\n            AssertTxSetEqual(_txs.Take(3).Append(duplicateNonceTx), StagePolicy.Iterate(_chain));\n\n            // If a transaction had been unstaged, it can be staged again.\n            Assert.True(StagePolicy.Unstage(_chain, _txs[2].Id));\n            AssertTxSetEqual(_txs.Take(2).Append(duplicateNonceTx), StagePolicy.Iterate(_chain));\n            Assert.True(StagePolicy.Stage(_chain, _txs[2]));\n            AssertTxSetEqual(\n                _txs.Take(2).Append(duplicateNonceTx).Append(_txs[2]),\n                StagePolicy.Iterate(_chain));\n        }\n\n        [Fact]\n        public void Unstage()\n        {\n            void AssertTxSetEqual(\n                IEnumerable<Transaction> setOne,\n                IEnumerable<Transaction> setTwo)\n            {\n                Assert.Equal(setOne.OrderBy(tx => tx.Id), setTwo.OrderBy(tx => tx.Id));\n            }\n\n            foreach (Transaction tx in _txs)\n            {\n                StagePolicy.Stage(_chain, tx);\n            }\n\n            AssertTxSetEqual(_txs, StagePolicy.Iterate(_chain));\n\n            Assert.True(StagePolicy.Unstage(_chain, _txs[0].Id));\n            AssertTxSetEqual(_txs.Skip(1), StagePolicy.Iterate(_chain));\n\n            // If already unstaged, no exception is thrown.\n            Assert.False(StagePolicy.Unstage(_chain, _txs[0].Id));\n            AssertTxSetEqual(_txs.Skip(1), StagePolicy.Iterate(_chain));\n\n            Assert.True(StagePolicy.Unstage(_chain, _txs.Last().Id));\n            AssertTxSetEqual(_txs.Skip(1).SkipLast(1), StagePolicy.Iterate(_chain));\n\n            Assert.True(StagePolicy.Unstage(_chain, _txs[2].Id));\n            AssertTxSetEqual(new[] { _txs[1], _txs[3] }, StagePolicy.Iterate(_chain));\n        }\n\n        [Fact]\n        public void Ignore()\n        {\n            // Ignore prevents staging.\n            Assert.False(StagePolicy.Ignores(_chain, _txs[0].Id));\n            StagePolicy.Ignore(_chain, _txs[0].Id);\n            Assert.True(StagePolicy.Ignores(_chain, _txs[0].Id));\n            Assert.False(StagePolicy.Stage(_chain, _txs[0]));\n            Assert.Null(StagePolicy.Get(_chain, _txs[0].Id));\n\n            // Ignore unstages.\n            Assert.False(StagePolicy.Ignores(_chain, _txs[1].Id));\n            Assert.True(StagePolicy.Stage(_chain, _txs[1]));\n            Assert.Equal(_txs[1], StagePolicy.Get(_chain, _txs[1].Id));\n            StagePolicy.Ignore(_chain, _txs[1].Id);\n            Assert.True(StagePolicy.Ignores(_chain, _txs[1].Id));\n            Assert.Null(StagePolicy.Get(_chain, _txs[1].Id));\n        }\n\n        [Fact]\n        public void Ignores()\n        {\n            // By default, nothing is ignored.\n            foreach (Transaction tx in _txs)\n            {\n                Assert.False(StagePolicy.Ignores(_chain, tx.Id));\n            }\n\n            // Staging has no effect on ignores.\n            Assert.True(StagePolicy.Stage(_chain, _txs[0]));\n            Assert.False(StagePolicy.Ignores(_chain, _txs[0].Id));\n\n            // Unstaging has no effect on ignores.\n            Assert.True(StagePolicy.Unstage(_chain, _txs[0].Id));\n            Assert.False(StagePolicy.Ignores(_chain, _txs[0].Id));\n\n            // Only Ignore() ignores regardless of staged state.\n            StagePolicy.Stage(_chain, _txs[1]);\n            StagePolicy.Ignore(_chain, _txs[1].Id);\n            StagePolicy.Ignore(_chain, _txs[2].Id);\n            Assert.True(StagePolicy.Ignores(_chain, _txs[1].Id));\n            Assert.True(StagePolicy.Ignores(_chain, _txs[2].Id));\n        }\n\n        [Fact]\n        public void Get()\n        {\n            foreach (Transaction tx in _txs)\n            {\n                Assert.Null(StagePolicy.Get(_chain, tx.Id));\n            }\n\n            StagePolicy.Stage(_chain, _txs[0]);\n            Assert.Equal(_txs[0], StagePolicy.Get(_chain, _txs[0].Id));\n\n            foreach (Transaction tx in _txs.Skip(1))\n            {\n                Assert.Null(StagePolicy.Get(_chain, tx.Id));\n            }\n\n            StagePolicy.Unstage(_chain, _txs[0].Id);\n            Assert.Null(StagePolicy.Get(_chain, _txs[0].Id));\n\n            foreach (Transaction tx in _txs.Skip(1))\n            {\n                Assert.Null(StagePolicy.Get(_chain, tx.Id));\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "test/Libplanet.Tests/Blockchain/Policies/VolatileStagePolicyTest.cs",
    "content": "using System;\nusing System.Linq;\nusing System.Threading;\nusing Libplanet.Action;\nusing Libplanet.Action.Tests.Common;\nusing Libplanet.Blockchain.Policies;\nusing Libplanet.Types.Tx;\nusing Xunit;\n\nnamespace Libplanet.Tests.Blockchain.Policies\n{\n    public class VolatileStagePolicyTest : StagePolicyTest\n    {\n        private readonly VolatileStagePolicy _stagePolicy =\n            new VolatileStagePolicy();\n\n        protected override IStagePolicy StagePolicy => _stagePolicy;\n\n        [Fact]\n        public void Lifetime()\n        {\n            TimeSpan timeBuffer = TimeSpan.FromSeconds(1);\n            Transaction tx = Transaction.Create(\n                0,\n                _key,\n                _fx.GenesisBlock.Hash,\n                Enumerable.Empty<DumbAction>().ToPlainValues(),\n                timestamp: (DateTimeOffset.UtcNow - _stagePolicy.Lifetime) + timeBuffer\n            );\n            Assert.True(_stagePolicy.Stage(_chain, tx));\n            Assert.Equal(tx, _stagePolicy.Get(_chain, tx.Id));\n            Assert.Contains(tx, _stagePolicy.Iterate(_chain));\n\n            // On some targets TimeSpan * int does not exist.\n            Thread.Sleep(timeBuffer);\n            Thread.Sleep(timeBuffer);\n            Assert.Null(_stagePolicy.Get(_chain, tx.Id));\n            Assert.DoesNotContain(tx, _stagePolicy.Iterate(_chain));\n        }\n\n        [Fact]\n        public void MaxLifetime()\n        {\n            var stagePolicy = new VolatileStagePolicy(TimeSpan.MaxValue);\n            Transaction tx = Transaction.Create(\n                0,\n                _key,\n                _fx.GenesisBlock.Hash,\n                Enumerable.Empty<DumbAction>().ToPlainValues(),\n                timestamp: DateTimeOffset.UtcNow);\n            Assert.True(stagePolicy.Stage(_chain, tx));\n        }\n\n        [Fact]\n        public void StageUnstage()\n        {\n            TimeSpan timeBuffer = TimeSpan.FromSeconds(1);\n            Transaction validTx = Transaction.Create(\n                0,\n                _key,\n                _fx.GenesisBlock.Hash,\n                Enumerable.Empty<DumbAction>().ToPlainValues(),\n                timestamp: (DateTimeOffset.UtcNow - _stagePolicy.Lifetime) + timeBuffer\n            );\n            Transaction staleTx = Transaction.Create(\n                0,\n                _key,\n                _fx.GenesisBlock.Hash,\n                Enumerable.Empty<DumbAction>().ToPlainValues(),\n                timestamp: (DateTimeOffset.UtcNow - _stagePolicy.Lifetime) - timeBuffer\n            );\n\n            Assert.False(_stagePolicy.Stage(_chain, staleTx));\n            Assert.True(_stagePolicy.Stage(_chain, validTx));\n            Assert.False(_stagePolicy.Stage(_chain, validTx));\n            Assert.True(_stagePolicy.Unstage(_chain, validTx.Id));\n            Assert.False(_stagePolicy.Unstage(_chain, validTx.Id));\n        }\n    }\n}\n"
  },
  {
    "path": "test/Libplanet.Tests/Blockchain/Renderers/AnonymousActionRendererTest.cs",
    "content": "using System;\nusing System.Security.Cryptography;\nusing Bencodex.Types;\nusing Libplanet.Action;\nusing Libplanet.Action.State;\nusing Libplanet.Action.Tests.Common;\nusing Libplanet.Blockchain.Renderers;\nusing Libplanet.Common;\nusing Libplanet.Mocks;\nusing Libplanet.Types.Blocks;\nusing Xunit;\n\nnamespace Libplanet.Tests.Blockchain.Renderers\n{\n    public class AnonymousActionRendererTest\n    {\n        private static IValue _action = new DumbAction().PlainValue;\n\n        private static IWorld _world = new World(MockUtil.MockModernWorldState);\n\n        private static ICommittedActionContext _actionContext =\n            new CommittedActionContext(new ActionContext(\n                default,\n                default,\n                default,\n                0,\n                Block.CurrentProtocolVersion,\n                null,\n                _world,\n                default,\n                false,\n                null));\n\n        private static Exception _exception = new Exception();\n\n        private static Block _genesis =\n            TestUtils.ProposeGenesisBlock(TestUtils.GenesisProposer);\n\n        private static Block _blockA =\n            TestUtils.ProposeNextBlock(_genesis, TestUtils.GenesisProposer);\n\n        private static Block _blockB =\n            TestUtils.ProposeNextBlock(_genesis, TestUtils.GenesisProposer);\n\n        [Fact]\n        public void ActionRenderer()\n        {\n            (IValue, ICommittedActionContext, HashDigest<SHA256>)? record = null;\n            var renderer = new AnonymousActionRenderer\n            {\n                ActionRenderer = (action, context, nextState) =>\n                    record = (action, context, nextState),\n            };\n\n            renderer.RenderActionError(_action, _actionContext, _exception);\n            Assert.Null(record);\n            renderer.RenderBlock(_genesis, _blockA);\n            Assert.Null(record);\n\n            renderer.RenderAction(_action, _actionContext, _world.Trie.Hash);\n            Assert.NotNull(record);\n            Assert.Same(_action, record?.Item1);\n            Assert.Same(_actionContext, record?.Item2);\n            Assert.Equal(_world.Trie.Hash, record?.Item3);\n        }\n\n        [Fact]\n        public void ActionErrorRenderer()\n        {\n            (IValue, ICommittedActionContext, Exception)? record = null;\n            var renderer = new AnonymousActionRenderer\n            {\n                ActionErrorRenderer = (action, context, exception) =>\n                    record = (action, context, exception),\n            };\n\n            renderer.RenderAction(_action, _actionContext, _world.Trie.Hash);\n            Assert.Null(record);\n            renderer.RenderBlock(_genesis, _blockA);\n            Assert.Null(record);\n\n            renderer.RenderActionError(_action, _actionContext, _exception);\n            Assert.NotNull(record);\n            Assert.Same(_action, record?.Item1);\n            Assert.Same(_actionContext, record?.Item2);\n            Assert.Same(_exception, record?.Item3);\n        }\n\n        [Fact]\n        public void BlockRenderer()\n        {\n            (Block Old, Block New)? record = null;\n            var renderer = new AnonymousActionRenderer\n            {\n                BlockRenderer = (oldTip, newTip) => record = (oldTip, newTip),\n            };\n\n            renderer.RenderAction(_action, _actionContext, _world.Trie.Hash);\n            Assert.Null(record);\n            renderer.RenderActionError(_action, _actionContext, _exception);\n            Assert.Null(record);\n\n            renderer.RenderBlock(_genesis, _blockA);\n            Assert.NotNull(record);\n            Assert.Same(_genesis, record?.Old);\n            Assert.Same(_blockA, record?.New);\n        }\n    }\n}\n"
  },
  {
    "path": "test/Libplanet.Tests/Blockchain/Renderers/AnonymousRendererTest.cs",
    "content": "using Libplanet.Blockchain.Renderers;\nusing Libplanet.Types.Blocks;\nusing Xunit;\n\nnamespace Libplanet.Tests.Blockchain.Renderers\n{\n    public class AnonymousRendererTest\n    {\n        private static Block _genesis =\n            TestUtils.ProposeGenesisBlock(TestUtils.GenesisProposer);\n\n        private static Block _blockA =\n            TestUtils.ProposeNextBlock(_genesis, TestUtils.GenesisProposer);\n\n        private static Block _blockB =\n            TestUtils.ProposeNextBlock(_genesis, TestUtils.GenesisProposer);\n\n        [Fact]\n        public void BlockRenderer()\n        {\n            (Block Old, Block New)? record = null;\n            var renderer = new AnonymousRenderer\n            {\n                BlockRenderer = (oldTip, newTip) => record = (oldTip, newTip),\n            };\n\n            renderer.RenderBlock(_genesis, _blockA);\n            Assert.NotNull(record);\n            Assert.Same(_genesis, record?.Old);\n            Assert.Same(_blockA, record?.New);\n        }\n    }\n}\n"
  },
  {
    "path": "test/Libplanet.Tests/Blockchain/Renderers/LoggedActionRendererTest.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Globalization;\nusing System.Linq;\nusing System.Security.Cryptography;\nusing Bencodex.Types;\nusing Libplanet.Action;\nusing Libplanet.Action.State;\nusing Libplanet.Action.Tests.Common;\nusing Libplanet.Blockchain.Renderers;\nusing Libplanet.Common;\nusing Libplanet.Mocks;\nusing Libplanet.Types.Blocks;\nusing Serilog;\nusing Serilog.Events;\nusing Serilog.Sinks.TestCorrelator;\nusing Xunit;\nusing Constants = Serilog.Core.Constants;\n\nnamespace Libplanet.Tests.Blockchain.Renderers\n{\n    public class LoggedActionRendererTest : IDisposable\n    {\n        private static IValue _action = new DumbAction().PlainValue;\n\n        private static IWorld _world = new World(MockUtil.MockModernWorldState);\n\n        private static Block _genesis =\n            TestUtils.ProposeGenesisBlock(TestUtils.GenesisProposer);\n\n        private static Block _blockA =\n            TestUtils.ProposeNextBlock(_genesis, TestUtils.GenesisProposer);\n\n        private static Block _blockB =\n            TestUtils.ProposeNextBlock(_genesis, TestUtils.GenesisProposer);\n\n        private ILogger _logger;\n\n        private ITestCorrelatorContext _context;\n\n        public LoggedActionRendererTest()\n        {\n            _logger = new LoggerConfiguration()\n                .MinimumLevel.Verbose()\n                .WriteTo.TestCorrelator()\n                .CreateLogger();\n            _context = TestCorrelator.CreateContext();\n        }\n\n        public IEnumerable<LogEvent> LogEvents =>\n            TestCorrelator.GetLogEventsFromContextGuid(_context.Guid);\n\n        public void Dispose()\n        {\n            _context.Dispose();\n        }\n\n        [Theory]\n        [InlineData(false, false)]\n        [InlineData(true, false)]\n        [InlineData(false, true)]\n        [InlineData(true, true)]\n        public void ActionRenderings(bool error, bool exception)\n        {\n            bool called = false;\n            LogEvent firstLog = null;\n            ICommittedActionContext actionContext =\n                new CommittedActionContext(new ActionContext(\n                    default,\n                    default,\n                    default,\n                    123,\n                    Block.CurrentProtocolVersion,\n                    // LastCommit should not be null if the block index is not 0, just for testing\n                    null,\n                    _world,\n                    default,\n                    false,\n                    null));\n            Exception actionError = new Exception();\n            IActionRenderer actionRenderer;\n            if (error)\n            {\n                Action<IValue, ICommittedActionContext, Exception> render = (action, cxt, e) =>\n                {\n                    LogEvent[] logs = LogEvents.ToArray();\n                    Assert.Single(logs);\n                    firstLog = logs[0];\n                    Assert.Same(_action, action);\n                    Assert.Same(actionContext, cxt);\n                    Assert.Same(actionError, e);\n                    called = true;\n                    if (exception)\n                    {\n                        throw new ThrowException.SomeException(string.Empty);\n                    }\n                };\n                actionRenderer = new AnonymousActionRenderer\n                {\n                    ActionErrorRenderer = render,\n                };\n            }\n            else\n            {\n                Action<IValue, ICommittedActionContext, HashDigest<SHA256>> render =\n                    (action, cxt, next) =>\n                    {\n                        LogEvent[] logs = LogEvents.ToArray();\n                        Assert.Single(logs);\n                        firstLog = logs[0];\n                        Assert.Same(_action, action);\n                        Assert.Same(actionContext, cxt);\n                        Assert.Equal(_world.Trie.Hash, next);\n                        called = true;\n                        if (exception)\n                        {\n                            throw new ThrowException.SomeException(string.Empty);\n                        }\n                    };\n                actionRenderer = new AnonymousActionRenderer\n                {\n                    ActionRenderer = render,\n                };\n            }\n\n            actionRenderer = new LoggedActionRenderer(\n                actionRenderer,\n                _logger,\n                LogEventLevel.Information\n            );\n            Assert.False(called);\n            Assert.Empty(LogEvents);\n\n            actionRenderer.RenderBlock(_genesis, _blockA);\n            Assert.False(called);\n            Assert.Equal(2, LogEvents.Count());\n            ResetContext();\n\n            ThrowException.SomeException thrownException = null;\n            try\n            {\n                if (error)\n                {\n                    actionRenderer.RenderActionError(_action, actionContext, actionError);\n                }\n                else\n                {\n                    actionRenderer.RenderAction(_action, actionContext, _world.Trie.Hash);\n                }\n            }\n            catch (ThrowException.SomeException e)\n            {\n                thrownException = e;\n            }\n\n            if (exception)\n            {\n                Assert.NotNull(thrownException);\n                Assert.IsType<ThrowException.SomeException>(thrownException);\n            }\n            else\n            {\n                Assert.Null(thrownException);\n            }\n\n            Assert.True(called);\n            LogEvent[] logEvents = LogEvents.ToArray();\n            Assert.Equal(2, logEvents.Length);\n            Assert.Equal(firstLog, logEvents[0]);\n            Assert.Equal(LogEventLevel.Information, firstLog.Level);\n            const string expected1stLog =\n                \"Invoking {MethodName}() for an action {ActionType} at block #{BlockIndex}...\";\n            Assert.Equal(\n                expected1stLog,\n                firstLog.MessageTemplate.Text\n            );\n            string methodName =\n                \"Render\" + \"Action\" + (error ? \"Error\" : string.Empty);\n            Assert.Equal($\"\\\"{methodName}\\\"\", firstLog.Properties[\"MethodName\"].ToString());\n            Assert.Equal(\n                actionContext.BlockIndex.ToString(CultureInfo.InvariantCulture),\n                firstLog.Properties[\"BlockIndex\"].ToString()\n            );\n            Assert.Equal(\n                $\"\\\"{typeof(AnonymousActionRenderer).FullName}\\\"\",\n                firstLog.Properties[Constants.SourceContextPropertyName].ToString()\n            );\n            Assert.Null(firstLog.Exception);\n            Assert.False(firstLog.Properties.ContainsKey(\"Rehearsal\"));\n\n            LogEvent secondLog = logEvents[1];\n            Assert.Equal(\n                exception ? LogEventLevel.Error : LogEventLevel.Information,\n                secondLog.Level\n            );\n            string expected2ndLog;\n            if (exception)\n            {\n                expected2ndLog =\n                    \"An exception was thrown during {MethodName}() for an action {ActionType} at \" +\n                    \"block #{BlockIndex}\";\n            }\n            else\n            {\n                expected2ndLog =\n                    \"Invoked {MethodName}() for an action {ActionType} at block #{BlockIndex}\";\n            }\n\n            Assert.Equal(\n                expected2ndLog,\n                secondLog.MessageTemplate.Text\n            );\n            Assert.Equal(firstLog.Properties[\"MethodName\"], secondLog.Properties[\"MethodName\"]);\n            Assert.Equal(firstLog.Properties[\"ActionType\"], secondLog.Properties[\"ActionType\"]);\n            Assert.Equal(firstLog.Properties[\"BlockIndex\"], secondLog.Properties[\"BlockIndex\"]);\n            Assert.Equal(\n                firstLog.Properties[Constants.SourceContextPropertyName],\n                secondLog.Properties[Constants.SourceContextPropertyName]\n            );\n            if (exception)\n            {\n                Assert.IsType<ThrowException.SomeException>(secondLog.Exception);\n            }\n            else\n            {\n                Assert.Null(secondLog.Exception);\n            }\n\n            Assert.False(firstLog.Properties.ContainsKey(\"Rehearsal\"));\n        }\n\n        [Theory]\n        [InlineData(false, false)]\n        [InlineData(false, true)]\n        [InlineData(true, false)]\n        [InlineData(true, true)]\n        public void RenderBlock(bool end, bool exception)\n        {\n            bool called = false;\n            LogEvent firstLog = null;\n\n            void Callback(Block oldTip, Block newTip)\n            {\n                LogEvent[] logs = LogEvents.ToArray();\n                Assert.Single(logs);\n                firstLog = logs[0];\n                Assert.Equal(_genesis, oldTip);\n                Assert.Equal(_blockA, newTip);\n                called = true;\n                if (exception)\n                {\n                    throw new ThrowException.SomeException(string.Empty);\n                }\n            }\n\n            IActionRenderer actionRenderer = new AnonymousActionRenderer\n            {\n                BlockRenderer = end ? (Action<Block, Block>)null : Callback,\n                BlockEndRenderer = end ? Callback : (Action<Block, Block>)null,\n            };\n            actionRenderer = new LoggedActionRenderer(actionRenderer, _logger);\n            var invoke = end\n                ? (Action<Block, Block>)actionRenderer.RenderBlockEnd\n                : actionRenderer.RenderBlock;\n            var invokeOpposite = end\n                ? (Action<Block, Block>)actionRenderer.RenderBlock\n                : actionRenderer.RenderBlockEnd;\n            var methodName = end ? \"RenderBlockEnd\" : \"RenderBlock\";\n\n            Assert.False(called);\n            Assert.Empty(LogEvents);\n\n            invokeOpposite(_genesis, _blockA);\n            Assert.False(called);\n            Assert.Equal(2, LogEvents.Count());\n            ResetContext();\n\n            if (exception)\n            {\n                Assert.Throws<ThrowException.SomeException>(\n                    () => invoke(_genesis, _blockA)\n                );\n            }\n            else\n            {\n                invoke(_genesis, _blockA);\n            }\n\n            Assert.True(called);\n            LogEvent[] logEvents = LogEvents.ToArray();\n            Assert.Equal(2, logEvents.Length);\n            Assert.Equal(firstLog, logEvents[0]);\n            Assert.Equal(LogEventLevel.Debug, firstLog.Level);\n            Assert.Equal(\n                \"Invoking {MethodName}() for #{NewIndex} {NewHash} (was #{OldIndex} {OldHash})...\",\n                firstLog.MessageTemplate.Text\n            );\n            Assert.Equal($\"\\\"{methodName}\\\"\", firstLog.Properties[\"MethodName\"].ToString());\n            Assert.Equal(\n                _blockA.Index.ToString(CultureInfo.InvariantCulture),\n                firstLog.Properties[\"NewIndex\"].ToString()\n            );\n            Assert.Equal($\"\\\"{_blockA.Hash}\\\"\", firstLog.Properties[\"NewHash\"].ToString());\n            Assert.Equal(\n                _genesis.Index.ToString(CultureInfo.InvariantCulture),\n                firstLog.Properties[\"OldIndex\"].ToString()\n            );\n            Assert.Equal($\"\\\"{_genesis.Hash}\\\"\", firstLog.Properties[\"OldHash\"].ToString());\n            Assert.Equal(\n                $\"\\\"{typeof(AnonymousActionRenderer).FullName}\\\"\",\n                firstLog.Properties[Constants.SourceContextPropertyName].ToString()\n            );\n            Assert.Null(firstLog.Exception);\n\n            LogEvent secondLog = logEvents[1];\n            Assert.Equal(\n                exception ? LogEventLevel.Error : LogEventLevel.Debug,\n                secondLog.Level\n            );\n            Assert.Equal(\n                exception\n                    ? \"An exception was thrown during {MethodName}() for #{NewIndex} {NewHash} \" +\n                        \"(was #{OldIndex} {OldHash})\"\n                    : \"Invoked {MethodName}() for #{NewIndex} {NewHash} \" +\n                        \"(was #{OldIndex} {OldHash})\",\n                secondLog.MessageTemplate.Text\n            );\n            Assert.Equal(firstLog.Properties[\"MethodName\"], secondLog.Properties[\"MethodName\"]);\n            Assert.Equal(firstLog.Properties[\"NewIndex\"], secondLog.Properties[\"NewIndex\"]);\n            Assert.Equal(firstLog.Properties[\"NewHash\"], secondLog.Properties[\"NewHash\"]);\n            Assert.Equal(firstLog.Properties[\"OldIndex\"], secondLog.Properties[\"OldIndex\"]);\n            Assert.Equal(firstLog.Properties[\"OldHash\"], secondLog.Properties[\"OldHash\"]);\n            Assert.Equal(\n                firstLog.Properties[Constants.SourceContextPropertyName],\n                secondLog.Properties[Constants.SourceContextPropertyName]\n            );\n            if (exception)\n            {\n                Assert.IsType<ThrowException.SomeException>(secondLog.Exception);\n            }\n            else\n            {\n                Assert.Null(secondLog.Exception);\n            }\n        }\n\n        private void ResetContext()\n        {\n            _context.Dispose();\n            _context = TestCorrelator.CreateContext();\n        }\n    }\n}\n"
  },
  {
    "path": "test/Libplanet.Tests/Blockchain/Renderers/LoggedRendererTest.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Globalization;\nusing System.Linq;\nusing Libplanet.Action.Tests.Common;\nusing Libplanet.Blockchain.Renderers;\nusing Serilog;\nusing Serilog.Events;\nusing Serilog.Sinks.TestCorrelator;\nusing Xunit;\nusing Constants = Serilog.Core.Constants;\nusing DumbBlock = Libplanet.Types.Blocks.Block;\n\nnamespace Libplanet.Tests.Blockchain.Renderers\n{\n    public class LoggedRendererTest : IDisposable\n    {\n        private static DumbBlock _genesis =\n            TestUtils.ProposeGenesisBlock(TestUtils.GenesisProposer);\n\n        private static DumbBlock _blockA =\n            TestUtils.ProposeNextBlock(_genesis, TestUtils.GenesisProposer);\n\n        private static DumbBlock _blockB =\n            TestUtils.ProposeNextBlock(_genesis, TestUtils.GenesisProposer);\n\n        private ILogger _logger;\n\n        private ITestCorrelatorContext _context;\n\n        public LoggedRendererTest()\n        {\n            _logger = new LoggerConfiguration()\n                .MinimumLevel.Verbose()\n                .WriteTo.TestCorrelator()\n                .CreateLogger();\n            _context = TestCorrelator.CreateContext();\n        }\n\n        public IEnumerable<LogEvent> LogEvents =>\n            TestCorrelator.GetLogEventsFromContextGuid(_context.Guid);\n\n        public void Dispose()\n        {\n            _context.Dispose();\n        }\n\n        [Theory]\n        [InlineData(false)]\n        [InlineData(true)]\n        public void RenderBlock(bool exception)\n        {\n            bool called = false;\n            LogEvent firstLog = null;\n\n            IRenderer renderer = new AnonymousRenderer\n            {\n                BlockRenderer = (oldTip, newTip) =>\n                {\n                    LogEvent[] logs = LogEvents.ToArray();\n                    Assert.Single(logs);\n                    firstLog = logs[0];\n                    Assert.Equal(_genesis, oldTip);\n                    Assert.Equal(_blockA, newTip);\n                    called = true;\n                    if (exception)\n                    {\n                        throw new ThrowException.SomeException(string.Empty);\n                    }\n                },\n            };\n            renderer = new LoggedRenderer(renderer, _logger);\n\n            Assert.False(called);\n            Assert.Empty(LogEvents);\n\n            if (exception)\n            {\n                Assert.Throws<ThrowException.SomeException>(\n                    () => renderer.RenderBlock(_genesis, _blockA)\n                );\n            }\n            else\n            {\n                renderer.RenderBlock(_genesis, _blockA);\n            }\n\n            Assert.True(called);\n            LogEvent[] logEvents = LogEvents.ToArray();\n            Assert.Equal(2, logEvents.Length);\n            Assert.Equal(firstLog, logEvents[0]);\n            Assert.Equal(LogEventLevel.Debug, firstLog.Level);\n            Assert.Equal(\n                \"Invoking {MethodName}() for #{NewIndex} {NewHash} (was #{OldIndex} {OldHash})...\",\n                firstLog.MessageTemplate.Text\n            );\n            Assert.Equal(\"\\\"RenderBlock\\\"\", firstLog.Properties[\"MethodName\"].ToString());\n            Assert.Equal(\n                _blockA.Index.ToString(CultureInfo.InvariantCulture),\n                firstLog.Properties[\"NewIndex\"].ToString()\n            );\n            Assert.Equal($\"\\\"{_blockA.Hash}\\\"\", firstLog.Properties[\"NewHash\"].ToString());\n            Assert.Equal(\n                _genesis.Index.ToString(CultureInfo.InvariantCulture),\n                firstLog.Properties[\"OldIndex\"].ToString()\n            );\n            Assert.Equal($\"\\\"{_genesis.Hash}\\\"\", firstLog.Properties[\"OldHash\"].ToString());\n            Assert.Equal(\n                $\"\\\"{typeof(AnonymousRenderer).FullName}\\\"\",\n                firstLog.Properties[Constants.SourceContextPropertyName].ToString()\n            );\n            Assert.Null(firstLog.Exception);\n\n            LogEvent secondLog = logEvents[1];\n            Assert.Equal(\n                exception ? LogEventLevel.Error : LogEventLevel.Debug,\n                secondLog.Level\n            );\n            Assert.Equal(\n                exception\n                    ? \"An exception was thrown during {MethodName}() for #{NewIndex} {NewHash} \" +\n                        \"(was #{OldIndex} {OldHash})\"\n                    : \"Invoked {MethodName}() for #{NewIndex} {NewHash} \" +\n                        \"(was #{OldIndex} {OldHash})\",\n                secondLog.MessageTemplate.Text\n            );\n            Assert.Equal(firstLog.Properties[\"MethodName\"], secondLog.Properties[\"MethodName\"]);\n            Assert.Equal(firstLog.Properties[\"NewIndex\"], secondLog.Properties[\"NewIndex\"]);\n            Assert.Equal(firstLog.Properties[\"NewHash\"], secondLog.Properties[\"NewHash\"]);\n            Assert.Equal(firstLog.Properties[\"OldIndex\"], secondLog.Properties[\"OldIndex\"]);\n            Assert.Equal(firstLog.Properties[\"OldHash\"], secondLog.Properties[\"OldHash\"]);\n            Assert.Equal(\n                firstLog.Properties[Constants.SourceContextPropertyName],\n                secondLog.Properties[Constants.SourceContextPropertyName]\n            );\n            if (exception)\n            {\n                Assert.IsType<ThrowException.SomeException>(secondLog.Exception);\n            }\n            else\n            {\n                Assert.Null(secondLog.Exception);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "test/Libplanet.Tests/Blockchain/TotalDifficultyComparerTest.cs",
    "content": ""
  },
  {
    "path": "test/Libplanet.Tests/Blocks/BlockCommitTest.cs",
    "content": "using System;\nusing System.Collections.Immutable;\nusing System.Linq;\nusing System.Numerics;\nusing System.Security.Cryptography;\nusing Libplanet.Common;\nusing Libplanet.Crypto;\nusing Libplanet.Tests.Store;\nusing Libplanet.Types.Blocks;\nusing Libplanet.Types.Consensus;\nusing Xunit;\nusing Xunit.Abstractions;\n\nnamespace Libplanet.Tests.Blocks\n{\n    public class BlockCommitTest\n    {\n        private static readonly Bencodex.Codec _codec = new Bencodex.Codec();\n        private readonly ITestOutputHelper _output;\n\n        public BlockCommitTest(ITestOutputHelper output)\n        {\n            _output = output;\n        }\n\n        [Fact]\n        public void ToHash()\n        {\n            var randomHash = new BlockHash(TestUtils.GetRandomBytes(BlockHash.Size));\n            var keys = Enumerable.Range(0, 4).Select(_ => new PrivateKey()).ToList();\n            var votes = keys.Select((key, index) =>\n                    new VoteMetadata(\n                        1,\n                        0,\n                        randomHash,\n                        DateTimeOffset.UtcNow,\n                        key.PublicKey,\n                        index == 0 ? (BigInteger?)null : BigInteger.One,\n                        VoteFlag.PreCommit).Sign(key))\n                .ToImmutableArray();\n            var blockCommit = new BlockCommit(1, 0, randomHash, votes);\n\n            var commitHash = blockCommit.ToHash();\n            var expected = HashDigest<SHA256>.DeriveFrom(_codec.Encode(blockCommit.Bencoded));\n\n            Assert.Equal(commitHash, expected);\n        }\n\n        [Fact]\n        public void HeightAndRoundMustNotBeNegative()\n        {\n            var hash = new BlockHash(TestUtils.GetRandomBytes(BlockHash.Size));\n            var key = new PrivateKey();\n            var votes = ImmutableArray<Vote>.Empty\n                .Add(\n                    new VoteMetadata(\n                            0,\n                            0,\n                            hash,\n                            DateTimeOffset.UtcNow,\n                            key.PublicKey,\n                            BigInteger.One,\n                            VoteFlag.PreCommit)\n                        .Sign(key));\n\n            // Negative height is not allowed.\n            Assert.Throws<ArgumentOutOfRangeException>(() =>\n                new BlockCommit(-1, 0, hash, votes));\n\n            // Negative round is not allowed.\n            Assert.Throws<ArgumentOutOfRangeException>(() =>\n                new BlockCommit(0, -1, hash, votes));\n        }\n\n        [Fact]\n        public void VotesCannotBeEmpty()\n        {\n            var hash = new BlockHash(TestUtils.GetRandomBytes(BlockHash.Size));\n            Assert.Throws<ArgumentException>(() =>\n                new BlockCommit(0, 0, hash, default));\n            Assert.Throws<ArgumentException>(() =>\n                new BlockCommit(0, 0, hash, ImmutableArray<Vote>.Empty));\n        }\n\n        [Fact]\n        public void EveryVoteMustHaveSameHeightAndRoundAsBlockCommit()\n        {\n            var height = 2;\n            var round = 3;\n            var hash = new BlockHash(TestUtils.GetRandomBytes(BlockHash.Size));\n            var key = new PrivateKey();\n\n            // Vote with different height is not allowed.\n            var votes = ImmutableArray<Vote>.Empty\n                .Add(new VoteMetadata(\n                    height + 1,\n                    round,\n                    hash,\n                    DateTimeOffset.UtcNow,\n                    key.PublicKey,\n                    BigInteger.One,\n                    VoteFlag.PreCommit).Sign(key));\n            Assert.Throws<ArgumentException>(() =>\n                new BlockCommit(height, round, hash, votes));\n\n            // Vote with different round is not allowed.\n            votes = ImmutableArray<Vote>.Empty\n                .Add(new VoteMetadata(\n                    height,\n                    round + 1,\n                    hash,\n                    DateTimeOffset.UtcNow,\n                    key.PublicKey,\n                    BigInteger.One,\n                    VoteFlag.PreCommit).Sign(key));\n            Assert.Throws<ArgumentException>(() =>\n                new BlockCommit(height, round, hash, votes));\n        }\n\n        [Fact]\n        public void EveryVoteMustHaveSameHashAsBlockCommit()\n        {\n            var height = 2;\n            var round = 3;\n            var hash = new BlockHash(TestUtils.GetRandomBytes(BlockHash.Size));\n            var badHash = new BlockHash(TestUtils.GetRandomBytes(BlockHash.Size));\n            var key = new PrivateKey();\n\n            var votes = ImmutableArray<Vote>.Empty\n                .Add(new VoteMetadata(\n                    height,\n                    round,\n                    badHash,\n                    DateTimeOffset.UtcNow,\n                    key.PublicKey,\n                    BigInteger.One,\n                    VoteFlag.PreCommit).Sign(key));\n            Assert.Throws<ArgumentException>(() => new BlockCommit(height, round, hash, votes));\n        }\n\n        [Fact]\n        public void EveryVoteFlagMustBeNullOrPreCommit()\n        {\n            var height = 2;\n            var round = 3;\n            var hash = new BlockHash(TestUtils.GetRandomBytes(BlockHash.Size));\n            var keys = Enumerable.Range(0, 4).Select(_ => new PrivateKey()).ToList();\n            var preCommitVotes = keys.Select(\n                    key => new VoteMetadata(\n                            height,\n                            round,\n                            hash,\n                            DateTimeOffset.UtcNow,\n                            key.PublicKey,\n                            BigInteger.One,\n                            VoteFlag.PreCommit)\n                        .Sign(key))\n                .ToList();\n\n            var votes = ImmutableArray<Vote>.Empty\n                .Add(new VoteMetadata(\n                    height,\n                    round,\n                    hash,\n                    DateTimeOffset.UtcNow,\n                    keys[0].PublicKey,\n                    BigInteger.One,\n                    VoteFlag.Null).Sign(null))\n                .AddRange(preCommitVotes.Skip(1));\n            _ = new BlockCommit(height, round, hash, votes);\n\n            votes = ImmutableArray<Vote>.Empty\n                .Add(new VoteMetadata(\n                    height,\n                    round,\n                    hash,\n                    DateTimeOffset.UtcNow,\n                    keys[0].PublicKey,\n                    BigInteger.One,\n                    VoteFlag.Unknown).Sign(null))\n                .AddRange(preCommitVotes.Skip(1));\n            Assert.Throws<ArgumentException>(() => new BlockCommit(height, round, hash, votes));\n\n            votes = ImmutableArray<Vote>.Empty\n                .Add(new VoteMetadata(\n                    height,\n                    round,\n                    hash,\n                    DateTimeOffset.UtcNow,\n                    keys[0].PublicKey,\n                    BigInteger.One,\n                    VoteFlag.PreVote).Sign(keys[0]))\n                .AddRange(preCommitVotes.Skip(1));\n            Assert.Throws<ArgumentException>(() => new BlockCommit(height, round, hash, votes));\n\n            votes = ImmutableArray<Vote>.Empty\n                .Add(new VoteMetadata(\n                    height,\n                    round,\n                    hash,\n                    DateTimeOffset.UtcNow,\n                    keys[0].PublicKey,\n                    BigInteger.One,\n                    VoteFlag.PreCommit).Sign(keys[0]))\n                .AddRange(preCommitVotes.Skip(1));\n            _ = new BlockCommit(height, round, hash, votes);\n        }\n\n        [Fact]\n        public void Bencoded()\n        {\n            var fx = new MemoryStoreFixture();\n            var keys = Enumerable.Range(0, 4).Select(_ => new PrivateKey()).ToList();\n            var votes = keys.Select(key =>\n                new VoteMetadata(\n                    1,\n                    0,\n                    fx.Hash1,\n                    DateTimeOffset.Now,\n                    key.PublicKey,\n                    BigInteger.One,\n                    VoteFlag.PreCommit).Sign(key))\n                .ToImmutableArray();\n            var expected = new BlockCommit(1, 0, fx.Hash1, votes);\n            var decoded = new BlockCommit(expected.Bencoded);\n            Assert.Equal(expected, decoded);\n        }\n    }\n}\n"
  },
  {
    "path": "test/Libplanet.Tests/Blocks/BlockContentTest.cs",
    "content": "using System;\nusing System.Collections.Immutable;\nusing System.Linq;\nusing System.Security.Cryptography;\nusing Libplanet.Common;\nusing Libplanet.Crypto;\nusing Libplanet.Tests.Fixtures;\nusing Libplanet.Types.Blocks;\nusing Libplanet.Types.Evidence;\nusing Libplanet.Types.Tx;\nusing Xunit;\nusing Xunit.Abstractions;\nusing static Libplanet.Tests.TestUtils;\n\nnamespace Libplanet.Tests.Blocks\n{\n    public class BlockContentTest : BlockContentFixture\n    {\n        private readonly ITestOutputHelper _output;\n\n        public BlockContentTest(ITestOutputHelper output)\n        {\n            _output = output;\n        }\n\n        [Fact]\n        public void CopyConstructors()\n        {\n            var block1 = new BlockContent(\n                Block1Metadata, Block1Content.Transactions, Block1Content.Evidence);\n            AssertBlockContentsEqual(Block1Content, block1);\n\n            Assert.Throws<InvalidBlockTxHashException>(() =>\n                new BlockContent(\n                    metadata: Block1Metadata,\n                    transactions: Array.Empty<Transaction>(),\n                    evidence: Array.Empty<EvidenceBase>())\n            );\n            Assert.Throws<InvalidBlockTxHashException>(\n                () => new BlockContent(\n                    metadata: Block1Metadata,\n                    transactions: new[] { Block1Tx0 },\n                    evidence: Array.Empty<EvidenceBase>())\n            );\n            Assert.Throws<InvalidBlockEvidenceHashException>(() =>\n                new BlockContent(\n                    metadata: Block1Metadata,\n                    transactions: Block1Content.Transactions,\n                    evidence: Array.Empty<EvidenceBase>())\n            );\n            Assert.Throws<InvalidBlockEvidenceHashException>(\n                () => new BlockContent(\n                    metadata: Block1Metadata,\n                    transactions: Block1Content.Transactions,\n                    evidence: Array.Empty<EvidenceBase>())\n            );\n        }\n\n        [Fact]\n        public void Transactions()\n        {\n            var key = PrivateKey.FromString(\n                \"ea0493b0ed67fc97b2e5e85a1d145adea294112f09df15398cb10f2ed5ad1a83\"\n            );\n            var tx2 = new Transaction(\n                new UnsignedTx(\n                    new TxInvoice(\n                        genesisHash: GenesisHash,\n                        timestamp: new DateTimeOffset(\n                            2021, 9, 7, 10, 23, 12, 345, default)\n                    ),\n                    new TxSigningMetadata(key.PublicKey, nonce: 0)\n                ),\n                signature: ByteUtil.ParseHexToImmutable(\n                    \"304402202a8324c83390b1fe0fdd4014056a049bc02ca059369ef62145fe574cb31224f\" +\n                    \"d022073bf8a48403cf46f5fa63f26f3e8ef4db8ef1d841684856da63d9b7eeb91759a\"\n                )\n            );\n            var txs = new[] { tx2, Block1Tx0, Block1Tx1 }.OrderBy(tx => tx.Id).ToImmutableList();\n            var evs = Array.Empty<EvidenceBase>();\n            var blockContent = new BlockContent(\n                new BlockMetadata(\n                    index: Block1Content.Index,\n                    timestamp: DateTimeOffset.UtcNow,\n                    publicKey: Block1Content.PublicKey,\n                    previousHash: Block1Content.PreviousHash,\n                    txHash: BlockContent.DeriveTxHash(txs),\n                    lastCommit: null,\n                    evidenceHash: null),\n                transactions: txs,\n                evidence: evs);\n            Assert.Equal(\n                new[] { Block1Tx1.Id, Block1Tx0.Id, tx2.Id },\n                blockContent.Transactions.Select(tx => tx.Id).ToArray());\n        }\n\n        [Fact]\n        public void TransactionsWithDuplicateNonce()\n        {\n            var dupTx1 = new Transaction(\n                new UnsignedTx(\n                    new TxInvoice(\n                        genesisHash: GenesisHash,\n                        updatedAddresses: new AddressSet(new[] { Block1Tx1.Signer }),\n                        timestamp: Block1Tx1.Timestamp,\n                        actions: TxActionList.Empty,\n                        maxGasPrice: null,\n                        gasLimit: null),\n                    new TxSigningMetadata(Block1Tx1.PublicKey, nonce: 1L)\n                ),\n                signature: ByteUtil.ParseHexToImmutable(\n                    \"304502210099e580e8599acf0b26ad0a80315f2d488703ffde01e9449b4bf399593b8cc\" +\n                    \"e63022002feb21bf0e4d76d25d17c8c1c4fbb3dfbda986e0693f984fbb302183ab7ece1\"\n                )\n            );\n            var txs = new[] { Block1Tx0, Block1Tx1, dupTx1 }.OrderBy(tx => tx.Id).ToArray();\n            var evs = Array.Empty<EvidenceBase>();\n            InvalidTxNonceException e = Assert.Throws<InvalidTxNonceException>(\n                () => new BlockContent(\n                    new BlockMetadata(\n                        index: Block1Content.Index,\n                        timestamp: DateTimeOffset.UtcNow,\n                        publicKey: Block1Content.PublicKey,\n                        previousHash: Block1Content.PreviousHash,\n                        txHash: BlockContent.DeriveTxHash(txs),\n                        lastCommit: null,\n                        evidenceHash: null),\n                    transactions: txs,\n                    evidence: evs));\n            Assert.Equal(Block1Tx1.Id, e.TxId);\n            Assert.Equal(2L, e.ExpectedNonce);\n            Assert.Equal(Block1Tx1.Nonce, e.ImproperNonce);\n        }\n\n        [Fact]\n        public void TransactionsWithMissingNonce()\n        {\n            var dupTx1 = new Transaction(\n                new UnsignedTx(\n                    new TxInvoice(\n                        genesisHash: GenesisHash,\n                        updatedAddresses: new AddressSet(new[] { Block1Tx1.Signer }),\n                        timestamp: Block1Tx1.Timestamp,\n                        actions: TxActionList.Empty,\n                        maxGasPrice: null,\n                        gasLimit: null),\n                    new TxSigningMetadata(Block1Tx1.PublicKey, nonce: 3L)\n                ),\n                signature: ByteUtil.ParseHexToImmutable(\n                    \"3045022100bfdf79427028efea9449ad46fbf46d5a806694aa5bbab1a01f4c76b21acd\" +\n                    \"cb16022057c851a01dd74797121385ccfc81e7b33842941189154b4d46d05e891a28e3eb\"\n                )\n            );\n            var txs = new[] { Block1Tx0, Block1Tx1, dupTx1 }.OrderBy(tx => tx.Id).ToArray();\n            var evs = Array.Empty<EvidenceBase>();\n            InvalidTxNonceException e = Assert.Throws<InvalidTxNonceException>(\n                () => new BlockContent(\n                    new BlockMetadata(\n                        index: Block1Content.Index,\n                        timestamp: DateTimeOffset.UtcNow,\n                        publicKey: Block1Content.PublicKey,\n                        previousHash: Block1Content.PreviousHash,\n                        txHash: BlockContent.DeriveTxHash(txs),\n                        lastCommit: null,\n                        evidenceHash: null),\n                    transactions: txs,\n                    evidence: evs));\n            Assert.Equal(dupTx1.Id, e.TxId);\n            Assert.Equal(2L, e.ExpectedNonce);\n            Assert.Equal(dupTx1.Nonce, e.ImproperNonce);\n        }\n\n        [Fact]\n        public void TransactionsWithInconsistentGenesisHashes()\n        {\n            var key = PrivateKey.FromString(\n                \"2ed05de0b35d93e4ae801ae40c8bb4257a771ff67c1e5d1754562e4191953710\"\n            );\n            var differentGenesisHash = BlockHash.FromString(\n                \"76942b42f99c28da02ed916ebd2fadb189415e8288a4bd87f9ae3594127b79e6\"\n            );\n            var txWithDifferentGenesis = new Transaction(\n                new UnsignedTx(\n                    new TxInvoice(\n                        genesisHash: differentGenesisHash,\n                        timestamp: new DateTimeOffset(\n                            2021, 9, 7, 12, 1, 12, 345, TimeSpan.FromHours(9)),\n                        actions: TxActionList.Empty\n                    ),\n                    new TxSigningMetadata(key.PublicKey, nonce: 0L)\n                ),\n                key\n            );\n            Transaction[] inconsistentTxs =\n                Block1Content.Transactions.Append(txWithDifferentGenesis).ToArray();\n            var evs = Array.Empty<EvidenceBase>();\n            InvalidTxGenesisHashException e = Assert.Throws<InvalidTxGenesisHashException>(\n                () => new BlockContent(\n                    new BlockMetadata(\n                        index: Block1Content.Index,\n                        timestamp: DateTimeOffset.UtcNow,\n                        publicKey: Block1Content.PublicKey,\n                        previousHash: Block1Content.PreviousHash,\n                        txHash: BlockContent.DeriveTxHash(inconsistentTxs),\n                        lastCommit: null,\n                        evidenceHash: null),\n                    transactions: inconsistentTxs,\n                    evidence: evs));\n            Assert.Equal(Block1Content.Transactions[0].GenesisHash, e.ExpectedGenesisHash);\n            Assert.Equal(differentGenesisHash, e.ImproperGenesisHash);\n        }\n\n        [Fact]\n        public void TxHash()\n        {\n            var expected = new HashDigest<SHA256>(new byte[]\n            {\n                0x65, 0x46, 0x98, 0xd3, 0x4b, 0x6d, 0x9a, 0x55, 0xb0, 0xc9, 0x3e,\n                0x4f, 0xfb, 0x26, 0x39, 0x27, 0x83, 0x24, 0x86, 0x8c, 0x91, 0x96,\n                0x5b, 0xc5, 0xf9, 0x6c, 0xb3, 0x07, 0x1d, 0x69, 0x03, 0xa0,\n            });\n            AssertBytesEqual(expected, Block1Content.TxHash);\n            Assert.Null(GenesisContentPv0.TxHash);\n        }\n\n        [Fact]\n        public void DeriveTxHash()\n        {\n            Assert.Null(\n                BlockContent.DeriveTxHash(Array.Empty<Transaction>())\n            );\n            AssertBytesEqual(\n                Block1Metadata.TxHash,\n                BlockContent.DeriveTxHash(Block1Content.Transactions)\n            );\n            Assert.Throws<ArgumentException>(\n                () => BlockContent.DeriveTxHash(Block1Content.Transactions.Reverse())\n            );\n        }\n    }\n}\n"
  },
  {
    "path": "test/Libplanet.Tests/Blocks/BlockFixture.cs",
    "content": "using System.Collections.Generic;\nusing System.Collections.Immutable;\nusing System.Security.Cryptography;\nusing Libplanet.Common;\nusing Libplanet.Crypto;\nusing Libplanet.Tests.Tx;\nusing Libplanet.Types.Blocks;\nusing Libplanet.Types.Consensus;\nusing Libplanet.Types.Evidence;\nusing Libplanet.Types.Tx;\n\nnamespace Libplanet.Tests.Blocks\n{\n    public class BlockFixture\n    {\n        public const int ProtocolVersion = BlockMetadata.CurrentProtocolVersion;\n\n        public BlockFixture()\n        {\n            Miner = TestUtils.GenesisProposer;\n            Genesis = TestUtils.ProposeGenesisBlock(\n                protocolVersion: ProtocolVersion,\n                miner: Miner,\n                stateRootHash: HashDigest<SHA256>.FromString(\n                    \"e2e938f9d8af0a20d16d1c233fc4e8f39157145d003565807e4055ce6b5a0121\")\n            );\n            TxFixture = new TxFixture(Genesis.Hash);\n            Next = TestUtils.ProposeNextBlock(\n                Genesis,\n                miner: Miner,\n                protocolVersion: ProtocolVersion,\n                stateRootHash: HashDigest<SHA256>.FromString(\n                    \"6a648da9e91c21aa22bdae4e35c338406392aad0db4a0f998c01a7d7973cb8aa\"),\n                lastCommit: null,\n                evidence: ImmutableArray<EvidenceBase>.Empty\n            );\n            HasTx = TestUtils.ProposeNextBlock(\n                Next,\n                miner: Miner,\n                txs: new List<Transaction>\n                {\n                    TxFixture.TxWithActions,\n                },\n                protocolVersion: ProtocolVersion,\n                stateRootHash: HashDigest<SHA256>.FromString(\n                    \"aaeda4f1a6a4aee7fc9a29014cff005109176e83a8e5d28876f2d889680e6421\"),\n                lastCommit: new BlockCommit(\n                    height: Next.Index,\n                    round: 0,\n                    blockHash: Next.Hash,\n                    votes: new[]\n                    {\n                        new VoteMetadata(\n                            Next.Index,\n                            0,\n                            Next.Hash,\n                            Next.Timestamp,\n                            Miner.PublicKey,\n                            TestUtils.ValidatorSet.GetValidator(Miner.PublicKey).Power,\n                            VoteFlag.PreCommit).Sign(Miner),\n                    }.ToImmutableArray()),\n                evidence: ImmutableArray<EvidenceBase>.Empty\n            );\n        }\n\n        internal TxFixture TxFixture { get; }\n\n        internal PrivateKey Miner { get; }\n\n        internal Block Genesis { get; }\n\n        internal Block Next { get; }\n\n        internal Block HasTx { get; }\n    }\n}\n"
  },
  {
    "path": "test/Libplanet.Tests/Blocks/BlockHashTest.cs",
    "content": "using System;\nusing System.Collections.Immutable;\nusing System.Security.Cryptography;\nusing Libplanet.Common;\nusing Libplanet.Types.Blocks;\nusing Xunit;\nusing static Libplanet.Tests.TestUtils;\n\nnamespace Libplanet.Tests.Blocks\n{\n    public class BlockHashTest\n    {\n        [Fact]\n        public void DefaultConstructor()\n        {\n            BlockHash def = default;\n            AssertBytesEqual(new byte[32].ToImmutableArray(), def.ByteArray);\n            AssertBytesEqual(new byte[32], def.ToByteArray());\n        }\n\n        [Fact]\n        public void LengthCheck()\n        {\n            Assert.Throws<ArgumentOutOfRangeException>(() => new BlockHash(new byte[0]));\n            Assert.Throws<ArgumentOutOfRangeException>(() => new BlockHash(new byte[1]));\n            Assert.Throws<ArgumentOutOfRangeException>(() => new BlockHash(new byte[31]));\n            Assert.Throws<ArgumentOutOfRangeException>(() => new BlockHash(new byte[33]));\n        }\n\n        [Fact]\n        public void FromString()\n        {\n            byte[] b =\n            {\n                0x28, 0x31, 0xd4, 0xc2, 0x4a, 0xe5, 0xd1, 0x93, 0x1a, 0x16, 0xde,\n                0x0a, 0x06, 0x6e, 0x23, 0x3e, 0x0e, 0xed, 0x1d, 0x3f, 0xdf, 0x6d,\n                0x57, 0x2a, 0xd5, 0x8d, 0x1c, 0x37, 0x05, 0xc8, 0xcb, 0xfc,\n            };\n            var expected = new BlockHash(b);\n            BlockHash actual = BlockHash.FromString(\n                \"2831d4c24ae5d1931a16de0a066e233e0eed1d3fdf6d572ad58d1c3705c8cbfc\"\n            );\n            Assert.Equal(expected, actual);\n\n            Assert.Throws<ArgumentNullException>(() => BlockHash.FromString(null));\n            Assert.Throws<ArgumentOutOfRangeException>(() => BlockHash.FromString(string.Empty));\n            Assert.Throws<ArgumentOutOfRangeException>(() => BlockHash.FromString(\"abc\"));\n            Assert.Throws<ArgumentOutOfRangeException>(() => BlockHash.FromString(\"ab\"));\n            Assert.Throws<ArgumentOutOfRangeException>(() =>\n                BlockHash.FromString(\n                    \"2831d4c24ae5d1931a16de0a066e233e0eed1d3fdf6d572ad58d1c3705c8cb\"\n                )\n            );\n            Assert.Throws<ArgumentOutOfRangeException>(() =>\n                BlockHash.FromString(\n                    \"2831d4c24ae5d1931a16de0a066e233e0eed1d3fdf6d572ad58d1c3705c8cbfc00\"\n                )\n            );\n            Assert.Throws<FormatException>(() => BlockHash.FromString(\"asdf\"));\n        }\n\n        [Fact]\n        public void FromHashDigest()\n        {\n            byte[] b =\n            {\n                0x28, 0x31, 0xd4, 0xc2, 0x4a, 0xe5, 0xd1, 0x93, 0x1a, 0x16, 0xde,\n                0x0a, 0x06, 0x6e, 0x23, 0x3e, 0x0e, 0xed, 0x1d, 0x3f, 0xdf, 0x6d,\n                0x57, 0x2a, 0xd5, 0x8d, 0x1c, 0x37, 0x05, 0xc8, 0xcb, 0xfc,\n            };\n            var expected = new BlockHash(b);\n            BlockHash actual = BlockHash.FromHashDigest(new HashDigest<SHA256>(b));\n            Assert.Equal(expected, actual);\n\n            Assert.Equal(\n                new BlockHash(new byte[32]),\n                BlockHash.FromHashDigest(default)\n            );\n        }\n\n        [Fact]\n        public void DeriveFrom()\n        {\n            byte[] foo = { 0x66, 0x6f, 0x6f }, bar = { 0x62, 0x61, 0x72 };\n            AssertBytesEqual(\n                BlockHash.FromString(\n                    \"2c26b46b68ffc68ff99b453c1d30413413422d706483bfa0f98a5e886266e7ae\"),\n                BlockHash.DeriveFrom(foo)\n            );\n            AssertBytesEqual(\n                BlockHash.FromString(\n                    \"fcde2b2edba56bf408601fb721fe9b5c338d10ee429ea04fae5511b68fbf8fb9\"),\n                BlockHash.DeriveFrom(bar)\n            );\n        }\n\n        [Fact]\n        public void FromImmutableArrayConstructor()\n        {\n            byte[] b =\n            {\n                0x28, 0x31, 0xd4, 0xc2, 0x4a, 0xe5, 0xd1, 0x93, 0x1a, 0x16, 0xde,\n                0x0a, 0x06, 0x6e, 0x23, 0x3e, 0x0e, 0xed, 0x1d, 0x3f, 0xdf, 0x6d,\n                0x57, 0x2a, 0xd5, 0x8d, 0x1c, 0x37, 0x05, 0xc8, 0xcb, 0xfc,\n            };\n            var bAsArray = b.ToImmutableArray();\n\n            var expected = new BlockHash(b);\n            var actual = new BlockHash(bAsArray);\n            Assert.Equal(expected, actual);\n        }\n\n        [SkippableFact]\n        public void JsonSerialization()\n        {\n            BlockHash hash = BlockHash.FromString(\n                \"2c26b46b68ffc68ff99b453c1d30413413422d706483bfa0f98a5e886266e7ae\");\n            AssertJsonSerializable(\n                hash,\n                \"\\\"2c26b46b68ffc68ff99b453c1d30413413422d706483bfa0f98a5e886266e7ae\\\"\"\n            );\n        }\n    }\n}\n"
  },
  {
    "path": "test/Libplanet.Tests/Blocks/BlockHeaderTest.cs",
    "content": "using System;\nusing System.Collections.Immutable;\nusing System.Security.Cryptography;\nusing Libplanet.Common;\nusing Libplanet.Types.Blocks;\nusing Xunit;\nusing static Libplanet.Tests.TestUtils;\n\nnamespace Libplanet.Tests.Blocks\n{\n    public class BlockHeaderTest : IClassFixture<BlockFixture>\n    {\n        private BlockFixture _fx;\n\n        public BlockHeaderTest(BlockFixture fixture) => _fx = fixture;\n\n        [Fact]\n        public void Constructors()\n        {\n            Block[] fixtures = { _fx.Genesis, _fx.Next, _fx.HasTx };\n            foreach (Block fx in fixtures)\n            {\n                var preEval = new PreEvaluationBlockHeader(fx);\n                var header = new BlockHeader(preEval, (fx.StateRootHash, fx.Signature, fx.Hash));\n                AssertBytesEqual(header.Hash, fx.Hash);\n                AssertPreEvaluationBlockHeadersEqual(fx, header);\n                AssertBytesEqual(fx.StateRootHash, header.StateRootHash);\n\n                Assert.Throws<InvalidBlockHashException>(() =>\n                    new BlockHeader(preEval, (fx.StateRootHash, fx.Signature, default))\n                );\n            }\n        }\n\n        [Fact]\n        public void ValidateSignature()\n        {\n            Block fx = _fx.HasTx;\n            var preEval = new PreEvaluationBlockHeader(fx);\n            HashDigest<SHA256> arbitraryHash = new Random().NextHashDigest<SHA256>();\n            ImmutableArray<byte> invalidSig = preEval.MakeSignature(_fx.Miner, arbitraryHash);\n            InvalidBlockSignatureException e = Assert.Throws<InvalidBlockSignatureException>(() =>\n                new BlockHeader(\n                    preEval,\n                    (\n                        fx.StateRootHash,\n                        invalidSig,\n                        preEval.DeriveBlockHash(fx.StateRootHash, invalidSig)\n                    )));\n            Assert.Equal(invalidSig, e.InvalidSignature);\n            Assert.Equal(fx.PublicKey, e.PublicKey);\n\n            BlockHash hashWithInvalidSig = preEval.DeriveBlockHash(arbitraryHash, invalidSig);\n            e = Assert.Throws<InvalidBlockSignatureException>(() =>\n                new BlockHeader(preEval, (fx.StateRootHash, invalidSig, hashWithInvalidSig))\n            );\n            Assert.Equal(invalidSig, e.InvalidSignature);\n            Assert.Equal(fx.PublicKey, e.PublicKey);\n        }\n\n        [Fact]\n        public void ValidateHash()\n        {\n            Block fx = _fx.HasTx;\n            var preEval = new PreEvaluationBlockHeader(fx);\n            ImmutableArray<byte> sig = fx.Signature.Value;\n            HashDigest<SHA256> arbitraryHash = new Random().NextHashDigest<SHA256>();\n            BlockHash invalidHash = preEval.DeriveBlockHash(arbitraryHash, sig);\n            Assert.Throws<InvalidBlockHashException>(() =>\n                new BlockHeader(preEval, (fx.StateRootHash, sig, invalidHash))\n            );\n        }\n\n        [Fact]\n        public void String()\n        {\n            var header = new BlockHeader(\n                new PreEvaluationBlockHeader(_fx.HasTx),\n                (_fx.HasTx.StateRootHash, _fx.HasTx.Signature, _fx.HasTx.Hash));\n            Assert.Equal($\"#{_fx.HasTx.Index} {_fx.HasTx.Hash}\", header.ToString());\n        }\n    }\n}\n"
  },
  {
    "path": "test/Libplanet.Tests/Blocks/BlockMarshalerTest.Legacy.cs",
    "content": "using System.Security.Cryptography;\nusing Libplanet.Common;\nusing Libplanet.Tests.Fixtures;\nusing Libplanet.Types.Blocks;\nusing Xunit;\n\nnamespace Libplanet.Tests.Blocks\n{\n    public partial class BlockMarshalerTest\n    {\n        [Fact]\n        public void UnmarshalLegacyBlock()\n        {\n#pragma warning disable MEN002  // Line must be no longer than 100 characters\n            var block = BlockMarshaler.UnmarshalBlock(LegacyBlocks.BencodedV0Block);\n            Assert.Equal(0, block.ProtocolVersion);\n            Assert.Equal(\n                new HashDigest<SHA256>(ByteUtil.ParseHex(\"1cd4451624ef9c79e2c2fb5a8e791e4fa56a7d8c610c14a8a34ae175b5205cf7\")),\n                block.PreEvaluationHash);\n            Assert.Equal(\n                new HashDigest<SHA256>(ByteUtil.ParseHex(\"6a648da9e91c21aa22bdae4e35c338406392aad0db4a0f998c01a7d7973cb8aa\")),\n                block.StateRootHash);\n            Assert.Equal(\n                new BlockHash(ByteUtil.ParseHex(\"4cc24bbbabb96b9d825fabdcc106753e2e01c3601f7925959656010eb6206974\")),\n                block.Hash);\n\n            block = BlockMarshaler.UnmarshalBlock(LegacyBlocks.BencodedV1Block);\n            Assert.Equal(1, block.ProtocolVersion);\n            Assert.Equal(\n                new HashDigest<SHA256>(ByteUtil.ParseHex(\"1bba9fcf4c8152c899ed1674ecbf4a6571c271922c0884ae809f91f037bed8fc\")),\n                block.PreEvaluationHash);\n            Assert.Equal(\n                new HashDigest<SHA256>(ByteUtil.ParseHex(\"6a648da9e91c21aa22bdae4e35c338406392aad0db4a0f998c01a7d7973cb8aa\")),\n                block.StateRootHash);\n            Assert.Equal(\n                new BlockHash(ByteUtil.ParseHex(\"41ac71ef0451ddd54078a1b3336b747e8b2f970b441c2e3cb5cad8290f7bc0d0\")),\n                block.Hash);\n\n            block = BlockMarshaler.UnmarshalBlock(LegacyBlocks.BencodedV2Block);\n            Assert.Equal(2, block.ProtocolVersion);\n            Assert.Equal(\n                new HashDigest<SHA256>(ByteUtil.ParseHex(\"e520162fef3516f4c0ccd6f79cc0c50f6e3bf7c53b1bf425b5e1931089e3fd8a\")),\n                block.PreEvaluationHash);\n            Assert.Equal(\n                new HashDigest<SHA256>(ByteUtil.ParseHex(\"6a648da9e91c21aa22bdae4e35c338406392aad0db4a0f998c01a7d7973cb8aa\")),\n                block.StateRootHash);\n            Assert.Equal(\n                new BlockHash(ByteUtil.ParseHex(\"d7e10ac5f4fe56db093458f998d25350db738b7af9c1988f19f905c9c8e55f62\")),\n                block.Hash);\n\n            block = BlockMarshaler.UnmarshalBlock(LegacyBlocks.BencodedV3Block);\n            Assert.Equal(3, block.ProtocolVersion);\n            Assert.Equal(\n                new HashDigest<SHA256>(ByteUtil.ParseHex(\"af519fa381741e58781ea58a43233d155c212351d9840ef69e0a3555f210ad50\")),\n                block.PreEvaluationHash);\n            Assert.Equal(\n                new HashDigest<SHA256>(ByteUtil.ParseHex(\"6a648da9e91c21aa22bdae4e35c338406392aad0db4a0f998c01a7d7973cb8aa\")),\n                block.StateRootHash);\n            Assert.Equal(\n                new BlockHash(ByteUtil.ParseHex(\"93294a9117d1d2b01d6479298864fccf29cd658c7cae60065349a07f9300bbd8\")),\n                block.Hash);\n#pragma warning restore MEN002\n        }\n    }\n}\n"
  },
  {
    "path": "test/Libplanet.Tests/Blocks/BlockMarshalerTest.cs",
    "content": "using System.Globalization;\nusing System.Linq;\nusing Bencodex.Types;\nusing Libplanet.Tests.Fixtures;\nusing Libplanet.Types.Blocks;\nusing Xunit;\nusing Xunit.Abstractions;\nusing static Libplanet.Tests.TestUtils;\n\nnamespace Libplanet.Tests.Blocks\n{\n    public partial class BlockMarshalerTest\n        : IClassFixture<BlockFixture>, IClassFixture<BlockContentFixture>\n    {\n        private const string TimestampFormat = \"yyyy-MM-ddTHH:mm:ss.ffffffZ\";\n\n        // Header fields:\n        private static readonly byte[] ProtocolVersionKey = { 0x00 };\n        private static readonly byte[] IndexKey = { 0x69 }; // 'i'\n        private static readonly byte[] TimestampKey = { 0x74 }; // 't'\n        private static readonly byte[] DifficultyKey = { 0x64 }; // 'd'; Legacy, unused.\n        private static readonly byte[] TotalDifficultyKey = { 0x54 }; // 'T'; Legacy, unused.\n        private static readonly byte[] NonceKey = { 0x6e }; // 'n'; Legacy, unused.\n        private static readonly byte[] MinerKey = { 0x6d }; // 'm'\n        private static readonly byte[] PublicKeyKey = { 0x50 }; // 'P'\n        private static readonly byte[] PreviousHashKey = { 0x70 }; // 'p'\n        private static readonly byte[] TxHashKey = { 0x78 }; // 'x'\n        private static readonly byte[] HashKey = { 0x68 }; // 'h'\n        private static readonly byte[] StateRootHashKey = { 0x73 }; // 's'\n        private static readonly byte[] SignatureKey = { 0x53 }; // 'S'\n        private static readonly byte[] PreEvaluationHashKey = { 0x63 }; // 'c'\n        private static readonly byte[] LastCommitKey = { 0x43 }; // 'C'\n        private static readonly byte[] EvidenceHashKey = { 0x76 }; // 'v\n\n        // Block fields:\n        private static readonly byte[] HeaderKey = { 0x48 }; // 'H'\n        private static readonly byte[] TransactionsKey = { 0x54 }; // 'T'\n\n        private readonly ITestOutputHelper _output;\n        private readonly BlockFixture _fx;\n        private readonly BlockContentFixture _content;\n        private readonly Dictionary _marshaledGenesisMetadata;\n        private readonly Dictionary _marshaledGenesis;\n        private readonly Dictionary _marshaledNextMetadata;\n        private readonly Dictionary _marshaledNext;\n        private readonly Dictionary _marshaledHasTxMetadata;\n        private readonly Dictionary _marshaledHasTx;\n\n        public BlockMarshalerTest(\n            BlockFixture fixture,\n            BlockContentFixture contentFixture,\n            ITestOutputHelper output\n        )\n        {\n            _output = output;\n            _fx = fixture;\n            _content = contentFixture;\n\n            _marshaledGenesisMetadata = Dictionary.Empty\n                .Add(ProtocolVersionKey, _fx.Genesis.ProtocolVersion)\n                .Add(IndexKey, _fx.Genesis.Index)\n                .Add(\n                    TimestampKey,\n                    _fx.Genesis.Timestamp.ToString(TimestampFormat, CultureInfo.InvariantCulture))\n                .Add(PublicKeyKey, _fx.Genesis.PublicKey.Format(compress: true))\n                .Add(TxHashKey, _fx.Genesis.TxHash.Value.ByteArray);\n            var expectedGenesisHeader = _marshaledGenesisMetadata\n                .Add(PreEvaluationHashKey, _fx.Genesis.PreEvaluationHash.ByteArray)\n                .Add(StateRootHashKey, _fx.Genesis.StateRootHash.ByteArray)\n                .Add(SignatureKey, _fx.Genesis.Signature ?? default)\n                .Add(HashKey, _fx.Genesis.Hash.ByteArray);\n            IValue expectedGenesisTx = new List(\n                _fx.Genesis.Transactions.Select(tx => tx.Serialize()));\n            _marshaledGenesis = Dictionary.Empty\n                .Add(HeaderKey, expectedGenesisHeader)\n                .Add(TransactionsKey, expectedGenesisTx);\n\n            // Index #1 block does not have LastCommit.\n            _marshaledNextMetadata = Dictionary.Empty\n                .Add(ProtocolVersionKey, _fx.Next.ProtocolVersion)\n                .Add(IndexKey, _fx.Next.Index)\n                .Add(PreviousHashKey, _fx.Next.PreviousHash.Value.ByteArray)\n                .Add(\n                    TimestampKey,\n                    _fx.Next.Timestamp.ToString(TimestampFormat, CultureInfo.InvariantCulture))\n                .Add(PublicKeyKey, _fx.Next.PublicKey.Format(compress: true));\n            var expectedNextHeader = _marshaledNextMetadata\n                .Add(PreEvaluationHashKey, _fx.Next.PreEvaluationHash.ByteArray)\n                .Add(StateRootHashKey, _fx.Next.StateRootHash.ByteArray)\n                .Add(SignatureKey, _fx.Next.Signature ?? default)\n                .Add(HashKey, _fx.Next.Hash.ByteArray);\n            _marshaledNext = Dictionary.Empty\n                .Add(HeaderKey, expectedNextHeader);\n\n            _marshaledHasTxMetadata = Dictionary.Empty\n                .Add(ProtocolVersionKey, _fx.HasTx.ProtocolVersion)\n                .Add(IndexKey, _fx.HasTx.Index)\n                .Add(PreviousHashKey, _fx.HasTx.PreviousHash.Value.ByteArray)\n                .Add(\n                    TimestampKey,\n                    _fx.HasTx.Timestamp.ToString(TimestampFormat, CultureInfo.InvariantCulture))\n                .Add(PublicKeyKey, _fx.HasTx.PublicKey.Format(true))\n                .Add(TxHashKey, _fx.HasTx.TxHash.Value.ByteArray)\n                .Add(LastCommitKey, _fx.HasTx.LastCommit.Bencoded);\n            var expectedHasTxHeader = _marshaledHasTxMetadata\n                .Add(PreEvaluationHashKey, _fx.HasTx.PreEvaluationHash.ByteArray)\n                .Add(StateRootHashKey, _fx.HasTx.StateRootHash.ByteArray)\n                .Add(SignatureKey, _fx.HasTx.Signature ?? default)\n                .Add(HashKey, _fx.HasTx.Hash.ByteArray);\n            IValue expectedHasTxTxs = new List(\n                _fx.HasTx.Transactions.Select(tx => tx.Serialize()));\n            _marshaledHasTx = Dictionary.Empty\n                .Add(HeaderKey, expectedHasTxHeader)\n                .Add(TransactionsKey, expectedHasTxTxs);\n        }\n\n        [Fact]\n        public void MarshalBlockMetadata()\n        {\n            AssertBencodexEqual(\n                _marshaledGenesisMetadata,\n                BlockMarshaler.MarshalBlockMetadata(_fx.Genesis)\n            );\n            AssertBencodexEqual(\n                _marshaledNextMetadata,\n                BlockMarshaler.MarshalBlockMetadata(_fx.Next)\n            );\n            AssertBencodexEqual(\n                _marshaledHasTxMetadata,\n                BlockMarshaler.MarshalBlockMetadata(_fx.HasTx)\n            );\n            AssertBencodexEqual(\n                Dictionary.Empty\n                    .Add(IndexKey, 0L)\n                    .Add(TimestampKey, \"2021-09-06T04:46:39.123000Z\")\n                    .Add(MinerKey, _content.GenesisContentPv0.Miner.Bencoded),\n                BlockMarshaler.MarshalBlockMetadata(_content.GenesisContentPv0)\n            );\n            AssertBencodexEqual(\n                Dictionary.Empty\n                    .Add(ProtocolVersionKey, 1)\n                    .Add(IndexKey, 1L)\n                    .Add(\n                        PreviousHashKey,\n                        _content.Block1ContentPv1.PreviousHash?.ByteArray ?? default)\n                    .Add(TimestampKey, \"2021-09-06T08:01:09.045000Z\")\n                    .Add(MinerKey, _content.Block1ContentPv1.Miner.Bencoded)\n                    .Add(TxHashKey, _content.Block1ContentPv1.TxHash?.ByteArray ?? default)\n                    .Add(\n                        EvidenceHashKey,\n                        _content.Block1ContentPv1.EvidenceHash?.ByteArray ?? default),\n                BlockMarshaler.MarshalBlockMetadata(_content.Block1ContentPv1)\n            );\n        }\n\n        [Fact]\n        public void MarshalBlock()\n        {\n            AssertBencodexEqual(_marshaledGenesis, _fx.Genesis.MarshalBlock());\n            AssertBencodexEqual(_marshaledNext, _fx.Next.MarshalBlock());\n            AssertBencodexEqual(_marshaledHasTx, _fx.HasTx.MarshalBlock());\n        }\n\n        [Fact]\n        public void UnmarshalBlockHash()\n        {\n            Assert.Equal(\n                _fx.Genesis.Hash,\n                BlockMarshaler.UnmarshalBlockHash(_fx.Genesis.MarshalBlock()));\n\n            Assert.Equal(\n                _fx.Next.Hash,\n                BlockMarshaler.UnmarshalBlockHash(_fx.Next.MarshalBlock()));\n\n            Assert.Equal(\n                _fx.HasTx.Hash,\n                BlockMarshaler.UnmarshalBlockHash(_fx.HasTx.MarshalBlock()));\n        }\n\n        [Fact]\n        public void UnmarshalBlock()\n        {\n            _output.WriteLine(\n                \"{0} = {1}\",\n                nameof(_marshaledGenesis),\n                _marshaledGenesis.Inspect());\n            Assert.Equal(\n                _fx.Genesis,\n                BlockMarshaler.UnmarshalBlock(_marshaledGenesis)\n            );\n            _output.WriteLine(\n                \"{0} = {1}\",\n                nameof(_marshaledNext),\n                _marshaledNext.Inspect());\n            Assert.Equal(\n                _fx.Next,\n                BlockMarshaler.UnmarshalBlock(_marshaledNext)\n            );\n            _output.WriteLine(\n                \"{0} = {1}\",\n                nameof(_marshaledHasTx),\n                _marshaledHasTx.Inspect());\n            Assert.Equal(\n                _fx.HasTx,\n                BlockMarshaler.UnmarshalBlock(_marshaledHasTx)\n            );\n        }\n    }\n}\n"
  },
  {
    "path": "test/Libplanet.Tests/Blocks/BlockMetadataExtensionsTest.cs",
    "content": "using System;\nusing Libplanet.Crypto;\nusing Libplanet.Tests.Fixtures;\nusing Libplanet.Types.Blocks;\nusing Xunit;\n\nnamespace Libplanet.Tests.Blocks\n{\n    public class BlockMetadataExtensionsTest : BlockContentFixture\n    {\n        [Fact]\n        public void ValidateTimestamp()\n        {\n            DateTimeOffset now = DateTimeOffset.UtcNow;\n            DateTimeOffset future = now + TimeSpan.FromSeconds(17);\n            PublicKey publicKey = new PrivateKey().PublicKey;\n            IBlockMetadata metadata = new BlockMetadata(\n                index: 0,\n                timestamp: future,\n                publicKey: publicKey,\n                previousHash: null,\n                txHash: null,\n                lastCommit: null,\n                evidenceHash: null);\n            Assert.Throws<InvalidBlockTimestampException>(() => metadata.ValidateTimestamp(now));\n\n            // It's okay because 3 seconds later.\n            metadata.ValidateTimestamp(now + TimeSpan.FromSeconds(3));\n        }\n    }\n}\n"
  },
  {
    "path": "test/Libplanet.Tests/Blocks/BlockMetadataTest.cs",
    "content": "using System;\nusing System.Collections.Immutable;\nusing System.Numerics;\nusing System.Security.Cryptography;\nusing Libplanet.Common;\nusing Libplanet.Crypto;\nusing Libplanet.Tests.Fixtures;\nusing Libplanet.Types.Blocks;\nusing Libplanet.Types.Consensus;\nusing Xunit;\nusing Xunit.Abstractions;\nusing static Libplanet.Common.ByteUtil;\nusing static Libplanet.Tests.TestUtils;\n\nnamespace Libplanet.Tests.Blocks\n{\n    public class BlockMetadataTest : BlockContentFixture\n    {\n        private readonly ITestOutputHelper _output;\n\n        public BlockMetadataTest(ITestOutputHelper output)\n        {\n            _output = output;\n        }\n\n        [Fact]\n        public void CopyConstructor()\n        {\n            var g = new BlockMetadata(GenesisContent);\n            AssertBlockMetadataEqual(GenesisContent, g);\n            var b1 = new BlockMetadata(Block1Content);\n            AssertBlockMetadataEqual(Block1Content, b1);\n        }\n\n        [Fact]\n        public void ProtocolVersion()\n        {\n            Assert.Throws<InvalidBlockProtocolVersionException>(\n                () => new BlockMetadata(\n                    protocolVersion: -1,\n                    index: Block1Metadata.Index,\n                    timestamp: Block1Metadata.Timestamp,\n                    miner: Block1Metadata.Miner,\n                    publicKey: null,\n                    previousHash: Block1Metadata.PreviousHash,\n                    txHash: Block1Metadata.TxHash,\n                    lastCommit: null,\n                    evidenceHash: null));\n            Assert.Throws<InvalidBlockProtocolVersionException>(\n                () => new BlockMetadata(\n                    protocolVersion: BlockMetadata.CurrentProtocolVersion + 1,\n                    index: Block1Metadata.Index,\n                    timestamp: Block1Metadata.Timestamp,\n                    miner: Block1Metadata.Miner,\n                    publicKey: null,\n                    previousHash: Block1Metadata.PreviousHash,\n                    txHash: Block1Metadata.TxHash,\n                    lastCommit: null,\n                    evidenceHash: null));\n        }\n\n        [Fact]\n        public void Index()\n        {\n            Assert.Throws<InvalidBlockIndexException>(() => new BlockMetadata(\n                index: -1L,\n                timestamp: DateTimeOffset.UtcNow,\n                publicKey: Block1Metadata.PublicKey,\n                previousHash: Block1Metadata.PreviousHash,\n                txHash: Block1Metadata.TxHash,\n                lastCommit: null,\n                evidenceHash: null));\n        }\n\n        [Fact]\n        public void Timestamp()\n        {\n            DateTimeOffset kstTimestamp =\n                new DateTimeOffset(2021, 9, 7, 9, 30, 12, 345, TimeSpan.FromHours(9));\n            BlockMetadata metadata = new BlockMetadata(\n                protocolVersion: Block1Metadata.ProtocolVersion,\n                index: Block1Metadata.Index,\n                timestamp: kstTimestamp,\n                miner: Block1Metadata.Miner,\n                publicKey: Block1Metadata.PublicKey,\n                previousHash: Block1Metadata.PreviousHash,\n                txHash: Block1Metadata.TxHash,\n                lastCommit: null,\n                evidenceHash: null);\n            Assert.Equal(TimeSpan.Zero, metadata.Timestamp.Offset);\n            Assert.Equal(\n                new DateTime(2021, 9, 7, 0, 30, 12, 345),\n                metadata.Timestamp.DateTime);\n            Assert.Equal(kstTimestamp, metadata.Timestamp);\n        }\n\n        [Fact]\n        public void PreviousHash()\n        {\n            Assert.Throws<InvalidBlockPreviousHashException>(() => new BlockMetadata(\n                index: GenesisMetadata.Index,\n                timestamp: DateTimeOffset.UtcNow,\n                publicKey: GenesisMetadata.PublicKey,\n                previousHash: Block1Metadata.PreviousHash,\n                txHash: GenesisMetadata.TxHash,\n                lastCommit: null,\n                evidenceHash: null));\n            Assert.Throws<InvalidBlockPreviousHashException>(() => new BlockMetadata(\n                index: Block1Metadata.Index,\n                timestamp: DateTimeOffset.UtcNow,\n                publicKey: Block1Metadata.PublicKey,\n                previousHash: null,\n                txHash: Block1Metadata.TxHash,\n                lastCommit: null,\n                evidenceHash: null));\n        }\n\n        [Fact]\n        public void MakeCandidateData()\n        {\n            Bencodex.Types.Dictionary expectedGenesis = Bencodex.Types.Dictionary.Empty\n                .Add(\"index\", 0L)\n                .Add(\"timestamp\", \"2021-09-06T04:46:39.123000Z\")\n                .Add(\"nonce\", ImmutableArray<byte>.Empty)\n                .Add(\n                    \"public_key\",\n                    ParseHex(\"0200e02709cc0c051dc105188c454a2e7ef7b36b85da34529d3abc1968167cf54f\")\n                )\n                .Add(\"protocol_version\", BlockMetadata.CurrentProtocolVersion)\n                .Add(\n                    \"transaction_fingerprint\",\n                    ParseHex(\"3d8e87977b1142863435b9385657e69557df8951a0698e9719f7d06c5fb8db1f\")\n                )\n                .Add(\n                    \"evidence_hash\",\n                    ParseHex(\"bd1b6bc740c7d74fe39f8c78dd6860b7b5bf9c58336a703a583a5a59651a4af3\")\n                );\n            AssertBencodexEqual(expectedGenesis, GenesisMetadata.MakeCandidateData());\n\n            Bencodex.Types.Dictionary expectedBlock1 = Bencodex.Types.Dictionary.Empty\n                .Add(\"index\", 1L)\n                .Add(\"timestamp\", \"2021-09-06T08:01:09.045000Z\")\n                .Add(\"nonce\", ImmutableArray<byte>.Empty)\n                .Add(\n                    \"public_key\",\n                    ParseHex(\"0215ba27a461a986f4ce7bcda1fd73dc708da767d0405729edaacaad7b7ff60eed\")\n                )\n                .Add(\n                    \"previous_hash\",\n                    ParseHex(\"341e8f360597d5bc45ab96aabc5f1b0608063f30af7bd4153556c9536a07693a\")\n                )\n                .Add(\n                    \"transaction_fingerprint\",\n                    ParseHex(\"654698d34b6d9a55b0c93e4ffb2639278324868c91965bc5f96cb3071d6903a0\")\n                )\n                .Add(\"protocol_version\", BlockMetadata.CurrentProtocolVersion)\n                .Add(\n                    \"evidence_hash\",\n                    ParseHex(\"e7198889cc4a82a8b7be4b7f428b6201400ef222709f756e540b32bc1e8d5d86\")\n                );\n            AssertBencodexEqual(\n                expectedBlock1,\n                Block1Metadata.MakeCandidateData());\n        }\n\n        [Fact]\n        public void MakeCandidateDataPv1()\n        {\n            Bencodex.Types.Dictionary expected = Bencodex.Types.Dictionary.Empty\n                .Add(\"index\", 1L)\n                .Add(\"timestamp\", \"2021-09-06T08:01:09.045000Z\")\n                .Add(\"nonce\", ImmutableArray<byte>.Empty)\n                .Add(\"reward_beneficiary\", ParseHex(\"8a29de186B85560D708451101C4Bf02D63b25c50\"))\n                .Add(\n                    \"previous_hash\",\n                    ParseHex(\n                        \"341e8f360597d5bc45ab96aabc5f1b0608063f30af7bd4153556c9536a07693a\"))\n                .Add(\n                    \"transaction_fingerprint\",\n                    ParseHex(\n                        \"654698d34b6d9a55b0c93e4ffb2639278324868c91965bc5f96cb3071d6903a0\"\n                    )\n                )\n                .Add(\n                    \"evidence_hash\",\n                    ParseHex(\"e7198889cc4a82a8b7be4b7f428b6201400ef222709f756e540b32bc1e8d5d86\")\n                )\n                .Add(\"protocol_version\", 1);\n            AssertBencodexEqual(expected, Block1MetadataPv1.MakeCandidateData());\n        }\n\n        [Fact]\n        public void MakeCandidateDataPv0()\n        {\n            Bencodex.Types.Dictionary expected = Bencodex.Types.Dictionary.Empty\n                .Add(\"index\", 0L)\n                .Add(\"timestamp\", \"2021-09-06T04:46:39.123000Z\")\n                .Add(\"nonce\", ImmutableArray<byte>.Empty)\n                .Add(\"reward_beneficiary\", ParseHex(\"268344BA46e6CA2A8a5096565548b9018bc687Ce\"));\n            AssertBencodexEqual(expected, GenesisMetadataPv0.MakeCandidateData());\n        }\n\n        [Fact]\n        public void DerivePreEvaluationHash()\n        {\n            ImmutableArray<byte> FromHex(string hex) => ParseHexToImmutable(hex);\n\n            HashDigest<SHA256> hash = GenesisMetadata.DerivePreEvaluationHash();\n            AssertBytesEqual(\n                FromHex(\"9ff328716814fed03de454dfc0a9d9aeb0077ad0c393513bf29895a45ded13aa\"),\n                hash.ByteArray);\n        }\n\n        [Fact]\n        public void ValidateLastCommit()\n        {\n            var validatorA = new PrivateKey();\n            var validatorB = new PrivateKey();\n            var validatorC = new PrivateKey();\n            BlockHash blockHash = new BlockHash(TestUtils.GetRandomBytes(BlockHash.Size));\n            BlockHash invalidBlockHash = new BlockHash(TestUtils.GetRandomBytes(BlockHash.Size));\n            DateTimeOffset timestamp = DateTimeOffset.UtcNow;\n\n            // Height of the last commit is invalid.\n            var invalidHeightLastCommit = new BlockCommit(\n                2,\n                0,\n                blockHash,\n                new[]\n                {\n                    GenerateVote(blockHash, 2, 0, VoteFlag.PreCommit),\n                    GenerateVote(blockHash, 2, 0, VoteFlag.PreCommit),\n                    GenerateVote(blockHash, 2, 0, VoteFlag.PreCommit),\n                }.ToImmutableArray());\n            Assert.Throws<InvalidBlockLastCommitException>(() => new BlockMetadata(\n                protocolVersion: BlockMetadata.CurrentProtocolVersion,\n                index: 2,\n                timestamp: timestamp,\n                miner: validatorA.Address,\n                publicKey: validatorA.PublicKey,\n                previousHash: blockHash,\n                txHash: null,\n                lastCommit: invalidHeightLastCommit,\n                evidenceHash: null));\n\n            // BlockHash of the last commit is invalid.\n            var invalidBlockHashLastCommit = new BlockCommit(\n                1,\n                0,\n                invalidBlockHash,\n                new[]\n                {\n                    GenerateVote(invalidBlockHash, 1, 0, VoteFlag.PreCommit),\n                    GenerateVote(invalidBlockHash, 1, 0, VoteFlag.PreCommit),\n                    GenerateVote(invalidBlockHash, 1, 0, VoteFlag.PreCommit),\n                }.ToImmutableArray());\n            Assert.Throws<InvalidBlockLastCommitException>(() => new BlockMetadata(\n                protocolVersion: BlockMetadata.CurrentProtocolVersion,\n                index: 2,\n                timestamp: timestamp,\n                miner: validatorA.Address,\n                publicKey: validatorA.PublicKey,\n                previousHash: GenesisHash,\n                txHash: null,\n                lastCommit: invalidBlockHashLastCommit,\n                evidenceHash: null));\n\n            var validLastCommit = new BlockCommit(\n                1,\n                0,\n                blockHash,\n                new[]\n                {\n                    GenerateVote(blockHash, 1, 0, VoteFlag.PreCommit),\n                    GenerateVote(blockHash, 1, 0, VoteFlag.PreCommit),\n                    GenerateVote(blockHash, 1, 0, VoteFlag.PreCommit),\n                    new VoteMetadata(\n                        1,\n                        0,\n                        blockHash,\n                        timestamp,\n                        validatorB.PublicKey,\n                        BigInteger.One,\n                        VoteFlag.Null).Sign(null),\n                }.ToImmutableArray());\n            var validMetadata = new BlockMetadata(\n                protocolVersion: BlockMetadata.CurrentProtocolVersion,\n                index: 2,\n                timestamp: timestamp,\n                miner: validatorA.Address,\n                publicKey: validatorA.PublicKey,\n                previousHash: blockHash,\n                txHash: null,\n                lastCommit: validLastCommit,\n                evidenceHash: null);\n        }\n\n        private static Vote GenerateVote(BlockHash hash, long height, int round, VoteFlag flag)\n        {\n            var key = new PrivateKey();\n            var voteMetadata = new VoteMetadata(\n                height, round, hash, DateTimeOffset.UtcNow, key.PublicKey, BigInteger.One, flag);\n            return flag == VoteFlag.PreVote || flag == VoteFlag.PreCommit\n                ? voteMetadata.Sign(key)\n                : voteMetadata.Sign(null);\n        }\n    }\n}\n"
  },
  {
    "path": "test/Libplanet.Tests/Blocks/BlockTest.cs",
    "content": "using System;\nusing System.Collections.Immutable;\nusing System.Linq;\nusing System.Security.Cryptography;\nusing Bencodex.Types;\nusing Libplanet.Action;\nusing Libplanet.Action.Tests.Common;\nusing Libplanet.Crypto;\nusing Libplanet.Tests.Fixtures;\nusing Libplanet.Types.Blocks;\nusing Libplanet.Types.Tx;\nusing Xunit;\nusing Xunit.Abstractions;\nusing static Libplanet.Tests.TestUtils;\n\nnamespace Libplanet.Tests.Blocks\n{\n    public class BlockTest : IClassFixture<BlockFixture>\n    {\n        private BlockFixture _fx;\n        private ITestOutputHelper _output;\n\n        public BlockTest(BlockFixture fixture, ITestOutputHelper output)\n        {\n            _fx = fixture;\n            _output = output;\n        }\n\n        [Fact]\n        public void Constructor()\n        {\n            var contents = new BlockContentFixture();\n            var random = new System.Random();\n            var stateRootHash = random.NextHashDigest<SHA256>();\n            PreEvaluationBlock preEval = contents.GenesisContent.Propose();\n            ImmutableArray<byte> signature =\n                preEval.Header.MakeSignature(contents.GenesisKey, stateRootHash);\n            var hash = preEval.Header.DeriveBlockHash(stateRootHash, signature);\n            var block = new Block(preEval, (stateRootHash, signature, hash));\n            AssertPreEvaluationBlocksEqual(preEval, block);\n            AssertBytesEqual(stateRootHash, block.StateRootHash);\n            AssertBytesEqual(signature, block.Signature?.ToArray());\n        }\n\n        [Fact]\n        public void CompareToOtherBlock()\n        {\n            Block sameBlock1 = _fx.Genesis;\n            var sameBlock2 = BlockMarshaler.UnmarshalBlock(_fx.Genesis.MarshalBlock());\n            Block differentBlock = _fx.Next;\n\n            Assert.Equal(sameBlock1, sameBlock2);\n            Assert.NotEqual(sameBlock2, differentBlock);\n\n            Assert.True(sameBlock1.Equals(sameBlock2));\n            Assert.False(sameBlock2.Equals(differentBlock));\n        }\n\n        [Fact]\n        public void TransactionOrderIdempotent()\n        {\n            const int signerCount = 5;\n            DateTimeOffset timestamp = DateTimeOffset.UtcNow;\n            var signers = Enumerable.Range(0, signerCount).Select(_ => new PrivateKey());\n            ImmutableArray<Transaction> txs = signers.Select(signer =>\n                Transaction.Create(\n                    0,\n                    signer,\n                    null,\n                    new[]\n                    {\n                        new ContextRecordingAction(signer.Address, new Text(\"Foo\")),\n                    }.ToPlainValues())).ToImmutableArray();\n            var blockA = ProposeGenesis(\n                GenesisProposer.PublicKey,\n                timestamp: timestamp,\n                transactions: txs);\n            var blockB = ProposeGenesis(\n                GenesisProposer.PublicKey,\n                timestamp: timestamp,\n                transactions: txs);\n\n            Assert.True(blockA.Transactions.SequenceEqual(blockB.Transactions));\n        }\n    }\n}\n"
  },
  {
    "path": "test/Libplanet.Tests/Blocks/PreEvaluationBlockHeaderTest.cs",
    "content": "using System;\nusing System.Collections.Immutable;\nusing System.Security.Cryptography;\nusing Bencodex;\nusing Bencodex.Types;\nusing Libplanet.Common;\nusing Libplanet.Crypto;\nusing Libplanet.Tests.Fixtures;\nusing Libplanet.Types.Blocks;\nusing Xunit;\nusing static Libplanet.Common.ByteUtil;\nusing static Libplanet.Tests.TestUtils;\n\nnamespace Libplanet.Tests.Blocks\n{\n    // FIXME: The most of the following tests are duplicated in PreEvaluationBlockTest.\n    public class PreEvaluationBlockHeaderTest\n    {\n        protected readonly BlockContentFixture _contents;\n        protected readonly Codec _codec;\n\n        public PreEvaluationBlockHeaderTest()\n        {\n            _contents = new BlockContentFixture();\n            _codec = new Codec();\n        }\n\n        [Fact]\n        public void CopyConstructor()\n        {\n            BlockMetadata metadata = new BlockMetadata(_contents.GenesisContent);\n            var preEvalBlock = new PreEvaluationBlockHeader(\n                metadata, metadata.DerivePreEvaluationHash());\n            var copy = new PreEvaluationBlockHeader(preEvalBlock);\n            AssertPreEvaluationBlockHeadersEqual(preEvalBlock, copy);\n        }\n\n        [Fact]\n        public void ValidatePreEvaluationHash()\n        {\n            BlockMetadata metadataPv1 = new BlockMetadata(_contents.Block1ContentPv1);\n            Assert.True(metadataPv1.ProtocolVersion < BlockMetadata.PBFTProtocolVersion);\n\n            // Should be fine.\n            var preEvaluationBlockHeaderPv1 = new PreEvaluationBlockHeader(\n                metadataPv1,\n                new HashDigest<SHA256>(TestUtils.GetRandomBytes(HashDigest<SHA256>.Size)));\n\n            BlockMetadata metadata = new BlockMetadata(_contents.Block1Content);\n            Assert.False(metadata.ProtocolVersion < BlockMetadata.PBFTProtocolVersion);\n            var preEvaluationBlockHeader = new PreEvaluationBlockHeader(\n                metadata,\n                metadata.DerivePreEvaluationHash());\n        }\n\n        [Fact]\n        public void MakeCandidateData()\n        {\n            var random = new Random();\n            Bencodex.Types.Dictionary expectedGenesis = Bencodex.Types.Dictionary.Empty\n                .Add(\"index\", 0L)\n                .Add(\"timestamp\", \"2021-09-06T04:46:39.123000Z\")\n                .Add(\"nonce\", ImmutableArray<byte>.Empty)\n                .Add(\n                    \"public_key\",\n                    ParseHex(\"0200e02709cc0c051dc105188c454a2e7ef7b36b85da34529d3abc1968167cf54f\")\n                )\n                .Add(\"protocol_version\", BlockMetadata.CurrentProtocolVersion)\n                .Add(\"state_root_hash\", default(HashDigest<SHA256>).ByteArray)\n                .Add(\n                    \"transaction_fingerprint\",\n                    ParseHex(\"3d8e87977b1142863435b9385657e69557df8951a0698e9719f7d06c5fb8db1f\")\n                )\n                .Add(\n                    \"evidence_hash\",\n                    ParseHex(\"bd1b6bc740c7d74fe39f8c78dd6860b7b5bf9c58336a703a583a5a59651a4af3\")\n                );\n            var genesis = new PreEvaluationBlockHeader(\n                _contents.GenesisMetadata,\n                _contents.GenesisMetadata.DerivePreEvaluationHash());\n            AssertBencodexEqual(expectedGenesis, genesis.MakeCandidateData(default));\n            HashDigest<SHA256> stateRootHash = random.NextHashDigest<SHA256>();\n            AssertBencodexEqual(\n                expectedGenesis.SetItem(\"state_root_hash\", stateRootHash.ByteArray),\n                genesis.MakeCandidateData(stateRootHash)\n            );\n\n            Bencodex.Types.Dictionary expectedBlock1 = Bencodex.Types.Dictionary.Empty\n                .Add(\"index\", 1L)\n                .Add(\"timestamp\", \"2021-09-06T08:01:09.045000Z\")\n                .Add(\"nonce\", ImmutableArray<byte>.Empty)\n                .Add(\n                    \"public_key\",\n                    ParseHex(\"0215ba27a461a986f4ce7bcda1fd73dc708da767d0405729edaacaad7b7ff60eed\")\n                )\n                .Add(\n                    \"previous_hash\",\n                    ParseHex(\n                        \"341e8f360597d5bc45ab96aabc5f1b0608063f30af7bd4153556c9536a07693a\"\n                    )\n                )\n                .Add(\n                    \"transaction_fingerprint\",\n                    ParseHex(\n                        \"654698d34b6d9a55b0c93e4ffb2639278324868c91965bc5f96cb3071d6903a0\"\n                    )\n                )\n                .Add(\n                    \"evidence_hash\",\n                    ParseHex(\n                        \"e7198889cc4a82a8b7be4b7f428b6201400ef222709f756e540b32bc1e8d5d86\"\n                    )\n                )\n                .Add(\"protocol_version\", BlockMetadata.CurrentProtocolVersion)\n                .Add(\"state_root_hash\", default(HashDigest<SHA256>).ByteArray);\n            var block1 = new PreEvaluationBlockHeader(\n                _contents.Block1Metadata,\n                _contents.Block1Metadata.DerivePreEvaluationHash());\n            AssertBencodexEqual(expectedBlock1, block1.MakeCandidateData(default));\n            stateRootHash = random.NextHashDigest<SHA256>();\n            AssertBencodexEqual(\n                expectedBlock1.SetItem(\"state_root_hash\", stateRootHash.ByteArray),\n                block1.MakeCandidateData(stateRootHash)\n            );\n        }\n\n        [Fact]\n        public void MakeSignature()\n        {\n            HashDigest<SHA256> arbitraryHash = HashDigest<SHA256>.FromString(\n                \"e6b3803208416556db8de50670aaf0b642e13c90afd77d24da8f642dc3e8f320\"\n            );\n\n            var key = _contents.Block1Key;\n            var block1 = new PreEvaluationBlockHeader(\n                _contents.Block1Metadata,\n                _contents.Block1Metadata.DerivePreEvaluationHash());\n            ImmutableArray<byte> validSig = block1.MakeSignature(key, arbitraryHash);\n            Assert.True(\n                key.PublicKey.Verify(\n                    _codec.Encode(block1.MakeCandidateData(arbitraryHash)),\n                    validSig\n                )\n            );\n            Assert.False(\n                key.PublicKey.Verify(_codec.Encode(block1.MakeCandidateData(default)), validSig)\n            );\n            Assert.False(\n                new PrivateKey().PublicKey.Verify(\n                    _codec.Encode(block1.MakeCandidateData(arbitraryHash)),\n                    validSig\n                )\n            );\n\n            ArgumentException e = Assert.Throws<ArgumentException>(\n                () => block1.MakeSignature(new PrivateKey(), arbitraryHash)\n            );\n            Assert.Equal(\"privateKey\", e.ParamName);\n            Assert.Contains(\"does not match\", e.Message);\n\n            var blockPv1 = new PreEvaluationBlockHeader(\n                _contents.Block1MetadataPv1,\n                _contents.Block1MetadataPv1.DerivePreEvaluationHash());\n            InvalidOperationException e2 = Assert.Throws<InvalidOperationException>(\n                () => blockPv1.MakeSignature(key, arbitraryHash)\n            );\n            Assert.Contains(\"protocol version\", e2.Message);\n        }\n\n        [Fact]\n        public void VerifySignature()\n        {\n            var random = new Random();\n            HashDigest<SHA256> arbitraryHash = HashDigest<SHA256>.FromString(\n                \"e6b3803208416556db8de50670aaf0b642e13c90afd77d24da8f642dc3e8f320\"\n            );\n\n            var block1 = new PreEvaluationBlockHeader(\n                _contents.Block1Metadata,\n                _contents.Block1Metadata.DerivePreEvaluationHash());\n\n            // Same as block1.MakeSignature(_contents.Block1Key, arbitraryHash)\n            ImmutableArray<byte> validSig = ByteUtil.ParseHexToImmutable(\n                \"3045022100f975e902971092f16dbbb1fe6b7c956de648a8cd62346dbadc07e5fca4ce3\" +\n                \"07a02200987a349f0763efd0448659ed66c6bd0ad0971dd57fbb89c672aed592fbd70d6\");\n            AssertBytesEqual(\n                validSig,\n                block1.MakeSignature(_contents.Block1Key, arbitraryHash));\n            Assert.True(block1.VerifySignature(validSig, arbitraryHash));\n            Assert.False(block1.VerifySignature(null, arbitraryHash));\n            Assert.False(block1.VerifySignature(validSig, default));\n            Assert.False(\n                block1.VerifySignature(\n                    random.NextBytes(validSig.Length).ToImmutableArray(),\n                    arbitraryHash\n                )\n            );\n\n            var blockPv1 = new PreEvaluationBlockHeader(\n                _contents.Block1MetadataPv1,\n                _contents.Block1MetadataPv1.DerivePreEvaluationHash());\n            Assert.True(blockPv1.VerifySignature(null, arbitraryHash));\n            Assert.False(blockPv1.VerifySignature(validSig, arbitraryHash));\n        }\n\n        [Fact]\n        public void DeriveBlockHash()\n        {\n            Func<string, BlockHash> fromHex = BlockHash.FromString;\n            HashDigest<SHA256> arbitraryHash = HashDigest<SHA256>.FromString(\n                \"9db253bdb987ec93df713522e5f90f4865a2d0fa337481d7a065d588ddae7fa7\"\n            );\n\n            var genesis = new PreEvaluationBlockHeader(\n                _contents.GenesisMetadata,\n                _contents.GenesisMetadata.DerivePreEvaluationHash());\n            AssertBytesEqual(\n                fromHex(\"d790aa3b2d985d58e6fe6547336ca9d2bfdb749a27cd58a17dbfd0c6880da8e3\"),\n                genesis.DeriveBlockHash(default, null)\n            );\n            AssertBytesEqual(\n                fromHex(\"47b5227dfdd99af4faf9ae9e82ef3b615063179d275081eae4c122685bbf7dcb\"),\n                genesis.DeriveBlockHash(\n                    default,\n                    genesis.MakeSignature(_contents.GenesisKey, default)\n                )\n            );\n            AssertBytesEqual(\n                fromHex(\"2c45bb52e4c7d79caa28da9b63ec0f492262836c975bfa5bb27f62e96f2aad99\"),\n                genesis.DeriveBlockHash(arbitraryHash, null)\n            );\n            AssertBytesEqual(\n                fromHex(\"e985fcdce3f73dee90a4eaec9399283f856bb6f9326e4300bbe1d6126ff7ad55\"),\n                genesis.DeriveBlockHash(\n                    arbitraryHash,\n                    genesis.MakeSignature(_contents.GenesisKey, arbitraryHash))\n            );\n\n            var block1 = new PreEvaluationBlockHeader(\n                _contents.Block1Metadata,\n                _contents.Block1Metadata.DerivePreEvaluationHash());\n            AssertBytesEqual(\n                fromHex(\"ade696a646c9e4321cc90160807cba3d15d7cd28556d2dfb4103e8730a46038c\"),\n                block1.DeriveBlockHash(default, null)\n            );\n            AssertBytesEqual(\n                fromHex(\"b3157a151d2168653e21ffc850f9d1a96bca6310275cccbeb9bd705f67c2e1c9\"),\n                block1.DeriveBlockHash(default, block1.MakeSignature(_contents.Block1Key, default))\n            );\n            AssertBytesEqual(\n                fromHex(\"3fd4ee37ed2fc5dae5a9533984f06b3975e176bdaa70689a3c14acd8b4ea384d\"),\n                block1.DeriveBlockHash(arbitraryHash, null)\n            );\n            AssertBytesEqual(\n                fromHex(\"83ceb4d1e5bbc385daaebfd044a5e4ba65bf1d8b63ef0aabe4d68fc5642b4516\"),\n                block1.DeriveBlockHash(\n                    arbitraryHash, block1.MakeSignature(_contents.Block1Key, arbitraryHash)\n                )\n            );\n        }\n    }\n}\n"
  },
  {
    "path": "test/Libplanet.Tests/Blocks/PreEvaluationBlockTest.cs",
    "content": "using System;\nusing System.Collections.Immutable;\nusing System.Security.Cryptography;\nusing Libplanet.Action;\nusing Libplanet.Action.Loader;\nusing Libplanet.Action.State;\nusing Libplanet.Action.Tests.Common;\nusing Libplanet.Blockchain;\nusing Libplanet.Blockchain.Policies;\nusing Libplanet.Common;\nusing Libplanet.Crypto;\nusing Libplanet.Store.Trie;\nusing Libplanet.Tests.Fixtures;\nusing Libplanet.Tests.Store;\nusing Libplanet.Types.Blocks;\nusing Libplanet.Types.Evidence;\nusing Xunit;\nusing Xunit.Abstractions;\nusing static Libplanet.Tests.TestUtils;\n\nnamespace Libplanet.Tests.Blocks\n{\n    // FIXME: The most of the following tests are duplicated in PreEvaluationBlockHeaderTest.\n    public class PreEvaluationBlockTest : PreEvaluationBlockHeaderTest\n    {\n        private readonly ITestOutputHelper _output;\n\n        public PreEvaluationBlockTest(ITestOutputHelper output)\n        {\n            _output = output;\n        }\n\n        [Fact]\n        public void Evaluate()\n        {\n            Address address = _contents.Block1Tx0.Signer;\n            var policy = new BlockPolicy(\n                new PolicyActionsRegistry(\n                    beginBlockActions: ImmutableArray<IAction>.Empty,\n                    endBlockActions: ImmutableArray.Create<IAction>(\n                        new SetStatesAtBlock(\n                        address,\n                        (Bencodex.Types.Integer)123,\n                        ReservedAddresses.LegacyAccount,\n                        0))),\n                blockInterval: TimeSpan.FromMilliseconds(3 * 60 * 60 * 1000));\n            var stagePolicy = new VolatileStagePolicy();\n\n            PreEvaluationBlock preEvalGenesis =\n                _contents.GenesisContent.Propose();\n\n            using (var fx = new MemoryStoreFixture())\n            {\n                var actionEvaluator = new ActionEvaluator(\n                    policy.PolicyActionsRegistry,\n                    fx.StateStore,\n                    new SingleActionLoader(typeof(Arithmetic)));\n                Block genesis = preEvalGenesis.Sign(\n                    _contents.GenesisKey,\n                    MerkleTrie.EmptyRootHash);\n                AssertPreEvaluationBlocksEqual(preEvalGenesis, genesis);\n                _output.WriteLine(\"#1: {0}\", genesis);\n\n                var blockChain = BlockChain.Create(\n                    policy,\n                    stagePolicy,\n                    fx.Store,\n                    fx.StateStore,\n                    genesis,\n                    actionEvaluator);\n                AssertBencodexEqual(\n                    (Bencodex.Types.Integer)123,\n                    blockChain\n                        .GetNextWorldState()\n                        .GetAccountState(ReservedAddresses.LegacyAccount)\n                        .GetState(address));\n\n                var txs = new[] { _contents.Block1Tx0 };\n                var evs = Array.Empty<EvidenceBase>();\n                BlockContent content1 = new BlockContent(\n                    new BlockMetadata(\n                        index: _contents.Block1Content.Index,\n                        timestamp: DateTimeOffset.UtcNow,\n                        publicKey: _contents.Block1Content.PublicKey,\n                        previousHash: genesis.Hash,\n                        txHash: BlockContent.DeriveTxHash(txs),\n                        lastCommit: null,\n                        evidenceHash: null),\n                    transactions: txs,\n                    evidence: evs);\n                PreEvaluationBlock preEval1 = content1.Propose();\n\n                HashDigest<SHA256> b1StateRootHash =\n                    blockChain.DetermineNextBlockStateRootHash(genesis, out _);\n                Block block1 = blockChain.EvaluateAndSign(preEval1, _contents.Block1Key);\n                AssertBytesEqual(b1StateRootHash, block1.StateRootHash);\n                AssertPreEvaluationBlocksEqual(preEval1, block1);\n                _output.WriteLine(\"#1: {0}\", block1);\n\n                blockChain.Append(block1, TestUtils.CreateBlockCommit(block1));\n                AssertBencodexEqual(\n                    (Bencodex.Types.Integer)158,\n                    blockChain\n                        .GetNextWorldState()\n                        .GetAccountState(ReservedAddresses.LegacyAccount)\n                        .GetState(address));\n            }\n        }\n\n        [Fact]\n        public void DetermineStateRootHash()\n        {\n            Address address = _contents.Block1Tx0.Signer;\n            var policy = new BlockPolicy(\n                new PolicyActionsRegistry(\n                    beginBlockActions: ImmutableArray<IAction>.Empty,\n                    endBlockActions: ImmutableArray.Create<IAction>(\n                        new SetStatesAtBlock(\n                            address,\n                            (Bencodex.Types.Integer)123,\n                            ReservedAddresses.LegacyAccount,\n                            0))),\n                blockInterval: TimeSpan.FromMilliseconds(3 * 60 * 60 * 1000));\n            var stagePolicy = new VolatileStagePolicy();\n\n            PreEvaluationBlock preEvalGenesis = _contents.GenesisContent.Propose();\n\n            using (var fx = new MemoryStoreFixture())\n            {\n                var actionEvaluator = new ActionEvaluator(\n                    policyActionsRegistry: policy.PolicyActionsRegistry,\n                    stateStore: fx.StateStore,\n                    actionTypeLoader: new SingleActionLoader(typeof(Arithmetic)));\n                HashDigest<SHA256> genesisStateRootHash = MerkleTrie.EmptyRootHash;\n                _output.WriteLine(\"#0 StateRootHash: {0}\", genesisStateRootHash);\n                Block genesis =\n                    preEvalGenesis.Sign(_contents.GenesisKey, genesisStateRootHash);\n                _output.WriteLine(\"#1: {0}\", genesis);\n\n                var blockChain = BlockChain.Create(\n                    policy,\n                    stagePolicy,\n                    fx.Store,\n                    fx.StateStore,\n                    genesis,\n                    actionEvaluator);\n                AssertBencodexEqual(\n                    (Bencodex.Types.Integer)123,\n                    blockChain\n                        .GetNextWorldState()\n                        .GetAccountState(ReservedAddresses.LegacyAccount)\n                        .GetState(address));\n\n                var txs = new[] { _contents.Block1Tx0 };\n                var evs = Array.Empty<EvidenceBase>();\n                BlockContent content1 = new BlockContent(\n                    new BlockMetadata(\n                        index: _contents.Block1Content.Index,\n                        timestamp: DateTimeOffset.UtcNow,\n                        publicKey: _contents.Block1Content.PublicKey,\n                        previousHash: genesis.Hash,\n                        txHash: BlockContent.DeriveTxHash(txs),\n                        lastCommit: null,\n                        evidenceHash: null),\n                    transactions: txs,\n                    evidence: evs);\n                PreEvaluationBlock preEval1 = content1.Propose();\n\n                HashDigest<SHA256> b1StateRootHash =\n                    blockChain.DetermineNextBlockStateRootHash(genesis, out _);\n                AssertBytesEqual(\n                    b1StateRootHash, blockChain.GetNextStateRootHash(genesis.Hash));\n\n                _output.WriteLine(\"#1 StateRootHash: {0}\", b1StateRootHash);\n                Block block1 = preEval1.Sign(_contents.Block1Key, b1StateRootHash);\n                _output.WriteLine(\"#1: {0}\", block1);\n\n                blockChain.Append(block1, TestUtils.CreateBlockCommit(block1));\n                AssertBencodexEqual(\n                    (Bencodex.Types.Integer)158,\n                    blockChain\n                        .GetNextWorldState()\n                        .GetAccountState(ReservedAddresses.LegacyAccount)\n                        .GetState(address));\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "test/Libplanet.Tests/Blocks/SimpleBlockExcerpt.cs",
    "content": "using Libplanet.Types.Blocks;\n\nnamespace Libplanet.Tests.Blocks\n{\n    public struct SimpleBlockExcerpt : IBlockExcerpt\n    {\n        public SimpleBlockExcerpt(\n            int protocolVersion,\n            long index,\n            BlockHash hash\n        )\n        {\n            ProtocolVersion = protocolVersion;\n            Index = index;\n            Hash = hash;\n        }\n\n        public int ProtocolVersion { get; set; }\n\n        public long Index { get; set; }\n\n        public BlockHash Hash { get; set; }\n\n        public override string ToString() => this.ToExcerptString();\n    }\n}\n"
  },
  {
    "path": "test/Libplanet.Tests/ByteArrayExtensionsTest.cs",
    "content": "using System;\nusing Libplanet.Common;\nusing Xunit;\n\nnamespace Libplanet.Tests\n{\n    public class ByteArrayExtensionsTest\n    {\n        [Fact]\n        public void StartsWith()\n        {\n            byte[] bytes = null;\n\n            Assert.Throws<ArgumentNullException>(() => bytes.StartsWith(new byte[] { 0 }));\n            bytes = new byte[]\n            {\n                0, 1,\n            };\n\n            Assert.Throws<ArgumentNullException>(() => bytes.StartsWith(null));\n\n            Assert.False(bytes.StartsWith(new byte[] { 0, 1, 2 }));\n            Assert.False(bytes.StartsWith(new byte[] { 0, 2 }));\n            Assert.False(bytes.StartsWith(new byte[] { 1 }));\n\n            Assert.True(bytes.StartsWith(new byte[] { 0 }));\n            Assert.True(bytes.StartsWith(new byte[] { 0, 1 }));\n        }\n\n        [Fact]\n        public void IndexOf()\n        {\n            Func<string, byte[]> b = ByteUtil.ParseHex;\n            Assert.Equal(-1, new byte[0].IndexOf(b(\"0a0b0c\")));\n            Assert.Equal(-1, b(\"0a0b\").IndexOf(b(\"0a0b0c\")));\n            Assert.Equal(0, b(\"0a0b0c0d\").IndexOf(b(\"0a0b0c\")));\n            Assert.Equal(1, b(\"0a0b0c0d\").IndexOf(b(\"0b0c0d\")));\n            Assert.Equal(2, b(\"08090a0b0c0d\").IndexOf(b(\"0a0b0c\")));\n            Assert.Equal(-1, b(\"07080a0b0c0d\").IndexOf(b(\"070809\")));\n        }\n    }\n}\n"
  },
  {
    "path": "test/Libplanet.Tests/ByteUtilTest.cs",
    "content": "using System;\nusing System.Collections.Immutable;\nusing Libplanet.Common;\nusing Xunit;\n\nnamespace Libplanet.Tests\n{\n    public class ByteUtilTest\n    {\n        [Fact]\n        public void HexTest()\n        {\n            var bs = new byte[]\n            {\n                0x45, 0xa2, 0x21, 0x87, 0xe2, 0xd8, 0x85, 0x0b, 0xb3, 0x57,\n                0x88, 0x69, 0x58, 0xbc, 0x3e, 0x85, 0x60, 0x92, 0x9c, 0xcc,\n            };\n            const string expectedHex = \"45a22187e2d8850bb357886958bc3e8560929ccc\";\n            Assert.Equal(expectedHex, ByteUtil.Hex(bs));\n            Assert.Equal(expectedHex, ByteUtil.Hex(ImmutableArray.Create(bs)));\n            Assert.Empty(ByteUtil.Hex(default(ImmutableArray<byte>)));\n        }\n\n        [Fact]\n        public void ParseHex()\n        {\n            const string hex = \"45a22187e2d8850bb357886958bc3e8560929ccc\";\n            Assert.Equal(\n                new byte[20]\n                {\n                    0x45, 0xa2, 0x21, 0x87, 0xe2, 0xd8, 0x85, 0x0b, 0xb3, 0x57,\n                    0x88, 0x69, 0x58, 0xbc, 0x3e, 0x85, 0x60, 0x92, 0x9c, 0xcc,\n                },\n                ByteUtil.ParseHex(hex)\n            );\n\n            Assert.Throws<ArgumentOutOfRangeException>(\n                () => ByteUtil.ParseHex(\"abc\")\n            );\n            Assert.Throws<FormatException>(\n                () => ByteUtil.ParseHex(\"abcdefgh\")\n            );\n        }\n\n        [Fact]\n        public void ParseHexToImmutable()\n        {\n            const string hex = \"45a22187e2d8850bb357886958bc3e8560929ccc\";\n            Assert.Equal(\n                new byte[20]\n                {\n                    0x45, 0xa2, 0x21, 0x87, 0xe2, 0xd8, 0x85, 0x0b, 0xb3, 0x57,\n                    0x88, 0x69, 0x58, 0xbc, 0x3e, 0x85, 0x60, 0x92, 0x9c, 0xcc,\n                },\n                ByteUtil.ParseHexToImmutable(hex)\n            );\n\n            Assert.Throws<ArgumentOutOfRangeException>(() => ByteUtil.ParseHexToImmutable(\"abc\"));\n            Assert.Throws<FormatException>(() => ByteUtil.ParseHexToImmutable(\"abcdefgh\"));\n        }\n\n        [Fact]\n        public void CanCalculateHashCode()\n        {\n            var bytes = new byte[20]\n            {\n                0x45, 0xa2, 0x21, 0x87, 0xe2, 0xd8, 0x85, 0x0b, 0xb3, 0x57,\n                0x88, 0x69, 0x58, 0xbc, 0x3e, 0x85, 0x60, 0x92, 0x9c, 0xcc,\n            };\n\n            Assert.Equal(-1026516859, ByteUtil.CalculateHashCode(bytes));\n\n            var otherBytes = TestUtils.GetRandomBytes(20);\n            otherBytes[19] = 0xdd;\n\n            Assert.NotEqual(\n                ByteUtil.CalculateHashCode(bytes),\n                ByteUtil.CalculateHashCode(otherBytes)\n            );\n        }\n\n        [Fact]\n        public void TimingSafelyCompare()\n        {\n            Assert.True(ByteUtil.TimingSafelyCompare(new byte[0], new byte[0]));\n            Assert.False(ByteUtil.TimingSafelyCompare(new byte[] { 0 }, new byte[] { 1 }));\n            Assert.True(ByteUtil.TimingSafelyCompare(new byte[] { 1 }, new byte[] { 1 }));\n            Assert.True(\n                ByteUtil.TimingSafelyCompare(new byte[] { 1, 2, 3, 4 }, new byte[] { 1, 2, 3, 4 })\n            );\n            Assert.False(\n                ByteUtil.TimingSafelyCompare(new byte[] { 1, 2, 3, 4 }, new byte[] { 1, 2, 3, 5 })\n            );\n            Assert.False(\n                ByteUtil.TimingSafelyCompare(new byte[] { 1, 2, 3, 4 }, new byte[] { 1, 2, 3 })\n            );\n        }\n\n        [Fact]\n        public void Satisfies()\n        {\n            Func<string, byte[]> hash = ByteUtil.ParseHex;\n            var emp = new byte[0];\n            var dl1 = hash(\"8ec2f5285c8fc2f5285c8fc2f5285c8fc2f5285c8fc2f5285c8fc2f5285c8f00\");\n            var dl2 = hash(\"e94a399c4fd6d508f022bbee8781a9c44754408bb92ca5b509fa824b00000000\");\n            var dl4 = hash(\"a85f4662e531e44d161346dcaa256af7923c87291b5408b109fa820000000000\");\n\n            Assert.True(ByteUtil.Satisfies(emp, 0));\n            Assert.True(ByteUtil.Satisfies(dl1, 0));\n            Assert.True(ByteUtil.Satisfies(dl2, 0));\n            Assert.True(ByteUtil.Satisfies(dl4, 0));\n\n            Assert.False(ByteUtil.Satisfies(emp, 1));\n            Assert.True(ByteUtil.Satisfies(dl1, 1));\n            Assert.True(ByteUtil.Satisfies(dl2, 1));\n            Assert.True(ByteUtil.Satisfies(dl4, 1));\n\n            Assert.False(ByteUtil.Satisfies(emp, 457));\n            Assert.True(ByteUtil.Satisfies(dl1, 457));\n            Assert.True(ByteUtil.Satisfies(dl2, 457));\n            Assert.True(ByteUtil.Satisfies(dl4, 457));\n\n            Assert.False(ByteUtil.Satisfies(emp, 458));\n            Assert.False(ByteUtil.Satisfies(dl1, 458));\n            Assert.True(ByteUtil.Satisfies(dl2, 458));\n            Assert.True(ByteUtil.Satisfies(dl4, 458));\n\n            Assert.False(ByteUtil.Satisfies(emp, 14560825400));\n            Assert.False(ByteUtil.Satisfies(dl1, 14560825400));\n            Assert.True(ByteUtil.Satisfies(dl2, 14560825400));\n            Assert.True(ByteUtil.Satisfies(dl4, 14560825400));\n\n            Assert.False(ByteUtil.Satisfies(emp, 14560825401));\n            Assert.False(ByteUtil.Satisfies(dl1, 14560825401));\n            Assert.False(ByteUtil.Satisfies(dl2, 14560825401));\n            Assert.True(ByteUtil.Satisfies(dl4, 14560825401));\n        }\n    }\n}\n"
  },
  {
    "path": "test/Libplanet.Tests/Consensus/Maj23MetadataTest.cs",
    "content": "using System;\nusing Libplanet.Consensus;\nusing Libplanet.Crypto;\nusing Libplanet.Types.Blocks;\nusing Libplanet.Types.Consensus;\nusing Xunit;\n\nnamespace Libplanet.Tests.Consensus\n{\n    public class Maj23MetadataTest\n    {\n        private static Bencodex.Codec _codec = new Bencodex.Codec();\n\n        [Fact]\n        public void VoteFlagShouldBePreVoteOrPreCommit()\n        {\n            var hash = new BlockHash(TestUtils.GetRandomBytes(BlockHash.Size));\n\n            // Works with PreVote and PreCommit vote flags.\n            _ = new Maj23Metadata(\n                2, 2, hash, DateTimeOffset.UtcNow, new PrivateKey().PublicKey, VoteFlag.PreVote);\n            _ = new Maj23Metadata(\n                2, 2, hash, DateTimeOffset.UtcNow, new PrivateKey().PublicKey, VoteFlag.PreCommit);\n\n            // Null and Unknown vote flags are not allowed.\n            Assert.Throws<ArgumentException>(() => new Maj23Metadata(\n                2,\n                2,\n                hash,\n                DateTimeOffset.UtcNow,\n                new PrivateKey().PublicKey,\n                VoteFlag.Null));\n            Assert.Throws<ArgumentException>(() => new Maj23Metadata(\n                2,\n                2,\n                hash,\n                DateTimeOffset.UtcNow,\n                new PrivateKey().PublicKey,\n                VoteFlag.Unknown));\n        }\n\n        [Fact]\n        public void Bencoded()\n        {\n            var hash = new BlockHash(TestUtils.GetRandomBytes(BlockHash.Size));\n            var key = new PrivateKey();\n            var expected = new Maj23Metadata(\n                1,\n                2,\n                hash,\n                DateTimeOffset.UtcNow,\n                key.PublicKey,\n                VoteFlag.PreCommit);\n            var decoded = new Maj23Metadata(expected.Encoded);\n            Assert.Equal(expected, decoded);\n        }\n    }\n}\n"
  },
  {
    "path": "test/Libplanet.Tests/Consensus/Maj23Test.cs",
    "content": "using System;\nusing Libplanet.Consensus;\nusing Libplanet.Crypto;\nusing Libplanet.Types.Blocks;\nusing Libplanet.Types.Consensus;\nusing Xunit;\n\nnamespace Libplanet.Tests.Consensus\n{\n    public class Maj23Test\n    {\n        [Fact]\n        public void InvalidSignature()\n        {\n            var hash = new BlockHash(TestUtils.GetRandomBytes(BlockHash.Size));\n\n            Maj23Metadata metadata = new Maj23Metadata(\n                1,\n                0,\n                hash,\n                DateTimeOffset.UtcNow,\n                new PrivateKey().PublicKey,\n                VoteFlag.PreVote);\n\n            // Empty Signature\n            var emptySigBencodex = metadata.Encoded.Add(Maj23.SignatureKey, Array.Empty<byte>());\n            Assert.Throws<ArgumentNullException>(() => new Maj23(emptySigBencodex));\n\n            // Invalid Signature\n            var invSigBencodex = metadata.Encoded.Add(\n                Maj23.SignatureKey,\n                new PrivateKey().Sign(TestUtils.GetRandomBytes(20)));\n            Assert.Throws<ArgumentException>(() => new Maj23(invSigBencodex));\n        }\n\n        [Fact]\n        public void Sign()\n        {\n            var key = new PrivateKey();\n            var hash = new BlockHash(TestUtils.GetRandomBytes(BlockHash.Size));\n\n            Maj23Metadata metadata = new Maj23Metadata(\n                1,\n                0,\n                hash,\n                DateTimeOffset.UtcNow,\n                key.PublicKey,\n                VoteFlag.PreVote);\n            Maj23 maj23 = metadata.Sign(key);\n\n            TestUtils.AssertBytesEqual(maj23.Signature, key.Sign(metadata.ByteArray));\n            Assert.True(key.PublicKey.Verify(metadata.ByteArray, maj23.Signature));\n        }\n    }\n}\n"
  },
  {
    "path": "test/Libplanet.Tests/Consensus/ProposalClaimMetadataTest.cs",
    "content": "using System;\nusing Libplanet.Consensus;\nusing Libplanet.Crypto;\nusing Libplanet.Types.Blocks;\nusing Xunit;\n\nnamespace Libplanet.Tests.Consensus\n{\n    public class ProposalClaimMetadataTest\n    {\n        [Fact]\n        public void Bencoded()\n        {\n            var hash = new BlockHash(TestUtils.GetRandomBytes(BlockHash.Size));\n            var key = new PrivateKey();\n            var expected = new ProposalClaimMetadata(\n                1,\n                2,\n                hash,\n                DateTimeOffset.UtcNow,\n                key.PublicKey);\n            var decoded = new ProposalClaimMetadata(expected.Encoded);\n            Assert.Equal(expected, decoded);\n        }\n    }\n}\n"
  },
  {
    "path": "test/Libplanet.Tests/Consensus/ProposalClaimTest.cs",
    "content": "using System;\nusing Libplanet.Consensus;\nusing Libplanet.Crypto;\nusing Libplanet.Types.Blocks;\nusing Xunit;\n\nnamespace Libplanet.Tests.Consensus\n{\n    public class ProposalClaimTest\n    {\n        [Fact]\n        public void InvalidSignature()\n        {\n            var hash = new BlockHash(TestUtils.GetRandomBytes(BlockHash.Size));\n\n            ProposalClaimMetadata metadata = new ProposalClaimMetadata(\n                1,\n                0,\n                hash,\n                DateTimeOffset.UtcNow,\n                new PrivateKey().PublicKey);\n\n            // Empty Signature\n            var emptySigBencodex = metadata.Encoded.Add(\n                ProposalClaim.SignatureKey,\n                Array.Empty<byte>());\n            Assert.Throws<ArgumentNullException>(() => new ProposalClaim(emptySigBencodex));\n\n            // Invalid Signature\n            var invSigBencodex = metadata.Encoded.Add(\n                ProposalClaim.SignatureKey,\n                new PrivateKey().Sign(TestUtils.GetRandomBytes(20)));\n            Assert.Throws<ArgumentException>(() => new ProposalClaim(invSigBencodex));\n        }\n\n        [Fact]\n        public void Sign()\n        {\n            var key = new PrivateKey();\n            var hash = new BlockHash(TestUtils.GetRandomBytes(BlockHash.Size));\n\n            ProposalClaimMetadata metadata = new ProposalClaimMetadata(\n                1,\n                0,\n                hash,\n                DateTimeOffset.UtcNow,\n                key.PublicKey);\n            ProposalClaim claim = metadata.Sign(key);\n\n            TestUtils.AssertBytesEqual(claim.Signature, key.Sign(metadata.ByteArray));\n            Assert.True(key.PublicKey.Verify(metadata.ByteArray, claim.Signature));\n        }\n    }\n}\n"
  },
  {
    "path": "test/Libplanet.Tests/Consensus/ProposalMetadataTest.cs",
    "content": "using System;\nusing Bencodex;\nusing Libplanet.Consensus;\nusing Libplanet.Crypto;\nusing Libplanet.Tests.Store;\nusing Libplanet.Types.Blocks;\nusing Serilog;\nusing Xunit;\nusing Xunit.Abstractions;\n\nnamespace Libplanet.Tests.Consensus\n{\n    public class ProposalMetadataTest\n    {\n        private ILogger _logger;\n\n        public ProposalMetadataTest(ITestOutputHelper output)\n        {\n            const string outputTemplate =\n                \"{Timestamp:HH:mm:ss:ffffffZ} - {Message}\";\n            Log.Logger = new LoggerConfiguration()\n                .MinimumLevel.Verbose()\n                .WriteTo.TestOutput(output, outputTemplate: outputTemplate)\n                .CreateLogger()\n                .ForContext<ProposalMetadataTest>();\n\n            _logger = Log.ForContext<ProposalMetadataTest>();\n        }\n\n        [Fact]\n        public void InvalidValues()\n        {\n            MemoryStoreFixture fx = new MemoryStoreFixture();\n            var codec = new Codec();\n\n            Assert.Throws<ArgumentOutOfRangeException>(() => new ProposalMetadata(\n                    -1,\n                    0,\n                    DateTimeOffset.UtcNow,\n                    new PrivateKey().PublicKey,\n                    codec.Encode(fx.Block1.MarshalBlock()),\n                    -1));\n\n            Assert.Throws<ArgumentOutOfRangeException>(() => new ProposalMetadata(\n                1,\n                -1,\n                DateTimeOffset.UtcNow,\n                new PrivateKey().PublicKey,\n                codec.Encode(fx.Block1.MarshalBlock()),\n                -1));\n\n            Assert.Throws<ArgumentOutOfRangeException>(() => new ProposalMetadata(\n                1,\n                0,\n                DateTimeOffset.UtcNow,\n                new PrivateKey().PublicKey,\n                codec.Encode(fx.Block1.MarshalBlock()),\n                -2));\n        }\n    }\n}\n"
  },
  {
    "path": "test/Libplanet.Tests/Consensus/ProposalTest.cs",
    "content": "using System;\nusing Bencodex;\nusing Libplanet.Consensus;\nusing Libplanet.Crypto;\nusing Libplanet.Tests.Store;\nusing Libplanet.Types.Blocks;\nusing Serilog;\nusing Xunit;\nusing Xunit.Abstractions;\n\nnamespace Libplanet.Tests.Consensus\n{\n    public class ProposalTest\n    {\n        private ILogger _logger;\n\n        public ProposalTest(ITestOutputHelper output)\n        {\n            const string outputTemplate =\n                \"{Timestamp:HH:mm:ss:ffffffZ} - {Message}\";\n            Log.Logger = new LoggerConfiguration()\n                .MinimumLevel.Verbose()\n                .WriteTo.TestOutput(output, outputTemplate: outputTemplate)\n                .CreateLogger()\n                .ForContext<ProposalTest>();\n\n            _logger = Log.ForContext<ProposalTest>();\n        }\n\n        [Fact]\n        public void InvalidSignature()\n        {\n            MemoryStoreFixture fx = new MemoryStoreFixture();\n            var codec = new Codec();\n\n            ProposalMetadata metadata = new ProposalMetadata(\n                1,\n                0,\n                DateTimeOffset.UtcNow,\n                new PrivateKey().PublicKey,\n                codec.Encode(fx.Block1.MarshalBlock()),\n                -1);\n\n            // Empty Signature\n            var emptySigBencodex = metadata.Encoded.Add(Proposal.SignatureKey, Array.Empty<byte>());\n            Assert.Throws<ArgumentNullException>(() => new Proposal(emptySigBencodex));\n\n            // Invalid Signature\n            var invSigBencodex = metadata.Encoded.Add(\n                Proposal.SignatureKey,\n                new PrivateKey().Sign(codec.Encode(fx.Block2.MarshalBlock())));\n            Assert.Throws<ArgumentException>(() => new Proposal(invSigBencodex));\n        }\n\n        [Fact]\n        public void Sign()\n        {\n            MemoryStoreFixture fx = new MemoryStoreFixture();\n            var codec = new Codec();\n            var key = new PrivateKey();\n\n            ProposalMetadata metadata = new ProposalMetadata(\n                1,\n                0,\n                DateTimeOffset.UtcNow,\n                key.PublicKey,\n                codec.Encode(fx.Block1.MarshalBlock()),\n                -1);\n            Proposal proposal = metadata.Sign(key);\n\n            TestUtils.AssertBytesEqual(proposal.Signature, key.Sign(metadata.ByteArray));\n            Assert.True(key.PublicKey.Verify(metadata.ByteArray, proposal.Signature));\n        }\n    }\n}\n"
  },
  {
    "path": "test/Libplanet.Tests/Consensus/ValidatorSetTest.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Collections.Immutable;\nusing System.Linq;\nusing System.Numerics;\nusing Libplanet.Crypto;\nusing Libplanet.Types.Blocks;\nusing Libplanet.Types.Consensus;\nusing Xunit;\n\nnamespace Libplanet.Tests.Consensus\n{\n    public class ValidatorSetTest\n    {\n        [Fact]\n        public void DuplicateValidatorPublicKeyNotAllowed()\n        {\n            List<PublicKey> publicKeys = Enumerable\n                .Range(0, 5).Select(_ => new PrivateKey().PublicKey).ToList();\n            var validators = publicKeys\n                .Select(publicKey => new Validator(publicKey, BigInteger.One))\n                .Append(new Validator(publicKeys.Last(), BigInteger.One))\n                .ToList();\n            Assert.Throws<ArgumentException>(() => new ValidatorSet(validators));\n        }\n\n        [Fact]\n        public void ZeroPowerValidatorNotAllowed()\n        {\n            List<PublicKey> publicKeys = Enumerable\n                .Range(0, 4).Select(_ => new PrivateKey().PublicKey).ToList();\n            var zeroPowerValidator = new Validator(new PrivateKey().PublicKey, BigInteger.Zero);\n            var validators = publicKeys\n                .Select(publicKey => new Validator(publicKey, BigInteger.One))\n                .Append(zeroPowerValidator)\n                .ToList();\n            Assert.Throws<ArgumentException>(() => new ValidatorSet(validators));\n        }\n\n        [Fact]\n        public void ValidatorsAreOrderedByAddress()\n        {\n            List<PublicKey> publicKeys = Enumerable\n                .Range(0, 10)\n                .Select(_ => new PrivateKey().PublicKey)\n                .ToList();\n            ValidatorSet validatorSet = new ValidatorSet(publicKeys.Select(\n                publicKey => new Validator(publicKey, BigInteger.One)).ToList());\n            TestUtils.AssertSorted(validatorSet.Validators.Select(\n                validator => validator.OperatorAddress));\n        }\n\n        [Fact]\n        public void ValidatorCount()\n        {\n            List<PublicKey> publicKeys = Enumerable\n                .Range(0, 10)\n                .Select(_ => new PrivateKey().PublicKey)\n                .ToList();\n            ValidatorSet validatorSet = new ValidatorSet(publicKeys.Select(\n                publicKey => new Validator(publicKey, BigInteger.One)).ToList());\n            Assert.Equal(10, validatorSet.TotalCount);\n            Assert.Equal(6, validatorSet.TwoThirdsCount);\n            Assert.Equal(3, validatorSet.OneThirdCount);\n        }\n\n        [Fact]\n        public void ValidatorTotalPower()\n        {\n            List<PublicKey> publicKeys = Enumerable\n                .Range(0, 10)\n                .Select(_ => new PrivateKey().PublicKey)\n                .ToList();\n            ValidatorSet validatorSet = new ValidatorSet(publicKeys.Select(\n                publicKey => new Validator(publicKey, BigInteger.One)).ToList());\n            Assert.Equal(10, validatorSet.TotalPower);\n            Assert.Equal(6, validatorSet.TwoThirdsPower);\n            Assert.Equal(3, validatorSet.OneThirdPower);\n        }\n\n        [Fact]\n        public void Update()\n        {\n            List<Validator> validators = Enumerable\n                .Range(0, 10)\n                .Select(_ => new Validator(new PrivateKey().PublicKey, BigInteger.One))\n                .ToList();\n            ValidatorSet validatorSet = new ValidatorSet(validators);\n\n            Assert.True(validatorSet.Validators.All(v => v.Power.Equals(BigInteger.One)));\n\n            // Add a new validator\n            var newValidator = new Validator(new PrivateKey().PublicKey, BigInteger.One);\n            var addValidatorSet = validatorSet.Update(newValidator);\n            Assert.Contains(newValidator, addValidatorSet.Validators);\n            Assert.Equal(11, addValidatorSet.Validators.Count);\n\n            // Modify an existing validator\n            var modValidator = new Validator(validators[3].PublicKey, new BigInteger(3));\n            var modValidatorSet = validatorSet.Update(modValidator);\n            Assert.Contains(modValidator, modValidatorSet.Validators);\n            Assert.Equal(10, modValidatorSet.Validators.Count);\n\n            // Remove a non-existing validator\n            var zeroPowerValidator = new Validator(new PrivateKey().PublicKey, BigInteger.Zero);\n            var noopValidatorSet = validatorSet.Update(zeroPowerValidator);\n            Assert.Equal(validatorSet, noopValidatorSet);\n\n            // Remove an existing validator\n            var subValidator = new Validator(validators[3].PublicKey, BigInteger.Zero);\n            var subValidatorSet = validatorSet.Update(subValidator);\n            Assert.DoesNotContain(subValidator.PublicKey, subValidatorSet.PublicKeys);\n            Assert.Equal(9, subValidatorSet.Validators.Count);\n        }\n\n        [Fact]\n        public void ValidateBlockCommitValidators()\n        {\n            Random random = new Random();\n            long height = 3;\n            int round = 5;\n            BlockHash hash = random.NextBlockHash();\n\n            var unorderedPrivateKeys = Enumerable\n                .Range(0, 10)\n                .Select(_ => new PrivateKey())\n                .ToList();\n            var orderedPrivateKeys = unorderedPrivateKeys\n                .OrderBy(key => key.Address)\n                .ToList();\n            var validatorSet = new ValidatorSet(unorderedPrivateKeys.Select(\n                key => new Validator(key.PublicKey, BigInteger.One)).ToList());\n            var unorderedVotes = unorderedPrivateKeys\n                .Select(\n                    key => new VoteMetadata(\n                        height,\n                        round,\n                        hash,\n                        DateTimeOffset.UtcNow,\n                        key.PublicKey,\n                        BigInteger.One,\n                        VoteFlag.PreCommit).Sign(key))\n                .ToImmutableArray();\n            var orderedVotes = orderedPrivateKeys\n                .Select(\n                    key => new VoteMetadata(\n                        height,\n                        round,\n                        hash,\n                        DateTimeOffset.UtcNow,\n                        key.PublicKey,\n                        BigInteger.One,\n                        VoteFlag.PreCommit).Sign(key))\n                .ToImmutableArray();\n            var invalidPowerVotes = orderedPrivateKeys\n                .Select(\n                    key => new VoteMetadata(\n                        height,\n                        round,\n                        hash,\n                        DateTimeOffset.UtcNow,\n                        key.PublicKey,\n                        2,\n                        VoteFlag.PreCommit).Sign(key))\n                .ToImmutableArray();\n\n            var blockCommitWithUnorderedVotes =\n                new BlockCommit(height, round, hash, unorderedVotes);\n            var blockCommitWithInvalidPowerVotes =\n                new BlockCommit(height, round, hash, invalidPowerVotes);\n            var blockCommitWithInsufficientVotes =\n                new BlockCommit(height, round, hash, orderedVotes.Take(5).ToImmutableArray());\n            var validBlockCommit = new BlockCommit(height, round, hash, orderedVotes);\n\n            Assert.Throws<InvalidBlockCommitException>(() =>\n                validatorSet.ValidateBlockCommitValidators(blockCommitWithUnorderedVotes));\n            Assert.Throws<InvalidBlockCommitException>(() =>\n                validatorSet.ValidateBlockCommitValidators(blockCommitWithInvalidPowerVotes));\n            Assert.Throws<InvalidBlockCommitException>(() =>\n                validatorSet.ValidateBlockCommitValidators(blockCommitWithInsufficientVotes));\n            validatorSet.ValidateBlockCommitValidators(validBlockCommit);\n        }\n    }\n}\n"
  },
  {
    "path": "test/Libplanet.Tests/Consensus/ValidatorTest.cs",
    "content": "using System;\nusing System.Numerics;\nusing Libplanet.Crypto;\nusing Libplanet.Types.Consensus;\nusing Xunit;\n\nnamespace Libplanet.Tests.Consensus\n{\n    public class ValidatorTest\n    {\n        [Fact]\n        public void Constructor()\n        {\n            var publicKey = new PrivateKey().PublicKey;\n            var power = new BigInteger(1);\n            var validator = new Validator(publicKey, power);\n            Assert.Equal(publicKey, validator.PublicKey);\n            Assert.Equal(power, validator.Power);\n\n            var negativePower = new BigInteger(-1);\n            Assert.Throws<ArgumentOutOfRangeException>(\n                () => new Validator(publicKey, negativePower));\n        }\n\n        [Fact]\n        public void Marshalling()\n        {\n            PublicKey publicKey = new PrivateKey().PublicKey;\n            Validator validator = new Validator(publicKey, BigInteger.One);\n            Validator unmarshalledValidator = new Validator(validator.Bencoded);\n            Assert.Equal(validator, unmarshalledValidator);\n            Assert.Equal(validator.PublicKey, unmarshalledValidator.PublicKey);\n            Assert.Equal(validator.Power, unmarshalledValidator.Power);\n        }\n    }\n}\n"
  },
  {
    "path": "test/Libplanet.Tests/Consensus/VoteMetadataTest.cs",
    "content": "using System;\nusing System.Numerics;\nusing Libplanet.Crypto;\nusing Libplanet.Types.Blocks;\nusing Libplanet.Types.Consensus;\nusing Xunit;\n\nnamespace Libplanet.Tests.Consensus\n{\n    public class VoteMetadataTest\n    {\n        private static Bencodex.Codec _codec = new Bencodex.Codec();\n\n        [Fact]\n        public void NullBlockHashNotAllowedForNullAndUnknown()\n        {\n            var hash = new BlockHash(TestUtils.GetRandomBytes(BlockHash.Size));\n\n            // Works with some hash value.\n            _ = new VoteMetadata(\n                2,\n                2,\n                hash,\n                DateTimeOffset.UtcNow,\n                new PrivateKey().PublicKey,\n                BigInteger.One,\n                VoteFlag.Null);\n            _ = new VoteMetadata(\n                2,\n                2,\n                hash,\n                DateTimeOffset.UtcNow,\n                new PrivateKey().PublicKey,\n                BigInteger.One,\n                VoteFlag.Unknown);\n\n            // Null hash is not allowed.\n            Assert.Throws<ArgumentException>(() => new VoteMetadata(\n                2,\n                2,\n                default,\n                DateTimeOffset.UtcNow,\n                new PrivateKey().PublicKey,\n                BigInteger.One,\n                VoteFlag.Null));\n            Assert.Throws<ArgumentException>(() => new VoteMetadata(\n                2,\n                2,\n                default,\n                DateTimeOffset.UtcNow,\n                new PrivateKey().PublicKey,\n                BigInteger.One,\n                VoteFlag.Unknown));\n        }\n\n        [Fact]\n        public void Bencoded()\n        {\n            var hash = new BlockHash(TestUtils.GetRandomBytes(BlockHash.Size));\n            var key = new PrivateKey();\n            var expected = new VoteMetadata(\n                1,\n                2,\n                hash,\n                DateTimeOffset.UtcNow,\n                key.PublicKey,\n                BigInteger.One,\n                VoteFlag.PreCommit);\n            var decoded = new VoteMetadata(expected.Bencoded);\n            Assert.Equal(expected, decoded);\n\n            expected = new VoteMetadata(\n                1,\n                2,\n                hash,\n                DateTimeOffset.UtcNow,\n                key.PublicKey,\n                null,\n                VoteFlag.PreCommit);\n            decoded = new VoteMetadata(expected.Bencoded);\n            Assert.Equal(expected, decoded);\n        }\n    }\n}\n"
  },
  {
    "path": "test/Libplanet.Tests/Consensus/VoteSetBitsMetadataTest.cs",
    "content": "using System;\nusing Libplanet.Consensus;\nusing Libplanet.Crypto;\nusing Libplanet.Types.Blocks;\nusing Libplanet.Types.Consensus;\nusing Xunit;\n\nnamespace Libplanet.Tests.Consensus\n{\n    public class VoteSetBitsMetadataTest\n    {\n        [Fact]\n        public void Bencoded()\n        {\n            var hash = new BlockHash(TestUtils.GetRandomBytes(BlockHash.Size));\n            var key = new PrivateKey();\n            var voteBits = new[] { true, true, false, false };\n            var expected = new VoteSetBitsMetadata(\n                1,\n                2,\n                hash,\n                DateTimeOffset.UtcNow,\n                key.PublicKey,\n                VoteFlag.PreCommit,\n                voteBits);\n            var decoded = new VoteSetBitsMetadata(expected.Encoded);\n            Assert.Equal(expected, decoded);\n        }\n    }\n}\n"
  },
  {
    "path": "test/Libplanet.Tests/Consensus/VoteSetBitsTest.cs",
    "content": "using System;\nusing Libplanet.Consensus;\nusing Libplanet.Crypto;\nusing Libplanet.Types.Blocks;\nusing Libplanet.Types.Consensus;\nusing Xunit;\n\nnamespace Libplanet.Tests.Consensus\n{\n    public class VoteSetBitsTest\n    {\n        [Fact]\n        public void InvalidSignature()\n        {\n            var hash = new BlockHash(TestUtils.GetRandomBytes(BlockHash.Size));\n\n            VoteSetBitsMetadata metadata = new VoteSetBitsMetadata(\n                1,\n                0,\n                hash,\n                DateTimeOffset.UtcNow,\n                new PrivateKey().PublicKey,\n                VoteFlag.PreVote,\n                new[] { true, true, false, false });\n\n            // Empty Signature\n            var emptySigBencodex = metadata.Encoded.Add(\n                VoteSetBits.SignatureKey,\n                Array.Empty<byte>());\n            Assert.Throws<ArgumentNullException>(() => new VoteSetBits(emptySigBencodex));\n\n            // Invalid Signature\n            var invSigBencodex = metadata.Encoded.Add(\n                VoteSetBits.SignatureKey,\n                new PrivateKey().Sign(TestUtils.GetRandomBytes(20)));\n            Assert.Throws<ArgumentException>(() => new VoteSetBits(invSigBencodex));\n        }\n\n        [Fact]\n        public void Sign()\n        {\n            var key = new PrivateKey();\n            var hash = new BlockHash(TestUtils.GetRandomBytes(BlockHash.Size));\n\n            VoteSetBitsMetadata metadata = new VoteSetBitsMetadata(\n                1,\n                0,\n                hash,\n                DateTimeOffset.UtcNow,\n                key.PublicKey,\n                VoteFlag.PreVote,\n                new[] { true, true, false, false });\n            VoteSetBits voteSetBits = metadata.Sign(key);\n\n            TestUtils.AssertBytesEqual(voteSetBits.Signature, key.Sign(metadata.ByteArray));\n            Assert.True(key.PublicKey.Verify(metadata.ByteArray, voteSetBits.Signature));\n        }\n    }\n}\n"
  },
  {
    "path": "test/Libplanet.Tests/Consensus/VoteTest.cs",
    "content": "using System;\nusing System.Collections.Immutable;\nusing System.Numerics;\nusing Libplanet.Crypto;\nusing Libplanet.Types.Blocks;\nusing Libplanet.Types.Consensus;\nusing Xunit;\n\nnamespace Libplanet.Tests.Consensus\n{\n    public class VoteTest\n    {\n        private static Bencodex.Codec _codec = new Bencodex.Codec();\n\n        [Fact]\n        public void Sign()\n        {\n            var hash = new BlockHash(TestUtils.GetRandomBytes(BlockHash.Size));\n            var privateKey = new PrivateKey();\n            var voteMetadata = new VoteMetadata(\n                1,\n                2,\n                hash,\n                DateTimeOffset.UtcNow,\n                privateKey.PublicKey,\n                BigInteger.One,\n                VoteFlag.PreCommit);\n            Vote vote = voteMetadata.Sign(privateKey);\n            Assert.True(\n                privateKey.PublicKey.Verify(_codec.Encode(voteMetadata.Bencoded), vote.Signature));\n\n            var nullPowerVoteMetadata = new VoteMetadata(\n                1,\n                2,\n                hash,\n                DateTimeOffset.UtcNow,\n                privateKey.PublicKey,\n                null,\n                VoteFlag.PreCommit);\n            Vote nullPowerVote = nullPowerVoteMetadata.Sign(privateKey);\n            Assert.True(\n                privateKey.PublicKey.Verify(\n                    _codec.Encode(nullPowerVoteMetadata.Bencoded),\n                    nullPowerVote.Signature));\n        }\n\n        [Fact]\n        public void CannotSignWithWrongPrivateKey()\n        {\n            var hash = new BlockHash(TestUtils.GetRandomBytes(BlockHash.Size));\n            var validatorPublicKey = new PrivateKey().PublicKey;\n            var key = new PrivateKey();\n            var voteMetadata = new VoteMetadata(\n                height: 2,\n                round: 3,\n                blockHash: hash,\n                timestamp: DateTimeOffset.UtcNow,\n                validatorPublicKey: validatorPublicKey,\n                validatorPower: BigInteger.One,\n                flag: VoteFlag.PreCommit);\n\n            // Cannot sign with Sign method\n            Assert.Throws<ArgumentException>(() => voteMetadata.Sign(key));\n\n            // Cannot bypass by attaching signature\n            Assert.Throws<ArgumentException>(() =>\n                new Vote(\n                    voteMetadata,\n                    key.Sign(_codec.Encode(voteMetadata.Bencoded).ToImmutableArray())));\n        }\n\n        [Fact]\n        public void EmptySignatureNotAllowedForPreVoteAndPreCommit()\n        {\n            var hash = new BlockHash(TestUtils.GetRandomBytes(BlockHash.Size));\n            var key = new PrivateKey();\n            var preVoteMetadata = new VoteMetadata(\n                height: 2,\n                round: 3,\n                blockHash: hash,\n                timestamp: DateTimeOffset.UtcNow,\n                validatorPublicKey: key.PublicKey,\n                validatorPower: BigInteger.One,\n                flag: VoteFlag.PreVote);\n            var preCommitMetadata = new VoteMetadata(\n                height: 2,\n                round: 3,\n                blockHash: hash,\n                timestamp: DateTimeOffset.UtcNow,\n                validatorPublicKey: key.PublicKey,\n                validatorPower: BigInteger.One,\n                flag: VoteFlag.PreCommit);\n\n            // Works fine.\n            _ = preVoteMetadata.Sign(key);\n            _ = preCommitMetadata.Sign(key);\n\n            Assert.Throws<ArgumentException>(() => preVoteMetadata.Sign(null));\n            Assert.Throws<ArgumentException>(() =>\n                new Vote(preVoteMetadata, ImmutableArray<byte>.Empty));\n            Assert.Throws<ArgumentException>(() => preCommitMetadata.Sign(null));\n            Assert.Throws<ArgumentException>(() =>\n                new Vote(preCommitMetadata, ImmutableArray<byte>.Empty));\n        }\n\n        [Fact]\n        public void NonEmptySignatureNotAllowedForNullAndUnknown()\n        {\n            var hash = new BlockHash(TestUtils.GetRandomBytes(BlockHash.Size));\n            var key = new PrivateKey();\n            var nullMetadata = new VoteMetadata(\n                height: 2,\n                round: 3,\n                blockHash: hash,\n                timestamp: DateTimeOffset.UtcNow,\n                validatorPublicKey: key.PublicKey,\n                validatorPower: BigInteger.One,\n                flag: VoteFlag.Null);\n            var unknownMetadata = new VoteMetadata(\n                height: 2,\n                round: 3,\n                blockHash: hash,\n                timestamp: DateTimeOffset.UtcNow,\n                validatorPublicKey: key.PublicKey,\n                validatorPower: BigInteger.One,\n                flag: VoteFlag.Unknown);\n\n            // Works fine.\n            _ = nullMetadata.Sign(null);\n            _ = unknownMetadata.Sign(null);\n\n            Assert.Throws<ArgumentException>(() => nullMetadata.Sign(key));\n            Assert.Throws<ArgumentException>(() =>\n                new Vote(\n                    nullMetadata,\n                    key.Sign(_codec.Encode(nullMetadata.Bencoded)).ToImmutableArray()));\n            Assert.Throws<ArgumentException>(() => unknownMetadata.Sign(key));\n            Assert.Throws<ArgumentException>(() =>\n                new Vote(\n                    unknownMetadata,\n                    key.Sign(_codec.Encode(unknownMetadata.Bencoded)).ToImmutableArray()));\n        }\n\n        [Fact]\n        public void DefaultSignatureIsInvalid()\n        {\n            var voteMetadata = new VoteMetadata(\n                0,\n                0,\n                default,\n                DateTimeOffset.UtcNow,\n                new PrivateKey().PublicKey,\n                BigInteger.One,\n                VoteFlag.PreCommit);\n            Assert.Throws<ArgumentException>(() => new Vote(voteMetadata, default));\n        }\n\n        [Fact]\n        public void Bencoded()\n        {\n            var hash = new BlockHash(TestUtils.GetRandomBytes(BlockHash.Size));\n            var key = new PrivateKey();\n            var expected = new VoteMetadata(\n                1,\n                2,\n                hash,\n                DateTimeOffset.UtcNow,\n                key.PublicKey,\n                BigInteger.One,\n                VoteFlag.PreCommit).Sign(key);\n            var decoded = new Vote(expected.Bencoded);\n            Assert.Equal(expected, decoded);\n        }\n    }\n}\n"
  },
  {
    "path": "test/Libplanet.Tests/Crypto/PrivateKeyTest.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Collections.Immutable;\nusing System.Linq;\nusing System.Text;\nusing Libplanet.Common;\nusing Libplanet.Crypto;\nusing Xunit;\nusing static Libplanet.Tests.TestUtils;\n\nnamespace Libplanet.Tests.Crypto\n{\n    public class PrivateKeyTest\n    {\n        [Fact]\n        public void FromString()\n        {\n            Assert.Throws<ArgumentOutOfRangeException>(() => PrivateKey.FromString(string.Empty));\n            Assert.Throws<ArgumentOutOfRangeException>(() => PrivateKey.FromString(\"a\"));\n            Assert.Throws<ArgumentOutOfRangeException>(() => PrivateKey.FromString(\"870912\"));\n            Assert.Throws<ArgumentOutOfRangeException>(() =>\n                PrivateKey.FromString(\n                    \"00000000000000000000000000000000000000000000000000000000870912\"\n                )\n            );\n            Assert.Throws<ArgumentOutOfRangeException>(() =>\n                PrivateKey.FromString(\n                    \"000000000000000000000000000000000000000000000000000000000000870912\"\n                )\n            );\n            Assert.Throws<FormatException>(() => PrivateKey.FromString(\"zz\"));\n            PrivateKey actual = PrivateKey.FromString(\n                \"e07107ca4b0d19147fa1152a0f2c7884705d59cbb6318e2f901bd28dd9ff78e3\"\n            );\n            AssertBytesEqual(\n                new byte[]\n                {\n                    0xe0, 0x71, 0x07, 0xca, 0x4b, 0x0d, 0x19, 0x14, 0x7f, 0xa1, 0x15,\n                    0x2a, 0x0f, 0x2c, 0x78, 0x84, 0x70, 0x5d, 0x59, 0xcb, 0xb6, 0x31,\n                    0x8e, 0x2f, 0x90, 0x1b, 0xd2, 0x8d, 0xd9, 0xff, 0x78, 0xe3,\n                },\n                actual.ToByteArray()\n            );\n        }\n\n        [Fact]\n        public void BytesTest()\n        {\n            var bs = new byte[]\n            {\n                0x98, 0x66, 0x98, 0x50, 0x72, 0x8c, 0x6c, 0x41, 0x0b, 0xf4,\n                0x2c, 0x45, 0xfe, 0x7c, 0x49, 0x23, 0x2d, 0x14, 0xcf, 0xb5,\n                0x5b, 0x78, 0x4d, 0x81, 0x35, 0xae, 0x40, 0x4c, 0x7c, 0x24,\n                0x3f, 0xc7,\n            };\n            var key = new PrivateKey(bs);\n            Assert.Equal(bs, key.ToByteArray());\n            key = new PrivateKey(bs.ToImmutableArray());\n            Assert.Equal(bs, key.ByteArray);\n        }\n\n        [Fact]\n        public void BytesSanityCheckTest()\n        {\n            Assert.Throws<ArgumentOutOfRangeException>(\n                () => new PrivateKey(new byte[] { 0x87, 0x09, 0x12 })\n             );\n            Assert.Throws<ArgumentOutOfRangeException>(() =>\n                new PrivateKey(new byte[31]\n                {\n                    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,\n                    0x87, 0x09, 0x12,\n                })\n            );\n            Assert.Throws<ArgumentOutOfRangeException>(() =>\n                new PrivateKey(new byte[33]\n                {\n                    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,\n                    0x87, 0x09, 0x12,\n                })\n            );\n\n            var bs = new byte[20]\n            {\n                0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,\n                0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,\n            };\n            Assert.Throws<ArgumentException>(() => new PrivateKey(bs));\n            ImmutableArray<byte> ibs = bs.ToImmutableArray();\n            Assert.Throws<ArgumentException>(() => new PrivateKey(ibs));\n        }\n\n        [Fact]\n        public void PublicKeyTest()\n        {\n            byte[] keyBytes =\n            {\n                0x82, 0xfc, 0x99, 0x47, 0xe8, 0x78, 0xfc, 0x7e, 0xd0, 0x1c,\n                0x6c, 0x31, 0x06, 0x88, 0x60, 0x3f, 0x0a, 0x41, 0xc8, 0xe8,\n                0x70, 0x4e, 0x5b, 0x99, 0x0e, 0x83, 0x88, 0x34, 0x3b, 0x0f,\n                0xd4, 0x65,\n            };\n            var expected = new byte[]\n            {\n                0x04, 0xc7, 0xc6, 0x74, 0xa2, 0x23, 0x66, 0x1f, 0xae, 0xfe,\n                0xd8, 0x51, 0x5f, 0xeb, 0xac, 0xc4, 0x11, 0xc0, 0xf3, 0x56,\n                0x9c, 0x10, 0xc6, 0x5e, 0xc8, 0x6c, 0xdc, 0xe4, 0xd8, 0x5c,\n                0x7e, 0xa2, 0x6c, 0x61, 0x7f, 0x0c, 0xf1, 0x9c, 0xe0, 0xb1,\n                0x06, 0x86, 0x50, 0x1e, 0x57, 0xaf, 0x1a, 0x70, 0x02, 0x28,\n                0x2f, 0xef, 0xa5, 0x28, 0x45, 0xbe, 0x22, 0x67, 0xd1, 0xf4,\n                0xd7, 0xaf, 0x32, 0x29, 0x74,\n            };\n\n            Assert.Equal(expected, new PrivateKey(keyBytes).PublicKey.Format(false));\n            Assert.Equal(\n                expected,\n                new PrivateKey(keyBytes.ToImmutableArray()).PublicKey.Format(false)\n            );\n        }\n\n        [Fact]\n        public void AddressTest()\n        {\n            var privateKey = new PrivateKey(\n                new byte[]\n                {\n                    0xbe, 0xe6, 0xf9, 0xcc, 0x62, 0x41, 0x27, 0x60, 0xb3, 0x69, 0x6e,\n                    0x05, 0xf6, 0xfb, 0x4a, 0xbe, 0xb9, 0xe8, 0x3c, 0x4f, 0x94, 0x4f,\n                    0x83, 0xfd, 0x62, 0x08, 0x1b, 0x74, 0x54, 0xcb, 0xc0, 0x38,\n                }\n            );\n            var expected = new Address(\"f45A22dD63f6428e85eE0a6E13a763278f57626d\");\n            Assert.Equal(expected, privateKey.Address);\n        }\n\n        [Fact]\n        public void SignTest()\n        {\n            var pk = new PrivateKey(\n                new byte[]\n                {\n                    0x52, 0x09, 0x38, 0xfa, 0xe0, 0x79, 0x78, 0x95, 0x61, 0x26,\n                    0x8c, 0x29, 0x33, 0xf6, 0x36, 0xd8, 0xb5, 0xa0, 0x01, 0x1e,\n                    0xa0, 0x41, 0x12, 0xdb, 0xab, 0xab, 0xf2, 0x95, 0xe5, 0xdd,\n                    0xef, 0x88,\n                }\n            );\n            var pubKey = pk.PublicKey;\n            var wrongPubKey = new PrivateKey().PublicKey;\n            var payload = new byte[]\n            {\n                0x64, 0x37, 0x3a, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73,\n                0x6c, 0x65, 0x31, 0x30, 0x3a, 0x70, 0x75, 0x62, 0x6c, 0x69,\n                0x63, 0x5f, 0x6b, 0x65, 0x79, 0x36, 0x35, 0x3a, 0x04, 0xb5,\n                0xa2, 0x4a, 0xa2, 0x11, 0x27, 0x20, 0x42, 0x3b, 0xad, 0x39,\n                0xa0, 0x20, 0x51, 0x82, 0x37, 0x9d, 0x6f, 0x2b, 0x33, 0xe3,\n                0x48, 0x7c, 0x9a, 0xb6, 0xcc, 0x8f, 0xc4, 0x96, 0xf8, 0xa5,\n                0x48, 0x34, 0x40, 0xef, 0xbb, 0xef, 0x06, 0x57, 0xac, 0x2e,\n                0xf6, 0xc6, 0xee, 0x05, 0xdb, 0x06, 0xa9, 0x45, 0x32, 0xfd,\n                0xa7, 0xdd, 0xc4, 0x4a, 0x16, 0x95, 0xe5, 0xce, 0x1a, 0x3d,\n                0x3c, 0x76, 0xdb, 0x39, 0x3a, 0x72, 0x65, 0x63, 0x69, 0x70,\n                0x69, 0x65, 0x6e, 0x74, 0x32, 0x30, 0x3a, 0x8a, 0xe7, 0x2e,\n                0xfa, 0xb0, 0x95, 0x94, 0x66, 0x51, 0x12, 0xe6, 0xd4, 0x9d,\n                0xfd, 0x19, 0x41, 0x53, 0x8c, 0xf3, 0x74, 0x36, 0x3a, 0x73,\n                0x65, 0x6e, 0x64, 0x65, 0x72, 0x32, 0x30, 0x3a, 0xb6, 0xc0,\n                0x3d, 0xe5, 0x7d, 0xdf, 0x03, 0x69, 0xc7, 0x20, 0x7d, 0x2d,\n                0x11, 0x3a, 0xdf, 0xf8, 0x20, 0x51, 0x99, 0xcf, 0x39, 0x3a,\n                0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x32,\n                0x37, 0x3a, 0x32, 0x30, 0x31, 0x38, 0x2d, 0x30, 0x31, 0x2d,\n                0x30, 0x32, 0x54, 0x30, 0x33, 0x3a, 0x30, 0x34, 0x3a, 0x30,\n                0x35, 0x2e, 0x30, 0x30, 0x36, 0x30, 0x30, 0x30, 0x5a, 0x65,\n            };\n\n            // byte[] API:\n            Assert.True(pubKey.Verify(payload, pk.Sign(payload)));\n            Assert.False(pubKey.Verify(payload.Skip(1).ToArray(), pk.Sign(payload)));\n            Assert.False(pubKey.Verify(payload, pk.Sign(payload).Skip(1).ToArray()));\n            Assert.False(wrongPubKey.Verify(payload, pk.Sign(payload)));\n            Assert.True(pubKey.Verify(payload, pk.Sign(payload)));\n\n            // ImmutableArray<byte> API:\n            var imPayload = payload.ToImmutableArray();\n            Assert.False(pubKey.Verify(payload.Skip(1).ToArray(), pk.Sign(imPayload).ToArray()));\n            Assert.False(pubKey.Verify(payload, pk.Sign(imPayload).Skip(1).ToArray()));\n            Assert.False(wrongPubKey.Verify(payload, pk.Sign(imPayload).ToArray()));\n        }\n\n        [Fact]\n        public void ExchangeTest()\n        {\n            PrivateKey prvKey = PrivateKey.FromString(\n                \"82fc9947e878fc7ed01c6c310688603f0a41c8e8704e5b990e8388343b0fd465\"\n            );\n            byte[] pubkeyBytes = ByteUtil.ParseHex(\n                \"5f706787ac72c1080275c1f398640fb07e9da0b124ae9734b28b8d0f01eda586\"\n            );\n            var pubKey = new PrivateKey(pubkeyBytes).PublicKey;\n\n            var expected = new SymmetricKey(\n                new byte[]\n                {\n                    0x59, 0x35, 0xd0, 0x47, 0x6a, 0xf9, 0xdf, 0x29, 0x98, 0xef,\n                    0xb6, 0x03, 0x83, 0xad, 0xf2, 0xff, 0x23, 0xbc, 0x92, 0x83,\n                    0x22, 0xcf, 0xbb, 0x73, 0x8f, 0xca, 0x88, 0xe4, 0x9d, 0x55,\n                    0x7d, 0x7e,\n                }\n            );\n            SymmetricKey actual = prvKey.ExchangeKey(pubKey);\n\n            Assert.Equal(expected, actual);\n        }\n\n        [Fact]\n        public void Decrypt()\n        {\n            var prvKey = new PrivateKey(\n                new byte[]\n                {\n                    0xfb, 0xc2, 0x00, 0x42, 0xb3, 0xa7, 0x07, 0xa7, 0xd5, 0xa1,\n                    0xfa, 0x57, 0x71, 0x71, 0xf4, 0x9c, 0xd3, 0xa9, 0xe6, 0x7a,\n                    0xb9, 0x29, 0x57, 0x57, 0xc7, 0x14, 0xe3, 0xf2, 0xf8, 0xc2,\n                    0xd5, 0x73,\n                }\n            );\n            var cipherText = new byte[]\n            {\n                0x03, 0xe3, 0x1a, 0x0d, 0xea, 0x31, 0xe2, 0xb1, 0x32, 0x7b,\n                0xd8, 0x70, 0x0a, 0xd3, 0x57, 0xcc, 0x69, 0x31, 0x4e, 0xca,\n                0xd7, 0x0a, 0xe2, 0xe4, 0xfa, 0x55, 0x17, 0xa3, 0x3b, 0x67,\n                0xcf, 0xb1, 0xc4, 0xfa, 0xa1, 0x10, 0xd4, 0xd2, 0x73, 0x11,\n                0xef, 0xf1, 0x47, 0x99, 0xd7, 0x3d, 0x3c, 0xaa, 0xa2, 0x0e,\n                0x35, 0x7c, 0x41, 0xc8, 0x8e, 0x14, 0x22, 0xc7, 0x64, 0xed,\n                0xcc, 0xe0, 0x6c, 0x06, 0xb5, 0x86, 0x44, 0xc1, 0x68, 0xa5,\n                0xab, 0xf3, 0x9d, 0xcb, 0x46, 0xb6, 0xe2,\n            };\n            var expected = Encoding.ASCII.GetBytes(\"test message\");\n\n            Assert.Equal(expected, prvKey.Decrypt(cipherText));\n            Assert.Equal(expected, prvKey.Decrypt(cipherText.ToImmutableArray()));\n        }\n\n        [Fact]\n        public void DecryptDetectInvalidCipherText()\n        {\n            var key1 = new PrivateKey(\n                new byte[]\n                {\n                    0xfb, 0xc2, 0x00, 0x42, 0xb3, 0xa7, 0x07, 0xa7, 0xd5, 0xa1,\n                    0xfa, 0x57, 0x71, 0x71, 0xf4, 0x9c, 0xd3, 0xa9, 0xe6, 0x7a,\n                    0xb9, 0x29, 0x57, 0x57, 0xc7, 0x14, 0xe3, 0xf2, 0xf8, 0xc2,\n                    0xd5, 0x73,\n                }\n            );\n            var key2 = new PrivateKey(\n                new byte[]\n                {\n                    0xfb, 0xc2, 0x00, 0x42, 0xb3, 0xa7, 0x07, 0xa7, 0xd5, 0xa1,\n                    0xfa, 0x57, 0x71, 0x71, 0xf4, 0x9c, 0xd3, 0xa9, 0xe6, 0x7a,\n                    0xb9, 0x29, 0x57, 0x57, 0xc7, 0x14, 0xe3, 0xf2, 0xf8, 0xc2,\n                    0xd5, 0x37,\n                }\n            );\n            var message = Encoding.ASCII.GetBytes(\"test message\");\n            var cipherText = key1.PublicKey.Encrypt(message);\n\n            Assert.Throws<InvalidCiphertextException>(() => key2.Decrypt(cipherText));\n            Assert.Throws<InvalidCiphertextException>(\n                () => key2.Decrypt(cipherText.ToImmutableArray())\n            );\n        }\n\n        [Fact]\n        public void EqualsTest()\n        {\n            var key1 = new PrivateKey(\n                new byte[]\n                {\n                    0xfb, 0xc2, 0x00, 0x42, 0xb3, 0xa7, 0x07, 0xa7, 0xd5, 0xa1,\n                    0xfa, 0x57, 0x71, 0x71, 0xf4, 0x9c, 0xd3, 0xa9, 0xe6, 0x7a,\n                    0xb9, 0x29, 0x57, 0x57, 0xc7, 0x14, 0xe3, 0xf2, 0xf8, 0xc2,\n                    0xd5, 0x73,\n                }\n            );\n            var key2 = new PrivateKey(\n                new byte[]\n                {\n                    0xfb, 0xc2, 0x00, 0x42, 0xb3, 0xa7, 0x07, 0xa7, 0xd5, 0xa1,\n                    0xfa, 0x57, 0x71, 0x71, 0xf4, 0x9c, 0xd3, 0xa9, 0xe6, 0x7a,\n                    0xb9, 0x29, 0x57, 0x57, 0xc7, 0x14, 0xe3, 0xf2, 0xf8, 0xc2,\n                    0xd5, 0x73,\n                }\n            );\n            var key3 = new PrivateKey(\n                new byte[]\n                {\n                    0xfb, 0xc2, 0x00, 0x42, 0xb3, 0xa7, 0x07, 0xa7, 0xd5, 0xa1,\n                    0xfa, 0x57, 0x71, 0x71, 0xf4, 0x9c, 0xd3, 0xa9, 0xe6, 0x7a,\n                    0xb9, 0x29, 0x57, 0x57, 0xc7, 0x14, 0xe3, 0xf2, 0xf8, 0xc2,\n                    0xd5, 0x37,\n                }\n            );\n\n            Assert.Equal(key1, key2);\n            Assert.NotEqual(key2, key3);\n\n            Assert.True(key1 == key2);\n            Assert.False(key2 == key3);\n\n            Assert.False(key1 != key2);\n            Assert.True(key2 != key3);\n        }\n\n        [Fact]\n        public void HexStringConstructor()\n        {\n            Assert.Throws<ArgumentOutOfRangeException>(() => new PrivateKey(string.Empty));\n            Assert.Throws<ArgumentOutOfRangeException>(() => new PrivateKey(\"a\"));\n            Assert.Throws<ArgumentOutOfRangeException>(() => new PrivateKey(\"870912\"));\n            Assert.Throws<ArgumentOutOfRangeException>(() =>\n                new PrivateKey(\n                    \"00000000000000000000000000000000000000000000000000000000870912\"\n                )\n            );\n            Assert.Throws<ArgumentOutOfRangeException>(() =>\n                new PrivateKey(\n                    \"000000000000000000000000000000000000000000000000000000000000870912\"\n                )\n            );\n            Assert.Throws<FormatException>(() => new PrivateKey(\"zz\"));\n            PrivateKey actual = new PrivateKey(\n                \"e07107ca4b0d19147fa1152a0f2c7884705d59cbb6318e2f901bd28dd9ff78e3\"\n            );\n            AssertBytesEqual(\n                new byte[]\n                {\n                    0xe0, 0x71, 0x07, 0xca, 0x4b, 0x0d, 0x19, 0x14, 0x7f, 0xa1, 0x15,\n                    0x2a, 0x0f, 0x2c, 0x78, 0x84, 0x70, 0x5d, 0x59, 0xcb, 0xb6, 0x31,\n                    0x8e, 0x2f, 0x90, 0x1b, 0xd2, 0x8d, 0xd9, 0xff, 0x78, 0xe3,\n                },\n                actual.ToByteArray()\n            );\n        }\n\n        [Fact]\n\n        public void PrivateKeyGenerateLongerThan31Bytes()\n        {\n            var faults = new List<int>();\n            for (int i = 0; i < 3000; i++)\n            {\n                var pk = new PrivateKey();\n\n                if (pk.ByteArray.Length < 32)\n                {\n                    faults.Add(i);\n                }\n            }\n\n            Assert.Empty(faults);\n        }\n\n        [Theory]\n        [InlineData(new byte[]\n        {\n            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n        })]\n        public void ThrowsWhenZeroBytesPrivateKey(byte[] bytes)\n        {\n            Assert.Throws<ArgumentException>(() => new PrivateKey(bytes));\n        }\n    }\n}"
  },
  {
    "path": "test/Libplanet.Tests/Crypto/PublicKeyTest.cs",
    "content": "using System;\nusing System.Collections.Immutable;\nusing System.ComponentModel;\nusing System.Text;\nusing Libplanet.Common;\nusing Libplanet.Crypto;\nusing Xunit;\nusing Xunit.Abstractions;\n\nnamespace Libplanet.Tests.Crypto\n{\n    public class PublicKeyTest\n    {\n        private readonly ITestOutputHelper _output;\n\n        public PublicKeyTest(ITestOutputHelper output)\n        {\n            _output = output;\n        }\n\n        [Fact]\n        public void Constructor()\n        {\n            byte[] bytes = ByteUtil.ParseHex(\n                \"04b5a24aa2112720423bad39a0205182379d6f2b33e3487c9ab6cc8fc496f8a54\" +\n                \"83440efbbef0657ac2ef6c6ee05db06a94532fda7ddc44a1695e5ce1a3d3c76db\");\n\n            var mutable = new PublicKey(bytes);\n            var immutable = new PublicKey(bytes.ToImmutableArray());\n            Assert.Equal(mutable, immutable);\n            var compressedMutable = new PublicKey(mutable.Format(compress: true));\n            Assert.Equal(mutable, compressedMutable);\n            var compressedImmutable = new PublicKey(immutable.ToImmutableArray(compress: true));\n            Assert.Equal(mutable, compressedImmutable);\n        }\n\n        [Fact]\n        public void Format()\n        {\n            byte[] bytes = ByteUtil.ParseHex(\n                \"04b5a24aa2112720423bad39a0205182379d6f2b33e3487c9ab6cc8fc496f8a54\" +\n                \"83440efbbef0657ac2ef6c6ee05db06a94532fda7ddc44a1695e5ce1a3d3c76db\");\n            byte[] compressed = ByteUtil.ParseHex(\n                \"03b5a24aa2112720423bad39a0205182379d6f2b33e3487c9ab6cc8fc496f8a548\");\n\n            var key = new PublicKey(bytes);\n            TestUtils.AssertBytesEqual(bytes, key.Format(compress: false));\n            TestUtils.AssertBytesEqual(compressed, key.Format(compress: true));\n            TestUtils.AssertBytesEqual(\n                bytes.ToImmutableArray(),\n                key.ToImmutableArray(compress: false)\n            );\n            TestUtils.AssertBytesEqual(\n                compressed.ToImmutableArray(),\n                key.ToImmutableArray(compress: true)\n            );\n        }\n\n        [Fact]\n        public void AddressTest()\n        {\n            var privateKey = new PrivateKey(ByteUtil.ParseHex(\n                \"bee6f9cc62412760b3696e05f6fb4abeb9e83c4f944f83fd62081b7454cbc038\"));\n            var publicKey = privateKey.PublicKey;\n            var expected = new Address(\"f45A22dD63f6428e85eE0a6E13a763278f57626d\");\n            Assert.Equal(expected, publicKey.Address);\n        }\n\n        [Fact]\n        public void Verify()\n        {\n            var pubKey = new PublicKey(ByteUtil.ParseHex(\n                \"04b5a24aa2112720423bad39a0205182379d6f2b33e3487c9ab6cc8fc496f8a54\" +\n                \"83440efbbef0657ac2ef6c6ee05db06a94532fda7ddc44a1695e5ce1a3d3c76db\"));\n            var payload = new byte[]\n            {\n                0x64, 0x37, 0x3a, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73,\n                0x6c, 0x65, 0x31, 0x30, 0x3a, 0x70, 0x75, 0x62, 0x6c, 0x69,\n                0x63, 0x5f, 0x6b, 0x65, 0x79, 0x36, 0x35, 0x3a, 0x04, 0xb5,\n                0xa2, 0x4a, 0xa2, 0x11, 0x27, 0x20, 0x42, 0x3b, 0xad, 0x39,\n                0xa0, 0x20, 0x51, 0x82, 0x37, 0x9d, 0x6f, 0x2b, 0x33, 0xe3,\n                0x48, 0x7c, 0x9a, 0xb6, 0xcc, 0x8f, 0xc4, 0x96, 0xf8, 0xa5,\n                0x48, 0x34, 0x40, 0xef, 0xbb, 0xef, 0x06, 0x57, 0xac, 0x2e,\n                0xf6, 0xc6, 0xee, 0x05, 0xdb, 0x06, 0xa9, 0x45, 0x32, 0xfd,\n                0xa7, 0xdd, 0xc4, 0x4a, 0x16, 0x95, 0xe5, 0xce, 0x1a, 0x3d,\n                0x3c, 0x76, 0xdb, 0x39, 0x3a, 0x72, 0x65, 0x63, 0x69, 0x70,\n                0x69, 0x65, 0x6e, 0x74, 0x32, 0x30, 0x3a, 0x8a, 0xe7, 0x2e,\n                0xfa, 0xb0, 0x95, 0x94, 0x66, 0x51, 0x12, 0xe6, 0xd4, 0x9d,\n                0xfd, 0x19, 0x41, 0x53, 0x8c, 0xf3, 0x74, 0x36, 0x3a, 0x73,\n                0x65, 0x6e, 0x64, 0x65, 0x72, 0x32, 0x30, 0x3a, 0xb6, 0xc0,\n                0x3d, 0xe5, 0x7d, 0xdf, 0x03, 0x69, 0xc7, 0x20, 0x7d, 0x2d,\n                0x11, 0x3a, 0xdf, 0xf8, 0x20, 0x51, 0x99, 0xcf, 0x39, 0x3a,\n                0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x32,\n                0x37, 0x3a, 0x32, 0x30, 0x31, 0x38, 0x2d, 0x30, 0x31, 0x2d,\n                0x30, 0x32, 0x54, 0x30, 0x33, 0x3a, 0x30, 0x34, 0x3a, 0x30,\n                0x35, 0x2e, 0x30, 0x30, 0x36, 0x30, 0x30, 0x30, 0x5a, 0x65,\n            };\n            var signature = new byte[]\n            {\n                0x30, 0x44, 0x02, 0x20, 0x62, 0xcf, 0x8a, 0x04, 0x41, 0x9c,\n                0x6a, 0x03, 0xba, 0xf5, 0x5d, 0xe1, 0x0d, 0x9b, 0x20, 0x0e,\n                0xda, 0xa9, 0xdf, 0x2b, 0x9b, 0xf0, 0xcf, 0x98, 0x9f, 0xd6,\n                0x5d, 0x71, 0xc5, 0x5c, 0x35, 0x60, 0x02, 0x20, 0x2a, 0xa5,\n                0x59, 0x69, 0xd0, 0xad, 0xb1, 0x5e, 0x9e, 0x70, 0x8d, 0x83,\n                0x00, 0xe1, 0x05, 0x31, 0x1e, 0x1a, 0x16, 0x16, 0x5d, 0xb7,\n                0x3e, 0xd8, 0xf4, 0xf0, 0x05, 0x1d, 0x9f, 0x13, 0x81, 0xfd,\n            };\n            Assert.True(pubKey.Verify(payload, signature));\n            Assert.False(pubKey.Verify(payload, ImmutableArray<byte>.Empty));\n            Assert.False(pubKey.Verify(payload, default(ImmutableArray<byte>)));\n        }\n\n        [Fact]\n        public void VerifyShouldNotCrashForAnyInputs()\n        {\n            var random = new Random();\n            var key = new PublicKey(ByteUtil.ParseHex(\n                \"04b5a24aa2112720423bad39a0205182379d6f2b33e3487c9ab6cc8fc496f8a54\" +\n                \"83440efbbef0657ac2ef6c6ee05db06a94532fda7ddc44a1695e5ce1a3d3c76db\"));\n            byte[][] testMessages =\n            {\n                // 0) Asn1ParsingException: corrupted stream - out of bounds length found: 77 >= 71\n                ByteUtil.ParseHex(\n                    \"91cd3ac5b0ee0642dc5f3c64061d8b87d6a7a1f9bfd3c4159068ebffa229bebb\" +\n                    \"a1b9932496f358b26a4e3611abf1e46cd39d3d8da5b2a1bd082535470306a0b2\"\n                ),\n                // 1) Asn1ParsingException: corrupted stream - out of bounds length found: 104 >= 71\n                ByteUtil.ParseHex(\n                    \"dbee28545e490ff2b1311a0545a7498eb1bae9156207ee732f1ee59ec1b18bb4\" +\n                    \"7bdce857e2476eb4988e52263f9b51fdb3ceabb546e00cd4ffb52540637131ff\"\n                ),\n            };\n            byte[][] testSignatures =\n            {\n                // 0) Asn1ParsingException: corrupted stream - out of bounds length found: 77 >= 71\n                ByteUtil.ParseHex(\n                    \"a180c24d8966f1e24fef8e709cb36a9e837e2c04ec3016ef17d51b70be10af64ad846f2\" +\n                    \"a2e97e36cab5a3db623312055bb97c484da9cc6706ad335b34b81243f402ac218433f6f\"\n                ),\n                // 1) Asn1ParsingException: corrupted stream - out of bounds length found: 104 >= 71\n                ByteUtil.ParseHex(\n                    \"a5668968bef1ac694b357cd4b4c83494cde8eaf206d66d9ad014582c222e50275c5281d\" +\n                    \"811e83ec12141691164381f378191727b863ff9cef8ee98aa997f461de4557862465b82\"\n                ),\n            };\n            Assert.Equal(testMessages.Length, testSignatures.Length);\n\n            for (int i = 0; i < testMessages.Length; i++)\n            {\n                bool validity;\n                byte[] message = testMessages[i];\n                byte[] sig = testSignatures[i];\n                try\n                {\n                    validity = key.Verify(message, sig);\n                }\n                catch (Exception)\n                {\n                    _output.WriteLine(\n                        \"An unexpected exception is thrown by {0}.{1}() method with input #{2}:\",\n                        nameof(PublicKey),\n                        nameof(PublicKey.Verify),\n                        i\n                    );\n                    _output.WriteLine(\"  message:   {0}\", ByteUtil.Hex(message));\n                    _output.WriteLine(\"  signature: {0}\", ByteUtil.Hex(sig));\n                    throw;\n                }\n\n                string msg =\n                    $\"{nameof(PublicKey.Verify)}() method made an incorrect answer for input \" +\n                    $\"#{i}:\\n\" +\n                    $\"  message:   {ByteUtil.Hex(message)}\\n\" +\n                    $\"  signature: {ByteUtil.Hex(sig)}\\n\";\n                Assert.False(validity, msg);\n            }\n\n            for (int i = 0; i < 100; i++)\n            {\n                byte[] message = random.NextBytes(64);\n                byte[] sig = random.NextBytes(71);\n                bool validity;\n                try\n                {\n                    validity = key.Verify(message, sig);\n                }\n                catch (Exception)\n                {\n                    _output.WriteLine(\n                        \"An unexpected exception is thrown by {0}.{1}() method with the input:\",\n                        nameof(PublicKey),\n                        nameof(PublicKey.Verify)\n                    );\n                    _output.WriteLine(\"  message:   {0}\", ByteUtil.Hex(message));\n                    _output.WriteLine(\"  signature: {0}\", ByteUtil.Hex(sig));\n                    throw;\n                }\n\n                string msg =\n                    $\"{nameof(PublicKey.Verify)}() method made an incorrect answer for the below \" +\n                    \"arbitrary inputs:\\n\" +\n                    $\"  message:   {ByteUtil.Hex(message)}\\n\" +\n                    $\"  signature: {ByteUtil.Hex(sig)}\\n\";\n                Assert.False(validity, msg);\n            }\n        }\n\n        [Fact]\n        public void EncryptTest()\n        {\n            var prvKey = new PrivateKey();\n            var pubKey = prvKey.PublicKey;\n            var bs = Encoding.ASCII.GetBytes(\"hello world\");\n\n            var encrypted = pubKey.Encrypt(bs);\n            TestUtils.AssertBytesEqual(bs, prvKey.Decrypt(encrypted));\n\n            ImmutableArray<byte> immutable = bs.ToImmutableArray();\n            var encryptedImmutable = pubKey.Encrypt(immutable);\n            TestUtils.AssertBytesEqual(immutable, prvKey.Decrypt(encryptedImmutable));\n        }\n\n        [Fact]\n        public void EqualsTest()\n        {\n            // key2 is compression of key1\n            var key1 = new PublicKey(ByteUtil.ParseHex(\n                \"0446115b0131baccf94a5856ede871295f6f3d352e6847cda9c03e89fe09f7328\" +\n                \"08711ec97af6e341f110a326da1bdb81f5ae3badf76a90b22c8c491aed3aaa296\"));\n            var key2 = new PublicKey(ByteUtil.ParseHex(\n                \"0246115b0131baccf94a5856ede871295f6f3d352e6847cda9c03e89fe09f73280\"));\n            var key3 = new PublicKey(ByteUtil.ParseHex(\n                \"04b5a24aa2112720423bad39a0205182379d6f2b33e3487c9ab6cc8fc496f8a54\" +\n                \"83440efbbef0657ac2ef6c6ee05db06a94532fda7ddc44a1695e5ce1a3d3c76db\"));\n\n            Assert.Equal(key1, key2);\n            Assert.NotEqual(key2, key3);\n\n            Assert.True(key1 == key2);\n            Assert.False(key2 == key3);\n\n            Assert.False(key1 != key2);\n            Assert.True(key2 != key3);\n        }\n\n        [Fact]\n        public void FromHex()\n        {\n            var expected = new PublicKey(\n                new byte[]\n                {\n                    0x04, 0x46, 0x11, 0x5b, 0x01, 0x31, 0xba, 0xcc, 0xf9, 0x4a,\n                    0x58, 0x56, 0xed, 0xe8, 0x71, 0x29, 0x5f, 0x6f, 0x3d, 0x35,\n                    0x2e, 0x68, 0x47, 0xcd, 0xa9, 0xc0, 0x3e, 0x89, 0xfe, 0x09,\n                    0xf7, 0x32, 0x80, 0x87, 0x11, 0xec, 0x97, 0xaf, 0x6e, 0x34,\n                    0x1f, 0x11, 0x0a, 0x32, 0x6d, 0xa1, 0xbd, 0xb8, 0x1f, 0x5a,\n                    0xe3, 0xba, 0xdf, 0x76, 0xa9, 0x0b, 0x22, 0xc8, 0xc4, 0x91,\n                    0xae, 0xd3, 0xaa, 0xa2, 0x96,\n                }\n            );\n            PublicKey key = PublicKey.FromHex(\n                \"0246115b0131baccf94a5856ede871295f6f3d352e6847cda9c03e89fe09f73280\");\n            Assert.Equal(expected, key);\n\n            key = PublicKey.FromHex(\n                \"0446115b0131baccf94a5856ede871295f6f3d352e6847cda9c03e89fe09f7328\" +\n                \"08711ec97af6e341f110a326da1bdb81f5ae3badf76a90b22c8c491aed3aaa296\");\n            Assert.Equal(expected, key);\n\n            Assert.Throws<ArgumentOutOfRangeException>(() => PublicKey.FromHex(\"abc\"));\n            Assert.Throws<FormatException>(() => PublicKey.FromHex(\"zz\"));\n        }\n\n        [Fact]\n        public void ToHex()\n        {\n            var key1 = new PublicKey(\n                new byte[]\n                {\n                    0x04, 0x46, 0x11, 0x5b, 0x01, 0x31, 0xba, 0xcc, 0xf9, 0x4a,\n                    0x58, 0x56, 0xed, 0xe8, 0x71, 0x29, 0x5f, 0x6f, 0x3d, 0x35,\n                    0x2e, 0x68, 0x47, 0xcd, 0xa9, 0xc0, 0x3e, 0x89, 0xfe, 0x09,\n                    0xf7, 0x32, 0x80, 0x87, 0x11, 0xec, 0x97, 0xaf, 0x6e, 0x34,\n                    0x1f, 0x11, 0x0a, 0x32, 0x6d, 0xa1, 0xbd, 0xb8, 0x1f, 0x5a,\n                    0xe3, 0xba, 0xdf, 0x76, 0xa9, 0x0b, 0x22, 0xc8, 0xc4, 0x91,\n                    0xae, 0xd3, 0xaa, 0xa2, 0x96,\n                }\n            );\n\n            Assert.Equal(\n                \"0446115b0131baccf94a5856ede871295f6f3d352e6847cda9c03e89fe09f7328\" +\n                \"08711ec97af6e341f110a326da1bdb81f5ae3badf76a90b22c8c491aed3aaa296\",\n                key1.ToHex(false)\n            );\n            Assert.Equal(\n                \"0246115b0131baccf94a5856ede871295f6f3d352e6847cda9c03e89fe09f73280\",\n                key1.ToHex(true)\n            );\n        }\n\n        [Fact]\n        public void String()\n        {\n            PublicKey key = PublicKey.FromHex(\n                \"0246115b0131baccf94a5856ede871295f6f3d352e6847cda9c03e89fe09f73280\");\n            Assert.Equal(\n                \"0246115b0131baccf94a5856ede871295f6f3d352e6847cda9c03e89fe09f73280\",\n                key.ToString());\n        }\n\n        [Fact]\n        public void TypeConverter()\n        {\n            TypeConverter converter = TypeDescriptor.GetConverter(typeof(PublicKey));\n            PublicKey key = PublicKey.FromHex(\n                \"0246115b0131baccf94a5856ede871295f6f3d352e6847cda9c03e89fe09f73280\");\n            Assert.True(converter.CanConvertFrom(typeof(string)));\n            Assert.Equal(\n                key,\n                converter.ConvertFrom(\n                    \"0246115b0131baccf94a5856ede871295f6f3d352e6847cda9c03e89fe09f73280\"));\n            Assert.Equal(\n                key,\n                converter.ConvertFrom(\n                    \"0246115B0131BACCF94A5856EDE871295F6F3D352E6847CDA9C03E89FE09F73280\"));\n            Assert.Equal(\n                key,\n                converter.ConvertFrom(\n                    \"0446115b0131baccf94a5856ede871295f6f3d352e6847cda9c03e89fe09f7328\" +\n                    \"08711ec97af6e341f110a326da1bdb81f5ae3badf76a90b22c8c491aed3aaa296\"));\n            Assert.Throws<ArgumentException>(() => converter.ConvertFrom(\"INVALID\"));\n\n            Assert.True(converter.CanConvertTo(typeof(string)));\n            Assert.Equal(\n                \"0246115b0131baccf94a5856ede871295f6f3d352e6847cda9c03e89fe09f73280\",\n                converter.ConvertTo(key, typeof(string)));\n        }\n\n        [SkippableFact]\n        public void JsonSerialization()\n        {\n            var key = new PublicKey(\n                new byte[]\n                {\n                    0x04, 0x46, 0x11, 0x5b, 0x01, 0x31, 0xba, 0xcc, 0xf9, 0x4a,\n                    0x58, 0x56, 0xed, 0xe8, 0x71, 0x29, 0x5f, 0x6f, 0x3d, 0x35,\n                    0x2e, 0x68, 0x47, 0xcd, 0xa9, 0xc0, 0x3e, 0x89, 0xfe, 0x09,\n                    0xf7, 0x32, 0x80, 0x87, 0x11, 0xec, 0x97, 0xaf, 0x6e, 0x34,\n                    0x1f, 0x11, 0x0a, 0x32, 0x6d, 0xa1, 0xbd, 0xb8, 0x1f, 0x5a,\n                    0xe3, 0xba, 0xdf, 0x76, 0xa9, 0x0b, 0x22, 0xc8, 0xc4, 0x91,\n                    0xae, 0xd3, 0xaa, 0xa2, 0x96,\n                }\n            );\n            TestUtils.AssertJsonSerializable(\n                key,\n                \"\\\"0246115b0131baccf94a5856ede871295f6f3d352e6847cda9c03e89fe09f73280\\\"\"\n            );\n        }\n    }\n}\n"
  },
  {
    "path": "test/Libplanet.Tests/Crypto/SymmetricKeyTest.cs",
    "content": "using System.Collections.Immutable;\nusing System.Text;\nusing Libplanet.Crypto;\nusing Xunit;\n\nusing static Libplanet.Tests.TestUtils;\n\nnamespace Libplanet.Tests.Crypto\n{\n    public class SymmetricKeyTest\n    {\n        private static readonly byte[] KeyBytes =\n            {\n                0x34, 0x9c, 0x46, 0x9e, 0x0e, 0xa9, 0xeb, 0x88, 0x22,\n                0x65, 0x8a, 0xaf, 0x08, 0x17, 0xa2, 0x21, 0xd7, 0xfd,\n                0x4b, 0xe7, 0x8b, 0x24, 0x3f, 0x45, 0x5d, 0x72, 0xb6,\n                0x0f, 0x9b, 0x1a, 0x3a, 0x4e,\n            };\n\n        [Fact]\n        public void DecryptTest()\n        {\n            byte[] ciphertext =\n            {\n                0x18, 0x81, 0x34, 0x2a, 0x29, 0x30, 0xcd, 0xc2, 0x73, 0x4a,\n                0xe1, 0x5e, 0x14, 0x3a, 0x09, 0xfe, 0x5b, 0x0a, 0x5f, 0x11,\n                0x3b, 0x0e, 0x2f, 0xcf, 0xc8, 0xd5, 0x6f, 0x23, 0xc5, 0x08,\n                0xa2, 0x89, 0x0d, 0x71, 0x39, 0xc5, 0x92, 0xcf, 0x4e, 0x4c,\n                0x76, 0x75, 0x8a, 0x9b, 0x23, 0x17, 0xcb, 0x94,\n            };\n            var expected = Encoding.ASCII.GetBytes(\"a secret message\");\n            var aes = new SymmetricKey(KeyBytes);\n            var actual = aes.Decrypt(ciphertext);\n\n            Assert.Equal(expected, actual);\n        }\n\n        [Fact]\n        public void ByteArray()\n        {\n            var aes = new SymmetricKey(KeyBytes);\n            ImmutableArray<byte> expected = KeyBytes.ToImmutableArray();\n            ImmutableArray<byte> actual = aes.ByteArray;\n            Assert.Equal<byte>(expected, actual);\n        }\n\n        [Fact]\n        public void ToByteArray()\n        {\n            var aes = new SymmetricKey(KeyBytes);\n            Assert.Equal(KeyBytes, aes.ToByteArray());\n        }\n    }\n}\n"
  },
  {
    "path": "test/Libplanet.Tests/EnumerableShim.cs",
    "content": "#pragma warning disable S1128\nusing System.Collections.Generic;\n#pragma warning restore S1128 // S1128: Remove this unnecessary 'using'\n\nnamespace Libplanet.Tests\n{\n    /// <summary>\n    /// Compatibility shim to fill the lack of extension methods on <see cref=\"IEnumerable{T}\"/>\n    /// in several target frameworks.\n    /// </summary>\n    public static class EnumerableShim\n    {\n#if NETFRAMEWORK && !NET48 && !NET472 && !NET471\n        // Enumerable.Append<T>(IEnumerable<T>, T) is introduced since .NET Framework 4.7.1\n        public static IEnumerable<T> Append<T>(this IEnumerable<T> source, T element)\n        {\n            foreach (T e in source)\n            {\n                yield return e;\n            }\n\n            yield return element;\n        }\n#endif\n    }\n}\n"
  },
  {
    "path": "test/Libplanet.Tests/Fixtures/Arithmetic.cs",
    "content": "using System;\nusing System.Numerics;\nusing Bencodex.Types;\nusing Libplanet.Action;\nusing Libplanet.Action.State;\n\nnamespace Libplanet.Tests.Fixtures\n{\n    /// <summary>\n    /// A simple arithmetic action.  This assumes that every address has an integer state or\n    /// a <see langword=\"null\"/> state (not <see cref=\"Bencodex.Types.Null\"/>,\n    /// but <see langword=\"null\"/> reference).\n    /// </summary>\n    public sealed class Arithmetic : IAction, IEquatable<Arithmetic>\n    {\n        public Arithmetic()\n        {\n            Error = \"An uninitialized action.\";\n        }\n\n        public Arithmetic(OperatorType @operator, BigInteger operand)\n        {\n            Error = null;\n            Operator = @operator;\n            Operand = operand;\n        }\n\n        public string Error { get; private set; }\n\n        public OperatorType Operator { get; private set; }\n\n        public BigInteger Operand { get; private set; }\n\n        public IValue PlainValue => (Error is null)\n            ? (IValue)Bencodex.Types.Dictionary.Empty\n                .Add(\n                    \"op\",\n                    Operator is OperatorType op ? new Text(op.ToString()) : (IValue)Null.Value\n                )\n                .Add(\"operand\", Operand)\n            : (Text)Error;\n\n        public static Arithmetic Add(BigInteger operand) =>\n            new Arithmetic(OperatorType.Add, operand);\n\n        public static Arithmetic Sub(BigInteger operand) =>\n            new Arithmetic(OperatorType.Sub, operand);\n\n        public static Arithmetic Mul(BigInteger operand) =>\n            new Arithmetic(OperatorType.Mul, operand);\n\n        public static Arithmetic Div(BigInteger operand) =>\n            new Arithmetic(OperatorType.Div, operand);\n\n        public static Arithmetic Mod(BigInteger operand) =>\n            new Arithmetic(OperatorType.Mod, operand);\n\n        public void LoadPlainValue(IValue plainValue)\n        {\n            if (plainValue is Text t)\n            {\n                Error = t;\n                return;\n            }\n\n            if (!(plainValue is Dictionary d))\n            {\n                Error =\n                    \"The action serialization is invalid; \" +\n                    \"the serialization should be a dictionary.\";\n                return;\n            }\n\n            if (!d.TryGetValue((Text)\"op\", out IValue opValue))\n            {\n                Error = \"The serialized dictionary lacks the key \\\"op\\\".\";\n                return;\n            }\n\n            if (!(opValue is Text opText))\n            {\n                Error = \"The serialized \\\"op\\\" field is not a text.\";\n                return;\n            }\n\n            string opStr = opText.Value;\n            if (!OperatorType.TryParse(opStr, true, out OperatorType op))\n            {\n                Error = $\"The serialized operator \\\"{opStr}\\\" is invalid.\";\n                return;\n            }\n\n            if (!d.TryGetValue((Text)\"operand\", out IValue operandValue))\n            {\n                Error = \"The serialized dictionary lacks the key \\\"operand\\\".\";\n                return;\n            }\n\n            if (!(operandValue is Bencodex.Types.Integer operandInt))\n            {\n                Error = \"The serialized \\\"operand\\\" field is not an integer.\";\n                return;\n            }\n\n            Operator = op;\n            Operand = operandInt.Value;\n            Error = null;\n        }\n\n        public IWorld Execute(IActionContext context)\n        {\n            if (Error != null)\n            {\n                throw new InvalidOperationException(Error);\n            }\n\n            IValue v = context.PreviousState.GetAccount(ReservedAddresses.LegacyAccount)\n                .GetState(context.Signer) ?? (Bencodex.Types.Integer)0;\n            if (!(v is Bencodex.Types.Integer value))\n            {\n                throw new InvalidOperationException(\n                    $\"The state of the address {context.Signer} is not an integer.\"\n                );\n            }\n\n            Func<BigInteger, BigInteger, BigInteger> func = Operator.ToFunc();\n            BigInteger result = func(value, Operand);\n            return context.PreviousState.SetAccount(\n                ReservedAddresses.LegacyAccount,\n                context.PreviousState.GetAccount(\n                    ReservedAddresses.LegacyAccount).SetState(\n                    context.Signer, (Bencodex.Types.Integer)result));\n        }\n\n        public bool Equals(Arithmetic other)\n        {\n            if (ReferenceEquals(null, other))\n            {\n                return false;\n            }\n            else if (ReferenceEquals(this, other))\n            {\n                return true;\n            }\n            else\n            {\n                return Error == other.Error &&\n                   Operator == other.Operator &&\n                   Operand.Equals(other.Operand);\n            }\n        }\n\n        public override bool Equals(object obj) =>\n            ReferenceEquals(this, obj) || (obj is Arithmetic other && Equals(other));\n\n        public override int GetHashCode() =>\n            (Error, (int)Operator, Operand).GetHashCode();\n    }\n}\n"
  },
  {
    "path": "test/Libplanet.Tests/Fixtures/BlockContentFixture.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Collections.Immutable;\nusing System.Linq;\nusing System.Security.Cryptography;\nusing Bencodex.Types;\nusing Libplanet.Action;\nusing Libplanet.Action.Sys;\nusing Libplanet.Common;\nusing Libplanet.Crypto;\nusing Libplanet.Tests.Blockchain.Evidence;\nusing Libplanet.Types.Blocks;\nusing Libplanet.Types.Evidence;\nusing Libplanet.Types.Tx;\nusing Xunit;\n\nnamespace Libplanet.Tests.Fixtures\n{\n    public class BlockContentFixture\n    {\n        public readonly PrivateKey GenesisKey;\n        public readonly BlockHash GenesisHash;\n        public readonly BlockContent GenesisContent;\n        public readonly BlockMetadata GenesisMetadata;\n\n        public readonly PrivateKey Block1Key;\n        public readonly PrivateKey Block1Tx0Key;\n        public readonly PrivateKey Block1Tx1Key;\n        public readonly Transaction Block1Tx0;\n        public readonly Transaction Block1Tx1;\n        public readonly EvidenceBase Block1Ev0;\n        public readonly EvidenceBase Block1Ev1;\n        public readonly BlockContent Block1Content;\n        public readonly HashDigest<SHA256> Block1TxHash;\n        public readonly BlockMetadata Block1Metadata;\n\n        public readonly BlockContent GenesisContentPv0;\n        public readonly BlockMetadata GenesisMetadataPv0;\n        public readonly BlockContent Block1ContentPv1;\n        public readonly BlockMetadata Block1MetadataPv1;\n\n        public BlockContentFixture()\n        {\n            TimeSpan kst = TimeSpan.FromHours(9);\n            GenesisKey = PrivateKey.FromString(\n                \"9bf4664ba09a89faeb684b94e69ffde01d26ae14b556204d3f6ab58f61f78418\");\n            Transaction genTx = Transaction.Create(\n                0,\n                GenesisKey,\n                null,\n                actions: new IAction[]\n                    {\n                        new Initialize(\n                            validatorSet: TestUtils.ValidatorSet,\n                            states: ImmutableDictionary.Create<Address, IValue>()),\n                    }.ToPlainValues(),\n                timestamp: DateTimeOffset.MinValue\n            );\n            Transaction[] genTxs = new[] { genTx };\n            EvidenceBase[] genEvidence = new[]\n            {\n                new TestEvidence(\n                    0, GenesisKey.Address, new DateTimeOffset(2024, 5, 24, 14, 12, 9, 45, kst)),\n            };\n            GenesisContent = new BlockContent(\n                new BlockMetadata(\n                    index: 0,\n                    timestamp: new DateTimeOffset(2021, 9, 6, 13, 46, 39, 123, kst),\n                    publicKey: GenesisKey.PublicKey,\n                    previousHash: null,\n                    txHash: BlockContent.DeriveTxHash(genTxs),\n                    lastCommit: null,\n                    evidenceHash: BlockContent.DeriveEvidenceHash(genEvidence)),\n                transactions: genTxs,\n                evidence: genEvidence);\n            GenesisMetadata = new BlockMetadata(GenesisContent);\n            GenesisHash = BlockHash.FromString(\n                \"341e8f360597d5bc45ab96aabc5f1b0608063f30af7bd4153556c9536a07693a\");\n\n            Block1Key = PrivateKey.FromString(\n                \"fcf30b333d04ccfeb562f000a32df488e7154949d31ddcac3cf9278acb5786c7\");\n            Block1Tx0Key = PrivateKey.FromString(\n                \"2d5c20079bc4b2e6eab9ecbb405da8ba6590c436edfb07b7d4466563d7dac096\");\n            Block1Tx0 = new Transaction(\n                new UnsignedTx(\n                    new TxInvoice(\n                        genesisHash: GenesisHash,\n                        updatedAddresses: new AddressSet(new[] { Block1Tx0Key.Address }),\n                        timestamp: new DateTimeOffset(2021, 9, 6, 17, 0, 1, 1, default),\n                        actions: new TxActionList(new IAction[]\n                        {\n                            Arithmetic.Add(10), Arithmetic.Add(50), Arithmetic.Sub(25),\n                        }.ToPlainValues()),\n                        maxGasPrice: null,\n                        gasLimit: null),\n                    new TxSigningMetadata(Block1Tx0Key.PublicKey, nonce: 0L)\n                ),\n                signature: ByteUtil.ParseHexToImmutable(\n                    \"30440220422c85ea44845a56253654d95595ad06d6f09f862ca71b97e986ecbb453eac\" +\n                    \"ae0220606e76276e40fa8f0795b880f712531fd6bd9db253bd8ab9c86aa4ab7d791d37\"\n                )\n            );\n            Block1Tx1Key = PrivateKey.FromString(\n                \"105341c78dfb0dd313b961081630444c2586a1f01fb0c625368ffdc9136cfa30\");\n            Block1Tx1 = new Transaction(\n                new UnsignedTx(\n                    new TxInvoice(\n                        genesisHash: GenesisHash,\n                        updatedAddresses: new AddressSet(new[] { Block1Tx1Key.Address }),\n                        timestamp: new DateTimeOffset(2021, 9, 6, 17, 0, 1, 1, default),\n                        actions: new TxActionList(new IAction[]\n                        {\n                            Arithmetic.Add(30),\n                        }.ToPlainValues()),\n                        maxGasPrice: null,\n                        gasLimit: null),\n                    new TxSigningMetadata(Block1Tx1Key.PublicKey, nonce: 1L)),\n                signature: ByteUtil.ParseHexToImmutable(\n                    \"3045022100abe3caabf2a46a297f2e4496f2c46d7e2f723e75fc42025d19f3ed7fce382\" +\n                    \"d4e02200ffd36f7bef759b6c7ab43bc0f8959a0c463f88fd0f1faeaa209a8661506c4f0\")\n            );\n            Block1Ev0 = new TestEvidence(\n                0, GenesisKey.Address, new DateTimeOffset(2024, 5, 24, 14, 13, 9, 45, kst));\n            Block1Ev1 = new TestEvidence(\n                0, GenesisKey.Address, new DateTimeOffset(2024, 5, 24, 14, 14, 9, 45, kst));\n\n            var block1Transactions = new List<Transaction>() { Block1Tx0, Block1Tx1 }\n                .OrderBy(tx => tx.Id).ToList();\n            var block1Evidence = new List<EvidenceBase>() { Block1Ev0, Block1Ev1 }\n                .OrderBy(tx => tx.Id).ToList();\n            Block1Content = new BlockContent(\n                new BlockMetadata(\n                    index: 1,\n                    timestamp: new DateTimeOffset(2021, 9, 6, 17, 1, 9, 45, kst),\n                    publicKey: Block1Key.PublicKey,\n                    previousHash: GenesisHash,\n                    txHash: BlockContent.DeriveTxHash(block1Transactions),\n                    lastCommit: null,\n                    evidenceHash: BlockContent.DeriveEvidenceHash(block1Evidence)),\n                transactions: block1Transactions,\n                evidence: block1Evidence);\n            Block1TxHash = HashDigest<SHA256>.FromString(\n                \"654698d34b6d9a55b0c93e4ffb2639278324868c91965bc5f96cb3071d6903a0\");\n            Block1Metadata = new BlockMetadata(Block1Content);\n\n            GenesisContentPv0 = new BlockContent(\n                new BlockMetadata(\n                    protocolVersion: 0,\n                    index: 0,\n                    timestamp: new DateTimeOffset(2021, 9, 6, 13, 46, 39, 123, kst),\n                    miner: GenesisKey.Address,\n                    publicKey: null,\n                    previousHash: null,\n                    txHash: null,\n                    lastCommit: null,\n                    evidenceHash: null),\n                transactions: new List<Transaction>(),\n                evidence: new List<EvidenceBase>()); // Tweaked GenesisContent\n            GenesisMetadataPv0 = new BlockMetadata(GenesisContentPv0);\n            Block1ContentPv1 = new BlockContent(\n                new BlockMetadata(\n                    protocolVersion: 1,\n                    index: 1,\n                    timestamp: new DateTimeOffset(2021, 9, 6, 17, 1, 9, 45, kst),\n                    miner: Block1Key.Address,\n                    publicKey: null,\n                    previousHash: GenesisHash,\n                    txHash: BlockContent.DeriveTxHash(block1Transactions),\n                    lastCommit: null,\n                    evidenceHash: BlockContent.DeriveEvidenceHash(block1Evidence)),\n                transactions: block1Transactions,\n                evidence: block1Evidence); // Tweaked Block1Content\n            Block1MetadataPv1 = new BlockMetadata(Block1ContentPv1);\n        }\n\n        [Fact]\n        public void ValidateBlockContentFixture()\n        {\n            Assert.Equal(Block1TxHash, Block1Content.TxHash);\n            Assert.Equal(Block1TxHash, Block1ContentPv1.TxHash);\n        }\n    }\n}\n"
  },
  {
    "path": "test/Libplanet.Tests/Fixtures/IntegerSet.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Collections.Immutable;\nusing System.Linq;\nusing System.Numerics;\nusing System.Security.Cryptography;\nusing Bencodex.Types;\nusing Libplanet.Action;\nusing Libplanet.Action.Loader;\nusing Libplanet.Action.State;\nusing Libplanet.Blockchain;\nusing Libplanet.Blockchain.Policies;\nusing Libplanet.Blockchain.Renderers;\nusing Libplanet.Blockchain.Renderers.Debug;\nusing Libplanet.Common;\nusing Libplanet.Crypto;\nusing Libplanet.Store;\nusing Libplanet.Store.Trie;\nusing Libplanet.Types.Blocks;\nusing Libplanet.Types.Tx;\n\nnamespace Libplanet.Tests.Fixtures\n{\n    public sealed class IntegerSet\n    {\n        public readonly IReadOnlyList<PrivateKey> PrivateKeys;\n        public readonly IReadOnlyList<Address> Addresses;\n        public readonly IReadOnlyList<Arithmetic> Actions;\n        public readonly IReadOnlyList<Transaction> Txs;\n        public readonly PrivateKey Miner;\n        public readonly Block Genesis;\n        public readonly BlockChain Chain;\n        public readonly IStore Store;\n        public readonly IKeyValueStore KVStore;\n        public readonly TrieStateStore StateStore;\n\n        public IntegerSet(int[] initialStates)\n            : this(initialStates.Select(s => new BigInteger?(s)).ToArray(), null, null)\n        {\n        }\n\n        public IntegerSet(\n            IReadOnlyList<BigInteger?> initialStates,\n            IBlockPolicy policy = null,\n            IEnumerable<IRenderer> renderers = null)\n        {\n            PrivateKeys = initialStates.Select(_ => new PrivateKey()).ToImmutableArray();\n            Addresses = PrivateKeys.Select(key => key.Address).ToImmutableArray();\n            Actions = initialStates\n                .Select((state, index) => new { State = state, Key = PrivateKeys[index] })\n                .Where(pair => !(pair.State is null))\n                .Select(pair => new { State = (BigInteger)pair.State, pair.Key })\n                .Select(pair => Arithmetic.Add(pair.State)).ToImmutableArray();\n            Txs = initialStates\n                .Select((state, index) => new { State = state, Key = PrivateKeys[index] })\n                .Where(pair => !(pair.State is null))\n                .Select(pair => new { State = (BigInteger)pair.State, pair.Key })\n                .Select(pair => new { Action = Arithmetic.Add(pair.State), pair.Key })\n                .Select(pair =>\n                    new Transaction(\n                        new UnsignedTx(\n                            new TxInvoice(\n                                actions: new TxActionList(new[] { pair.Action.PlainValue })),\n                            new TxSigningMetadata(pair.Key.PublicKey, 0)),\n                        pair.Key))\n                .OrderBy(tx => tx.Id)\n                .ToImmutableArray();\n            Miner = new PrivateKey();\n            policy = policy ?? new NullBlockPolicy();\n            Store = new MemoryStore();\n            KVStore = new MemoryKeyValueStore();\n            StateStore = new TrieStateStore(KVStore);\n            var actionEvaluator = new ActionEvaluator(\n                policy.PolicyActionsRegistry,\n                StateStore,\n                new SingleActionLoader(typeof(Arithmetic)));\n            Genesis = TestUtils.ProposeGenesisBlock(\n                TestUtils.ProposeGenesis(\n                    Miner.PublicKey,\n                    Txs,\n                    null,\n                    DateTimeOffset.UtcNow,\n                    Block.CurrentProtocolVersion),\n                Miner);\n            Chain = BlockChain.Create(\n                policy,\n                new VolatileStagePolicy(),\n                Store,\n                StateStore,\n                Genesis,\n                actionEvaluator,\n                renderers: renderers ?? new[] { new ValidatingActionRenderer() });\n        }\n\n        public int Count => Addresses.Count;\n\n        public IBlockPolicy Policy => Chain.Policy;\n\n        public IReadOnlyList<IRenderer> Renderers => Chain.Renderers;\n\n        public Block Tip => Chain.Tip;\n\n        public TxWithContext Sign(PrivateKey signer, params Arithmetic[] actions)\n        {\n            Address signerAddress = signer.Address;\n            KeyBytes rawStateKey = KeyConverters.ToStateKey(signerAddress);\n            long nonce = Chain.GetNextTxNonce(signerAddress);\n            Transaction tx =\n                Transaction.Create(nonce, signer, Genesis.Hash, actions.ToPlainValues());\n            BigInteger prevState = Chain.GetNextWorldState().GetAccountState(\n                ReservedAddresses.LegacyAccount).GetState(signerAddress) is Bencodex.Types.Integer i\n                    ? i.Value\n                    : 0;\n            HashDigest<SHA256> prevStateRootHash = Chain.Tip.StateRootHash;\n            ITrie prevTrie = GetTrie(Chain.Tip.Hash);\n            (BigInteger, HashDigest<SHA256>) prevPair = (prevState, prevStateRootHash);\n            (BigInteger, HashDigest<SHA256>) stagedStates = Chain.ListStagedTransactions()\n                .Where(t => t.Signer.Equals(signerAddress))\n                .OrderBy(t => t.Nonce)\n                .SelectMany(t => t.Actions)\n                .Aggregate(prevPair, (prev, act) =>\n                {\n                    var a = TestUtils.ToAction<Arithmetic>(act);\n                    if (a.PlainValue is Text error)\n                    {\n                        return (prev.Item1, prev.Item2);\n                    }\n                    else\n                    {\n                        BigInteger nextState = a.Operator.ToFunc()(prev.Item1, a.Operand);\n                        var updatedRawStates = ImmutableDictionary<KeyBytes, IValue>.Empty\n                            .Add(rawStateKey, (Bencodex.Types.Integer)nextState);\n                        HashDigest<SHA256> nextRootHash = Chain.StateStore.Commit(\n                            updatedRawStates.Aggregate(\n                                prevTrie,\n                                (trie, pair) => trie.Set(pair.Key, pair.Value))).Hash;\n                        return (nextState, nextRootHash);\n                    }\n                });\n            Chain.StageTransaction(tx);\n            ImmutableArray<(BigInteger, HashDigest<SHA256>)> expectedDelta = tx.Actions\n                .Aggregate(\n                    ImmutableArray.Create(stagedStates),\n                    (delta, act) =>\n                    {\n                        var a = TestUtils.ToAction<Arithmetic>(act);\n                        if (a.PlainValue is Text error)\n                        {\n                            return delta.Add(delta[delta.Length - 1]);\n                        }\n                        else\n                        {\n                            BigInteger nextState =\n                                a.Operator.ToFunc()(delta[delta.Length - 1].Item1, a.Operand);\n                            var updatedRawStates = ImmutableDictionary<KeyBytes, IValue>.Empty\n                                .Add(rawStateKey, (Bencodex.Types.Integer)nextState);\n                            HashDigest<SHA256> nextRootHash = Chain.StateStore.Commit(\n                                updatedRawStates.Aggregate(\n                                    prevTrie,\n                                    (trie, pair) => trie.Set(pair.Key, pair.Value))).Hash;\n                            return delta.Add((nextState, nextRootHash));\n                        }\n                    }\n                );\n            return new TxWithContext()\n            {\n                Tx = tx,\n                ExpectedDelta = expectedDelta,\n            };\n        }\n\n        public TxWithContext Sign(int signerIndex, params Arithmetic[] actions) =>\n            Sign(PrivateKeys[signerIndex], actions);\n\n        public Block Propose() => Chain.ProposeBlock(\n            Miner, TestUtils.CreateBlockCommit(Chain.Tip));\n\n        public void Append(Block block) =>\n            Chain.Append(block, TestUtils.CreateBlockCommit(block));\n\n        public ITrie GetTrie(BlockHash? blockHash)\n        {\n            return (blockHash is BlockHash h &&\n                    Store.GetBlockDigest(h) is BlockDigest d &&\n                    d.StateRootHash is HashDigest<SHA256> rootHash)\n                ? StateStore.GetStateRoot(rootHash)\n                : null;\n        }\n\n        public struct TxWithContext\n        {\n            public Transaction Tx;\n            public IReadOnlyList<(BigInteger Value, HashDigest<SHA256> RootHash)> ExpectedDelta;\n\n            public void Deconstruct(\n                out Transaction tx,\n                out IReadOnlyList<(BigInteger Value, HashDigest<SHA256> RootHash)> expectedDelta\n            )\n            {\n                tx = Tx;\n                expectedDelta = ExpectedDelta;\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "test/Libplanet.Tests/Fixtures/LegacyBlocks.cs",
    "content": "using Bencodex.Types;\nusing Libplanet.Common;\n\nnamespace Libplanet.Tests.Fixtures\n{\n    /// <summary>\n    /// A fixture containing <see cref=\"IValue\"/> representations of somewhat valid\n    /// blocks that are no longer fully supported.\n    /// </summary>\n    public static class LegacyBlocks\n    {\n        // Block fields:\n        public static readonly Binary HeaderKey = new Binary(new byte[] { 0x48 }); // 'H'\n        public static readonly Binary TransactionsKey = new Binary(new byte[] { 0x54 }); // 'T'\n\n        // Header fields:\n        public static readonly Binary ProtocolVersionKey = new Binary(0x00);\n        public static readonly Binary IndexKey = new Binary(0x69); // 'i'\n        public static readonly Binary TimestampKey = new Binary(0x74); // 't'\n        public static readonly Binary DifficultyKey = new Binary(0x64); // 'd'; legacy, unused\n        public static readonly Binary TotalDifficultyKey = new Binary(0x54); // 'T'; legacy, unused\n        public static readonly Binary NonceKey = new Binary(0x6e); // 'n'; Legacy, unused.\n        public static readonly Binary MinerKey = new Binary(0x6d); // 'm'\n        public static readonly Binary PublicKeyKey = new Binary(0x50); // 'P'\n        public static readonly Binary PreviousHashKey = new Binary(0x70); // 'p'\n        public static readonly Binary TxHashKey = new Binary(0x78); // 'x'\n        public static readonly Binary HashKey = new Binary(0x68); // 'h'\n        public static readonly Binary StateRootHashKey = new Binary(0x73); // 's'\n        public static readonly Binary SignatureKey = new Binary(0x53); // 'S'\n        public static readonly Binary PreEvaluationHashKey = new Binary(0x63); // 'c'\n        public static readonly Binary LastCommitKey = new Binary(0x43); // 'C'\n\n#pragma warning disable MEN002 // Line must be no longer than 100 characters\n        // Taken from 0.10.3\n        // Modified with state root hash from current fixture\n        public static readonly Dictionary BencodedV0Block = Dictionary.Empty\n            .Add(\n                HeaderKey,\n                Dictionary.Empty\n                    .Add(TotalDifficultyKey, new Integer(1))\n                    .Add(PreEvaluationHashKey, new Binary(ByteUtil.ParseHex(\"1cd4451624ef9c79e2c2fb5a8e791e4fa56a7d8c610c14a8a34ae175b5205cf7\")))\n                    .Add(DifficultyKey, new Integer(1))\n                    .Add(HashKey, new Binary(ByteUtil.ParseHex(\"4cc24bbbabb96b9d825fabdcc106753e2e01c3601f7925959656010eb6206974\")))\n                    .Add(IndexKey, new Integer(1))\n                    .Add(MinerKey, new Binary(ByteUtil.ParseHex(\"21744f4f08db23e044178dafb8273aeb5ebe6644\")))\n                    .Add(NonceKey, new Binary(ByteUtil.ParseHex(\"02000000\")))\n                    .Add(PreviousHashKey, new Binary(ByteUtil.ParseHex(\"d4f35834e27d5ab459a4d401e9a08268e3fe321b8c685075aec5bd5d18d642aa\")))\n                    .Add(StateRootHashKey, new Binary(ByteUtil.ParseHex(\"6a648da9e91c21aa22bdae4e35c338406392aad0db4a0f998c01a7d7973cb8aa\")))\n                    .Add(TimestampKey, new Text(\"2018-11-29T00:00:15.000000Z\")));\n\n        // Taken from 0.17.0\n        // Modified with state root hash from current fixture\n        // Adds ProtocolVersion\n        public static readonly Dictionary BencodedV1Block = Dictionary.Empty\n            .Add(\n                HeaderKey,\n                Dictionary.Empty\n                    .Add(ProtocolVersionKey, new Integer(1))\n                    .Add(TotalDifficultyKey, new Integer(1))\n                    .Add(PreEvaluationHashKey, new Binary(ByteUtil.ParseHex(\"1bba9fcf4c8152c899ed1674ecbf4a6571c271922c0884ae809f91f037bed8fc\")))\n                    .Add(DifficultyKey, new Integer(1))\n                    .Add(HashKey, new Binary(ByteUtil.ParseHex(\"41ac71ef0451ddd54078a1b3336b747e8b2f970b441c2e3cb5cad8290f7bc0d0\")))\n                    .Add(IndexKey, new Integer(1))\n                    .Add(MinerKey, new Binary(ByteUtil.ParseHex(\"21744f4f08db23e044178dafb8273aeb5ebe6644\")))\n                    .Add(NonceKey, new Binary(ByteUtil.ParseHex(\"02000000\")))\n                    .Add(PreviousHashKey, new Binary(ByteUtil.ParseHex(\"d693da3866a34d659e014f97c8feb08afe2e97c99e3f3389da025fd0665c621c\")))\n                    .Add(StateRootHashKey, new Binary(ByteUtil.ParseHex(\"6a648da9e91c21aa22bdae4e35c338406392aad0db4a0f998c01a7d7973cb8aa\")))\n                    .Add(TimestampKey, new Text(\"2018-11-29T00:00:15.000000Z\")));\n\n        // Taken from 0.27.7\n        // Adds miner public key and signature while removing miner address\n        public static readonly Dictionary BencodedV2Block = Dictionary.Empty\n            .Add(\n                HeaderKey,\n                Dictionary.Empty\n                    .Add(ProtocolVersionKey, new Integer(2))\n                    .Add(PublicKeyKey, new Binary(ByteUtil.ParseHex(\"037456f9cb6ec23d5cdc39ead2f783f4ca4e744d646458428e4f813d6267890b7c\")))\n                    .Add(SignatureKey, new Binary(ByteUtil.ParseHex(\"304402202d2cd14d4b909d9fa9422e321dba6b893bb891bda408e43e062e790cfb0100590220201e1e925edfbf6e2f484c3e4a56d13d21c13defadcb7322a8b23b60f6b17d15\")))\n                    .Add(TotalDifficultyKey, new Integer(1))\n                    .Add(PreEvaluationHashKey, new Binary(ByteUtil.ParseHex(\"e520162fef3516f4c0ccd6f79cc0c50f6e3bf7c53b1bf425b5e1931089e3fd8a\")))\n                    .Add(DifficultyKey, new Integer(1))\n                    .Add(HashKey, new Binary(ByteUtil.ParseHex(\"d7e10ac5f4fe56db093458f998d25350db738b7af9c1988f19f905c9c8e55f62\")))\n                    .Add(IndexKey, new Integer(1))\n                    .Add(NonceKey, new Binary(ByteUtil.ParseHex(\"02000000\")))\n                    .Add(PreviousHashKey, new Binary(ByteUtil.ParseHex(\"8ca7dd38c558e79f7981c720369766d326a9994883b38667ccd27d29d2945682\")))\n                    .Add(StateRootHashKey, new Binary(ByteUtil.ParseHex(\"6a648da9e91c21aa22bdae4e35c338406392aad0db4a0f998c01a7d7973cb8aa\")))\n                    .Add(TimestampKey, new Text(\"2018-11-29T00:00:15.000000Z\")));\n\n        // Taken from 0.49.3\n        // No changes other than protocol version\n        public static readonly Dictionary BencodedV3Block = Dictionary.Empty\n            .Add(\n                HeaderKey,\n                Dictionary.Empty\n                    .Add(ProtocolVersionKey, new Integer(3))\n                    .Add(PublicKeyKey, new Binary(ByteUtil.ParseHex(\"037456f9cb6ec23d5cdc39ead2f783f4ca4e744d646458428e4f813d6267890b7c\")))\n                    .Add(SignatureKey, new Binary(ByteUtil.ParseHex(\"3045022100cffa465a22aeb7c07f7a5663fc6a07ee1b4f1c70e6fb13ac501165574a3711df02207da2166c05d7915f9a166b4d0b79d81035ae640a7f2e7f338ae23418f210f445\")))\n                    .Add(TotalDifficultyKey, new Integer(1))\n                    .Add(PreEvaluationHashKey, new Binary(ByteUtil.ParseHex(\"af519fa381741e58781ea58a43233d155c212351d9840ef69e0a3555f210ad50\")))\n                    .Add(DifficultyKey, new Integer(1))\n                    .Add(HashKey, new Binary(ByteUtil.ParseHex(\"93294a9117d1d2b01d6479298864fccf29cd658c7cae60065349a07f9300bbd8\")))\n                    .Add(IndexKey, new Integer(1))\n                    .Add(NonceKey, new Binary(ByteUtil.ParseHex(\"02000000\")))\n                    .Add(PreviousHashKey, new Binary(ByteUtil.ParseHex(\"9e0b8085c105cff4da7db38ae37f61afeaa435db0377d2a1c6ad17d28d7e229d\")))\n                    .Add(StateRootHashKey, new Binary(ByteUtil.ParseHex(\"6a648da9e91c21aa22bdae4e35c338406392aad0db4a0f998c01a7d7973cb8aa\")))\n                    .Add(TimestampKey, new Text(\"2018-11-29T00:00:15.000000Z\")));\n#pragma warning restore MEN002\n    }\n}\n"
  },
  {
    "path": "test/Libplanet.Tests/Fixtures/OperatorType.cs",
    "content": "namespace Libplanet.Tests.Fixtures\n{\n    public enum OperatorType\n    {\n        /// <summary>\n        /// Addition.\n        /// </summary>\n        Add,\n\n        /// <summary>\n        /// Subtraction.\n        /// </summary>\n        Sub,\n\n        /// <summary>\n        /// Multiplication.\n        /// </summary>\n        Mul,\n\n        /// <summary>\n        /// Division.\n        /// </summary>\n        Div,\n\n        /// <summary>\n        /// Modulo.\n        /// </summary>\n        Mod,\n    }\n}\n"
  },
  {
    "path": "test/Libplanet.Tests/Fixtures/OperatorTypeExtensions.cs",
    "content": "using System;\nusing System.Numerics;\n\nnamespace Libplanet.Tests.Fixtures\n{\n    public static class OperatorTypeExtensions\n    {\n        public static Func<BigInteger, BigInteger, BigInteger> ToFunc(this OperatorType @operator)\n        {\n            switch (@operator)\n            {\n                case OperatorType.Add:\n                    return BigInteger.Add;\n                case OperatorType.Sub:\n                    return BigInteger.Subtract;\n                case OperatorType.Mul:\n                    return BigInteger.Multiply;\n                case OperatorType.Div:\n                    return BigInteger.Divide;\n                case OperatorType.Mod:\n                    return BigInteger.Remainder;\n            }\n\n            throw new ArgumentException(\"Unsupported operator: \" + @operator, nameof(@operator));\n        }\n    }\n}\n"
  },
  {
    "path": "test/Libplanet.Tests/HashDigestTest.cs",
    "content": "using System;\nusing System.Collections.Immutable;\nusing System.ComponentModel;\nusing System.Security.Cryptography;\nusing Libplanet.Common;\nusing Xunit;\nusing static Libplanet.Tests.TestUtils;\n\nnamespace Libplanet.Tests\n{\n    public class HashDigestTest\n    {\n        [Fact]\n        public void DefaultConstructor()\n        {\n            HashDigest<SHA1> sha1Default = default;\n            Assert.Equal(new HashDigest<SHA1>(new byte[20]), sha1Default);\n\n            HashDigest<SHA256> sha256Default = default;\n            Assert.Equal(new HashDigest<SHA256>(new byte[32]), sha256Default);\n        }\n\n        [Fact]\n        public void DisallowNull()\n        {\n            Assert.Throws<ArgumentNullException>(\n                () => new HashDigest<SHA1>((byte[])null));\n            Assert.Throws<ArgumentNullException>(\n                () => new HashDigest<SHA256>((byte[])null));\n        }\n\n        [Fact]\n        public void Bencoded()\n        {\n            Assert.NotEqual(HashDigest<SHA1>.Size, HashDigest<SHA256>.Size);\n            var digest = new HashDigest<SHA256>(TestUtils.GetRandomBytes(HashDigest<SHA256>.Size));\n            var bencoded = digest.Bencoded;\n            var decoded = new HashDigest<SHA256>(bencoded);\n            Assert.Equal(digest, decoded);\n            Assert.Throws<ArgumentOutOfRangeException>(() => new HashDigest<SHA1>(bencoded));\n        }\n\n        [Fact]\n        public void ToHashDigestWorks()\n        {\n            var b =\n                new byte[20]\n                {\n                    0x45, 0xa2, 0x21, 0x87, 0xe2, 0xd8, 0x85, 0x0b, 0xb3, 0x57,\n                    0x88, 0x69, 0x58, 0xbc, 0x3e, 0x85, 0x60, 0x92, 0x9c, 0xcc,\n                };\n            var expected = new HashDigest<SHA1>(b);\n            HashDigest<SHA1> actual =\n                \"45a22187e2d8850bb357886958bc3e8560929ccc\".ToHashDigest<SHA1>();\n\n            Assert.Equal(expected, actual);\n        }\n\n        [Fact]\n        public void FromStringWorks()\n        {\n            var b =\n                new byte[20]\n                {\n                    0x45, 0xa2, 0x21, 0x87, 0xe2, 0xd8, 0x85, 0x0b, 0xb3, 0x57,\n                    0x88, 0x69, 0x58, 0xbc, 0x3e, 0x85, 0x60, 0x92, 0x9c, 0xcc,\n                };\n            var expected = new HashDigest<SHA1>(b);\n            HashDigest<SHA1> actual = HashDigest<SHA1>.FromString(\n                \"45a22187e2d8850bb357886958bc3e8560929ccc\");\n\n            Assert.Equal(expected, actual);\n\n            Assert.Throws<ArgumentNullException>(\n                () => HashDigest<SHA1>.FromString(null)\n            );\n        }\n\n        [Fact]\n        public void DeriveFrom()\n        {\n            byte[] foo = { 0x66, 0x6f, 0x6f }, bar = { 0x62, 0x61, 0x72 };\n            Assert.Equal(\n                HashDigest<SHA1>.FromString(\"0beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a33\"),\n                HashDigest<SHA1>.DeriveFrom(foo)\n            );\n            Assert.Equal(\n                HashDigest<SHA1>.DeriveFrom(foo),\n                HashDigest<SHA1>.DeriveFrom(ImmutableArray.Create(foo))\n            );\n            Assert.Equal(\n                HashDigest<SHA1>.DeriveFrom(foo),\n                HashDigest<SHA1>.DeriveFrom(foo.AsSpan())\n            );\n            Assert.Equal(\n                HashDigest<SHA1>.FromString(\"62cdb7020ff920e5aa642c3d4066950dd1f01f4d\"),\n                HashDigest<SHA1>.DeriveFrom(bar)\n            );\n            Assert.Equal(\n                HashDigest<MD5>.FromString(\"acbd18db4cc2f85cedef654fccc4a4d8\"),\n                HashDigest<MD5>.DeriveFrom(foo)\n            );\n            Assert.Equal(\n                HashDigest<MD5>.FromString(\"37b51d194a7513e45b56f6524f2d51f2\"),\n                HashDigest<MD5>.DeriveFrom(bar)\n            );\n        }\n\n        [Fact]\n        public void HashDigestDisallowsIncorrectSizedBytes()\n        {\n            for (int i = 0; i < 22; ++i)\n            {\n                if (i == 20)\n                {\n                    new HashDigest<SHA1>(new byte[i]);\n                    HashDigest<SHA1>.FromString(new string('0', i * 2));\n                    continue;\n                }\n\n                Assert.Throws<ArgumentOutOfRangeException>(\n                    () => new HashDigest<SHA1>(new byte[i])\n                );\n                Assert.Throws<ArgumentOutOfRangeException>(\n                    () => HashDigest<SHA1>.FromString(new string('0', i * 2))\n                );\n            }\n        }\n\n        [Fact]\n        public void FromImmutableArrayConstructor()\n        {\n            var b =\n                new byte[20]\n                {\n                    0x45, 0xa2, 0x21, 0x87, 0xe2, 0xd8, 0x85, 0x0b, 0xb3, 0x57,\n                    0x88, 0x69, 0x58, 0xbc, 0x3e, 0x85, 0x60, 0x92, 0x9c, 0xcc,\n                };\n            var bAsArray = b.ToImmutableArray();\n\n            var expected = new HashDigest<SHA1>(b);\n            HashDigest<SHA1> actual = new HashDigest<SHA1>(bAsArray);\n\n            Assert.Equal(expected, actual);\n        }\n\n        [Fact]\n        public void FromImmutableArrayDisallowIncorrectSizeBytes()\n        {\n            var b =\n                new byte[10]\n                {\n                    0x45, 0xa2, 0x21, 0x87, 0xe2, 0xd8, 0x85, 0x0b, 0xb3, 0x57,\n                };\n            var bAsArray = b.ToImmutableArray();\n\n            Assert.Throws<ArgumentOutOfRangeException>(\n                () => new HashDigest<SHA1>(bAsArray)\n            );\n        }\n\n        [Fact]\n        public void TypeConverter()\n        {\n            TypeConverter converter = TypeDescriptor.GetConverter(typeof(HashDigest<SHA1>));\n            var sha1 = HashDigest<SHA1>.FromString(\"62cdb7020ff920e5aa642c3d4066950dd1f01f4d\");\n            Assert.True(converter.CanConvertFrom(typeof(string)));\n            Assert.Equal(\n                sha1,\n                converter.ConvertFrom(\"62cdb7020ff920e5aa642c3d4066950dd1f01f4d\"));\n            Assert.Equal(\n                sha1,\n                converter.ConvertFrom(\"62CDB7020FF920E5AA642C3D4066950DD1F01F4D\"));\n            Assert.Throws<ArgumentException>(() => converter.ConvertFrom(\"INVALID\"));\n\n            Assert.True(converter.CanConvertTo(typeof(string)));\n            Assert.Equal(\n                \"62cdb7020ff920e5aa642c3d4066950dd1f01f4d\",\n                converter.ConvertTo(sha1, typeof(string)));\n        }\n\n        [SkippableFact]\n        public void JsonSerialization()\n        {\n            HashDigest<SHA1> digest =\n                HashDigest<SHA1>.FromString(\"0beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a33\");\n            AssertJsonSerializable(\n                digest,\n                \"\\\"0beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a33\\\"\"\n            );\n        }\n    }\n}\n"
  },
  {
    "path": "test/Libplanet.Tests/HashSetExtensions.cs",
    "content": "using System.Collections.Generic;\n\nnamespace Libplanet.Tests\n{\n    public static class HashSetExtensions\n    {\n        public static HashSet<T> ToHashSet<T>(this IEnumerable<T> l)\n        {\n            return new HashSet<T>(l);\n        }\n    }\n}\n"
  },
  {
    "path": "test/Libplanet.Tests/ImmutableArrayEqualityComparer.cs",
    "content": "using System.Collections.Generic;\nusing System.Collections.Immutable;\nusing System.Linq;\n\nnamespace Libplanet.Tests\n{\n    public class ImmutableArrayEqualityComparer<T> : IEqualityComparer<ImmutableArray<T>>\n    {\n        public bool Equals(ImmutableArray<T> x, ImmutableArray<T> y)\n            => x.Length == y.Length && x.SequenceEqual(y);\n\n        public int GetHashCode(ImmutableArray<T> obj)\n        {\n            int code = 0;\n            unchecked\n            {\n                foreach (T el in obj)\n                {\n                    code = (code * 397) ^ el.GetHashCode();\n                }\n            }\n\n            return code;\n        }\n    }\n}\n"
  },
  {
    "path": "test/Libplanet.Tests/JsonConverters/BigIntegerJsonConverterTest.cs",
    "content": "using System.Numerics;\nusing System.Text;\nusing System.Text.Json;\nusing Libplanet.Common.JsonConverters;\nusing Xunit;\n\nnamespace Libplanet.Tests.JsonConverters\n{\n    public class BigIntegerJsonConverterTest\n    {\n        [Fact]\n        public void Write()\n        {\n            var converter = new BigIntegerJsonConverter();\n            var stream = new System.IO.MemoryStream();\n            using (var writer = new Utf8JsonWriter(stream))\n            {\n                converter.Write(writer, new BigInteger(ulong.MaxValue) + 1, null);\n            }\n\n            stream.Seek(0, System.IO.SeekOrigin.Begin);\n            string actual = Encoding.ASCII.GetString(stream.GetBuffer(), 0, (int)stream.Length);\n            Assert.Equal(\"18446744073709551616\", actual);\n        }\n\n        [Fact]\n        public void Read()\n        {\n            byte[] jsonBytes = Encoding.ASCII.GetBytes(\"18446744073709551616\");\n            var reader = new Utf8JsonReader(jsonBytes);\n            reader.Read();\n            var converter = new BigIntegerJsonConverter();\n            BigInteger actual = converter.Read(ref reader, typeof(BigInteger), null);\n            Assert.Equal(new BigInteger(ulong.MaxValue) + 1, actual);\n        }\n    }\n}\n"
  },
  {
    "path": "test/Libplanet.Tests/JsonConverters/ByteArrayJsonConverterTest.cs",
    "content": "using System.Collections.Generic;\nusing System.Collections.Immutable;\nusing System.Text;\nusing System.Text.Json;\nusing Libplanet.Common.JsonConverters;\nusing Xunit;\n\nnamespace Libplanet.Tests.JsonConverters\n{\n    public class ByteArrayJsonConverterTest\n    {\n        [Fact]\n        public void Write()\n        {\n            var converter = new ByteArrayJsonConverter();\n            var stream = new System.IO.MemoryStream();\n            using (var writer = new Utf8JsonWriter(stream))\n            {\n                writer.WriteStartArray();\n                converter.Write(writer, new byte[] { 0xc4, 0x92, 0xa0 }, null);\n                converter.Write(writer, ImmutableArray.Create<byte>(0xfa, 0x7e, 0xf0), null);\n                converter.Write(\n                    writer,\n                    (ImmutableArray<byte>?)ImmutableArray.Create<byte>(0x3c, 0xce, 0x82),\n                    null\n                );\n                converter.Write(writer, (ImmutableArray<byte>?)null, null);\n                writer.WriteEndArray();\n            }\n\n            stream.Seek(0, System.IO.SeekOrigin.Begin);\n            string actual = Encoding.ASCII.GetString(stream.GetBuffer(), 0, (int)stream.Length);\n            Assert.Equal(\"[\\\"c492a0\\\",\\\"fa7ef0\\\",\\\"3cce82\\\",null]\", actual);\n        }\n\n        [Fact]\n        public void Read()\n        {\n            byte[] jsonBytes = Encoding.ASCII.GetBytes(\"\\\"c492a0\\\"\");\n            var reader = new Utf8JsonReader(jsonBytes);\n            reader.Read();\n            var converter = new ByteArrayJsonConverter();\n            IReadOnlyList<byte> actual = converter.Read(ref reader, typeof(byte[]), null);\n            Assert.IsType<byte[]>(actual);\n            Assert.Equal(new byte[] { 0xc4, 0x92, 0xa0 }, actual);\n\n            reader = new Utf8JsonReader(jsonBytes);\n            reader.Read();\n            actual = converter.Read(ref reader, typeof(ImmutableArray<byte>), null);\n            Assert.IsType<ImmutableArray<byte>>(actual);\n            Assert.Equal(ImmutableArray.Create<byte>(0xc4, 0x92, 0xa0), actual);\n\n            jsonBytes = Encoding.ASCII.GetBytes(\"null\");\n            reader = new Utf8JsonReader(jsonBytes);\n            reader.Read();\n            actual = converter.Read(ref reader, typeof(ImmutableArray<byte>?), null);\n            Assert.Null(actual);\n        }\n    }\n}\n"
  },
  {
    "path": "test/Libplanet.Tests/KeyStore/Ciphers/Aes128CtrTest.cs",
    "content": "using System;\nusing System.Collections.Immutable;\nusing System.Text.Json;\nusing Libplanet.KeyStore;\nusing Libplanet.KeyStore.Ciphers;\nusing Xunit;\n\nnamespace Libplanet.Tests.KeyStore.Ciphers\n{\n    public class Aes128CtrTest : CipherTest<Aes128Ctr>\n    {\n        public Aes128CtrTest()\n        {\n            var random = new Random();\n            var buffer = new byte[16];\n            random.NextBytes(buffer);\n            Cipher = new Aes128Ctr(buffer.ToImmutableArray());\n        }\n\n        public override Aes128Ctr Cipher { get; }\n\n        [Fact]\n        public void Constructor()\n        {\n            Assert.Throws<ArgumentException>(() =>\n                new Aes128Ctr(new byte[0].ToImmutableArray())\n            );\n            var random = new Random();\n            var buffer = new byte[17];\n            random.NextBytes(buffer);\n            Assert.Throws<ArgumentOutOfRangeException>(() =>\n                new Aes128Ctr(buffer.ToImmutableArray())\n            );\n        }\n\n        [Fact]\n        public void FromJson()\n        {\n            var options = new JsonDocumentOptions\n            {\n                AllowTrailingCommas = true,\n                CommentHandling = JsonCommentHandling.Skip,\n            };\n\n            Aes128Ctr Load(string json)\n            {\n                using (JsonDocument doc = JsonDocument.Parse(json, options))\n                {\n                    return (Aes128Ctr)Aes128Ctr.FromJson(doc.RootElement);\n                }\n            }\n\n            Aes128Ctr cipher = Load(@\"{\n                \"\"iv\"\": \"\"bc7f2ca23bfee0dd9725228ab2b0d98a\"\",\n            }\");\n            TestUtils.AssertBytesEqual(\n                new byte[]\n                {\n                    0xbc, 0x7f, 0x2c, 0xa2, 0x3b, 0xfe, 0xe0, 0xdd,\n                    0x97, 0x25, 0x22, 0x8a, 0xb2, 0xb0, 0xd9, 0x8a,\n                }.ToImmutableArray(),\n                cipher.Iv\n            );\n\n            Assert.Throws<InvalidKeyJsonException>(() =>\n                Load(@\"{\n                    // \"\"iv\"\": \"\"...\"\",  // lacks\n                }\")\n            );\n\n            Assert.Throws<InvalidKeyJsonException>(() =>\n                Load(@\"{\n                    \"\"iv\"\": true,  // not a string\n                }\")\n            );\n\n            Assert.Throws<InvalidKeyJsonException>(() =>\n                Load(@\"{\n                    \"\"iv\"\": null,  // not a string, but null\n                }\")\n            );\n\n            Assert.Throws<InvalidKeyJsonException>(() =>\n                Load(@\"{\n                    \"\"iv\"\": \"\"not a hexadecimal string\"\",\n                }\")\n            );\n\n            Assert.Throws<InvalidKeyJsonException>(() =>\n                Load(@\"{\n                    \"\"iv\"\": \"\"bc7f2ca23bfee0dd9725228ab2b0d98\"\",\n                    // iv: invalid length\n                }\")\n            );\n        }\n    }\n}\n"
  },
  {
    "path": "test/Libplanet.Tests/KeyStore/Ciphers/CipherTest.cs",
    "content": "using System.Collections.Immutable;\nusing Libplanet.KeyStore.Ciphers;\nusing Xunit;\nusing Random = System.Random;\n\nnamespace Libplanet.Tests.KeyStore.Ciphers\n{\n    public abstract class CipherTest<T>\n        where T : ICipher\n    {\n        public abstract T Cipher { get; }\n\n        [Fact]\n        public void EncryptDecrypt()\n        {\n            var random = new Random();\n            var buffer = new byte[4096];\n            random.NextBytes(buffer);\n            ImmutableArray<byte> key = ImmutableArray.Create(buffer, 0, 16);\n            random.NextBytes(buffer);\n            ImmutableArray<byte> value = buffer.ToImmutableArray();\n            T c = Cipher;\n            ImmutableArray<byte> encrypted = c.Encrypt(key, value);\n            ImmutableArray<byte> decrypted = c.Decrypt(key, encrypted);\n            TestUtils.AssertBytesEqual(value, decrypted);\n        }\n    }\n}\n"
  },
  {
    "path": "test/Libplanet.Tests/KeyStore/IncorrectPassphraseExceptionTest.cs",
    "content": "using System.Collections.Immutable;\nusing Libplanet.KeyStore;\nusing Xunit;\nusing static Libplanet.Tests.TestUtils;\n\nnamespace Libplanet.Tests.KeyStore\n{\n    public class IncorrectPassphraseExceptionTest\n    {\n        [Fact]\n        public void Constructor()\n        {\n            ImmutableArray<byte>\n                expectedMac = new byte[] { 0x00, 0x01, 0x02, 0x03 }.ToImmutableArray(),\n                inputMac = new byte[] { 0x04, 0x05, 0x06, 0x07 }.ToImmutableArray();\n            var e = new IncorrectPassphraseException(\n                \"Some message.\",\n                \"paramName\",\n                expectedMac,\n                inputMac\n            );\n            Assert.StartsWith(\n                \"Some message.\\nExpected MAC: 00010203\\nInput MAC: 04050607\",\n                e.Message\n            );\n            Assert.Equal(\"paramName\", e.ParamName);\n            AssertBytesEqual(expectedMac, e.ExpectedMac);\n            AssertBytesEqual(inputMac, e.InputMac);\n        }\n    }\n}\n"
  },
  {
    "path": "test/Libplanet.Tests/KeyStore/Kdfs/KdfTest.cs",
    "content": "using System.Collections.Immutable;\nusing System.Security.Cryptography;\nusing Libplanet.KeyStore.Kdfs;\nusing Xunit;\n\nnamespace Libplanet.Tests.KeyStore.Kdfs\n{\n    public abstract class KdfTest<T>\n        where T : IKdf\n    {\n        public abstract T MakeInstance(byte[] randomBytes);\n\n        [InlineData(16, \"foo\")]\n        [InlineData(32, \"foo\")]\n        [InlineData(32, \"unicode-暗號\")]\n        [Theory]\n        public void Derive(int size, string passphrase)\n        {\n            var randomBytes = new byte[size];\n            using (RandomNumberGenerator rng = RandomNumberGenerator.Create())\n            {\n                rng.GetBytes(randomBytes);\n            }\n\n            T kdf = MakeInstance(randomBytes);\n            ImmutableArray<byte> dFoo = kdf.Derive(passphrase);\n            Assert.Equal(size, dFoo.Length);\n            ImmutableArray<byte> dBar = kdf.Derive($\"different-{passphrase}\");\n            Assert.NotEqual(dFoo, dBar);\n            TestUtils.AssertBytesEqual(dFoo, kdf.Derive(passphrase));\n        }\n    }\n}\n"
  },
  {
    "path": "test/Libplanet.Tests/KeyStore/Kdfs/Pbkdf2Test.cs",
    "content": "using System.Collections.Immutable;\nusing System.Text.Json;\nusing Libplanet.KeyStore;\nusing Libplanet.KeyStore.Kdfs;\nusing Org.BouncyCastle.Crypto.Digests;\nusing Xunit;\n\nnamespace Libplanet.Tests.KeyStore.Kdfs\n{\n    public class Pbkdf2Test : KdfTest<Pbkdf2<Sha256Digest>>\n    {\n        public override Pbkdf2<Sha256Digest> MakeInstance(byte[] randomBytes)\n        {\n            return new Pbkdf2<Sha256Digest>(10, randomBytes, randomBytes.Length);\n        }\n\n        [Fact]\n        public void FromJson()\n        {\n            var options = new JsonDocumentOptions\n            {\n                AllowTrailingCommas = true,\n                CommentHandling = JsonCommentHandling.Skip,\n            };\n\n            Pbkdf2<Sha256Digest> Load(string json)\n            {\n                using (JsonDocument doc = JsonDocument.Parse(json, options))\n                {\n                    return (Pbkdf2<Sha256Digest>)Pbkdf2.FromJson(doc.RootElement);\n                }\n            }\n\n            var kdf = Load(@\"\n            {\n                \"\"c\"\": 10240,\n                \"\"dklen\"\": 32,\n                \"\"prf\"\": \"\"hmac-sha256\"\",\n                \"\"salt\"\": \"\"3eeaaf35da70928387cae1ead31ed782b1135d7578a89d95e30cc914010ba2ed\"\",\n            }\n            \");\n            Assert.Equal(10240, kdf.Iterations);\n            Assert.Equal(32, kdf.KeyLength);\n            TestUtils.AssertBytesEqual(\n                new byte[]\n                {\n                    0x3e, 0xea, 0xaf, 0x35, 0xda, 0x70, 0x92, 0x83, 0x87, 0xca, 0xe1,\n                    0xea, 0xd3, 0x1e, 0xd7, 0x82, 0xb1, 0x13, 0x5d, 0x75, 0x78, 0xa8,\n                    0x9d, 0x95, 0xe3, 0x0c, 0xc9, 0x14, 0x01, 0x0b, 0xa2, 0xed,\n                }.ToImmutableArray(),\n                kdf.Salt\n            );\n\n            Assert.Throws<InvalidKeyJsonException>(() =>\n                Load(@\"\n                {\n                    // \"\"c\"\": 10240,  // lacks\n                    \"\"dklen\"\": 32,\n                    \"\"prf\"\": \"\"hmac-sha256\"\",\n                    \"\"salt\"\": \"\"3eeaaf35da70928387cae1ead31ed782b1135d7578a89d95e30cc914010ba2ed\"\",\n                }\n                \")\n            );\n\n            Assert.Throws<InvalidKeyJsonException>(() =>\n                Load(@\"\n                {\n                    \"\"c\"\": true,  // not a number\n                    \"\"dklen\"\": 32,\n                    \"\"prf\"\": \"\"hmac-sha256\"\",\n                    \"\"salt\"\": \"\"3eeaaf35da70928387cae1ead31ed782b1135d7578a89d95e30cc914010ba2ed\"\",\n                }\n                \")\n            );\n\n            Assert.Throws<InvalidKeyJsonException>(() =>\n                Load(@\"\n                {\n                    \"\"c\"\": null,  // not a number, but null\n                    \"\"dklen\"\": 32,\n                    \"\"prf\"\": \"\"hmac-sha256\"\",\n                    \"\"salt\"\": \"\"3eeaaf35da70928387cae1ead31ed782b1135d7578a89d95e30cc914010ba2ed\"\",\n                }\n                \")\n            );\n\n            Assert.Throws<InvalidKeyJsonException>(() =>\n                Load(@\"\n                {\n                    \"\"c\"\": 10240,\n                    // \"\"dklen\"\": 32,  // lacks\n                    \"\"prf\"\": \"\"hmac-sha256\"\",\n                    \"\"salt\"\": \"\"3eeaaf35da70928387cae1ead31ed782b1135d7578a89d95e30cc914010ba2ed\"\",\n                }\n                \")\n            );\n\n            Assert.Throws<InvalidKeyJsonException>(() =>\n                Load(@\"\n                {\n                    \"\"c\"\": 10240,\n                    \"\"dklen\"\": false,  // not a number\n                    \"\"prf\"\": \"\"hmac-sha256\"\",\n                    \"\"salt\"\": \"\"3eeaaf35da70928387cae1ead31ed782b1135d7578a89d95e30cc914010ba2ed\"\",\n                }\n                \")\n            );\n\n            Assert.Throws<InvalidKeyJsonException>(() =>\n                Load(@\"\n                {\n                    \"\"c\"\": 10240,\n                    \"\"dklen\"\": null,  // not a number, but null\n                    \"\"prf\"\": \"\"hmac-sha256\"\",\n                    \"\"salt\"\": \"\"3eeaaf35da70928387cae1ead31ed782b1135d7578a89d95e30cc914010ba2ed\"\",\n                }\n                \")\n            );\n\n            Assert.Throws<InvalidKeyJsonException>(() =>\n                Load(@\"\n                {\n                    \"\"c\"\": 10240,\n                    \"\"dklen\"\": 32,\n                    // \"\"prf\"\": \"\"hmac-sha256\"\",  // lacks\n                    \"\"salt\"\": \"\"3eeaaf35da70928387cae1ead31ed782b1135d7578a89d95e30cc914010ba2ed\"\",\n                }\n                \")\n            );\n\n            Assert.Throws<InvalidKeyJsonException>(() =>\n                Load(@\"\n                {\n                    \"\"c\"\": 10240,\n                    \"\"dklen\"\": 32,\n                    \"\"prf\"\": 123,  // not a string, but a number\n                    \"\"salt\"\": \"\"3eeaaf35da70928387cae1ead31ed782b1135d7578a89d95e30cc914010ba2ed\"\",\n                }\n                \")\n            );\n\n            Assert.Throws<UnsupportedKeyJsonException>(() =>\n                Load(@\"\n                {\n                    \"\"c\"\": 10240,\n                    \"\"dklen\"\": 32,\n                    \"\"prf\"\": \"\"hmac-sha512\"\",  // unsupported prf\n                    \"\"salt\"\": \"\"3eeaaf35da70928387cae1ead31ed782b1135d7578a89d95e30cc914010ba2ed\"\",\n                }\n                \")\n            );\n\n            Assert.Throws<InvalidKeyJsonException>(() =>\n                Load(@\"\n                {\n                    \"\"c\"\": 10240,\n                    \"\"dklen\"\": 32,\n                    \"\"prf\"\": \"\"hmac-sha256\"\",\n                    // \"\"salt\"\": \"\"...\"\",  // lacks\n                }\n                \")\n            );\n\n            Assert.Throws<InvalidKeyJsonException>(() =>\n                Load(@\"\n                {\n                    \"\"c\"\": 10240,\n                    \"\"dklen\"\": 32,\n                    \"\"prf\"\": \"\"hmac-sha256\"\",\n                    \"\"salt\"\": 1234,  // not a string, but a number\n                }\n                \")\n            );\n\n            Assert.Throws<InvalidKeyJsonException>(() =>\n                Load(@\"\n                {\n                    \"\"c\"\": 10240,\n                    \"\"dklen\"\": 32,\n                    \"\"prf\"\": \"\"hmac-sha256\"\",\n                    \"\"salt\"\": \"\"not a hexadecimal string\"\",\n                }\n                \")\n            );\n\n            Assert.Throws<InvalidKeyJsonException>(() =>\n                Load(@\"\n                {\n                    \"\"c\"\": 10240,\n                    \"\"dklen\"\": 32,\n                    \"\"prf\"\": \"\"hmac-sha256\"\",\n                    \"\"salt\"\": \"\"3eeaaf35da70928387cae1ead31ed782b1135d7578a89d95e30cc914010ba2e\"\",\n                    // salt: invalid length\n                }\n                \")\n            );\n        }\n    }\n}\n"
  },
  {
    "path": "test/Libplanet.Tests/KeyStore/Kdfs/ScryptTest.cs",
    "content": "using System;\nusing System.Collections.Immutable;\nusing System.Diagnostics.CodeAnalysis;\nusing System.Text.Json;\nusing Libplanet.KeyStore;\nusing Libplanet.KeyStore.Kdfs;\nusing Xunit;\n\nnamespace Libplanet.Tests.KeyStore.Kdfs\n{\n    public class ScryptTest : KdfTest<Scrypt>\n    {\n        public override Scrypt MakeInstance(byte[] randomBytes)\n        {\n            return new Scrypt(8, randomBytes, randomBytes.Length, 1, 8);\n        }\n\n        [Fact]\n        public void ScryptInitialize()\n        {\n            Assert.Throws<ArgumentOutOfRangeException>(() =>\n                new Scrypt(1, ImmutableArray<byte>.Empty, 0, 1, 8)\n                // Cost must be a power of 2 greater than 1!\n            );\n            Assert.Throws<ArgumentOutOfRangeException>(() =>\n                new Scrypt(2, ImmutableArray<byte>.Empty, 0, 1, int.MaxValue)\n                // Parameter cost is too large!\n            );\n            Assert.Throws<ArgumentOutOfRangeException>(() =>\n                new Scrypt(2, ImmutableArray<byte>.Empty, 0, int.MaxValue, 8)\n                // Parameter blockSize is too large!\n            );\n        }\n\n        [SuppressMessage(\n            \"Microsoft.StyleCop.CSharp.ReadabilityRules\",\n            \"MEN003\",\n            Justification = \"There are just test cases.\")]\n        [Fact]\n        public void FromJson()\n        {\n            var options = new JsonDocumentOptions\n            {\n                AllowTrailingCommas = true,\n                CommentHandling = JsonCommentHandling.Skip,\n            };\n\n            Scrypt Load(string json)\n            {\n                using (JsonDocument doc = JsonDocument.Parse(json, options))\n                {\n                    return (Scrypt)Scrypt.FromJson(doc.RootElement);\n                }\n            }\n\n            var kdf = Load(@\"\n            {\n                \"\"dklen\"\": 32,\n                \"\"n\"\": 262144,\n                \"\"p\"\": 1,\n                \"\"r\"\": 8,\n                \"\"salt\"\": \"\"3ada4bad7033fdaa65684ecf93dab3186e48d3f80965070d5fc9aac07811dc8f\"\",\n            }\n            \");\n            Assert.Equal(262144, kdf.Cost);\n            Assert.Equal(32, kdf.KeyLength);\n            Assert.Equal(1, kdf.Parallelization);\n            Assert.Equal(8, kdf.BlockSize);\n            TestUtils.AssertBytesEqual(\n                new byte[]\n                {\n                    0x3a, 0xda, 0x4b, 0xad, 0x70, 0x33, 0xfd, 0xaa, 0x65, 0x68, 0x4e,\n                    0xcf, 0x93, 0xda, 0xb3, 0x18, 0x6e, 0x48, 0xd3, 0xf8, 0x09, 0x65,\n                    0x07, 0x0d, 0x5f, 0xc9, 0xaa, 0xc0, 0x78, 0x11, 0xdc, 0x8f,\n                }.ToImmutableArray(),\n                kdf.Salt\n            );\n\n            Assert.Throws<InvalidKeyJsonException>(() =>\n                Load(@\"\n                {\n                    // \"\"dklen\"\": 32,  // lacks\n                    \"\"n\"\": 262144,\n                    \"\"p\"\": 1,\n                    \"\"r\"\": 8,\n                    \"\"salt\"\": \"\"3ada4bad7033fdaa65684ecf93dab3186e48d3f80965070d5fc9aac07811dc8f\"\",\n                }\n                \")\n            );\n\n            Assert.Throws<InvalidKeyJsonException>(() =>\n                Load(@\"\n                {\n                    \"\"dklen\"\": true,  // not a number\n                    \"\"n\"\": 262144,\n                    \"\"p\"\": 1,\n                    \"\"r\"\": 8,\n                    \"\"salt\"\": \"\"3ada4bad7033fdaa65684ecf93dab3186e48d3f80965070d5fc9aac07811dc8f\"\",\n                }\n                \")\n            );\n\n            Assert.Throws<InvalidKeyJsonException>(() =>\n                Load(@\"\n                {\n                    \"\"dklen\"\": null,  // not a number, but null\n                    \"\"n\"\": 262144,\n                    \"\"p\"\": 1,\n                    \"\"r\"\": 8,\n                    \"\"salt\"\": \"\"3ada4bad7033fdaa65684ecf93dab3186e48d3f80965070d5fc9aac07811dc8f\"\",\n                }\n                \")\n            );\n\n            Assert.Throws<InvalidKeyJsonException>(() =>\n                Load(@\"\n                {\n                    \"\"dklen\"\": 32,\n                    // \"\"n\"\": 262144,  // lacks\n                    \"\"p\"\": 1,\n                    \"\"r\"\": 8,\n                    \"\"salt\"\": \"\"3ada4bad7033fdaa65684ecf93dab3186e48d3f80965070d5fc9aac07811dc8f\"\",\n                }\n                \")\n            );\n\n            Assert.Throws<InvalidKeyJsonException>(() =>\n                Load(@\"\n                {\n                    \"\"dklen\"\": 32,\n                    \"\"n\"\": false,  // not a number\n                    \"\"p\"\": 1,\n                    \"\"r\"\": 8,\n                    \"\"salt\"\": \"\"3ada4bad7033fdaa65684ecf93dab3186e48d3f80965070d5fc9aac07811dc8f\"\",\n                }\n                \")\n            );\n\n            Assert.Throws<InvalidKeyJsonException>(() =>\n                Load(@\"\n                {\n                    \"\"dklen\"\": 32,\n                    \"\"n\"\": null,  // not a number, but null\n                    \"\"p\"\": 1,\n                    \"\"r\"\": 8,\n                    \"\"salt\"\": \"\"3ada4bad7033fdaa65684ecf93dab3186e48d3f80965070d5fc9aac07811dc8f\"\",\n                }\n                \")\n            );\n\n            Assert.Throws<InvalidKeyJsonException>(() =>\n                Load(@\"\n                {\n                    \"\"dklen\"\": 32,\n                    \"\"n\"\": 262144,\n                    // \"\"p\"\": 1,  // lacks\n                    \"\"r\"\": 8,\n                    \"\"salt\"\": \"\"3ada4bad7033fdaa65684ecf93dab3186e48d3f80965070d5fc9aac07811dc8f\"\",\n                }\n                \")\n            );\n\n            Assert.Throws<InvalidKeyJsonException>(() =>\n                Load(@\"\n                {\n                    \"\"dklen\"\": 32,\n                    \"\"n\"\": 262144,\n                    \"\"p\"\": false,  // not a number\n                    \"\"r\"\": 8,\n                    \"\"salt\"\": \"\"3ada4bad7033fdaa65684ecf93dab3186e48d3f80965070d5fc9aac07811dc8f\"\",\n                }\n                \")\n            );\n\n            Assert.Throws<InvalidKeyJsonException>(() =>\n                Load(@\"\n                {\n                    \"\"dklen\"\": 32,\n                    \"\"n\"\": 262144,\n                    \"\"p\"\": null,  // not a number, but null\n                    \"\"r\"\": 8,\n                    \"\"salt\"\": \"\"3ada4bad7033fdaa65684ecf93dab3186e48d3f80965070d5fc9aac07811dc8f\"\",\n                }\n                \")\n            );\n\n            Assert.Throws<InvalidKeyJsonException>(() =>\n                Load(@\"\n                {\n                    \"\"dklen\"\": 32,\n                    \"\"n\"\": 262144,\n                    \"\"p\"\": 1,\n                    // \"\"r\"\": 8,  // lacks\n                    \"\"salt\"\": \"\"3ada4bad7033fdaa65684ecf93dab3186e48d3f80965070d5fc9aac07811dc8f\"\",\n                }\n                \")\n            );\n\n            Assert.Throws<InvalidKeyJsonException>(() =>\n                Load(@\"\n                {\n                    \"\"dklen\"\": 32,\n                    \"\"n\"\": 262144,\n                    \"\"p\"\": 1,\n                    \"\"r\"\": false,  // not a number\n                    \"\"salt\"\": \"\"3ada4bad7033fdaa65684ecf93dab3186e48d3f80965070d5fc9aac07811dc8f\"\",\n                }\n                \")\n            );\n\n            Assert.Throws<InvalidKeyJsonException>(() =>\n                Load(@\"\n                {\n                    \"\"dklen\"\": 32,\n                    \"\"n\"\": 262144,\n                    \"\"p\"\": 1,\n                    \"\"r\"\": null,  // not a number, but null\n                    \"\"salt\"\": \"\"3ada4bad7033fdaa65684ecf93dab3186e48d3f80965070d5fc9aac07811dc8f\"\",\n                }\n                \")\n            );\n\n            Assert.Throws<InvalidKeyJsonException>(() =>\n                Load(@\"\n                {\n                    \"\"dklen\"\": 32,\n                    \"\"n\"\": 262144,\n                    \"\"p\"\": 1,\n                    \"\"r\"\": 8,\n                    // \"\"salt\"\": \"\"...\"\",  // lacks\n                }\n                \")\n            );\n\n            Assert.Throws<InvalidKeyJsonException>(() =>\n                Load(@\"\n                {\n                    \"\"dklen\"\": 32,\n                    \"\"n\"\": 262144,\n                    \"\"p\"\": 1,\n                    \"\"r\"\": 8,\n                    \"\"salt\"\": null,\n                }\n                \")\n            );\n\n            Assert.Throws<InvalidKeyJsonException>(() =>\n                Load(@\"\n                {\n                    \"\"dklen\"\": 32,\n                    \"\"n\"\": 262144,\n                    \"\"p\"\": 1,\n                    \"\"r\"\": 8,\n                    \"\"salt\"\": 1234,  // not a string, but a number\n                }\n                \")\n            );\n\n            Assert.Throws<InvalidKeyJsonException>(() =>\n                Load(@\"\n                {\n                    \"\"dklen\"\": 32,\n                    \"\"n\"\": 262144,\n                    \"\"p\"\": 1,\n                    \"\"r\"\": 8,\n                    \"\"salt\"\": \"\"not a hexadecimal string\"\",\n                }\n                \")\n            );\n\n            Assert.Throws<InvalidKeyJsonException>(() =>\n                Load(@\"\n                {\n                    \"\"dklen\"\": 32,\n                    \"\"n\"\": 262144,\n                    \"\"p\"\": 1,\n                    \"\"r\"\": 8,\n                    \"\"salt\"\": \"\"3ada4bad7033fdaa65684ecf93dab3186e48d3f80965070d5fc9aac07811dc8\"\",\n                    // salt: invalid length\n                }\n                \")\n            );\n        }\n    }\n}\n"
  },
  {
    "path": "test/Libplanet.Tests/KeyStore/KeyStoreTest.cs",
    "content": "using System;\nusing System.Linq;\nusing Libplanet.Crypto;\nusing Libplanet.KeyStore;\nusing Xunit;\n\nnamespace Libplanet.Tests.KeyStore\n{\n    public abstract class KeyStoreTest<T>\n        where T : IKeyStore\n    {\n        public abstract T KeyStore { get; }\n\n        [Fact]\n        public void List()\n        {\n            Assert.Empty(KeyStore.List());\n            Assert.Empty(KeyStore.ListIds());\n\n            var key = new PrivateKey();\n            ProtectedPrivateKey ppk = ProtectedPrivateKey.Protect(key, \"pass\");\n            Guid id = KeyStore.Add(ppk);\n\n            Assert.Single(KeyStore.List());\n            Tuple<Guid, ProtectedPrivateKey> pair = KeyStore.List().First();\n            Assert.Equal(id, pair.Item1);\n            Assert.Equal(ppk.Address, pair.Item2.Address);\n            Assert.Equal(new[] { id }, KeyStore.ListIds());\n\n            var key2 = new PrivateKey();\n            ProtectedPrivateKey ppk2 = ProtectedPrivateKey.Protect(key2, \"pass\");\n            Guid id2 = KeyStore.Add(ppk2);\n\n            Assert.Equal(\n                new[] { (id, ppk.Address), (id2, ppk2.Address) }.ToHashSet(),\n                KeyStore.List().Select(tuple => (tuple.Item1, tuple.Item2.Address)).ToHashSet()\n            );\n            Assert.Equal(\n                new[] { id, id2 }.ToHashSet(),\n                KeyStore.ListIds().ToHashSet()\n            );\n        }\n\n        [Fact]\n        public void Get()\n        {\n            var key = new PrivateKey();\n            ProtectedPrivateKey ppk = ProtectedPrivateKey.Protect(key, \"pass\");\n            Guid id = KeyStore.Add(ppk);\n\n            Assert.Equal(ppk.Address, KeyStore.Get(id).Address);\n            Assert.Equal(key, KeyStore.Get(id).Unprotect(\"pass\"));\n            Assert.Throws<NoKeyException>(() => KeyStore.Get(Guid.NewGuid()));\n        }\n\n        [Fact]\n        public void Add()\n        {\n            var key = new PrivateKey();\n            ProtectedPrivateKey ppk = ProtectedPrivateKey.Protect(key, \"pass\");\n            Guid id = KeyStore.Add(ppk);\n            var key2 = new PrivateKey();\n            ProtectedPrivateKey ppk2 = ProtectedPrivateKey.Protect(key2, \"pass\");\n            Guid id2 = KeyStore.Add(ppk2);\n\n            // Key ids should be unique.\n            Assert.NotEqual(id, id2);\n\n            Assert.Equal(ppk.Address, KeyStore.Get(id).Address);\n            Assert.Equal(ppk2.Address, KeyStore.Get(id2).Address);\n\n            (Guid, Address Address) ToSimplePair(Tuple<Guid, ProtectedPrivateKey> pair) =>\n                (pair.Item1, pair.Item2.Address);\n\n            Assert.Contains((id, ppk.Address), KeyStore.List().Select(ToSimplePair));\n            Assert.Contains((id2, ppk2.Address), KeyStore.List().Select(ToSimplePair));\n        }\n\n        [Fact]\n        public void Remove()\n        {\n            var key = new PrivateKey();\n            Guid id = KeyStore.Add(ProtectedPrivateKey.Protect(key, \"pass\"));\n\n            Assert.Throws<NoKeyException>(() => KeyStore.Remove(Guid.NewGuid()));\n            Assert.Equal(new[] { id }, KeyStore.ListIds());\n\n            KeyStore.Remove(id);\n            Assert.Throws<NoKeyException>(() => KeyStore.Get(id));\n            Assert.Empty(KeyStore.ListIds());\n        }\n    }\n}\n"
  },
  {
    "path": "test/Libplanet.Tests/KeyStore/MismatchedAddressExceptionTest.cs",
    "content": "using Libplanet.Crypto;\nusing Libplanet.KeyStore;\nusing Xunit;\n\nnamespace Libplanet.Tests.KeyStore\n{\n    public class MismatchedAddressExceptionTest\n    {\n        [Fact]\n        public void Constructor()\n        {\n            Address\n                expectedAddress = default,\n                actualAddress = new Address(\"01234567789aBcdEF01234567789ABCdeF012345\");\n            var e = new MismatchedAddressException(\n                \"Some message.\",\n                expectedAddress,\n                actualAddress\n            );\n            Assert.Equal(\n                \"Some message.\\nExpected address: 0x0000000000000000000000000000000000000000\\n\" +\n                \"Actual address: 0x01234567789aBcdEF01234567789ABCdeF012345\",\n                e.Message\n            );\n            Assert.Equal(expectedAddress, e.ExpectedAddress);\n            Assert.Equal(actualAddress, e.ActualAddress);\n        }\n    }\n}\n"
  },
  {
    "path": "test/Libplanet.Tests/KeyStore/ProtectedPrivateKeyTest.cs",
    "content": "using System;\nusing System.Collections.Immutable;\nusing System.IO;\nusing System.Text;\nusing Libplanet.Crypto;\nusing Libplanet.KeyStore;\nusing Libplanet.KeyStore.Ciphers;\nusing Libplanet.KeyStore.Kdfs;\nusing Org.BouncyCastle.Crypto.Digests;\nusing Xunit;\nusing static Libplanet.Tests.TestUtils;\n\nnamespace Libplanet.Tests.KeyStore\n{\n    public class ProtectedPrivateKeyTest\n    {\n        public const string PassphraseFixture = \"asdf\";\n\n        public static readonly byte[] CiphertextFixture =\n        {\n            0x53, 0x5b, 0xab, 0x75, 0xc1, 0x12, 0xfe, 0x32, 0x7d, 0xc2, 0xe2,\n            0x93, 0xf8, 0x02, 0x97, 0xff, 0x33, 0x9e, 0x1e, 0x3c, 0xb7, 0x67,\n            0x49, 0x61, 0x53, 0x13, 0xcd, 0xc2, 0xaa, 0xa3, 0xb3, 0x7a,\n        };\n\n        public static readonly ImmutableArray<byte> IvFixture = new byte[]\n        {\n            0xbc, 0x7f, 0x2c, 0xa2, 0x3b, 0xfe, 0xe0, 0xdd,\n            0x97, 0x25, 0x22, 0x8a, 0xb2, 0xb0, 0xd9, 0x8a,\n        }.ToImmutableArray();\n\n        public static readonly byte[] SaltFixture =\n        {\n            0x3e, 0xea, 0xaf, 0x35, 0xda, 0x70, 0x92, 0x83, 0x87, 0xca, 0xe1,\n            0xea, 0xd3, 0x1e, 0xd7, 0x82, 0xb1, 0x13, 0x5d, 0x75, 0x78, 0xa8,\n            0x9d, 0x95, 0xe3, 0x0c, 0xc9, 0x14, 0x01, 0x0b, 0xa2, 0xed,\n        };\n\n        public static readonly byte[] MacFixture =\n        {\n            0xd8, 0x6a, 0xb9, 0xef, 0xf2, 0x3f, 0x28, 0x21, 0x0d, 0xc0, 0x10,\n            0x2a, 0x23, 0x64, 0x98, 0xe5, 0xc9, 0x68, 0x88, 0xbe, 0x6b, 0x5c,\n            0xd6, 0xf3, 0x09, 0x81, 0xaa, 0x89, 0x6b, 0xe8, 0x42, 0xd1,\n        };\n\n        public static readonly Address AddressFixture =\n            new Address(\"d80d933db45cc0cf69e9632090f8aaff635dc8e5\");\n\n        public static readonly IKdf KdfFixture = new Pbkdf2<Sha256Digest>(10240, SaltFixture, 32);\n\n        public static readonly ICipher CipherFixture = new Aes128Ctr(IvFixture);\n\n        public static readonly ProtectedPrivateKey Fixture = new ProtectedPrivateKey(\n            AddressFixture,\n            KdfFixture,\n            MacFixture,\n            CipherFixture,\n            CiphertextFixture\n        );\n\n        public static readonly byte[] CiphertextFixture2 =\n        {\n            0x78, 0x70, 0xdf, 0xf7, 0x1e, 0x17, 0x4a, 0xf3, 0xcd, 0xc3, 0xe9,\n            0xdd, 0x47, 0xec, 0xfd, 0x2d, 0xbe, 0xca, 0x66, 0x5c, 0xd1, 0x33,\n            0xfb, 0x0f, 0x87, 0xdd, 0x93, 0x59, 0xf3, 0x27, 0x9e, 0x0b,\n        };\n\n        public static readonly ImmutableArray<byte> IvFixture2 = new byte[]\n        {\n            0x85, 0x4e, 0x9d, 0x92, 0x31, 0x6a, 0x08, 0x02,\n            0xab, 0x5a, 0x9c, 0x09, 0x58, 0x78, 0x61, 0x94,\n        }.ToImmutableArray();\n\n        public static readonly ICipher CipherFixture2 = new Aes128Ctr(IvFixture2);\n\n        public static readonly Address AddressFixture2 =\n            new Address(\"89c2b1031ade56524ecb2fe73bf45f18e6d2f06d\");\n\n        public static readonly byte[] SaltFixture2 =\n        {\n            0x75, 0xde, 0x08, 0x2f, 0x96, 0xf1, 0xc7, 0x80, 0xe4, 0x60, 0xb8,\n            0x40, 0x01, 0x66, 0xd4, 0x11, 0x48, 0x2b, 0xff, 0x40, 0x24, 0x44,\n            0xb8, 0x69, 0x12, 0x5e, 0x75, 0x59, 0x31, 0x5e, 0xa8, 0x92,\n        };\n\n        public static readonly IKdf KdfFixture2 = new Scrypt(\n            262144, SaltFixture2, 32, 1, 8\n        );\n\n        public static readonly byte[] MacFixture2 =\n        {\n            0xc3, 0xf7, 0xe2, 0xbe, 0x00, 0xe7, 0xf6, 0xc3, 0x37, 0x71, 0x21,\n            0xbc, 0x7f, 0xe2, 0x96, 0x7c, 0x22, 0xd6, 0x27, 0xc3, 0x28, 0x9b,\n            0xe1, 0xb8, 0xac, 0xe3, 0xa6, 0xb3, 0xc4, 0xa5, 0x4d, 0xad,\n        };\n\n        public static readonly ProtectedPrivateKey Fixture2 = new ProtectedPrivateKey(\n            AddressFixture2,\n            KdfFixture2,\n            MacFixture2,\n            CipherFixture2,\n            CiphertextFixture2\n        );\n\n        [Fact]\n        public void Unprotect()\n        {\n            Assert.Equal(AddressFixture, Fixture.Address);\n            Assert.Equal(AddressFixture, Fixture.Unprotect(PassphraseFixture).Address);\n            Assert.Equal(AddressFixture2, Fixture2.Unprotect(PassphraseFixture).Address);\n            var incorrectPassphraseException = Assert.Throws<IncorrectPassphraseException>(\n                () => Fixture.Unprotect(\"wrong passphrase\")\n            );\n            TestUtils.AssertBytesEqual(\n                MacFixture.ToImmutableArray(),\n                incorrectPassphraseException.ExpectedMac\n            );\n            Assert.NotEqual(MacFixture, incorrectPassphraseException.InputMac);\n\n            var invalidPpk = new ProtectedPrivateKey(\n                default,\n                KdfFixture,\n                MacFixture,\n                CipherFixture,\n                CiphertextFixture\n            );\n            var mismatchedAddressException = Assert.Throws<MismatchedAddressException>(\n                () => invalidPpk.Unprotect(PassphraseFixture)\n            );\n            Assert.Equal(default(Address), mismatchedAddressException.ExpectedAddress);\n            Assert.Equal(AddressFixture, mismatchedAddressException.ActualAddress);\n        }\n\n        [Theory]\n        [InlineData(\"foobar\")]\n        [InlineData(\"unicode-暗號\")]\n        public void Protect(string passphrase)\n        {\n            PrivateKey privKey = new PrivateKey();\n            ProtectedPrivateKey protectedKey = ProtectedPrivateKey.Protect(privKey, passphrase);\n            AssertBytesEqual(\n                privKey.ByteArray,\n                protectedKey.Unprotect(passphrase).ByteArray\n            );\n            Assert.Throws<IncorrectPassphraseException>(() => protectedKey.Unprotect(\"WRONG\"));\n        }\n\n        [Fact]\n        public void FromJson()\n        {\n            ProtectedPrivateKey key = ProtectedPrivateKey.FromJson(@\"{\n                \"\"address\"\": \"\"d80d933db45cc0cf69e9632090f8aaff635dc8e5\"\",\n                \"\"crypto\"\": {\n                    \"\"cipher\"\": \"\"aes-128-ctr\"\",\n                    \"\"cipherparams\"\": {\n                        \"\"iv\"\": \"\"bc7f2ca23bfee0dd9725228ab2b0d98a\"\",\n                    },\n                    \"\"ciphertext\"\":\n                        \"\"535bab75c112fe327dc2e293f80297ff339e1e3cb76749615313cdc2aaa3b37a\"\",\n                    \"\"kdf\"\": \"\"pbkdf2\"\",\n                    \"\"kdfparams\"\": {\n                        \"\"c\"\": 10240,\n                        \"\"dklen\"\": 32,\n                        \"\"prf\"\": \"\"hmac-sha256\"\",\n                        \"\"salt\"\":\n                            \"\"3eeaaf35da70928387cae1ead31ed782b1135d7578a89d95e30cc914010ba2ed\"\",\n                    },\n                    \"\"mac\"\": \"\"d86ab9eff23f28210dc0102a236498e5c96888be6b5cd6f30981aa896be842d1\"\",\n                },\n                \"\"id\"\": \"\"3b647634-1234-cd02-e93c-02e1c0f54faa\"\",\n                \"\"version\"\": 3,\n            }\");\n\n            Assert.Equal(\n                new Address(\"d80d933db45cc0cf69e9632090f8aaff635dc8e5\"),\n                key.Address\n            );\n            Assert.IsType<Aes128Ctr>(key.Cipher);\n            AssertBytesEqual(\n                new byte[]\n                {\n                    0x53, 0x5b, 0xab, 0x75, 0xc1, 0x12, 0xfe, 0x32, 0x7d, 0xc2, 0xe2,\n                    0x93, 0xf8, 0x02, 0x97, 0xff, 0x33, 0x9e, 0x1e, 0x3c, 0xb7, 0x67,\n                    0x49, 0x61, 0x53, 0x13, 0xcd, 0xc2, 0xaa, 0xa3, 0xb3, 0x7a,\n                }.ToImmutableArray(),\n                key.Ciphertext\n            );\n            Assert.IsType<Pbkdf2<Sha256Digest>>(key.Kdf);\n            AssertBytesEqual(\n                new byte[]\n                {\n                    0xd8, 0x6a, 0xb9, 0xef, 0xf2, 0x3f, 0x28, 0x21, 0x0d, 0xc0, 0x10,\n                    0x2a, 0x23, 0x64, 0x98, 0xe5, 0xc9, 0x68, 0x88, 0xbe, 0x6b, 0x5c,\n                    0xd6, 0xf3, 0x09, 0x81, 0xaa, 0x89, 0x6b, 0xe8, 0x42, 0xd1,\n                }.ToImmutableArray(),\n                key.Mac\n            );\n\n            ProtectedPrivateKey key2 = ProtectedPrivateKey.FromJson(@\"{\n                \"\"address\"\": \"\"8e5f4b9b8f84ff90c559c6a4deb3c1febe551f29\"\",\n                \"\"crypto\"\": {\n                    \"\"cipher\"\": \"\"aes-128-ctr\"\",\n                    \"\"cipherparams\"\": {\n                        \"\"iv\"\": \"\"cc730222e304f4c230854c63f105ff5b\"\"\n                    },\n                    \"\"ciphertext\"\":\n                        \"\"45a5b80fd3ea8f4f0db824b9b56b42be2c1e3759e77c0197cfa3a136f18d5957\"\",\n                    \"\"kdf\"\": \"\"scrypt\"\",\n                    \"\"kdfparams\"\": {\n                        \"\"dklen\"\": 32,\n                        \"\"n\"\": 262144,\n                        \"\"p\"\": 1,\n                        \"\"r\"\": 8,\n                        \"\"salt\"\":\n                            \"\"3ada4bad7033fdaa65684ecf93dab3186e48d3f80965070d5fc9aac07811dc8f\"\"\n                    },\n                    \"\"mac\"\": \"\"445c0bbc6c310d1fcabf7d7456fd3c558e504c4d308ddb83eddb0b2b8f66f834\"\"\n                },\n                \"\"id\"\": \"\"29ee8172-710d-44b3-9fe9-f401f7b35ad5\"\",\n                \"\"version\"\": 3,\n            }\");\n            Assert.Equal(\n                new Address(\"8e5f4b9b8f84ff90c559c6a4deb3c1febe551f29\"),\n                key2.Address\n            );\n            Assert.IsType<Aes128Ctr>(key2.Cipher);\n            AssertBytesEqual(\n                new byte[]\n                {\n                    0x45, 0xa5, 0xb8, 0x0f, 0xd3, 0xea, 0x8f, 0x4f, 0x0d, 0xb8, 0x24,\n                    0xb9, 0xb5, 0x6b, 0x42, 0xbe, 0x2c, 0x1e, 0x37, 0x59, 0xe7, 0x7c,\n                    0x01, 0x97, 0xcf, 0xa3, 0xa1, 0x36, 0xf1, 0x8d, 0x59, 0x57,\n                }.ToImmutableArray(),\n                key2.Ciphertext\n            );\n            Assert.IsType<Scrypt>(key2.Kdf);\n            AssertBytesEqual(\n                new byte[]\n                {\n                    0x44, 0x5c, 0x0b, 0xbc, 0x6c, 0x31, 0x0d, 0x1f, 0xca, 0xbf, 0x7d,\n                    0x74, 0x56, 0xfd, 0x3c, 0x55, 0x8e, 0x50, 0x4c, 0x4d, 0x30, 0x8d,\n                    0xdb, 0x83, 0xed, 0xdb, 0x0b, 0x2b, 0x8f, 0x66, 0xf8, 0x34,\n                }.ToImmutableArray(),\n                key2.Mac\n            );\n        }\n\n        #pragma warning disable MEN003\n        [Fact]\n        public void FromJsonInvalidCases()\n        {\n            Func<string, ProtectedPrivateKey> load = ProtectedPrivateKey.FromJson;\n\n            Assert.Throws<InvalidKeyJsonException>(() =>\n                load(\"[]  // Not an object\")\n            );\n\n            Assert.Throws<InvalidKeyJsonException>(() =>\n                load(@\"{\n                    \"\"address\"\": \"\"d80d933db45cc0cf69e9632090f8aaff635dc8e5\"\",\n                    \"\"id\"\": \"\"3b647634-1234-cd02-e93c-02e1c0f54faa\"\",\n                    // \"\"version\"\": 3,  // Lacks\n                }\")\n            );\n\n            Assert.Throws<InvalidKeyJsonException>(() =>\n                load(@\"{\n                    \"\"address\"\": \"\"d80d933db45cc0cf69e9632090f8aaff635dc8e5\"\",\n                    \"\"id\"\": \"\"3b647634-1234-cd02-e93c-02e1c0f54faa\"\",\n                    \"\"version\"\": true,  // Not a number\n                }\")\n            );\n\n            Assert.Throws<UnsupportedKeyJsonException>(() =>\n                load(@\"{\n                    \"\"address\"\": \"\"d80d933db45cc0cf69e9632090f8aaff635dc8e5\"\",\n                    \"\"id\"\": \"\"3b647634-1234-cd02-e93c-02e1c0f54faa\"\",\n                    \"\"version\"\": 2,  // Unsupported version\n                }\")\n            );\n\n            Assert.Throws<InvalidKeyJsonException>(() =>\n                load(@\"{\n                    \"\"address\"\": \"\"d80d933db45cc0cf69e9632090f8aaff635dc8e5\"\",\n                    // \"\"crypto\"\": {},  // Lacks\n                    \"\"id\"\": \"\"3b647634-1234-cd02-e93c-02e1c0f54faa\"\",\n                    \"\"version\"\": 3,\n                }\")\n            );\n\n            Assert.Throws<InvalidKeyJsonException>(() =>\n                load(@\"{\n                    \"\"address\"\": \"\"d80d933db45cc0cf69e9632090f8aaff635dc8e5\"\",\n                    \"\"crypto\"\": null,  // Not an object\n                    \"\"id\"\": \"\"3b647634-1234-cd02-e93c-02e1c0f54faa\"\",\n                    \"\"version\"\": 3,\n                }\")\n            );\n\n            Assert.Throws<InvalidKeyJsonException>(() =>\n                load(@\"{\n                    // \"\"address\"\": \"\"d80d933db45cc0cf69e9632090f8aaff635dc8e5\"\",  // Lacks\n                    \"\"crypto\"\": {\n                        \"\"cipher\"\": \"\"aes-128-ctr\"\",\n                        \"\"cipherparams\"\": {\n                            \"\"iv\"\": \"\"bc7f2ca23bfee0dd9725228ab2b0d98a\"\",\n                        },\n                        \"\"ciphertext\"\":\n                            \"\"535bab75c112fe327dc2e293f80297ff339e1e3cb76749615313cdc2aaa3b37a\"\",\n                        \"\"kdf\"\": \"\"pbkdf2\"\",\n                        \"\"kdfparams\"\": {\n                            \"\"c\"\": 10240,\n                            \"\"dklen\"\": 32,\n                            \"\"prf\"\": \"\"hmac-sha256\"\",\n                            \"\"salt\"\":\n                                \"\"3eeaaf35da70928387cae1ead31ed782b1135d7578a89d95e30cc914010ba2ed\"\"\n                        },\n                        \"\"mac\"\":\n                            \"\"d86ab9eff23f28210dc0102a236498e5c96888be6b5cd6f30981aa896be842d1\"\",\n                    },\n                    \"\"id\"\": \"\"3b647634-1234-cd02-e93c-02e1c0f54faa\"\",\n                    \"\"version\"\": 3,\n                }\")\n            );\n\n            Assert.Throws<InvalidKeyJsonException>(() =>\n                load(@\"{\n                    \"\"address\"\": 123,  // Not a string\n                    \"\"crypto\"\": {\n                        \"\"cipher\"\": \"\"aes-128-ctr\"\",\n                        \"\"cipherparams\"\": {\n                            \"\"iv\"\": \"\"bc7f2ca23bfee0dd9725228ab2b0d98a\"\",\n                        },\n                        \"\"ciphertext\"\":\n                            \"\"535bab75c112fe327dc2e293f80297ff339e1e3cb76749615313cdc2aaa3b37a\"\",\n                        \"\"kdf\"\": \"\"pbkdf2\"\",\n                        \"\"kdfparams\"\": {\n                            \"\"c\"\": 10240,\n                            \"\"dklen\"\": 32,\n                            \"\"prf\"\": \"\"hmac-sha256\"\",\n                            \"\"salt\"\":\n                                \"\"3eeaaf35da70928387cae1ead31ed782b1135d7578a89d95e30cc914010ba2ed\"\"\n                        },\n                        \"\"mac\"\":\n                            \"\"d86ab9eff23f28210dc0102a236498e5c96888be6b5cd6f30981aa896be842d1\"\",\n                    },\n                    \"\"id\"\": \"\"3b647634-1234-cd02-e93c-02e1c0f54faa\"\",\n                    \"\"version\"\": 3,\n                }\")\n            );\n\n            Assert.Throws<InvalidKeyJsonException>(() =>\n                load(@\"{\n                    \"\"address\"\": null,  // Not a string, but null\n                    \"\"crypto\"\": {\n                        \"\"cipher\"\": \"\"aes-128-ctr\"\",\n                        \"\"cipherparams\"\": {\n                            \"\"iv\"\": \"\"bc7f2ca23bfee0dd9725228ab2b0d98a\"\",\n                        },\n                        \"\"ciphertext\"\":\n                            \"\"535bab75c112fe327dc2e293f80297ff339e1e3cb76749615313cdc2aaa3b37a\"\",\n                        \"\"kdf\"\": \"\"pbkdf2\"\",\n                        \"\"kdfparams\"\": {\n                            \"\"c\"\": 10240,\n                            \"\"dklen\"\": 32,\n                            \"\"prf\"\": \"\"hmac-sha256\"\",\n                            \"\"salt\"\":\n                                \"\"3eeaaf35da70928387cae1ead31ed782b1135d7578a89d95e30cc914010ba2ed\"\"\n                        },\n                        \"\"mac\"\":\n                            \"\"d86ab9eff23f28210dc0102a236498e5c96888be6b5cd6f30981aa896be842d1\"\",\n                    },\n                    \"\"id\"\": \"\"3b647634-1234-cd02-e93c-02e1c0f54faa\"\",\n                    \"\"version\"\": 3,\n                }\")\n            );\n\n            Assert.Throws<InvalidKeyJsonException>(() =>\n                load(@\"{\n                    \"\"address\"\": \"\"Not a hexadecimal string\"\",\n                    \"\"crypto\"\": {\n                        \"\"cipher\"\": \"\"aes-128-ctr\"\",\n                        \"\"cipherparams\"\": {\n                            \"\"iv\"\": \"\"bc7f2ca23bfee0dd9725228ab2b0d98a\"\",\n                        },\n                        \"\"ciphertext\"\":\n                            \"\"535bab75c112fe327dc2e293f80297ff339e1e3cb76749615313cdc2aaa3b37a\"\",\n                        \"\"kdf\"\": \"\"pbkdf2\"\",\n                        \"\"kdfparams\"\": {\n                            \"\"c\"\": 10240,\n                            \"\"dklen\"\": 32,\n                            \"\"prf\"\": \"\"hmac-sha256\"\",\n                            \"\"salt\"\":\n                                \"\"3eeaaf35da70928387cae1ead31ed782b1135d7578a89d95e30cc914010ba2ed\"\"\n                        },\n                        \"\"mac\"\":\n                            \"\"d86ab9eff23f28210dc0102a236498e5c96888be6b5cd6f30981aa896be842d1\"\",\n                    },\n                    \"\"id\"\": \"\"3b647634-1234-cd02-e93c-02e1c0f54faa\"\",\n                    \"\"version\"\": 3,\n                }\")\n            );\n\n            Assert.Throws<InvalidKeyJsonException>(() =>\n                load(@\"{\n                    \"\"address\"\": \"\"d80d933db45cc0cf69e9632090f8aaff635dc8e500\"\",  // Invalid length\n                    \"\"crypto\"\": {\n                        \"\"cipher\"\": \"\"aes-128-ctr\"\",\n                        \"\"cipherparams\"\": {\n                            \"\"iv\"\": \"\"bc7f2ca23bfee0dd9725228ab2b0d98a\"\",\n                        },\n                        \"\"ciphertext\"\":\n                            \"\"535bab75c112fe327dc2e293f80297ff339e1e3cb76749615313cdc2aaa3b37a\"\",\n                        \"\"kdf\"\": \"\"pbkdf2\"\",\n                        \"\"kdfparams\"\": {\n                            \"\"c\"\": 10240,\n                            \"\"dklen\"\": 32,\n                            \"\"prf\"\": \"\"hmac-sha256\"\",\n                            \"\"salt\"\":\n                                \"\"3eeaaf35da70928387cae1ead31ed782b1135d7578a89d95e30cc914010ba2ed\"\"\n                        },\n                        \"\"mac\"\":\n                            \"\"d86ab9eff23f28210dc0102a236498e5c96888be6b5cd6f30981aa896be842d1\"\",\n                    },\n                    \"\"id\"\": \"\"3b647634-1234-cd02-e93c-02e1c0f54faa\"\",\n                    \"\"version\"\": 3,\n                }\")\n            );\n\n            Assert.Throws<InvalidKeyJsonException>(() =>\n                load(@\"{\n                    \"\"address\"\": \"\"d80d933db45cc0cf69e9632090f8aaff635dc8e5\"\",\n                    \"\"crypto\"\": {\n                        // \"\"cipher\"\": \"\"aes-128-ctr\"\",  // Lacks\n                        \"\"cipherparams\"\": {\n                            \"\"iv\"\": \"\"bc7f2ca23bfee0dd9725228ab2b0d98a\"\",\n                        },\n                        \"\"ciphertext\"\":\n                            \"\"535bab75c112fe327dc2e293f80297ff339e1e3cb76749615313cdc2aaa3b37a\"\",\n                        \"\"kdf\"\": \"\"pbkdf2\"\",\n                        \"\"kdfparams\"\": {\n                            \"\"c\"\": 10240,\n                            \"\"dklen\"\": 32,\n                            \"\"prf\"\": \"\"hmac-sha256\"\",\n                            \"\"salt\"\":\n                                \"\"3eeaaf35da70928387cae1ead31ed782b1135d7578a89d95e30cc914010ba2ed\"\"\n                        },\n                        \"\"mac\"\":\n                            \"\"d86ab9eff23f28210dc0102a236498e5c96888be6b5cd6f30981aa896be842d1\"\",\n                    },\n                    \"\"id\"\": \"\"3b647634-1234-cd02-e93c-02e1c0f54faa\"\",\n                    \"\"version\"\": 3,\n                }\")\n            );\n\n            Assert.Throws<InvalidKeyJsonException>(() =>\n                load(@\"{\n                    \"\"address\"\": \"\"d80d933db45cc0cf69e9632090f8aaff635dc8e5\"\",\n                    \"\"crypto\"\": {\n                        \"\"cipher\"\": null,  // Not a string, but null\n                        \"\"cipherparams\"\": {\n                            \"\"iv\"\": \"\"bc7f2ca23bfee0dd9725228ab2b0d98a\"\",\n                        },\n                        \"\"ciphertext\"\":\n                            \"\"535bab75c112fe327dc2e293f80297ff339e1e3cb76749615313cdc2aaa3b37a\"\",\n                        \"\"kdf\"\": \"\"pbkdf2\"\",\n                        \"\"kdfparams\"\": {\n                            \"\"c\"\": 10240,\n                            \"\"dklen\"\": 32,\n                            \"\"prf\"\": \"\"hmac-sha256\"\",\n                            \"\"salt\"\":\n                                \"\"3eeaaf35da70928387cae1ead31ed782b1135d7578a89d95e30cc914010ba2ed\"\"\n                        },\n                        \"\"mac\"\":\n                            \"\"d86ab9eff23f28210dc0102a236498e5c96888be6b5cd6f30981aa896be842d1\"\",\n                    },\n                    \"\"id\"\": \"\"3b647634-1234-cd02-e93c-02e1c0f54faa\"\",\n                    \"\"version\"\": 3,\n                }\")\n            );\n\n            Assert.Throws<UnsupportedKeyJsonException>(() =>\n                load(@\"{\n                    \"\"address\"\": \"\"d80d933db45cc0cf69e9632090f8aaff635dc8e5\"\",\n                    \"\"crypto\"\": {\n                        \"\"cipher\"\": \"\"aes-256-ctr\"\",  // Unsupported\n                        \"\"cipherparams\"\": {\n                            \"\"iv\"\": \"\"bc7f2ca23bfee0dd9725228ab2b0d98a\"\",\n                        },\n                        \"\"ciphertext\"\":\n                            \"\"535bab75c112fe327dc2e293f80297ff339e1e3cb76749615313cdc2aaa3b37a\"\",\n                        \"\"kdf\"\": \"\"pbkdf2\"\",\n                        \"\"kdfparams\"\": {\n                            \"\"c\"\": 10240,\n                            \"\"dklen\"\": 32,\n                            \"\"prf\"\": \"\"hmac-sha256\"\",\n                            \"\"salt\"\":\n                                \"\"3eeaaf35da70928387cae1ead31ed782b1135d7578a89d95e30cc914010ba2ed\"\"\n                        },\n                        \"\"mac\"\":\n                            \"\"d86ab9eff23f28210dc0102a236498e5c96888be6b5cd6f30981aa896be842d1\"\",\n                    },\n                    \"\"id\"\": \"\"3b647634-1234-cd02-e93c-02e1c0f54faa\"\",\n                    \"\"version\"\": 3,\n                }\")\n            );\n\n            Assert.Throws<InvalidKeyJsonException>(() =>\n                load(@\"{\n                    \"\"address\"\": \"\"d80d933db45cc0cf69e9632090f8aaff635dc8e5\"\",\n                    \"\"crypto\"\": {\n                        \"\"cipher\"\": \"\"aes-128-ctr\"\",\n                        // \"\"cipherparams\"\": {},  // Lacks\n                        \"\"ciphertext\"\":\n                            \"\"535bab75c112fe327dc2e293f80297ff339e1e3cb76749615313cdc2aaa3b37a\"\",\n                        \"\"kdf\"\": \"\"pbkdf2\"\",\n                        \"\"kdfparams\"\": {\n                            \"\"c\"\": 10240,\n                            \"\"dklen\"\": 32,\n                            \"\"prf\"\": \"\"hmac-sha256\"\",\n                            \"\"salt\"\":\n                                \"\"3eeaaf35da70928387cae1ead31ed782b1135d7578a89d95e30cc914010ba2ed\"\"\n                        },\n                        \"\"mac\"\":\n                            \"\"d86ab9eff23f28210dc0102a236498e5c96888be6b5cd6f30981aa896be842d1\"\",\n                    },\n                    \"\"id\"\": \"\"3b647634-1234-cd02-e93c-02e1c0f54faa\"\",\n                    \"\"version\"\": 3,\n                }\")\n            );\n\n            Assert.Throws<InvalidKeyJsonException>(() =>\n                load(@\"{\n                    \"\"address\"\": \"\"d80d933db45cc0cf69e9632090f8aaff635dc8e5\"\",\n                    \"\"crypto\"\": {\n                        \"\"cipher\"\": \"\"aes-128-ctr\"\",\n                        \"\"cipherparams\"\": \"\"Not an object, but a string\"\",\n                        \"\"ciphertext\"\":\n                            \"\"535bab75c112fe327dc2e293f80297ff339e1e3cb76749615313cdc2aaa3b37a\"\",\n                        \"\"kdf\"\": \"\"pbkdf2\"\",\n                        \"\"kdfparams\"\": {\n                            \"\"c\"\": 10240,\n                            \"\"dklen\"\": 32,\n                            \"\"prf\"\": \"\"hmac-sha256\"\",\n                            \"\"salt\"\":\n                                \"\"3eeaaf35da70928387cae1ead31ed782b1135d7578a89d95e30cc914010ba2ed\"\"\n                        },\n                        \"\"mac\"\":\n                            \"\"d86ab9eff23f28210dc0102a236498e5c96888be6b5cd6f30981aa896be842d1\"\",\n                    },\n                    \"\"id\"\": \"\"3b647634-1234-cd02-e93c-02e1c0f54faa\"\",\n                    \"\"version\"\": 3,\n                }\")\n            );\n\n            Assert.Throws<InvalidKeyJsonException>(() =>\n                load(@\"{\n                    \"\"address\"\": \"\"d80d933db45cc0cf69e9632090f8aaff635dc8e5\"\",\n                    \"\"crypto\"\": {\n                        \"\"cipher\"\": \"\"aes-128-ctr\"\",\n                        \"\"cipherparams\"\": {\n                            \"\"iv\"\": \"\"bc7f2ca23bfee0dd9725228ab2b0d98a\"\",\n                        },\n                        // \"\"ciphertext\"\": \"\"...\"\",  // Lacks\n                        \"\"kdf\"\": \"\"pbkdf2\"\",\n                        \"\"kdfparams\"\": {\n                            \"\"c\"\": 10240,\n                            \"\"dklen\"\": 32,\n                            \"\"prf\"\": \"\"hmac-sha256\"\",\n                            \"\"salt\"\":\n                                \"\"3eeaaf35da70928387cae1ead31ed782b1135d7578a89d95e30cc914010ba2ed\"\"\n                        },\n                        \"\"mac\"\":\n                            \"\"d86ab9eff23f28210dc0102a236498e5c96888be6b5cd6f30981aa896be842d1\"\",\n                    },\n                    \"\"id\"\": \"\"3b647634-1234-cd02-e93c-02e1c0f54faa\"\",\n                    \"\"version\"\": 3,\n                }\")\n            );\n\n            Assert.Throws<InvalidKeyJsonException>(() =>\n                load(@\"{\n                    \"\"address\"\": \"\"d80d933db45cc0cf69e9632090f8aaff635dc8e5\"\",\n                    \"\"crypto\"\": {\n                        \"\"cipher\"\": \"\"aes-128-ctr\"\",\n                        \"\"cipherparams\"\": {\n                            \"\"iv\"\": \"\"bc7f2ca23bfee0dd9725228ab2b0d98a\"\",\n                        },\n                        \"\"ciphertext\"\":\n                            \"\"535bab75c112fe327dc2e293f80297ff339e1e3cb76749615313cdc2aaa3b37a\"\",\n                        // \"\"kdf\"\": \"\"pbkdf2\"\",  // Lacks\n                        \"\"kdfparams\"\": {\n                            \"\"c\"\": 10240,\n                            \"\"dklen\"\": 32,\n                            \"\"prf\"\": \"\"hmac-sha256\"\",\n                            \"\"salt\"\":\n                                \"\"3eeaaf35da70928387cae1ead31ed782b1135d7578a89d95e30cc914010ba2ed\"\"\n                        },\n                        \"\"mac\"\":\n                            \"\"d86ab9eff23f28210dc0102a236498e5c96888be6b5cd6f30981aa896be842d1\"\",\n                    },\n                    \"\"id\"\": \"\"3b647634-1234-cd02-e93c-02e1c0f54faa\"\",\n                    \"\"version\"\": 3,\n                }\")\n            );\n\n            Assert.Throws<InvalidKeyJsonException>(() =>\n                load(@\"{\n                    \"\"address\"\": \"\"d80d933db45cc0cf69e9632090f8aaff635dc8e5\"\",\n                    \"\"crypto\"\": {\n                        \"\"cipher\"\": \"\"aes-128-ctr\"\",\n                        \"\"cipherparams\"\": {\n                            \"\"iv\"\": \"\"bc7f2ca23bfee0dd9725228ab2b0d98a\"\",\n                        },\n                        \"\"ciphertext\"\":\n                            \"\"535bab75c112fe327dc2e293f80297ff339e1e3cb76749615313cdc2aaa3b37a\"\",\n                        \"\"kdf\"\": 123,  // Not a string, but a number\n                        \"\"kdfparams\"\": {\n                            \"\"c\"\": 10240,\n                            \"\"dklen\"\": 32,\n                            \"\"prf\"\": \"\"hmac-sha256\"\",\n                            \"\"salt\"\":\n                                \"\"3eeaaf35da70928387cae1ead31ed782b1135d7578a89d95e30cc914010ba2ed\"\"\n                        },\n                        \"\"mac\"\":\n                            \"\"d86ab9eff23f28210dc0102a236498e5c96888be6b5cd6f30981aa896be842d1\"\",\n                    },\n                    \"\"id\"\": \"\"3b647634-1234-cd02-e93c-02e1c0f54faa\"\",\n                    \"\"version\"\": 3,\n                }\")\n            );\n\n            Assert.Throws<UnsupportedKeyJsonException>(() =>\n                load(@\"{\n                    \"\"address\"\": \"\"d80d933db45cc0cf69e9632090f8aaff635dc8e5\"\",\n                    \"\"crypto\"\": {\n                        \"\"cipher\"\": \"\"aes-128-ctr\"\",\n                        \"\"cipherparams\"\": {\n                            \"\"iv\"\": \"\"bc7f2ca23bfee0dd9725228ab2b0d98a\"\",\n                        },\n                        \"\"ciphertext\"\":\n                            \"\"535bab75c112fe327dc2e293f80297ff339e1e3cb76749615313cdc2aaa3b37a\"\",\n                        \"\"kdf\"\": \"\"unsupported-kdf\"\",  // Unsupported KDF\n                        \"\"kdfparams\"\": {\n                            \"\"c\"\": 10240,\n                            \"\"dklen\"\": 32,\n                            \"\"prf\"\": \"\"hmac-sha256\"\",\n                            \"\"salt\"\":\n                                \"\"3eeaaf35da70928387cae1ead31ed782b1135d7578a89d95e30cc914010ba2ed\"\"\n                        },\n                        \"\"mac\"\":\n                            \"\"d86ab9eff23f28210dc0102a236498e5c96888be6b5cd6f30981aa896be842d1\"\",\n                    },\n                    \"\"id\"\": \"\"3b647634-1234-cd02-e93c-02e1c0f54faa\"\",\n                    \"\"version\"\": 3,\n                }\")\n            );\n\n            Assert.Throws<InvalidKeyJsonException>(() =>\n                load(@\"{\n                    \"\"address\"\": \"\"d80d933db45cc0cf69e9632090f8aaff635dc8e5\"\",\n                    \"\"crypto\"\": {\n                        \"\"cipher\"\": \"\"aes-128-ctr\"\",\n                        \"\"cipherparams\"\": {\n                            \"\"iv\"\": \"\"bc7f2ca23bfee0dd9725228ab2b0d98a\"\",\n                        },\n                        \"\"ciphertext\"\":\n                            \"\"535bab75c112fe327dc2e293f80297ff339e1e3cb76749615313cdc2aaa3b37a\"\",\n                        \"\"kdf\"\": \"\"pbkdf2\"\",\n                        // \"\"kdfparams\"\": {},  // Lacks\n                        \"\"mac\"\":\n                            \"\"d86ab9eff23f28210dc0102a236498e5c96888be6b5cd6f30981aa896be842d1\"\",\n                    },\n                    \"\"id\"\": \"\"3b647634-1234-cd02-e93c-02e1c0f54faa\"\",\n                    \"\"version\"\": 3,\n                }\")\n            );\n\n            Assert.Throws<InvalidKeyJsonException>(() =>\n                load(@\"{\n                    \"\"address\"\": \"\"d80d933db45cc0cf69e9632090f8aaff635dc8e5\"\",\n                    \"\"crypto\"\": {\n                        \"\"cipher\"\": \"\"aes-128-ctr\"\",\n                        \"\"cipherparams\"\": {\n                            \"\"iv\"\": \"\"bc7f2ca23bfee0dd9725228ab2b0d98a\"\",\n                        },\n                        \"\"ciphertext\"\":\n                            \"\"535bab75c112fe327dc2e293f80297ff339e1e3cb76749615313cdc2aaa3b37a\"\",\n                        \"\"kdf\"\": \"\"pbkdf2\"\",\n                        \"\"kdfparams\"\": \"\"Not an object, but a string\"\",\n                        \"\"mac\"\":\n                            \"\"d86ab9eff23f28210dc0102a236498e5c96888be6b5cd6f30981aa896be842d1\"\",\n                    },\n                    \"\"id\"\": \"\"3b647634-1234-cd02-e93c-02e1c0f54faa\"\",\n                    \"\"version\"\": 3,\n                }\")\n            );\n\n            Assert.Throws<InvalidKeyJsonException>(() =>\n                load(@\"{\n                    \"\"address\"\": \"\"d80d933db45cc0cf69e9632090f8aaff635dc8e5\"\",\n                    \"\"crypto\"\": {\n                        \"\"cipher\"\": \"\"aes-128-ctr\"\",\n                        \"\"cipherparams\"\": {\n                            \"\"iv\"\": \"\"bc7f2ca23bfee0dd9725228ab2b0d98a\"\",\n                        },\n                        \"\"ciphertext\"\":\n                            \"\"535bab75c112fe327dc2e293f80297ff339e1e3cb76749615313cdc2aaa3b37a\"\",\n                        \"\"kdf\"\": \"\"pbkdf2\"\",\n                        \"\"kdfparams\"\": {\n                            \"\"c\"\": 10240,\n                            \"\"dklen\"\": 32,\n                            \"\"prf\"\": \"\"hmac-sha256\"\",\n                            \"\"salt\"\":\n                                \"\"3eeaaf35da70928387cae1ead31ed782b1135d7578a89d95e30cc914010ba2ed\"\"\n                        },\n                        // \"\"mac\"\": \"\"...\"\",  // Lacks\n                    },\n                    \"\"id\"\": \"\"3b647634-1234-cd02-e93c-02e1c0f54faa\"\",\n                    \"\"version\"\": 3,\n                }\")\n            );\n\n            Assert.Throws<InvalidKeyJsonException>(() =>\n                load(@\"{\n                    \"\"address\"\": \"\"d80d933db45cc0cf69e9632090f8aaff635dc8e5\"\",\n                    \"\"crypto\"\": {\n                        \"\"cipher\"\": \"\"aes-128-ctr\"\",\n                        \"\"cipherparams\"\": {\n                            \"\"iv\"\": \"\"bc7f2ca23bfee0dd9725228ab2b0d98a\"\",\n                        },\n                        \"\"ciphertext\"\":\n                            \"\"535bab75c112fe327dc2e293f80297ff339e1e3cb76749615313cdc2aaa3b37a\"\",\n                        \"\"kdf\"\": \"\"pbkdf2\"\",\n                        \"\"kdfparams\"\": {\n                            \"\"c\"\": 10240,\n                            \"\"dklen\"\": 32,\n                            \"\"prf\"\": \"\"hmac-sha256\"\",\n                            \"\"salt\"\":\n                                \"\"3eeaaf35da70928387cae1ead31ed782b1135d7578a89d95e30cc914010ba2ed\"\"\n                        },\n                        \"\"mac\"\": 123,  // Not a string, but a number\n                    },\n                    \"\"id\"\": \"\"3b647634-1234-cd02-e93c-02e1c0f54faa\"\",\n                    \"\"version\"\": 3,\n                }\")\n            );\n\n            Assert.Throws<InvalidKeyJsonException>(() =>\n                load(@\"{\n                    \"\"address\"\": \"\"d80d933db45cc0cf69e9632090f8aaff635dc8e5\"\",\n                    \"\"crypto\"\": {\n                        \"\"cipher\"\": \"\"aes-128-ctr\"\",\n                        \"\"cipherparams\"\": {\n                            \"\"iv\"\": \"\"bc7f2ca23bfee0dd9725228ab2b0d98a\"\",\n                        },\n                        \"\"ciphertext\"\":\n                            \"\"535bab75c112fe327dc2e293f80297ff339e1e3cb76749615313cdc2aaa3b37a\"\",\n                        \"\"kdf\"\": \"\"pbkdf2\"\",\n                        \"\"kdfparams\"\": {\n                            \"\"c\"\": 10240,\n                            \"\"dklen\"\": 32,\n                            \"\"prf\"\": \"\"hmac-sha256\"\",\n                            \"\"salt\"\":\n                                \"\"3eeaaf35da70928387cae1ead31ed782b1135d7578a89d95e30cc914010ba2ed\"\"\n                        },\n                        \"\"mac\"\": \"\"Not a hexadecimal string\"\",\n                    },\n                    \"\"id\"\": \"\"3b647634-1234-cd02-e93c-02e1c0f54faa\"\",\n                    \"\"version\"\": 3,\n                }\")\n            );\n\n            Assert.Throws<InvalidKeyJsonException>(() =>\n                load(@\"{\n                    \"\"address\"\": \"\"89c2b1031ade56524ecb2fe73bf45f18e6d2f06d\"\",\n                    \"\"crypto\"\": {\n                        \"\"cipher\"\": \"\"aes-128-ctr\"\",\n                        \"\"ciphertext\"\":\n                            \"\"7870dff71e174af3cdc3e9dd47ecfd2dbeca665cd133fb0f87dd9359f3279e0b\"\",\n                        \"\"cipherparams\"\": {\n                            \"\"iv\"\": \"\"854e9d92316a0802ab5a9c0958786194\"\"\n                        },\n                        \"\"kdf\"\": \"\"scrypt\"\",\n                        \"\"kdfparams\"\": {\n                            \"\"dklen\"\": 32,\n                            \"\"n\"\": 1,  //  n(Cost) must be a power of 2 greater than 1.\n                            \"\"p\"\": 1,\n                            \"\"r\"\": 8,\n                            \"\"salt\"\":\n                                \"\"75de082f96f1c780e460b8400166d411482bff402444b869125e7559315ea892\"\"\n                        },\n                        \"\"mac\"\":\n                            \"\"c3f7e2be00e7f6c3377121bc7fe2967c22d627c3289be1b8ace3a6b3c4a54dad\"\",\n                    },\n                    \"\"id\"\": \"\"c3348c6a-de9c-4c61-828e-7d6b0ec3da26\"\",\n                    \"\"version\"\": 3,\n                }\")\n            );\n        }\n        #pragma warning restore MEN003\n\n        [Fact]\n        public void WriteJson()\n        {\n            string json;\n            using (var stream = new MemoryStream())\n            {\n                Fixture.WriteJson(stream);\n                json = Encoding.UTF8.GetString(stream.ToArray());\n            }\n\n            // TODO: More decent tests should be written.\n            ProtectedPrivateKey key = ProtectedPrivateKey.FromJson(json);\n            Assert.Equal(AddressFixture, key.Address);\n            Assert.Equal(AddressFixture, key.Unprotect(PassphraseFixture).Address);\n\n            using (var stream = new MemoryStream())\n            {\n                Fixture2.WriteJson(stream);\n                json = Encoding.UTF8.GetString(stream.ToArray());\n            }\n\n            ProtectedPrivateKey key2 = ProtectedPrivateKey.FromJson(json);\n            Assert.Equal(AddressFixture2, key2.Address);\n            Assert.Equal(AddressFixture2, key2.Unprotect(PassphraseFixture).Address);\n        }\n    }\n}\n"
  },
  {
    "path": "test/Libplanet.Tests/KeyStore/Web3KeyStoreTest.cs",
    "content": "using System;\nusing System.IO;\nusing System.Runtime.InteropServices;\nusing Libplanet.Crypto;\nusing Libplanet.KeyStore;\nusing Xunit;\n\nnamespace Libplanet.Tests.KeyStore\n{\n    public class Web3KeyStoreTest : KeyStoreTest<Web3KeyStore>, IDisposable\n    {\n        public Web3KeyStoreTest()\n        {\n            var tempDir = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName());\n            KeyStore = new Web3KeyStore(tempDir);\n        }\n\n        public override Web3KeyStore KeyStore { get; }\n\n        [Fact]\n        public void Constructor()\n        {\n            // Constructor creates a directory if needed.\n            Assert.True(Directory.Exists(KeyStore.Path));\n        }\n\n        [Fact]\n        public void DefaultKeyStore()\n        {\n            string path = Web3KeyStore.DefaultKeyStore.Path;\n            if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux) ||\n                RuntimeInformation.IsOSPlatform(OSPlatform.OSX))\n            {\n                Assert.Equal(\n                    Path.Combine(\n                        Environment.GetFolderPath(Environment.SpecialFolder.UserProfile),\n                        \".config\",\n                        \"planetarium\",\n                        \"keystore\"\n                    ),\n                    path\n                );\n            }\n            else if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))\n            {\n                Assert.Equal(\n                    Path.Combine(\n                        Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData),\n                        \"planetarium\",\n                        \"keystore\"\n                    ),\n                    path\n                );\n            }\n        }\n\n        [Fact]\n        public void Load()\n        {\n            string idStr = \"c8b0c0b1-82a0-41cd-9528-a22a0f208dee\";\n            Guid id = Guid.Parse(idStr);\n            var path = Path.Combine(KeyStore.Path, $\"UTC--2020-03-23T00-00-00Z--{idStr}\");\n            var key = new PrivateKey();\n            ProtectedPrivateKey ppk = ProtectedPrivateKey.Protect(key, \"pass\");\n            using (var f = new FileStream(path, FileMode.Create))\n            {\n                ppk.WriteJson(f, id);\n            }\n\n            Assert.Equal(new[] { id }, KeyStore.ListIds());\n            Assert.Equal(ppk.Address, KeyStore.Get(id).Address);\n        }\n\n        public void Dispose()\n        {\n            Directory.Delete(KeyStore.Path, true);\n        }\n    }\n}\n"
  },
  {
    "path": "test/Libplanet.Tests/Libplanet.Tests.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <PropertyGroup>\n    <Nullable>disable</Nullable>\n    <TreatWarningsAsErrors>true</TreatWarningsAsErrors>\n    <NoWarn>$(NoWarn);SA1401;SYSLIB0011</NoWarn>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <AdditionalFiles Remove=\"..\\..\\Menees.Analyzers.Settings.xml\" />\n    <AdditionalFiles Include=\"$(MSBuildThisFileDirectory)Menees.Analyzers.Settings.xml\">\n      <Link>Menees.Analyzers.Settings.xml</Link>\n    </AdditionalFiles>\n  </ItemGroup>\n\n  <ItemGroup>\n    <PackageReference Include=\"AsyncEnumerator\" Version=\"4.0.2\" />\n    <PackageReference Include=\"DiffPlex\" Version=\"1.7.0\" />\n    <PackageReference Include=\"Microsoft.Bcl.AsyncInterfaces\" Version=\"6.0.0\" />\n    <PackageReference Include=\"Serilog.Enrichers.Thread\" Version=\"3.0.0\" />\n    <PackageReference Include=\"Serilog.Sinks.TestCorrelator\" Version=\"3.2.0\" />\n    <PackageReference Include=\"Serilog.Sinks.XUnit\" Version=\"1.0.7\" />\n    <PackageReference Include=\"System.Collections.Immutable\" Version=\"1.7.*\" />\n    <PackageReference Include=\"SystemTextJson.JsonDiffPatch.Xunit\" Version=\"1.3.0\" />\n    <PackageReference Include=\"xRetry\" Version=\"1.5.0\" />\n    <PackageReference Include=\"Xunit.SkippableFact\" Version=\"1.3.12\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <ProjectReference Include=\"..\\..\\src\\Libplanet\\Libplanet.csproj\" />\n    <ProjectReference Include=\"..\\..\\src\\Libplanet.Store\\Libplanet.Store.csproj\" />\n    <ProjectReference Include=\"..\\..\\src\\Libplanet.Types\\Libplanet.Types.csproj\" />\n    <ProjectReference Include=\"..\\Libplanet.Action.Tests\\Libplanet.Action.Tests.csproj\" />\n    <ProjectReference Include=\"..\\Libplanet.Mocks\\Libplanet.Mocks.csproj\" />\n  </ItemGroup>\n\n</Project>\n"
  },
  {
    "path": "test/Libplanet.Tests/LoggerExtensions.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing Libplanet.Blockchain;\nusing Libplanet.Types.Blocks;\nusing Serilog;\nusing Serilog.Events;\n\nnamespace Libplanet.Tests\n{\n    public static class LoggerExtensions\n    {\n        public static void CompareBothChains(\n            this ILogger logger,\n            LogEventLevel logLevel,\n            string labelA,\n            BlockChain chainA,\n            string labelB,\n            BlockChain chainB)\n        =>\n            logger.CompareBothChains(\n                logLevel,\n                labelA,\n                chainA.BlockHashes.Select(h => chainA[h]).ToArray(),\n                labelB,\n                chainB.BlockHashes.Select(h => chainB[h]).ToArray()\n            );\n\n        public static void CompareBothChains(\n            this ILogger logger,\n            LogEventLevel logLevel,\n            string labelA,\n            IReadOnlyList<Block> chainA,\n            string labelB,\n            IReadOnlyList<Block> chainB)\n        {\n            if (chainA is null)\n            {\n                throw new ArgumentNullException(nameof(chainA));\n            }\n            else if (chainB is null)\n            {\n                throw new ArgumentNullException(nameof(chainB));\n            }\n            else if (chainA.Any(b => b is null))\n            {\n                throw new ArgumentException($\"The {nameof(chainA)} contains null.\", nameof(chainA));\n            }\n            else if (chainB.Any(b => b is null))\n            {\n                throw new ArgumentException($\"The {nameof(chainB)} contains null.\", nameof(chainB));\n            }\n\n            if (!logger.IsEnabled(logLevel))\n            {\n                return;\n            }\n\n            void Print(string i, string x, string y)\n            {\n                char bar = x.Equals(y) ? '|' : ':';\n                logger.Write(logLevel, $\"{bar} {i,3} {bar} {x,-64} {bar} {y,-64} {bar}\");\n            }\n\n            var aTipIdx = (int)chainA[chainA.Count - 1].Index;\n            var bTipIdx = (int)chainB[chainB.Count - 1].Index;\n            Print(\"Idx\", $\"{labelA} (tip: {aTipIdx})\", $\"{labelB} (tip: {bTipIdx})\");\n            int tipIdx = Math.Max(aTipIdx, bTipIdx);\n            int idx = 0;\n            while (idx <= tipIdx)\n            {\n                Print(\n                    $\"#{idx}\",\n                    aTipIdx >= idx ? chainA[idx].ToString() : string.Empty,\n                    bTipIdx >= idx ? chainB[idx].ToString() : string.Empty\n                );\n                idx++;\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "test/Libplanet.Tests/Menees.Analyzers.Settings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n<Menees.Analyzers.Settings>\n  <MaxLineColumns>100</MaxLineColumns>\n  <MaxMethodLines>300</MaxMethodLines>\n  <MaxFileLines>2470</MaxFileLines>\n</Menees.Analyzers.Settings>\n"
  },
  {
    "path": "test/Libplanet.Tests/NameValueCollectionExtensionsTest.cs",
    "content": "using System;\nusing System.Collections.Specialized;\n#if !NETFRAMEWORK\nusing static System.Web.HttpUtility;\n#endif\nusing Libplanet.Common;\n#if NETFRAMEWORK\nusing static Mono.Web.HttpUtility;\n#endif\nusing Xunit;\n\nnamespace Libplanet.Tests\n{\n    public class NameValueCollectionExtensionsTest\n    {\n        [Fact]\n        public void GetInt32()\n        {\n            NameValueCollection c = ParseQueryString(\n                \"foo=12&bar=345&baz=-1&qux=0&quux=9999999999999999&quuz=invalid\");\n            Assert.Equal(12, c.GetInt32(\"foo\"));\n            Assert.Equal(12, c.GetInt32(\"foo\", -123));\n            Assert.Equal(345, c.GetInt32(\"bar\"));\n            Assert.Equal(345, c.GetInt32(\"bar\", -123));\n            Assert.Equal(-1, c.GetInt32(\"baz\"));\n            Assert.Equal(-1, c.GetInt32(\"baz\", -123));\n            Assert.Equal(0, c.GetInt32(\"qux\"));\n            Assert.Equal(0, c.GetInt32(\"qux\", -123));\n            Assert.Throws<OverflowException>(() => c.GetInt32(\"quux\"));\n            Assert.Equal(-123, c.GetInt32(\"quux\", -123));\n            Assert.Throws<FormatException>(() => c.GetInt32(\"quuz\"));\n            Assert.Equal(-123, c.GetInt32(\"quuz\", -123));\n            Assert.Null(c.GetInt32(\"non-existent\"));\n            Assert.Equal(-123, c.GetInt32(\"non-existent\", -123));\n        }\n\n        [Fact]\n        public void GetUInt64()\n        {\n            NameValueCollection c = ParseQueryString(\n                \"foo=12&bar=345&baz=-1&qux=0&quux=9999999999999999999999999999999999&quuz=invalid\");\n            Assert.Equal(12UL, c.GetUInt64(\"foo\"));\n            Assert.Equal(12UL, c.GetUInt64(\"foo\", 11223344UL));\n            Assert.Equal(345UL, c.GetUInt64(\"bar\"));\n            Assert.Equal(345UL, c.GetUInt64(\"bar\", 11223344UL));\n            Assert.Throws<OverflowException>(() => c.GetUInt64(\"baz\"));\n            Assert.Equal(11223344UL, c.GetUInt64(\"baz\", 11223344UL));\n            Assert.Equal(0UL, c.GetUInt64(\"qux\"));\n            Assert.Equal(0UL, c.GetUInt64(\"qux\", 11223344UL));\n            Assert.Throws<OverflowException>(() => c.GetUInt64(\"quux\"));\n            Assert.Equal(11223344UL, c.GetUInt64(\"quux\", 11223344UL));\n            Assert.Throws<FormatException>(() => c.GetUInt64(\"quuz\"));\n            Assert.Equal(11223344UL, c.GetUInt64(\"quuz\", 11223344UL));\n            Assert.Null(c.GetUInt64(\"non-existent\"));\n            Assert.Equal(11223344UL, c.GetUInt64(\"non-existent\", 11223344UL));\n        }\n\n        [Fact]\n        public void GetBoolean()\n        {\n            NameValueCollection c = ParseQueryString(\n                \"num-f=0&num-t=1&yn-f=n&yn-t=y&yesno-f=no&yesno-t=yes&tf-t=t&tf-f=f&\" +\n                \"truefalse-t=true&truefalse-f=false&onoff-t=on&onoff-f=off&invalid=xyz\"\n            );\n            Assert.False(c.GetBoolean(\"num-f\"));\n            Assert.False(c.GetBoolean(\"num-f\", true));\n            Assert.True(c.GetBoolean(\"num-t\"));\n            Assert.True(c.GetBoolean(\"num-t\", true));\n            Assert.False(c.GetBoolean(\"yn-f\"));\n            Assert.False(c.GetBoolean(\"yn-f\", true));\n            Assert.True(c.GetBoolean(\"yn-t\"));\n            Assert.True(c.GetBoolean(\"yn-t\", true));\n            Assert.False(c.GetBoolean(\"yesno-f\"));\n            Assert.False(c.GetBoolean(\"yesno-f\", true));\n            Assert.True(c.GetBoolean(\"yesno-t\"));\n            Assert.True(c.GetBoolean(\"yesno-t\", true));\n            Assert.False(c.GetBoolean(\"tf-f\"));\n            Assert.False(c.GetBoolean(\"tf-f\", true));\n            Assert.True(c.GetBoolean(\"tf-t\"));\n            Assert.True(c.GetBoolean(\"tf-t\", true));\n            Assert.False(c.GetBoolean(\"truefalse-f\"));\n            Assert.False(c.GetBoolean(\"truefalse-f\", true));\n            Assert.True(c.GetBoolean(\"truefalse-t\"));\n            Assert.True(c.GetBoolean(\"truefalse-t\", true));\n            Assert.False(c.GetBoolean(\"onoff-f\"));\n            Assert.False(c.GetBoolean(\"onoff-f\", true));\n            Assert.True(c.GetBoolean(\"onoff-t\"));\n            Assert.True(c.GetBoolean(\"onoff-t\", true));\n            Assert.False(c.GetBoolean(\"invalid\"));\n            Assert.True(c.GetBoolean(\"invalid\", true));\n            Assert.False(c.GetBoolean(\"non-existent\"));\n            Assert.True(c.GetBoolean(\"non-existent\", true));\n        }\n    }\n}\n"
  },
  {
    "path": "test/Libplanet.Tests/RandomExtensions.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Security.Cryptography;\nusing Libplanet.Common;\nusing Libplanet.Crypto;\nusing Libplanet.Types.Blocks;\nusing Libplanet.Types.Tx;\n\nnamespace Libplanet.Tests\n{\n    public static class RandomExtensions\n    {\n        public static byte[] NextBytes(this Random random, int size)\n        {\n            var buffer = new byte[size];\n            random.NextBytes(buffer);\n            return buffer;\n        }\n\n        public static TxId NextTxId(this Random random) =>\n            new TxId(random.NextBytes(TxId.Size));\n\n        public static Address NextAddress(this Random random) =>\n            new Address(random.NextBytes(Address.Size));\n\n        public static HashDigest<T> NextHashDigest<T>(this Random random)\n            where T : HashAlgorithm\n        =>\n            new HashDigest<T>(random.NextBytes(HashDigest<T>.Size));\n\n        public static BlockHash NextBlockHash(this Random random) =>\n            new BlockHash(random.NextBytes(BlockHash.Size));\n\n        public static IOrderedEnumerable<T> Shuffle<T>(this Random random, IEnumerable<T> source) =>\n            source.OrderBy(_ => random.Next());\n\n        public static IOrderedEnumerable<T> Shuffle<T>(this IEnumerable<T> source, Random random) =>\n            random.Shuffle(source);\n    }\n}\n"
  },
  {
    "path": "test/Libplanet.Tests/Store/BaseTracker.cs",
    "content": "using System.Collections.Generic;\nusing System.Collections.Immutable;\n\nnamespace Libplanet.Tests.Store\n{\n    public abstract class BaseTracker\n    {\n        private readonly List<StoreTrackLog> _logs;\n\n        protected BaseTracker()\n        {\n            _logs = new List<StoreTrackLog>();\n        }\n\n        public IImmutableList<StoreTrackLog> Logs =>\n            _logs.ToImmutableList();\n\n        public void ClearLogs() => _logs.Clear();\n\n        protected void Log(string method, params object[] @params)\n        {\n            _logs.Add(StoreTrackLog.Create(method, @params));\n        }\n    }\n}\n"
  },
  {
    "path": "test/Libplanet.Tests/Store/BlockSetTest.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing Libplanet.Store;\nusing Libplanet.Types.Blocks;\nusing Xunit;\n\nnamespace Libplanet.Tests.Store\n{\n    public class BlockSetTest : IDisposable\n    {\n        private readonly StoreFixture _fx;\n        private readonly BlockSet _set;\n\n        public BlockSetTest()\n        {\n            _fx = new MemoryStoreFixture();\n            _set = new BlockSet(_fx.Store);\n        }\n\n        [Fact]\n        public void CanStoreItem()\n        {\n            _set[_fx.Block1.Hash] = _fx.Block1;\n            Assert.Equal(_set[_fx.Block1.Hash], _fx.Block1);\n        }\n\n        [Fact]\n        public void CanIterateItems()\n        {\n            Assert.Empty(_set);\n            Assert.Empty(_set.Keys);\n            Assert.Empty(_set.Values);\n            _set[_fx.Block1.Hash] = _fx.Block1;\n            _set[_fx.Block2.Hash] = _fx.Block2;\n            _set[_fx.Block3.Hash] = _fx.Block3;\n\n            Assert.Equal(\n                new HashSet<BlockHash>()\n                {\n                    _fx.Block1.Hash,\n                    _fx.Block2.Hash,\n                    _fx.Block3.Hash,\n                },\n                _set.Keys.ToHashSet());\n\n            Assert.Equal(\n                new HashSet<Block>()\n                {\n                    _fx.Block1,\n                    _fx.Block2,\n                    _fx.Block3,\n                },\n                _set.Values.ToHashSet());\n        }\n\n        [Fact]\n        public void CanCountItem()\n        {\n            Assert.Empty(_set);\n\n            _set[_fx.Block1.Hash] = _fx.Block1;\n            Assert.Single(_set);\n\n            _set[_fx.Block2.Hash] = _fx.Block2;\n            _set[_fx.Block3.Hash] = _fx.Block3;\n            Assert.Equal(3, _set.Count);\n        }\n\n        [Fact]\n        public void CanDetectInvalidHash()\n        {\n            Assert.Throws<InvalidBlockHashException>(\n                () => _set[_fx.Block1.Hash] = _fx.Block2);\n        }\n\n        [Fact]\n        public void CanCheckContainsKey()\n        {\n            Assert.False(_set.ContainsKey(_fx.Block1.Hash));\n            Assert.False(_set.ContainsKey(_fx.Block2.Hash));\n\n            _set[_fx.Block1.Hash] = _fx.Block1;\n\n            Assert.True(_set.ContainsKey(_fx.Block1.Hash));\n            Assert.False(_set.ContainsKey(_fx.Block2.Hash));\n        }\n\n        [Fact]\n        public void CanRemoveItem()\n        {\n            Assert.False(_set.Remove(_fx.Block1.Hash));\n            _set[_fx.Block1.Hash] = _fx.Block1;\n            Assert.True(_set.Remove(_fx.Block1.Hash));\n            Assert.Throws<KeyNotFoundException>(() => { var val = _set[_fx.Block1.Hash]; });\n        }\n\n        public void Dispose()\n        {\n            _fx.Dispose();\n        }\n    }\n}\n"
  },
  {
    "path": "test/Libplanet.Tests/Store/DataModelTest.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Collections.Immutable;\nusing System.Linq;\nusing System.Numerics;\nusing Libplanet.Crypto;\nusing Libplanet.Store;\nusing Serilog;\nusing Xunit;\nusing Xunit.Abstractions;\nusing BTypes = Bencodex.Types;\n\nnamespace Libplanet.Tests.Store\n{\n    public class DataModelTest\n    {\n        private readonly ILogger _logger;\n\n        public DataModelTest(ITestOutputHelper output)\n        {\n            Log.Logger = _logger = new LoggerConfiguration()\n                .MinimumLevel.Verbose()\n                .Enrich.WithThreadId()\n                .WriteTo.TestOutput(output)\n                .CreateLogger()\n                .ForContext<DataModelTest>();\n        }\n\n        [Fact]\n        public void Encode()\n        {\n            RootModel root = new RootModel();\n\n            BTypes.Dictionary rootEncoded = root.Encode();\n            Assert.Equal(\n                root.Bool,\n                ((BTypes.Boolean)rootEncoded[nameof(root.Bool)]).Value);\n            Assert.Equal(\n                root.Int,\n                (int)((BTypes.Integer)rootEncoded[nameof(root.Int)]).Value);\n            Assert.Equal(\n                root.Long,\n                (long)((BTypes.Integer)rootEncoded[nameof(root.Long)]).Value);\n            Assert.Equal(\n                root.BigInt,\n                ((BTypes.Integer)rootEncoded[nameof(root.BigInt)]).Value);\n            Assert.Equal(\n                root.Bytes,\n                ((BTypes.Binary)rootEncoded[nameof(root.Bytes)]).ToByteArray());\n            Assert.Equal(\n                root.Guid,\n                new Guid(((BTypes.Binary)rootEncoded[nameof(root.Guid)]).ToByteArray()));\n            Assert.Equal(\n                root.Addr,\n                new Address(((BTypes.Binary)rootEncoded[nameof(root.Addr)]).ToByteArray()));\n            Assert.Equal(\n                root.Str,\n                ((BTypes.Text)rootEncoded[nameof(root.Str)]).Value);\n            Assert.Empty(\n                (BTypes.List)rootEncoded[nameof(root.ListEmpty)]);\n            Assert.Equal(\n                root.ListBool,\n                ((BTypes.List)rootEncoded[nameof(root.ListBool)])\n                    .Select(x => ((BTypes.Boolean)x).Value));\n            Assert.Equal(\n                root.ListInt,\n                ((BTypes.List)rootEncoded[nameof(root.ListInt)])\n                    .Select(x => (int)((BTypes.Integer)x).Value));\n            Assert.Equal(\n                root.ListLong,\n                ((BTypes.List)rootEncoded[nameof(root.ListLong)])\n                    .Select(x => (long)((BTypes.Integer)x).Value));\n            Assert.Equal(\n                root.ListBigInt,\n                ((BTypes.List)rootEncoded[nameof(root.ListBigInt)])\n                    .Select(x => ((BTypes.Integer)x).Value));\n            Assert.Equal(\n                root.ListBytes,\n                ((BTypes.List)rootEncoded[nameof(root.ListBytes)])\n                    .Select(x => ((BTypes.Binary)x).ByteArray));\n            Assert.Equal(\n                root.ListGuid,\n                ((BTypes.List)rootEncoded[nameof(root.ListGuid)])\n                    .Select(x => new Guid(((BTypes.Binary)x).ToByteArray())));\n            Assert.Equal(\n                root.ListAddr,\n                ((BTypes.List)rootEncoded[nameof(root.ListAddr)])\n                    .Select(x => new Address(((BTypes.Binary)x).ByteArray)));\n            Assert.Equal(\n                root.ListStr,\n                ((BTypes.List)rootEncoded[nameof(root.ListStr)])\n                    .Select(x => ((BTypes.Text)x).Value));\n            Assert.Empty(\n                (BTypes.Dictionary)rootEncoded[nameof(root.DictEmpty)]);\n\n            var dictionaryBytesBool =\n                ((BTypes.Dictionary)rootEncoded[nameof(root.DictBytesBool)])\n                    .Select(x => new KeyValuePair<ImmutableArray<byte>, bool>(\n                        ((BTypes.Binary)x.Key).ByteArray, ((BTypes.Boolean)x.Value).Value))\n                    .ToImmutableDictionary();\n            foreach (var kv in root.DictBytesBool)\n            {\n                Assert.Equal(kv.Value, dictionaryBytesBool[kv.Key]);\n            }\n\n            var dictionaryBytesInt =\n                ((BTypes.Dictionary)rootEncoded[nameof(root.DictBytesInt)])\n                    .Select(x => new KeyValuePair<ImmutableArray<byte>, int>(\n                        ((BTypes.Binary)x.Key).ByteArray, (int)((BTypes.Integer)x.Value).Value))\n                    .ToImmutableDictionary();\n            foreach (var kv in root.DictBytesInt)\n            {\n                Assert.Equal(kv.Value, dictionaryBytesInt[kv.Key]);\n            }\n\n            var dictionaryBytesLong =\n                ((BTypes.Dictionary)rootEncoded[nameof(root.DictBytesLong)])\n                    .Select(x => new KeyValuePair<ImmutableArray<byte>, long>(\n                        ((BTypes.Binary)x.Key).ByteArray, (long)((BTypes.Integer)x.Value).Value))\n                    .ToImmutableDictionary();\n            foreach (var kv in root.DictBytesLong)\n            {\n                Assert.Equal(kv.Value, dictionaryBytesLong[kv.Key]);\n            }\n\n            var dictionaryBytesBigInteger =\n                ((BTypes.Dictionary)rootEncoded[nameof(root.DictBytesBigInt)])\n                    .Select(x => new KeyValuePair<ImmutableArray<byte>, BigInteger>(\n                        ((BTypes.Binary)x.Key).ByteArray, ((BTypes.Integer)x.Value).Value))\n                    .ToImmutableDictionary();\n            foreach (var kv in root.DictBytesBigInt)\n            {\n                Assert.Equal(kv.Value, dictionaryBytesBigInteger[kv.Key]);\n            }\n\n            var dictionaryBytesBytes =\n                ((BTypes.Dictionary)rootEncoded[nameof(root.DictBytesBytes)])\n                    .Select(x => new KeyValuePair<ImmutableArray<byte>, ImmutableArray<byte>>(\n                        ((BTypes.Binary)x.Key).ByteArray, ((BTypes.Binary)x.Value).ByteArray))\n                    .ToImmutableDictionary();\n            foreach (var kv in root.DictBytesBytes)\n            {\n                Assert.Equal(kv.Value, dictionaryBytesBytes[kv.Key]);\n            }\n\n            var dictionaryBytesAddr =\n                ((BTypes.Dictionary)rootEncoded[nameof(root.DictBytesAddr)])\n                    .Select(x => new KeyValuePair<ImmutableArray<byte>, Address>(\n                        ((BTypes.Binary)x.Key).ByteArray,\n                        new Address(((BTypes.Binary)x.Value).ByteArray)))\n                .ToImmutableDictionary();\n            foreach (var kv in root.DictBytesAddr)\n            {\n                Assert.Equal(kv.Value, dictionaryBytesAddr[kv.Key]);\n            }\n\n            var dictionaryBytesString =\n                ((BTypes.Dictionary)rootEncoded[nameof(root.DictBytesStr)])\n                    .Select(x => new KeyValuePair<ImmutableArray<byte>, string>(\n                        ((BTypes.Binary)x.Key).ByteArray, ((BTypes.Text)x.Value).Value))\n                    .ToImmutableDictionary();\n            foreach (var kv in root.DictBytesStr)\n            {\n                Assert.Equal(kv.Value, dictionaryBytesString[kv.Key]);\n            }\n\n            var dictionaryGuidStr =\n                ((BTypes.Dictionary)rootEncoded[nameof(root.DictGuidStr)])\n                    .Select(x => new KeyValuePair<Guid, string>(\n                        new Guid(((BTypes.Binary)x.Key).ToByteArray()),\n                        ((BTypes.Text)x.Value).Value))\n                .ToImmutableDictionary();\n            foreach (var kv in root.DictGuidStr)\n            {\n                Assert.Equal(kv.Value, dictionaryGuidStr[kv.Key]);\n            }\n\n            var dictionaryAddrStr =\n                ((BTypes.Dictionary)rootEncoded[nameof(root.DictAddrStr)])\n                    .Select(x => new KeyValuePair<Address, string>(\n                        new Address(((BTypes.Binary)x.Key).ByteArray),\n                        ((BTypes.Text)x.Value).Value))\n                .ToImmutableDictionary();\n            foreach (var kv in root.DictAddrStr)\n            {\n                Assert.Equal(kv.Value, dictionaryAddrStr[kv.Key]);\n            }\n\n            var dictionaryStringString =\n                ((BTypes.Dictionary)rootEncoded[nameof(root.DictStrStr)])\n                    .Select(x => new KeyValuePair<string, string>(\n                        ((BTypes.Text)x.Key).Value, ((BTypes.Text)x.Value).Value))\n                    .ToImmutableDictionary();\n            foreach (var kv in root.DictStrStr)\n            {\n                Assert.Equal(kv.Value, dictionaryStringString[kv.Key]);\n            }\n\n            // Although not entirely strict, for the most part, we only check\n            // randomly generated guid string still matches to assume all has gone well.\n            Assert.Equal(\n                root.Mid.Str,\n                ((BTypes.Text)(\n                    (BTypes.Dictionary)rootEncoded[nameof(root.Mid)]\n                )[nameof(root.Mid.Str)]).Value);\n            Assert.Equal(\n                root.Leaf.Str,\n                ((BTypes.Text)(\n                    (BTypes.Dictionary)rootEncoded[nameof(root.Leaf)]\n                )[nameof(root.Leaf.Str)]).Value);\n            Assert.Equal(\n                root.Mid.Leaf.Str,\n                ((BTypes.Text)(\n                    (BTypes.Dictionary)(\n                        (BTypes.Dictionary)rootEncoded[nameof(root.Mid)]\n                    )[nameof(root.Mid.Leaf)]\n                )[nameof(root.Mid.Leaf.Str)]).Value);\n        }\n\n        [Fact]\n        public void Decode()\n        {\n            // This is written under a strong assumption that a sufficient amount of check\n            // is done under Encode() test.\n            RootModel root = new RootModel();\n            MidModel mid = new MidModel();\n            LeafModel leaf = new LeafModel();\n\n            Assert.Equal(root.Encode(), new RootModel(root.Encode()).Encode());\n            Assert.Equal(mid.Encode(), new MidModel(mid.Encode()).Encode());\n            Assert.Equal(leaf.Encode(), new LeafModel(leaf.Encode()).Encode());\n        }\n\n        [Fact]\n        public void EncodeFromBadTypes()\n        {\n            Assert.Throws<NotSupportedException>(\n                () => new HasNullableBoolType().Encode());\n            Assert.Throws<NotSupportedException>(\n                () => new HasNullableIntType().Encode());\n            Assert.Throws<NotSupportedException>(\n                () => new HasNullableLongType().Encode());\n            Assert.Throws<NotSupportedException>(\n                () => new HasNullableBigIntegerType().Encode());\n            Assert.Throws<NotSupportedException>(\n                () => new HasNullableBytesType().Encode());\n            Assert.Throws<NotSupportedException>(\n                () => new HasNullableGuidType().Encode());\n            Assert.Throws<NotSupportedException>(\n                () => new HasNullableAddressType().Encode());\n\n            Assert.Throws<NotSupportedException>(\n                () => new HasNullableListValueType().Encode());\n            Assert.Throws<ArgumentException>(\n                () => new HasInvalidListValueType().Encode());\n            Assert.Throws<ArgumentException>(\n                () => new HasInvalidDictionaryKeyType().Encode());\n            Assert.Throws<NotSupportedException>(\n                () => new HasNullableDictionaryValueType().Encode());\n            Assert.Throws<ArgumentException>(\n                () => new HasInvalidDictionaryValueType().Encode());\n        }\n\n        [Fact]\n        public void EncodeFromBadValues()\n        {\n            Assert.Throws<NotSupportedException>(\n                () => new HasNullReferencePropertyValue().Encode());\n            Assert.Throws<NotSupportedException>(\n                () => new HasNullReferenceListValue().Encode());\n            Assert.Throws<NotSupportedException>(\n                () => new HasNullReferenceDictValue().Encode());\n        }\n\n        [Fact]\n        public void DecodeFromBadIValues()\n        {\n            System.Random random = new System.Random();\n            bool randBool = random.NextDouble() < 0.5;\n            int randInt = random.Next();\n            string randStr = Guid.NewGuid().ToString();\n            byte[] buffer = new byte[10];\n            random.NextBytes(buffer);\n            ImmutableArray<byte> randBytes = buffer.ToImmutableArray();\n            Guid randGuid = Guid.NewGuid();\n            Address randAddress = new PrivateKey().Address;\n\n            BTypes.Dictionary encoded;\n\n            // Try assigning null.\n            encoded = BTypes.Dictionary.Empty\n                .Add(nameof(HasNullableBoolType.Value), BTypes.Null.Value);\n            Assert.Throws<NotSupportedException>(() => new HasNullableBoolType(encoded));\n            encoded = BTypes.Dictionary.Empty\n                .Add(nameof(HasNullReferencePropertyValue.Value), BTypes.Null.Value);\n            Assert.Throws<NotSupportedException>(() => new HasNullReferencePropertyValue(encoded));\n\n            // Sanity check\n            encoded = BTypes.Dictionary.Empty\n                .Add(nameof(IntWrapper.Value), (BTypes.IValue)new BTypes.Integer(randInt));\n            IntWrapper decodedIntWrapper = new IntWrapper(encoded);\n            Assert.Equal(randInt, decodedIntWrapper.Value);\n            encoded = BTypes.Dictionary.Empty\n                .Add(nameof(StrWrapper.Value), (BTypes.IValue)new BTypes.Text(randStr));\n            StrWrapper decodedStrWrapper = new StrWrapper(encoded);\n            Assert.Equal(randStr, decodedStrWrapper.Value);\n            encoded = BTypes.Dictionary.Empty\n                .Add(\n                    nameof(ListIntWrapper.Value),\n                    (BTypes.IValue)BTypes.List.Empty\n                        .Add((BTypes.IValue)new BTypes.Integer(randInt)));\n            ListIntWrapper decodedListIntWrapper = new ListIntWrapper(encoded);\n            Assert.Equal(randInt, decodedListIntWrapper.Value[0]);\n            encoded = BTypes.Dictionary.Empty\n                .Add(\n                    nameof(DictStrIntWrapper.Value),\n                    (BTypes.IValue)BTypes.Dictionary.Empty\n                        .Add(\n                            (BTypes.IKey)new BTypes.Text(randStr),\n                            (BTypes.IValue)new BTypes.Integer(randInt)));\n            DictStrIntWrapper decodedDictStrIntWrapper = new DictStrIntWrapper(encoded);\n            Assert.Equal(randInt, decodedDictStrIntWrapper.Value[randStr]);\n\n            // Try null.\n            Assert.Throws<NullReferenceException>(\n                () => new IntWrapper(null));\n\n            // Try missing data.\n            encoded = BTypes.Dictionary.Empty;\n            Assert.Throws<KeyNotFoundException>(() => new IntWrapper(encoded));\n            Assert.Throws<KeyNotFoundException>(() => new GuidWrapper(encoded));\n            Assert.Throws<KeyNotFoundException>(() => new AddressWrapper(encoded));\n            Assert.Throws<KeyNotFoundException>(() => new StrWrapper(encoded));\n            Assert.Throws<KeyNotFoundException>(() => new ListIntWrapper(encoded));\n            Assert.Throws<KeyNotFoundException>(() => new DictStrIntWrapper(encoded));\n\n            // Try type mismatch.\n            encoded = BTypes.Dictionary.Empty\n                .Add(nameof(IntWrapper.Value), (BTypes.IValue)new BTypes.Text(\"foo\"));\n            Assert.Throws<ArgumentException>(() => new IntWrapper(encoded));\n            encoded = BTypes.Dictionary.Empty\n                .Add(nameof(GuidWrapper.Value), (BTypes.IValue)new BTypes.Text(\"bar\"));\n            Assert.Throws<ArgumentException>(() => new GuidWrapper(encoded));\n            encoded = BTypes.Dictionary.Empty\n                .Add(nameof(AddressWrapper.Value), (BTypes.IValue)new BTypes.Text(\"bar\"));\n            Assert.Throws<ArgumentException>(() => new AddressWrapper(encoded));\n            encoded = BTypes.Dictionary.Empty\n                .Add(nameof(StrWrapper.Value), (BTypes.IValue)new BTypes.Integer(2));\n            Assert.Throws<ArgumentException>(() => new StrWrapper(encoded));\n            encoded = BTypes.Dictionary.Empty\n                .Add(\n                    nameof(ListIntWrapper.Value),\n                    (BTypes.IValue)BTypes.List.Empty\n                        .Add((BTypes.IValue)new BTypes.Text(\"foo\")));\n            Assert.Throws<ArgumentException>(() => new ListIntWrapper(encoded));\n            encoded = BTypes.Dictionary.Empty\n                .Add(\n                    nameof(DictStrIntWrapper.Value),\n                    (BTypes.IValue)BTypes.Dictionary.Empty\n                        .Add(\n                            (BTypes.IKey)new BTypes.Text(\"foo\"),\n                            (BTypes.IValue)new BTypes.Text(\"bar\")));\n            Assert.Throws<ArgumentException>(() => new DictStrIntWrapper(encoded));\n\n            // Try bad data; Address specifically requires length Address.Size bytes\n            // and Guid specifically requires length 16 bytes.\n            Assert.NotEqual(Address.Size, randBytes.Length);\n            Assert.NotEqual(randGuid.ToByteArray().Length, randBytes.Length);\n            encoded = BTypes.Dictionary.Empty\n                .Add(\n                    nameof(GuidWrapper.Value),\n                    (BTypes.IValue)new BTypes.Binary(randBytes));\n            Assert.Throws<ArgumentException>(() => new GuidWrapper(encoded));\n            encoded = BTypes.Dictionary.Empty\n                .Add(\n                    nameof(AddressWrapper.Value),\n                    (BTypes.IValue)new BTypes.Binary(randBytes));\n            Assert.Throws<ArgumentException>(() => new AddressWrapper(encoded));\n\n            // Try assigning null to inner collection.\n            encoded = BTypes.Dictionary.Empty\n                .Add(\n                    nameof(ListIntWrapper.Value),\n                    (BTypes.IValue)BTypes.List.Empty\n                        .Add((BTypes.IValue)new BTypes.Integer(5))\n                        .Add(BTypes.Null.Value));\n            Assert.Throws<NotSupportedException>(() => new ListIntWrapper(encoded));\n            encoded = BTypes.Dictionary.Empty\n                .Add(\n                    nameof(DictStrIntWrapper.Value),\n                    (BTypes.IValue)BTypes.Dictionary.Empty\n                        .Add(\n                            (BTypes.IKey)new BTypes.Text(\"foo\"),\n                            (BTypes.IValue)new BTypes.Integer(5))\n                        .Add(\n                            (BTypes.IKey)new BTypes.Text(\"bar\"),\n                            (BTypes.IValue)BTypes.Null.Value));\n            Assert.Throws<NotSupportedException>(() => new DictStrIntWrapper(encoded));\n        }\n\n        [Fact]\n        public void DecodeToBadTypes()\n        {\n            System.Random random = new System.Random();\n            bool randBool = random.NextDouble() < 0.5;\n            int randInt = random.Next();\n            string randStr = Guid.NewGuid().ToString();\n            byte[] buffer = new byte[10];\n            random.NextBytes(buffer);\n            ImmutableArray<byte> randBytes = buffer.ToImmutableArray();\n            Guid randGuid = Guid.NewGuid();\n            Address randAddress = new PrivateKey().Address;\n\n            BTypes.Dictionary encoded;\n\n            // Try decoding to invalid class.\n            encoded = BTypes.Dictionary.Empty\n                .Add(\n                    nameof(HasNullableBoolType.Value),\n                    (BTypes.IValue)new BTypes.Boolean(randBool));\n            Assert.Throws<NotSupportedException>(() => new HasNullableBoolType(encoded));\n            encoded = BTypes.Dictionary.Empty\n                .Add(\n                    nameof(HasNullableIntType.Value),\n                    (BTypes.IValue)new BTypes.Integer(randInt));\n            Assert.Throws<NotSupportedException>(() => new HasNullableIntType(encoded));\n            encoded = BTypes.Dictionary.Empty\n                .Add(\n                    nameof(HasNullableLongType.Value),\n                    (BTypes.IValue)new BTypes.Integer(randInt));\n            Assert.Throws<NotSupportedException>(() => new HasNullableLongType(encoded));\n            encoded = BTypes.Dictionary.Empty\n                .Add(\n                    nameof(HasNullableBigIntegerType.Value),\n                    (BTypes.IValue)new BTypes.Integer(randInt));\n            Assert.Throws<NotSupportedException>(() => new HasNullableBigIntegerType(encoded));\n            encoded = BTypes.Dictionary.Empty\n                .Add(\n                    nameof(HasNullableBytesType.Value),\n                    (BTypes.IValue)new BTypes.Binary(randBytes));\n            Assert.Throws<NotSupportedException>(() => new HasNullableBytesType(encoded));\n            encoded = BTypes.Dictionary.Empty\n                .Add(\n                    nameof(HasNullableGuidType.Value),\n                    (BTypes.IValue)new BTypes.Binary(randGuid.ToByteArray()));\n            Assert.Throws<NotSupportedException>(() => new HasNullableBytesType(encoded));\n            encoded = BTypes.Dictionary.Empty\n                .Add(\n                    nameof(HasNullableBytesType.Value),\n                    (BTypes.IValue)new BTypes.Binary(randAddress.ByteArray));\n            Assert.Throws<NotSupportedException>(() => new HasNullableBytesType(encoded));\n        }\n\n        private class RootModel : DataModel\n        {\n            public RootModel()\n                : base()\n            {\n                System.Random random = new System.Random();\n                Bool = random.NextDouble() < 0.5;\n                Int = random.Next();\n                Long = (long)random.Next();\n                BigInt = (BigInteger)random.Next();\n                byte[] buffer = new byte[10];\n                random.NextBytes(buffer);\n                Bytes = buffer.ToImmutableArray();\n                Guid = Guid.NewGuid();\n                Addr = new PrivateKey().Address;\n                Str = Guid.NewGuid().ToString();\n\n                ListEmpty = ImmutableList<int>.Empty;\n                ListBool = Enumerable\n                    .Range(0, 2)\n                    .Select(_ => random.NextDouble() < 0.5)\n                    .ToImmutableList();\n                ListInt = Enumerable\n                    .Range(0, 2)\n                    .Select(_ => random.Next())\n                    .ToImmutableList();\n                ListLong = Enumerable\n                    .Range(0, 2)\n                    .Select(_ => (long)random.Next())\n                    .ToImmutableList();\n                ListBigInt = Enumerable\n                    .Range(0, 2)\n                    .Select(_ => (BigInteger)random.Next())\n                    .ToImmutableList();\n                ListBytes = Enumerable\n                    .Range(0, 2)\n                    .Select(_ => Guid.NewGuid().ToByteArray().ToImmutableArray())\n                    .ToImmutableList();\n                ListGuid = Enumerable\n                    .Range(0, 2)\n                    .Select(_ => Guid.NewGuid())\n                    .ToImmutableList();\n                ListAddr = Enumerable\n                    .Range(0, 2)\n                    .Select(_ => new PrivateKey().Address)\n                    .ToImmutableList();\n                ListStr = Enumerable\n                    .Range(0, 2)\n                    .Select(_ => Guid.NewGuid().ToString())\n                    .ToImmutableList();\n\n                DictEmpty = ImmutableDictionary<string, string>.Empty;\n                DictBytesBool = Enumerable\n                    .Range(0, 2)\n                    .Select(_ => new KeyValuePair<ImmutableArray<byte>, bool>(\n                        Guid.NewGuid().ToByteArray().ToImmutableArray(),\n                        random.NextDouble() < 0.5))\n                    .ToImmutableDictionary();\n                DictBytesInt = Enumerable\n                    .Range(0, 2)\n                    .Select(_ => new KeyValuePair<ImmutableArray<byte>, int>(\n                        Guid.NewGuid().ToByteArray().ToImmutableArray(),\n                        random.Next()))\n                    .ToImmutableDictionary();\n                DictBytesLong = Enumerable\n                    .Range(0, 2)\n                    .Select(_ => new KeyValuePair<ImmutableArray<byte>, long>(\n                        Guid.NewGuid().ToByteArray().ToImmutableArray(),\n                        (long)random.Next()))\n                    .ToImmutableDictionary();\n                DictBytesBigInt = Enumerable\n                    .Range(0, 2)\n                    .Select(_ => new KeyValuePair<ImmutableArray<byte>, BigInteger>(\n                        Guid.NewGuid().ToByteArray().ToImmutableArray(),\n                        (BigInteger)random.Next()))\n                    .ToImmutableDictionary();\n                DictBytesBytes = Enumerable\n                    .Range(0, 2)\n                    .Select(_ => new KeyValuePair<ImmutableArray<byte>, ImmutableArray<byte>>(\n                        Guid.NewGuid().ToByteArray().ToImmutableArray(),\n                        Guid.NewGuid().ToByteArray().ToImmutableArray()))\n                    .ToImmutableDictionary();\n                DictBytesAddr = Enumerable\n                    .Range(0, 2)\n                    .Select(_ => new KeyValuePair<ImmutableArray<byte>, Address>(\n                        Guid.NewGuid().ToByteArray().ToImmutableArray(),\n                        new PrivateKey().Address))\n                    .ToImmutableDictionary();\n                DictBytesStr = Enumerable\n                    .Range(0, 2)\n                    .Select(_ => new KeyValuePair<ImmutableArray<byte>, string>(\n                        Guid.NewGuid().ToByteArray().ToImmutableArray(),\n                        Guid.NewGuid().ToString()))\n                    .ToImmutableDictionary();\n                DictGuidStr = Enumerable\n                    .Range(0, 2)\n                    .Select(_ => new KeyValuePair<Guid, string>(\n                        Guid.NewGuid(),\n                        Guid.NewGuid().ToString()))\n                    .ToImmutableDictionary();\n                DictAddrStr = Enumerable\n                    .Range(0, 2)\n                    .Select(_ => new KeyValuePair<Address, string>(\n                        new PrivateKey().Address,\n                        Guid.NewGuid().ToString()))\n                    .ToImmutableDictionary();\n                DictStrStr = Enumerable\n                    .Range(0, 2)\n                    .Select(_ => new KeyValuePair<string, string>(\n                        Guid.NewGuid().ToString(),\n                        Guid.NewGuid().ToString()))\n                    .ToImmutableDictionary();\n\n                Mid = new MidModel();\n                Leaf = new LeafModel();\n            }\n\n            public RootModel(BTypes.Dictionary encoded)\n                : base(encoded)\n            {\n            }\n\n            public bool Bool { get; private set; }\n\n            public int Int { get; private set; }\n\n            public long Long { get; private set; }\n\n            public BigInteger BigInt { get; private set; }\n\n            public ImmutableArray<byte> Bytes { get; private set; }\n\n            public Guid Guid { get; private set; }\n\n            public Address Addr { get; private set; }\n\n            public string Str { get; private set; }\n\n            public ImmutableList<int> ListEmpty { get; private set; }\n\n            public ImmutableList<bool> ListBool { get; private set; }\n\n            public ImmutableList<int> ListInt { get; private set; }\n\n            public ImmutableList<long> ListLong { get; private set; }\n\n            public ImmutableList<BigInteger> ListBigInt { get; private set; }\n\n            public ImmutableList<ImmutableArray<byte>> ListBytes { get; private set; }\n\n            public ImmutableList<Guid> ListGuid { get; private set; }\n\n            public ImmutableList<Address> ListAddr { get; private set; }\n\n            public ImmutableList<string> ListStr { get; private set; }\n\n            public ImmutableDictionary<string, string>\n                DictEmpty { get; private set; }\n\n            public ImmutableDictionary<ImmutableArray<byte>, bool>\n                DictBytesBool { get; private set; }\n\n            public ImmutableDictionary<ImmutableArray<byte>, int>\n                DictBytesInt { get; private set; }\n\n            public ImmutableDictionary<ImmutableArray<byte>, long>\n                DictBytesLong { get; private set; }\n\n            public ImmutableDictionary<ImmutableArray<byte>, BigInteger>\n                DictBytesBigInt { get; private set; }\n\n            public ImmutableDictionary<ImmutableArray<byte>, ImmutableArray<byte>>\n                DictBytesBytes { get; private set; }\n\n            public ImmutableDictionary<ImmutableArray<byte>, Address>\n                DictBytesAddr { get; private set; }\n\n            public ImmutableDictionary<ImmutableArray<byte>, string>\n                DictBytesStr { get; private set; }\n\n            public ImmutableDictionary<Guid, string>\n                DictGuidStr { get; private set; }\n\n            public ImmutableDictionary<Address, string>\n                DictAddrStr { get; private set; }\n\n            public ImmutableDictionary<string, string>\n                DictStrStr { get; private set; }\n\n            public MidModel Mid { get; private set; }\n\n            public LeafModel Leaf { get; private set; }\n        }\n\n        private class MidModel : DataModel\n        {\n            public MidModel()\n                : base()\n            {\n                System.Random random = new System.Random();\n                Bool = random.NextDouble() < 0.5;\n                Int = random.Next();\n                Str = Guid.NewGuid().ToString();\n                ListInt = new List<int>()\n                {\n                    random.Next(),\n                    random.Next(),\n                }.ToImmutableList();\n                Leaf = new LeafModel();\n            }\n\n            public MidModel(BTypes.Dictionary encoded)\n                : base(encoded)\n            {\n            }\n\n            public bool Bool { get; private set; }\n\n            public int Int { get; private set; }\n\n            public string Str { get; private set; }\n\n            public ImmutableList<int> ListInt { get; private set; }\n\n            public LeafModel Leaf { get; private set; }\n        }\n\n        private class LeafModel : DataModel\n        {\n            public LeafModel()\n                : base()\n            {\n                System.Random random = new System.Random();\n                Bool = random.NextDouble() < 0.5;\n                Int = random.Next();\n                Str = Guid.NewGuid().ToString();\n                DictStrStr = new Dictionary<string, string>()\n                {\n                    { Guid.NewGuid().ToString(), Guid.NewGuid().ToString() },\n                    { Guid.NewGuid().ToString(), Guid.NewGuid().ToString() },\n                }.ToImmutableDictionary();\n            }\n\n            public LeafModel(BTypes.Dictionary encoded)\n                : base(encoded)\n            {\n            }\n\n            public bool Bool { get; private set; }\n\n            public int Int { get; private set; }\n\n            public string Str { get; private set; }\n\n            public ImmutableDictionary<string, string> DictStrStr\n            {\n                get;\n                private set;\n            }\n        }\n\n        private class HasNullableBoolType : DataModel\n        {\n            public HasNullableBoolType()\n                : base()\n            {\n                Value = true;\n            }\n\n            public HasNullableBoolType(BTypes.Dictionary encoded)\n                : base(encoded)\n            {\n            }\n\n            public bool? Value { get; private set; }\n        }\n\n        private class HasNullableIntType : DataModel\n        {\n            public HasNullableIntType()\n                : base()\n            {\n                Value = 1;\n            }\n\n            public HasNullableIntType(BTypes.Dictionary encoded)\n                : base(encoded)\n            {\n            }\n\n            public int? Value { get; private set; }\n        }\n\n        private class HasNullableLongType : DataModel\n        {\n            public HasNullableLongType()\n                : base()\n            {\n                Value = 1;\n            }\n\n            public HasNullableLongType(BTypes.Dictionary encoded)\n                : base(encoded)\n            {\n            }\n\n            public long? Value { get; private set; }\n        }\n\n        private class HasNullableBigIntegerType : DataModel\n        {\n            public HasNullableBigIntegerType()\n                : base()\n            {\n                Value = 1;\n            }\n\n            public HasNullableBigIntegerType(BTypes.Dictionary encoded)\n                : base(encoded)\n            {\n            }\n\n            public BigInteger? Value { get; private set; }\n        }\n\n        private class HasNullableBytesType : DataModel\n        {\n            public HasNullableBytesType()\n                : base()\n            {\n                Value = new List<byte>() { 0, 1 }.ToImmutableArray();\n            }\n\n            public HasNullableBytesType(BTypes.Dictionary encoded)\n                : base(encoded)\n            {\n            }\n\n            public ImmutableArray<byte>? Value { get; private set; }\n        }\n\n        private class HasNullableGuidType : DataModel\n        {\n            public HasNullableGuidType()\n                : base()\n            {\n                Value = Guid.NewGuid();\n            }\n\n            public HasNullableGuidType(BTypes.Dictionary encoded)\n                : base(encoded)\n            {\n            }\n\n            public Guid? Value { get; private set; }\n        }\n\n        private class HasNullableAddressType : DataModel\n        {\n            public HasNullableAddressType()\n                : base()\n            {\n                Value = new Address(\"0000000000000000000000000000000000000001\");\n            }\n\n            public HasNullableAddressType(BTypes.Dictionary encoded)\n                : base(encoded)\n            {\n            }\n\n            public Address? Value { get; private set; }\n        }\n\n        private class HasNullableListValueType : DataModel\n        {\n            public HasNullableListValueType()\n                : base()\n            {\n                Value = new List<int?>() { 0, 1 }.ToImmutableList();\n            }\n\n            public HasNullableListValueType(BTypes.Dictionary encoded)\n                : base(encoded)\n            {\n            }\n\n            public ImmutableList<int?> Value { get; private set; }\n        }\n\n        private class HasInvalidListValueType : DataModel\n        {\n            public HasInvalidListValueType()\n                : base()\n            {\n                Value = new List<MidModel>()\n                {\n                    new MidModel(),\n                    new MidModel(),\n                }.ToImmutableList();\n            }\n\n            public HasInvalidListValueType(BTypes.Dictionary encoded)\n                : base(encoded)\n            {\n            }\n\n            public ImmutableList<MidModel> Value { get; private set; }\n        }\n\n        private class HasInvalidDictionaryKeyType : DataModel\n        {\n            public HasInvalidDictionaryKeyType()\n                : base()\n            {\n                Value = new Dictionary<int, int>()\n                {\n                    { 0, 1 },\n                    { 2, 3 },\n                }.ToImmutableDictionary();\n            }\n\n            public HasInvalidDictionaryKeyType(BTypes.Dictionary encoded)\n                : base(encoded)\n            {\n            }\n\n            public ImmutableDictionary<int, int> Value { get; private set; }\n        }\n\n        private class HasNullableDictionaryValueType : DataModel\n        {\n            public HasNullableDictionaryValueType()\n                : base()\n            {\n                Value = new Dictionary<string, int?>()\n                {\n                    { \"foo\", 0 },\n                    { \"bar\", 1 },\n                }.ToImmutableDictionary();\n            }\n\n            public HasNullableDictionaryValueType(BTypes.Dictionary encoded)\n                : base(encoded)\n            {\n            }\n\n            public ImmutableDictionary<string, int?> Value { get; private set; }\n        }\n\n        private class HasInvalidDictionaryValueType : DataModel\n        {\n            public HasInvalidDictionaryValueType()\n                : base()\n            {\n                Value = new Dictionary<string, MidModel>()\n                {\n                    { \"foo\", new MidModel() },\n                    { \"bar\", new MidModel() },\n                }.ToImmutableDictionary();\n            }\n\n            public HasInvalidDictionaryValueType(BTypes.Dictionary encoded)\n                : base(encoded)\n            {\n            }\n\n            public ImmutableDictionary<string, MidModel> Value { get; private set; }\n        }\n\n        private class HasNullReferencePropertyValue : DataModel\n        {\n            public HasNullReferencePropertyValue()\n                : base()\n            {\n                Value = null;\n            }\n\n            public HasNullReferencePropertyValue(BTypes.Dictionary encoded)\n                : base(encoded)\n            {\n            }\n\n            public string Value { get; private set; }\n        }\n\n        private class HasNullReferenceListValue : DataModel\n        {\n            public HasNullReferenceListValue()\n                : base()\n            {\n                Value = new List<string>() { \"foo\", null, \"bar\" }.ToImmutableList();\n            }\n\n            public HasNullReferenceListValue(BTypes.Dictionary encoded)\n                : base(encoded)\n            {\n            }\n\n            public ImmutableList<string> Value { get; private set; }\n        }\n\n        private class HasNullReferenceDictValue : DataModel\n        {\n            public HasNullReferenceDictValue()\n                : base()\n            {\n                Value = new Dictionary<string, string>()\n                {\n                    { \"foo\", \"bar\" },\n                    { \"lorem\", null },\n                }.ToImmutableDictionary();\n            }\n\n            public HasNullReferenceDictValue(BTypes.Dictionary encoded)\n                : base(encoded)\n            {\n            }\n\n            public ImmutableDictionary<string, string> Value { get; private set; }\n        }\n\n        private class IntWrapper : DataModel\n        {\n            public IntWrapper(int value)\n                : base()\n            {\n                Value = value;\n            }\n\n            public IntWrapper(BTypes.Dictionary encoded)\n                : base(encoded)\n            {\n            }\n\n            public int Value { get; private set; }\n        }\n\n        private class BytesWrapper : DataModel\n        {\n            public BytesWrapper(ImmutableArray<byte> value)\n                : base()\n            {\n                Value = value;\n            }\n\n            public BytesWrapper(BTypes.Dictionary encoded)\n                : base(encoded)\n            {\n            }\n\n            public ImmutableArray<byte> Value { get; private set; }\n        }\n\n        private class GuidWrapper : DataModel\n        {\n            public GuidWrapper(Guid value)\n                : base()\n            {\n                Value = value;\n            }\n\n            public GuidWrapper(BTypes.Dictionary encoded)\n                : base(encoded)\n            {\n            }\n\n            public Guid Value { get; private set; }\n        }\n\n        private class AddressWrapper : DataModel\n        {\n            public AddressWrapper(Address value)\n                : base()\n            {\n                Value = value;\n            }\n\n            public AddressWrapper(BTypes.Dictionary encoded)\n                : base(encoded)\n            {\n            }\n\n            public Address Value { get; private set; }\n        }\n\n        private class StrWrapper : DataModel\n        {\n            public StrWrapper(string value)\n                : base()\n            {\n                Value = value;\n            }\n\n            public StrWrapper(BTypes.Dictionary encoded)\n                : base(encoded)\n            {\n            }\n\n            public string Value { get; private set; }\n        }\n\n        private class ListIntWrapper : DataModel\n        {\n            public ListIntWrapper(List<int> value)\n                : base()\n            {\n                Value = value.ToImmutableList();\n            }\n\n            public ListIntWrapper(BTypes.Dictionary encoded)\n                : base(encoded)\n            {\n            }\n\n            public ImmutableList<int> Value { get; private set; }\n        }\n\n        private class DictStrIntWrapper : DataModel\n        {\n            public DictStrIntWrapper(Dictionary<string, int> value)\n                : base()\n            {\n                Value = value.ToImmutableDictionary();\n            }\n\n            public DictStrIntWrapper(BTypes.Dictionary encoded)\n                : base(encoded)\n            {\n            }\n\n            public ImmutableDictionary<string, int> Value { get; private set; }\n        }\n    }\n}\n"
  },
  {
    "path": "test/Libplanet.Tests/Store/DefaultStoreFixture.cs",
    "content": "using System;\nusing System.IO;\nusing Libplanet.Action;\nusing Libplanet.Store;\nusing Libplanet.Store.Trie;\n\nnamespace Libplanet.Tests.Store\n{\n    public class DefaultStoreFixture : StoreFixture, IDisposable\n    {\n        public DefaultStoreFixture(\n            bool memory = true,\n            IPolicyActionsRegistry policyActionsRegistry = null)\n            : base(policyActionsRegistry)\n        {\n            if (memory)\n            {\n                Path = null;\n            }\n            else\n            {\n                Path = System.IO.Path.Combine(\n                    System.IO.Path.GetTempPath(),\n                    $\"defaultstore_test_{Guid.NewGuid()}\"\n                );\n            }\n\n            Scheme = \"default+file://\";\n\n            var store = new DefaultStore(Path, blockCacheSize: 2, txCacheSize: 2);\n            Store = store;\n            StateStore = LoadTrieStateStore(Path);\n        }\n\n        public IStateStore LoadTrieStateStore(string path)\n        {\n            IKeyValueStore stateKeyValueStore =\n                new DefaultKeyValueStore(path is null\n                    ? null\n                    : System.IO.Path.Combine(path, \"states\"));\n            return new TrieStateStore(stateKeyValueStore);\n        }\n\n        public override void Dispose()\n        {\n            Store?.Dispose();\n            StateStore?.Dispose();\n\n            if (!(Path is null))\n            {\n                Directory.Delete(Path, true);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "test/Libplanet.Tests/Store/DefaultStoreTest.cs",
    "content": "using System;\nusing System.IO;\nusing Libplanet.Store;\nusing Libplanet.Store.Trie;\nusing Xunit;\nusing Xunit.Abstractions;\n\nnamespace Libplanet.Tests.Store\n{\n    public class DefaultStoreTest : StoreTest, IDisposable\n    {\n        private readonly DefaultStoreFixture _fx;\n\n        public DefaultStoreTest(ITestOutputHelper testOutputHelper)\n        {\n            TestOutputHelper = testOutputHelper;\n            Fx = _fx = new DefaultStoreFixture(memory: false);\n            FxConstructor = () => new DefaultStoreFixture(memory: false);\n        }\n\n        protected override ITestOutputHelper TestOutputHelper { get; }\n\n        protected override StoreFixture Fx { get; }\n\n        protected override Func<StoreFixture> FxConstructor { get; }\n\n        public void Dispose()\n        {\n            _fx?.Dispose();\n        }\n\n        [Fact]\n        public void ConstructorAcceptsRelativePath()\n        {\n            string tmpDir = System.IO.Path.GetTempPath();\n            string dirName = $\"defaultstore_{Guid.NewGuid()}\";\n            string cwd = Directory.GetCurrentDirectory();\n            IStore store;\n            try\n            {\n                Directory.SetCurrentDirectory(tmpDir);\n                store = new DefaultStore(dirName);\n                store.PutTransaction(Fx.Transaction1);\n            }\n            finally\n            {\n                Directory.SetCurrentDirectory(cwd);\n            }\n\n            // If CWD is changed after DefaultStore instance was created\n            // the instance should work as it had been.\n            store.PutTransaction(Fx.Transaction2);\n\n            // The following `identicalStore' instance should be identical to\n            // the `store' instance above, i.e., views the same data.\n            var identicalStore = new DefaultStore(Path.Combine(tmpDir, dirName));\n            Assert.Equal(\n                Fx.Transaction1,\n                identicalStore.GetTransaction(Fx.Transaction1.Id)\n            );\n            Assert.Equal(\n                Fx.Transaction2,\n                identicalStore.GetTransaction(Fx.Transaction2.Id)\n            );\n        }\n\n        [Fact]\n        public void Loader()\n        {\n            // TODO: Test query parameters as well.\n            string tempDirPath = Path.GetTempFileName();\n            File.Delete(tempDirPath);\n            var uri = new Uri(tempDirPath, UriKind.Absolute);\n            uri = new Uri(\"default+\" + uri);\n            (IStore Store, IStateStore StateStore)? pair = StoreLoaderAttribute.LoadStore(uri);\n            Assert.NotNull(pair);\n            IStore store = pair.Value.Store;\n            Assert.IsAssignableFrom<DefaultStore>(store);\n            var stateStore = (TrieStateStore)pair.Value.StateStore;\n            Assert.IsAssignableFrom<DefaultKeyValueStore>(stateStore.StateKeyValueStore);\n        }\n    }\n}\n"
  },
  {
    "path": "test/Libplanet.Tests/Store/MemoryStoreFixture.cs",
    "content": "using Libplanet.Action;\nusing Libplanet.Store;\nusing Libplanet.Store.Trie;\n\nnamespace Libplanet.Tests.Store\n{\n    public class MemoryStoreFixture : StoreFixture\n    {\n        public MemoryStoreFixture(\n            IPolicyActionsRegistry policyActionsRegistry = null)\n            : base(policyActionsRegistry)\n        {\n            Store = new MemoryStore();\n            StateStore = new TrieStateStore(new MemoryKeyValueStore());\n        }\n\n        public override void Dispose()\n        {\n            Store?.Dispose();\n            StateStore?.Dispose();\n        }\n    }\n}\n"
  },
  {
    "path": "test/Libplanet.Tests/Store/MemoryStoreTest.cs",
    "content": "using System;\nusing Libplanet.Store;\nusing Libplanet.Store.Trie;\nusing Xunit;\nusing Xunit.Abstractions;\n\nnamespace Libplanet.Tests.Store\n{\n    public class MemoryStoreTest : StoreTest, IDisposable\n    {\n        public MemoryStoreTest(ITestOutputHelper testOutputHelper)\n        {\n            TestOutputHelper = testOutputHelper;\n            Fx = new MemoryStoreFixture();\n            FxConstructor = () => new MemoryStoreFixture();\n        }\n\n        protected override ITestOutputHelper TestOutputHelper { get; }\n\n        protected override StoreFixture Fx { get; }\n\n        protected override Func<StoreFixture> FxConstructor { get; }\n\n        [Theory]\n        [InlineData(\"memory:\")]\n        [InlineData(\"memory://\")]\n        public void Loader(string uri)\n        {\n            (IStore Store, IStateStore StateStore)? pair =\n                StoreLoaderAttribute.LoadStore(new Uri(uri));\n            Assert.NotNull(pair);\n            IStore store = pair.Value.Store;\n            Assert.IsAssignableFrom<MemoryStore>(store);\n            var stateStore = (TrieStateStore)pair.Value.StateStore;\n            Assert.IsAssignableFrom<MemoryKeyValueStore>(stateStore.StateKeyValueStore);\n        }\n\n        public void Dispose()\n        {\n            Fx?.Dispose();\n        }\n    }\n}\n"
  },
  {
    "path": "test/Libplanet.Tests/Store/ProxyStore.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing Libplanet.Crypto;\nusing Libplanet.Store;\nusing Libplanet.Types.Blocks;\nusing Libplanet.Types.Evidence;\nusing Libplanet.Types.Tx;\n\nnamespace Libplanet.Tests.Store\n{\n    /// <summary>\n    /// An thin <see cref=\"IStore\"/> implementation that forwards all method calls to the actual\n    /// <see cref=\"Store\"/> implementation.  As this purposes to override only few parts of\n    /// an existing <see cref=\"Store\"/> implementation with maintaining the rest of methods,\n    /// its all methods are declared as <c>virtual</c>.\n    /// </summary>\n    public abstract class ProxyStore : IStore\n    {\n        /// <summary>\n        /// Creates a new <see cref=\"ProxyStore\"/> instance with the given actual\n        /// <paramref name=\"store\"/> implementation.\n        /// </summary>\n        /// <param name=\"store\">The actual <see cref=\"IStore\"/> implementation.</param>\n        protected ProxyStore(IStore store)\n        {\n            Store = store;\n        }\n\n        /// <summary>\n        /// The actual <see cref=\"IStore\"/> implementation.\n        /// </summary>\n        public IStore Store { get; }\n\n        /// <inheritdoc cref=\"IStore.Dispose()\"/>\n        public virtual void Dispose() =>\n            Store.Dispose();\n\n        /// <inheritdoc cref=\"IStore.ListChainIds()\"/>\n        public virtual IEnumerable<Guid> ListChainIds() =>\n            Store.ListChainIds();\n\n        /// <inheritdoc cref=\"IStore.DeleteChainId(Guid)\"/>\n        public virtual void DeleteChainId(Guid chainId) =>\n            Store.DeleteChainId(chainId);\n\n        /// <inheritdoc cref=\"IStore.GetCanonicalChainId()\"/>\n        public virtual Guid? GetCanonicalChainId() =>\n            Store.GetCanonicalChainId();\n\n        /// <inheritdoc cref=\"IStore.SetCanonicalChainId(Guid)\"/>\n        public virtual void SetCanonicalChainId(Guid chainId) =>\n            Store.SetCanonicalChainId(chainId);\n\n        /// <inheritdoc cref=\"IStore.CountIndex(Guid)\"/>\n        public virtual long CountIndex(Guid chainId) =>\n            Store.CountIndex(chainId);\n\n        /// <inheritdoc cref=\"IStore.IterateIndexes(Guid, int, int?)\"/>\n        public virtual IEnumerable<BlockHash> IterateIndexes(\n            Guid chainId,\n            int offset = 0,\n            int? limit = null\n        ) =>\n            Store.IterateIndexes(chainId, offset, limit);\n\n        /// <inheritdoc cref=\"IStore.IndexBlockHash(Guid, long)\"/>\n        public virtual BlockHash? IndexBlockHash(Guid chainId, long index) =>\n            Store.IndexBlockHash(chainId, index);\n\n        /// <inheritdoc cref=\"IStore.AppendIndex(Guid, BlockHash)\"/>\n        public virtual long AppendIndex(Guid chainId, BlockHash hash) =>\n            Store.AppendIndex(chainId, hash);\n\n        /// <inheritdoc cref=\"IStore.ForkBlockIndexes(Guid, Guid, BlockHash)\"/>\n        public virtual void ForkBlockIndexes(\n            Guid sourceChainId,\n            Guid destinationChainId,\n            BlockHash branchpoint\n        ) =>\n            Store.ForkBlockIndexes(sourceChainId, destinationChainId, branchpoint);\n\n        /// <inheritdoc cref=\"IStore.GetTransaction(TxId)\"/>\n        public virtual Transaction GetTransaction(TxId txid) =>\n            Store.GetTransaction(txid);\n\n        /// <inheritdoc cref=\"IStore.GetTransaction(TxId)\"/>\n        public virtual void PutTransaction(Transaction tx) =>\n            Store.PutTransaction(tx);\n\n        /// <inheritdoc cref=\"IStore.IterateBlockHashes()\"/>\n        public virtual IEnumerable<BlockHash> IterateBlockHashes() =>\n            Store.IterateBlockHashes();\n\n        /// <inheritdoc cref=\"IStore.GetBlock{T}\"/>\n        public virtual Block GetBlock(BlockHash blockHash) =>\n            Store.GetBlock(blockHash);\n\n        /// <inheritdoc cref=\"IStore.GetBlockIndex(BlockHash)\"/>\n        public virtual long? GetBlockIndex(BlockHash blockHash) =>\n            Store.GetBlockIndex(blockHash);\n\n        /// <inheritdoc cref=\"IStore.GetBlockDigest(BlockHash)\"/>\n        public virtual BlockDigest? GetBlockDigest(BlockHash blockHash) =>\n            Store.GetBlockDigest(blockHash);\n\n        /// <inheritdoc cref=\"IStore.PutBlock{T}(Block{T})\"/>\n        public virtual void PutBlock(Block block) =>\n            Store.PutBlock(block);\n\n        /// <inheritdoc cref=\"IStore.DeleteBlock(BlockHash)\"/>\n        public virtual bool DeleteBlock(BlockHash blockHash) =>\n            Store.DeleteBlock(blockHash);\n\n        /// <inheritdoc cref=\"IStore.ContainsBlock(BlockHash)\"/>\n        public virtual bool ContainsBlock(BlockHash blockHash) =>\n            Store.ContainsBlock(blockHash);\n\n        /// <inheritdoc cref=\"IStore.PutTxExecution\"/>\n        public virtual void PutTxExecution(TxExecution txExecution) =>\n            Store.PutTxExecution(txExecution);\n\n        /// <inheritdoc cref=\"IStore.GetTxExecution(BlockHash, TxId)\"/>\n        public virtual TxExecution GetTxExecution(BlockHash blockHash, TxId txid) =>\n            Store.GetTxExecution(blockHash, txid);\n\n        /// <inheritdoc cref=\"IStore.PutTxIdBlockHashIndex(TxId, BlockHash)\"/>\n        public virtual void PutTxIdBlockHashIndex(TxId txId, BlockHash blockHash) =>\n            Store.PutTxIdBlockHashIndex(txId, blockHash);\n\n        /// <inheritdoc cref=\"IStore.GetFirstTxIdBlockHashIndex(TxId)\"/>\n        public virtual BlockHash? GetFirstTxIdBlockHashIndex(TxId txId) =>\n            Store.GetFirstTxIdBlockHashIndex(txId);\n\n        /// <inheritdoc cref=\"IStore.IterateTxIdBlockHashIndex(TxId)\"/>\n        public virtual IEnumerable<BlockHash> IterateTxIdBlockHashIndex(TxId txId) =>\n            Store.IterateTxIdBlockHashIndex(txId);\n\n        /// <inheritdoc cref=\"IStore.DeleteTxIdBlockHashIndex(TxId, BlockHash)\"/>\n        public virtual void DeleteTxIdBlockHashIndex(TxId txId, BlockHash blockHash) =>\n            Store.DeleteTxIdBlockHashIndex(txId, blockHash);\n\n        /// <inheritdoc cref=\"IStore.ListTxNonces(Guid)\"/>\n        public virtual IEnumerable<KeyValuePair<Address, long>> ListTxNonces(Guid chainId) =>\n            Store.ListTxNonces(chainId);\n\n        /// <inheritdoc cref=\"IStore.GetTxNonce(Guid, Address)\"/>\n        public virtual long GetTxNonce(Guid chainId, Address address) =>\n            Store.GetTxNonce(chainId, address);\n\n        /// <inheritdoc cref=\"IStore.IncreaseTxNonce(Guid, Address, long)\"/>\n        public virtual void IncreaseTxNonce(Guid chainId, Address signer, long delta = 1) =>\n            Store.IncreaseTxNonce(chainId, signer, delta);\n\n        /// <inheritdoc cref=\"IStore.ContainsTransaction(TxId)\"/>\n        public virtual bool ContainsTransaction(TxId txId) =>\n            Store.ContainsTransaction(txId);\n\n        /// <inheritdoc cref=\"IStore.CountBlocks()\"/>\n        public virtual long CountBlocks() =>\n            Store.CountBlocks();\n\n        /// <inheritdoc cref=\"IStore.ForkTxNonces(Guid, Guid)\"/>\n        public virtual void ForkTxNonces(Guid sourceChainId, Guid destinationChainId) =>\n            Store.ForkTxNonces(sourceChainId, destinationChainId);\n\n        /// <inheritdoc cref=\"IStore.PruneOutdatedChains(bool)\"/>\n        public void PruneOutdatedChains(bool noopWithoutCanon = false) =>\n            Store.PruneOutdatedChains(noopWithoutCanon);\n\n        /// <inheritdoc cref=\"IStore.GetChainBlockCommit\" />\n        public BlockCommit GetChainBlockCommit(Guid chainId) =>\n            Store.GetChainBlockCommit(chainId);\n\n        /// <inheritdoc cref=\"IStore.PutChainBlockCommit\" />\n        public void PutChainBlockCommit(Guid chainId, BlockCommit blockCommit) =>\n            Store.PutChainBlockCommit(chainId, blockCommit);\n\n        /// <inheritdoc cref=\"IStore.GetBlockCommit\"/>\n        public BlockCommit GetBlockCommit(BlockHash blockHash) =>\n            Store.GetBlockCommit(blockHash);\n\n        /// <inheritdoc cref=\"IStore.PutBlockCommit\"/>\n        public void PutBlockCommit(BlockCommit blockCommit) =>\n            Store.PutBlockCommit(blockCommit);\n\n        /// <inheritdoc cref=\"IStore.DeleteBlockCommit\"/>\n        public void DeleteBlockCommit(BlockHash blockHash) =>\n            Store.DeleteBlockCommit(blockHash);\n\n        /// <inheritdoc cref=\"IStore.GetBlockCommitHashes\"/>\n        public IEnumerable<BlockHash> GetBlockCommitHashes() =>\n            Store.GetBlockCommitHashes();\n\n        public IEnumerable<EvidenceId> IteratePendingEvidenceIds() =>\n            Store.IteratePendingEvidenceIds();\n\n        public EvidenceBase GetPendingEvidence(EvidenceId evidenceId) =>\n            Store.GetPendingEvidence(evidenceId);\n\n        public EvidenceBase GetCommittedEvidence(EvidenceId evidenceId) =>\n            Store.GetCommittedEvidence(evidenceId);\n\n        public void PutPendingEvidence(EvidenceBase evidence) =>\n            Store.PutPendingEvidence(evidence);\n\n        public void PutCommittedEvidence(EvidenceBase evidence) =>\n            Store.PutCommittedEvidence(evidence);\n\n        public void DeletePendingEvidence(EvidenceId evidenceId) =>\n            Store.DeletePendingEvidence(evidenceId);\n\n        public void DeleteCommittedEvidence(EvidenceId evidenceId) =>\n            Store.DeleteCommittedEvidence(evidenceId);\n\n        public bool ContainsPendingEvidence(EvidenceId evidenceId) =>\n            Store.ContainsPendingEvidence(evidenceId);\n\n        public bool ContainsCommittedEvidence(EvidenceId evidenceId) =>\n            Store.ContainsCommittedEvidence(evidenceId);\n    }\n}\n"
  },
  {
    "path": "test/Libplanet.Tests/Store/StateStoreTracker.cs",
    "content": "using System.Security.Cryptography;\nusing Libplanet.Common;\nusing Libplanet.Store;\nusing Libplanet.Store.Trie;\n\nnamespace Libplanet.Tests.Store\n{\n    public sealed class StateStoreTracker : BaseTracker, IStateStore\n    {\n        private readonly IStateStore _stateStore;\n        private bool _disposed = false;\n\n        public StateStoreTracker(IStateStore stateStore)\n        {\n            _stateStore = stateStore;\n        }\n\n        public ITrie GetStateRoot(HashDigest<SHA256>? stateRootHash)\n        {\n            Log(nameof(GetStateRoot), stateRootHash);\n            return _stateStore.GetStateRoot(stateRootHash);\n        }\n\n        public ITrie Commit(ITrie trie)\n        {\n            Log(nameof(Commit), trie.Hash);\n            return _stateStore.Commit(trie);\n        }\n\n        public void Dispose()\n        {\n            if (!_disposed)\n            {\n                _stateStore?.Dispose();\n                _disposed = true;\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "test/Libplanet.Tests/Store/StoreFixture.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Numerics;\nusing System.Security.Cryptography;\nusing Libplanet.Action;\nusing Libplanet.Action.Loader;\nusing Libplanet.Action.Tests.Common;\nusing Libplanet.Common;\nusing Libplanet.Crypto;\nusing Libplanet.Store;\nusing Libplanet.Store.Trie;\nusing Libplanet.Types.Blocks;\nusing Libplanet.Types.Tx;\n\nnamespace Libplanet.Tests.Store\n{\n    public abstract class StoreFixture : IDisposable\n    {\n        protected StoreFixture(IPolicyActionsRegistry policyActionsRegistry = null)\n        {\n            Path = null;\n\n            Scheme = string.Empty;\n\n            StoreChainId = Guid.NewGuid();\n\n            Address1 = new Address(new byte[]\n            {\n                0x45, 0xa2, 0x21, 0x87, 0xe2, 0xd8, 0x85, 0x0b, 0xb3, 0x57,\n                0x88, 0x69, 0x58, 0xbc, 0x3e, 0x85, 0x60, 0x92, 0x9c, 0xcc,\n            });\n            Address2 = new Address(new byte[]\n            {\n                0x55, 0xa2, 0x21, 0x87, 0xe2, 0xd8, 0x85, 0x0b, 0xb3, 0x57,\n                0x88, 0x69, 0x58, 0xbc, 0x3e, 0x85, 0x60, 0x92, 0x9c, 0xdd,\n            });\n            Address3 = new Address(new byte[]\n            {\n                0xa3, 0x4b, 0x0c, 0x91, 0xda, 0x58, 0xd4, 0x73, 0xd3, 0x70,\n                0xc4, 0x5b, 0xf9, 0x6f, 0x6d, 0x98, 0xa5, 0x01, 0xd9, 0x22,\n            });\n            Address4 = new Address(new byte[]\n            {\n                0xbf, 0x78, 0x67, 0x29, 0xba, 0x04, 0x1b, 0xa7, 0x6f, 0xfb,\n                0xa0, 0x6c, 0x8c, 0x4d, 0xc1, 0x24, 0xee, 0x3e, 0x8c, 0x8b,\n            });\n            Address5 = new Address(new byte[]\n            {\n                0x03, 0xf0, 0x42, 0x7f, 0x2e, 0x6c, 0x0f, 0x5f, 0xdb, 0xd3,\n                0x77, 0x9d, 0xb2, 0x84, 0xd6, 0x1b, 0x04, 0x38, 0xdf, 0xb6,\n            });\n            TxId1 = new TxId(new byte[]\n            {\n                0x45, 0xa2, 0x21, 0x87, 0xe2, 0xd8, 0x85, 0x0b, 0xb3, 0x57,\n                0x88, 0x69, 0x58, 0xbc, 0x3e, 0x85, 0x60, 0x92, 0x9c, 0xcc,\n                0x88, 0x69, 0x58, 0xbc, 0x3e, 0x85, 0x60, 0x92, 0x9c, 0xcc,\n                0x9c, 0xcc,\n            });\n            TxId2 = new TxId(new byte[]\n            {\n                0x45, 0xa2, 0x21, 0x87, 0xe2, 0xd8, 0x85, 0x0b, 0xb3, 0x57,\n                0x88, 0x69, 0x58, 0xbc, 0x3e, 0x85, 0x60, 0x92, 0x9c, 0xcc,\n                0x88, 0x69, 0x58, 0xbc, 0x3e, 0x85, 0x60, 0x92, 0x9c, 0xcc,\n                0x9c, 0xdd,\n            });\n            TxId3 = new TxId(new byte[]\n            {\n                0x45, 0xa2, 0x21, 0x87, 0xe2, 0xd8, 0x85, 0x0b, 0xb3, 0x57,\n                0x88, 0x69, 0x58, 0xbc, 0x3e, 0x85, 0x60, 0x92, 0x9c, 0xcc,\n                0x88, 0x69, 0x58, 0xbc, 0x3e, 0x85, 0x60, 0x92, 0x9c, 0xcc,\n                0x9c, 0xee,\n            });\n            Hash1 = new BlockHash(new byte[]\n            {\n                0x45, 0xa2, 0x21, 0x87, 0xe2, 0xd8, 0x85, 0x0b, 0xb3, 0x57,\n                0x88, 0x69, 0x58, 0xbc, 0x3e, 0x85, 0x60, 0x92, 0x9c, 0xcc,\n                0x88, 0x69, 0x58, 0xbc, 0x3e, 0x85, 0x60, 0x92, 0x9c, 0xcc,\n                0x9c, 0xcc,\n            });\n            Hash2 = new BlockHash(new byte[]\n            {\n                0x45, 0xa2, 0x21, 0x87, 0xe2, 0xd8, 0x85, 0x0b, 0xb3, 0x57,\n                0x88, 0x69, 0x58, 0xbc, 0x3e, 0x85, 0x60, 0x92, 0x9c, 0xcc,\n                0x88, 0x69, 0x58, 0xbc, 0x3e, 0x85, 0x60, 0x92, 0x9c, 0xcc,\n                0x9c, 0xdd,\n            });\n            Hash3 = new BlockHash(new byte[]\n            {\n                0x45, 0xa2, 0x21, 0x87, 0xe2, 0xd8, 0x85, 0x0b, 0xb3, 0x57,\n                0x88, 0x69, 0x58, 0xbc, 0x3e, 0x85, 0x60, 0x92, 0x9c, 0xcc,\n                0x88, 0x69, 0x58, 0xbc, 0x3e, 0x85, 0x60, 0x92, 0x9c, 0xcc,\n                0x9c, 0xee,\n            });\n\n            var stateStore = new TrieStateStore(new MemoryKeyValueStore());\n            var stateRootHashes = new Dictionary<BlockHash, HashDigest<SHA256>>();\n            Proposer = TestUtils.GenesisProposer;\n            ProposerPower = TestUtils.ValidatorSet[0].Power;\n            var preEval = TestUtils.ProposeGenesis(\n                proposer: Proposer.PublicKey,\n                validatorSet: TestUtils.ValidatorSet);\n            var actionEvaluator = new ActionEvaluator(\n                policyActionsRegistry ?? new PolicyActionsRegistry(),\n                stateStore,\n                new SingleActionLoader(typeof(DumbAction)));\n            GenesisBlock = preEval.Sign(\n                Proposer,\n                MerkleTrie.EmptyRootHash);\n            stateRootHashes[GenesisBlock.Hash] = GenesisBlock.StateRootHash;\n            var genesisNextSrh = actionEvaluator.Evaluate(\n                GenesisBlock, GenesisBlock.StateRootHash).Last().OutputState;\n            Block1 = TestUtils.ProposeNextBlock(\n                GenesisBlock,\n                miner: Proposer,\n                stateRootHash: genesisNextSrh,\n                lastCommit: null);\n            stateRootHashes[Block1.Hash] = Block1.StateRootHash;\n            Block2 = TestUtils.ProposeNextBlock(\n                Block1,\n                miner: Proposer,\n                stateRootHash: genesisNextSrh,\n                lastCommit: TestUtils.CreateBlockCommit(Block1));\n            stateRootHashes[Block2.Hash] = Block2.StateRootHash;\n            Block3 = TestUtils.ProposeNextBlock(\n                Block2,\n                miner: Proposer,\n                stateRootHash: genesisNextSrh,\n                lastCommit: TestUtils.CreateBlockCommit(Block2));\n            stateRootHashes[Block3.Hash] = Block3.StateRootHash;\n            Block3Alt = TestUtils.ProposeNextBlock(\n                Block2, miner: Proposer, stateRootHash: genesisNextSrh);\n            stateRootHashes[Block3Alt.Hash] = Block3Alt.StateRootHash;\n            Block4 = TestUtils.ProposeNextBlock(\n                Block3, miner: Proposer, stateRootHash: genesisNextSrh);\n            stateRootHashes[Block4.Hash] = Block4.StateRootHash;\n            Block5 = TestUtils.ProposeNextBlock(\n                Block4, miner: Proposer, stateRootHash: genesisNextSrh);\n            stateRootHashes[Block5.Hash] = Block5.StateRootHash;\n\n            Transaction1 = MakeTransaction(new List<DumbAction>());\n            Transaction2 = MakeTransaction(new List<DumbAction>());\n            Transaction3 = MakeTransaction(new List<DumbAction>());\n        }\n\n        public string Path { get; set; }\n\n        public string Scheme { get; set; }\n\n        public Guid StoreChainId { get; }\n\n        public Address Address1 { get; }\n\n        public Address Address2 { get; }\n\n        public Address Address3 { get; }\n\n        public Address Address4 { get; }\n\n        public Address Address5 { get; }\n\n        public TxId TxId1 { get; }\n\n        public TxId TxId2 { get; }\n\n        public TxId TxId3 { get; }\n\n        public BlockHash Hash1 { get; }\n\n        public BlockHash Hash2 { get; }\n\n        public BlockHash Hash3 { get; }\n\n        public PrivateKey Proposer { get; }\n\n        public BigInteger ProposerPower { get; }\n\n        public Block GenesisBlock { get; }\n\n        public Block Block1 { get; }\n\n        public Block Block2 { get; }\n\n        public Block Block3 { get; }\n\n        public Block Block3Alt { get; }\n\n        public Block Block4 { get; }\n\n        public Block Block5 { get; }\n\n        public Transaction Transaction1 { get; }\n\n        public Transaction Transaction2 { get; }\n\n        public Transaction Transaction3 { get; }\n\n        public IStore Store { get; set; }\n\n        public IStateStore StateStore { get; set; }\n\n        public IKeyValueStore StateHashKeyValueStore { get; set; }\n\n        public IKeyValueStore StateKeyValueStore { get; set; }\n\n        public abstract void Dispose();\n\n        public Transaction MakeTransaction(\n            IEnumerable<DumbAction> actions = null,\n            long nonce = 0,\n            PrivateKey privateKey = null,\n            DateTimeOffset? timestamp = null\n        )\n        {\n            privateKey = privateKey ?? new PrivateKey();\n            timestamp = timestamp ?? DateTimeOffset.UtcNow;\n\n            return Transaction.Create(\n                nonce,\n                privateKey,\n                GenesisBlock.Hash,\n                actions?.ToPlainValues() ?? Array.Empty<DumbAction>().ToPlainValues(),\n                null,\n                null,\n                timestamp\n            );\n        }\n    }\n}\n"
  },
  {
    "path": "test/Libplanet.Tests/Store/StoreLoaderAttributeTest.cs",
    "content": "using System;\nusing System.Collections.Specialized;\n#if !NETFRAMEWORK\nusing static System.Web.HttpUtility;\n#endif\nusing Libplanet.Store;\nusing Libplanet.Store.Trie;\n#if NETFRAMEWORK\nusing static Mono.Web.HttpUtility;\n#endif\nusing Xunit;\n\nnamespace Libplanet.Tests.Store\n{\n    public class StoreLoaderAttributeTest\n    {\n        [Fact]\n        public void Constructor()\n        {\n            var attr = new StoreLoaderAttribute(\"Test\");\n            Assert.Equal(\"test\", attr.UriScheme);\n        }\n\n        [Fact]\n        public void ListStoreLoaders()\n        {\n            Assert.Contains(\n                StoreLoaderAttribute.ListStoreLoaders(),\n                pair => pair.UriScheme == \"test\" &&\n                    pair.DeclaringType == typeof(StoreLoaderAttributeTest)\n            );\n            Assert.DoesNotContain(\n                StoreLoaderAttribute.ListStoreLoaders(),\n                pair => pair.UriScheme == \"non-existent\"\n            );\n        }\n\n        [Fact]\n        public void LoadStore()\n        {\n            Assert.Null(StoreLoaderAttribute.LoadStore(new Uri(\"non-existent+test://\")));\n            (IStore Store, IStateStore StateStore)? pair =\n                StoreLoaderAttribute.LoadStore(new Uri(\"test:///\"));\n            Assert.NotNull(pair);\n            Assert.IsAssignableFrom<MemoryStore>(pair.Value.Store);\n            Assert.IsAssignableFrom<TrieStateStore>(pair.Value.StateStore);\n        }\n\n        [StoreLoader(\"test\")]\n        private static (IStore Store, IStateStore StateStore) TestLoader(Uri storeUri)\n        {\n            NameValueCollection query = ParseQueryString(storeUri.Query);\n            var store = new MemoryStore();\n            var stateStore = new TrieStateStore(new MemoryKeyValueStore());\n            return (store, stateStore);\n        }\n    }\n}\n"
  },
  {
    "path": "test/Libplanet.Tests/Store/StoreTest.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Collections.Immutable;\nusing System.Linq;\nusing System.Numerics;\nusing System.Security.Cryptography;\nusing System.Threading.Tasks;\nusing Bencodex.Types;\nusing Libplanet.Action;\nusing Libplanet.Action.Loader;\nusing Libplanet.Action.State;\nusing Libplanet.Action.Tests.Common;\nusing Libplanet.Blockchain;\nusing Libplanet.Blockchain.Policies;\nusing Libplanet.Common;\nusing Libplanet.Crypto;\nusing Libplanet.Store;\nusing Libplanet.Store.Trie;\nusing Libplanet.Types.Blocks;\nusing Libplanet.Types.Consensus;\nusing Libplanet.Types.Evidence;\nusing Libplanet.Types.Tx;\nusing Serilog;\nusing Xunit;\nusing Xunit.Abstractions;\nusing static Libplanet.Tests.TestUtils;\n\nnamespace Libplanet.Tests.Store\n{\n    public abstract class StoreTest\n    {\n        private ILogger _logger = null;\n\n        protected abstract ITestOutputHelper TestOutputHelper { get; }\n\n        protected abstract StoreFixture Fx { get; }\n\n        protected abstract Func<StoreFixture> FxConstructor { get; }\n\n        protected ILogger Logger => _logger ?? (\n            _logger = new LoggerConfiguration()\n                .MinimumLevel.Verbose()\n                .WriteTo.TestOutput(TestOutputHelper)\n                .CreateLogger()\n                .ForContext(this.GetType()));\n\n        [SkippableFact]\n        public void ListChainId()\n        {\n            Assert.Empty(Fx.Store.ListChainIds());\n\n            Fx.Store.PutBlock(Fx.Block1);\n            Fx.Store.AppendIndex(Fx.StoreChainId, Fx.Block1.Hash);\n            Assert.Equal(\n                new[] { Fx.StoreChainId }.ToImmutableHashSet(),\n                Fx.Store.ListChainIds().ToImmutableHashSet()\n            );\n\n            Guid arbitraryGuid = Guid.NewGuid();\n            Fx.Store.AppendIndex(arbitraryGuid, Fx.Block1.Hash);\n            Assert.Equal(\n                new[] { Fx.StoreChainId, arbitraryGuid }.ToImmutableHashSet(),\n                Fx.Store.ListChainIds().ToImmutableHashSet()\n            );\n        }\n\n        [SkippableFact]\n        public void ListChainIdAfterForkAndDelete()\n        {\n            var chainA = Guid.NewGuid();\n            var chainB = Guid.NewGuid();\n\n            Fx.Store.PutBlock(Fx.GenesisBlock);\n            Fx.Store.PutBlock(Fx.Block1);\n            Fx.Store.PutBlock(Fx.Block2);\n\n            Fx.Store.AppendIndex(chainA, Fx.GenesisBlock.Hash);\n            Fx.Store.AppendIndex(chainA, Fx.Block1.Hash);\n            Fx.Store.ForkBlockIndexes(chainA, chainB, Fx.Block1.Hash);\n            Fx.Store.AppendIndex(chainB, Fx.Block2.Hash);\n\n            Fx.Store.DeleteChainId(chainA);\n\n            Assert.Equal(\n                new[] { chainB }.ToImmutableHashSet(),\n                Fx.Store.ListChainIds().ToImmutableHashSet()\n            );\n        }\n\n        [SkippableFact]\n        public void DeleteChainId()\n        {\n            Block block1 = ProposeNextBlock(\n                ProposeGenesisBlock(GenesisProposer),\n                GenesisProposer,\n                new[] { Fx.Transaction1 });\n            Fx.Store.AppendIndex(Fx.StoreChainId, block1.Hash);\n            Guid arbitraryChainId = Guid.NewGuid();\n            Fx.Store.AppendIndex(arbitraryChainId, block1.Hash);\n            Fx.Store.IncreaseTxNonce(Fx.StoreChainId, Fx.Transaction1.Signer);\n\n            Fx.Store.DeleteChainId(Fx.StoreChainId);\n\n            Assert.Equal(\n                new[] { arbitraryChainId }.ToImmutableHashSet(),\n                Fx.Store.ListChainIds().ToImmutableHashSet()\n            );\n            Assert.Equal(0, Fx.Store.GetTxNonce(Fx.StoreChainId, Fx.Transaction1.Signer));\n        }\n\n        [SkippableFact]\n        public void DeleteChainIdIsIdempotent()\n        {\n            Assert.Empty(Fx.Store.ListChainIds());\n            Fx.Store.DeleteChainId(Guid.NewGuid());\n            Assert.Empty(Fx.Store.ListChainIds());\n        }\n\n        [SkippableFact]\n        public void DeleteChainIdWithForks()\n        {\n            Skip.IfNot(\n                Environment.GetEnvironmentVariable(\"XUNIT_UNITY_RUNNER\") is null,\n                \"Flaky test : Libplanet.Blocks.InvalidBlockSignatureException\"\n            );\n\n            IStore store = Fx.Store;\n            Guid chainA = Guid.NewGuid();\n            Guid chainB = Guid.NewGuid();\n            Guid chainC = Guid.NewGuid();\n\n            // We need `Block<T>`s because `IStore` can't retrieve index(long) by block hash without\n            // actual block...\n            store.PutBlock(Fx.GenesisBlock);\n            store.PutBlock(Fx.Block1);\n            store.PutBlock(Fx.Block2);\n            store.PutBlock(Fx.Block3);\n\n            store.AppendIndex(chainA, Fx.GenesisBlock.Hash);\n            store.AppendIndex(chainB, Fx.GenesisBlock.Hash);\n            store.AppendIndex(chainC, Fx.GenesisBlock.Hash);\n\n            store.AppendIndex(chainA, Fx.Block1.Hash);\n            store.ForkBlockIndexes(chainA, chainB, Fx.Block1.Hash);\n            store.AppendIndex(chainB, Fx.Block2.Hash);\n            store.ForkBlockIndexes(chainB, chainC, Fx.Block2.Hash);\n            store.AppendIndex(chainC, Fx.Block3.Hash);\n\n            // Deleting chainA doesn't effect chainB, chainC\n            store.DeleteChainId(chainA);\n\n            Assert.Empty(store.IterateIndexes(chainA));\n            Assert.Null(store.IndexBlockHash(chainA, 0));\n            Assert.Null(store.IndexBlockHash(chainA, 1));\n\n            Assert.Equal(\n                new[]\n                {\n                    Fx.GenesisBlock.Hash,\n                    Fx.Block1.Hash,\n                    Fx.Block2.Hash,\n                },\n                store.IterateIndexes(chainB)\n            );\n            Assert.Equal(Fx.GenesisBlock.Hash, store.IndexBlockHash(chainB, 0));\n            Assert.Equal(Fx.Block1.Hash, store.IndexBlockHash(chainB, 1));\n            Assert.Equal(Fx.Block2.Hash, store.IndexBlockHash(chainB, 2));\n\n            Assert.Equal(\n                new[]\n                {\n                    Fx.GenesisBlock.Hash,\n                    Fx.Block1.Hash,\n                    Fx.Block2.Hash,\n                    Fx.Block3.Hash,\n                },\n                store.IterateIndexes(chainC)\n            );\n            Assert.Equal(Fx.GenesisBlock.Hash, store.IndexBlockHash(chainC, 0));\n            Assert.Equal(Fx.Block1.Hash, store.IndexBlockHash(chainC, 1));\n            Assert.Equal(Fx.Block2.Hash, store.IndexBlockHash(chainC, 2));\n            Assert.Equal(Fx.Block3.Hash, store.IndexBlockHash(chainC, 3));\n\n            // Deleting chainB doesn't effect chainC\n            store.DeleteChainId(chainB);\n\n            Assert.Empty(store.IterateIndexes(chainA));\n            Assert.Null(store.IndexBlockHash(chainA, 0));\n            Assert.Null(store.IndexBlockHash(chainA, 1));\n\n            Assert.Empty(store.IterateIndexes(chainB));\n            Assert.Null(store.IndexBlockHash(chainB, 0));\n            Assert.Null(store.IndexBlockHash(chainB, 1));\n            Assert.Null(store.IndexBlockHash(chainB, 2));\n\n            Assert.Equal(\n                new[]\n                {\n                    Fx.GenesisBlock.Hash,\n                    Fx.Block1.Hash,\n                    Fx.Block2.Hash,\n                    Fx.Block3.Hash,\n                },\n                store.IterateIndexes(chainC)\n            );\n            Assert.Equal(Fx.GenesisBlock.Hash, store.IndexBlockHash(chainC, 0));\n            Assert.Equal(Fx.Block1.Hash, store.IndexBlockHash(chainC, 1));\n            Assert.Equal(Fx.Block2.Hash, store.IndexBlockHash(chainC, 2));\n            Assert.Equal(Fx.Block3.Hash, store.IndexBlockHash(chainC, 3));\n\n            store.DeleteChainId(chainC);\n\n            Assert.Empty(store.IterateIndexes(chainA));\n            Assert.Empty(store.IterateIndexes(chainB));\n            Assert.Empty(store.IterateIndexes(chainC));\n            Assert.Null(store.IndexBlockHash(chainC, 0));\n            Assert.Null(store.IndexBlockHash(chainC, 1));\n            Assert.Null(store.IndexBlockHash(chainC, 2));\n            Assert.Null(store.IndexBlockHash(chainC, 3));\n        }\n\n        [SkippableFact]\n        public void DeleteChainIdWithForksReverse()\n        {\n            IStore store = Fx.Store;\n            Guid chainA = Guid.NewGuid();\n            Guid chainB = Guid.NewGuid();\n            Guid chainC = Guid.NewGuid();\n\n            // We need `Block<T>`s because `IStore` can't retrieve index(long) by block hash without\n            // actual block...\n            store.PutBlock(Fx.GenesisBlock);\n            store.PutBlock(Fx.Block1);\n            store.PutBlock(Fx.Block2);\n            store.PutBlock(Fx.Block3);\n\n            store.AppendIndex(chainA, Fx.GenesisBlock.Hash);\n            store.AppendIndex(chainB, Fx.GenesisBlock.Hash);\n            store.AppendIndex(chainC, Fx.GenesisBlock.Hash);\n\n            store.AppendIndex(chainA, Fx.Block1.Hash);\n            store.ForkBlockIndexes(chainA, chainB, Fx.Block1.Hash);\n            store.AppendIndex(chainB, Fx.Block2.Hash);\n            store.ForkBlockIndexes(chainB, chainC, Fx.Block2.Hash);\n            store.AppendIndex(chainC, Fx.Block3.Hash);\n\n            store.DeleteChainId(chainC);\n\n            Assert.Equal(\n                new[]\n                {\n                    Fx.GenesisBlock.Hash,\n                    Fx.Block1.Hash,\n                },\n                store.IterateIndexes(chainA)\n            );\n            Assert.Equal(\n                new[]\n                {\n                    Fx.GenesisBlock.Hash,\n                    Fx.Block1.Hash,\n                    Fx.Block2.Hash,\n                },\n                store.IterateIndexes(chainB)\n            );\n            Assert.Empty(store.IterateIndexes(chainC));\n\n            store.DeleteChainId(chainB);\n\n            Assert.Equal(\n                new[]\n                {\n                    Fx.GenesisBlock.Hash,\n                    Fx.Block1.Hash,\n                },\n                store.IterateIndexes(chainA)\n            );\n            Assert.Empty(store.IterateIndexes(chainB));\n            Assert.Empty(store.IterateIndexes(chainC));\n\n            store.DeleteChainId(chainA);\n            Assert.Empty(store.IterateIndexes(chainA));\n            Assert.Empty(store.IterateIndexes(chainB));\n            Assert.Empty(store.IterateIndexes(chainC));\n        }\n\n        [SkippableFact]\n        public void ForkFromChainWithDeletion()\n        {\n            IStore store = Fx.Store;\n            Guid chainA = Guid.NewGuid();\n            Guid chainB = Guid.NewGuid();\n            Guid chainC = Guid.NewGuid();\n\n            // We need `Block<T>`s because `IStore` can't retrieve index(long) by block hash without\n            // actual block...\n            store.PutBlock(Fx.GenesisBlock);\n            store.PutBlock(Fx.Block1);\n            store.PutBlock(Fx.Block2);\n            store.PutBlock(Fx.Block3);\n\n            store.AppendIndex(chainA, Fx.GenesisBlock.Hash);\n            store.AppendIndex(chainA, Fx.Block1.Hash);\n            store.ForkBlockIndexes(chainA, chainB, Fx.Block1.Hash);\n            store.DeleteChainId(chainA);\n\n            store.ForkBlockIndexes(chainB, chainC, Fx.Block1.Hash);\n            Assert.Equal(\n                Fx.Block1.Hash,\n                store.IndexBlockHash(chainC, Fx.Block1.Index)\n            );\n        }\n\n        [SkippableFact]\n        public void CanonicalChainId()\n        {\n            Assert.Null(Fx.Store.GetCanonicalChainId());\n            Guid a = Guid.NewGuid();\n            Fx.Store.SetCanonicalChainId(a);\n            Assert.Equal(a, Fx.Store.GetCanonicalChainId());\n            Guid b = Guid.NewGuid();\n            Fx.Store.SetCanonicalChainId(b);\n            Assert.Equal(b, Fx.Store.GetCanonicalChainId());\n        }\n\n        [SkippableFact]\n        public void StoreBlock()\n        {\n            Assert.Empty(Fx.Store.IterateBlockHashes());\n            Assert.Null(Fx.Store.GetBlock(Fx.Block1.Hash));\n            Assert.Null(Fx.Store.GetBlock(Fx.Block2.Hash));\n            Assert.Null(Fx.Store.GetBlock(Fx.Block3.Hash));\n            Assert.Null(Fx.Store.GetBlockIndex(Fx.Block1.Hash));\n            Assert.Null(Fx.Store.GetBlockIndex(Fx.Block2.Hash));\n            Assert.Null(Fx.Store.GetBlockIndex(Fx.Block3.Hash));\n            Assert.False(Fx.Store.DeleteBlock(Fx.Block1.Hash));\n            Assert.False(Fx.Store.ContainsBlock(Fx.Block1.Hash));\n            Assert.False(Fx.Store.ContainsBlock(Fx.Block2.Hash));\n            Assert.False(Fx.Store.ContainsBlock(Fx.Block3.Hash));\n\n            Fx.Store.PutBlock(Fx.Block1);\n            Assert.Equal(1, Fx.Store.CountBlocks());\n            Assert.Equal(\n                new HashSet<BlockHash> { Fx.Block1.Hash },\n                Fx.Store.IterateBlockHashes().ToHashSet());\n            Assert.Equal(\n                Fx.Block1,\n                Fx.Store.GetBlock(Fx.Block1.Hash));\n            Assert.Null(Fx.Store.GetBlock(Fx.Block2.Hash));\n            Assert.Null(Fx.Store.GetBlock(Fx.Block3.Hash));\n            Assert.Equal(Fx.Block1.Index, Fx.Store.GetBlockIndex(Fx.Block1.Hash));\n            Assert.Null(Fx.Store.GetBlockIndex(Fx.Block2.Hash));\n            Assert.Null(Fx.Store.GetBlockIndex(Fx.Block3.Hash));\n            Assert.True(Fx.Store.ContainsBlock(Fx.Block1.Hash));\n            Assert.False(Fx.Store.ContainsBlock(Fx.Block2.Hash));\n            Assert.False(Fx.Store.ContainsBlock(Fx.Block3.Hash));\n\n            Fx.Store.PutBlock(Fx.Block2);\n            Assert.Equal(2, Fx.Store.CountBlocks());\n            Assert.Equal(\n                new HashSet<BlockHash> { Fx.Block1.Hash, Fx.Block2.Hash },\n                Fx.Store.IterateBlockHashes().ToHashSet());\n            Assert.Equal(\n                Fx.Block1,\n                Fx.Store.GetBlock(Fx.Block1.Hash));\n            Assert.Equal(\n                Fx.Block2,\n                Fx.Store.GetBlock(Fx.Block2.Hash));\n            Assert.Null(Fx.Store.GetBlock(Fx.Block3.Hash));\n            Assert.Equal(Fx.Block1.Index, Fx.Store.GetBlockIndex(Fx.Block1.Hash));\n            Assert.Equal(Fx.Block2.Index, Fx.Store.GetBlockIndex(Fx.Block2.Hash));\n            Assert.Null(Fx.Store.GetBlockIndex(Fx.Block3.Hash));\n            Assert.True(Fx.Store.ContainsBlock(Fx.Block1.Hash));\n            Assert.True(Fx.Store.ContainsBlock(Fx.Block2.Hash));\n            Assert.False(Fx.Store.ContainsBlock(Fx.Block3.Hash));\n\n            Assert.True(Fx.Store.DeleteBlock(Fx.Block1.Hash));\n            Assert.Equal(1, Fx.Store.CountBlocks());\n            Assert.Equal(\n                new HashSet<BlockHash> { Fx.Block2.Hash },\n                Fx.Store.IterateBlockHashes().ToHashSet());\n            Assert.Null(Fx.Store.GetBlock(Fx.Block1.Hash));\n            Assert.Equal(\n                Fx.Block2,\n                Fx.Store.GetBlock(Fx.Block2.Hash));\n            Assert.Null(Fx.Store.GetBlock(Fx.Block3.Hash));\n            Assert.Null(Fx.Store.GetBlockIndex(Fx.Block1.Hash));\n            Assert.Equal(Fx.Block2.Index, Fx.Store.GetBlockIndex(Fx.Block2.Hash));\n            Assert.Null(Fx.Store.GetBlockIndex(Fx.Block3.Hash));\n            Assert.False(Fx.Store.ContainsBlock(Fx.Block1.Hash));\n            Assert.True(Fx.Store.ContainsBlock(Fx.Block2.Hash));\n            Assert.False(Fx.Store.ContainsBlock(Fx.Block3.Hash));\n        }\n\n        [SkippableFact]\n        public void TxExecution()\n        {\n            void AssertTxExecutionEqual(TxExecution expected, TxExecution actual)\n            {\n                Assert.Equal(expected.Fail, actual.Fail);\n                Assert.Equal(expected.TxId, actual.TxId);\n                Assert.Equal(expected.BlockHash, actual.BlockHash);\n                Assert.Equal(expected.InputState, actual.InputState);\n                Assert.Equal(expected.OutputState, actual.OutputState);\n                Assert.Equal(expected.ExceptionNames, actual.ExceptionNames);\n            }\n\n            Assert.Null(Fx.Store.GetTxExecution(Fx.Hash1, Fx.TxId1));\n            Assert.Null(Fx.Store.GetTxExecution(Fx.Hash1, Fx.TxId2));\n            Assert.Null(Fx.Store.GetTxExecution(Fx.Hash2, Fx.TxId1));\n            Assert.Null(Fx.Store.GetTxExecution(Fx.Hash2, Fx.TxId2));\n\n            var inputA = new TxExecution(\n                Fx.Hash1,\n                Fx.TxId1,\n                false,\n                new HashDigest<SHA256>(TestUtils.GetRandomBytes(HashDigest<SHA256>.Size)),\n                new HashDigest<SHA256>(TestUtils.GetRandomBytes(HashDigest<SHA256>.Size)),\n                new List<string>() { string.Empty });\n            Fx.Store.PutTxExecution(inputA);\n\n            AssertTxExecutionEqual(inputA, Fx.Store.GetTxExecution(Fx.Hash1, Fx.TxId1));\n            Assert.Null(Fx.Store.GetTxExecution(Fx.Hash1, Fx.TxId2));\n            Assert.Null(Fx.Store.GetTxExecution(Fx.Hash2, Fx.TxId1));\n            Assert.Null(Fx.Store.GetTxExecution(Fx.Hash2, Fx.TxId2));\n\n            var inputB = new TxExecution(\n                Fx.Hash1,\n                Fx.TxId2,\n                true,\n                new HashDigest<SHA256>(TestUtils.GetRandomBytes(HashDigest<SHA256>.Size)),\n                new HashDigest<SHA256>(TestUtils.GetRandomBytes(HashDigest<SHA256>.Size)),\n                new List<string>() { \"AnExceptionName\" });\n            Fx.Store.PutTxExecution(inputB);\n\n            AssertTxExecutionEqual(inputA, Fx.Store.GetTxExecution(Fx.Hash1, Fx.TxId1));\n            AssertTxExecutionEqual(inputB, Fx.Store.GetTxExecution(Fx.Hash1, Fx.TxId2));\n            Assert.Null(Fx.Store.GetTxExecution(Fx.Hash2, Fx.TxId1));\n            Assert.Null(Fx.Store.GetTxExecution(Fx.Hash2, Fx.TxId2));\n\n            var inputC = new TxExecution(\n                Fx.Hash2,\n                Fx.TxId1,\n                true,\n                new HashDigest<SHA256>(TestUtils.GetRandomBytes(HashDigest<SHA256>.Size)),\n                new HashDigest<SHA256>(TestUtils.GetRandomBytes(HashDigest<SHA256>.Size)),\n                new List<string>() { \"AnotherExceptionName\", \"YetAnotherExceptionName\" });\n            Fx.Store.PutTxExecution(inputC);\n\n            AssertTxExecutionEqual(inputA, Fx.Store.GetTxExecution(Fx.Hash1, Fx.TxId1));\n            AssertTxExecutionEqual(inputB, Fx.Store.GetTxExecution(Fx.Hash1, Fx.TxId2));\n            AssertTxExecutionEqual(inputC, Fx.Store.GetTxExecution(Fx.Hash2, Fx.TxId1));\n            Assert.Null(Fx.Store.GetTxExecution(Fx.Hash2, Fx.TxId2));\n        }\n\n        [SkippableFact]\n        public void TxIdBlockHashIndex()\n        {\n            Assert.Null(Fx.Store.GetFirstTxIdBlockHashIndex(Fx.TxId1));\n            Assert.Null(Fx.Store.GetFirstTxIdBlockHashIndex(Fx.TxId2));\n            Assert.Null(Fx.Store.GetFirstTxIdBlockHashIndex(Fx.TxId3));\n\n            Fx.Store.PutTxIdBlockHashIndex(Fx.TxId1, Fx.Hash1);\n            Assert.Null(Fx.Store.GetFirstTxIdBlockHashIndex(Fx.TxId2));\n            Assert.Null(Fx.Store.GetFirstTxIdBlockHashIndex(Fx.TxId3));\n\n            Fx.Store.PutTxIdBlockHashIndex(Fx.TxId2, Fx.Hash2);\n            Fx.Store.PutTxIdBlockHashIndex(Fx.TxId3, Fx.Hash3);\n\n            Assert.True(Fx.Store.GetFirstTxIdBlockHashIndex(Fx.TxId1)?.Equals(Fx.Hash1));\n            Assert.True(Fx.Store.GetFirstTxIdBlockHashIndex(Fx.TxId2)?.Equals(Fx.Hash2));\n            Assert.True(Fx.Store.GetFirstTxIdBlockHashIndex(Fx.TxId3)?.Equals(Fx.Hash3));\n\n            Fx.Store.PutTxIdBlockHashIndex(Fx.TxId1, Fx.Hash3);\n            Fx.Store.PutTxIdBlockHashIndex(Fx.TxId2, Fx.Hash3);\n            Fx.Store.PutTxIdBlockHashIndex(Fx.TxId3, Fx.Hash1);\n            Assert.Equal(2, Fx.Store.IterateTxIdBlockHashIndex(Fx.TxId1).Count());\n            Assert.Equal(2, Fx.Store.IterateTxIdBlockHashIndex(Fx.TxId2).Count());\n            Assert.Equal(2, Fx.Store.IterateTxIdBlockHashIndex(Fx.TxId3).Count());\n\n            Fx.Store.DeleteTxIdBlockHashIndex(Fx.TxId1, Fx.Hash1);\n            Fx.Store.DeleteTxIdBlockHashIndex(Fx.TxId2, Fx.Hash2);\n            Fx.Store.DeleteTxIdBlockHashIndex(Fx.TxId3, Fx.Hash3);\n\n            Assert.True(Fx.Store.GetFirstTxIdBlockHashIndex(Fx.TxId1)?.Equals(Fx.Hash3));\n            Assert.True(Fx.Store.GetFirstTxIdBlockHashIndex(Fx.TxId2)?.Equals(Fx.Hash3));\n            Assert.True(Fx.Store.GetFirstTxIdBlockHashIndex(Fx.TxId3)?.Equals(Fx.Hash1));\n\n            Assert.Single(Fx.Store.IterateTxIdBlockHashIndex(Fx.TxId1));\n            Assert.Single(Fx.Store.IterateTxIdBlockHashIndex(Fx.TxId2));\n            Assert.Single(Fx.Store.IterateTxIdBlockHashIndex(Fx.TxId3));\n\n            Fx.Store.DeleteTxIdBlockHashIndex(Fx.TxId1, Fx.Hash1);\n            Fx.Store.DeleteTxIdBlockHashIndex(Fx.TxId2, Fx.Hash2);\n            Fx.Store.DeleteTxIdBlockHashIndex(Fx.TxId3, Fx.Hash3);\n\n            Fx.Store.DeleteTxIdBlockHashIndex(Fx.TxId1, Fx.Hash3);\n            Fx.Store.DeleteTxIdBlockHashIndex(Fx.TxId2, Fx.Hash3);\n            Fx.Store.DeleteTxIdBlockHashIndex(Fx.TxId3, Fx.Hash1);\n\n            Assert.Null(Fx.Store.GetFirstTxIdBlockHashIndex(Fx.TxId1));\n            Assert.Null(Fx.Store.GetFirstTxIdBlockHashIndex(Fx.TxId2));\n            Assert.Null(Fx.Store.GetFirstTxIdBlockHashIndex(Fx.TxId3));\n        }\n\n        [SkippableFact]\n        public void StoreTx()\n        {\n            Assert.Null(Fx.Store.GetTransaction(Fx.Transaction1.Id));\n            Assert.Null(Fx.Store.GetTransaction(Fx.Transaction2.Id));\n            Assert.False(Fx.Store.ContainsTransaction(Fx.Transaction1.Id));\n            Assert.False(Fx.Store.ContainsTransaction(Fx.Transaction2.Id));\n\n            Fx.Store.PutTransaction(Fx.Transaction1);\n            Assert.Equal(\n                Fx.Transaction1,\n                Fx.Store.GetTransaction(Fx.Transaction1.Id)\n            );\n            Assert.Null(Fx.Store.GetTransaction(Fx.Transaction2.Id));\n            Assert.True(Fx.Store.ContainsTransaction(Fx.Transaction1.Id));\n            Assert.False(Fx.Store.ContainsTransaction(Fx.Transaction2.Id));\n\n            Fx.Store.PutTransaction(Fx.Transaction2);\n            Assert.Equal(\n                Fx.Transaction1,\n                Fx.Store.GetTransaction(Fx.Transaction1.Id)\n            );\n            Assert.Equal(\n                Fx.Transaction2,\n                Fx.Store.GetTransaction(Fx.Transaction2.Id));\n            Assert.True(Fx.Store.ContainsTransaction(Fx.Transaction1.Id));\n            Assert.True(Fx.Store.ContainsTransaction(Fx.Transaction2.Id));\n\n            Assert.Equal(\n                Fx.Transaction2,\n                Fx.Store.GetTransaction(Fx.Transaction2.Id)\n            );\n            Assert.True(Fx.Store.ContainsTransaction(Fx.Transaction2.Id));\n        }\n\n        [SkippableFact]\n        public void StoreIndex()\n        {\n            Assert.Equal(0, Fx.Store.CountIndex(Fx.StoreChainId));\n            Assert.Empty(Fx.Store.IterateIndexes(Fx.StoreChainId));\n            Assert.Null(Fx.Store.IndexBlockHash(Fx.StoreChainId, 0));\n            Assert.Null(Fx.Store.IndexBlockHash(Fx.StoreChainId, -1));\n\n            Assert.Equal(0, Fx.Store.AppendIndex(Fx.StoreChainId, Fx.Hash1));\n            Assert.Equal(1, Fx.Store.CountIndex(Fx.StoreChainId));\n            Assert.Equal(\n                new List<BlockHash> { Fx.Hash1 },\n                Fx.Store.IterateIndexes(Fx.StoreChainId));\n            Assert.Equal(Fx.Hash1, Fx.Store.IndexBlockHash(Fx.StoreChainId, 0));\n            Assert.Equal(Fx.Hash1, Fx.Store.IndexBlockHash(Fx.StoreChainId, -1));\n\n            Assert.Equal(1, Fx.Store.AppendIndex(Fx.StoreChainId, Fx.Hash2));\n            Assert.Equal(2, Fx.Store.CountIndex(Fx.StoreChainId));\n            Assert.Equal(\n                new List<BlockHash> { Fx.Hash1, Fx.Hash2 },\n                Fx.Store.IterateIndexes(Fx.StoreChainId));\n            Assert.Equal(Fx.Hash1, Fx.Store.IndexBlockHash(Fx.StoreChainId, 0));\n            Assert.Equal(Fx.Hash2, Fx.Store.IndexBlockHash(Fx.StoreChainId, 1));\n            Assert.Equal(Fx.Hash2, Fx.Store.IndexBlockHash(Fx.StoreChainId, -1));\n            Assert.Equal(Fx.Hash1, Fx.Store.IndexBlockHash(Fx.StoreChainId, -2));\n        }\n\n        [SkippableFact]\n        public void IterateIndexes()\n        {\n            var ns = Fx.StoreChainId;\n            var store = Fx.Store;\n\n            store.AppendIndex(ns, Fx.Hash1);\n            store.AppendIndex(ns, Fx.Hash2);\n            store.AppendIndex(ns, Fx.Hash3);\n\n            var indexes = store.IterateIndexes(ns).ToArray();\n            Assert.Equal(new[] { Fx.Hash1, Fx.Hash2, Fx.Hash3 }, indexes);\n\n            indexes = store.IterateIndexes(ns, 1).ToArray();\n            Assert.Equal(new[] { Fx.Hash2, Fx.Hash3 }, indexes);\n\n            indexes = store.IterateIndexes(ns, 2).ToArray();\n            Assert.Equal(new[] { Fx.Hash3 }, indexes);\n\n            indexes = store.IterateIndexes(ns, 3).ToArray();\n            Assert.Equal(new BlockHash[0], indexes);\n\n            indexes = store.IterateIndexes(ns, 4).ToArray();\n            Assert.Equal(new BlockHash[0], indexes);\n\n            indexes = store.IterateIndexes(ns, limit: 0).ToArray();\n            Assert.Equal(new BlockHash[0], indexes);\n\n            indexes = store.IterateIndexes(ns, limit: 1).ToArray();\n            Assert.Equal(new[] { Fx.Hash1 }, indexes);\n\n            indexes = store.IterateIndexes(ns, limit: 2).ToArray();\n            Assert.Equal(new[] { Fx.Hash1, Fx.Hash2 }, indexes);\n\n            indexes = store.IterateIndexes(ns, limit: 3).ToArray();\n            Assert.Equal(new[] { Fx.Hash1, Fx.Hash2, Fx.Hash3 }, indexes);\n\n            indexes = store.IterateIndexes(ns, limit: 4).ToArray();\n            Assert.Equal(new[] { Fx.Hash1, Fx.Hash2, Fx.Hash3 }, indexes);\n\n            indexes = store.IterateIndexes(ns, 1, 1).ToArray();\n            Assert.Equal(new[] { Fx.Hash2 }, indexes);\n        }\n\n        [SkippableFact]\n        public void TxNonce()\n        {\n            Assert.Equal(0, Fx.Store.GetTxNonce(Fx.StoreChainId, Fx.Transaction1.Signer));\n            Assert.Equal(0, Fx.Store.GetTxNonce(Fx.StoreChainId, Fx.Transaction2.Signer));\n\n            Fx.Store.IncreaseTxNonce(Fx.StoreChainId, Fx.Transaction1.Signer);\n            Assert.Equal(1, Fx.Store.GetTxNonce(Fx.StoreChainId, Fx.Transaction1.Signer));\n            Assert.Equal(0, Fx.Store.GetTxNonce(Fx.StoreChainId, Fx.Transaction2.Signer));\n            Assert.Equal(\n                new Dictionary<Address, long>\n                {\n                    [Fx.Transaction1.Signer] = 1,\n                },\n                Fx.Store.ListTxNonces(Fx.StoreChainId).ToDictionary(p => p.Key, p => p.Value)\n            );\n\n            Fx.Store.IncreaseTxNonce(Fx.StoreChainId, Fx.Transaction2.Signer, 5);\n            Assert.Equal(1, Fx.Store.GetTxNonce(Fx.StoreChainId, Fx.Transaction1.Signer));\n            Assert.Equal(5, Fx.Store.GetTxNonce(Fx.StoreChainId, Fx.Transaction2.Signer));\n            Assert.Equal(\n                new Dictionary<Address, long>\n                {\n                    [Fx.Transaction1.Signer] = 1,\n                    [Fx.Transaction2.Signer] = 5,\n                },\n                Fx.Store.ListTxNonces(Fx.StoreChainId).ToDictionary(p => p.Key, p => p.Value)\n            );\n\n            Fx.Store.IncreaseTxNonce(Fx.StoreChainId, Fx.Transaction1.Signer, 2);\n            Assert.Equal(3, Fx.Store.GetTxNonce(Fx.StoreChainId, Fx.Transaction1.Signer));\n            Assert.Equal(5, Fx.Store.GetTxNonce(Fx.StoreChainId, Fx.Transaction2.Signer));\n            Assert.Equal(\n                new Dictionary<Address, long>\n                {\n                    [Fx.Transaction1.Signer] = 3,\n                    [Fx.Transaction2.Signer] = 5,\n                },\n                Fx.Store.ListTxNonces(Fx.StoreChainId).ToDictionary(p => p.Key, p => p.Value)\n            );\n        }\n\n        [SkippableFact]\n        public void ListTxNonces()\n        {\n            var chainId1 = Guid.NewGuid();\n            var chainId2 = Guid.NewGuid();\n\n            Address address1 = Fx.Address1;\n            Address address2 = Fx.Address2;\n\n            Assert.Empty(Fx.Store.ListTxNonces(chainId1));\n            Assert.Empty(Fx.Store.ListTxNonces(chainId2));\n\n            Fx.Store.IncreaseTxNonce(chainId1, address1);\n            Assert.Equal(\n                new Dictionary<Address, long> { [address1] = 1, },\n                Fx.Store.ListTxNonces(chainId1));\n\n            Fx.Store.IncreaseTxNonce(chainId2, address2);\n            Assert.Equal(\n                new Dictionary<Address, long> { [address2] = 1, },\n                Fx.Store.ListTxNonces(chainId2));\n\n            Fx.Store.IncreaseTxNonce(chainId1, address1);\n            Fx.Store.IncreaseTxNonce(chainId1, address2);\n            Assert.Equal(\n                new Dictionary<Address, long> { [address1] = 2, [address2] = 1, },\n                Fx.Store.ListTxNonces(chainId1));\n\n            Fx.Store.IncreaseTxNonce(chainId2, address1);\n            Fx.Store.IncreaseTxNonce(chainId2, address2);\n            Assert.Equal(\n                new Dictionary<Address, long> { [address1] = 1, [address2] = 2, },\n                Fx.Store.ListTxNonces(chainId2));\n        }\n\n        [SkippableFact]\n        public void IndexBlockHashReturnNull()\n        {\n            Fx.Store.PutBlock(Fx.Block1);\n            Fx.Store.AppendIndex(Fx.StoreChainId, Fx.Block1.Hash);\n            Assert.Equal(1, Fx.Store.CountIndex(Fx.StoreChainId));\n            Assert.Null(Fx.Store.IndexBlockHash(Fx.StoreChainId, 2));\n        }\n\n        [SkippableFact]\n        public void ContainsBlockWithoutCache()\n        {\n            Fx.Store.PutBlock(Fx.Block1);\n            Fx.Store.PutBlock(Fx.Block2);\n            Fx.Store.PutBlock(Fx.Block3);\n\n            Assert.True(Fx.Store.ContainsBlock(Fx.Block1.Hash));\n            Assert.True(Fx.Store.ContainsBlock(Fx.Block2.Hash));\n            Assert.True(Fx.Store.ContainsBlock(Fx.Block3.Hash));\n        }\n\n        [SkippableFact]\n        public void ContainsTransactionWithoutCache()\n        {\n            Fx.Store.PutTransaction(Fx.Transaction1);\n            Fx.Store.PutTransaction(Fx.Transaction2);\n            Fx.Store.PutTransaction(Fx.Transaction3);\n\n            Assert.True(Fx.Store.ContainsTransaction(Fx.Transaction1.Id));\n            Assert.True(Fx.Store.ContainsTransaction(Fx.Transaction2.Id));\n            Assert.True(Fx.Store.ContainsTransaction(Fx.Transaction3.Id));\n        }\n\n        [SkippableFact]\n        public void TxAtomicity()\n        {\n            Transaction MakeTx(\n                System.Random random,\n                MD5 md5,\n                PrivateKey key,\n                int txNonce\n            )\n            {\n                byte[] arbitraryBytes = new byte[20];\n                random.NextBytes(arbitraryBytes);\n                byte[] digest = md5.ComputeHash(arbitraryBytes);\n                var action = new AtomicityTestAction\n                {\n                    ArbitraryBytes = arbitraryBytes.ToImmutableArray(),\n                    Md5Digest = digest.ToImmutableArray(),\n                };\n                return Transaction.Create(\n                    txNonce,\n                    key,\n                    null,\n                    new[] { action }.ToPlainValues(),\n                    null,\n                    null,\n                    DateTimeOffset.UtcNow);\n            }\n\n            const int taskCount = 5;\n            const int txCount = 30;\n            var md5Hasher = MD5.Create();\n            Transaction commonTx = MakeTx(\n                new System.Random(),\n                md5Hasher,\n                new PrivateKey(),\n                0\n            );\n            Task[] tasks = new Task[taskCount];\n            for (int i = 0; i < taskCount; i++)\n            {\n                var task = new Task(() =>\n                {\n                    PrivateKey key = new PrivateKey();\n                    var random = new System.Random();\n                    var md5 = MD5.Create();\n                    Transaction tx;\n                    for (int j = 0; j < 50; j++)\n                    {\n                        Fx.Store.PutTransaction(commonTx);\n                    }\n\n                    for (int j = 0; j < txCount; j++)\n                    {\n                        tx = MakeTx(random, md5, key, j + 1);\n                        Fx.Store.PutTransaction(tx);\n                    }\n                });\n                task.Start();\n                tasks[i] = task;\n            }\n\n            try\n            {\n                Task.WaitAll(tasks);\n            }\n            catch (AggregateException e)\n            {\n                foreach (Exception innerException in e.InnerExceptions)\n                {\n                    TestOutputHelper.WriteLine(innerException.ToString());\n                }\n\n                throw;\n            }\n        }\n\n        [SkippableFact]\n        public void ForkBlockIndex()\n        {\n            IStore store = Fx.Store;\n            Guid chainA = Guid.NewGuid();\n            Guid chainB = Guid.NewGuid();\n            Guid chainC = Guid.NewGuid();\n\n            // We need `Block<T>`s because `IStore` can't retrieve index(long) by block hash without\n            // actual block...\n            store.PutBlock(Fx.GenesisBlock);\n            store.PutBlock(Fx.Block1);\n            store.PutBlock(Fx.Block2);\n            store.PutBlock(Fx.Block3);\n\n            store.AppendIndex(chainA, Fx.GenesisBlock.Hash);\n            store.AppendIndex(chainB, Fx.GenesisBlock.Hash);\n            store.AppendIndex(chainC, Fx.GenesisBlock.Hash);\n\n            store.AppendIndex(chainA, Fx.Block1.Hash);\n            store.ForkBlockIndexes(chainA, chainB, Fx.Block1.Hash);\n            store.AppendIndex(chainB, Fx.Block2.Hash);\n            store.AppendIndex(chainB, Fx.Block3.Hash);\n\n            Assert.Equal(\n                new[]\n                {\n                    Fx.GenesisBlock.Hash,\n                    Fx.Block1.Hash,\n                },\n                store.IterateIndexes(chainA)\n            );\n            Assert.Equal(\n                new[]\n                {\n                    Fx.GenesisBlock.Hash,\n                    Fx.Block1.Hash,\n                    Fx.Block2.Hash,\n                    Fx.Block3.Hash,\n                },\n                store.IterateIndexes(chainB)\n            );\n\n            store.ForkBlockIndexes(chainB, chainC, Fx.Block3.Hash);\n            store.AppendIndex(chainC, Fx.Block4.Hash);\n            store.AppendIndex(chainC, Fx.Block5.Hash);\n\n            Assert.Equal(\n                new[]\n                {\n                    Fx.GenesisBlock.Hash,\n                    Fx.Block1.Hash,\n                },\n                store.IterateIndexes(chainA)\n            );\n            Assert.Equal(\n                new[]\n                {\n                    Fx.GenesisBlock.Hash,\n                    Fx.Block1.Hash,\n                    Fx.Block2.Hash,\n                    Fx.Block3.Hash,\n                },\n                store.IterateIndexes(chainB)\n            );\n            Assert.Equal(\n                new[]\n                {\n                    Fx.GenesisBlock.Hash,\n                    Fx.Block1.Hash,\n                    Fx.Block2.Hash,\n                    Fx.Block3.Hash,\n                    Fx.Block4.Hash,\n                    Fx.Block5.Hash,\n                },\n                store.IterateIndexes(chainC)\n            );\n\n            Assert.Equal(\n                new[]\n                {\n                    Fx.Block1.Hash,\n                    Fx.Block2.Hash,\n                    Fx.Block3.Hash,\n                    Fx.Block4.Hash,\n                    Fx.Block5.Hash,\n                },\n                store.IterateIndexes(chainC, offset: 1)\n            );\n\n            Assert.Equal(\n                new[]\n                {\n                    Fx.Block2.Hash,\n                    Fx.Block3.Hash,\n                    Fx.Block4.Hash,\n                    Fx.Block5.Hash,\n                },\n                store.IterateIndexes(chainC, offset: 2)\n            );\n\n            Assert.Equal(\n                new[]\n                {\n                    Fx.Block3.Hash,\n                    Fx.Block4.Hash,\n                    Fx.Block5.Hash,\n                },\n                store.IterateIndexes(chainC, offset: 3)\n            );\n\n            Assert.Equal(\n                new[]\n                {\n                    Fx.Block4.Hash,\n                    Fx.Block5.Hash,\n                },\n                store.IterateIndexes(chainC, offset: 4)\n            );\n\n            Assert.Equal(\n                new[]\n                {\n                    Fx.Block5.Hash,\n                },\n                store.IterateIndexes(chainC, offset: 5)\n            );\n\n            Assert.Equal(\n                Array.Empty<BlockHash>(),\n                store.IterateIndexes(chainC, offset: 6)\n            );\n\n            Assert.Equal(Fx.Block1.Hash, store.IndexBlockHash(chainA, 1));\n            Assert.Equal(Fx.Block1.Hash, store.IndexBlockHash(chainB, 1));\n            Assert.Equal(Fx.Block1.Hash, store.IndexBlockHash(chainC, 1));\n            Assert.Equal(Fx.Block2.Hash, store.IndexBlockHash(chainB, 2));\n            Assert.Equal(Fx.Block2.Hash, store.IndexBlockHash(chainC, 2));\n            Assert.Equal(Fx.Block3.Hash, store.IndexBlockHash(chainB, 3));\n            Assert.Equal(Fx.Block3.Hash, store.IndexBlockHash(chainC, 3));\n            Assert.Equal(Fx.Block4.Hash, store.IndexBlockHash(chainC, 4));\n            Assert.Equal(Fx.Block5.Hash, store.IndexBlockHash(chainC, 5));\n        }\n\n        [SkippableFact]\n        public void ForkWithBranch()\n        {\n            IStore store = Fx.Store;\n            Guid chainA = Guid.NewGuid();\n            Guid chainB = Guid.NewGuid();\n\n            // We need `Block<T>`s because `IStore` can't retrieve index(long) by block hash without\n            // actual block...\n            Block anotherBlock3 = ProposeNextBlock(\n                Fx.Block2,\n                Fx.Proposer,\n                lastCommit: CreateBlockCommit(Fx.Block2.Hash, 2, 0));\n            store.PutBlock(Fx.GenesisBlock);\n            store.PutBlock(Fx.Block1);\n            store.PutBlock(Fx.Block2);\n            store.PutBlock(Fx.Block3);\n            store.PutBlock(anotherBlock3);\n\n            store.AppendIndex(chainA, Fx.GenesisBlock.Hash);\n            store.AppendIndex(chainA, Fx.Block1.Hash);\n            store.AppendIndex(chainA, Fx.Block2.Hash);\n            store.AppendIndex(chainA, Fx.Block3.Hash);\n\n            store.ForkBlockIndexes(chainA, chainB, Fx.Block2.Hash);\n            store.AppendIndex(chainB, anotherBlock3.Hash);\n\n            Assert.Equal(\n                new[]\n                {\n                    Fx.Block2.Hash,\n                    anotherBlock3.Hash,\n                },\n                store.IterateIndexes(chainB, 2, 2)\n            );\n            Assert.Equal(\n                new[]\n                {\n                    Fx.Block2.Hash,\n                    anotherBlock3.Hash,\n                },\n                store.IterateIndexes(chainB, 2)\n            );\n\n            Assert.Equal(\n                new[]\n                {\n                    anotherBlock3.Hash,\n                },\n                store.IterateIndexes(chainB, 3, 1)\n            );\n\n            Assert.Equal(\n                new[]\n                {\n                    anotherBlock3.Hash,\n                },\n                store.IterateIndexes(chainB, 3)\n            );\n        }\n\n        [SkippableFact]\n        public void Copy()\n        {\n            using (StoreFixture fx = FxConstructor())\n            using (StoreFixture fx2 = FxConstructor())\n            {\n                IStore s1 = fx.Store, s2 = fx2.Store;\n                var policy = new NullBlockPolicy();\n                var preEval = ProposeGenesis(proposer: GenesisProposer.PublicKey);\n                var actionEvaluator = new ActionEvaluator(\n                    policy.PolicyActionsRegistry,\n                    fx.StateStore,\n                    new SingleActionLoader(typeof(DumbAction)));\n                var genesis = preEval.Sign(\n                    GenesisProposer,\n                    MerkleTrie.EmptyRootHash);\n                var blocks = BlockChain.Create(\n                    policy,\n                    new VolatileStagePolicy(),\n                    s1,\n                    fx.StateStore,\n                    genesis,\n                    actionEvaluator);\n\n                // FIXME: Need to add more complex blocks/transactions.\n                var key = new PrivateKey();\n                var block = blocks.ProposeBlock(key);\n                blocks.Append(block, CreateBlockCommit(block));\n                block = blocks.ProposeBlock(key, CreateBlockCommit(blocks.Tip));\n                blocks.Append(block, CreateBlockCommit(block));\n                block = blocks.ProposeBlock(key, CreateBlockCommit(blocks.Tip));\n                blocks.Append(block, CreateBlockCommit(block));\n\n                s1.Copy(to: Fx.Store);\n                Fx.Store.Copy(to: s2);\n\n                Assert.Equal(s1.ListChainIds().ToHashSet(), s2.ListChainIds().ToHashSet());\n                Assert.Equal(s1.GetCanonicalChainId(), s2.GetCanonicalChainId());\n                foreach (Guid chainId in s1.ListChainIds())\n                {\n                    Assert.Equal(s1.IterateIndexes(chainId), s2.IterateIndexes(chainId));\n                    foreach (BlockHash blockHash in s1.IterateIndexes(chainId))\n                    {\n                        Assert.Equal(s1.GetBlock(blockHash), s2.GetBlock(blockHash));\n                    }\n                }\n\n                // ArgumentException is thrown if the destination store is not empty.\n                Assert.Throws<ArgumentException>(() => Fx.Store.Copy(fx2.Store));\n            }\n        }\n\n        [SkippableFact]\n        public void GetBlock()\n        {\n            using (StoreFixture fx = FxConstructor())\n            {\n                Block genesisBlock = fx.GenesisBlock;\n                Block block = ProposeNextBlock(\n                    genesisBlock,\n                    miner: fx.Proposer);\n\n                fx.Store.PutBlock(block);\n                Block storedBlock =\n                    fx.Store.GetBlock(block.Hash);\n\n                Assert.Equal(block, storedBlock);\n            }\n        }\n\n        [SkippableFact]\n        public void GetBlockCommit()\n        {\n            using (StoreFixture fx = FxConstructor())\n            {\n                // Commits with votes\n                var height = 1;\n                var round = 0;\n                var hash = fx.Block2.Hash;\n                var validators = Enumerable.Range(0, 4)\n                    .Select(x => new PrivateKey())\n                    .ToArray();\n                var votes = validators.Select(validator => new VoteMetadata(\n                    height,\n                    round,\n                    hash,\n                    DateTimeOffset.UtcNow,\n                    validator.PublicKey,\n                    BigInteger.One,\n                    VoteFlag.PreCommit).Sign(validator)).ToImmutableArray();\n\n                BlockCommit commit = new BlockCommit(height, round, hash, votes);\n                fx.Store.PutBlockCommit(commit);\n                BlockCommit storedCommitVotes =\n                    fx.Store.GetBlockCommit(commit.BlockHash);\n\n                Assert.Equal(commit, storedCommitVotes);\n            }\n        }\n\n        [SkippableFact]\n        public void GetBlockCommitIndices()\n        {\n            using (StoreFixture fx = FxConstructor())\n            {\n                var votesOne = ImmutableArray<Vote>.Empty\n                    .Add(new VoteMetadata(\n                        1,\n                        0,\n                        fx.Block1.Hash,\n                        DateTimeOffset.UtcNow,\n                        fx.Proposer.PublicKey,\n                        fx.ProposerPower,\n                        VoteFlag.PreCommit).Sign(fx.Proposer));\n                var votesTwo = ImmutableArray<Vote>.Empty\n                    .Add(new VoteMetadata(\n                        2,\n                        0,\n                        fx.Block2.Hash,\n                        DateTimeOffset.UtcNow,\n                        fx.Proposer.PublicKey,\n                        fx.ProposerPower,\n                        VoteFlag.PreCommit).Sign(fx.Proposer));\n\n                BlockCommit[] blockCommits =\n                {\n                    new BlockCommit(1, 0, fx.Block1.Hash, votesOne),\n                    new BlockCommit(2, 0, fx.Block2.Hash, votesTwo),\n                };\n\n                foreach (var blockCommit in blockCommits)\n                {\n                    fx.Store.PutBlockCommit(blockCommit);\n                }\n\n                IEnumerable<BlockHash> indices = fx.Store.GetBlockCommitHashes();\n\n                HashSet<long> indicesFromOperation = indices\n                    .Select(hash => fx.Store.GetBlockCommit(hash).Height)\n                    .ToHashSet();\n                HashSet<long> expectedIndices = new HashSet<long>() { 1, 2 };\n\n                Assert.Equal(indicesFromOperation, expectedIndices);\n            }\n        }\n\n        [SkippableFact]\n        public void DeleteLastCommit()\n        {\n            using (StoreFixture fx = FxConstructor())\n            {\n                var validatorPrivateKey = new PrivateKey();\n                BlockCommit blockCommit =\n                    new BlockCommit(\n                        0,\n                        0,\n                        Fx.GenesisBlock.Hash,\n                        ImmutableArray<Vote>.Empty\n                            .Add(new VoteMetadata(\n                                0,\n                                0,\n                                Fx.GenesisBlock.Hash,\n                                DateTimeOffset.UtcNow,\n                                validatorPrivateKey.PublicKey,\n                                BigInteger.One,\n                                VoteFlag.PreCommit).Sign(validatorPrivateKey)));\n\n                fx.Store.PutBlockCommit(blockCommit);\n                Assert.NotNull(fx.Store.GetBlockCommit(blockCommit.BlockHash));\n\n                fx.Store.DeleteBlockCommit(blockCommit.BlockHash);\n                Assert.Null(fx.Store.GetBlockCommit(blockCommit.BlockHash));\n            }\n        }\n\n        [SkippableFact]\n        public void IteratePendingEvidenceIds()\n        {\n            using (StoreFixture fx = FxConstructor())\n            {\n                var signer = TestUtils.ValidatorPrivateKeys[0];\n                var duplicateVoteOne = ImmutableArray<Vote>.Empty\n                    .Add(new VoteMetadata(\n                        height: 1,\n                        round: 0,\n                        blockHash: fx.Block1.Hash,\n                        timestamp: DateTimeOffset.UtcNow,\n                        validatorPublicKey: signer.PublicKey,\n                        validatorPower: BigInteger.One,\n                        flag: VoteFlag.PreCommit).Sign(signer))\n                    .Add(new VoteMetadata(\n                        height: 1,\n                        round: 0,\n                        blockHash: fx.Block2.Hash,\n                        timestamp: DateTimeOffset.UtcNow,\n                        validatorPublicKey: signer.PublicKey,\n                        validatorPower: BigInteger.One,\n                        flag: VoteFlag.PreCommit).Sign(signer));\n                var duplicateVoteTwo = ImmutableArray<Vote>.Empty\n                    .Add(new VoteMetadata(\n                        height: 2,\n                        round: 0,\n                        blockHash: fx.Block2.Hash,\n                        timestamp: DateTimeOffset.UtcNow,\n                        validatorPublicKey: signer.PublicKey,\n                        validatorPower: BigInteger.One,\n                        flag: VoteFlag.PreCommit).Sign(signer))\n                    .Add(new VoteMetadata(\n                        height: 2,\n                        round: 0,\n                        blockHash: fx.Block3.Hash,\n                        timestamp: DateTimeOffset.UtcNow,\n                        validatorPublicKey: signer.PublicKey,\n                        validatorPower: BigInteger.One,\n                        flag: VoteFlag.PreCommit).Sign(signer));\n\n                EvidenceBase[] evidence =\n                {\n                    new DuplicateVoteEvidence(\n                        duplicateVoteOne[0],\n                        duplicateVoteOne[1],\n                        TestUtils.ValidatorSet,\n                        duplicateVoteOne.Last().Timestamp),\n                    new DuplicateVoteEvidence(\n                        duplicateVoteTwo[0],\n                        duplicateVoteTwo[1],\n                        TestUtils.ValidatorSet,\n                        duplicateVoteTwo.Last().Timestamp),\n                };\n\n                foreach (var ev in evidence)\n                {\n                    fx.Store.PutPendingEvidence(ev);\n                }\n\n                IEnumerable<EvidenceId> ids = fx.Store.IteratePendingEvidenceIds();\n                Assert.Equal(evidence.Select(e => e.Id).ToHashSet(), ids.ToHashSet());\n            }\n        }\n\n        [SkippableFact]\n        public void ManipulatePendingEvidence()\n        {\n            using (StoreFixture fx = FxConstructor())\n            {\n                var signer = TestUtils.ValidatorPrivateKeys[0];\n                var duplicateVote = ImmutableArray<Vote>.Empty\n                    .Add(new VoteMetadata(\n                        height: 1,\n                        round: 0,\n                        blockHash: fx.Block1.Hash,\n                        timestamp: DateTimeOffset.UtcNow,\n                        validatorPublicKey: signer.PublicKey,\n                        validatorPower: BigInteger.One,\n                        flag: VoteFlag.PreCommit).Sign(signer))\n                    .Add(new VoteMetadata(\n                        height: 1,\n                        round: 0,\n                        blockHash: fx.Block2.Hash,\n                        timestamp: DateTimeOffset.UtcNow,\n                        validatorPublicKey: signer.PublicKey,\n                        validatorPower: BigInteger.One,\n                        flag: VoteFlag.PreCommit).Sign(signer));\n                EvidenceBase evidence = new DuplicateVoteEvidence(\n                    duplicateVote[0],\n                    duplicateVote[1],\n                    TestUtils.ValidatorSet,\n                    duplicateVote.Last().Timestamp);\n\n                Assert.False(fx.Store.ContainsPendingEvidence(evidence.Id));\n\n                fx.Store.PutPendingEvidence(evidence);\n                EvidenceBase storedEvidence = fx.Store.GetPendingEvidence(evidence.Id);\n\n                Assert.Equal(evidence, storedEvidence);\n                Assert.True(fx.Store.ContainsPendingEvidence(evidence.Id));\n\n                fx.Store.DeletePendingEvidence(evidence.Id);\n                Assert.False(fx.Store.ContainsPendingEvidence(evidence.Id));\n            }\n        }\n\n        [SkippableFact]\n        public void ManipulateCommittedEvidence()\n        {\n            using (StoreFixture fx = FxConstructor())\n            {\n                var signer = TestUtils.ValidatorPrivateKeys[0];\n                var duplicateVote = ImmutableArray<Vote>.Empty\n                    .Add(new VoteMetadata(\n                        height: 1,\n                        round: 0,\n                        blockHash: fx.Block1.Hash,\n                        timestamp: DateTimeOffset.UtcNow,\n                        validatorPublicKey: signer.PublicKey,\n                        validatorPower: BigInteger.One,\n                        flag: VoteFlag.PreCommit).Sign(signer))\n                    .Add(new VoteMetadata(\n                        height: 1,\n                        round: 0,\n                        blockHash: fx.Block2.Hash,\n                        timestamp: DateTimeOffset.UtcNow,\n                        validatorPublicKey: signer.PublicKey,\n                        validatorPower: BigInteger.One,\n                        flag: VoteFlag.PreCommit).Sign(signer));\n                EvidenceBase evidence = new DuplicateVoteEvidence(\n                    duplicateVote[0],\n                    duplicateVote[1],\n                    TestUtils.ValidatorSet,\n                    duplicateVote.Last().Timestamp);\n\n                Assert.False(fx.Store.ContainsCommittedEvidence(evidence.Id));\n\n                fx.Store.PutCommittedEvidence(evidence);\n                EvidenceBase storedEvidence = fx.Store.GetCommittedEvidence(evidence.Id);\n\n                Assert.Equal(evidence, storedEvidence);\n                Assert.True(fx.Store.ContainsCommittedEvidence(evidence.Id));\n\n                fx.Store.DeleteCommittedEvidence(evidence.Id);\n                Assert.False(fx.Store.ContainsCommittedEvidence(evidence.Id));\n            }\n        }\n\n        [SkippableFact]\n        public void ForkTxNonces()\n        {\n            IStore store = Fx.Store;\n            Guid sourceChainId = Guid.NewGuid();\n            Guid destinationChainId = Guid.NewGuid();\n            store.IncreaseTxNonce(sourceChainId, Fx.Address1, 1);\n            store.IncreaseTxNonce(sourceChainId, Fx.Address2, 2);\n            store.IncreaseTxNonce(sourceChainId, Fx.Address3, 3);\n\n            store.ForkTxNonces(sourceChainId, destinationChainId);\n\n            Assert.Equal(1, store.GetTxNonce(destinationChainId, Fx.Address1));\n            Assert.Equal(2, store.GetTxNonce(destinationChainId, Fx.Address2));\n            Assert.Equal(3, store.GetTxNonce(destinationChainId, Fx.Address3));\n\n            store.IncreaseTxNonce(sourceChainId, Fx.Address1, 1);\n            Assert.Equal(2, store.GetTxNonce(sourceChainId, Fx.Address1));\n            Assert.Equal(1, store.GetTxNonce(destinationChainId, Fx.Address1));\n        }\n\n        [SkippableFact]\n        public void PruneOutdatedChains()\n        {\n            IStore store = Fx.Store;\n            store.PutBlock(Fx.GenesisBlock);\n            store.PutBlock(Fx.Block1);\n            store.PutBlock(Fx.Block2);\n            store.PutBlock(Fx.Block3);\n\n            Guid cid1 = Guid.NewGuid();\n            store.AppendIndex(cid1, Fx.GenesisBlock.Hash);\n            store.AppendIndex(cid1, Fx.Block1.Hash);\n            store.AppendIndex(cid1, Fx.Block2.Hash);\n            Assert.Single(store.ListChainIds());\n            Assert.Equal(\n                new[] { Fx.GenesisBlock.Hash, Fx.Block1.Hash, Fx.Block2.Hash },\n                store.IterateIndexes(cid1, 0, null));\n\n            Guid cid2 = Guid.NewGuid();\n            store.ForkBlockIndexes(cid1, cid2, Fx.Block1.Hash);\n            store.AppendIndex(cid2, Fx.Block2.Hash);\n            store.AppendIndex(cid2, Fx.Block3.Hash);\n            Assert.Equal(2, store.ListChainIds().Count());\n            Assert.Equal(\n                new[] { Fx.GenesisBlock.Hash, Fx.Block1.Hash, Fx.Block2.Hash, Fx.Block3.Hash },\n                store.IterateIndexes(cid2, 0, null));\n\n            Guid cid3 = Guid.NewGuid();\n            store.ForkBlockIndexes(cid1, cid3, Fx.Block2.Hash);\n            Assert.Equal(3, store.ListChainIds().Count());\n            Assert.Equal(\n                new[] { Fx.GenesisBlock.Hash, Fx.Block1.Hash, Fx.Block2.Hash },\n                store.IterateIndexes(cid3, 0, null));\n\n            Assert.Throws<InvalidOperationException>(() => store.PruneOutdatedChains());\n            store.PruneOutdatedChains(true);\n            store.SetCanonicalChainId(cid3);\n            store.PruneOutdatedChains();\n            Assert.Single(store.ListChainIds());\n            Assert.Equal(\n                new[] { Fx.GenesisBlock.Hash, Fx.Block1.Hash, Fx.Block2.Hash },\n                store.IterateIndexes(cid3, 0, null));\n            Assert.Equal(3, store.CountIndex(cid3));\n        }\n\n        [SkippableFact]\n        public void IdempotentDispose()\n        {\n#pragma warning disable S3966 // Objects should not be disposed more than once\n            Fx.Store?.Dispose();\n            Fx.Store?.Dispose();\n#pragma warning restore S3966 // Objects should not be disposed more than once\n        }\n\n        private class AtomicityTestAction : IAction\n        {\n            public ImmutableArray<byte> ArbitraryBytes { get; set; }\n\n            public ImmutableArray<byte> Md5Digest { get; set; }\n\n            public IValue PlainValue => Bencodex.Types.Dictionary.Empty\n                .Add(\"bytes\", ArbitraryBytes)\n                .Add(\"md5\", Md5Digest);\n\n            public void LoadPlainValue(IValue plainValue)\n            {\n                LoadPlainValue((Dictionary)plainValue);\n            }\n\n            public void LoadPlainValue(Dictionary plainValue)\n            {\n                ArbitraryBytes = ((Binary)plainValue[\"bytes\"]).ByteArray;\n                Md5Digest = ((Binary)plainValue[\"md5\"]).ByteArray;\n            }\n\n            public IWorld Execute(IActionContext context)\n            {\n                return context.PreviousState;\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "test/Libplanet.Tests/Store/StoreTrackLog.cs",
    "content": "using System;\nusing System.Linq;\n\nnamespace Libplanet.Tests.Store\n{\n    public sealed class StoreTrackLog : IEquatable<StoreTrackLog>\n    {\n        private StoreTrackLog(string method, object[] @params)\n        {\n            Method = method;\n            Params = @params;\n        }\n\n        public string Method { get; }\n\n        public object[] Params { get; }\n\n        public static StoreTrackLog Create(string method, params object[] @params)\n        {\n            return new StoreTrackLog(method, @params);\n        }\n\n        public bool Equals(StoreTrackLog trackLog)\n        {\n            return !(trackLog is null) && trackLog.Method == Method &&\n                   trackLog.Params.SequenceEqual(Params);\n        }\n    }\n}\n"
  },
  {
    "path": "test/Libplanet.Tests/Store/StoreTracker.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing Libplanet.Crypto;\nusing Libplanet.Store;\nusing Libplanet.Types.Blocks;\nusing Libplanet.Types.Evidence;\nusing Libplanet.Types.Tx;\n\nnamespace Libplanet.Tests.Store\n{\n    public sealed class StoreTracker : BaseTracker, IStore\n    {\n        private readonly IStore _store;\n        private bool _disposed = false;\n\n        public StoreTracker(IStore store)\n        {\n            _store = store;\n        }\n\n        public long AppendIndex(Guid chainId, BlockHash hash)\n        {\n            Log(nameof(AppendIndex), chainId, hash);\n            return _store.AppendIndex(chainId, hash);\n        }\n\n        public long CountBlocks()\n        {\n            Log(nameof(CountBlocks));\n            return _store.CountBlocks();\n        }\n\n        public long CountIndex(Guid chainId)\n        {\n            Log(nameof(CountIndex), chainId);\n            return _store.CountIndex(chainId);\n        }\n\n        public bool DeleteBlock(BlockHash blockHash)\n        {\n            Log(nameof(DeleteBlock), blockHash);\n            return _store.DeleteBlock(blockHash);\n        }\n\n        public bool ContainsBlock(BlockHash blockHash)\n        {\n            Log(nameof(ContainsBlock), blockHash);\n            return _store.ContainsBlock(blockHash);\n        }\n\n        public void PutTxExecution(TxExecution txExecution)\n        {\n            Log(nameof(PutTxExecution), txExecution);\n            _store.PutTxExecution(txExecution);\n        }\n\n        public TxExecution GetTxExecution(BlockHash blockHash, TxId txid)\n        {\n            Log(nameof(GetTxExecution), blockHash, txid);\n            return _store.GetTxExecution(blockHash, txid);\n        }\n\n        public void PutTxIdBlockHashIndex(TxId txId, BlockHash blockHash)\n        {\n            Log(nameof(PutTxIdBlockHashIndex), txId, blockHash);\n            _store.PutTxIdBlockHashIndex(txId, blockHash);\n        }\n\n        public BlockHash? GetFirstTxIdBlockHashIndex(TxId txId)\n        {\n            Log(nameof(GetFirstTxIdBlockHashIndex), txId);\n            return _store.GetFirstTxIdBlockHashIndex(txId);\n        }\n\n        public IEnumerable<BlockHash> IterateTxIdBlockHashIndex(TxId txId)\n        {\n            Log(nameof(IterateTxIdBlockHashIndex), txId);\n            return _store.IterateTxIdBlockHashIndex(txId);\n        }\n\n        public void DeleteTxIdBlockHashIndex(TxId txId, BlockHash blockHash)\n        {\n            Log(nameof(DeleteTxIdBlockHashIndex), txId, blockHash);\n            _store.DeleteTxIdBlockHashIndex(txId, blockHash);\n        }\n\n        public void DeleteChainId(Guid chainId)\n        {\n            Log(nameof(DeleteChainId), chainId);\n            _store.DeleteChainId(chainId);\n        }\n\n        public Block GetBlock(BlockHash blockHash)\n        {\n            Log(nameof(GetBlock), blockHash);\n            return _store.GetBlock(blockHash);\n        }\n\n        public long? GetBlockIndex(BlockHash blockHash)\n        {\n            Log(nameof(GetBlockIndex), blockHash);\n            return _store.GetBlockIndex(blockHash);\n        }\n\n        public BlockDigest? GetBlockDigest(BlockHash blockHash)\n        {\n            Log(nameof(GetBlockDigest), blockHash);\n            return _store.GetBlockDigest(blockHash);\n        }\n\n        public Transaction GetTransaction(TxId txid)\n        {\n            Log(nameof(GetTransaction), txid);\n            return _store.GetTransaction(txid);\n        }\n\n        public BlockHash? IndexBlockHash(Guid chainId, long index)\n        {\n            Log(nameof(IndexBlockHash), chainId, index);\n            return _store.IndexBlockHash(chainId, index);\n        }\n\n        public IEnumerable<BlockHash> IterateBlockHashes()\n        {\n            Log(nameof(IterateBlockHashes));\n            return _store.IterateBlockHashes();\n        }\n\n        public IEnumerable<BlockHash> IterateIndexes(Guid chainId, int offset, int? limit)\n        {\n             Log(nameof(IterateIndexes), chainId, offset, limit);\n             return _store.IterateIndexes(chainId, offset, limit);\n        }\n\n        public IEnumerable<Guid> ListChainIds()\n        {\n            Log(nameof(ListChainIds));\n            return _store.ListChainIds();\n        }\n\n        public void PutBlock(Block block)\n        {\n            Log(nameof(PutBlock), block);\n            _store.PutBlock(block);\n        }\n\n        public void PutTransaction(Transaction tx)\n        {\n            Log(nameof(PutTransaction), tx);\n            _store.PutTransaction(tx);\n        }\n\n        public bool ContainsTransaction(TxId txId)\n        {\n            Log(nameof(ContainsTransaction), txId);\n            return _store.ContainsTransaction(txId);\n        }\n\n        public void ForkBlockIndexes(\n            Guid sourceChainId,\n            Guid destinationChainId,\n            BlockHash branchPoint)\n        {\n            Log(nameof(ForkBlockIndexes), sourceChainId, destinationChainId, branchPoint);\n            _store.ForkBlockIndexes(sourceChainId, destinationChainId, branchPoint);\n        }\n\n        public IEnumerable<KeyValuePair<Address, long>> ListTxNonces(Guid chainId)\n        {\n            Log(nameof(ListTxNonces), chainId);\n            return _store.ListTxNonces(chainId);\n        }\n\n        public long GetTxNonce(Guid chainId, Address address)\n        {\n            Log(nameof(GetTxNonce), chainId, address);\n            return _store.GetTxNonce(chainId, address);\n        }\n\n        public void IncreaseTxNonce(Guid chainId, Address address, long delta = 1)\n        {\n            Log(nameof(IncreaseTxNonce), chainId, address, delta);\n            _store.IncreaseTxNonce(chainId, address, delta);\n        }\n\n        public void ForkTxNonces(Guid sourceChainId, Guid destinationChainId)\n        {\n            Log(nameof(ForkTxNonces), sourceChainId, destinationChainId);\n            _store.ForkTxNonces(sourceChainId, destinationChainId);\n        }\n\n        public void PruneOutdatedChains(bool noopWithoutCanon = false)\n        {\n            Log(nameof(PruneOutdatedChains));\n            _store.PruneOutdatedChains();\n        }\n\n        public BlockCommit GetChainBlockCommit(Guid chainId)\n        {\n            Log(nameof(GetChainBlockCommit), chainId);\n            return _store.GetChainBlockCommit(chainId);\n        }\n\n        public void PutChainBlockCommit(Guid chainId, BlockCommit blockCmmit)\n        {\n            Log(nameof(PutChainBlockCommit), blockCmmit);\n            _store.PutChainBlockCommit(chainId, blockCmmit);\n        }\n\n        public BlockCommit GetBlockCommit(BlockHash blockHash)\n        {\n            Log(nameof(GetBlockCommit), blockHash);\n            return _store.GetBlockCommit(blockHash);\n        }\n\n        public void PutBlockCommit(BlockCommit commit)\n        {\n            Log(nameof(PutBlockCommit), commit);\n            _store.PutBlockCommit(commit);\n        }\n\n        public void DeleteBlockCommit(BlockHash blockHash)\n        {\n            Log(nameof(DeleteBlockCommit), blockHash);\n            _store.DeleteBlockCommit(blockHash);\n        }\n\n        public IEnumerable<BlockHash> GetBlockCommitHashes()\n        {\n            Log(nameof(GetBlockCommitHashes));\n            return _store.GetBlockCommitHashes();\n        }\n\n        public IEnumerable<EvidenceId> IteratePendingEvidenceIds()\n        {\n            Log(nameof(IteratePendingEvidenceIds));\n            return _store.IteratePendingEvidenceIds();\n        }\n\n        public EvidenceBase GetPendingEvidence(EvidenceId evidenceId)\n        {\n            Log(nameof(GetPendingEvidence));\n            return _store.GetPendingEvidence(evidenceId);\n        }\n\n        public EvidenceBase GetCommittedEvidence(EvidenceId evidenceId)\n        {\n            Log(nameof(GetCommittedEvidence));\n            return _store.GetCommittedEvidence(evidenceId);\n        }\n\n        public void PutPendingEvidence(EvidenceBase evidence)\n        {\n            Log(nameof(PutPendingEvidence));\n            _store.PutPendingEvidence(evidence);\n        }\n\n        public void PutCommittedEvidence(EvidenceBase evidence)\n        {\n            Log(nameof(PutCommittedEvidence));\n            _store.PutCommittedEvidence(evidence);\n        }\n\n        public void DeletePendingEvidence(EvidenceId evidenceId)\n        {\n            Log(nameof(DeletePendingEvidence));\n            _store.DeletePendingEvidence(evidenceId);\n        }\n\n        public void DeleteCommittedEvidence(EvidenceId evidenceId)\n        {\n            Log(nameof(DeleteCommittedEvidence));\n            _store.DeleteCommittedEvidence(evidenceId);\n        }\n\n        public bool ContainsPendingEvidence(EvidenceId evidenceId)\n        {\n            Log(nameof(ContainsPendingEvidence));\n            return _store.ContainsPendingEvidence(evidenceId);\n        }\n\n        public bool ContainsCommittedEvidence(EvidenceId evidenceId)\n        {\n            Log(nameof(ContainsCommittedEvidence));\n            return _store.ContainsCommittedEvidence(evidenceId);\n        }\n\n        public Guid? GetCanonicalChainId()\n        {\n            Log(nameof(GetCanonicalChainId));\n            return _store.GetCanonicalChainId();\n        }\n\n        public void SetCanonicalChainId(Guid chainId)\n        {\n            Log(nameof(SetCanonicalChainId), chainId);\n            _store.SetCanonicalChainId(chainId);\n        }\n\n        public void Dispose()\n        {\n            if (!_disposed)\n            {\n                _store?.Dispose();\n                _disposed = true;\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "test/Libplanet.Tests/Store/StoreTrackerTest.cs",
    "content": "using System;\nusing Xunit;\n\nnamespace Libplanet.Tests.Store\n{\n    public sealed class StoreTrackerTest\n    {\n        private readonly StoreFixture _fx;\n        private readonly StoreTracker _tracker;\n\n        public StoreTrackerTest()\n        {\n            _fx = new MemoryStoreFixture();\n            _tracker = new StoreTracker(_fx.Store);\n        }\n\n        [Fact]\n        public void LogsAreEmptyAtFirst()\n        {\n            Assert.Empty(_tracker.Logs);\n        }\n\n        [Fact]\n        public void MethodCallsAreLogged()\n        {\n            _tracker.ListChainIds();\n            Assert.Equal(1, _tracker.Logs.Count);\n            Assert.Equal(\n                StoreTrackLog.Create(\"ListChainIds\"),\n                _tracker.Logs[0]);\n\n            var chainId = Guid.NewGuid();\n            _tracker.CountIndex(chainId);\n            Assert.Equal(2, _tracker.Logs.Count);\n            Assert.Equal(StoreTrackLog.Create(\"CountIndex\", chainId), _tracker.Logs[1]);\n        }\n\n        [Fact]\n        public void ClearLogs()\n        {\n            _tracker.ListChainIds();\n            _tracker.CountIndex(Guid.NewGuid());\n            Assert.Equal(2, _tracker.Logs.Count);\n\n            _tracker.ClearLogs();\n            Assert.Empty(_tracker.Logs);\n        }\n    }\n}\n"
  },
  {
    "path": "test/Libplanet.Tests/Store/Trie/BytesEqualityComparer.cs",
    "content": "using System.Collections.Generic;\nusing System.Linq;\n\nnamespace Libplanet.Tests.Store.Trie\n{\n    internal class BytesEqualityComparer : IEqualityComparer<byte[]>\n    {\n        public bool Equals(byte[] x, byte[] y) =>\n            x is byte[] xb && y is byte[] yb &&\n            xb.LongLength == yb.LongLength &&\n            xb.SequenceEqual(yb);\n\n        public int GetHashCode(byte[] obj)\n        {\n            int hash = 17;\n            unchecked\n            {\n                foreach (byte b in obj)\n                {\n                    hash *= 31 + b;\n                }\n            }\n\n            return hash;\n        }\n    }\n}\n"
  },
  {
    "path": "test/Libplanet.Tests/Store/Trie/CacheableKeyValueStoreTest.cs",
    "content": "using System;\nusing Libplanet.Store.Trie;\n\nnamespace Libplanet.Tests.Store.Trie\n{\n    public class CacheableKeyValueStoreTest : KeyValueStoreTest, IDisposable\n    {\n        private readonly CacheableKeyValueStore _cacheableKeyValueStore;\n\n        public CacheableKeyValueStoreTest()\n        {\n            // Memory mode.\n            KeyValueStore = _cacheableKeyValueStore =\n                new CacheableKeyValueStore(new DefaultKeyValueStore(null));\n            InitializePreStoredData();\n        }\n\n        public void Dispose()\n        {\n            _cacheableKeyValueStore.Dispose();\n        }\n    }\n}\n"
  },
  {
    "path": "test/Libplanet.Tests/Store/Trie/DefaultKeyValueStoreTest.cs",
    "content": "using System;\nusing Libplanet.Store.Trie;\n\nnamespace Libplanet.Tests.Store.Trie\n{\n    public class DefaultKeyValueStoreTest : KeyValueStoreTest, IDisposable\n    {\n        private readonly DefaultKeyValueStore _defaultKeyValueStore;\n\n        public DefaultKeyValueStoreTest()\n        {\n            // Memory mode.\n            KeyValueStore = _defaultKeyValueStore = new DefaultKeyValueStore(null);\n            InitializePreStoredData();\n        }\n\n        public void Dispose()\n        {\n            _defaultKeyValueStore.Dispose();\n        }\n    }\n}\n"
  },
  {
    "path": "test/Libplanet.Tests/Store/Trie/KeyBytesTest.cs",
    "content": "using System;\nusing System.Collections.Immutable;\nusing Libplanet.Store.Trie;\nusing Xunit;\nusing static Libplanet.Tests.TestUtils;\n\nnamespace Libplanet.Tests.Store.Trie\n{\n    public class KeyBytesTest\n    {\n        [Fact]\n        public void Constructors()\n        {\n            AssertBytesEqual(ImmutableArray<byte>.Empty, default(KeyBytes).ByteArray);\n            AssertBytesEqual(\n                ImmutableArray<byte>.Empty,\n                new KeyBytes(string.Empty).ByteArray\n            );\n            AssertBytesEqual(\n                ImmutableArray<byte>.Empty.Add(1).Add(2).Add(3).Add(4),\n                new KeyBytes(ImmutableArray<byte>.Empty.Add(1).Add(2).Add(3).Add(4)).ByteArray\n            );\n            AssertBytesEqual(\n                new KeyBytes(ImmutableArray.Create<byte>(1, 2, 3, 4, 5)).ByteArray,\n                new KeyBytes(1, 2, 3, 4, 5).ByteArray\n            );\n            AssertBytesEqual(\n                new KeyBytes(ImmutableArray.Create<byte>(0x66, 0x6f, 0x6f)).ByteArray,\n                new KeyBytes(\"foo\").ByteArray\n            );\n        }\n\n        [Fact]\n        public void Length()\n        {\n            Assert.Equal(0, default(KeyBytes).Length);\n            Assert.Equal(2, new KeyBytes(0, 0).Length);\n            Assert.Equal(4, new KeyBytes(1, 2, 3, 4).Length);\n            Assert.Equal(5, new KeyBytes(1, 2, 3, 4, 5).Length);\n        }\n\n        [Fact]\n        public void ByteArray()\n        {\n            KeyBytes empty = default;\n            AssertBytesEqual(ImmutableArray<byte>.Empty, empty.ByteArray);\n            AssertBytesEqual(Array.Empty<byte>(), empty.ToByteArray());\n\n            var foo = new KeyBytes(0x66, 0x6f, 0x6f);\n            AssertBytesEqual(ImmutableArray.Create<byte>(0x66, 0x6f, 0x6f), foo.ByteArray);\n            AssertBytesEqual(new byte[] { 0x66, 0x6f, 0x6f }, foo.ToByteArray());\n        }\n\n        [Fact]\n        public void FromHex()\n        {\n            Assert.Equal(default, KeyBytes.FromHex(string.Empty));\n            Assert.Equal(new KeyBytes(1, 2, 3), KeyBytes.FromHex(\"010203\"));\n            Assert.Equal(new KeyBytes(0xab, 0xcd, 0xef), KeyBytes.FromHex(\"AbcdeF\"));\n            Assert.Throws<ArgumentOutOfRangeException>(() => KeyBytes.FromHex(\"abc\"));\n            Assert.Throws<FormatException>(() => KeyBytes.FromHex(\"zzzz\"));\n            Assert.Throws<FormatException>(() => KeyBytes.FromHex(\"0xabcd\"));\n        }\n\n        [Fact]\n        public void Hex()\n        {\n            KeyBytes empty = default;\n            var b123 = new KeyBytes(1, 2, 3);\n            var b122 = new KeyBytes(1, 2, 2);\n            var b1234 = new KeyBytes(1, 2, 3, 4);\n\n            Assert.Empty(empty.Hex);\n            Assert.Equal(\"010203\", b123.Hex);\n            Assert.Equal(\"010202\", b122.Hex);\n            Assert.Equal(\"01020304\", b1234.Hex);\n        }\n\n        [Fact]\n        public void Equality()\n        {\n            KeyBytes empty = default;\n            var b123 = new KeyBytes(1, 2, 3);\n            var b122 = new KeyBytes(1, 2, 2);\n            var b1234 = new KeyBytes(1, 2, 3, 4);\n\n            Assert.True(empty.Equals(new KeyBytes(Array.Empty<byte>())));\n            Assert.False(empty.Equals(b123));\n            Assert.False(empty.Equals(b122));\n            Assert.False(empty.Equals(b1234));\n            Assert.True(empty == new KeyBytes(Array.Empty<byte>()));\n            Assert.False(empty == b123);\n            Assert.False(empty == b122);\n            Assert.False(empty == b1234);\n            Assert.False(empty != new KeyBytes(Array.Empty<byte>()));\n            Assert.True(empty != b123);\n            Assert.True(empty != b122);\n            Assert.True(empty != b1234);\n            Assert.False(empty.Equals((object)Array.Empty<byte>()));\n            Assert.True(empty.Equals((object)new KeyBytes(Array.Empty<byte>())));\n            Assert.False(empty.Equals((object)b123));\n            Assert.False(empty.Equals((object)b122));\n            Assert.False(empty.Equals((object)b1234));\n            Assert.False(empty.Equals((object)null));\n            Assert.Equal(empty.GetHashCode(), new KeyBytes(Array.Empty<byte>()).GetHashCode());\n            Assert.NotEqual(empty.GetHashCode(), b123.GetHashCode());\n            Assert.NotEqual(empty.GetHashCode(), b122.GetHashCode());\n            Assert.NotEqual(empty.GetHashCode(), b1234.GetHashCode());\n\n            Assert.False(b123.Equals(empty));\n            Assert.True(b123.Equals(new KeyBytes(1, 2, 3)));\n            Assert.False(b123.Equals(b122));\n            Assert.False(b123.Equals(b1234));\n            Assert.False(b123 == new KeyBytes(Array.Empty<byte>()));\n            Assert.True(b123 == new KeyBytes(1, 2, 3));\n            Assert.False(b123 == b122);\n            Assert.False(b123 == b1234);\n            Assert.True(b123 != default);\n            Assert.False(b123 != new KeyBytes(1, 2, 3));\n            Assert.True(b123 != b122);\n            Assert.True(b123 != b1234);\n            Assert.False(b123.Equals((object)default(KeyBytes)));\n            Assert.True(b123.Equals((object)b123));\n            Assert.False(b123.Equals((object)b122));\n            Assert.False(b123.Equals((object)b1234));\n            Assert.False(b123.Equals((object)null));\n            Assert.NotEqual(b123.GetHashCode(), default(KeyBytes).GetHashCode());\n            Assert.Equal(b123.GetHashCode(), new KeyBytes(1, 2, 3).GetHashCode());\n            Assert.NotEqual(b123.GetHashCode(), b122.GetHashCode());\n            Assert.NotEqual(b123.GetHashCode(), b1234.GetHashCode());\n        }\n\n        [Fact]\n        public void String()\n        {\n            KeyBytes empty = default;\n            var b123 = new KeyBytes(1, 2, 3);\n            var b122 = new KeyBytes(1, 2, 2);\n            var b1234 = new KeyBytes(1, 2, 3, 4);\n\n            Assert.Equal(\"KeyBytes (0 B)\", empty.ToString());\n            Assert.Equal(\"KeyBytes (3 B) 010203\", b123.ToString());\n            Assert.Equal(\"KeyBytes (3 B) 010202\", b122.ToString());\n            Assert.Equal(\"KeyBytes (4 B) 01020304\", b1234.ToString());\n        }\n    }\n}\n"
  },
  {
    "path": "test/Libplanet.Tests/Store/Trie/KeyValueStoreTest.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Collections.Immutable;\nusing System.Linq;\nusing Libplanet.Store.Trie;\nusing Xunit;\n\nnamespace Libplanet.Tests.Store.Trie\n{\n    public abstract class KeyValueStoreTest\n    {\n        private const int PreStoredDataCount = 10;\n\n        private const int PreStoredDataKeySize = 16;\n\n        private const int PreStoredDataValueSize = 32;\n\n        protected IKeyValueStore KeyValueStore { get; set; }\n\n        protected Random Random { get; } = new Random();\n\n        private KeyBytes[] PreStoredDataKeys { get; set; }\n\n        private byte[][] PreStoredDataValues { get; set; }\n\n        [SkippableFact]\n        public void Get()\n        {\n            foreach (var (key, expectedValue) in PreStoredDataKeys.Zip(\n                PreStoredDataValues, ValueTuple.Create))\n            {\n                var actual = KeyValueStore.Get(key);\n                Assert.Equal(expectedValue, actual);\n            }\n\n            var randomKey = NewRandomKey();\n            Assert.Throws<KeyNotFoundException>(() => KeyValueStore.Get(randomKey));\n        }\n\n        [SkippableFact]\n        public void Set()\n        {\n            var key = new KeyBytes(Random.NextBytes(PreStoredDataKeySize));\n            byte[] value = Random.NextBytes(PreStoredDataValueSize);\n            KeyValueStore.Set(key, value);\n\n            Assert.Equal(value, KeyValueStore.Get(key));\n        }\n\n        [SkippableFact]\n        public void SetMany()\n        {\n            var values = new Dictionary<KeyBytes, byte[]>();\n            foreach (int i in Enumerable.Range(0, 10))\n            {\n                values[new KeyBytes(Random.NextBytes(PreStoredDataKeySize))] =\n                    Random.NextBytes(PreStoredDataValueSize);\n            }\n\n            KeyValueStore.Set(values);\n\n            foreach (KeyValuePair<KeyBytes, byte[]> kv in values)\n            {\n                Assert.Equal(kv.Value, KeyValueStore.Get(kv.Key));\n            }\n        }\n\n        // This test will cover DefaultKeyValueStore.Set\n        [SkippableFact]\n        public void Overwrite()\n        {\n            foreach (var (key, expectedValue) in PreStoredDataKeys.Zip(\n                PreStoredDataValues, ValueTuple.Create))\n            {\n                var randomValue = Random.NextBytes(PreStoredDataValueSize);\n                var actual = KeyValueStore.Get(key);\n                Assert.Equal(expectedValue, actual);\n\n                KeyValueStore.Set(key, randomValue);\n                actual = KeyValueStore.Get(key);\n                Assert.Equal(randomValue, actual);\n                Assert.NotEqual(expectedValue, actual);\n            }\n        }\n\n        [SkippableFact]\n        public virtual void Delete()\n        {\n            foreach (KeyBytes key in PreStoredDataKeys)\n            {\n                KeyValueStore.Delete(key);\n                Assert.False(KeyValueStore.Exists(key));\n            }\n\n            KeyBytes nonExistent = NewRandomKey();\n            KeyValueStore.Delete(nonExistent);\n            Assert.False(KeyValueStore.Exists(nonExistent));\n        }\n\n        [SkippableFact]\n        public virtual void DeleteMany()\n        {\n            KeyBytes[] nonExistentKeys = Enumerable.Range(0, 10)\n                .Select(_ => NewRandomKey())\n                .ToArray();\n            KeyBytes[] keys = PreStoredDataKeys\n                .Concat(PreStoredDataKeys.Take(PreStoredDataCount / 2))\n                .Concat(nonExistentKeys)\n                .ToArray();\n            KeyValueStore.Delete(keys);\n            Assert.All(keys, k => Assert.False(KeyValueStore.Exists(k)));\n        }\n\n        [SkippableFact]\n        public void Exists()\n        {\n            foreach (var (key, _) in PreStoredDataKeys.Zip(PreStoredDataValues, ValueTuple.Create))\n            {\n                Assert.True(KeyValueStore.Exists(key));\n            }\n\n            var randomKey = NewRandomKey();\n            Assert.False(KeyValueStore.Exists(randomKey));\n        }\n\n        [SkippableFact]\n        public void ListKeys()\n        {\n            ImmutableHashSet<KeyBytes> keys = KeyValueStore.ListKeys().ToImmutableHashSet();\n            Assert.Equal(PreStoredDataCount, keys.Count);\n            Assert.True(PreStoredDataKeys.ToImmutableHashSet().SetEquals(keys));\n        }\n\n        public KeyBytes NewRandomKey()\n        {\n            KeyBytes randomKey;\n            do\n            {\n                randomKey = new KeyBytes(Random.NextBytes(PreStoredDataKeySize));\n            }\n            while (KeyValueStore.Exists(randomKey));\n\n            return randomKey;\n        }\n\n        protected void InitializePreStoredData()\n        {\n            PreStoredDataKeys = new KeyBytes[PreStoredDataCount];\n            PreStoredDataValues = new byte[PreStoredDataCount][];\n\n            for (int i = 0; i < PreStoredDataCount; ++i)\n            {\n                PreStoredDataKeys[i] = new KeyBytes(Random.NextBytes(PreStoredDataKeySize));\n                PreStoredDataValues[i] = Random.NextBytes(PreStoredDataValueSize);\n                KeyValueStore.Set(PreStoredDataKeys[i], PreStoredDataValues[i]);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "test/Libplanet.Tests/Store/Trie/MerkleTrieDiffTest.cs",
    "content": "using System.Linq;\nusing Bencodex.Types;\nusing Libplanet.Store;\nusing Libplanet.Store.Trie;\nusing Xunit;\n\nnamespace Libplanet.Tests.Store.Trie\n{\n    public class MerkleTrieDiffTest\n    {\n        [Fact]\n        public void EmptySourceNode()\n        {\n            KeyBytes k01 = KeyBytes.FromHex(\"01\");\n            IValue v01 = new Text(\"01\");\n\n            IKeyValueStore keyValueStore = new MemoryKeyValueStore();\n            IStateStore stateStore = new TrieStateStore(keyValueStore);\n            ITrie source = stateStore.GetStateRoot(null);\n            ITrie target = stateStore.GetStateRoot(null);\n            Assert.Null(target.Root);\n            Assert.Empty(((MerkleTrie)source).Diff((MerkleTrie)target));\n\n            target = target.Set(k01, v01);\n            target = stateStore.Commit(target);\n            Assert.NotNull(target.Root);\n            Assert.Empty(source.Diff(target));\n        }\n\n        [Fact]\n        public void ValueSourceNode()\n        {\n            KeyBytes k = KeyBytes.FromHex(string.Empty);\n            IValue v = new Text(string.Empty);\n\n            IKeyValueStore keyValueStore = new MemoryKeyValueStore();\n            IStateStore stateStore = new TrieStateStore(keyValueStore);\n            ITrie source = stateStore.GetStateRoot(null);\n            source = source.Set(k, v);\n            source = stateStore.Commit(source);\n\n            ITrie target = stateStore.GetStateRoot(null);\n            var diff = source.Diff(target).ToList();\n            Assert.Single(diff);\n            Assert.Contains((k, null, v), diff);\n        }\n\n        [Theory]\n        [InlineData(false, false)]\n        [InlineData(false, true)]\n        [InlineData(true, false)]\n        [InlineData(true, true)]\n        public void Diff(bool commitSource, bool commitTarget)\n        {\n            KeyBytes k00 = KeyBytes.FromHex(\"00\");\n            IValue v00 = new Text(\"00\");\n            KeyBytes k01 = KeyBytes.FromHex(\"01\");\n            IValue v01 = new Text(\"01\");\n            IValue v01a = new Text(\"01A\");\n            KeyBytes k0000 = KeyBytes.FromHex(\"0000\");\n            IValue v0000 = new Text(\"0000\");\n            KeyBytes k0010 = KeyBytes.FromHex(\"0010\");\n            IValue v0010 = new Text(\"0010\");\n            IValue v0010a = new Text(\"0010A\");\n\n            IKeyValueStore keyValueStore = new MemoryKeyValueStore();\n            IStateStore stateStore = new TrieStateStore(keyValueStore);\n            ITrie source = stateStore.GetStateRoot(null);\n            source = source.Set(k00, v00);\n            source = source.Set(k01, v01);\n            source = source.Set(k0000, v0000);\n            source = source.Set(k0010, v0010);\n            source = commitSource ? stateStore.Commit(source) : source;\n\n            // Same value for K00 and missing value for K0000\n            ITrie target = stateStore.GetStateRoot(null);\n            target = target.Set(k00, v00);\n            target = target.Set(k01, v01a);\n            target = target.Set(k0010, v0010a);\n            target = commitTarget ? stateStore.Commit(target) : target;\n\n            // source - target\n            var diff = source.Diff(target).ToList();\n            Assert.Equal(3, diff.Count);    // K01, K0000, K0010\n            Assert.Contains((k01, v01a, v01), diff);\n            Assert.Contains((k0000, null, v0000), diff);\n            Assert.Contains((k0010, v0010a, v0010), diff);\n\n            // target - source\n            diff = target.Diff(source).ToList();\n            Assert.Equal(2, diff.Count);    // K01, K0010\n            Assert.Contains((k01, v01, v01a), diff);\n            Assert.Contains((k0010, v0010, v0010a), diff);\n        }\n    }\n}"
  },
  {
    "path": "test/Libplanet.Tests/Store/Trie/MerkleTrieProofTest.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Collections.Immutable;\nusing System.Security.Cryptography;\nusing Bencodex;\nusing Bencodex.Types;\nusing Libplanet.Common;\nusing Libplanet.Store;\nusing Libplanet.Store.Trie;\nusing Libplanet.Store.Trie.Nodes;\nusing Xunit;\n\nnamespace Libplanet.Tests.Store.Trie\n{\n    public class MerkleTrieProofTest\n    {\n        public readonly IStateStore StateStore;\n\n        // \"1b16b1df538ba12dc3f97edbb85caa7050d46c148134290feba80f8236c83db9\"\n        public readonly ITrie EmptyTrie;\n\n        // Note that * denotes an existence of a value and L denotes the encoded length.\n        // Structure:\n        // [HashNode:L35]\n        // |\n        // |\n        // [ShortNode:L24]\n        // |\n        // | 0\n        // [FullNode:L19]\n        // |\n        // |___________________\n        // | 0                 | 1\n        // [ValueNode:*:L08]   [ValueNode:*:L08]\n        public readonly ITrie HalfTrie;\n\n        public readonly HashDigest<SHA256> HalfTrieHash = new HashDigest<SHA256>(\n            ByteUtil.ParseHex(\"6cc5c2ca1b7b146268f0d930c58c7e5441b807e72cf16d56f52c869a594b17bf\"));\n\n        // An uncommitted instance of FullTrie.\n        public readonly ITrie UncommittedTrie;\n\n        // Note that * denotes an existence of a value and L denotes the encoded length.\n        // Structure:\n        // [HashNode:L35]\n        // |\n        // |\n        // [ShortNode:L40]\n        // |\n        // | 0\n        // [HashNode:35]-------[FullNode:L60]\n        //                     |\n        // ____________________|___________________\n        // | 0                                    | 1\n        // [HashNode:L35]------[FullNode:*:L74]   [ValueNode:*:L08]\n        // ____________________|\n        // | 0                 | 1\n        // [ShortNode:L15]     [HashNode:L35]-----[ShortNode:L40]\n        // |                                      |\n        // | 0                                    | 0\n        // [ValueNode:*:L10]                      [HashNode:L35]-----[ValueNode:*:L39]\n        public readonly ITrie FullTrie;\n\n        public readonly HashDigest<SHA256> FullTrieHash = new HashDigest<SHA256>(\n            ByteUtil.ParseHex(\"979a00921d42d2ca63e98c1c2ac07f0eacbb99e363b8f2f7f8e4d19c854b6c20\"));\n\n        public readonly KeyBytes K00 = KeyBytes.FromHex(\"00\");\n        public readonly KeyBytes K01 = KeyBytes.FromHex(\"01\");\n        public readonly KeyBytes K0000 = KeyBytes.FromHex(\"0000\");\n        public readonly KeyBytes K0010 = KeyBytes.FromHex(\"0010\");\n\n        public readonly IValue V00 = new Text(\"00\");\n        public readonly IValue V01 = new Text(\"01\");\n        public readonly IValue V0000 = new Text(\"0000\");\n        public readonly IValue V0010 = new Text(\"00000000000000000000000000000010\");\n\n        public readonly IReadOnlyList<INode> P00;\n        public readonly IReadOnlyList<INode> P01;\n        public readonly IReadOnlyList<INode> P0000;\n        public readonly IReadOnlyList<INode> P0010;\n\n        private static readonly Codec _codec = new Codec();\n\n        public MerkleTrieProofTest()\n        {\n            StateStore = new TrieStateStore(new MemoryKeyValueStore());\n            ITrie trie = StateStore.GetStateRoot(null);\n            EmptyTrie = trie;\n\n            trie = trie.Set(K00, V00);\n            trie = trie.Set(K01, V01);\n            trie = StateStore.Commit(trie);\n            HalfTrie = trie;\n\n            trie = trie.Set(K0000, V0000);\n            trie = trie.Set(K0010, V0010);\n            UncommittedTrie = trie;\n            trie = StateStore.Commit(trie);\n            FullTrie = trie;\n\n            Nibbles n0 = new Nibbles(new byte[] { 0 }.ToImmutableArray());\n\n            INode proofNode0010 = new ValueNode(V0010);\n            INode proofNode001 = new ShortNode(n0, ToHashNode(proofNode0010));\n            INode proofNode00 = FullNode.Empty\n                .SetChild(0, new ShortNode(n0, new ValueNode(V0000)))\n                .SetChild(1, ToHashNode(proofNode001))\n                .SetChild(FullNode.ChildrenCount - 1, new ValueNode(V00));\n            INode proofNode0 = FullNode.Empty\n                .SetChild(0, ToHashNode(proofNode00))\n                .SetChild(1, new ValueNode(V01));\n            INode proofRoot = new ShortNode(n0, ToHashNode(proofNode0));\n            P00 = new List<INode>() { proofRoot, proofNode0, proofNode00 };\n            P01 = new List<INode>() { proofRoot, proofNode0 };\n            P0000 = new List<INode>() { proofRoot, proofNode0, proofNode00 };\n            P0010 = new List<INode>()\n                { proofRoot, proofNode0, proofNode00, proofNode001, proofNode0010 };\n        }\n\n        [Fact]\n        public void CheckFixtures()\n        {\n            Assert.Equal(HalfTrieHash, HalfTrie.Hash);\n            Assert.Equal(FullTrieHash, FullTrie.Hash);\n        }\n\n        [Fact]\n        public void GetProof()\n        {\n            var proof = ((MerkleTrie)FullTrie).GenerateProof(K00, V00);\n            Assert.Equal(P00, proof);\n\n            proof = ((MerkleTrie)FullTrie).GenerateProof(K01, V01);\n            Assert.Equal(P01, proof);\n\n            proof = ((MerkleTrie)FullTrie).GenerateProof(K0000, V0000);\n            Assert.Equal(P0000, proof);\n\n            proof = ((MerkleTrie)FullTrie).GenerateProof(K0010, V0010);\n            Assert.Equal(P0010, proof);\n\n            KeyBytes k = KeyBytes.FromHex(string.Empty);\n            IValue v = new Text(string.Empty);\n            var trie = StateStore.Commit(EmptyTrie.Set(k, v));\n            proof = ((MerkleTrie)trie).GenerateProof(k, v);\n            Assert.Equal(v, Assert.IsType<ValueNode>(Assert.Single(proof)).Value);\n\n            trie = StateStore.Commit(FullTrie.Set(k, v));\n            proof = ((MerkleTrie)trie).GenerateProof(k, v);\n            Assert.Equal(\n                v,\n                Assert.IsType<ValueNode>(\n                    Assert.IsType<FullNode>(\n                        Assert.Single(proof)).Value).Value);\n        }\n\n        [Fact]\n        public void DifferentRootsProduceDifferentProofs()\n        {\n            var proof1 = ((MerkleTrie)FullTrie).GenerateProof(K00, V00);\n            var proof2 = ((MerkleTrie)HalfTrie).GenerateProof(K00, V00);\n            Assert.NotEqual(proof1.Count, proof2.Count);\n\n            Assert.True(\n                MerkleTrie.ValidateProof(FullTrieHash, proof1, K00, V00));\n            Assert.False(\n                MerkleTrie.ValidateProof(FullTrieHash, proof2, K00, V00));\n            Assert.False(\n                MerkleTrie.ValidateProof(HalfTrieHash, proof1, K00, V00));\n            Assert.True(\n                MerkleTrie.ValidateProof(HalfTrieHash, proof2, K00, V00));\n        }\n\n        [Fact]\n        public void InvalidGenerateProofCalls()\n        {\n            Assert.Contains(\n                \"recorded\",\n                Assert.Throws<InvalidOperationException>(\n                    () => ((MerkleTrie)UncommittedTrie).GenerateProof(K00, V00)).Message);\n            Assert.Contains(\n                \"non-null\",\n                Assert.Throws<InvalidOperationException>(\n                    () => ((MerkleTrie)EmptyTrie).GenerateProof(K00, V00)).Message);\n            Assert.Contains(\n                \"does not match\",\n                Assert.Throws<ArgumentException>(\n                    () => ((MerkleTrie)FullTrie).GenerateProof(K00, V01)).Message);\n            Assert.Contains(\n                \"could not be fully resolved\",\n                Assert.Throws<ArgumentException>(\n                    () => ((MerkleTrie)FullTrie).GenerateProof(\n                        KeyBytes.FromHex(\"000000\"), V0000)).Message);\n            Assert.Contains(\n                \"could not be properly resolved\",\n                Assert.Throws<ArgumentException>(\n                    () => ((MerkleTrie)FullTrie).GenerateProof(\n                        KeyBytes.FromHex(\"0020\"), V0000)).Message);\n        }\n\n        [Fact]\n        public void ValidateProof()\n        {\n            Assert.True(MerkleTrie.ValidateProof(\n                FullTrieHash,\n                ((MerkleTrie)FullTrie).GenerateProof(K00, V00),\n                K00,\n                V00));\n            Assert.True(MerkleTrie.ValidateProof(\n                FullTrieHash,\n                ((MerkleTrie)FullTrie).GenerateProof(K01, V01),\n                K01,\n                V01));\n            Assert.True(MerkleTrie.ValidateProof(\n                FullTrieHash,\n                ((MerkleTrie)FullTrie).GenerateProof(K0000, V0000),\n                K0000,\n                V0000));\n            Assert.True(MerkleTrie.ValidateProof(\n                FullTrieHash,\n                ((MerkleTrie)FullTrie).GenerateProof(K0010, V0010),\n                K0010,\n                V0010));\n\n            Assert.False(MerkleTrie.ValidateProof(\n                HalfTrieHash,\n                ((MerkleTrie)FullTrie).GenerateProof(K00, V00),\n                K00,\n                V00));  // Wrong hash\n            Assert.False(MerkleTrie.ValidateProof(\n                FullTrieHash,\n                ((MerkleTrie)FullTrie).GenerateProof(K00, V00),\n                K00,\n                V01));  // Wrong value\n            Assert.False(MerkleTrie.ValidateProof(\n                FullTrieHash,\n                ((MerkleTrie)FullTrie).GenerateProof(K00, V00),\n                K01,\n                V00));  // Wrong key\n            Assert.False(MerkleTrie.ValidateProof(\n                FullTrieHash,\n                ((MerkleTrie)FullTrie).GenerateProof(K00, V00),\n                K01,\n                V01));  // Wrong proof\n        }\n\n        private HashNode ToHashNode(INode node) =>\n            new HashNode(HashDigest<SHA256>.DeriveFrom(_codec.Encode(node.ToBencodex())));\n   }\n}\n"
  },
  {
    "path": "test/Libplanet.Tests/Store/Trie/MerkleTrieTest.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Security.Cryptography;\nusing System.Text;\nusing Bencodex.Types;\nusing Libplanet.Common;\nusing Libplanet.Store;\nusing Libplanet.Store.Trie;\nusing Libplanet.Store.Trie.Nodes;\nusing Xunit;\nusing static System.Linq.Enumerable;\nusing static Libplanet.Common.HashDigest<System.Security.Cryptography.SHA256>;\nusing static Libplanet.Tests.TestUtils;\n\nnamespace Libplanet.Tests.Store.Trie\n{\n    public class MerkleTrieTest\n    {\n        [Fact]\n        public void ConstructWithHashDigest()\n        {\n            var hashDigest = new HashDigest<SHA256>(GetRandomBytes(Size));\n            var merkleTrie = new MerkleTrie(new MemoryKeyValueStore(), hashDigest);\n            Assert.Equal(hashDigest, merkleTrie.Hash);\n\n            // See https://github.com/planetarium/libplanet/pull/1091\n            merkleTrie = new MerkleTrie(new MemoryKeyValueStore(), MerkleTrie.EmptyRootHash);\n            Assert.Null(merkleTrie.Root);\n        }\n\n        [Fact]\n        public void ConstructWithRootNode()\n        {\n            var hashDigest = new HashDigest<SHA256>(GetRandomBytes(Size));\n            INode rootNode = new HashNode(hashDigest);\n            var merkleTrie = new MerkleTrie(new MemoryKeyValueStore(), rootNode);\n            Assert.Equal(hashDigest, merkleTrie.Hash);\n        }\n\n        [Fact]\n        public void IterateValues()\n        {\n            IKeyValueStore keyValueStore = new MemoryKeyValueStore();\n            IStateStore stateStore = new TrieStateStore(keyValueStore);\n            ITrie trie = stateStore.GetStateRoot(null);\n\n            trie = trie\n                .Set(new KeyBytes(0x01), Null.Value)\n                .Set(new KeyBytes(0x02), Null.Value)\n                .Set(new KeyBytes(0x03), Null.Value)\n                .Set(new KeyBytes(0x04), Null.Value)\n                .Set(new KeyBytes(0xbe, 0xef), Dictionary.Empty);\n\n            Dictionary<KeyBytes, IValue> states = trie\n                .IterateValues()\n                .ToDictionary(pair => pair.Path, pair => pair.Value);\n            Assert.Equal(5, states.Count);\n            Assert.Equal(Null.Value, states[new KeyBytes(0x01)]);\n            Assert.Equal(Null.Value, states[new KeyBytes(0x02)]);\n            Assert.Equal(Null.Value, states[new KeyBytes(0x03)]);\n            Assert.Equal(Null.Value, states[new KeyBytes(0x04)]);\n            Assert.Equal(Dictionary.Empty, states[new KeyBytes(0xbe, 0xef)]);\n\n            trie = stateStore.Commit(trie);\n            states = trie.IterateValues().ToDictionary(pair => pair.Path, pair => pair.Value);\n            Assert.Equal(5, states.Count);\n            Assert.Equal(Null.Value, states[new KeyBytes(0x01)]);\n            Assert.Equal(Null.Value, states[new KeyBytes(0x02)]);\n            Assert.Equal(Null.Value, states[new KeyBytes(0x03)]);\n            Assert.Equal(Null.Value, states[new KeyBytes(0x04)]);\n            Assert.Equal(Dictionary.Empty, states[new KeyBytes(0xbe, 0xef)]);\n        }\n\n        [Fact]\n        public void IterateNodes()\n        {\n            IStateStore stateStore = new TrieStateStore(new MemoryKeyValueStore());\n            MerkleTrie merkleTrie = (MerkleTrie)stateStore.GetStateRoot(null);\n            // There is nothing.\n            Assert.Empty(merkleTrie.IterateNodes());\n\n            merkleTrie = (MerkleTrie)merkleTrie.Set(\n                new KeyBytes(0xbe, 0xef),\n                Dictionary.Empty.Add(GetRandomBytes(32), Null.Value));\n            // There are (ShortNode, ValueNode)\n            Assert.Equal(2, merkleTrie.IterateNodes().Count());\n\n            merkleTrie = (MerkleTrie)stateStore.Commit(merkleTrie);\n            // There are (HashNode, ShortNode, HashNode, ValueNode)\n            Assert.Equal(4, merkleTrie.IterateNodes().Count());\n        }\n\n        [Theory]\n        [InlineData(true, \"_\")]\n        [InlineData(false, \"_\")]\n        [InlineData(true, \"_1ab3_639e\")]\n        [InlineData(false, \"_1ab3_639e\")]\n        public void IterateSubTrie(bool commit, string extraKey)\n        {\n            IStateStore stateStore = new TrieStateStore(new MemoryKeyValueStore());\n            ITrie trie = stateStore.GetStateRoot(null);\n\n            string prefix = \"_\";\n            string[] keys =\n            {\n                \"1b418c98\",\n                \"__3b8a\",\n                \"___\",\n            };\n\n            foreach (var key in keys)\n            {\n                trie = trie.Set(new KeyBytes(Encoding.ASCII.GetBytes(key)), new Text(key));\n            }\n\n            trie = commit ? stateStore.Commit(trie) : trie;\n            Assert.Empty(\n                ((MerkleTrie)trie)\n                    .IterateSubTrieNodes(new KeyBytes(Encoding.ASCII.GetBytes(prefix))));\n            Assert.Empty(\n                ((MerkleTrie)trie)\n                    .IterateSubTrieValues(new KeyBytes(Encoding.ASCII.GetBytes(prefix))));\n\n            trie = trie.Set(new KeyBytes(Encoding.ASCII.GetBytes(extraKey)), new Text(extraKey));\n            trie = commit ? stateStore.Commit(trie) : trie;\n            Assert.Equal(\n                3,\n                ((MerkleTrie)trie)\n                    .IterateSubTrieNodes(new KeyBytes(Encoding.ASCII.GetBytes(prefix)))\n                    .Count(pair => pair.Node is ValueNode));\n            Assert.Equal(\n                3,\n                ((MerkleTrie)trie)\n                    .IterateSubTrieValues(new KeyBytes(Encoding.ASCII.GetBytes(prefix)))\n                    .Count());\n        }\n\n        [Theory]\n        [InlineData(true)]\n        [InlineData(false)]\n        public void Set(bool commit)\n        {\n            IStateStore stateStore = new TrieStateStore(new MemoryKeyValueStore());\n            ITrie trie = stateStore.GetStateRoot(null);\n            AssertBytesEqual(\n                FromString(\"1b16b1df538ba12dc3f97edbb85caa7050d46c148134290feba80f8236c83db9\"),\n                trie.Hash\n            );\n            Assert.Null(trie.Get(new KeyBytes(0xbe, 0xef)));\n            Assert.Null(trie.Get(new KeyBytes(0x11, 0x22)));\n            Assert.Null(trie.Get(new KeyBytes(0xaa, 0xbb)));\n            Assert.Null(trie.Get(new KeyBytes(0x12, 0x34)));\n\n            trie = trie.Set(new KeyBytes(0xbe, 0xef), Null.Value);\n            trie = commit ? stateStore.Commit(trie) : trie;\n            AssertBytesEqual(\n                FromString(\"16fc25f43edd0c2d2cb6e3cc3827576e57f4b9e04f8dc3a062c7fe59041f77bd\"),\n                trie.Hash\n            );\n            AssertBencodexEqual(Null.Value, trie.Get(new KeyBytes(0xbe, 0xef)));\n            Assert.Null(trie.Get(new KeyBytes(0x11, 0x22)));\n            Assert.Null(trie.Get(new KeyBytes(0xaa, 0xbb)));\n            Assert.Null(trie.Get(new KeyBytes(0x12, 0x34)));\n\n            trie = trie.Set(new KeyBytes(0xbe, 0xef), new Bencodex.Types.Boolean(true));\n            trie = commit ? stateStore.Commit(trie) : trie;\n            AssertBytesEqual(\n                FromString(\"4458796f4092b5ebfc1ffb3989e72edee228501e438080a12dea45591dc66d58\"),\n                trie.Hash\n            );\n            AssertBencodexEqual(\n                new Bencodex.Types.Boolean(true),\n                trie.Get(new KeyBytes(0xbe, 0xef))\n            );\n            Assert.Null(trie.Get(new KeyBytes(0x11, 0x22)));\n            Assert.Null(trie.Get(new KeyBytes(0xaa, 0xbb)));\n            Assert.Null(trie.Get(new KeyBytes(0x12, 0x34)));\n\n            trie = trie.Set(new KeyBytes(0x11, 0x22), List.Empty);\n            trie = commit ? stateStore.Commit(trie) : trie;\n            AssertBytesEqual(\n                FromString(\"ab1359a2497453110a9c658dd3db45f282404fe68d8c8aca30856f395572284c\"),\n                trie.Hash\n            );\n            AssertBencodexEqual(\n                new Bencodex.Types.Boolean(true),\n                trie.Get(new KeyBytes(0xbe, 0xef))\n            );\n            AssertBencodexEqual(List.Empty, trie.Get(new KeyBytes(0x11, 0x22)));\n            Assert.Null(trie.Get(new KeyBytes(0xaa, 0xbb)));\n            Assert.Null(trie.Get(new KeyBytes(0x12, 0x34)));\n\n            trie = trie.Set(new KeyBytes(0xaa, 0xbb), new Text(\"hello world\"));\n            trie = commit ? stateStore.Commit(trie) : trie;\n            AssertBytesEqual(\n                FromString(\"abb5759141f7af1c40f1b0993ba60073cf4227900617be9641373e5a097eaa3c\"),\n                trie.Hash\n            );\n            AssertBencodexEqual(\n                new Bencodex.Types.Boolean(true),\n                trie.Get(new KeyBytes(0xbe, 0xef))\n            );\n            AssertBencodexEqual(List.Empty, trie.Get(new KeyBytes(0x11, 0x22)));\n            AssertBencodexEqual(\n                new Text(\"hello world\"),\n                trie.Get(new KeyBytes(0xaa, 0xbb))\n            );\n            Assert.Null(trie.Get(new KeyBytes(0x12, 0x34)));\n\n            // Once node encoding length exceeds certain length,\n            // uncommitted and committed hash diverge\n            var longText = new Text(string.Join(\"\\n\", Range(0, 1000).Select(i => $\"long str {i}\")));\n            trie = trie.Set(new KeyBytes(0xaa, 0xbb), longText);\n            trie = commit ? stateStore.Commit(trie) : trie;\n            AssertBytesEqual(\n                FromString(commit\n                    ? \"56e5a39a726acba1f7631a6520ae92e20bb93ca3992a7b7d3542c6daee68e56d\"\n                    : \"ad9fb53a8f643bd308d7afea57a5d1796d6031b1df95bdd415fa69b44177d155\"),\n                trie.Hash\n            );\n            AssertBencodexEqual(\n                new Bencodex.Types.Boolean(true),\n                trie.Get(new KeyBytes(0xbe, 0xef))\n            );\n            AssertBencodexEqual(List.Empty, trie.Get(new KeyBytes(0x11, 0x22)));\n            AssertBencodexEqual(longText, trie.Get(new KeyBytes(0xaa, 0xbb)));\n            Assert.Null(trie.Get(new KeyBytes(0x12, 0x34)));\n\n            trie = trie.Set(new KeyBytes(0x12, 0x34), Dictionary.Empty);\n            trie = commit ? stateStore.Commit(trie) : trie;\n            AssertBytesEqual(\n                FromString(commit\n                    ? \"88d6375097fd03e6c30a129eb0030d938caeaa796643971ca938fbd27ff5e057\"\n                    : \"77d13e9d97033400ad31fcb0441819285b9165f6ea6ae599d85e7d7e24428feb\"),\n                trie.Hash\n            );\n            AssertBencodexEqual(\n                new Bencodex.Types.Boolean(true),\n                trie.Get(new KeyBytes(0xbe, 0xef))\n            );\n            AssertBencodexEqual(List.Empty, trie.Get(new KeyBytes(0x11, 0x22)));\n            AssertBencodexEqual(longText, trie.Get(new KeyBytes(0xaa, 0xbb)));\n            AssertBencodexEqual(Dictionary.Empty, trie.Get(new KeyBytes(0x12, 0x34)));\n\n            List complexList = List.Empty\n                .Add(\"Hello world\")\n                .Add(Dictionary.Empty\n                    .Add(\"foo\", 1)\n                    .Add(\"bar\", 2)\n                    .Add(\n                        \"lst\",\n                        new List(Range(0, 1000).Select(i => new Text($\"long str {i}\")))))\n                .Add(new List(Range(0, 1000).Select(i => new Text($\"long str {i}\"))));\n            trie = trie.Set(new KeyBytes(0x11, 0x22), complexList);\n            trie = commit ? stateStore.Commit(trie) : trie;\n            AssertBytesEqual(\n                FromString(commit\n                    ? \"f29820df65c1d1a66b69a59b9fe3e21911bbd2d97a9f298853c529804bf84a26\"\n                    : \"586ba0ba5dfe07433b01fbf7611f95832bde07b8dc5669540ef8866f465bbb85\"),\n                trie.Hash\n            );\n            AssertBencodexEqual(\n                new Bencodex.Types.Boolean(true),\n                trie.Get(new KeyBytes(0xbe, 0xef))\n            );\n            AssertBencodexEqual(complexList, trie.Get(new KeyBytes(0x11, 0x22)));\n            AssertBencodexEqual(longText, trie.Get(new KeyBytes(0xaa, 0xbb)));\n            AssertBencodexEqual(Dictionary.Empty, trie.Get(new KeyBytes(0x12, 0x34)));\n\n            Dictionary complexDict = Dictionary.Empty\n                .Add(\"foo\", 123)\n                .Add(\"bar\", 456)\n                .Add(\"lst\", new List(Range(0, 1000).Select(i => new Text($\"long str {i}\"))))\n                .Add(\"cls\", complexList)\n                .Add(\n                    \"dct\",\n                    Dictionary.Empty\n                        .Add(\"abcd\", Null.Value)\n                        .Add(\"efgh\", false)\n                        .Add(\"ijkl\", true)\n                        .Add(\"mnop\", new Binary(\"hello world\", Encoding.ASCII))\n                        .Add(\"qrst\", complexList)\n                        .Add(\"uvwx\", Dictionary.Empty));\n            trie = trie.Set(new KeyBytes(0x12, 0x34), complexDict);\n            trie = commit ? stateStore.Commit(trie) : trie;\n            AssertBytesEqual(\n                FromString(commit\n                    ? \"1dabec2c0fea02af0182e9fee6c7ce7ad1a9d9bcfaa2cd80c2971bbce5272655\"\n                    : \"4783d18dfc8a2d4d98f722a935e45bd7fc1d0197fb4d33e62f734bfde968af39\"),\n                trie.Hash\n            );\n            AssertBencodexEqual(\n                new Bencodex.Types.Boolean(true),\n                trie.Get(new KeyBytes(0xbe, 0xef))\n            );\n            AssertBencodexEqual(complexList, trie.Get(new KeyBytes(0x11, 0x22)));\n            AssertBencodexEqual(longText, trie.Get(new KeyBytes(0xaa, 0xbb)));\n            AssertBencodexEqual(complexDict, trie.Get(new KeyBytes(0x12, 0x34)));\n        }\n\n        [Fact]\n        public void GetNode()\n        {\n            IStateStore stateStore = new TrieStateStore(new MemoryKeyValueStore());\n            ITrie trie = stateStore.GetStateRoot(null);\n\n            KeyBytes key00 = new KeyBytes(new byte[] { 0x00 });\n            IValue value00 = new Text(\"00\");\n            KeyBytes key0000 = new KeyBytes(new byte[] { 0x00, 0x00 });\n            IValue value0000 = new Text(\"0000\");\n            KeyBytes key0010 = new KeyBytes(new byte[] { 0x00, 0x10 });\n            IValue value0010 = new Text(\"00000000000000000000000000000000_0010\");\n\n            trie = trie.Set(key00, value00);\n            trie = trie.Set(key0000, value0000);\n            trie = trie.Set(key0010, value0010);\n\n            Assert.IsType<ShortNode>(trie.GetNode(Nibbles.FromHex(string.Empty)));\n            Assert.IsType<FullNode>(trie.GetNode(Nibbles.FromHex(\"00\")));\n            Assert.Null(trie.GetNode(Nibbles.FromHex(\"01\")));\n            Assert.IsType<ShortNode>(trie.GetNode(Nibbles.FromHex(\"000\")));\n            Assert.IsType<ShortNode>(trie.GetNode(Nibbles.FromHex(\"001\")));\n            Assert.IsType<ValueNode>(trie.GetNode(Nibbles.FromHex(\"0000\")));\n            Assert.IsType<ValueNode>(trie.GetNode(Nibbles.FromHex(\"0010\")));\n\n            trie = stateStore.Commit(trie);\n            Assert.IsType<HashNode>(trie.GetNode(Nibbles.FromHex(string.Empty)));\n            Assert.IsType<HashNode>(trie.GetNode(Nibbles.FromHex(\"00\")));\n            Assert.Null(trie.GetNode(Nibbles.FromHex(\"01\")));\n            Assert.IsType<ShortNode>(trie.GetNode(Nibbles.FromHex(\"000\")));\n            Assert.IsType<HashNode>(trie.GetNode(Nibbles.FromHex(\"001\")));\n            Assert.IsType<ValueNode>(trie.GetNode(Nibbles.FromHex(\"0000\")));\n            Assert.IsType<HashNode>(trie.GetNode(Nibbles.FromHex(\"0010\")));\n        }\n\n        [Fact]\n        public void ResolveToValueAtTheEndOfShortNode()\n        {\n            IStateStore stateStore = new TrieStateStore(new MemoryKeyValueStore());\n            ITrie trie = stateStore.GetStateRoot(null);\n\n            KeyBytes key00 = new KeyBytes(new byte[] { 0x00 });\n            IValue value00 = new Text(\"00\");\n            KeyBytes key0000 = new KeyBytes(new byte[] { 0x00, 0x00 });\n\n            trie = trie.Set(key00, value00);\n            trie = stateStore.Commit(trie);\n\n            Assert.Null(trie.Get(key0000));\n        }\n\n        [Fact]\n        public void SetValueToExtendedKey()\n        {\n            IStateStore stateStore = new TrieStateStore(new MemoryKeyValueStore());\n            ITrie trie = stateStore.GetStateRoot(null);\n            KeyBytes key00 = new KeyBytes(new byte[] { 0x00 });\n            IValue value00 = new Text(\"00\");\n            KeyBytes key0000 = new KeyBytes(new byte[] { 0x00, 0x00 });\n            IValue value0000 = new Text(\"0000\");\n\n            trie = trie.Set(key00, value00);\n            trie = trie.Set(key0000, value0000);\n            trie = stateStore.Commit(trie);\n\n            Assert.Equal(2, trie.IterateValues().Count());\n            Assert.Equal(value00, trie.Get(key00));\n            Assert.Equal(value0000, trie.Get(key0000));\n        }\n\n        [Fact]\n        public void SetValueToFullNode()\n        {\n            IStateStore stateStore = new TrieStateStore(new MemoryKeyValueStore());\n            ITrie trie = stateStore.GetStateRoot(null);\n            KeyBytes key00 = new KeyBytes(new byte[] { 0x00 });\n            IValue value00 = new Text(\"00\");\n            KeyBytes key0000 = new KeyBytes(new byte[] { 0x00, 0x00 });\n            IValue value0000 = new Text(\"0000\");\n            KeyBytes key0010 = new KeyBytes(new byte[] { 0x00, 0x10 });\n            IValue value0010 = new Text(\"0010\");\n\n            trie = trie.Set(key0000, value0000);\n            trie = trie.Set(key0010, value0010);\n            trie = trie.Set(key00, value00);\n            trie = stateStore.Commit(trie);\n\n            Assert.Equal(3, trie.IterateValues().Count());\n            Assert.Equal(value00, trie.Get(key00));\n            Assert.Equal(value0000, trie.Get(key0000));\n            Assert.Equal(value0010, trie.Get(key0010));\n        }\n\n        [Fact]\n        public void RemoveValue()\n        {\n            IKeyValueStore keyValueStore = new MemoryKeyValueStore();\n            IStateStore stateStore = new TrieStateStore(keyValueStore);\n            ITrie trie = stateStore.GetStateRoot(null);\n            HashDigest<SHA256> nullTrieHash = trie.Hash;\n\n            KeyBytes key = new KeyBytes(Array.Empty<byte>());\n            IValue value = new Text(string.Empty);\n            KeyBytes key00 = new KeyBytes(new byte[] { 0x00 });\n            IValue value00 = new Text(\"00\");\n            KeyBytes key0000 = new KeyBytes(new byte[] { 0x00, 0x00 });\n            IValue value0000 = new Text(\"0000\");\n\n            // Add value at root and remove from root.\n            // Also checks \"null hash\" is never recorded.\n            trie = trie.Set(key, value);\n            trie = stateStore.Commit(trie);\n            Assert.NotEqual(nullTrieHash, trie.Hash);\n            trie = trie.Remove(key);\n            trie = stateStore.Commit(trie);\n            Assert.Null(trie.Root);\n            Assert.Equal(nullTrieHash, trie.Hash);\n            Assert.Empty(trie.IterateValues());\n            Assert.Throws<KeyNotFoundException>(\n                () => keyValueStore.Get(new KeyBytes(nullTrieHash.ByteArray)));\n\n            // Add single value to make short node and remove it.\n            trie = stateStore.GetStateRoot(null);\n            trie = trie.Set(key00, value00);\n            trie = stateStore.Commit(trie);\n            Assert.NotEqual(nullTrieHash, trie.Hash);\n            trie = trie.Remove(key00);\n            trie = stateStore.Commit(trie);\n            Assert.Null(trie.Root);\n            Assert.Equal(nullTrieHash, trie.Hash);\n            Assert.Empty(trie.IterateNodes());\n            Assert.Empty(trie.IterateValues());\n\n            // Add two values to make full node + short node\n            // and remove \"middle value\" to get a single short node.\n            trie = stateStore.GetStateRoot(null);\n            trie = trie.Set(key0000, value0000);\n            trie = stateStore.Commit(trie);\n            int expectedNodeCount = trie.IterateNodes().Count();\n            int expectedValueCount = trie.IterateValues().Count();\n            HashDigest<SHA256> expectedHash = trie.Hash;\n\n            trie = stateStore.GetStateRoot(null);\n            trie = trie.Set(key00, value00);\n            trie = trie.Set(key0000, value0000);\n            trie = stateStore.Commit(trie);\n            trie = trie.Remove(key00);\n            trie = stateStore.Commit(trie);\n            Assert.Equal(value0000, trie.Get(key0000));\n            Assert.Equal(expectedNodeCount, trie.IterateNodes().Count());\n            Assert.Equal(expectedValueCount, trie.IterateValues().Count());\n            Assert.Equal(expectedHash, trie.Hash);\n\n            // Add two values to make full node + short node\n            // and remove \"longer value\" to get a single short node.\n            trie = stateStore.GetStateRoot(null);\n            trie = trie.Set(key00, value00);\n            trie = stateStore.Commit(trie);\n            expectedNodeCount = trie.IterateNodes().Count();\n            expectedValueCount = trie.IterateValues().Count();\n            expectedHash = trie.Hash;\n\n            trie = stateStore.GetStateRoot(null);\n            trie = trie.Set(key00, value00);\n            trie = trie.Set(key0000, value0000);\n            trie = stateStore.Commit(trie);\n            trie = trie.Remove(key0000);\n            trie = stateStore.Commit(trie);\n            Assert.Equal(value00, Assert.Single(trie.IterateValues()).Value);\n            Assert.Equal(expectedNodeCount, trie.IterateNodes().Count());\n            Assert.Equal(expectedValueCount, trie.IterateValues().Count());\n            Assert.Equal(expectedHash, trie.Hash);\n\n            // Add two values to make full node + short node\n            // and remove both to get a null node.\n            // Also checks that once stored values are not actually removed from the\n            // underlying key value store.\n            trie = stateStore.GetStateRoot(null);\n            trie = trie.Set(key00, value00);\n            trie = trie.Set(key0000, value0000);\n            trie = stateStore.Commit(trie);\n            HashDigest<SHA256> hash = trie.Hash; // A reference to an earlier point in time.\n            trie = trie.Remove(key00);\n            trie = trie.Remove(key0000);\n            trie = stateStore.Commit(trie);\n            Assert.Null(trie.Root);\n            Assert.Equal(nullTrieHash, trie.Hash);\n            Assert.Empty(trie.IterateNodes());\n            Assert.Empty(trie.IterateValues());\n            trie = stateStore.GetStateRoot(hash);\n            Assert.Equal(value00, trie.Get(key00)); // Nothing is actually removed from storage.\n            Assert.Equal(value0000, trie.Get(key0000));\n\n            // Add randomized kvs and remove kvs in order.\n            // The way the test is set up, identical kv pairs shouldn't matter.\n            Random random = new Random();\n            List<(KeyBytes Key, Text Value)> kvs = Enumerable\n                .Range(0, 100)\n                .Select(_ => TestUtils.GetRandomBytes(random.Next(2, 10)))\n                .Select(bytes => (new KeyBytes(bytes), new Text(ByteUtil.Hex(bytes))))\n                .ToList();\n            Stack<(HashDigest<SHA256>, int, int)> expected =\n                new Stack<(HashDigest<SHA256>, int, int)>();\n            trie = stateStore.GetStateRoot(null);\n            expected.Push((nullTrieHash, 0, 0));\n\n            foreach (var kv in kvs)\n            {\n                trie = trie.Set(kv.Key, kv.Value);\n                trie = stateStore.Commit(trie);\n                expected.Push(\n                    (trie.Hash, trie.IterateNodes().Count(), trie.IterateValues().Count()));\n            }\n\n            expected.Pop();\n            kvs.Reverse();\n            foreach (var kv in kvs)\n            {\n                trie = trie.Remove(kv.Key);\n                trie = stateStore.Commit(trie);\n                var tuple = expected.Pop();\n\n                Assert.Equal(tuple.Item3, trie.IterateValues().Count());\n                Assert.Equal(tuple.Item2, trie.IterateNodes().Count());\n                Assert.Equal(tuple.Item1, trie.Hash);\n            }\n\n            Assert.Empty(expected);\n            Assert.Null(trie.Root);\n        }\n\n        [Fact]\n        public void RemoveValueNoOp()\n        {\n            IStateStore stateStore = new TrieStateStore(new MemoryKeyValueStore());\n            ITrie trie = stateStore.GetStateRoot(null);\n\n            KeyBytes key00 = new KeyBytes(new byte[] { 0x00 });\n            KeyBytes key0000 = new KeyBytes(new byte[] { 0x00, 0x00 });\n            IValue value0000 = new Text(\"0000\");\n            KeyBytes key0011 = new KeyBytes(new byte[] { 0x00, 0x11 });\n            IValue value0011 = new Text(\"0011\");\n            KeyBytes key000000 = new KeyBytes(new byte[] { 0x00, 0x00, 0x00 });\n\n            trie = trie.Set(key0000, value0000);\n            trie = trie.Set(key0011, value0011);\n            trie = stateStore.Commit(trie);\n            int expectedNodeCount = trie.IterateNodes().Count();\n            int expectedValueCount = trie.IterateValues().Count();\n            HashDigest<SHA256> expectedHash = trie.Hash;\n\n            // Does nothing without throwing an exception when trying to remove value from\n            // a path where there is a node without value or a non-existent path.\n            trie = trie.Remove(key00);\n            trie = trie.Remove(key000000);\n            trie = stateStore.Commit(trie);\n            Assert.Equal(expectedNodeCount, trie.IterateNodes().Count());\n            Assert.Equal(expectedValueCount, trie.IterateValues().Count());\n            Assert.Equal(expectedHash, trie.Hash);\n        }\n    }\n}\n"
  },
  {
    "path": "test/Libplanet.Tests/Store/Trie/NibblesTest.cs",
    "content": "using System.Collections.Immutable;\nusing Libplanet.Store.Trie;\nusing Xunit;\n\nnamespace Libplanet.Tests.Store.Trie\n{\n    public class NibblesTest\n    {\n        [Fact]\n        public void Default()\n        {\n            Nibbles nibbles = default;\n            Assert.Equal(0, nibbles.Length);\n            Assert.Empty(nibbles.ByteArray);\n            Assert.Equal(string.Empty, nibbles.Hex);\n        }\n\n        [Fact]\n        public void Constructor()\n        {\n            byte[] nibbleBytes = new byte[] { 2, 4, 13, 8, 3 };\n            Nibbles nibbles = new Nibbles(nibbleBytes.ToImmutableArray());\n            Assert.Equal(5, nibbles.Length);\n            Assert.Equal(nibbleBytes, nibbles.ByteArray);\n            Assert.Equal(\"24d83\", nibbles.Hex);\n        }\n\n        [Fact]\n        public void FromHex()\n        {\n            string hex = \"92fc1\";\n            Nibbles nibbles = Nibbles.FromHex(hex);\n            Assert.Equal(5, nibbles.Length);\n            Assert.Equal(new byte[] { 9, 2, 15, 12, 1 }, nibbles.ByteArray);\n            Assert.Equal(hex, nibbles.Hex);\n        }\n\n        [Fact]\n        public void FromKeyBytes()\n        {\n            KeyBytes keyBytes = new KeyBytes(new byte[] { 0x2f, 0x1c });\n            Nibbles nibbles = Nibbles.FromKeyBytes(keyBytes);\n            Assert.Equal(4, nibbles.Length);\n            Assert.Equal(\"2f1c\", nibbles.Hex);\n        }\n\n        [Fact]\n        public void Add()\n        {\n            string hex = \"6912f\";\n            Nibbles nibbles = Nibbles.FromHex(hex);\n            Assert.Equal(5, nibbles.Length);\n            Assert.Equal(hex, nibbles.Hex);\n\n            nibbles = nibbles.Add(2);\n            Assert.Equal(6, nibbles.Length);\n            Assert.Equal(\"6912f2\", nibbles.Hex);\n\n            nibbles = nibbles.AddRange(new byte[] { 1, 12 }.ToImmutableArray());\n            Assert.Equal(8, nibbles.Length);\n            Assert.Equal(\"6912f21c\", nibbles.Hex);\n\n            nibbles = nibbles.AddRange(Nibbles.FromHex(\"b82\"));\n            Assert.Equal(11, nibbles.Length);\n            Assert.Equal(\"6912f21cb82\", nibbles.Hex);\n        }\n    }\n}\n"
  },
  {
    "path": "test/Libplanet.Tests/Store/Trie/Nodes/FullNodeTest.cs",
    "content": "using System.Collections.Immutable;\nusing System.Linq;\nusing Bencodex.Types;\nusing Libplanet.Store.Trie.Nodes;\nusing Xunit;\n\nnamespace Libplanet.Tests.Store.Trie.Nodes\n{\n    public class FullNodeTest\n    {\n        [Fact]\n        public void ToBencodex()\n        {\n            var fullNode = new FullNode(\n                Enumerable.Repeat<INode>(null, 16).ToImmutableArray()\n                    .Add(new ValueNode(Dictionary.Empty)).ToImmutableArray());\n\n            var expected =\n                new List(Enumerable.Repeat<IValue>(Null.Value, 16).ToImmutableArray()\n                    .Add(new List(new IValue[] { Null.Value, Dictionary.Empty })));\n            var encoded = fullNode.ToBencodex();\n            Assert.IsType<List>(encoded);\n            Assert.Equal(expected.Count, ((List)encoded).Count);\n            Assert.Equal(expected, encoded);\n        }\n    }\n}\n"
  },
  {
    "path": "test/Libplanet.Tests/Store/Trie/Nodes/HashNodeTest.cs",
    "content": "using System;\nusing System.Security.Cryptography;\nusing Bencodex.Types;\nusing Libplanet.Common;\nusing Libplanet.Store.Trie.Nodes;\nusing Xunit;\n\nnamespace Libplanet.Tests.Store.Trie.Nodes\n{\n    public class HashNodeTest\n    {\n        [Fact]\n        public void ToBencodex()\n        {\n            var buf = new byte[128];\n            var random = new Random();\n            random.NextBytes(buf);\n            var hashDigest = HashDigest<SHA256>.DeriveFrom(buf);\n\n            var valueNode = new HashNode(hashDigest);\n            Assert.Equal((Binary)hashDigest.ToByteArray(), valueNode.ToBencodex());\n        }\n    }\n}\n"
  },
  {
    "path": "test/Libplanet.Tests/Store/Trie/Nodes/NodeDecoderTest.cs",
    "content": "using System.Linq;\nusing System.Security.Cryptography;\nusing Bencodex.Types;\nusing Libplanet.Common;\nusing Libplanet.Store.Trie;\nusing Libplanet.Store.Trie.Nodes;\nusing Xunit;\n\nnamespace Libplanet.Tests.Store.Trie.Nodes\n{\n    public class NodeDecoderTest\n    {\n        [Fact]\n        public void DecodeValidFullNode()\n        {\n            var hashA = HashDigest<SHA256>.DeriveFrom(TestUtils.GetRandomBytes(128));\n            var hashB = HashDigest<SHA256>.DeriveFrom(TestUtils.GetRandomBytes(128));\n            var list = new List(new IValue[]\n            {\n                (Binary)hashA.ToByteArray(),\n                Null.Value,\n                Null.Value,\n                Null.Value,\n                Null.Value,\n                Null.Value,\n                Null.Value,\n                Null.Value,\n                Null.Value,\n                Null.Value,\n                Null.Value,\n                Null.Value,\n                Null.Value,\n                Null.Value,\n                Null.Value,\n                Null.Value,\n                (Binary)hashB.ToByteArray(),\n            });\n            Assert.Equal(17, list.Count);\n\n            INode node = NodeDecoder.Decode(list, NodeDecoder.NodeType.Full);\n            Assert.IsType<FullNode>(node);\n            var fullNode = (FullNode)node;\n            Assert.Equal(new HashNode(hashB), fullNode.Value);\n            Assert.Equal(new HashNode(hashA), fullNode.Children[0]);\n            for (int i = 1; i < 16; ++i)\n            {\n                Assert.Null(fullNode.Children[i]);\n            }\n        }\n\n        [Theory]\n        [InlineData(1)]\n        [InlineData(18)]\n        public void DecodeInvalidFullNodeThrowsException(int listCount)\n        {\n            var list = new List(Enumerable.Repeat((IValue)Null.Value, listCount));\n            Assert.Throws<InvalidTrieNodeException>(\n                () => NodeDecoder.Decode(list, NodeDecoder.NodeType.Full));\n        }\n\n        [Fact]\n        public void DecodeValidValueNode()\n        {\n            var list = List.Empty\n                .Add(new Binary(Nibbles.FromHex(\"beef\").ByteArray))\n                .Add(new List(new IValue[] { Null.Value, (Text)\"beef\", }));\n\n            INode node = NodeDecoder.Decode(list, NodeDecoder.NodeType.Short);\n            Assert.IsType<ShortNode>(node);\n            var shortNode = (ShortNode)node;\n            Assert.IsType<ValueNode>(shortNode.Value);\n            Assert.Equal(Nibbles.FromHex(\"beef\"), shortNode.Key);\n            Assert.Equal(new ValueNode((Text)\"beef\"), shortNode.Value);\n        }\n\n        [Fact]\n        public void DecodeValidExtensionNode()\n        {\n            var list = List.Empty\n                .Add(new Binary(Nibbles.FromHex(\"beef\").ByteArray))\n                .Add(default(HashDigest<SHA256>).ByteArray);\n\n            INode node = NodeDecoder.Decode(list, NodeDecoder.NodeType.Short);\n            Assert.IsType<ShortNode>(node);\n            var shortNode = (ShortNode)node;\n            Assert.IsType<HashNode>(shortNode.Value);\n            Assert.Equal(new HashNode(default), shortNode.Value);\n        }\n\n        [Fact]\n        public void OnlyDecodeAllowedNodeType()\n        {\n            IValue valueNodeEncoded = new ValueNode(new Text(\"foo\")).ToBencodex();\n            IValue shortNodeEncoded = new ShortNode(\n                Nibbles.FromHex(\"b4\"),\n                new ValueNode(new Text(\"bar\"))).ToBencodex();\n            IValue fullNodeEncoded = FullNode.Empty\n                .SetChild(4, new ValueNode(new Text(\"4\")))\n                .SetChild(10, new ValueNode(new Text(\"c\")))\n                .ToBencodex();\n            IValue hashNodeEncoded =\n                new HashNode(\n                    new HashDigest<SHA256>(\n                        TestUtils.GetRandomBytes(HashDigest<SHA256>.Size))).ToBencodex();\n\n            Assert.Null(NodeDecoder.Decode(Null.Value, NodeDecoder.AnyNodeType));\n            Assert.IsType<ValueNode>(\n                NodeDecoder.Decode(valueNodeEncoded, NodeDecoder.AnyNodeType));\n            Assert.IsType<ShortNode>(\n                NodeDecoder.Decode(shortNodeEncoded, NodeDecoder.AnyNodeType));\n            Assert.IsType<FullNode>(\n                NodeDecoder.Decode(fullNodeEncoded, NodeDecoder.AnyNodeType));\n            Assert.IsType<FullNode>(\n                NodeDecoder.Decode(fullNodeEncoded, NodeDecoder.AnyNodeType));\n            Assert.Throws<InvalidTrieNodeException>(() =>\n                NodeDecoder.Decode(Null.Value, NodeDecoder.NodeType.Value));\n            Assert.Throws<InvalidTrieNodeException>(() =>\n                NodeDecoder.Decode(valueNodeEncoded, NodeDecoder.NodeType.Short));\n            Assert.Throws<InvalidTrieNodeException>(() =>\n                NodeDecoder.Decode(shortNodeEncoded, NodeDecoder.NodeType.Full));\n            Assert.Throws<InvalidTrieNodeException>(() =>\n                NodeDecoder.Decode(fullNodeEncoded, NodeDecoder.NodeType.Null));\n        }\n    }\n}\n"
  },
  {
    "path": "test/Libplanet.Tests/Store/Trie/Nodes/ShortNodeTest.cs",
    "content": "using Bencodex.Types;\nusing Libplanet.Store.Trie;\nusing Libplanet.Store.Trie.Nodes;\nusing Xunit;\n\nnamespace Libplanet.Tests.Store.Trie.Nodes\n{\n    public class ShortNodeTest\n    {\n        [Fact]\n        public void ToBencodex()\n        {\n            var shortNode = new ShortNode(\n                Nibbles.FromHex(\"beef\"),\n                new ValueNode((Text)\"foo\")\n            );\n\n            var expected =\n                new List(new IValue[]\n                {\n                    (Binary)Nibbles.FromHex(\"beef\").ByteArray,\n                    new List(new IValue[] { Null.Value, (Text)\"foo\" }),\n                });\n            var encoded = shortNode.ToBencodex();\n            Assert.IsType<List>(encoded);\n            Assert.Equal(expected.Count, ((List)encoded).Count);\n            Assert.Equal(expected, encoded);\n        }\n    }\n}\n"
  },
  {
    "path": "test/Libplanet.Tests/Store/Trie/Nodes/ValueNodeTest.cs",
    "content": "using Bencodex.Types;\nusing Libplanet.Common;\nusing Libplanet.Store.Trie.Nodes;\nusing Xunit;\n\nnamespace Libplanet.Tests.Store.Trie.Nodes\n{\n    public class ValueNodeTest\n    {\n        [Fact]\n        public void ToBencodex()\n        {\n            var values = new IValue[]\n            {\n                Null.Value,\n                (Binary)ByteUtil.ParseHexToImmutable(\"beef\"),\n                (Integer)0xbeef,\n                Dictionary.Empty,\n                List.Empty,\n            };\n\n            foreach (var value in values)\n            {\n                var valueNode = new ValueNode(value);\n                var expected = new List(new[]\n                {\n                    Null.Value, value,\n                });\n                Assert.Equal(expected, valueNode.ToBencodex());\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "test/Libplanet.Tests/Store/Trie/PathCursorTest.cs",
    "content": "using System;\nusing Libplanet.Store.Trie;\nusing Xunit;\nusing static Libplanet.Tests.TestUtils;\n\nnamespace Libplanet.Tests.Store.Trie\n{\n    public class PathCursorTest\n    {\n        [Fact]\n        public void Constructor()\n        {\n            KeyBytes keyBytes = KeyBytes.FromHex(\"cfed4460\");\n            var cursor = new PathCursor(keyBytes);\n            Assert.Equal(Nibbles.FromKeyBytes(keyBytes), cursor.Nibbles);\n            Assert.Equal(8, cursor.Length);\n            Assert.Equal(0, cursor.Offset);\n        }\n\n        [Fact]\n        public void Next()\n        {\n            var cursor = new PathCursor(KeyBytes.FromHex(\"cfed4460\"));\n            Assert.Equal(0, cursor.Offset);\n            Assert.Equal(8, cursor.RemainingNibbleLength);\n            Assert.Equal((byte)0xc, cursor.NextNibble);\n            AssertBytesEqual(\n                Nibbles.FromHex(\"cfed4460\").ByteArray, cursor.GetRemainingNibbles().ByteArray);\n\n            Assert.Throws<ArgumentOutOfRangeException>(() => { cursor = cursor.Next(-1); });\n            Assert.Equal(0, cursor.Offset);\n            Assert.Equal(8, cursor.RemainingNibbleLength);\n\n            Assert.Throws<ArgumentOutOfRangeException>(() => { cursor = cursor.Next(9); });\n            Assert.Equal(0, cursor.Offset);\n            Assert.Equal(8, cursor.RemainingNibbleLength);\n\n            var next = cursor.Next(1);\n            Assert.Equal(0, cursor.Offset);\n            Assert.Equal(8, cursor.RemainingNibbleLength);\n            Assert.Equal((byte)0xc, cursor.NextNibble);\n            AssertBytesEqual(\n                Nibbles.FromHex(\"cfed4460\").ByteArray, cursor.GetRemainingNibbles().ByteArray);\n            Assert.Equal(1, next.Offset);\n            Assert.Equal((byte)0xf, next.NextNibble);\n            Assert.Equal(7, next.RemainingNibbleLength);\n            AssertBytesEqual(\n                Nibbles.FromHex(\"fed4460\").ByteArray, next.GetRemainingNibbles().ByteArray);\n\n            Assert.Throws<ArgumentOutOfRangeException>(() => { next = next.Next(-1); });\n            Assert.Equal(1, next.Offset);\n            Assert.Equal(7, next.RemainingNibbleLength);\n\n            Assert.Throws<ArgumentOutOfRangeException>(() => { next = next.Next(8); });\n            Assert.Equal(1, next.Offset);\n            Assert.Equal(7, next.RemainingNibbleLength);\n\n            var next2 = next.Next(5);\n            Assert.Equal(0, cursor.Offset);\n            Assert.Equal(8, cursor.RemainingNibbleLength);\n            Assert.Equal((byte)0xc, cursor.NextNibble);\n            AssertBytesEqual(\n                Nibbles.FromHex(\"cfed4460\").ByteArray, cursor.GetRemainingNibbles().ByteArray);\n            Assert.Equal(1, next.Offset);\n            Assert.Equal(7, next.RemainingNibbleLength);\n            Assert.Equal((byte)0xf, next.NextNibble);\n            AssertBytesEqual(\n                Nibbles.FromHex(\"fed4460\").ByteArray, next.GetRemainingNibbles().ByteArray);\n            Assert.Equal(6, next2.Offset);\n            Assert.Equal(2, next2.RemainingNibbleLength);\n            Assert.Equal((byte)0x6, next2.NextNibble);\n            AssertBytesEqual(\n                Nibbles.FromHex(\"60\").ByteArray, next2.GetRemainingNibbles().ByteArray);\n        }\n\n        [Fact]\n        public void CountCommonStartingNibbles()\n        {\n            var cursor = new PathCursor(KeyBytes.FromHex(\"cfed4460\"));\n            Assert.Equal(\n                0,\n                cursor.CountCommonStartingNibbles(Nibbles.Empty));\n            Assert.Equal(\n                0,\n                cursor.CountCommonStartingNibbles(Nibbles.FromHex(\"abcd\")));\n            Assert.Equal(\n                3,\n                cursor.CountCommonStartingNibbles(Nibbles.FromHex(\"cfeffff\")));\n            Assert.Equal(\n                8,\n                cursor.CountCommonStartingNibbles(Nibbles.FromHex(\"cfed4460abcd\")));\n\n            PathCursor next = cursor.Next(3);\n            Assert.Equal(\n                0,\n                next.CountCommonStartingNibbles(Nibbles.Empty));\n            Assert.Equal(\n                0,\n                next.CountCommonStartingNibbles(Nibbles.FromHex(\"cfeffff\")));\n            Assert.Equal(\n                3,\n                next.CountCommonStartingNibbles(Nibbles.FromHex(\"d44abc\")));\n            Assert.Equal(\n                5,\n                next.CountCommonStartingNibbles(Nibbles.FromHex(\"d4460abcd\")));\n        }\n\n        [Fact]\n        public void RemainingNibblesStartWith()\n        {\n            var cursor = new PathCursor(KeyBytes.FromHex(\"cfed4460\"));\n            Assert.True(cursor.RemainingNibblesStartWith(Nibbles.FromHex(\"cfed4\")));\n            Assert.False(\n                cursor.RemainingNibblesStartWith(Nibbles.FromHex(\"cfed4460a\")));\n            Assert.False(cursor.RemainingNibblesStartWith(Nibbles.FromHex(\"cfedfff\")));\n\n            PathCursor next = cursor.Next(3);\n            Assert.True(next.RemainingNibblesStartWith(Nibbles.FromHex(\"d44\")));\n            Assert.False(next.RemainingNibblesStartWith(Nibbles.FromHex(\"d4460abcd\")));\n            Assert.False(next.RemainingNibblesStartWith(Nibbles.FromHex(\"d4abc\")));\n        }\n    }\n}\n"
  },
  {
    "path": "test/Libplanet.Tests/Store/Trie/TrieMetadataTest.cs",
    "content": "using System;\nusing Bencodex.Types;\nusing Libplanet.Store.Trie;\nusing Libplanet.Types.Blocks;\nusing Xunit;\n\nnamespace Libplanet.Tests.Store.Trie\n{\n    public class TrieMetadataTest\n    {\n        [Fact]\n        public void CannotCreateWithInvalidVersion()\n        {\n            Assert.Throws<ArgumentException>(\n                () => new TrieMetadata(BlockMetadata.WorldStateProtocolVersion - 1));\n            Assert.Throws<ArgumentException>(\n                () => new TrieMetadata(BlockMetadata.CurrentProtocolVersion + 1));\n        }\n\n        [Fact]\n        public void Bencoded()\n        {\n            var meta = new TrieMetadata(BlockMetadata.WorldStateProtocolVersion);\n            IValue bencoded = meta.Bencoded;\n            var decoded = new TrieMetadata(bencoded);\n            Assert.Equal(meta.Version, decoded.Version);\n        }\n    }\n}\n"
  },
  {
    "path": "test/Libplanet.Tests/Store/Trie/TrieTest.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Collections.Immutable;\nusing System.Linq;\nusing Bencodex.Types;\nusing Libplanet.Crypto;\nusing Libplanet.Store;\nusing Libplanet.Store.Trie;\nusing Xunit;\n\nnamespace Libplanet.Tests.Store.Trie\n{\n    public class TrieTest\n    {\n        [Theory]\n        [InlineData(2)]\n        [InlineData(4)]\n        [InlineData(8)]\n        [InlineData(16)]\n        [InlineData(128)]\n        [InlineData(1024)]\n        public void GetAndSet(int addressCount)\n        {\n            ITrie trie = new MerkleTrie(new MemoryKeyValueStore());\n\n            var addresses = Enumerable\n                .Range(0, addressCount)\n                .Select(_ => new PrivateKey().Address)\n                .ToImmutableArray();\n            var states = new Dictionary<Address, IValue>();\n\n            void CheckAddressStates()\n            {\n                foreach (var address in addresses)\n                {\n                    IValue v = trie.Get(new[] { new KeyBytes(address.ByteArray) })[0];\n                    IValue expectedState = states.ContainsKey(address) ? states[address] : null;\n                    Assert.Equal(expectedState, v);\n                }\n            }\n\n            foreach (var address in addresses)\n            {\n                states[address] = (Text)address.ToHex();\n                trie = trie.Set(new KeyBytes(address.ByteArray), states[address]);\n                CheckAddressStates();\n            }\n        }\n\n        [Theory]\n        [InlineData(2)]\n        [InlineData(4)]\n        [InlineData(8)]\n        [InlineData(16)]\n        [InlineData(128)]\n        [InlineData(1024)]\n        public void Commit(int addressCount)\n        {\n            IKeyValueStore keyValueStore = new MemoryKeyValueStore();\n            IStateStore stateStore = new TrieStateStore(keyValueStore);\n            ITrie trieA = stateStore.GetStateRoot(null);\n\n            var addresses = new Address[addressCount];\n            var states = new IValue[addressCount];\n            for (int i = 0; i < addressCount; ++i)\n            {\n                addresses[i] = new PrivateKey().Address;\n                states[i] = (Binary)TestUtils.GetRandomBytes(128);\n\n                trieA = trieA.Set(new KeyBytes(addresses[i].ByteArray), states[i]);\n            }\n\n            KeyBytes path = new KeyBytes(TestUtils.GetRandomBytes(32));\n            trieA = trieA.Set(path, (Text)\"foo\");\n            Assert.Equal((Text)\"foo\", trieA.Get(new[] { path })[0]);\n\n            ITrie trieB = stateStore.Commit(trieA);\n            Assert.Equal((Text)\"foo\", trieB.Get(new[] { path })[0]);\n\n            trieB = trieB.Set(path, (Text)\"bar\");\n            Assert.Equal((Text)\"foo\", trieA.Get(new[] { path })[0]);\n            Assert.Equal((Text)\"bar\", trieB.Get(new[] { path })[0]);\n\n            ITrie trieC = stateStore.Commit(trieB);\n            ITrie trieD = stateStore.Commit(trieC);\n\n            Assert.NotEqual(trieA.Hash, trieB.Hash);\n            Assert.NotEqual(trieA.Hash, trieC.Hash);\n            Assert.NotEqual(trieB.Hash, trieC.Hash);\n            Assert.Equal(trieC.Hash, trieD.Hash);\n        }\n\n        [Fact]\n        public void EmptyRootHash()\n        {\n            IKeyValueStore keyValueStore = new MemoryKeyValueStore();\n            IStateStore stateStore = new TrieStateStore(keyValueStore);\n            ITrie trie = stateStore.GetStateRoot(null);\n            Assert.Equal(MerkleTrie.EmptyRootHash, trie.Hash);\n\n            var committedTrie = stateStore.Commit(trie);\n            Assert.Equal(MerkleTrie.EmptyRootHash, committedTrie.Hash);\n\n            trie = trie.Set(new KeyBytes(default(Address).ByteArray), Dictionary.Empty);\n            committedTrie = stateStore.Commit(trie);\n            Assert.NotEqual(MerkleTrie.EmptyRootHash, committedTrie.Hash);\n        }\n\n        [Fact]\n        public void ThrowArgumentNullExceptionWhenSettingNull()\n        {\n            IKeyValueStore keyValueStore = new MemoryKeyValueStore();\n            ITrie trie = new MerkleTrie(keyValueStore);\n\n            Assert.Throws<ArgumentNullException>(\n                () => trie.Set(new KeyBytes(0xbe, 0xef), null)\n            );\n        }\n    }\n}\n"
  },
  {
    "path": "test/Libplanet.Tests/Store/TrieStateStoreCommitTest.cs",
    "content": "using System;\nusing System.Linq;\nusing System.Security.Cryptography;\nusing Bencodex.Types;\nusing Libplanet.Common;\nusing Libplanet.Store;\nusing Libplanet.Store.Trie;\nusing Libplanet.Store.Trie.Nodes;\nusing Xunit;\n\nnamespace Libplanet.Tests.Store\n{\n    public class TrieStateStoreCommitTest\n    {\n        [Fact]\n        public void CommitEmptyDoesNotWrite()\n        {\n            IKeyValueStore keyValueStore = new MemoryKeyValueStore();\n            IStateStore stateStore = new TrieStateStore(new MemoryKeyValueStore());\n            ITrie emptyTrie = stateStore.GetStateRoot(null);\n            HashDigest<SHA256> emptyRootHash = emptyTrie.Hash;\n\n            Assert.Null(emptyTrie.Root);\n            Assert.True(stateStore.GetStateRoot(emptyRootHash).Recorded);\n            Assert.Null(stateStore.GetStateRoot(emptyRootHash).Root);\n            Assert.False(keyValueStore.Exists(new KeyBytes(emptyRootHash.ByteArray)));\n\n            emptyTrie = stateStore.Commit(emptyTrie);\n            Assert.Null(emptyTrie.Root);\n            Assert.Equal(emptyRootHash, emptyTrie.Hash);\n            Assert.True(stateStore.GetStateRoot(emptyRootHash).Recorded);\n            Assert.False(keyValueStore.Exists(new KeyBytes(emptyRootHash.ByteArray)));\n        }\n\n        [Fact]\n        public void Commit()\n        {\n            IKeyValueStore keyValueStore = new MemoryKeyValueStore();\n            IStateStore stateStore = new TrieStateStore(keyValueStore);\n            ITrie trie = stateStore.GetStateRoot(null);\n\n            trie = trie.Set(new KeyBytes(new byte[] { 0x2c, 0x73 }), new Text(\"2c73\"));\n            trie = trie.Set(new KeyBytes(new byte[] { 0x23, 0x4f }), new Text(\"234f\"));\n\n            HashDigest<SHA256> hashBeforeCommit = trie.Hash;\n            trie = stateStore.Commit(trie);\n            HashDigest<SHA256> hashAfterCommitOnce = trie.Hash;\n            trie = stateStore.Commit(trie);\n            HashDigest<SHA256> hashAfterCommitTwice = trie.Hash;\n\n            Assert.NotEqual(hashBeforeCommit, hashAfterCommitOnce);\n            Assert.Equal(hashAfterCommitOnce, hashAfterCommitTwice);\n            Assert.False(stateStore.GetStateRoot(hashBeforeCommit).Recorded);\n            Assert.True(stateStore.GetStateRoot(hashAfterCommitOnce).Recorded);\n            Assert.False(keyValueStore.Exists(new KeyBytes(hashBeforeCommit.ByteArray)));\n            Assert.True(keyValueStore.Exists(new KeyBytes(hashAfterCommitOnce.ByteArray)));\n\n            trie = stateStore.GetStateRoot(hashAfterCommitOnce);\n            Assert.Equal(2, trie.IterateValues().Count());\n            Assert.Equal(new Text(\"2c73\"), trie.Get(new KeyBytes(new byte[] { 0x2c, 0x73 })));\n            Assert.Equal(new Text(\"234f\"), trie.Get(new KeyBytes(new byte[] { 0x23, 0x4f })));\n        }\n\n        [Fact]\n        public void CommittedNonEmptyTrieRootIsHashNode()\n        {\n            IKeyValueStore keyValueStore = new MemoryKeyValueStore();\n            IStateStore stateStore = new TrieStateStore(keyValueStore);\n            ITrie trie = stateStore.GetStateRoot(null);\n            trie = trie.Set(new KeyBytes(Array.Empty<byte>()), new Integer(1));\n            trie = stateStore.Commit(trie);\n            HashNode root = Assert.IsType<HashNode>(trie.Root);\n            trie = stateStore.GetStateRoot(trie.Hash);\n            Assert.IsType<HashNode>(trie.Root);\n            Assert.Equal(root, trie.Root);\n        }\n    }\n}\n"
  },
  {
    "path": "test/Libplanet.Tests/Store/TrieStateStoreTest.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Collections.Immutable;\nusing System.Linq;\nusing System.Security.Cryptography;\nusing Bencodex.Types;\nusing Libplanet.Common;\nusing Libplanet.Crypto;\nusing Libplanet.Store;\nusing Libplanet.Store.Trie;\nusing Xunit;\nusing static Libplanet.Tests.TestUtils;\n\nnamespace Libplanet.Tests.Store\n{\n    public class TrieStateStoreTest\n    {\n        private readonly IKeyValueStore _stateKeyValueStore;\n\n        public TrieStateStoreTest()\n        {\n            _stateKeyValueStore = new DefaultKeyValueStore(null);\n        }\n\n        public static KeyBytes KeyFoo => new KeyBytes(\"foo\");\n\n        public static KeyBytes KeyBar => new KeyBytes(\"bar\");\n\n        public static KeyBytes KeyBaz => new KeyBytes(\"baz\");\n\n        public static KeyBytes KeyQux => new KeyBytes(\"qux\");\n\n        public static KeyBytes KeyQuux => new KeyBytes(\"quux\");\n\n        [Fact]\n        public void GetStateRoot()\n        {\n            var stateStore = new TrieStateStore(_stateKeyValueStore);\n            ITrie empty = stateStore.GetStateRoot(null);\n            Assert.True(empty.Recorded);\n            Assert.Null(empty.Get(new[] { KeyFoo })[0]);\n            Assert.Null(empty.Get(new[] { KeyBar })[0]);\n            Assert.Null(empty.Get(new[] { KeyBaz })[0]);\n            Assert.Null(empty.Get(new[] { KeyQux })[0]);\n            Assert.Null(empty.Get(new[] { KeyQuux })[0]);\n\n            KeyBytes fooKey = new KeyBytes(\"foo\");\n            KeyBytes barKey = new KeyBytes(\"bar\");\n            KeyBytes bazKey = new KeyBytes(\"baz\");\n            KeyBytes quxKey = new KeyBytes(\"qux\");\n            var values = ImmutableDictionary<KeyBytes, IValue>.Empty\n                .Add(fooKey, (Binary)GetRandomBytes(32))\n                .Add(barKey, (Text)ByteUtil.Hex(GetRandomBytes(32)))\n                .Add(bazKey, (Bencodex.Types.Boolean)false)\n                .Add(quxKey, Bencodex.Types.Dictionary.Empty);\n            ITrie trie = stateStore.Commit(\n                values.Aggregate(\n                    stateStore.GetStateRoot(null),\n                    (prev, kv) => prev.Set(kv.Key, kv.Value)));\n            HashDigest<SHA256> hash = trie.Hash;\n            ITrie found = stateStore.GetStateRoot(hash);\n            Assert.True(found.Recorded);\n            AssertBencodexEqual(values[fooKey], found.Get(new[] { KeyFoo })[0]);\n            AssertBencodexEqual(values[barKey], found.Get(new[] { KeyBar })[0]);\n            AssertBencodexEqual(values[bazKey], found.Get(new[] { KeyBaz })[0]);\n            AssertBencodexEqual(values[quxKey], found.Get(new[] { KeyQux })[0]);\n            Assert.Null(found.Get(new[] { KeyQuux })[0]);\n        }\n\n        [Fact]\n        public void CopyStates()\n        {\n            var stateStore = new TrieStateStore(_stateKeyValueStore);\n            IKeyValueStore targetStateKeyValueStore = new MemoryKeyValueStore();\n            var targetStateStore = new TrieStateStore(targetStateKeyValueStore);\n            Random random = new Random();\n            List<(KeyBytes, IValue)> kvs = Enumerable.Range(0, 1_000)\n                .Select(_ =>\n                (\n                    new KeyBytes(GetRandomBytes(random.Next(1, 20))),\n                    (IValue)new Binary(GetRandomBytes(20))\n                ))\n                .ToList();\n\n            ITrie trie = stateStore.GetStateRoot(null);\n            foreach (var kv in kvs)\n            {\n                trie = trie.Set(kv.Item1, kv.Item2);\n            }\n\n            trie = stateStore.Commit(trie);\n            int prevStatesCount = _stateKeyValueStore.ListKeys().Count();\n\n            // NOTE: Avoid possible collision of KeyBytes, just in case.\n            _stateKeyValueStore.Set(\n                new KeyBytes(GetRandomBytes(30)),\n                ByteUtil.ParseHex(\"00\"));\n            _stateKeyValueStore.Set(\n                new KeyBytes(GetRandomBytes(40)),\n                ByteUtil.ParseHex(\"00\"));\n\n            Assert.Equal(prevStatesCount + 2, _stateKeyValueStore.ListKeys().Count());\n            Assert.Empty(targetStateKeyValueStore.ListKeys());\n\n            stateStore.CopyStates(\n                ImmutableHashSet<HashDigest<SHA256>>.Empty.Add(trie.Hash),\n                targetStateStore);\n\n            // It will stay at the same count of nodes.\n            // FIXME: Bencodex fingerprints also should be tracked.\n            //        https://github.com/planetarium/libplanet/issues/1653\n            Assert.Equal(prevStatesCount, targetStateKeyValueStore.ListKeys().Count());\n            Assert.Equal(\n                trie.IterateNodes().Count(),\n                targetStateStore.GetStateRoot(trie.Hash).IterateNodes().Count());\n            Assert.Equal(\n                trie.IterateValues().Count(),\n                targetStateStore.GetStateRoot(trie.Hash).IterateValues().Count());\n        }\n\n        [Fact]\n        public void CopyWorldStates()\n        {\n            var stateStore = new TrieStateStore(_stateKeyValueStore);\n            IKeyValueStore targetStateKeyValueStore = new MemoryKeyValueStore();\n            var targetStateStore = new TrieStateStore(targetStateKeyValueStore);\n            Random random = new Random();\n            Dictionary<Address, List<(KeyBytes, IValue)>> data = Enumerable\n                .Range(0, 20)\n                .Select(_ => new Address(GetRandomBytes(Address.Size)))\n                .ToDictionary(\n                    address => address,\n                    _ => Enumerable\n                        .Range(0, 100)\n                        .Select(__ =>\n                        (\n                            new KeyBytes(GetRandomBytes(random.Next(20))),\n                            (IValue)new Binary(GetRandomBytes(20))\n                        ))\n                        .ToList());\n\n            ITrie worldTrie = stateStore.GetStateRoot(null);\n            worldTrie = worldTrie.SetMetadata(new TrieMetadata(5));\n\n            List<HashDigest<SHA256>> accountHashes = new List<HashDigest<SHA256>>();\n            foreach (var elem in data)\n            {\n                ITrie trie = stateStore.GetStateRoot(null);\n                foreach (var kv in elem.Value)\n                {\n                    trie = trie.Set(kv.Item1, kv.Item2);\n                }\n\n                trie = stateStore.Commit(trie);\n                worldTrie = worldTrie.Set(new KeyBytes(elem.Key.ByteArray), trie.Hash.Bencoded);\n                accountHashes.Add(trie.Hash);\n            }\n\n            worldTrie = stateStore.Commit(worldTrie);\n            int prevStatesCount = _stateKeyValueStore.ListKeys().Count();\n\n            // NOTE: Avoid possible collision of KeyBytes, just in case.\n            _stateKeyValueStore.Set(\n                new KeyBytes(GetRandomBytes(30)),\n                ByteUtil.ParseHex(\"00\"));\n            _stateKeyValueStore.Set(\n                new KeyBytes(GetRandomBytes(40)),\n                ByteUtil.ParseHex(\"00\"));\n\n            Assert.Equal(prevStatesCount + 2, _stateKeyValueStore.ListKeys().Count());\n            Assert.Empty(targetStateKeyValueStore.ListKeys());\n\n            stateStore.CopyStates(\n                ImmutableHashSet<HashDigest<SHA256>>.Empty.Add(worldTrie.Hash),\n                targetStateStore);\n\n            // It will stay at the same count of nodes.\n            // FIXME: Bencodex fingerprints also should be tracked.\n            //        https://github.com/planetarium/libplanet/issues/1653\n            Assert.Equal(prevStatesCount, targetStateKeyValueStore.ListKeys().Count());\n            Assert.Equal(\n                worldTrie.IterateNodes().Count(),\n                targetStateStore.GetStateRoot(worldTrie.Hash).IterateNodes().Count());\n            Assert.Equal(\n                worldTrie.IterateValues().Count(),\n                targetStateStore.GetStateRoot(worldTrie.Hash).IterateValues().Count());\n            Assert.Equal(\n                stateStore.GetStateRoot(accountHashes.First()).IterateNodes().Count(),\n                targetStateStore.GetStateRoot(accountHashes.First()).IterateNodes().Count());\n            Assert.Equal(\n                stateStore.GetStateRoot(accountHashes.First()).IterateValues().Count(),\n                targetStateStore.GetStateRoot(accountHashes.First()).IterateValues().Count());\n        }\n\n        [Fact]\n#pragma warning disable S2699 // Tests should include assertions\n        public void IdempotentDispose()\n#pragma warning restore S2699 // Tests should include assertions\n        {\n            var stateStore = new TrieStateStore(_stateKeyValueStore);\n            stateStore.Dispose();\n#pragma warning disable S3966 // Objects should not be disposed more than once\n            stateStore.Dispose();\n#pragma warning restore S3966 // Objects should not be disposed more than once\n        }\n    }\n}\n"
  },
  {
    "path": "test/Libplanet.Tests/TestUtils.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Collections.Immutable;\nusing System.IO;\nusing System.Linq;\nusing System.Linq.Expressions;\nusing System.Numerics;\nusing System.Security.Cryptography;\nusing System.Text;\nusing System.Text.Json;\nusing System.Text.Json.JsonDiffPatch.Xunit;\nusing System.Text.Json.Nodes;\nusing System.Threading.Tasks;\nusing Bencodex.Types;\nusing DiffPlex.DiffBuilder;\nusing DiffPlex.DiffBuilder.Model;\nusing Libplanet.Action;\nusing Libplanet.Action.Loader;\nusing Libplanet.Action.Sys;\nusing Libplanet.Action.Tests.Common;\nusing Libplanet.Blockchain;\nusing Libplanet.Blockchain.Policies;\nusing Libplanet.Blockchain.Renderers;\nusing Libplanet.Blockchain.Renderers.Debug;\nusing Libplanet.Common;\nusing Libplanet.Crypto;\nusing Libplanet.Store;\nusing Libplanet.Store.Trie;\nusing Libplanet.Types.Blocks;\nusing Libplanet.Types.Consensus;\nusing Libplanet.Types.Evidence;\nusing Libplanet.Types.Tx;\nusing Xunit;\nusing Xunit.Abstractions;\nusing Xunit.Sdk;\nusing Random = System.Random;\n\nnamespace Libplanet.Tests\n{\n    public static class TestUtils\n    {\n        public static readonly ImmutableList<PrivateKey> ValidatorPrivateKeys = new List<PrivateKey>\n        {\n            PrivateKey.FromString(\n                \"e5792a1518d9c7f7ecc35cd352899211a05164c9dde059c9811e0654860549ef\"),\n            PrivateKey.FromString(\n                \"91d61834be824c952754510fcf545180eca38e036d3d9b66564f0667b30d5b93\"),\n            PrivateKey.FromString(\n                \"b17c919b07320edfb3e6da2f1cfed75910322de2e49377d6d4d226505afca550\"),\n            PrivateKey.FromString(\n                \"91602d7091c5c7837ac8e71a8d6b1ed1355cfe311914d9a76107899add0ad56a\"),\n        }.ToImmutableList();  // The ordering here should match the ordering by address.\n\n        public static readonly ValidatorSet ValidatorSet = new ValidatorSet(\n            ValidatorPrivateKeys.Select(\n                privateKey => new Validator(privateKey.PublicKey, BigInteger.One)).ToList());\n\n        // These keys are used to generate a situation that two adjacent peers generated by these\n        // keys are in different buckets in routing table of Kademlia Protocol.\n        public static readonly PrivateKey[] AdjacentKeys = new PrivateKey[10]\n        {\n            new PrivateKey(new byte[]\n            {\n                0x98, 0x66, 0x98, 0x50, 0x72, 0x8c, 0x6c, 0x41, 0x0b, 0xf4,\n                0x2c, 0x45, 0xfe, 0x7c, 0x49, 0x23, 0x2d, 0x14, 0xcf, 0xb5,\n                0x5b, 0x78, 0x4d, 0x81, 0x35, 0xae, 0x40, 0x4c, 0x7c, 0x24,\n                0x3f, 0xc7,\n            }),\n            new PrivateKey(new byte[]\n            {\n                0xd2, 0x47, 0x6f, 0xf3, 0x1a, 0xf3, 0x4f, 0x00, 0x5a, 0xe2,\n                0xd9, 0x24, 0x18, 0x60, 0xe9, 0xb9, 0xd0, 0x42, 0x9a, 0x30,\n                0x67, 0x81, 0x2b, 0x00, 0xf0, 0x45, 0x87, 0x70, 0x3f, 0xd5,\n                0x51, 0x93,\n            }),\n            new PrivateKey(new byte[]\n            {\n                0x9e, 0xd4, 0xdb, 0x20, 0xfd, 0x4d, 0x1c, 0x52, 0x55, 0x24,\n                0x80, 0x52, 0xc6, 0x1f, 0x95, 0x1c, 0xf1, 0x49, 0x4a, 0xd6,\n                0xf9, 0x1d, 0x29, 0xb9, 0xa3, 0x0b, 0x0e, 0x0c, 0xc8, 0xaa,\n                0xb0, 0x79,\n            }),\n            new PrivateKey(new byte[]\n            {\n                0x0a, 0x4f, 0x84, 0xeb, 0x69, 0x4d, 0xc1, 0xf0, 0xf3, 0x15,\n                0x97, 0xcc, 0x95, 0x53, 0x66, 0x01, 0x27, 0x2a, 0xc1, 0xcd,\n                0x0f, 0xf6, 0x02, 0x6f, 0x08, 0x29, 0x1d, 0xd0, 0x79, 0xda,\n                0xcc, 0x36,\n            }),\n            new PrivateKey(new byte[]\n            {\n                0x68, 0xbd, 0xc3, 0xda, 0xf1, 0xa1, 0x67, 0x9c, 0xa1, 0x1e,\n                0x5a, 0x64, 0x10, 0xe6, 0x74, 0x95, 0x77, 0xbc, 0x47, 0x1c,\n                0x55, 0xd7, 0x38, 0xa3, 0x67, 0x48, 0x73, 0x08, 0xcd, 0x74,\n                0x3c, 0x4b,\n            }),\n            new PrivateKey(new byte[]\n            {\n                0x02, 0x40, 0xa6, 0x72, 0xdd, 0xc0, 0x65, 0x04, 0x54, 0xfb,\n                0x34, 0x29, 0x05, 0xaa, 0xa6, 0x1e, 0x94, 0x30, 0x89, 0x26,\n                0xfd, 0x30, 0xd1, 0x61, 0x8c, 0x1b, 0x75, 0x79, 0x86, 0xf8,\n                0x8a, 0x6a,\n            }),\n            new PrivateKey(new byte[]\n            {\n                0x74, 0x6d, 0x07, 0xb0, 0xb9, 0x7e, 0x0d, 0xb9, 0x1f, 0x96,\n                0x59, 0xe1, 0x20, 0x8d, 0x31, 0xac, 0x94, 0xcd, 0xc8, 0xaa,\n                0x0c, 0x0d, 0xeb, 0x35, 0xab, 0x93, 0x95, 0x65, 0xae, 0x5f,\n                0xc1, 0x4b,\n            }),\n            new PrivateKey(new byte[]\n            {\n                0xc5, 0x1e, 0xc4, 0x6c, 0x81, 0x6a, 0x9d, 0x41, 0xc2, 0xae,\n                0x61, 0x51, 0x0f, 0x97, 0xd0, 0x0e, 0x3a, 0x7b, 0x86, 0xd3,\n                0xbd, 0xf1, 0x1e, 0xfe, 0x55, 0x67, 0x8f, 0x31, 0x92, 0xc1,\n                0xdf, 0xe4,\n            }),\n            new PrivateKey(new byte[]\n            {\n                0x0a, 0x9e, 0x67, 0x59, 0x4b, 0xfc, 0xdd, 0x81, 0xcd, 0x86,\n                0xa0, 0xf1, 0x79, 0x74, 0x56, 0x0f, 0x56, 0x85, 0xff, 0x3f,\n                0x75, 0xd3, 0xbc, 0xaa, 0xf0, 0xa2, 0xec, 0xdb, 0x05, 0xa5,\n                0x59, 0x79,\n            }),\n            new PrivateKey(new byte[]\n            {\n                0x3d, 0xae, 0x2d, 0x2f, 0x87, 0x1b, 0x11, 0xaa, 0x41, 0xbd,\n                0xec, 0x81, 0x4c, 0x4d, 0x27, 0xf3, 0xba, 0xd9, 0x1f, 0x61,\n                0xc3, 0x57, 0xab, 0x43, 0xa0, 0x0c, 0x63, 0x1b, 0x2b, 0x15,\n                0x13, 0xf2,\n            }),\n        };\n\n        private static readonly Random _random = new Random();\n\n        public static PrivateKey GenesisProposer => ValidatorPrivateKeys[0];\n\n        public static void AssertBytesEqual(byte[] expected, byte[] actual)\n        {\n            if (expected is null)\n            {\n                Assert.Null(actual);\n                return;\n            }\n\n            Assert.NotNull(actual);\n\n            string msg;\n            if (expected.LongLength < 1024 && actual.LongLength < 1024 &&\n                expected.All(b => b < 0x80) && actual.All(b => b < 0x80))\n            {\n                // If both arrays can be ASCII encoding, print them directly.\n                string expectedStr = Encoding.ASCII.GetString(expected);\n                string actualStr = Encoding.ASCII.GetString(actual);\n                msg = $@\"Two byte arrays do not equal\nExpected length: ({expected.LongLength}) {expectedStr}\nActual length:   ({actual.LongLength}) {actualStr}\";\n            }\n            else\n            {\n                string expectedRepr = Repr(expected);\n                string actualRepr = Repr(actual);\n                msg = $@\"Two byte arrays do not equal\nExpected (C# array lit): new byte[{expected.LongLength}] {{ {expectedRepr} }}\nActual (C# array lit):   new byte[{actual.LongLength}] {{ {actualRepr} }}\";\n            }\n\n            if (!expected.SequenceEqual(actual))\n            {\n                throw new AssertActualExpectedException(\n                    ByteUtil.Hex(expected),\n                    ByteUtil.Hex(actual),\n                    msg,\n                    \"Expected (hex)\",\n                    \"Actual (hex)\"\n                );\n            }\n\n            string Repr(byte[] bytes)\n            {\n                const int limit = 1024;\n                if (bytes.LongLength > limit)\n                {\n                    bytes = bytes.Take(limit).ToArray();\n                }\n\n                string s = string.Join(\n                    \", \",\n                    bytes.Select(b => b < 0x10 ? $\"0x0{b:x}\" : $\"0x{b:x}\")\n                );\n                return bytes.LongLength > limit ? $\"{s}, ...\" : s;\n            }\n        }\n\n        public static void AssertBytesEqual(\n            byte[] expected,\n            ImmutableArray<byte> actual) =>\n            AssertBytesEqual(expected, actual.ToArray());\n\n        public static void AssertBytesEqual(\n            byte[] expected,\n            string actualHex) =>\n            AssertBytesEqual(expected, ByteUtil.ParseHex(actualHex));\n\n        public static void AssertBytesEqual(\n            ImmutableArray<byte> expected,\n            byte[] actual) =>\n            AssertBytesEqual(expected.ToArray(), actual);\n\n        public static void AssertBytesEqual(\n            ImmutableArray<byte> expected,\n            ImmutableArray<byte> actual) =>\n            AssertBytesEqual(expected.ToArray(), actual.ToArray());\n\n        public static void AssertBytesEqual(\n            ImmutableArray<byte> expected,\n            string actualHex) =>\n            AssertBytesEqual(expected.ToArray(), ByteUtil.ParseHex(actualHex));\n\n        public static void AssertBytesEqual(\n            string expectedHex,\n            byte[] actual) =>\n            AssertBytesEqual(ByteUtil.ParseHex(expectedHex), actual);\n\n        public static void AssertBytesEqual(\n            string expectedHex,\n            ImmutableArray<byte> actual) =>\n            AssertBytesEqual(ByteUtil.ParseHex(expectedHex), actual.ToArray());\n\n        public static void AssertBytesEqual(\n            string expectedHex,\n            string actualHex) =>\n            AssertBytesEqual(ByteUtil.ParseHex(expectedHex), ByteUtil.ParseHex(actualHex));\n\n        public static void AssertBytesEqual(TxId expected, TxId actual) =>\n            AssertBytesEqual(expected.ToByteArray(), actual.ToByteArray());\n\n        public static void AssertBytesEqual(TxId? expected, TxId? actual) =>\n            AssertBytesEqual(expected?.ToByteArray(), actual?.ToByteArray());\n\n        public static void AssertBytesEqual(BlockHash expected, BlockHash actual) =>\n            AssertBytesEqual(expected.ToByteArray(), actual.ToByteArray());\n\n        public static void AssertBytesEqual(BlockHash? expected, BlockHash? actual) =>\n            AssertBytesEqual(expected?.ToByteArray(), actual?.ToByteArray());\n\n        public static void AssertBytesEqual<T>(HashDigest<T> expected, HashDigest<T> actual)\n            where T : HashAlgorithm =>\n            AssertBytesEqual(expected.ToByteArray(), actual.ToByteArray());\n\n        public static void AssertBytesEqual<T>(HashDigest<T>? expected, HashDigest<T>? actual)\n            where T : HashAlgorithm =>\n            AssertBytesEqual(expected?.ToByteArray(), actual?.ToByteArray());\n\n        public static void AssertBytesEqual(Address expected, Address actual) =>\n            AssertBytesEqual(expected.ToByteArray(), actual.ToByteArray());\n\n        public static void AssertBytesEqual(Address? expected, Address? actual) =>\n            AssertBytesEqual(expected?.ToByteArray(), actual?.ToByteArray());\n\n        public static void AssertBytesEqual(KeyBytes expected, KeyBytes actual) =>\n            AssertBytesEqual(expected.ToByteArray(), actual.ToByteArray());\n\n        public static void AssertBytesEqual(KeyBytes? expected, KeyBytes? actual) =>\n            AssertBytesEqual(expected?.ToByteArray(), actual?.ToByteArray());\n\n        public static void AssertBencodexEqual(IValue expected, IValue actual)\n        {\n            bool equal = (expected is null && actual is null) ||\n                (expected is Null && actual is Null) ||\n                (expected is Bencodex.Types.Boolean && actual is Bencodex.Types.Boolean &&\n                    expected.Equals(actual)) ||\n                (expected is Integer && actual is Integer && expected.Equals(actual)) ||\n                (expected is Binary && actual is Binary && expected.Equals(actual)) ||\n                (expected is Text && actual is Text && expected.Equals(actual)) ||\n                (expected is List && actual is List && expected.Equals(actual)) ||\n                (expected is Dictionary && actual is Dictionary && expected.Equals(actual));\n            if (equal)\n            {\n                return;\n            }\n\n            string expectedInspection = expected?.ToString() ?? \"(null)\";\n            string actualInspection = actual?.ToString() ?? \"(null)\";\n            DiffPaneModel diffModel = InlineDiffBuilder.Diff(expectedInspection, actualInspection);\n            var prefixes = new Dictionary<ChangeType, string>\n            {\n                [ChangeType.Deleted] = \"-\",\n                [ChangeType.Inserted] = \"+\",\n                [ChangeType.Unchanged] = \" \",\n            };\n\n            string diff = string.Join(\n                Environment.NewLine,\n                diffModel.Lines.Select(line =>\n                    (prefixes.TryGetValue(line.Type, out string prefix) ? prefix : \" \") + line.Text\n                )\n            );\n            throw new XunitException(\n                \"Two Bencodex values are not equal.\\n--- Expected\\n+++ Actual\\n\\n\" + diff\n            );\n        }\n\n        public static void AssertSorted<T>(IEnumerable<T> expected)\n            where T : IComparable<T>\n        {\n            // Was implemented by `.Zip()`, but the method has different\n            // overloads in .NET Framework, so cannot be used.\n            T[] arr = expected.ToArray();\n            foreach ((int i, (T first, T second)) in Enumerable\n                         .Range(0, arr.Length - 1)\n                         .Select(i => (i, (arr[i], arr[i + 1]))))\n            {\n                string errorMessage =\n                    $\"Given list is not sorted since item {first} at {i} \" +\n                    $\"is greater than item {second} at {i + 1}\";\n                Assert.True(first.CompareTo(second) <= 0, errorMessage);\n            }\n        }\n\n        public static void AssertBlockMetadataEqual(IBlockMetadata expected, IBlockMetadata actual)\n        {\n            Assert.NotNull(expected);\n            Assert.NotNull(actual);\n            Assert.Equal(expected.ProtocolVersion, actual.ProtocolVersion);\n            Assert.Equal(expected.Index, actual.Index);\n            Assert.Equal(expected.Timestamp, actual.Timestamp);\n            AssertBytesEqual(expected.Miner, actual.Miner);\n            AssertBytesEqual(expected.PreviousHash, actual.PreviousHash);\n            AssertBytesEqual(expected.TxHash, actual.TxHash);\n        }\n\n        public static void AssertBlockContentsEqual(\n            IBlockContent expected, IBlockContent actual)\n        {\n            AssertBlockMetadataEqual(expected, actual);\n            Assert.Equal(expected.Transactions, actual.Transactions);\n        }\n\n        public static void AssertPreEvaluationBlockHeadersEqual(\n            IPreEvaluationBlockHeader expected,\n            IPreEvaluationBlockHeader actual\n        )\n        {\n            AssertBlockMetadataEqual(expected, actual);\n            AssertBytesEqual(expected.PreEvaluationHash, actual.PreEvaluationHash);\n        }\n\n        public static void AssertPreEvaluationBlocksEqual(\n            IPreEvaluationBlock expected,\n            IPreEvaluationBlock actual)\n        {\n            AssertPreEvaluationBlockHeadersEqual(expected, actual);\n            AssertBlockContentsEqual(expected, actual);\n        }\n\n        public static byte[] GetRandomBytes(int size)\n        {\n            var bytes = new byte[size];\n            _random.NextBytes(bytes);\n\n            return bytes;\n        }\n\n        public static T ToAction<T>(IValue plainValue)\n            where T : IAction, new()\n        {\n            var action = new T();\n            action.LoadPlainValue(plainValue);\n            return action;\n        }\n\n        public static BlockCommit CreateBlockCommit(\n            Block block,\n            bool deterministicTimestamp = false)\n        {\n            if (block.Index <= 0 || block.ProtocolVersion < BlockMetadata.PBFTProtocolVersion)\n            {\n                return null;\n            }\n\n            var useValidatorPower = block.ProtocolVersion >= BlockMetadata.EvidenceProtocolVersion;\n            return CreateBlockCommit(\n                block.Hash, block.Index, 0, deterministicTimestamp, useValidatorPower);\n        }\n\n        public static BlockCommit CreateBlockCommit(\n            BlockHash blockHash,\n            long height,\n            int round,\n            bool deterministicTimestamp = false,\n            bool useValidatorPower = true)\n        {\n            // Index #1 block cannot have lastCommit: There was no consensus of genesis block.\n            if (height == 0)\n            {\n                return null;\n            }\n\n            // Using the unix epoch time as the timestamp of the vote if deterministicTimestamp is\n            // flagged for getting a deterministic random value from PreEvaluationHash.\n            var votes = ValidatorPrivateKeys.Select(key => new VoteMetadata(\n                height,\n                round,\n                blockHash,\n                deterministicTimestamp ? DateTimeOffset.UnixEpoch : DateTimeOffset.UtcNow,\n                key.PublicKey,\n                useValidatorPower ? ValidatorSet.GetValidator(key.PublicKey).Power : null,\n                VoteFlag.PreCommit).Sign(key)).ToImmutableArray();\n\n            return new BlockCommit(\n                height, round, blockHash, votes);\n        }\n\n        public static PreEvaluationBlock ProposeGenesis(\n            PublicKey proposer,\n            IReadOnlyList<Transaction> transactions = null,\n            ValidatorSet validatorSet = null,\n            DateTimeOffset? timestamp = null,\n            int protocolVersion = Block.CurrentProtocolVersion\n        )\n        {\n            var txs = transactions?.ToList() ?? new List<Transaction>();\n            long nonce = txs.Count(tx => tx.Signer.Equals(GenesisProposer.Address));\n            validatorSet = validatorSet ?? ValidatorSet;\n            txs.Add(\n                Transaction.Create(\n                    nonce++,\n                    GenesisProposer,\n                    null,\n                    actions: new IAction[]\n                    {\n                        new Initialize(\n                            validatorSet: validatorSet,\n                            states: ImmutableDictionary.Create<Address, IValue>()),\n                    }.Select(x => x.PlainValue),\n                    timestamp: DateTimeOffset.MinValue));\n            txs = txs.OrderBy(tx => tx.Id).ToList();\n\n            var content = new BlockContent(\n                new BlockMetadata(\n                    protocolVersion: protocolVersion,\n                    index: 0,\n                    timestamp: timestamp ??\n                        new DateTimeOffset(2018, 11, 29, 0, 0, 0, TimeSpan.Zero),\n                    miner: (proposer ?? GenesisProposer.PublicKey).Address,\n                    publicKey: protocolVersion >= 2 ? proposer ?? GenesisProposer.PublicKey : null,\n                    previousHash: null,\n                    txHash: BlockContent.DeriveTxHash(txs),\n                    lastCommit: null,\n                    evidenceHash: null),\n                transactions: txs,\n                evidence: Array.Empty<EvidenceBase>());\n            return content.Propose();\n        }\n\n        public static Block ProposeGenesisBlock(\n            PrivateKey miner,\n            IReadOnlyList<Transaction> transactions = null,\n            DateTimeOffset? timestamp = null,\n            int protocolVersion = Block.CurrentProtocolVersion,\n            HashDigest<SHA256> stateRootHash = default\n        )\n        {\n            PreEvaluationBlock preEval = ProposeGenesis(\n                miner?.PublicKey,\n                transactions,\n                null,\n                timestamp,\n                protocolVersion\n            );\n            return preEval.Sign(miner, stateRootHash);\n        }\n\n        public static Block ProposeGenesisBlock(\n            PreEvaluationBlock preEval,\n            PrivateKey privateKey)\n        {\n            return preEval.Sign(\n                privateKey,\n                MerkleTrie.EmptyRootHash);\n        }\n\n        public static PreEvaluationBlock ProposeNext(\n            Block previousBlock,\n            IReadOnlyList<Transaction> transactions = null,\n            PublicKey miner = null,\n            TimeSpan? blockInterval = null,\n            int protocolVersion = Block.CurrentProtocolVersion,\n            BlockCommit lastCommit = null,\n            ImmutableArray<EvidenceBase>? evidence = null)\n        {\n            var txs = transactions is null\n                ? new List<Transaction>()\n                : transactions.OrderBy(tx => tx.Id).ToList();\n\n            var evidenceHash = evidence != null\n                ? BlockContent.DeriveEvidenceHash(evidence)\n                : null;\n            var content = new BlockContent(\n                new BlockMetadata(\n                    protocolVersion: protocolVersion,\n                    index: previousBlock.Index + 1,\n                    timestamp: previousBlock.Timestamp.Add(\n                        blockInterval ?? TimeSpan.FromSeconds(15)),\n                    miner: miner?.Address ?? previousBlock.Miner,\n                    publicKey: protocolVersion >= 2 ? miner ?? previousBlock.PublicKey : null,\n                    previousHash: previousBlock.Hash,\n                    txHash: BlockContent.DeriveTxHash(txs),\n                    lastCommit: lastCommit,\n                    evidenceHash: evidenceHash),\n                transactions: txs,\n                evidence: Array.Empty<EvidenceBase>());\n            var preEval = content.Propose();\n            preEval.ValidateTimestamp();\n            return preEval;\n        }\n\n        public static Block ProposeNextBlock(\n            Block previousBlock,\n            PrivateKey miner,\n            IReadOnlyList<Transaction> txs = null,\n            TimeSpan? blockInterval = null,\n            int protocolVersion = Block.CurrentProtocolVersion,\n            HashDigest<SHA256> stateRootHash = default,\n            BlockCommit lastCommit = null,\n            ImmutableArray<EvidenceBase>? evidence = null)\n        {\n            Skip.IfNot(\n                Environment.GetEnvironmentVariable(\"XUNIT_UNITY_RUNNER\") is null,\n                \"Flaky test : Libplanet.Blocks.InvalidBlockSignatureException\"\n            );\n\n            PreEvaluationBlock preEval = ProposeNext(\n                previousBlock,\n                txs,\n                miner?.PublicKey,\n                blockInterval,\n                protocolVersion,\n                lastCommit,\n                evidence);\n            return preEval.Sign(miner, stateRootHash);\n        }\n\n        /// <summary>\n        /// Creates a <see cref=\"BlockChain\"/> instance containing\n        /// only a genesis <see cref=\"Block\"/>.\n        /// </summary>\n        /// <param name=\"policy\">A <see cref=\"BlockPolicy\"/> of the chain.</param>\n        /// <param name=\"store\">An <see cref=\"IStore\"/> instance to store blocks and txs.</param>\n        /// <param name=\"stateStore\">An <see cref=\"IStateStore\"/> instance to store states.</param>\n        /// <param name=\"actionLoader\">An <see cref=\"IActionLoader\"/> instance to load actions.\n        /// </param>\n        /// <param name=\"actions\"><see cref=\"Action{T}\"/>s to be included in genesis block.\n        /// Works only if <paramref name=\"genesisBlock\"/> is null.</param>\n        /// <param name=\"validatorSet\"><see cref=\"ValidatorSet\"/> to be included in genesis block.\n        /// Works only if <paramref name=\"genesisBlock\"/> is null.</param>\n        /// <param name=\"privateKey\">A <see cref=\"PrivateKey\"/> to sign genesis actions.\n        /// Works only if <paramref name=\"genesisBlock\"/> is null.</param>\n        /// <param name=\"timestamp\"><see cref=\"DateTimeOffset\"/> of the genesis block.\n        /// Works only if <paramref name=\"genesisBlock\"/> is null.</param>\n        /// <param name=\"renderers\">\n        /// An <see cref=\"IEnumerable{T}\"/> of <see cref=\"IRenderer\"/>s.</param>\n        /// <param name=\"genesisBlock\">Genesis <see cref=\"Block\"/> of the chain.\n        /// If null is given, a genesis will be generated.</param>\n        /// <param name=\"protocolVersion\">Block protocol version of genesis block.</param>\n        /// <typeparam name=\"T\">An <see cref=\"IAction\"/> type.</typeparam>\n        /// <returns>A <see cref=\"BlockChain\"/> instance.</returns>\n        public static BlockChain MakeBlockChain(\n            IBlockPolicy policy,\n            IStore store,\n            IStateStore stateStore,\n            IActionLoader actionLoader,\n            IEnumerable<IAction> actions = null,\n            ValidatorSet validatorSet = null,\n            PrivateKey privateKey = null,\n            DateTimeOffset? timestamp = null,\n            IEnumerable<IRenderer> renderers = null,\n            Block genesisBlock = null,\n            int protocolVersion = Block.CurrentProtocolVersion\n        )\n        {\n            return MakeBlockChainAndActionEvaluator(\n                policy,\n                store,\n                stateStore,\n                actionLoader,\n                actions,\n                validatorSet,\n                privateKey,\n                timestamp,\n                renderers,\n                genesisBlock,\n                protocolVersion\n            ).BlockChain;\n        }\n\n        public static (BlockChain BlockChain, ActionEvaluator ActionEvaluator)\n            MakeBlockChainAndActionEvaluator(\n            IBlockPolicy policy,\n            IStore store,\n            IStateStore stateStore,\n            IActionLoader actionLoader,\n            IEnumerable<IAction> actions = null,\n            ValidatorSet validatorSet = null,\n            PrivateKey privateKey = null,\n            DateTimeOffset? timestamp = null,\n            IEnumerable<IRenderer> renderers = null,\n            Block genesisBlock = null,\n            int protocolVersion = Block.CurrentProtocolVersion\n        )\n        {\n            actions = actions ?? ImmutableArray<IAction>.Empty;\n            privateKey = privateKey ?? GenesisProposer;\n\n            var txs = new[]\n            {\n                Transaction.Create(\n                    0,\n                    privateKey,\n                    null,\n                    actions.Select(x => x.PlainValue),\n                    timestamp: timestamp ?? DateTimeOffset.MinValue),\n            };\n\n            var blockChainStates = new BlockChainStates(store, stateStore);\n            var actionEvaluator = new ActionEvaluator(\n                policy.PolicyActionsRegistry,\n                stateStore: stateStore,\n                actionTypeLoader: actionLoader);\n\n            if (genesisBlock is null)\n            {\n                var preEval = ProposeGenesis(\n                    privateKey.PublicKey,\n                    txs,\n                    validatorSet,\n                    timestamp,\n                    protocolVersion);\n                var evaluatedSrh = actionEvaluator.Evaluate(preEval, null).Last().OutputState;\n                genesisBlock = protocolVersion < BlockMetadata.SignatureProtocolVersion\n                    ? new Block(\n                        preEval,\n                        (\n                            evaluatedSrh,\n                            null,\n                            preEval.Header.DeriveBlockHash(evaluatedSrh, null)\n                        ))\n                    : protocolVersion < BlockMetadata.SlothProtocolVersion\n                        ? preEval.Sign(privateKey, evaluatedSrh)\n                        : preEval.Sign(privateKey, MerkleTrie.EmptyRootHash);\n            }\n\n            ValidatingActionRenderer validator = null;\n#pragma warning disable S1121\n            var chain = BlockChain.Create(\n                policy,\n                new VolatileStagePolicy(),\n                store,\n                stateStore,\n                genesisBlock,\n                renderers: renderers ?? new[] { validator = new ValidatingActionRenderer() },\n                blockChainStates: blockChainStates,\n                actionEvaluator: actionEvaluator\n            );\n#pragma warning restore S1121\n\n            return (chain, actionEvaluator);\n        }\n\n        public static async Task AssertThatEventually(\n            Expression<Func<bool>> condition,\n            TimeSpan timeout,\n            TimeSpan delay,\n            ITestOutputHelper output = null,\n            string conditionLabel = null\n        )\n        {\n            Func<bool> conditionFunc = condition.Compile();\n            DateTimeOffset started = DateTimeOffset.UtcNow;\n            DateTimeOffset until = started + timeout;\n            while (!conditionFunc() && DateTimeOffset.UtcNow <= until)\n            {\n                output?.WriteLine(\n                    \"[{0}/{1}] Waiting for {2}...\",\n                    DateTimeOffset.UtcNow - started,\n                    timeout,\n                    conditionLabel is string c1\n                        ? c1\n                        : $\"satisfying the condition ({condition.Body})\"\n                );\n                await Task.Delay(delay);\n            }\n\n            Assert.True(\n                conditionFunc(),\n                $\"Waited {timeout} but the condition (\" +\n                    (conditionLabel is string l ? l : condition.Body.ToString()) +\n                    \") has never been satisfied.\"\n            );\n\n            output?.WriteLine(\n                \"[{0}/{1}] Done {2}...\",\n                DateTimeOffset.UtcNow - started,\n                timeout,\n                conditionLabel is string c2 ? c2 : $\"satisfying the condition ({condition.Body})\"\n            );\n        }\n\n        public static Task AssertThatEventually(\n            Expression<Func<bool>> condition,\n            int timeoutMilliseconds,\n            int delayMilliseconds = 100,\n            ITestOutputHelper output = null,\n            string conditionLabel = null\n        ) =>\n            AssertThatEventually(\n                condition,\n                TimeSpan.FromMilliseconds(timeoutMilliseconds),\n                TimeSpan.FromMilliseconds(delayMilliseconds),\n                output,\n                conditionLabel\n            );\n\n        public static void AssertJsonSerializable<T>(\n            T obj,\n            string expectedJson,\n            bool testDeserializable = true)\n            where T : IEquatable<T>\n        {\n            Skip.IfNot(\n                Environment.GetEnvironmentVariable(\"XUNIT_UNITY_RUNNER\") is null,\n                \"System.Text.Json 6.0.0+ does not work well with Unity/Mono.\"\n            );\n\n            var buffer = new MemoryStream();\n            JsonSerializer.Serialize(buffer, obj);\n            buffer.Seek(0L, SeekOrigin.Begin);\n            var options = new JsonSerializerOptions\n            {\n                AllowTrailingCommas = true,\n                ReadCommentHandling = JsonCommentHandling.Skip,\n                PropertyNamingPolicy = JsonNamingPolicy.CamelCase,\n            };\n            JsonNode actual = JsonSerializer.SerializeToNode(obj, options);\n            JsonNode expected = JsonNode.Parse(expectedJson, null, new JsonDocumentOptions\n            {\n                AllowTrailingCommas = true,\n                CommentHandling = JsonCommentHandling.Skip,\n            });\n            JsonAssert.Equal(expected, actual, true);\n            if (testDeserializable)\n            {\n                var deserialized = JsonSerializer.Deserialize<T>(expectedJson, options);\n                Assert.Equal(obj, deserialized);\n            }\n        }\n\n        public static bool IsDumbAction(IValue action)\n        {\n            return action is Dictionary dictionary &&\n                dictionary.TryGetValue(new Text(\"type_id\"), out var typeId) &&\n                typeId.Equals(new Text(nameof(DumbAction)));\n        }\n\n        public static bool IsMinerReward(IValue action)\n        {\n            return action is Dictionary dictionary &&\n                   dictionary.TryGetValue((Text)\"reward\", out IValue rewards) &&\n                   rewards is Integer;\n        }\n\n        public static DumbAction ToDumbAction(IValue plainValue)\n        {\n            var action = new DumbAction();\n            action.LoadPlainValue(plainValue);\n            return action;\n        }\n    }\n}\n"
  },
  {
    "path": "test/Libplanet.Tests/TimeSpanExtensionsTest.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing Libplanet.Common;\nusing Xunit;\n\nnamespace Libplanet.Tests\n{\n    public class TimeSpanExtensionsTest\n    {\n        public static IEnumerable<object[]> MultiplicationTestData()\n        {\n            // This code is borrowed from the official .NET implementation:\n            //   https://git.io/JYvjS#L1095-L1105\n            // We can remove these copy-and-pasted lines in the future when Libplanet drops\n            // .NET Standard 2.0 support and becomes to support .NET Standard 2.1 or higher.\n            yield return new object[]\n            {\n                new TimeSpan(2, 30, 0),\n                2.0,\n                new TimeSpan(5, 0, 0),\n            };\n            yield return new object[]\n            {\n                new TimeSpan(14, 2, 30, 0),\n                192.0,\n                TimeSpan.FromDays(2708),\n            };\n            yield return new object[]\n            {\n                TimeSpan.FromDays(366),\n                Math.PI,\n                new TimeSpan(993446995288779),\n            };\n            yield return new object[]\n            {\n                TimeSpan.FromDays(366),\n                -Math.E,\n                new TimeSpan(-859585952922633),\n            };\n#if NET\n            // For unknown reason, TimeSpan.FromDays()'s behavior on Mono\n            // slightly differs from .NET Core.\n            yield return new object[]\n            {\n                TimeSpan.FromDays(29.530587981),\n                13.0,\n                TimeSpan.FromDays(29.530587981 * 13.0),\n            };\n            yield return new object[]\n            {\n                TimeSpan.FromDays(-29.530587981),\n                -12.0,\n                TimeSpan.FromDays(-29.530587981 * -12.0),\n            };\n#endif\n            yield return new object[]\n            {\n                TimeSpan.FromDays(-29.530587981),\n                0.0,\n                TimeSpan.Zero,\n            };\n            yield return new object[]\n            {\n                TimeSpan.MaxValue,\n                0.5,\n                TimeSpan.FromTicks((long)(long.MaxValue * 0.5)),\n            };\n        }\n\n        [Theory]\n        [MemberData(nameof(MultiplicationTestData))]\n        public static void Multiplication(TimeSpan timeSpan, double factor, TimeSpan expected)\n        {\n            // This code is borrowed from the official .NET implementation:\n            //   https://bit.ly/3MhgH63\n            // We can remove these copy-and-pasted lines in the future when Libplanet drops\n            // .NET Standard 2.0 support and becomes to support .NET Standard 2.1 or higher.\n            Assert.Equal(expected, TimeSpanExtensions.Multiply(timeSpan, factor));\n        }\n\n        [Theory]\n        [MemberData(nameof(MultiplicationTestData))]\n        public static void Division(TimeSpan timeSpan, double factor, TimeSpan expected)\n        {\n            // This code is borrowed from the official .NET implementation:\n            //   https://bit.ly/3FVRjAw\n            // We can remove these copy-and-pasted lines in the future when Libplanet drops\n            // .NET Standard 2.0 support and becomes to support .NET Standard 2.1 or higher.\n            double divisor = 1.0 / factor;\n            Assert.Equal(expected, TimeSpanExtensions.Divide(timeSpan, divisor));\n        }\n\n        [Fact]\n        public static void DivideByZero()\n        {\n            // This code is borrowed from the official .NET implementation:\n            //   https://bit.ly/3MhilEx\n            // We can remove these copy-and-pasted lines in the future when Libplanet drops\n            // .NET Standard 2.0 support and becomes to support .NET Standard 2.1 or higher.\n            Assert.Throws<OverflowException>(\n                () => TimeSpanExtensions.Divide(TimeSpan.FromDays(1), 0)\n            );\n            Assert.Throws<OverflowException>(\n                () => TimeSpanExtensions.Divide(TimeSpan.FromDays(-1), 0)\n            );\n            Assert.Throws<OverflowException>(() => TimeSpanExtensions.Divide(TimeSpan.Zero, 0));\n        }\n\n        [Fact]\n        public static void NaNMultiplication()\n        {\n            // This code is borrowed from the official .NET implementation:\n            //   https://bit.ly/3PgO36S\n            // We can remove these copy-and-pasted lines in the future when Libplanet drops\n            // .NET Standard 2.0 support and becomes to support .NET Standard 2.1 or higher.\n            ArgumentException e = Assert.Throws<ArgumentException>(\n                () => TimeSpanExtensions.Multiply(TimeSpan.FromDays(1), double.NaN));\n            Assert.Equal(\"factor\", e.ParamName);\n        }\n\n        [Fact]\n        public static void NaNDivision()\n        {\n            // This code is borrowed from the official .NET implementation:\n            //   https://bit.ly/3FRNXP0\n            // We can remove these copy-and-pasted lines in the future when Libplanet drops\n            // .NET Standard 2.0 support and becomes to support .NET Standard 2.1 or higher.\n            ArgumentException e = Assert.Throws<ArgumentException>(\n                () => TimeSpanExtensions.Divide(TimeSpan.FromDays(1), double.NaN)\n            );\n            Assert.Equal(\"divisor\", e.ParamName);\n        }\n    }\n}\n"
  },
  {
    "path": "test/Libplanet.Tests/Tx/AddressSetTest.cs",
    "content": "using System.Collections.Generic;\nusing System.Collections.Immutable;\nusing Libplanet.Crypto;\nusing Libplanet.Types.Tx;\nusing Xunit;\n\nnamespace Libplanet.Tests.Tx\n{\n    public class AddressSetTest\n    {\n        [Fact]\n        public void Empty()\n        {\n            Assert.Empty(AddressSet.Empty);\n        }\n\n        [Fact]\n        public void Constructor()\n        {\n            Address[] addresses =\n            {\n                new Address(\"4000000000000000000000000000000000000000\"),\n                new Address(\"3000000000000000000000000000000000000001\"),\n                new Address(\"2000000000000000000000000000000000000002\"),\n                new Address(\"1000000000000000000000000000000000000003\"),\n                new Address(\"0000000000000000000000000000000000000004\"),\n\n                // dups:\n                new Address(\"0000000000000000000000000000000000000004\"),\n                new Address(\"2000000000000000000000000000000000000002\"),\n                new Address(\"4000000000000000000000000000000000000000\"),\n            };\n            var set = new AddressSet(addresses);\n            Assert.Equal(5, set.Count);\n            Assert.Equal<IEnumerable<Address>>(\n                new[]\n                {\n                    new Address(\"4000000000000000000000000000000000000000\"),\n                    new Address(\"3000000000000000000000000000000000000001\"),\n                    new Address(\"2000000000000000000000000000000000000002\"),\n                    new Address(\"1000000000000000000000000000000000000003\"),\n                    new Address(\"0000000000000000000000000000000000000004\"),\n                },\n                set\n            );\n        }\n\n        [Fact]\n        public void TryGetValue()\n        {\n            var set = new AddressSet(new Address[]\n            {\n                new Address(\"2000000000000000000000000000000000000000\"),\n                new Address(\"1000000000000000000000000000000000000001\"),\n                new Address(\"0000000000000000000000000000000000000002\"),\n            });\n\n            bool found = set.TryGetValue(\n                new Address(\"1000000000000000000000000000000000000001\"),\n                out Address value);\n            Assert.True(found);\n            Assert.Equal(new Address(\"1000000000000000000000000000000000000001\"), value);\n\n            found = set.TryGetValue(\n                new Address(\"ffffffffffffffffffffffffffffffffffffffff\"),\n                out Address value2);\n            Assert.False(found);\n            Assert.Equal(default(Address), value2);\n        }\n\n        [Fact]\n        public void SymmetricExcept()\n        {\n            var set = new AddressSet(new Address[]\n            {\n                new Address(\"2000000000000000000000000000000000000000\"),\n                new Address(\"1000000000000000000000000000000000000001\"),\n                new Address(\"0000000000000000000000000000000000000002\"),\n            });\n\n            IImmutableSet<Address> result = set.SymmetricExcept(new Address[]\n            {\n                new Address(\"ffffffffffffffffffffffffffffffffffffffff\"),\n                default(Address),\n                new Address(\"0000000000000000000000000000000000000002\"),\n                new Address(\"1000000000000000000000000000000000000001\"),\n                default(Address),\n                new Address(\"ffffffffffffffffffffffffffffffffffffffff\"),\n            });\n            Assert.Equal<IEnumerable<Address>>(\n                new Address[]\n                {\n                    new Address(\"2000000000000000000000000000000000000000\"),\n                    new Address(\"ffffffffffffffffffffffffffffffffffffffff\"),\n                    default(Address),\n                },\n                result\n            );\n        }\n\n        [Fact]\n        public void IsProperSubsetOf()\n        {\n            var set = new AddressSet(new Address[]\n            {\n                new Address(\"2000000000000000000000000000000000000000\"),\n                new Address(\"1000000000000000000000000000000000000001\"),\n                new Address(\"0000000000000000000000000000000000000002\"),\n            });\n\n            bool result = set.IsProperSubsetOf(new Address[]\n            {\n                new Address(\"ffffffffffffffffffffffffffffffffffffffff\"),\n                new Address(\"1000000000000000000000000000000000000001\"),\n                new Address(\"2000000000000000000000000000000000000000\"),\n                new Address(\"0000000000000000000000000000000000000002\"),\n                new Address(\"2000000000000000000000000000000000000000\"),\n                new Address(\"ffffffffffffffffffffffffffffffffffffffff\"),\n            });\n            Assert.True(result);\n\n            result = set.IsProperSubsetOf(new Address[]\n            {\n                new Address(\"1000000000000000000000000000000000000001\"),\n                new Address(\"0000000000000000000000000000000000000002\"),\n                new Address(\"2000000000000000000000000000000000000000\"),\n                new Address(\"1000000000000000000000000000000000000001\"),\n            });\n            Assert.False(result);\n\n            result = set.IsProperSubsetOf(new Address[]\n            {\n                new Address(\"0000000000000000000000000000000000000002\"),\n                new Address(\"2000000000000000000000000000000000000000\"),\n                new Address(\"2000000000000000000000000000000000000000\"),\n                new Address(\"0000000000000000000000000000000000000002\"),\n            });\n            Assert.False(result);\n\n            result = set.IsProperSubsetOf(new Address[]\n            {\n                new Address(\"ffffffffffffffffffffffffffffffffffffffff\"),\n                new Address(\"0000000000000000000000000000000000000002\"),\n                new Address(\"0000000000000000000000000000000000000002\"),\n                new Address(\"2000000000000000000000000000000000000000\"),\n                new Address(\"ffffffffffffffffffffffffffffffffffffffff\"),\n            });\n            Assert.False(result);\n        }\n\n        [Fact]\n        public void IsProperSupersetOf()\n        {\n            var set = new AddressSet(new Address[]\n            {\n                new Address(\"2000000000000000000000000000000000000000\"),\n                new Address(\"1000000000000000000000000000000000000001\"),\n                new Address(\"0000000000000000000000000000000000000002\"),\n            });\n\n            bool result = set.IsProperSupersetOf(new Address[]\n            {\n                new Address(\"0000000000000000000000000000000000000002\"),\n                new Address(\"0000000000000000000000000000000000000002\"),\n                new Address(\"2000000000000000000000000000000000000000\"),\n            });\n            Assert.True(result);\n\n            result = set.IsProperSupersetOf(new Address[]\n            {\n                new Address(\"1000000000000000000000000000000000000001\"),\n                new Address(\"0000000000000000000000000000000000000002\"),\n                new Address(\"2000000000000000000000000000000000000000\"),\n                new Address(\"1000000000000000000000000000000000000001\"),\n            });\n            Assert.False(result);\n\n            result = set.IsProperSupersetOf(new Address[]\n            {\n                new Address(\"ffffffffffffffffffffffffffffffffffffffff\"),\n                new Address(\"0000000000000000000000000000000000000002\"),\n                new Address(\"2000000000000000000000000000000000000000\"),\n                new Address(\"ffffffffffffffffffffffffffffffffffffffff\"),\n            });\n            Assert.False(result);\n\n            result = set.IsProperSupersetOf(new Address[]\n            {\n                new Address(\"ffffffffffffffffffffffffffffffffffffffff\"),\n                new Address(\"1000000000000000000000000000000000000001\"),\n                new Address(\"0000000000000000000000000000000000000002\"),\n                new Address(\"2000000000000000000000000000000000000000\"),\n                new Address(\"ffffffffffffffffffffffffffffffffffffffff\"),\n            });\n            Assert.False(result);\n        }\n\n        [Fact]\n        public void IsSubsetOf()\n        {\n            var set = new AddressSet(new Address[]\n            {\n                new Address(\"2000000000000000000000000000000000000000\"),\n                new Address(\"1000000000000000000000000000000000000001\"),\n                new Address(\"0000000000000000000000000000000000000002\"),\n            });\n\n            bool result = set.IsSubsetOf(new Address[]\n            {\n                new Address(\"ffffffffffffffffffffffffffffffffffffffff\"),\n                new Address(\"1000000000000000000000000000000000000001\"),\n                new Address(\"0000000000000000000000000000000000000002\"),\n                new Address(\"2000000000000000000000000000000000000000\"),\n                new Address(\"1000000000000000000000000000000000000001\"),\n            });\n            Assert.True(result);\n\n            result = set.IsSubsetOf(new Address[]\n            {\n                new Address(\"1000000000000000000000000000000000000001\"),\n                new Address(\"0000000000000000000000000000000000000002\"),\n                new Address(\"2000000000000000000000000000000000000000\"),\n                new Address(\"1000000000000000000000000000000000000001\"),\n            });\n            Assert.True(result);\n\n            result = set.IsSubsetOf(new Address[]\n            {\n                new Address(\"0000000000000000000000000000000000000002\"),\n                new Address(\"2000000000000000000000000000000000000000\"),\n                new Address(\"0000000000000000000000000000000000000002\"),\n            });\n            Assert.False(result);\n\n            result = set.IsSubsetOf(new Address[]\n            {\n                new Address(\"ffffffffffffffffffffffffffffffffffffffff\"),\n                new Address(\"0000000000000000000000000000000000000002\"),\n                new Address(\"2000000000000000000000000000000000000000\"),\n                new Address(\"ffffffffffffffffffffffffffffffffffffffff\"),\n            });\n            Assert.False(result);\n        }\n\n        [Fact]\n        public void IsSupersetOf()\n        {\n            var set = new AddressSet(new Address[]\n            {\n                new Address(\"2000000000000000000000000000000000000000\"),\n                new Address(\"1000000000000000000000000000000000000001\"),\n                new Address(\"0000000000000000000000000000000000000002\"),\n            });\n\n            bool result = set.IsSupersetOf(new Address[]\n            {\n                new Address(\"0000000000000000000000000000000000000002\"),\n                new Address(\"2000000000000000000000000000000000000000\"),\n                new Address(\"0000000000000000000000000000000000000002\"),\n            });\n            Assert.True(result);\n\n            result = set.IsSupersetOf(new Address[]\n            {\n                new Address(\"1000000000000000000000000000000000000001\"),\n                new Address(\"0000000000000000000000000000000000000002\"),\n                new Address(\"2000000000000000000000000000000000000000\"),\n                new Address(\"0000000000000000000000000000000000000002\"),\n            });\n            Assert.True(result);\n\n            result = set.IsSupersetOf(new Address[]\n            {\n                new Address(\"ffffffffffffffffffffffffffffffffffffffff\"),\n                new Address(\"ffffffffffffffffffffffffffffffffffffffff\"),\n                new Address(\"0000000000000000000000000000000000000002\"),\n                new Address(\"2000000000000000000000000000000000000000\"),\n            });\n            Assert.False(result);\n\n            result = set.IsSupersetOf(new Address[]\n            {\n                new Address(\"ffffffffffffffffffffffffffffffffffffffff\"),\n                new Address(\"1000000000000000000000000000000000000001\"),\n                new Address(\"0000000000000000000000000000000000000002\"),\n                new Address(\"0000000000000000000000000000000000000002\"),\n                new Address(\"2000000000000000000000000000000000000000\"),\n            });\n            Assert.False(result);\n        }\n\n        [Fact]\n        public void Overlaps()\n        {\n            var set = new AddressSet(new Address[]\n            {\n                new Address(\"2000000000000000000000000000000000000000\"),\n                new Address(\"1000000000000000000000000000000000000001\"),\n                new Address(\"0000000000000000000000000000000000000002\"),\n            });\n\n            bool result = set.Overlaps(new Address[]\n            {\n                new Address(\"ffffffffffffffffffffffffffffffffffffffff\"),\n                new Address(\"1000000000000000000000000000000000000001\"),\n                new Address(\"0000000000000000000000000000000000000002\"),\n                new Address(\"0000000000000000000000000000000000000002\"),\n                new Address(\"2000000000000000000000000000000000000000\"),\n                default(Address),\n            });\n            Assert.True(result);\n\n            result = set.Overlaps(new Address[]\n            {\n                new Address(\"ffffffffffffffffffffffffffffffffffffffff\"),\n                default(Address),\n                default(Address),\n            });\n            Assert.False(result);\n        }\n\n        [Fact]\n        public void Equality()\n        {\n            var set = new AddressSet(new Address[]\n            {\n                new Address(\"2000000000000000000000000000000000000000\"),\n                new Address(\"1000000000000000000000000000000000000001\"),\n                new Address(\"0000000000000000000000000000000000000002\"),\n            });\n            var set2 = new AddressSet(new Address[]\n            {\n                new Address(\"0000000000000000000000000000000000000002\"),\n                new Address(\"2000000000000000000000000000000000000000\"),\n                new Address(\"1000000000000000000000000000000000000001\"),\n            });\n            var set3 = new AddressSet(new Address[]\n            {\n                new Address(\"1000000000000000000000000000000000000001\"),\n                new Address(\"ffffffffffffffffffffffffffffffffffffffff\"),\n                new Address(\"0000000000000000000000000000000000000002\"),\n            });\n            var set4 = new AddressSet(new Address[]\n            {\n                new Address(\"2000000000000000000000000000000000000000\"),\n                new Address(\"1000000000000000000000000000000000000001\"),\n            });\n            var set5 = new AddressSet(new Address[]\n            {\n                new Address(\"2000000000000000000000000000000000000000\"),\n                new Address(\"1000000000000000000000000000000000000001\"),\n                new Address(\"0000000000000000000000000000000000000002\"),\n                new Address(\"ffffffffffffffffffffffffffffffffffffffff\"),\n            });\n            (AddressSet A, AddressSet B, bool Equal)[] truthTable =\n            {\n                (set, set, true),\n                (set, set2, true),\n                (set, set3, false),\n                (set, set4, false),\n                (set, set5, false),\n                (set2, set3, false),\n                (set2, set4, false),\n                (set2, set5, false),\n            };\n            foreach ((AddressSet a, AddressSet b, bool equal) in truthTable)\n            {\n                if (equal)\n                {\n                    Assert.Equal<AddressSet>(a, b);\n                    Assert.Equal<AddressSet>(b, a);\n                    Assert.True(a.Equals((object)b));\n                    Assert.True(b.Equals((object)a));\n                    Assert.True(a.SetEquals(b));\n                    Assert.True(b.SetEquals(a));\n                    Assert.Equal(a.GetHashCode(), b.GetHashCode());\n                }\n                else\n                {\n                    Assert.NotEqual<AddressSet>(a, b);\n                    Assert.NotEqual<AddressSet>(b, a);\n                    Assert.False(a.Equals((object)b));\n                    Assert.False(b.Equals((object)a));\n                    Assert.False(a.SetEquals(b));\n                    Assert.False(b.SetEquals(a));\n                    Assert.NotEqual(b.GetHashCode(), a.GetHashCode());\n                }\n\n                Assert.False(a.Equals((AddressSet)null));\n                Assert.False(b.Equals((AddressSet)null));\n                Assert.False(a.Equals((object)null));\n                Assert.False(b.Equals((object)null));\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "test/Libplanet.Tests/Tx/TransactionExtensionsTest.cs",
    "content": "using System;\nusing System.Collections.Immutable;\nusing System.Linq;\nusing Libplanet.Action;\nusing Libplanet.Action.Tests.Common;\nusing Libplanet.Crypto;\nusing Libplanet.Types.Blocks;\nusing Libplanet.Types.Tx;\nusing Xunit;\n\nnamespace Libplanet.Tests.Tx\n{\n    public class TransactionExtensionsTest\n    {\n        private static readonly Address AddressA =\n            new Address(\"D6D639DA5a58A78A564C2cD3DB55FA7CeBE244A9\");\n\n        private static readonly Address AddressB =\n            new Address(\"B61CE2Ce6d28237C1BC6E114616616762f1a12Ab\");\n\n        [Fact]\n        public void Sign()\n        {\n            var genesisHash = BlockHash.FromString(\n                \"92854cf0a62a7103b9c610fd588ad45254e64b74ceeeb209090ba572a41bf265\");\n            var updatedAddresses = ImmutableHashSet.Create(AddressA, AddressB);\n            var timestamp = new DateTimeOffset(2023, 3, 29, 1, 2, 3, 456, TimeSpan.Zero);\n            var actions = new TxActionList(new IAction[]\n            {\n                DumbAction.Create((AddressA, \"foo\")),\n                DumbAction.Create((AddressB, \"bar\")),\n            }.Select(x => x.PlainValue));\n            var invoice = new TxInvoice(\n                genesisHash,\n                updatedAddresses,\n                timestamp,\n                actions,\n                null,\n                null);\n            var privateKey =\n                new PrivateKey(\"51fb8c2eb261ed761429c297dd1f8952c8ce327d2ec2ec5bcc7728e3362627c2\");\n            Transaction tx = invoice.Sign(privateKey, 123L);\n            Assert.Equal<ITxInvoice>(invoice, tx);\n            Assert.Equal<ITxSigningMetadata>(new TxSigningMetadata(privateKey.PublicKey, 123L), tx);\n            Assert.True(new UnsignedTx(tx).VerifySignature(tx.Signature.ToImmutableArray()));\n        }\n    }\n}\n"
  },
  {
    "path": "test/Libplanet.Tests/Tx/TransactionTest.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Collections.Immutable;\nusing System.Linq;\nusing Bencodex.Types;\nusing Libplanet.Action;\nusing Libplanet.Action.Sys;\nusing Libplanet.Action.Tests.Common;\nusing Libplanet.Common;\nusing Libplanet.Crypto;\nusing Libplanet.Types.Blocks;\nusing Libplanet.Types.Consensus;\nusing Libplanet.Types.Tx;\nusing Xunit;\nusing static Libplanet.Tests.TestUtils;\n\nnamespace Libplanet.Tests.Tx\n{\n    public class TransactionTest\n    {\n        private readonly TxFixture _fx;\n\n        public TransactionTest()\n        {\n            _fx = new TxFixture(null);\n        }\n\n        [Fact]\n        public void ConstructorWithVerification()\n        {\n            var tx = new Transaction(\n                _fx.Tx,\n                ImmutableArray.Create(_fx.Tx.Signature));\n            Assert.Equal<ITransaction>(_fx.Tx, tx);\n\n            var wrongSig = ImmutableArray.Create(_fx.TxWithActions.Signature);\n            InvalidTxSignatureException e = Assert.Throws<InvalidTxSignatureException>(\n                () => new Transaction(_fx.Tx, wrongSig));\n            TestUtils.AssertBytesEqual(\n                \"d4e3e4db802ef1b19c4bc74dd8fae5da60108414a6772b060752825034cb7f1b\",\n                e.TxId.ByteArray);\n        }\n\n        [Fact]\n        public void ConstructorWithSigning()\n        {\n            PrivateKey validKey = _fx.PrivateKey1;\n            var tx = new Transaction(_fx.Tx, validKey);\n            Assert.Equal<ITransaction>(_fx.Tx, tx);\n\n            var wrongKey = new PrivateKey();\n            ArgumentException e = Assert.Throws<ArgumentException>(\n                () => new Transaction(_fx.Tx, wrongKey));\n            Assert.Equal(\"privateKey\", e.ParamName);\n        }\n\n        [Fact]\n        public void CreateWithSystemAction()\n        {\n            var privateKey = new PrivateKey(\n                new byte[]\n                {\n                    0xcf, 0x36, 0xec, 0xf9, 0xe4, 0x7c, 0x87, 0x9a, 0x0d, 0xbf,\n                    0x46, 0xb2, 0xec, 0xd8, 0x3f, 0xd2, 0x76, 0x18, 0x2a, 0xde,\n                    0x02, 0x65, 0x82, 0x5e, 0x3b, 0x8c, 0x6b, 0xa2, 0x14, 0x46,\n                    0x7b, 0x76,\n                }\n            );\n            var timestamp =\n                new DateTimeOffset(2018, 11, 21, 0, 0, 0, TimeSpan.Zero);\n            var action = new Initialize(\n                new ValidatorSet(new List<Validator>()\n                    { new Validator(privateKey.PublicKey, 1) }),\n                new Dictionary<Address, IValue>\n                {\n                    [default] = (Text)\"initial value\",\n                }.ToImmutableDictionary());\n            Transaction tx = Transaction.Create(\n                0,\n                privateKey,\n                null,\n                actions: new IAction[] { action }.Select(x => x.PlainValue),\n                timestamp: timestamp\n            );\n\n            AssertBytesEqual(privateKey.Address, tx.Signer);\n            Assert.Empty(tx.UpdatedAddresses);\n            Assert.Equal(privateKey.PublicKey, tx.PublicKey);\n            Assert.Equal(timestamp, tx.Timestamp);\n            AssertBytesEqual(\n                new byte[]\n                {\n                    0x30, 0x44, 0x02, 0x20, 0x60, 0x8a, 0xbf, 0x3d, 0xdf, 0x50,\n                    0xf2, 0x00, 0x27, 0x56, 0xbb, 0x84, 0xc5, 0x65, 0x7c, 0xd9,\n                    0x4f, 0xbc, 0x33, 0x81, 0xe1, 0x0d, 0xc1, 0x5b, 0x23, 0x11,\n                    0xc4, 0x97, 0x61, 0x3e, 0xa0, 0xff, 0x02, 0x20, 0x44, 0x08,\n                    0xf8, 0x71, 0x43, 0x8c, 0x51, 0xd6, 0xa8, 0x22, 0x7d, 0x8c,\n                    0x7d, 0xb2, 0xc5, 0x97, 0x5b, 0xef, 0x72, 0x07, 0xfe, 0x4f,\n                    0x9d, 0x4c, 0x25, 0xc6, 0xb2, 0x1a, 0x89, 0xc7, 0xad, 0x10,\n                },\n                tx.Signature\n            );\n            AssertBytesEqual(\n                TxId.FromHex(\"eff61a6ee0faa2705b3dbd23abefbf18b4c864fa6b344c4fc3846cbb71a0e294\"),\n                tx.Id\n            );\n        }\n\n        [Fact]\n        public void CreateWithCustomActions()\n        {\n            var privateKey = new PrivateKey(ByteUtil.ParseHex(\n                \"cf36ecf9e47c879a0dbf46b2ecd83fd276182ade0265825e3b8c6ba214467b76\"));\n            var timestamp =\n                new DateTimeOffset(2018, 11, 21, 0, 0, 0, TimeSpan.Zero);\n            Address stateStore = new Address(\n                new byte[]\n                {\n                    0xe6, 0x95, 0x1c, 0x43, 0x02, 0xdf, 0x13, 0xf9, 0x29, 0xfc,\n                    0xdb, 0xc5, 0x56, 0xd9, 0xac, 0x20, 0x41, 0xfe, 0xf9, 0x5f,\n                }\n            );\n            Transaction tx = Transaction.Create(\n                0,\n                privateKey,\n                null,\n                new[]\n                {\n                    DumbAction.Create((stateStore, \"F\"), recordRandom: false),\n                }.Select(x => x.PlainValue),\n                null,\n                null,\n                timestamp\n            );\n\n            Assert.Equal(\n                new Address(privateKey.PublicKey),\n                tx.Signer\n            );\n            Assert.Equal(privateKey.PublicKey, tx.PublicKey);\n            Assert.Equal(timestamp, tx.Timestamp);\n            AssertBytesEqual(\n                \"3045022100c489671a0c97a0033c3273b15bb90bdff96e47bfaf475a1914ad5441bac32\" +\n                \"d6e022066ed765bbfead057a5cb12fa3ad4188833f1ea139f80383d062ffd315213289d\",\n                tx.Signature\n            );\n            AssertBytesEqual(\n                new TxId(ByteUtil.ParseHex(\n                    \"201ff302e08e0a3a6ce62415265dff6ec7c4439673f5079ceaeb2572fe05f632\")),\n                tx.Id\n            );\n        }\n\n        [Fact]\n        public void CreateWithDefaultUpdatedAddresses()\n        {\n            Transaction emptyTx = Transaction.Create(\n                0,\n                _fx.PrivateKey1,\n                null,\n                Array.Empty<DumbAction>().Select(x => x.PlainValue));\n            Assert.Empty(emptyTx.UpdatedAddresses);\n        }\n\n        [Fact]\n        public void CreateWithDefaultTimestamp()\n        {\n            DateTimeOffset rightBefore = DateTimeOffset.UtcNow;\n            Transaction tx = Transaction.Create(\n                0,\n                _fx.PrivateKey1,\n                null,\n                Array.Empty<DumbAction>().Select(x => x.PlainValue),\n                null,\n                null);\n            DateTimeOffset rightAfter = DateTimeOffset.UtcNow;\n\n            Assert.InRange(tx.Timestamp, rightBefore, rightAfter);\n        }\n\n        [Fact]\n        public void CreateWithMissingRequiredArguments()\n        {\n            // The privateKey parameter cannot be null.\n            Assert.Throws<ArgumentNullException>(() =>\n                Transaction.Create(\n                    0,\n                    null,\n                    null,\n                    Array.Empty<DumbAction>().Select(x => x.PlainValue),\n                    null,\n                    null,\n                    DateTimeOffset.UtcNow\n                )\n            );\n        }\n\n        [Fact]\n        public void MakeWithSignature()\n        {\n            var privateKey = new PrivateKey(\n                new byte[]\n                {\n                    0xcf, 0x36, 0xec, 0xf9, 0xe4, 0x7c, 0x87, 0x9a, 0x0d, 0xbf,\n                    0x46, 0xb2, 0xec, 0xd8, 0x3f, 0xd2, 0x76, 0x18, 0x2a, 0xde,\n                    0x02, 0x65, 0x82, 0x5e, 0x3b, 0x8c, 0x6b, 0xa2, 0x14, 0x46,\n                    0x7b, 0x76,\n                }\n            );\n            var timestamp = new DateTimeOffset(2018, 11, 21, 0, 0, 0, TimeSpan.Zero);\n            var signature = new byte[]\n            {\n                0x30, 0x44, 0x02, 0x20, 0x2f, 0x2d, 0xbe, 0x5a, 0x91, 0x65, 0x59, 0xde, 0xdb, 0xe8,\n                0xd8, 0x4f, 0xa9, 0x20, 0xe2, 0x01, 0x29, 0x4d, 0x4f, 0x40, 0xea, 0x1e, 0x97, 0x44,\n                0x1f, 0xbf, 0xa2, 0x5c, 0x8b, 0xd0, 0x0e, 0x23, 0x02, 0x20, 0x3c, 0x06, 0x02, 0x1f,\n                0xb8, 0x3f, 0x67, 0x49, 0x92, 0x3c, 0x07, 0x59, 0x67, 0x96, 0xa8, 0x63, 0x04, 0xb0,\n                0xc3, 0xfe, 0xbb, 0x6c, 0x7a, 0x7b, 0x58, 0x58, 0xe9, 0x7d, 0x37, 0x67, 0xe1, 0xe9,\n            };\n            var tx = new Transaction(\n                new UnsignedTx(\n                new TxInvoice(timestamp: timestamp),\n                new TxSigningMetadata(privateKey.PublicKey, nonce: 0L)\n                ),\n                signature: signature.ToImmutableArray()\n            );\n\n            Assert.Equal(\n                new Address(privateKey.PublicKey),\n                tx.Signer\n            );\n            Assert.Equal(ImmutableHashSet<Address>.Empty, tx.UpdatedAddresses);\n            Assert.Equal(privateKey.PublicKey, tx.PublicKey);\n            Assert.Equal(timestamp, tx.Timestamp);\n            AssertBytesEqual(\n                signature,\n                tx.Signature\n            );\n            AssertBytesEqual(\n                new TxId(\n                    new byte[]\n                    {\n                        0xb0, 0x69, 0xfd, 0xe2, 0x53, 0x88, 0x53, 0xbe, 0x81, 0xb3, 0xea, 0xac,\n                        0xc2, 0x38, 0x55, 0x42, 0x0e, 0x03, 0xe5, 0x62, 0x6f, 0x75, 0x7f, 0xa1,\n                        0x9b, 0x37, 0x92, 0x60, 0x1a, 0x94, 0x88, 0x81,\n                    }\n                ),\n                tx.Id\n            );\n\n            var invalidSignature = new byte[]\n            {\n                0x30, 0x45, 0x02, 0x21, 0x00, 0x9b, 0x8e, 0xb8, 0xb8, 0x6b,\n                0x31, 0x8d, 0xb4, 0x86, 0xb5, 0x9a, 0x4f, 0x8e, 0x54, 0xea,\n                0xa6, 0x8f, 0x88, 0x73, 0x94, 0x63, 0xa9, 0x19, 0x36, 0x1a,\n                0x4b, 0x1a, 0x32, 0xcf, 0x22, 0xf2, 0x1e, 0x02, 0x20, 0x76,\n                0xbe, 0x7f, 0xbf, 0x76, 0xa2, 0x09, 0x71, 0xfe, 0xf9, 0x28,\n                0xc6, 0x44, 0x0e, 0xdf, 0xda, 0xf3, 0x82, 0x29, 0x7b, 0x0f,\n                0x09, 0xf4, 0x50, 0x9f, 0xb1, 0xb1, 0x1e, 0xab, 0x11, 0x4b,\n                0x3f,\n            };\n        }\n\n        [Fact]\n        public void DetectBadSignature()\n        {\n            Assert.Throws<InvalidTxSignatureException>(() =>\n                new Transaction(\n                    (IUnsignedTx)_fx.Tx,\n                    new byte[_fx.Tx.Signature.Length].ToImmutableArray()\n                )\n            );\n        }\n\n        [Fact]\n        public void ActionsAreIsolatedFromOutside()\n        {\n            var actions = new List<DumbAction>();\n            Transaction tx = Transaction.Create(\n                0,\n                _fx.PrivateKey1,\n                null,\n                actions.ToPlainValues()\n            );\n            actions.Add(new DumbAction());\n            Assert.Empty(tx.Actions);\n        }\n\n        [Fact]\n        public void Equality()\n        {\n            var genesisHash = BlockHash.FromString(\n                \"92854cf0a62a7103b9c610fd588ad45254e64b74ceeeb209090ba572a41bf265\");\n            Address addressA = new Address(\"D6D639DA5a58A78A564C2cD3DB55FA7CeBE244A9\");\n            Address addressB = new Address(\"B61CE2Ce6d28237C1BC6E114616616762f1a12Ab\");\n            var updatedAddresses = ImmutableHashSet.Create(addressA, addressB);\n            var timestamp = new DateTimeOffset(2023, 3, 29, 1, 2, 3, 456, TimeSpan.Zero);\n            var actions = new TxActionList(new IAction[]\n            {\n                DumbAction.Create((addressA, \"foo\")),\n                DumbAction.Create((addressB, \"bar\")),\n            }.ToPlainValues());\n            var invoice = new TxInvoice(\n                genesisHash,\n                updatedAddresses,\n                timestamp,\n                actions,\n                null,\n                null);\n            var privateKey =\n                new PrivateKey(\"51fb8c2eb261ed761429c297dd1f8952c8ce327d2ec2ec5bcc7728e3362627c2\");\n            PublicKey publicKey = privateKey.PublicKey;\n            var signingMetadata = new TxSigningMetadata(publicKey, 123L);\n            var unsignedTx = new UnsignedTx(invoice, signingMetadata);\n            ImmutableArray<byte> signature = ByteUtil.ParseHexToImmutable(\n                \"30430220502da40025cf537d0517a111bb2078b04ec421755743177e0bad75ff47dcf\" +\n                \"066021f154bb551ec7e5e9228debcd44beee5a74db8249670e06f2c5b355f56730627\");\n            var tx = new Transaction(unsignedTx, signature: signature);\n\n            Assert.Equal<ITxInvoice>(invoice, tx);\n            Assert.Equal<ITxSigningMetadata>(signingMetadata, tx);\n            Assert.Equal<IUnsignedTx>(unsignedTx, tx);\n\n            var copy = new Transaction(unsignedTx, signature: signature);\n            Assert.Equal<IUnsignedTx>(tx, copy);\n            Assert.Equal<ITransaction>(tx, copy);\n            Assert.Equal<Transaction>(tx, copy);\n            Assert.True(tx.Equals((object)copy));\n            Assert.Equal(tx.GetHashCode(), copy.GetHashCode());\n\n            var wrongKey = new PrivateKey();\n            for (int i = 0; i < 6; i++)\n            {\n                var diffInvoice = new TxInvoice(\n                    i == 0 ? (BlockHash?)null : invoice.GenesisHash,\n                    i == 1 ? AddressSet.Empty : invoice.UpdatedAddresses,\n                    i == 2 ? DateTimeOffset.MinValue : invoice.Timestamp,\n                    i == 3 ? TxActionList.Empty : invoice.Actions,\n                    null,\n                    null);\n                var diffSigningMetadata = new TxSigningMetadata(\n                    i == 4 ? wrongKey.PublicKey : signingMetadata.PublicKey,\n                    i == 5 ? 456L : signingMetadata.Nonce\n                );\n\n                if (i < 4)\n                {\n                    Assert.NotEqual<ITxInvoice>(diffInvoice, unsignedTx);\n                    Assert.Equal<ITxSigningMetadata>(diffSigningMetadata, unsignedTx);\n                }\n                else\n                {\n                    Assert.Equal<ITxInvoice>(diffInvoice, unsignedTx);\n                    Assert.NotEqual<ITxSigningMetadata>(diffSigningMetadata, unsignedTx);\n                }\n\n                var diffUnsignedTx = new UnsignedTx(diffInvoice, diffSigningMetadata);\n                var diffTx = new Transaction(\n                    diffUnsignedTx,\n                    i == 4 ? wrongKey : privateKey);\n                Assert.NotEqual<IUnsignedTx>(tx, diffTx);\n                Assert.NotEqual<ITransaction>(tx, diffTx);\n                Assert.NotEqual<Transaction>(tx, diffTx);\n                Assert.False(tx.Equals((object)diffTx));\n                Assert.NotEqual(tx.GetHashCode(), diffTx.GetHashCode());\n            }\n        }\n\n        [Fact]\n        public void JsonSerialization()\n        {\n            var genesisHash = BlockHash.FromString(\n                \"92854cf0a62a7103b9c610fd588ad45254e64b74ceeeb209090ba572a41bf265\");\n            Address addressA = new Address(\"D6D639DA5a58A78A564C2cD3DB55FA7CeBE244A9\");\n            Address addressB = new Address(\"B61CE2Ce6d28237C1BC6E114616616762f1a12Ab\");\n            var updatedAddresses = ImmutableHashSet.Create(addressA, addressB);\n            var timestamp = new DateTimeOffset(2023, 3, 29, 1, 2, 3, 456, TimeSpan.Zero);\n            var actions = new TxActionList(new IAction[]\n            {\n                DumbAction.Create((addressA, \"foo\")),\n                DumbAction.Create((addressB, \"bar\")),\n            }.ToPlainValues());\n            var invoice = new TxInvoice(\n                genesisHash,\n                updatedAddresses,\n                timestamp,\n                actions,\n                null,\n                null);\n            var privateKey =\n                new PrivateKey(\"51fb8c2eb261ed761429c297dd1f8952c8ce327d2ec2ec5bcc7728e3362627c2\");\n            PublicKey publicKey = privateKey.PublicKey;\n            var signingMetadata = new TxSigningMetadata(publicKey, 123L);\n            var unsignedTx = new UnsignedTx(invoice, signingMetadata);\n            ImmutableArray<byte> signature = ByteUtil.ParseHexToImmutable(\n                \"30430220502da40025cf537d0517a111bb2078b04ec421755743177e0bad75ff47dcf\" +\n                \"066021f154bb551ec7e5e9228debcd44beee5a74db8249670e06f2c5b355f56730627\");\n            var tx = new Transaction(unsignedTx, signature: signature);\n\n#pragma warning disable MEN002  // Long lines are OK for test JSON data.\n            AssertJsonSerializable(\n                tx,\n                @\"\n                    {\n                      \"\"id\"\": \"\"926c8ee03479bfe29ee78ab71e81684badca177cee9c63bcc1a8f3bdf6ad4d45\"\",\n                      \"\"nonce\"\": 123,\n                      \"\"signer\"\": \"\"89F0eE48e8BeaE3131B17Dc79A1282A0D7EdC6b9\"\",\n                      \"\"updatedAddresses\"\": [\n                        \"\"B61CE2Ce6d28237C1BC6E114616616762f1a12Ab\"\",\n                        \"\"D6D639DA5a58A78A564C2cD3DB55FA7CeBE244A9\"\"\n                      ],\n                      \"\"signature\"\": \"\"MEMCIFAtpAAlz1N9BRehEbsgeLBOxCF1V0MXfgutdf9H3PBmAh8VS7VR7H5ekijevNRL7uWnTbgklnDgbyxbNV9WcwYn\"\",\n                      \"\"actions\"\": [\n                        {\n                          \"\"\\uFEFFitem\"\": \"\"\\uFEFFfoo\"\",\n                          \"\"\\uFEFFtarget_address\"\": \"\"0xd6d639da5a58a78a564c2cd3db55fa7cebe244a9\"\",\n                          \"\"\\uFEFFtype_id\"\": \"\"\\uFEFFDumbAction\"\"\n                        },\n                        {\n                          \"\"\\uFEFFitem\"\": \"\"\\uFEFFbar\"\",\n                          \"\"\\uFEFFtarget_address\"\": \"\"0xb61ce2ce6d28237c1bc6e114616616762f1a12ab\"\",\n                          \"\"\\uFEFFtype_id\"\": \"\"\\uFEFFDumbAction\"\"\n                        }\n                      ],\n                      \"\"timestamp\"\": \"\"2023-03-29T01:02:03.456\\u002B00:00\"\",\n                      \"\"publicKey\"\": \"\"03f804c12768bf9e05978ee37c56d037f68523fd9079642691eec82e233e1559bf\"\",\n                      \"\"genesisHash\"\": \"\"92854cf0a62a7103b9c610fd588ad45254e64b74ceeeb209090ba572a41bf265\"\",\n                      \"\"maxGasPrice\"\": null,\n                      \"\"gasLimit\"\": null\n                    }\n                \",\n                false);\n#pragma warning restore MEN002\n        }\n    }\n}\n"
  },
  {
    "path": "test/Libplanet.Tests/Tx/TxActionListTest.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing Bencodex.Types;\nusing Libplanet.Action;\nusing Libplanet.Action.Tests.Common;\nusing Libplanet.Crypto;\nusing Libplanet.Types.Assets;\nusing Libplanet.Types.Tx;\nusing Xunit;\nusing static Libplanet.Tests.TestUtils;\n\nnamespace Libplanet.Tests.Tx\n{\n    public class TxActionListTest\n    {\n        public static readonly Address AddressA =\n            new Address(\"D6D639DA5a58A78A564C2cD3DB55FA7CeBE244A9\");\n\n        private static readonly Currency FOO = Currency.Uncapped(\"FOO\", 2, null);\n\n        [Fact]\n        public void Empty()\n        {\n            Assert.Empty(TxActionList.Empty);\n            Assert.Empty(TxActionList.Empty.Actions);\n            Assert.Throws<IndexOutOfRangeException>(() => TxActionList.Empty[0]);\n            AssertBencodexEqual(\n                Bencodex.Types.List.Empty,\n                TxActionList.Empty.Bencoded);\n        }\n\n        [Fact]\n        public void Constructor()\n        {\n            var emptyList = new TxActionList(Array.Empty<IAction>().ToPlainValues());\n            Assert.Equal(TxActionList.Empty, emptyList);\n\n            IAction[] actions =\n            {\n                DumbAction.Create((default, \"foo\")),\n                DumbAction.Create((default, \"bar\")),\n            };\n            var list = new TxActionList(actions.ToPlainValues());\n            Assert.Equal(2, list.Count);\n            Assert.Equal<IEnumerable<IValue>>(actions.Select(action => action.PlainValue), list);\n        }\n\n        [Fact]\n        public void Index()\n        {\n            var emptyList = new TxActionList(Array.Empty<IAction>().ToPlainValues());\n            Assert.Throws<ArgumentOutOfRangeException>(() => emptyList[-1]);\n            Assert.Throws<IndexOutOfRangeException>(() => emptyList[0]);\n\n            IAction[] actions =\n            {\n                DumbAction.Create((default, \"foo\")),\n                DumbAction.Create((default, \"bar\")),\n            };\n            var list = new TxActionList(actions.ToPlainValues());\n            Assert.Throws<ArgumentOutOfRangeException>(() => list[-1]);\n            Assert.Equal(actions[0].PlainValue, list[0]);\n            Assert.Equal(actions[1].PlainValue, list[1]);\n            Assert.Throws<IndexOutOfRangeException>(() => list[2]);\n        }\n\n        [Fact]\n        public void Equality()\n        {\n            IAction[] actions1 =\n            {\n                DumbAction.Create((default, \"foo\")),\n                DumbAction.Create((AddressA, \"bar\")),\n            };\n            IAction[] actions2 =\n            {\n                DumbAction.Create((default, \"foo\")),\n                DumbAction.Create((AddressA, \"bar\")),\n            };\n            IAction[] actions3 =\n            {\n                DumbAction.Create((default, \"foo\")),\n                DumbAction.Create((AddressA, \"baz\")),\n            };\n\n            AssertEquality(\n                new TxActionList(actions1.ToPlainValues()),\n                new TxActionList(actions1.ToPlainValues()),\n                true);\n            AssertEquality(\n                new TxActionList(actions1.ToPlainValues()),\n                new TxActionList(actions2.ToPlainValues()),\n                true);\n            AssertEquality(\n                new TxActionList(actions1.ToPlainValues()),\n                new TxActionList(actions3.ToPlainValues()),\n                false);\n        }\n\n        [Fact]\n        public void Enumeration()\n        {\n            var emptyList = new TxActionList(Array.Empty<IAction>().ToPlainValues());\n            Assert.Empty(emptyList);\n\n            IAction[] actions =\n            {\n                DumbAction.Create((default, \"foo\")),\n                DumbAction.Create((default, \"bar\")),\n            };\n            var list = new TxActionList(actions.ToPlainValues());\n            Assert.Equal<IEnumerable<IValue>>(actions.Select(action => action.PlainValue), list);\n        }\n\n        [Fact]\n        public void Bencoded()\n        {\n            var emptyList = new TxActionList(Array.Empty<IAction>().ToPlainValues());\n            AssertBencodexEqual(\n                Bencodex.Types.List.Empty,\n                emptyList.Bencoded);\n\n            // TODO: We should introduce snapshot testing.\n            IAction[] actions =\n            {\n                DumbAction.Create((default, \"foo\")),\n                DumbAction.Create((default, \"bar\")),\n            };\n            var actionList = new TxActionList(actions.ToPlainValues());\n            var expected = new List(actions.Select(action => action.PlainValue));\n            AssertBencodexEqual(expected, actionList.Bencoded);\n\n            var decoded = new TxActionList(actionList.Bencoded);\n            Assert.Equal(actionList, decoded);\n\n            var invalidInput = Dictionary.Empty;\n            Assert.Throws<ArgumentException>(() => new TxActionList(invalidInput));\n        }\n\n        [Fact]\n        public void JsonSerialize()\n        {\n            var actionList = new TxActionList(\n                new IAction[]\n                {\n                    DumbAction.Create((default, \"foo\")),\n                    DumbAction.Create((AddressA, \"bar\")),\n                }.ToPlainValues());\n            var emptyActionList = new TxActionList(Array.Empty<IAction>().ToPlainValues());\n            const string actionListJson = @\"\n                [\n                  {\n                    \"\"\\uFEFFitem\"\": \"\"\\uFEFFfoo\"\",\n                    \"\"\\uFEFFtarget_address\"\": \"\"0x0000000000000000000000000000000000000000\"\",\n                    \"\"\\uFEFFtype_id\"\": \"\"\\uFEFFDumbAction\"\"\n                  },\n                  {\n                    \"\"\\uFEFFitem\"\": \"\"\\uFEFFbar\"\",\n                    \"\"\\uFEFFtarget_address\"\": \"\"0xd6d639da5a58a78a564c2cd3db55fa7cebe244a9\"\",\n                    \"\"\\uFEFFtype_id\"\": \"\"\\uFEFFDumbAction\"\"\n                  }\n                ]\";\n            TestUtils.AssertJsonSerializable<TxActionList>(\n                actionList,\n                actionListJson,\n                false);\n            TestUtils.AssertJsonSerializable<TxActionList>(\n                emptyActionList,\n                \"[]\",\n                false);\n        }\n\n        private static void AssertEquality(TxActionList a, TxActionList b, bool equal)\n        {\n            if (equal)\n            {\n                Assert.True(a.Equals(b));\n                Assert.True(((object)a).Equals(b));\n                Assert.Equal(a.GetHashCode(), b.GetHashCode());\n            }\n            else\n            {\n                Assert.False(a.Equals(b));\n                Assert.False(((object)a).Equals(b));\n                Assert.NotEqual(a.GetHashCode(), b.GetHashCode());\n            }\n\n            Assert.False(a.Equals(null));\n            Assert.False(((object)a).Equals(null));\n            Assert.False(b.Equals(null));\n            Assert.False(((object)b).Equals(null));\n        }\n    }\n}\n"
  },
  {
    "path": "test/Libplanet.Tests/Tx/TxExecutionTest.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Security.Cryptography;\nusing Bencodex.Types;\nusing Libplanet.Types.Assets;\nusing Libplanet.Types.Tx;\nusing Xunit;\n\nnamespace Libplanet.Tests.Tx\n{\n    public class TxExecutionTest\n    {\n        [Theory]\n        [InlineData(false, \"\")]\n        [InlineData(true, \"SomeException\")]\n        public void Constructor(bool fail, string exceptionName)\n        {\n            var random = new Random();\n            var blockHash = random.NextBlockHash();\n            var txId = random.NextTxId();\n            var inputState = random.NextHashDigest<SHA256>();\n            var outputState = random.NextHashDigest<SHA256>();\n            var exceptionNames = new List<string>() { exceptionName };\n            var execution = new TxExecution(\n                blockHash,\n                txId,\n                fail,\n                inputState,\n                outputState,\n                exceptionNames);\n            Assert.Equal(blockHash, execution.BlockHash);\n            Assert.Equal(txId, execution.TxId);\n            Assert.Equal(fail, execution.Fail);\n            Assert.Equal(inputState, execution.InputState);\n            Assert.Equal(outputState, execution.OutputState);\n            Assert.Equal(exceptionNames, execution.ExceptionNames);\n        }\n\n        [Fact]\n        public void EncodeDecode()\n        {\n            var random = new Random();\n            var execution = new TxExecution(\n                random.NextBlockHash(),\n                random.NextTxId(),\n                true,\n                random.NextHashDigest<SHA256>(),\n                random.NextHashDigest<SHA256>(),\n                new List<string>() { null, \"SomeException\", \"AnotherException\" });\n            var encoded = execution.ToBencodex();\n            var decoded = new TxExecution(\n                execution.BlockHash,\n                execution.TxId,\n                encoded);\n            Assert.Equal(execution.BlockHash, decoded.BlockHash);\n            Assert.Equal(execution.TxId, decoded.TxId);\n            Assert.Equal(execution.Fail, decoded.Fail);\n            Assert.Equal(execution.InputState, decoded.InputState);\n            Assert.Equal(execution.OutputState, decoded.OutputState);\n            Assert.Equal(execution.ExceptionNames, decoded.ExceptionNames);\n        }\n\n        [Fact]\n        public void ConstructorWithExceptions()\n        {\n            var random = new Random();\n            var blockHash = random.NextBlockHash();\n            var txId = random.NextTxId();\n            var inputState = random.NextHashDigest<SHA256>();\n            var outputState = random.NextHashDigest<SHA256>();\n            var exceptions = new List<Exception>() { null, new ArgumentException(\"Message\") };\n            var execution = new TxExecution(\n                blockHash,\n                txId,\n                true,\n                inputState,\n                outputState,\n                exceptions);\n            Assert.Equal(blockHash, execution.BlockHash);\n            Assert.Equal(txId, execution.TxId);\n            Assert.True(execution.Fail);\n            Assert.Equal(inputState, execution.InputState);\n            Assert.Equal(outputState, execution.OutputState);\n            Assert.Equal(\n                exceptions\n                    .Select(exception => exception is Exception e\n                        ? e.GetType().FullName\n                        : null),\n                execution.ExceptionNames);\n        }\n\n        [Fact]\n        public void DecodeFailLegacy()\n        {\n            var random = new Random();\n            var blockHash = random.NextBlockHash();\n            var txId = random.NextTxId();\n\n            Dictionary legacyEncoded = Dictionary.Empty\n                .Add(\"fail\", true)\n                .Add(\"exc\", \"SomeException\");\n            var failExecution = new TxExecution(\n                blockHash,\n                txId,\n                legacyEncoded);\n            Assert.Equal(blockHash, failExecution.BlockHash);\n            Assert.Equal(txId, failExecution.TxId);\n            Assert.True(failExecution.Fail);\n            Assert.Null(failExecution.InputState);\n            Assert.Null(failExecution.OutputState);\n            Assert.Null(failExecution.ExceptionNames);\n        }\n\n        [Fact]\n        public void DecodeSuccessLegacy()\n        {\n            var random = new Random();\n            var blockHash = random.NextBlockHash();\n            var txId = random.NextTxId();\n\n            // Note: Actual format for sDelta and updatedFAVs doesn't really matter,\n            // it is important decoding doesn't throw an exception.\n            var currency = Currency.Uncapped(\"FOO\", 0, null);\n            Dictionary legacyEncoded = Dictionary.Empty\n                .Add(\"fail\", false)\n                .Add(\"sDelta\", Dictionary.Empty\n                    .Add(random.NextAddress().ByteArray, random.NextAddress().ByteArray))\n                .Add(\"updatedFAVs\", List.Empty\n                    .Add(currency.Serialize())\n                    .Add(123));\n            var successExecution = new TxExecution(\n                blockHash,\n                txId,\n                legacyEncoded);\n            Assert.Equal(blockHash, successExecution.BlockHash);\n            Assert.Equal(txId, successExecution.TxId);\n            Assert.False(successExecution.Fail);\n            Assert.Null(successExecution.InputState);\n            Assert.Null(successExecution.OutputState);\n            Assert.Null(successExecution.ExceptionNames);\n        }\n    }\n}\n"
  },
  {
    "path": "test/Libplanet.Tests/Tx/TxFixture.cs",
    "content": "using System;\nusing System.Collections.Immutable;\nusing Libplanet.Action;\nusing Libplanet.Action.Tests.Common;\nusing Libplanet.Crypto;\nusing Libplanet.Types.Blocks;\nusing Libplanet.Types.Tx;\n\nnamespace Libplanet.Tests.Tx\n{\n    public class TxFixture\n    {\n        public TxFixture(BlockHash? genesisHash)\n        {\n            PrivateKey1 = new PrivateKey(\n                new byte[]\n                {\n                    0xcf, 0x36, 0xec, 0xf9, 0xe4, 0x7c, 0x87, 0x9a, 0x0d, 0xbf,\n                    0x46, 0xb2, 0xec, 0xd8, 0x3f, 0xd2, 0x76, 0x18, 0x2a, 0xde,\n                    0x02, 0x65, 0x82, 0x5e, 0x3b, 0x8c, 0x6b, 0xa2, 0x14, 0x46,\n                    0x7b, 0x76,\n                }\n            );\n            PrivateKey2 = new PrivateKey(\n                new byte[]\n                {\n                    0xa8, 0x69, 0xfd, 0xac, 0xed, 0x45, 0x18, 0xd5, 0x36, 0x30,\n                    0x25, 0xe5, 0xfa, 0x15, 0x26, 0x10, 0x88, 0x39, 0x78, 0x0e,\n                    0xac, 0x98, 0x73, 0x5c, 0x3f, 0x3f, 0x42, 0xec, 0xd3, 0xd2,\n                    0x42, 0x46,\n                }\n            );\n            PrivateKey3 = new PrivateKey(\n                new byte[]\n                {\n                    0x92, 0x7e, 0xed, 0x40, 0x7f, 0x15, 0x0f, 0x50, 0xc5, 0x60,\n                    0x50, 0x15, 0x54, 0x0d, 0xe7, 0xaa, 0x4d, 0x0e, 0xa3, 0x34,\n                    0x31, 0x9b, 0x4e, 0xa8, 0x91, 0xab, 0xcd, 0x02, 0xdb, 0x14,\n                    0x9f, 0x5f,\n                }\n            );\n            PrivateKey4 = new PrivateKey(\n                new byte[]\n                {\n                    0x0e, 0x7c, 0x4d, 0x5b, 0x05, 0x49, 0x3c, 0x5b, 0x7b, 0xd5,\n                    0x8d, 0x39, 0x79, 0x53, 0x44, 0x37, 0x26, 0xce, 0x0f, 0xce,\n                    0xb1, 0x0f, 0x5e, 0x63, 0x08, 0x9a, 0x64, 0xcd, 0x8c, 0x79,\n                    0x81, 0xbe,\n                }\n            );\n            PrivateKey5 = new PrivateKey(\n                new byte[]\n                {\n                    0x27, 0xd6, 0xc0, 0xc8, 0xf4, 0x5a, 0x7e, 0xef, 0xf7, 0x68,\n                    0xb4, 0x12, 0x67, 0x9b, 0x92, 0xf8, 0x55, 0xaf, 0xe9, 0x52,\n                    0x8f, 0x23, 0xc8, 0xf2, 0x4f, 0xfc, 0xa6, 0x45, 0x2c, 0x71,\n                    0x7e, 0xfb,\n                }\n            );\n            var recipient = new Address(PrivateKey1.PublicKey);\n            var timestamp = new DateTimeOffset(2018, 11, 21, 0, 0, 0, TimeSpan.Zero);\n\n            Tx = Transaction.Create(\n                0,\n                PrivateKey1,\n                genesisHash,\n                Array.Empty<BaseAction>().ToPlainValues(),\n                timestamp: timestamp\n            );\n            BaseAction[] actions =\n            {\n                new Attack\n                {\n                    Weapon = \"wand\",\n                    Target = \"orc\",\n                    TargetAddress = recipient,\n                },\n                new Sleep\n                {\n                    ZoneId = 10,\n                },\n            };\n            TxWithActions = new Transaction(\n                new UnsignedTx(\n                    new TxInvoice(\n                        genesisHash: genesisHash,\n                        updatedAddresses: ImmutableHashSet.Create(\n                            new Address(\"c2a86014073d662a4a9bfcf9cb54263dfa4f5cbc\")),\n                        timestamp: timestamp,\n                        actions: new TxActionList(actions.ToPlainValues()),\n                        maxGasPrice: null,\n                        gasLimit: null),\n                    new TxSigningMetadata(PrivateKey1.PublicKey, 0)),\n                PrivateKey1);\n        }\n\n        public PrivateKey PrivateKey1 { get; }\n\n        public PrivateKey PrivateKey2 { get; }\n\n        public PrivateKey PrivateKey3 { get; }\n\n        public PrivateKey PrivateKey4 { get; }\n\n        public PrivateKey PrivateKey5 { get; }\n\n        public PublicKey PublicKey1 => PrivateKey1.PublicKey;\n\n        public PublicKey PublicKey2 => PrivateKey2.PublicKey;\n\n        public PublicKey PublicKey3 => PrivateKey3.PublicKey;\n\n        public PublicKey PublicKey4 => PrivateKey4.PublicKey;\n\n        public PublicKey PublicKey5 => PrivateKey5.PublicKey;\n\n        public Address Address1 => PublicKey1.Address;\n\n        public Address Address2 => PublicKey2.Address;\n\n        public Address Address3 => PublicKey3.Address;\n\n        public Address Address4 => PublicKey4.Address;\n\n        public Address Address5 => PublicKey5.Address;\n\n        public Transaction Tx { get; }\n\n        public Transaction TxWithActions { get; }\n    }\n}\n"
  },
  {
    "path": "test/Libplanet.Tests/Tx/TxIdTest.cs",
    "content": "using System;\nusing System.Collections.Immutable;\nusing System.Linq;\nusing Libplanet.Types.Tx;\nusing Xunit;\nusing static Libplanet.Tests.TestUtils;\n\nnamespace Libplanet.Tests.Tx\n{\n    public class TxIdTest\n    {\n        [Fact]\n        public void TxIdMustBe32Bytes()\n        {\n            for (int size = 0; size < 36; size++)\n            {\n                if (size == 32)\n                {\n                    continue;\n                }\n\n                byte[] bytes = GetRandomBytes(size);\n                ImmutableArray<byte> immutableBytes = bytes.ToImmutableArray();\n                Assert.Throws<ArgumentOutOfRangeException>(\n                    \"txid\",\n                    () => new TxId(immutableBytes));\n                Assert.Throws<ArgumentOutOfRangeException>(\n                    \"txid\",\n                    () => new TxId(bytes));\n            }\n        }\n\n        [Fact]\n        public void FromHex()\n        {\n            TxId actual = TxId.FromHex(\n                \"45a22187e2d8850bb357886958bc3e8560929ccc886958bc3e8560929ccc9ccc\");\n            var expected = new TxId(\n                new byte[]\n                {\n                    0x45, 0xa2, 0x21, 0x87, 0xe2, 0xd8, 0x85, 0x0b, 0xb3, 0x57,\n                    0x88, 0x69, 0x58, 0xbc, 0x3e, 0x85, 0x60, 0x92, 0x9c, 0xcc,\n                    0x88, 0x69, 0x58, 0xbc, 0x3e, 0x85, 0x60, 0x92, 0x9c, 0xcc,\n                    0x9c, 0xcc,\n                }\n            );\n            Assert.Equal(expected, actual);\n\n            Assert.Throws<FormatException>(() => TxId.FromHex(\"0g\"));\n            Assert.Throws<ArgumentOutOfRangeException>(\"hex\", () => TxId.FromHex(\"1\"));\n            Assert.Throws<ArgumentOutOfRangeException>(\n                \"hex\",\n                () => TxId.FromHex(\n                    \"45a22187e2d8850bb357886958bc3e8560929ccc886958bc3e8560929ccc9c\"));\n            Assert.Throws<ArgumentOutOfRangeException>(\n                \"hex\",\n                () => TxId.FromHex(\n                    \"45a22187e2d8850bb357886958bc3e8560929ccc886958bc3e8560929ccc9ccc0\"));\n            Assert.Throws<ArgumentOutOfRangeException>(\n                \"hex\",\n                () => TxId.FromHex(\n                    \"45a22187e2d8850bb357886958bc3e8560929ccc886958bc3e8560929ccc9ccc00\"));\n        }\n\n        [Fact]\n        public void ToByteArray()\n        {\n            var bytes = GetRandomBytes(TxId.Size);\n            var txId = new TxId(bytes);\n\n            Assert.Equal(bytes, txId.ToByteArray());\n        }\n\n        [Fact]\n        public void ToByteArrayShouldNotExposeContents()\n        {\n            var txId = new TxId(\n                new byte[]\n                {\n                    0x45, 0xa2, 0x21, 0x87, 0xe2, 0xd8, 0x85, 0x0b, 0xb3, 0x57,\n                    0x88, 0x69, 0x58, 0xbc, 0x3e, 0x85, 0x60, 0x92, 0x9c, 0xcc,\n                    0x88, 0x69, 0x58, 0xbc, 0x3e, 0x85, 0x60, 0x92, 0x9c, 0xcc,\n                    0x9c, 0xcc,\n                }\n            );\n            txId.ToByteArray()[0] = 0x00;\n            Assert.Equal(0x45, txId.ToByteArray()[0]);\n        }\n\n        [Fact]\n        public void ToHex()\n        {\n            var id = new TxId(\n                new byte[]\n                {\n                    0x45, 0xa2, 0x21, 0x87, 0xe2, 0xd8, 0x85, 0x0b, 0xb3, 0x57,\n                    0x88, 0x69, 0x58, 0xbc, 0x3e, 0x85, 0x60, 0x92, 0x9c, 0xcc,\n                    0x88, 0x69, 0x58, 0xbc, 0x3e, 0x85, 0x60, 0x92, 0x9c, 0xcc,\n                    0x9c, 0xcc,\n                }\n            );\n            Assert.Equal(\n                \"45a22187e2d8850bb357886958bc3e8560929ccc886958bc3e8560929ccc9ccc\",\n                id.ToHex()\n            );\n        }\n\n        [Fact]\n        public void ToString_()\n        {\n            var txId = new TxId(\n                new byte[]\n                {\n                    0x45, 0xa2, 0x21, 0x87, 0xe2, 0xd8, 0x85, 0x0b, 0xb3, 0x57,\n                    0x88, 0x69, 0x58, 0xbc, 0x3e, 0x85, 0x60, 0x92, 0x9c, 0xcc,\n                    0x88, 0x69, 0x58, 0xbc, 0x3e, 0x85, 0x60, 0x92, 0x9c, 0xcc,\n                    0x9c, 0xcc,\n                }\n            );\n            Assert.Equal(\n                \"45a22187e2d8850bb357886958bc3e8560929ccc886958bc3e8560929ccc9ccc\",\n                txId.ToString()\n            );\n        }\n\n        [Fact]\n        public void Equals_()\n        {\n            var sameTxId1 = new TxId(\n                new byte[]\n                {\n                    0x45, 0xa2, 0x21, 0x87, 0xe2, 0xd8, 0x85, 0x0b, 0xb3, 0x57,\n                    0x88, 0x69, 0x58, 0xbc, 0x3e, 0x85, 0x60, 0x92, 0x9c, 0xcc,\n                    0x88, 0x69, 0x58, 0xbc, 0x3e, 0x85, 0x60, 0x92, 0x9c, 0xcc,\n                    0x9c, 0xcc,\n                }\n            );\n            var sameTxId2 = new TxId(\n                new byte[]\n                {\n                    0x45, 0xa2, 0x21, 0x87, 0xe2, 0xd8, 0x85, 0x0b, 0xb3, 0x57,\n                    0x88, 0x69, 0x58, 0xbc, 0x3e, 0x85, 0x60, 0x92, 0x9c, 0xcc,\n                    0x88, 0x69, 0x58, 0xbc, 0x3e, 0x85, 0x60, 0x92, 0x9c, 0xcc,\n                    0x9c, 0xcc,\n                }\n            );\n            var differentTxId = new TxId(\n                new byte[]\n                {\n                    0x45, 0xa2, 0x21, 0x87, 0xe2, 0xd8, 0x85, 0x0b, 0xb3, 0x57,\n                    0x88, 0x69, 0x58, 0xbc, 0x3e, 0x85, 0x60, 0x92, 0x9c, 0x00,\n                    0x88, 0x69, 0x58, 0xbc, 0x3e, 0x85, 0x60, 0x92, 0x9c, 0x00,\n                    0x9c, 0x00,\n                }\n            );\n\n            Assert.Equal(sameTxId1, sameTxId2);\n            Assert.NotEqual(sameTxId2, differentTxId);\n\n            Assert.True(sameTxId1 == sameTxId2);\n            Assert.False(sameTxId2 == differentTxId);\n\n            Assert.False(sameTxId1 != sameTxId2);\n            Assert.True(sameTxId2 != differentTxId);\n        }\n\n        [Fact]\n        public void Compare()\n        {\n            var random = new Random();\n            var buffer = new byte[32];\n            TxId[] txIds = Enumerable.Repeat(0, 50).Select(_ =>\n            {\n                random.NextBytes(buffer);\n                return new TxId(buffer);\n            }).ToArray();\n            for (int i = 1; i < txIds.Length; i++)\n            {\n                TxId left = txIds[i - 1], right = txIds[i];\n                string leftString = left.ToHex().ToLower(),\n                    rightString = right.ToHex().ToLower();\n                Assert.Equal(\n                    Math.Min(Math.Max(left.CompareTo(right), 1), -1),\n                    Math.Min(Math.Max(leftString.CompareTo(rightString), 1), -1)\n                );\n                Assert.Equal(\n                    left.CompareTo(right),\n                    (left as IComparable).CompareTo(right)\n                );\n            }\n\n            Assert.Throws<ArgumentException>(() => txIds[0].CompareTo(null));\n            Assert.Throws<ArgumentException>(() => txIds[0].CompareTo(\"invalid\"));\n        }\n\n        [Fact]\n        public void Bencoded()\n        {\n            var expected = new TxId(TestUtils.GetRandomBytes(TxId.Size));\n            var deserialized = new TxId(expected.Bencoded);\n            Assert.Equal(expected, deserialized);\n            expected = default(TxId);\n            deserialized = new TxId(expected.Bencoded);\n            Assert.Equal(expected, deserialized);\n        }\n\n        [SkippableFact]\n        public void JsonSerialization()\n        {\n            TxId txid = TxId.FromHex(\n                \"45a22187e2d8850bb357886958bc3e8560929ccc886958bc3e8560929ccc9ccc\");\n            AssertJsonSerializable(\n                txid,\n                \"\\\"45a22187e2d8850bb357886958bc3e8560929ccc886958bc3e8560929ccc9ccc\\\"\"\n            );\n        }\n    }\n}\n"
  },
  {
    "path": "test/Libplanet.Tests/Tx/TxInvoiceTest.cs",
    "content": "using System;\nusing System.Collections.Immutable;\nusing Bencodex.Types;\nusing Libplanet.Action;\nusing Libplanet.Action.Tests.Common;\nusing Libplanet.Crypto;\nusing Libplanet.Types.Assets;\nusing Libplanet.Types.Blocks;\nusing Libplanet.Types.Tx;\nusing Xunit;\n\nnamespace Libplanet.Tests.Tx\n{\n    public class TxInvoiceTest\n    {\n        public static readonly Address AddressA =\n            new Address(\"D6D639DA5a58A78A564C2cD3DB55FA7CeBE244A9\");\n\n        public static readonly Address AddressB =\n            new Address(\"B61CE2Ce6d28237C1BC6E114616616762f1a12Ab\");\n\n        [Fact]\n        public void ConstructorGasConditions()\n        {\n            var random = new System.Random();\n            var genesisHash = random.NextBlockHash();\n            var timestamp = DateTimeOffset.UtcNow;\n            var actions = new TxActionList(Array.Empty<IValue>());\n\n            _ = new TxInvoice(\n                genesisHash: genesisHash,\n                timestamp: timestamp,\n                actions: actions,\n                maxGasPrice: null,\n                gasLimit: null);\n            _ = new TxInvoice(\n                genesisHash: genesisHash,\n                timestamp: timestamp,\n                actions: actions,\n                maxGasPrice: Currency.Uncapped(\"DUMB\", 0, null) * 100,\n                gasLimit: 100);\n\n            Assert.Throws<ArgumentException>(() =>\n                new TxInvoice(\n                    genesisHash: genesisHash,\n                    timestamp: timestamp,\n                    actions: actions,\n                    maxGasPrice: Currency.Uncapped(\"DUMB\", 0, null) * 100,\n                    gasLimit: null));\n            Assert.Throws<ArgumentException>(() =>\n                new TxInvoice(\n                    genesisHash: genesisHash,\n                    timestamp: timestamp,\n                    actions: actions,\n                    maxGasPrice: null,\n                    gasLimit: 100));\n            Assert.Throws<ArgumentException>(() =>\n                new TxInvoice(\n                    genesisHash: genesisHash,\n                    timestamp: timestamp,\n                    actions: actions,\n                    maxGasPrice: Currency.Uncapped(\"DUMB\", 0, null) * -100,\n                    gasLimit: 100));\n            Assert.Throws<ArgumentException>(() =>\n                new TxInvoice(\n                    genesisHash: genesisHash,\n                    timestamp: timestamp,\n                    actions: actions,\n                    maxGasPrice: Currency.Uncapped(\"DUMB\", 0, null) * 100,\n                    gasLimit: -100));\n        }\n\n        [Fact]\n        public void PlainConstructor()\n        {\n            var random = new System.Random();\n            var genesisHash = random.NextBlockHash();\n            var updatedAddresses = ImmutableHashSet.Create(\n                random.NextAddress(),\n                random.NextAddress());\n            var timestamp = DateTimeOffset.UtcNow;\n            var actions = new TxActionList(new IAction[]\n            {\n                DumbAction.Create((random.NextAddress(), \"foo\")),\n                DumbAction.Create((random.NextAddress(), \"bar\")),\n            }.ToPlainValues());\n            var invoice = new TxInvoice(\n                genesisHash,\n                updatedAddresses,\n                timestamp,\n                actions,\n                null,\n                null);\n            Assert.Equal(genesisHash, invoice.GenesisHash);\n            Assert.True(updatedAddresses.SetEquals(invoice.UpdatedAddresses));\n            Assert.Equal(timestamp, invoice.Timestamp);\n            Assert.Equal(actions, invoice.Actions);\n        }\n\n        [Fact]\n        public void ShortcutConstructor()\n        {\n            var before = DateTimeOffset.UtcNow;\n            var invoice = new TxInvoice();\n            var after = DateTimeOffset.UtcNow;\n            Assert.Null(invoice.GenesisHash);\n            Assert.Empty(invoice.UpdatedAddresses);\n            Assert.InRange(invoice.Timestamp, before, after);\n            Assert.IsType<TxActionList>(invoice.Actions);\n            Assert.Empty(invoice.Actions);\n        }\n\n        [Fact]\n        public void CopyConstructor()\n        {\n            var random = new System.Random();\n            var genesisHash = random.NextBlockHash();\n            var updatedAddresses = ImmutableHashSet.Create(\n                random.NextAddress(),\n                random.NextAddress());\n            var timestamp = DateTimeOffset.UtcNow;\n            var actions = new TxActionList(new IAction[]\n            {\n                DumbAction.Create((random.NextAddress(), \"foo\")),\n                DumbAction.Create((random.NextAddress(), \"bar\")),\n            }.ToPlainValues());\n            var original = new TxInvoice(\n                genesisHash,\n                updatedAddresses,\n                timestamp,\n                actions,\n                null,\n                null);\n            var copy = new TxInvoice(original);\n            Assert.Equal(genesisHash, copy.GenesisHash);\n            Assert.True(updatedAddresses.SetEquals(copy.UpdatedAddresses));\n            Assert.Equal(timestamp, copy.Timestamp);\n            Assert.Equal(actions, copy.Actions);\n\n            var mock = new MockTxInvoice();\n            var copyFromInterface = new TxInvoice(mock);\n            Assert.Equal(mock.GenesisHash, copyFromInterface.GenesisHash);\n            Assert.True(mock.UpdatedAddresses.SetEquals(copyFromInterface.UpdatedAddresses));\n            Assert.Equal(mock.Timestamp, copyFromInterface.Timestamp);\n            Assert.Equal(mock.Actions, copyFromInterface.Actions);\n            Assert.Equal(mock.MaxGasPrice, copyFromInterface.MaxGasPrice);\n            Assert.Equal(mock.GasLimit, copyFromInterface.GasLimit);\n        }\n\n        [Fact]\n        public void Equality()\n        {\n            var genesisHash = BlockHash.FromString(\n                \"92854cf0a62a7103b9c610fd588ad45254e64b74ceeeb209090ba572a41bf265\");\n            var updatedAddresses = ImmutableHashSet.Create(AddressA, AddressB);\n            var timestamp = new DateTimeOffset(2023, 3, 29, 1, 2, 3, 456, TimeSpan.Zero);\n            var actions = new TxActionList(new IAction[]\n            {\n                DumbAction.Create((AddressA, \"foo\")),\n                DumbAction.Create((AddressB, \"bar\")),\n            }.ToPlainValues());\n            var invoice1 = new TxInvoice(\n                genesisHash,\n                updatedAddresses,\n                timestamp,\n                actions,\n                null,\n                null);\n            var invoice2 = new TxInvoice(\n                genesisHash,\n                updatedAddresses,\n                timestamp,\n                actions,\n                null,\n                null);\n            Assert.True(invoice1.Equals(invoice2));\n            Assert.True(invoice1.Equals((object)invoice2));\n            Assert.Equal(invoice1.GetHashCode(), invoice2.GetHashCode());\n\n            var mock = new MockTxInvoice();\n            Assert.True(invoice1.Equals(mock));\n            Assert.True(invoice1.Equals((object)mock));\n\n            Assert.False(invoice1.Equals(null));\n\n            for (int i = 0; i < 5; i++)\n            {\n                // NOTE: Non-null cases for MaxGasPrice and GasLimit are flipped as existing\n                // mock object has respective values set to null.\n                var invoice = new TxInvoice(\n                    i == 0 ? (BlockHash?)null : genesisHash,\n                    i == 1 ? (IImmutableSet<Address>)AddressSet.Empty : updatedAddresses,\n                    i == 2 ? DateTimeOffset.MinValue : timestamp,\n                    i == 3 ? TxActionList.Empty : actions,\n                    i == 4\n                        ? FungibleAssetValue.FromRawValue(\n                            Currency.Uncapped(\"FOO\", 18, new PrivateKey().Address),\n                            100)\n                        : (FungibleAssetValue?)null,\n                    i == 4 ? 10 : (long?)null);\n                Assert.False(invoice1.Equals(invoice));\n                Assert.False(invoice1.Equals((object)invoice));\n                Assert.NotEqual(invoice1.GetHashCode(), invoice.GetHashCode());\n            }\n        }\n\n        [Fact]\n        public void JsonSerialization()\n        {\n            var genesisHash = BlockHash.FromString(\n                \"92854cf0a62a7103b9c610fd588ad45254e64b74ceeeb209090ba572a41bf265\");\n            var updatedAddresses = ImmutableHashSet.Create(AddressA, AddressB);\n            var timestamp = new DateTimeOffset(2023, 3, 29, 1, 2, 3, 456, TimeSpan.Zero);\n            var actions = new TxActionList(new IAction[]\n            {\n                DumbAction.Create((AddressA, \"foo\")),\n                DumbAction.Create((AddressB, \"bar\")),\n            }.ToPlainValues());\n            var invoice = new TxInvoice(\n                genesisHash,\n                updatedAddresses,\n                timestamp,\n                actions,\n                new FungibleAssetValue(\n                    Currency.Uncapped(\"FOO\", 18, AddressA),\n                    1234,\n                    5678),\n                100\n            );\n#pragma warning disable MEN002  // Long lines are OK for test JSON data.\n            TestUtils.AssertJsonSerializable(\n                invoice,\n                $@\"\n                    {{\n                      \"\"genesisHash\"\": \"\"92854cf0a62a7103b9c610fd588ad45254e64b74ceeeb209090ba572a41bf265\"\",\n                      \"\"updatedAddresses\"\": [\n                        \"\"B61CE2Ce6d28237C1BC6E114616616762f1a12Ab\"\",\n                        \"\"D6D639DA5a58A78A564C2cD3DB55FA7CeBE244A9\"\"\n                      ],\n                      \"\"timestamp\"\": \"\"2023-03-29T01:02:03.456\\u002B00:00\"\",\n                      \"\"actions\"\": [\n                        {{\n                          \"\"\\uFEFFitem\"\": \"\"\\uFEFFfoo\"\",\n                          \"\"\\uFEFFtarget_address\"\": \"\"0xd6d639da5a58a78a564c2cd3db55fa7cebe244a9\"\",\n                          \"\"\\uFEFFtype_id\"\": \"\"\\uFEFFDumbAction\"\"\n                        }},\n                        {{\n                          \"\"\\uFEFFitem\"\": \"\"\\uFEFFbar\"\",\n                          \"\"\\uFEFFtarget_address\"\": \"\"0xb61ce2ce6d28237c1bc6e114616616762f1a12ab\"\",\n                          \"\"\\uFEFFtype_id\"\": \"\"\\uFEFFDumbAction\"\"\n                        }}\n                      ],\n                      \"\"maxGasPrice\"\": {{\n                        \"\"quantity\"\": \"\"1234.000000000000005678\"\",\n                        \"\"currency\"\": {{\n                          \"\"maximumSupply\"\": null,\n                          \"\"ticker\"\": \"\"FOO\"\",\n                          \"\"decimalPlaces\"\": 18,\n                          \"\"minters\"\": [\n                            \"\"D6D639DA5a58A78A564C2cD3DB55FA7CeBE244A9\"\"\n                          ],\n                          \"\"hash\"\": \"\"a0d19219acb8d69815b3d299393c48bc8a93e0ec\"\",\n                          \"\"totalSupplyTrackable\"\": true\n                        }}\n                      }},\n                      \"\"gasLimit\"\": 100,\n                    }}\n                \",\n                false);\n#pragma warning restore MEN002\n        }\n\n        private class MockTxInvoice : ITxInvoice\n        {\n            public IImmutableSet<Address> UpdatedAddresses =>\n                ImmutableHashSet.Create(AddressA, AddressB);\n\n            public DateTimeOffset Timestamp =>\n                new DateTimeOffset(2023, 3, 29, 1, 2, 3, 456, TimeSpan.Zero);\n\n            public BlockHash? GenesisHash => BlockHash.FromString(\n                \"92854cf0a62a7103b9c610fd588ad45254e64b74ceeeb209090ba572a41bf265\");\n\n            public TxActionList Actions => new TxActionList(new IAction[]\n            {\n                DumbAction.Create((AddressA, \"foo\")),\n                DumbAction.Create((AddressB, \"bar\")),\n            }.ToPlainValues());\n\n            public FungibleAssetValue? MaxGasPrice => null;\n\n            public long? GasLimit => null;\n\n            bool IEquatable<ITxInvoice>.Equals(ITxInvoice other) => false;\n        }\n    }\n}\n"
  },
  {
    "path": "test/Libplanet.Tests/Tx/TxMarshalerTest.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Collections.Immutable;\nusing Bencodex;\nusing Bencodex.Types;\nusing Libplanet.Action.Loader;\nusing Libplanet.Action.Tests.Common;\nusing Libplanet.Common;\nusing Libplanet.Crypto;\nusing Libplanet.Types.Tx;\nusing Xunit;\nusing static Libplanet.Tests.TestUtils;\n\nnamespace Libplanet.Tests.Tx\n{\n    public class TxMarshalerTest\n    {\n        private readonly TxFixture _fx;\n        private readonly Dictionary _marshaledTxInvoice;\n        private readonly Dictionary _marshaledTxSigningMetadata;\n        private readonly Dictionary _marshaledUnsignedTx;\n        private readonly Dictionary _marshaledTransaction;\n        private readonly Dictionary _marshaledTxInvoiceWithCustomActions;\n        private readonly Dictionary _marshaledUnsignedTxWithCustomActions;\n        private readonly Dictionary _marshaledTransactionWithCustomActions;\n\n        public TxMarshalerTest()\n        {\n            _fx = new TxFixture(null);\n\n            _marshaledTxInvoice = Bencodex.Types.Dictionary.Empty\n                .Add(new byte[] { 0x61 }, Bencodex.Types.List.Empty) // 'a'\n                .Add(new byte[] { 0x74 }, \"2018-11-21T00:00:00.000000Z\") // 't'\n                .Add(new byte[] { 0x75 }, Bencodex.Types.List.Empty); // 'u'\n            _marshaledTxSigningMetadata = Bencodex.Types.Dictionary.Empty\n                .Add(new byte[] { 0x6e }, 0L) // 'n'\n                .Add(\n                    new byte[] { 0x70 }, // 'p'\n                    ByteUtil.ParseHex(\n                        \"0446115b0131baccf94a5856ede871295f6f3d352e6847cda9c03e89fe09f7328\" +\n                        \"08711ec97af6e341f110a326da1bdb81f5ae3badf76a90b22c8c491aed3aaa296\"))\n                .Add(\n                    new byte[] { 0x73 }, // 's'\n                    ByteUtil.ParseHex(\"c2a86014073d662a4a9bfcf9cb54263dfa4f5cbc\"));\n            _marshaledUnsignedTx =\n                (Dictionary)_marshaledTxInvoice.SetItems(_marshaledTxSigningMetadata);\n            _marshaledTransaction = _marshaledUnsignedTx\n                .Add(\n                    new byte[] { 0x53 },  // 'S'\n                    ByteUtil.ParseHex(\n                        \"304402202f2dbe5a916559dedbe8d84fa920e201294d4f40ea1e97441fbfa25c8bd00e\" +\n                        \"2302203c06021fb83f6749923c07596796a86304b0c3febb6c7a7b5858e97d3767e1e9\"\n                    ));\n\n            Bencodex.Types.Dictionary actionAttack = Bencodex.Types.Dictionary.Empty\n                .Add(\"type_id\", \"attack\")\n                .Add(\n                    \"values\",\n                    Bencodex.Types.Dictionary.Empty\n                        .Add(\"target\", \"orc\")\n                        .Add(\n                            \"target_address\",\n                            ByteUtil.ParseHex(\"c2a86014073d662a4a9bfcf9cb54263dfa4f5cbc\"))\n                        .Add(\"weapon\", \"wand\"));\n            Bencodex.Types.Dictionary actionSleep = Bencodex.Types.Dictionary.Empty\n                .Add(\"type_id\", \"sleep\")\n                .Add(\"values\", Bencodex.Types.Dictionary.Empty.Add(\"zone_id\", 10));\n            _marshaledTxInvoiceWithCustomActions = Bencodex.Types.Dictionary.Empty\n                .Add(\n                    new byte[] { 0x61 }, // 'a'\n                    Bencodex.Types.List.Empty.Add(actionAttack).Add(actionSleep))\n                .Add(new byte[] { 0x74 }, \"2018-11-21T00:00:00.000000Z\") // 't'\n                .Add(\n                    new byte[] { 0x75 }, // 'u'\n                    Bencodex.Types.List.Empty\n                        .Add(ByteUtil.ParseHex(\"c2a86014073d662a4a9bfcf9cb54263dfa4f5cbc\")));\n            _marshaledUnsignedTxWithCustomActions = (Dictionary)_marshaledTxInvoiceWithCustomActions\n                .SetItems(_marshaledTxSigningMetadata);\n            _marshaledTransactionWithCustomActions = _marshaledUnsignedTxWithCustomActions\n                .Add(\n                    new byte[] { 0x53 },  // 'S'\n                    ByteUtil.ParseHex(\n                        \"304402204cf2d4d92297a67fd04769f253e20e6213f063b8142fff4cb9e9c04733edbc\" +\n                        \"1602200efebb0e2a7bcf4d5c7a628ed2e7a91f440afa31197ff616fb32d8badad3e9cc\"\n                    ));\n        }\n\n        [Fact]\n        public void MarshalTxInvoice()\n        {\n            AssertBencodexEqual(_marshaledTxInvoice, _fx.Tx.MarshalTxInvoice());\n            AssertBencodexEqual(\n                _marshaledTxInvoiceWithCustomActions,\n                _fx.TxWithActions.MarshalTxInvoice());\n        }\n\n        [Fact]\n        public void MarshalTxSigningMetadata()\n        {\n            AssertBencodexEqual(_marshaledTxSigningMetadata, _fx.Tx.MarshalTxSigningMetadata());\n            AssertBencodexEqual(\n                _marshaledTxSigningMetadata,\n                _fx.TxWithActions.MarshalTxSigningMetadata());\n        }\n\n        [Fact]\n        public void MarshalUnsignedTx()\n        {\n            AssertBencodexEqual(_marshaledUnsignedTx, _fx.Tx.MarshalUnsignedTx());\n            AssertBencodexEqual(\n                _marshaledUnsignedTxWithCustomActions,\n                _fx.TxWithActions.MarshalUnsignedTx());\n        }\n\n        [Fact]\n        public void MarshalTransaction()\n        {\n            AssertBencodexEqual(_marshaledTransaction, _fx.Tx.MarshalTransaction());\n            AssertBencodexEqual(\n                _marshaledTransactionWithCustomActions,\n                _fx.TxWithActions.MarshalTransaction());\n        }\n\n        [Fact]\n        public void UnmarshalTxInvoice()\n        {\n            Assert.Equal<ITxInvoice>(\n                TxMarshaler.UnmarshalTxInvoice(_marshaledTxInvoice),\n                _fx.Tx);\n            Assert.Equal<ITxInvoice>(\n                TxMarshaler.UnmarshalTxInvoice(_marshaledTxInvoiceWithCustomActions),\n                _fx.TxWithActions);\n        }\n\n        [Fact]\n        public void UnmarshalTxInvoice_PreserveOrderOfUpdatedAddresses()\n        {\n            Bencodex.Types.Dictionary marshaledInvoiceA = _marshaledTxInvoice.SetItem(\n                new byte[] { 0x75 },\n                Bencodex.Types.List.Empty\n                    .Add(ByteUtil.ParseHex(\"0000000000000000000000000000000000000000\"))\n                    .Add(ByteUtil.ParseHex(\"ffffffffffffffffffffffffffffffffffffffff\")));\n            Bencodex.Types.Dictionary marshaledInvoiceB = _marshaledTxInvoice.SetItem(\n                new byte[] { 0x75 },\n                Bencodex.Types.List.Empty\n                    .Add(ByteUtil.ParseHex(\"ffffffffffffffffffffffffffffffffffffffff\"))\n                    .Add(ByteUtil.ParseHex(\"0000000000000000000000000000000000000000\")));\n            ITxInvoice invoiceA = TxMarshaler.UnmarshalTxInvoice(marshaledInvoiceA);\n            ITxInvoice invoiceB = TxMarshaler.UnmarshalTxInvoice(marshaledInvoiceB);\n            Assert.Equal<ITxInvoice>(invoiceA, invoiceB);\n            Assert.Equal<IEnumerable<Address>>(\n                new[] { default(Address), new Address(\"ffffffffffffffffffffffffffffffffffffffff\") },\n                invoiceA.UpdatedAddresses\n            );\n            Assert.Equal<IEnumerable<Address>>(\n                new[] { new Address(\"ffffffffffffffffffffffffffffffffffffffff\"), default(Address) },\n                invoiceB.UpdatedAddresses\n            );\n            AssertBencodexEqual(marshaledInvoiceA, invoiceA.MarshalTxInvoice());\n            AssertBencodexEqual(marshaledInvoiceB, invoiceB.MarshalTxInvoice());\n        }\n\n        [Fact]\n        public void UnmarshalTxSigningMetadata()\n        {\n            Assert.Equal<ITxSigningMetadata>(\n                TxMarshaler.UnmarshalTxSigningMetadata(_marshaledTxSigningMetadata),\n                _fx.Tx);\n            Assert.Equal<ITxSigningMetadata>(\n                TxMarshaler.UnmarshalTxSigningMetadata(_marshaledTxSigningMetadata),\n                _fx.TxWithActions);\n        }\n\n        [Fact]\n        public void UnmarshalUnsignedTx()\n        {\n            Assert.Equal<IUnsignedTx>(\n                TxMarshaler.UnmarshalUnsignedTx(_marshaledUnsignedTx),\n                _fx.Tx);\n            Assert.Equal<IUnsignedTx>(\n                TxMarshaler.UnmarshalUnsignedTx(\n                    _marshaledUnsignedTxWithCustomActions),\n                _fx.TxWithActions);\n        }\n\n        [Fact]\n        public void UnmarshalTransactionSignature()\n        {\n            AssertBytesEqual(\n                \"304402202f2dbe5a916559dedbe8d84fa920e201294d4f40ea1e97441fbfa25c8bd00e\" +\n                \"2302203c06021fb83f6749923c07596796a86304b0c3febb6c7a7b5858e97d3767e1e9\",\n                Assert.IsType<ImmutableArray<byte>>(\n                    TxMarshaler.UnmarshalTransactionSignature(_marshaledTransaction)));\n\n            Assert.Null(TxMarshaler.UnmarshalTransactionSignature(_marshaledUnsignedTx));\n        }\n\n        [Fact]\n        public void UnmarshalTransaction()\n        {\n            PublicKey publicKey = new PrivateKey(ByteUtil.ParseHex(\n                \"cf36ecf9e47c879a0dbf46b2ecd83fd276182ade0265825e3b8c6ba214467b76\")).PublicKey;\n            Transaction tx =\n                TxMarshaler.UnmarshalTransaction(_marshaledTransaction);\n\n            Assert.Equal(publicKey, tx.PublicKey);\n            Assert.Equal(ImmutableHashSet<Address>.Empty, tx.UpdatedAddresses);\n            Assert.Equal(new Address(publicKey), tx.Signer);\n            Assert.Equal(new DateTimeOffset(2018, 11, 21, 0, 0, 0, TimeSpan.Zero), tx.Timestamp);\n            AssertBytesEqual(\n                \"304402202f2dbe5a916559dedbe8d84fa920e201294d4f40ea1e97441fbfa25c8bd00e\" +\n                \"2302203c06021fb83f6749923c07596796a86304b0c3febb6c7a7b5858e97d3767e1e9\",\n                tx.Signature\n            );\n            AssertBytesEqual(\n                new TxId(ByteUtil.ParseHex(\n                    \"b069fde2538853be81b3eaacc23855420e03e5626f757fa19b3792601a948881\")),\n                tx.Id\n            );\n\n            Assert.Throws<DecodingException>(() =>\n                TxMarshaler.UnmarshalTransaction(_marshaledUnsignedTx));\n        }\n\n        [Fact]\n        public void UnmarshalTransactionWithCustomActions()\n        {\n            PublicKey publicKey = new PrivateKey(ByteUtil.ParseHex(\n                \"cf36ecf9e47c879a0dbf46b2ecd83fd276182ade0265825e3b8c6ba214467b76\")).PublicKey;\n            Transaction tx =\n                TxMarshaler.UnmarshalTransaction(\n                    _marshaledTransactionWithCustomActions);\n\n            Assert.Equal(publicKey, tx.PublicKey);\n            Assert.Equal(\n                ImmutableHashSet.Create(new Address(publicKey)),\n                tx.UpdatedAddresses\n            );\n            Assert.Equal(new Address(publicKey), tx.Signer);\n            Assert.Equal(new DateTimeOffset(2018, 11, 21, 0, 0, 0, TimeSpan.Zero), tx.Timestamp);\n            AssertBytesEqual(\n                \"304402204cf2d4d92297a67fd04769f253e20e6213f063b8142fff4cb9e9c04733edbc\" +\n                \"1602200efebb0e2a7bcf4d5c7a628ed2e7a91f440afa31197ff616fb32d8badad3e9cc\",\n                tx.Signature\n            );\n            AssertBytesEqual(\n                new TxId(ByteUtil.ParseHex(\n                    \"2c7d15f4c1d536ce4ca2a359bcd873a94f3c6518109ffabcf87e3485f363a534\")),\n                tx.Id\n            );\n\n            Assert.Equal(2, tx.Actions.Count);\n\n            var actionLoader = TypedActionLoader.Create(\n                typeof(BaseAction).Assembly, typeof(BaseAction));\n            var action0 = actionLoader.LoadAction(0, tx.Actions[0]);\n            Assert.IsType<Attack>(action0);\n            var targetAddress =\n                ((Binary)((Dictionary)((Dictionary)action0.PlainValue)[\"values\"])[\"target_address\"])\n                    .ByteArray;\n            AssertBytesEqual(\n                new Address(publicKey).ByteArray,\n                targetAddress\n            );\n            Assert.Equal(\n                Dictionary.Empty\n                    .Add(\"type_id\", \"attack\")\n                    .Add(\"values\", Dictionary.Empty\n                        .Add(\"weapon\", \"wand\")\n                        .Add(\"target\", \"orc\")\n                        .Add(\"target_address\", new Address(publicKey).Bencoded)),\n                action0.PlainValue\n            );\n\n            var action1 = actionLoader.LoadAction(0, tx.Actions[1]);\n            Assert.IsType<Sleep>(action1);\n            Assert.Equal(\n                Dictionary.Empty\n                    .Add(\"type_id\", \"sleep\")\n                    .Add(\"values\", Dictionary.Empty.Add(\"zone_id\", 10)),\n                action1.PlainValue\n            );\n            Assert.Throws<DecodingException>(() =>\n                TxMarshaler.UnmarshalTransaction(\n                    _marshaledUnsignedTxWithCustomActions));\n        }\n    }\n}\n"
  },
  {
    "path": "test/Libplanet.Tests/Tx/TxMetadataTest.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Collections.Immutable;\nusing Bencodex.Types;\nusing Libplanet.Common;\nusing Libplanet.Crypto;\nusing Libplanet.Types.Assets;\nusing Libplanet.Types.Blocks;\nusing Libplanet.Types.Tx;\nusing Xunit;\nusing static Libplanet.Tests.TestUtils;\n\nnamespace Libplanet.Tests.Tx\n{\n    public class TxMetadataTest\n    {\n        private readonly PrivateKey _key1;\n        private readonly PrivateKey _key2;\n\n        public TxMetadataTest()\n        {\n            _key1 = new PrivateKey(new byte[]\n            {\n                0x9b, 0xf4, 0x66, 0x4b, 0xa0, 0x9a, 0x89, 0xfa, 0xeb, 0x68, 0x4b,\n                0x94, 0xe6, 0x9f, 0xfd, 0xe0, 0x1d, 0x26, 0xae, 0x14, 0xb5, 0x56,\n                0x20, 0x4d, 0x3f, 0x6a, 0xb5, 0x8f, 0x61, 0xf7, 0x84, 0x18,\n            });\n\n            _key2 = new PrivateKey(new byte[]\n            {\n                0xfc, 0xf3, 0x0b, 0x33, 0x3d, 0x04, 0xcc, 0xfe, 0xb5, 0x62, 0xf0,\n                0x00, 0xa3, 0x2d, 0xf4, 0x88, 0xe7, 0x15, 0x49, 0x49, 0xd3, 0x1d,\n                0xdc, 0xac, 0x3c, 0xf9, 0x27, 0x8a, 0xcb, 0x57, 0x86, 0xc7,\n            });\n        }\n\n        public static IEnumerable<object[]> ToBencodexTheoryData() =>\n            new object[][]\n            {\n                new object[] { new DateTimeOffset(2022, 5, 23, 10, 2, 0, default) },\n                new object[] { new DateTimeOffset(2022, 5, 23, 19, 2, 0, TimeSpan.FromHours(9)) },\n            };\n\n        [Fact]\n        public void Constructor()\n        {\n            DateTimeOffset before = DateTimeOffset.UtcNow;\n            var meta = new TxMetadata(_key1.PublicKey);\n            DateTimeOffset after = DateTimeOffset.UtcNow;\n            Assert.Equal(0L, meta.Nonce);\n            AssertBytesEqual(_key1.Address, meta.Signer);\n            Assert.Empty(meta.UpdatedAddresses);\n            Assert.InRange(meta.Timestamp, before, after);\n            Assert.Equal(_key1.PublicKey, meta.PublicKey);\n            Assert.Null(meta.GenesisHash);\n        }\n\n        [Fact]\n        public void CopyConstructor()\n        {\n            var meta1 = new MetadataTransaction\n            {\n                PublicKey = _key1.PublicKey,\n                Nonce = 123L,\n                Timestamp = new DateTimeOffset(2022, 5, 23, 10, 2, 0, default),\n            };\n            var copy1 = new TxMetadata(meta1);\n            Assert.Equal(meta1.Nonce, copy1.Nonce);\n            AssertBytesEqual(meta1.Signer, copy1.Signer);\n            Assert.Equal(meta1.UpdatedAddresses, copy1.UpdatedAddresses);\n            Assert.Equal(meta1.Timestamp, copy1.Timestamp);\n            Assert.Equal(meta1.PublicKey, copy1.PublicKey);\n            AssertBytesEqual(meta1.GenesisHash, copy1.GenesisHash);\n\n            var meta2 = new MetadataTransaction\n            {\n                PublicKey = _key2.PublicKey,\n                Nonce = 0L,\n                UpdatedAddresses = new[]\n                {\n                    _key1.Address,\n                    _key2.Address,\n                }.ToImmutableHashSet(),\n                Timestamp = new DateTimeOffset(2022, 1, 12, 4, 56, 7, 890, default),\n                GenesisHash = BlockHash.FromString(\n                    \"83915317ebdbf870c567b263dd2e61ec9dca7fb381c592d80993291b6ffe5ad5\"),\n            };\n            var copy2 = new TxMetadata(meta2);\n            Assert.Equal(meta2.Nonce, copy2.Nonce);\n            AssertBytesEqual(meta2.Signer, copy2.Signer);\n            Assert.Equal(meta2.UpdatedAddresses, copy2.UpdatedAddresses);\n            Assert.Equal(meta2.Timestamp, copy2.Timestamp);\n            Assert.Equal(meta2.PublicKey, copy2.PublicKey);\n            AssertBytesEqual(meta2.GenesisHash, copy2.GenesisHash);\n        }\n\n        [Fact]\n        public void Deserialize()\n        {\n            Bencodex.Types.Dictionary dict1 = Dictionary.Empty\n                .Add(new byte[] { 0x6e }, 123L)\n                .Add(new byte[] { 0x73 }, _key1.Address.Bencoded)\n                .Add(new byte[] { 0x75 }, new List())\n                .Add(new byte[] { 0x74 }, \"2022-05-23T10:02:00.000000Z\")\n                .Add(new byte[] { 0x70 }, _key1.PublicKey.ToImmutableArray(compress: false));\n            var meta1 = new TxMetadata(dict1);\n            Assert.Equal(123L, meta1.Nonce);\n            AssertBytesEqual(_key1.Address, meta1.Signer);\n            Assert.Empty(meta1.UpdatedAddresses);\n            Assert.Equal(\n                new DateTimeOffset(2022, 5, 23, 10, 2, 0, default),\n                meta1.Timestamp);\n            Assert.Equal(_key1.PublicKey, meta1.PublicKey);\n            Assert.Null(meta1.GenesisHash);\n\n            Bencodex.Types.Dictionary dict2 = Dictionary.Empty\n                .Add(new byte[] { 0x6e }, 0L)\n                .Add(new byte[] { 0x73 }, _key2.Address.Bencoded)\n                .Add(\n                    new byte[] { 0x75 },\n                    Bencodex.Types.List.Empty\n                        .Add(_key1.Address.Bencoded)\n                        .Add(_key2.Address.Bencoded))\n                .Add(new byte[] { 0x74 }, \"2022-01-12T04:56:07.890000Z\")\n                .Add(new byte[] { 0x70 }, _key2.PublicKey.ToImmutableArray(compress: false))\n                .Add(\n                    new byte[] { 0x67 },\n                    ByteUtil.ParseHex(\n                        \"83915317ebdbf870c567b263dd2e61ec9dca7fb381c592d80993291b6ffe5ad5\"));\n            var meta2 = new TxMetadata(dict2);\n            Assert.Equal(0L, meta2.Nonce);\n            AssertBytesEqual(_key2.Address, meta2.Signer);\n            Assert.Equal(\n                new[] { _key1.Address, _key2.Address }.ToImmutableHashSet(),\n                meta2.UpdatedAddresses);\n            Assert.Equal(\n                new DateTimeOffset(2022, 1, 12, 4, 56, 7, 890, default),\n                meta2.Timestamp);\n            Assert.Equal(_key2.PublicKey, meta2.PublicKey);\n            AssertBytesEqual(\n                BlockHash.FromString(\n                    \"83915317ebdbf870c567b263dd2e61ec9dca7fb381c592d80993291b6ffe5ad5\"),\n                meta2.GenesisHash\n            );\n        }\n\n        [Theory]\n        [MemberData(nameof(ToBencodexTheoryData))]\n        public void ToBencodex(DateTimeOffset timestamp)\n        {\n            var meta1 = new TxMetadata(_key1.PublicKey)\n            {\n                Nonce = 123L,\n                Timestamp = timestamp,\n            };\n            Bencodex.Types.Dictionary expected1 = Dictionary.Empty\n                .Add(new byte[] { 0x6e }, 123L)\n                .Add(new byte[] { 0x73 }, _key1.Address.Bencoded)\n                .Add(new byte[] { 0x75 }, new List())\n                .Add(new byte[] { 0x74 }, \"2022-05-23T10:02:00.000000Z\")\n                .Add(new byte[] { 0x70 }, _key1.PublicKey.ToImmutableArray(compress: false));\n            AssertBencodexEqual(\n                expected1,\n                meta1.ToBencodex());\n\n            var meta2 = new TxMetadata(_key2.PublicKey)\n            {\n                Nonce = 0L,\n                UpdatedAddresses = new[]\n                {\n                    _key1.Address,\n                    _key2.Address,\n                }.ToImmutableHashSet(),\n                Timestamp = new DateTimeOffset(2022, 1, 12, 4, 56, 7, 890, default),\n                GenesisHash = BlockHash.FromString(\n                    \"83915317ebdbf870c567b263dd2e61ec9dca7fb381c592d80993291b6ffe5ad5\"),\n            };\n            Bencodex.Types.Dictionary expected2 = Dictionary.Empty\n                .Add(new byte[] { 0x6e }, 0L)\n                .Add(new byte[] { 0x73 }, _key2.Address.Bencoded)\n                .Add(\n                    new byte[] { 0x75 },\n                    Bencodex.Types.List.Empty\n                        .Add(_key1.Address.Bencoded)\n                        .Add(_key2.Address.Bencoded))\n                .Add(new byte[] { 0x74 }, \"2022-01-12T04:56:07.890000Z\")\n                .Add(new byte[] { 0x70 }, _key2.PublicKey.ToImmutableArray(compress: false))\n                .Add(\n                    new byte[] { 0x67 },\n                    ByteUtil.ParseHex(\n                        \"83915317ebdbf870c567b263dd2e61ec9dca7fb381c592d80993291b6ffe5ad5\"));\n            AssertBencodexEqual(\n                expected2,\n                meta2.ToBencodex());\n        }\n\n        private class MetadataTransaction : ITransaction\n        {\n            public TxId Id { get; set; } = default(TxId);\n\n            public long Nonce { get; set; } = 0L;\n\n            public Address Signer => PublicKey.Address;\n\n            public IImmutableSet<Address> UpdatedAddresses { get; set; } =\n                ImmutableHashSet<Address>.Empty;\n\n            public DateTimeOffset Timestamp { get; set; }\n\n            public PublicKey PublicKey { get; set; }\n\n            public BlockHash? GenesisHash { get; set; }\n\n            public byte[] Signature => Array.Empty<byte>();\n\n            public TxActionList Actions => TxActionList.Empty;\n\n            public FungibleAssetValue? MaxGasPrice => null;\n\n            public long? GasLimit => null;\n\n            bool IEquatable<ITxInvoice>.Equals(ITxInvoice other) => false;\n\n            bool IEquatable<ITxSigningMetadata>.Equals(ITxSigningMetadata other) => false;\n\n            bool IEquatable<IUnsignedTx>.Equals(IUnsignedTx other) => false;\n        }\n    }\n}\n"
  },
  {
    "path": "test/Libplanet.Tests/Tx/TxSigningMetadataTest.cs",
    "content": "using System;\nusing Libplanet.Common;\nusing Libplanet.Crypto;\nusing Libplanet.Types.Tx;\nusing Xunit;\n\nnamespace Libplanet.Tests.Tx\n{\n    public class TxSigningMetadataTest\n    {\n        private static readonly PublicKey PublicKey = new PublicKey(\n            ByteUtil.ParseHex(\n                \"03f804c12768bf9e05978ee37c56d037f68523fd9079642691eec82e233e1559bf\"));\n\n        [Fact]\n        public void Constructor()\n        {\n            var metadata = new TxSigningMetadata(PublicKey, 123L);\n            Assert.Equal(PublicKey.Address, metadata.Signer);\n            Assert.Equal(PublicKey, metadata.PublicKey);\n            Assert.Equal(123L, metadata.Nonce);\n\n            Assert.Throws<ArgumentOutOfRangeException>(\n                () => new TxSigningMetadata(PublicKey, -1L));\n        }\n\n        [Fact]\n        public void CopyConstructor()\n        {\n            var metadata = new TxSigningMetadata(PublicKey, 123L);\n            var copy = new TxSigningMetadata(metadata);\n            Assert.Equal(PublicKey.Address, copy.Signer);\n            Assert.Equal(PublicKey, copy.PublicKey);\n            Assert.Equal(123L, copy.Nonce);\n\n            var copyFromInterface = new TxSigningMetadata(new MockingTxSigningMetadata());\n            Assert.Equal(PublicKey.Address, copyFromInterface.Signer);\n            Assert.Equal(PublicKey, copyFromInterface.PublicKey);\n            Assert.Equal(123L, copyFromInterface.Nonce);\n        }\n\n        [Fact]\n        public void Equality()\n        {\n            var metadata = new TxSigningMetadata(PublicKey, 123L);\n            var copy = new TxSigningMetadata(metadata);\n            Assert.True(metadata.Equals(copy));\n            Assert.True(metadata.Equals((object)copy));\n            Assert.Equal(metadata.GetHashCode(), copy.GetHashCode());\n\n            var mock = new MockingTxSigningMetadata();\n            Assert.True(metadata.Equals(mock));\n            Assert.True(metadata.Equals((object)mock));\n\n            var diffPublicKey = new TxSigningMetadata(new PrivateKey().PublicKey, 123L);\n            Assert.False(metadata.Equals(diffPublicKey));\n            Assert.False(metadata.Equals((object)diffPublicKey));\n            Assert.NotEqual(metadata.GetHashCode(), diffPublicKey.GetHashCode());\n            Assert.False(diffPublicKey.Equals(mock));\n            Assert.False(diffPublicKey.Equals((object)mock));\n            Assert.NotEqual(diffPublicKey.GetHashCode(), mock.GetHashCode());\n\n            var diffNonce = new TxSigningMetadata(PublicKey, 456L);\n            Assert.False(metadata.Equals(diffNonce));\n            Assert.False(metadata.Equals((object)diffNonce));\n            Assert.NotEqual(metadata.GetHashCode(), diffNonce.GetHashCode());\n            Assert.False(diffNonce.Equals(mock));\n            Assert.False(diffNonce.Equals((object)mock));\n            Assert.NotEqual(diffNonce.GetHashCode(), mock.GetHashCode());\n        }\n\n        [Fact]\n        public void JsonSerialization()\n        {\n#pragma warning disable MEN002  // Long lines are OK for test JSON data.\n            TestUtils.AssertJsonSerializable(\n                new TxSigningMetadata(PublicKey, 123L),\n                @\"\n                    {\n                      \"\"signer\"\": \"\"89F0eE48e8BeaE3131B17Dc79A1282A0D7EdC6b9\"\",\n                      \"\"publicKey\"\": \"\"03f804c12768bf9e05978ee37c56d037f68523fd9079642691eec82e233e1559bf\"\",\n                      \"\"nonce\"\": 123\n                    }\n                \",\n                false);\n#pragma warning restore MEN002\n        }\n\n        private class MockingTxSigningMetadata : ITxSigningMetadata\n        {\n            long ITxSigningMetadata.Nonce => 123L;\n\n            Address ITxSigningMetadata.Signer => PublicKey.Address;\n\n            PublicKey ITxSigningMetadata.PublicKey => PublicKey;\n\n            bool IEquatable<ITxSigningMetadata>.Equals(ITxSigningMetadata other) => false;\n        }\n    }\n}\n"
  },
  {
    "path": "test/Libplanet.Tests/Tx/TxSigningMetadataTest.ts",
    "content": "namespace Libplanet.Tests.Tx {\n    class X {}\n}\n"
  },
  {
    "path": "test/Libplanet.Tests/Tx/UnsignedTxTest.cs",
    "content": "using System;\nusing System.Collections.Immutable;\nusing Bencodex;\nusing Libplanet.Action;\nusing Libplanet.Action.Tests.Common;\nusing Libplanet.Common;\nusing Libplanet.Crypto;\nusing Libplanet.Types.Blocks;\nusing Libplanet.Types.Tx;\nusing Xunit;\n\nnamespace Libplanet.Tests.Tx\n{\n    public class UnsignedTxTest\n    {\n        private static readonly Address AddressA =\n            new Address(\"D6D639DA5a58A78A564C2cD3DB55FA7CeBE244A9\");\n\n        private static readonly Address AddressB =\n            new Address(\"B61CE2Ce6d28237C1BC6E114616616762f1a12Ab\");\n\n        private static readonly PublicKey PublicKey = new PublicKey(\n            ByteUtil.ParseHex(\n                \"03f804c12768bf9e05978ee37c56d037f68523fd9079642691eec82e233e1559bf\"));\n\n        private readonly TxInvoice _invoice;\n        private readonly TxSigningMetadata _signingMetadata;\n\n        public UnsignedTxTest()\n        {\n            var genesisHash = BlockHash.FromString(\n                \"92854cf0a62a7103b9c610fd588ad45254e64b74ceeeb209090ba572a41bf265\");\n            var updatedAddresses = ImmutableHashSet.Create(AddressA, AddressB);\n            var timestamp = new DateTimeOffset(2023, 3, 29, 1, 2, 3, 456, TimeSpan.Zero);\n            var actions = new TxActionList(new IAction[]\n            {\n                DumbAction.Create((AddressA, \"foo\")),\n                DumbAction.Create((AddressB, \"bar\")),\n            }.ToPlainValues());\n            _invoice = new TxInvoice(\n                genesisHash,\n                updatedAddresses,\n                timestamp,\n                actions,\n                null,\n                null);\n            _signingMetadata = new TxSigningMetadata(PublicKey, 123L);\n        }\n\n        [Fact]\n        public void Constructor()\n        {\n            var unsignedTx = new UnsignedTx(_invoice, _signingMetadata);\n            Assert.Equal<ITxInvoice>(_invoice, unsignedTx);\n            Assert.Equal<ITxSigningMetadata>(_signingMetadata, unsignedTx);\n\n            unsignedTx = new UnsignedTx(\n                (ITxInvoice)_invoice,\n                (ITxSigningMetadata)_signingMetadata);\n            Assert.Equal<ITxInvoice>(_invoice, unsignedTx);\n            Assert.Equal<ITxSigningMetadata>(_signingMetadata, unsignedTx);\n        }\n\n        [Fact]\n        public void CopyConstructor()\n        {\n            var original = new UnsignedTx(_invoice, _signingMetadata);\n            var copy = new UnsignedTx(original);\n            Assert.Equal<ITxInvoice>(_invoice, copy);\n            Assert.Equal<ITxSigningMetadata>(_signingMetadata, copy);\n        }\n\n        [Fact]\n        public void CreateSignature()\n        {\n            var unsignedTx = new UnsignedTx(_invoice, _signingMetadata);\n            var privateKey =\n                new PrivateKey(\"51fb8c2eb261ed761429c297dd1f8952c8ce327d2ec2ec5bcc7728e3362627c2\");\n            var wrongKey = new PrivateKey();\n            ImmutableArray<byte> signature = unsignedTx.CreateSignature(privateKey);\n            byte[] message = new Codec().Encode(unsignedTx.MarshalUnsignedTx());\n            Assert.True(privateKey.PublicKey.Verify(message, signature));\n            Assert.False(wrongKey.PublicKey.Verify(message, signature));\n\n            ArgumentException e = Assert.Throws<ArgumentException>(\n                () => unsignedTx.CreateSignature(wrongKey));\n            Assert.Equal(\"privateKey\", e.ParamName);\n        }\n\n        [Fact]\n        public void VerifySignature()\n        {\n            var unsignedTx = new UnsignedTx(_invoice, _signingMetadata);\n            var privateKey =\n                new PrivateKey(\"51fb8c2eb261ed761429c297dd1f8952c8ce327d2ec2ec5bcc7728e3362627c2\");\n            var signature = ByteUtil.ParseHexToImmutable(\n                \"30430220502da40025cf537d0517a111bb2078b04ec421755743177e0bad75ff47dcf\" +\n                \"066021f154bb551ec7e5e9228debcd44beee5a74db8249670e06f2c5b355f56730627\");\n            var wrongSignature = ByteUtil.ParseHexToImmutable(\n                \"3045022100e4df322ba35e0e5ed96043b1c214e4a0f23734a7491b5db4c4a88834d3f47\" +\n                \"48a0220691b0972641a8759ac921b731e5750c20505f05fd993d45b24eb989de33018b1\");\n            Assert.True(unsignedTx.VerifySignature(signature));\n            Assert.False(unsignedTx.VerifySignature(wrongSignature));\n        }\n\n        [Fact]\n        public void Equality()\n        {\n            var unsignedTx = new UnsignedTx(_invoice, _signingMetadata);\n            Assert.Equal<ITxInvoice>(_invoice, unsignedTx);\n            Assert.Equal<ITxSigningMetadata>(_signingMetadata, unsignedTx);\n            var copy = new UnsignedTx(unsignedTx);\n            Assert.Equal<IUnsignedTx>(unsignedTx, copy);\n            Assert.Equal<UnsignedTx>(unsignedTx, copy);\n            Assert.True(unsignedTx.Equals((object)copy));\n            Assert.Equal(unsignedTx.GetHashCode(), copy.GetHashCode());\n\n            var wrongKey = new PrivateKey();\n            for (int i = 0; i < 6; i++)\n            {\n                var diffInvoice = new TxInvoice(\n                    i == 0 ? (BlockHash?)null : _invoice.GenesisHash,\n                    i == 1 ? AddressSet.Empty : _invoice.UpdatedAddresses,\n                    i == 2 ? DateTimeOffset.MinValue : _invoice.Timestamp,\n                    i == 3 ? TxActionList.Empty : _invoice.Actions,\n                    null,\n                    null);\n                var diffSigningMetadata = new TxSigningMetadata(\n                    i == 4 ? wrongKey.PublicKey : _signingMetadata.PublicKey,\n                    i == 5 ? 456L : _signingMetadata.Nonce\n                );\n\n                if (i < 4)\n                {\n                    Assert.NotEqual<ITxInvoice>(diffInvoice, unsignedTx);\n                    Assert.Equal<ITxSigningMetadata>(diffSigningMetadata, unsignedTx);\n                }\n                else\n                {\n                    Assert.Equal<ITxInvoice>(diffInvoice, unsignedTx);\n                    Assert.NotEqual<ITxSigningMetadata>(diffSigningMetadata, unsignedTx);\n                }\n\n                var diffUnsignedTx = new UnsignedTx(diffInvoice, diffSigningMetadata);\n                Assert.NotEqual<IUnsignedTx>(unsignedTx, diffUnsignedTx);\n                Assert.NotEqual<UnsignedTx>(unsignedTx, diffUnsignedTx);\n                Assert.False(unsignedTx.Equals((object)diffUnsignedTx));\n                Assert.NotEqual(unsignedTx.GetHashCode(), diffUnsignedTx.GetHashCode());\n            }\n        }\n\n#pragma warning disable MEN002  // Long lines are OK for test JSON data.\n        [Fact]\n        public void JsonSerialization()\n        {\n            TestUtils.AssertJsonSerializable(\n                new UnsignedTx(_invoice, _signingMetadata),\n                @\"\n                    {\n                      \"\"updatedAddresses\"\": [\n                        \"\"B61CE2Ce6d28237C1BC6E114616616762f1a12Ab\"\",\n                        \"\"D6D639DA5a58A78A564C2cD3DB55FA7CeBE244A9\"\"\n                      ],\n                      \"\"timestamp\"\": \"\"2023-03-29T01:02:03.456\\u002B00:00\"\",\n                      \"\"genesisHash\"\": \"\"92854cf0a62a7103b9c610fd588ad45254e64b74ceeeb209090ba572a41bf265\"\",\n                      \"\"actions\"\": [\n                        {\n                          \"\"\\uFEFFitem\"\": \"\"\\uFEFFfoo\"\",\n                          \"\"\\uFEFFtarget_address\"\": \"\"0xd6d639da5a58a78a564c2cd3db55fa7cebe244a9\"\",\n                          \"\"\\uFEFFtype_id\"\": \"\"\\uFEFFDumbAction\"\"\n                        },\n                        {\n                          \"\"\\uFEFFitem\"\": \"\"\\uFEFFbar\"\",\n                          \"\"\\uFEFFtarget_address\"\": \"\"0xb61ce2ce6d28237c1bc6e114616616762f1a12ab\"\",\n                          \"\"\\uFEFFtype_id\"\": \"\"\\uFEFFDumbAction\"\"\n                        }\n                      ],\n                      \"\"nonce\"\": 123,\n                      \"\"signer\"\": \"\"89F0eE48e8BeaE3131B17Dc79A1282A0D7EdC6b9\"\",\n                      \"\"publicKey\"\": \"\"03f804c12768bf9e05978ee37c56d037f68523fd9079642691eec82e233e1559bf\"\",\n                      \"\"maxGasPrice\"\": null,\n                      \"\"gasLimit\"\": null,\n                    }\n                \",\n                false);\n        }\n#pragma warning restore MEN002\n    }\n}\n"
  },
  {
    "path": "test/Libplanet.Tests/xunit.runner.mono.json",
    "content": "{\n  \"$schema\": \"https://xunit.github.io/schema/current/xunit.runner.schema.json\",\n  \"appDomain\": \"denied\",\n  \"parallelizeAssembly\": false,\n  \"parallelizeTestCollections\": false\n}\n"
  },
  {
    "path": "tools/Directory.Build.props",
    "content": "<Project>\n\n  <Import Project=\"$([MSBuild]::GetPathOfFileAbove('Directory.Build.props', '$(MSBuildThisFileDirectory)../'))\" />\n\n  <PropertyGroup>\n    <IsTestProject>false</IsTestProject>\n    <NoWarn>$(NoWarn);SA1000</NoWarn>\n  </PropertyGroup>\n\n</Project>\n"
  },
  {
    "path": "tools/Libplanet.Analyzers/ActionAnalyzer.cs",
    "content": "using System.Collections.Immutable;\nusing System.Linq;\nusing Libplanet.Action;\nusing Microsoft.CodeAnalysis;\nusing Microsoft.CodeAnalysis.Diagnostics;\nusing Microsoft.CodeAnalysis.Operations;\n\nnamespace Libplanet.Analyzers\n{\n    [DiagnosticAnalyzer(\n        LanguageNames.CSharp,\n        LanguageNames.FSharp,\n        LanguageNames.VisualBasic\n    )]\n    public class ActionAnalyzer : DiagnosticAnalyzer\n    {\n        public const string IdPrefix = \"LAA\";\n\n#pragma warning disable S1075\n        public const string HelpLinkUriPrefix =\n            \"https://github.com/planetarium/libplanet/blob/main/Libplanet.Analyzers/rules/LAA\";\n#pragma warning restore S1075\n\n#pragma warning disable SA1118\n        private static readonly DiagnosticDescriptor[] Diagnostics =\n        {\n            new DiagnosticDescriptor(\n                id: $\"{IdPrefix}9999\",\n                title: \"DebugMessageWhichShouldNotAppearToUsers\",\n                messageFormat: \"DEBUG: {0}\",\n                category: \"Debug\",\n                defaultSeverity: DiagnosticSeverity.Hidden,\n                isEnabledByDefault: true\n            ),\n            new DiagnosticDescriptor(\n                id: $\"{IdPrefix}1001\",\n                title: \"SystemRandomBreaksActionDeterminism\",\n                messageFormat:\n                    $\"The {{0}} makes an {nameof(IAction)} indeterministic; use \" +\n                    $\"{nameof(IActionContext)}.{nameof(IActionContext.GetRandom)} method instead.\",\n                category: \"Determinism\",\n                defaultSeverity: DiagnosticSeverity.Warning,\n                isEnabledByDefault: true,\n                helpLinkUri: $\"{HelpLinkUriPrefix}1001.md\"\n            ),\n            new DiagnosticDescriptor(\n                id: $\"{IdPrefix}1002\",\n                title: \"DictionariesOrSetsShouldBeOrderedToEnumerate\",\n                messageFormat: \"Enumerating an instance of {0} is indeterministic since \" +\n                    \"the order of {0} is unspecified; explicitly sort them before {1}.\",\n                category: \"Determinism\",\n                defaultSeverity: DiagnosticSeverity.Warning,\n                isEnabledByDefault: true,\n                helpLinkUri: $\"{HelpLinkUriPrefix}1002.md\"\n            ),\n        };\n#pragma warning restore SA1118\n\n        public static IImmutableDictionary<string, DiagnosticDescriptor> Rules =>\n            Diagnostics.ToImmutableDictionary(d => d.Id, d => d);\n\n        public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics =>\n            Diagnostics.ToImmutableArray();\n\n        public override void Initialize(AnalysisContext context)\n        {\n            context.EnableConcurrentExecution();\n            context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.Analyze);\n            context.RegisterOperationAction(LAA1001_SystemRandom, OperationKind.ObjectCreation);\n            context.RegisterOperationAction(\n                LAA1002_DictionarySetEnumeration,\n                OperationKind.Conversion,\n                OperationKind.Loop\n            );\n        }\n\n        private static void LAA1001_SystemRandom(OperationAnalysisContext context)\n        {\n            if (context.Operation is IObjectCreationOperation op &&\n                context.Compilation.GetTypeByMetadataName(\"System.Random\") is ITypeSymbol ts &&\n                op.Type is ITypeSymbol opType &&\n                SymbolEqualityComparer.Default.Equals(opType, ts))\n            {\n                Diagnostic diag = Diagnostic.Create(\n                    Rules[$\"{IdPrefix}1001\"],\n                    op.Syntax.GetLocation(),\n                    ts.ToDisplayString(SymbolDisplayFormat.CSharpErrorMessageFormat)\n                );\n                context.ReportDiagnostic(diag);\n            }\n        }\n\n        private static void LAA1002_DictionarySetEnumeration(OperationAnalysisContext context)\n        {\n            const string ns = \"System.Collections\";\n            SymbolDisplayFormat symbolFormat = SymbolDisplayFormat.CSharpErrorMessageFormat;\n            Compilation comp = context.Compilation;\n            SymbolEqualityComparer comparer = SymbolEqualityComparer.Default;\n\n            bool TypeEquals(ITypeSymbol? valType, string metadataName) => valType is ITypeSymbol a\n                && comp.GetTypeByMetadataName(metadataName) is INamedTypeSymbol b\n                && comparer.Equals(a, b);\n\n            string[] dictOrSets =\n            {\n                $\"{ns}.Generic.IDictionary`2\",\n                $\"{ns}.Generic.IReadOnlyDictionary`2\",\n                $\"{ns}.Immutable.IImmutableDictionary`2\",\n                $\"{ns}.IDictionary\",\n                $\"{ns}.Generic.ISet`1\",\n                $\"{ns}.Immutable.IImmutableSet`1\",\n            };\n\n            string[] sortedTypes =\n            {\n                $\"{ns}.Generic.SortedDictionary`2\",\n                $\"{ns}.Immutable.ImmutableSortedDictionary`2\",\n                $\"{ns}.Generic.SortedSet`1\",\n                $\"{ns}.Immutable.ImmutableSortedSet`1\",\n                \"Bencodex.Types.Dictionary\",\n            };\n\n            bool IsDictOrSet(ITypeSymbol? valType) =>\n                valType is ITypeSymbol t && t.OriginalDefinition.AllInterfaces\n                    .OfType<ITypeSymbol>()\n                    .Select(ifce => ifce.OriginalDefinition)\n                    .OfType<ITypeSymbol>()\n                    .Any(i => dictOrSets.Any(dst => TypeEquals(i, dst)));\n\n            bool IsUnordered(ITypeSymbol? valType) =>\n                valType is ITypeSymbol t && IsDictOrSet(t) &&\n                !sortedTypes.Any(sortedType => TypeEquals(t.OriginalDefinition, sortedType));\n\n            switch (context.Operation)\n            {\n                case IConversionOperation conv:\n                {\n                    ITypeSymbol? endType = conv.Type;\n                    if (!TypeEquals(endType?.OriginalDefinition, $\"{ns}.Generic.IEnumerable`1\") &&\n                        !TypeEquals(endType, $\"{ns}.IEnumerable\"))\n                    {\n                        return;\n                    }\n\n                    if (conv.Parent is IArgumentOperation arg &&\n                        arg.Parent is IInvocationOperation invoke &&\n                        invoke.TargetMethod.IsGenericMethod &&\n                        invoke.TargetMethod.OriginalDefinition is IMethodSymbol proto)\n                    {\n                        var method = invoke.TargetMethod.Name;\n                        if (method.StartsWith(\"OrderBy\") &&\n                            TypeEquals(proto.ContainingType, \"System.Linq.Enumerable\") &&\n                            TypeEquals(\n                                proto.ReturnType.OriginalDefinition,\n                                \"System.Linq.IOrderedEnumerable`1\"\n                            ))\n                        {\n                            // Ignores Linq's .OrderBy()/OrderByDescending() methods.\n                            return;\n                        }\n                        else if (method.StartsWith(\"To\") &&\n                                 (method.EndsWith(\"Dictionary\") || method.EndsWith(\"Set\")) &&\n                                 IsDictOrSet(proto.ReturnType))\n                        {\n                            // Ignores .ToDictionary()/ToHashSet() etc.\n                            return;\n                        }\n                    }\n\n                    if (conv.Parent is IArgumentOperation arg1 &&\n                        arg1.Parent is IObjectCreationOperation @new &&\n                        IsDictOrSet(@new.Type))\n                    {\n                        // Ignores new Dictionary()/new HashSet() etc.\n                        return;\n                    }\n\n                    ITypeSymbol? valType = conv.Operand?.Type;\n                    if (IsUnordered(valType))\n                    {\n                        string func = \"enumerating\";\n                        if (conv.Parent is IArgumentOperation argConv)\n                        {\n                            func = argConv.Parent switch\n                            {\n                                IObjectCreationOperation c =>\n                                    $\"passing to {c.Constructor.ToDisplayString(symbolFormat)} \" +\n                                    \"constructor\",\n                                IInvocationOperation m =>\n                                    $\"passing to {m.TargetMethod.ToDisplayString(symbolFormat)} \" +\n                                    \"method\",\n                                _ => func,\n                            };\n                        }\n\n                        Diagnostic diag = Diagnostic.Create(\n                            Rules[$\"{IdPrefix}1002\"],\n                            conv.Syntax.GetLocation(),\n                            valType!.ToDisplayString(symbolFormat),\n                            func\n                        );\n                        context.ReportDiagnostic(diag);\n                    }\n\n                    break;\n                }\n\n                case IForEachLoopOperation loop:\n                {\n                    IOperation collection = loop.Collection;\n                    ITypeSymbol? collType = collection.Type;\n                    if (IsUnordered(collType))\n                    {\n                        Diagnostic diag = Diagnostic.Create(\n                            Rules[$\"{IdPrefix}1002\"],\n                            collection.Syntax.GetLocation(),\n                            collType.ToDisplayString(symbolFormat),\n                            \"iterating via foreach\"\n                        );\n                        context.ReportDiagnostic(diag);\n                    }\n\n                    break;\n                }\n            }\n        }\n\n        private static Diagnostic Debug(string message) =>\n            Diagnostic.Create(Rules[$\"{IdPrefix}9999\"], null, message);\n    }\n}\n"
  },
  {
    "path": "tools/Libplanet.Analyzers/Libplanet.Analyzers.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <PropertyGroup>\n    <Title>Static analysis on Libplanet-powered apps</Title>\n    <Description>The Roslyn analyzer which checks if code has common <!--\n    --> mistakes prone to made with Libplanet-powered game apps.</Description>\n  </PropertyGroup>\n\n  <PropertyGroup>\n    <IncludeBuildOutput>false</IncludeBuildOutput>\n    <TreatWarningsAsErrors>true</TreatWarningsAsErrors>\n    <NoWarn>$(NoWarn);NU5128</NoWarn>\n    <IsPackable>true</IsPackable>\n    </PropertyGroup>\n\n  <ItemGroup>\n    <None Remove=\"..\\..\\README.md\" />\n    <None Include=\"README.md\" Pack=\"true\" PackagePath=\"README.md\" />\n    <AdditionalFiles Include=\"..\\..\\Menees.Analyzers.Settings.xml\">\n      <Link>Menees.Analyzers.Settings.xml</Link>\n    </AdditionalFiles>\n    <AdditionalFiles Include=\"..\\..\\stylecop.json\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <PackageReference Include=\"Microsoft.CodeAnalysis.Analyzers\" Version=\"3.3.0\" PrivateAssets=\"all\" />\n    <PackageReference Include=\"Microsoft.CodeAnalysis.CSharp.Workspaces\" Version=\"3.7.0\" PrivateAssets=\"all\" />\n    <PackageReference Update=\"NETStandard.Library\" PrivateAssets=\"all\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <ProjectReference Include=\"..\\..\\src\\Libplanet\\Libplanet.csproj\" />\n    <!-- FIXME: We should specify the version range when the following NuGet\n    issue is addressed: <https://github.com/NuGet/Home/issues/5556>. -->\n  </ItemGroup>\n\n  <ItemGroup>\n    <None Include=\"tools\\*.ps1\" CopyToOutputDirectory=\"Always\" Pack=\"true\" PackagePath=\"tools\" />\n    <None Include=\"$(TargetPath)\" Pack=\"true\" PackagePath=\"analyzers/dotnet/cs\" Visible=\"false\" />\n  </ItemGroup>\n\n</Project>\n"
  },
  {
    "path": "tools/Libplanet.Analyzers/README.md",
    "content": "Libplanet.Analyzers: Static analysis on Libplanet-powered apps\n==============================================================\n\n[![NuGet][nuget-badge]][NuGet]\n[![NuGet (prerelease)][nuget-prerelease-badge]][NuGet]\n\nThis Roslyn analyzer checks if code has common mistakes prone to made with\nLibplanet-powered game apps.  E.g., breaking determinism in `IAction`\nimplementations.\n\n~~~~ xml\n<!-- The below Version attribute should match to your Libplanet's version. -->\n<PackageReference Include=\"Libplanet.Analyzers\" Version=\"0.0.0\">\n  <IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>\n  <PrivateAssets>all</PrivateAssets>\n</PackageReference>\n~~~~\n\nIf you want to check your script on Unity editor:\n\n -  Ensure you use Unity 2020.2 or higher.\n -  Read the official docs: [*Roslyn analyzers and ruleset files*][1].\n\n[NuGet]: https://www.nuget.org/packages/Libplanet.Analyzers/\n[nuget-badge]: https://img.shields.io/nuget/v/Libplanet.Analyzers.svg?style=flat\n[nuget-prerelease-badge]: https://img.shields.io/nuget/vpre/Libplanet.Analyzers.svg?style=flat\n[1]: https://docs.unity3d.com/2020.2/Documentation/Manual/roslyn-analyzers.html\n\n\nRules\n-----\n\n| Rule                        |                                                |\n|-----------------------------|------------------------------------------------|\n| [LAA1001](rules/LAA1001.md) | SystemRandomBreaksActionDeterminism            |\n| [LAA1002](rules/LAA1002.md) | DictionariesOrSetsShouldBeOrderedToEnumerate   |\n"
  },
  {
    "path": "tools/Libplanet.Analyzers/rules/LAA1001.md",
    "content": "<def>LAA1001</def>: SystemRandomBreaksActionDeterminism\n=======================================================\n\nSince random values derived from local system's seeds break `IAction`'s\ndeterminism, `IActionContext.Random` property should be used instead.\n\n\nExamples\n--------\n\nThe following code is warned by the rule LAA1001:\n\n~~~~ csharp\npublic IAccountStateDelta Execute(IActionContext context)\n{\n    var states = context.PreviousState;\n    System.Random random = new System.Random();  // LAA1001\n    states.SetState(_targetAddress, (Bencodex.Types.Integer)random.Next());\n    return states;\n}\n~~~~\n\nThis can be addressed like below:\n\n~~~~ csharp\npublic IAccountStateDelta Execute(IActionContext context)\n{\n    var states = context.PreviousState;\n    IRandom random = context.Random;  // Fixed\n    states.SetState(_targetAddress, (Bencodex.Types.Integer)random.Next());\n    return states;\n}\n~~~~\n"
  },
  {
    "path": "tools/Libplanet.Analyzers/rules/LAA1002.md",
    "content": "<def>LAA1002</def>: DictionariesOrSetsShouldBeOrderedToEnumerate\n================================================================\n\nSince there is no explicit order to enumerate dictionaries or sets,\nenumerating them breaks `IAction`'s determinism.  They should be explicitly\nordered before being enumerated.\n\nApplied interfaces are:\n\n -  `System.Collections.Generic.IDictionary<K, V>`\n -  `System.Collections.Generic.IReadOnlyDictionary<K, V>`\n -  `System.Collections.Generic.ISet<V>`\n -  `System.Collections.Immutable.IImmutableSet<V>`\n -  `System.Collections.IDictionary`\n\nHowever, the following containers are excepted as they are already sorted:\n\n -  `System.Collections.Generic.SortedDictionary<K, V>`\n -  `System.Collections.Generic.SortedSet<T>`\n -  `System.Collections.Immutable.ImmutableSortedDictionary<K, V>`\n -  `System.Collections.Immutable.ImmutableSortedSet<T>`\n -  `Bencodex.Types.Dictionary` (which became to guarantee enumeration order\n    since [Bencodex 0.4.0-dev.20211116020419+abea0858][Bencodex\n    0.4.0-dev.20211116020419])\n\n[Bencodex 0.4.0-dev.20211116020419]: https://www.nuget.org/packages/Bencodex/0.4.0-dev.20211116020419\n\n\nExamples\n--------\n\nThe following code is warned by the rule LAA1002:\n\n~~~~ csharp\npublic IAccountStateDelta Execute(IActionContext context)\n{\n    var states = context.PreviousState;\n    if (states.GetState(_address) is Bencodex.Types.Dictionary d)\n    {\n        string list = d.Keys\n            .OfType<Bencodex.Types.Text>(k => k.Value);  // LAA1002\n        states.SetState(_targetAddress, (Bencodex.Types.Text)list);\n    }\n\n    return states;\n}\n~~~~\n\nThis can be addressed like below:\n\n~~~~ csharp\npublic IAccountStateDelta Execute(IActionContext context)\n{\n    var states = context.PreviousState;\n    if (states.GetState(_address) is Bencodex.Types.Dictionary d)\n    {\n        string list = d.Keys\n            .OfType<Bencodex.Types.Text>(k => k.Value)\n            .OrderBy(k => k);  // Fixed\n        states.SetState(_targetAddress, (Bencodex.Types.Text)list);\n    }\n\n    return states;\n}\n~~~~\n"
  },
  {
    "path": "tools/Libplanet.Analyzers/tools/README",
    "content": "These PowerShell scripts are required to enable this (Roslyn) Analyzer.\nThe contents are copied from the official docs:\n\nhttps://docs.microsoft.com/en-us/nuget/guides/analyzers-conventions#install-and-uninstall-scripts\n"
  },
  {
    "path": "tools/Libplanet.Analyzers/tools/install.ps1",
    "content": "param ($installPath, $toolsPath, $package, $project)\n\n$analyzersPaths = Join-Path `\n  (Join-Path (Split-Path -Path $toolsPath -Parent) \"analyzers\" ) * -Resolve\n\nforeach ($analyzersPath in $analyzersPaths) {\n  # Install the language agnostic analyzers.\n  if (Test-Path $analyzersPath) {\n    foreach ($analyzerFilePath in Get-ChildItem $analyzersPath -Filter *.dll) {\n      if ($project.Object.AnalyzerReferences) {\n        $project.Object.AnalyzerReferences.Add($analyzerFilePath.FullName)\n      }\n    }\n  }\n}\n\n$project.Type  # gives the language name like (C# or VB.NET)\n$languageFolder = \"\"\nif ($project.Type -eq \"C#\") {\n    $languageFolder = \"cs\"\n} elseif($project.Type -eq \"VB.NET\") {\n    $languageFolder = \"vb\"\n} elseif($languageFolder -eq \"\") {\n    return\n}\n\nforeach($analyzersPath in $analyzersPaths) {\n  # Install language specific analyzers.\n  $languageAnalyzersPath = Join-Path $analyzersPath $languageFolder\n  if (Test-Path $languageAnalyzersPath) {\n    $analyzerFilePaths = Get-ChildItem $languageAnalyzersPath -Filter *.dll\n    foreach ($analyzerFilePath in $analyzerFilePaths) {\n      if($project.Object.AnalyzerReferences) {\n        $project.Object.AnalyzerReferences.Add($analyzerFilePath.FullName)\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "tools/Libplanet.Analyzers/tools/uninstall.ps1",
    "content": "param ($installPath, $toolsPath, $package, $project)\n\n$analyzersPaths = Join-Path `\n  (Join-Path (Split-Path -Path $toolsPath -Parent) \"analyzers\" ) * -Resolve\n\nforeach ($analyzersPath in $analyzersPaths) {\n  # Uninstall the language agnostic analyzers.\n  if (Test-Path $analyzersPath) {\n    $analyzerFilePaths = Get-ChildItem $analyzersPath -Filter *.dll\n    foreach ($analyzerFilePath in $analyzerFilePaths) {\n      if ($project.Object.AnalyzerReferences) {\n        $project.Object.AnalyzerReferences.Remove($analyzerFilePath.FullName)\n      }\n    }\n  }\n}\n\n$project.Type # gives the language name like (C# or VB.NET)\n$languageFolder = \"\"\nif ($project.Type -eq \"C#\") {\n  $languageFolder = \"cs\"\n} elseif ($project.Type -eq \"VB.NET\") {\n  $languageFolder = \"vb\"\n} elseif ($languageFolder -eq \"\") {\n  return\n}\n\nforeach ($analyzersPath in $analyzersPaths) {\n  # Uninstall language specific analyzers.\n  $languageAnalyzersPath = Join-Path $analyzersPath $languageFolder\n  if (Test-Path $languageAnalyzersPath) {\n    foreach ($analyzerFilePath in Get-ChildItem $languageAnalyzersPath -Filter *.dll) {\n      if ($project.Object.AnalyzerReferences) {\n        try {\n          $project.Object.AnalyzerReferences.Remove($analyzerFilePath.FullName)\n        } catch {\n        }\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "tools/Libplanet.Benchmarks/AppendBlock.cs",
    "content": "using BenchmarkDotNet.Attributes;\nusing Libplanet.Action;\nusing Libplanet.Action.Loader;\nusing Libplanet.Action.Tests.Common;\nusing Libplanet.Blockchain.Policies;\nusing Libplanet.Crypto;\nusing Libplanet.Types.Blocks;\nusing Libplanet.Tests;\nusing Libplanet.Tests.Store;\nusing System.Collections.Immutable;\n\nnamespace Libplanet.Benchmarks\n{\n    public class AppendBlock\n    {\n        private Libplanet.Blockchain.BlockChain _blockChain;\n        private PrivateKey _privateKey;\n        private BlockCommit _lastCommit;\n        private Block _block;\n        private BlockCommit _commit;\n\n        public AppendBlock()\n        {\n            var fx = new DefaultStoreFixture();\n            _blockChain = Libplanet.Blockchain.BlockChain.Create(\n                new NullBlockPolicy(),\n                new VolatileStagePolicy(),\n                fx.Store,\n                fx.StateStore,\n                fx.GenesisBlock,\n                new ActionEvaluator(\n                    policyActionsRegistry: new PolicyActionsRegistry(),\n                    stateStore: fx.StateStore,\n                    actionTypeLoader: new SingleActionLoader(typeof(DumbAction))));\n            _privateKey = new PrivateKey();\n        }\n\n        [IterationSetup(Target = nameof(AppendBlockOneTransactionNoAction))]\n        public void PrepareAppendMakeOneTransactionNoAction()\n        {\n            _blockChain.MakeTransaction(_privateKey, new DumbAction[] { });\n            PrepareAppend();\n        }\n\n        [IterationSetup(Target = nameof(AppendBlockTenTransactionsNoAction))]\n        public void PrepareAppendMakeTenTransactionsNoAction()\n        {\n            for (var i = 0; i < 10; i++)\n            {\n                _blockChain.MakeTransaction(new PrivateKey(), new DumbAction[] { });\n            }\n            PrepareAppend();\n        }\n\n        [IterationSetup(Target = nameof(AppendBlockOneTransactionWithActions))]\n        public void PrepareAppendMakeOneTransactionWithActions()\n        {\n            var privateKey = new PrivateKey();\n            var address = privateKey.Address;\n            var actions = new[]\n            {\n                DumbAction.Create((address, \"foo\")),\n                DumbAction.Create((address, \"bar\")),\n                DumbAction.Create((address, \"baz\")),\n                DumbAction.Create((address, \"qux\")),\n            };\n            _blockChain.MakeTransaction(privateKey, actions);\n            PrepareAppend();\n        }\n\n        [IterationSetup(Target = nameof(AppendBlockTenTransactionsWithActions))]\n        public void PrepareAppendMakeTenTransactionsWithActions()\n        {\n            for (var i = 0; i < 10; i++)\n            {\n                var privateKey = new PrivateKey();\n                var address = privateKey.Address;\n                var actions = new[]\n                {\n                    DumbAction.Create((address, \"foo\")),\n                    DumbAction.Create((address, \"bar\")),\n                    DumbAction.Create((address, \"baz\")),\n                    DumbAction.Create((address, \"qux\")),\n                };\n                _blockChain.MakeTransaction(privateKey, actions);\n            }\n            PrepareAppend();\n        }\n\n        [Benchmark]\n        public void AppendBlockOneTransactionNoAction()\n        {\n            _blockChain.Append(_block, blockCommit: _commit);\n        }\n\n        [Benchmark]\n        public void AppendBlockTenTransactionsNoAction()\n        {\n            _blockChain.Append(_block, blockCommit: _commit);\n        }\n\n        [Benchmark]\n        public void AppendBlockOneTransactionWithActions()\n        {\n            _blockChain.Append(_block, blockCommit: _commit);\n        }\n\n        [Benchmark]\n        public void AppendBlockTenTransactionsWithActions()\n        {\n            _blockChain.Append(_block, blockCommit: _commit);\n        }\n\n        private void PrepareAppend()\n        {\n            _lastCommit = TestUtils.CreateBlockCommit(_blockChain.Tip);\n            _block = _blockChain.ProposeBlock(_privateKey, _lastCommit);\n            _commit = TestUtils.CreateBlockCommit(_block);\n        }\n    }\n}\n"
  },
  {
    "path": "tools/Libplanet.Benchmarks/BlockChain.cs",
    "content": "using System.Collections.Immutable;\nusing BenchmarkDotNet.Attributes;\nusing Libplanet.Action;\nusing Libplanet.Action.Loader;\nusing Libplanet.Action.Tests.Common;\nusing Libplanet.Blockchain.Policies;\nusing Libplanet.Crypto;\nusing Libplanet.Tests.Store;\n\nnamespace Libplanet.Benchmarks\n{\n    public class BlockChain\n    {\n        private StoreFixture _fx;\n        private Libplanet.Blockchain.BlockChain _blockChain;\n\n        public BlockChain()\n        {\n        }\n\n        [IterationCleanup]\n        public void FinalizeFixture()\n        {\n            _fx.Dispose();\n        }\n\n        [IterationSetup(Target = nameof(ContainsBlock))]\n        public void SetupChain()\n        {\n            _fx = new DefaultStoreFixture();\n            _blockChain = Libplanet.Blockchain.BlockChain.Create(\n                new NullBlockPolicy(),\n                new VolatileStagePolicy(),\n                _fx.Store,\n                _fx.StateStore,\n                _fx.GenesisBlock,\n                new ActionEvaluator(\n                    policyActionsRegistry: new PolicyActionsRegistry(),\n                    stateStore: _fx.StateStore,\n                    actionTypeLoader: new SingleActionLoader(typeof(DumbAction))));\n            var key = new PrivateKey();\n            for (var i = 0; i < 500; i++)\n            {\n                _blockChain.ProposeBlock(key);\n            }\n        }\n\n        [Benchmark]\n        public void ContainsBlock()\n        {\n            _blockChain.ContainsBlock(_blockChain.Tip.Hash);\n        }\n    }\n}\n"
  },
  {
    "path": "tools/Libplanet.Benchmarks/Commit.cs",
    "content": "using System;\nusing System.Collections.Immutable;\nusing System.Linq;\nusing System.Numerics;\nusing BenchmarkDotNet.Attributes;\nusing Libplanet.Crypto;\nusing Libplanet.Types.Blocks;\nusing Libplanet.Types.Consensus;\nusing Libplanet.Tests;\n\nnamespace Libplanet.Benchmarks\n{\n    public class Commit\n    {\n        private const int MaxValidatorSize = 100;\n\n        private Vote[] _votes;\n        private PrivateKey[] _privateKeys;\n        private BlockHash _blockHash;\n        private BlockCommit _blockCommit;\n        private Bencodex.Types.IValue _encodedBlockCommit;\n\n        [Params(4, 10, 25, 50, MaxValidatorSize)]\n        // ReSharper disable once MemberCanBePrivate.Global\n        // System.InvalidOperationException: Member \"ValidatorSize\" must be public if it has the\n        // [ParamsAttribute] attribute applied to it\n        public int ValidatorSize { get; set; }\n\n        [GlobalSetup]\n        public void Setup()\n        {\n            _blockHash = new BlockHash(TestUtils.GetRandomBytes(BlockHash.Size));\n            SetupKeys();\n            SetupVotes();\n        }\n\n        [IterationSetup(Target = nameof(DecodeBlockCommit))]\n        public void PrepareDecode()\n        {\n            _blockCommit = new BlockCommit(1, 0, _blockHash, _votes.Take(ValidatorSize).ToImmutableArray());\n            _encodedBlockCommit = _blockCommit.Bencoded;\n        }\n\n        [Benchmark]\n        public void DecodeBlockCommit()\n        {\n            _blockCommit = new BlockCommit(_encodedBlockCommit);\n        }\n\n        private void SetupKeys()\n        {\n            _privateKeys = new PrivateKey[MaxValidatorSize];\n            for (int i = 0; i < MaxValidatorSize; i++)\n            {\n                _privateKeys[i] = new PrivateKey();\n            }\n        }\n\n        private void SetupVotes()\n        {\n            _votes = Enumerable.Range(0, MaxValidatorSize)\n                .Select(x =>\n                    new VoteMetadata(\n                        1,\n                        0,\n                        _blockHash,\n                        DateTimeOffset.UtcNow,\n                        _privateKeys[x].PublicKey,\n                        BigInteger.One,\n                        VoteFlag.PreCommit).Sign(_privateKeys[x]))\n                .ToArray();\n        }\n    }\n}\n"
  },
  {
    "path": "tools/Libplanet.Benchmarks/DataModel/DataModelBenchmark.LeafModel.cs",
    "content": "using System.Collections.Generic;\nusing System.Collections.Immutable;\nusing System.Linq;\nusing Libplanet.Crypto;\nusing BTypes = Bencodex.Types;\nusing StoreDataModel = Libplanet.Store.DataModel;\n\nnamespace Libplanet.Benchmarks.DataModel\n{\n    public partial class DataModelBenchmark\n    {\n        public class LeafModel : StoreDataModel\n        {\n            public LeafModel()\n                : base()\n            {\n                System.Random random = new System.Random(2);\n                BigList = Enumerable\n                    .Range(0, 1000)\n                    .Select(_ => random.Next())\n                    .ToImmutableList();\n                BigDict = Enumerable\n                    .Range(0, 1000)\n                    .Select(_ => new KeyValuePair<Address, string>(\n                        new PrivateKey().Address,\n                        new PrivateKey().Address.ToString()))\n                    .ToImmutableDictionary();\n            }\n\n            public LeafModel(Bencodex.Types.Dictionary encoded)\n                : base(encoded)\n            {\n            }\n\n            public ImmutableList<int> BigList { get; private set; }\n\n            public ImmutableDictionary<Address, string> BigDict { get; private set; }\n        }\n\n        public class RawLeafModel\n        {\n            public RawLeafModel(Bencodex.Types.Dictionary encoded)\n            {\n                BigList = ((BTypes.List)encoded[nameof(BigList)])\n                    .Select(x => (int)((BTypes.Integer)x).Value)\n                    .ToImmutableList();\n                BigDict = ((BTypes.Dictionary)encoded[nameof(BigDict)])\n                    .Select(kv => new KeyValuePair<Address, string>(\n                        new Address(((BTypes.Binary)kv.Key).ByteArray),\n                        ((BTypes.Text)kv.Value).Value))\n                    .ToImmutableDictionary();\n            }\n\n            public BTypes.Dictionary Encode()\n            {\n                return BTypes.Dictionary.Empty\n                    .Add(\n                        nameof(BigList),\n                        (BTypes.IValue)new BTypes.List(\n                            BigList.Select(x => (BTypes.IValue)new BTypes.Integer(x)).ToList()))\n                    .Add(\n                        nameof(BigDict),\n                        new BTypes.Dictionary(\n                            BigDict\n                                .Select(kv => new KeyValuePair<BTypes.IKey, BTypes.IValue>(\n                                    new BTypes.Binary(kv.Key.ByteArray),\n                                    new BTypes.Text(kv.Value)))));\n            }\n\n            public ImmutableList<int> BigList { get; private set; }\n\n            public ImmutableDictionary<Address, string> BigDict { get; private set; }\n        }\n    }\n}\n"
  },
  {
    "path": "tools/Libplanet.Benchmarks/DataModel/DataModelBenchmark.MidModel.cs",
    "content": "using System.Collections.Generic;\nusing System.Collections.Immutable;\nusing System.Linq;\nusing Libplanet.Crypto;\nusing StoreDataModel = Libplanet.Store.DataModel;\n\nnamespace Libplanet.Benchmarks.DataModel\n{\n    public partial class DataModelBenchmark\n    {\n        public class MidModel : StoreDataModel\n        {\n            public MidModel()\n                : base()\n            {\n                System.Random random = new System.Random(1);\n                LeafModel = new LeafModel();\n                BigList = Enumerable\n                    .Range(0, 1000)\n                    .Select(_ => random.Next())\n                    .ToImmutableList();\n                BigDict = Enumerable\n                    .Range(0, 1000)\n                    .Select(_ => new KeyValuePair<Address, string>(\n                        new PrivateKey().Address,\n                        new PrivateKey().Address.ToString()))\n                    .ToImmutableDictionary();\n            }\n\n            public MidModel(Bencodex.Types.Dictionary encoded)\n                : base(encoded)\n            {\n            }\n\n            public LeafModel LeafModel { get; private set; }\n\n            public ImmutableList<int> BigList { get; private set; }\n\n            public ImmutableDictionary<Address, string> BigDict { get; private set; }\n        }\n    }\n}\n"
  },
  {
    "path": "tools/Libplanet.Benchmarks/DataModel/DataModelBenchmark.RootModel.cs",
    "content": "using System.Collections.Generic;\nusing System.Collections.Immutable;\nusing System.Linq;\nusing Libplanet.Crypto;\nusing StoreDataModel = Libplanet.Store.DataModel;\n\nnamespace Libplanet.Benchmarks.DataModel\n{\n    public partial class DataModelBenchmark\n    {\n        public class RootModel : StoreDataModel\n        {\n            public RootModel()\n                : base()\n            {\n                System.Random random = new System.Random(0);\n                MidModel = new MidModel();\n                BigList = Enumerable\n                    .Range(0, 1000)\n                    .Select(_ => random.Next())\n                    .ToImmutableList();\n                BigDict = Enumerable\n                    .Range(0, 1000)\n                    .Select(_ => new KeyValuePair<Address, string>(\n                        new PrivateKey().Address,\n                        new PrivateKey().Address.ToString()))\n                    .ToImmutableDictionary();\n            }\n\n            public RootModel(Bencodex.Types.Dictionary encoded)\n                : base(encoded)\n            {\n            }\n\n            public MidModel MidModel { get; private set; }\n\n            public ImmutableList<int> BigList { get; private set; }\n\n            public ImmutableDictionary<Address, string> BigDict { get; private set; }\n        }\n    }\n}\n"
  },
  {
    "path": "tools/Libplanet.Benchmarks/DataModel/DataModelBenchmark.cs",
    "content": "using BenchmarkDotNet.Attributes;\nusing BTypes = Bencodex.Types;\n\nnamespace Libplanet.Benchmarks.DataModel\n{\n    public partial class DataModelBenchmark\n    {\n        private RootModel _rootModel;\n        private LeafModel _leafModel;\n        private RawLeafModel _rawLeafModel;\n\n        private BTypes.Dictionary _encodedRootModel;\n        private BTypes.Dictionary _encodedLeafModel;\n\n        [GlobalSetup]\n        public void Setup()\n        {\n            _rootModel = new RootModel();\n            _leafModel = new LeafModel();\n            _encodedRootModel = _rootModel.Encode();\n            _encodedLeafModel = _leafModel.Encode();\n\n            _rawLeafModel = new RawLeafModel(_encodedLeafModel);\n        }\n\n        [Benchmark]\n        public Bencodex.Types.IValue EncodeRootModel()\n        {\n            return _rootModel.Encode();\n        }\n\n        [Benchmark]\n        public Bencodex.Types.IValue EncodeLeafModel()\n        {\n            return _leafModel.Encode();\n        }\n\n        [Benchmark]\n        public Bencodex.Types.IValue EncodeRawLeafModel()\n        {\n            return _rawLeafModel.Encode();\n        }\n\n        [Benchmark]\n        public Libplanet.Store.DataModel DecodeRootModel()\n        {\n            return new RootModel(_encodedRootModel);\n        }\n\n        [Benchmark]\n        public Libplanet.Store.DataModel DecodeLeafModel()\n        {\n            return new LeafModel(_encodedLeafModel);\n        }\n\n        [Benchmark]\n        public RawLeafModel DecodeRawLeafModel()\n        {\n            return new RawLeafModel(_encodedLeafModel);\n        }\n    }\n}\n"
  },
  {
    "path": "tools/Libplanet.Benchmarks/Libplanet.Benchmarks.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <PropertyGroup>\n    <Nullable>disable</Nullable>\n    <OutputType>Exe</OutputType>\n    <IsPackable>false</IsPackable>\n    <TreatWarningsAsErrors>true</TreatWarningsAsErrors>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <PackageReference Include=\"BenchmarkDotNet\" Version=\"0.12.1\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <PackageReference Remove=\"Menees.Analyzers.2017\" />\n    <PackageReference Remove=\"StyleCop.Analyzers\" />\n  </ItemGroup>\n\n  <ItemGroup Condition=\"'$(SkipSonar)' != 'true'\">\n    <PackageReference Remove=\"SonarAnalyzer.CSharp\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <ProjectReference Include=\"..\\..\\src\\Libplanet\\Libplanet.csproj\" />\n    <ProjectReference Include=\"..\\..\\src\\Libplanet.Net\\Libplanet.Net.csproj\" />\n    <ProjectReference Include=\"..\\..\\test\\Libplanet.Tests\\Libplanet.Tests.csproj\" />\n  </ItemGroup>\n\n</Project>\n"
  },
  {
    "path": "tools/Libplanet.Benchmarks/Program.cs",
    "content": "using System.IO;\nusing System.Linq;\nusing System.Text.Json.Nodes;\nusing BenchmarkDotNet.Running;\nusing Xunit.Sdk;\n\nnamespace Libplanet.Benchmarks\n{\n    public class Program\n    {\n        public static void Main(string[] args)\n        {\n            BenchmarkSwitcher.FromAssembly(typeof(Program).Assembly).Run(args);\n            CombineBenchmarkResults();\n        }\n        private static void CombineBenchmarkResults(\n            string resultsDir = \"./BenchmarkDotNet.Artifacts/results\",\n            string resultsFile = \"Combined.Benchmarks\",\n            string searchPattern = \"Libplanet.Benchmarks.*.json\")\n        {\n            var resultsPath = Path.Combine(resultsDir, resultsFile + \".json\");\n\n            if (!Directory.Exists(resultsDir))\n            {\n                throw new DirectoryNotFoundException($\"Directory not found '{resultsDir}'\");\n            }\n\n            if (File.Exists(resultsPath))\n            {\n                File.Delete(resultsPath);\n            }\n\n            var reports = Directory\n                .GetFiles(resultsDir, searchPattern, SearchOption.TopDirectoryOnly)\n                .ToArray();\n            if (!reports.Any())\n            {\n                throw new FileNotFoundException($\"Reports not found '{searchPattern}'\");\n            }\n\n            var combinedReport = JsonNode.Parse(File.ReadAllText(reports.First()));\n\n            if (combinedReport?[\"Title\"] == null ||\n                combinedReport[\"Benchmarks\"] == null)\n            {\n                return;\n            }\n\n            var title = combinedReport[\"Title\"];\n            var titleString = title.GetValue<string>();\n            var timestampString = titleString.Substring(titleString.Length - 15);\n            var benchmarks = combinedReport[\"Benchmarks\"].AsArray();\n            // Rename title whilst keeping original timestamp\n            combinedReport[\"Title\"] = $\"{resultsFile}-{timestampString}\";\n\n            foreach (var report in reports.Skip(1))\n            {\n                var reportJsonNode = JsonNode.Parse(File.ReadAllText(report));\n                if (reportJsonNode?[\"Benchmarks\"] == null)\n                {\n                    continue;\n                }\n\n                var targetBenchmarks = reportJsonNode[\"Benchmarks\"].AsArray();\n                foreach (var benchmark in targetBenchmarks)\n                {\n                    // Double parse avoids \"The node already has a parent\" exception\n                    benchmarks.Add(JsonNode.Parse(benchmark.ToJsonString()));\n                }\n            }\n            File.WriteAllText(resultsPath, combinedReport.ToString());\n        }\n    }\n}\n"
  },
  {
    "path": "tools/Libplanet.Benchmarks/ProposeBlock.cs",
    "content": "using BenchmarkDotNet.Attributes;\nusing Libplanet.Action;\nusing Libplanet.Action.Loader;\nusing Libplanet.Action.Tests.Common;\nusing Libplanet.Blockchain.Policies;\nusing Libplanet.Crypto;\nusing Libplanet.Types.Blocks;\nusing Libplanet.Tests;\nusing Libplanet.Tests.Store;\nusing System.Collections.Immutable;\n\nnamespace Libplanet.Benchmarks\n{\n    public class ProposeBlock\n    {\n        private Libplanet.Blockchain.BlockChain _blockChain;\n        private PrivateKey _privateKey;\n        private BlockCommit _lastCommit;\n        private Block _block;\n\n        public ProposeBlock()\n        {\n            var fx = new DefaultStoreFixture();\n            _blockChain = Libplanet.Blockchain.BlockChain.Create(\n                new NullBlockPolicy(),\n                new VolatileStagePolicy(),\n                fx.Store,\n                fx.StateStore,\n                fx.GenesisBlock,\n                new ActionEvaluator(\n                    policyActionsRegistry: new PolicyActionsRegistry(),\n                    stateStore: fx.StateStore,\n                    actionTypeLoader: new SingleActionLoader(typeof(DumbAction))));\n            _privateKey = new PrivateKey();\n        }\n\n        [IterationSetup(Target = nameof(ProposeBlockEmpty))]\n        public void PreparePropose()\n        {\n            _lastCommit = TestUtils.CreateBlockCommit(_blockChain.Tip);\n        }\n\n        [IterationCleanup(\n            Targets = new []\n            {\n                nameof(ProposeBlockEmpty),\n                nameof(ProposeBlockOneTransactionNoAction),\n                nameof(ProposeBlockTenTransactionsNoAction),\n                nameof(ProposeBlockOneTransactionWithActions),\n                nameof(ProposeBlockTenTransactionsWithActions),\n            }\n        )]\n        public void CleanupPropose()\n        {\n            // To unstaging transactions, a block is appended to blockchain.\n            _blockChain.Append(_block, TestUtils.CreateBlockCommit(_block));\n        }\n\n        [IterationSetup(Target = nameof(ProposeBlockOneTransactionNoAction))]\n        public void MakeOneTransactionNoAction()\n        {\n            PreparePropose();\n            _blockChain.MakeTransaction(_privateKey, new DumbAction[] { });\n        }\n\n        [IterationSetup(Target = nameof(ProposeBlockTenTransactionsNoAction))]\n        public void MakeTenTransactionsNoAction()\n        {\n            for (var i = 0; i < 10; i++)\n            {\n                _blockChain.MakeTransaction(new PrivateKey(), new DumbAction[] { });\n            }\n            PreparePropose();\n        }\n\n        [IterationSetup(Target = nameof(ProposeBlockOneTransactionWithActions))]\n        public void MakeOneTransactionWithActions()\n        {\n            var privateKey = new PrivateKey();\n            var address = privateKey.Address;\n            var actions = new[]\n            {\n                DumbAction.Create((address, \"foo\")),\n                DumbAction.Create((address, \"bar\")),\n                DumbAction.Create((address, \"baz\")),\n                DumbAction.Create((address, \"qux\")),\n            };\n            _blockChain.MakeTransaction(privateKey, actions);\n            PreparePropose();\n        }\n\n        [IterationSetup(Target = nameof(ProposeBlockTenTransactionsWithActions))]\n        public void MakeTenTransactionsWithActions()\n        {\n            for (var i = 0; i < 10; i++)\n            {\n                var privateKey = new PrivateKey();\n                var address = privateKey.Address;\n                var actions = new[]\n                {\n                    DumbAction.Create((address, \"foo\")),\n                    DumbAction.Create((address, \"bar\")),\n                    DumbAction.Create((address, \"baz\")),\n                    DumbAction.Create((address, \"qux\")),\n                };\n                _blockChain.MakeTransaction(privateKey, actions);\n            }\n            PreparePropose();\n        }\n\n        [Benchmark]\n        public void ProposeBlockEmpty()\n        {\n            _block = _blockChain.ProposeBlock(_privateKey, _lastCommit);\n        }\n\n        [Benchmark]\n        public void ProposeBlockOneTransactionNoAction()\n        {\n            _block = _blockChain.ProposeBlock(_privateKey, _lastCommit);\n        }\n\n        [Benchmark]\n        public void ProposeBlockTenTransactionsNoAction()\n        {\n            _block = _blockChain.ProposeBlock(_privateKey, _lastCommit);\n        }\n\n        [Benchmark]\n        public void ProposeBlockOneTransactionWithActions()\n        {\n            _block = _blockChain.ProposeBlock(_privateKey, _lastCommit);\n        }\n\n        [Benchmark]\n        public void ProposeBlockTenTransactionsWithActions()\n        {\n            _block = _blockChain.ProposeBlock(_privateKey, _lastCommit);\n        }\n    }\n}\n"
  },
  {
    "path": "tools/Libplanet.Benchmarks/Store.cs",
    "content": "using System.Collections.Generic;\nusing System.Collections.Immutable;\nusing BenchmarkDotNet.Attributes;\nusing Bencodex.Types;\nusing Libplanet.Crypto;\nusing Libplanet.Types.Blocks;\nusing Libplanet.Types.Tx;\nusing Libplanet.Store;\nusing Libplanet.Tests;\nusing Libplanet.Tests.Store;\n\nnamespace Libplanet.Benchmarks\n{\n    public class Store\n    {\n        private readonly ImmutableArray<Block> Blocks = default;\n        private readonly int BlocksCount = default;\n        private readonly ImmutableArray<Transaction> Txs = default;\n        private StoreFixture _fx = null;\n        private int TxsCount = default;\n        private IStore _store = null;\n\n        public Store()\n        {\n            var blocks = new List<Block>();\n            var txs = new List<Transaction>();\n            Block genesis = TestUtils.ProposeGenesisBlock(TestUtils.GenesisProposer);\n            blocks.Add(genesis);\n            Block block = genesis;\n            var key = new PrivateKey();\n            long nonce = 0;\n            for (int i = 0; i < 500; i++)\n            {\n                var blockTxs = new List<Transaction>();\n                for (int j = 0; j < i % 5; j++)\n                {\n                    blockTxs.Add(Transaction.Create(\n                        nonce++, key, genesis.Hash, List.Empty));\n                }\n                block = TestUtils.ProposeNextBlock(\n                    block, TestUtils.GenesisProposer, blockTxs);\n                blocks.Add(block);\n                txs.AddRange(blockTxs);\n            }\n            Blocks = blocks.ToImmutableArray();\n            BlocksCount = Blocks.Length;\n            Txs = txs.ToImmutableArray();\n            TxsCount = Txs.Length;\n        }\n\n        [IterationSetup]\n        public void InitializeFixture()\n        {\n            _fx = new DefaultStoreFixture();\n            _store = _fx.Store;\n        }\n\n        [IterationCleanup]\n        public void FinalizeFixture()\n        {\n            _fx.Dispose();\n        }\n\n        [Benchmark]\n        public void PutFirstEmptyBlock()\n        {\n            _store.PutBlock(Blocks[0]);\n        }\n\n        [Benchmark]\n        public void PutFirstBlockWithTxs()\n        {\n            _store.PutBlock(Blocks[5]);\n        }\n\n        [IterationSetup(\n            Targets = new []\n            {\n                nameof(PutBlockOnManyBlocks),\n                nameof(GetOldBlockOutOfManyBlocks),\n                nameof(GetRecentBlockOutOfManyBlocks),\n            }\n        )]\n        public void PutManyBlocks()\n        {\n            InitializeFixture();\n            int i = 0;\n            foreach (Block block in Blocks)\n            {\n                _store.PutBlock(block);\n                i++;\n                if (i >= Blocks.Length - 1)\n                {\n                    break;\n                }\n            }\n        }\n\n        [Benchmark]\n        public void PutBlockOnManyBlocks()\n        {\n            _store.PutBlock(Blocks[BlocksCount - 1]);\n        }\n\n        [Benchmark]\n        public Block GetOldBlockOutOfManyBlocks()\n        {\n            // Note that why this benchmark method returns something is\n            // because without this JIT can remove the below statement at all\n            // during dead code elimination optimization.\n            // https://benchmarkdotnet.org/articles/guides/good-practices.html#avoid-dead-code-elimination\n            return _store.GetBlock(Blocks[0].Hash);\n        }\n\n        [Benchmark]\n        public Block GetRecentBlockOutOfManyBlocks()\n        {\n            // Note that why this benchmark method returns something is\n            // because without this JIT can remove the below statement at all\n            // during dead code elimination optimization.\n            // https://benchmarkdotnet.org/articles/guides/good-practices.html#avoid-dead-code-elimination\n            return _store.GetBlock(Blocks[BlocksCount - 2].Hash);\n        }\n\n        [Benchmark]\n        public Block TryGetNonExistentBlockHash()\n        {\n            // Note that why this benchmark method returns something is\n            // because without this JIT can remove the below statement at all\n            // during dead code elimination optimization.\n            // https://benchmarkdotnet.org/articles/guides/good-practices.html#avoid-dead-code-elimination\n            return _store.GetBlock(default);\n        }\n\n        [Benchmark]\n        public void PutFirstTx()\n        {\n            _store.PutTransaction(Txs[0]);\n        }\n\n        [IterationSetup(\n            Targets = new []\n            {\n                nameof(PutTxOnManyTxs),\n                nameof(GetOldTxOutOfManyTxs),\n                nameof(GetRecentTxOutOfManyTxs),\n            }\n        )]\n        public void PutManyTxs()\n        {\n            InitializeFixture();\n            int i = 0;\n            foreach (Transaction tx in Txs)\n            {\n                _store.PutTransaction(tx);\n                i++;\n                if (i >= Txs.Length - 1)\n                {\n                    break;\n                }\n            }\n        }\n\n        [Benchmark]\n        public void PutTxOnManyTxs()\n        {\n            _store.PutTransaction(Txs[TxsCount - 1]);\n        }\n\n        [Benchmark]\n        public Transaction GetOldTxOutOfManyTxs()\n        {\n            // Note that why this benchmark method returns something is\n            // because without this JIT can remove the below statement at all\n            // during dead code elimination optimization.\n            // https://benchmarkdotnet.org/articles/guides/good-practices.html#avoid-dead-code-elimination\n            return _store.GetTransaction(Txs[0].Id);\n        }\n\n        [Benchmark]\n        public Transaction GetRecentTxOutOfManyTxs()\n        {\n            // Note that why this benchmark method returns something is\n            // because without this JIT can remove the below statement at all\n            // during dead code elimination optimization.\n            // https://benchmarkdotnet.org/articles/guides/good-practices.html#avoid-dead-code-elimination\n            return _store.GetTransaction(Txs[TxsCount - 2].Id);\n        }\n\n        [Benchmark]\n        public Transaction TryGetNonExistentTxId()\n        {\n            // Note that why this benchmark method returns something is\n            // because without this JIT can remove the below statement at all\n            // during dead code elimination optimization.\n            // https://benchmarkdotnet.org/articles/guides/good-practices.html#avoid-dead-code-elimination\n            return _store.GetTransaction(default);\n        }\n    }\n}\n"
  },
  {
    "path": "tools/Libplanet.Explorer/AssemblyInfo.cs",
    "content": "using System.Runtime.CompilerServices;\n\n[assembly: InternalsVisibleTo(\"Libplanet.Explorer.Tests\")]\n[assembly: InternalsVisibleTo(\"Libplanet.Explorer.Cocona\")]\n"
  },
  {
    "path": "tools/Libplanet.Explorer/ExplorerStartup.cs",
    "content": "using GraphQL.Server;\nusing Libplanet.Explorer.GraphTypes;\nusing Libplanet.Explorer.Indexing;\nusing Libplanet.Explorer.Interfaces;\nusing Libplanet.Explorer.Queries;\nusing Libplanet.Explorer.Schemas;\nusing Libplanet.Store;\nusing Microsoft.AspNetCore.Builder;\nusing Microsoft.AspNetCore.Hosting;\nusing Microsoft.Extensions.Configuration;\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.DependencyInjection.Extensions;\nusing Microsoft.Extensions.Hosting;\n\nnamespace Libplanet.Explorer\n{\n    public class ExplorerStartup<TU>\n        where TU : class, IBlockChainContext\n    {\n        public ExplorerStartup(IConfiguration configuration)\n        {\n            Configuration = configuration;\n        }\n\n        public IConfiguration Configuration { get; }\n\n        public void ConfigureServices(IServiceCollection services)\n        {\n            services.AddCors(options =>\n                options.AddPolicy(\n                    \"AllowAllOrigins\",\n                    builder =>\n                        builder.AllowAnyOrigin()\n                            .AllowAnyMethod()\n                            .AllowAnyHeader()\n                )\n            );\n            services.AddControllers();\n\n            services.AddSingleton<IBlockChainContext, TU>();\n            services.AddSingleton<IStore>(\n                provider => provider.GetRequiredService<IBlockChainContext>().Store);\n            services.AddSingleton<IBlockChainIndex>(\n                provider => provider.GetRequiredService<IBlockChainContext>().Index);\n\n            services.TryAddSingleton<ActionType>();\n            services.TryAddSingleton<BlockType>();\n            services.TryAddSingleton<TransactionType>();\n            services.TryAddSingleton<EvidenceType>();\n            services.TryAddSingleton<NodeStateType>();\n            services.TryAddSingleton<BlockQuery>();\n            services.TryAddSingleton<TransactionQuery>();\n            services.TryAddSingleton<EvidenceQuery>();\n            services.TryAddSingleton<ExplorerQuery>();\n            services.TryAddSingleton<LibplanetExplorerSchema>();\n\n            services.AddGraphQL()\n                    .AddSystemTextJson()\n                    .AddGraphTypes(typeof(LibplanetExplorerSchema));\n        }\n\n        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)\n        {\n            if (env.IsDevelopment())\n            {\n                app.UseDeveloperExceptionPage();\n            }\n\n            app.UseStaticFiles();\n            app.UseCors(\"AllowAllOrigins\");\n            app.UseRouting();\n            app.UseEndpoints(endpoints =>\n            {\n                endpoints.MapControllers();\n            });\n\n            // FIXME: '/graphql' endpoint will be deprecated after\n            //        libplanet-explorer-frontend migration.\n            app.UseGraphQL<LibplanetExplorerSchema>(\"/graphql\");\n            app.UseGraphQL<LibplanetExplorerSchema>(\"/graphql/explorer\");\n            app.UseGraphQLPlayground();\n        }\n    }\n}\n"
  },
  {
    "path": "tools/Libplanet.Explorer/GraphTypes/AccountStateType.cs",
    "content": "using System.Linq;\nusing System.Security.Cryptography;\nusing GraphQL;\nusing GraphQL.Types;\nusing Libplanet.Action.State;\nusing Libplanet.Common;\nusing Libplanet.Crypto;\nusing Libplanet.Store.Trie;\n\nnamespace Libplanet.Explorer.GraphTypes\n{\n    public class AccountStateType : ObjectGraphType<IAccountState>\n    {\n        internal static readonly KeyBytes ValidatorSetKey =\n            new KeyBytes(new byte[] { _underScore, _underScore, _underScore });\n\n        private const byte _underScore = 95;  // '_'\n\n        private static readonly byte[] _conversionTable =\n        {\n            48,  // '0'\n            49,  // '1'\n            50,  // '2'\n            51,  // '3'\n            52,  // '4'\n            53,  // '5'\n            54,  // '6'\n            55,  // '7'\n            56,  // '8'\n            57,  // '9'\n            97,  // 'a'\n            98,  // 'b'\n            99,  // 'c'\n            100, // 'd'\n            101, // 'e'\n            102, // 'f'\n        };\n\n        public AccountStateType()\n        {\n            Name = \"AccountState\";\n            Description =\n                \"Represents a raw account state.  This is meant to represent a raw storage state \" +\n                \"void of any application layer context and/or logic.  In particular, \" +\n                \"this does not deal with currency or fungible asset value directly, \" +\n                \"which requires additional information on currency such as its ticker \" +\n                \"and possible minters, etc. while interpreting the data retrieved \" +\n                \"with the provided contextual information. The same is true for validator sets.\";\n\n            Field<NonNullGraphType<HashDigestType<SHA256>>>(\n                name: \"stateRootHash\",\n                description: \"The state root hash associated with this account state.\",\n                resolve: context => context.Source.Trie.Hash\n            );\n\n            Field<IValueType>(\n                name: \"state\",\n                description: \"The state at given address.\",\n                arguments: new QueryArguments(\n                    new QueryArgument<NonNullGraphType<AddressType>>\n                    {\n                        Name = \"address\",\n                        Description = \"The address to look up.\",\n                    }\n                ),\n                resolve: context =>\n                    context.Source.GetState(context.GetArgument<Address>(\"address\"))\n            );\n\n            Field<NonNullGraphType<ListGraphType<IValueType>>>(\n                name: \"states\",\n                description: \"The states at given addresses.\",\n                arguments: new QueryArguments(\n                    new QueryArgument<\n                        NonNullGraphType<ListGraphType<NonNullGraphType<AddressType>>>>\n                    {\n                        Name = \"addresses\",\n                        Description = \"The list of addresses to look up.\",\n                    }\n                ),\n                resolve: context =>\n                    context.GetArgument<Address[]>(\"addresses\")\n                        .Select(address => context.Source.GetState(address))\n                        .ToArray()\n            );\n\n            Field<IValueType>(\n                name: \"balance\",\n                deprecationReason: \"Does not work post block protocol version 7.\",\n                description: \"Balance at given address and currency hash pair.\",\n                arguments: new QueryArguments(\n                    new QueryArgument<NonNullGraphType<AddressType>>\n                    {\n                        Name = \"address\",\n                        Description = \"The address to look up.\",\n                    },\n                    new QueryArgument<NonNullGraphType<HashDigestType<SHA1>>>\n                    {\n                        Name = \"currencyHash\",\n                        Description = \"The currency hash to look up.\",\n                    }\n                ),\n                resolve: context =>\n                    context.Source.Trie.Get(ToFungibleAssetKey(\n                        context.GetArgument<Address>(\"address\"),\n                        context.GetArgument<HashDigest<SHA1>>(\"currencyHash\")))\n            );\n\n            Field<NonNullGraphType<ListGraphType<IValueType>>>(\n                name: \"balances\",\n                deprecationReason: \"Does not work post block protocol version 7.\",\n                description: \"Balances at given addresses and currency hash pair.\",\n                arguments: new QueryArguments(\n                    new QueryArgument<NonNullGraphType<\n                        ListGraphType<NonNullGraphType<AddressType>>>>\n                    {\n                        Name = \"addresses\",\n                        Description = \"The list of addresses to look up.\",\n                    },\n                    new QueryArgument<NonNullGraphType<HashDigestType<SHA1>>>\n                    {\n                        Name = \"currencyHash\",\n                        Description = \"The currency hash to look up.\",\n                    }\n                ),\n                resolve: context =>\n                    context.GetArgument<Address[]>(\"addresses\")\n                        .Select(address => context.Source.Trie.Get(\n                            ToFungibleAssetKey(\n                                address, context.GetArgument<HashDigest<SHA1>>(\"currencyHash\"))))\n            );\n\n            Field<IValueType>(\n                name: \"totalSupply\",\n                deprecationReason: \"Does not work post block protocol version 7.\",\n                description: \"Total supply in circulation, if recorded, for given currency hash.\",\n                arguments: new QueryArguments(\n                    new QueryArgument<NonNullGraphType<HashDigestType<SHA1>>>\n                    {\n                        Name = \"currencyHash\",\n                        Description = \"The currency hash to look up.\",\n                    }\n                ),\n                resolve: context =>\n                    context.Source.Trie.Get(ToTotalSupplyKey(\n                        context.GetArgument<HashDigest<SHA1>>(\"currencyHash\")))\n            );\n\n            Field<IValueType>(\n                deprecationReason: \"Does not work post block protocol version 6.\",\n                name: \"validatorSet\",\n                description: \"The validator set.\",\n                resolve: context => context.Source.Trie.Get(ValidatorSetKey)\n            );\n        }\n\n        internal static KeyBytes ToFungibleAssetKey(Address address, HashDigest<SHA1> currencyHash)\n        {\n            var addressBytes = address.ByteArray;\n            var currencyBytes = currencyHash.ByteArray;\n            byte[] buffer = new byte[addressBytes.Length * 2 + currencyBytes.Length * 2 + 2];\n\n            buffer[0] = _underScore;\n            for (int i = 0; i < addressBytes.Length; i++)\n            {\n                buffer[1 + i * 2] = _conversionTable[addressBytes[i] >> 4];\n                buffer[1 + i * 2 + 1] = _conversionTable[addressBytes[i] & 0xf];\n            }\n\n            var offset = addressBytes.Length * 2;\n            buffer[offset + 1] = _underScore;\n            for (int i = 0; i < currencyBytes.Length; i++)\n            {\n                buffer[offset + 2 + i * 2] = _conversionTable[currencyBytes[i] >> 4];\n                buffer[offset + 2 + i * 2 + 1] = _conversionTable[currencyBytes[i] & 0xf];\n            }\n\n            return new KeyBytes(buffer);\n        }\n\n        internal static KeyBytes ToTotalSupplyKey(HashDigest<SHA1> currencyHash)\n        {\n            var currencyBytes = currencyHash.ByteArray;\n            byte[] buffer = new byte[currencyBytes.Length * 2 + 2];\n\n            buffer[0] = _underScore;\n            buffer[1] = _underScore;\n\n            for (int i = 0; i < currencyBytes.Length; i++)\n            {\n                buffer[2 + i * 2] = _conversionTable[currencyBytes[i] >> 4];\n                buffer[2 + i * 2 + 1] = _conversionTable[currencyBytes[i] & 0xf];\n            }\n\n            return new KeyBytes(buffer);\n        }\n    }\n}\n"
  },
  {
    "path": "tools/Libplanet.Explorer/GraphTypes/ActionType.cs",
    "content": "using System;\nusing System.IO;\nusing System.Text;\nusing System.Text.Json;\nusing Bencodex;\nusing Bencodex.Types;\nusing GraphQL;\nusing GraphQL.Types;\nusing Libplanet.Common;\n\nnamespace Libplanet.Explorer.GraphTypes\n{\n    public class ActionType : ObjectGraphType<IValue>\n    {\n        public ActionType()\n        {\n            Name = \"Action\";\n\n            Field<NonNullGraphType<StringGraphType>>(\n                name: \"Raw\",\n                description: \"Raw Action data ('hex' or 'base64' encoding available.)\",\n                arguments: new QueryArguments(\n                    new QueryArgument<StringGraphType>\n                    {\n                        DefaultValue = \"hex\",\n                        Name = \"encode\",\n                    }),\n                resolve: ctx =>\n                {\n                    var codec = new Codec();\n                    var encoded = codec.Encode(ctx.Source);\n\n                    var encode = ctx.GetArgument<string>(\"encode\");\n                    switch (encode)\n                    {\n                        case \"hex\":\n                            return ByteUtil.Hex(encoded);\n\n                        case \"base64\":\n                            return Convert.ToBase64String(encoded);\n\n                        default:\n                            var msg =\n                                \"Unsupported 'encode' method came. \" +\n                                \"It supports only 'hex' or 'base64'.\";\n                            throw new ExecutionError(msg);\n                    }\n                }\n            );\n\n            Field<NonNullGraphType<StringGraphType>>(\n                name: \"Inspection\",\n                description: \"A readable representation for debugging.\",\n                resolve: ctx => ctx.Source.Inspect()\n            );\n\n            Field<NonNullGraphType<StringGraphType>>(\n                name: \"json\",\n                description: \"A JSON representation of action data\",\n                resolve: ctx =>\n                {\n                    var converter = new Bencodex.Json.BencodexJsonConverter();\n                    var buffer = new MemoryStream();\n                    var writer = new Utf8JsonWriter(buffer);\n                    converter.Write(writer, ctx.Source, new JsonSerializerOptions());\n                    return Encoding.UTF8.GetString(buffer.ToArray());\n                }\n            );\n        }\n    }\n}\n"
  },
  {
    "path": "tools/Libplanet.Explorer/GraphTypes/AddressType.cs",
    "content": "using GraphQL.Language.AST;\nusing GraphQL.Types;\nusing Libplanet.Crypto;\n\nnamespace Libplanet.Explorer.GraphTypes\n{\n    public class AddressType : StringGraphType\n    {\n        public AddressType()\n        {\n            Name = \"Address\";\n        }\n\n        public override object? ParseLiteral(IValue value)\n        {\n            if (value is StringValue stringValue)\n            {\n                return ParseValue(stringValue.Value);\n            }\n\n            if (value is NullValue)\n            {\n                return null;\n            }\n\n            return ThrowLiteralConversionError(value);\n        }\n\n        public override object? ParseValue(object? value)\n        {\n            if (value is null)\n            {\n                return null;\n            }\n\n            if (value is string str)\n            {\n                // NOTE: 0x-prefixed *and* 0x-non-prefixed version should both be allowed.\n                return new Address(str);\n            }\n\n            return ThrowValueConversionError(value);\n        }\n\n        public override object? Serialize(object? value)\n        {\n            if (value is null)\n            {\n                return null;\n            }\n\n            if (value is Address address)\n            {\n                // NOTE: 0x-prefixed format is preferred as output.\n                return address.ToString();\n            }\n\n            return ThrowSerializationError(value);\n        }\n    }\n}\n"
  },
  {
    "path": "tools/Libplanet.Explorer/GraphTypes/BencodexValueType.cs",
    "content": "using System;\nusing Bencodex;\nusing GraphQL.Language.AST;\nusing GraphQL.Types;\nusing Libplanet.Common;\n\nnamespace Libplanet.Explorer.GraphTypes\n{\n    public class BencodexValueType : StringGraphType\n    {\n        private static readonly Codec _codec = new();\n\n        public BencodexValueType()\n        {\n            Name = \"BencodexValue\";\n        }\n\n        public override object? Serialize(object? value)\n        {\n            if (value is Bencodex.Types.IValue iv)\n            {\n                return _codec.Encode(iv);\n            }\n\n            return value;\n        }\n\n        public override object? ParseValue(object? value)\n        {\n            return value switch\n            {\n                null => null,\n                string hex => _codec.Decode(ByteUtil.ParseHex(hex)),\n                _ => throw new ArgumentException(\n                    $\"Expected a hexadecimal string but {value}\",\n                    nameof(value)\n                ),\n            };\n        }\n\n        public override object? ParseLiteral(IValue? value)\n        {\n            if (value is StringValue)\n            {\n                return ParseValue(value.Value);\n            }\n\n            return null;\n        }\n    }\n}\n"
  },
  {
    "path": "tools/Libplanet.Explorer/GraphTypes/BlockCommitType.cs",
    "content": "using GraphQL.Types;\nusing Libplanet.Types.Blocks;\n\nnamespace Libplanet.Explorer.GraphTypes\n{\n    public class BlockCommitType : ObjectGraphType<BlockCommit>\n    {\n        public BlockCommitType()\n        {\n            Name = \"BlockCommit\";\n\n            Field<NonNullGraphType<LongGraphType>>(\n                name: \"Height\",\n                description: \"The height of the block commit.\",\n                resolve: x => x.Source.Height\n            );\n            Field<NonNullGraphType<IntGraphType>>(\n                name: \"Round\",\n                description: \"The round of the block commit.\",\n                resolve: x => x.Source.Round\n            );\n            Field<NonNullGraphType<IdGraphType>>(\n                name: \"BlockHash\",\n                description: \"The hash of the block which contains block commit.\",\n                resolve: ctx => ctx.Source.BlockHash.ToString()\n            );\n            Field<NonNullGraphType<ListGraphType<NonNullGraphType<VoteType>>>>(\n                name: \"Votes\",\n                description: \"Total votes of the block commit.\",\n                resolve: x => x.Source.Votes\n            );\n        }\n    }\n}\n"
  },
  {
    "path": "tools/Libplanet.Explorer/GraphTypes/BlockHashType.cs",
    "content": "using GraphQL.Language.AST;\nusing GraphQL.Types;\nusing Libplanet.Common;\nusing Libplanet.Types.Blocks;\n\nnamespace Libplanet.Explorer.GraphTypes\n{\n    public class BlockHashType : StringGraphType\n    {\n        public BlockHashType()\n        {\n            Name = \"BlockHash\";\n        }\n\n        public override object? ParseLiteral(IValue value)\n        {\n            if (value is StringValue stringValue)\n            {\n                return ParseValue(stringValue.Value);\n            }\n\n            if (value is NullValue)\n            {\n                return null;\n            }\n\n            return ThrowLiteralConversionError(value);\n        }\n\n        public override object? ParseValue(object? value)\n        {\n            if (value is null)\n            {\n                return null;\n            }\n\n            if (value is string str)\n            {\n                return new BlockHash(ByteUtil.ParseHex(str));\n            }\n\n            return ThrowValueConversionError(value);\n        }\n\n        public override object? Serialize(object? value)\n        {\n            if (value is null)\n            {\n                return null;\n            }\n\n            if (value is BlockHash blockHash)\n            {\n                return ByteUtil.Hex(blockHash.ByteArray);\n            }\n\n            return ThrowSerializationError(value);\n        }\n    }\n}\n"
  },
  {
    "path": "tools/Libplanet.Explorer/GraphTypes/BlockType.cs",
    "content": "using Bencodex;\nusing GraphQL.Types;\nusing Libplanet.Explorer.Interfaces;\nusing Libplanet.Types.Blocks;\n\nnamespace Libplanet.Explorer.GraphTypes;\n\npublic class BlockType : ObjectGraphType<Block>\n{\n    private static readonly Codec _codec = new();\n\n    public BlockType(IBlockChainContext context)\n    {\n        Name = \"Block\";\n\n        // We need multiple row of description for clearer, not confusing explanation of field.\n        Field<NonNullGraphType<IdGraphType>>(\n            \"Hash\",\n            description: \"A block's hash.\",\n            resolve: ctx => ctx.Source.Hash.ToString()\n        );\n        Field<NonNullGraphType<LongGraphType>>(\n            name: \"Index\",\n            description: \"The height of the block.\",\n            resolve: x => x.Source.Index\n        );\n        Field<NonNullGraphType<AddressType>>(\n            name: \"Miner\",\n            description: \"The address of the miner.\",\n            resolve: x => x.Source.Miner\n        );\n        Field<PublicKeyType>(\n            name: \"PublicKey\",\n            description: \"The public key of the Miner.\",\n            resolve: x => x.Source.PublicKey\n        );\n        Field<BlockType>(\n            name: \"PreviousBlock\",\n            description: \"The previous block.  If it's a genesis block (i.e., its index is \" +\n                         \"0) this must be null.\",\n            resolve: ctx =>\n            {\n                if (ctx.Source.PreviousHash is not { } h)\n                {\n                    return null;\n                }\n\n                return context.Store.GetBlock(h);\n            }\n        );\n        Field(x => x.Timestamp);\n        Field<NonNullGraphType<ByteStringType>>(\n            name: \"StateRootHash\",\n            description: \"The hash of the resulting states after evaluating transactions \" +\n                         \"and a block action (if exists)\",\n            resolve: ctx => ctx.Source.StateRootHash.ToByteArray());\n        Field<ByteStringType>(\n            name: \"Signature\",\n            description: \"The digital signature of the whole block content (except for hash, \" +\n                         \"which is derived from the signature and other contents)\",\n            resolve: ctx => ctx.Source.Signature?.ToBuilder().ToArray());\n        Field<NonNullGraphType<ListGraphType<NonNullGraphType<TransactionType>>>>(\n            name: \"transactions\",\n            description: \"Transactions belonging to the block.\"\n        );\n        Field<NonNullGraphType<ListGraphType<NonNullGraphType<EvidenceType>>>>(\n            name: \"evidence\",\n            description: \"Evidence belonging to the block.\"\n        );\n        Field<BlockCommitType>(\n            name: \"LastCommit\",\n            description: \"The LastCommit of the block.\",\n            resolve: ctx => ctx.Source.LastCommit);\n        Field<NonNullGraphType<LongGraphType>>(\n            name: \"Difficulty\",\n            description: \"The mining difficulty that the block's nonce has to satisfy.\",\n            deprecationReason: \"Block does not have Difficulty field in PBFT.\",\n            resolve: _ => 0);\n        Field<NonNullGraphType<BigIntGraphType>>(\n            name: \"TotalDifficulty\",\n            description: \"The total mining difficulty since the genesis including \" +\n                         \"the block's difficulty.\",\n            deprecationReason: \"Block does not have TotalDifficulty field in PBFT.\",\n            resolve: _ => 0);\n        Field<NonNullGraphType<ByteStringType>>(\n            name: \"Nonce\",\n            description: \"The proof-of-work nonce which satisfies the required difficulty.\",\n            deprecationReason: \"Block does not have Nonce field in PBFT.\",\n            resolve: _ => new byte[] { }\n        );\n        Field<NonNullGraphType<ByteStringType>>(\n            name: \"PreEvaluationHash\",\n            description: \"The hash of PreEvaluationBlock.\",\n            resolve: ctx => ctx.Source.PreEvaluationHash.ToByteArray());\n        Field<NonNullGraphType<IntGraphType>>(\n            name: \"ProtocolVersion\",\n            description: \"The protocol version number of the block.\",\n            resolve: ctx => ctx.Source.ProtocolVersion);\n        Field<NonNullGraphType<ByteStringType>>(\n            name: \"Raw\",\n            description: \"The bencodex serialization of the block\",\n            resolve: ctx => _codec.Encode(ctx.Source.MarshalBlock()));\n    }\n}\n"
  },
  {
    "path": "tools/Libplanet.Explorer/GraphTypes/BoundPeerType.cs",
    "content": "using GraphQL.Types;\nusing Libplanet.Net;\nusing Libplanet.Store;\n\nnamespace Libplanet.Explorer.GraphTypes\n{\n    public class BoundPeerType : ObjectGraphType<BoundPeer>\n    {\n        public BoundPeerType()\n        {\n            Name = \"BoundPeer\";\n\n            // We need multiple row of description for clearer, not confusing explanation of field.\n            Field<NonNullGraphType<PublicKeyType>>(\n                \"publicKey\",\n                description: \"The public key of the peer.\",\n                resolve: ctx => ctx.Source.PublicKey\n            );\n            Field<NonNullGraphType<StringGraphType>>(\n                name: \"endPoint\",\n                description: \"The endpoint of the peer.\",\n                resolve: ctx => ctx.Source.EndPoint.ToString()\n            );\n            Field<StringGraphType>(\n                name: \"publicIpAddress\",\n                description: \"The address of the miner.\",\n                resolve: ctx => ctx.Source.PublicIPAddress?.ToString()\n            );\n        }\n    }\n}\n"
  },
  {
    "path": "tools/Libplanet.Explorer/GraphTypes/ByteStringType.cs",
    "content": "using System;\nusing GraphQL.Language.AST;\nusing GraphQL.Types;\nusing Libplanet.Common;\n\nnamespace Libplanet.Explorer.GraphTypes\n{\n    public class ByteStringType : StringGraphType\n    {\n        public ByteStringType()\n        {\n            Name = \"ByteString\";\n        }\n\n        public override object? Serialize(object? value)\n        {\n            return value switch\n            {\n                byte[] b => ByteUtil.Hex(b),\n                string s => s,\n                _ => null,\n            };\n        }\n\n        public override object? ParseValue(object? value)\n        {\n            switch (value)\n            {\n                case null:\n                    return null;\n                case string hex:\n                    return ByteUtil.ParseHex(hex);\n                default:\n                    throw new ArgumentException(\"Expected a hexadecimal string.\", nameof(value));\n            }\n        }\n\n        public override object? ParseLiteral(IValue value)\n        {\n            return value switch\n            {\n                StringValue stringValue => ParseValue(stringValue.Value),\n                _ => null,\n            };\n        }\n    }\n}\n"
  },
  {
    "path": "tools/Libplanet.Explorer/GraphTypes/CurrencyInputType.cs",
    "content": "using System.Collections.Generic;\nusing System.Collections.Immutable;\nusing System.Linq;\nusing System.Numerics;\nusing GraphQL;\nusing GraphQL.Types;\nusing Libplanet.Crypto;\nusing Libplanet.Types.Assets;\n\nnamespace Libplanet.Explorer.GraphTypes\n{\n    public class CurrencyInputType : InputObjectGraphType<Currency>\n    {\n        public CurrencyInputType()\n        {\n            Name = \"CurrencyInput\";\n            Field<NonNullGraphType<StringGraphType>>(\n                \"ticker\",\n                \"The ticker symbol, e.g., USD.\"\n            );\n            Field<NonNullGraphType<ByteGraphType>>(\n                \"decimalPlaces\",\n                \"The number of digits to treat as minor units (i.e., exponents).\"\n            );\n            Field<ListGraphType<NonNullGraphType<AddressType>>>(\n                \"minters\",\n                \"The addresses who can mint this currency.  If this is null anyone can \" +\n                \"mint the currency.  On the other hand, unlike null, an empty set means no one \" +\n                \"can mint the currency.\"\n            );\n            Field<BigIntGraphType>(\"maximumSupplyMajorUnit\");\n            Field<BigIntGraphType>(\"maximumSupplyMinorUnit\");\n            Field<BooleanGraphType>(\n                \"totalSupplyTrackable\",\n                \"Whether the total supply of this currency is trackable.\"\n            );\n        }\n\n        public override object ParseDictionary(IDictionary<string, object?> value)\n        {\n            IImmutableSet<Address>? minters = null;\n            var rawMinters = value.TryGetValue(\"minters\", out object? obj) && obj is object[] o\n                ? o\n                : null;\n            if (rawMinters is not null)\n            {\n                if (rawMinters.Any())\n                {\n                    minters = ImmutableHashSet<Address>.Empty;\n                    foreach (var rawMinter in rawMinters)\n                    {\n                        minters = minters.Add((Address)rawMinter);\n                    }\n                }\n            }\n\n            const bool DefaultTotalSupplyTrackable = false;\n            bool totalSupplyTrackable = value.TryGetValue(\n                \"totalSupplyTrackable\", out object? booleanValue)\n                ? (\n                    booleanValue is bool boolean\n                        ? boolean\n                        : throw new ExecutionError(\"totalSupplyTrackable must be boolean value.\")\n                  )\n                : DefaultTotalSupplyTrackable;\n            (BigInteger, BigInteger)? maximumSupply = GetMaximumSupply(value);\n            if (maximumSupply is { } && !totalSupplyTrackable)\n            {\n                throw new ExecutionError(\n                    \"Maximum supply is not available for legacy untracked currencies.\");\n            }\n\n            string ticker = (string)value[\"ticker\"]!;\n            byte decimalPlaces = (byte)value[\"decimalPlaces\"]!;\n\n#pragma warning disable CS0618\n\n            if (!totalSupplyTrackable)\n            {\n                return Currency.Legacy(\n                    ticker,\n                    decimalPlaces,\n                    minters: minters);\n            }\n#pragma warning restore CS0618\n\n            return maximumSupply is { } ms\n                ? Currency.Capped(ticker, decimalPlaces, ms, minters)\n                : Currency.Uncapped(ticker, decimalPlaces, minters);\n        }\n\n        private static (BigInteger, BigInteger)? GetMaximumSupply(\n            IDictionary<string, object?> variables\n        )\n        {\n            BigInteger? nullableMajorUnit =\n                variables.TryGetValue(\"maximumSupplyMajorUnit\", out object? nullableMajorUnitValue)\n                && nullableMajorUnitValue is BigInteger majorUnit\n                    ? majorUnit\n                    : null;\n            BigInteger? nullableMinorUnit =\n                variables.TryGetValue(\"maximumSupplyMinorUnit\", out object? nullableMinorUnitValue)\n                && nullableMinorUnitValue is BigInteger minorUnit\n                    ? minorUnit\n                    : null;\n\n            return (nullableMajorUnit, nullableMinorUnit) switch\n            {\n                (null, null) => null,\n                (BigInteger x, BigInteger y) => (x, y),\n                _ => throw new ExecutionError(\n                    \"Both \\\"maximumSupplyMajorUnit\\\" and \\\"maximumSupplyMinorUnit\\\" must \" +\n                    \"be present or omitted\"\n                ),\n            };\n        }\n    }\n}\n"
  },
  {
    "path": "tools/Libplanet.Explorer/GraphTypes/CurrencyType.cs",
    "content": "using System.Linq;\nusing System.Security.Cryptography;\nusing GraphQL.Types;\nusing Libplanet.Types.Assets;\n\nnamespace Libplanet.Explorer.GraphTypes;\n\npublic class CurrencyType : ObjectGraphType<Currency>\n{\n    public CurrencyType()\n    {\n        Name = \"Currency\";\n        Field<NonNullGraphType<StringGraphType>>(\n            \"ticker\",\n            \"The ticker symbol, e.g., USD.\",\n            resolve: context => context.Source.Ticker\n        );\n        Field<NonNullGraphType<ByteGraphType>>(\n            \"decimalPlaces\",\n            \"The number of digits to treat as minor units (i.e., exponents).\",\n            resolve: context => (uint)context.Source.DecimalPlaces\n        );\n        Field<ListGraphType<NonNullGraphType<AddressType>>>(\n            \"minters\",\n            \"The addresses who can mint this currency.  If this is null anyone can \" +\n                \"mint the currency.  On the other hand, unlike null, an empty set means no one \" +\n                \"can mint the currency.\",\n            resolve: context => context.Source.Minters\n                ?.OrderBy(a => a)\n                ?.ToList()\n        );\n        Field<FungibleAssetValueType>(\n            \"maximumSupply\",\n            \"The uppermost quantity of currency allowed to exist.  \" +\n                \"null means unlimited supply.\",\n            resolve: context => context.Source.MaximumSupply\n        );\n        Field<NonNullGraphType<BooleanGraphType>>(\n            \"totalSupplyTrackable\",\n            \"Whether the total supply of this currency is trackable.\",\n            resolve: context => context.Source.TotalSupplyTrackable\n        );\n        Field<NonNullGraphType<ByteStringType>>(\n            \"hash\",\n            \"The deterministic hash derived from other fields.\",\n            resolve: context => context.Source.Hash.ToByteArray()\n        );\n    }\n}\n"
  },
  {
    "path": "tools/Libplanet.Explorer/GraphTypes/EvidenceIdType.cs",
    "content": "using GraphQL.Language.AST;\nusing GraphQL.Types;\nusing Libplanet.Common;\nusing Libplanet.Types.Evidence;\n\nnamespace Libplanet.Explorer.GraphTypes\n{\n    public class EvidenceIdType : StringGraphType\n    {\n        public EvidenceIdType()\n        {\n            Name = \"EvidenceId\";\n        }\n\n        public override object? ParseLiteral(IValue value)\n        {\n            if (value is StringValue stringValue)\n            {\n                return ParseValue(stringValue.Value);\n            }\n\n            if (value is NullValue)\n            {\n                return null;\n            }\n\n            return ThrowLiteralConversionError(value);\n        }\n\n        public override object? ParseValue(object? value)\n        {\n            if (value is null)\n            {\n                return null;\n            }\n\n            if (value is string str)\n            {\n                return new EvidenceId(ByteUtil.ParseHex(str));\n            }\n\n            return ThrowValueConversionError(value);\n        }\n\n        public override object? Serialize(object? value)\n        {\n            if (value is null)\n            {\n                return null;\n            }\n\n            if (value is EvidenceId evidenceId)\n            {\n                return ByteUtil.Hex(evidenceId.ByteArray);\n            }\n\n            return ThrowSerializationError(value);\n        }\n    }\n}\n"
  },
  {
    "path": "tools/Libplanet.Explorer/GraphTypes/EvidenceType.cs",
    "content": "using GraphQL.Types;\nusing Libplanet.Types.Evidence;\n\nnamespace Libplanet.Explorer.GraphTypes\n{\n    public class EvidenceType : ObjectGraphType<EvidenceBase>\n    {\n        public EvidenceType()\n        {\n            Name = \"Evidence\";\n\n            Field<NonNullGraphType<IdGraphType>>(\n                name: \"Id\",\n                description: \"A unique identifier derived from this Evidence content\",\n                resolve: ctx => ctx.Source.Id.ToString()\n            );\n            Field<NonNullGraphType<StringGraphType>>(\n                name: \"Type\",\n                description: \"Evidence type.\",\n                resolve: x => x.Source.GetType().FullName\n            );\n            Field<NonNullGraphType<LongGraphType>>(\n                name: \"Height\",\n                description: \"Indicates the block height that infraction has been occurred.\",\n                resolve: x => x.Source.Height\n            );\n            Field<NonNullGraphType<AddressType>>(\n                name: \"TargetAddress\",\n                description: \"Indicates the address of the target that caused the infraction.\",\n                resolve: x => x.Source.TargetAddress\n            );\n            Field<NonNullGraphType<DateTimeOffsetGraphType>>(\n                name: \"Timestamp\",\n                description: \"Indicates the timestamp the infraction occurred.\",\n                resolve: x => x.Source.Timestamp\n            );\n        }\n    }\n}\n"
  },
  {
    "path": "tools/Libplanet.Explorer/GraphTypes/FungibleAssetValueType.cs",
    "content": "using GraphQL.Types;\nusing Libplanet.Types.Assets;\n\nnamespace Libplanet.Explorer.GraphTypes;\n\npublic class FungibleAssetValueType : ObjectGraphType<FungibleAssetValue>\n{\n    public FungibleAssetValueType()\n    {\n        Name = \"FungibleAssetValue\";\n        Description = \"Holds a fungible asset value which holds its currency together.\";\n        Field<NonNullGraphType<CurrencyType>>(\n            \"currency\",\n            \"The currency of the fungible asset.\",\n            resolve: ctx => ctx.Source.Currency\n        );\n        Field<NonNullGraphType<IntGraphType>>(\n            \"sign\",\n            \"Gets a number that indicates the sign (-1: negative, 1: positive, \" +\n                \"or 0: zero) of the value.\",\n            resolve: ctx => ctx.Source.Sign\n        );\n        Field(\"majorUnit\", source => source.MajorUnit);\n        Field(\"minorUnit\", source => source.MinorUnit);\n        Field<NonNullGraphType<StringGraphType>>(\n            \"quantity\",\n            \"The value quantity without its currency in string, e.g., \\\"123.45\\\".\",\n            resolve: ctx => ctx.Source.GetQuantityString()\n        );\n        Field<NonNullGraphType<StringGraphType>>(\n            \"string\",\n            \"The value quantity with its currency in string, e.g., \\\"123.45 ABC\\\".\",\n            resolve: ctx => ctx.Source.ToString()\n        );\n    }\n}\n"
  },
  {
    "path": "tools/Libplanet.Explorer/GraphTypes/HashDigestSHA256Type.cs",
    "content": "#nullable disable\nusing System;\nusing System.Security.Cryptography;\nusing GraphQL.Language.AST;\nusing GraphQL.Types;\nusing Libplanet.Common;\n\nnamespace Libplanet.Explorer.GraphTypes\n{\n    public class HashDigestSHA256Type : StringGraphType\n    {\n        public HashDigestSHA256Type()\n        {\n            Name = \"HashDigest_SHA256\";\n        }\n\n        public override object Serialize(object value)\n        {\n            if (value is HashDigest<SHA256> hash)\n            {\n                return hash.ToString();\n            }\n\n            return value;\n        }\n\n        public override object ParseValue(object value) =>\n            value switch\n            {\n                null => null,\n                string hex => HashDigest<SHA256>.FromString(hex),\n                _ => throw new ArgumentException(\n                    $\"Expected a hexadecimal string but {value}\", nameof(value)),\n            };\n\n        public override object ParseLiteral(IValue value) =>\n            value switch\n            {\n                StringValue str => ParseValue(str.Value),\n                _ => throw new ArgumentException(\n                    $\"Expected a hexadecimal string but {value}\", nameof(value)),\n            };\n    }\n}\n"
  },
  {
    "path": "tools/Libplanet.Explorer/GraphTypes/HashDigestType.cs",
    "content": "using System.Security.Cryptography;\nusing GraphQL.Language.AST;\nusing GraphQL.Types;\nusing Libplanet.Common;\n\nnamespace Libplanet.Explorer.GraphTypes\n{\n    public class HashDigestType<T> : StringGraphType\n        where T : HashAlgorithm\n    {\n        public HashDigestType()\n        {\n            Name = $\"HashDigest{typeof(T).Name}\";\n        }\n\n        public override object? ParseLiteral(IValue value)\n        {\n            if (value is StringValue stringValue)\n            {\n                return ParseValue(stringValue.Value);\n            }\n\n            if (value is NullValue)\n            {\n                return null;\n            }\n\n            return ThrowLiteralConversionError(value);\n        }\n\n        public override object? ParseValue(object? value)\n        {\n            if (value is null)\n            {\n                return null;\n            }\n\n            if (value is string str)\n            {\n                return new HashDigest<T>(ByteUtil.ParseHex(str));\n            }\n\n            return ThrowValueConversionError(value);\n        }\n\n        public override object? Serialize(object? value)\n        {\n            if (value is null)\n            {\n                return null;\n            }\n\n            if (value is HashDigest<T> hashDigest)\n            {\n                return ByteUtil.Hex(hashDigest.ByteArray);\n            }\n\n            return ThrowSerializationError(value);\n        }\n    }\n}\n"
  },
  {
    "path": "tools/Libplanet.Explorer/GraphTypes/IValueType.cs",
    "content": "using System;\nusing System.IO;\nusing System.Text;\nusing System.Text.Json;\nusing Bencodex;\nusing Bencodex.Types;\nusing GraphQL.Types;\nusing Libplanet.Common;\n\nnamespace Libplanet.Explorer.GraphTypes\n{\n    public class IValueType : ObjectGraphType<IValue>\n    {\n        private static Codec _codec = new Codec();\n\n        public IValueType()\n        {\n            Name = \"IValue\";\n\n            Field<NonNullGraphType<StringGraphType>>(\n                name: \"hex\",\n                description:\n                    \"A hexadecimal representation of the bencodex value encoded as byte array.\",\n                resolve: context => ByteUtil.Hex(_codec.Encode(context.Source))\n            );\n\n            Field<NonNullGraphType<StringGraphType>>(\n                name: \"base64\",\n                description:\n                    \"A base64 representation of the bencodex value encoded to byte array.\",\n                resolve: context => Convert.ToBase64String(_codec.Encode(context.Source))\n            );\n\n            Field<NonNullGraphType<StringGraphType>>(\n                name: \"inspection\",\n                description: \"A human readable representation of the bencodex value.\",\n                resolve: context => context.Source.Inspect()\n            );\n\n            Field<NonNullGraphType<StringGraphType>>(\n                name: \"json\",\n                description: \"A JSON representation of the bencodex value\",\n                resolve: context =>\n                {\n                    var converter = new Bencodex.Json.BencodexJsonConverter();\n                    var buffer = new MemoryStream();\n                    var writer = new Utf8JsonWriter(buffer);\n                    converter.Write(writer, context.Source, new JsonSerializerOptions());\n                    return Encoding.UTF8.GetString(buffer.ToArray());\n                }\n            );\n        }\n    }\n}\n"
  },
  {
    "path": "tools/Libplanet.Explorer/GraphTypes/KeyBytesType.cs",
    "content": "using GraphQL.Language.AST;\nusing GraphQL.Types;\nusing Libplanet.Common;\nusing Libplanet.Store.Trie;\n\nnamespace Libplanet.Explorer.GraphTypes\n{\n    public class KeyBytesType : StringGraphType\n    {\n        public KeyBytesType()\n        {\n            Name = \"KeyBytes\";\n        }\n\n        public override object? ParseLiteral(IValue value)\n        {\n            if (value is StringValue stringValue)\n            {\n                return ParseValue(stringValue.Value);\n            }\n\n            if (value is NullValue)\n            {\n                return null;\n            }\n\n            return ThrowLiteralConversionError(value);\n        }\n\n        public override object? ParseValue(object? value)\n        {\n            if (value is null)\n            {\n                return null;\n            }\n\n            if (value is string str)\n            {\n                return new KeyBytes(ByteUtil.ParseHex(str));\n            }\n\n            return ThrowValueConversionError(value);\n        }\n\n        public override object? Serialize(object? value)\n        {\n            if (value is null)\n            {\n                return null;\n            }\n\n            if (value is KeyBytes keyBytes)\n            {\n                return ByteUtil.Hex(keyBytes.ByteArray);\n            }\n\n            return ThrowSerializationError(value);\n        }\n    }\n}\n"
  },
  {
    "path": "tools/Libplanet.Explorer/GraphTypes/NodeStateType.cs",
    "content": "using System.Collections.Generic;\nusing GraphQL.Types;\nusing Libplanet.Explorer.Interfaces;\nusing Libplanet.Net;\n\nnamespace Libplanet.Explorer.GraphTypes\n{\n    public class NodeStateType : ObjectGraphType<IBlockChainContext>\n    {\n        public NodeStateType()\n        {\n            Name = \"NodeState\";\n\n            Field<NonNullGraphType<BoundPeerType>>(\n                name: \"self\",\n                resolve: context => context.Source.Swarm.AsPeer\n            );\n            Field<NonNullGraphType<BooleanGraphType>>(\n                name: \"preloaded\",\n                resolve: context => context.Source.Preloaded\n            );\n            Field<NonNullGraphType<ListGraphType<NonNullGraphType<BoundPeerType>>>>(\n                name: \"peers\",\n                resolve: context => context.Source.Swarm?.Peers ?? new List<BoundPeer>()\n            );\n            Field<NonNullGraphType<ListGraphType<NonNullGraphType<BoundPeerType>>>>(\n                name: \"validators\",\n                resolve: context => context.Source.Swarm?.Validators ?? new List<BoundPeer>()\n            );\n        }\n    }\n}\n"
  },
  {
    "path": "tools/Libplanet.Explorer/GraphTypes/PublicKeyType.cs",
    "content": "using GraphQL.Language.AST;\nusing GraphQL.Types;\nusing Libplanet.Common;\nusing Libplanet.Crypto;\n\nnamespace Libplanet.Explorer.GraphTypes\n{\n    public class PublicKeyType : StringGraphType\n    {\n        public PublicKeyType()\n        {\n            Name = \"PublicKey\";\n        }\n\n        public override object? ParseLiteral(IValue value)\n        {\n            if (value is StringValue stringValue)\n            {\n                return ParseValue(stringValue.Value);\n            }\n\n            if (value is NullValue)\n            {\n                return null;\n            }\n\n            return ThrowLiteralConversionError(value);\n        }\n\n        public override object? ParseValue(object? value)\n        {\n            if (value is null)\n            {\n                return null;\n            }\n\n            if (value is string str)\n            {\n                // NOTE: Compressed and uncompressed should both be allowed.\n                return new PublicKey(ByteUtil.ParseHex(str));\n            }\n\n            return ThrowValueConversionError(value);\n        }\n\n        public override object? Serialize(object? value)\n        {\n            if (value is null)\n            {\n                return null;\n            }\n\n            if (value is PublicKey publicKey)\n            {\n                // NOTE: Compressed format is preferred as output.\n                return publicKey.ToString();\n            }\n\n            return ThrowSerializationError(value);\n        }\n    }\n}\n"
  },
  {
    "path": "tools/Libplanet.Explorer/GraphTypes/TransactionType.cs",
    "content": "using System;\nusing GraphQL;\nusing GraphQL.Types;\nusing Libplanet.Explorer.Indexing;\nusing Libplanet.Explorer.Interfaces;\nusing Libplanet.Types.Tx;\n\nnamespace Libplanet.Explorer.GraphTypes\n{\n    public class TransactionType : ObjectGraphType<Transaction>\n    {\n        public TransactionType(IBlockChainContext context)\n        {\n            Name = \"Transaction\";\n\n            Field<NonNullGraphType<IdGraphType>>(\n                name: \"Id\",\n                description: \"A unique identifier derived from this transaction content.\",\n                resolve: ctx => ctx.Source.Id.ToString()\n            );\n            Field<NonNullGraphType<LongGraphType>>(\n                name: \"Nonce\",\n                description: \"The number of previous transactions committed by the signer of \" +\n                    \"this tx.\",\n                resolve: x => x.Source.Nonce\n            );\n            Field(\n                type: typeof(NonNullGraphType<AddressType>),\n                name: \"Signer\",\n                description: \"An address of the account who signed this transaction.\",\n                resolve: x => x.Source.Signer\n            );\n            Field<NonNullGraphType<ByteStringType>>(\n                name: \"PublicKey\",\n                description: \"A PublicKey of the account who signed this transaction.\",\n                resolve: ctx => ctx.Source.PublicKey.Format(true)\n            );\n            Field<NonNullGraphType<ListGraphType<NonNullGraphType<AddressType>>>>(\n                name: \"UpdatedAddresses\",\n                description: \"Addresses whose states were affected by Actions.\",\n                resolve: x => x.Source.UpdatedAddresses\n            );\n            Field<NonNullGraphType<ByteStringType>>(\n                name: \"Signature\",\n                description: \"A digital signature of the content of this transaction.\",\n                resolve: x => x.Source.Signature\n            );\n            Field<NonNullGraphType<DateTimeOffsetGraphType>>(\n                name: \"Timestamp\",\n                description: \"The time this transaction was created and signed.\",\n                resolve: x => x.Source.Timestamp\n            );\n            Field<NonNullGraphType<ListGraphType<NonNullGraphType<ActionType>>>>(\n                name: \"Actions\",\n                description: \"A list of actions in this transaction.\"\n            );\n            Field<NonNullGraphType<StringGraphType>>(\n                name: \"SerializedPayload\",\n                description: \"A serialized tx payload in base64 string.\",\n                resolve: x =>\n                {\n                    byte[] bytes = x.Source.Serialize();\n                    return Convert.ToBase64String(bytes);\n                });\n\n            // The block including the transaction, only available when IBlockChainIndex is\n            // provided.\n            Field<NonNullGraphType<BlockType>>(\n                name: \"BlockRef\",\n                description: \"The block including the transaction.\",\n                resolve: ctx =>\n                {\n                    if (context is { Index: { } index, BlockChain: { } chain })\n                    {\n                        return chain[index.GetContainedBlockHashByTxId(ctx.Source.Id)];\n                    }\n\n                    var exceptionMessage =\n                        \"To resolve the field 'BlockRef', an instance of\"\n                        + $\" {nameof(IBlockChainIndex)} must be provided to the\"\n                        + $\" {nameof(IBlockChainContext)}.\";\n                    ctx.Errors.Add(new ExecutionError(exceptionMessage));\n                    return null;\n                });\n        }\n    }\n}\n"
  },
  {
    "path": "tools/Libplanet.Explorer/GraphTypes/TrieType.cs",
    "content": "using System.Linq;\nusing GraphQL;\nusing GraphQL.Types;\nusing Libplanet.Store.Trie;\n\nnamespace Libplanet.Explorer.GraphTypes\n{\n    public class TrieType : ObjectGraphType<ITrie>\n    {\n        public TrieType()\n        {\n            Name = \"Trie\";\n\n            Field<IValueType>(\n                name: \"value\",\n                description: \"Gets the value stored at given key.\",\n                arguments: new QueryArguments(\n                    new QueryArgument<NonNullGraphType<KeyBytesType>>\n                    {\n                        Name = \"key\",\n                        Description = \"The key to search.\",\n                    }\n                ),\n                resolve: context => context.Source.Get(context.GetArgument<KeyBytes>(\"key\"))\n            );\n\n            Field<IValueType>(\n                name: \"values\",\n                description: \"Gets the values stored at given multiple keys.\",\n                arguments: new QueryArguments(\n                    new QueryArgument<\n                        NonNullGraphType<ListGraphType<NonNullGraphType<KeyBytesType>>>>\n                    {\n                        Name = \"keys\",\n                        Description = \"The list of keys to search.\",\n                    }\n                ),\n                resolve: context => context\n                    .GetArgument<KeyBytes[]>(\"keys\")\n                    .Select(key => context.Source.Get(key))\n                    .ToArray()\n            );\n        }\n    }\n}\n"
  },
  {
    "path": "tools/Libplanet.Explorer/GraphTypes/TxIdType.cs",
    "content": "using GraphQL.Language.AST;\nusing GraphQL.Types;\nusing Libplanet.Common;\nusing Libplanet.Types.Tx;\n\nnamespace Libplanet.Explorer.GraphTypes\n{\n    public class TxIdType : StringGraphType\n    {\n        public TxIdType()\n        {\n            Name = \"TxId\";\n        }\n\n        public override object? ParseLiteral(IValue value)\n        {\n            if (value is StringValue stringValue)\n            {\n                return ParseValue(stringValue.Value);\n            }\n\n            if (value is NullValue)\n            {\n                return null;\n            }\n\n            return ThrowLiteralConversionError(value);\n        }\n\n        public override object? ParseValue(object? value)\n        {\n            if (value is null)\n            {\n                return null;\n            }\n\n            if (value is string str)\n            {\n                return new TxId(ByteUtil.ParseHex(str));\n            }\n\n            return ThrowValueConversionError(value);\n        }\n\n        public override object? Serialize(object? value)\n        {\n            if (value is null)\n            {\n                return null;\n            }\n\n            if (value is TxId txId)\n            {\n                return ByteUtil.Hex(txId.ByteArray);\n            }\n\n            return ThrowSerializationError(value);\n        }\n    }\n}\n"
  },
  {
    "path": "tools/Libplanet.Explorer/GraphTypes/TxResult.cs",
    "content": "using System.Collections.Generic;\nusing System.Security.Cryptography;\nusing Libplanet.Common;\n\nnamespace Libplanet.Explorer.GraphTypes\n{\n    public class TxResult\n    {\n        public TxResult(\n            TxStatus status,\n            long? blockIndex,\n            string? blockHash,\n            HashDigest<SHA256>? inputState,\n            HashDigest<SHA256>? outputState,\n            List<string?>? exceptionNames)\n        {\n            TxStatus = status;\n            BlockIndex = blockIndex;\n            BlockHash = blockHash;\n            InputState = inputState;\n            OutputState = outputState;\n            ExceptionNames = exceptionNames;\n        }\n\n        public TxStatus TxStatus { get; private set; }\n\n        public long? BlockIndex { get; private set; }\n\n        public string? BlockHash { get; private set; }\n\n        public HashDigest<SHA256>? InputState { get; private set; }\n\n        public HashDigest<SHA256>? OutputState { get; private set; }\n\n        public List<string?>? ExceptionNames { get; private set; }\n    }\n}\n"
  },
  {
    "path": "tools/Libplanet.Explorer/GraphTypes/TxResultType.cs",
    "content": "using System.Security.Cryptography;\nusing GraphQL.Types;\n\nnamespace Libplanet.Explorer.GraphTypes\n{\n    public class TxResultType : ObjectGraphType<TxResult>\n    {\n        public TxResultType()\n        {\n            Field<NonNullGraphType<TxStatusType>>(\n                nameof(TxResult.TxStatus),\n                description: \"The transaction status.\",\n                resolve: context => context.Source.TxStatus\n            );\n\n            Field<LongGraphType>(\n                nameof(TxResult.BlockIndex),\n                description: \"The block index which the target transaction executed.\",\n                resolve: context => context.Source.BlockIndex\n            );\n\n            Field<StringGraphType>(\n                nameof(TxResult.BlockHash),\n                description: \"The block hash which the target transaction executed.\",\n                resolve: context => context.Source.BlockHash\n            );\n\n            Field<HashDigestSHA256Type>(\n                nameof(TxResult.InputState),\n                description: \"The input state's root hash \" +\n                \"which the target transaction executed.\",\n                resolve: context => context.Source.InputState\n            );\n\n            Field<HashDigestSHA256Type>(\n                nameof(TxResult.OutputState),\n                description: \"The output state's root hash \" +\n                \"which the target transaction executed.\",\n                resolve: context => context.Source.OutputState\n            );\n\n            Field<ListGraphType<StringGraphType>>(\n                nameof(TxResult.ExceptionNames),\n                description: \"The name of exception. (when only failed)\",\n                resolve: context => context.Source.ExceptionNames\n            );\n        }\n    }\n}\n"
  },
  {
    "path": "tools/Libplanet.Explorer/GraphTypes/TxStatusType.cs",
    "content": "using GraphQL.Types;\nusing Libplanet.Action;\nusing Libplanet.Blockchain;\nusing Libplanet.Types.Tx;\n\nnamespace Libplanet.Explorer.GraphTypes\n{\n    public enum TxStatus\n    {\n        /// <summary>\n        /// The Transaction doesn't staged or invalid.\n        /// </summary>\n        INVALID,\n\n        /// <summary>\n        /// The Transaction is currently staged.\n        /// </summary>\n        STAGING,\n\n        /// <summary>\n        /// The <see cref=\"Transaction\"/> was successfully executed.\n        /// Specifically, this means that there is a record of the execution of\n        /// said <see cref=\"Transaction\"/> that can be found that indicates its execution\n        /// was success.  In particular, for this to be the case, the <see cref=\"Transaction\"/>\n        /// must have included one or more <see cref=\"IAction\"/>s and the execution of\n        /// every <see cref=\"IAction\"/> was successful.\n        /// </summary>\n        SUCCESS,\n\n        /// <summary>\n        /// The <see cref=\"Transaction\"/> failed to execute without an error.\n        /// Specifically, this means that there is a record of the execution of\n        /// said <see cref=\"Transaction\"/> that can be found that indicates its execution\n        /// was a failure.  In particular, for this to be the case, the <see cref=\"Transaction\"/>\n        /// must have included one or more <see cref=\"IAction\"/>s and an execution of\n        /// of at least one <see cref=\"IAction\"/> was a failure.\n        /// </summary>\n        FAILURE,\n\n        /// <summary>\n        /// The <see cref=\"Transaction\"/> is found in the <see cref=\"BlockChain\"/> but its\n        /// execution result cannot be determined.  This can happen due to one of\n        /// the two following reasons:\n        /// <list type=\"bullet\">\n        ///     <item><description>\n        ///         The <see cref=\"Transaction\"/> is an empty <see cref=\"Transaction\"/>\n        ///         that does not contain any <see cref=\"IAction\"/>s.\n        ///     </description></item>\n        ///     <item><description>\n        ///         The execution record of <see cref=\"Transaction\"/> is simply missing for\n        ///         some other reason.\n        ///     </description></item>\n        /// </list>\n        /// </summary>\n        INCLUDED,\n    }\n\n    public class TxStatusType : EnumerationGraphType<TxStatus>\n    {\n    }\n}\n"
  },
  {
    "path": "tools/Libplanet.Explorer/GraphTypes/ValidatorType.cs",
    "content": "using GraphQL.Types;\nusing Libplanet.Types.Consensus;\n\nnamespace Libplanet.Explorer.GraphTypes;\n\npublic class ValidatorType : ObjectGraphType<Validator>\n{\n    public ValidatorType()\n    {\n        Name = \"Validator\";\n        Description = \"A data type holds validator's public key and its voting power.\";\n\n        Field<NonNullGraphType<PublicKeyType>>(\n            \"publicKey\",\n            \"The public key of the validator.\",\n            resolve: ctx => ctx.Source.PublicKey\n        );\n        Field<NonNullGraphType<BigIntGraphType>>(\n            \"power\",\n            \"Gets the voting power of the validator.\",\n            resolve: ctx => ctx.Source.Power\n        );\n    }\n}\n"
  },
  {
    "path": "tools/Libplanet.Explorer/GraphTypes/VoteFlagType.cs",
    "content": "using System;\nusing GraphQL.Language.AST;\nusing GraphQL.Types;\nusing Libplanet.Types.Consensus;\n\nnamespace Libplanet.Explorer.GraphTypes\n{\n    public class VoteFlagType : StringGraphType\n    {\n        public VoteFlagType()\n        {\n            Name = \"VoteFlag\";\n        }\n\n        public override object? Serialize(object? value)\n        {\n            if (value is VoteFlag flag)\n            {\n                switch (flag)\n                {\n                    case VoteFlag.Null:\n                        return \"Null\";\n                    case VoteFlag.PreVote:\n                        return \"PreVote\";\n                    case VoteFlag.PreCommit:\n                        return \"PreCommit\";\n                    case VoteFlag.Unknown:\n                        return \"Unknown\";\n                }\n            }\n\n            throw new ArgumentException($\"Expected a voteflag, but {value}\", nameof(value));\n        }\n\n        public override object? ParseValue(object? value)\n        {\n            if (value is string flag)\n            {\n                switch (flag)\n                {\n                    case \"Null\":\n                        return VoteFlag.Null;\n                    case \"PreVote\":\n                        return VoteFlag.PreVote;\n                    case \"PreCommit\":\n                        return VoteFlag.PreCommit;\n                    case \"Unknown\":\n                        return VoteFlag.Unknown;\n                }\n            }\n            else if (value is null)\n            {\n                return null;\n            }\n\n            throw new ArgumentException(\n                $\"Expected a voteflag string but {value}\", nameof(value));\n        }\n\n        public override object? ParseLiteral(IValue value)\n        {\n            if (value is StringValue)\n            {\n                return ParseValue(value.Value);\n            }\n\n            return null;\n        }\n    }\n}\n"
  },
  {
    "path": "tools/Libplanet.Explorer/GraphTypes/VoteType.cs",
    "content": "using System.Linq;\nusing GraphQL.Types;\nusing Libplanet.Types.Consensus;\n\nnamespace Libplanet.Explorer.GraphTypes\n{\n    public class VoteType : ObjectGraphType<Vote>\n    {\n        public VoteType()\n        {\n            Name = \"Vote\";\n\n            Field<NonNullGraphType<LongGraphType>>(\n                \"Height\",\n                description: \"Height of the consensus voted.\",\n                resolve: ctx => ctx.Source.Height);\n            Field<NonNullGraphType<IntGraphType>>(\n                \"Round\",\n                description: \"Round of the consensus voted.\",\n                resolve: ctx => ctx.Source.Round);\n            Field<NonNullGraphType<StringGraphType>>(\n                \"BlockHash\",\n                description: \"Hash of the block voted.\",\n                resolve: ctx => ctx.Source.BlockHash.ToString());\n            Field<NonNullGraphType<DateTimeOffsetGraphType>>(\n                name: \"timestamp\",\n                description: \"The time this vote was created and signed.\",\n                resolve: ctx => ctx.Source.Timestamp);\n            Field<NonNullGraphType<PublicKeyType>>(\n                \"ValidatorPublicKey\",\n                description: \"Public key of the validator which is subject of the vote.\",\n                resolve: ctx => ctx.Source.ValidatorPublicKey);\n            Field<StringGraphType>(\n                \"ValidatorPower\",\n                description: \"Power of the validator which is subject of the vote.\",\n                resolve: ctx => ctx.Source.ValidatorPower?.ToString());\n            Field<NonNullGraphType<VoteFlagType>>(\n                \"Flag\",\n                description: \"Flag of the vote\",\n                resolve: ctx => ctx.Source.Flag);\n            Field<NonNullGraphType<ByteStringType>>(\n                name: \"Signature\",\n                description: \"A digital signature of the content of this vote.\",\n                resolve: ctx => ctx.Source.Signature.ToArray());\n        }\n    }\n}\n"
  },
  {
    "path": "tools/Libplanet.Explorer/GraphTypes/WorldStateType.cs",
    "content": "using System.Linq;\nusing System.Security.Cryptography;\nusing GraphQL;\nusing GraphQL.Types;\nusing Libplanet.Action.State;\nusing Libplanet.Crypto;\nusing Libplanet.Types.Assets;\n\nnamespace Libplanet.Explorer.GraphTypes\n{\n    public class WorldStateType : ObjectGraphType<IWorldState>\n    {\n        public WorldStateType()\n        {\n            Name = \"WorldState\";\n\n            Field<NonNullGraphType<HashDigestType<SHA256>>>(\n                name: \"stateRootHash\",\n                description: \"The state root hash of the world state.\",\n                resolve: context => context.Source.Trie.Hash\n            );\n\n            Field<NonNullGraphType<BooleanGraphType>>(\n                name: \"legacy\",\n                description: \"The legacy flag of the world state.\",\n                resolve: context => context.Source.Legacy\n            );\n\n            Field<NonNullGraphType<IntGraphType>>(\n                name: \"version\",\n                description: \"The version of the bakcing data model.\",\n                resolve: context => context.Source.Version\n            );\n\n            Field<NonNullGraphType<AccountStateType>>(\n                name: \"account\",\n                description:\n                    \"Gets the account associated with given address.\",\n                arguments: new QueryArguments(\n                    new QueryArgument<NonNullGraphType<AddressType>>\n                    {\n                        Name = \"address\",\n                        Description = \"The address of an account to retrieve.\",\n                    }\n                ),\n                resolve: context =>\n                    context.Source.GetAccountState(context.GetArgument<Address>(\"address\"))\n            );\n\n            Field<NonNullGraphType<ListGraphType<NonNullGraphType<AccountStateType>>>>(\n                name: \"accounts\",\n                description:\n                    \"Gets the accounts associated with given addresses.\",\n                arguments: new QueryArguments(\n                    new QueryArgument<\n                        NonNullGraphType<ListGraphType<NonNullGraphType<AddressType>>>>\n                    {\n                        Name = \"addresses\",\n                        Description = \"The list of addresses of accounts to retrieve.\",\n                    }\n                ),\n                resolve: context => context\n                    .GetArgument<Address[]>(\"addresses\")\n                    .Select(address => context.Source.GetAccountState(address))\n                    .ToArray()\n            );\n\n            Field<NonNullGraphType<FungibleAssetValueType>>(\n                name: \"balance\",\n                description: \"Balance at given address and currency pair.\",\n                arguments: new QueryArguments(\n                    new QueryArgument<NonNullGraphType<CurrencyInputType>>\n                    {\n                        Name = \"currency\",\n                        Description = \"The currency to look up.\",\n                    },\n                    new QueryArgument<NonNullGraphType<AddressType>>\n                    {\n                        Name = \"address\",\n                        Description = \"The address to look up.\",\n                    }\n                ),\n                resolve: context => context.Source.GetBalance(\n                    context.GetArgument<Address>(\"address\"),\n                    context.GetArgument<Currency>(\"currency\"))\n            );\n\n            Field<NonNullGraphType<FungibleAssetValueType>>(\n                name: \"totalSupply\",\n                description: \"Total supply in circulation for given currency.\",\n                arguments: new QueryArguments(\n                    new QueryArgument<NonNullGraphType<CurrencyInputType>>\n                    {\n                        Name = \"currency\",\n                        Description = \"The currency to look up.\",\n                    }\n                ),\n                resolve: context =>\n                    context.Source.GetTotalSupply(context.GetArgument<Currency>(\"currency\"))\n            );\n\n            Field<NonNullGraphType<IValueType>>(\n                name: \"validatorSet\",\n                description: \"The validator set.\",\n                resolve: context => context.Source.GetValidatorSet().Bencoded\n            );\n        }\n    }\n}\n"
  },
  {
    "path": "tools/Libplanet.Explorer/Indexing/BlockChainIndexBase.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing Libplanet.Crypto;\nusing Libplanet.Store;\nusing Libplanet.Types.Blocks;\nusing Libplanet.Types.Tx;\nusing Serilog;\n\nnamespace Libplanet.Explorer.Indexing;\n\n/// <summary>\n/// A base implementation of <see cref=\"IBlockChainIndex\"/>.\n/// </summary>\npublic abstract class BlockChainIndexBase : IBlockChainIndex\n{\n    private ILogger? _logger;\n\n    private ILogger? _defaultLogger;\n\n    /// <inheritdoc />\n    public (long Index, BlockHash Hash) Tip\n        => GetTipImpl() ?? throw new IndexOutOfRangeException(\"The index is empty.\");\n\n    protected ILogger Logger\n    {\n        get\n        {\n            _defaultLogger ??= Log\n                .ForContext<IBlockChainIndex>()\n                .ForContext(\"Source\", GetType().Name);\n            return _logger ?? _defaultLogger;\n        }\n        set => _logger = _logger is null ? value : throw new InvalidOperationException(\n            \"The logger is already set.\");\n    }\n\n    /// <inheritdoc />\n    public async Task<(long Index, BlockHash Hash)> GetTipAsync() =>\n        await GetTipAsyncImpl().ConfigureAwait(false)\n        ?? throw new IndexOutOfRangeException(\"The index is empty.\");\n\n    /// <inheritdoc />\n    public abstract long BlockHashToIndex(BlockHash hash);\n\n    /// <inheritdoc />\n    public abstract Task<long> BlockHashToIndexAsync(BlockHash hash);\n\n    /// <inheritdoc />\n    public abstract BlockHash IndexToBlockHash(long index);\n\n    /// <inheritdoc />\n    public abstract Task<BlockHash> IndexToBlockHashAsync(long index);\n\n    /// <inheritdoc />\n    public IEnumerable<(long Index, BlockHash Hash)>\n        GetBlockHashesByRange(Range indexRange, bool desc, Address? producer)\n    {\n        var (fromHeight, maxCount) =\n            indexRange.GetOffsetAndLength((int)(Tip.Index + 1 & int.MaxValue));\n        return GetBlockHashesFromIndex(fromHeight, maxCount, desc, producer);\n    }\n\n    /// <inheritdoc />\n    public async IAsyncEnumerable<(long Index, BlockHash Hash)>\n        GetBlockHashesByRangeAsync(Range indexRange, bool desc, Address? producer)\n    {\n        var (fromHeight, maxCount) =\n            indexRange.GetOffsetAndLength((int)(Tip.Index + 1 & int.MaxValue));\n        await foreach (\n            var item in GetBlockHashesFromIndexAsync(fromHeight, maxCount, desc, producer)\n                .ConfigureAwait(false))\n        {\n            yield return item;\n        }\n    }\n\n    /// <inheritdoc />\n    public abstract IEnumerable<(long Index, BlockHash Hash)>\n        GetBlockHashesFromIndex(int? fromHeight, int? maxCount, bool desc, Address? producer);\n\n    /// <inheritdoc />\n    public abstract IAsyncEnumerable<(long Index, BlockHash Hash)>\n        GetBlockHashesFromIndexAsync(int? fromHeight, int? maxCount, bool desc, Address? producer);\n\n    /// <inheritdoc />\n    public abstract IEnumerable<TxId>\n        GetSignedTxIdsByAddress(Address signer, int? fromNonce, int? maxCount, bool desc);\n\n    /// <inheritdoc />\n    public abstract IAsyncEnumerable<TxId>\n        GetSignedTxIdsByAddressAsync(Address signer, int? fromNonce, int? maxCount, bool desc);\n\n    /// <inheritdoc />\n    public abstract long? GetLastNonceByAddress(Address address);\n\n    /// <inheritdoc />\n    public abstract Task<long?> GetLastNonceByAddressAsync(Address address);\n\n    /// <inheritdoc />\n    public BlockHash GetContainedBlockHashByTxId(TxId txId) =>\n        TryGetContainedBlockHashById(txId, out var containedBlock)\n            ? containedBlock\n            : throw new IndexOutOfRangeException(\n                $\"The txId {txId} does not exist in the index.\");\n\n    /// <inheritdoc />\n    public async Task<BlockHash> GetContainedBlockHashByTxIdAsync(TxId txId) =>\n        await TryGetContainedBlockHashByIdAsync(txId).ConfigureAwait(false)\n        ?? throw new IndexOutOfRangeException(\n            $\"The txId {txId} does not exist in the index.\");\n\n    /// <inheritdoc />\n    public abstract bool TryGetContainedBlockHashById(TxId txId, out BlockHash containedBlock);\n\n    /// <inheritdoc />\n    public abstract Task<BlockHash?> TryGetContainedBlockHashByIdAsync(TxId txId);\n\n    /// <inheritdoc />\n    async Task IBlockChainIndex.IndexAsync(\n        BlockDigest blockDigest, IEnumerable<ITransaction> txs, CancellationToken stoppingToken) =>\n        await IndexAsyncImpl(blockDigest, txs, null, stoppingToken).ConfigureAwait(false);\n\n    async Task IBlockChainIndex.SynchronizeForeverAsync(\n        IStore store, TimeSpan pollInterval, CancellationToken stoppingToken)\n    {\n        var syncMetadata = await GetSyncMetadata(store).ConfigureAwait(false);\n        await CheckIntegrity(store, syncMetadata).ConfigureAwait(false);\n        while (true)\n        {\n            await SynchronizeAsyncImpl(store, syncMetadata, false, stoppingToken)\n                .ConfigureAwait(false);\n            await Task.Delay(pollInterval, stoppingToken).ConfigureAwait(false);\n        }\n    }\n\n    async Task IBlockChainIndex.SynchronizeAsync(IStore store, CancellationToken stoppingToken)\n    {\n        var syncMetadata = await GetSyncMetadata(store).ConfigureAwait(false);\n        await CheckIntegrity(store, syncMetadata).ConfigureAwait(false);\n        await SynchronizeAsyncImpl(store, syncMetadata, true, stoppingToken)\n            .ConfigureAwait(false);\n    }\n\n    protected abstract (long Index, BlockHash Hash)? GetTipImpl();\n\n    protected abstract Task<(long Index, BlockHash Hash)?> GetTipAsyncImpl();\n\n    protected abstract Task IndexAsyncImpl(\n        BlockDigest blockDigest,\n        IEnumerable<ITransaction> txs,\n        IIndexingContext? context,\n        CancellationToken token);\n\n    /// <summary>\n    /// Get a context that can be consumed by <see cref=\"IBlockChainIndex.IndexAsync\"/> and\n    /// <see cref=\"IBlockChainIndex.IndexAsync\"/> for batch processing.\n    /// </summary>\n    /// <returns>A context that can be consumed by <see cref=\"IBlockChainIndex.IndexAsync\"/>.\n    /// </returns>\n    protected abstract IIndexingContext GetIndexingContext();\n\n    /// <summary>\n    /// Commits the data gathered in the context gained from <see cref=\"GetIndexingContext\"/>.\n    /// </summary>\n    /// <param name=\"context\">A context gained from <see cref=\"GetIndexingContext\"/>.</param>\n    protected abstract void CommitIndexingContext(IIndexingContext context);\n\n    /// <inheritdoc cref=\"CommitIndexingContext\"/>\n    protected abstract Task CommitIndexingContextAsync(IIndexingContext context);\n\n    private static string FormatSeconds(int seconds)\n    {\n        var minutes = seconds / 60;\n        seconds %= 60;\n        var hours = minutes / 60;\n        minutes %= 60;\n        return hours > 0\n            ? $\"{hours}h{minutes}m{seconds}s\"\n            : minutes > 0\n                ? $\"{minutes}m{seconds}s\"\n                : $\"{seconds}s\";\n    }\n\n    private async Task CheckIntegrity(\n        IStore store,\n        (\n            Guid ChainId,\n            long IndexTipIndex,\n            long ChainTipIndex,\n            BlockHash? IndexTipHash) syncMetadata)\n    {\n        var chainId = syncMetadata.ChainId;\n        var indexTipIndex = syncMetadata.IndexTipIndex;\n        var chainTipIndex = syncMetadata.ChainTipIndex;\n        var indexTipHash = syncMetadata.IndexTipHash;\n        if (indexTipIndex >= 0)\n        {\n            var indexHash = await IndexToBlockHashAsync(0).ConfigureAwait(false);\n            using var chainIndexEnumerator =\n                store.IterateIndexes(chainId, limit: 1).GetEnumerator();\n            if (!chainIndexEnumerator.MoveNext())\n            {\n                throw new InvalidOperationException(\n                    \"The store does not contain a valid genesis block.\");\n            }\n\n            var chainHash = chainIndexEnumerator.Current;\n            if (!indexHash.Equals(chainHash))\n            {\n                throw new IndexMismatchException(0, indexHash, chainHash);\n            }\n        }\n\n        if (indexTipIndex >= 1)\n        {\n            var commonLatestIndex = Math.Min(indexTipIndex, chainTipIndex);\n            using var chainIndexEnumerator =\n                store.IterateIndexes(chainId, (int)commonLatestIndex, limit: 1).GetEnumerator();\n            BlockHash? chainTipHash = chainIndexEnumerator.MoveNext()\n                ? chainIndexEnumerator.Current\n                : null;\n            if (chainTipHash is not { } chainTipHashValue\n                || !indexTipHash!.Value.Equals(chainTipHashValue))\n            {\n                throw new IndexMismatchException(\n                    indexTipIndex, indexTipHash!.Value, chainTipHash);\n            }\n        }\n\n        if (indexTipIndex > chainTipIndex)\n        {\n            Logger.Information(\n                \"The height of the index is higher than the height of the blockchain. The index\"\n                + \" will continue to be synchronized, but if a block of an existing height and a\"\n                + $\" different hash is encountered, an {nameof(IndexMismatchException)} will be\"\n                + \" raised.\");\n        }\n    }\n\n    private async Task SynchronizeAsyncImpl(\n        IStore store,\n        (\n            Guid ChainId,\n            long IndexTipIndex,\n            long ChainTipIndex,\n            BlockHash? IndexTipHash) syncMetadata,\n        bool log,\n        CancellationToken stoppingToken\n    )\n    {\n        var chainId = syncMetadata.ChainId;\n        var indexTipIndex = syncMetadata.IndexTipIndex;\n        var chainTipIndex = syncMetadata.ChainTipIndex;\n\n        if (indexTipIndex > chainTipIndex)\n        {\n            return;\n        }\n\n        if (indexTipIndex == chainTipIndex)\n        {\n            if (log)\n            {\n                Logger.Information(\"Index is up to date.\");\n            }\n\n            return;\n        }\n\n        if (log)\n        {\n            Logger.Information(\"Index is out of date. Synchronizing...\");\n        }\n\n        long processedBlockCount = 0,\n            totalBlocksToSync = chainTipIndex - indexTipIndex,\n            intervalBlockCount = 0,\n            intervalTxCount = 0;\n        var populateStart = DateTimeOffset.Now;\n        var intervalStart = populateStart;\n\n        using var indexEnumerator =\n            store.IterateIndexes(chainId, (int)indexTipIndex + 1).GetEnumerator();\n        var addBlockContext = GetIndexingContext();\n        while (indexEnumerator.MoveNext() && indexTipIndex + processedBlockCount < chainTipIndex)\n        {\n            if (stoppingToken.IsCancellationRequested)\n            {\n                if (log)\n                {\n                    Logger.Information(\"Index synchronization interrupted.\");\n                }\n\n                break;\n            }\n\n            var blockDigest = store.GetBlockDigest(indexEnumerator.Current)!.Value;\n            ITransaction[] txs = blockDigest.TxIds\n                .Select(txId => store.GetTransaction(new TxId(txId))\n                    ?? throw new InvalidOperationException(\n                        $\"Could not find transaction with txid {txId} in store.\"))\n                .ToArray();\n            try\n            {\n                await IndexAsyncImpl(blockDigest, txs, addBlockContext, stoppingToken)\n                    .ConfigureAwait(false);\n            }\n            catch (OperationCanceledException)\n            {\n                break;\n            }\n\n            intervalTxCount += txs.Length;\n            ++processedBlockCount;\n            ++intervalBlockCount;\n\n            var now = DateTimeOffset.Now;\n            var interval = (now - intervalStart).TotalSeconds;\n            if (interval > 10)\n            {\n                var processedPercentage =\n                    (float)(indexTipIndex + processedBlockCount) / chainTipIndex * 100;\n                var totalElapsedSec = (now - populateStart).TotalSeconds;\n                var currentRate = intervalBlockCount / interval;\n                var totalRate = processedBlockCount / totalElapsedSec;\n                var txRate = intervalTxCount / interval;\n                var elapsedStr = FormatSeconds((int)totalElapsedSec);\n                var eta = FormatSeconds(\n                    (int)TimeSpan.FromSeconds(\n                            (chainTipIndex - indexTipIndex - processedBlockCount) / currentRate)\n                        .TotalSeconds);\n\n                if (log)\n                {\n                    Logger.Information(\n                        $\"Height #{blockDigest.Index} of {chainTipIndex},\"\n                        + $\" {totalBlocksToSync - processedBlockCount} to go\"\n                        + $\" ({processedPercentage:F1}% synced),\"\n                        + $\" session: {processedBlockCount}/{totalBlocksToSync},\"\n                        + $\" current: {(int)currentRate}blk/s, total: {(int)totalRate}blk/s,\"\n                        + $\" txrate: {(int)txRate}tx/s,\"\n                        + $\" tx density: {intervalTxCount / intervalBlockCount}tx/blk,\"\n                        + $\" elapsed: {elapsedStr}, eta: {eta}\");\n                }\n\n                intervalStart = now;\n                intervalBlockCount = 0;\n                intervalTxCount = 0;\n            }\n        }\n\n        await CommitIndexingContextAsync(addBlockContext).ConfigureAwait(false);\n\n        if (log)\n        {\n            Logger.Information(\n                $\"{processedBlockCount} out of {totalBlocksToSync} blocks processed, elapsed:\"\n                + $\" {FormatSeconds((int)(DateTimeOffset.Now - populateStart).TotalSeconds)}\");\n        }\n\n        stoppingToken.ThrowIfCancellationRequested();\n\n        if (totalBlocksToSync == processedBlockCount && log)\n        {\n            Logger.Information(\"Finished synchronizing index.\");\n        }\n    }\n\n    private async Task<(\n        Guid ChainId,\n        long IndexTipIndex,\n        long ChainTipIndex,\n        BlockHash? IndexTipHash)>\n        GetSyncMetadata(IStore store)\n    {\n        var indexTip = await GetTipAsyncImpl().ConfigureAwait(false);\n        var indexTipIndex = indexTip?.Index ?? -1;\n        var chainId = store.GetCanonicalChainId()\n                      ?? throw new InvalidOperationException(\n                          \"The store does not contain a valid chain.\");\n        var chainTipIndex = store.CountIndex(chainId) - 1;\n        return (chainId, indexTipIndex, chainTipIndex, indexTip?.Hash);\n    }\n}\n"
  },
  {
    "path": "tools/Libplanet.Explorer/Indexing/IBlockChainIndex.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing Libplanet.Crypto;\nusing Libplanet.Store;\nusing Libplanet.Types.Blocks;\nusing Libplanet.Types.Tx;\n\nnamespace Libplanet.Explorer.Indexing;\n\n/// <summary>\n/// An interface that provides indexing to Libplanet.Explorer.\n/// </summary>\npublic interface IBlockChainIndex\n{\n    /// <summary>\n    /// The height and the <see cref=\"BlockHash\"/> of the most recently indexed\n    /// <see cref=\"Block\"/>.\n    /// </summary>\n    /// <exception cref=\"IndexOutOfRangeException\">Thrown if the index is empty.</exception>\n    (long Index, BlockHash Hash) Tip { get; }\n\n    /// <inheritdoc cref=\"IndexToBlockHash\"/>\n    BlockHash this[long index] => IndexToBlockHash(index);\n\n    /// <inheritdoc cref=\"GetBlockHashesByRange\"/>\n    IEnumerable<BlockHash> this[Range indexRange] =>\n        GetBlockHashesByRange(indexRange).Select(tuple => tuple.Hash);\n\n    /// <summary>\n    /// Get the height and the <see cref=\"BlockHash\"/> of the most recently indexed\n    /// <see cref=\"Block\"/>.\n    /// </summary>\n    /// <returns>A <see cref=\"ValueTuple{Long,BlockHash}\"/> that contains the height and the\n    /// <see cref=\"BlockHash\"/> of the most recently indexed <see cref=\"Block\"/>.</returns>\n    /// <exception cref=\"IndexOutOfRangeException\">Thrown if the index is empty.</exception>\n    Task<(long Index, BlockHash Hash)> GetTipAsync();\n\n    /// <summary>\n    /// Get the indexed height of the <see cref=\"Block\"/> with the given <paramref name=\"hash\"/>.\n    /// </summary>\n    /// <param name=\"hash\">The <see cref=\"BlockHash\"/> of the desired indexed\n    /// <see cref=\"Block\"/>.</param>\n    /// <returns>The height of the block with the <paramref name=\"hash\"/>.</returns>\n    /// <exception cref=\"IndexOutOfRangeException\">Thrown if the <see cref=\"Block\"/> with the\n    /// given <paramref name=\"hash\"/> is not indexed yet.</exception>\n    long BlockHashToIndex(BlockHash hash);\n\n    /// <inheritdoc cref=\"BlockHashToIndex\"/>\n    Task<long> BlockHashToIndexAsync(BlockHash hash);\n\n    /// <summary>\n    /// Gets the indexed <see cref=\"BlockHash\"/> of the <see cref=\"Block\"/> at\n    /// <paramref name=\"index\"/> height.\n    /// </summary>\n    /// <param name=\"index\">The height of the desired indexed <see cref=\"Block\"/>.</param>\n    /// <returns>The indexed <see cref=\"BlockHash\"/> of the <see cref=\"Block\"/> at\n    /// <paramref name=\"index\"/> height.</returns>\n    /// <exception cref=\"IndexOutOfRangeException\">Thrown if the index does not contain the\n    /// <see cref=\"Block\"/> at the given <paramref name=\"index\"/>.</exception>\n    BlockHash IndexToBlockHash(long index);\n\n    /// <inheritdoc cref=\"IndexToBlockHash\"/>\n    Task<BlockHash> IndexToBlockHashAsync(long index);\n\n    /// <summary>\n    /// Get the height and the <see cref=\"BlockHash\"/> of the indexed <see cref=\"Block\"/>s in the\n    /// given <paramref name=\"indexRange\"/>.\n    /// </summary>\n    /// <param name=\"indexRange\">The range of <see cref=\"Block\"/> height to look up.</param>\n    /// <param name=\"desc\">Whether to look up the index in the descending order.</param>\n    /// <param name=\"producer\">The producer of the block, if filtering by the producer is desired.\n    /// </param>\n    /// <returns>The height and the <see cref=\"BlockHash\"/> of the indexed <see cref=\"Block\"/>s\n    /// in the given <paramref name=\"indexRange\"/>.</returns>\n    /// <exception cref=\"IndexOutOfRangeException\">Thrown if the given range exceeds the block\n    /// count.</exception>\n    IEnumerable<(long Index, BlockHash Hash)> GetBlockHashesByRange(\n        Range indexRange, bool desc = false, Address? producer = null);\n\n    /// <inheritdoc cref=\"GetBlockHashesByRange\"/>\n    IAsyncEnumerable<(long Index, BlockHash Hash)> GetBlockHashesByRangeAsync(\n        Range indexRange, bool desc = false, Address? producer = null);\n\n    /// <summary>\n    /// Get the height and the <see cref=\"BlockHash\"/> of the indexed <see cref=\"Block\"/>s\n    /// starting at <paramref name=\"fromHeight\"/>, at most <paramref name=\"maxCount\"/>.\n    /// </summary>\n    /// <param name=\"fromHeight\">The starting height.</param>\n    /// <param name=\"maxCount\">The upper limit of <see cref=\"Block\"/>s to look up.</param>\n    /// <param name=\"desc\">Whether to look up the index in the descending order.</param>\n    /// <param name=\"producer\">The producer of the block, if filtering by the producer is desired.\n    /// </param>\n    /// <returns>The height and the <see cref=\"BlockHash\"/> of the indexed <see cref=\"Block\"/>s\n    /// starting at <paramref name=\"fromHeight\"/> and at most <paramref name=\"maxCount\"/>.\n    /// </returns>\n    IEnumerable<(long Index, BlockHash Hash)> GetBlockHashesFromIndex(\n        int? fromHeight = null, int? maxCount = null, bool desc = false, Address? producer = null);\n\n    /// <inheritdoc cref=\"GetBlockHashesFromIndex\"/>\n    IAsyncEnumerable<(long Index, BlockHash Hash)> GetBlockHashesFromIndexAsync(\n        int? fromHeight = null, int? maxCount = null, bool desc = false, Address? producer = null);\n\n    /// <summary>\n    /// Get the <see cref=\"TxId\"/> of the indexed <see cref=\"Transaction\"/>s starting at\n    /// <paramref name=\"fromNonce\"/> that was signed by the <paramref name=\"signer\"/>, at most\n    /// <paramref name=\"maxCount\"/>.\n    /// </summary>\n    /// <param name=\"signer\">The signer of the <see cref=\"Transaction\"/>.</param>\n    /// <param name=\"fromNonce\">The tx nonce to start from (inclusive).</param>\n    /// <param name=\"maxCount\">The upper limit of <see cref=\"TxId\"/>s to return.</param>\n    /// <param name=\"desc\">Whether to look up the <see cref=\"TxId\"/>s in the descending order.\n    /// </param>\n    /// <returns>The <see cref=\"TxId\"/> of the indexed <see cref=\"Transaction\"/>s signed by\n    /// the <paramref name=\"signer\"/> starting at <paramref name=\"fromNonce\"/> and at most\n    /// <paramref name=\"maxCount\"/>.</returns>\n    IEnumerable<TxId> GetSignedTxIdsByAddress(\n            Address signer, int? fromNonce = null, int? maxCount = null, bool desc = false);\n\n    /// <inheritdoc cref=\"GetSignedTxIdsByAddress\"/>\n    IAsyncEnumerable<TxId> GetSignedTxIdsByAddressAsync(\n        Address signer, int? fromNonce = null, int? maxCount = null, bool desc = false);\n\n    /// <summary>\n    /// Get the <see cref=\"BlockHash\"/> of the indexed <see cref=\"Block\"/> that contains the\n    /// <see cref=\"Transaction\"/> with the <paramref name=\"txId\"/>.\n    /// </summary>\n    /// <param name=\"txId\">The <see cref=\"TxId\"/> of the <see cref=\"Transaction\"/> to look up the\n    /// containing <see cref=\"Block\"/>.</param>\n    /// <returns>The <see cref=\"BlockHash\"/> of the indexed <see cref=\"Block\"/> that contains the\n    /// <see cref=\"Transaction\"/> with the <paramref name=\"txId\"/>.</returns>\n    /// <exception cref=\"IndexOutOfRangeException\">Thrown if the <paramref name=\"txId\"/> does not\n    /// exist in the index.</exception>\n    BlockHash GetContainedBlockHashByTxId(TxId txId);\n\n    /// <inheritdoc cref=\"GetContainedBlockHashByTxId\"/>\n    Task<BlockHash> GetContainedBlockHashByTxIdAsync(TxId txId);\n\n    /// <summary>\n    /// Attempt to get the <see cref=\"BlockHash\"/> of the indexed block that contains the\n    /// <see cref=\"Transaction\"/> with the <paramref name=\"txId\"/>, and return whether if the\n    /// lookup was successful.\n    /// </summary>\n    /// <param name=\"txId\">The <see cref=\"TxId\"/> of the <see cref=\"Transaction\"/> to find the\n    /// containing <see cref=\"Block\"/>.</param>\n    /// <param name=\"containedBlock\">The <see cref=\"BlockHash\"/> of the indexed block that contains\n    /// the <see cref=\"Transaction\"/> with the <paramref name=\"txId\"/>, if it exists.</param>\n    /// <returns>Whether the retrieval was successful.</returns>\n    bool TryGetContainedBlockHashById(TxId txId, out BlockHash containedBlock);\n\n    /// <summary>\n    /// Attempt to get the <see cref=\"BlockHash\"/> of the indexed block that contains the\n    /// <see cref=\"Transaction\"/> with the <paramref name=\"txId\"/>, and return the retrieved\n    /// <see cref=\"BlockHash\"/> if it exists, or <c>null</c> if it does not.\n    /// </summary>\n    /// <param name=\"txId\">The <see cref=\"TxId\"/> of the <see cref=\"Transaction\"/> to find the\n    /// containing <see cref=\"Block\"/>.</param>\n    /// <returns>The <see cref=\"BlockHash\"/> of the block containing the\n    /// <see cref=\"Transaction\"/> with the <paramref name=\"txId\"/> if it exists, or <c>null</c>\n    /// if it does not.</returns>\n    Task<BlockHash?> TryGetContainedBlockHashByIdAsync(TxId txId);\n\n    /// <summary>\n    /// Get the last tx nonce of the <paramref name=\"address\"/> that was indexed.\n    /// </summary>\n    /// <param name=\"address\">The address to retrieve the tx nonce.</param>\n    /// <returns>The last tx nonce of the <paramref name=\"address\"/> that was indexed.</returns>\n    /// <remarks>This method does not return the tx nonces of <see cref=\"Transaction\"/>s that\n    /// are currently staged.</remarks>\n    long? GetLastNonceByAddress(Address address);\n\n    /// <inheritdoc cref=\"GetLastNonceByAddress\"/>\n    Task<long?> GetLastNonceByAddressAsync(Address address);\n\n    /// <summary>\n    /// Index the metadata of a <see cref=\"Block\"/> corresponding to the given\n    /// <paramref name=\"blockDigest\"/>.\n    /// </summary>\n    /// <param name=\"blockDigest\">The block digest object to index.</param>\n    /// <param name=\"txs\">An <see cref=\"IEnumerable{T}\"/> containing the <see cref=\"ITransaction\"/>\n    /// instances corresponding to <see cref=\"BlockDigest.TxIds\"/> of given\n    /// <paramref name=\"blockDigest\"/>.</param>\n    /// <param name=\"token\">A token to mark the cancellation of processing.</param>\n    /// <returns>A <see cref=\"Task\"/> that represents this asynchronous method.</returns>\n    /// <exception cref=\"IndexMismatchException\">Thrown if the index already has seen a block in\n    /// the height of the given block, but the hash of the indexed block and the given block is\n    /// different.</exception>\n    internal Task IndexAsync(\n        BlockDigest blockDigest, IEnumerable<ITransaction> txs, CancellationToken token);\n\n    internal Task SynchronizeForeverAsync(\n        IStore store, TimeSpan pollInterval, CancellationToken stoppingToken);\n\n    internal Task SynchronizeAsync(IStore store, CancellationToken stoppingToken);\n}\n"
  },
  {
    "path": "tools/Libplanet.Explorer/Indexing/IIndexingContext.cs",
    "content": "namespace Libplanet.Explorer.Indexing;\n\npublic interface IIndexingContext\n{\n}\n"
  },
  {
    "path": "tools/Libplanet.Explorer/Indexing/IndexMismatchException.cs",
    "content": "using System;\nusing Libplanet.Types.Blocks;\n\nnamespace Libplanet.Explorer.Indexing;\n\n/// <summary>\n/// An exception raised when the indexed blocks do not match the blocks in the provided\n/// <see cref=\"Blockchain.BlockChain\"/> object at the same height.\n/// </summary>\npublic class IndexMismatchException : Exception\n{\n    internal IndexMismatchException(long index, BlockHash indexHash, BlockHash? chainHash)\n        : base(\n            $\"The existing hash in the index for block #{index} doesn't match the hash\"\n            + $\" in the chain. ({indexHash} != {chainHash}) This means the index is inconsistent\"\n            + \" with the chain. Please make sure that the index is intended for the chain,\"\n            + \" and if absolutely sure, delete the index database and try again.\")\n    {\n        Index = index;\n        IndexHash = indexHash;\n        ChainHash = chainHash;\n    }\n\n    /// <summary>\n    /// The index of the mismatched blocks.\n    /// </summary>\n    public long Index { get; }\n\n    /// <summary>\n    /// The hash of the indexed block.\n    /// </summary>\n    public BlockHash IndexHash { get; }\n\n    /// <summary>\n    /// The hash of the block inside the <see cref=\"Blockchain.BlockChain\"/> object.\n    /// </summary>\n    public BlockHash? ChainHash { get; }\n}\n"
  },
  {
    "path": "tools/Libplanet.Explorer/Indexing/IndexingService.cs",
    "content": "using System;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing Libplanet.Store;\nusing Microsoft.Extensions.Hosting;\n\nnamespace Libplanet.Explorer.Indexing;\n\n/// <summary>\n/// An ASP.NET Core service that indexes blocks added to the given <see cref=\"IStore\"/>\n/// instance to the provided <see cref=\"IBlockChainIndex\"/> instance.\n/// </summary>\npublic class IndexingService : BackgroundService\n{\n    private readonly IBlockChainIndex _index;\n    private readonly IStore _store;\n    private readonly TimeSpan _pollInterval;\n\n    /// <summary>\n    /// Create an instance of the service that indexes blocks added to the <paramref name=\"chain\"/>\n    /// to the <paramref name=\"index\"/>.\n    /// </summary>\n    /// <param name=\"index\">The index object that blocks will be indexed.</param>\n    /// <param name=\"store\">The <see cref=\"IStore\"/> object that will be indexed by the\n    /// <paramref name=\"index\"/>.</param>\n    /// <param name=\"pollInterval\">The interval between index synchronization polls in\n    /// <see cref=\"TimeSpan\"/>. Recommended value is about the same as block interval.</param>\n    public IndexingService(IBlockChainIndex index, IStore store, TimeSpan pollInterval)\n    {\n        _index = index;\n        _store = store;\n        _pollInterval = pollInterval;\n    }\n\n    protected override async Task ExecuteAsync(CancellationToken stoppingToken)\n    {\n        try\n        {\n            await _index.SynchronizeForeverAsync(_store, _pollInterval, stoppingToken);\n        }\n        catch (OperationCanceledException)\n        {\n        }\n    }\n}\n"
  },
  {
    "path": "tools/Libplanet.Explorer/Indexing/RocksDbBlockChainIndex.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Collections.Immutable;\nusing System.IO;\nusing System.Linq;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing Bencodex;\nusing Bencodex.Types;\nusing Libplanet.Common;\nusing Libplanet.Crypto;\nusing Libplanet.Store;\nusing Libplanet.Types.Blocks;\nusing Libplanet.Types.Tx;\nusing RocksDbSharp;\n\nnamespace Libplanet.Explorer.Indexing;\n\n/// <summary>\n/// An <see cref=\"IBlockChainIndex\"/> object that uses RocksDB as the backend.\n/// </summary>\npublic class RocksDbBlockChainIndex : BlockChainIndexBase\n{\n    private static readonly byte[] BlockHashToIndexPrefix = { (byte)'b' };\n    private static readonly byte[] IndexToBlockHashPrefix = { (byte)'i' };\n    private static readonly byte[] ProducerToBlockIndexPrefix = { (byte)'p' };\n    private static readonly byte[] SignerToTxIdPrefix = { (byte)'s' };\n    private static readonly byte[] InvolvedAddressToTxIdPrefix = { (byte)'I' };\n    private static readonly byte[] TxIdToContainedBlockHashPrefix = { (byte)'t' };\n    private static readonly byte[] ActionTypeIdToTxIdPrefix = { (byte)'A' };\n    private static readonly byte[] ActionTypeIdPrefix = { (byte)'a' };\n    private static readonly Codec Codec = new();\n    private readonly RocksDb _db;\n\n    /// <summary>\n    /// Create an instance of <see cref=\"IBlockChainIndex\"/> that uses RocksDB as the backend.\n    /// </summary>\n    /// <param name=\"path\">The path containing the RocksDB index database.</param>\n    public RocksDbBlockChainIndex(string path)\n    {\n        if (path is null)\n        {\n            throw new ArgumentNullException(nameof(path));\n        }\n\n        path = Path.GetFullPath(path);\n\n        if (!Directory.Exists(path))\n        {\n            Directory.CreateDirectory(path);\n        }\n\n        if (!Directory.Exists(Path.Combine(path, \"indexdb\")))\n        {\n            Directory.CreateDirectory(Path.Combine(path, \"indexdb\"));\n        }\n\n        var rocksDbOption = new DbOptions()\n            .SetCreateIfMissing();\n\n        _db = RocksDb.Open(rocksDbOption, Path.Combine(path, \"indexdb\"));\n    }\n\n    /// <inheritdoc />\n    public override long BlockHashToIndex(BlockHash hash) =>\n        _db.Get(\n            BlockHashToIndexPrefix.Concat(hash.ByteArray).ToArray()) is { } arr\n            ? BigEndianByteArrayToLong(arr)\n            : throw new IndexOutOfRangeException(\n                $\"The hash {hash} does not exist in the index.\");\n\n    /// <inheritdoc />\n    public override async Task<long> BlockHashToIndexAsync(BlockHash hash) =>\n        await Task.Run(() => BlockHashToIndex(hash)).ConfigureAwait(false);\n\n    /// <inheritdoc />\n    public override IEnumerable<TxId>\n        GetSignedTxIdsByAddress(Address signer, int? fromNonce, int? maxCount, bool desc) =>\n        IteratePrefix(\n                fromNonce, maxCount, desc, SignerToTxIdPrefix.Concat(signer.ByteArray).ToArray())\n            .Select(kv => new TxId(kv.Value));\n\n    /// <inheritdoc />\n    public override async IAsyncEnumerable<TxId>\n        GetSignedTxIdsByAddressAsync(Address signer, int? fromNonce, int? maxCount, bool desc)\n    {\n        using var enumerator =\n            GetSignedTxIdsByAddress(signer, fromNonce, maxCount, desc).GetEnumerator();\n        while (await Task.Run(() => enumerator.MoveNext()).ConfigureAwait(false))\n        {\n            yield return enumerator.Current;\n        }\n    }\n\n    /// <inheritdoc />\n    public override long? GetLastNonceByAddress(Address address)\n    {\n        using var iter = IteratePrefix(\n                0, 1, true, SignerToTxIdPrefix.Concat(address.ByteArray).ToArray())\n            .Select(kv => BigEndianByteArrayToLong(kv.Key)).GetEnumerator();\n        return iter.MoveNext()\n            ? iter.Current\n            : null;\n    }\n\n    /// <inheritdoc />\n    public override async Task<long?> GetLastNonceByAddressAsync(Address address) =>\n        await Task.Run(() => GetLastNonceByAddress(address)).ConfigureAwait(false);\n\n    /// <inheritdoc />\n    public override bool TryGetContainedBlockHashById(TxId txId, out BlockHash containedBlock)\n    {\n        containedBlock = default;\n        var bytes =\n            _db.Get(TxIdToContainedBlockHashPrefix.Concat(txId.ByteArray).ToArray());\n        if (bytes is not { })\n        {\n            return false;\n        }\n\n        containedBlock = new BlockHash(bytes);\n        return true;\n    }\n\n    /// <inheritdoc />\n    public override async Task<BlockHash?> TryGetContainedBlockHashByIdAsync(TxId txId) =>\n        await Task.Run(() =>\n            TryGetContainedBlockHashById(txId, out var containedBlock)\n                ? containedBlock\n                : (BlockHash?)null\n        ).ConfigureAwait(false);\n\n    public override BlockHash IndexToBlockHash(long index)\n    {\n        return _db.Get(\n                IndexToBlockHashPrefix.Concat(\n                    LongToBigEndianByteArray(\n                        index >= 0 ? index : (GetTipImpl()?.Index ?? 0) + index + 1)).ToArray())\n            is { } arr\n            ? new BlockHash(arr)\n            : throw new IndexOutOfRangeException(\n                $\"The block #{index} does not exist in the index.\");\n    }\n\n    public override async Task<BlockHash> IndexToBlockHashAsync(long index)\n        => await Task.Run(() => IndexToBlockHash(index)).ConfigureAwait(false);\n\n    public override IEnumerable<(long Index, BlockHash Hash)>\n        GetBlockHashesFromIndex(int? fromHeight, int? maxCount, bool desc, Address? producer)\n    {\n        if (producer is { } minerVal)\n        {\n            return IteratePrefix(\n                    fromHeight,\n                    maxCount,\n                    desc,\n                    ProducerToBlockIndexPrefix.Concat(minerVal.ByteArray).ToArray())\n                .Select(\n                    kv => (\n                        BigEndianByteArrayToLong(kv.Value[..8]),\n                        new BlockHash(kv.Value[8..40])));\n        }\n\n        return IteratePrefix(fromHeight, maxCount, desc, IndexToBlockHashPrefix)\n            .Select(kv => (BigEndianByteArrayToLong(kv.Key), new BlockHash(kv.Value)));\n    }\n\n    public override async IAsyncEnumerable<(long Index, BlockHash Hash)>\n        GetBlockHashesFromIndexAsync(int? fromHeight, int? maxCount, bool desc, Address? producer)\n    {\n        using var enumerator =\n            GetBlockHashesFromIndex(fromHeight, maxCount, desc, producer)\n                .GetEnumerator();\n        while (await Task.Run(() => enumerator.MoveNext()).ConfigureAwait(false))\n        {\n            yield return enumerator.Current;\n        }\n    }\n\n    protected override (long Index, BlockHash Hash)? GetTipImpl()\n    {\n        using var iter =\n            GetBlockHashesFromIndex(0, 1, true, null)\n                .GetEnumerator();\n        return iter.MoveNext()\n            ? iter.Current\n            : null;\n    }\n\n    protected override async Task<(long Index, BlockHash Hash)?> GetTipAsyncImpl()\n        => await Task.Run(GetTipImpl).ConfigureAwait(false);\n\n    /// <inheritdoc />\n    protected override async Task IndexAsyncImpl(\n        BlockDigest blockDigest,\n        IEnumerable<ITransaction> txs,\n        IIndexingContext? context,\n        CancellationToken stoppingToken) =>\n        await Task.Run(() => IndexImpl(blockDigest, txs, context, stoppingToken), stoppingToken)\n            .ConfigureAwait(false);\n\n    protected override IIndexingContext GetIndexingContext() =>\n        new RocksDbIndexingContext();\n\n    protected override void CommitIndexingContext(IIndexingContext context)\n    {\n        if (context is not RocksDbIndexingContext)\n        {\n            throw new ArgumentException(\n                $\"Received an unsupported {nameof(IIndexingContext)}: {context.GetType()}\");\n        }\n    }\n\n    protected override async Task CommitIndexingContextAsync(IIndexingContext context) =>\n        await Task.Run(() => CommitIndexingContext(context));\n\n    // Use big endian for easier iterator prev seek\n    private static byte[] ShortToBigEndianByteArray(short val)\n    {\n        byte[] arr = BitConverter.GetBytes(val);\n        if (BitConverter.IsLittleEndian)\n        {\n            Array.Reverse(arr);\n        }\n\n        return arr;\n    }\n\n    private static byte[] LongToBigEndianByteArray(long val)\n    {\n        byte[] arr = BitConverter.GetBytes(val);\n        if (BitConverter.IsLittleEndian)\n        {\n            Array.Reverse(arr);\n        }\n\n        return arr;\n    }\n\n    private static long BigEndianByteArrayToLong(byte[] val)\n    {\n        var len = val.Length;\n        if (len != 8)\n        {\n            throw new ArgumentException(\n                $\"a byte array of size 8 must be provided, but the size of given array was {len}.\",\n                nameof(val));\n        }\n\n        if (BitConverter.IsLittleEndian)\n        {\n            Array.Reverse(val);\n        }\n\n        return BitConverter.ToInt64(val);\n    }\n\n    private void IndexImpl(\n        BlockDigest blockDigest,\n        IEnumerable<ITransaction> txs,\n        IIndexingContext? context,\n        CancellationToken stoppingToken)\n    {\n        var minerAddress = blockDigest.Miner.ByteArray.ToArray();\n        var blockHash = blockDigest.Hash.ByteArray.ToArray();\n        var indexToBlockHashKey = IndexToBlockHashPrefix\n            .Concat(LongToBigEndianByteArray(blockDigest.Index)).ToArray();\n\n        var writeBatch = new WriteBatch();\n        if (_db.Get(indexToBlockHashKey) is { } existingHash)\n        {\n            writeBatch.Dispose();\n            if (new BlockHash(existingHash).Equals(blockDigest.Hash))\n            {\n                return;\n            }\n\n            throw new IndexMismatchException(\n                blockDigest.Index, GetTipImpl()!.Value.Hash, blockDigest.Hash);\n        }\n\n        writeBatch.Put(indexToBlockHashKey, blockHash);\n        writeBatch.Put(\n            BlockHashToIndexPrefix.Concat(blockHash).ToArray(),\n            LongToBigEndianByteArray(blockDigest.Index));\n        writeBatch.Put(\n            GetNextOrdinalKey(ProducerToBlockIndexPrefix.Concat(minerAddress).ToArray()),\n            LongToBigEndianByteArray(blockDigest.Index).Concat(blockHash).ToArray());\n\n        IImmutableDictionary<byte[], long> duplicateActionTypeIdToTxTimestampOrdinalMemos =\n            ImmutableDictionary<byte[], long>.Empty.WithComparers(ByteArrayComparer.Instance);\n        IImmutableDictionary<byte[], long> duplicateAccountNonceOrdinalMemos =\n            ImmutableDictionary<byte[], long>.Empty.WithComparers(ByteArrayComparer.Instance);\n        IImmutableDictionary<byte[], long> duplicateInvolvedTxTimestampOrdinalMemos =\n            ImmutableDictionary<byte[], long>.Empty.WithComparers(ByteArrayComparer.Instance);\n        IImmutableSet<byte[]> encounteredActionTypeIdToTxIdKeys =\n            ImmutableHashSet<byte[]>.Empty.WithComparer(ByteArrayComparer.Instance);\n        IImmutableSet<byte[]> encounteredSignerToTxIdKeys =\n            ImmutableHashSet<byte[]>.Empty.WithComparer(ByteArrayComparer.Instance);\n        IImmutableSet<byte[]> encounteredInvolvedAddressToTxIdKeys =\n            ImmutableHashSet<byte[]>.Empty.WithComparer(ByteArrayComparer.Instance);\n        foreach (var tx in txs)\n        {\n            if (stoppingToken.IsCancellationRequested)\n            {\n                writeBatch.Dispose();\n                throw new OperationCanceledException(stoppingToken);\n            }\n\n            var signerAddress = tx.Signer.ByteArray.ToArray();\n            var txId = tx.Id.ByteArray.ToArray();\n            var txIdToContainedBlockHashKey = TxIdToContainedBlockHashPrefix.Concat(txId).ToArray();\n            if (_db.Get(txIdToContainedBlockHashKey) is { })\n            {\n                continue;\n            }\n\n            PutOrPutDuplicateOrdinal(\n                ref writeBatch,\n                SignerToTxIdPrefix\n                    .Concat(signerAddress)\n                    .Concat(LongToBigEndianByteArray(tx.Nonce))\n                    .ToArray(),\n                txId,\n                ref encounteredSignerToTxIdKeys,\n                ref duplicateAccountNonceOrdinalMemos);\n\n            writeBatch.Put(txIdToContainedBlockHashKey, blockHash);\n            foreach (var address in tx.UpdatedAddresses.Select(address => address.ByteArray))\n            {\n                if (stoppingToken.IsCancellationRequested)\n                {\n                    writeBatch.Dispose();\n                    throw new OperationCanceledException(stoppingToken);\n                }\n\n                PutOrPutDuplicateOrdinal(\n                    ref writeBatch,\n                    InvolvedAddressToTxIdPrefix\n                        .Concat(address)\n                        .Concat(LongToBigEndianByteArray(tx.Timestamp.UtcTicks))\n                        .ToArray(),\n                    txId,\n                    ref encounteredInvolvedAddressToTxIdKeys,\n                    ref duplicateInvolvedTxTimestampOrdinalMemos);\n            }\n\n            if (tx.Actions is not { } actions)\n            {\n                continue;\n            }\n\n            foreach (var action in actions)\n            {\n                if (stoppingToken.IsCancellationRequested)\n                {\n                    writeBatch.Dispose();\n                    throw new OperationCanceledException(stoppingToken);\n                }\n\n                if (action is not Dictionary actionDict\n                    || !actionDict.TryGetValue((Text)\"type_id\", out var typeId))\n                {\n                    continue;\n                }\n\n                // Use IValue for string, as \"abc\" and \"abcd\" as raw byte strings overlap.\n                writeBatch.Put(\n                    ActionTypeIdPrefix.Concat(Codec.Encode(typeId)).ToArray(),\n                    Array.Empty<byte>());\n                PutOrPutDuplicateOrdinal(\n                    ref writeBatch,\n                    ActionTypeIdToTxIdPrefix\n                        .Concat(Codec.Encode(typeId))\n                        .Concat(LongToBigEndianByteArray(tx.Timestamp.UtcTicks))\n                        .ToArray(),\n                    txId,\n                    ref encounteredActionTypeIdToTxIdKeys,\n                    ref duplicateActionTypeIdToTxTimestampOrdinalMemos);\n            }\n        }\n\n        _db.Write(writeBatch);\n        writeBatch.Dispose();\n    }\n\n    private IEnumerable<(byte[] Key, byte[] Value)>\n        IteratePrefix(int? offset, int? limit, bool desc, byte[] prefix)\n    {\n        if (limit == 0)\n        {\n            yield break;\n        }\n\n        Iterator iter = _db.NewIterator().Seek(prefix);\n        if (!iter.Valid() || !iter.Key().StartsWith(prefix))\n        {\n            yield break;\n        }\n\n        if (desc)\n        {\n            byte[] upper = new byte[iter.Key().Length - prefix.Length];\n            Array.Fill(upper, byte.MaxValue);\n            iter.Dispose();\n            iter = _db.NewIterator().SeekForPrev(prefix.Concat(upper).ToArray());\n        }\n\n        byte[] key;\n        Func<long> GetAdvancer()\n        {\n            long count = 0;\n            System.Action advance = desc\n                ? () => iter.Prev()\n                : () => iter.Next();\n            return () =>\n            {\n                advance();\n                return ++count;\n            };\n        }\n\n        var advance = GetAdvancer();\n        for (var i = 0; i < offset; ++i)\n        {\n            advance();\n        }\n\n        for (long count = 0L;\n             iter.Valid()\n             && (key = iter.Key()).StartsWith(prefix)\n             && (limit is not { } || count < (offset ?? 0) + limit);\n             count = advance())\n        {\n            yield return (key[prefix.Length..], iter.Value());\n        }\n\n        iter.Dispose();\n    }\n\n    private long GetNextOrdinal(byte[] prefix)\n    {\n        using Iterator iter = _db.NewIterator().Seek(prefix);\n        if (!iter.Valid() || !iter.Key().StartsWith(prefix))\n        {\n            return 0L;\n        }\n\n        byte[] upper = new byte[iter.Key().Length - prefix.Length];\n        Array.Fill(upper, byte.MaxValue);\n        using Iterator lastIter = _db.NewIterator().SeekForPrev(prefix.Concat(upper).ToArray());\n        return BigEndianByteArrayToLong(lastIter.Key()[prefix.Length..]) + 1;\n    }\n\n    private byte[] GetNextOrdinalKey(byte[] prefix)\n    {\n        long? memo = null;\n        return GetNextOrdinalKey(prefix, ref memo);\n    }\n\n    private byte[] GetNextOrdinalKey(byte[] prefix, ref long? memo) =>\n        prefix.Concat(\n            LongToBigEndianByteArray(\n                (long)(memo = memo is { } memoVal\n                    ? ++memoVal\n                    : (memo = GetNextOrdinal(prefix)).Value))).ToArray();\n\n    private void PutOrdinalWithMemo(\n        ref WriteBatch writeBatch,\n        byte[] prefix,\n        byte[] value,\n        ref IImmutableDictionary<byte[], long> memos)\n    {\n        long? memo = memos.TryGetValue(prefix, out var memoValue)\n            ? memoValue\n            : null;\n        writeBatch.Put(GetNextOrdinalKey(prefix, ref memo), value);\n        memos = memos.SetItem(prefix, memo!.Value);\n    }\n\n    private void PutOrPutDuplicateOrdinal(\n        ref WriteBatch writeBatch,\n        byte[] key,\n        byte[] value,\n        ref IImmutableSet<byte[]> encounteredKeys,\n        ref IImmutableDictionary<byte[], long> duplicateMemos)\n    {\n        if (\n            !encounteredKeys.Contains(key)\n            && _db.Get(key) is null)\n        {\n            writeBatch.Put(key, value);\n            encounteredKeys = encounteredKeys.Add(key);\n        }\n        else\n        {\n            PutOrdinalWithMemo(\n                ref writeBatch,\n                key,\n                value,\n                ref duplicateMemos);\n        }\n    }\n\n    private class ByteArrayComparer : IEqualityComparer<byte[]>\n    {\n        public static readonly ByteArrayComparer Instance = new ByteArrayComparer();\n\n        public bool Equals(byte[]? x, byte[]? y) =>\n            ((ReadOnlySpan<byte>)x).SequenceEqual(y);\n\n        public int GetHashCode(byte[] obj)\n        {\n            HashCode hash = default;\n            hash.AddBytes(obj);\n            return hash.ToHashCode();\n        }\n    }\n}\n"
  },
  {
    "path": "tools/Libplanet.Explorer/Indexing/RocksDbIndexingContext.cs",
    "content": "namespace Libplanet.Explorer.Indexing;\n\npublic record RocksDbIndexingContext : IIndexingContext;\n"
  },
  {
    "path": "tools/Libplanet.Explorer/Interfaces/IBlockChainContext.cs",
    "content": "using System.Runtime.CompilerServices;\nusing GraphQL.Types;\nusing Libplanet.Action;\nusing Libplanet.Blockchain;\nusing Libplanet.Explorer.Indexing;\nusing Libplanet.Explorer.Queries;\nusing Libplanet.Net;\nusing Libplanet.Store;\n\nnamespace Libplanet.Explorer.Interfaces\n{\n    public interface IBlockChainContext\n    {\n        bool Preloaded { get; }\n\n        BlockChain BlockChain { get; }\n\n        IStore Store { get; }\n\n        Swarm Swarm { get; }\n\n        IBlockChainIndex Index { get; }\n    }\n\n    public static class BlockChainContext\n    {\n        private static ConditionalWeakTable<object, Schema> _schemaObjects =\n            new ConditionalWeakTable<object, Schema>();\n\n        public static Schema GetSchema(this IBlockChainContext context)\n        {\n            return _schemaObjects.GetValue(\n                context,\n                (_) =>\n                {\n                    var s = new Schema { Query = new ExplorerQuery(context) };\n                    return s;\n                }\n            );\n        }\n    }\n}\n"
  },
  {
    "path": "tools/Libplanet.Explorer/Libplanet.Explorer.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <PropertyGroup>\n    <NoWarn>$(NoWarn);NU1701;NU5104;SA1118</NoWarn>\n    <CodeAnalysisRuleSet>..\\..\\Libplanet.Explorer.ruleset</CodeAnalysisRuleSet>\n    <TreatWarningsAsErrors>true</TreatWarningsAsErrors>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <PackageReference Include=\"Microsoft.AspNetCore.Mvc.NewtonsoftJson\" Version=\"6.0.7\" />\n    <PackageReference Include=\"MySqlConnector\" Version=\"1.1.0\" />\n    <PackageReference Include=\"SqlKata\" Version=\"2.2.0\" />\n    <PackageReference Include=\"SqlKata.Execution\" Version=\"2.2.0\" />\n    <PackageReference Include=\"GraphQL\" Version=\"4.7.1\" />\n    <PackageReference Include=\"GraphQL.SystemTextJson\" Version=\"4.7.1\" />\n    <PackageReference Include=\"GraphQL.Server.Authorization.AspNetCore\" Version=\"5.1.1\" />\n    <PackageReference Include=\"GraphQL.Server.Transports.AspNetCore.SystemTextJson\" Version=\"5.1.1\" />\n    <PackageReference Include=\"GraphQL.Server.Ui.Playground\" Version=\"5.1.1\" />\n    <PackageReference Include=\"GraphQL.Server.Transports.AspNetCore\" Version=\"5.1.1\" />\n    <FrameworkReference Include=\"Microsoft.AspNetCore.App\" />\n  </ItemGroup>\n\n  <ItemGroup Condition=\"'$(SkipSonar)' != 'true'\">\n    <PackageReference Remove=\"SonarAnalyzer.CSharp\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <ProjectReference Include=\"..\\..\\src\\Libplanet.Net\\Libplanet.Net.csproj\" />\n    <ProjectReference Include=\"..\\..\\src\\Libplanet\\Libplanet.csproj\" />\n    <ProjectReference Include=\"..\\..\\src\\Libplanet.RocksDBStore\\Libplanet.RocksDBStore.csproj\" />\n    <PackageReference Include=\"Bencodex.Json\" Version=\"0.16.0\" />\n    <!-- FIXME: We should specify the version range when the following NuGet\n    issue is addressed: <https://github.com/NuGet/Home/issues/5556>. -->\n  </ItemGroup>\n\n  <ItemGroup>\n    <EmbeddedResource Include=\"Views\\**\" />\n    <None Include=\"wwwroot\\*\" />\n    <Compile Remove=\"Store\\RocksDBStoreBitConverter.cs\" />\n  </ItemGroup>\n\n</Project>\n"
  },
  {
    "path": "tools/Libplanet.Explorer/Mutations/TransactionMutation.cs",
    "content": "using System;\nusing GraphQL;\nusing GraphQL.Types;\nusing Libplanet.Blockchain;\nusing Libplanet.Common;\nusing Libplanet.Explorer.GraphTypes;\nusing Libplanet.Explorer.Interfaces;\nusing Libplanet.Types.Tx;\n\nnamespace Libplanet.Explorer.Mutations\n{\n    public class TransactionMutation : ObjectGraphType\n    {\n        private readonly IBlockChainContext _context;\n\n        public TransactionMutation(IBlockChainContext context)\n        {\n            _context = context ?? throw new ArgumentNullException(nameof(context));\n\n            Field<TransactionType>(\n                \"stage\",\n                description: \"Stage transaction to current chain\",\n                arguments: new QueryArguments(\n                    new QueryArgument<NonNullGraphType<StringGraphType>>\n                    {\n                        Name = \"payload\",\n                        #pragma warning disable MEN002\n                        Description = \"The hexadecimal string of the serialized transaction to stage.\",\n                        #pragma warning restore MEN002\n                    }\n                ),\n                resolve: context =>\n                {\n                    BlockChain chain = _context.BlockChain;\n                    byte[] payload = ByteUtil.ParseHex(context.GetArgument<string>(\"payload\"));\n                    Transaction tx = Transaction.Deserialize(payload);\n                    if (!chain.StageTransaction(tx))\n                    {\n                        throw new ExecutionError(\n                            \"Failed to stage given tx; it may be already expired or ignored.\"\n                        );\n                    }\n\n                    return tx;\n                }\n            );\n        }\n    }\n}\n"
  },
  {
    "path": "tools/Libplanet.Explorer/Queries/BlockQuery.cs",
    "content": "using GraphQL;\nusing GraphQL.Types;\nusing Libplanet.Crypto;\nusing Libplanet.Explorer.GraphTypes;\nusing Libplanet.Types.Blocks;\n\nnamespace Libplanet.Explorer.Queries\n{\n    public class BlockQuery : ObjectGraphType\n    {\n        public BlockQuery()\n        {\n            Field<NonNullGraphType<ListGraphType<NonNullGraphType<BlockType>>>>(\n                \"blocks\",\n                arguments: new QueryArguments(\n                    new QueryArgument<NonNullGraphType<BooleanGraphType>>\n                    {\n                        Name = \"desc\",\n                        Description = \"Whether to query blocks in descending order or not.\",\n                        DefaultValue = false,\n                    },\n                    new QueryArgument<NonNullGraphType<IntGraphType>>\n                    {\n                        Name = \"offset\",\n                        Description = \"The offset of the first queried block.\",\n                        DefaultValue = 0,\n                    },\n                    new QueryArgument<IntGraphType>\n                    {\n                        Name = \"limit\",\n                        Description =\n                            \"The maximum number of blocks to return.  This limits the \" +\n                            \"offset index range to query, not the result, i.e. excluded \" +\n                            \"blocks due to a block being empty or not matching the miner \" +\n                            \"(if specified in other arguments) are still counted.\",\n                    }\n                ),\n                resolve: context =>\n                {\n                    bool desc = context.GetArgument<bool>(\"desc\");\n                    long offset = context.GetArgument<long>(\"offset\");\n                    int? limit = context.GetArgument<int?>(\"limit\", 100);\n                    return ExplorerQuery.ListBlocks(desc, offset, limit);\n                }\n            );\n\n            Field<BlockType>(\n                \"block\",\n                arguments: new QueryArguments(\n                    new QueryArgument<IdGraphType> { Name = \"hash\" },\n                    new QueryArgument<IdGraphType> { Name = \"index\" }\n                ),\n                resolve: context =>\n                {\n                    string hash = context.GetArgument<string>(\"hash\");\n                    long? index = context.GetArgument<long?>(\"index\", null);\n\n                    if (!(hash is null ^ index is null))\n                    {\n                        throw new GraphQL.ExecutionError(\n                            \"The parameters hash and index are mutually exclusive; \" +\n                            \"give only one at a time.\");\n                    }\n\n                    if (hash is { } nonNullHash)\n                    {\n                        return ExplorerQuery.GetBlockByHash(BlockHash.FromString(nonNullHash));\n                    }\n\n                    if (index is { } nonNullIndex)\n                    {\n                        return ExplorerQuery.GetBlockByIndex(nonNullIndex);\n                    }\n\n                    throw new GraphQL.ExecutionError(\"Unexpected block query\");\n                }\n            );\n\n            Name = \"BlockQuery\";\n        }\n    }\n}\n"
  },
  {
    "path": "tools/Libplanet.Explorer/Queries/EvidenceQuery.cs",
    "content": "using System;\nusing GraphQL;\nusing GraphQL.Types;\nusing Libplanet.Common;\nusing Libplanet.Explorer.GraphTypes;\nusing Libplanet.Types.Blocks;\nusing Libplanet.Types.Evidence;\n\nnamespace Libplanet.Explorer.Queries\n{\n    public class EvidenceQuery : ObjectGraphType\n    {\n        private const int MaxLimit = 100;\n\n        public EvidenceQuery()\n        {\n            Name = \"EvidenceQuery\";\n            Description = \"Retrieve evidence information.\";\n\n            Field<NonNullGraphType<ListGraphType<NonNullGraphType<EvidenceType>>>>(\n                \"committedEvidence\",\n                arguments: new QueryArguments(\n                    new QueryArgument<BlockHashType>\n                    {\n                        Name = \"blockHash\",\n                        DefaultValue = null,\n                    },\n                    new QueryArgument<BooleanGraphType>\n                    {\n                        Name = \"desc\",\n                        DefaultValue = false,\n                    },\n                    new QueryArgument<IntGraphType>\n                    {\n                        Name = \"offset\",\n                        DefaultValue = 0,\n                    },\n                    new QueryArgument<IntGraphType>\n                    {\n                        Name = \"limit\",\n                        DefaultValue = MaxLimit,\n                    }\n                ),\n                resolve: context =>\n                {\n                    var blockHash = context.GetArgument<BlockHash?>(\"blockHash\");\n                    bool desc = context.GetArgument<bool>(\"desc\");\n                    int offset = context.GetArgument<int>(\"offset\");\n                    int? limit = context.GetArgument<int?>(\"limit\");\n\n                    return ExplorerQuery.ListCommitEvidence(blockHash, desc, offset, limit);\n                }\n            );\n\n            Field<NonNullGraphType<ListGraphType<NonNullGraphType<EvidenceType>>>>(\n                \"pendingEvidence\",\n                arguments: new QueryArguments(\n                    new QueryArgument<BooleanGraphType>\n                    {\n                        Name = \"desc\",\n                        DefaultValue = false,\n                    },\n                    new QueryArgument<IntGraphType>\n                    {\n                        Name = \"offset\",\n                        DefaultValue = 0,\n                    },\n                    new QueryArgument<IntGraphType>\n                    {\n                        Name = \"limit\",\n                        DefaultValue = MaxLimit,\n                    }\n                ),\n                resolve: context =>\n                {\n                    bool desc = context.GetArgument<bool>(\"desc\");\n                    int offset = context.GetArgument<int>(\"offset\");\n                    int? limit = context.GetArgument<int?>(\"limit\", null);\n\n                    return ExplorerQuery.ListPendingEvidence(desc, offset, limit);\n                }\n            );\n\n            Field<EvidenceType>(\n                \"Evidence\",\n                arguments: new QueryArguments(\n                    new QueryArgument<EvidenceIdType> { Name = \"id\" }\n                ),\n                resolve: context => ExplorerQuery.GetEvidence(\n                    new EvidenceId(ByteUtil.ParseHex(context.GetArgument<string>(\"id\")\n                        ?? throw new ExecutionError(\"Given id cannot be null.\"))))\n            );\n        }\n    }\n}\n"
  },
  {
    "path": "tools/Libplanet.Explorer/Queries/ExplorerQuery.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing GraphQL.Types;\nusing Libplanet.Blockchain;\nusing Libplanet.Crypto;\nusing Libplanet.Explorer.GraphTypes;\nusing Libplanet.Explorer.Interfaces;\nusing Libplanet.Store;\nusing Libplanet.Types.Blocks;\nusing Libplanet.Types.Evidence;\nusing Libplanet.Types.Tx;\n\nnamespace Libplanet.Explorer.Queries\n{\n    public class ExplorerQuery : ObjectGraphType\n    {\n        private static IBlockChainContext? _chainContext;\n\n        public ExplorerQuery(IBlockChainContext chainContext)\n        {\n            _chainContext = chainContext;\n            Field<BlockQuery>(\"blockQuery\", resolve: context => new { });\n            Field<TransactionQuery>(\"transactionQuery\", resolve: context => new { });\n            Field<EvidenceQuery>(\"evidenceQuery\", resolve: context => new { });\n            Field<StateQuery>(\"stateQuery\", resolve: context => chainContext.BlockChain);\n            Field<NonNullGraphType<NodeStateType>>(\"nodeState\", resolve: context => chainContext);\n            Field<HelperQuery>(\"helperQuery\", resolve: context => new { });\n            Field<RawStateQuery>(\"rawStateQuery\", resolve: context => chainContext.BlockChain);\n\n            Name = \"ExplorerQuery\";\n        }\n\n        private static IBlockChainContext ChainContext => _chainContext!;\n\n        private static BlockChain Chain => ChainContext.BlockChain;\n\n        private static IStore Store => ChainContext.Store;\n\n        internal static IEnumerable<Block> ListBlocks(\n            bool desc,\n            long offset,\n            long? limit)\n        {\n            Block tip = Chain.Tip;\n            long tipIndex = tip.Index;\n\n            var blocks = ListBlocks(\n                Chain,\n                desc ? tipIndex - offset - (limit ?? 100) : offset,\n                limit ?? 100);\n            return desc ? blocks.OrderByDescending(x => x.Index)\n                : blocks.OrderBy(x => x.Index);\n        }\n\n        internal static IEnumerable<Transaction> ListTransactions(\n            Address? signer, bool desc, long offset, int? limit)\n        {\n            Block tip = Chain.Tip;\n            long tipIndex = tip.Index;\n\n            if (offset < 0)\n            {\n                offset = tipIndex + offset + 1;\n            }\n\n            if (tipIndex < offset || offset < 0)\n            {\n                yield break;\n            }\n\n            Block? block = Chain[desc ? tipIndex - offset : offset];\n            while (block is not null && limit is null or > 0)\n            {\n                foreach (var tx in desc ? block.Transactions.Reverse() : block.Transactions)\n                {\n                    if (IsValidTransaction(tx, signer))\n                    {\n                        yield return tx;\n                        limit--;\n                        if (limit <= 0)\n                        {\n                            break;\n                        }\n                    }\n                }\n\n                block = GetNextBlock(block, desc);\n            }\n        }\n\n        internal static IEnumerable<Transaction> ListStagedTransactions(\n            Address? signer, bool desc, int offset, int? limit)\n        {\n            if (offset < 0)\n            {\n                throw new ArgumentOutOfRangeException(\n                    nameof(offset),\n                    $\"{nameof(ListStagedTransactions)} doesn't support negative offset.\");\n            }\n\n            var stagedTxs = Chain.StagePolicy.Iterate(Chain)\n                .Where(tx => IsValidTransaction(tx, signer))\n                .Skip(offset);\n\n            stagedTxs = desc ? stagedTxs.OrderByDescending(tx => tx.Timestamp)\n                : stagedTxs.OrderBy(tx => tx.Timestamp);\n\n            stagedTxs = stagedTxs.TakeWhile((tx, index) => limit is null || index < limit);\n\n            return stagedTxs;\n        }\n\n        internal static IEnumerable<EvidenceBase> ListPendingEvidence(\n            bool desc, int offset, int? limit)\n        {\n            if (offset < 0)\n            {\n                throw new ArgumentOutOfRangeException(\n                    nameof(offset),\n                    $\"{nameof(ListPendingEvidence)} doesn't support negative offset.\");\n            }\n\n            var blockChain = Chain;\n            var comparer = desc ? EvidenceIdComparer.Descending : EvidenceIdComparer.Ascending;\n            var evidence = blockChain.GetPendingEvidence()\n                                      .Skip(offset)\n                                      .Take(limit ?? int.MaxValue)\n                                      .OrderBy(ev => ev.Id, comparer);\n\n            return evidence;\n        }\n\n        internal static IEnumerable<EvidenceBase> ListCommitEvidence(\n            BlockHash? blockHash, bool desc, int offset, int? limit)\n        {\n            var blockChain = Chain;\n            var block = blockHash != null ? blockChain[blockHash.Value] : blockChain.Tip;\n            var comparer = desc ? EvidenceIdComparer.Descending : EvidenceIdComparer.Ascending;\n            var evidence = block.Evidence\n                                 .Skip(offset)\n                                 .Take(limit ?? int.MaxValue)\n                                 .OrderBy(ev => ev.Id, comparer);\n\n            return evidence;\n        }\n\n        internal static Block? GetBlockByHash(BlockHash hash) => Store.GetBlock(hash);\n\n        internal static Block GetBlockByIndex(long index) => Chain[index];\n\n        internal static Transaction GetTransaction(TxId id) => Chain.GetTransaction(id);\n\n        internal static EvidenceBase GetEvidence(EvidenceId id) => Chain.GetCommittedEvidence(id);\n\n        private static Block? GetNextBlock(Block block, bool desc)\n        {\n            if (desc && block.PreviousHash is { } prev)\n            {\n                return Chain[prev];\n            }\n            else if (!desc && block != Chain.Tip)\n            {\n                return Chain[block.Index + 1];\n            }\n\n            return null;\n        }\n\n        private static IEnumerable<Block> ListBlocks(BlockChain chain, long from, long limit)\n        {\n            if (chain.Tip.Index < from)\n            {\n                return new List<Block>();\n            }\n\n            var count = (int)Math.Min(limit, chain.Tip.Index - from + 1);\n            var blocks = Enumerable.Range(0, count)\n                .Select(offset => chain[from + offset])\n                .OrderBy(block => block.Index);\n\n            return blocks;\n        }\n\n        private static bool IsValidTransaction(\n            Transaction tx,\n            Address? signer)\n        {\n            if (signer is { } signerVal)\n            {\n                return tx.Signer.Equals(signerVal);\n            }\n\n            return true;\n        }\n    }\n}\n"
  },
  {
    "path": "tools/Libplanet.Explorer/Queries/HelperQuery.cs",
    "content": "using System.Security.Cryptography;\nusing System.Text;\nusing Bencodex;\nusing GraphQL;\nusing GraphQL.Types;\nusing Libplanet.Common;\nusing Libplanet.Explorer.GraphTypes;\nusing Libplanet.Store.Trie;\nusing Libplanet.Types.Assets;\n\nnamespace Libplanet.Explorer.Queries\n{\n    public class HelperQuery : ObjectGraphType\n    {\n        private static Codec _codec = new Codec();\n\n        public HelperQuery()\n        {\n            Name = \"HelperQuery\";\n            Description = \"A number of queries for convenience.\";\n\n            Field<NonNullGraphType<HashDigestType<SHA1>>>(\n                name: \"currencyHash\",\n                description: \"Converts currency info to currency hash.\",\n                arguments: new QueryArguments(\n                    new QueryArgument<NonNullGraphType<CurrencyInputType>>\n                    {\n                        Name = \"currency\",\n                        Description = \"The currency to convert.\",\n                    }\n                ),\n                resolve: context => context.GetArgument<Currency>(\"currency\").Hash\n            );\n\n            Field<NonNullGraphType<IValueType>>(\n                name: \"bencodexValue\",\n                description: \"Decodes hex encoded bencodex value\",\n                arguments: new QueryArguments(\n                    new QueryArgument<NonNullGraphType<StringGraphType>>\n                    {\n                        Name = \"hex\",\n                        Description = \"The byte array in hex representation to decode.\",\n                    }\n                ),\n                resolve: context =>\n                    _codec.Decode(ByteUtil.ParseHex(context.GetArgument<string>(\"hex\")))\n            );\n\n            Field<NonNullGraphType<KeyBytesType>>(\n                name: \"keyHex\",\n                description: \"Converts string to key hex representation\",\n                arguments: new QueryArguments(\n                    new QueryArgument<NonNullGraphType<StringGraphType>>\n                    {\n                        Name = \"value\",\n                        Description = \"The string value to convert to key hex.\",\n                    }\n                ),\n                resolve: context =>\n                    new KeyBytes(Encoding.ASCII.GetBytes(context.GetArgument<string>(\"value\")))\n            );\n        }\n    }\n}\n"
  },
  {
    "path": "tools/Libplanet.Explorer/Queries/RawStateQuery.cs",
    "content": "using System;\nusing System.Security.Cryptography;\nusing Bencodex.Types;\nusing GraphQL;\nusing GraphQL.Types;\nusing Libplanet.Action.State;\nusing Libplanet.Common;\nusing Libplanet.Explorer.GraphTypes;\nusing Libplanet.Store.Trie;\n\nnamespace Libplanet.Explorer.Queries;\n\npublic class RawStateQuery : ObjectGraphType<IBlockChainStates>\n{\n    public RawStateQuery()\n    {\n        Name = \"RawStateQuery\";\n\n        // FIXME: IBlockChainStates does not support direct retrieval of an ITrie.\n        Field<NonNullGraphType<TrieType>>(\n            \"trie\",\n            description: \"Retrieves trie from given state root hash.\",\n            arguments: new QueryArguments(\n                new QueryArgument<HashDigestSHA256Type> { Name = \"stateRootHash\" }\n            ),\n            resolve: context => context.Source.GetWorldState(\n                context.GetArgument<HashDigest<SHA256>>(\"stateRootHash\")).Trie\n        );\n    }\n}\n"
  },
  {
    "path": "tools/Libplanet.Explorer/Queries/StateQuery.cs",
    "content": "using System.Security.Cryptography;\nusing GraphQL;\nusing GraphQL.Types;\nusing Libplanet.Action.State;\nusing Libplanet.Common;\nusing Libplanet.Crypto;\nusing Libplanet.Explorer.GraphTypes;\nusing Libplanet.Types.Assets;\nusing Libplanet.Types.Blocks;\n\nnamespace Libplanet.Explorer.Queries;\n\npublic class StateQuery : ObjectGraphType<IBlockChainStates>\n{\n    public StateQuery()\n    {\n        Name = \"StateQuery\";\n\n        Field<NonNullGraphType<WorldStateType>>(\n            \"world\",\n            arguments: new QueryArguments(\n                new QueryArgument<BlockHashType> { Name = \"blockHash\" },\n                new QueryArgument<HashDigestType<SHA256>> { Name = \"stateRootHash\" }\n            ),\n            resolve: ResolveWorldState\n        );\n\n        Field<NonNullGraphType<ListGraphType<BencodexValueType>>>(\n            \"states\",\n            description: \"Retrieves states from the legacy account.\",\n            arguments: new QueryArguments(\n                new QueryArgument<NonNullGraphType<ListGraphType<NonNullGraphType<AddressType>>>>\n                    { Name = \"addresses\" },\n                new QueryArgument<IdGraphType> { Name = \"offsetBlockHash\" },\n                new QueryArgument<HashDigestSHA256Type> { Name = \"offsetStateRootHash\" }\n            ),\n            resolve: ResolveStates\n        );\n        Field<NonNullGraphType<FungibleAssetValueType>>(\n            \"balance\",\n            description: \"Retrieves balance from the legacy account.\",\n            arguments: new QueryArguments(\n                new QueryArgument<NonNullGraphType<AddressType>> { Name = \"owner\" },\n                new QueryArgument<NonNullGraphType<CurrencyInputType>> { Name = \"currency\" },\n                new QueryArgument<IdGraphType> { Name = \"offsetBlockHash\" },\n                new QueryArgument<HashDigestSHA256Type> { Name = \"offsetStateRootHash\" }\n            ),\n            resolve: ResolveBalance\n        );\n        Field<FungibleAssetValueType>(\n            \"totalSupply\",\n            description: \"Retrieves total supply from the legacy account.\",\n            arguments: new QueryArguments(\n                new QueryArgument<NonNullGraphType<CurrencyInputType>> { Name = \"currency\" },\n                new QueryArgument<IdGraphType> { Name = \"offsetBlockHash\" },\n                new QueryArgument<HashDigestSHA256Type> { Name = \"offsetStateRootHash\" }\n            ),\n            resolve: ResolveTotalSupply\n        );\n        Field<ListGraphType<NonNullGraphType<ValidatorType>>>(\n            \"validators\",\n            description: \"Retrieves validator set from the legacy account.\",\n            arguments: new QueryArguments(\n                new QueryArgument<IdGraphType> { Name = \"offsetBlockHash\" },\n                new QueryArgument<HashDigestSHA256Type> { Name = \"offsetStateRootHash\" }\n            ),\n            resolve: ResolveValidatorSet\n        );\n    }\n\n    private static object ResolveWorldState(IResolveFieldContext<IBlockChainStates> context)\n    {\n        BlockHash? blockHash = context.GetArgument<BlockHash?>(\"blockHash\");\n        HashDigest<SHA256>? stateRootHash =\n            context.GetArgument<HashDigest<SHA256>?>(\"stateRootHash\");\n\n        switch (blockhash: blockHash, srh: stateRootHash)\n        {\n            case (blockhash: not null, srh: not null):\n                throw new ExecutionError(\n                    \"blockHash and stateRootHash cannot be specified at the same time.\"\n                );\n            case (blockhash: null, srh: null):\n                throw new ExecutionError(\n                    \"Either blockHash or stateRootHash must be specified.\"\n                );\n            case (blockhash: not null, _):\n                return context.Source.GetWorldState((BlockHash)blockHash);\n            case (_, srh: not null):\n                return context.Source.GetWorldState(stateRootHash);\n        }\n    }\n\n    private static object? ResolveStates(IResolveFieldContext<IBlockChainStates> context)\n    {\n        Address[] addresses = context.GetArgument<Address[]>(\"addresses\");\n        BlockHash? offsetBlockHash =\n            context.GetArgument<string?>(\"offsetBlockHash\") is { } blockHashString\n                ? BlockHash.FromString(blockHashString)\n                : null;\n        HashDigest<SHA256>? offsetStateRootHash = context\n            .GetArgument<HashDigest<SHA256>?>(\"offsetStateRootHash\");\n\n        switch (blockhash: offsetBlockHash, srh: offsetStateRootHash)\n        {\n            case (blockhash: not null, srh: not null):\n                throw new ExecutionError(\n                    \"offsetBlockHash and offsetStateRootHash cannot be specified at the same time.\"\n                );\n            case (blockhash: null, srh: null):\n                throw new ExecutionError(\n                    \"Either offsetBlockHash or offsetStateRootHash must be specified.\"\n                );\n            case (blockhash: not null, _):\n            {\n                return context.Source\n                    .GetWorldState((BlockHash)offsetBlockHash)\n                    .GetAccountState(ReservedAddresses.LegacyAccount)\n                    .GetStates(addresses);\n            }\n\n            case (_, srh: not null):\n                return context.Source\n                    .GetWorldState(offsetStateRootHash)\n                    .GetAccountState(ReservedAddresses.LegacyAccount)\n                    .GetStates(addresses);\n        }\n    }\n\n    private static object ResolveBalance(IResolveFieldContext<IBlockChainStates> context)\n    {\n        Address owner = context.GetArgument<Address>(\"owner\");\n        Currency currency = context.GetArgument<Currency>(\"currency\");\n        BlockHash? offsetBlockHash =\n            context.GetArgument<string?>(\"offsetBlockHash\") is { } blockHashString\n                ? BlockHash.FromString(blockHashString)\n                : null;\n        HashDigest<SHA256>? offsetStateRootHash = context\n            .GetArgument<HashDigest<SHA256>?>(\"offsetStateRootHash\");\n\n        switch (blockhash: offsetBlockHash, srh: offsetStateRootHash)\n        {\n            case (blockhash: not null, srh: not null):\n                throw new ExecutionError(\n                    \"offsetBlockHash and offsetStateRootHash cannot be specified at the same time.\"\n                );\n            case (blockhash: null, srh: null):\n                throw new ExecutionError(\n                    \"Either offsetBlockHash or offsetStateRootHash must be specified.\"\n                );\n            case (blockhash: not null, _):\n            {\n                return context.Source\n                    .GetWorldState((BlockHash)offsetBlockHash)\n                    .GetBalance(owner, currency);\n            }\n\n            case (_, srh: not null):\n                return context.Source\n                    .GetWorldState(offsetStateRootHash)\n                    .GetBalance(owner, currency);\n        }\n    }\n\n    private static object? ResolveTotalSupply(IResolveFieldContext<IBlockChainStates> context)\n    {\n        Currency currency = context.GetArgument<Currency>(\"currency\");\n        BlockHash? offsetBlockHash =\n            context.GetArgument<string?>(\"offsetBlockHash\") is { } blockHashString\n                ? BlockHash.FromString(blockHashString)\n                : null;\n        HashDigest<SHA256>? offsetStateRootHash = context\n            .GetArgument<HashDigest<SHA256>?>(\"offsetStateRootHash\");\n\n        switch (blockhash: offsetBlockHash, srh: offsetStateRootHash)\n        {\n            case (blockhash: not null, srh: not null):\n                throw new ExecutionError(\n                    \"offsetBlockHash and offsetStateRootHash cannot be specified at the same time.\"\n                );\n            case (blockhash: null, srh: null):\n                throw new ExecutionError(\n                    \"Either offsetBlockHash or offsetStateRootHash must be specified.\"\n                );\n            case (blockhash: not null, _):\n                return context.Source\n                    .GetWorldState((BlockHash)offsetBlockHash)\n                    .GetTotalSupply(currency);\n            case (_, srh: not null):\n                return context.Source\n                    .GetWorldState(offsetStateRootHash)\n                    .GetTotalSupply(currency);\n        }\n    }\n\n    private static object? ResolveValidatorSet(IResolveFieldContext<IBlockChainStates> context)\n    {\n        BlockHash? offsetBlockHash =\n            context.GetArgument<string?>(\"offsetBlockHash\") is { } blockHashString\n                ? BlockHash.FromString(blockHashString)\n                : null;\n        HashDigest<SHA256>? offsetStateRootHash = context\n            .GetArgument<HashDigest<SHA256>?>(\"offsetStateRootHash\");\n\n        switch (blockhash: offsetBlockHash, srh: offsetStateRootHash)\n        {\n            case (blockhash: not null, srh: not null):\n                throw new ExecutionError(\n                    \"offsetBlockHash and offsetStateRootHash cannot be specified at the same time.\"\n                );\n            case (blockhash: null, srh: null):\n                throw new ExecutionError(\n                    \"Either offsetBlockHash or offsetStateRootHash must be specified.\"\n                );\n            case (blockhash: not null, _):\n                return context.Source\n                    .GetWorldState((BlockHash)offsetBlockHash)\n                    .GetValidatorSet().Validators;\n            case (_, srh: not null):\n                return context.Source\n                    .GetWorldState(offsetStateRootHash)\n                    .GetValidatorSet().Validators;\n        }\n    }\n}\n"
  },
  {
    "path": "tools/Libplanet.Explorer/Queries/TransactionQuery.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Collections.Immutable;\nusing Bencodex;\nusing Bencodex.Types;\nusing GraphQL;\nusing GraphQL.Types;\nusing Libplanet.Blockchain;\nusing Libplanet.Common;\nusing Libplanet.Crypto;\nusing Libplanet.Explorer.GraphTypes;\nusing Libplanet.Explorer.Interfaces;\nusing Libplanet.Types.Blocks;\nusing Libplanet.Types.Tx;\n\nnamespace Libplanet.Explorer.Queries\n{\n    public class TransactionQuery : ObjectGraphType\n    {\n        private static readonly Codec _codec = new Codec();\n        private readonly IBlockChainContext _context;\n\n        // FIXME should be refactored to reduce LoC of constructor.\n        #pragma warning disable MEN003\n        public TransactionQuery(IBlockChainContext context)\n        #pragma warning restore MEN003\n        {\n            _context = context ?? throw new ArgumentNullException(nameof(context));\n\n            Field<NonNullGraphType<ListGraphType<NonNullGraphType<TransactionType>>>>(\n                \"transactions\",\n                arguments: new QueryArguments(\n                    new QueryArgument<AddressType>\n                    {\n                        Name = \"signer\",\n                        DefaultValue = null,\n                    },\n                    new QueryArgument<AddressType>\n                    {\n                        Name = \"involvedAddress\",\n                        DefaultValue = null,\n                    },\n                    new QueryArgument<BooleanGraphType>\n                    {\n                        Name = \"desc\",\n                        DefaultValue = false,\n                    },\n                    new QueryArgument<IntGraphType>\n                    {\n                        Name = \"offset\",\n                        DefaultValue = 0,\n                    },\n                    new QueryArgument<IntGraphType> { Name = \"limit\" }\n                ),\n                resolve: context =>\n                {\n                    var signer = context.GetArgument<Address?>(\"signer\");\n                    bool desc = context.GetArgument<bool>(\"desc\");\n                    long offset = context.GetArgument<long>(\"offset\");\n                    int? limit = context.GetArgument<int?>(\"limit\");\n\n                    return ExplorerQuery.ListTransactions(signer, desc, offset, limit);\n                }\n            );\n\n            Field<NonNullGraphType<ListGraphType<NonNullGraphType<TransactionType>>>>(\n                \"stagedTransactions\",\n                arguments: new QueryArguments(\n                    new QueryArgument<AddressType>\n                    {\n                        Name = \"signer\",\n                        DefaultValue = null,\n                    },\n                    new QueryArgument<AddressType>\n                    {\n                        Name = \"involvedAddress\",\n                        DefaultValue = null,\n                    },\n                    new QueryArgument<BooleanGraphType>\n                    {\n                        Name = \"desc\",\n                        DefaultValue = false,\n                    },\n                    new QueryArgument<IntGraphType>\n                    {\n                        Name = \"offset\",\n                        DefaultValue = 0,\n                    },\n                    new QueryArgument<IntGraphType> { Name = \"limit\" }\n                ),\n                resolve: context =>\n                {\n                    var signer = context.GetArgument<Address?>(\"signer\");\n                    bool desc = context.GetArgument<bool>(\"desc\");\n                    int offset = context.GetArgument<int>(\"offset\");\n                    int? limit = context.GetArgument<int?>(\"limit\", null);\n\n                    return ExplorerQuery.ListStagedTransactions(\n                        signer,\n                        desc,\n                        offset,\n                        limit\n                    );\n                }\n            );\n\n            Field<TransactionType>(\n                \"transaction\",\n                arguments: new QueryArguments(\n                    new QueryArgument<IdGraphType> { Name = \"id\" }\n                ),\n                resolve: context => ExplorerQuery.GetTransaction(\n                    new TxId(ByteUtil.ParseHex(context.GetArgument<string>(\"id\")\n                        ?? throw new ArgumentException(\"Given id cannot be null.\"))))\n            );\n\n            Field<NonNullGraphType<ByteStringType>>(\n                name: \"unsignedTransaction\",\n                arguments: new QueryArguments(\n                    new QueryArgument<NonNullGraphType<StringGraphType>>\n                    {\n                        Name = \"publicKey\",\n                        Description = \"The hexadecimal string of public key for Transaction.\",\n                    },\n                    new QueryArgument<NonNullGraphType<StringGraphType>>\n                    {\n                        Name = \"plainValue\",\n                        Description = \"The hexadecimal string of plain value for Action.\",\n                    },\n                    new QueryArgument<LongGraphType>\n                    {\n                        Name = \"nonce\",\n                        Description = \"The nonce for Transaction.\",\n                    }\n                ),\n                resolve: context =>\n                {\n                    BlockChain chain = _context.BlockChain;\n                    string plainValueString = context.GetArgument<string>(\"plainValue\");\n                    IValue plainValue = _codec.Decode(ByteUtil.ParseHex(plainValueString));\n                    var publicKey = new PublicKey(\n                        ByteUtil.ParseHex(context.GetArgument<string>(\"publicKey\"))\n                    );\n                    Address signer = publicKey.Address;\n                    long nonce = context.GetArgument<long?>(\"nonce\") ??\n                        chain.GetNextTxNonce(signer);\n                    var sigMeta = new TxSigningMetadata(publicKey, nonce);\n                    var invoice = new TxInvoice(\n                        chain.Genesis.Hash,\n                        actions: new TxActionList(new List<IValue>\n                        {\n                            plainValue,\n                        }));\n                    var unsignedTx = new UnsignedTx(invoice, sigMeta);\n                    return unsignedTx.SerializeUnsignedTx();\n                }\n            );\n\n            Field<NonNullGraphType<LongGraphType>>(\n                name: \"nextNonce\",\n                arguments: new QueryArguments(\n                    new QueryArgument<NonNullGraphType<AddressType>>\n                    {\n                        Name = \"address\",\n                        Description = \"Address of the account to get the next tx nonce.\",\n                    }\n                ),\n                resolve: context =>\n                    _context.BlockChain.GetNextTxNonce(context.GetArgument<Address>(\"address\"))\n            );\n\n            Field<NonNullGraphType<StringGraphType>>(\n                name: \"bindSignature\",\n                #pragma warning disable MEN002\n                description: \"Attach the given signature to the given transaction and return tx as hexadecimal\",\n                #pragma warning restore MEN002\n                arguments: new QueryArguments(\n                    new QueryArgument<NonNullGraphType<StringGraphType>>\n                    {\n                        Name = \"unsignedTransaction\",\n                        #pragma warning disable MEN002\n                        Description = \"The hexadecimal string of unsigned transaction to attach the given signature.\",\n                        #pragma warning restore MEN002\n                    },\n                    new QueryArgument<NonNullGraphType<StringGraphType>>\n                    {\n                        Name = \"signature\",\n                        #pragma warning disable MEN002\n                        Description = \"The hexadecimal string of the given unsigned transaction.\",\n                        #pragma warning restore MEN002\n                    }\n                ),\n                resolve: context =>\n                {\n                    ImmutableArray<byte> signature = ByteUtil.ParseHexToImmutable(\n                        context.GetArgument<string>(\"signature\")\n                    );\n                    IUnsignedTx unsignedTx = TxMarshaler.DeserializeUnsignedTx(\n                        ByteUtil.ParseHex(context.GetArgument<string>(\"unsignedTransaction\"))\n                    );\n                    var signedTransaction = unsignedTx.Verify(signature);\n                    return ByteUtil.Hex(signedTransaction.Serialize());\n                }\n            );\n\n            Field<NonNullGraphType<TxResultType>>(\n                name: \"transactionResult\",\n                arguments: new QueryArguments(\n                    new QueryArgument<NonNullGraphType<IdGraphType>>\n                    {\n                        Name = \"txId\",\n                        Description = \"transaction id.\",\n                    }\n                ),\n                resolve: context =>\n                {\n                    var blockChain = _context.BlockChain;\n                    var store = _context.Store;\n                    var index = _context.Index;\n                    var txId = new TxId(ByteUtil.ParseHex(context.GetArgument<string>(\"txId\")));\n\n                    if (GetBlockContainingTx(_context, txId) is { } block)\n                    {\n                        return _context.BlockChain.GetTxExecution(block.Hash, txId) is { } execution\n                            ? new TxResult(\n                                execution.Fail ? TxStatus.FAILURE : TxStatus.SUCCESS,\n                                block.Index,\n                                block.Hash.ToString(),\n                                execution.InputState,\n                                execution.OutputState,\n                                execution.ExceptionNames)\n                            : new TxResult(\n                                TxStatus.INCLUDED,\n                                block.Index,\n                                block.Hash.ToString(),\n                                null,\n                                null,\n                                null);\n                    }\n                    else\n                    {\n                        return blockChain.GetStagedTransactionIds().Contains(txId)\n                            ? new TxResult(\n                                TxStatus.STAGING,\n                                null,\n                                null,\n                                null,\n                                null,\n                                null)\n                            : new TxResult(\n                                TxStatus.INVALID,\n                                null,\n                                null,\n                                null,\n                                null,\n                                null);\n                    }\n                }\n            );\n\n            Name = \"TransactionQuery\";\n        }\n\n        /// <summary>\n        /// Gets the <see cref=\"Block\"/> from the context <see cref=\"BlockChain\"/> containing\n        /// given <paramref name=\"txId\"/>.\n        /// </summary>\n        /// <param name=\"context\">The <see cref=\"IBlockChainContext\"/> to use as context.</param>\n        /// <param name=\"txId\">The target <see cref=\"TxId\"/> that a <see cref=\"Block\"/>\n        /// must contain.</param>\n        /// <returns>The <see cref=\"Block\"/> containing <paramref name=\"txId\"/> if found,\n        /// otherwise <see langword=\"null\"/>.</returns>\n        private static Block? GetBlockContainingTx(IBlockChainContext context, TxId txId)\n        {\n            // Try searching index first.\n            if (context.Index is { } index)\n            {\n                if (index.TryGetContainedBlockHashById(txId, out var blockHash))\n                {\n                    return context.BlockChain[blockHash];\n                }\n            }\n\n            // If not found in index, search IStore directly.\n            var blockHashCandidates = context.Store.IterateTxIdBlockHashIndex(txId);\n            foreach (var blockHashCandidate in blockHashCandidates)\n            {\n                if (context.BlockChain.ContainsBlock(blockHashCandidate))\n                {\n                    return context.BlockChain[blockHashCandidate];\n                }\n            }\n\n            return null;\n        }\n    }\n}\n"
  },
  {
    "path": "tools/Libplanet.Explorer/README.md",
    "content": "Libplanet Explorer\n==================\n\nExplorer blocks, transactions, and addresses on your Libplanet-powered\ndistributed games.  For the frontend, see also [libplanet-explorer-frontend].\n\n[libplanet-explorer-frontend]: https://github.com/planetarium/libplanet-explorer-frontend\n\n\nHow to build and develop\n------------------------\n\nYou need to install [.NET Core] 6.0 or higher.  It works on Linux, macOS,\nand Windows.  After you install them, execute the following command to run\na development server:\n\n~~~~ bash\ndotnet watch -p Libplanet.Explorer.Executable run -- \\\n  --store-path BLOCKCHAIN_STORE_PATH\n~~~~\n\n`BLOCKCHAIN_STORE_PATH` refers to a directory or a file made by\na Libplanet-powered game.  If you need a sample data file please contact us\non [our Discord chat][1]!\n\nIf you omit `--store-path` switch in online mode, explorer will use memory to\nstore blockchain instead of storage.\n\n[.NET Core]: https://dotnet.microsoft.com/\n[PowerShell]: https://microsoft.com/PowerShell\n[1]: https://link.planetarium.dev/libplanet-explorer-readme--pl-dev-discord\n\n\nGraphQL\n-------\n\nThe key purpose of this project is to provide GraphQL endpoint.  The endpoint\nis placed:\n\n    /graphql/\n\n\nGraphQL Playground\n------------------\n\nThis provides a built-in GraphQL Playground.  The web root path serves it:\n\n    /\n\nHow to use progressive features\n-------------------------------\n\nNow, it uses `IRichStore` to improve transaction query speed\nand provide more usable features (e.g., `blockRef`).\n\nIt provides some implementations like below:\n\n - `LiteDBRichStore`\n - `MySQLRichStore`\n\nTo use `MySQLRichStore`, it needs to fill command line arguments started with\n`mysql-` prefix fully and correctly.\nElse, it will use `LiteDBRichStore` as default.\n"
  },
  {
    "path": "tools/Libplanet.Explorer/Schemas/LibplanetExplorerSchema.cs",
    "content": "using System;\nusing GraphQL.Types;\nusing Libplanet.Explorer.Mutations;\nusing Libplanet.Explorer.Queries;\nusing Microsoft.Extensions.DependencyInjection;\n\nnamespace Libplanet.Explorer.Schemas\n{\n    public class LibplanetExplorerSchema : Schema\n    {\n        public LibplanetExplorerSchema(IServiceProvider serviceProvider)\n            : base(serviceProvider)\n        {\n            Query = serviceProvider.GetRequiredService<ExplorerQuery>();\n        }\n    }\n}\n"
  },
  {
    "path": "tools/Libplanet.Explorer/k8s/deployment.yaml",
    "content": "apiVersion: apps/v1beta1\nkind: Deployment\nmetadata:\n  name: block-explorer\nspec:\n  replicas: 1\n  template:\n    metadata:\n      labels:\n        app: block-explorer\n    spec:\n      nodeSelector:\n        \"beta.kubernetes.io/os\": linux\n      containers:\n      - name: block-explorer\n        image: planetariumtest.azurecr.io/<IMAGE_NAME>\n        command:\n          - \"dotnet\"\n          - \"./Libplanet.Explorer.Executable/out/Libplanet.Explorer.dll\"\n          - \"--port 31234\"\n          - \"<STORAGE_PATH>\"\n        livenessProbe:\n          failureThreshold: 3\n          initialDelaySeconds: 120\n          periodSeconds: 5\n          successThreshold: 1\n          tcpSocket:\n            port: 31234\n          timeoutSeconds: 1\n        resources:\n          requests:\n            cpu: 1\n        ports:\n        - containerPort: 31234\n          name: block-explorer\n        volumeMounts:\n          - name: volume\n            mountPath: /data\n      volumes:\n        - name: volume\n          persistentVolumeClaim:\n            claimName: azurefile\n"
  },
  {
    "path": "tools/Libplanet.Explorer/k8s/service.yaml",
    "content": "apiVersion: v1\nkind: Service\nmetadata:\n  name: block-explorer\nspec:\n  ports:\n  - port: 31234\n    nodePort: 31234\n    targetPort: 31234\n  selector:\n    app: block-explorer\n  type: LoadBalancer\n  loadBalancerIP: <BLOCK_EXPLORER_IP>\n"
  },
  {
    "path": "tools/Libplanet.Explorer/run.ps1",
    "content": "#!/usr/bin/env pwsh\nif ($args.Length -lt 1) {\n  $stderr = [Console]::Error.WriteLine\n  $stderr.Invoke(\"error: Too few arguments.\")\n  $stderr.Invoke(\"Try ``run.ps1 --help' for more information.\")\n  exit 1\n} elseif ($args.Contains(\"--help\") -or $args.Contains(\"-h\")) {\n  dotnet run --project . -- @args\n  exit $?\n}\ndotnet watch --project . -- run -- @args\n"
  },
  {
    "path": "tools/Libplanet.Explorer/schema.graphql",
    "content": "schema {\n  query: ExplorerQuery\n}\n\ntype ExplorerQuery {\n  blockQuery: BlockQuery\n  transactionQuery: TransactionQuery\n  stateQuery: LibplanetStateQuery\n  nodeState: NodeState!\n  helperQuery: HelperQuery\n}\n\ntype BlockQuery {\n  blocks(\n    desc: Boolean = false\n    offset: Int = 0\n    limit: Int\n    excludeEmptyTxs: Boolean = false\n    miner: Address\n  ): [Block!]!\n  block(hash: BlockHash, index: Long): Block\n}\n\ntype Block {\n  # A block's hash.\n  hash: BlockHash!\n\n  # The height of the block.\n  index: Long!\n\n  # The address of the miner.\n  miner: Address!\n\n  # The public key of the Miner.\n  publicKey: PublicKey\n\n  # The previous block.  If it's a genesis block (i.e., its index is 0) this must be null.\n  previousBlock: Block\n  timestamp: DateTimeOffset!\n\n  # The hash of the resulting states after evaluating transactions and a block action (if exists)\n  stateRootHash: HashDigestSHA256!\n\n  # The digital signature of the whole block content (except for hash, which is derived from the signature and other contents)\n  signature: ByteString\n\n  # Transactions belonging to the block.\n  transactions: [Transaction!]!\n\n  # The LastCommit of the block.\n  lastCommit: BlockCommit\n\n  # The mining difficulty that the block's nonce has to satisfy.\n  difficulty: Long!\n    @deprecated(reason: \"Block does not have Difficulty field in PBFT.\")\n\n  # The total mining difficulty since the genesis including the block's difficulty.\n  totalDifficulty: BigInt!\n    @deprecated(reason: \"Block does not have TotalDifficulty field in PBFT.\")\n\n  # The proof-of-work nonce which satisfies the required difficulty.\n  nonce: ByteString!\n    @deprecated(reason: \"Block does not have Nonce field in PBFT.\")\n\n  # The hash of PreEvaluationBlock.\n  preEvaluationHash: HashDigestSHA256!\n}\n\nscalar BlockHash\n\nscalar Long\n\nscalar Address\n\nscalar PublicKey\n\n# The `DateTimeOffset` scalar type represents a date, time and offset from UTC. `DateTimeOffset` expects timestamps to be formatted in accordance with the [ISO-8601](https://en.wikipedia.org/wiki/ISO_8601) standard.\nscalar DateTimeOffset\n\nscalar HashDigestSHA256\n\nscalar ByteString\n\ntype Transaction {\n  # A unique identifier derived from this transaction content.\n  id: TxId!\n\n  # The number of previous transactions committed by the signer of this tx.\n  nonce: Long!\n\n  # An address of the account who signed this transaction.\n  signer: Address!\n\n  # A PublicKey of the account who signed this transaction.\n  publicKey: ByteString!\n\n  # Addresses whose states were affected by Actions.\n  updatedAddresses: [Address!]!\n\n  # A digital signature of the content of this transaction.\n  signature: ByteString!\n\n  # The time this transaction was created and signed.\n  timestamp: DateTimeOffset!\n\n  # A list of actions in this transaction.\n  actions: [Action!]!\n\n  # A serialized tx payload in base64 string.\n  serializedPayload: String!\n\n  # The block including the transaction.\n  blockRef: Block!\n}\n\nscalar TxId\n\ntype Action {\n  # Raw Action data ('hex' or 'base64' encoding available.)\n  raw(encode: String = \"hex\"): String!\n\n  # A readable representation for debugging.\n  inspection: String!\n\n  # A JSON representation of action data\n  json: String!\n}\n\ntype BlockCommit {\n  # The height of the block commit.\n  height: Long!\n\n  # The round of the block commit.\n  round: Int!\n\n  # The hash of the block which contains block commit.\n  blockHash: BlockHash!\n\n  # Total votes of the block commit.\n  votes: [Vote!]!\n}\n\ntype Vote {\n  # Height of the consensus voted.\n  height: Long!\n\n  # Round of the consensus voted.\n  round: Int!\n\n  # Hash of the block voted.\n  blockHash: String!\n\n  # The time this vote was created and signed.\n  timestamp: DateTimeOffset!\n\n  # Public key of the validator which is subject of the vote.\n  validatorPublicKey: PublicKey!\n\n  # Flag of the vote\n  flag: VoteFlag!\n\n  # A digital signature of the content of this vote.\n  signature: ByteString!\n}\n\nscalar VoteFlag\n\nscalar BigInt\n\ntype TransactionQuery {\n  transactions(\n    signer: Address\n    desc: Boolean = false\n    offset: Int = 0\n    limit: Int\n  ): [Transaction!]!\n  stagedTransactions(\n    signer: Address\n    desc: Boolean = false\n    offset: Int = 0\n    limit: Int\n  ): [Transaction!]!\n  transaction(id: TxId!): Transaction\n  unsignedTransaction(\n    # The hexadecimal string of public key for Transaction.\n    publicKey: String!\n\n    # The hexadecimal string of plain value for Action.\n    plainValue: String!\n\n    # The nonce for Transaction.\n    nonce: Long\n  ): ByteString!\n  nextNonce(\n    # Address of the account to get the next tx nonce.\n    address: Address!\n  ): Long!\n\n  # Attach the given signature to the given transaction and return tx as hexadecimal\n  bindSignature(\n    # The hexadecimal string of unsigned transaction to attach the given signature.\n    unsignedTransaction: String!\n\n    # The hexadecimal string of the given unsigned transaction.\n    signature: String!\n  ): String!\n  transactionResult(\n    # transaction id.\n    txId: TxId!\n  ): TxResult!\n}\n\ntype TxResult {\n  # The transaction status.\n  txStatus: TxStatus!\n\n  # The block index which the target transaction executed.\n  blockIndex: Long\n\n  # The block hash which the target transaction executed.\n  blockHash: String\n\n  # The input state's root hash which the target transaction executed.\n  inputState: HashDigestSHA256\n\n  # The output state's root hash which the target transaction executed.\n  outputState: HashDigestSHA256\n\n  # The name of exception. (when only failed)\n  exceptionNames: [String]\n}\n\nenum TxStatus {\n  INVALID\n  STAGING\n  SUCCESS\n  FAILURE\n  INCLUDED\n}\n\ntype LibplanetStateQuery {\n  world(blockHash: BlockHash, stateRootHash: HashDigestSHA256): WorldState!\n\n  # Retrieves states from the legacy account.\n  states(\n    addresses: [Address!]!\n    offsetBlockHash: BlockHash\n    offsetStateRootHash: HashDigestSHA256\n  ): [BencodexValue]!\n\n  # Retrieves balance from the legacy account.\n  balance(\n    owner: Address!\n    currency: CurrencyInput!\n    offsetBlockHash: BlockHash\n    offsetStateRootHash: HashDigestSHA256\n  ): FungibleAssetValue!\n\n  # Retrieves total supply from the legacy account.\n  totalSupply(\n    currency: CurrencyInput!\n    offsetBlockHash: BlockHash\n    offsetStateRootHash: HashDigestSHA256\n  ): FungibleAssetValue\n\n  # Retrieves validator set from the legacy account.\n  validators(\n    offsetBlockHash: BlockHash\n    offsetStateRootHash: HashDigestSHA256\n  ): [Validator!]\n}\n\ntype WorldState {\n  # The state root hash of the world state.\n  stateRootHash: HashDigestSHA256!\n\n  # The legacy flag of the world state.\n  legacy: Boolean!\n\n  # Gets the account associated with given address.\n  account(\n    # The address of an account to retrieve.\n    address: Address!\n  ): AccountState!\n\n  # Gets the accounts associated with given addresses.\n  accounts(\n    # The list of addresses of accounts to retrieve.\n    addresses: [Address!]!\n  ): [AccountState!]!\n}\n\n# Represents a raw account state.  This is meant to represent a raw storage state void of any application layer context and/or logic.  In particular, this does not deal with currency or fungible asset value directly, which requires additional information on currency such as its ticker and possible minters, etc. while interpreting the data retrieved with the provided contextual information. The same is true for validator sets.\ntype AccountState {\n  # The state root hash associated with this account state.\n  stateRootHash: HashDigestSHA256!\n\n  # The state at given address.\n  state(\n    # The address to look up.\n    address: Address!\n  ): IValue\n\n  # The states at given addresses.\n  states(\n    # The list of addresses to look up.\n    addresses: [Address!]!\n  ): [IValue]!\n\n  # Balance at given address and currency hash pair.\n  balance(\n    # The address to look up.\n    address: Address!\n\n    # The currency hash to look up.\n    currencyHash: HashDigestSHA1!\n  ): IValue\n\n  # Balances at given addresses and currency hash pair.\n  balances(\n    # The list of addresses to look up.\n    addresses: [Address!]!\n\n    # The currency hash to look up.\n    currencyHash: HashDigestSHA1!\n  ): [IValue]!\n\n  # Total supply in circulation, if recorded, for given currency hash.\n  totalSupply(\n    # The currency hash to look up.\n    currencyHash: HashDigestSHA1!\n  ): IValue\n\n  # The validator set.\n  validatorSet: IValue\n}\n\ntype IValue {\n  # A hexadecimal representation of the bencodex value encoded as byte array.\n  hex: String!\n\n  # A base64 representation of the bencodex value encoded to byte array.\n  base64: String!\n\n  # A human readable representation of the bencodex value.\n  inspection: String!\n\n  # A JSON representation of the bencodex value\n  json: String!\n}\n\nscalar HashDigestSHA1\n\nscalar BencodexValue\n\n# Holds a fungible asset value which holds its currency together.\ntype FungibleAssetValue {\n  # The currency of the fungible asset.\n  currency: Currency!\n\n  # Gets a number that indicates the sign (-1: negative, 1: positive, or 0: zero) of the value.\n  sign: Int!\n  majorUnit: BigInt!\n  minorUnit: BigInt!\n\n  # The value quantity without its currency in string, e.g., \"123.45\".\n  quantity: String!\n\n  # The value quantity with its currency in string, e.g., \"123.45 ABC\".\n  string: String!\n}\n\ntype Currency {\n  # The ticker symbol, e.g., USD.\n  ticker: String!\n\n  # The number of digits to treat as minor units (i.e., exponents).\n  decimalPlaces: Byte!\n\n  # The addresses who can mint this currency.  If this is null anyone can mint the currency.  On the other hand, unlike null, an empty set means no one can mint the currency.\n  minters: [Address!]\n\n  # The uppermost quantity of currency allowed to exist.  null means unlimited supply.\n  maximumSupply: FungibleAssetValue\n\n  # Whether the total supply of this currency is trackable.\n  totalSupplyTrackable: Boolean!\n\n  # The deterministic hash derived from other fields.\n  hash: HashDigestSHA1!\n}\n\nscalar Byte\n\ninput CurrencyInput {\n  # The ticker symbol, e.g., USD.\n  ticker: String!\n\n  # The number of digits to treat as minor units (i.e., exponents).\n  decimalPlaces: Byte!\n\n  # The addresses who can mint this currency.  If this is null anyone can mint the currency.  On the other hand, unlike null, an empty set means no one can mint the currency.\n  minters: [Address!]\n  maximumSupplyMajorUnit: BigInt\n  maximumSupplyMinorUnit: BigInt\n\n  # Whether the total supply of this currency is trackable.\n  totalSupplyTrackable: Boolean\n}\n\n# A data type holds validator's public key and its voting power.\ntype Validator {\n  # The public key of the validator.\n  publicKey: PublicKey!\n\n  # Gets the voting power of the validator.\n  power: BigInt!\n}\n\ntype NodeState {\n  preloaded: Boolean!\n  peers: [BoundPeer!]\n  validators: [BoundPeer!]\n}\n\ntype BoundPeer {\n  # The public key of the peer.\n  publicKey: PublicKey!\n\n  # The endpoint of the peer.\n  endPoint: String!\n\n  # The address of the miner.\n  publicIpAddress: String\n}\n\n# A number of queries for convenience.\ntype HelperQuery {\n  # Converts currency info to currency hash.\n  currencyHash(\n    # The currency to convert.\n    currency: CurrencyInput!\n  ): HashDigestSHA1!\n\n  # Decodes hex encoded bencodex value\n  bencodexValue(\n    # The byte array in hex representation to decode.\n    hex: String!\n  ): IValue!\n}\n"
  },
  {
    "path": "tools/Libplanet.Explorer/sql/initialize-rich-store.sql",
    "content": "CREATE TABLE IF NOT EXISTS `tx_references` (\n    CONSTRAINT `uid` UNIQUE (`tx_id`, `block_hash`),\n\n    `tx_id`         BINARY(32),\n    `block_hash`    BINARY(32),\n    `tx_nonce`      BIGINT\n);\n\nCREATE TABLE IF NOT EXISTS `signer_references` (\n    CONSTRAINT `uid` UNIQUE (`signer`, `tx_id`),\n\n    `signer`    BINARY(20),\n    `tx_id`     BINARY(32),\n    `tx_nonce`  BIGINT\n);\n\nCREATE TABLE IF NOT EXISTS `updated_address_references` (\n    CONSTRAINT `uid` UNIQUE (`updated_address`, `tx_id`),\n\n    `updated_address`   BINARY(20),\n    `tx_id`             BINARY(32),\n    `tx_nonce`          BIGINT\n);\n"
  },
  {
    "path": "tools/Libplanet.Explorer.Cocona/AssemblyInfo.cs",
    "content": "using System.Runtime.CompilerServices;\n\n[assembly: InternalsVisibleTo(\"Libplanet.Explorer.Cocona.Tests\")]\n"
  },
  {
    "path": "tools/Libplanet.Explorer.Cocona/Commands/IndexCommand.cs",
    "content": "using System;\nusing System.Threading.Tasks;\nusing Cocona;\nusing Cocona.Help;\nusing Libplanet.Explorer.Indexing;\nusing Libplanet.Extensions.Cocona;\nusing Libplanet.Store;\nusing Serilog;\n\nnamespace Libplanet.Explorer.Cocona.Commands\n{\n    /// <summary>\n    /// A class that provides <see cref=\"Cocona\"/> commands related to\n    /// <see cref=\"IBlockChainIndex\"/>.\n    /// </summary>\n    public class IndexCommand : CoconaLiteConsoleAppBase\n    {\n        private const string StoreArgumentDescription =\n            \"The URI that represents the backend of an \" + nameof(IStore) + \" object.\"\n            + \" <store-type>://<store-path> (e.g., rocksdb+file:///path/to/store)\";\n\n        private const string IndexArgumentDescription =\n            \"The URI that represents the backend of an \" + nameof(IBlockChainIndex) + \" object.\"\n            + \" <index-type>://<index-path (e.g., sqlite+file:///path/to/store)\";\n\n        public IndexCommand()\n        {\n            Log.Logger = new LoggerConfiguration()\n                .WriteTo.Console()\n                .CreateLogger();\n        }\n\n        [Command(\n            Description =\n                \"Synchronizes an index database for use with libplanet explorer services.\")]\n        public async Task Sync(\n            [Argument(\"STORE\", Description = StoreArgumentDescription)]\n            string storeUri,\n            [Argument(\"INDEX\", Description = IndexArgumentDescription)]\n            string indexUri\n        )\n        {\n            try\n            {\n                await LoadIndexFromUri(indexUri).SynchronizeAsync(\n                        Utils.LoadStoreFromUri(storeUri), Context.CancellationToken)\n                    .ConfigureAwait(false);\n            }\n            catch (OperationCanceledException)\n            {\n            }\n        }\n\n        [PrimaryCommand]\n        public void Help([FromService] ICoconaHelpMessageBuilder helpMessageBuilder) =>\n            Console.Error.WriteLine(helpMessageBuilder.BuildAndRenderForCurrentContext());\n\n        internal static IBlockChainIndex LoadIndexFromUri(string uriString)\n        {\n            // Adapted from Libplanet.Extensions.Cocona.Utils.LoadStoreFromUri().\n            // TODO: Cocona supports .NET's TypeConverter protocol for instantiating objects\n            // from CLI options/arguments.  We'd better to implement it for IStore, and simply\n            // use IStore as the option/argument types rather than taking them as strings.\n            var uri = new Uri(uriString);\n\n            var protocol = uri.Scheme.Split('+')[0];\n            var transport = string.Join('+', uri.Scheme.Split('+')[1..]);\n\n            if (string.IsNullOrWhiteSpace(transport))\n            {\n                throw new ArgumentException(\n                    $\"The index URI scheme must contain a transport (e.g. sqlite+file://).\",\n                    nameof(uriString)\n                );\n            }\n\n            if (protocol is \"rocksdb\" && transport is \"file\")\n            {\n                return new RocksDbBlockChainIndex(uri.LocalPath);\n            }\n\n            throw new ArgumentException(\n                $\"The index URI scheme {uri.Scheme}:// is not supported.\",\n                nameof(uriString)\n            );\n        }\n    }\n}\n"
  },
  {
    "path": "tools/Libplanet.Explorer.Cocona/Libplanet.Explorer.Cocona.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <PropertyGroup>\n    <TreatWarningsAsErrors>true</TreatWarningsAsErrors>\n    <NoWarn>$(NoWarn);CS1591;S1118;SA1118;NU1903</NoWarn>\n    </PropertyGroup>\n\n  <ItemGroup>\n    <PackageReference Include=\"Cocona.Lite\" Version=\"2.0.*\" />\n    <PackageReference Include=\"Serilog.Sinks.Console\" Version=\"4.1.0\" />\n    <PackageReference Include=\"System.Text.Json\" Version=\"9.0.*\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <ProjectReference Include=\"..\\..\\src\\Libplanet\\Libplanet.csproj\" />\n    <ProjectReference Include=\"..\\..\\src\\Libplanet.RocksDBStore\\Libplanet.RocksDBStore.csproj\" />\n    <ProjectReference Include=\"..\\Libplanet.Explorer\\Libplanet.Explorer.csproj\" />\n    <ProjectReference Include=\"..\\Libplanet.Extensions.Cocona\\Libplanet.Extensions.Cocona.csproj\" />\n  </ItemGroup>\n\n  <ItemGroup Condition=\"'$(SkipSonar)' != 'true'\">\n    <PackageReference Remove=\"SonarAnalyzer.CSharp\" />\n  </ItemGroup>\n\n</Project>\n"
  },
  {
    "path": "tools/Libplanet.Explorer.Executable/Exceptions/InvalidOptionValueException.cs",
    "content": "using System;\n\nnamespace Libplanet.Explorer.Executable.Exceptions\n{\n    public class InvalidOptionValueException : Exception\n    {\n        public InvalidOptionValueException(\n            string optionName,\n            string optionValue,\n            string[] expectedValues)\n        {\n            OptionName = optionName;\n            OptionValue = optionValue;\n            ExpectedValues = expectedValues;\n        }\n\n        public string OptionName { get; }\n\n        public string OptionValue { get; }\n\n        public string[] ExpectedValues { get; }\n    }\n}\n"
  },
  {
    "path": "tools/Libplanet.Explorer.Executable/Libplanet.Explorer.Executable.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <PropertyGroup>\n    <Nullable>disable</Nullable>\n    <OutputType>Exe</OutputType>\n    <TreatWarningsAsErrors>true</TreatWarningsAsErrors>\n    <NoWarn>$(NoWarn);NU1701,SA1118,SYSLIB0014</NoWarn>\n    <CodeAnalysisRuleSet>..\\..\\Libplanet.Explorer.ruleset</CodeAnalysisRuleSet>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <PackageReference Include=\"Serilog.AspNetCore\" Version=\"2.1.1\" />\n    <PackageReference Include=\"Serilog.Sinks.Console\" Version=\"3.1.1\" />\n    <PackageReference Include=\"Cocona.Lite\" Version=\"1.5.0\" />\n  </ItemGroup>\n\n  <ItemGroup Condition=\"'$(SkipSonar)' != 'true'\">\n    <PackageReference Remove=\"SonarAnalyzer.CSharp\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <ProjectReference Include=\"..\\Libplanet.Explorer\\Libplanet.Explorer.csproj\" />\n    <ProjectReference Include=\"..\\..\\src\\Libplanet.Net\\Libplanet.Net.csproj\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <Content Include=\"wwwroot\\**\\*\">\n      <CopyToPublishDirectory>Always</CopyToPublishDirectory>\n    </Content>\n  </ItemGroup>\n\n</Project>\n"
  },
  {
    "path": "tools/Libplanet.Explorer.Executable/Options.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Net;\nusing System.Threading.Tasks;\nusing Bencodex;\nusing Libplanet.Blockchain.Policies;\nusing Libplanet.Common;\nusing Libplanet.Crypto;\nusing Libplanet.Net;\nusing Libplanet.Types.Blocks;\n\nnamespace Libplanet.Explorer.Executable\n{\n    public class Options\n    {\n        private static readonly Codec Codec = new Codec();\n\n        public Options(\n            bool debug,\n            string host,\n            int port,\n            int blockIntervalMilliseconds,\n            string appProtocolVersionToken,\n            int maxTransactionsPerBlock,\n            int maxTransactionsBytes,\n            int maxGenesisTransactionsBytes,\n            IEnumerable<string> seedStrings,\n            string iceServerUrl,\n            string storePath,\n            string storeType,\n            string genesisBlockPath\n        )\n        {\n            Debug = debug;\n            Host = host;\n            Port = port;\n            BlockIntervalMilliseconds = blockIntervalMilliseconds;\n            AppProtocolVersionToken = appProtocolVersionToken;\n            MaxTransactionsPerBlock = maxTransactionsPerBlock;\n            MaxTransactionsBytes = maxTransactionsBytes;\n            MaxGenesisTransactionsBytes = maxGenesisTransactionsBytes;\n            SeedStrings = seedStrings;\n            IceServerUrl = iceServerUrl;\n            StorePath = storePath;\n            StoreType = storeType;\n            GenesisBlockPath = genesisBlockPath;\n        }\n\n        public bool Debug { get; set; }\n\n        public string Host { get; set; }\n\n        public int Port { get; set; }\n\n        public int BlockIntervalMilliseconds { get; set; }\n\n        public string AppProtocolVersionToken { get; set; }\n\n        public int MaxTransactionsPerBlock { get; set; }\n\n        public int MaxTransactionsBytes { get; set; }\n\n        public int MaxGenesisTransactionsBytes { get; set; }\n\n        public IEnumerable<string> SeedStrings\n        {\n            get\n            {\n                return Seeds?.Select(seed => $\"{ByteUtil.Hex(seed.PublicKey.Format(true))},\" +\n                                             $\"{seed.EndPoint.Host},{seed.EndPoint.Port}\");\n            }\n\n            set\n            {\n                Seeds = value?.Select(str =>\n                {\n                    string[] parts = str.Split(',');\n                    if (parts.Length != 3)\n                    {\n                        throw new FormatException(\n                            $\"A seed must be a command-separated triple. {str}\");\n                    }\n\n                    byte[] pubkeyBytes = ByteUtil.ParseHex(parts[0]);\n                    var pubkey = new PublicKey(pubkeyBytes);\n                    var endpoint = new DnsEndPoint(parts[1], int.Parse(parts[2]));\n                    return new BoundPeer(pubkey, endpoint);\n                });\n            }\n        }\n\n        public IEnumerable<BoundPeer> Seeds { get; set; }\n\n        public string IceServerUrl\n        {\n            get => IceServer is null ? null : IceServer.Url.ToString();\n            set => IceServer = value is null ? null : new IceServer(value);\n        }\n\n        public IceServer IceServer { get; set; }\n\n        public string StorePath { get; set; }\n\n        public string StoreType { get; set; }\n\n        public string GenesisBlockPath { get; set; }\n\n        internal async Task<Block> GetGenesisBlockAsync(IBlockPolicy policy)\n        {\n#if NETSTATNDARD2_1_OR_GREATER\n            var uri = new Uri(GenesisBlockPath);\n            awai Task.CompletedTask;\n            using (var client = new WebClient())\n            {\n                var serialized = client.DownloadData(uri);\n                var dict = (Bencodex.Types.Dictionary)Codec.Decode(serialized);\n                return BlockMarshaler.UnmarshalBlock(dict);\n            }\n#elif NET6_0_OR_GREATER\n            var uri = new Uri(GenesisBlockPath);\n            using (var client = new System.Net.Http.HttpClient())\n            {\n                var serialized = await client.GetByteArrayAsync(uri);\n                var dict = (Bencodex.Types.Dictionary)Codec.Decode(serialized);\n                return BlockMarshaler.UnmarshalBlock(dict);\n            }\n#else\n            throw new System.PlatformNotSupportedException();\n#endif\n        }\n    }\n}\n"
  },
  {
    "path": "tools/Libplanet.Explorer.Executable/Program.cs",
    "content": "using System;\nusing System.Collections.Immutable;\nusing System.Diagnostics.CodeAnalysis;\nusing System.Linq;\nusing System.Security.Cryptography;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing Cocona;\nusing GraphQL.Server;\nusing GraphQL.Utilities;\nusing Libplanet.Action;\nusing Libplanet.Action.Loader;\nusing Libplanet.Blockchain;\nusing Libplanet.Blockchain.Policies;\nusing Libplanet.Common;\nusing Libplanet.Crypto;\nusing Libplanet.Explorer.Executable.Exceptions;\nusing Libplanet.Explorer.Indexing;\nusing Libplanet.Explorer.Interfaces;\nusing Libplanet.Explorer.Schemas;\nusing Libplanet.Net;\nusing Libplanet.Net.Options;\nusing Libplanet.Net.Transports;\nusing Libplanet.Store;\nusing Libplanet.Store.Trie;\nusing Libplanet.Types.Blocks;\nusing Libplanet.Types.Tx;\nusing Microsoft.AspNetCore;\nusing Microsoft.AspNetCore.Hosting;\nusing Microsoft.Extensions.DependencyInjection;\nusing NetMQ;\nusing Serilog;\nusing Serilog.Events;\n\nnamespace Libplanet.Explorer.Executable\n{\n    /// <summary>\n    /// The program entry point to run a web server.\n    /// </summary>\n    public class Program : CoconaLiteConsoleAppBase\n    {\n        public static async Task Main(string[] args)\n        {\n            if (args.Length > 0 && !new string[]\n            {\n                \"serve\",\n                \"schema\",\n            }.Contains(args[0]))\n            {\n                Console.Error.WriteLine(\n                    \"NOTICE: the root primary command has been deprecated and moved \" +\n                    \"to the `serve` command. Currently the root primary command forwards \" +\n                    \"to the `serve` command but it'll be obsoleted in the 0.47.0 release.\");\n            }\n\n            await CoconaLiteApp.RunAsync<Program>(args);\n        }\n\n        [Command(Description = \"Show GraphQL schema\")]\n        public void Schema()\n        {\n            var serviceCollection = new ServiceCollection();\n            serviceCollection.AddGraphQL()\n                .AddGraphTypes(typeof(LibplanetExplorerSchema));\n\n            serviceCollection.AddSingleton<IBlockChainContext, Startup>();\n            serviceCollection.AddSingleton<IStore, MemoryStore>();\n\n            IServiceProvider serviceProvider = serviceCollection.BuildServiceProvider();\n            var schema = new LibplanetExplorerSchema(serviceProvider);\n            var printer = new SchemaPrinter(schema);\n\n            Console.WriteLine(printer.Print());\n        }\n\n        // This command has been deprecated. The `serve` command should be used instead.\n        // FIXME: Obsolete this command in 0.47.0 release.\n        [CommandMethodForwardedTo(typeof(Program), nameof(Serve))]\n        [PrimaryCommand]\n        public void Run()\n            => throw new NotSupportedException();\n\n        [Command(Description = \"Run libplanet-explorer with options.\")]\n        [SuppressMessage(\n            \"Microsoft.StyleCop.CSharp.ReadabilityRules\",\n            \"MEN003\",\n            Justification = \"Many lines are required for running the method.\")]\n        public async Task Serve(\n            [Option(\n                \"store-path\",\n                new[] { 'P' },\n                Description = @\"The path of the blockchain store. If omitted (default)\nin memory version is used.\")]\n            string storePath,\n            [Option(\n                \"store-type\",\n                new[] { 'T' },\n                Description = @\"The type of the blockchain store. If omitted (default)\nin DefaultStore is used.\")]\n            string storeType,\n            [Option(\n                \"genesis-block\",\n                new[] { 'G' },\n                Description = \"The path of the genesis block. It should be absolute or http url.\")]\n            string genesisBlockPath,\n            [Option(\"debug\", new[] { 'd' }, Description = \"Print logs for debugging as well.\")]\n            bool debug = false,\n            [Option(\"host\", new[] { 'H' }, Description = \"The host address to listen.\")]\n            string host = \"0.0.0.0\",\n            [Option(\"port\", new[] { 'p' }, Description = \"The port number to listen.\")]\n            int port = 5000,\n            [Option(\n                \"block-interval\",\n                new[] { 'i' },\n                Description = @\"An appropriate interval in milliseconds between\nconsecutive blocks.\")]\n            int blockIntervalMilliseconds = 5000,\n            [Option(\n                \"app-protocol-version\",\n                new[] { 'V' },\n                Description = \"An app protocol version token.\")]\n            string appProtocolVersionToken = null,\n            [Option(\n                \"max-transactions-per-block\",\n                Description = @\"The number of maximum transactions able to be included\nin a block.\")]\n            int maxTransactionsPerBlock = 100,\n            [Option(\n                \"max-transactions-bytes\",\n                Description = @\"The number of maximum bytes size of all transactions in a block\nexcept for genesis block.\")]\n            int maxTransactionsBytes = 100 * 1024,\n            [Option(\n                \"max-genesis-transactions-bytes\",\n                Description = @\"The number of maximum bytes size of all transactions\nin the genesis block.\")]\n            int maxGenesisTransactionsBytes = 1024 * 1024,\n            [Option(\n                \"seed\",\n                new[] { 's' },\n                Description = @\"Seed nodes to join to the network as a node. The format of each\nseed is a comma-separated triple of a peer's hexadecimal public key, host, and port number.\nE.g., `02ed49dbe0f2c34d9dff8335d6dd9097f7a3ef17dfb5f048382eebc7f451a50aa1,example.com,31234'.\nIf omitted (default) explorer only the local blockchain store.\")]\n            string[] seedStrings = null,\n            [Option(\n                \"ice-server\",\n                new[] { 'I' },\n                Description = \"URL to ICE server (TURN/STUN) to work around NAT.\")]\n            string iceServerUrl = null\n        )\n        {\n            Options options = new Options(\n                debug,\n                host,\n                port,\n                blockIntervalMilliseconds,\n                appProtocolVersionToken,\n                maxTransactionsPerBlock,\n                maxTransactionsBytes,\n                maxGenesisTransactionsBytes,\n                seedStrings,\n                iceServerUrl,\n                storePath,\n                storeType,\n                genesisBlockPath);\n\n            var loggerConfig = new LoggerConfiguration();\n            loggerConfig = options.Debug\n                ? loggerConfig.MinimumLevel.Debug()\n                : loggerConfig.MinimumLevel.Information();\n            loggerConfig = loggerConfig\n                .MinimumLevel.Override(\"Microsoft\", LogEventLevel.Information)\n                .Enrich.FromLogContext()\n                .WriteTo.Console();\n            Log.Logger = loggerConfig.CreateLogger();\n\n            try\n            {\n                IStore store = LoadStore(options);\n                IStateStore stateStore = new NoOpStateStore();\n\n                IBlockPolicy policy =\n                    new DumbBlockPolicy(LoadBlockPolicy(options));\n                IStagePolicy stagePolicy =\n                    new VolatileStagePolicy();\n                var blockChainStates = new BlockChainStates(store, stateStore);\n                var blockChain =\n                    new BlockChain(\n                        policy,\n                        stagePolicy,\n                        store,\n                        stateStore,\n                        await options.GetGenesisBlockAsync(policy),\n                        blockChainStates,\n                        new ActionEvaluator(\n                            policy.PolicyActionsRegistry,\n                            stateStore,\n                            new SingleActionLoader(typeof(NullAction))));\n                Startup.PreloadedSingleton = false;\n                Startup.BlockChainSingleton = blockChain;\n                Startup.StoreSingleton = store;\n\n                IWebHost webHost = WebHost.CreateDefaultBuilder()\n                    .UseStartup<ExplorerStartup<Startup>>()\n                    .UseSerilog()\n                    .UseUrls($\"http://{options.Host}:{options.Port}/\")\n                    .Build();\n\n                Swarm swarm = null;\n                if (!(options.Seeds is null))\n                {\n                    string aggregatedSeedStrings =\n                        options.SeedStrings.Aggregate(string.Empty, (s, s1) => s + s1);\n                    Console.Error.WriteLine(\n                        $\"Seeds are {aggregatedSeedStrings}\");\n\n                    // TODO: Take privateKey as a CLI option\n                    // TODO: Take appProtocolVersion as a CLI option\n                    // TODO: Take host as a CLI option\n                    // TODO: Take listenPort as a CLI option\n                    if (options.IceServer is null)\n                    {\n                        Console.Error.WriteLine(\n                            \"error: -s/--seed option requires -I/--ice-server as well.\"\n                        );\n                        Environment.Exit(1);\n                        return;\n                    }\n\n                    Console.Error.WriteLine(\"Creating Swarm.\");\n\n                    var privateKey = new PrivateKey();\n                    var consensusPrivateKey = new PrivateKey();\n\n                    // FIXME: The appProtocolVersion should be fixed properly.\n                    var swarmOptions = new SwarmOptions\n                    {\n                        BootstrapOptions = new BootstrapOptions\n                        {\n                            SeedPeers = options.Seeds.ToImmutableList(),\n                        },\n                        TimeoutOptions = new TimeoutOptions\n                        {\n                            MaxTimeout = TimeSpan.FromSeconds(10),\n                        },\n                    };\n\n                    var apvOptions = new AppProtocolVersionOptions()\n                    {\n                        AppProtocolVersion = options.AppProtocolVersionToken is string t\n                            ? AppProtocolVersion.FromToken(t)\n                            : default(AppProtocolVersion),\n                    };\n\n                    var hostOptions = new HostOptions(null, new[] { options.IceServer });\n\n                    var transport = await NetMQTransport.Create(\n                        privateKey,\n                        apvOptions,\n                        hostOptions,\n                        swarmOptions.MessageTimestampBuffer);\n\n                    swarm = new Swarm(\n                        blockChain,\n                        privateKey,\n                        transport,\n                        options: swarmOptions);\n                }\n\n                Startup.SwarmSingleton = swarm;\n\n                using (var cts = new CancellationTokenSource())\n                using (swarm)\n                {\n                    Console.CancelKeyPress += (sender, eventArgs) =>\n                    {\n                        eventArgs.Cancel = true;\n                        cts.Cancel();\n                    };\n\n                    try\n                    {\n                        await Task.WhenAll(\n                            webHost.RunAsync(cts.Token),\n                            StartSwarmAsync(swarm, cts.Token)\n                        );\n                    }\n                    catch (OperationCanceledException)\n                    {\n                        await swarm?.StopAsync(waitFor: TimeSpan.FromSeconds(1))\n                            .ContinueWith(_ => NetMQConfig.Cleanup(false));\n                    }\n                }\n            }\n            catch (InvalidOptionValueException e)\n            {\n                string expectedValues = string.Join(\", \", e.ExpectedValues);\n                Console.Error.WriteLine($\"Unexpected value given through '{e.OptionName}'\\n\"\n                          + $\"  given value: {e.OptionValue}\\n\"\n                          + $\"  expected values: {expectedValues}\");\n            }\n        }\n\n        private static IStore LoadStore(Options options)\n        {\n            // FIXME: This method basically does the same thing to Libplanet.Extensions.Cocona's\n            // Utils.LoadStoreFromUri() method.\n            // The duplicate code should be extract to a shared common method.\n            // https://github.com/planetarium/libplanet/issues/1573\n            bool readOnlyMode = options.Seeds is null;\n            switch (options.StoreType)\n            {\n                case \"rocksdb\":\n                    return new RocksDBStore.RocksDBStore(\n                      options.StorePath,\n                      maxTotalWalSize: 16 * 1024 * 1024,\n                      keepLogFileNum: 1);\n                case \"default\":\n                    return new DefaultStore(\n                        options.StorePath,\n                        flush: false,\n                        readOnly: readOnlyMode);\n                default:\n                    // FIXME: give available store type as argument hint without code duplication.\n                    var availableStoreTypes = new[] { \"rocksdb\", \"default\" };\n                    const string longOptionName = \"store-type\";\n                    throw new InvalidOptionValueException(\n                        \"--\" + longOptionName,\n                        options.StoreType,\n                        availableStoreTypes);\n            }\n        }\n\n        private static BlockPolicy LoadBlockPolicy(Options options)\n        {\n            return new BlockPolicy(\n                new PolicyActionsRegistry(),\n                blockInterval: TimeSpan.FromMilliseconds(options.BlockIntervalMilliseconds),\n                getMaxTransactionsBytes: i => i > 0\n                    ? options.MaxTransactionsBytes\n                    : options.MaxGenesisTransactionsBytes,\n                getMaxTransactionsPerBlock: _ => options.MaxTransactionsPerBlock);\n        }\n\n        private static async Task StartSwarmAsync(Swarm swarm, CancellationToken cancellationToken)\n        {\n            if (swarm is null)\n            {\n                Startup.PreloadedSingleton = true;\n                return;\n            }\n\n            try\n            {\n                Console.Error.WriteLine(\"Bootstrapping.\");\n                await swarm.BootstrapAsync(cancellationToken);\n            }\n            catch (TimeoutException)\n            {\n                Console.Error.WriteLine(\"No any neighbors.\");\n            }\n\n            Console.Error.WriteLine(\"Starts preloading.\");\n            await swarm.PreloadAsync(cancellationToken: cancellationToken);\n            Console.Error.WriteLine(\"Finished preloading.\");\n            Startup.PreloadedSingleton = true;\n\n            await swarm.StartAsync(cancellationToken: cancellationToken);\n        }\n\n        internal class DumbBlockPolicy : IBlockPolicy\n        {\n            private readonly IBlockPolicy _impl;\n\n            public DumbBlockPolicy(BlockPolicy blockPolicy)\n            {\n                _impl = blockPolicy;\n            }\n\n            public IPolicyActionsRegistry PolicyActionsRegistry => _impl.PolicyActionsRegistry;\n\n            public int GetMinTransactionsPerBlock(long index) =>\n                _impl.GetMinTransactionsPerBlock(index);\n\n            public int GetMaxTransactionsPerBlock(long index) =>\n                _impl.GetMaxTransactionsPerBlock(index);\n\n            public long GetMaxTransactionsBytes(long index) =>\n                _impl.GetMaxTransactionsBytes(index);\n\n            public TxPolicyViolationException ValidateNextBlockTx(\n                BlockChain blockChain,\n                Transaction transaction) =>\n                _impl.ValidateNextBlockTx(blockChain, transaction);\n\n            public BlockPolicyViolationException ValidateNextBlock(\n                BlockChain blockChain,\n                Block nextBlock\n            ) => _impl.ValidateNextBlock(blockChain, nextBlock);\n\n            public int GetMaxTransactionsPerSignerPerBlock(long index) =>\n                _impl.GetMaxTransactionsPerSignerPerBlock(index);\n\n            public long GetMaxEvidencePendingDuration(long index) =>\n                _impl.GetMaxEvidencePendingDuration(index);\n        }\n\n        internal class Startup : IBlockChainContext\n        {\n            public bool Preloaded => PreloadedSingleton;\n\n            public BlockChain BlockChain => BlockChainSingleton;\n\n            public IStore Store => StoreSingleton;\n\n            public Swarm Swarm => SwarmSingleton;\n\n            // XXX workaround for build; we decided to decommission Libplanet.Explorer.Executable\n            // project, but it will be removed after we move the schema command. As this project\n            // does not work as is, this change is barely enough to allow the build.\n            // See also: https://github.com/planetarium/libplanet/discussions/2588\n            public IBlockChainIndex Index => null;\n\n            internal static bool PreloadedSingleton { get; set; }\n\n            internal static BlockChain BlockChainSingleton { get; set; }\n\n            internal static IStore StoreSingleton { get; set; }\n\n            internal static Swarm SwarmSingleton { get; set; }\n        }\n\n        private class NoOpStateStore : IStateStore\n        {\n            public ITrie GetStateRoot(HashDigest<SHA256>? stateRootHash) => null;\n\n            public ITrie Commit(ITrie trie) => null;\n\n            public void Dispose()\n            {\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "tools/Libplanet.Explorer.Executable/wwwroot/playground.html",
    "content": "<!DOCTYPE html>\n<!-- Copied from https://github.com/prisma/graphql-playground/blob/master/packages/graphql-playground-html/minimal.html -->\n<!-- Ref: https://github.com/prisma/graphql-playground#as-html-page -->\n<html>\n\n<head>\n  <meta charset=utf-8/>\n  <meta name=\"viewport\" content=\"user-scalable=no, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, minimal-ui\">\n  <title>GraphQL Playground</title>\n  <link rel=\"stylesheet\" href=\"//cdn.jsdelivr.net/npm/graphql-playground-react/build/static/css/index.css\" />\n  <link rel=\"shortcut icon\" href=\"//cdn.jsdelivr.net/npm/graphql-playground-react/build/favicon.png\" />\n  <script src=\"//cdn.jsdelivr.net/npm/graphql-playground-react/build/static/js/middleware.js\"></script>\n</head>\n\n<body>\n  <div id=\"root\">\n    <style>\n      body {\n        background-color: rgb(23, 42, 58);\n        font-family: Open Sans, sans-serif;\n        height: 90vh;\n      }\n\n      #root {\n        height: 100%;\n        width: 100%;\n        display: flex;\n        align-items: center;\n        justify-content: center;\n      }\n\n      .loading {\n        font-size: 32px;\n        font-weight: 200;\n        color: rgba(255, 255, 255, .6);\n        margin-left: 20px;\n      }\n\n      img {\n        width: 78px;\n        height: 78px;\n      }\n\n      .title {\n        font-weight: 400;\n      }\n    </style>\n    <img src='//cdn.jsdelivr.net/npm/graphql-playground-react/build/logo.png' alt=''>\n    <div class=\"loading\"> Loading\n      <span class=\"title\">GraphQL Playground</span>\n    </div>\n  </div>\n  <script>window.addEventListener('load', function (event) {\n      GraphQLPlayground.init(document.getElementById('root'), {\n        endpoint: '/graphql/',\n      })\n    })</script>\n</body>\n\n</html>\n"
  },
  {
    "path": "tools/Libplanet.Extensions.Cocona/AssemblyInfo.cs",
    "content": "using System.Runtime.CompilerServices;\n\n[assembly: InternalsVisibleTo(\"Libplanet.Extensions.Cocona.Tests\")]\n"
  },
  {
    "path": "tools/Libplanet.Extensions.Cocona/BlockPolicyParams.cs",
    "content": "namespace Libplanet.Extensions.Cocona;\n\nusing System;\nusing System.Diagnostics.CodeAnalysis;\nusing System.Linq;\nusing System.Reflection;\nusing global::Cocona;\nusing Libplanet.Action;\nusing Libplanet.Blockchain.Policies;\n\npublic class BlockPolicyParams : ICommandParameterSet\n{\n    private string[] _assembliesToLoad = Array.Empty<string>();\n    private string? _policyFactory;\n    private Assembly[]? _loadedAssemblies;\n\n    [Option(\n        \"load-assembly\",\n        new[] { 'A' },\n        Description = \"The path of the assembly DLL to load.  Can be specified multiple times.  \" +\n            \"Note that all referenced assemblies of the specified assemblies are also loaded \" +\n            \"automatically if they are placed in the same directory.  Tip: In case there are \" +\n            \"missing references, you can use `dotnet publish` to copy all the required \" +\n            \"assemblies to a single directory.\")]\n    [HasDefaultValue]\n    public string[] AssembliesToLoad\n    {\n        get => _assembliesToLoad;\n        set\n        {\n            _assembliesToLoad = value;\n            _loadedAssemblies = null;\n        }\n    }\n\n    [Option(\n        'F',\n        Description = \"The qualified name of the factory method to instantiate a \" +\n            nameof(IBlockPolicy) + \"<T>.  The factory method must be static and \" +\n            \"has no parameters.  An assembly that the factory method and \" +\n            \"the policy type belong to has to be loaded using -A/--load-assembly option.\")]\n    [HasDefaultValue]\n    public string? PolicyFactory\n    {\n        get => _policyFactory;\n        set\n        {\n            _policyFactory = value;\n            _loadedAssemblies = null;\n        }\n    }\n\n    [SuppressMessage(\n        \"Major Code Smell\",\n        \"S3885:\\\"Assembly.Load\\\" should be used\",\n        Justification = \"Assembly.Load does not automatically resolve dependencies from target \"\n            + \"assembly path, whereas Assembly.LoadFrom does, which is appropriate in this use \"\n            + \"case.\")]\n    public Assembly[] LoadAssemblies()\n    {\n        if (_loadedAssemblies is { } assemblies)\n        {\n            return assemblies;\n        }\n\n        _loadedAssemblies = AssembliesToLoad.Select(Assembly.LoadFrom).ToArray();\n        return _loadedAssemblies;\n    }\n\n    public object? GetBlockPolicy() =>\n        GetBlockPolicy(LoadAssemblies());\n\n    public PolicyActionsRegistry GetPolicyActionsRegistry() =>\n        GetPolicyActionsRegistry(LoadAssemblies());\n\n    [SuppressMessage(\n        \"Major Code Smell\",\n        \"S3011:Reflection should not be used to increase accessibility of classes, methods, \" +\n            \"or fields\",\n        Justification = \"It might not be practical to have BlockPolicy factory method to be \"\n            + \"public, as it is not likely to be used as a public API.\")]\n    internal object? GetBlockPolicy(Assembly[] assemblies)\n    {\n        // TODO: Consider to refer to a method in an inner class.\n        if (PolicyFactory is null)\n        {\n            return null;\n        }\n\n        int separatorIndex = PolicyFactory.LastIndexOf('.');\n        string typeName = separatorIndex < 0\n            ? throw new TypeLoadException(\"Expected a qualified name of a factory method.\")\n            : PolicyFactory.Substring(0, separatorIndex);\n        string methodName = PolicyFactory.Substring(separatorIndex + 1);\n        foreach (Assembly asm in assemblies)\n        {\n            if (asm.GetType(typeName, throwOnError: false) is { } type)\n            {\n                MethodInfo method = type.GetMethod(\n                    methodName,\n                    BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic\n                ) ?? throw new TypeLoadException(\n                    $\"Failed to find a static method named {methodName}() in {type.FullName}.\");\n\n                if (method.GetParameters().Length != 0)\n                {\n                    throw new TypeLoadException(\n                        $\"The factory method {PolicyFactory}() must have no parameters.\"\n                    );\n                }\n\n                Type returnType = method.ReturnType;\n                if (!typeof(IBlockPolicy).IsAssignableFrom(returnType))\n                {\n                    throw new TypeLoadException(\n                        $\"The return type of {PolicyFactory}() must be \" +\n                        $\"{nameof(IBlockPolicy)}.\"\n                    );\n                }\n\n                return method.Invoke(null, Array.Empty<object>()) ??\n                    throw new InvalidOperationException(\n                        $\"The factory method {PolicyFactory}() returned null.\"\n                    );\n            }\n        }\n\n        throw new TypeLoadException(\n            $\"Failed to load policy type {typeName} from assemblies:\\n\\n\" +\n            string.Join(\"\\n\", assemblies.Select(asm => asm.FullName))\n        );\n    }\n\n    internal PolicyActionsRegistry GetPolicyActionsRegistry(Assembly[] assemblies)\n    {\n        object? policy = GetBlockPolicy(assemblies);\n        if (policy is null)\n        {\n            return new PolicyActionsRegistry();\n        }\n\n        PropertyInfo? propertyInfo = policy\n            .GetType()\n            .GetProperty(nameof(IBlockPolicy.PolicyActionsRegistry));\n        if (propertyInfo is null)\n        {\n            var message = $\"The policy type \"\n                + $\"'{policy.GetType().FullName}' does not have a \"\n                + $\"'{nameof(IBlockPolicy.PolicyActionsRegistry)}' property.\";\n            throw new InvalidOperationException(message);\n        }\n\n        var value = propertyInfo.GetValue(policy);\n        if (value is null)\n        {\n            var message = $\"The value of property \"\n                + $\"'{nameof(IBlockPolicy.PolicyActionsRegistry)}' of type \"\n                + $\"'{policy.GetType().FullName}' cannot be null.\";\n            throw new InvalidOperationException(message);\n        }\n\n        return (PolicyActionsRegistry)value;\n    }\n}\n"
  },
  {
    "path": "tools/Libplanet.Extensions.Cocona/Commands/ApvCommand.cs",
    "content": "using Libplanet.Common;\nusing Libplanet.Crypto;\n\nnamespace Libplanet.Extensions.Cocona.Commands;\n\nusing System;\nusing System.Collections.Generic;\nusing System.Globalization;\nusing System.IO;\nusing System.Linq;\nusing System.Text.Json;\nusing Bencodex;\nusing Bencodex.Types;\nusing global::Cocona;\nusing Libplanet.KeyStore;\nusing Libplanet.Net;\nusing Libplanet.Net.Transports;\n\npublic class ApvCommand\n{\n    [Command(Description = \"Sign a new app protocol version.\")]\n    public void Sign(\n        [Argument(Name = \"KEY-ID\", Description = \"A private key to use for signing.\")]\n        Guid keyId,\n        [Argument(Name = \"VERSION\", Description = \"A version number to sign.\")]\n        int version,\n        PassphraseParameters passphrase,\n        [Option(\n            'E',\n            ValueName = \"FILE\",\n            Description = \"Bencodex file to use for extra data.  \" +\n                \"For standard input, use a hyphen (`-').  \" +\n                \"For an actual file named a hyphen, prepend `./', i.e., `./-'.\"\n        )]\n        string? extraFile = null,\n        [Option(\n            'e',\n            ValueName = \"KEY=VALUE\",\n            Description = \"Set a value to a key on extra Bencodex dictionary.  \" +\n                \"Can be applied multiple times (e.g., `-e foo=1 -e bar=baz').  \" +\n                \"This option implies the extra data to be a Bencodex dictionary, \" +\n                \"hence cannot be used together with -E/--extra-file option.\"\n        )]\n        string[]? extra = null\n    )\n    {\n        if (passphrase.PassphraseFile == \"-\" && extraFile == \"-\")\n        {\n            throw Utils.Error(\n                \"-P/--passphrase-file and -E/--extra-file cannot read standard input at a \" +\n                \"time.  Please specify one of both to read from a regular file.\"\n            );\n        }\n\n        // FIXME: Declare a ICommandParameterSet type taking key ID and keystore path instead:\n        PrivateKey key = new KeyCommand().UnprotectKey(keyId, passphrase, ignoreStdin: true);\n        IValue? extraValue = null;\n        if (extraFile is string path)\n        {\n            if (extra is string[] e && e.Length > 0)\n            {\n                throw Utils.Error(\n                    \"-E/--extra-file and -e/--extra cannot be used together at a time.\"\n                );\n            }\n\n            var codec = new Codec();\n            if (path == \"-\")\n            {\n                // Stream for stdin does not support .Seek()\n                using MemoryStream buffer = new MemoryStream();\n                using (Stream stream = Console.OpenStandardInput())\n                {\n                    stream.CopyTo(buffer);\n                }\n\n                buffer.Seek(0, SeekOrigin.Begin);\n                extraValue = codec.Decode(buffer);\n            }\n            else\n            {\n                using Stream stream = File.Open(path, FileMode.Open, FileAccess.Read);\n                extraValue = codec.Decode(stream);\n            }\n        }\n        else if (extra is string[] e && e.Length > 0)\n        {\n            var dict = Bencodex.Types.Dictionary.Empty;\n            foreach (string pair in e)\n            {\n                int sepPos = pair.IndexOf('=');\n                if (sepPos < 0)\n                {\n                    throw Utils.Error(\n                        \"-e/--extra must be a pair of KEY=VALUE, but no equal (=) separator: \" +\n                        $\"`{pair}'.\"\n                    );\n                }\n\n                string key_ = pair.Substring(0, sepPos);\n                string value = pair.Substring(sepPos + 1);\n                dict = dict.SetItem(key_, value);\n            }\n\n            extraValue = dict;\n        }\n\n        AppProtocolVersion v = AppProtocolVersion.Sign(key, version, extraValue);\n        Console.WriteLine(v.Token);\n    }\n\n    [Command(Description = \"Verify a given app protocol version token's signature.\")]\n    public void Verify(\n        [Argument(\n            Name = \"APV-TOKEN\",\n            Description = \"An app protocol version token to verify.  \" +\n                \"Read from the standard input if omitted.\"\n        )]\n        string? token = null,\n        [Option(\n            'p',\n            ValueName = \"PUBLIC-KEY\",\n            Description = \"Public key(s) to be used for verification.  \" +\n                \"Can be applied multiple times.\"\n        )]\n        PublicKey[]? publicKeys = null,\n        [Option(\n            'K',\n            Description = \"Do not use any keys in the key store, \" +\n                \"but only -p/--public-key options.\"\n        )]\n        bool noKeyStore = false\n    )\n    {\n        AppProtocolVersion v = ParseAppProtocolVersionToken(token);\n\n        if (publicKeys is { } pubKeys)\n        {\n            foreach (PublicKey pubKey in pubKeys)\n            {\n                if (v.Verify(pubKey))\n                {\n                    Console.Error.WriteLine(\n                        \"The signature successfully was verified using the {0}.\",\n                        pubKey\n                    );\n                    return;\n                }\n\n                Console.Error.WriteLine(\n                    \"The signature was failed to verify using the {0}.\",\n                    pubKey\n                );\n            }\n        }\n\n        if (!noKeyStore)\n        {\n            KeyCommand keyInstance = new KeyCommand();\n            IEnumerable<Tuple<Guid, ProtectedPrivateKey>> ppks = keyInstance.KeyStore.List()\n                .Where(pair => pair.Item2.Address.Equals(v.Signer));\n            foreach (Tuple<Guid, ProtectedPrivateKey> pair in ppks)\n            {\n                pair.Deconstruct(out Guid keyId, out ProtectedPrivateKey ppk);\n\n                // FIXME: The command should take options like --key-id, --key-passphrase, &\n                // --key-passphrase-file:\n                PublicKey pubKey = keyInstance.UnprotectKey(\n                    keyId,\n                    new PassphraseParameters()\n                ).PublicKey;\n                if (v.Verify(pubKey))\n                {\n                    Console.Error.WriteLine(\n                        \"The signature successfully was verified using the key {0}.\",\n                        keyId\n                    );\n                    return;\n                }\n\n                Console.Error.WriteLine(\n                    \"The signature was failed to verify using the key {0}.\",\n                    keyId\n                );\n            }\n        }\n\n        throw Utils.Error(\"Failed to verify.\");\n    }\n\n    [Command(Description = \"Parse and analyze a given app protocol version token.\")]\n    public void Analyze(\n        [Argument(\n            Name = \"APV-TOKEN\",\n            Description = \"An app protocol version token to analyze.  \" +\n                \"Read from the standard input if omitted.\"\n        )]\n        string? token = null,\n        [Option(Description = \"Print information of given token as JSON.\")]\n        bool json = false\n    )\n    {\n        AppProtocolVersion v = ParseAppProtocolVersionToken(token);\n\n        var data = new List<(string, string)>\n        {\n            (\"version\", v.Version.ToString(CultureInfo.InvariantCulture)),\n            (\"signature\", ByteUtil.Hex(v.Signature)),\n            (\"signer\", v.Signer.ToString()),\n        };\n\n        if (v.Extra is IValue extra)\n        {\n            void TreeIntoTable(IValue tree, List<(string, string)> table, string key)\n            {\n                switch (tree)\n                {\n                    case Null _:\n                        table.Add((key, \"null\"));\n                        return;\n\n                    case Bencodex.Types.Boolean b:\n                        table.Add((key, b ? \"true\" : \"false\"));\n                        return;\n\n                    case Binary bin:\n                        table.Add((key, ByteUtil.Hex(bin.ToByteArray())));\n                        return;\n\n                    case Text t:\n                        table.Add((key, t.Value));\n                        return;\n\n                    case Bencodex.Types.Integer i:\n                        table.Add((key, i.Value.ToString(CultureInfo.InvariantCulture)));\n                        return;\n\n                    case Bencodex.Types.List l:\n                        int idx = 0;\n                        foreach (IValue el in l)\n                        {\n                            TreeIntoTable(el, table, $\"{key}[{idx}]\");\n                            idx++;\n                        }\n\n                        return;\n\n                    case Bencodex.Types.Dictionary d:\n                        foreach (KeyValuePair<IKey, IValue> kv in d)\n                        {\n                            string k = kv.Key switch\n                            {\n                                Binary bk => ByteUtil.Hex(bk.ToArray()),\n                                Text txt => txt.Value,\n                                _ => kv.Key.ToString() ?? string.Empty,\n                            };\n                            TreeIntoTable(kv.Value, table, $\"{key}.{k}\");\n                        }\n\n                        return;\n\n                    default:\n                        table.Add((key, tree.ToString() ?? string.Empty));\n                        return;\n                }\n            }\n\n            TreeIntoTable(v.Extra, data, \"extra\");\n        }\n\n        if (json)\n        {\n            Console.WriteLine(\n                JsonSerializer.Serialize(\n                    data.ToDictionary(e => e.Item1, e => e.Item2)));\n        }\n        else\n        {\n            Utils.PrintTable((\"Field\", \"Value\"), data);\n        }\n    }\n\n    [Command(Description = \"Query app protocol version (a.k.a. APV) of target node.\")]\n    public void Query(\n        [Argument(\n            Name = \"TARGET\",\n            Description = \"Comma separated peer information({pubkey},{host},{port}) \" +\n                \"of target node.  \" +\n                \"(E.g., 027bd36895d68681290e570692ad3736750ceaab37be402442ffb203967f98f7b6,\" +\n                \"9c.planetarium.dev,31236)\")]\n        string peerInfo)\n    {\n        BoundPeer peer;\n        AppProtocolVersion apv;\n\n        try\n        {\n            peer = BoundPeer.ParsePeer(peerInfo);\n        }\n        catch\n        {\n            throw Utils.Error($\"Failed to parse peer. Please check the input. [{peerInfo}]\");\n        }\n\n        try\n        {\n            // FIXME: Must provide --transport option.\n            // https://github.com/planetarium/libplanet/issues/1623\n            apv = peer.QueryAppProtocolVersionNetMQ();\n        }\n        catch\n        {\n            throw Utils.Error($\"Failed to query app protocol version.\");\n        }\n\n        Console.WriteLine(apv.Token);\n    }\n\n    private AppProtocolVersion ParseAppProtocolVersionToken(string? token)\n    {\n        if (token is null)\n        {\n            token = Console.ReadLine() ?? string.Empty;\n        }\n\n        try\n        {\n            return AppProtocolVersion.FromToken(token.Trim());\n        }\n        catch (FormatException e)\n        {\n            throw Utils.Error($\"Not a valid app protocol version token.  {e.Message}\");\n        }\n    }\n}\n"
  },
  {
    "path": "tools/Libplanet.Extensions.Cocona/Commands/BlockCommand.cs",
    "content": "namespace Libplanet.Extensions.Cocona.Commands;\n\nusing System;\nusing System.Collections.Generic;\nusing System.IO;\nusing System.Collections.Immutable;\nusing System.Linq;\nusing System.Numerics;\nusing System.Text.Json;\nusing Bencodex;\nusing Bencodex.Types;\nusing ImmutableTrie;\nusing global::Cocona;\nusing Libplanet.Action;\nusing Libplanet.Action.Loader;\nusing Libplanet.Action.Sys;\nusing Libplanet.Blockchain;\nusing Libplanet.Crypto;\nusing Libplanet.Types.Blocks;\nusing Libplanet.Types.Consensus;\nusing Libplanet.Types.Tx;\nusing Libplanet.Store;\nusing Libplanet.Store.Trie;\n\npublic class BlockCommand\n{\n    public enum OutputFormat\n    {\n        /// <summary>\n        /// Bencode Extensible Binary Object Notation\n        /// </summary>\n        Bencodex,\n\n        /// <summary>\n        /// Json (Human-readable)\n        /// </summary>\n        Json,\n    }\n\n    [Command(Description = \"Analyze the given block.\")]\n    public void Analyze(\n        [Argument(\n            Description = \"The file path of the block to analyze.  If \" +\n                \"a hyphen (-) is given it reads from the standard input (if you want to read \" +\n                \"just a file named \\\"-\\\", use \\\"./-\\\" instead).\"\n        )]\n        string file,\n        [Option(\n            'o',\n            Description = \"The file path to write the analysis result to.  \" +\n                \"If a hyphen (-) is given it writes to the standard output (if you want to write \" +\n                \"just a file named \\\"-\\\", use \\\"./-\\\" instead).  If not given, it writes to \" +\n                \"the standard output.\"\n        )]\n        string output = \"-\"\n    )\n    {\n        using Stream inputStream = file == \"-\"\n            ? Console.OpenStandardInput()\n            : File.OpenRead(file);\n        string sourceName = file == \"-\" ? \"stdin\" : $\"file {file}\";\n        Codec codec = new ();\n        Block block;\n        try\n        {\n            var dict = (Bencodex.Types.Dictionary)codec.Decode(inputStream);\n            block = BlockMarshaler.UnmarshalBlock(dict);\n        }\n        catch (DecodingException e)\n        {\n            throw new CommandExitedException(\n                $\"The {sourceName} does not contain a valid Bencodex data: {e.Message}\",\n                -1\n            );\n        }\n        catch (InvalidCastException)\n        {\n            throw new CommandExitedException(\n                $\"The {sourceName} does not contain a valid Bencodex dictionary.\",\n                -2\n            );\n        }\n        catch (InvalidBlockException e)\n        {\n            throw new CommandExitedException(\n                $\"The {sourceName} does not contain a valid block: {e.Message}\",\n                -4\n            );\n        }\n        catch (Exception e) when (e is IndexOutOfRangeException or KeyNotFoundException)\n        {\n            throw new CommandExitedException(\n                $\"The {sourceName} lacks some required fields.\",\n                -3\n            );\n        }\n\n        using Stream outputStream = output == \"-\"\n            ? Console.OpenStandardOutput()\n            : File.Open(file, FileMode.Create);\n        var writerOptions = new JsonWriterOptions { Indented = true };\n        using (var writer = new Utf8JsonWriter(outputStream, writerOptions))\n        {\n            var serializerOptions = new JsonSerializerOptions\n            {\n                AllowTrailingCommas = false,\n                DictionaryKeyPolicy = JsonNamingPolicy.CamelCase,\n                PropertyNamingPolicy = JsonNamingPolicy.CamelCase,\n                IgnoreReadOnlyProperties = false,\n            };\n            JsonSerializer.Serialize(writer, block, serializerOptions);\n        }\n\n        using var textWriter = new StreamWriter(outputStream);\n        textWriter.WriteLine();\n    }\n\n    [Command(Description = \"Generate a genesis block.\")]\n    public void GenerateGenesis(\n        [Argument(Name = \"KEY-ID\", Description = \"A private key to use for signing.\")]\n        Guid keyId,\n        PassphraseParameters passphrase,\n        [Argument(Name = \"FILE\", Description = \"File to write the genesis block to.  \" +\n            \"Use `-` for stdout (you can still refer to a file named \\\"-\\\" by \\\"./-\\\").\")]\n        string file,\n        [Option('v', Description = \"A public key to use for validating.\")]\n        string[] validatorKey,\n        BlockPolicyParams blockPolicyParams,\n        [Option('f', Description = \"Output format.\")]\n        OutputFormat format = OutputFormat.Bencodex\n    )\n    {\n        // FIXME: Declare a ICommandParameterSet type taking key ID and keystore path instead:\n        PrivateKey key = new KeyCommand().UnprotectKey(keyId, passphrase, ignoreStdin: true);\n\n        var validatorSet = new ValidatorSet(\n            validatorKey\n                .Select(PublicKey.FromHex)\n                .Select(k => new Validator(k, BigInteger.One))\n                .ToList());\n        var emptyState =\n            ImmutableTrieDictionary<Address, IValue>.Empty;\n        ImmutableList<Transaction> txs = Array.Empty<Transaction>()\n\n            // FIXME: Remove this pragma after fixing the following issue:\n            // https://github.com/dotnet/platform-compat/blob/master/docs/PC002.md\n #pragma warning disable PC002\n            .Append(Transaction.Create(\n #pragma warning restore PC002\n                0,\n                key,\n                null,\n                new IAction[]\n                {\n                    new Initialize(validatorSet, emptyState),\n                }.Select(x => x.PlainValue)))\n            .ToImmutableList();\n\n        var policyActionsRegistry = blockPolicyParams.GetPolicyActionsRegistry();\n        var actionEvaluator = new ActionEvaluator(\n            policyActionsRegistry,\n            new TrieStateStore(new DefaultKeyValueStore(null)),\n            new SingleActionLoader(typeof(NullAction)));\n        Block genesis = BlockChain.ProposeGenesisBlock(\n            privateKey: key, transactions: txs);\n        using Stream stream = file == \"-\"\n            ? Console.OpenStandardOutput()\n            : File.Open(file, FileMode.Create);\n        switch (format)\n        {\n            // FIXME: Configure JsonConverter for Block:\n            case OutputFormat.Json:\n                var writerOptions = new JsonWriterOptions { Indented = true };\n                using (var writer = new Utf8JsonWriter(stream, writerOptions))\n                {\n                    var serializerOptions = new JsonSerializerOptions\n                    {\n                        AllowTrailingCommas = false,\n                        DictionaryKeyPolicy = JsonNamingPolicy.CamelCase,\n                        PropertyNamingPolicy = JsonNamingPolicy.CamelCase,\n                        IgnoreReadOnlyProperties = false,\n                    };\n                    JsonSerializer.Serialize(writer, genesis, serializerOptions);\n                }\n\n                using (var textWriter = new StreamWriter(stream))\n                {\n                    textWriter.WriteLine();\n                }\n\n                break;\n\n            default:\n                Codec codec = new ();\n                codec.Encode(genesis.MarshalBlock(), stream);\n                break;\n        }\n    }\n}\n"
  },
  {
    "path": "tools/Libplanet.Extensions.Cocona/Commands/KeyCommand.cs",
    "content": "using Libplanet.Common;\nusing Libplanet.Crypto;\n\nnamespace Libplanet.Extensions.Cocona.Commands;\n\nusing System;\nusing System.Collections.Generic;\nusing System.IO;\nusing System.Linq;\nusing global::Cocona;\nusing Libplanet.KeyStore;\n\npublic class KeyCommand\n{\n    public KeyCommand()\n    {\n        KeyStore = Web3KeyStore.DefaultKeyStore;\n    }\n\n    public IKeyStore KeyStore { get; set; }\n\n    [PrimaryCommand]\n    [Command(Description = \"List all private keys.\")]\n    public void List(\n        [Option(\n            Description = \"Specify key store path to list.\"\n        )]\n        string? path = null)\n    {\n        ChangeKeyStorePath(path);\n        PrintKeys(KeyStore.List().Select(t => t.ToValueTuple()));\n    }\n\n    [Command(Description = \"Create a new private key.\")]\n    public void Create(\n        PassphraseParameters passphrase,\n        [Option(\n            Description = \"Print created private key as Web3 Secret Storage format.\"\n        )]\n        bool json = false,\n        [Option(Description = \"Do not add to the key store, but only show the created key.\")]\n        bool dryRun = false,\n        [Option(Description = \"Path to key store\")]\n        string? path = null\n    )\n    {\n        ChangeKeyStorePath(path);\n        string passphraseValue = passphrase.Take(\"Passphrase: \", \"Retype passphrase: \");\n        PrivateKey pkey = new PrivateKey();\n        ProtectedPrivateKey ppk = ProtectedPrivateKey.Protect(pkey, passphraseValue);\n        Guid keyId = Add(ppk, dryRun);\n        if (json)\n        {\n            Stream stdout = Console.OpenStandardOutput();\n            ppk.WriteJson(stdout, keyId);\n            stdout.WriteByte(0x0a);\n        }\n        else\n        {\n            PrintKeys(new[] { (keyId, ppk) });\n        }\n    }\n\n    [Command(Aliases = new[] { \"rm\" }, Description = \"Remove a private key.\")]\n    public void Remove(\n        [Argument(Name = \"KEY-ID\", Description = \"A key UUID to remove.\")]\n        Guid keyId,\n        PassphraseParameters passphrase,\n        [Option(Description = \"Remove without asking passphrase.\")]\n        bool noPassphrase = false,\n        [Option(Description = \"Path to key store.\")]\n        string? path = null\n    )\n    {\n        ChangeKeyStorePath(path);\n        try\n        {\n            if (!noPassphrase)\n            {\n                UnprotectKey(keyId, passphrase);\n            }\n\n            KeyStore.Remove(keyId);\n        }\n        catch (NoKeyException)\n        {\n            throw Utils.Error($\"No such key ID: {keyId}\");\n        }\n    }\n\n    [Command(Description = \"Import a raw private key or Web3 Secret Storage.\")]\n    public void Import(\n        [Argument(\n            \"PRIVATE-KEY\",\n            Description = \"A raw private key in hexadecimal string, or path to Web3 Secret \" +\n                            \"Storage to import\"\n        )]\n        string key,\n        PassphraseParameters passphrase,\n        [Option(\n            Description = \"Import Web3 Secret Storage key.\"\n        )]\n        bool json = false,\n        [Option(Description = \"Do not add to the key store, but only show the created key.\")]\n        bool dryRun = false,\n        [Option(Description = \"Path to key store.\")]\n        string? path = null\n    )\n    {\n        ChangeKeyStorePath(path);\n        if (json)\n        {\n            try\n            {\n                ProtectedPrivateKey ppk = ProtectedPrivateKey.FromJson(ValidateJsonPath(key));\n                PrintKeys(new[] { (Add(ppk, dryRun), ppk) });\n            }\n            catch (CommandExitedException)\n            {\n                throw;\n            }\n            catch (Exception)\n            {\n                throw Utils.Error(\"Couldn't load ppk from json.\");\n            }\n        }\n        else\n        {\n            PrivateKey privateKey = ValidateRawHex(key);\n            string passphraseValue = passphrase.Take(\"Passphrase: \", \"Retype passphrase: \");\n            ProtectedPrivateKey ppk = ProtectedPrivateKey.Protect(\n                privateKey, passphraseValue);\n            PrintKeys(new[] { (Add(ppk, dryRun), ppk) });\n        }\n    }\n\n    [Command(Description = \"Export a raw private key (or public key).\")]\n    public void Export(\n        [Argument(\"KEY-ID\", Description = \"A key UUID to export.\")]\n        Guid keyId,\n        PassphraseParameters passphrase,\n        [Option('P', Description = \"Export a public key instead of private key.\")]\n        bool publicKey = false,\n        [Option(\n            'b',\n            Description = \"Print raw bytes instead of hexadecimal.  No trailing LF appended.\"\n        )]\n        bool bytes = false,\n        [Option(Description = \"Export a Web3 Secret Storage Formatted json\")]\n        bool json = false,\n        [Option(Description = \"Path to key store to export from.\")]\n        string? path = null\n    )\n    {\n        ChangeKeyStorePath(path);\n        PrivateKey key = UnprotectKey(keyId, passphrase);\n        byte[] rawKey = publicKey ? key.PublicKey.Format(true) : key.ToByteArray();\n        using Stream stdout = Console.OpenStandardOutput();\n        if (bytes)\n        {\n            stdout.Write(rawKey, 0, rawKey.Length);\n        }\n        else if (json)\n        {\n            var ppk = KeyStore.Get(keyId);\n            ppk.WriteJson(stdout, keyId);\n            stdout.WriteByte(0x0a);\n        }\n        else\n        {\n            Console.WriteLine(ByteUtil.Hex(rawKey));\n        }\n    }\n\n    [Command(\n        Aliases = new[] { \"gen\" },\n        Description = \"Generate a raw private key without storing it.\"\n    )]\n    public void Generate(\n        [Option('A', Description = \"Do not show a derived address.\")]\n        bool noAddress = false,\n        [Option('p', Description = \"Show a public key as well.\")]\n        bool publicKey = false\n    )\n    {\n        var key = new PrivateKey();\n        string priv = ByteUtil.Hex(key.ByteArray);\n        string addr = key.Address.ToString();\n        string pub = ByteUtil.Hex(key.PublicKey.Format(compress: true));\n\n        if (!noAddress && publicKey)\n        {\n            Utils.PrintTable(\n                (\"Private key\", \"Address\", \"Public key\"),\n                new[] { (priv, addr, pub) }\n            );\n        }\n        else if (!noAddress)\n        {\n            Utils.PrintTable((\"Private key\", \"Address\"), new[] { (priv, addr) });\n        }\n        else if (publicKey)\n        {\n            Utils.PrintTable((\"Private key\", \"Public key\"), new[] { (priv, pub) });\n        }\n        else\n        {\n            Console.WriteLine(priv);\n        }\n    }\n\n    [Command(Description = \"Sign a message.\")]\n    public void Sign(\n        [Argument(\"KEY-ID\", Description = \"A key UUID to sign.\")]\n        Guid keyId,\n        [Argument(\n            \"FILE\",\n            Description = \"A path of the file to sign. If you pass '-' dash character, \" +\n                            \"it will receive the message to sign from stdin.\"\n        )]\n        string path,\n        PassphraseParameters passphrase,\n        [Option(Description = \"A path of the file to save the signature. \" +\n                                \"If you pass '-' dash character, it will print to stdout \" +\n                                \"as raw bytes not hexadecimal string or else. \" +\n                                \"If this option isn't given, it will print hexadecimal string \" +\n                                \"to stdout as default behaviour.\")]\n        string? binaryOutput = null,\n        [Option(Description = \"Path to key store to use key from.\")]\n        string? storePath = null\n    )\n    {\n        ChangeKeyStorePath(storePath);\n        PrivateKey key = UnprotectKey(keyId, passphrase);\n\n        byte[] message;\n        if (path == \"-\")\n        {\n            // Stream for stdin does not support .Seek()\n            using MemoryStream buffer = new MemoryStream();\n            using (Stream stream = Console.OpenStandardInput())\n            {\n                stream.CopyTo(buffer);\n            }\n\n            message = buffer.ToArray();\n        }\n        else\n        {\n            message = File.ReadAllBytes(path);\n        }\n\n        var signature = key.Sign(message);\n        if (binaryOutput is null)\n        {\n            Console.WriteLine(ByteUtil.Hex(signature));\n        }\n        else if (binaryOutput == \"-\")\n        {\n            using Stream stdout = Console.OpenStandardOutput();\n            stdout.Write(signature, 0, signature.Length);\n        }\n        else\n        {\n            File.WriteAllBytes(binaryOutput, signature);\n        }\n    }\n\n    [Command(Description = \"Derive public key and address from private key.\")]\n    public void Derive(\n        [Argument(\n            \"KEY\",\n            Description = \"A raw private key (or a public key if -P/--public-key is used) \" +\n                \"to derive the address from.\"\n        )]\n        string key,\n        [Option('P', Description = \"Derive from a public key instead of a private key.\")]\n        bool publicKey = false\n    )\n    {\n        PublicKey pubKey = publicKey\n            ? PublicKey.FromHex(key)\n            : ValidateRawHex(key).PublicKey;\n        string addr = pubKey.Address.ToString();\n        string pub = ByteUtil.Hex(pubKey.Format(compress: true));\n        Utils.PrintTable((\"Public Key\", \"Address\"), new[] { (pub, addr) });\n    }\n\n    // FIXME: Declare a ICommandParameterSet type taking key ID and keystore path instead:\n    public PrivateKey UnprotectKey(\n        Guid keyId,\n        PassphraseParameters passphrase,\n        bool ignoreStdin = false\n    )\n    {\n        ProtectedPrivateKey ppk;\n        try\n        {\n            ppk = KeyStore.Get(keyId);\n        }\n        catch (NoKeyException)\n        {\n            throw Utils.Error($\"No such key ID: {keyId}\");\n        }\n\n        string passphraseValue = passphrase.Take($\"Passphrase (of {keyId}): \");\n\n        try\n        {\n            return ppk.Unprotect(passphraseValue);\n        }\n        catch (IncorrectPassphraseException)\n        {\n            throw Utils.Error(\"The passphrase is wrong.\");\n        }\n    }\n\n    private Guid Add(\n        ProtectedPrivateKey ppk,\n        bool dryRun\n    )\n    {\n        Guid keyId = dryRun ? Guid.NewGuid() : KeyStore.Add(ppk);\n        return keyId;\n    }\n\n    private void PrintKeys(IEnumerable<(Guid KeyId, ProtectedPrivateKey Key)> keys)\n    {\n        Utils.PrintTable(\n            (\"Key ID\", \"Address\"),\n            keys.Select(t => (t.KeyId.ToString(), t.Key.Address.ToString()))\n        );\n    }\n\n    private PrivateKey ValidateRawHex(string rawKeyHex)\n    {\n        PrivateKey key;\n        try\n        {\n            key = PrivateKey.FromString(rawKeyHex);\n        }\n        catch (FormatException)\n        {\n            throw Utils.Error(\"A raw private key should be hexadecimal.\");\n        }\n        catch (ArgumentOutOfRangeException)\n        {\n            throw Utils.Error(\"Hexadecimal characters should be even (not odd).\");\n        }\n        catch (Exception)\n        {\n            throw Utils.Error(\"Invalid private key.\");\n        }\n\n        return key;\n    }\n\n    private string ValidateJsonPath(string jsonPath)\n    {\n        try\n        {\n            string json = new StreamReader(jsonPath).ReadToEnd();\n            return json;\n        }\n        catch (System.IO.FileNotFoundException)\n        {\n            throw Utils.Error(\"This file does not exist.\");\n        }\n    }\n\n    // FIXME: Declare a ICommandParameterSet type taking key ID and keystore path instead:\n    private void ChangeKeyStorePath(string? path)\n    {\n        if (path != null)\n        {\n            KeyStore = new Web3KeyStore(Path.GetFullPath(path));\n        }\n        else\n        {\n            KeyStore = Web3KeyStore.DefaultKeyStore;\n        }\n    }\n}\n"
  },
  {
    "path": "tools/Libplanet.Extensions.Cocona/Commands/MptCommand.cs",
    "content": "using Libplanet.Common;\n\nnamespace Libplanet.Extensions.Cocona.Commands;\n\nusing System;\nusing System.Collections.Generic;\nusing System.Collections.Immutable;\nusing System.Linq;\nusing System.Security.Cryptography;\nusing System.Text.Json;\nusing Bencodex;\nusing Bencodex.Types;\nusing global::Cocona;\nusing global::Cocona.Help;\nusing Libplanet.Extensions.Cocona.Configuration;\nusing Libplanet.Extensions.Cocona.Services;\nusing Libplanet.RocksDBStore;\nusing Libplanet.Store;\nusing Libplanet.Store.Trie;\n\ninternal enum SchemeType\n{\n    // For extensibility.\n #pragma warning disable SA1602\n    // This is set to 0 for `default` value.\n    File = 0,\n #pragma warning restore SA1602\n}\n\npublic class MptCommand\n{\n    private const string KVStoreURIExample =\n        \"<kv-store-type>://<kv-store-path> (e.g., rocksdb:///path/to/kv-store)\";\n\n    private const string KVStoreArgumentDescription =\n        \"The alias name registered through `planet mpt add' command or the URI included \" +\n        \"the type of \" + nameof(IKeyValueStore) + \" implementation and the path where \" +\n        \"it was used at. \" + KVStoreURIExample;\n\n    private readonly IImmutableDictionary<string, Func<string, IKeyValueStore>>\n        _kvStoreConstructors =\n            new Dictionary<string, Func<string, IKeyValueStore>>\n            {\n                [\"default\"] = kvStorePath => new DefaultKeyValueStore(kvStorePath),\n                [\"rocksdb\"] = kvStorePath => new RocksDBKeyValueStore(kvStorePath),\n            }.ToImmutableSortedDictionary();\n\n    [Command(Description = \"Compare two trees via root hash.\")]\n    public void Diff(\n        [Argument(\n            Name = \"KV-STORE\",\n            Description = KVStoreArgumentDescription)]\n        string kvStoreUri,\n        [Argument(\n            Name = \"STATE-ROOT-HASH\",\n            Description = \"The state root hash to compare.\")]\n        string stateRootHashHex,\n        [Argument(\n            Name = \"OTHER-KV-STORE\",\n            Description = KVStoreArgumentDescription)]\n        string otherKvStoreUri,\n        [Argument(\n            Name = \"OTHER-STATE-ROOT-HASH\",\n            Description = \"Another state root hash to compare.\")]\n        string otherStateRootHashHex,\n        [FromService] IConfigurationService<ToolConfiguration> configurationService)\n    {\n        ToolConfiguration toolConfiguration = configurationService.Load();\n        kvStoreUri = ConvertKVStoreUri(kvStoreUri, toolConfiguration);\n        otherKvStoreUri = ConvertKVStoreUri(otherKvStoreUri, toolConfiguration);\n\n        IStateStore stateStore = new TrieStateStore(LoadKVStoreFromURI(kvStoreUri));\n        IStateStore otherStateStore = new TrieStateStore(LoadKVStoreFromURI(otherKvStoreUri));\n        var trie =\n            stateStore.GetStateRoot(HashDigest<SHA256>.FromString(stateRootHashHex));\n        var otherTrie =\n            otherStateStore.GetStateRoot(HashDigest<SHA256>.FromString(otherStateRootHashHex));\n\n        var codec = new Codec();\n        HashDigest<SHA256> originRootHash = trie.Hash;\n        HashDigest<SHA256> otherRootHash = otherTrie.Hash;\n\n        string originRootHashHex = ByteUtil.Hex(originRootHash.ByteArray);\n        string otherRootHashHex = ByteUtil.Hex(otherRootHash.ByteArray);\n        foreach (var (key, targetValue, sourceValue) in trie.Diff(otherTrie))\n        {\n            var data = new DiffData(ByteUtil.Hex(key.ByteArray), new Dictionary<string, string>\n            {\n                [otherRootHashHex] = targetValue is null\n                    ? \"null\"\n                    : ByteUtil.Hex(codec.Encode(targetValue)),\n                [originRootHashHex] = ByteUtil.Hex(codec.Encode(sourceValue)),\n            });\n\n            Console.WriteLine(JsonSerializer.Serialize(data));\n        }\n    }\n\n    [Command(Description = \"Export all states of the state root hash as JSON.\")]\n    public void Export(\n        [Argument(\n            Name = \"KV-STORE\",\n            Description = KVStoreArgumentDescription)]\n        string kvStoreUri,\n        [Argument(\n            Name = \"STATE-ROOT-HASH\",\n            Description = \"The state root hash to compare.\")]\n        string stateRootHashHex,\n        [FromService] IConfigurationService<ToolConfiguration> configurationService)\n    {\n        ToolConfiguration toolConfiguration = configurationService.Load();\n        kvStoreUri = ConvertKVStoreUri(kvStoreUri, toolConfiguration);\n\n        IStateStore stateStore = new TrieStateStore(LoadKVStoreFromURI(kvStoreUri));\n        var trie = stateStore.GetStateRoot(HashDigest<SHA256>.FromString(stateRootHashHex));\n        var codec = new Codec();\n\n        // This assumes the original key was encoded from a sensible string.\n        ImmutableDictionary<string, byte[]> decoratedStates = trie.IterateValues()\n            .ToImmutableDictionary(\n                pair => KeyBytes.Encoding.GetString(pair.Path.ToByteArray()),\n                pair => codec.Encode(pair.Value));\n\n        Console.WriteLine(JsonSerializer.Serialize(decoratedStates));\n    }\n\n    // FIXME: Now, it works like `set` not `add`. It allows override.\n    [Command(Description=\"Register an alias name to refer to a key-value store.\")]\n    public void Add(\n        [Argument(\n            Name = \"ALIAS\",\n            Description = \"The alias to refer to the fully qualified key-value store URI.\")]\n        string alias,\n        [Argument(\n            Name = \"KV-STORE-URI\",\n            Description = KVStoreURIExample)]\n        string uri,\n        [FromService] IConfigurationService<ToolConfiguration> configurationService)\n    {\n        if (Uri.IsWellFormedUriString(alias, UriKind.Absolute))\n        {\n            throw new CommandExitedException(\n                \"The alias should not look like a URI to prevent it\" +\n                \"from being ambiguous. Please try to use other alias name.\",\n                -1);\n        }\n\n        try\n        {\n            // Checks the `uri` is valid.\n            LoadKVStoreFromURI(uri);\n        }\n        catch (Exception e)\n        {\n            throw new CommandExitedException(\n                $\"It seems the uri is not valid. (exceptionMessage: {e.Message})\", -1);\n        }\n\n        var configuration = configurationService.Load();\n        configuration.Mpt.Aliases.Add(alias, uri);\n        configurationService.Store(configuration);\n    }\n\n    [Command(Description=\"Deregister an alias to a key-value store.\")]\n    public void Remove(\n        [Argument(\n            Name = \"ALIAS\",\n            Description = \"The alias name to deregister.\")]\n        string alias,\n        [FromService] IConfigurationService<ToolConfiguration> configurationService)\n    {\n        var configuration = configurationService.Load();\n        configuration.Mpt.Aliases.Remove(alias);\n        configurationService.Store(configuration);\n    }\n\n    [Command(Description=\"List all aliases stored.\")]\n    public void List(\n        [FromService] IConfigurationService<ToolConfiguration> configurationService)\n    {\n        ToolConfiguration configuration = configurationService.Load();\n        Dictionary<string, string> aliases = configuration.Mpt.Aliases;\n\n        int maxAliasLength = aliases.Keys.Max(alias => alias.Length),\n            maxPathLength = aliases.Values.Max(alias => alias.Length);\n        Console.Error.WriteLine(\n            $\"{{0,-{maxAliasLength}}} | {{1,-{maxPathLength}}}\",\n            \"ALIAS\",\n            \"PATH\");\n        Console.Error.WriteLine(new string('-', 3 + maxAliasLength + maxPathLength));\n        Console.Error.Flush();\n        foreach (KeyValuePair<string, string> pair in aliases)\n        {\n            Console.Write($\"{{0,-{maxAliasLength}}} \", pair.Key);\n            Console.Out.Flush();\n            Console.Error.Write(\"| \");\n            Console.Error.Flush();\n            Console.WriteLine($\"{{0,-{maxPathLength}}}\", pair.Value);\n            Console.Out.Flush();\n        }\n    }\n\n    [Command(\n        Description = \"Query a state of the state key at the state root hash.  It will \" +\n            \"print the state as hexadecimal bytes string into stdout.  \" +\n            \"If it doesn't exist, it will not print anything.\")]\n    public void Query(\n        [Argument(\n            Name = \"KV-STORE\",\n            Description = KVStoreArgumentDescription)]\n        string kvStoreUri,\n        [Argument(\n            Name = \"STATE-ROOT-HASH\",\n            Description = \"The state root hash to compare.\")]\n        string stateRootHashHex,\n        [Argument(\n            Name = \"STATE-KEY\",\n            Description = \"The key of the state to query.\")]\n        string stateKey,\n        [FromService] IConfigurationService<ToolConfiguration> configurationService)\n    {\n        ToolConfiguration toolConfiguration = configurationService.Load();\n        kvStoreUri = ConvertKVStoreUri(kvStoreUri, toolConfiguration);\n        IKeyValueStore keyValueStore = LoadKVStoreFromURI(kvStoreUri);\n        var trie = new MerkleTrie(\n            keyValueStore,\n            HashDigest<SHA256>.FromString(stateRootHashHex));\n        KeyBytes stateKeyBytes = new KeyBytes(stateKey);\n        IReadOnlyList<IValue?> values = trie.Get(new[] { stateKeyBytes });\n        if (values.Count > 0 && values[0] is { } value)\n        {\n            var codec = new Codec();\n            Console.WriteLine(ByteUtil.Hex(codec.Encode(value)));\n        }\n        else\n        {\n            Console.Error.WriteLine(\n                $\"The state corresponded to {stateKey} at the state root hash \" +\n                $\"\\\"{stateRootHashHex}\\\" in the KV store \\\"{kvStoreUri}\\\" seems not existed.\");\n        }\n    }\n\n    [PrimaryCommand]\n    public void Help([FromService] ICoconaHelpMessageBuilder helpMessageBuilder)\n    {\n        Console.Error.WriteLine(helpMessageBuilder.BuildAndRenderForCurrentContext());\n    }\n\n    private IKeyValueStore LoadKVStoreFromURI(string rawUri)\n    {\n        var uri = new Uri(rawUri);\n        var scheme = uri.Scheme;\n        var splitScheme = scheme.Split('+');\n        if (splitScheme.Length <= 0 || splitScheme.Length > 2)\n        {\n            var exceptionMessage = \"A key-value store URI must have a scheme, \" +\n                                    \"e.g., default://, rocksdb+file://.\";\n            throw new ArgumentException(exceptionMessage, nameof(rawUri));\n        }\n\n        if (!_kvStoreConstructors.TryGetValue(\n            splitScheme[0],\n            out Func<string, IKeyValueStore>? constructor))\n        {\n            throw new NotSupportedException(\n                $\"No key-value store backend supports the such scheme: {splitScheme[0]}.\");\n        }\n\n        // NOTE: Actually, there is only File scheme support and it will work to check only.\n        if (splitScheme.Length == 2\n            && !SchemeType.TryParse(splitScheme[1], ignoreCase: true, out SchemeType _))\n        {\n            throw new NotSupportedException(\n                $\"No key-value store backend supports the such scheme: {splitScheme[1]}.\");\n        }\n\n        return constructor(uri.AbsolutePath);\n    }\n\n    private string ConvertKVStoreUri(string kvStoreUri, ToolConfiguration toolConfiguration)\n    {\n        // If it is not Uri format,\n        // try to get uri from configuration service by using it as alias.\n        if (!Uri.IsWellFormedUriString(kvStoreUri, UriKind.Absolute))\n        {\n            try\n            {\n                kvStoreUri = toolConfiguration.Mpt.Aliases[kvStoreUri];\n            }\n            catch (KeyNotFoundException)\n            {\n                var exceptionMessage =\n                    $\"The alias, '{kvStoreUri}' doesn't exist. \" +\n                    $\"Please pass correct uri or alias.\";\n                throw new CommandExitedException(\n                    exceptionMessage,\n                    -1);\n            }\n        }\n\n        return kvStoreUri;\n    }\n\n    private sealed class DiffData\n    {\n        public DiffData(string key, Dictionary<string, string> stateRootHashToValue)\n        {\n            Key = key;\n            StateRootHashToValue = stateRootHashToValue;\n        }\n\n        public string Key { get; }\n\n        public Dictionary<string, string> StateRootHashToValue { get; }\n    }\n}\n"
  },
  {
    "path": "tools/Libplanet.Extensions.Cocona/Commands/StatsCommand.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing global::Cocona;\nusing Libplanet.Store;\nusing Libplanet.Types.Blocks;\n\nnamespace Libplanet.Extensions.Cocona.Commands;\n\npublic class StatsCommand\n{\n    private const string StoreArgumentDescription =\n        \"The URI denotes the type and path of concrete class for \" + nameof(IStore) + \".\"\n        + \"<store-type>://<store-path> (e.g., rocksdb+file:///path/to/store)\";\n\n    [Command(Description = \"Outputs a summary of a stored chain in a CSV format.\")]\n    public void Summary(\n        [Option('p', Description = StoreArgumentDescription)]\n        string path,\n        [Option('r', Description = \"Whether to include header row\")]\n        bool header,\n        [Option('o', Description =\n            \"Starting index offset; \" +\n            \"supports negative indexing\")]\n        long offset = 0,\n        [Option('l', Description =\n            \"Maximum number of results to return; \" +\n            \"no limit by default\")]\n        long? limit = null) => Summary(\n            store: Utils.LoadStoreFromUri(path),\n            header: header,\n            offset: offset,\n            limit: limit);\n\n    internal void Summary(\n        IStore store,\n        bool header,\n        long offset,\n        long? limit)\n    {\n        if (limit is { } && limit < 1)\n        {\n            throw new ArgumentException($\"limit must be at least 1: {limit}\");\n        }\n\n        Guid chainId = store.GetCanonicalChainId()\n            ?? throw Utils.Error($\"Failed to find the canonical chain in store.\");\n        long chainLength = store.CountIndex(chainId);\n\n        if (offset >= chainLength || (offset < 0 && chainLength + offset < 0))\n        {\n            throw new ArgumentException(\n                $\"invalid offset value {offset} for found chain length {chainLength}\");\n        }\n\n        IEnumerable<BlockHash> hashes = store.IterateIndexes(\n            chainId,\n            offset: offset >= 0\n                ? (int)offset\n                : (int)(chainLength + offset),\n            limit: (int?)limit);\n\n        if (header)\n        {\n            Console.WriteLine(\"index,hash,difficulty,miner,txCount,timestamp,perceivedTime\");\n        }\n\n        foreach (var hash in hashes)\n        {\n            BlockDigest blockDigest = store.GetBlockDigest(hash) ??\n                throw Utils.Error($\"Failed to load the block {hash}.\");\n            BlockHeader blockHeader =\n                blockDigest.GetHeader();\n\n            Console.WriteLine(\n                $\"{blockHeader.Index},\" +\n                $\"{blockHeader.Hash},\" +\n                $\"{blockHeader.Miner},\" +\n                $\"{blockDigest.TxIds.Length},\" +\n                $\"{blockHeader.Timestamp.ToUnixTimeMilliseconds()}\");\n        }\n    }\n}\n"
  },
  {
    "path": "tools/Libplanet.Extensions.Cocona/Commands/StoreCommand.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Collections.Immutable;\nusing System.Globalization;\nusing System.Linq;\nusing global::Cocona;\nusing Libplanet.Common;\nusing Libplanet.Store;\nusing Libplanet.Types.Blocks;\nusing Libplanet.Types.Tx;\n\nnamespace Libplanet.Extensions.Cocona.Commands;\n\npublic class StoreCommand\n{\n    private const string StoreArgumentDescription =\n        \"The URI denotes the type and path of concrete class for \" + nameof(IStore) + \".\"\n        + \"<store-type>://<store-path> (e.g., rocksdb+file:///path/to/store)\";\n\n    [Command(Description = \"List all chain IDs.\")]\n    public void ChainIds(\n        [Argument(\"STORE\", Description = StoreArgumentDescription)]\n        string storeUri,\n        [Option(\"hash\", Description = \"Show the hash of the chain tip.\")]\n        bool showHash\n    )\n    {\n        IStore store = Utils.LoadStoreFromUri(storeUri);\n        Guid? canon = store.GetCanonicalChainId();\n        var headerWithoutHash = (\"Chain ID\", \"Height\", \"Canon?\");\n        var headerWithHash = (\"Chain ID\", \"Height\", \"Canon?\", \"Hash\");\n        var chainIds = store.ListChainIds().Select(id =>\n        {\n            var height = store.CountIndex(id) - 1;\n            return (\n                id.ToString(),\n                height.ToString(CultureInfo.InvariantCulture),\n                id == canon ? \"*\" : string.Empty,\n                store.GetBlockDigest(\n                    store.IndexBlockHash(id, height)!.Value)!.Value.Hash.ToString());\n        });\n        if (showHash)\n        {\n            Utils.PrintTable(headerWithHash, chainIds);\n        }\n        else\n        {\n            Utils.PrintTable(\n                headerWithoutHash, chainIds.Select(i => (i.Item1, i.Item2, i.Item3)));\n        }\n    }\n\n    [Command(Description = \"Build an index for transaction id and block hash.\")]\n    public void BuildIndexTxBlock(\n        [Argument(\"STORE\", Description = StoreArgumentDescription)]\n        string home,\n        [Argument(\"OFFSET\", Description = \"block index\")]\n        int offset,\n        [Argument(\"LIMIT\", Description = \"block index\")]\n        int limit\n    )\n    {\n        IStore store = Utils.LoadStoreFromUri(home);\n        var prev = DateTimeOffset.UtcNow;\n        foreach (var index in BuildTxIdBlockHashIndex(store, offset, limit))\n        {\n            Console.WriteLine($\"processing {index}/{offset + limit}...\");\n        }\n\n        Console.WriteLine($\"It taken {DateTimeOffset.UtcNow - prev}\");\n        store?.Dispose();\n    }\n\n    [Command(Description = \"Query block hashes by transaction id.\")]\n    public void BlockHashesByTxId(\n        [Argument(\"STORE\", Description = StoreArgumentDescription)]\n        string home,\n        [Argument(\"TX-ID\", Description = \"tx id\")]\n        string strTxId\n    )\n    {\n        IStore store = Utils.LoadStoreFromUri(home);\n        var blockHashes = store.IterateTxIdBlockHashIndex(new TxId(ByteUtil.ParseHex(strTxId)))\n            .ToImmutableArray();\n        Console.WriteLine(Utils.SerializeHumanReadable(blockHashes));\n        store?.Dispose();\n    }\n\n    [Command(Description = \"Query a list of blocks by transaction id.\")]\n    public void BlocksByTxId(\n        [Argument(\"STORE\", Description = StoreArgumentDescription)]\n        string home,\n        [Argument(\"TX-ID\", Description = \"tx id\")]\n        string strTxId\n    )\n    {\n        using IStore store = Utils.LoadStoreFromUri(home);\n        var txId = TxId.FromHex(strTxId);\n        if (!(store.GetFirstTxIdBlockHashIndex(txId) is { } ))\n        {\n            throw Utils.Error($\"cannot find the block with the TxId[{txId.ToString()}]\");\n        }\n\n        var blocks = IterateBlocks(store, txId).ToImmutableList();\n\n        Console.WriteLine(Utils.SerializeHumanReadable(blocks));\n    }\n\n    [Command(Description = \"Query a block by index.\")]\n    public void BlockByIndex(\n        [Argument(\"STORE\", Description = StoreArgumentDescription)]\n        string home,\n        [Argument(\"BLOCK-INDEX\", Description = \"block index\")]\n        int blockIndex\n    )\n    {\n        using IStore store = Utils.LoadStoreFromUri(home);\n        var blockHash = GetBlockHash(store, blockIndex);\n        var block = GetBlock(store, blockHash);\n        Console.WriteLine(Utils.SerializeHumanReadable(block));\n    }\n\n    [Command(Description = \"Query a block by hash.\")]\n    public void BlockByHash(\n        [Argument(\"STORE\", Description = StoreArgumentDescription)]\n        string home,\n        [Argument(\"BLOCK-HASH\", Description = \"block hash\")]\n        string blockHash\n    )\n    {\n        using IStore store = Utils.LoadStoreFromUri(home);\n        var block = GetBlock(store, BlockHash.FromString(blockHash));\n        Console.WriteLine(Utils.SerializeHumanReadable(block));\n    }\n\n    [Command(Description = \"Query a transaction by tx id.\")]\n    public void TxById(\n        [Argument(\"STORE\", Description = StoreArgumentDescription)]\n        string home,\n        [Argument(\"TX-ID\", Description = \"tx id\")]\n        string strTxId\n    )\n    {\n        IStore store = Utils.LoadStoreFromUri(home);\n        var tx = GetTransaction(store, new TxId(ByteUtil.ParseHex(strTxId)));\n        Console.WriteLine(Utils.SerializeHumanReadable(tx));\n        store?.Dispose();\n    }\n\n    [Command]\n    public void MigrateIndex(string storePath)\n    {\n        if (RocksDBStore.RocksDBStore.MigrateChainDBFromColumnFamilies(storePath))\n        {\n            Console.WriteLine(\"Successfully migrated.\");\n        }\n        else\n        {\n            Console.WriteLine(\"Already migrated, no need to migrate.\");\n        }\n    }\n\n    private static Block GetBlock(IStore store, BlockHash blockHash)\n    {\n        if (!(store.GetBlock(blockHash) is { } block))\n        {\n            throw Utils.Error($\"cannot find the block with the hash[{blockHash.ToString()}]\");\n        }\n\n        return block;\n    }\n\n    private static BlockHash GetBlockHash(IStore store, int blockIndex)\n    {\n        if (!(store.GetCanonicalChainId() is { } chainId))\n        {\n            throw Utils.Error(\"Cannot find the main branch of the blockchain.\");\n        }\n\n        if (!(store.IndexBlockHash(chainId, blockIndex) is { } blockHash))\n        {\n            throw Utils.Error(\n                $\"Cannot find the block with the height {blockIndex}\" +\n                $\" within the blockchain {chainId}.\"\n            );\n        }\n\n        return blockHash;\n    }\n\n    private static IEnumerable<Block> IterateBlocks(IStore store, TxId txId)\n    {\n        foreach (var blockHash in store.IterateTxIdBlockHashIndex(txId))\n        {\n            yield return GetBlock(store, blockHash);\n        }\n    }\n\n    private static Transaction GetTransaction(IStore store, TxId txId)\n    {\n        if (!(store.GetTransaction(txId) is { } tx))\n        {\n            throw Utils.Error($\"cannot find the tx with the tx id[{txId.ToString()}]\");\n        }\n\n        return tx;\n    }\n\n    private static IEnumerable<int> BuildTxIdBlockHashIndex(IStore store, int offset, int limit)\n    {\n        if (!(store.GetCanonicalChainId() is { } chainId))\n        {\n            throw Utils.Error(\"Cannot find the main branch of the blockchain.\");\n        }\n\n        var index = offset;\n        foreach (BlockHash blockHash in store.IterateIndexes(chainId, offset, limit))\n        {\n            yield return index++;\n            if (!(store.GetBlockDigest(blockHash) is { } blockDigest))\n            {\n                throw Utils.Error(\n                    $\"Block is missing for BlockHash: {blockHash} index: {index}.\");\n            }\n\n            foreach (TxId txId in blockDigest.TxIds.Select(bytes => new TxId(bytes.ToArray())))\n            {\n                store.PutTxIdBlockHashIndex(txId, blockHash);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "tools/Libplanet.Extensions.Cocona/Commands/TxCommand.cs",
    "content": "using System;\nusing System.Collections.Immutable;\nusing System.IO;\nusing System.Text.Json;\nusing Bencodex;\nusing Bencodex.Types;\nusing global::Cocona;\nusing global::Cocona.Help;\nusing Libplanet.Types.Tx;\n\nnamespace Libplanet.Extensions.Cocona.Commands;\n\npublic class TxCommand\n{\n    private static readonly Codec Codec = new Codec();\n\n    [Command(Description = \"Analyze the given signed or unsigned transaction.\")]\n    public int Analyze(\n        [Argument(\n            Description = \"The file path of the transaction to analyze.  If \" +\n                \"a hyphen (-) is given it reads from the standard input (if you want to read \" +\n                \"just a file named \\\"-\\\", use \\\"./-\\\" instead).\"\n        )]\n        string file,\n        [Option(\n            'u',\n            Description = \"Analyze an unsigned transaction.  This option is \" +\n                \"mutually exclusive with -i/--ignore-signature.\"\n        )]\n        bool unsigned = false,\n        [Option(\n            'i',\n            Description = \"Terminate the program with a zero exit code (success) even if \" +\n                \"the signature is invalid.  However, it still prints the error message to \" +\n                \"the standard error, and the exit code is still non-zero if the transaction \" +\n                \"is invalid in other ways.  This option is mutually exclusive with \" +\n                \"-u/--unsigned.\"\n        )]\n        bool ignoreSignature = false\n    )\n    {\n        if (unsigned && ignoreSignature)\n        {\n            throw new CommandExitedException(\n                \"The -u/--unsigned and -i/--ignore-signature options are mutually exclusive.\",\n                -1\n            );\n        }\n\n        IValue rawTx;\n        string sourceName = string.Empty;\n        try\n        {\n            if (file == \"-\")\n            {\n                sourceName = \"stdin\";\n                using var stdin = Console.OpenStandardInput();\n                rawTx = Codec.Decode(stdin);\n            }\n            else\n            {\n                sourceName = $\"file {file}\";\n                try\n                {\n                    using FileStream fileStream = File.OpenRead(file);\n                    rawTx = Codec.Decode(fileStream);\n                }\n                catch (IOException)\n                {\n                    throw new CommandExitedException(\n                        $\"Failed to read the file {file}; it may not exist nor be readable.\",\n                        -1\n                    );\n                }\n            }\n        }\n        catch (DecodingException e)\n        {\n            throw new CommandExitedException(\n                $\"Failed to decode the {sourceName} as a Bencodex tree: {e}\",\n                -1\n            );\n        }\n\n        if (rawTx is not Bencodex.Types.Dictionary txDict)\n        {\n            throw new CommandExitedException(\n                $\"The {sourceName} is not a Bencodex dictionary.\",\n                -1\n            );\n        }\n\n        UnsignedTx unsignedTx;\n        try\n        {\n            unsignedTx = TxMarshaler.UnmarshalUnsignedTx(txDict);\n        }\n        catch (Exception e)\n        {\n            throw new CommandExitedException(\n                $\"Failed to deserialize the {sourceName}: {e}\",\n                -1\n            );\n        }\n\n        ImmutableArray<byte>? signature = TxMarshaler.UnmarshalTransactionSignature(txDict);\n        if (unsigned && signature is not null)\n        {\n            throw new CommandExitedException(\n                \"The transaction is signed, but the -u/--unsigned option is given.\",\n                -1\n            );\n        }\n\n        bool invalid = false;\n        Transaction? tx = null;\n        if (!unsigned)\n        {\n            if (signature is not { } sig)\n            {\n                throw new CommandExitedException(\n                    \"The transaction is unsigned.  If you want to analyze it anyway, \" +\n                        \"use the -u/--unsigned option.\",\n                    -1\n                );\n            }\n\n            try\n            {\n                tx = unsignedTx.Verify(sig);\n            }\n            catch (Exception e)\n            {\n                invalid = true;\n                Console.Error.WriteLine(\n                    \"The signature from the transaction {0} is invalid: {1}\",\n                    sourceName,\n                    e\n                );\n            }\n\n            if (invalid)\n            {\n                invalid = !ignoreSignature;\n            }\n            else\n            {\n                Console.Error.WriteLine(\n                    \"The signature from the transaction {0} is valid.\",\n                    sourceName\n                );\n            }\n        }\n\n        var writerOptions = new JsonWriterOptions { Indented = true };\n        using var stdout = Console.OpenStandardOutput();\n        using var writer = new Utf8JsonWriter(stdout, writerOptions);\n\n        var serializerOptions = new JsonSerializerOptions\n        {\n            AllowTrailingCommas = false,\n            DictionaryKeyPolicy = JsonNamingPolicy.CamelCase,\n            PropertyNamingPolicy = JsonNamingPolicy.CamelCase,\n            IgnoreReadOnlyProperties = false,\n        };\n\n        // Note that JsonSerializer.Serialize() is a generic method, so it depends on\n        // compile-time types.  In other words, we cannot replace the below with a single line\n        // with a ternary operator, as it lets the compiler infer the type parameter of\n        // JsonSerializer.Serialize() to be IUnsignedTx even when the tx is not null:\n        if (tx is { } txObj)\n        {\n            JsonSerializer.Serialize(writer, txObj, serializerOptions);\n        }\n        else\n        {\n            JsonSerializer.Serialize(writer, unsignedTx, serializerOptions);\n        }\n\n        writer.Flush();\n        Console.WriteLine();\n        return invalid ? -1 : 0;\n    }\n\n    [Command(Description = \"Show this help message.\")]\n    public void Help([FromService] ICoconaHelpMessageBuilder helpMessageBuilder)\n    {\n        Console.WriteLine(helpMessageBuilder.BuildAndRenderForCurrentContext());\n    }\n}\n"
  },
  {
    "path": "tools/Libplanet.Extensions.Cocona/Configuration/MptConfiguration.cs",
    "content": "using System.Collections.Generic;\n\nnamespace Libplanet.Extensions.Cocona.Configuration\n{\n    public struct MptConfiguration\n    {\n        public MptConfiguration(Dictionary<string, string> aliases)\n        {\n            Aliases = aliases;\n        }\n\n        public Dictionary<string, string> Aliases { get; set; }\n    }\n}\n"
  },
  {
    "path": "tools/Libplanet.Extensions.Cocona/Configuration/ToolConfiguration.cs",
    "content": "namespace Libplanet.Extensions.Cocona.Configuration\n{\n    public struct ToolConfiguration\n    {\n        public ToolConfiguration(MptConfiguration mpt)\n        {\n            Mpt = mpt;\n        }\n\n        public MptConfiguration Mpt { get; set; }\n    }\n}\n"
  },
  {
    "path": "tools/Libplanet.Extensions.Cocona/ConsolePasswordReader.cs",
    "content": "namespace Libplanet.Extensions.Cocona;\n\nusing System;\nusing System.Text;\n\npublic class ConsolePasswordReader\n{\n    public static string Read(string prompt)\n    {\n        var password = new StringBuilder();\n\n        Console.Write(prompt);\n        do\n        {\n            var key = Console.ReadKey(true).KeyChar;\n\n            if (key == '\\b')\n            {\n                if (password.Length <= 0)\n                {\n                    continue;\n                }\n\n                password.Remove(password.Length - 1, 1);\n                Console.SetCursorPosition(Console.CursorLeft - 1, Console.CursorTop);\n                Console.Write(' ');\n                Console.SetCursorPosition(Console.CursorLeft - 1, Console.CursorTop);\n            }\n            else if (key == '\\r')\n            {\n                Console.WriteLine();\n                break;\n            }\n            else if (!char.IsControl(key))\n            {\n                password.Append(key);\n                Console.Write('*');\n            }\n        }\n        while (true);\n\n        return password.ToString();\n    }\n}\n"
  },
  {
    "path": "tools/Libplanet.Extensions.Cocona/Extensions/ICoconaLiteServiceCollectionExtensions.cs",
    "content": "namespace Libplanet.Extensions.Cocona.Extensions;\n\nusing System.IO;\nusing global::Cocona.Lite;\nusing Libplanet.Extensions.Cocona.Configuration;\nusing Libplanet.Extensions.Cocona.Services;\nusing Zio.FileSystems;\n\npublic static class ICoconaLiteServiceCollectionExtensions\n{\n    public static void AddJsonConfigurationService(\n        this ICoconaLiteServiceCollection services,\n        string jsonConfigurationPath)\n    {\n        string jsonConfigurationDirectory = Directory.GetParent(jsonConfigurationPath)?.FullName\n            ?? Directory.GetCurrentDirectory();\n        if (!Directory.Exists(jsonConfigurationDirectory))\n        {\n            Directory.CreateDirectory(jsonConfigurationDirectory);\n        }\n\n        var pfs = new PhysicalFileSystem();\n        var fileSystem = new SubFileSystem(\n            pfs,\n            pfs.ConvertPathFromInternal(jsonConfigurationDirectory),\n            owned: true);\n        services.AddTransient<IConfigurationService<ToolConfiguration>>(\n            _ => new JsonConfigurationService(\n                fileSystem,\n                Path.GetFileName(jsonConfigurationPath)));\n    }\n}\n"
  },
  {
    "path": "tools/Libplanet.Extensions.Cocona/Libplanet.Extensions.Cocona.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <PropertyGroup>\n    <TreatWarningsAsErrors>true</TreatWarningsAsErrors>\n    <NoWarn>$(NoWarn);CS1591;S1118;SA1118</NoWarn>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <PackageReference Include=\"Cocona.Lite\" Version=\"2.0.*\" />\n    <PackageReference Include=\"System.ValueTuple\" Version=\"4.5.0\" />\n    <PackageReference Include=\"System.Text.Json\" Version=\"9.0.*\" />\n  </ItemGroup>\n\n  <ItemGroup Condition=\"'$(SkipSonar)' != 'true'\">\n    <PackageReference Remove=\"SonarAnalyzer.CSharp\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <ProjectReference Include=\"..\\..\\src\\Libplanet\\Libplanet.csproj\" />\n    <ProjectReference Include=\"..\\..\\src\\Libplanet.Net\\Libplanet.Net.csproj\" />\n    <ProjectReference Include=\"..\\..\\src\\Libplanet.RocksDBStore\\Libplanet.RocksDBStore.csproj\" />\n  </ItemGroup>\n\n</Project>\n"
  },
  {
    "path": "tools/Libplanet.Extensions.Cocona/PassphraseParameters.cs",
    "content": "namespace Libplanet.Extensions.Cocona;\n\nusing System;\nusing System.IO;\nusing global::Cocona;\n\npublic class PassphraseParameters : ICommandParameterSet\n{\n    [Option(\n        'p',\n        ValueName = \"PASSPHRASE\",\n        Description = \"Take passphrase through this option instead of prompt.  \" +\n            \"Mutually exclusive with --passphrase-file option.\"\n    )]\n    [HasDefaultValue]\n    public string? Passphrase { get; set; } = null;\n\n    [Option(\n        ValueName = \"FILE\",\n        Description = \"Read passphrase from the specified file instead of taking it \" +\n            \"through prompt.  Mutually exclusive with -p/--passphrase option.  \" +\n            \"For standard input, use a hyphen (`-').  For an actual file named a hyphen, \" +\n            \"prepend `./', i.e., `./-'.  Note that the trailing CR/LF is trimmed.\"\n    )]\n    [HasDefaultValue]\n    public string? PassphraseFile { get; set; } = null;\n\n    public string Take(string prompt, string? retypePrompt = null, bool ignoreStdin = false)\n    {\n        if (Passphrase is { } passphrase)\n        {\n            if (PassphraseFile is { })\n            {\n                throw Utils.Error(\n                    $\"-p/--passphrase and --passphrase-file options are mutually exclusive.\"\n                );\n            }\n\n            return passphrase;\n        }\n        else if (PassphraseFile is { } filePath)\n        {\n            if (filePath == \"-\")\n            {\n                if (File.Exists(\"-\"))\n                {\n                    Console.Error.WriteLine(\n                        \"Note: Passphrase is read from standard input (`-').  If you want \" +\n                        \"to read from a file, prepend `./', i.e.: --passphrase-file=./-\"\n                    );\n                }\n\n                return Console.In.ReadToEnd().TrimEnd('\\r', '\\n');\n            }\n\n            try\n            {\n                return File.ReadAllText(filePath).TrimEnd('\\r', '\\n');\n            }\n            catch (FileNotFoundException)\n            {\n                throw Utils.Error($\"Passphrase file is not found: {filePath}\");\n            }\n        }\n\n        if (Console.IsInputRedirected && !ignoreStdin)\n        {\n            throw Utils.Error(\n                \"Error: The standard input is not associated to any terminal device (tty), \" +\n                \"which means it probably is piped.  If you need to pass the passphrase \" +\n                \"through pipe, use --passphrase-file=- option instead (`-' means stdin).\"\n            );\n        }\n\n        string first = ConsolePasswordReader.Read(prompt);\n        if (retypePrompt is { })\n        {\n            string retype = ConsolePasswordReader.Read(retypePrompt);\n            if (first != retype)\n            {\n                throw Utils.Error(\"Passphrases do not match.\");\n            }\n        }\n\n        return first;\n    }\n}\n"
  },
  {
    "path": "tools/Libplanet.Extensions.Cocona/Services/IConfigurationService.cs",
    "content": "namespace Libplanet.Extensions.Cocona.Services;\n\npublic interface IConfigurationService<TConfiguration>\n{\n    TConfiguration Load();\n\n    void Store(TConfiguration configuration);\n}\n"
  },
  {
    "path": "tools/Libplanet.Extensions.Cocona/Services/JsonConfigurationService.cs",
    "content": "namespace Libplanet.Extensions.Cocona.Services;\n\nusing System;\nusing System.Collections.Generic;\nusing System.Text.Json;\nusing Libplanet.Extensions.Cocona.Configuration;\nusing Zio;\n\npublic class JsonConfigurationService : IConfigurationService<ToolConfiguration>\n{\n    private readonly IFileSystem _fileSystem;\n    private readonly string _configurationFileName;\n\n    public JsonConfigurationService(IFileSystem fileSystem, string configurationFileName)\n    {\n        _fileSystem = fileSystem;\n        _configurationFileName = configurationFileName;\n    }\n\n    public ToolConfiguration Load()\n    {\n        if (!_fileSystem.FileExists(UPath.Root / _configurationFileName))\n        {\n            return new ToolConfiguration(\n                new MptConfiguration(new Dictionary<string, string>()));\n        }\n\n        return JsonSerializer.Deserialize<ToolConfiguration>(\n            _fileSystem.ReadAllText(UPath.Root / _configurationFileName));\n    }\n\n    public void Store(ToolConfiguration configuration)\n    {\n        Console.WriteLine(JsonSerializer.Serialize(configuration));\n        _fileSystem.WriteAllText(\n            UPath.Root / _configurationFileName,\n            JsonSerializer.Serialize(configuration));\n    }\n}\n"
  },
  {
    "path": "tools/Libplanet.Extensions.Cocona/Utils.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Collections.Immutable;\nusing System.Globalization;\nusing System.Linq;\nusing System.Text.Json;\nusing System.Text.Json.Serialization;\nusing Bencodex.Types;\nusing global::Cocona;\nusing Libplanet.Action;\nusing Libplanet.Action.State;\nusing Libplanet.Common.JsonConverters;\nusing Libplanet.Store;\n\nnamespace Libplanet.Extensions.Cocona;\n\npublic static class Utils\n{\n    public static readonly string DateTimeOffsetFormat = \"yyyy-MM-ddTHH:mm:ss.ffffffZ\";\n\n    public static CommandExitedException Error(string message, int exitCode = 128)\n    {\n        Console.Error.WriteLine(\"Error: {0}\", message);\n        Console.Error.Flush();\n        return new CommandExitedException(exitCode);\n    }\n\n    public static void\n        PrintTable<T1>(ValueTuple<string> header, IEnumerable<ValueTuple<T1>> rows)\n        where T1 : notnull\n    {\n        PrintTable(\n            new object[]\n            {\n                header.Item1,\n            },\n            rows.Select(row => new object[]\n            {\n                row.Item1,\n            }));\n    }\n\n    public static void\n        PrintTable<T1, T2>((string, string) header, IEnumerable<(T1, T2)> rows)\n        where T1 : notnull\n        where T2 : notnull\n    {\n        PrintTable(\n            new object[]\n            {\n                header.Item1,\n                header.Item2,\n            },\n            rows.Select(row => new object[]\n            {\n                row.Item1,\n                row.Item2,\n            }));\n    }\n\n    public static void\n        PrintTable<T1, T2, T3>(\n            (string, string, string) header,\n            IEnumerable<(T1, T2, T3)> rows)\n        where T1 : notnull\n        where T2 : notnull\n        where T3 : notnull\n    {\n        PrintTable(\n            new object[]\n            {\n                header.Item1,\n                header.Item2,\n                header.Item3,\n            },\n            rows.Select(row => new object[]\n            {\n                row.Item1,\n                row.Item2,\n                row.Item3,\n            }));\n    }\n\n    public static void\n        PrintTable<T1, T2, T3, T4>(\n            (string, string, string, string) header,\n            IEnumerable<(T1, T2, T3, T4)> rows)\n        where T1 : notnull\n        where T2 : notnull\n        where T3 : notnull\n        where T4 : notnull\n    {\n        PrintTable(\n            new object[]\n            {\n                header.Item1,\n                header.Item2,\n                header.Item3,\n                header.Item4,\n            },\n            rows.Select(row => new object[]\n            {\n                row.Item1,\n                row.Item2,\n                row.Item3,\n                row.Item4,\n            }));\n    }\n\n    public static IStore LoadStoreFromUri(string uriString)\n    {\n        // TODO: Cocona supports .NET's TypeConverter protocol for instantiating objects\n        // from CLI options/arguments.  We'd better to implement it for IStore, and simply\n        // use IStore as the option/argument types rather than taking them as strings.\n        var uri = new Uri(uriString);\n\n        // FIXME: A workaround for MSBuild not including unused references. Find a better way\n        // to handle this. See: https://github.com/planetarium/libplanet/issues/2623\n#pragma warning disable CS0219\n        RocksDBStore.RocksDBStore? rocksDbStore = null;\n#pragma warning restore CS0219\n\n        switch (uri.Scheme)\n        {\n            case \"default\":\n            case \"rocksdb\":\n                Console.Error.WriteLine(\n                    \"Warning: The scheme {0}:// for the store URI is deprecated.  \" +\n                    \"Use {0}+file:// instead.\",\n                    uri.Scheme\n                );\n                Console.Error.Flush();\n                uri = new Uri($\"{uri.Scheme}+file{uri.ToString().Substring(7)}\");\n                break;\n\n            case \"\":\n            case null:\n                const string? exceptionMessage = \"A store URI must have a scheme, \" +\n                                                 \"e.g., default+file://, rocksdb+file://.\";\n                throw new ArgumentException(exceptionMessage, nameof(uriString));\n        }\n\n        if (StoreLoaderAttribute.LoadStore(uri) is { } pair)\n        {\n            pair.StateStore.Dispose();\n            return pair.Store;\n        }\n\n        (string UriScheme, Type DeclaringType)[] loaders =\n            StoreLoaderAttribute.ListStoreLoaders().ToArray();\n        int longestSchemeLength = Math.Max(\n            \"URI SCHEME\".Length,\n            loaders.Max(loader => loader.UriScheme.Length + 1)\n        );\n        string loaderTable = string.Join(\n            \"\\n\",\n            loaders.Select(pair =>\n                $\"  {(pair.UriScheme + \":\").PadRight(longestSchemeLength)}\" +\n                $\"  {pair.DeclaringType.Name}\")\n        );\n\n        throw new ArgumentException(\n            $\"The store URI scheme {uri.Scheme}:// is not supported.  See also \" +\n            $\"the list of supported store URI schemes:\\n\\n\" +\n            $\"  {\"URI SCHEME\".PadRight(longestSchemeLength)}  PROVIDED BY\\n{loaderTable}\\n\",\n            nameof(uriString)\n        );\n    }\n\n    public static string SerializeHumanReadable<T>(T target) =>\n        JsonSerializer.Serialize(\n            target,\n            new JsonSerializerOptions\n            {\n                WriteIndented = true,\n                Converters =\n                {\n                    new ByteArrayJsonConverter(),\n                    new DateTimeOffsetJsonConverter(),\n                },\n            }\n        );\n\n    public static T? DeserializeHumanReadable<T>(string target)\n        where T : notnull\n    =>\n        JsonSerializer.Deserialize<T>(\n            target, new JsonSerializerOptions\n            {\n                Converters =\n                {\n                    new ByteArrayJsonConverter(),\n                    new DateTimeOffsetJsonConverter(),\n                },\n            }\n        );\n\n    private static void PrintTable(object[] header, IEnumerable<object[]> rows)\n    {\n        IEnumerable<(int, string)> RowToStrings(object[] row)\n        {\n            return Enumerable.Range(0, row.Length)\n                .Select(i => (i, row[i]?.ToString()?.Normalize() ?? string.Empty));\n        }\n\n        // Calculates the column lengths:\n        object[][] rowsArray = rows.ToArray();\n        int[] columnLengths = RowToStrings(header).Select(pair => pair.Item2.Length).ToArray();\n        foreach (object[] row in rowsArray)\n        {\n            foreach ((int i, string col) in RowToStrings(row))\n            {\n                int length = col.Length;\n                if (columnLengths[i] < length)\n                {\n                    columnLengths[i] = length;\n                }\n            }\n        }\n\n        // Prints column names (into /dev/stderr):\n        foreach ((int i, string col) in RowToStrings(header))\n        {\n            int length = columnLengths[i];\n            Console.Error.Write(i > 0 ? $\" {{0,-{length}}}\" : $\"{{0,-{length}}}\", col);\n        }\n\n        Console.Error.WriteLine();\n\n        // Prints horizontal lines (into /dev/stderr):\n        foreach ((int i, string col) in RowToStrings(header))\n        {\n            Console.Error.Write(i > 0 ? \" {0}\" : \"{0}\", new string('-', columnLengths[i]));\n        }\n\n        Console.Error.WriteLine();\n        Console.Error.Flush();\n\n        // Print rows:\n        foreach (object[] row in rowsArray)\n        {\n            foreach ((int i, string col) in RowToStrings(row))\n            {\n                int length = columnLengths[i];\n                Console.Write(i > 0 ? $\" {{0,-{length}}}\" : $\"{{0,-{length}}}\", col);\n            }\n\n            Console.WriteLine();\n        }\n    }\n\n    public class DummyAction : IAction\n    {\n        public DummyAction()\n        {\n            PlainValue = Null.Value;\n        }\n\n        /// <inheritdoc/>\n        public IValue PlainValue { get; private set; }\n\n        /// <inheritdoc/>\n        public IWorld Execute(IActionContext context) =>\n            context.PreviousState;\n\n        /// <inheritdoc/>\n        public void LoadPlainValue(IValue plainValue)\n        {\n            PlainValue = plainValue;\n        }\n    }\n\n    private sealed class DateTimeOffsetJsonConverter : JsonConverter<DateTimeOffset>\n    {\n        public override DateTimeOffset Read(\n            ref Utf8JsonReader reader,\n            Type typeToConvert,\n            JsonSerializerOptions options)\n        {\n            var jsonString = reader.GetString()\n                ?? throw new JsonException(\"Expected a string.\");\n            return DateTimeOffset.ParseExact(\n                jsonString,\n                DateTimeOffsetFormat,\n                CultureInfo.InvariantCulture\n            );\n        }\n\n        public override void Write(\n            Utf8JsonWriter writer,\n            DateTimeOffset value,\n            JsonSerializerOptions options)\n        {\n            writer.WriteStringValue(\n                value.ToString(\n                    DateTimeOffsetFormat,\n                    CultureInfo.InvariantCulture\n                ));\n        }\n    }\n}\n"
  },
  {
    "path": "tools/Libplanet.Tools/.gitignore",
    "content": "!bin/\nbin/*/\npackage.tgz\n"
  },
  {
    "path": "tools/Libplanet.Tools/CONTRIBUTING.md",
    "content": "On npm packaging\n================\n\nAlthough *Libplanet.Tools* is a CLI program written in .NET, it's also\ndistributed via *npm*, the popular package manager for JavaScript:\n*[@planetarium/cli]*.  The npm package consists of three scripts:\n\n -  *download.mjs* downloads an appropriate archive file for the machine from\n    GitHub release page, and unpack the executable binary to the right place.\n -  *install.mjs* simply invokes the above script.  It's automatically invoked\n    by npm when the package is installed.\n -  *bin/planet.mjs* is used on Windows or if the package is installed with\n    npm's `--ignore-scripts` option.  The suffix *.mjs* is stripped when it's\n    installed in a Linux/macOS system or replaced by *.exe* on Windows.\n    Read the comment on the top of the file\n    for details.\n\nAs the npm package *[@planetarium/cli]* is just a thin wrapper around\n*Libplanet.Tools* project, which is also a thin entrypoint of\n*Libplanet.Extensions.Cocona* project, if you want to change the program itself\nsee *Libplanet.Extensions.Cocona* project instead.\n\n[@planetarium/cli]: https://www.npmjs.com/package/@planetarium/cli\n\n\nTesting the installer\n---------------------\n\nNote that the below examples do not test `npm install @planetarium/cli@0.27.3`,\nbut install *Libplanet.Tools* 0.27.3 with the *current install script in your\nlocal working directory*.\n\n### Linux/macOS\n\nThere are prerequisites for testing:\n\n -  GNU Bash\n -  jq\n -  npm\n\nHere's a testing script:\n\n~~~ bash\nbin/npm-test.sh 0.27.3  # Libplanet.Tools version to install\n~~~\n\nIt must terminate with the output `Succeeded!` in the end if tests passed.\n\n### Windows\n\nThere are prerequisites for testing:\n\n -  PowerShell 5.1 or higher\n -  npm\n\nHere's a testing script:\n\n~~~ powershell\npowershell `\n  -ExecutionPolicy Bypass `\n  -File bin\\npm-test.ps1 `\n  -Version 0.27.3  # Libplanet.Tools version to install\n~~~\n\nIt must terminate with the output `Succeeded!` in the end if tests passed.\n"
  },
  {
    "path": "tools/Libplanet.Tools/Libplanet.Tools.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <PropertyGroup>\n    <Title>planet: Libplanet CLI Tools</Title>\n    <Summary>planet: Libplanet CLI Tools</Summary>\n    <Description>This CLI app is a collection of utilities for application <!--\n    --> programmers who create decentralized games powered by Libplanet <!--\n    --> (https://libplanet.io/).</Description>\n    <OutputType>Exe</OutputType>\n    <ToolCommandName>planet</ToolCommandName>\n    <TreatWarningsAsErrors>true</TreatWarningsAsErrors>\n    <NoWarn>$(NoWarn);CS1591;S1118;SA1118</NoWarn>\n  </PropertyGroup>\n\n  <PropertyGroup Condition=\" '$(PublishSingleFile)' != 'true' \">\n    <PackAsTool>true</PackAsTool>\n  </PropertyGroup>\n\n  <PropertyGroup Condition=\" '$(PublishSingleFile)' == 'true' \">\n    <AssemblyName>planet</AssemblyName>\n  </PropertyGroup>\n\n  <PropertyGroup Condition=\" '$(PublishSingleFile)' == 'true' And '$(RuntimeIdentifier).Substring(0, 6)' == 'linux-' \">\n    <InvariantGlobalization>true</InvariantGlobalization>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <None Remove=\"..\\..\\README.md\" />\n    <None Include=\"README.md\" Pack=\"true\" PackagePath=\"README.md\" />\n    <AdditionalFiles Include=\"..\\..\\Menees.Analyzers.Settings.xml\">\n      <Link>Menees.Analyzers.Settings.xml</Link>\n    </AdditionalFiles>\n    <AdditionalFiles Include=\"..\\..\\stylecop.json\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <PackageReference Include=\"Cocona.Lite\" Version=\"2.0.*\" />\n  </ItemGroup>\n\n  <ItemGroup Condition=\"'$(SkipSonar)' != 'true'\">\n    <PackageReference Remove=\"SonarAnalyzer.CSharp\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <ProjectReference Include=\"..\\Libplanet.Extensions.Cocona\\Libplanet.Extensions.Cocona.csproj\" />\n    <ProjectReference Include=\"..\\..\\src\\Libplanet\\Libplanet.csproj\" />\n    <ProjectReference Include=\"..\\..\\src\\Libplanet.RocksDBStore\\Libplanet.RocksDBStore.csproj\" />\n    <ProjectReference Include=\"..\\..\\src\\Libplanet.Crypto.Secp256k1\\Libplanet.Crypto.Secp256k1.csproj\" />\n    <!-- FIXME: We should specify the version range when the following NuGet\n    issue is addressed: <https://github.com/NuGet/Home/issues/5556>. -->\n  </ItemGroup>\n\n</Project>\n"
  },
  {
    "path": "tools/Libplanet.Tools/Program.cs",
    "content": "namespace Libplanet.Tools;\n\nusing System;\nusing System.IO;\nusing System.Security.Cryptography;\nusing System.Threading.Tasks;\nusing Cocona;\nusing Libplanet.Crypto.Secp256k1;\nusing Libplanet.Extensions.Cocona.Commands;\nusing Libplanet.Extensions.Cocona.Extensions;\nusing CryptoConfig = Libplanet.Crypto.CryptoConfig;\n\n[HasSubCommands(typeof(ApvCommand), \"apv\", Description = \"App protocol version utilities.\")]\n[HasSubCommands(typeof(KeyCommand), \"key\", Description = \"Manage private keys.\")]\n[HasSubCommands(typeof(MptCommand), \"mpt\", Description = \"Merkle Patricia Trie utilities.\")]\n[HasSubCommands(typeof(StoreCommand), \"store\", Description = \"Store utilities.\")]\n[HasSubCommands(typeof(StatsCommand), \"stats\", Description = \"Stats utilities.\")]\n[HasSubCommands(typeof(TxCommand), \"tx\", Description = \"Transaction utilities.\")]\n[HasSubCommands(typeof(BlockCommand), \"block\", Description = \"Block utilities.\")]\npublic class Program\n{\n    private static readonly string FileConfigurationServiceRoot = Path.Combine(\n        Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData),\n        \"planetarium\",\n        \"cli.json\");\n\n    // Workaround for linking with Libplanet.RocksDBStore.\n    private static readonly Type _rocksdb = typeof(Libplanet.RocksDBStore.RocksDBStore);\n\n    public static Task Main(string[] args)\n    {\n        try\n        {\n            CryptoConfig.CryptoBackend = new Secp256k1CryptoBackend<SHA256>();\n        }\n        catch (Exception)\n        {\n            // If it fails to load the Secp256k1CryptoBackend<T> for any reason\n            // fall back to the DefaultCryptoBackend<T> instead.\n        }\n\n        return CoconaLiteApp.CreateHostBuilder()\n            .ConfigureServices(services =>\n            {\n                services.AddJsonConfigurationService(FileConfigurationServiceRoot);\n            })\n            .RunAsync<Program>(args, options =>\n            {\n                options.TreatPublicMethodsAsCommands = false;\n                options.EnableShellCompletionSupport = true;\n            });\n    }\n\n    [PrimaryCommand]\n    public Task Help() =>\n        /* FIXME: I believe there is a better way... */\n        Main(new[] { \"--help\" });\n}\n"
  },
  {
    "path": "tools/Libplanet.Tools/README.md",
    "content": "`planet`: Libplanet CLI Tools\n=============================\n\n[![npm][npm-badge]][npm]\n[![NuGet][nuget-badge]][NuGet]\n[![NuGet (prerelease)][nuget-prerelease-badge]][NuGet]\n\nThis CLI app is a collection of utilities for application programmers who\ncreate decentralized games powered by [Libplanet].\n\n[npm]: https://www.npmjs.com/package/@planetarium/cli\n[npm-badge]: https://img.shields.io/npm/v/@planetarium/cli\n[NuGet]: https://www.nuget.org/packages/Libplanet.Tools/\n[nuget-badge]: https://img.shields.io/nuget/v/Libplanet.Tools.svg?style=flat\n[nuget-prerelease-badge]: https://img.shields.io/nuget/vpre/Libplanet.Tools.svg?style=flat\n[Libplanet]: https://libplanet.io/\n\n\nInstallation\n------------\n\nThere are multiple ways to install the `planet` command.  Pick the most handy\none for you.\n\n### `npm` [![npm][npm-badge]][npm]\n\nInstall as an `npm` package if `npm` is installed on your system:\n\n~~~~ bash\nnpm install @planetarium/cli\n~~~~\n\n### .NET Core tool [![NuGet][nuget-badge]][NuGet]\n\nInstall as a [.NET Core tool] if .NET Core SDK is installed on your system:\n\n~~~~ bash\ndotnet tool install -g Libplanet.Tools\n~~~~\n\n[.NET Core tool]: https://docs.microsoft.com/en-us/dotnet/core/tools/global-tools\n\n### Manual installation [![GitHub Releases][releases-badge]][releases page]\n\nOr you could just download an executable binary for your platform from\nthe [releases page]: *planet-\\*-{linux,osx,win}-{x64, arm64}.{tar.xz,zip}* files are\nCLI tools.  Linux (x64), macOS (x64, arm64), and Windows (x64) are supported.\nExtract the binary to an appropriate directory in your `PATH`.\n\n[releases page]: https://github.com/planetarium/libplanet/releases\n[releases-badge]: https://img.shields.io/github/v/release/planetarium/libplanet?sort=semver\n\n\nUsage\n-----\n\n~~~~ bash\nplanet --help\n~~~~\n\nIf you installed it using `npm` *without `-g`/`--global` option*\nuse `npx planet` command instead:\n\n~~~~ bash\nnpx planet --help\n~~~~\n\nOr if you installed it using .NET Core SDK *without `-g`/`--global` option*\nuse `dotnet planet` command instead:\n\n~~~~ bash\ndotnet planet --help\n~~~~\n\n### Command-line completion\n\nAll subcommands and options can be completed in bash and zsh.  You can\nconfigure command-line completion through `--completion` option.\n\nFor bash:\n\n~~~~ bash\nsource <(planet --completion bash)\n~~~~\n\nFor zsh:\n\n~~~~ zsh\nplanet --completion zsh > ~/.zsh/functions\n~~~~\n"
  },
  {
    "path": "tools/Libplanet.Tools/bin/npm-test.ps1",
    "content": "#!/usr/bin/env pwsh\nparam (\n  [Parameter(Mandatory, Position=0, HelpMessage=\"Enter a version to download.\")]\n  [ValidatePattern(\"^(0|[1-9]\\d*)\\.(0|[1-9]\\d*)\\.(0|[1-9]\\d*)(?:-((?:0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\\.(?:0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\\+([0-9a-zA-Z-]+(?:\\.[0-9a-zA-Z-]+)*))?$\")]\n  [string]\n  $Version\n)\n\n$ErrorActionPreference = \"Stop\"\n$InformationPreference = \"Continue\"\n$DebugPreference = \"Continue\"\n\nfunction New-TemporaryDirectory {\n  New-TemporaryFile | ForEach-Object {\n    Remove-Item $_\n    New-Item -ItemType Directory -Path $_\n  }\n}\n\nfunction Test-Npx(\n  [Parameter(Mandatory, Position=0)][string[]]$Command,\n  [Parameter(Mandatory, Position=1)][string]$Expected\n) {\n  if ($env:ACTIONS_RUNNER_DEBUG -eq \"true\") {\n    $cmd = $Command -Join \" \"\n    & \"npx\" @Command\n    Write-Debug \"The command 'npx $cmd' terminated with $?.\"\n  }\n  $actual = & \"npx\" @Command\n  if ($actual -ne $Expected) {\n    $cmd = $Command -Join \" \"\n    Write-Error \"The command 'npx $cmd' printed an unexpected output.\n  Expected: $Expected\n  Actual: $actual\"\n    exit 1\n  }\n}\n\nfunction Test-Planet() {\n  Test-Npx @(\"planet\", \"--version\") \"planet $Version\"\n}\n\nif (-not (Get-Command yarn 2> $null)) {\n  Write-Error \"The yarn is unavailable.\"\n  exit 1\n} elseif (-not (Get-Command npm 2> $null)) {\n  Write-Error \"The npm is unavailable.\"\n  exit 1\n} elseif (-not (Get-Command npx 2> $null)) {\n  Write-Error \"The npx command is unavailable.\"\n  exit 1\n}\n\n$PackageDir = Resolve-Path (Split-Path -Path $PSScriptRoot -Parent)\n\nCopy-Item (Join-Path -Path $PackageDir -ChildPath \"package.json\") `\n  (Join-Path -Path $PackageDir -ChildPath \".package.json.bak\")\ntry {\n  $Package = Get-Content \"package.json\" | ConvertFrom-Json\n  $Package.private = $false\n  $Package.version = $Version\n  ConvertTo-Json -Depth 100 $Package | Set-Content \"package.json\"\n\n  if (Test-Path package.tgz) {\n    Remove-Item -Force package.tgz\n  }\n  yarn pack --install-if-needed\n  $PackagePath = Join-Path `\n    -Path $PackageDir `\n    -ChildPath \"package.tgz\"\n\n  Write-Information 'Test with \"npm install\"...'\n  $tempDir = New-TemporaryDirectory\n  Push-Location $tempDir\n  Write-Debug \"Enter a temporary directory: $($tempDir.FullName)\"\n  npm install --save $PackagePath\n  Test-Planet\n  Pop-Location\n\n  Write-Information 'Test with \"npm install --ignore-scripts\"...'\n  $tempDir = New-TemporaryDirectory\n  Push-Location $tempDir\n  Write-Debug \"Enter a temporary directory: $($tempDir.FullName)\"\n  npm install --quiet --ignore-scripts --save $PackagePath\n  Test-Planet\n  Pop-Location\n\n  Write-Output \"Succeeded!\"\n} finally {\n  Remove-Item (Join-Path -Path $PackageDir -ChildPath \"package.json\")\n  Rename-Item (Join-Path -Path $PackageDir -ChildPath \".package.json.bak\") `\n    (Join-Path -Path $PackageDir -ChildPath \"package.json\")\n  Pop-Location -PassThru\n}\n"
  },
  {
    "path": "tools/Libplanet.Tools/bin/npm-test.sh",
    "content": "#!/bin/bash\nset -e\n\n# Taken from https://github.com/har7an/bash-semver-regex\n# Regex for a semver digit\nD='0|[1-9][0-9]*'\n# Regex for a semver pre-release word\nPW='[0-9]*[a-zA-Z-][0-9a-zA-Z-]*'\n# Regex for a semver build-metadata word\nMW='[0-9a-zA-Z-]+'\n\nif [[ \"$1\" = \"\" ]]; then\n  echo error: missing version to download >&2\n  exit 1\nelif [[ \"$1\" =~ ^($D)\\.($D)\\.($D)(-(($D|$PW)(\\.($D|$PW))*))?(\\+($MW(\\.$MW)*))?$ ]]; then\n  version=\"$1\"\nelse\n  echo error: invalid version number: \"$1\" >&2\n  exit 1\nfi\n\nfunction test_npx() {\n  cmd=\"$1\"\n  expected=\"$2\"\n  actual=\"$(npx $1)\"\n  if [[ \"$actual\" != \"$expected\" ]]; then\n    {\n      echo \"The command \\`$cmd' printed an unexpected output.\"\n      echo \"  expected: $expected\"\n      echo \"  actual:   $actual\"\n    } >&2\n    exit 1\n  fi\n}\n\nfunction test_planet() {\n  test_npx \"planet --version\" \"planet $version\"\n}\n\npkgdir=\"$(cd \"$(dirname \"$0\")\"; cd ..; pwd)\"\n\ncp \"$pkgdir/package.json\" \"$pkgdir/.package.json.bak\"\n# shellcheck disable=SC2064\ntrap \"mv '$pkgdir/.package.json.bak' '$pkgdir/package.json'\" EXIT\njq --arg v \"$version\" 'del(.private) | .version = $v' package.json \\\n  > .package.json.tmp\nmv .package.json.tmp package.json\n\nrm -f package.tgz\nyarn pack --install-if-needed\n\necho Test with \\`npm install\\'... >&2\npushd \"$(mktemp -d)\"\nnpm install --quiet --save \"$pkgdir/package.tgz\"\ntest_planet\npopd\n\necho Test with \\`npm install --ignore-scripts\\'... >&2\npushd \"$(mktemp -d)\"\nnpm install \\\n  --quiet \\\n  --ignore-scripts \\\n  --save \\\n  \"$pkgdir/package.tgz\"\ntest_planet\npopd\n\nrm \"$pkgdir\"/package.tgz\n\necho \"Succeeded!\"\n"
  },
  {
    "path": "tools/Libplanet.Tools/bin/planet.mjs",
    "content": "#!/usr/bin/env node\n\"use strict\";\n// About this script: this script has two purposes:\n//\n// - Some users could pass --ignore-scripts option to \"npm install\" command,\n//   which ignores the install.js script.  In such case, \"npx planet\" will\n//   invoke this script at first time, and this downloads the actual ELF binary\n//   and overwrites this scripts with the ELF binary.  After the first invoke,\n//   \"npx planet\" becomes to directly invoke the ELF binary instead.\n//\n// - On Windows, npm creates a fake executable named \"planet.cmd\" to invoke\n//   this script, regardless of --ignore-scripts option.  There is likely no way\n//   to avoid this node.js script being invoked before the actual planet.exe\n//   is invoked.\nimport child_process from \"child_process\";\nimport fs from \"fs\";\nimport path from \"path\";\nimport { BIN_PATH, BIN_NAME, download } from \"../download.mjs\";\n\nconst exePath = path.join(BIN_PATH, BIN_NAME);\n\nfunction runExe() {\n  child_process.spawnSync(exePath, process.argv.slice(2), { stdio: \"inherit\" });\n}\n\nif (process.platform === \"win32\") {\n  // On Windows, this script is never overwritten even after download() was\n  // executed, as on Windows executables always have suffixes,\n  // e.g., \"planet.exe\".  Therefore, this script is always called on Windows\n  // regardless of presence of planet.exe, so this script has to check if\n  // planet.exe exists every time.\n  fs.access(exePath, fs.constants.R_OK, err => {\n    if (!err) return runExe();\n    return download({ log: console.warn }).then(runExe).catch(console.error);\n  });\n} else {\n  // On the other hand, on POSIX platforms other than Windows, this script\n  // is overwritten after download() executed, which means if the below code is\n  // executed there must *not* be the actual ELF binary of the \"planet\" command.\n  // Therefore, download() should be invoked first.\n  const downloaded = await download({ log: console.warn });\n  runExe(downloaded);\n}\n\n// vim: ts=2 sw=2 et ft=javascript\n"
  },
  {
    "path": "tools/Libplanet.Tools/download.mjs",
    "content": "// The planet binary downloader for npm.\n// Inspired by Elm's npm packaging: <https://www.npmjs.com/package/elm>.\n\"use strict\";\nimport child_process from \"child_process\";\nimport { createWriteStream } from \"fs\";\nimport { chmod, copyFile, mkdtemp, readFile } from \"fs/promises\";\nimport { pipeline } from \"stream/promises\";\nimport os from \"os\";\nimport { fileURLToPath } from 'url';\nimport path from \"path\";\nimport fetch from \"node-fetch\";\nimport extractZip from \"extract-zip\";\n\nconst URL_BASE = \"https://github.com/planetarium/libplanet/releases/download\";\nconst SUFFIXES = {\n  darwin: {x64: \"osx-x64.tar.xz\", arm64: \"osx-arm64.tar.xz\"},\n  linux: {x64: \"linux-x64.tar.xz\"},\n  win32: {x64: \"win-x64.zip\"},\n};\nconst PACKAGE_PATH = path.dirname(fileURLToPath(import.meta.url));\nconst METADATA_PATH = path.join(PACKAGE_PATH, \"package.json\");\nexport const BIN_NAME = process.platform === \"win32\" ? \"planet.exe\" : \"planet\";\nexport const BIN_PATH = path.join(PACKAGE_PATH, \"bin\");\n\nexport async function download(options = {}) {\n  const { binPath = BIN_PATH, binName = BIN_NAME, log = console.log } = options;\n  const packageMetadata = JSON.parse(await readFile(METADATA_PATH));\n  const ver = packageMetadata.version;\n  const platform = os.platform();\n  const platformSuffixes = SUFFIXES[platform];\n\n  if (platformSuffixes == null) {\n    throw new Error(`Unsupported platform: ${platform}`);\n  }\n\n  const arch = os.arch();\n  const suffix = platformSuffixes[arch];\n\n  if (suffix == null) {\n    throw new Error(`Unsupported architecture: ${platform}-${arch}`);\n  }\n\n  const url = `${URL_BASE}/${ver}/planet-${ver}-${suffix}`;\n\n  const dirPath = await mkdtemp(path.join(os.tmpdir(), \"planet-\"));\n  const srcPath = path.join(dirPath, BIN_NAME);\n  const dstPath = path.join(binPath, binName);\n  const finalize = async () => {\n    await copyFile(srcPath, dstPath);\n    if (platform === \"win32\") return;\n    await chmod(dstPath, 0o755);\n  };\n\n  const unarchive = (archivePath) => {\n    if (suffix.toLowerCase().endsWith(\".zip\")) {\n      return extractZip(archivePath, { dir: dirPath });\n    } else {\n      return new Promise((resolve, reject) => {\n        const subproc = child_process.spawn(\"tar\", [\"xvfJ\", archivePath], {\n          cwd: dirPath,\n          stdio: [\"ignore\", \"ignore\", \"ignore\"]\n        });\n        subproc.on(\"close\", code => {\n          if (code !== 0) return reject(code);\n          return resolve();\n        });\n      });\n    }\n  };\n\n  const adhocSign = () => {\n    return new Promise((resolve, reject) => {\n        const args = [\n            \"--sign\",\n            \"-\",\n            \"--force\",\n            \"--preserve-metadata=entitlements,requirements,flags,runtime\",\n            srcPath\n        ]\n        child_process.execFile(\n            \"codesign\",\n            args,\n            (err, stdout, stderr) => {\n                if (err)\n                {\n                    return reject(stderr || err);\n                } else {\n                    return resolve(stdout);\n                }\n            }\n        );\n    });\n  }\n\n  if (log != null) log(`\n-------------------------------------------------------------------------------\nDownloading Libplanet CLI Tools ${ver} from GitHub...\n\nNOTE: You can avoid npm entirely by downloading directly from:\n\n  ${url}\n\nAll this package does is downloading that file and put it somewhere.\n-------------------------------------------------------------------------------\n  `);\n\n  const archivePath = path.join(dirPath, url.match(/[^/]+$/)[0]);\n  const writeStream = createWriteStream(archivePath);\n  try {\n    const res = await fetch(url);\n    await pipeline(res.body, writeStream);\n  } catch (err) {\n    console.error(`\n-------------------------------------------------------------------------------\nAn error occurred during Libplanet CLI Tools from GitHub:\n\n  ${url}\n\nReport this issue from https://github.com/planetarium/libplanet/issues\n\n${err}\n-------------------------------------------------------------------------------\n    `);\n    throw e;\n  }\n  try {\n    await unarchive(archivePath);\n  } catch (err) {\n    console.error(`\n-------------------------------------------------------------------------------\nAn error occurred during unarchiving Libplanet CLI Tools:\n\n  ${archivePath}\n\n... which is downloaded from:\n\n  ${url}\n\nReport this issue from https://github.com/planetarium/libplanet/issues\n\n${err}\n-------------------------------------------------------------------------------\n    `);\n    throw err;\n  }\n  if (platform === \"darwin\" && arch === \"arm64\")\n  {\n    try {\n        await adhocSign();\n    } catch(err) {\n        console.error(`\n    -------------------------------------------------------------------------------\n    An error occurred during installing Libplanet CLI Tools:\n\n      codesign ${srcPath}\n\n    Report this issue from https://github.com/planetarium/libplanet/issues\n\n    ${err}\n    -------------------------------------------------------------------------------\n        `);\n        throw err;\n    }\n  }\n  try {\n    await finalize();\n  } catch(err) {\n    console.error(`\n-------------------------------------------------------------------------------\nAn error occurred during installing Libplanet CLI Tools:\n\n  ${srcPath} -> ${dstPath}\n\nReport this issue from https://github.com/planetarium/libplanet/issues\n\n${err}\n-------------------------------------------------------------------------------\n    `);\n    throw err;\n  }\n}\n"
  },
  {
    "path": "tools/Libplanet.Tools/install.mjs",
    "content": "// Post-install hook for npm.\n\"use strict\";\nimport { download } from \"./download.mjs\";\n\ndownload().then(console.debug).catch(console.error);\n\n// vim: ts=2 sw=2 et ft=javascript\n"
  },
  {
    "path": "tools/Libplanet.Tools/package.json",
    "content": "{\n  \"name\": \"@planetarium/cli\",\n  \"version\": \"0.0.0\",\n  \"private\": true,\n  \"description\": \"This CLI app is a collection of utilities for application programmers who create decentralized games powered by Libplanet.\",\n  \"os\": [\n    \"darwin\",\n    \"linux\",\n    \"win32\"\n  ],\n  \"cpu\": [\n    \"x64\",\n    \"arm64\"\n  ],\n  \"engines\": {\n    \"node\": \">=12\"\n  },\n  \"files\": [\n    \"README.md\",\n    \"bin/planet.mjs\",\n    \"download.mjs\",\n    \"install.mjs\"\n  ],\n  \"dependencies\": {\n    \"extract-zip\": \"^2.0.1\",\n    \"node-fetch\": \"^3.1.1\"\n  },\n  \"type\": \"module\",\n  \"scripts\": {\n    \"install\": \"node install.mjs\"\n  },\n  \"bin\": {\n    \"planet\": \"bin/planet.mjs\"\n  },\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"https://github.com/planetarium/libplanet.git\",\n    \"directory\": \"tools/Libplanet.Tools\"\n  },\n  \"keywords\": [\n    \"planetarium\",\n    \"libplanet\",\n    \"blockchain\",\n    \"p2p\",\n    \"game\"\n  ],\n  \"author\": \"Planetarium\",\n  \"license\": \"LGPL-2.1-or-later\",\n  \"bugs\": {\n    \"url\": \"https://github.com/planetarium/libplanet/labels/tools\"\n  },\n  \"homepage\": \"https://github.com/planetarium/libplanet/tree/main/tools/Libplanet.Tools\"\n}\n"
  }
]